【学习笔记】投机解码:让大模型推理快 2-3 倍的「免费午餐」
前面三篇推理优化我们讲了第 11 篇 三板斧KV Cache / PagedAttention / Continuous Batching—— 优化吞吐第 12 篇 量化压缩 —— 优化显存第 13 篇 Flash Attention —— 优化prefill 延迟这一篇我们讲一个专门优化decode 延迟的奇思妙想——投机解码Speculative Decoding。它的神奇之处在于用一种「先猜后验」的方式让单个序列的生成速度提升 2-3 倍而且数学上完全无损。更神奇的是它的核心思想极其简单——让小模型先草拟大模型再验证——但这个简单想法背后是对 GPU 计算特性的深刻理解。如果你做过相关工作下面这些问题应该不陌生单用户场景下70B 模型怎么跑得更快为什么投机解码在 batch 大时反而没用Medusa、EAGLE、Lookup Decoding 都是什么投机解码不会改变输出吗真的无损vLLM 怎么开启投机解码读完本文你将能理解投机解码的核心洞察——为什么验证比生成便宜区分 4 种主流变种的差异、适用场景用 vLLM 实际启用投机解码并实测知道何时该用、何时不该用我们开始。一、为什么 Decode 是个独特的瓶颈1.1 Decode 阶段的特殊性回顾第 11 篇我们讲的 Prefill vs Decode阶段计算特性主要瓶颈Prefill一次处理 n 个 token并行度高算力compute-boundDecode一次处理 1 个 token串行生成显存带宽memory-boundDecode 阶段的核心痛苦每生成 1 个 token都要把整个模型权重从 HBM 读到 SRAM 一遍。对 Llama-3-70BINT870 GB 权重单次 decode 必须读 70 GBH100 显存带宽 3.35 TB/s理论最大速度3350 / 70 ≈48 tokens/s单序列这是个硬上限——再怎么优化单序列也快不过这个数。1.2 batch 救不了单用户第 11 篇我们讲过 Continuous Batching 能把吞吐量提到几千 tokens/s。但那是 batch 整体——单用户感知的速度仍然是 ~50 tokens/s。单用户视角48 tokens/s 在生成 batch 整体4800 tokens/s100 用户并发对单用户来说batch 不能加速我的请求。这就是为什么 ChatGPT 那种聊天场景打字速度是个绕不开的体验痛点。1.3 GPU 的「隐藏算力」但其实 GPU 在 decode 阶段算力是闲置的。H100 的算力 vs 带宽FP16 算力989 TFLOPS带宽3.35 TB/s算力/带宽比295意思是读 1 byte 数据GPU 能算 295 次。但 decode 阶段每个 token 只算约 2 次前向乘加。算力利用率约 0.7%。GPU 99% 的算力在 decode 时被浪费了。如果能把这浪费的算力利用起来——让 GPU 一次性算 N 个 token 而不是 1 个——速度就能提升 N 倍。这正是投机解码的切入点。二、投机解码的核心原理2.1 一个反直觉的洞察验证 N 个 token 和生成 1 个 token对 GPU 来说时间几乎一样。为什么因为 attention 在 prefill 模式下可以并行。具体说生成 1 个 token处理 1 个 query往 KV Cache 找历史 → forward 一次验证 N 个 token把 N 个 query 一起送入 → 同样 forward 一次两者计算量差异很大N 倍但都是 1 次 forward——而 forward 时间主要由「读完模型权重一遍」决定与计算量关系不大memory-bound。所以在 decode 时一次性验证 N 个 token 几乎是免费的。2.2 投机解码的核心算法那怎么搞到 N 个候选 token 来验证用一个小模型先草拟。完整流程 1. Draft 模型生成 K 个候选 token (快) 2. Target 模型一次性 forward 验证 K 个 token 3. 比较两个模型的概率分布决定接受哪些 4. 至少接受 1 个最多 K 个 5. 重复关键问题怎么决定接受这里有数学保证——通过rejection sampling最终输出的概率分布与Target 模型直接生成完全一致。2.3 接受策略Rejection Sampling设 Draft 模型在某位置给出 tokenx的概率是q(x)Target 模型给出x的概率是p(x)情况 Ap(x) q(x) → 直接接受这个 token 情况 Bp(x) q(x) → 以 p(x)/q(x) 的概率接受 → 否则从 normalized(max(0, p - q)) 重新采样一个 token这种策略让最终采样概率严格等于 p(x)——也就是 Target 模型自己直接采样的分布。关键认知投机解码数学上完全无损——和 Target 模型直接生成的结果分布完全一致在贪心解码下甚至 token 序列也完全相同。2.4 加速效果取决于什么加速比 ≈ (1 接受长度) / (1 Draft 模型相对耗时)两个关键因素接受长度 (Accept Length)Draft 模型预测准的连续 token 数Draft 模型耗时占比Draft 模型相对 Target 模型的速度举例Target Llama-3-70BDraft Llama-3-1BDraft 耗时 ≈ Target 的 1/30平均接受长度 ≈ 4实际加速约 2.5-3×2.5 一个完整的例子Prompt: 今天天气真 Draft 模型生成 4 个候选: 好啊我想 Target 模型一次性 forward 这 4 个 token 位置 0 (好): Target 概率高 → 接受 位置 1 (啊): Target 概率高 → 接受 位置 2 (): Target 概率高 → 接受 位置 3 (我): Target 觉得应该是出 → 拒绝重新采样得到出 最终输出: 好啊出 下一轮 Draft 从出继续生成 4 个候选 ...一次 Target forward 输出了 4 个 token——而平时只能输出 1 个。4× 加速。三、投机解码的四大变种3.1 经典投机解码2022, Google DeepMind 同时提出最朴素的形式用一个独立的小模型做 Draft。典型组合TargetDraft加速Llama-3-70BLlama-3-1B / 8B2-3×GPT-4GPT-3.52×Claude OpusClaude Haiku2.5×条件Draft 和 Target 必须tokenizer 完全一致不一致就没法验证Draft 越准越好但不一定是越大越好——平衡点Draft 越快越好优点概念简单不需要改 Target 模型通用缺点需要部署 2 个模型显存占用增加通常 Draft 比 Target 小 7-10 倍才能有收益3.2 Medusa2024自己「分裂」出多个头不想部署两个模型那就让 Target 模型自己同时预测多个未来 token。Medusa 的做法在 Target 模型最后一层 加 K 个额外的 head head_0: 预测下一个 token (原本就有) head_1: 预测下下个 token head_2: 预测下下下个 token ... 每个 head 是个轻量分类器只需训练几小时。工作流程一次 forward每个 head 给出多个候选形成候选 token 树Target 模型再 forward 一次验证整个树接受最长的有效路径优点只用一个模型训练成本低额外的 head 几小时训完加速2-3×缺点需要轻微改造模型接受长度通常比双模型方案短3.3 EAGLE 系列2024-2025当下 SOTAEAGLE 把投机解码推到了新高度。核心思想用 Target 模型的 hidden state 而不是最终 logits 做 draft。原因hidden state 信息量远高于 logitslogits 是 hidden state 投影到 vocab 后的结果用它做 draft 更准。EAGLE 的结构Target 模型 ├─ 最后一层 hidden state ──→ EAGLE 小模型 (1-2 层 Transformer) └─ logits 输出 ↓ 生成候选 token 树 ↓ Target 验证EAGLE-2 (2024 中)引入了动态树结构——根据置信度自适应调整候选树形状。EAGLE-3 (2025)进一步把多层 hidden state 一起利用加速达到 3-5×。实测Llama-3-70B方法加速无投机1×经典Llama-1B Draft2.3×Medusa2.5×EAGLE-23.5×EAGLE-34.5×EAGLE 系列已经成为 vLLM、SGLang 等推理框架的默认推荐。3.4 N-gram / Lookup Decoding不需要模型最极端的方案——根本不用模型来做 draft。核心洞察很多场景下输出和输入有大量重复RAG模型经常引用 prompt 中的原文Code 助手modify 代码时大量复用原代码多轮对话经常重复之前提到的实体翻译人名地名直接保留Lookup Decoding 做法1. 从 prompt 已生成 token 中提取所有 n-gram 2. 当当前生成位置匹配某个 n-gram 的前缀 3. 直接用 n-gram 的后续作为候选 4. Target 验证优点零额外模型零额外显存实现极简缺点只对重复输入场景有效通用对话场景效果差适用场景RAG → 2-3× 加速Code 完成 → 3-5× 加速代码重复多长文档总结 → 2× 加速闲聊 → 几乎无收益3.5 四种方法对比方法需要额外模型加速比适用场景实现复杂度经典是小模型2-3×通用中Medusa否加 head2-3×通用中EAGLE-3否轻量小网络3-5×通用中Lookup否2-5×视场景RAG / Code极低四、工程实战怎么启用投机解码4.1 vLLM 启用 EAGLE 投机解码# vLLM 0.6 支持 EAGLE vllm serve meta-llama/Llama-3-70B-Instruct \ --speculative-model yuhuili/EAGLE-LLaMA3-Instruct-70B \ --num-speculative-tokens 5 \ --use-v2-block-manager \ --speculative-draft-tensor-parallel-size 1 \ --tensor-parallel-size 4关键参数--speculative-modelDraft 模型EAGLE 权重--num-speculative-tokens每次猜测的 token 数典型 4-8--use-v2-block-manager必须开--speculative-draft-tensor-parallel-sizeDraft 的并行配置4.2 vLLM 启用经典投机解码如果你的 Target 是 70B用 8B 做 Draftvllm serve meta-llama/Llama-3-70B-Instruct \ --speculative-model meta-llama/Llama-3-8B-Instruct \ --num-speculative-tokens 5 \ --tensor-parallel-size 4⚠️Tokenizer 必须完全一致——同家族模型才行Llama → Llama不能 Llama → Qwen。4.3 vLLM 启用 Lookupn-gram投机vllm serve meta-llama/Llama-3-70B-Instruct \ --speculative-model [ngram] \ --num-speculative-tokens 5 \ --ngram-prompt-lookup-max 4特别适合 RAG 场景——零成本启用。4.4 实测性能数据我们用 Llama-3-70B INT8 在 H100 × 2 上做对比单序列、prompt 1K、生成 500配置TPOT (ms)tokens/s相对无投机22451×Lookup (n-gram)12831.8×经典 (8B Draft)91102.5×Medusa81252.8×EAGLE-352004.4×输出完全一致贪心解码下逐 token 比对无差异。4.5 选 Draft 模型的经验如果用经典投机解码Draft 模型选择规则Target 规模推荐 Draft加速7B-14B0.5B-1B2×32B1B-3B2.5×70B7B-8B2.5-3×405B / 671B13B-32B3×规则Draft 约为 Target 的 1/10-1/30 大小。太小不准接受率低太大太慢draft 自己耗时多。五、避坑 决策建议5.1 投机解码的「死敌」大 batch投机解码最大的反直觉事实batch 越大投机解码的收益越小。原因投机解码利用的是闲置算力大 batch 已经把算力打满没有免费午餐可吃了实测Batch Size投机解码加速13×42×161.3×641.05×256~1×结论单用户场景batch1投机解码 必开高并发场景batch 32投机解码意义不大中等并发根据 SLA 决定5.2 适用场景判断场景投机解码推荐度单用户对话ChatGPT 风格⭐⭐⭐⭐⭐ 必开Code 助手IDE 集成⭐⭐⭐⭐⭐ 必开RAG重复内容多⭐⭐⭐⭐ 推荐 LookupAgent单次复杂任务⭐⭐⭐⭐ 推荐大流量 APIbatch 大⭐⭐ 边际收益批量任务离线处理⭐ 不必开5.3 5 大常见坑坑 1Tokenizer 不匹配症状启用后直接 crash 或输出乱码。对策Target 和 Draft 必须完全相同tokenizer 和 vocab。同家族模型一般 OK跨家族不行。坑 2Draft 太大症状开了投机解码反而变慢。对策Draft 模型本身耗时不能超过 Target 的 1/3否则得不偿失。坑 3num_speculative_tokens 设置不当症状加速不明显。对策设小如 2接受率高但收益少设大如 16接受率下降快经验值4-8坑 4长尾恶化症状99% 延迟反而比平均延迟差。原因投机解码对某些难预测内容数字、代码、专有名词效果差。对策监控 p99 延迟必要时为不同请求路径选不同策略坑 5在采样温度高时失效症状温度 1.0 时加速比明显下降。原因高温度让 Target 分布平坦rejection sampling 拒绝率高。对策温度低的场景 0.5投机解码效果最好温度高的场景考虑改用 Lookup 等不依赖 Draft 分布的方法5.4 进阶投机解码 其他优化的组合投机解码可以和大部分推理优化叠加组合协同效果投机解码 Flash Attention✓ 完美兼容投机解码 PagedAttention✓ vLLM 默认支持投机解码 INT4 量化✓ Target/Draft 都可量化投机解码 Continuous Batching△ batch 大时效益降实际生产部署的豪华套餐Llama-3-70B AWQ INT4 Flash Attention v3 PagedAttention EAGLE-3 投机解码 FP8 KV Cache单 H100 上的吞吐从无优化的 30 tokens/s 提升到3500 tokens/s——综合100× 加速。六、扩展话题与下一篇预告6.1 投机解码的未来方向研究热点自适应 N根据当前 token 难度动态调整候选数量多 Draft 集成多个小模型同时草拟取共识Draft 在线学习Draft 模型根据 Target 反馈持续微调Tree-based decoding 进化更复杂的候选树结构6.2 大公司怎么用OpenAI、Anthropic 用没用投机解码虽然没公开承认但 ChatGPT / Claude 的延迟特性强烈暗示用了单用户感知速度远超理论极限70B 单卡 48 tokens/s vs Claude 实测 100速度对内容类型敏感代码块更快OpenAI o1 系列的thinking阶段特别适合投机解码——因为它会生成大量草稿思考重复模式很多。6.3 投机解码 vs 多 Token 预测MTPDeepSeek V3 引入了MTPMulti-Token Prediction——这是训练时就让模型一次预测多个 token。和投机解码思想相似但是训练阶段的优化。两者可以叠加MTP 让模型本身就能多 token 预测投机解码进一步加速 decodeDeepSeek V3 的 R1 模型据说就用了这种组合。6.4 不适用场景虽然投机解码很强但这些场景不要用极致追求吞吐的批处理用 batch 更划算极小模型 7B单用户 —— 已经够快没必要嵌入式 / 端侧场景 —— 显存吃紧不容许多模型七、结语从「省时间」到「省 GPU」读完本文你应该明白Decode 阶段 GPU 99% 算力闲置——这是投机解码的物理基础验证 N 个 token 几乎等于生成 1 个 token 的时间——这是核心洞察数学上无损——rejection sampling 保证输出分布与原模型一致EAGLE-3 是当下 SOTA——3-5× 加速已在主流推理框架可用Lookup Decoding 在 RAG / Code 场景免费 2-3×大 batch 下意义不大——这是投机解码最重要的边界条件参考文献14.投机解码让大模型推理快 2-3 倍的「免费午餐」