本文是《高效推理与压缩(算法侧):解码、投机、量化与 KV》系列的第 2 篇(共六篇)。上一篇:解码策略、采样与约束生成;下一篇:训练后量化:误差模型、GPTQ、AWQ 与旋转

投机解码是本系列里唯一不改变输出分布的方法。04 系列第七篇已经完成了它的基础部分:拒绝采样保证输出严格等于目标分布的证明、期望接受长度 \(\frac{1 - \alpha^{\gamma+1}}{1 - \alpha}\)、以及 Roofline 决定的收益区间——验证 \(\gamma + 1\) 个 token 几乎免费的条件是 \(B(\gamma + 1) \lesssim \text{ridge}\),超过就亏本。那一篇把草稿方案列成了一张表(独立小模型、Medusa、EAGLE、n-gram、MTP),给了各自”通常报告”的接受率区间。

这一篇从那张表往下挖。加速比只由两个量决定——接受率 \(\alpha\) 与草稿成本 \(c\)——而这两个量都是算法工程师能改的:\(\alpha\) 是草稿分布与目标分布的接近程度,由草稿怎么训练决定;\(c\) 由草稿的结构决定;树状草稿则改变了”一轮能验证多少”这个游戏规则本身。2023 年的独立小模型 \(\alpha \approx 0.7\)、加速 2 倍;2025 年的 EAGLE-3 报告接受长度 5–6、加速 3–6 倍。差别不在验证算法,在草稿。

本篇要回答的核心问题是:

为什么 EAGLE 的接受率高于 Medusa 而草稿成本差不多?一个 70B 模型该用什么草稿?

一、总览:加速比的两个自由度

1. 从 04-07 接过来的公式

一轮投机解码:草稿产出 \(\gamma\) 个 token,目标模型一次前向验证,期望产出

\[\mathbb{E}[\text{tokens}] = \frac{1 - \alpha^{\gamma+1}}{1 - \alpha}, \qquad \text{speedup} = \frac{\mathbb{E}[\text{tokens}]}{\gamma c + 1}\]

(在 memory-bound 区间内,验证的时间等于一次普通 decode 步。)\(\alpha\) 是单个位置的期望接受率,\(c\) 是草稿一步相对于目标一步的时间。\(\alpha = 0.8\)、\(\gamma = 4\)、\(c = 0.1\) 时加速 2.4 倍。这个公式假设各位置的接受独立同分布——实际上接受率随位置递减(后面的草稿 token 以前面的草稿为条件,错误累积),所以真实的接受长度低于公式,但公式的结构是对的。

2. 两个自由度

自由度 含义 由什么决定 改进方向
\(\alpha\) \(1 - \text{TV}(p, q)\):草稿分布与目标分布的总变差距离的补 草稿模型的容量、训练目标、输入信息 训练草稿去匹配目标(蒸馏);给草稿更多信息(目标的隐状态)
\(c\) 草稿一步 / 目标一步 草稿的参数量、层数、是否复用目标的计算 更小的草稿;复用目标模型的特征;一次前向出多个草稿
一轮验证多条候选路径 树的形状、每层的分支数 在同样的验证成本下提高期望接受长度

三者不独立:草稿越小,\(c\) 越低但 \(\alpha\) 也越低;树越宽,期望接受长度越高但验证的 token 数越多(更早撞上 ridge)。所有草稿方案都是在这个三角上找位置。

3. 先说答案

Medusa 与 EAGLE 的草稿成本都接近零(一个几层或一层的模块,\(c \approx 0.02\)–\(0.05\)),差别在草稿看到了什么。Medusa 的第 \(k\) 个头从目标模型当前位置的隐状态直接预测第 \(t + k\) 个 token,各头之间没有条件依赖——第 3 个头不知道第 2 个头猜了什么,预测的是一个边缘分布;EAGLE 在目标模型的特征空间里做自回归——用当前特征与上一个草稿 token 的 embedding 预测下一个特征,再从特征出 token——每个草稿 token 都以前面的草稿为条件,预测的是条件分布。边缘分布的 TV 距离天然大于条件分布的。此外,特征比 token 更”平滑”:从特征预测下一个特征的不确定性低于从 token 预测下一个 token(token 是特征经过 lm_head 与采样之后的离散化,丢了信息)。第四章展开。

一个 70B 模型该用什么草稿:2025 年的答案是 EAGLE-3 一类的特征级草稿(接受长度 4–6,加速 3 倍以上),或者如果模型本身带 MTP 头(DeepSeek-V3 一类),直接用 MTP 头。独立小模型(用 8B 给 70B 起草)在没有训练资源时是可用的,但 \(c \approx 0.11\) 且 \(\alpha\) 受限于两个独立训练的模型的分布差。n-gram 只在有大量复制的任务上有效。第八章的选型表。

