引言:大模型推理的”慢”到底慢在哪里?
如果你在生产环境中部署过 GPT 级别的自回归语言模型,一定对 Token 生成速度之慢感同身受:即使在 A100/H100 这类顶级 GPU 上,大模型的 Decode 阶段每步也仅产出 1 个 Token,延迟通常需要几十毫秒。以一个 2,000 Token 的回复为例,单次推理请求的耗时可能长达数十秒。
为什么如此之慢?根本原因在于大模型推理的 Decode 阶段是严重的访存受限(Memory-Bound)操作。在每次迭代中,模型需要将全部参数从 HBM(High Bandwidth Memory)读入计算单元,但仅仅计算 1 个 Token 的输出——计算量(FLOPs)极小而访存量极大,导致 GPU 的计算利用率往往仅有个位数百分比。具体而言,在 FP16 精度下,A100-80G 的算力峰值为 312 TFLOPS,但一次 Decode 操作的实际算力利用率往往低于 5%。
KV Cache 的引入缓解了重复计算,但每次 Token 生成仍需读取完整的模型权值和逐步增长的 KV Cache,访存带宽依然是无法绕过的瓶颈。面对这一困境,工业界和学术界都在寻找”如何用一个 GPU 单位时间的计算能力生成更多 Token”的突破方案。

