Multi-LoRA 部署#
使用 Ray Serve LLM 高效部署多个微调的 LoRA 适配器。
理解 Multi-LoRA 部署#
Multi-LoRA 允许您的模型在运行时切换不同的微调适配器,而无需重新加载基础模型。
当您的应用程序需要使用单个共享模型后端支持多个域、用户或任务时,请使用 multi-LoRA。以下是您可能希望在工作流程中添加适配器的主要原因:
参数效率:LoRA 适配器很小,通常不到基础模型大小的 1%。这使得它们存储成本低、加载速度快,并且在推理过程中易于进行交换,这在内存紧张的情况下尤其有用。
运行时自适应:使用 multi-LoRA,您可以在推理时切换不同的适配器,而无需重新加载基础模型。这使得能够根据用户、任务、域或上下文动态行为,所有这些都来自单个部署。
简化的 MLOps:Multi-LoRA 通过将推理集中在一个模型上来降低基础设施复杂性和成本。
请求路由如何工作#
当收到针对特定 LoRA 适配器的请求时,Ray Serve 会
检查是否有任何副本已加载该适配器
查找一个已加载适配器但未过载的副本,并将请求路由到该副本
如果所有带有该适配器的副本都已过载,则将请求路由到一个较不繁忙的副本,该副本将加载适配器
如果没有副本加载该适配器,则根据默认请求路由逻辑(例如“Power of 2”)将请求路由到一个副本,并在那里加载它
Ray Serve LLM 然后缓存该适配器以供后续请求使用。Ray Serve LLM 通过具有最大大小的最近最少使用 (LRU) 机制控制每个副本上的 LoRA 适配器缓存,您可以通过 max_num_adapters_per_replica 变量来控制它。
使用 Multi-LoRA 配置 Ray Serve LLM#
要在您的部署上启用 multi-LoRA,请使用以下附加设置更新您的 Ray Serve LLM 配置。
LoRA 配置#
将 dynamic_lora_loading_path 设置为您的 AWS 或 GCS 存储路径
lora_config=dict(
dynamic_lora_loading_path="s3://my_dynamic_lora_path",
max_num_adapters_per_replica=16, # Optional: limit adapters per replica
)
dynamic_lora_loading_path:包含 LoRA 检查点子目录的目录路径。max_num_adapters_per_replica:每个副本缓存的 LoRA 适配器的最大数量。必须与max_loras匹配。
引擎参数#
将这些参数转发到您的 vLLM 引擎
engine_kwargs=dict(
enable_lora=True,
max_lora_rank=32, # Set to the highest LoRA rank you plan to use
max_loras=16, # Must match max_num_adapters_per_replica
)
enable_lora:在 vLLM 引擎中启用 LoRA 支持。max_lora_rank:支持的最大 LoRA 秩。设置为您计划使用的最高秩。max_loras:每个批次的最大 LoRA 数量。必须与max_num_adapters_per_replica匹配。
示例#
以下示例展示了一个完整的 multi-LoRA 配置
from ray import serve
from ray.serve.llm import LLMConfig, build_openai_app
# Configure the model with LoRA
llm_config = LLMConfig(
model_loading_config=dict(
model_id="qwen-0.5b",
model_source="Qwen/Qwen2.5-0.5B-Instruct",
),
lora_config=dict(
# Assume this is where LoRA weights are stored on S3.
# For example
# s3://my_dynamic_lora_path/lora_model_1_ckpt
# s3://my_dynamic_lora_path/lora_model_2_ckpt
# are two of the LoRA checkpoints
dynamic_lora_loading_path="s3://my_dynamic_lora_path",
max_num_adapters_per_replica=16, # Need to set this to the same value as `max_loras`.
),
engine_kwargs=dict(
enable_lora=True,
max_loras=16, # Need to set this to the same value as `max_num_adapters_per_replica`.
),
deployment_config=dict(
autoscaling_config=dict(
min_replicas=1,
max_replicas=2,
)
),
accelerator_type="A10G",
)
# Build and deploy the model
app = build_openai_app({"llm_configs": [llm_config]})
serve.run(app, blocking=True)
将请求发送到 Multi-LoRA 适配器#
要查询基础模型,请像往常一样调用您的服务。
要在推理时使用特定的 LoRA 适配器,请在请求中使用以下格式包含适配器名称
<base_model_id>:<adapter_name>
其中
<base_model_id>是您在 Ray Serve LLM 配置中定义的model_id<adapter_name>是您云存储中适配器的文件夹名称
示例查询#
查询基础模型和不同的 LoRA 适配器
from openai import OpenAI
client = OpenAI(base_url="https://:8000/v1", api_key="fake-key")
# Base model request (no adapter)
response = client.chat.completions.create(
model="qwen-0.5b", # No adapter
messages=[{"role": "user", "content": "Hello!"}],
)
# Adapter 1
response = client.chat.completions.create(
model="qwen-0.5b:adapter_name_1", # Follow naming convention in your cloud storage
messages=[{"role": "user", "content": "Hello!"}],
stream=True,
)
for chunk in response:
if chunk.choices[0].delta.content is not None:
print(chunk.choices[0].delta.content, end="", flush=True)
# Adapter 2
response = client.chat.completions.create(
model="qwen-0.5b:adapter_name_2",
messages=[{"role": "user", "content": "Hello!"}],
)