跳到主要内容

性能优化

本章介绍如何通过量化、并行和配置调优来提升 vLLM 的推理性能。

量化技术

量化通过降低模型权重和计算的精度来减少显存占用和加速推理。vLLM 支持多种量化方法,包括 AWQ、GPTQ、FP8、INT8 等。

快速选择指南

场景推荐量化理由
消费级 GPU(24GB 以下)AWQ/GPTQ 4-bit最大化显存节省
专业 GPU(A100/H100)FP8 或 INT8平衡精度和速度
Hopper GPU(H100/H200)FP8原生硬件支持
精度敏感应用INT8精度损失最小

使用示例

from vllm import LLM

# AWQ 量化(4-bit,显存节省约 65%)
llm = LLM(
model="TheBloke/Llama-2-7B-AWQ",
quantization="awq"
)

# FP8 量化(Hopper GPU)
llm = LLM(
model="meta-llama/Llama-2-7b-chat-hf",
quantization="fp8"
)

量化技术的详细原理、配置方法和最佳实践请参考 量化详解 章节。

并行策略

张量并行(Tensor Parallelism)

张量并行将模型权重沿维度分割到多个 GPU:

vllm serve meta-llama/Llama-2-70b-chat-hf \
--tensor-parallel-size 4
from vllm import LLM

llm = LLM(
model="meta-llama/Llama-2-70b-chat-hf",
tensor_parallel_size=4
)

适用场景:

  • 单个 GPU 无法容纳模型
  • 需要最大化吞吐量

流水线并行(Pipeline Parallelism)

流水线并行将模型层分割到不同 GPU:

from vllm import LLM

llm = LLM(
model="meta-llama/Llama-2-70b-chat-hf",
pipeline_parallel_size=4, # 4 个 GPU 流水并行
tensor_parallel_size=2 # 每个流水线阶段内部 2 卡张量并行
)

数据并行(Data Parallelism)

数据并行用于扩展服务能力:

# 启动多个实例
vllm serve meta-llama/Llama-2-7b-chat-hf --port 8000 &
vllm serve meta-llama/Llama-2-7b-chat-hf --port 8001 &

# 使用负载均衡器分发请求

LoRA 适配器支持

LoRA(Low-Rank Adaptation)是一种轻量级的模型微调方法,通过在原模型旁边添加少量可训练参数来实现定制化。vLLM 支持在推理时动态加载和切换多个 LoRA 适配器,极大降低了部署多个定制模型的成本。

为什么使用 LoRA

传统方式部署多个定制模型需要为每个模型加载完整的权重,显存开销巨大。例如,部署 10 个微调版本的 Llama-2-7B,需要约 140GB 显存(每个模型约 14GB)。

使用 LoRA 后,只需加载一个基础模型(14GB)和 10 个小型 LoRA 适配器(每个约 100MB),总显存仅需约 15GB。

离线推理中使用 LoRA

from vllm import LLM, SamplingParams
from vllm.lora.request import LoRARequest
from huggingface_hub import snapshot_download

# 下载 LoRA 适配器
sql_lora_path = snapshot_download(repo_id="yard1/llama-2-7b-sql-lora-test")

# 创建基础模型并启用 LoRA
llm = LLM(
model="meta-llama/Llama-2-7b-hf",
enable_lora=True,
max_lora_rank=64 # 设置 LoRA 的最大秩
)

# 定义采样参数
sampling_params = SamplingParams(
temperature=0,
max_tokens=256
)

# 定义提示词
prompts = [
"Write a SQL query to find all users over 25 years old.",
"Write a SQL query to count orders by status."
]

# 使用 LoRA 适配器生成
outputs = llm.generate(
prompts,
sampling_params,
lora_request=LoRARequest(
"sql_adapter", # 适配器名称
1, # 全局唯一 ID
sql_lora_path # LoRA 适配器路径
)
)

for output in outputs:
print(output.outputs[0].text)

服务端部署 LoRA

启动服务时指定 LoRA 模块:

vllm serve meta-llama/Llama-2-7b-hf \
--enable-lora \
--lora-modules sql-lora=/path/to/sql-lora-adapter \
--max-lora-rank 64

同时加载多个 LoRA 适配器:

vllm serve meta-llama/Llama-2-7b-hf \
--enable-lora \
--lora-modules \
sql-lora=/path/to/sql-lora \
chat-lora=/path/to/chat-lora \
code-lora=/path/to/code-lora \
--max-lora-rank 64

使用 JSON 格式指定基础模型信息:

vllm serve meta-llama/Llama-2-7b-hf \
--enable-lora \
--lora-modules '{"name": "sql-lora", "path": "/path/to/sql-lora", "base_model_name": "meta-llama/Llama-2-7b-hf"}'

客户端调用 LoRA 模型

使用 OpenAI 客户端调用 LoRA 适配器:

from openai import OpenAI

client = OpenAI(
base_url="http://localhost:8000/v1",
api_key="not-needed"
)

