Transformer 解剖:从 Attention 到推理系统

第 17 章 投机解码:用小模型加速大模型

作者 杨艺韬 · 4,298 字

第 17 章 投机解码:用小模型加速大模型

第 14 章我们看到 Decode 阶段是 memory-bound——GPU 算力大量空闲、HBM 带宽是瓶颈。第 16 章用量化把权重压缩,HBM 读取量减半减四倍。但还有一种更聪明的思路——既然 GPU 算力空闲,能不能一次多算几个 token?

听起来像作弊:自回归生成不是必须一个 token 一个 token 来吗?答案是:借助一个聪明的「投机」机制,可以——这就是 投机解码(Speculative Decoding)

它的核心想法用一个生活化比喻就讲完:你想读一本书,你可以一字一字读(Decode 模式);也可以让一个朋友先快速浏览、把他猜测的内容讲给你听,你只在「不对的地方」打断纠正。如果朋友猜得大多对,你听几句就能掌握一大段——这就是投机解码用小模型「先猜、大模型『后验』」的本质。

读完这章你能:

17.1 一个直觉:Decode 的算力是浪费的

回顾第 14 章。Llama-3 70B 在单卡 H100 上 Decode 一个 token:

也就是说每次 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 和大模型的预测:

例如:

位置:        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)。

设大模型分布是 p(xi)p(x_i),draft 模型分布是 q(xi)q(x_i)。投机解码的接受规则:

  1. q(x)q(x) 采样得到 draft token x~\tilde{x}
  2. 计算接受概率:α=min(1,p(x~)/q(x~))\alpha = \min(1, p(\tilde{x}) / q(\tilde{x}))
  3. 以概率 α\alpha 接受 x~\tilde{x}
  4. 如果拒绝,从修正分布 p(x)=max(0,p(x)q(x))/sump'(x) = \max(0, p(x) - q(x)) / \text{sum} 采样

Leviathan et al.(Google,2023)和 Chen et al.(DeepMind,2023)独立证明了:这个流程下,每个被接受的 token 完全等价于从 p(x)p(x) 直接采样——也就是说投机解码的输出分布和原大模型逐 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,平均能接受 nˉ\bar{n} 个。接受率 β=nˉ/K\beta = \bar{n} / K 是决定加速比的关键变量。

加速比公式:

Speedup=1+nˉ1+Kc\text{Speedup} = \frac{1 + \bar{n}}{1 + K \cdot c}

其中 c=Tdraft/Tverifyc = T_{\text{draft}} / T_{\text{verify}} 是 draft 单步时间相对大模型 verify 时间的比例。

直观理解:

举个具体数字:

如果接受率高、draft 占比小,加速比可以更高:

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
GPT-4 GPT-4-mini 不公开
Claude Opus Claude Haiku 不公开

要求:draft 模型必须和大模型用同一个 tokenizer——否则 draft 输出的 token id 大模型理解不了。

工程问题:

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 的优势:

Medusa 论文报告 Llama-2 7B 上 2.5-2.8× 加速,几乎无质量损失。

代价:

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:

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 越大,单轮潜在加速越大,但:

实际工程 K=4-8 是甜点。Medusa 默认 K=4-5。EAGLE 通过 tree decoding 让有效 K 增加到 30+ 但实际只验证一支。

Trade-off 2:draft 模型质量

draft 越准接受率越高、加速比越大;但 draft 越大本身越慢,c 上升。

经验值:

Trade-off 3:与 batching 的兼容

投机解码和 continuous batching 有冲突。常规 batching:每个用户每步生成 1 token,batch 中所有用户同步推进。投机解码:每个用户每步生成 1+β·K 个 token,不同用户的实际推进速度不同——同步性破坏。

工程上的处理:

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.5,要么换 draft 模型、要么减小 K。

17.9 投机解码的「赌性」

为什么这一章副标题是「为什么是对赌」?

投机解码的本质是个赌局:

所以这是「只赢不输的赌局」——赢则大赚,输则小亏,长期 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):

所有这些叠加,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 年仍在研究的方向。

未来方向

  1. Tree-based speculation(EAGLE-2/3):一次产生多个分支,选最优一支
  2. Self-speculative:让大模型自己作为自己的 draft——用浅层做 draft、深层做 verify(DraftRetriever)
  3. Hardware-aware speculation:针对不同 GPU 内存层级专门优化的 draft 调度
  4. Continual draft training:在线学习,根据用户实际输入分布持续训练 draft 网络

本章小结

  1. 投机解码的核心:用小 draft 模型猜出 K 个候选 token,让大模型一次 forward 验证全部——把「1 步 1 token」变成「1 步多 token」。
  2. 数学正确性:拒绝采样保证输出分布与原大模型逐 token 采样完全一致——质量零损失。
  3. 加速比公式Speedup = (1 + 平均接受 token 数) / (1 + draft 工作量比例)。常见 2-5×。
  4. 主流方案:经典两模型、Medusa(多 LM head)、EAGLE(小 Transformer draft)、Lookahead(n-gram + Jacobi)。EAGLE-3 是当前最强。
  5. 「对赌」性质:赢则大赚(K+1 token 一步)、输则小亏(仅慢一点)—— 期望值显著正。
  6. 不是所有场景都赢:极小模型、大 batch、特殊 sampling、草稿质量差的情况下加速有限。
  7. 与其他优化协同:量化 + Flash Attention + KV Cache + 投机解码 ≈ 整体 8-15× 推理加速。
  8. vLLM / SGLang / TensorRT-LLM 都已内置——开箱即用,无需自己实现。

第六部分还剩最后一章——第 18 章 Flash Attention 与分布式推理。我们要把推理优化的最后两块拼图拼上:单卡级别的 Flash Attention 怎么把 attention 内存层级吃干净,多卡级别的 TP / PP / EP 怎么把超大模型分到几张甚至几百张 GPU 上。

延伸阅读