📑 本页目录(点开跳转)
19 · 投机解码
⏱ 34 分钟 | 🎁 用闲置的算力换延迟
🎯 一句话
Decode 阶段算力有 95% 在闲置(第 15 章)。 投机解码把这些闲置算力用起来:先用小模型猜几个 token,再用大模型一次性验证。 猜对了就白赚,猜错了也不亏 —— 而且输出分布和原模型完全一致。
💡 一、核心思路
操作步骤
- ⭐ 关键观察:
- · 大模型验证【5 个 token】和验证【1 个 token】,耗时几乎一样
- (因为都是带宽瓶颈,读一遍权重的成本一样)⭐
- · 所以"多算几个"是【免费的】
- 流程:
- 草稿模型(小,快)自回归生成 k 个候选 token
- 目标模型(大)【一次前向】并行验证这 k 个
- 接受第一个不匹配之前的所有 token
- 从不匹配处继续
结果对照
🔑 为什么"验证 5 个和验证 1 个一样快": Decode 是带宽瓶颈,时间几乎全花在把权重从 HBM 读一遍上。 一次读进来,算 1 个 token 和算 5 个 token 的计算差异微不足道。 这就是投机解码的物理基础。
🎲 二、为什么输出质量不会下降
对照
⭐ 这是投机解码最漂亮的地方:
用【推测采样(speculative sampling)】的接受-拒绝规则,
可以证明【输出分布和直接用大模型采样【完全相同】】
📐 接受-拒绝规则(想看再点)
设草稿模型给出分布 $q(x)$,目标模型给出 $p(x)$,草稿采样得到 token $x$。
- 以概率 $\min\left(1, \frac{p(x)}{q(x)}\right)$ 接受
- 若拒绝,从修正分布 $\text{norm}(\max(0, p - q))$ 重新采样
可以证明:最终得到的 token 服从 $p$,和直接从目标模型采样一模一样。
💡 直觉:草稿模型高估了某个 token($q > p$)时,按比例拒绝一部分; 拒绝后从"目标模型想要但草稿模型给得不够"的那部分分布里补采样。 两边正好抵消。
🔑 这一点非常重要: 投机解码不是近似加速,它是精确的。 不像量化那样需要评估质量损失 —— 它没有质量损失。
📊 三、加速比取决于什么
$$\text{加速比} \approx \frac{1 + \alpha + \alpha^2 + \cdots + \alpha^k}{1 + c\cdot k}$$
(α = 接受率,c = 草稿模型相对目标模型的成本比)
信息关系
信息关系
💡 为什么代码补全场景收益最大: 代码有大量可预测的模式(缩进、括号、常见变量名、样板代码), 草稿模型的接受率能到 0.85 以上。
🧰 四、四种实现方式
| 方式 | 草稿从哪来 | 特点 |
|---|---|---|
| 独立草稿模型 | 同系列的小模型(如 Llama-7B 配 Llama-1B) | 经典做法,要额外显存 |
| n-gram / 提示词查找 ⭐ | 从输入或已生成文本里找重复片段 | 零额外模型,对 RAG/改写/代码补全极有效 |
| Medusa | 给目标模型加几个额外的预测头 | 不需要独立模型,要微调 |
| EAGLE ⭐ | 在特征层做预测,接受率更高 | 目前效果最好的方案之一 |
⭐ n-gram 投机值得特别推荐: 它不需要任何额外模型 —— 直接从提示词里找匹配的片段当草稿。 在这些场景几乎白送: - RAG(答案大量引用检索到的原文) - 代码编辑(大部分内容不变) - 文本改写/翻译(结构相似)
# 🧩 骨架:`LLM` 来自你自己的代码,这一段只看写法
# vLLM 的几种配置
llm = LLM(model="meta-llama/Llama-3.1-70B",
speculative_model="meta-llama/Llama-3.2-1B", # 独立草稿
num_speculative_tokens=5)
llm = LLM(model="...", # ⭐ n-gram,零成本
speculative_model="[ngram]",
num_speculative_tokens=4,
ngram_prompt_lookup_max=4)
🌳 Medusa 和 EAGLE:不要独立模型的两条路
上面表格里这两个各只有一行,但它们值得多说两句 —— 因为它们回答的是同一个问题:怎么让"草稿成本 c"接近零,同时把接受率 α 拉高。
Medusa:给目标模型加几个预测头
操作步骤
⚠️ 代价在于这些头彼此独立预测:第 3 个头不知道第 1、2 个头猜了什么,越往后越不准。 解法是每个头取 top-k 组成一棵候选树,用树注意力(tree attention)一次验完整棵树 —— 把所有节点拼成一个序列,配一个特制 mask 让每个节点只看得见自己的祖先。
⭐ 这是本章第一节那条物理基础的自然推广: "验证 5 个和验证 1 个一样快"→ "验证一棵树和验证一条链也差不多快"。 既然多算是免费的,那就别只猜一条路。 ⚠️ 但树不能无限大 —— 树一大 attention 的计算量就不可忽略,而且候选之间高度重复。
EAGLE:把自回归挪到特征层
EAGLE 的观察是:token 层面难猜,特征层面好猜。
对照
❌ 普通草稿模型:在【token 空间】里自回归
token 是 hidden 特征【采样之后】的结果 —— 信息已经丢了一大截
✅ EAGLE:在目标模型的【特征(hidden state)序列】上自回归
一个很轻的单层解码器,输入是
[上一步的特征, 上一步【真正采样出来】的 token 的 embedding]
预测下一个特征,再借目标模型【自己的 LM head】把特征变回 token 分布
⭐ 接受率更高的两个原因:
① 特征比 token 信息量大(token 是特征塌缩之后的结果);
② 把 [真正采样出的 token] 一起喂进去,等于把"采样带来的不确定性"显式补回去 ——
草稿模型不用再去猜"上一步到底采样出了哪个"。
| 独立草稿模型 | Medusa | EAGLE ⭐ | |
|---|---|---|---|
| 草稿成本 c | 一份小模型 × k 步,最贵 | ≈ 0(一次前向出 k 个) | 很小(轻量解码器 × k 步) |
| 接受率 α | 取决于两个模型有多像 | 偏低(头之间互相不知道) | 最高 ⭐ |
| 要不要训练 | ❌ 现成小模型就行 ⭐ | ✅ 要训那几个头(微调级) | ✅ 要训那个解码器(微调级) |
| 额外显存 | 一整个小模型 | 几个头,很小 | 一个小解码器,很小 |
⚠️ 别去背"EAGLE 能到百分之多少接受率"这种数字 —— 它随模型、任务、树形变化很大。 要记的是这张表的结构:
独立模型 = 不用训但最贵、Medusa = 便宜但猜得糙、EAGLE = 用特征层换接受率。 ⭐ 而且它们都逃不掉第五节那条限制:草稿再便宜,高并发下算力已经用满,整体仍是负收益。
⚠️ 五、什么时候【不该】用
结果对照
| 场景 | 建议 |
|---|---|
| 单用户 / 低并发 | ✅ 开,收益明显 |
| 高吞吐批量服务 | ❌ 别开,会拖慢 ⭐ |
| 代码补全 | ✅ 强烈推荐(接受率高 + 延迟敏感) |
| RAG 问答 | ✅ 用 n-gram 投机,零成本 ⭐ |
🔑 一句话判断: 看你的 GPU 算力利用率。低(<20%)就开,高就别开。 这也再次印证了第 1 章那句 —— 每个优化都是一笔交易,要知道它拿什么换的。
🔗 和站内其他章的关系
| 相关的地方 | 这里的位置 |
|---|---|
| 第 15 章 Decode 算力闲置 95% | 投机解码的物理基础 ⭐ |
| 第 15 章 吞吐 vs 延迟权衡 | 投机解码站在延迟这边 |
| 第 1 章 每个优化都是交易 | 本章是最好的例证 ⭐ |
| 第 17 章 批处理 | 两者会互相冲突 |
| 《大模型全景导论》06 推理优化 武器三:投机解码 | 那边给"什么时候用",本章给接受-拒绝规则和加速比公式 ⭐ |
| 《智能体工程教程》11 检索与 RAG 检索结果塞进提示词 | 这正是 n-gram 投机零成本白赚的场景 —— 答案大量复用提示词里已有的片段 ⭐ |
✅ 检查点
- 投机解码的物理基础是什么?为什么"验证 5 个和 1 个一样快"?
- 流程的四步是什么?
- 为什么输出质量不会下降?这和量化有什么本质区别?
- 加速比取决于哪两个变量?典型的接受率是多少?
- 为什么代码补全场景收益最大?
- n-gram 投机的思路是什么?它在哪三个场景几乎白送?
- Medusa 的草稿成本为什么接近零?它的弱点是什么?树注意力怎么补救?
- EAGLE 为什么接受率更高?它把自回归挪到了哪一层?
- 什么时候不该用投机解码?为什么?
- 一句话的判断标准是什么?
👀 答案
- Decode 阶段算力有 95% 闲置。因为 Decode 是带宽瓶颈,时间几乎全花在把权重从 HBM 读一遍上,一次读进来算 1 个还是 5 个 token 的计算差异微不足道。
- ①草稿模型自回归生成 k 个候选 ②目标模型一次前向并行验证 ③接受第一个不匹配之前的所有 token ④从不匹配处继续。
- 因为用推测采样的接受-拒绝规则(以 min(1, p/q) 接受,拒绝后从 norm(max(0,p−q)) 补采样),可证明输出分布和直接用大模型采样完全相同。本质区别:量化是近似加速需要评估质量损失,投机解码是精确的、没有质量损失。
- 接受率 α(草稿猜得多准,典型 0.6-0.8)和草稿成本 c(通常要 ≤1/10 才划算)。
- 因为代码有大量可预测的模式(缩进、括号、常见变量名、样板代码),接受率能到 0.85 以上。
- 不用任何额外模型,直接从输入或已生成文本里找重复片段当草稿。三个场景:RAG(答案大量引用检索原文)、代码编辑(大部分内容不变)、文本改写/翻译(结构相似)。
- 因为它在目标模型最后一层 hidden 上接几个额外的线性头,第 i 个头直接预测"再往后第 i 个 token"——一次前向就吐出 k 个候选,草稿不用自回归。弱点:这些头彼此独立,第 3 个头不知道前两个猜了什么,越往后越不准。补救:每头取 top-k 组成候选树,用树注意力(拼成一个序列 + 特制 mask 让每个节点只看得见祖先)一次前向验完所有路径——这是"验证 5 个和 1 个一样快"的推广:验证一棵树和一条链也差不多快。
- 因为 token 是 hidden 特征采样之后的结果,信息已经丢了一大截。EAGLE 把自回归挪到特征(hidden state)层:一个轻量解码器,输入
[上一步的特征, 上一步真正采样出的 token 的 embedding],预测下一个特征,再借目标模型自己的 LM head 变回 token 分布。更准的两个原因:①特征比 token 信息量大 ②把真正采样出的 token 喂进去,等于把采样的不确定性显式补回去。 - 高并发场景。batch 大时算力已被用满,投机解码抢不到闲置算力,验证开销变成纯损失,吞吐反而下降。
- 看 GPU 算力利用率——低(<20%)就开,高就别开。
🛑 可以停在这里
⚡ 走神救援
⭐ 物理基础:Decode 阶段算力绝大部分闲置,而大模型验证五个 token 和验证一个几乎一样快(都是带宽瓶颈,读一遍权重的成本相同)——所以「多算几个」是免费的。流程是小模型猜 k 个、大模型一次前向并行验证、接受第一个不匹配之前的全部。
⭐⭐ 输出质量不会下降,而且是可证明的:那套接受-拒绝规则让输出分布和直接用大模型采样完全相同。⭐ 这和量化有本质区别——量化是近似加速、要评估质量损失,投机解码是精确的。
加速比取决于接受率和草稿成本。⭐ 收益跟着可预测性走:结构化文本(代码、样板、缩进括号)最高,高创造性文本几乎没有。
四种实现里 ⭐ n-gram 查找几乎是白送的——零额外模型,直接从输入里找重复片段,在 RAG、代码编辑、改写翻译三个场景收益立竿见影。
Medusa 和 EAGLE 解决的是同一个问题:让草稿成本接近零、同时把接受率拉高。Medusa 在最后一层接几个额外的头,一次前向就吐出多个候选、草稿不用自回归;⚠️ 弱点是这些头彼此独立、越往后越不准,补救是候选树加树注意力——⭐ 这是「验证五个和一个一样快」的推广:验证一棵树和验证一条链也差不多快。 EAGLE 的观察是 ⭐ token 层难猜、特征层好猜(token 是特征采样后的结果,信息丢了一大截),所以它在特征序列上自回归。
⚠️ 别背具体的接受率数字,记那张表的结构:独立模型不用训但最贵、Medusa 便宜但猜得糙、EAGLE 用特征层换接受率。
⚠️⭐ 什么时候别用:高并发。 batch 大时算力已被用满,投机抢不到闲置算力,验证开销变成纯损失、吞吐反而下降。⭐ 判断只看一件事:GPU 算力利用率低就开,高就别开——再次印证「每个优化都是一笔交易」。
下一节 👉 20-推理服务化.md