Speculative Decoding¶
约 1502 个字 44 行代码 预计阅读时间 6 分钟
Motivation¶
LLM inference 在生成阶段通常是 GPU memory-bound,而不是单纯的 compute-bound。
普通 autoregressive decoding 每次只能生成一个 token:
每次 forward 都需要访问模型参数和 KV cache。对于大模型来说,模型参数非常大,因此显存带宽访问成本很高。
所以 speculative decoding 想解决的问题是:
如何增加每次 iteration 里的有效计算量,让一次大模型 forward 尽可能推进多个 token,同时不显著增加 GPU memory access?
Speculative decoding 的核心思路是:
先用一个小模型快速猜多个 token,再用大模型一次性验证这些 token。
这个小模型一般叫做 draft model,大模型叫做 target model。
流程大概是:
1. draft model 根据当前上下文,连续猜 k 个 token
2. target model 一次 forward 验证这 k 个 token
3. 如果 draft token 被 target model 接受,就直接保留
4. 如果某个 token 不被接受,就从该位置开始重新采样
也就是说,大模型不是一个 token 一个 token 地生成,而是一次性判断 draft model 猜出来的一段 token 是否合理。
Why It Works¶
关键在于 LLM inference 的瓶颈通常是显存访问,而不是计算。
普通 decoding 每次 iteration 的显存访问大致是:
Speculative decoding 每次 iteration 的显存访问大致是:
其中 k 是 draft model 猜的 token 数量。
虽然 speculative decoding 增加了计算量,因为 target model 需要同时验证多个 token:
但是显存访问并没有按比例增加:
模型参数仍然只需要读一遍,KV cache 只是多了几个 token 对应的部分。
因此,如果当前系统是 memory-bound,那么增加一些计算并不会明显增加 iteration latency。
也就是说:
换句话说:
单次 iteration 的时间差不多,但一次 iteration 能产出更多 token,所以整体吞吐提升。
Acceptance Rate¶
Speculative decoding 的效果非常依赖 acceptance rate。
Acceptance rate 越高,说明 draft model 猜得越准,大模型接受的 token 越多,加速效果越好。
例如:
平均可以接受 2 个 token,再加上 target model 自己生成的 1 个 token,一次 iteration 大约能推进 3 个 token。
但是如果 acceptance rate 很低,比如 3 个 token 只接受 0 或 1 个,那么收益就会下降。因为 draft model 做了额外计算,但最终没有多少 token 被保留下来。
所以 speculative decoding 的关键是:
如果 draft model 太弱,猜得不准,acceptance rate 低,收益有限。
如果 draft model 太强,虽然猜得准,但本身推理成本也高,可能抵消加速收益。
Batch Size 对 Memory-bound / Compute-bound 的影响¶
LLM serving 在 decode 阶段,小 batch size 时通常是 memory-bound。
原因是每生成一个 token,都要读取一次大模型参数:
这时候 GPU 做的计算不多,但显存数据搬运很多,所以瓶颈主要在 HBM bandwidth / memory access。
当 batch size 变大之后,情况会变化:
也就是说,同样读一遍模型参数,现在可以服务更多 request。模型参数读取成本被多个 request 摊薄了。
所以 batch size 变大后:
系统就会从 memory-bound 逐渐偏向 compute-bound。
可以这样理解:
batch size 小:
搬一次模型参数,只算 1 个/少量 token
=> 搬运成本占主导
=> memory-bound
batch size 大:
搬一次模型参数,同时算很多 token
=> 计算量显著增加
=> compute-bound
Speculative decoding 之所以有效,是因为它假设 decode 阶段还有不少空闲计算能力:
于是它增加一些计算,比如一次验证多个 draft tokens,来换取更多 token 产出。
但如果 batch size 已经很大,系统逐渐变成 compute-bound,那么 speculative decoding 增加的额外计算就可能不再“免费”。
此时:
batch size 小:
增加计算不会明显增加 iteration time
speculative decoding 收益明显
batch size 大:
GPU compute 已经接近满载
额外验证多个 token 会增加 iteration time
speculative decoding 收益可能下降
所以更准确地说:
Speculative decoding 更适合 decode 阶段 memory-bound、batch size 不太大、GPU 计算资源没有被充分利用的场景。
Tree verification¶
- [To be or] --> [not to], [sleep in], [go to]
- [To be or] guess multiple choices: [not to], [sleep in], [go to]
让 draft model 生成多条路径:
target model 一次 forward 同时验证整棵树
How to tell if the verification is right or wrong - Deterministic sampling ( spec decode bad case) - Random sampling: correct when guess probability > threshold
部署挑战¶
为什么算法收益会被系统开销吃掉¶
一个 speculative decoding 算法在纸面上可能节省 target model 调用,但 serving 系统里还有很多隐藏成本。
首先是 KV Cache。target model 已经要为每个请求维护 KV Cache,如果再引入 draft model,draft model 也可能需要自己的 KV Cache。小模型虽然参数少,但在长上下文、高并发、连续 decode的场景下,它的缓存也不是免费的。
其次是并行策略。target model 可能使用 tensor parallel、pipeline parallel 或特定的 GPU 切分方式;draft model 因为更小,最优并行方式可能完全不同。如果强行让小模型沿用大模型的并行部 署形态,可能浪费 GPU、增加同步,甚至让“小模型”不再便宜。
KV block 与丢弃 token¶
speculative decoding 会产生一些“可能被接受,也可能被丢弃”的 token。这对 KV Cache 管理非常麻烦。系统可能需要预先为候选 token 分配 KV block,但验证后如果 token 被拒绝,这些缓存就不能作为最终上下文继续使用。
更复杂的是 block 边界。假设一个请求当前已经接近 block 尾部,proposer 又猜了多个 token,候选 token 可能跨过新的 block。系统需要在接受、拒绝、回滚和继续生成之间保持一致,不能让无效 token 的 KV 状态污染后续推理。
猜几个 token 应该是动态的¶
猜测 token 数不应固定。不同请求、不同上下文、不同阶段的可预测性差异很大。有的请求格式稳定,可以多猜;有的请求开放性强,猜多了反而频繁拒绝。
因此,未来更合理的 serving 策略可能是动态选择: - 哪些请求启用 speculative decoding。 - 每个请求当前轮猜几个 token。 - 使用 N-gram、draft model、Medusa 还是完全不猜。 - 根据最近接受率、请求类型、上下文重复度和系统负载调整策略。
这类策略甚至可以被建模成在线决策问题:系统根据历史接受率和当前资源状态选择动作,目标是在质量不变的前提下最大化吞吐或降低延迟。
Last update: April 29, 2026
Discussion