4. 本文的章节安排

主题 内容
接受率的本质 \(\alpha = 1 - \text{TV}\) 的推导;接受率随位置递减;温度对接受率的影响;greedy 下的接受率
训练草稿 草稿的正确训练目标是蒸馏;on-policy 的重要性;独立小模型的局限
Medusa 与 EAGLE 多头 vs 特征级自回归;各自的结构、训练目标与成本;EAGLE-2 的动态树与 EAGLE-3 的多层特征
树状草稿的验证 tree attention 的 mask;多路径的接受规则与分布保证;期望接受长度在树上的形式
MTP 作为草稿 DeepSeek-V3 的 MTP 头;训练目标与推理草稿的两种身份
免费的草稿 n-gram / prompt lookup;自投机(层跳过);何时够用
何时投机变慢 大 batch;短输出;长上下文的验证成本;草稿与目标不匹配;一张选型表
草稿的评测 接受长度、每 token 延迟、分布一致性检验
动手(建议) vLLM 上两种草稿在两类任务上的对照
十一 本文小结  

二、接受率的本质

1. 接受率等于 1 减总变差距离

04-07 证明了单步接受概率 \(\beta = \sum_x \min(p(x), q(x))\)。总变差距离的定义是 \(\text{TV}(p, q) = \frac{1}{2} \sum_x \lvert p(x) - q(x) \rvert\)。用 \(\lvert a - b \rvert = a + b - 2\min(a, b)\):

\[\text{TV}(p, q) = \frac{1}{2} \sum_x \big(p(x) + q(x) - 2 \min(p(x), q(x))\big) = \frac{1}{2}(1 + 1) - \sum_x \min(p, q) = 1 - \beta\]

所以 \(\beta = 1 - \text{TV}(p, q)\)。接受率就是两个分布的重叠部分。这给了”怎么提高接受率”一个精确的目标:让草稿分布在总变差意义下接近目标分布。它也说明了为什么草稿的”准确率”(argmax 是否一致)不是正确的度量——两个 argmax 相同但形状不同的分布,TV 距离可以很大;反过来 argmax 不同但形状接近的分布,接受率可以很高。

2. 接受率随位置递减

第 \(i\) 个草稿 token 的分布是 \(q(\cdot \mid \text{prefix}, x_{<i})\),其中 \(x_{<i}\) 是草稿自己产出的。如果草稿在第 2 步产出了一个目标模型认为不太可能的 token(但没有被拒绝——接受是概率性的),第 3 步的条件就偏离了目标模型”会走”的路径,第 3 步的分布差更大。所以 \(\alpha_1 \ge \alpha_2 \ge \cdots\),且差距随草稿与目标的不匹配程度增大。EAGLE 论文报告的典型数字:第 1 个草稿 token 接受率约 0.8,第 5 个降到 0.5 左右。这决定了 \(\gamma\) 不能无限增加——第 6、7 个草稿 token 的接受率已经低到不值得验证的成本。

3. 温度的影响

采样温度改变 \(p\) 与 \(q\) 的形状,也改变它们的重叠。\(T \to 0\)(greedy)时两者都退化为 one-hot,接受当且仅当 argmax 一致——接受率等于草稿的 top-1 准确率。\(T = 1\) 时是两个完整分布的重叠。中间温度下,两个分布都变尖,如果它们的 argmax 一致,重叠增加;如果不一致,重叠减少。实证上(Leviathan 等 2023 与后续工作的观察)接受率在 greedy 下最高、随温度上升而下降——因为 argmax 一致的位置占多数,变尖让这些位置的重叠趋近 1。这意味着投机解码在低温下收益更大,而推理模型推荐的 \(T = 0.6\) 是一个中间位置。

一个常被忽略的实现细节:草稿采样用的温度必须与目标一致——分布等式的证明要求 \(p\) 与 \(q\) 是各自在同一采样规则下的分布。如果目标用了 top-p 截断,\(p\) 是截断后的分布,草稿也要在同一规则下采样与计算 \(q(x)\),否则输出分布不再等于目标的。vLLM 的实现里草稿与目标共享 SamplingParams,这是原因。

4. greedy 下的简化与”宽松验证”

greedy 下验证规则退化为逐 token 比较,不需要计算概率比。一些系统在 greedy 下放松验证:接受 top-k 内的草稿 token(”typical acceptance”,Medusa 提出),换来更高的接受率、代价是输出不再严格等于目标模型的 greedy 输出。这是一个有意的分布改变,属于本系列后面几篇的范畴——用它时要像评测量化模型一样评测它。

