LoRA 介面卡¶
本文件將向您展示如何在基礎模型之上,在 vLLM 中使用 LoRA 介面卡。
LoRA 介面卡可以與任何實現了 SupportsLoRA 的 vLLM 模型一起使用。
介面卡可以高效地按請求進行服務,開銷極小。首先,我們下載介面卡並使用以下命令將其本地儲存:
from huggingface_hub import snapshot_download
sql_lora_path = snapshot_download(repo_id="yard1/llama-2-7b-sql-lora-test")
然後,我們例項化基礎模型並傳遞 enable_lora=True 標誌
from vllm import LLM, SamplingParams
from vllm.lora.request import LoRARequest
llm = LLM(model="meta-llama/Llama-2-7b-hf", enable_lora=True)
現在我們可以提交提示,並透過 lora_request 引數呼叫 llm.generate。LoRARequest 的第一個引數是人類可識別的名稱,第二個引數是介面卡的全域性唯一 ID,第三個引數是 LoRA 介面卡的路徑。
程式碼
sampling_params = SamplingParams(
temperature=0,
max_tokens=256,
stop=["[/assistant]"],
)
prompts = [
"[user] Write a SQL query to answer the question based on the table schema.\n\n context: CREATE TABLE table_name_74 (icao VARCHAR, airport VARCHAR)\n\n question: Name the ICAO for lilongwe international airport [/user] [assistant]",
"[user] Write a SQL query to answer the question based on the table schema.\n\n context: CREATE TABLE table_name_11 (nationality VARCHAR, elector VARCHAR)\n\n question: When Anchero Pantaleone was the elector what is under nationality? [/user] [assistant]",
]
outputs = llm.generate(
prompts,
sampling_params,
lora_request=LoRARequest("sql_adapter", 1, sql_lora_path),
)
請檢視 examples/offline_inference/multilora_inference.py 以獲取使用非同步引擎的 LoRA 介面卡以及如何使用更高階配置選項的示例。
服務 LoRA 介面卡¶
LoRA 適配的模型也可以與相容 OpenAI 的 vLLM 伺服器一起提供服務。為此,我們使用 --lora-modules {name}={path} {name}={path} 在啟動伺服器時指定每個 LoRA 模組。
vllm serve meta-llama/Llama-2-7b-hf \
--enable-lora \
--lora-modules sql-lora=$HOME/.cache/huggingface/hub/models--yard1--llama-2-7b-sql-lora-test/snapshots/0dfa347e8877a4d4ed19ee56c140fa518470028c/
注意
提交 ID 0dfa347e8877a4d4ed19ee56c140fa518470028c 可能會隨時間變化。請檢查您環境中的最新提交 ID,以確保您使用的是正確的 ID。
伺服器入口點接受所有其他 LoRA 配置引數(max_loras、max_lora_rank、max_cpu_loras 等),這些引數將應用於所有後續請求。在查詢 /models 端點時,我們應該看到我們的 LoRA 及其基礎模型(如果未安裝 jq,您可以按照 此指南 進行安裝。)
命令
請求可以透過 model 請求引數將 LoRA 介面卡指定為任何其他模型。請求將根據伺服器範圍的 LoRA 配置進行處理(即與基礎模型請求並行,並且如果提供了其他 LoRA 介面卡請求並且 max_loras 設定得足夠高,則可能與其他 LoRA 介面卡請求並行處理)。
以下是一個示例請求
curl https://:8000/v1/completions \
-H "Content-Type: application/json" \
-d '{
"model": "sql-lora",
"prompt": "San Francisco is a",
"max_tokens": 7,
"temperature": 0
}' | jq
動態服務 LoRA 介面卡¶
除了在伺服器啟動時提供 LoRA 介面卡之外,vLLM 伺服器還支援透過專用的 API 端點和外掛在執行時動態配置 LoRA 介面卡。當需要即時更改模型的靈活性時,此功能可能特別有用。
注意:在生產環境中啟用此功能存在風險,因為使用者可能會參與模型介面卡的管理。
要啟用動態 LoRA 配置,請確保將環境變數 VLLM_ALLOW_RUNTIME_LORA_UPDATING 設定為 True。
使用 API 端點¶
載入 LoRA 介面卡
要動態載入 LoRA 介面卡,請向 /v1/load_lora_adapter 端點發送 POST 請求,並提供要載入的介面卡的必要詳細資訊。請求負載應包括 LoRA 介面卡的名稱和路徑。
載入 LoRA 介面卡的示例請求
curl -X POST https://:8000/v1/load_lora_adapter \
-H "Content-Type: application/json" \
-d '{
"lora_name": "sql_adapter",
"lora_path": "/path/to/sql-lora-adapter"
}'
成功請求後,API 將從 vllm serve 返回 200 OK 狀態碼,curl 返回響應體:Success: LoRA adapter 'sql_adapter' added successfully。如果發生錯誤,例如找不到或無法載入介面卡,則會返回適當的錯誤訊息。
解除安裝 LoRA 介面卡
要解除安裝先前載入的 LoRA 介面卡,請向 /v1/unload_lora_adapter 端點發送 POST 請求,並提供要解除安裝的介面卡的名稱或 ID。
成功請求後,API 將從 vllm serve 返回 200 OK 狀態碼,curl 返回響應體:Success: LoRA adapter 'sql_adapter' removed successfully。
解除安裝 LoRA 介面卡的示例請求
curl -X POST https://:8000/v1/unload_lora_adapter \
-H "Content-Type: application/json" \
-d '{
"lora_name": "sql_adapter"
}'
使用外掛¶
或者,您可以使用 LoRAResolver 外掛動態載入 LoRA 介面卡。LoRAResolver 外掛使您能夠從本地和遠端源(如本地檔案系統和 S3)載入 LoRA 介面卡。在每個請求上,當有尚未載入的新模型名稱時,LoRAResolver 將嘗試解析並載入相應的 LoRA 介面卡。
如果您想從不同源載入 LoRA 介面卡,可以設定多個 LoRAResolver 外掛。例如,您可以有一個用於本地檔案的解析器,另一個用於 S3 儲存。vLLM 將載入它找到的第一個 LoRA 介面卡。
您可以安裝現有外掛或實現自己的外掛。預設情況下,vLLM 提供一個 用於從本地目錄載入 LoRA 介面卡的解析器外掛。 要啟用此解析器,請將 VLLM_ALLOW_RUNTIME_LORA_UPDATING 設定為 True,將 VLLM_PLUGINS 設定為包含 lora_filesystem_resolver,然後將 VLLM_LORA_RESOLVER_CACHE_DIR 設定為本地目錄。當 vLLM 收到使用 LoRA 介面卡 foobar 的請求時,它會首先在本地目錄中查詢名為 foobar 的目錄,並嘗試將該目錄的內容作為 LoRA 介面卡載入。如果成功,請求將正常完成,並且該介面卡將可用於伺服器上的正常使用。
或者,請按照以下示例步驟實現自己的外掛
-
實現 LoRAResolver 介面。
簡單的 S3 LoRAResolver 實現示例
import os import s3fs from vllm.lora.request import LoRARequest from vllm.lora.resolver import LoRAResolver class S3LoRAResolver(LoRAResolver): def __init__(self): self.s3 = s3fs.S3FileSystem() self.s3_path_format = os.getenv("S3_PATH_TEMPLATE") self.local_path_format = os.getenv("LOCAL_PATH_TEMPLATE") async def resolve_lora(self, base_model_name, lora_name): s3_path = self.s3_path_format.format(base_model_name=base_model_name, lora_name=lora_name) local_path = self.local_path_format.format(base_model_name=base_model_name, lora_name=lora_name) # Download the LoRA from S3 to the local path await self.s3._get( s3_path, local_path, recursive=True, maxdepth=1 ) lora_request = LoRARequest( lora_name=lora_name, lora_path=local_path, lora_int_id=abs(hash(lora_name)), ) return lora_request -
註冊
LoRAResolver外掛。from vllm.lora.resolver import LoRAResolverRegistry s3_resolver = S3LoRAResolver() LoRAResolverRegistry.register_resolver("s3_resolver", s3_resolver)有關更多詳細資訊,請參閱 vLLM 的外掛系統。
--lora-modules 的新格式¶
在以前的版本中,使用者會透過以下格式提供 LoRA 模組,可以是鍵值對或 JSON 格式。例如:
--lora-modules sql-lora=$HOME/.cache/huggingface/hub/models--yard1--llama-2-7b-sql-lora-test/snapshots/0dfa347e8877a4d4ed19ee56c140fa518470028c/
這僅包含每個 LoRA 模組的 name 和 path,但沒有提供指定 base_model_name 的方法。現在,您可以使用 JSON 格式在名稱和路徑旁邊指定 base_model_name。例如:
--lora-modules '{"name": "sql-lora", "path": "/path/to/lora", "base_model_name": "meta-llama/Llama-2-7b"}'
為了提供向後相容支援,您仍然可以使用舊的鍵值格式(name=path),但 base_model_name 在這種情況下將保持未指定。
模型卡中的 LoRA 模型譜系¶
--lora-modules 的新格式主要是為了支援在模型卡中顯示父模型資訊。以下是對您當前響應如何支援此功能的解釋:
- LoRA 模型
sql-lora的parent欄位現在連結到其基礎模型meta-llama/Llama-2-7b-hf。這正確地反映了基礎模型和 LoRA 介面卡之間的分層關係。 root欄位指向 LoRA 介面卡的工件位置。
命令輸出
$ curl https://:8000/v1/models
{
"object": "list",
"data": [
{
"id": "meta-llama/Llama-2-7b-hf",
"object": "model",
"created": 1715644056,
"owned_by": "vllm",
"root": "~/.cache/huggingface/hub/models--meta-llama--Llama-2-7b-hf/snapshots/01c7f73d771dfac7d292323805ebc428287df4f9/",
"parent": null,
"permission": [
{
.....
}
]
},
{
"id": "sql-lora",
"object": "model",
"created": 1715644056,
"owned_by": "vllm",
"root": "~/.cache/huggingface/hub/models--yard1--llama-2-7b-sql-lora-test/snapshots/0dfa347e8877a4d4ed19ee56c140fa518470028c/",
"parent": meta-llama/Llama-2-7b-hf,
"permission": [
{
....
}
]
}
]
}
多模態模型的預設 LoRA 模型¶
某些模型,例如 Granite Speech 和 Phi-4-multimodal-instruct 多模態模型,包含 LoRA 介面卡,當存在給定模態時,預期始終應用這些介面卡。使用上述方法管理起來可能有點麻煩,因為它需要使用者傳送 LoRARequest(離線)或根據請求的多模態資料內容在基礎模型和 LoRA 模型(伺服器)之間過濾請求。
為此,我們允許註冊預設的多模態 LoRA 以自動處理此問題,使用者可以將每種模態對映到一個 LoRA 介面卡,以便在存在相應輸入時自動應用它。請注意,目前,我們每個提示只允許一個 LoRA;如果提供了多個模態,並且每種模態都註冊了一個給定的模態,則它們都不會被應用。
離線推理的示例用法
from transformers import AutoTokenizer
from vllm import LLM, SamplingParams
from vllm.assets.audio import AudioAsset
model_id = "ibm-granite/granite-speech-3.3-2b"
tokenizer = AutoTokenizer.from_pretrained(model_id)
def get_prompt(question: str, has_audio: bool):
"""Build the input prompt to send to vLLM."""
if has_audio:
question = f"<|audio|>{question}"
chat = [
{"role": "user", "content": question},
]
return tokenizer.apply_chat_template(chat, tokenize=False)
llm = LLM(
model=model_id,
enable_lora=True,
max_lora_rank=64,
max_model_len=2048,
limit_mm_per_prompt={"audio": 1},
# Will always pass a `LoRARequest` with the `model_id`
# whenever audio is contained in the request data.
default_mm_loras = {"audio": model_id},
enforce_eager=True,
)
question = "can you transcribe the speech into a written format?"
prompt_with_audio = get_prompt(
question=question,
has_audio=True,
)
audio = AudioAsset("mary_had_lamb").audio_and_sample_rate
inputs = {
"prompt": prompt_with_audio,
"multi_modal_data": {
"audio": audio,
}
}
outputs = llm.generate(
inputs,
sampling_params=SamplingParams(
temperature=0.2,
max_tokens=64,
),
)
您還可以傳遞一個 --default-mm-loras 的 JSON 字典,將模態對映到 LoRA 模型 ID。例如,在啟動伺服器時:
vllm serve ibm-granite/granite-speech-3.3-2b \
--max-model-len 2048 \
--enable-lora \
--default-mm-loras '{"audio":"ibm-granite/granite-speech-3.3-2b"}' \
--max-lora-rank 64
注意:預設多模態 LoRA 目前僅適用於 .generate 和聊天補全。
使用技巧¶
配置 max_lora_rank¶
--max-lora-rank 引數控制 LoRA 介面卡允許的最大秩。此設定會影響記憶體分配和效能。
- 將其設定為最大秩 — 您計劃使用的所有 LoRA 介面卡中的最大值。
- 避免設定過高 — 使用遠大於所需的值會浪費記憶體並可能導致效能問題。
例如,如果您的 LoRA 介面卡具有秩 [16, 32, 64],則使用 --max-lora-rank 64 而不是 256。