Chapter 06

Speculative Decoding:用小模型押大模型

大模型一步只出一个 token,GPU 浪费;让小模型先猜 4 个,大模型一次验证,对了就白赚 3 个——延迟减半,精度不变。这就是投机解码。

直觉先行:为什么 decode 慢

大模型 decode 每一步要跑完整个 forward pass,70B 模型一次 forward 大概 20ms——却只产出 1 个 token。瓶颈不是计算,是从 HBM 读权重的带宽:一次读 140GB,只用来算 1 个 token,极度浪费

观察:如果这一步 forward 能一次性验证 4 个 token,"每 token 成本" 从 20ms 降到 5ms。关键是从哪儿来这 4 个候选 token

投机解码工作流

Step 1 [Draft]   小模型(快)生成 4 个 token:  t̂1 t̂2 t̂3 t̂4
Step 2 [Verify]  大模型 (贵但一次 forward)     t1  t2  t3  t4 (并行 4 个位置)
Step 3 [Accept]  比较 p_draft 和 p_target,拒绝采样裁出最长前缀
                 ──────
                 比如大小模型前 3 个一致,第 4 个不一致
                 → 接受 t1 t2 t3,丢弃 t̂4
                 → 用大模型自己算的 t4 继续

本轮产出 4 个正确 token,只花了 1 次大模型 forward + 4 次小模型 forward
数学保证
使用推测采样(speculative sampling)——在 draft 模型分布和 target 模型分布之间做拒绝采样,数学上保证最终输出分布与直接从 target 采样完全相同。不是"近似",精度零损失

三种 Draft 方案

1. Draft Model(独立小模型)

找个同 tokenizer 的小模型(Llama-3-8B 配 Llama-3.2-1B,Qwen2-72B 配 Qwen2-0.5B),它来 draft,大的来 verify:

vllm serve meta-llama/Llama-3-70B-Instruct \
  --speculative-model meta-llama/Llama-3.2-1B-Instruct \
  --num-speculative-tokens 5 \
  --use-v2-block-manager

典型加速 1.5-2.5×。draft 模型越接近 target 分布,接受率越高,加速越明显。

2. Medusa(多个输出头)

不单独跑 draft 模型,在 target 模型顶部加 N 个 LM head,每个 head 预测未来第 1、2、3… 个 token。vLLM 直接加载预训好的 Medusa head 即可。

vllm serve meta-llama/Llama-3-70B-Instruct \
  --speculative-model FasterDecoding/Medusa-Llama-3-70B \
  --speculative-draft-tensor-parallel-size 1 \
  --num-speculative-tokens 4

不用额外 draft 模型,显存占用小;但需要专门训练 Medusa head。

3. N-gram(零成本)

最朴素:从已生成的序列里抓最近出现过的 N-gram 模式,直接当 draft。适合代码、检索增强(context 里就有答案)、重复文本。

vllm serve meta-llama/Llama-3-70B-Instruct \
  --speculative-model [ngram] \
  --num-speculative-tokens 5 \
  --ngram-prompt-lookup-max 4
N-gram 神奇在哪
不用额外模型、不用 GPU 算力,纯 CPU 字符串匹配。代码补全场景接受率能到 70%+,因为很多 token 就是在复制 context。RAG 场景也很受益——答案常常出现在检索段落里。

三种方案对比

方案draft 成本接受率典型加速适合场景
Draft Model小模型 forward60-80%1.5-2.5×通用对话
Medusa几个 LM head50-70%1.8-2.3×通用,显存紧张
N-gram~030-80%(分场景)1.3-3.5×代码 / RAG / 摘要

num-speculative-tokens 怎么选

投多少个候选(k)直接影响收益:

期望加速 ≈ (1 + α + α² + ... + α^k) / (1 + k × c)

α = 接受率,c = draft 成本 / target 成本

例子:α = 0.7, c = 0.05 (1B draft for 70B target)
  k=1  加速 1.62
  k=3  加速 2.07
  k=5  加速 2.18  ← 甜点
  k=8  加速 2.13  ← 开始下降
  k=12 加速 1.96

经验值:Draft Model 取 k=5,Medusa 取 k=4,N-gram 取 k=5-10。太大没收益还增加验证成本。

什么时候投机解码不划算

监控投机解码的指标

vLLM 的 Prometheus 指标:

指标含义
vllm:spec_decode_draft_acceptance_rate草稿接受率,<50% 要调 draft 模型
vllm:spec_decode_system_efficiency系统效率(vs 普通解码的 speedup)
vllm:spec_decode_num_accepted_tokens_total累计接受 token 数
vllm:spec_decode_num_emitted_tokens_total累计输出 token 数

实战 benchmark:Llama-3-70B

1×A100-80G(AWQ-INT4),batch=1 的延迟:

配置TPOTTTFT生成 200 token 总耗时
无投机22ms180ms4.6s
Draft 1B, k=510ms180ms2.2s(2.1×)
Medusa, k=411ms180ms2.4s(1.9×)
N-gram (代码补全)7ms180ms1.6s(2.9×)

和 batching 的交互

投机解码在小 batch 低延迟场景收益最大(memory-bound),大 batch 高吞吐场景收益变小甚至反向。生产建议:

  1. 在线聊天服务(延迟敏感、batch 通常 < 16):开投机,用 Draft Model 或 Medusa
  2. 批量离线处理(吞吐敏感、batch 大):关投机,让 Continuous Batching 充分打满 GPU
  3. 代码补全 / RAG:开 N-gram,零成本白赚

本章小结