Transformer 解剖:从 Attention 到推理系统
第 17 章 投机解码:用小模型加速大模型
第 17 章 投机解码:用小模型加速大模型
第 14 章我们看到 Decode 阶段是 memory-bound——GPU 算力大量空闲、HBM 带宽是瓶颈。第 16 章用量化把权重压缩,HBM 读取量减半减四倍。但还有一种更聪明的思路——既然 GPU 算力空闲,能不能一次多算几个 token?
听起来像作弊:自回归生成不是必须一个 token 一个 token 来吗?答案是:借助一个聪明的「投机」机制,可以——这就是 投机解码(Speculative Decoding)。
它的核心想法用一个生活化比喻就讲完:你想读一本书,你可以一字一字读(Decode 模式);也可以让一个朋友先快速浏览、把他猜测的内容讲给你听,你只在「不对的地方」打断纠正。如果朋友猜得大多对,你听几句就能掌握一大段——这就是投机解码用小模型「先猜、大模型『后验』」的本质。
读完这章你能:
- 解释投机解码为什么能在 memory-bound 场景下提速;
- 推导它的拒绝采样数学,证明它输出与原模型完全一致;
- 对比 Medusa、EAGLE、Lookahead 等不同 draft 机制的取舍;
- 估算给定模型对的加速倍数;
- 在 vLLM / SGLang 里启用投机解码并 tune 参数。
17.1 一个直觉:Decode 的算力是浪费的
回顾第 14 章。Llama-3 70B 在单卡 H100 上 Decode 一个 token:
- HBM 读取:140 GB / 3.35 TB/s ≈ 42 ms
- 实际算力消耗:极少(一个 token 的 forward 算量很小)
- GPU MFU:5-15%
也就是说每次 Decode 时 GPU 算力 85-95% 闲着——它在等 HBM 把权重搬过来。
如果我们能让 GPU 在等 HBM 的同时多算几个 token,几乎不增加额外延迟——但有效输出翻倍、翻三倍——这就是投机解码的工程动机。
flowchart LR
subgraph "传统 Decode"
T1["t=0 读权重 算 1 个 token"]
T2["t=42ms 读权重 算 1 个 token"]
T3["t=84ms 读权重 算 1 个 token"]
T4["..."]
end
subgraph "投机解码"
D1["小模型快速猜 4 个 token<br/>仅几 ms"]
BIG["大模型 1 次 forward<br/>验证全部 4 个"]
D1 --> BIG
BIG --> ACCEPT["接受 3 个(假设)"]
BIG --> CORRECT["纠正第 4 个"]
end
关键:大模型一次 forward 不论是处理 1 个 token 还是 5 个 token,HBM 读取量几乎一样(权重读一次、KV Cache 读一次),延迟也几乎一样——多算几个 token 几乎免费。
17.2 投机解码的基本流程
完整流程,以 K=4(每轮草稿 4 个 token)为例:
Step 1:Draft(草稿生成)
用一个小模型(draft model)在当前上下文上自回归地生成 K=4 个候选 token:
当前已生成: "The cat sat on"
draft model 接着生成: "the mat with a"
↑ ↑ ↑ ↑
d_1 d_2 d_3 d_4 (4 个 draft token)
draft 模型每生成一个 token 也是 memory-bound 的,但它远小(比如 1-7B)——一个 token 大概 5-10 ms(远快于 70B 大模型的 42 ms)。生成 4 个总共 ~30 ms。
Step 2:Verify(验证)
把这 4 个 draft token 拼接到当前上下文,把整个序列喂进大模型一次 forward。大模型同时输出 5 个位置的 logits:
位置: ... -1 0 1 2 3 4
内容: ... on the mat with a [大模型预测的下一个]
↑ ↑ ↑ ↑ ↑
d_1 d_2 d_3 d_4 prediction_5
第 0、1、2、3 位置是「大模型对 draft 的看法」(如果大模型自己来生成,会怎么选这 4 个位置)。第 4 位置是「在 draft 之外的下一个 token 预测」。
Step 3:Accept or Reject(接受或拒绝)
逐个比对 draft token 和大模型的预测:
- 如果 draft d_i 和大模型在位置 i 的最高概率 token 一致 → 接受
- 如果不一致 → 拒绝,从 d_i 开始之后的 draft 全部丢弃,用大模型在位置 i 的预测代替
例如:
位置: 1 2 3 4
draft: the mat with a
big model: the mat on ? ← 第 3 位置不同
结果: 接受 接受 拒绝 --- ← 接受 the, mat;拒绝 with、a 也丢;用 on 替换
最终: the mat on ← 一轮接受了 3 个 token
Step 4:Continue
下一轮 draft 从「the mat on」之后继续。
如果第 1 步就拒绝(draft d_1 和大模型不同),这一轮浪费了 draft 的算力,但仍然「正确」——大模型预测的 token 是 ground truth,至少接受了 1 个 token。
17.3 「等价于原模型」的拒绝采样
上面流程的关键问题:「接受/拒绝」的标准是什么?只看 argmax 是否一致吗?
如果只看 argmax,那只能模拟「贪心解码」(greedy decoding),不支持温度采样。真正的投机解码要保证输出分布与原大模型逐 token 采样一致——这就需要拒绝采样(rejection sampling)。
设大模型分布是 ,draft 模型分布是 。投机解码的接受规则:
- 从 采样得到 draft token
- 计算接受概率:
- 以概率 接受
- 如果拒绝,从修正分布 采样
Leviathan et al.(Google,2023)和 Chen et al.(DeepMind,2023)独立证明了:这个流程下,每个被接受的 token 完全等价于从 直接采样——也就是说投机解码的输出分布和原大模型逐 token 采样完全一致。这是数学保证,不是近似。
flowchart LR Q["draft 分布 q(x)<br/>从中采样 ~x"] --> COMP["计算 α = min(1, p(x)/q(x))"] P["大模型分布 p(x)"] --> COMP COMP --> R["以 α 概率接受"] R -.->|"接受"| KEEP["保留 ~x"] R -.->|"拒绝"| RESAMP["从 p'(x) 重新采样"] RESAMP --> NEW["新 token"]
这条数学保证是投机解码的「合法性」根基——不是近似、不是 trade-off,而是一种纯粹的工程加速。质量与原模型一字不差。
17.4 接受率:决定加速比的核心变量
每轮草稿 K 个 token,平均能接受 个。接受率 是决定加速比的关键变量。
加速比公式:
其中 是 draft 单步时间相对大模型 verify 时间的比例。
直观理解:
- 每轮投机的工作量 = draft 生成 K 个 + 大模型 verify 一次 ≈ K·c + 1(大模型一次)
- 每轮产出 = 个 token(最少 1 个:拒绝时大模型预测;最多 K+1:全接受时 + 大模型加 1 个)
举个具体数字:
- K=4,draft 是大模型的 10×(c=0.1,每个 draft token 等于大模型的 1/10)
- 平均接受 3 个(β=0.75)
- Speedup = (1+3) / (1+0.4) ≈ 2.86×
如果接受率高、draft 占比小,加速比可以更高:
- K=4, c=0.05, β=0.9: Speedup ≈ 4.1×
- K=8, c=0.03, β=0.9: Speedup ≈ 5.8×
17.5 主流投机解码方法
1. 经典 Speculative Decoding(two-model)
最早的版本(Leviathan 2023, Chen 2023):用一个小模型作为 draft model。
典型选择:
| 大模型 | draft 模型 | 比例 |
|---|---|---|
| Llama-2 70B | Llama-2 7B | 10× |
| Llama-3 70B | Llama-3 8B | 9× |
| GPT-4 | GPT-4-mini | 不公开 |
| Claude Opus | Claude Haiku | 不公开 |
要求:draft 模型必须和大模型用同一个 tokenizer——否则 draft 输出的 token id 大模型理解不了。
工程问题:
- 要部署两份模型,多占显存
- draft 自己也是 memory-bound,每个 token 仍然要全网走一遍
- draft 越小越快但接受率越低(小模型预测得不准)
2. Medusa(Cai et al., 2024)
关键想法:不要部署一个独立 draft 模型;给大模型加几个『预测头』,每个头预测未来某个位置的 token。
具体地,大模型最后一层之后接 N 个独立的 LM head(叫 Medusa heads),第 k 个 head 预测「未来第 k 个位置的 token」:
flowchart TB X[输入 token] --> TR[Transformer Backbone] TR --> H[hidden state] H --> H0[原 LM Head: 下一位置 token] H --> M1[Medusa Head 1: 下下位置 token] H --> M2[Medusa Head 2: 下下下位置 token] H --> M3[Medusa Head 3: 下下下下位置 token]
Medusa 的优势:
- 不需要单独 draft 模型——所有计算在一次大模型 forward 里完成
- Medusa heads 很小(每个就是一个 Linear 层)
- 大模型 forward 一次同时得到 K 个候选 token + 验证它们
Medusa 论文报告 Llama-2 7B 上 2.5-2.8× 加速,几乎无质量损失。
代价:
- 需要训练 Medusa heads(虽然很轻量,但仍是额外训练步骤)
- 候选数 K 受 head 数限制
3. EAGLE(Li et al., 2024)
EAGLE 是 Medusa 的进化版,用一个小的额外网络根据大模型的 hidden state 预测多个未来 token——比 Medusa 更聪明、接受率更高。
关键 insight:Medusa 的多个独立 head 互相不通信、各自只看 hidden state——这限制了准确度。EAGLE 用一个小型 Transformer 接力大模型的 hidden state,自回归地生成多个 draft token——每个 draft 都能看到前面的 draft(更连贯)。
EAGLE-2、EAGLE-3 进一步引入树状候选(tree decoding)——一次生成多个 draft 序列树,让 verify 同时考虑多个分支,选最好的一支。这把接受率推得更高。
EAGLE-3 论文报告在 Llama-3-70B 上达到 4-5× 加速——但要注意这是任务相关的:在 reasoning / 代码生成等「文本预测性强」的任务上确实接近 4-5×,在通用 chat 上接近 2-3×,在高温度采样 / 创意写作场景下可能只剩 1.5-2×。实际部署时一定要在你的具体任务分布上 benchmark 一遍。
4. Lookahead Decoding(Fu et al., 2024)
Lookahead 不需要额外训练任何东西——它用 Jacobi 迭代 + n-gram 词典直接产生 draft:
- 维护一个观察到的 n-gram 词典(训练数据 / 已生成内容里的常见短语)
- 每轮基于当前上下文从词典里查可能的延续
- 用 Jacobi 迭代并行求解多个位置的 token,逐渐收敛
Lookahead 的好处:零训练、零额外参数、可即插即用。在常见任务上能 1.5-2× 加速。代价是接受率不如 EAGLE。
主流方案对照
| 方法 | draft 来源 | 训练需求 | 加速比 | 实现复杂度 |
|---|---|---|---|---|
| 经典两模型 | 单独小模型(如 Llama-2-7B) | 无 | 2-3× | 中 |
| Medusa | 大模型 + 多 LM head | 训 head(轻) | 2-3× | 中 |
| EAGLE | 大模型 + 小 Transformer | 训 EAGLE 网络 | 3-5× | 高 |
| EAGLE-3 | EAGLE + tree decoding | 同上 | 4-5× | 很高 |
| Lookahead | n-gram + Jacobi | 无 | 1.5-2× | 低 |
| ReDrafter | 类 Medusa + RNN | 训 RNN | 2-3× | 中 |
主流推理引擎(vLLM、SGLang、TensorRT-LLM)都内置了一种或多种。
17.6 投机解码的工程取舍
Trade-off 1:K(draft 长度)的选择
K 越大,单轮潜在加速越大,但:
- 每个 draft token 都要算(即使后面被拒绝),算多了浪费
- 大 K 时大概率前几个就拒绝,浪费 draft 算力
实际工程 K=4-8 是甜点。Medusa 默认 K=4-5。EAGLE 通过 tree decoding 让有效 K 增加到 30+ 但实际只验证一支。
Trade-off 2:draft 模型质量
draft 越准接受率越高、加速比越大;但 draft 越大本身越慢,c 上升。
经验值:
- 小模型 5-10× 比大模型小最优(Llama-2 7B 给 70B 做 draft)
- 同系列模型 draft 比跨家族 draft 接受率高得多
Trade-off 3:与 batching 的兼容
投机解码和 continuous batching 有冲突。常规 batching:每个用户每步生成 1 token,batch 中所有用户同步推进。投机解码:每个用户每步生成 1+β·K 个 token,不同用户的实际推进速度不同——同步性破坏。
工程上的处理:
- vLLM / SGLang 把投机解码和 continuous batching 统一在调度器里——每个用户独立维护自己的 draft / verify 状态
- 实现复杂度比无投机时高 30-50%
Trade-off 4:长上下文友好度
投机解码在长上下文下加速比下降——因为 KV Cache 读取占的比例变大,「多算几个 token」节省的比例小了。在 32K+ 上下文下加速比从 3× 降到 2× 是常见现象。
17.7 何时投机解码不划算
不是所有场景投机解码都赢。几个反例:
反例 1:极小模型
7B 以下模型本身已经够快,draft 模型更小不容易找。投机解码的加速比可能 < 1.5×,不如直接量化。
反例 2:大 batch 推理
大 batch(如 batch=128)下大模型已经接近 compute-bound——多算几个 token 不再「免费」。投机解码加速比从 3× 降到 1.2× 甚至更低。
反例 3:特殊 sampling 配置
低温度(temperature=0.1)下大模型分布尖锐,draft 接受率会高(容易猜中);高温度(temperature=1.5)下分布平坦,接受率低。极端 top_k=1(贪心)下投机解码完全等同于「先猜 + 后验」,但任何小偏差都拒绝——接受率反而低。
反例 4:草稿模型质量太差
如果 draft 是从不同家族训的(比如用 Mistral-7B 给 Llama-70B 做 draft),分布差太多接受率会低。最好用同源模型。
17.8 一个工程实例:vLLM 启用投机解码
vLLM 0.6+ 内置 EAGLE / Medusa 支持。最简单的两模型版本:
vllm serve meta-llama/Meta-Llama-3-70B-Instruct \
--speculative-model meta-llama/Meta-Llama-3-8B-Instruct \
--num-speculative-tokens 5 \
--max-model-len 32768
--num-speculative-tokens 5 每轮草稿 5 个 token。
EAGLE 版本:
vllm serve meta-llama/Meta-Llama-3-70B-Instruct \
--speculative-model "yuhuili/EAGLE-LLaMA3-Instruct-70B" \
--speculative-draft-tensor-parallel-size 1 \
--num-speculative-tokens 5
启用后实测加速:在 chat 类任务上 2.5-3.5×,长 reasoning 任务上 3-4×(reasoning 文本更可预测,接受率更高)。
监控指标:
- acceptance_rate:接受率(目标 > 0.7)
- mean_accepted_tokens_per_step:每步平均接受 token 数(目标 > 2.5)
- draft_tps / target_tps:draft 模型和大模型的 token/s 比例
如果 acceptance_rate 低于 0.5,要么换 draft 模型、要么减小 K。
17.9 投机解码的「赌性」
为什么这一章副标题是「为什么是对赌」?
投机解码的本质是个赌局:
- 赌赢:draft 的 K 个 token 都被接受,一轮拿到 K+1 个 token——大幅加速
- 赌输:第一个就拒绝,浪费了 draft 的所有算力——只比常规 Decode 慢一点
- 赌局规则不变:无论赢输,输出质量一字不差(拒绝采样保证)
所以这是「只赢不输的赌局」——赢则大赚,输则小亏,长期 EV 显著正——这是它能稳定提速 2-4× 的根本原因。
flowchart TB GAMBLE["每轮投机 = 一次赌"] GAMBLE --> WIN["赢: K 个 draft 都接受<br/>一轮 K+1 token<br/>大加速"] GAMBLE --> LOSE["输: 第一个就拒绝<br/>仅 1 token 输出<br/>仅慢一点点"] WIN --> EV["质量不变 + 期望加速正<br/>= 必玩"] LOSE --> EV
17.10 投机解码与其他优化的协同
投机解码不和其他推理优化互斥,反而协同:
flowchart TB Q["量化 (INT4)<br/>HBM 读取减 4x"] --> COMBINE K["KV Cache (PagedAttention)<br/>显存利用率 95%"] --> COMBINE F["Flash Attention<br/>HBM 访问减"] --> COMBINE S["Speculative<br/>每步多 token"] --> COMBINE COMBINE["叠加 = 整体 8-15x 加速"]
实际工业部署的最优组合(H100 集群跑 Llama-3-70B):
- INT4 + AWQ:HBM 读取从 140 GB 降到 35 GB
- PagedAttention:KV Cache 利用率 95%
- Flash Attention 3:attention 部分进一步加速
- EAGLE 投机解码:每步 3 个 token
所有这些叠加,70B 模型在单卡 H100 上能跑到 ~150 tokens/s(FP16 单 token 解码本来需要 30+ ms)。
17.11 投机解码的局限与未来
局限 1:天花板是大模型本身
投机解码不能让大模型的「实际输出能力」超过它本身——它只是把同样的输出更快产出。如果大模型本身已经很快(小模型、多卡、量化),加速空间有限。
局限 2:训练投资
EAGLE / Medusa 等方法需要训练 draft 网络,需要计算资源和数据。这是一次性投入但门槛不低。
局限 3:与 reasoning 模型的兼容
o1 / Claude 思考链类模型生成超长 reasoning trace(几千到几万 token),投机解码理论上加速更大(reasoning 文本更可预测)。但思考链生成时模型在「探索-修正」模式,分布波动大,实际接受率可能下降。这是 2025 年仍在研究的方向。
未来方向:
- Tree-based speculation(EAGLE-2/3):一次产生多个分支,选最优一支
- Self-speculative:让大模型自己作为自己的 draft——用浅层做 draft、深层做 verify(DraftRetriever)
- Hardware-aware speculation:针对不同 GPU 内存层级专门优化的 draft 调度
- Continual draft training:在线学习,根据用户实际输入分布持续训练 draft 网络
本章小结
- 投机解码的核心:用小 draft 模型猜出 K 个候选 token,让大模型一次 forward 验证全部——把「1 步 1 token」变成「1 步多 token」。
- 数学正确性:拒绝采样保证输出分布与原大模型逐 token 采样完全一致——质量零损失。
- 加速比公式:
Speedup = (1 + 平均接受 token 数) / (1 + draft 工作量比例)。常见 2-5×。 - 主流方案:经典两模型、Medusa(多 LM head)、EAGLE(小 Transformer draft)、Lookahead(n-gram + Jacobi)。EAGLE-3 是当前最强。
- 「对赌」性质:赢则大赚(K+1 token 一步)、输则小亏(仅慢一点)—— 期望值显著正。
- 不是所有场景都赢:极小模型、大 batch、特殊 sampling、草稿质量差的情况下加速有限。
- 与其他优化协同:量化 + Flash Attention + KV Cache + 投机解码 ≈ 整体 8-15× 推理加速。
- vLLM / SGLang / TensorRT-LLM 都已内置——开箱即用,无需自己实现。
第六部分还剩最后一章——第 18 章 Flash Attention 与分布式推理。我们要把推理优化的最后两块拼图拼上:单卡级别的 Flash Attention 怎么把 attention 内存层级吃干净,多卡级别的 TP / PP / EP 怎么把超大模型分到几张甚至几百张 GPU 上。
延伸阅读
- Leviathan et al., Fast Inference from Transformers via Speculative Decoding, ICML 2023——投机解码奠基论文(Google)。
- Chen et al., Accelerating Large Language Model Decoding with Speculative Sampling, 2023——同期独立工作(DeepMind)。
- Cai et al., Medusa: Simple LLM Inference Acceleration Framework with Multiple Decoding Heads, ICML 2024——Medusa 论文。
- Li et al., EAGLE: Speculative Sampling Requires Rethinking Feature Uncertainty, ICML 2024——EAGLE 论文。
- Li et al., EAGLE-2: Faster Inference of Language Models with Dynamic Draft Trees, EMNLP 2024。
- Fu et al., Break the Sequential Dependency of LLM Inference Using Lookahead Decoding, ICML 2024——Lookahead。
- vLLM 投机解码文档: https://docs.vllm.ai/en/latest/features/spec_decode.html
- SGLang 投机解码 Benchmark: https://github.com/sgl-project/sglang