Transformer 解剖:从 Attention 到推理系统
第 17 章 投机解码:用小模型加速大模型
第 14 章我们看到 Decode 阶段是 memory-bound——GPU 算力大量空闲、HBM 带宽是瓶颈。第 16 章用量化把权重压缩,HBM 读取量减半减四倍。但还有一种更聪明的思路——既然 GPU 算力空闲,能不能一次多算几个 token?
听起来像作弊:自回归生成不是必须一个 token 一个 token 来吗?答案是:借助一个聪明的「投机」机制,可以——这就是 投机解码(Speculative Decoding)。
它的核心想法用一个生活化比喻就讲完:你想读一本书,你可以一字一字读(Decode 模式);也可以让一个朋友先快速浏览、把他猜测的内容讲给你听,你只在「不对的地方」打断纠正。如果朋友猜得大多对,你听几句就能掌握一大段——这就是投机解码用小模型「先猜、大模型『后验』」的本质。
读完这章你能:
- 解释投机解码为什么能在 memory-bound 场景下提速;
- 推导它的拒绝采样数学,证明它输出分布与原模型完全一致;
- 对比 Medusa、EAGLE、Lookahead 等不同 draft 机制的取舍;
- 估算给定模型对的加速倍数;
- 在 vLLM 里启用投机解码并选择参数。
17.1 一个直觉:Decode 的算力是浪费的
回顾第 14 章。Llama-3 70B(BF16,140 GB 权重)Decode 一个 token 的下界(单卡等效口径,见第 14 章):
- HBM 读取:140 GB / 3.35 TB/s ≈ 42 ms
- 实际算力消耗:极少(一个 token 的 forward 算量很小)
- GPU MFU(推理 Decode 口径,batch=1):只有峰值的千分之几(第 14 章 roofline:算术强度约 1 FLOP/byte,远低于 H100 约 295 FLOP/byte 的拐点)
也就是说每次 Decode 时 GPU 算力绝大部分闲着——它在等 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 的,但它远小(比如 8B,权重 16 GB)——按同样的带宽下界,一个 token 约 16 GB / 3.35 TB/s ≈ 5 ms(远快于 70B 的 42 ms),生成 4 个约 20 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(接受 2 个 draft + 大模型补 1 个)
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(接受的 draft 或拒绝后重采样的 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,而是一种纯粹的工程加速。输出分布与原模型完全相同(贪心解码时则逐 token 与原模型的 argmax 一致)。vLLM 的配置里接受规则是一个可选项、缺省就是拒绝采样:vllm-0.8.5/vllm/config.py:2164 的 acceptance_method 缺省值是 "rejection_sampler"(另一档 typical_acceptance_sampler 不保证分布一致)。不过这个字段只有 V0 的 vllm-0.8.5/vllm/spec_decode/spec_decode_worker.py 读取,V1 固定使用 vllm-0.8.5/vllm/v1/sample/rejection_sampler.py 里的拒绝采样。
17.4 接受率:决定加速比的核心变量
这里必须把两个容易混为一谈的量分开:
- :单 token 接受率——一个 draft token 被接受的概率
- :每轮平均接受数——一轮 K 个 draft 里期望被接受几个
(17.3 里的接受概率随上下文变化;这里的 是它的期望,Leviathan 等人论文里记为 。拒绝采样下单步接受率等于 ,即两个分布的重合度。)
只要各位置的接受相互独立同分布、且一旦拒绝后面全丢,一轮能产出的 token 数(含大模型补的那 1 个)就是个截断几何分布,期望为(Leviathan et al. 式 (1)):
加速比就是「每轮产出」除以「每轮成本」(Leviathan et al. 定理 3.8,原文记 K 为 ):
其中 是 draft 单步时间相对大模型 verify 时间的比例。
直观理解:
- 每轮投机的成本 = draft 生成 K 个 + 大模型 verify 一次 ≈ (以大模型一步为单位)
- 每轮产出 = 个 token(最少 1 个:第一个就被拒时用大模型重采样的 token;最多 K+1:全接受时再加大模型多给的 1 个 bonus token)
举个具体数字(,K=4,draft 单步耗时是大模型的 1/10,c=0.1):
接受率更高、draft 占比更小时更好看:
- =0.9, K=4, c=0.05:E=4.10,Speedup ≈ 3.4×
- =0.9, K=8, c=0.03:E=6.13,Speedup ≈ 4.9×
一个必须记住的硬上界
注意 时 :
无论草稿多长、draft 多便宜,加速比都被单 token 接受率死死卡住。 时天花板是 5×, 时是 10×。这解释了为什么各家论文都在拼命抬接受率(EAGLE 的特征层 draft、树状候选),而不是一味加大 K——K 加大只会让你更快地贴近这条上界,同时把 那项的浪费做大。
17.5 主流投机解码方法
1. 经典 Speculative Decoding(two-model)
最早的版本(Leviathan 2023, Chen 2023):用一个小模型作为 draft model。两篇论文分别报告 T5-XXL 上 2-3×、Chinchilla 70B 上 2-2.5× 的加速。
典型选择:
| 大模型 | draft 模型 | 比例 |
|---|---|---|
| Llama-2 70B | Llama-2 7B | 10× |
| Llama-3 70B | Llama-3 8B | 9× |
要求:draft 模型必须和大模型用同一个 tokenizer——否则 draft 输出的 token id 大模型理解不了。
工程问题:
- 要部署两份模型,多占显存
- draft 自己也是 memory-bound,每个 token 仍然要全网走一遍
- draft 越小越快但接受率越低(小模型预测得不准)
2. Medusa(Cai et al., 2024)
关键想法:不要部署一个独立 draft 模型;给大模型加几个『预测头』,每个头预测未来某个位置的 token。
具体地,大模型最后一层之后接 N 个独立的 LM head(叫 Medusa heads),原 LM head 预测下一位置,第 k 个 Medusa head 再往后预测第 k 个位置(即第 t+k+1 个位置)的 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 层)
- 各 head 取 top 若干个候选组成一棵静态候选树,下一次大模型 forward 用 tree attention 一次验证整棵树,同时产出新一轮候选
Medusa 论文报告两档:Medusa-1(只在冻结的 backbone 上微调 head)超过 2.2× 且无损;Medusa-2(head 和 backbone 一起微调)到 2.3–3.6×,但需要一套专门的训练配方来保住 backbone 的能力。要无损就用前者,要极限加速才考虑后者。
代价:
- 需要训练 Medusa heads(虽然很轻量,但仍是额外训练步骤)
- 草稿深度受 head 数限制
3. EAGLE(Li et al., 2024)
EAGLE 同样不用独立 draft 模型,用一个小的额外网络(一层 Transformer 解码层)根据大模型倒数第二层的特征(hidden state)预测多个未来 token,接受率比 Medusa 高。
关键 insight:Medusa 的多个独立 head 互相不通信、各自只看 hidden state——这限制了准确度。EAGLE 用这个小网络接力大模型的 hidden state,在特征层面自回归(输入里还拼上提前一步的 token 序列),逐个生成 draft token——每个 draft 都能看到前面的 draft(更连贯)。论文报告 LLaMA2-Chat 70B 上 2.7-3.5× 的延迟加速。
EAGLE-1 和 Medusa 一样用静态候选树(树形固定,只按位置决定每层展开多少)。EAGLE-2 改成按上下文动态建树:利用 draft 模型置信度与接受率高度相关这一点,按置信度决定展开哪些分支,论文报告 3.05-4.26×、比 EAGLE-1 快 20%-40%。EAGLE-3 的改动在 draft 模型本身:不再回归特征、直接预测 token,并用「training-time test」融合目标模型多层特征,使 draft 能从更多训练数据中持续获益。
EAGLE-3 论文在 chat 与 reasoning 两类模型、五个任务上评测,报告最高 6.5× 加速、比 EAGLE-2 提升约 1.4×。但同一篇论文还给了一个更该被记住的数字:在 SGLang 框架下、batch size 64 时吞吐提升只有 1.38×。加速比是单请求延迟口径,batch 一大收益就会被摊薄——投机解码本质是拿算力换延迟,而大 batch 下算力本来就是瓶颈。所以选型时要看清楚对方报的是哪个口径,并在自己的 batch 配置上实测。
4. Lookahead Decoding(Fu et al., 2024)
Lookahead 不需要额外训练任何东西,也不需要辅助模型或外部数据存储——它用 Jacobi 迭代 + n-gram 池直接产生 draft:
- 用 Jacobi 迭代并行猜测多个未来位置的 token,迭代轨迹里产生一批 n-gram
- 把这些 n-gram 收进 n-gram 池,每轮按当前最后一个 token 从池里查可能的延续
- 大模型在同一次 forward 里验证这些候选,只接受与自己逐 token 生成一致的部分
Lookahead 的好处:零训练、零额外参数、可即插即用。论文报告 MT-bench 上最高 1.8×(代码补全任务多卡强扩展下最高 4×)。代价是加速幅度通常不如 EAGLE 这类训练过的 draft。
还有一档更简单的:n-gram / prompt lookup——直接在上下文(prompt 和已生成内容)里找与末尾几个 token 相同的片段,把它后面的 token 当 draft。零训练、几乎零开销,在输出大量复用输入的任务(代码修改、摘要、RAG 问答)上很有效。17.8 里 vLLM 的 ngram 就是这种。
主流方案对照
| 方法 | draft 来源 | 训练需求 | 论文报告加速比(单请求口径) | 实现复杂度 |
|---|---|---|---|---|
| 经典两模型 | 单独小模型(如 Llama-2-7B) | 无(用现成小模型) | 2-3×(T5-XXL)、2-2.5×(Chinchilla 70B) | 中 |
| Medusa | 大模型 + 多 LM head,静态树 | 训 head(轻) | Medusa-1 超过 2.2×,Medusa-2 为 2.3-3.6× | 中 |
| EAGLE / EAGLE-2 | 大模型特征 + 一层解码层;静态树 / 动态树 | 训 EAGLE 网络 | 2.7-3.5×(LLaMA2-Chat 70B)/ 3.05-4.26× | 高 |
| EAGLE-3 | 直接预测 token + 多层特征融合 | 同上 | 最高 6.5× | 很高 |
| Lookahead | n-gram + Jacobi | 无 | 最高 1.8×(MT-bench) | 低 |
| ReDrafter | RNN draft + 动态树 attention | 训 RNN(蒸馏) | 最高 2.8×(H100,MT-Bench) | 中 |
各论文的模型、硬件和任务都不同,这一列只能看量级,不能横向直接比大小。
主流推理引擎(vLLM、SGLang、TensorRT-LLM)都内置了一种或多种。
17.6 投机解码的工程取舍
Trade-off 1:K(draft 长度)的选择
K 越大,单轮潜在加速越大,但:
- 每个 draft token 都要算(即使后面被拒绝),算多了浪费
- 大 K 时大概率前几个就拒绝,浪费 draft 算力
K 的最优值由 和 c 共同决定(17.4 的公式对 K 求最大即可),接受率越高、draft 越便宜,最优 K 越大。树状草稿(Medusa、EAGLE 系列)则换了个思路:一次 forward 用 tree attention 验证整棵候选树的几十个 token,最后接受其中最长的一条被接受路径。
Trade-off 2:draft 模型质量
draft 越准接受率越高、加速比越大;但 draft 越大本身越慢,c 上升。
经验上:
- 最优大小要按 17.4 的公式权衡 和 c:Leviathan 等人在 T5-XXL(11B)上测下来,最快的反而是最小的 T5-small(77M),比稍大的 T5-base、T5-large 都快——draft 并非越接近大模型越好
- 同系列模型 draft 通常比跨家族 draft 接受率高
Trade-off 3:与 batching 的兼容
投机解码和 continuous batching 有冲突。常规 batching:每个用户每步生成 1 token,batch 中所有用户同步推进。投机解码:每个用户每步生成 1 到 K+1 个不等的 token,不同用户的实际推进速度不同——同步性破坏。
工程上的处理:
- vLLM / SGLang 把投机解码和 continuous batching 统一在调度器里——每个用户独立维护自己的 draft / verify 状态
- 每个请求要额外记录本步的 draft token 和已验证长度;vLLM V1 里回滚就是把请求的
num_computed_tokens退回去,被拒位置的 KV 槽位下一步直接覆盖(详见《vLLM 推理内核深度解析》第 12 章)
Trade-off 4:长上下文友好度
长上下文对投机解码有两面:大模型 verify 时 K+1 个位置共用一次 KV Cache 读取,这部分收益照样被摊薄;但 draft 本身也要读自己那份随上下文增长的 KV Cache(或在长上下文上跑注意力),c 会变大。加速比随上下文长度是升是降取决于 draft 结构和 batch,需要在自己的上下文长度上实测。
17.7 何时投机解码不划算
不是所有场景投机解码都赢。几个反例:
反例 1:极小模型
7B 以下模型本身已经够快,更小的同源 draft 模型不容易找,c 也难以压低,投机解码的收益有限,往往不如直接量化。
反例 2:大 batch 推理
大 batch 下权重读取已经被 B 个请求摊薄,再乘上每个请求 K+1 个验证位置,算术强度很容易越过第 14 章的拐点(H100 约 295 FLOP/byte)进入 compute-bound——多算几个 token 不再「免费」。EAGLE-3 论文在 SGLang、batch=64 时报告的吞吐提升只有 1.38×;batch 再大,投机解码甚至可能变慢。
反例 3:高温度采样
接受率等于两个分布的重合度 。温度越低分布越尖锐,只要两个模型的高概率 token 一致,重合度就高——贪心解码(temperature→0)时退化成「draft 的 argmax 和大模型的 argmax 是否一致」。Leviathan 等人的实验也观察到,调整后的分布越尖锐, 越高(T5-XXL 上温度 0 的 普遍高于温度 1)。反过来,高温度(如 temperature=1.5)下分布被拉平,大量低概率 token 上的差异都会计入,接受率通常掉下去,加速比跟着缩水。
反例 4:草稿模型质量太差
如果 draft 和大模型来自不同家族(即便 tokenizer 恰好相同,训练数据和配方也不同),分布差太多接受率会低。最好用同源模型。
17.8 一个工程实例:vLLM 启用投机解码
注意 CLI 变过一次:早期版本用一组 --speculative-model / --num-speculative-tokens 的散装参数,到 v0.8.5 已经统一收敛成一个 JSON 配置 --speculative-config(vllm-0.8.5/vllm/engine/arg_utils.py:749)。散装参数在 v0.8.5 上已不在命令行参数表里,传了会直接报错,网上大量旧教程还停在老写法。
另一个 v0.8.5 特有的坑:V1 引擎把 ngram 和 EAGLE 投机都当实验特性,不显式设 VLLM_USE_V1=1 就会回退到 V0 引擎(vllm-0.8.5/vllm/engine/arg_utils.py:1484-1490),所以下面的命令都带上了这个环境变量。
最省事的一档是不需要任何额外权重的 n-gram(即上面的 prompt lookup:在 prompt 和已生成内容里找匹配的 n-gram,把其后续 token 当 draft):
VLLM_USE_V1=1 vllm serve meta-llama/Meta-Llama-3-70B-Instruct \
--speculative-config '{"method": "ngram", "num_speculative_tokens": 5}' \
--max-model-len 32768
num_speculative_tokens: 5 就是每轮草稿 5 个 token(前面公式里的 K)。
EAGLE 版本要多给一份 draft head 的权重:
VLLM_USE_V1=1 vllm serve meta-llama/Meta-Llama-3-70B-Instruct \
--speculative-config '{"method": "eagle", "model": "<对应的 EAGLE head 权重>", "num_speculative_tokens": 5}'
v0.8.5 的 V1 引擎直接接进去的 proposer 只有 n-gram 和 EAGLE / EAGLE-3——配置层认识的方法名比实际接通的更多:vllm-0.8.5/vllm/config.py:2137 的 SpeculativeMethod 里还列着 medusa、mlp_speculator、draft_model,选这些会回退 V0 引擎;但 vllm-0.8.5/vllm/v1/spec_decode/ 目录下只有 ngram_proposer.py 和 eagle.py 两个实现。选型前先确认你要的那个 method 在你的版本里真的有实现。
加速幅度高度依赖任务和 batch 配置:模板化、可预测的文本(代码、结构化输出、长 reasoning trace)接受率高、加速明显;开放式闲聊接受率低。务必在自己的 workload 和 batch size 上实测,不要照搬任何一篇文章的倍数(见上面 EAGLE-3 那个 6.5× vs 1.38× 的对比)。
要盯的两个指标:
- 单 token 接受率 :直接决定 17.4 那条硬上界
- 每步平均接受 token 数:真正兑现的收益,等于
具体的 metric 名字各引擎不同。vLLM v0.8.5 的 V1 在 vllm-0.8.5/vllm/v1/spec_decode/metrics.py 里暴露 vllm:spec_decode_num_drafts_total、vllm:spec_decode_num_draft_tokens_total、vllm:spec_decode_num_accepted_tokens_total 等计数器,接受数除以草稿 token 数就是实测接受率。
如果单 token 接受率低于 0.5,按上面的硬上界,天花板也就 2× 了——这时候要么换 draft 模型、要么干脆关掉投机。
17.9 投机解码的「赌性」
为什么说投机解码是一场「对赌」?
投机解码的本质是个赌局:
- 赌赢:draft 的 K 个 token 都被接受,一轮拿到 K+1 个 token——大幅加速
- 赌输:第一个就拒绝,浪费了 draft 的所有算力——这一轮比常规 Decode 慢一点
- 赌局规则不变:无论赢输,输出分布都不变(拒绝采样保证)
所以这是「质量上不会输的赌局」——赢则大赚,输则小亏;接受率够高时长期 EV 为正。但 EV 并非总是正的:按 17.4 的公式,、K=4、c=0.1 时加速比只有约 0.89×,反而变慢。别忘了 17.4 的硬上界:EV 再正,也涨不过 。
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/>显存浪费接近零"] --> COMBINE F["Flash Attention<br/>HBM 访问减"] --> COMBINE S["Speculative<br/>每步多 token"] --> COMBINE COMBINE["叠加 = 相对朴素实现的数量级提升"]
一个示意性的叠加组合(H100 跑 Llama-3-70B):
- INT4 + AWQ:HBM 读取从 140 GB 降到 35 GB
- PagedAttention:显存浪费限制在每个请求的最后一个 block 内
- Flash Attention 3:attention 部分进一步加速
- EAGLE 投机解码:假设每步平均产出 3 个 token
所有这些叠加,INT4 后的 70B 权重只有 35 GB、能进单卡 H100,单 token 的访存下界降到约 10 ms,再让投机解码把「一次访存换多个 token」摊开——单流吞吐能从几十 tokens/s 提到上百 tokens/s 这个量级。(具体数字取决于接受率和 batch,自己压测。)
17.11 投机解码的局限与未来
局限 1:天花板是大模型本身
投机解码不能让大模型的「实际输出能力」超过它本身——它只是把同样的输出更快产出。如果大模型本身已经很快(小模型、多卡、量化),加速空间有限。
局限 2:训练投资
EAGLE / Medusa 等方法需要训练 draft 网络,需要计算资源和数据。这是一次性投入但门槛不低。
局限 3:与 reasoning 模型的兼容
o1 / Claude 思考链类模型生成超长 reasoning trace(几千到几万 token),投机解码理论上加速更大(reasoning 文本更可预测)。但思考链生成时模型在「探索-修正」模式,分布波动大,实际接受率可能下降。这仍是在研究中的方向。
未来方向:
- Tree-based speculation:一次产生多个分支、一次验证整棵树,接受最长的一条被接受路径——Medusa、EAGLE 已用静态树,EAGLE-2 改为按置信度动态建树
- Self-speculative:让大模型自己作为自己的 draft——跳过部分层做 draft、全模型做 verify(Self-Speculative Decoding、LayerSkip 等)
- Hardware-aware speculation:针对不同 GPU 内存层级专门优化的 draft 调度
- Continual draft training:在线学习,根据用户实际输入分布持续训练 draft 网络
本章小结
- 投机解码的核心:用小 draft 模型猜出 K 个候选 token,让大模型一次 forward 验证全部——把「1 步 1 token」变成「1 步多 token」。
- 数学正确性:拒绝采样保证输出分布与原大模型逐 token 采样完全一致——质量零损失。
- 加速比公式:,硬上界是 ——加速比由单 token 接受率封顶,加长草稿救不了低接受率。论文报告的单请求加速多在 2-4× 区间。
- 主流方案:经典两模型、Medusa(多 LM head + 静态树)、EAGLE 系列(特征层 draft;EAGLE-2 动态树)、Lookahead(n-gram + Jacobi)、prompt lookup。上表中 EAGLE-3 论文报告的加速比最高。
- 「对赌」性质:赢则大赚(K+1 token 一步)、输则小亏(仅慢一点)——接受率够高时期望值为正。
- 不是所有场景都赢:极小模型、大 batch、高温度采样、草稿质量差的情况下加速有限。
- 与其他优化协同:量化 + Flash Attention + KV Cache + 投机解码叠加,相对朴素实现是数量级的提升。
- 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(arXiv:2211.17192,2022 年 11 月首发)——投机解码奠基论文(Google)。
- Chen et al., Accelerating Large Language Model Decoding with Speculative Sampling, 2023(arXiv:2302.01318)——同期独立工作(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