返回博客

投机解码为何能保持分布,却未必加速?

从接受概率、残差校正与三 token 例子出发,推导连续接受长度如何转换为每输出 token 的时间,并检查 KV 缓存、掩码、采样配置与服务评估的边界。

投机解码最吸引人的承诺,是让大模型少跑几轮,同时保留原来的生成分布。但“分布相同”和“时间更短”来自两套不同的条件:前者依赖概率质量的精确补偿,后者依赖硬件是否能把多位置验证做得足够便宜。本文围绕经典线性草稿算法,逐步检查这两笔账。

这里讨论的是已有基础方法:Leviathan 等的论文首版发布于 2022 年 11 月 30 日,后发表于 ICML 2023;Chen 等的论文首版发布于 2023 年 2 月 2 日。本文阅读前者 v2 与后者 v1,并以 EAGLE-3 的 2025 年工作连接后续设计,不把旧论文当成新发布。

1. 先说清楚“保留谁的分布”

固定已提交的前缀 \(h\),令 \(p(x\mid h)\) 为目标分布,\(q(x\mid h)\) 为实际草稿提议分布,两者使用同一 token 空间。下文省略条件 \(h\)。它们必须已经完成温度、top-p、top-k 或其他处理并重新归一化;不能用处理前的 softmax 概率核验从处理后分布抽出的 token。目标和草稿的参数不必相同,但记录的 \(q\) 必须对应真正执行的采样。

“精确”首先是理想算术下相对于指定 \(p\) 的结论。把目标模型量化之后,保留的是量化目标实际定义的分布,并不自动等于原精度模型。Chen 等讨论了硬件数值与随机种子的边界:两种算法消耗随机数的路径不同,同一 seed 不保证逐字一致。Greedy 则另行约定为目标 argmax 的点质量分布,固定并列值的处理规则;此时接受匹配目标选择的草稿,遇到不匹配即替换。不能把任意“相似就接受”的策略也称为精确保真。

2. 拒绝以后,为什么不能直接再抽一次目标模型

从 \(q\) 抽取候选 \(x\),仅对 \(q(x)>0\) 的候选定义接受概率:

\[a(x)=\min\!\left(1,\frac{p(x)}{q(x)}\right).\]

固定前缀的总接受概率为 \(\alpha\)。把每个 token 已经获准输出的质量相加,得到:

\[\begin{aligned} \alpha&=\sum_x q(x)a(x)=\sum_x\min\!\bigl(p(x),q(x)\bigr)\\ &=1-\operatorname{TV}(p,q),\qquad \operatorname{TV}(p,q)=\frac12\sum_x|p(x)-q(x)|. \end{aligned}\]

因此,接受率衡量的是两种分布在这个前缀上的重叠,而非草稿模型的一般知识水平。拒绝事件发生后,应补上目标尚未得到的质量,而不是重新支付一份完整的 \(p\):

\[r(x)=\frac{(p(x)-q(x))_+}{1-\alpha},\qquad (u)_+=\max(u,0),\quad \alpha\lt1.\]

这就是原算法的残差校正。输出 token \(X\) 的两条路径恰好相加:

\[\begin{aligned} \Pr(X=x) &=\min\!\bigl(p(x),q(x)\bigr)+(1-\alpha)r(x)\\ &=\min\!\bigl(p(x),q(x)\bigr)+(p(x)-q(x))_+=p(x). \end{aligned}\]

若 \(\alpha=1\),拒绝不会发生,不应计算零分母;若 \(q(x)=0\) 而 \(p(x)>0\),该 token 仍可经残差产生。实现需要完整残差分布,不能只保存所抽中 token 的一个概率,再假设已经具备纠偏所需的信息。

3. 用三个 token 看见补偿流向

构造词表中的三个符号 \(\mathrm{A},\mathrm{B},\mathrm{C}\),设 \(p=(0.5,0.3,0.2)\)、\(q=(0.2,0.2,0.6)\)。这是说明算法的人工例子,不是语言模型测量。

token\(p(x)\)\(q(x)\)\(a(x)\)直接接受的质量拒绝后补入的质量
A0.50.210.20.3
B0.30.210.20.1
C0.20.6\(\tfrac{1}{3}\)0.20

