← Back to homepage

1.6 Speculative Decoding(投机解码)

自回归解码是严重访存受限(Memory-Bound)的,GPU 的绝大部分算力处于闲置状态。投机解码(Speculative Decoding)正是把这段闲置算力变现的技术——先用廉价方式猜出未来若干 token,再让大模型用一次并行前向把它们一次性验证掉。本节从加速比的定量分析出发,证明其分布无损性,并依次剖析 Medusa、EAGLE 与 MTP 三代主流实现。

动机:自回归解码"慢得没道理"

一次标准的解码步骤,要把整个模型的权重从 HBM 搬进片上 SRAM,然后只算出一个 token。以 70B 模型、BF16 权重为例:

单步 Decode 的成本拆解(70B 模型,BF16,H100,batch=1)

  权重搬运量   ≈ 140 GB
  计算量       ≈ 140 GFLOPs

  访存耗时     = 140 GB / 3.35 TB/s   ≈ 42 ms      ← 瓶颈
  计算耗时     = 140 GFLOPs / 990 TFLOPS ≈ 0.14 ms  ← 几乎空闲

  算术强度 = 140e9 / 140e9 ≈ 2 FLOPs/Byte
  H100 ridge point ≈ 300 FLOPs/Byte
  → GPU 有 99% 以上的时间在等内存
这个失衡带来一个关键推论:在小 batch 场景下,一次前向处理 1 个 token 和处理 8 个 token 的耗时几乎相同——权重只搬一次,多算几个 token 基本是"免费"的。投机解码的全部收益都建立在这个前提上。

1.6.1 draft-then-verify 与加速比分析

基本框架

记目标模型(target model)为 M_p,其在前缀下的条件分布为 p;草稿模型(draft model)为 M_q,分布为 q。一轮投机解码由两个阶段构成。

Draft 阶段:用 M_q 自回归地生成 γ 个候选 token,同时保留每一步的完整分布(拒绝采样时要用)。

x̃₁ ~ q(· | x<t)
x̃₂ ~ q(· | x<t, x̃₁)
 ⋮
x̃_γ ~ q(· | x<t, x̃₁..x̃_{γ-1})

Verify 阶段:把 [x<t, x̃₁, ..., x̃_γ] 一次性送入 M_p。由于因果注意力的性质,这一次前向同时给出了 γ+1 个位置的分布:

p₁ = p(· | x<t)
p₂ = p(· | x<t, x̃₁)
 ⋮
p_{γ+1} = p(· | x<t, x̃₁..x̃_γ)

注意最后一个分布 p_{γ+1}:它是"假设所有草稿都被接受"之后的下一个 token 分布。这意味着即使 γ 个草稿全部被接受,仍能白送一个 token,即所谓的 bonus token。因此单轮最多产出 γ+1 个 token。

一轮 draft-then-verify(γ = 4)

  前缀: "The capital of France is"

  Draft (小模型 4 步串行,每步很便宜)
    → [" Paris", ",", " a", " city"]

  Verify (大模型 1 次并行前向,5 个位置同时出分布)
    位置1 ✓ Paris    位置2 ✓ ,    位置3 ✗ a  → 拒绝
    位置3 重采样 → " which"
    位置4、5 丢弃,KV cache 回滚

  本轮产出 3 个 token,代价 = 4×T_draft + 1×T_target

三个前提条件

  1. Verify 近似免费:一次处理 γ+1 个 token 的前向,耗时应接近处理 1 个 token。在 memory-bound 区间成立,随 batch size 增大逐渐失效。

  2. Draft 足够便宜:记 c = T_draft / T_target 为单步成本比。独立小模型 c ≈ 0.02–0.1;Medusa / EAGLE 这类轻量头 c 可低至 0.01–0.05;n-gram / prompt lookup 则 c ≈ 0。

  3. Draft 足够准:接受率 α 要高。α 与任务强相关——代码、摘要、格式化输出这类低熵任务 α 高;开放式创作、高温采样则 α 低。

期望接受长度

定义单步接受率 α = E[min(1, p(x̃)/q(x̃))]。在"各步接受事件独立同分布"这一常用简化假设下,接受的草稿数服从截断几何分布,加上必得的 1 个 token(重采样 token 或 bonus token),单轮产出期望为:

