什么是投机解码 (Speculative Decoding)
投机解码(Speculative Decoding)是大语言模型推理加速领域的一项创新技术,它通过”先猜后验”的策略,在保持生成质量不变的前提下,将推理速度提升 2-3 倍。这项技术由 Google 等团队在 2023 年提出,迅速成为推理优化的重要方向。
为什么要提出投机解码?
传统自回归生成的瓶颈
大语言模型生成文本时采用的是自回归(Auto-regressive)方式:
1 | 第1步: 输入 "今天天气" → 模型计算 → 输出 "真" |
问题在哪里?
每个 token 的生成都需要:
- 将完整序列输入模型
- 执行一次完整的前向传播(Forward Pass)
- 从输出分布中采样一个 token
- 重复上述过程
flowchart TD
A[输入序列] --> B["模型前向传播
计算成本高"]
B --> C["采样 1 个 token"]
C --> D[追加到序列]
D --> B
style B fill:#ffcdd2
style C fill:#ffe0b2
E[生成 N 个 token] --> F["需要 N 次前向传播
速度受限"]
style F fill:#ff8a65,color:#fff
核心瓶颈:串行生成,每次只能产生 1 个 token
对于一个 1000 token 的生成任务,即使模型计算再快,也至少需要 1000 次串行推理步骤。这就是延迟瓶颈。
投机解码的核心洞察
关键发现:很多 token 的生成是”可预测”的
比如:
- “人工”后面大概率是”智能”
- “今天天气”后面很可能是”真好”
- “hello”后面通常是”world”
投机解码的想法:用一个小的”草稿模型”快速猜测多个 token,然后用大模型一次性验证
flowchart TD
A[传统方式] --> B1["大模型逐个生成
1000 次前向传播"]
A --> B2["速度慢
延迟高"]
C[投机解码] --> D1["小模型快速猜测 K 个"]
C --> D2["大模型并行验证 K 个"]
C --> D3["大幅减少前向传播次数"]
B1 -.优化.-> D1
B2 -.优化.-> D3
style A fill:#ffebee
style C fill:#e8f5e9
style D1 fill:#66bb6a,color:#fff
style D2 fill:#42a5f5,color:#fff
style D3 fill:#ffa726,color:#fff
投机解码的核心思想
投机解码采用Draft then Verify(先草稿后验证)的策略:
两模型架构
草稿模型(Draft Model)
- 小模型(如 1B-3B 参数)
- 快速生成多个候选 token
- 可以是 distilled 模型或同一模型的早期层
目标模型(Target Model)
- 大模型(如 7B-70B 参数)
- 验证草稿的准确性
- 保证生成质量
工作流程
flowchart TD
subgraph Phase1["阶段1: 草稿生成"]
A1[输入序列] --> B1[草稿模型]
B1 --> C1["快速生成 K 个 token
x₁, x₂, ..., x_K"]
end
subgraph Phase2["阶段2: 并行验证"]
A2[输入 + K 个草稿 token] --> B2[目标模型]
B2 --> C2["一次性计算 K 个位置的分布"]
C2 --> D2["验证每个草稿 token
是否匹配目标分布"]
end
subgraph Phase3["阶段3: 接受或拒绝"]
A3[验证结果] --> B3{草稿是否正确?}
B3 -->|接受| C3[保留正确的 token]
B3 -->|拒绝| D3[从目标分布重新采样]
C3 --> E3[继续下一轮]
D3 --> E3
end
Phase1 --> Phase2
Phase2 --> Phase3
style Phase1 fill:#fff3e0
style Phase2 fill:#e3f2fd
style Phase3 fill:#e8f5e9
style C1 fill:#ffcc80
style C2 fill:#90caf9
style C3 fill:#a5d6a7
style D3 fill:#ef9a9a
投机解码的详细算法
算法步骤
假设置信度阈值为 $p$,草稿长度为 $K$:
步骤 1:草稿生成
草稿模型自回归生成 $K$ 个 token:
$$\hat{x}_1, \hat{x}_2, …, \hat{x}_K \sim P_{\text{draft}}(x | x_{1:t})$$
步骤 2:并行验证
目标模型一次性计算这 $K$ 个位置的概率分布:
$$P_{\text{target}}(x_1 | x_{1:t}),\ P_{\text{target}}(x_2 | x_{1:t}, \hat{x}_1),\ …,\ P_{\text{target}}(x_K | x_{1:t}, \hat{x}_{1:K-1})$$
步骤 3:投机接受
对于第 $i$ 个草稿 token $\hat{x}_{i}$,计算接受概率:
$$\alpha_i = \min\left(1,\ \frac{P_{\text{target}}(\hat{x}_i | x_{1:t+i-1})}{P_{\text{draft}}(\hat{x}_i | x_{1:t+i-1})}\right)$$
以概率 $\alpha_{i}$ 接受 $\hat{x}_{i}$,否则拒绝并从目标分布重新采样。
flowchart TD
A[草稿 token x̂ᵢ] --> B["计算 P_target(x̂ᵢ)"]
A --> C["计算 P_draft(x̂ᵢ)"]
B --> D["α = min(1, P_target / P_draft)"]
C --> D
D --> E{随机数 r < α?}
E -->|是| F["✅ 接受 x̂ᵢ"]
E -->|否| G["❌ 拒绝
从 P_target 采样"]
F --> H[继续验证下一个]
G --> I[终止验证,从该位置继续]
style D fill:#ffe0b2
style E fill:#ce93d8
style F fill:#a5d6a7
style G fill:#ef9a9a
一个具体示例
假设我们要生成”人工智能是未来的”:
传统方式:
1 | 输入: "人工" |
投机解码(K=3):
1 | 输入: "人工" |
flowchart LR
subgraph Traditional["传统方式"]
A1["大模型×4
4 次推理"] --> B1["输出 4 个 token"]
end
subgraph Speculative["投机解码"]
A2["小模型×1"] --> B2["草稿 3 个 token"]
B2 --> C2["大模型×1 验证"]
C2 --> D2["接受 2 个 + 采样 1 个"]
end
style Traditional fill:#ffebee
style Speculative fill:#e8f5e9
style A1 fill:#ffcdd2
style C2 fill:#66bb6a,color:#fff
style D2 fill:#42a5f5,color:#fff
加速比分析
理论加速比
设:
- $K$:草稿长度
- $\alpha$:平均接受率(0 到 1 之间)
- $T_{\text{draft}}$:草稿模型推理时间
- $T_{\text{target}}$:目标模型推理时间
每轮生成的期望 token 数:
$$
E[\text{tokens per round}] = \sum_{i=1}^{K} \prod_{j=1}^{i} \alpha_j \approx \frac{1 - \alpha^{K+1}}{1 - \alpha}
$$
加速比:
$$
\text{Speedup} \approx \frac{K \cdot T_{\text{target}}}{T_{\text{draft}} + T_{\text{target}}} \cdot \alpha_{\text{avg}}
$$
实际性能数据
以 LLaMA-70B(目标)+ LLaMA-7B(草稿)为例:
| 场景 | 草稿长度 K | 接受率 α | 加速比 |
|---|---|---|---|
| 代码生成 | 4 | 0.85 | 3.2x |
| 中文文本 | 3 | 0.75 | 2.5x |
| 数学推导 | 2 | 0.60 | 1.8x |
| 创意写作 | 3 | 0.65 | 2.1x |
flowchart TD
A[投机解码性能] --> B1["代码生成: 3.2x"]
A --> B2["中文文本: 2.5x"]
A --> B3["创意写作: 2.1x"]
A --> B4["数学推导: 1.8x"]
B1 --> C["草稿质量越高,加速比越大"]
B2 --> C
B3 --> C
B4 --> C
style A fill:#ff7043,color:#fff
style B1 fill:#66bb6a,color:#fff
style B2 fill:#42a5f5,color:#fff
style B3 fill:#ab47bc,color:#fff
style B4 fill:#ffa726
style C fill:#26c6da
关键规律:
- 草稿模型与目标模型越接近,接受率越高
- 结构化强的任务(代码、翻译)接受率更高
- 创意性强的任务接受率相对较低
投机解码的变体
1. Medusa(多头推测解码)
Medusa 在目标模型顶部添加多个”解码头”,每个头预测不同位置的 token:
flowchart TD
A[目标模型 backbone] --> B1[Head 0: 预测 t+1]
A --> B2[Head 1: 预测 t+2]
A --> B3[Head 2: 预测 t+3]
A --> B4[Head 3: 预测 t+4]
B1 --> C1[无需草稿模型]
B2 --> C1
B3 --> C1
B4 --> C1
C1 --> D[一次性生成多个候选]
D --> E[目标模型验证]
style A fill:#ffa726
style B1 fill:#66bb6a
style B2 fill:#66bb6a
style B3 fill:#66bb6a
style B4 fill:#66bb6a
style E fill:#42a5f5,color:#fff
优势:
- 不需要额外的草稿模型
- 所有头共享 backbone 表示
- 训练成本低
2. EAGLE(Extra Acceleration through Generation with Language Enhancement)
EAGLE 通过以下方式进一步优化:
- 使用目标模型的隐藏状态作为草稿模型的输入
- 动态调整草稿长度
- 更好的特征对齐
3. 自投机解码(Self-Speculative Decoding)
同一个模型既当草稿模型又当目标模型:
- 使用模型的早期层作为草稿
- 使用完整模型作为验证
- 无需额外模型,但加速比相对较低
flowchart TD
A[输入] --> B["模型层 1-10
草稿"]
B --> C["生成 K 个 token"]
C --> D["模型层 1-32
完整验证"]
D --> E[接受或拒绝]
style B fill:#ffcc80
style D fill:#90caf9
style E fill:#a5d6a7
代码实现(简化版)
下面是一个投机解码的简化实现,帮助理解核心逻辑:
1 | import torch |
投机解码 vs 其他推理加速技术
| 技术 | 加速原理 | 加速比 | 质量损失 | 适用场景 |
|---|---|---|---|---|
| 投机解码 | 小模型猜测+大模型验证 | 2-3x | 无 | 通用场景 |
| KV Cache | 缓存历史 K/V | 2-4x | 无 | 长序列生成 |
| Flash Attention | IO 优化计算 | 2-4x | 无 | 长序列计算 |
| 量化 | 降低精度 | 2-3x | 微小 | 资源受限 |
| 连续批处理 | 动态 batching | 10-20x | 无 | 高吞吐服务 |
flowchart TD
A[推理加速技术] --> B1["投机解码
算法级优化"]
A --> B2["KV Cache
内存优化"]
A --> B3["Flash Attention
计算优化"]
A --> B4["量化
精度优化"]
B1 --> C["质量无损
2-3x 加速"]
B2 --> D["质量无损
2-4x 加速"]
B3 --> D
B4 --> E["微小损失
2-3x 加速"]
style A fill:#ff7043,color:#fff
style B1 fill:#66bb6a,color:#fff
style C fill:#42a5f5,color:#fff
关键洞察:这些技术可以组合使用!
1 | 典型的高性能推理栈: |
实际应用场景
1. 交互式对话
flowchart LR
A[用户输入] --> B[投机解码生成回复]
B --> C["响应时间减少 50%"]
C --> D[提升用户体验]
style A fill:#bbdefb
style B fill:#66bb6a,color:#fff
style D fill:#ffa726
效果:
- GPT-4 级别模型的响应时间从 2 秒降到 0.7 秒
- 实时对话更流畅
2. 代码补全
- IDE 中的代码建议需要极低延迟
- 代码具有强结构性,草稿接受率高(0.8-0.9)
- 加速比可达 3x 以上
3. 批量翻译
- 翻译任务模式固定,投机解码效果好
- 结合 Continuous Batching 可实现高吞吐
4. 边缘设备部署
- 小模型在端侧,大模型在云端
- 端侧生成草稿,云端验证
- 降低云端计算压力
投机解码的局限性
1. 需要额外的草稿模型
flowchart TD
A[投机解码要求] --> B1["需要训练/选择草稿模型"]
A --> B2["草稿模型质量影响加速比"]
A --> B3["模型不匹配时效果差"]
B1 --> C["增加系统复杂度"]
B2 --> C
B3 --> C
style A fill:#ffcc80
style C fill:#ef9a9a
2. 任务依赖性
- 结构化任务(代码、翻译):接受率高,加速明显
- 创意任务(故事、诗歌):接受率低,加速有限
3. 实现复杂度
- 需要协调两个模型的推理
- 需要处理接受/拒绝逻辑
- 推理框架需要专门支持
4. 显存占用
- 需要同时加载草稿模型和目标模型
- 对于超大模型(如 175B),可能显存不足
解决方案:Medusa(不需要额外模型)或 Self-Speculative(同一模型不同层)
未来发展方向
timeline
title 投机解码发展历程
2023-01 : Google 提出 Speculative Decoding 理论框架
2023-06 : Medusa 发布 多解码头方法
2023-09 : EAGLE 提出 隐藏状态对齐优化
2024-01 : Self-Speculative Decoding 单模型方案
2024-06 : 主流推理框架支持 vLLM/TGI 集成
2025-? : 自适应草稿长度 动态优化策略
研究热点
自适应草稿长度
- 根据置信度动态调整 $K$
- 高置信度时增加草稿长度
- 低置信度时减少草稿长度
多草稿并行
- 同时生成多组草稿
- 选择接受率最高的草稿
与量化结合
- 草稿模型用 INT4
- 目标模型用 FP16
- 进一步降低延迟
流式生成优化
- Token-by-token 流式输出
- 结合 speculative 实现超低延迟
总结
投机解码通过”先猜后验”的策略,在不损失生成质量的前提下,将大语言模型的推理速度提升 2-3 倍。
flowchart TD
A[投机解码核心优势] --> B1["质量无损
数学保证"]
A --> B2["延迟降低
2-3x 加速"]
A --> B3["通用性强
适用于各种模型"]
A --> B4["可组合
与其他加速技术协同"]
B1 --> C[高效大模型推理]
B2 --> C
B3 --> C
B4 --> C
C --> D1[交互式应用]
C --> D2[代码补全]
C --> D3[实时翻译]
C --> D4[批量生成]
style A fill:#ff7043,color:#fff
style C fill:#42a5f5,color:#fff
style D1 fill:#66bb6a
style D2 fill:#ab47bc
style D3 fill:#26c6da
style D4 fill:#ffa726
核心价值:
- ✅ 数学保证:接受策略确保生成分布与目标模型完全一致
- ✅ 即插即用:无需修改模型架构,适用于任何自回归模型
- ✅ 生态成熟:vLLM、TGI 等主流框架已集成
- ✅ 组合优化:可与 KV Cache、Flash Attention、量化等技术叠加
投机解码代表了推理优化的一个重要方向:通过算法创新,在保持质量的同时突破性能瓶颈。随着技术的不断演进,它将在大模型落地中发挥越来越重要的作用。
参考资料
- Chen, C., et al. (2023). “Accelerating Large Language Model Decoding with Speculative Sampling”
- Leviathan, Y., et al. (2023). “Fast Inference from Transformers via Speculative Decoding”
- Cai, T., et al. (2023). “Medusa: Simple LLM Inference Acceleration Framework with Multiple Decoding Heads”
- Li, Y., et al. (2024). “EAGLE: Speculative Sampling Requires Rethinking Feature Uncertainty”
- vLLM Documentation: Speculative Decoding Integration