深色模式
投机解码 Speculative Decoding
摘要:投机解码用一个小的 draft 模型先"猜"若干 token,再用大模型一次性验证,把多次内存受限的 decode 步合并成更少的验证步,从而加速且输出分布与单独用大模型严格一致(无损)。加速倍数完全取决于接受率。本文讲原理、变体与 vLLM 配置。适用版本:vLLM 0.8.x–0.9.x(含 n-gram/EAGLE 支持),具体开关以官方文档为准。
适用版本与前提
- 引擎:vLLM(speculative_config)、部分引擎支持 EAGLE/Medusa
- 理解:自回归 decode 是内存带宽瓶颈(见
serving-overview.md) - 注意:投机解码增加显存(要同时驻留 draft + target 的权重与 KV)
核心概念:为什么能加速且无损
Decode 每生成一个 token 都要把全部权重从 HBM 读入计算单元——算力大量闲置,瓶颈在显存带宽。投机解码的循环:
- Draft:小模型快速提出 K 个候选 token(常见 3–8)。
- Verify:大模型一次前向并行验证这 K 个 token(成本约等于一次普通前向)。
- Accept/Reject:目标模型接受最长的前缀匹配,在第一个分歧处自己生成一个 token 续上;被拒的后续丢弃,循环重来。
为什么无损
目标模型对每条 draft token 按自身概率分布做拒绝采样(接受概率 min(1, p_target/q_draft),被拒则从修正分布重采样)。数学上可证明:最终输出的 token 分布与"只用目标模型"完全一致(仅受浮点精度影响)。所以它是加速而非近似。理论来源:Leviathan et al. 2023、Chen et al. 2023(DeepMind)对 speculative sampling 的形式化。
加速来自哪里:接受率
总加速 ≈ "每步平均净推进 token 数 / 一次验证步成本"。这完全取决于接受率(acceptance rate)——目标模型多大程度同意 draft。
- 接受率低(~20%):每步只推进 1–2 token,还要白付 draft 算力 → 可能比不开还慢。
- 接受率高(~80–90%):每步推进多个 token → 2–3× 常见,特定场景更高。
- draft 模型要与 target 行为对齐:随便挑个小模型当 draft,若预测分布差得远,反而拖慢。
别盲信"最高 6.5×"
EAGLE-3 论文 benchmark 称最高 ~6.5×,Red Hat 2025-07 在 A100 上实测 Llama-3.1-8B 最多 ~1.8× 延迟下降、Llama-3.3-70B ~1.6×。这些是特定模型对 + 特定硬件的数字。你自己的模型对必须满足"小而对齐",否则可能负优化。务必在自己模型上测接受率与端到端延迟。
变体对比
| 变体 | 机制 | 是否需训练 | 额外显存 | 适用 |
|---|---|---|---|---|
| n-gram / prompt lookup | 从上下文里匹配已出现的 n-gram 作候选 | 否 | 极低 | RAG/摘要/代码编辑(输出抄输入) |
| Draft 模型 | 独立小模型(如同族小号) | 否(需对齐模型) | 高(整第二个模型) | 有现成对齐小模型 |
| EAGLE / EAGLE-3 | 在目标模型隐状态上挂轻量 draft head | 是(训练 head) | 低 | 有训练资源、追求高接受率 |
| Medusa | 目标模型挂多个并行解码 head | 是 | 低 | 自训模型 |
| MTP(多 token 预测) | 目标模型自带 MTP head(如 DeepSeek-V3) | 训练时已有 | 低 | DeepSeek-V3 等原生支持,无需额外模型 |
零成本起步:先试 n-gram
如果你的负载是 RAG/摘要/代码编辑(输出常复制输入),用 n-gram / prompt-lookup 投机,不需要额外模型、几乎零显存、即开即用,往往就有可见收益。再考虑 EAGLE/MTP。
生产配置(vLLM 示例)
bash
# 方式一:n-gram 投机(无需额外模型,最易上手)
docker run --gpus all --ipc=host -p 8000:8000 \
-v /mnt/models:/models \
vllm/vllm-openai:latest \
--model /models/Qwen2.5-7B-Instruct \
--speculative-config '{"method":"ngram","num_speculative_tokens":5}'
# [版本相关] speculative_config 的 method 名/字段随版本演进,以官方文档为准1
2
3
4
5
6
7
2
3
4
5
6
7
python
# 方式二:独立 draft 模型(需 draft 与 target 同词表、行为对齐)
from vllm import LLM, SamplingParams
llm = LLM(
model="/models/Qwen2.5-7B-Instruct",
speculative_config={
"model": "/models/Qwen2.5-0.5B-Instruct", # 小一档的同族模型作 draft
"num_speculative_tokens": 5,
},
tensor_parallel_size=1,
)
# [版本相关] LLM 的 speculative_config 参数以官方 API 参考为准1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
bash
# DeepSeek-V3 等原生 MTP:可直接复用模型自带 MTP head(无需额外 draft 模型)
# 具体开关名随版本,请以官方文档核对 --speculative-config 的 mtp 用法1
2
2
验证
- 看日志/指标里的 acceptance rate / draft 接受长度:若平均接受 <2 token,说明 draft 没用,关掉。
- 测端到端延迟(TPOT/P99),而非只看"理论加速"。若开启后延迟没降甚至升,回退。
- 确认输出分布未变:对同一 prompt 固定 seed 对比开/关投机的解码结果(应一致,除采样随机性)。
回滚与清理
显存与负优化
投机解码要同时驻留 draft + target 的权重与 KV,显存上涨。小模型显存不够时可能 OOM。且接受率低会负优化。上线前:①测接受率;②测端到端延迟;③确认显存余量。异常直接去掉 --speculative-config 重启。
故障排查
| 现象 | 原因 | 处理 |
|---|---|---|
| 延迟没降/反升 | 接受率低 | 换更对齐的 draft、降 num_speculative_tokens、或关掉 |
| OOM | draft+target 双模型 | 量化、加卡、或改用 n-gram/MTP |
| 输出异常/分布偏移 | 配置错误 | 核对 speculative_config;确认无损性(理论上应一致) |
| 不支持的 method | 版本不匹配 | 查官方文档该版本支持的 method 列表 |
安全与合规
- 成本失控:投机解码不是免费午餐,双模型显存 + 低接受率会浪费算力。用接受率指标监控,接受率持续低则自动降级。
- 越权:API 鉴权前置。
- 许可:draft 模型同样受权重许可证约束。
成本与性能(示意)
| 场景 | draft 方案 | 加速(估) | 显存 |
|---|---|---|---|
| RAG/摘要 | n-gram | 1.2–2×[未实测] | 几乎不变 |
| 对齐小模型 | draft 模型 | 1.5–3×[未实测] | +一个小模型 |
| 自训 head | EAGLE-3 | 论文峰值 6.5×,实测 1.6–1.8×[外源实测] | +少量 head |
决策顺序
- 先看负载是否"输出抄输入"(RAG/编辑)→ 用 n-gram,零成本;2) 有同族小模型且对齐 → draft 模型;3) 有训练资源追求极致 → EAGLE/MTP。永远先量接受率。