TT Lab
博客

한국어 English 日本語 中文

开始
博客

博客

亲自测算 LoRA 适配器服务:吞吐量成本、适配器槽位与运行时加载

状态:草稿(2026-10-07),实测文章。 适配器是用作性能测试的 随机权重,因此输出质量没有意义,仅测量了速度和资源行为。计算出的内容标记为“计算”,未测出的内容标记为“未实测”。 编写规则:以实测数据为基础,未测出的内容标记为“未实测”。

目录

1. 为什么要服务 LoRA

如果为每个用途微调模型,就需要将整个模型加载到内存中。LoRA 的方式是保持基底权重 W 不变,训练两个低秩矩阵(B, A)将其转换为 W + (α/r)·B·A ,因此可以在 单个基底模型上附加多个小适配器 ,并在每个请求中使用不同的适配器。这就是为什么我们要尝试在单张 GPU 上为不同客户和业务提供模型服务。vLLM 文档说明,适配器可以以较低的开销按请求单位进行服务。本文将测试“较低”在此环境中究竟是百分之多少。

2. 环境与方法

项目 值
GPU 单张 8GB 级笔记本 GPU,无其他任务
服务器 vLLM 0.31.0, Qwen3-1.7B(bf16), --max-model-len 4096, --max-num-seqs 64, --max-lora-rank 16
适配器 使用 PEFT 创建的 3 个 LoRA (a, b, c)。秩为 8,目标是注意力机制的 q、k、v、o 投影, lora_B 使用具有不同随机种子(标准差 0.02)的随机值初始化
适配器大小 有 3,211,264 个可训练参数,占基底模型 1,720,574,976 个参数的 0.19%(测量值)。如果是 bf16 则约为 6.4MB(计算值)
请求 输入 Write a long story about a robot.,输出 128 个 Token,温度为 0, ignore_eos,每个请求通过服务器的模型名称选择适配器
重复 一次性发送相同的请求批次,并计算总吞吐量(输出 Token 数 ÷ 耗时)

请注意并发请求数量。 本文的表格记录的是“一次性发送的请求数”(3 个、18 个、48 个)。由于测试工具的参数名称,最初称其为“并发 1, 16”,但在确认实际发送了 3 倍的请求后进行了纠正。

由于适配器是随机的,输出没有意义。由于适配器矩阵的大小和计算量与是否训练无关, 我们认为速度和内存行为与训练后的适配器相同,但并未在训练后的适配器上进行验证(未实测)。

3. 吞吐量的成本

从基础服务器(关闭 LoRA)和开启 LoRA 的服务器发送了相同的请求。

一次性发送的请求数 服务器 请求使用的模型 总吞吐量 相对基准 ITL 中位数
3 关闭 LoRA 基底 199 tok/s 基准 15ms
3 开启 LoRA 基底(无适配器) 200 tok/s +0.5% 15ms
3 开启 LoRA 适配器 a 182 tok/s −8.5% 16ms
48 关闭 LoRA 基底 2,667 tok/s 基准 17ms
48 开启 LoRA 基底(无适配器) 2,664 tok/s −0.1% 17ms
48 开启 LoRA 适配器 a 2,190 tok/s −17.9% 19ms
48 开启 LoRA 交替使用 a 和 b 2,323 tok/s −12.9% 20ms
48 开启 LoRA 交替使用 a、b 和无适配器 2,346 tok/s −12.0% 20ms

重复测试(每次 5 次,同一服务器)。 我们将 48 个请求(并发 16 的 3 倍)按无适配器、适配器 a、交替使用适配器 a 和 b 这三种条件打乱顺序,各发送了 5 次(--max-loras 2).

条件 吞吐量 (tok/s),5次 中位数 相比基准
无适配器 2,647, 2,658, 2,669, 2,663, 2,667 2,663 基准
适配器 a 2,183, 2,398, 2,390, 2,391, 2,390 2,390 -10.3%
交替使用适配器 a 和 b 2,329, 2,330, 2,332, 2,329, 2,332 2,330 -12.5%

4. 适配器槽位:当适配器数量超过 --max-loras 时,

--max-loras 是 单个批次中可以容纳的不同 LoRA 的数量(默认值为 1)。最初,我将其记为“可以同时加载到 GPU 上的适配器数量”,但当我直接阅读本文所使用的 vLLM 0.31.0 镜像的源码(vllm/config/lora.py)时,发现其解释是“Max number of LoRAs in a single batch”,而放置在 CPU 端的适配器数量是单独的 --max-cpu-loras(默认值与 max_loras 相同)。我们用 3 个适配器同时发送了 18 个请求(每个设置重复 2 次。虽然两次的值大多相同,但 2 个槽位的适配器 a 和 b 分别为 886 和 984,有所不同)。

服务器设置 无适配器 适配器 a、b 适配器 a、b、c
--max-loras 2 1,120 tok/s 886~984 tok/s 529 tok/s
--max-loras 4 1,131 tok/s 986~987 tok/s 950 tok/s

4-1. 如果在 SGLang 中进行相同的测试

