Speculative Decoding(投机采样):大模型"先猜后验",生成速度翻倍

核心观点:用小模型"打草稿"、大模型"批改",在几乎不损失质量的前提下,把大模型生成速度提升 2-3 倍。

一、一个反直觉的真相:大模型生成慢,卡的不是算力,是内存带宽

先讲一个很多人不知道、但理解后会觉得"原来如此"的事实:大模型在生成文本(也就是推理)的时候,瓶颈往往不在 GPU 的算力,而在内存带宽。

为什么?这得从大模型"生成"一个 token 的底层过程说起。

我们平时用 ChatGPT、Claude 这类模型聊天,模型是一个字一个字(准确说是 token 一个 token)往外蹦的。这种生成方式,学术上叫 自回归(autoregressive)生成:模型先根据已有内容,预测出下一个 token 的概率分布,然后采样出一个 token,把它拼到已有内容后面,再基于新的内容预测再下一个 token,如此循环。

关键问题就出在"循环"这两个字上。每生成一个 token,模型都要把整个模型的权重从头到尾"过一遍"。

以一个大模型为例,假设它有 700 亿参数(70B)。用 FP16 半精度存储,这些权重在显存里大概占 140GB。注意:生成每一个 token,这 140GB 的权重都要从显存里读出来、参与一次前向计算。也就是说,生成 N 个 token,就要把这 140GB 的权重读 N 遍。

这里就暴露了真正的瓶颈:GPU 从显存读数据的速度,是有限的。现在主流的 GPU(比如 H100)内存带宽大约是 3TB/s 左右。用 3TB/s 去除 140GB,你会发现:光是把权重读一遍,就要花大约 0.05 秒左右。

这个数字意味着什么?意味着在理想情况下(算力完全够用,纯粹被内存带宽卡住),这个 70B 模型每秒最多也就能生成 20 个 token 左右。而实际上,现代 GPU 的算力(FLOPS)是绰绰有余的------真正拖慢速度的,就是这个"每生成一个 token 就要把全部权重读一遍"的物理过程。

所以结论很反直觉:自回归生成慢,本质上不是因为"算不动",而是因为"读不过来"。 每步都要重读一遍权重,这是一个硬性的物理约束。

那么,有没有办法在"每步都要读一遍权重"这个前提下,让每一步产出更多的 token?这就是投机采样要解决的问题。

二、核心思想:让便宜的模型"打草稿",让贵的大模型"批改"

投机采样(Speculative Decoding)的思路非常巧妙,可以用一个日常场景来类比。

想象你是一家公司的 CEO,需要逐句审阅并敲定一份重要报告。如果你自己一句一句写,那速度就是你亲自写作的速度,很慢。但如果换一种方式:你让一个能力一般但动作极快的助理,先一次性起草出后面好几句话的草稿 ,然后你一次性快速浏览这几句草稿,认可正确的、划掉错误的,只对出错的地方亲自重写。

你会发现,只要助理写得大部分是对的,你的整体产出速度就会大幅提升------因为你不是从零开始逐句憋,而是"批改"已经写好的草稿。助理帮你承担了"从 0 到 1"的粗活,你只做"从 1 到 N"的精修。

投机采样就是把这个逻辑搬到了大模型上:

  • 草稿模型(draft model) :一个很小、很快、便宜的小模型(比如几亿参数)。它的任务是一次性"猜"出后面 K 个 token 的草稿。因为它小,权重少,读一遍权重快得多,所以它能飞快地生成一串草稿。

  • 目标模型(target model) :就是那个又大又贵的真正大模型(70B 那个)。它的任务不再是"自己从头生成",而是对草稿模型猜出来的这 K 个 token 做一次批量验证------一次性检查这一串草稿里,哪些 token 是自己本来也会生成的,哪些是草稿模型猜错了的。

  • 验证与修正:目标模型一次性验证这 K 个草稿 token。验证通过的(也就是草稿模型猜对了的)token 被直接采纳;一旦遇到第一个猜错的 token,目标模型就亲自生成一个正确的 token,把它替换上去,然后从这个位置往后重新开始下一轮"打草稿 + 验证"。