τ = E[#tokens] = ( 1 - α^(γ+1) ) / ( 1 - α )

这个量常被称为接受长度 τ(acceptance length),是评价投机解码方法最核心的指标,因为它与具体硬件无关。直觉检查:α → 1 时 τ → γ+1(全接受);α → 0 时 τ → 1(退化为普通解码)。另外 τ 关于 γ 是次线性增长且有上界 1/(1-α),这是"γ 不能无限加大"的根本原因。

加速比公式

单轮墙钟时间为 γ·T_draft + T_target = T_target·(γc + 1),而基线每个 token 耗时 T_target。于是:

Speedup(γ, α, c) = ( 1 - α^(γ+1) ) / [ (1 - α) × (γc + 1) ]

    分子 = 收益(接受长度)    分母 = 代价(draft 开销)

代入几组典型值(Leviathan et al., 2023 的经典结果):

αc最优 γ*最优加速比说明
0.60.0541.92×草稿质量一般,独立小模型典型值
0.80.059–103.08×优秀草稿(EAGLE 级别)
0.90.0513–154.67×极强草稿 / 低熵任务
0.80.2041.87×草稿模型过大,收益被吃掉一半
0.80.0120+4.0×近乎免费的草稿头

可以读出三条工程结论:

公式没说的部分:现实中的偏差

Batch size 的杀伤力。 随着 batch 增大,target 模型本身就离开了 memory-bound 区间,"并行验证近似免费"的前提崩塌:验证 γ+1 个 token 的成本开始正比于 γ+1。在高 batch 的吞吐导向场景(离线批处理),投机解码经常是负收益,因为浪费的 FLOPs 直接转化为吞吐损失。
生产系统通常设置 batch size 阈值,超过阈值就自动关闭投机解码或动态调低 γ(vLLM、TensorRT-LLM 都有类似机制)。

1.6.2 为什么能保证输出分布不变

投机解码最漂亮的地方在于:它不是近似加速,而是在数学上精确等价于从目标模型采样。这一点使它区别于量化、剪枝、蒸馏等所有有损加速手段——你不需要重新跑一遍质量评测。

修正拒绝采样(Modified Rejection Sampling)

在单个位置上,给定草稿分布 q、目标分布 p 和草稿采出的 token x̃ ~ q,判定规则是:

1. 采 r ~ U[0, 1]
2. 若 r ≤ min(1, p(x̃) / q(x̃)) → 接受
3. 否则 拒绝,从残差分布重采样:
    x ~ p'(·),   p'(x) = max(0, p(x) - q(x)) / Σ_x' max(0, p(x') - q(x'))

关键在第 3 步:拒绝时不是从 p 重采(那样会破坏分布),而是从"p 比 q 多出来的那部分质量"里采。直觉上,接受步骤已经按照 min(p, q) 的比例把 token 发出去了,剩下的缺口恰好是 max(0, p−q)。

正确性证明

记接受概率 β = Σ_x q(x)·min(1, p(x)/q(x)) = Σ_x min(p(x), q(x))。最终输出 token 为 x 的总概率由两条互斥路径组成:

P(out = x) = q(x)·min(1, p(x)/q(x)) + (1 - β)·p'(x)
           └─ 采到 x 且被接受 ─┘   └─ 被拒后重采到 x ─┘

逐项化简。第一项:

q(x)·min(1, p(x)/q(x)) = min(q(x), p(x))

第二项,先算归一化常数。注意到:

Σ_x max(0, p(x) - q(x)) = Σ_x [ p(x) - min(p(x), q(x)) ] = 1 - β

∴ (1 - β)·p'(x) = (1 - β) × max(0, p(x)-q(x)) / (1 - β) = max(0, p(x) - q(x))

归一化常数正好抵消。两项相加,分情况讨论:

若 p(x) ≥ q(x):   q(x) + (p(x) - q(x)) = p(x)  ✓
若 p(x) < q(x):   p(x) + 0 = p(x)  ✓

∴ P(out = x) = p(x)  对任意 x 成立
单个位置的输出严格服从目标分布,与 q 无关。 由于每个位置的判定都基于真实前缀(被接受的草稿本身就构成合法采样路径),归纳可得整条序列的联合分布与朴素自回归采样完全一致。q 只影响 β(速度),不影响分布(质量)——这是整个方法的立身之本。

贪心解码的特例

当温度为 0 时,p 退化为 one-hot。此时 min(1, p(x̃)/q(x̃)) 非零当且仅当 x̃ = argmax p,规则退化为逐位置精确匹配:草稿 token 等于目标模型的 argmax 就接受,否则用 argmax 替换。这也是实现里最常见的路径,通常称为 greedy verification。

容易踩的坑

采样变换必须一致。 temperature、top-k、top-p、repetition penalty 都会改变分布。若目标端做了 top-p 截断,那么用于计算接受率的 p 必须是截断并重归一化之后的分布,q 同理。混用(比如 q 用原始 softmax、p 用 top-p 后的)会破坏等价性。工程上的标准做法是:先对两侧应用完全相同的 logits processor,再进入拒绝采样。

数值精度带来的实际偏差。 严格等价成立于实数域。实际系统中,BF16/FP16 的 logits 有舍入误差;更麻烦的是,target 模型在 verify 阶段以序列长度 γ+1 做前向,而基线是长度 1 的前向,两者会走到不同的 GEMM kernel、不同的规约顺序,同一位置的 logits 会有 1e-3 量级差异。因此"投机解码输出与基线逐 token 完全一致"在贪心模式下也只是高概率成立,长序列上偶尔会因为两个近似相等的 logit 翻转而分叉。这是数值问题不是算法问题,但做回归测试时要有心理准备。

bonus token 的正确性。 全接受时额外产出的 token 直接从 p_{γ+1} 采样,无需拒绝采样,因为它的前缀已经全部被验证过,p_{γ+1} 就是真实条件分布。

推广到多候选。 拒绝采样天然是"单条链"的。当需要在一个位置同时验证多个候选(树形草稿,见下节),需推广到 SpecInfer 提出的多轮拒绝采样:依次对候选做判定,每拒绝一个就把残差分布更新为 norm(max(0, p − q⁽ⁱ⁾)),再用下一个候选去试;全部拒绝则从最终残差分布采样。可以证明这仍保持分布不变,且接受概率随候选数单调上升。

1.6.3 Medusa 与树形注意力

独立草稿模型有两个现实问题:需要一个词表对齐、架构兼容的小模型(很多模型系列根本没有足够小的成员);以及它要维护自己的一整套 KV cache 和执行流。Medusa(Cai et al., 2024)提出了另一条路:不要独立模型,直接在目标模型上长出几个额外的预测头

Medusa Heads

设目标模型最后一层的隐状态为 h_t。原始 LM head 用 h_t 预测 x_{t+1};Medusa 额外添加 K 个头,第 k 个头用同一个 h_t 预测 x_{t+1+k}:

p_t^(k) = softmax( W_lm · ( h_t + SiLU(W₁^(k) · h_t) ) )

即一个带残差连接的单层 MLP,后接(共享的)LM head。参数量极小(每个头约 d² ),前向开销可忽略,c 接近 0.01。训练有两种模式:

从"链"到"树"

Medusa 的根本弱点:头之间并行且相互独立。 head-1 预测 x_{t+2},head-2 预测 x_{t+3},两者都只看 h_t,head-2 并不知道 head-1 采了什么。草稿 token 之间没有依赖建模,α 因此不高——第 2、3 个头的 top-1 准确率通常只有 60% 和 40% 左右。

补救办法是用宽度换深度:既然单条链不准,就每个头取 top-k 个候选,组合成一棵候选树。只要其中任意一条路径被接受,这一轮就赚到了。朴素笛卡尔积会指数爆炸(k^K),所以 Medusa 用稀疏树:在校准集上统计每个头第 i 个候选的准确率,一条路径的期望接受率近似为路径上各节点准确率之积,按此贪心选取节点,构造一棵固定的(如 64 节点)树。典型形状是"头重脚轻"——浅层宽、深层窄。

树形注意力(Tree Attention)

问题来了:如何用一次前向验证整棵树?答案是把树展平成一个序列,然后定制 attention mask 与 position id:

候选树:               展平序列:
                      [ ...prefix, x_t, A, B, AA, AB, BA ]
      x_t
     /   \            Attention Mask (■ = 可见)
    A     B                   pre  A  B  AA AB BA
   / \     \            A      ■   ■  ·  ·  ·  ·
  AA  AB    BA          B      ■   ·  ■  ·  ·  ·
                        AA     ■   ■  ·  ■  ·  ·
                        AB     ■   ■  ·  ·  ■  ·
                        BA     ■   ·  ■  ·  ·  ■

  Position ID:  A, B → t+1        AA, AB, BA → t+2
                (兄弟节点共享 position,按树深度而非展平下标)

一次前向就得到了树上每个节点位置的目标分布,之后沿树从根往下找出最长的被接受路径,接受它,并把不在该路径上的 KV 条目从 cache 中剔除(实现上通常是把选中路径的 KV 搬到连续位置)。树形注意力是 Medusa 的核心工程贡献,此后被 EAGLE、SpecInfer、DeepSeek MTP 部署等几乎所有方案继承。

Typical Acceptance

Medusa 在验证时默认不用严格拒绝采样,而是用 typical acceptance:

接受 x̃  ⟺  p(x̃ | x<t) > min( ε , δ · exp(−H(p(· | x<t))) )

    H 为目标分布的熵,典型取 ε = 0.3, δ = 0.09

含义是:只要目标模型认为这个 token "不算离谱"就放行;分布越不确定(熵越高),门槛越低。

这牺牲了分布严格不变,换来明显更高的接受率。作者的论据是:温度采样本身就说明我们不追求唯一正确答案,典型集合内的 token 都可接受。实践中质量下降通常不显著,但这是一个需要显式知情的取舍——如果你的产品对"与原模型 bit-level 一致"有承诺(需复现历史输出、或有合规要求),就不能用这类方案。

Medusa 的整体效果约为 2.2–2.8× 加速。

1.6.4 EAGLE 与 EAGLE-3

EAGLE(Extrapolation Algorithm for Greater Language-model Efficiency,Li et al., 2024)系列是目前开源方案中效果最好的一支,也是理解"草稿模型应该建模什么"的关键。

核心洞察:在特征层做自回归

两点合起来给出 EAGLE 的结构:

f̂_{t+1} = DecoderLayer( FC( [ f_t ; e_{t+1} ] ) )

  FC:         2d → d 的线性层
  DecoderLayer: 单层 Transformer decoder
  然后复用目标模型冻结的 LM head 得到 token 分布
EAGLE 草稿循环

  [f_t , e_{t+1}] → FC → Decoder → f̂_{t+1} → LM head → 采样 x̃_{t+2}
                                       │                     │
                                       └──────┬──────────────┘
                                              ↓
  [f̂_{t+1} , e_{t+2}] → FC → Decoder → f̂_{t+2} → LM head → 采样 x̃_{t+3}
                                              ↓
                                            ......

  对比 Medusa: 第 k 步能看到前 k-1 步采出的 token → 草稿间存在依赖
EAGLE 的草稿步骤是真正自回归的,恢复了 Medusa 丢失的因果链,α 大幅提升;而代价只是一层 decoder(7B 模型约 0.25B 参数),c 仍然很小。

训练

L = L_reg + w_cls · L_cls
  = SmoothL1( f_{t+1} , f̂_{t+1} ) + w_cls · CE( p_{t+2} , p̂_{t+2} )

  典型 w_cls = 0.1,分类项用目标模型的软分布做蒸馏

一个重要细节是 training-test 不一致:训练时喂的 f_t 是目标模型的真实特征,而推理时第二步之后喂的是草稿模型自己预测的 f̂,带有误差。EAGLE 的处理是训练时对输入特征加入均匀噪声 U(−0.1, 0.1)。训练数据量很小(ShareGPT 约 68k 对话),单卡数天即可完成,且目标模型完全冻结——这是相对 Medusa-2 的一大优势,不存在损害原模型的风险。

EAGLE-2:动态草稿树

EAGLE-1 沿用 Medusa 式的静态树:形状在校准阶段确定,推理时对所有输入都一样。但接受率是上下文相关的——"the United States of" 后面接 "America" 几乎必然被接受,而一段开放式叙述的下一个词则高度不确定,用同一棵树对待两者显然低效。

EAGLE-2 的贡献是发现:草稿模型输出的置信度是接受率的良好近似。于是可以在运行时动态构树:

相同验证预算下拿到更高的接受长度,EAGLE-2 相比 EAGLE-1 再提升约 20–40%。

EAGLE-3:放弃特征回归,拥抱 scaling

EAGLE-3(2025)来自一个反直觉的发现:特征回归损失 L_reg 是 scaling 的绊脚石。 增加训练数据时,EAGLE-1/2 的接受长度很快饱和,因为模型容量被"精确复现目标模型的中间特征"这一约束占用了,而这个约束对最终目标(预测对 token)并非必要。

改动一:去掉特征预测,改为 training-time test。

直接丢弃 L_reg,只保留 token 层面的目标。但这样一来,"喂给下一步的特征"就没有监督对齐了。解决办法是在训练时显式模拟多步草稿过程:把草稿模型自己产生的中间表示接回输入,走 2–3 步,每一步都算 token 级损失。这直接消除了 training-test 不一致,比加噪声的做法更彻底。

改动二:融合多层特征。

g_t = [ h_t^(low) ; h_t^(mid) ; h_t^(high) ] ∈ R^{3d}  →  降维层 (3d → d)

  不同深度携带互补信息:浅层偏词法/句法,深层偏语义

结果是接受长度显著提升,且随训练数据量持续增长而不饱和——具备了 scaling 性质。EAGLE-3 在 LLaMA、Qwen、DeepSeek 等模型上普遍达到 4–6.5× 加速(batch=1),接受长度 τ 可达 6–8。目前 SGLang、vLLM、TensorRT-LLM 均已内置支持,是开源部署的事实标准之一。

三代方法对比

维度独立小模型MedusaEAGLE-1/2EAGLE-3
草稿单元完整小模型K 个 MLP 头1 层 decoder1 层 decoder
草稿间依赖有(自回归)(并行头)有(特征级)
输入tokenh_tf_t + e_{t+1}多层 h + e
训练目标独立预训练CESmoothL1 + CECE(多步模拟)
骨干是否改动Medusa-2 会改
分布不变否(typical)
草稿树通常无静态树静态 / 动态树动态树
典型加速1.5–2×2.2–2.8×2.5–4×4–6.5×

1.6.5 MTP(Multi-Token Prediction)

前面的方法都是事后给一个已训练好的模型加装草稿模块。MTP 则把"预测多个未来 token"提前到预训练阶段,作为模型自身的一部分。

起点:MTP 首先是一种训练目标

Gloeckle et al. (2024) 提出:在共享 trunk 上接 n 个独立输出头,第 k 个头预测 x_{t+k}:

L = Σ_{k=1..n} CE( x_{t+k} , p^(k)(· | x_≤t) )

他们发现这不只是为了加速,还能提升模型质量本身,尤其在代码等需要"规划"的任务上。直觉解释:next-token prediction 会让模型过度关注局部模式,很多 token 由前一个词就能猜出(teacher forcing 下的"捷径");强迫模型同时预测更远的 token,迫使它在隐状态中编码更长程的意图。同时每个位置提供 n 个训练信号,监督被致密化,数据效率更高。副产品是这些头天然可以拿来做自投机解码。注意该论文的头是并行独立的(与 Medusa 类似),预测之间没有因果链。

DeepSeek-V3 的顺序式 MTP

DeepSeek-V3 把 MTP 做成了保持完整因果链的形式,并作为正式的预训练目标之一。设深度为 D(V3 中 D=1),第 k 个 MTP 模块:

h'_i^(k) = M_k · [ RMSNorm( h_i^(k-1) ) ; RMSNorm( Emb( t_{i+k} ) ) ]

h^(k)_{1:T-k} = TRM_k( h'^(k)_{1:T-k} )

P^(k)_{i+k+1} = OutHead( h_i^(k) )

  M_k : 2d → d 投影矩阵  |  TRM_k : 一层 Transformer block
  Embedding 层与 OutHead 与主模型共享
这个结构和 EAGLE 几乎一模一样:都是把「当前隐状态」和「下一个 token 的 embedding」拼接后过一层 Transformer,再复用共享的 LM head。
维度EAGLEDeepSeek MTP
训练时机事后,目标模型冻结与主模型联合预训练
数据量约 68k 对话全部预训练语料(万亿 token)
对主模型的影响提升主模型质量(额外训练信号)
输入特征倒数第二层主模型最终隐状态

训练目标为各深度损失的平均乘以权重 λ 加到主损失上(V3 中前 10T token 用 0.3,后 4.8T 用 0.1)。推理时有两种用法:(a)直接丢弃 MTP 模块,主模型独立工作,此时 MTP 纯粹是一种训练时的正则/增强;(b)保留 MTP 模块做投机解码。DeepSeek 报告第二个 token 的接受率在 85%–90% 之间(跨任务稳定),配合投机解码可使 TPS 提升约 1.8×

MTP 已成为标配

在 DeepSeek-V3 之后,MTP 迅速被主流开源模型采纳——Qwen3、GLM-4.5/4.6、MiniMax、Kimi 等都在预训练中加入了 MTP 模块并随权重一起发布。这带来一个重要变化:投机解码的草稿模块不再需要下游使用者自己训练,它作为模型权重的一部分直接发布,推理框架开箱即用。

工程上的若干要点:

MTP 与 EAGLE 的关系

演化脉络

  Medusa      并行独立头,无依赖建模          → 靠树宽补救
     ↓
  EAGLE       特征 + 下一 token embedding     → 恢复因果链,事后训练
     ↓
  EAGLE-3     多层特征 + 多步模拟训练          → 可 scaling
     ↓
  MTP         同样的结构,搬进预训练           → 草稿质量随基座一起 scale
                                               且反过来提升基座质量

MTP 是这条线的自然终点:既然草稿模块的质量随训练数据 scale,那就干脆让它跟着基座模型一起在万亿 token 上训练。

1.6.6 小结与工程实践建议

方法选择

场景推荐方案
模型自带 MTP 模块(DeepSeek-V3、Qwen3、GLM-4.5 等)直接开启 MTP 投机解码
有训练资源、追求最高加速EAGLE-3
无训练资源,输出与输入高度重叠(RAG、代码补全、文本编辑、格式化改写)n-gram / prompt lookup decoding,零训练零成本
已有同系列小模型且词表对齐经典 draft model
高 batch 吞吐场景谨慎评估,很可能应当关闭

评测指标

不要只看端到端加速比(严重依赖硬件、batch、序列长度)。核心应报告接受长度 τ(与硬件无关,反映草稿质量)与 c(反映草稿开销),二者代入 1.6.1 的公式即可预估任意硬件上的收益。同时要区分延迟(TPOT)与吞吐(total TPS)两个维度——投机解码优化前者,可能损害后者。

必做的正确性检查

一个常见 bug 是树形注意力的 position id 用了展平序列的下标而非树深度。症状很隐蔽:接受率无缘无故偏低,而输出仍然"看起来正常"(因为验证逻辑本身仍会纠正错误 token)。

自适应策略

生产系统通常需要根据运行时信号动态调整:

参考文献

  1. Leviathan, Y., Kalman, M., Matias, Y. Fast Inference from Transformers via Speculative Decoding. ICML 2023.

  2. Chen, C., Borgeaud, S., et al. Accelerating Large Language Model Decoding with Speculative Sampling. 2023.

  3. Miao, X., et al. SpecInfer: Accelerating Generative LLM Serving with Tree-based Speculative Inference and Verification. ASPLOS 2024.

  4. Cai, T., Li, Y., et al. Medusa: Simple LLM Inference Acceleration Framework with Multiple Decoding Heads. ICML 2024.

  5. Li, Y., Wei, F., Zhang, C., Zhang, H. EAGLE: Speculative Sampling Requires Rethinking Feature Uncertainty. ICML 2024.

  6. Li, Y., et al. EAGLE-2: Faster Inference of Language Models with Dynamic Draft Trees. EMNLP 2024.

  7. Li, Y., et al. EAGLE-3: Scaling up Inference Acceleration of Large Language Models via Training-Time Test. 2025.

  8. Gloeckle, F., Idrissi, B.Y., et al. Better & Faster Large Language Models via Multi-token Prediction. ICML 2024.

  9. DeepSeek-AI. DeepSeek-V3 Technical Report. 2024.

© Xiaoyi | Homepage