投机解码
用小模型猜出若干个 token,再用大模型一次性全部验证。白拿的速度,完全一样的输出。
生成是串行的:一次一个 token,每个 token 都要完整过一遍模型。这一遍的开销主要花在从显存里把每一个参数读出来,而不是花在算术上。
这意味着硬件大部分时间是闲着的。算力是有的,瓶颈在于为单个 token 的工作量搬运数据所需的显存带宽。
投机解码(speculative decoding)利用的就是这道落差。验证若干个 token 的代价,几乎和生成一个 token 一样,因为验证是并行的,而且只把同样的数据搬运一遍。
怎么运作
两个模型:一个小而快的草稿模型,和你真正想要其输出的大目标模型。
- 草稿模型便宜地、串行地往前生成若干个 token——比如四个。
- 目标模型在一次前向传播里处理这四个 token,在每个位置产出自己的概率分布。
- 比对。凡是和目标模型本来会产出的结果一致的草稿 token 就接受;从第一处不一致开始,后面的全部拒绝。
- 从最后被接受的位置继续。
如果四个全被接受,你就用大约一次目标模型前向的代价拿到了四个 token。如果第一个就被拒,你只拿到一个 token——目标模型自己产出的那个——草稿的工作白费了。
输出完全一致
让这项技术值得用、而不只是有意思的那个性质是:输出的概率分布可证明地没有改变。
接受规则的设计,使得最终得到的 token 序列具有和目标模型单独生成时完全相同的分布。被拒的位置回退到从目标模型的分布里采样,并做了调整,以确保不引入偏差。
这不是近似,也不是质量上的取舍。它是同样的输出,只是更快。这正是它区别于量化和蒸馏的地方——后两者都要拿质量换速度。
收益由什么决定
接受率决定一切。它取决于草稿模型能多准地预测目标模型的选择,而这一点因内容而差异极大——样板文字、常见措辞、可预测的代码,草稿能猜得很准;新颖的推理则不行。
草稿长度要权衡。草稿越长,被接受时每次验证能拿到越多 token,但早早就被拒时浪费的工作也越多。最优长度取决于接受率,有些自适应方案会在生成过程中动态调整它。
草稿模型的成本必须相对目标模型保持很小。草稿模型如果大小接近,省下来的就全被吃掉了。
公开报道的加速比通常是:在有利的内容上大约 2-3 倍,困难的生成任务上更少。这种波动是内在的——这项技术最能加速的,就是可预测的文本。
几种变体
**独立的草稿模型。**从同一个模型家族里挑一个小模型,选它是为了词表兼容。实现简单,但要同时服务两个模型。
**自投机。**拿目标模型自己的一个层子集当草稿,跳过其余部分。只有一个模型,不需要额外部署,但接受率通常更低。
**Medusa 式额外头。**给目标模型加上轻量的头,直接预测往后若干位置。不需要独立模型,但需要训练这些头。
**N-gram 与查找式草稿。**完全不用模型,直接从 prompt 或最近文本的缓存里复制来充当草稿。当输出会重复输入时——摘要、编辑、改代码——效果好得惊人。而且便宜到几乎等于免费。
什么情况下有帮助,什么情况下没有
帮助最大的是单请求延迟:一个用户等一个回答。这就是它被设计出来要解决的场景。
**在重批处理下帮助最小。**当许多请求被一起处理时,硬件本来就忙,投机所利用的那部分闲置算力已经没有了。服务系统在高负载时常常会把它关掉——所以一项能把单个用户的延迟减半的技术,可能对总体吞吐量毫无帮助。
**增加显存占用。**多一个模型或额外的头,再加上草稿的 KV cache。
**增加延迟波动。**单个 token 的耗时随接受情况变得不均匀。
要点回顾
- 生成受显存带宽限制,算力闲着——验证若干个 token 的代价几乎和生成一个一样。
- 小的草稿模型提出候选,大的目标模型一次前向完成验证,一致的 token 被接受。
- 输出分布可证明地完全相同——提速但不损失质量,这点和量化、蒸馏不同。
- 收益取决于接受率,可预测的文本上高,新颖的推理上低。
- 最适合单请求延迟;在重批处理下基本没有效果。
下一篇: 推理服务是怎么运作的