LoRA 介面卡¶
本文件將向您展示如何在基礎模型之上,將 LoRA 介面卡與 vLLM 結合使用。
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 適配模型也可以透過相容 Open-AI 的 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,以確保使用正確。
伺服器入口點接受所有其他 LoRA 配置引數(如 max_loras
, max_lora_rank
, max_cpu_loras
等),這些引數將應用於所有後續請求。查詢 /models
端點時,我們應該能看到我們的 LoRA 及其基礎模型(如果未安裝 jq
,您可以按照此指南進行安裝)。
命令
請求可以透過 model
請求引數指定 LoRA 介面卡,就像指定任何其他模型一樣。請求將根據伺服器範圍內的 LoRA 配置進行處理(即與基礎模型請求並行,並且如果提供了其他 LoRA 介面卡請求且 max_loras
設定得足夠高,則也與它們並行處理)。
以下是一個請求示例
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
和聊天補全。