关键的点在于:目标模型验证 K 个 token,和它自己生成 1 个 token,在"读权重"这件事上的成本几乎是一样的。

还记得第一节的结论吗?生成慢是因为"每读一遍权重只能产出 1 个 token"。而投机采样让"每读一遍权重"能产出多个 token------只要草稿模型猜对得多,这一遍权重读下来,就能一次性验证并采纳好几个 token。这就是提速的来源。

用一个数字来感受:如果草稿模型平均能猜对 3 个 token(也就是目标模型每次验证能平均采纳 3 个),那生成速度理论上就能接近原来的 3 倍。猜对得越多,提速越明显。

三、关键点:为什么结果和原来"完全一致",质量零损失?

投机采样最容易让人担心的问题是:用一个小模型先猜,会不会让生成结果变差?毕竟小模型能力不如大模型。

答案是:不会。投机采样的结果,和目标模型自己老老实实逐 token 生成的结果,在数学上是完全一致的。质量零损失。

这是投机采样最漂亮的地方,也是最容易被误解的地方。很多人以为"小模型先猜,大模型再改"会引入小模型的偏差,导致质量下降。但事实恰恰相反------小模型在这里只是个"加速器",它没有任何决定权,最终敲定的永远是目标模型。

怎么理解"完全一致"?关键在于验证机制的设计。

目标模型在验证草稿的时候,用的不是"草稿模型觉得这个 token 对不对",而是目标模型自己对这个 token 的预测概率。具体来说,对于草稿里的第 i 个 token,目标模型会算出"在给定前缀的情况下,我自己会以多大概率生成这个 token"。然后通过一个巧妙的随机采样机制(通常基于拒绝采样 / rejection sampling),决定是否采纳。

这个采样机制的精妙之处在于:它保证了"最终采纳的 token 序列"的概率分布,和目标模型自己逐个生成时的概率分布完全一致。 换句话说,你无法从最终结果上区分"这是投机采样生成的"还是"这是目标模型逐 token 生成的"。两者在统计上等价。

可以这么理解:草稿模型猜出的 token,只有当"目标模型自己本来也会大概率生成它"时,才会被采纳;否则就会被目标模型亲自重写。所以草稿模型的"错误"永远不会混进最终结果------它最多只是"猜错了、白猜了、被丢弃了",而不会污染输出。

因此,投机采样是"无损加速":速度快了,但输出内容和原来一模一样,没有任何质量损失。 这是它区别于其他"用更小的模型近似替代大模型"的加速方案(比如蒸馏、量化)的最核心优势------那些方案或多或少会牺牲质量,而投机采样不会。

不过,这里要补一个诚实的说明:说"完全一致"是指理想化的实现。在具体工程落地中,有一些实现为了追求极致速度,会做细微的近似(比如用一个"确定性接受"的简化版本,即"草稿 token 只要超过某个概率阈值就直接接受,不做严格拒绝采样")。这种简化版会有极小的、几乎不可察觉的质量波动。但标准实现(严格拒绝采样)在数学上是严格无损的。这个细节,是我们作为从业者需要知道并区分清楚的。

四、为什么能真的快起来:一次"读权重"换多个 token

我们再从底层算力账的角度,把"为什么能快"这件事算清楚,这样理解会更扎实。

设目标模型有 W 个参数,权重总量为 S(字节)。自回归生成时:

  • 生成 1 个 token 的成本 ≈ 读 S 字节权重 + 一次前向计算(算力部分相对不贵)。
  • 生成 T 个 token 的成本 ≈ T × S 字节的读取。

投机采样时,草稿模型很小(权重远小于 S),它快速生成 K 个草稿 token 的成本几乎可以忽略不计(因为它读的权重很少,读得飞快)。然后目标模型做一次验证:

  • 验证 K 个 token 的成本 ≈ 读 S 字节权重(一次)+ 对 K 个 token 的批量前向计算。

