vLLM系统拆解-09-高级加速:Speculative Decoding、CUDA Graph与量化

前几篇把 vLLM 的主干讲清楚了:请求进入引擎 → scheduler 分配 token 预算 → worker 在 GPU 上做 forward → KV Cache 分页管理 → prefix caching 复用跨请求前缀。

这篇进入另一个层次:在主干系统已经做得比较好的基础上,还能从哪些方向继续榨性能?

vLLM 当前比较重要的高阶加速可以归为三类:

  • 算法级:Speculative Decoding(减少 decode 串行等待)
  • 执行级:CUDA Graph(减少重复执行的固定开销)
  • 数值级:量化(降低显存占用与数据移动成本)

这三类加速有一个共同特点:每一种都只对特定瓶颈有效,开错场景收益有限,甚至有副作用。 把它们当成无脑加速开关是常见误区。


三类加速总览

先建立整体认知,再展开每一类。

机制 本质优化对象 常见收益 常见代价
Speculative Decoding decode 串行生成的等待成本 降低 ITL,改善低 QPS 场景响应流畅度 额外 draft 计算、调度更复杂、高并发下收益不稳
CUDA Graph 重复 launch 与框架调度的固定开销 降低每轮执行开销,提升 decode 稳定性 需要额外 capture 内存,对动态 batch 不友好
量化 显存占用、数据移动与带宽压力 降低显存占用,可能提升吞吐 精度风险、算子兼容性、硬件收益差异大

这三者不是 vLLM 的地基,而是在「调度 + 内存 + 执行链已经对齐」之后,继续拉高性能上限的手段。


Speculative Decoding:减的不是单次 forward,是串行等待

为什么 decode 天然是串行的

Autoregressive 生成的根本约束是:生成第 t+1 个 token,必须等第 t 个 token 已经确定。 这意味着即使 GPU 算力很强,decode 阶段也只能一步一步串行走。

单次 forward 跑得再快,每一步之间的等待成本仍然存在。这是 speculative decoding 要解决的问题——注意,它不是让单次 forward 更快,而是减少必须严格串行等待的轮数

猜测-验证的基本框架

1
2
3
4
5
6
7
8
9
10
┌─────────────────────────────────────────────────┐
│ 一轮 speculative decoding │
│ │
│ Drafter(便宜)→ token1, token2, token3, token4 │
│ ↓ │
│ Target model(一次并行验证) │
│ ✓ ✓ ✗ │
│ ↓ │
│ 接受 token1, token2,拒绝 token3 及之后 │
└─────────────────────────────────────────────────┘

核心逻辑:先用一个更便宜的 drafter/proposer 预测接下来几个 token,再让 target model 并行验证。如果 drafter 猜得准,target model 一轮就能确认多个 token,平均串行等待时间下降,用户感受到的输出速度提高。

这套机制是正确的(被拒绝的 token 不会改变分布),但有成本:drafter 本身要算,verification 逻辑更复杂,batch 结构可能更不规则,scheduler 处理路径也更复杂。

适用场景有明确边界

Speculative decoding 更适合:

  • QPS 不高、memory-bound decode 是主要瓶颈的场景
  • 用户对 ITL(inter-token latency)敏感、更在意对话流畅度的交互式应用

高并发吞吐压榨场景下,收益不一定稳定。 这时系统更怕额外计算和复杂调度,而不是怕单个请求的 token 间等待。用一句话概括:speculative decoding 是延迟优化工具,不是吞吐优化工具。

vLLM 为什么支持多种 speculation 方法

vLLM 没有把 speculative decoding 做成单一机制,而是支持 draft model、EAGLE、MTP、PARD、MLP speculator、n-gram、suffix decoding 等多种方法。

方法类型 思路 优点 局限
Draft model 额外小模型先草拟候选 token 通用,适合多数场景 需维护额外模型,drafter 精度和延迟都很关键
MTP(Multi-Token Prediction) 目标模型原生支持一次预测多个未来 token 若模型原生支持则路径更自然,协调成本低 依赖模型架构,不通用
n-gram / suffix 利用上下文重复模式或简单启发式猜测 轻量,易启用,在代码补全等重复性场景有价值 收益不如 model-based 稳定,上限有限