三种符号各贡献 0.2 的接受质量,所以 \(\alpha=0.6\),拒绝概率为 0.4;残差为 \(r=(0.75,0.25,0)\)。把拒绝质量按此比例补回,最终正好是 \(p\)。如果改成“拒绝后从 \(p\) 重抽”,输出会变为 \((0.4,0.32,0.28)\):草稿高估的 C 又被补了一次。问题并非抽样次数不够,而是校正分布本身错误。

原创流程图:顺序草拟、因果验证、连续接受,以及首次拒绝时的残差采样或全部接受后的奖励采样,最后裁剪目标 KV 缓存。
原创分析示意,非实验数据。概率补偿解释输出分布;草稿、验证和维护时间解释实际速度,两者需要分别验收。

4. 一轮产出看连续接受,不能只看平均通过率

每轮顺序草拟 \(\gamma\) 个 token,再由目标模型并行计算各位置条件分布。从左到右验证,到首个拒绝即丢弃后缀,并从该位置残差抽一个替换 token;全通过则额外从目标分布抽一个奖励 token。令 \(A\) 为连续接受的草稿数,\(K\) 为本轮提交数。忽略 EOS 与长度上限截断时,尾和恒等式给出:

\[K=A+1,\qquad \mathbb{E}[K]=1+\sum_{i=1}^{\gamma}\Pr(A\ge i).\]

这不要求各位置独立。若额外假设接受事件独立且每步概率均为 \(\alpha\),才得到经典近似:

\[\mathbb{E}[K]\approx1+\sum_{i=1}^{\gamma}\alpha^i =\frac{1-\alpha^{\gamma+1}}{1-\alpha},\qquad \alpha\lt1.\]

当 \(\alpha=1\) 时结果为 \(\gamma+1\)。真实前缀会变化,难点也会连续出现;首位置接受率不能直接代替整条生存曲线 \(\Pr(A\ge i)\)。例如在上述独立近似下,\(\alpha=0.6,\gamma=3\) 只带来 \(\mathbb{E}[K]\approx2.176\),而非四个 token。越靠后的候选越容易成为已经付费但未提交的计算。

5. 概率正确,还需要缓存代表同一个前缀

给出一个可审计的实现约定:token 从 1 编号、位置从 0 编号。已有 \(L\ge1\) 个已提交 token,目标 KV 缓存只包含前 \(L-1\) 个,最后的 \(x_L\) 尚待前向处理。把 \([x_L,d_1,\ldots,d_\gamma]\) 一次送入目标模型,行 \(r=0,\ldots,\gamma\) 的绝对位置是 \(L-1+r\),其 logits 预测:

\[p_{r+1}(\,\cdot\mid x_{1:L},d_{1:r}).\]

其中 \(d_{1:0}\) 表示空序列。查询张量每条序列的形状为 \(H_{\mathrm q}\times(\gamma+1)\times d_k\),其中 \(H_{\mathrm q}\) 是查询头数,\(d_k\) 是每头查询/键的维度;新增键值后的逻辑长度为 \(L+\gamma\),KV 头数可以不同于查询头数。键的零基索引为 \(c\),因果掩码必须满足:

\[M_{rc}=\begin{cases} 0,&c\le L-1+r,\\ -\infty,&c>L-1+r. \end{cases}\]

这样每行只能看到合法前缀,不能因为整段输入已经存在就偷看后续草稿。实际内核的查询长度短于 KV 长度时,还须核对因果对齐位置:FlashAttention 文档明确记录了右下对齐与版本行为变化,不能只凭 causal=true 就假定语义正确。若连续接受 \(A\) 个,目标缓存裁到 \(L+A\) 项;新产生的残差或奖励 token \(y\) 尚未进入缓存,恰好恢复“新序列长度减一”的不变量。按此约定不需要额外的目标补算:

# One linear draft round; no EOS or length truncation shown.
# verify uses the absolute positions and causal mask defined above.
draft, q = propose(h, gamma)      # q stores actual proposal distributions
p, target_kv = verify([h[-1]] + draft, target_kv)
A = 0
for i in range(gamma):
    x = draft[i]
    if uniform_0_1() < min(1, p[i][x] / q[i][x]):
        A += 1
    else:
        break
if A < gamma:
    y = sample(normalize(positive_part(p[A] - q[A])))
else:
    y = sample(p[gamma])