Speculative Decoding(推测解码)正是在这一背景下崭露头角。它跳出了”每次推理只出一 Token”的思维定式,核心思路非常直观:用一个更小的”草稿模型”快速生成多个候选 Token,再用大模型一次性验证这些 Token 的正确性,从而在维持生成质量完全不变的前提下实现 2x-3x 的推理加速。
Speculative Decoding 的核心原理
自回归解码的本质局限
自回归(Autoregressive)生成的标准流程是:给定已生成的 Token 序列 x_1, x_2, …, x_t,模型预测下一个 Token 的分布 P(x_{t+1} | x_1, …, x_t),采样后将其追加到序列末尾,重复此过程直至生成结束标记。这意味着生成 N 个 Token 需要 N 次串行的模型前向传播——这是延迟的源头。
一个值得注意的反直觉事实是:在 Batch Size = 1 的推理场景中,执行一次可以并行处理 M 个 Token 的前向传播,其耗时和单 Token 的前向传播几乎相同。因为两者的计算规模都由模型参数量的访存主导,而不是由 Token 数量的计算量主导。这为 Speculative Decoding 提供了理论可行性:为什么不一次提交多个 Token 进行一次大模型验证呢?
草稿-验证(Draft-Verify)范式
Speculative Decoding 的工作流程可以概括为以下三个步骤:
- 草稿生成(Draft):使用一个高效的小模型(Draft Model,通常是大模型参数的 1/10 甚至更小),自回归地生成 γ 个候选 Token 序列 y_1, y_2, …, y_γ。因为小模型参数量少,这一步的速度远快于大模型。
- 并行验证(Verify):将大模型在输入序列后拼接上这 γ 个候选 Token,执行一次完整的前向传播。大模型一次性计算出每个位置对所有候选 Token 的接受概率。
- 接受/拒绝采样(Rejection Sampling):基于 Rejection Sampling 机制,逐个位置判断候选 Token 是否可以通过验证。通过的位置的 Token 直接保留;被拒绝的位置,从大模型自身的分布中重新采样一个 Token 替换,并在此处终止验证,剩余的候选 Token 被丢弃。
整个过程的关键在于:Rejection Sampling 保证了大模型和草稿模型的联合采样分布与大模型自身的原始分布完全一致——这意味着 Speculative Decoding 是一个无损的加速方法,生成结果的质量在数学意义上不会受到任何影响。
Rejection Sampling 的数学保证
用数学语言来描述这个验证过程:设大模型的目标分布为 q(x),草稿模型的分布为 p(x),对于每个位置 t,我们从 p(x) 采样得到一个候选 Token,然后以概率 min(1, q(x)/p(x)) 接受它。如果被拒绝,从分布 (q(x) – p(x))⁺ / Σ(q – p)⁺ 中重新采样。
这一机制与 Metropolis-Hastings 算法有着深刻的联系。可以证明:经过这种接受/拒绝处理后,最终的 Token 分布严格等于大模型的原始分布 q(x),不会引入任何偏差或质量损失。换言之,Speculative Decoding 在「生成质量」维度上是完全无损的——这一点对于生产环境中的质量敏感型应用来说至关重要。
# 伪代码:Speculative Decoding 的单步过程
def speculative_decoding_step(target_model, draft_model, prefix, gamma=5):
# Step 1: Draft — 用小模型快跑 gamma 步
draft_tokens = []
draft_logits = []
for _ in range(gamma):
logits = draft_model.forward(prefix + draft_tokens)
token = sample(logits[-1])
draft_tokens.append(token)
draft_logits.append(logits[-1])
# Step 2: Verify — 大模型一次前向传播
target_logits = target_model.forward(prefix + draft_tokens)
# target_logits.shape = (gamma+1, vocab_size)
# Step 3: Rejection Sampling
accepted = []
rng = random_generator()
for i in range(gamma):
q = softmax(target_logits[i])
p = softmax(draft_logits[i])
r = rng.random()
if r < min(1.0, q[draft_tokens[i]] / p[draft_tokens[i]]):
accepted.append(draft_tokens[i])
else:
# 拒绝:从 q - p 的残余分布重新采样
residual = max(0, q - p)
new_token = sample(residual / sum(residual))
accepted.append(new_token)
break
return prefix + accepted
主流实现方案对比
自 DeepMind 在 2022 年发表《Fast Inference from Transformers via Speculative Decoding》以来,工业界涌现出多种实现方案,各有侧重。下面对主要方案进行对比分析:
| 方案 | 出处 | 草稿模型 | 加速比 | 优点 | 缺点 |
|---|---|---|---|---|---|
| 标准 Speculative Decoding | DeepMind 2022 | 独立小模型 | 2x-3x | 实现简单,普适性强 | 需额外加载一个模型,显存开销加倍 |
| Medusa | 2024 | 大模型多头预测头 | 2x-3.5x | 无需独立草稿模型,节省显存 | 需微调预测头,部署稍复杂 |
| Eagle | 2024 | 特征层预测(Feature-Level Draft) | 2x-4x | 利用大模型内部特征,接受率高 | 实现最复杂,工程化挑战大 |
| Lookahead Decoding | MIT 2023 | Jacobi 迭代(非自回归) | 1.5x-2x | 无需额外模型,纯工程方法 | 加速比相对有限 |
标准 Speculative Decoding:DeepMind 的开山之作
DeepMind 提出的方案最为经典:额外加载一个参数更少的 Draft Model(如 7B 大模型配 1B 草稿模型),用小模型快速自回归生成 γ 个候选 Token,然后大模型并行验证。在 γ=5 的情况下,实际平均生成的 Token 数约为 3-4 个。如果 Draft Model 与大模型的对齐程度较高,接受率可达 70%-90%。
在实践中,这种方法需要双倍的显存来容纳两个模型。对于显存已经捉襟见肘的 7B/13B 级别部署来说,这是一个不小的负担。不过很多生产系统中已经使用了多 GPU 推理方案(Tensor Parallelism / Pipeline Parallelism),可以将草稿模型部署在独立的 GPU 上。
Medusa:用预测头替代独立模型
加州大学伯克利分校提出的 Medusa 另辟蹊径:它不去加载一个额外的草稿模型,而是在大模型的最后一层 Transformer 之上添加 K 个轻量级预测头(Draft Heads),每个预测头负责预测未来第 i 步的 Token。这些预测头只有非常少的参数(通常只有一层 MLP + LayerNorm),因此额外显存开销可以忽略不计。
Medusa 的部署流程分为两步:首先在大模型的同源训练数据上对预测头进行微调(仅更新预测头参数,不改变原始模型),然后在推理时利用这 K 个预测头同时生成 K 组候选 Token,最后通过 Tree Attention 机制并行筛选出最优序列。
# Medusa 架构示意
class MedusaModel(nn.Module):
def __init__(self, base_model, num_heads=5, head_dim=2048):
super().__init__()
self.base_model = base_model # 冻结参数
self.medusa_heads = nn.ModuleList([
nn.Sequential(
nn.Linear(base_model.config.hidden_size, head_dim),
nn.SiLU(),
nn.Linear(head_dim, base_model.config.vocab_size)
)
for _ in range(num_heads)
])
def forward(self, input_ids):
hidden_states = self.base_model(input_ids, output_hidden_states=True)
# 从最后一个隐藏状态预测未来多个 Token
draft_tokens = []
for head in self.medusa_heads:
logits = head(hidden_states.last_hidden_state[:, -1, :])
draft_tokens.append(logits.argmax(dim=-1))
return torch.stack(draft_tokens, dim=1) # (batch, num_heads)
Medusa 的优势在于无需额外加载模型,对已部署的服务改造成本很低。但其预测头的训练需要一定量的对齐数据,且在非对齐场景下(如 Prompt 风格与训练数据差异很大时)接受率可能下降。
生产环境中的工程实践
方案选择决策树
面对多种 Speculative Decoding 方案,在实际部署中如何选择?以下是一个实用的决策框架:
- 显存充足(如 H100 80G × 多卡):选择标准 Speculative Decoding,Draft Model 用大模型同系列的较小版本(如 LLaMA-3.1-70B 配 LLaMA-3.1-8B),接受率最高、实现最稳定。
- 显存紧张(单卡部署 7B-13B 模型):选择 Medusa 或 Eagle,通过轻量预测头实现加速,避免额外显存开销。
- 无法修改模型权重:选择 Lookahead Decoding 或其他基于工程侧的方案,无需训练或微调。
- 批处理场景(Batch Serving):在 vLLM 等推理引擎中,批处理天然提高了 GPU 利用率,Speculative Decoding 的加速效果会有所稀释(约 1.3x-1.8x),但仍值得启用。
vLLM 中的 Speculative Decoding 配置
目前主流的推理引擎 vLLM(v0.6.0+)已经原生支持 Speculative Decoding。以下是一个典型的配置示例:
# 使用 vLLM 启动 Speculative Decoding
from vllm import LLM, SamplingParams
# 使用标准 Speculative Decoding(独立草稿模型)
llm = LLM(
model="meta-llama/Llama-3.1-70B-Instruct",
speculative_model="meta-llama/Llama-3.1-8B-Instruct", # 草稿模型
num_speculative_tokens=5, # γ 值
speculative_max_model_len=4096,
use_v2_block_manager=True,
enable_chunked_prefill=False,
)
# 使用 Medusa(多头预测)
llm = LLM(
model="my-org/llama-medusa-heads",
speculative_model="medusa", # 使用 Medusa 模式
num_speculative_tokens=5,
medusa_num_heads=5,
use_v2_block_manager=True,
)
# 推理时无需额外参数,透明加速
sampling_params = SamplingParams(temperature=0.6, top_p=0.9, max_tokens=1024)
output = llm.generate("请用 Python 实现一个快速排序算法", sampling_params)
γ 参数的优化策略
Speculation Length(γ 值)是影响加速效果的关键超参数。γ 太小则加速效果不明显;γ 太大则草稿模型的生成延迟增加,且尾部 Token 的接受率天然下降(因为草稿模型在长序列上偏离大模型分布的方差更大),浪费大模型的验证计算。
实际工程经验表明:
- 对于标准 Speculative Decoding(模型对齐度好),γ=5~7 是最优区间
- 对于 Medusa(预测头精度有限),γ=3~5 更合适
- 高 Temperature 采样(如 T=1.0)下接受率比低 Temperature(T=0.1)低约 10-15%,应适当降低 γ
- 应实现自适应的 γ 调整:当最近的接受率高于 80% 时适当增加 γ,低于 50% 时减少 γ
# 自适应 γ 调整算法(简化版)
class AdaptiveSpeculationLength:
def __init__(self, min_gamma=2, max_gamma=10, initial_gamma=5):
self.gamma = initial_gamma
self.min_gamma = min_gamma
self.max_gamma = max_gamma
self.recent_acceptance = deque(maxlen=50)
def update(self, accepted_count, gamma):
rate = accepted_count / max(gamma, 1)
self.recent_acceptance.append(rate)
avg_rate = mean(self.recent_acceptance)
if avg_rate > 0.8:
self.gamma = min(self.gamma + 1, self.max_gamma)
elif avg_rate < 0.5:
self.gamma = max(self.gamma - 1, self.min_gamma)
return self.gamma
显存优化与模型放置策略
在多 GPU 环境中,一个常见的优化是将大模型和草稿模型部署在不同的 GPU 上,通过 NVLink/PCIe 传输 KV Cache 和 Token 序列。在 2×A100 配置中,一个合理的分配方案是:
- GPU 0:大模型(30-70GB 显存占用)
- GPU 1:草稿模型(3-8GB 显存占用)+ KV Cache 共享缓冲
这样可以充分利用 GPU 1 的空闲显存,同时避免大模型加载草稿模型导致的显存碎片化。如果使用 NVIDIA 的 MIG(Multi-Instance GPU)技术,还可以在同一张 GPU 上切分出两个独立的实例分别运行大模型和草稿模型。
性能实测数据与收益分析
以下是基于 LLaMA-3.1-70B 搭配 LLaMA-3.1-8B 的实测数据(A100-80G × 1,FP16,Batch Size=1):
| 配置 | 平均 Token/步 | Tokens/s | 加速比 | 接受率 |
|---|---|---|---|---|
| 无推测解码(基准) | 1.0 | 28.5 | 1.0x | — |
| Spec Decoding (γ=5) | 3.2 | 72.8 | 2.55x | 76% |
| Spec Decoding (γ=7) | 3.6 | 78.4 | 2.75x | 68% |
| Medusa (K=5) | 2.8 | 65.3 | 2.29x | 62% |
| Lookahead Decoding | 2.1 | 48.5 | 1.70x | — |
可以看到,标准 Speculative Decoding 在 γ=5 时获得了 2.55x 的加速比,这是在保持完全相同的生成质量下实现的。值得注意的是,随着 γ 从 5 增加到 7,平均每步生成的 Token 数从 3.2 增加到 3.6,但因为草稿模型的生成耗时增加了,端到端加速比的边际收益递减。
局限性分析与注意事项
Speculative Decoding 并非万能灵药,在实际部署中需要注意以下几个关键限制:
草稿模型对齐度是关键瓶颈
Draft Model 与 Target Model 的分布对齐程度直接决定了接受率和加速比。如果两者在预训练数据、SFT 数据或 Prompt 风格上存在显著差异,接受率可能骤降至 30% 以下,此时 Speculative Decoding 反而可能因草稿生成的开销而拖慢整体速度。实践中建议使用同一系列模型(如 LLaMA 系列的大版本配小版本),或者为草稿模型做专门的蒸馏训练以对齐分布。
批处理场景下的效果稀释
当推理系统采用动态批处理(Continuous Batching)时,Speculative Decoding 的加速效果会显著下降。原因在于批处理本身已经大幅提高了 GPU 的计算利用率,而 Speculative Decoding 需要等待草稿模型先生成候选序列,这会打断批处理的流水线节奏。在 Batch Size > 16 的高并发场景下,加速比通常降至 1.2x-1.5x。
长文本生成中的接受率衰减
实验表明,随着生成序列的增长(超过 1,024 Token),草稿模型的接受率呈现单调下降趋势。这是因为草稿模型在长距离依赖上越来越难以与大模型保持一致的分布。一种缓解策略是在长文本生成场景中动态降低 γ 值,或者在序列长度超过阈值后关闭 Speculative Decoding。
硬件约束
Speculative Decoding 需要在显存中同时容纳大模型和草稿模型(或 Medusa 预测头),增加了部署的硬件门槛。在 A10/RTX 4090 等 24GB 显存级别的显卡上,部署 7B + 1B 的模型组合已经显得吃力,且草稿模型的前向传播也会消耗一定的计算资源。对于这类场景,可以考虑使用量化后的草稿模型(如 INT4 量化),将显存占用降低约 60%。
未来展望
Speculative Decoding 作为大模型推理加速家族中的一员,正在快速演进。以下几个方向值得关注:
- 多草稿模型集成:同时使用多个不同特点的草稿模型,通过集成策略提高接受率。
- 自蒸馏草稿模型:从大模型自身的推理过程中蒸馏出草稿模型,从根本上对齐分布。
- 硬件事物:NVIDIA 等厂商正在探索在 GPU 硬件层面原生支持 Token 级并行验证指令,这将使 Speculative Decoding 的延迟进一步降低。
- 与 KV Cache 量化联合优化:将 Speculative Decoding 与 INT8/INT4 KV Cache 量化结合,在有限显存下运行更大的草稿模型。
- Mobile/Edge 部署:在手机 NPU 上部署极简草稿模型,与大模型云服务配合实现端云协同推理。
总结
Speculative Decoding 是当前大模型推理加速领域中最具实用价值的技术之一,其「以小博大」的思路——用轻量级草稿模型探索候选路径,再由大模型并行验证——在保持生成质量完全不变的前提下,实现了 2x-3x 的推理加速。与量化和剪枝等方法不同,它不牺牲模型精度,也不需要重新训练或微调基础模型,因此特别适合对质量要求极其严苛的生产环境。
在实际工程落地时,需要根据显存约束、吞吐量需求和模型对齐度综合选择合适的方案。标准 Speculative Decoding 适合显存充裕的场景,Medusa 适合显存敏感型部署,而 Lookahead Decoding 则适合无法修改模型权重的受限环境。配合合理的 γ 调参与自适应策略,Speculative Decoding 可以成为大模型推理优化工具箱中不可或缺的一环。
随着大模型体量的持续增长和实时性需求的不断提升,Speculative Decoding 及其衍生技术在 AI Infra 基础设施中的重要性只会越来越大。对于 AI Infra 工程师而言,深入理解其原理落点和工程细节,已经成为必备的核心技能之一。
汤不热吧