这背后的设计判断很清楚:不同模型家族、不同硬件环境、不同业务目标,适合的方案并不一样。vLLM 给出的是一套统一的承载框架,而不是把某种具体方案写死。

对主干系统的影响

Speculative decoding 不只是「多了个 drafter」,它改变了整个调度-执行链的语义:

  • scheduler 层:需要考虑请求是否走 speculation 路径、当前 speculation 深度、accept/reject 后下一轮预算如何分配
  • worker 层:需要执行 draft path、verify path、处理 accept/reject 逻辑、维护 speculative metadata
  • 性能分析层:不能只看原始吞吐,还要看 acceptance ratio、drafter 额外成本是否合算、高 batch 下是否退化

CUDA Graph:固定开销问题,不是计算问题

Decode 阶段的固定开销困境

Decode 每步工作量不大,但如果每步都要经历:Python 层发起调用 → 构图/调度 → 发起一串 GPU kernel launch,那么固定管理成本在整个执行时间里的占比会相当高。

batch 较小、模型较小、decode 路径重复度高的场景尤其明显。CUDA Graph 的出发点就是:既然很多 decode batch 的执行结构高度相似,为什么不能把这套执行图录下来,后面直接重放?

这是执行路径的优化,不是数学计算本身的优化。Replay 后减少的是 CPU 参与度和 launch 开销,GPU 跑的还是同样的计算。

为什么不能对所有 batch 都用 CUDA Graph

关键约束:CUDA Graph 要求执行形状足够稳定。 但 LLM serving 的核心特点恰好是高度动态:

  • batch size 在变
  • 序列长度在变
  • prefill/decode/mixed batch 形态在变
  • LoRA、多模态、attention backend 条件在变

这就是 vLLM CUDA Graph 设计复杂性的来源——不是 API 难,而是「大多数时候 batch 不足够稳定」。

Full 与 Piecewise 两种模式

vLLM 不是简单二选一,而是用分层退化策略:

模式 适合场景 优点 代价
Full CUDA Graph 结构高度稳定的均匀 decode batch 固定开销压得最狠,性能上限高 capture 条件苛刻,额外内存更多
Piecewise CUDA Graph 更复杂的 batch,只对可稳定的子段做 capture 更灵活,对动态 batch 适配度更高 理论极限性能通常低于 full graph
Eager(不走 graph) 形态变化太大无法 capture 时兜底 无额外约束 每步都有 launch 开销

实际策略:能 full 就尽量 full;不适合 full 时退到 piecewise;再不行就 eager。

在 V1 里,CUDA Graph 是运行时模式,不是手动开关

这一点很重要。在 vLLM V1 中,CUDA Graph 不是用户勾选的 feature,而是由 dispatcher 根据当前 batch 条件做模式选择:当前 batch 是否规整、attention backend 是否兼容、是否是 pure decode / mixed batch、当前 compilation level 是什么。

这个设计说明 vLLM 已经把 CUDA Graph 放进了主运行时体系,而不是外部包装器。理解这一点,就超过了「知道如何开启 CUDA Graph」这个层次。

CUDA Graph 的代价同样要正视:capture 本身占额外内存,启动阶段需要编译和准备多个 batch size 变体,batch 越动态则 graph 命中率越低,收益越小。用一句话总结:用更多前期准备与额外内存,换取运行期更低的固定开销。


量化:不是为了「装得下」,而是为了「跑得动」

四类价值

量化不只是「模型太大装不下所以压缩一下」。更完整的理解是:量化同时影响容量、带宽、计算路径、吞吐和部署成本。

具体来说,在推理里量化至少有四类价值:

  1. 让更大的模型放进显存
  2. 减少权重读取的数据量(直接降低带宽压力)
  3. 在合适硬件上提高吞吐(使用低比特专用 kernel)
  4. 降低部署成本

LLM 的 decode 阶段本来就容易是 memory-bound 的。如果把权重从 FP16/BF16 压到 INT8/FP8/INT4,等于从「数据移动成本」这个根上减负,直接影响 tokens/s。