h = h + draft[:A] + [y]
target_kv.crop(len(h) - 1)
draft_kv = synchronize_draft_cache(h, draft_kv)

草稿缓存不能照抄目标缓存的裁剪逻辑:顺序采样得到的最后一个草稿往往还没有进入草稿 KV,需按实际有效前缀补齐,成本计入草拟阶段。裁剪可更新逻辑长度或页表,避免复制整个长缓存;关键是被拒绝 token 后续不可见,绝对位置不被错误重置。

并行验证也没有消除算术。令 \(m=\gamma+1\),模型共有 \(N_\ell\) 层,KV 头数为 \(H_{\mathrm{kv}}\),并假设值向量维度也为 \(d_k\)。对单条序列的标准密集注意力,每层注意力乘加量级为 \(O(H_{\mathrm q}m(L+\gamma)d_k)\);它不包含 QKV/输出投影、MLP 或词表投影,不能当作总 FLOPs。目标 KV 在验证时需容纳 \(2N_\ell H_{\mathrm{kv}}(L+\gamma)d_k\) 个元素,包含临时草稿;转换为字节还要乘每元素的存储大小。权重、激活及草稿模型的缓存另计。若朴素保留各位置完整的目标和提议概率,词表 \(\mathcal V\) 还带来 \(O((\gamma+1)|\mathcal V|)\) 个概率缓冲元素;可按需重算,但必须计入成本。这解释了为何节省轮次并不等于按同一比例节省计算或显存。

6. 把省下的轮次换成时间,需要另一条不等式

Chen 等的硬件分析解释了一个机会:小批量解码可能受权重读取、KV 访问与通信延迟限制,短块验证能利用尚未饱和的计算资源。但这不是“验证任意长草稿都免费”的保证。草稿仍可能串行运行;长上下文、大批量或额外模型的显存占用,都可能改变瓶颈。

令 \(T_{\mathrm d}\)、\(T_{\mathrm v}\)、\(T_{\mathrm b}\) 分别为每轮草稿及其同步、目标验证、其余采样与维护的耗时,避免重复计费。在不重叠的执行约定下,令 \(C=T_{\mathrm d}+T_{\mathrm v}+T_{\mathrm b}\)。对足够长且工作负载稳定的运行,应比较累计时间与累计提交数:

\[\bar t_{\mathrm{spec}} =\frac{\sum_j C_j}{\sum_j K_j} \approx\frac{\mathbb{E}[T_{\mathrm d}+T_{\mathrm v}+T_{\mathrm b}]}{\mathbb{E}[K]} \lt \bar t_{\mathrm{base}}.\]

单位是时间/token;\(\bar t_{\mathrm{base}}\) 必须来自相同目标、精度、采样配置与工作负载。它不是各轮 \(\tfrac{C_j}{K_j}\) 的简单平均。若计算与通信重叠,应直接测关键路径上的整轮时间,不能把重叠区间相加。

这个账本导出一个可检验的选长准则:把 \(\gamma\) 增加一位,只有新增时间相对于新增提交量足够低才值得。用当前每轮均值 \(\bar C,\bar K\),以及策略改变后的增量 \(\Delta C,\Delta K\),在 \(\Delta K>0\) 时有:

\[\frac{\bar C+\Delta C}{\bar K+\Delta K}\lt\frac{\bar C}{\bar K} \quad\Longleftrightarrow\quad \frac{\Delta C}{\Delta K}\lt\frac{\bar C}{\bar K}.\]

令 \(A^{(\gamma+1)}\) 表示延长至 \(\gamma+1\) 个候选后的连续接受数。仅在相同起始前缀或相同起始前缀分布下,且前 \(\gamma\) 步提议与接受的联合规律不变时,才有 \(\Delta K=\Pr(A^{(\gamma+1)}\ge\gamma+1)\)。一般应实测两种策略的均值增量。因此最优草稿长度是服务状态的一部分,而不是只由模型名称决定的常数。

7. 更好的草稿,究竟改善了哪一项

EAGLE-3(首版 2025 年 3 月 3 日,本文阅读 v3)取消对目标顶层特征的直接拟合约束,融合不同层的特征,并在训练中模拟后续草拟时使用自身输出的情形。这提示一种设计方向:减少多步提议的失配,改善连续接受,而非只提高第一步命中。