# 指定 LoRA 模型名称
response = client.chat.completions.create(
model="sql-lora", # 使用 sql-lora 适配器
messages=[
{"role": "user", "content": "Write a SQL query to find active users."}
]
)
print(response.choices[0].message.content)

使用 curl 调用:

curl http://localhost:8000/v1/completions \
-H "Content-Type: application/json" \
-d '{
"model": "sql-lora",
"prompt": "Write a SQL query to select all products.",
"max_tokens": 100
}'

动态加载 LoRA 适配器

vLLM 支持在运行时动态加载和卸载 LoRA 适配器:

# 启用动态 LoRA 更新
export VLLM_ALLOW_RUNTIME_LORA_UPDATING=True

vllm serve meta-llama/Llama-2-7b-hf --enable-lora

动态加载适配器:

curl -X POST http://localhost:8000/v1/load_lora_adapter \
-H "Content-Type: application/json" \
-d '{
"lora_name": "new-adapter",
"lora_path": "/path/to/new-lora-adapter"
}'

动态卸载适配器:

curl -X POST http://localhost:8000/v1/unload_lora_adapter \
-H "Content-Type: application/json" \
-d '{
"lora_name": "new-adapter"
}'

LoRA 配置参数

参数说明默认值
max_lora_rankLoRA 的最大秩16
max_loras同时加载的最大 LoRA 数量1
max_cpu_lorasCPU 上缓存的 LoRA 数量与 max_loras 相同
lora_extra_vocab_sizeLoRA 额外词汇表大小256
llm = LLM(
model="meta-llama/Llama-2-7b-hf",
enable_lora=True,
max_lora_rank=64, # 设置最大秩
max_loras=4, # 同时加载 4 个 LoRA
max_cpu_loras=8 # CPU 缓存 8 个 LoRA
)

配置 max_lora_rank 的建议

max_lora_rank 参数影响内存分配和性能:

  • 设置为所有 LoRA 适配器中的最大秩值
  • 不要设置过高,会浪费内存并影响性能
  • 如果 LoRA 适配器的秩分别为 [16, 32, 64],应使用 --max-lora-rank 64

关键参数调优

显存利用率

from vllm import LLM

# 默认 0.9,保守值 0.8
llm = LLM(
model="meta-llama/Llama-2-7b-chat-hf",
gpu_memory_utilization=0.85, # 留出更多显存给其他任务
max_model_len=4096
)

最大序列长度

llm = LLM(
model="meta-llama/Llama-2-7b-chat-hf",
max_model_len=8192, # 根据实际需求设置
max_num_seqs=256 # 最大并发数
)

批处理参数

llm = LLM(
model="meta-llama/Llama-2-7b-chat-hf",
max_num_seqs=256, # 最大并发序列数
max_num_batched_tokens=8192, # 单批次最大 token 数
max_model_len=4096
)

性能基准测试

使用 benchmark 脚本

# 安装 benchmark 工具
pip install vllm[benchmark]

# 运行吞吐量测试
python -m vllm benchmark throughput \
--model meta-llama/Llama-2-7b-chat-hf \
--num-prompts 1000 \
--input-len 512 \
--output-len 128

自定义性能测试

import time
from vllm import LLM, SamplingParams

llm = LLM(model="meta-llama/Llama-2-7b-chat-hf")
sampling_params = SamplingParams(temperature=0.7, max_tokens=100)

prompts = ["测试提示词"] * 100

# 预热
llm.generate(prompts[:10], sampling_params)

# 正式测试
start = time.time()
outputs = llm.generate(prompts, sampling_params)
end = time.time()

total_tokens = sum(len(o.outputs[0].token_ids) for o in outputs)
throughput = total_tokens / (end - start)

print(f"总耗时: {end - start:.2f}s")
print(f"总 token 数: {total_tokens}")
print(f"吞吐量: {throughput:.2f} tokens/s")

常见性能问题

延迟过高

检查项

  1. 确认 GPU 利用率
  2. 检查 batch size 是否合适
  3. 启用 Chunked Prefill
llm = LLM(
model="meta-llama/Llama-2-7b-chat-hf",
enable_chunked_prefill=True,
max_num_batched_tokens=2048
)

显存不足(OOM)

解决方案

llm = LLM(
model="meta-llama/Llama-2-7b-chat-hf",
gpu_memory_utilization=0.7, # 降低显存使用
max_model_len=2048, # 限制最大序列长度
quantization="fp8" # 启用量化
)

吞吐量低

优化方向

llm = LLM(
model="meta-llama/Llama-2-7b-chat-hf",
max_num_seqs=512, # 提高并发数
max_num_batched_tokens=16384, # 增加批次大小
enable_chunked_prefill=True
)

小结

性能优化需要根据实际场景选择合适的策略:

  1. 量化:首选 FP8(Hopper)或 AWQ,减少显存占用
  2. 并行:根据模型大小和 GPU 数量选择合适的并行策略
  3. 参数调优:调整 max_model_len 和批处理参数找到最优配置
  4. 测试验证:使用 benchmark 工具验证优化效果