权重量化 vs KV Cache 量化:必须分开理解

这是面试里很容易被追问的点,两类量化解决的是完全不同的问题:

权重量化 KV Cache 量化
优化目标 减小模型参数占用与读取带宽 减小历史上下文缓存的显存占用
主要受益阶段 prefill 和 decode 都有帮助 decode 更关键,长上下文、高并发更关键
核心机制 每次 forward 访问权重的数据量减少 KV Cache 体积随序列增长和并发增长的累积速度降低

两者最终都会反馈到调度层:可用 KV Cache 空间变大 → preemption 频率降低 → batch 能做更大 → 整体吞吐改善。量化虽然发生在数值表示层,但收益会传导到整个 serving 调度层。

vLLM 支持大量量化格式的原因

AWQ、GPTQ、bitsandbytes、GGUF、INT4 W4A16、INT8 W8A8、FP8 W8A8、KV cache 量化、TorchAO、Model Optimizer……量化方案很多,原因是量化从来不是「一招打天下」

  • 某些方法更适合离线权重量化(部署前转换)
  • 某些方法更适合特定 GPU 架构(依赖专用 kernel)
  • 某些方法重点在保持精度,某些在极致压缩
  • 某些方法需要模型架构层的配合

所以 vLLM 的正确定位不是「某种量化工具」,而是「可接入多量化实现的推理平台」。

量化的代价也需要正视:精度损失风险(信息压缩必然损耗)、硬件专用性(不是所有平台都能把低比特收益吃满)、工程兼容性(模型结构、attention/MoE/LoRA 路径是否兼容对应 kernel)。不是 bit 数越低越好,正确思路是在可接受精度损失的前提下,找到最适合当前硬件和业务目标的方案。


三类加速与主干系统的关联

这一节值得单独拿出来。学完三类加速之后,最容易犯的错误是把它们当成孤立的 feature 去记忆。正确的方式是把它们嵌回 vLLM 的主干系统。

flowchart TD
    subgraph 主干系统
        A[Scheduler\n token 预算分配] --> B[Worker\n GPU forward]
        C[KV Cache Manager\n 分页显存] --> B
    end

    subgraph 高级加速
        D[Speculative Decoding] -- 改变调度语义\n speculation深度/accept/reject预算 --> A
        E[CUDA Graph] -- 改变 worker 执行模式\nfull/piecewise/eager dispatch --> B
        F[量化] -- 改变显存分配\n权重更小→KV Cache空间更大 --> C
    end

    D -- 改变 worker 执行结构\ndraft path + verify path --> B
    F -- 影响 preemption 频率\n和可用 batch 预算 --> A

三类加速之间也会互相影响:

  • speculative decoding 会改变 batch 形态和执行路径,可能影响 CUDA Graph 的可捕获性
  • 量化影响 memory budget,从而影响 batch size、KV Cache 容量和 preemption 频率
  • CUDA Graph 本身需要额外内存,也会和量化、KV Cache 预算形成耦合

这就是为什么 vLLM 要把这些优化放进统一运行时框架,而不是做成简单开关:现实 serving 环境的 batch 高度动态、硬件条件不同、模型家族不同、业务目标不同,每种优化都需要根据当前条件决定是否启用、以哪种模式启用。


几个核心结论

Speculative decoding 优化的是 decode 的串行等待,不是单次 forward 的底层效率。它更偏延迟优化,尤其适合低到中等 QPS、memory-bound 场景;高并发下收益不稳。

CUDA Graph 优化的是重复执行中的固定开销,不改变数学计算本身。LLM serving batch 高度动态,所以 vLLM 必须有 full/piecewise/eager 的分层退化设计,而不是靠单一 graph 模式走到底。

量化优化的是显存占用、数据移动和带宽压力,不是只为了「模型装得下」。权重量化和 KV Cache 量化解决的是两类不同问题,最终收益都会向上传导到调度层。

三类加速有一个共同的适用边界:它们都只对特定瓶颈有效。 判断系统当前真正的瓶颈是什么,比选择哪种加速机制更重要。



系列导航