但训练得更强不等于部署必然更快。多一层草稿计算、特征搬运或更大的候选树,也可能提高分子中的成本。官方实现区分模型检查点与草稿树设置;公平比较需要一起记录。EAGLE-3 使用动态树草稿,本文的线性链计数与缓存伪代码不能直接当作其树验证实现。分支可见性、提议概率与残差处理都必须按实际算法另查,不能凭“也用了投机”便自动套用证明。

8. 怎样证明系统真的更好,而不是指标换了分母

本文没有运行 LLM GPU 延迟实验,也没有复现论文的加速倍数。配套小检验已使用有理数精确计算三 token 例子,并通过 9 个边界例、2048 组分布、64 棵条件树的三 token 输出枚举、45 个抽象缓存/掩码案例及 28 个独立假设下的长度公式案例。负对照能检出“greedy 提议却使用原 softmax 概率核验”的错误。可下载仅依赖 Python 标准库的概率与缓存约定检验脚本。缓存测试只验证抽象 token/上下文不变量,没有执行神经注意力、KV 内核或 GPU,也不验证物理分页缓存与浮点行为。可执行的系统评估应分两层:

  • 先检验正确性。在小词表枚举接受和残差路径,再做多次抽样比较频率;固定前缀,把批量验证每行 logits 与逐 token 基线对齐,说明数值容差。强制首拒、中拒、全通过,并比较回滚后缓存与完整重算结果;另测 EOS、长度上限及 top-p 支持集变化。同 seed 的单条文本相同并不是随机采样的必要验收条件。
  • 再检验服务表现。固定目标检查点、tokenizer、精度、硬件、总显存预算和请求集;在单请求与多并发、短长上下文、不同输出长度下扫描草稿长度。记录生存曲线、实际提交 token 数、整轮分项耗时、峰值显存,以及满足相同服务约束时的吞吐。

用于选择草稿长度的调参请求应与最终测试请求分开,并保留语言、代码及不同难度的分层结果。对随机生成,使用相同提示分布和最大输出预算,按实际提交数量报告成本;不能把未提交的草稿计为输出吞吐。EOS 导致的真实长度差异也应公开,不能靠缩短答案制造加速。

Prefill 处理输入前缀,decode 逐步生成新 token;只优化 decode,不能按相同比例推断首 token 延迟。应同时报告首 token 延迟、端到端请求时延、平均每输出 token 耗时和流式到达间隔的 p50/p95,并披露排队、预热与批处理策略。一次交付多个 token 可改善均摊成本,却仍可能让用户等待较长的一轮;吞吐增加也不保证 p95 下降。

最终的反证很直接:若概率检验不通过,速度没有可比的质量前提;若接受长度提升而相同约束下的时间/token 或 p95 变差,草稿优化就尚未转化为服务收益。投机解码的价值,在于同时守住分布约定和执行预算。

参考资料

  1. Fast Inference from Transformers via Speculative Decoding — arXiv v2 (first posted 2022-11-30) · 2023-05-18 · 查阅 2026-10-06
  2. Fast Inference from Transformers via Speculative Decoding — ICML 2023, PMLR 202:19274–19286 · 2023-07 · 查阅 2026-10-06
  3. Accelerating Large Language Model Decoding with Speculative Sampling — arXiv v1 · 2023-02-02 · 查阅 2026-10-06
  4. EAGLE-3: Scaling up Inference Acceleration of Large Language Models via Training-Time Test — arXiv v3 (first posted 2025-03-03) · 2025-04-23 · 查阅 2026-10-06
  5. SafeAILab/EAGLE — Official implementation and checkpoint/evaluation guidance · 查阅 2026-10-06
  6. FlashAttention README — KV-cache interface and causal alignment (commit 47e91f1f7dd8a22649cee0dd9a182b69ffe782ef) · 查阅 2026-10-06
利友诚

关于作者

利友诚 · Youcheng Li

北京大学智能学院人工智能专业博士研究生,导师为王立威教授;Isoplex Intelligence(壹索智能)联合创始人兼 CTO。

研究关注医疗人工智能、生成式基础模型、诊断推理与科学智能体。以第一作者或共同第一作者身份在 Nature Biomedical Engineering、Scientific Data、KDD 和 PLOS Computational Biology 发表研究。