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)
我们现在可以提交提示词并通过llm.generate
的lora_request
参数进行调用。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以确保使用正确的版本。
服务器入口点接受所有其他LoRA配置参数(max_loras
、max_lora_rank
、max_cpu_loras
等),这些参数将应用于所有后续请求。查询/models
端点时,我们应该能看到LoRA及其基础模型(如果未安装jq
,可以按照此指南安装):
curl localhost:8000/v1/models | jq .
{
"object": "list",
"data": [
{
"id": "meta-llama/Llama-2-7b-hf",
"object": "model",
...
},
{
"id": "sql-lora",
"object": "model",
...
}
]
}
请求可以通过model
请求参数指定LoRA适配器,就像指定其他模型一样。这些请求将根据服务器全局的LoRA配置进行处理(即与基础模型请求并行处理,如果提供了其他LoRA适配器请求且max_loras
设置得足够高,还可能同时处理其他LoRA适配器请求)。
以下是一个示例请求
curl http://localhost: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 http://localhost:8000/v1/load_lora_adapter \
-H "Content-Type: application/json" \
-d '{
"lora_name": "sql_adapter",
"lora_path": "/path/to/sql-lora-adapter"
}'
请求成功后,API将返回200 OK
状态码(来自vllm serve
),同时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 http://localhost: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适配器加载。如果成功,请求将正常完成,
该适配器随后便可在服务器上正常使用。
或者,按照以下示例步骤实现您自己的插件: 1. 实现LoRAResolver接口。
Example of a simple S3 LoRAResolver implementation:
```python
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插件。
```python 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 http://localhost: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": [
{
....
}
]
}
]
}