三、训练草稿:目标是蒸馏

1. 正确的训练目标

要最小化 \(\text{TV}(p, q)\),直接优化 TV 不方便(不可微处多)。Pinsker 不等式给了一个可微的上界:\(\text{TV}(p, q) \le \sqrt{\frac{1}{2} \text{KL}(p \| q)}\)。最小化 KL\((p \| q)\) 就是前向 KL 的 logits 级蒸馏L5 第七篇第三章)——草稿是学生,目标模型是教师。这个联系不只是类比:Zhou 等 2024(DistillSpec)系统地验证了用蒸馏训练草稿模型,接受率比用原始数据训练的同尺寸草稿高 10–45%。

三个推论:

  • 草稿应该匹配目标模型,而不是匹配数据。一个在训练数据上困惑度更低的小模型,不一定是更好的草稿——目标是像目标模型一样犯错。
  • on-policy 很重要。草稿在推理时看到的前缀是目标模型生成的文本(被接受的 token 来自 \(p\))。所以训练时的前缀应该来自目标模型的生成,而不是来自数据集——这正是 L5 第七篇讲的 on-policy 蒸馏(GKD)的动机:修暴露偏差。DistillSpec 的实验里 on-policy 数据比固定数据集的接受率高 3–8 个点。
  • 前向 KL 还是反向 KL:前向 KL 让草稿 mode-covering——在目标模型有概率的地方都放概率,这对接受率有利(重叠大);反向 KL 让草稿 mode-seeking——集中在目标的峰上,在 greedy 下有利(argmax 一致率高)。DistillSpec 的结论是任务与温度依赖,没有普适的赢家,但前向 KL 是稳妥的默认。

2. 独立小模型的局限

用同系列的小模型(Llama-3.1-8B 给 70B)起草,不需要任何训练,\(c \approx 8/70 \approx 0.11\)。它的接受率受两个限制:两个模型是独立训练的(同数据但不同容量,分布的差别不只是容量差,还有训练过程的随机性),且后训练阶段(SFT、RLHF)让两者的分布进一步分开——8B-Instruct 与 70B-Instruct 的对话风格可能不同。公开报告的接受率通常 0.6–0.75,加速 1.5–2 倍。用蒸馏微调一下小模型(几千步、几 GPU 小时),接受率可以提高到 0.8 以上。

另一个限制是词表必须相同——概率比 \(p(x)/q(x)\) 要求两者对同一个 token 有定义。跨词表的投机(用 Qwen 给 Llama 起草)需要在字节或字符级别对齐,接受率损失大,实践中很少用。

3. 草稿的容量与成本的平衡

草稿越大接受率越高但 \(c\) 越大。对 \(\text{speedup} = \mathbb{E}[\text{tokens}] / (\gamma c + 1)\) 关于草稿大小求最优,需要 \(\alpha(c)\) 的形状——没有闭式,但经验上:从 \(c = 0.01\) 到 \(0.05\) 接受率提升明显(一层到几层的草稿),从 \(0.05\) 到 \(0.2\) 提升缓慢。这是 Medusa / EAGLE 一类”极小草稿”胜出的原因:它们把 \(c\) 压到 0.02–0.05,同时用目标模型的隐状态把 \(\alpha\) 保持在 0.7–0.8。

四、Medusa 与 EAGLE:草稿看到了什么

1. Medusa:多个头,各猜一个位置

Medusa(Cai 等 2024)在目标模型最后一层的隐状态 \(h_t\) 上接 \(K\) 个轻量头(每个是一层残差 MLP 加一个 lm_head),第 \(k\) 个头预测第 \(t + k + 1\) 个 token:

\[p^{(k)}(x_{t+k+1}) = \text{softmax}\big(W_k \cdot (\text{SiLU}(W'_k h_t) + h_t)\big)\]

一次目标前向同时出所有 \(K\) 个头的预测——草稿成本几乎为零(\(K\) 个 MLP + \(K\) 个 lm_head,lm_head 是 \(d \times V\),是主要开销)。\(K = 3\)–\(5\)。

它的结构性缺陷是各头之间没有条件依赖:第 2 个头预测 \(x_{t+3}\) 时不知道第 1 个头预测的 \(x_{t+2}\) 是什么,它输出的是 \(p(x_{t+3} \mid x_{\le t+1})\)——对 \(x_{t+2}\) 的边缘分布。边缘分布比条件分布平,与目标(条件分布)的 TV 距离大。所以 Medusa 的接受率随头序号快速下降(第 1 头约 0.6–0.7,第 3 头可能只有 0.3–0.4),且各头的 top-1 组合成一条路径的接受长度很短。Medusa 的对策是:每个头取 top-\(s_k\) 个候选,组合成一棵候选树,一次验证多条路径(第五章)——用树的宽度弥补每条路径的短。

训练:Medusa-1 冻结目标模型只训头(自蒸馏:用目标模型自己的输出当标签,几小时);Medusa-2 联合微调目标模型与头(需要小心不伤目标模型的质量,用了两阶段与 lr 分离)。论文报告 Medusa-1 约 2.2 倍、Medusa-2 约 2.3–3.6 倍(Vicuna 7B–33B,greedy 或 typical acceptance)。

2. EAGLE:在特征空间里自回归

EAGLE(Li 等 2024)的两个观察:(1)token 级的自回归不确定性高,特征级的低——下一个 token 是一次采样的结果,随机;而下一个特征(倒数第二层的隐状态,lm_head 之前)是一个连续量,更可预测;(2)但特征也有不确定性,来源是采样——同一个特征 \(f_t\) 经过 lm_head 采样可以得到不同的 \(x_{t+1}\),从而导致不同的 \(f_{t+1}\)。所以草稿要同时看到特征与被采样的 token。

结构:一个单层 decoder(与目标模型同宽),输入是目标模型的特征序列 \(f_{\le t}\) 与 token 的 embedding \(e(x_{\le t+1})\) 拼接后降维(一个 \(2d \to d\) 的线性层),输出预测的特征 \(\hat{f}_{t+1}\);再过目标模型的 lm_head(共享、冻结)得到草稿 token 的分布。草稿的自回归:

\[\hat{f}_{t+1} = \text{Draft}(f_{\le t}, e(x_{\le t+1})), \quad \hat{x}_{t+2} \sim \text{softmax}(W_{lm} \hat{f}_{t+1}), \quad \hat{f}_{t+2} = \text{Draft}(f_{\le t}, \hat{f}_{t+1}, e(x_{\le t+1}), e(\hat{x}_{t+2})), \ \ldots\]

每一步草稿都以前一步的草稿 token 和特征为条件——这是与 Medusa 的本质差别。成本:一层 decoder + 一次 lm_head,对 70B(80 层)来说 \(c \approx 1/80 +\) lm_head \(\approx 0.02\)–\(0.03\);对 7B(32 层)\(c \approx 0.04\)–\(0.05\)。

训练目标是两项:特征回归(预测特征与真实特征的 smooth L1)+ token 分类(预测的 token 分布与目标分布的交叉熵):

\[\mathcal{L} = \mathcal{L}_{reg}(\hat{f}_{t+1}, f_{t+1}) + w_{cls} \cdot \text{CE}\big(\text{softmax}(W_{lm} \hat{f}_{t+1}), \text{softmax}(W_{lm} f_{t+1})\big)\]

\(w_{cls} = 0.1\)。数据是 ShareGPT 一类的对话数据经目标模型前向得到的特征(不需要目标模型生成——但 EAGLE 也发现用目标模型生成的文本效果更好,与第三章的 on-policy 结论一致)。训练一个 EAGLE 头对 70B 目标约 1–2 天单机 8 卡,比 Medusa 贵但远低于任何目标模型的训练。

论文报告:LLaMA2-Chat 70B 上 greedy 约 3.0 倍、\(T = 1\) 约 2.5 倍,接受长度约 3.8–4.5(树,验证 26 个 token)。

3. EAGLE-2:动态草稿树

EAGLE 用固定形状的树(每层的分支数预先定好)。EAGLE-2(Li 等 2024b)的观察:接受率不只依赖位置,还强烈依赖上下文——某些位置模型很确定(接受率 0.95),某些位置很不确定(0.3)。固定的树在确定的位置浪费了分支、在不确定的位置分支不够。

动态树:草稿模型自己的置信度(草稿分布的概率)是接受率的良好近似(论文验证了相关性);按每条路径上草稿概率的乘积(近似这条路径全部被接受的概率)对候选节点排序,保留全局 top-\(N\) 个节点构成树。这样确定的位置只留一两个分支、不确定的位置留很多。同样验证 60 个 token,EAGLE-2 的接受长度比 EAGLE 高 20–40%,加速比提升到 3.0–4.3 倍。

4. EAGLE-3:多层特征与训练时测试

EAGLE-3(Li 等 2025)改了两处。放弃特征回归:EAGLE-1/2 让草稿预测目标的倒数第二层特征、并施加回归损失,这限制了草稿——它被迫模仿一个特定的中间表示而不是直接优化 token 预测;EAGLE-3 去掉回归损失,只用 token 分类损失,让草稿的中间表示自由。多层特征融合:输入不再只是倒数第二层,而是目标模型低、中、高三层的特征拼接(\(3d \to d\)),提供更丰富的信息。

去掉特征回归带来一个新问题:草稿在第 2 步之后的输入是自己上一步的隐状态,而不是”目标的特征”,训练时如果只用目标特征训一步,推理时多步自回归会有分布偏移。EAGLE-3 的解法是训练时测试(training-time test):训练时就模拟多步自回归,把草稿自己的输出喂回去,让它学会在自己的错误上继续。这与 L5 讲的 on-policy / 暴露偏差是同一个问题的又一个实例。

结果:LLaMA-3.1 8B / 70B 上接受长度 5–6.5(树),加速 3.5–6.5 倍(greedy),比 EAGLE-2 再高 20–40%。它也表明了一个 scaling 现象:EAGLE-1/2 的接受率不随训练数据增加而提高(特征回归的约束),EAGLE-3 的会。

5. 三者对照

  Medusa EAGLE-1 EAGLE-2 EAGLE-3
草稿输入 最后层隐状态 \(h_t\) 倒数第二层特征 + token embedding 同 EAGLE-1 低中高三层特征 + token embedding
草稿结构 \(K\) 个独立 MLP 头 一层 decoder,特征级自回归 一层 decoder,无回归约束
条件依赖 无(各头独立)
固定 固定 动态(按草稿置信度) 动态
训练目标 各头的 CE(自蒸馏) 特征 smooth L1 + token CE 只 token CE + 训练时测试
\(c\)(70B) ~0.02 ~0.02–0.03 ~0.03
接受长度(报告) 2.5–3 3.8–4.5 4.5–5.5 5–6.5
加速(报告,greedy) 2.2–2.8× 2.7–3.5× 3.0–4.3× 3.5–6.5×
训练成本(70B) 数小时 1–2 天 × 8 卡 同或略多

数字来自各论文(Vicuna / LLaMA2 / LLaMA3 系列、A100 或 H100、batch 1),不同论文的基线不同,跨列比较只看趋势。

回答核心问题的前半:Medusa 与 EAGLE 的草稿成本相近(都是极小的模块),接受率的差别来自条件依赖(EAGLE 的每个草稿 token 以前面的草稿为条件,Medusa 的头预测的是边缘分布)与输入信息(特征比 token 携带更多关于目标模型”想什么”的信息)。EAGLE-2 与 3 进一步用动态树与更自由的训练目标提高接受长度。

五、树状草稿的验证

1. 为什么要树

一条草稿链的期望接受长度受限于接受率的递减(第二章)。树用宽度换深度:第 1 层给 \(s_1\) 个候选,每个候选下面再给 \(s_2\) 个,……一次验证覆盖多条路径,只要其中一条被接受得长,这一轮就产出多。验证成本是树的节点总数 \(N_{tree}\)(Medusa 默认 64、EAGLE 约 26、EAGLE-2/3 约 60),在 memory-bound 区间内验证 \(N_{tree}\) 个 token 与验证 1 个几乎同价——但 \(B \cdot N_{tree} \lesssim \text{ridge}\) 的约束更紧了:batch 1 时 60 个节点没问题,batch 8 时 480 个节点已经接近 H100 的 ridge。树在 batch 1 上最有效,batch 增大时要缩小树。

2. tree attention 的 mask

把树的所有节点展平成一个序列送进目标模型做一次前向,但 attention mask 不是因果下三角——每个节点只能看到它在树上的祖先(加上共同的前缀)。这是一个稀疏的、由树结构决定的 mask:节点 \(i\) 与节点 \(j\) 之间的 mask 为 1 当且仅当 \(j\) 是 \(i\) 的祖先。位置编码也按树的深度赋值(同一层的兄弟节点位置相同)。一次前向后,每个节点的输出就是目标模型在”以该节点的祖先路径为前缀”条件下的分布——正是验证需要的。

实现上,tree attention 要求 attention kernel 支持任意 mask(FlashAttention 的标准 kernel 只支持因果 / 滑窗;需要 FlexAttention 一类或专门的 kernel),KV cache 要能存树的分支再按接受结果回收——这是引擎侧的复杂度(vLLM 的 EAGLE 支持经过了多次重写),也是很多系统长期只支持链式草稿的原因。

3. 多路径的接受规则

树上的验证从根开始,按拒绝采样逐层进行:在第 1 层,草稿给了 \(s_1\) 个候选 \(x^{(1)}, \ldots, x^{(s_1)}\),它们来自同一个草稿分布 \(q_1\)。多个候选的拒绝采样(Miao 等 2024 的 SpecInfer;Sun 等 2024 的 SpecTr 给了更优的形式):依次对每个候选做接受判定,接受概率 \(\min(1, p(x^{(j)}) / q(x^{(j)}))\),但每拒绝一个,就从 \(p\) 中减去该候选的 \(q\) 质量再归一化(因为”已经知道 \(x^{(j)}\) 被拒了”改变了剩余的分布);全部拒绝则从残差分布采样。这套规则保证输出仍严格等于 \(p\)。接受了第 1 层的某个节点后,进入它的子树继续。

期望接受长度在树上没有简单闭式,但有一个直觉:如果第 1 层的 \(s_1\) 个候选是草稿分布的 top-\(s_1\),它们的 \(q\) 质量之和 \(Q_1 = \sum_{j \le s_1} q(x^{(j)})\) 通常远大于单个 \(q(x^{(1)})\),第 1 层”至少接受一个”的概率约为 \(\sum_{j} \min(p(x^{(j)}), q(x^{(j)}))\),接近 \(\min(P_1, Q_1)\)——比链式的 \(\alpha\) 高。EAGLE 报告的链式接受长度约 3.0、树式约 3.8–4.5,是这个效应的量级。

4. 树的形状

固定树的形状是一个超参数(Medusa 用了搜索得到的稀疏树:第 1 层 10 个、第 2 层每个下面 5 个……总 64);动态树由草稿置信度决定(EAGLE-2)。原则是同一个:把验证预算分配到接受概率高的路径上。一个有用的度量是”每验证 token 的期望接受”——树增大时它递减,与 ridge 约束一起决定最优大小。

六、MTP 作为草稿

1. 一个模块的两种身份

04 系列第十二篇讲了 MTP(multi-token prediction)作为训练目标:在主模型之外加一个模块预测第 \(t + 2\) 个 token,训练时的辅助损失让主模型的表示”看得更远”,提高数据效率。DeepSeek-V3 的 MTP 模块是一个完整的 Transformer 层(带自己的 embedding 输入拼接与 RMSNorm,共享主模型的 embedding 与 lm_head),串行地以主模型的最终隐状态和下一个 token 的 embedding 为输入——这正是 EAGLE 的结构

所以推理时它天然是一个草稿:主模型出 \(x_{t+1}\) 的分布与隐状态,MTP 模块接过隐状态与采样的 \(x_{t+1}\),出 \(x_{t+2}\) 的草稿。\(\gamma = 1\)(DeepSeek-V3 只训了一个 MTP 深度)。技术报告称第二个 token 的接受率在 85–90%,对应 \(\mathbb{E}[\text{tokens}] \approx 1.85\)–\(1.9\),解码吞吐提升约 1.8 倍。

2. 与 EAGLE 的比较

MTP 的接受率高于 EAGLE 的第 1 个草稿(0.85–0.9 vs 约 0.8),因为它是与主模型联合训练的——主模型的表示为了 MTP 的损失而调整过,两者的分布更接近;而 EAGLE 是事后在冻结的目标上训的。代价是 MTP 需要在预训练时就决定并付出训练成本(DeepSeek-V3 的 MTP 模块约占一层的参数,训练开销几个百分点),且深度固定(\(\gamma = 1\),除非训多个 MTP 模块或让它自回归——后者是 EAGLE 的做法,DeepSeek 没有报告)。

2025 年的趋势是在预训练时就为投机解码准备草稿:MTP 头兼作训练目标与草稿(DeepSeek-V3、GLM-4.5、MiMo),或发布时附带训好的 EAGLE 头。这是”算法工程师在训练阶段就设计部署”的一个具体实例。

七、免费的草稿

1. n-gram / prompt lookup

在上下文里查找当前最后 \(n\) 个 token 上次出现的位置,把它后面的 \(\gamma\) 个 token 当草稿(Saxena 2023 的 prompt lookup decoding;vLLM 的 ngram 草稿)。零训练、零模型、\(c \approx 0\)。接受率完全取决于任务:改写、摘要、RAG(答案大量复制原文)、代码编辑(大量复制原代码)上 \(\alpha\) 可以到 0.7 以上,加速 2–3 倍;自由生成上接近 0,只剩验证的开销(幸好很小)。

它与 EAGLE 可以组合:先查 n-gram,查到就用,查不到用 EAGLE。也可以用 n-gram 作为 EAGLE 树的一部分候选。

2. 自投机:跳层

让目标模型自己的前几层(或跳过一部分中间层)作为草稿(Draft & Verify、LayerSkip)。不需要额外参数,但需要目标模型在”跳层”模式下仍能输出合理的 token——LayerSkip 通过训练时的 early exit 损失做到;对没有这样训过的模型,跳层的输出质量太差,接受率低。\(c\) 约等于跳过后剩余层的比例(0.3–0.5),比 EAGLE 高得多,实践中不如 EAGLE。

3. 何时免费的够用

如果负载有大量复制(RAG、编辑、结构化输出),n-gram 是第一选择——没有任何训练与部署成本。否则需要一个训过的草稿。

八、何时投机反而变慢

1. 大 batch

04-07 的结论:\(B(\gamma + 1) \gtrsim \text{ridge}\) 时验证进入 compute-bound,加速比下降甚至低于 1。树把 \(\gamma + 1\) 换成 \(N_{tree}\),约束更紧。对高吞吐、大 batch 的服务负载,投机解码要么关掉,要么缩小到 \(\gamma = 1\)–\(2\) 的链式草稿。这是投机解码在延迟优化(batch 小、单请求快)上有用、在吞吐优化(batch 大、总 token/s 高)上用处有限的原因——两个目标用不同的工具。

一个折中:动态投机——按当前 batch 大小调整 \(\gamma\) 或关闭投机(vLLM 的 speculative_disable_by_batch_size)。

2. 短输出

每轮投机有固定开销(草稿、树构建、接受判定、KV 回退),输出只有几十个 token 时(分类、短答案),这些开销的比例大。且短输出上 prefill 占主导,投机对 prefill 无效。

3. 长上下文的验证

验证 \(N_{tree}\) 个 token 的 attention 要读整个 KV cache \(N_{tree}\) 次(每个节点一次)——在长上下文下 KV 读取是 decode 的主要流量(04 系列第三篇),验证的 attention 成本不再”几乎免费”。128K 上下文、\(N_{tree} = 60\) 时,验证的 KV 读取是普通 decode 的 60 倍——除非 attention kernel 对树内节点共享 KV 读取(可以,因为它们读的是同一份前缀 KV,MagicDec 等工作正是利用这点,但需要专门的 kernel)。

4. 草稿与目标不匹配

草稿在目标模型的训练分布上训练,部署在另一个领域(草稿训在对话数据上,用户发来的是代码),接受率下降。EAGLE 论文的跨领域实验显示接受长度下降 10–20%。对领域明确的部署,用领域数据训草稿。

5. 一张选型表

负载 推荐草稿 预期 备注
单用户 / 低延迟、通用对话 EAGLE-3 或模型自带 MTP 3–5× batch 1–4
有大量复制(RAG、编辑、摘要) n-gram,或 n-gram + EAGLE 2–3× 免费 零成本先试
推理模型、长输出 EAGLE-3(\(T = 0.6\) 接受率略降) 2.5–4× 注意长上下文验证成本
高吞吐、大 batch 服务 关闭,或 \(\gamma = 1\) 链式(MTP) 1.0–1.5× 收益小,可能为负
没有训练资源 同系列小模型 1.5–2× 蒸馏几千步可到 2× 以上
模型带 MTP 头 直接用 ~1.8×(\(\gamma = 1\)) 零额外训练

九、草稿的评测

投机解码不改变分布,所以不需要评任务准确率(除非用了宽松验证)。要评的是效率与正确性:

  • 接受长度(每轮平均产出的 token 数)与按位置的接受率:前者是效率的直接度量,后者告诉你 \(\gamma\) 该多大。在目标负载的真实 prompt 上测,不要只在训练分布上测。
  • 每 token 延迟吞吐随 batch 的曲线:找到收益消失的 batch。
  • 分布一致性检验:在同一组 prompt 上,投机与非投机各采样几千次,比较 token 频率分布(或用 KS 检验)——应当统计上无差别。差别意味着实现有 bug(最常见:草稿与目标的采样参数不一致、KV 回退错误、树 mask 错误)。greedy 下更简单:输出应逐 token 相同。
  • 草稿自身的成本:真实的 \(c\)——在目标硬件上测草稿一步的时间,而不是按参数比例估算;lm_head 在小草稿里占比很大,128K 词表的 lm_head 对一层 decoder 的草稿来说不是可忽略的。

十、动手(建议)

vLLM 支持 n-gram 与 EAGLE 两种草稿,社区有 Llama-3.1-8B-Instruct 的 EAGLE / EAGLE-3 头可以直接下载。在一张 24 GB 的卡上:

  • 目标:Llama-3.1-8B-Instruct,BF16。
  • 两类任务:(a)改写 / 摘要——给一段 500 词的文本要求改写;(b)自由生成——开放式问答。各 200 条 prompt。
  • 三种配置:无投机、ngramnum_speculative_tokens=5)、EAGLE-3 头(num_speculative_tokens=5,链式;若引擎版本支持树则再试树)。
  • batch ∈ {1, 4, 16, 64}。
  • 记录:每轮接受长度(vLLM 的 spec_decode 指标)、每 token 延迟、吞吐;greedy 下核对三种配置的输出逐 token 一致。

该看的:(a)任务上 n-gram 的接受长度是否接近 EAGLE;(b)任务上 n-gram 是否接近 1(无收益);EAGLE 的接受长度随 batch 是否不变而加速比随 batch 下降——把加速比降到 1 的 batch 与 04-07 的 \(\text{ridge}/(\gamma+1)\) 估算对照;\(T = 0.6\) 与 greedy 下 EAGLE 接受长度的差。

不引用任何未跑过的数字。EAGLE-3 论文报告的 8B 接受长度约 5–6 是在 batch 1、特定数据集上的,你的负载上大概率更低。

十一、本文小结

规则 / 公式 备注
接受率 \(\alpha = 1 - \text{TV}(p, q)\) 分布的重叠,不是 argmax 准确率;随位置递减;greedy 下最高
训练目标 最小化 KL\((p | q)\) = 前向 KL 蒸馏;on-policy 数据 DistillSpec:+10–45% 接受率;草稿匹配目标不是匹配数据
Medusa \(K\) 个独立头,边缘分布,固定树 64 节点 \(c \approx 0.02\);接受长度 2.5–3;数小时训练
EAGLE 特征级自回归(特征 + token embedding),一层 decoder 条件依赖 + 特征信息 → 接受长度 3.8–4.5
EAGLE-2 / 3 动态树按草稿置信度;去掉特征回归 + 多层特征 + 训练时测试 接受长度 5–6.5;3.5–6.5×
树验证 tree attention mask(只看祖先);多候选拒绝采样保持分布 需要任意 mask 的 kernel;\(B \cdot N_{tree} \lesssim \text{ridge}\)
MTP 训练目标兼草稿,联合训练 → 接受率 85–90% \(\gamma = 1\),约 1.8×;预训练时决定
免费草稿 n-gram:复制类任务 2–3×,自由生成 ≈ 0 零成本先试
变慢 大 batch;短输出;长上下文验证的 KV 读取;领域不匹配 延迟优化的工具,不是吞吐优化的
评测 接受长度、按位置接受率、延迟—batch 曲线、分布一致性 greedy 下输出应逐 token 相同

核心问题的答案:Medusa 与 EAGLE 的草稿都是目标模型上的一个极小模块,成本相近;接受率差在两处——EAGLE 的草稿是自回归的,每个草稿 token 以前面的草稿为条件,预测的是条件分布,而 Medusa 的各头相互独立,预测的是边缘分布,边缘分布天然更平、与目标的重叠更小;EAGLE 的输入是目标模型的特征(连续、信息丰富)加上被采样的 token(补上采样的随机性),Medusa 只有最后层的隐状态。EAGLE-2 用草稿置信度动态分配树的分支,EAGLE-3 去掉特征回归的约束并用训练时测试修暴露偏差,把接受长度推到 5–6。一个 70B 模型的草稿:如果它自带 MTP 头就直接用(约 1.8 倍,零成本);否则训一个 EAGLE-3 头(1–2 天 8 卡,3 倍以上);负载有大量复制就先试 n-gram;大 batch 的吞吐服务上投机的收益有限,考虑关掉。

下一篇进入会改变分布的方法:训练后量化——从量化误差的统计模型出发,讲清楚为什么 RTN 到 4 bit 就不够、GPTQ 与 AWQ 各在最小化什么、旋转怎么让 W4A4 成为可能。

下一篇

训练后量化:误差模型、GPTQ、AWQ 与旋转

本文由 arganzheng 创作,采用 CC BY 4.0 许可协议。在保留原文作者、署名以及完整原文链接(https://arganzheng.life/speculative-decoding-drafters-acceptance-and-trees.html)的前提下,欢迎各种形式的转载、翻译或商业引用。


COMMENTS

评论存放在 GitHub Discussions, 用 GitHub 账号登录即可发表,支持 Markdown。 想针对正文某句话说?选中那段文字,点浮出的「评论」即可划线评论;觉得哪里写错了,发表时勾上「同时提交 Issue」。 有人回复你时 GitHub 会按你的通知设置发邮件,不用守在这里。

×