注意:验证 K 个 token,只读了一遍 S 字节的权重。 因为验证时,目标模型可以"并行地"处理这 K 个 token 的预测------它读一次权重,就能同时对 K 个位置做预测。这就是关键差异:

  • 原来:读一遍权重(S 字节)→ 产出 1 个 token。
  • 现在:读一遍权重(S 字节)→ 验证并采纳 K 个 token(平均)。

假设平均每次能采纳 α 个 token(α 就是"草稿模型猜对 token 的平均个数",也叫接受率),那么理论上提速倍数就是 α。如果草稿模型选得好,α 达到 2-3 是很常见的,于是整体提速 2-3 倍。

当然,实际提速会略低于理论值,因为还有草稿模型自身的前向计算开销、验证机制的额外开销、以及"草稿没猜对导致的浪费"等。但即便打折扣,"2-3 倍提速、质量无损"这个结论在工程上是被反复验证过的,是真实的。

顺便说一句:投机采样特别适合那种"草稿模型容易猜对"的场景------比如代码生成、机器翻译、结构化文本生成、遵循固定格式的输出等,这些场景下大模型的下一个 token 相对可预测,草稿模型能猜对很多,提速更明显。而在"发散性创意写作"这种每个 token 都高度不确定的场景,草稿模型猜对的少,提速就有限。这也是为什么你会看到投机采样在代码补全、翻译服务等场景里被广泛采用。

五、工程落地:vLLM / TensorRT-LLM 的现成实现与真实收益

好消息是,投机采样已经是一个相当成熟的技术,主流推理框架都有现成实现,你不用自己从头造轮子。

5.1 开源实现盘点

vLLM:目前最流行的高性能 LLM 推理引擎之一,对投机采样支持得比较完善。它支持配置一个草稿模型(draft model),自动和目标模型配合做投机解码。你只需要在启动时指定草稿模型,vLLM 就帮你把"打草稿 + 验证"这套机制跑起来。它还支持"自投机(self-speculation)"的一些变体,以及用 Medusa 头(在目标模型上加几个小预测头,代替独立草稿模型)这类进阶玩法。

TensorRT-LLM:NVIDIA 官方的推理框架,同样内置了投机采样。它在 NVIDIA GPU 上的优化做得非常极致,支持草稿模型和目标模型同机部署,并且可以和量化、KV cache 优化等其他技术叠加使用。

Hugging Face Transformers :也提供了投机采样的参考实现(assisted generation 相关接口),适合实验和学习原理,生产环境一般还是用 vLLM / TensorRT-LLM 这类更工程化的框架。

Medusa / Lookahead Decoding 等变体:在标准投机采样基础上,还有一批演进方案。Medusa 是在目标模型顶部加几个并行的"预测头",同时预测后续多个 token,省掉了独立的草稿模型;Lookahead Decoding 则是让模型自己"先看一步"来加速。这些变体的思路殊途同归,都是为了打破"一次读权重只产出一个 token"的瓶颈。

5.2 真实收益大概有多少

公开的论文和业界实践给出的数字比较一致,可以参考:

  • 在代码生成、翻译等场景,配合一个合适的草稿模型,实测吞吐(每秒 token 数)能提升 2-3 倍,也就是加速比 2-3x。
  • 对于某些草稿模型命中率特别高的场景(比如结构固定的 JSON 输出),加速比甚至能到 3x 以上。
  • 对于发散性强的对话生成,加速比通常在 1.5-2x 左右,收益相对温和但依然可观。

更重要的是,这个提速是"免费"的------不需要更换更大的 GPU,不需要牺牲输出质量,甚至可以在同一块 GPU 上直接启用,让现有的推理服务吞吐翻倍。对成本敏感、又追求吞吐的团队来说,这是性价比极高的一项优化。

5.3 落地的几个实用建议

如果你想把投机采样用起来,有几个实战要点值得记下:

第一,草稿模型要选"小而准、且和目标模型同架构或同 tokenizer"的。 草稿模型和目标模型的词表(tokenizer)必须一致,否则 token 对不上,验证机制就失效了。通常选择同一个模型家族的更小版本(比如目标模型是 Llama-3-70B,草稿模型用 Llama-3-8B),这样词表一致、分布也接近,草稿命中率高。

第二,草稿长度 K 和"草稿模型大小"之间要权衡。 K 太大,草稿模型猜错后浪费就多;K 太小,每次验证采纳的 token 少,提速不明显。K 太大或草稿模型太大,草稿模型自身的开销也会吃掉一部分收益。工程上通常动态调整 K(根据最近几轮的命中率自适应)。

第三,注意显存占用。 投机采样需要在显存里同时装下目标模型和草稿模型(除非用 Medusa 这类无独立草稿模型的方案)。好在草稿模型很小(目标模型的 1/10 甚至更小),增加的显存占用不大,但规划 GPU 资源时要把这部分算进去。

第四,关注是否真的受带宽瓶颈约束。 投机采样解决的是"内存带宽瓶颈"下的生成慢问题。如果你的场景是小批量、低并发、且已经做了其他优化(比如量化、KV cache 优化),那投机采样可能不是第一优先级;但如果是大批量、高吞吐的在线服务,它几乎必上。

六、总结与展望

投机采样,本质上是用一个非常优雅的"借力"思路,绕开了自回归生成"每步都要重读一遍权重"的物理瓶颈。它的核心只有一句话:让便宜的小模型先猜草稿,让贵的大模型只做批改------小模型出力,大模型把关,结果一点不变,速度翻倍。

它最打动人的地方,是它把"加速"和"无损"这两件通常矛盾的事情统一了起来:既有工程上的巨大收益(2-3 倍吞吐提升),又有数学上的严格保证(输出分布与原模型完全一致)。这也是它能在 vLLM、TensorRT-LLM 等主流框架里快速落地、成为大模型推理标配优化技术的原因。

展望未来,投机采样背后的"用多个更便宜的模型/预测头并行猜测,再由权威模型验证"这一思想,还在持续演化------Medusa、Lookahead、以及各类"并行猜测 + 树状验证"的进阶方案,都在沿着同一个方向突破:尽可能让大模型"读一遍权重"就产出更多的 token。 而这条路的尽头,是让大模型的推理成本持续下降、速度持续上升,最终让"大模型服务"这件事,变得又快又便宜。

理解了投机采样,你也就理解了大模型推理优化的一个核心脉络:很多看似"魔法"的提速,本质都是在和"内存带宽"这个物理天花板较劲------而投机采样,是用最聪明的方式,绕过了它。

相关推荐
荆棘鸟智能1 小时前
AI算法持续学习与迭代怎么做?从数据闭环到灰度发布的MLOps工程实践
人工智能·算法·架构·边缘计算
a1117761 小时前
网页版「MATLAB」开源
前端·开源
Lyyaoo.1 小时前
【二分查找】【中等】搜索二维矩阵/排序数组的第一位和最后位置/搜索旋转排序数组/旋转排序数组中的最小值
java·数据结构·算法
JianZhen✓1 小时前
解决SPA发版旧版本残留+动态路由打包失效的完整方案(附落地代码)
前端·状态模式
计算机魔术师1 小时前
Dario Amodei 发文呼吁放缓前沿 AI 开发后各方表态汇总
前端
土司大王1 小时前
LeetCode hot100——153.寻找旋转排序数组中的最小值:Java 二分模板与 O(log n) 分析
java·算法·leetcode
光电的一只菜鸡1 小时前
isp中关于锐化对图像清晰度的影响
算法
anyup2 小时前
仍然是简单一句话,uView Pro Starter 一键清理 Skill 发布
前端·人工智能·uni-app
码农飞哥2 小时前
企业级RAG系统架构详解
java·人工智能·ai编程·rag·ai应用