我们使用相同的模型和 3 个相同的随机适配器(rank 16,占参数的 0.19%)对 SGLang 0.5.21 的 LoRA(--enable-lora --max-loras-per-batch N)进行了测试。

测试 SGLang vLLM(上述第 3、4 节)
并发 16(48 个请求),无适配器 2,544 tok/s(3 次服务器测试的中位数,2,533~2,552) 2,664(开启 LoRA 服务器的无适配器请求)
相同负载,适配器 a 2,515 tok/s(-1.1%,3 次服务器测试的中位数,2,509~2,518) 2,390 tok/s(-10.3%,5 次测试的中位数)
18 个请求,混合 2 个适配器,槽位 2 1,045 tok/s(无适配器 1,027) 886~984 tok/s(无适配器 1,120)
18 个请求,混合 3 个适配器,槽位 2 558 tok/s 529 tok/s
相同测试,槽位 4 1,034 tok/s(3 次服务器测试的中位数,1,030~1,038,首次测试 1,045) 950 tok/s

5. 运行时加载适配器所需的时间

VLLM_ALLOW_RUNTIME_LORA_UPDATING=True 启动服务器后,通过 /v1/load_lora_adapter 添加了适配器 c。

项目 结果
加载请求的响应 LoRA adapter 'c' added successfully,完整调用耗时 0.18 秒(包含远程命令执行开销)
加载后的首批请求 3 个请求 182 tok/s,与适配器 a 速度相同

6. 生产环境中的注意事项

  1. 预先测量使用适配器的请求的吞吐量代价。 在此环境中为 8~18%,具体取决于模型和并发度。
  2. --max-loras 将 与同时出现的适配器数量相匹配。如果槽位不足,性能会下降到约一半水平。
  3. 适配器部署虽然轻量,但不受控制地加载存在风险。 应通过流水线进行控制,并且只加载经过验证的适配器。
  4. 常驻 LoRA 没有额外代价。 对不使用适配器的请求没有影响。
  5. 必须针对训练过的适配器和更大的模型重新测量。 本文的数值是从小模型(1.7B)、一个 4B-FP8 数据点以及随机适配器中得出的。

7. 面试可能出现的问题

外部依据:通过论文和官方资料确认的内容

由于外部数值的模型、GPU 和适配器配置有所不同,因此不进行直接对比,仅判定方向和数量级是否一致。

主题 资料与确认位置 确认的内容与条件 与本文的关系
LoRA 的大小 Hu 等人, 「LoRA: Low-Rank Adaptation of Large Language Models」, arXiv 2106.09685 (ICLR 2022), 摘要与第 4.2 节 在 GPT-3 175B 中,训练参数最多减少 10,000 倍,检查点从 350GB 缩减至 35MB(秩为 4,仅应用于查询和值投影)。论文在局限性中指出,推理延迟没有增加的说法 W0 + BA 仅适用于合并后的单个适配器,在合并状态下混合不同的批次适配器是很困难的 支持。 我们的适配器占基础模型的 0.19%(3,211,264 个,根据模型配置计算得出一致)。第 3 节中 8.5~17.9% 的降幅是不进行合并、在每个请求中进行选择的方式所带来的代价
多适配器服务的吞吐量 Chen 等人, Punica, MLSys 2024, arXiv 2310.18547, 第 7 节图 11。Sheng 等人, S-LoRA, MLSys 2024, arXiv 2311.03285, 第 7.2 节表 3 Punica: 单张 A100 80GB,Llama-2 7B·13B,秩 16。仅使用相同适配器时,比仅主干网的 vLLM 低约 8.4% (7B) 和 12.2% (13B)(根据论文数值计算),每个 Token 增加约 2ms 延迟。S-LoRA: 将适配器保存在主机内存中,仅将运行中请求的适配器拉取到 GPU,即使适配器从 5 个增加到 100 个也能维持吞吐量,仅有微小下降 有限支持。 使用适配器的请求吞吐量下降且数量级相同。没有与「超出槽位时减半」相对应的外部数值,S-LoRA 解释称活跃适配器数量决定了代价,这暗示该现象可能专属于 vLLM 的 max_loras 配置
--max-loras 含义 vLLM 0.31.0 源码 config/lora.py, v1/core/sched/scheduler.py(直接从本文使用的图片中读取) 单批次中不同的 LoRA 数量(默认 1)。达到限制时,会跳过其他适配器的请求。 max_cpu_loras 是独立的(默认与 max_loras相同) 修正先前的表述。 上文第 4 节
开销与运行时加载 vLLM 文档 「LoRA Adapters」(标记为 2026-09-28) 记载称以较低开销按请求提供适配器服务,但没有给出定量数值。 VLLM_ALLOW_RUNTIME_LORA_UPDATING 警告称除非在隔离的可信环境中,否则不要在生产环境中使用,且未写明具体原因 有限支持。 「较低开销」在此环境中为 8.5~17.9%,并不算小

未确认的内容

参考资料

确认的版本与日期

截至 2026-10-07。vLLM 0.31.0, PEFT 0.21.2, accelerate 1.15.0, Qwen3-1.7B(bf16)。

登录后即可点赞

评论

还没有评论。

登录后即可发表评论