Gemma 4 多 token 预测:用推测解码把推理速度拉到 ~3 倍

2026-05-25 15 预计阅读时间:1 分钟
来源:infoq.com AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:11 分钟

大模型推理的瓶颈从来不是算力不够,而是逐 token 生成时的串行等待——每一步都要等前一个 token 出来才能算下一个。Gemma 4 引入了多 token 预测(Multi-Token Prediction, MTP)drafter,配合推测解码(speculative decoding)把这条串行链路撕开:小模型一次猜出多个 token,大模型一遍验证,速度提升最高约 3 倍,输出质量不变。

推测解码的核心逻辑

传统自回归生成是"生成一个 → 送回模型 → 生成下一个",循环往复。推测解码换了个思路:

  1. Drafter 快速起草——一个轻量模型(或 MTP 头)并行预测接下来的 k 个 token。
  2. 主模型一次性验证——主模型对这 k 个 token 做一次前向传播,同时产出每个位置的概率分布。
  3. 按概率裁剪——从第一个 token 开始逐个比对,只要 drafter 的预测与主模型分布吻合就接受;遇到不吻合就拒绝,并以主模型的采样结果替代,后续 draft token 全部丢弃。

关键点:主模型只做了一次前向传播,却可能接受多个 token。接受率越高,等效吞吐越大。

MTP Drafter 与传统小模型 Drafter 的区别

以前的推测解码通常用一个更小的独立模型做 drafter(比如用 Gemma 2B 为 Gemma 27B 起草)。问题在于:小模型和主模型的训练数据、对齐方式可能不一致,接受率波动大。

Gemma 4 的 MTP drafter 直接在主模型架构内扩展——在原有 next-token 预测头之外,附加多个并行预测头,每个头负责预测位置 t+1、t+2、……t+k 的 token。这些头与主模型共享大部分参数,训练时联合优化,因此:

  • 分布一致性高——drafter 和主模型"住在同一个大脑里",预测风格天然对齐,接受率更稳定。
  • 无额外模型加载——不需要单独下载和部署一个小模型,内存和工程复杂度更可控。
  • k 值可调——预测头数量是架构参数,可以根据延迟/吞吐目标选择 k=4 或 k=8 等配置。

实际跑起来:用 vLLM 开启推测解码

vLLM 从 0.6 版起支持推测解码,Gemma 4 的 MTP drafter 可以直接作为 draft model 配置。以下是一个最小可运行示例:

# 安装 vLLM(确保版本 ≥ 0.6.0)
pip install "vllm>=0.6.0"

# 启动推理服务,启用 MTP speculative decoding
# --model: 主模型路径
# --speculative-model: MTP drafter 模型路径(与主模型同系列)
# --num-speculative-tokens: 一次起草的 token 数,建议 4-5
# --speculative-max-model-len: drafter 最大序列长度,通常略小于主模型
vllm serve google/gemma-4-27b-it \
  --speculative-model google/gemma-4-27b-it-mtp-drafter \
  --num-speculative-tokens 5 \
  --speculative-max-model-len 2048 \
  --gpu-memory-utilization 0.9 \
  --max-model-len 4096

启动后用 OpenAI 兼容 API 调用:

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="empty")

response = client.chat.completions.create(
    model="google/gemma-4-27b-it",
    messages=[
        {"role": "user", "content": "用三句话解释什么是推测解码,面向有基础的开发者。"}
    ],
    max_tokens=256,
    temperature=0.7,
)

print(response.choices[0].message.content)

注意gemma-4-27b-it-mtp-drafter 是示例模型名,实际发布时请替换为 Google 官方 Hub 上的 MTP drafter 模型 ID。如果官方只发布了一个统一模型(MTP 头内置),则 --speculative-model 可以指向同一模型,vLLM 会自动识别 draft 头。

用 transformers 手动验证接受率

如果你想更直观地理解推测解码的内部运作,可以用 transformers 手动跑一次 MTP 起草 + 验证:

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

model_id = "google/gemma-4-27b-it"  # 替换为实际可用模型
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
    model_id, torch_dtype=torch.bfloat16, device_map="auto"
)

prompt = "推测解码的核心思想是"
input_ids = tokenizer.encode(prompt, return_tensors="pt").to(model.device)

# ---- Step 1: MTP drafter 一次预测 k 个 token ----
k = 4
with torch.no_grad():
    # 主模型前向,拿到 logits(同时作为验证基准)
    outputs = model(input_ids)
    main_logits = outputs.logits[0, -1]  # 最后位置的 logits

    # 模拟 drafter:从 main_logits 采样 k 个候选
    # 实际 MTP 头会有独立的 logits,这里用主模型 top-k 近似演示
    top_k_probs = torch.softmax(main_logits, dim=-1)
    draft_tokens = torch.multinomial(top_k_probs, num_samples=k)  # [k]

# ---- Step 2: 逐个验证 ----
accepted = 0
for i, draft_tok in enumerate(draft_tokens):
    # 主模型在该位置的概率
    p_main = torch.softmax(main_logits, dim=-1)[draft_tok].item()
    # drafter 的概率(简化:假设 drafter 置信度略低)
    p_draft = p_main * 0.9  # 近似,实际需从 MTP 头 logits 计算

    # 接受条件:uniform(0,1) < p_main / p_draft
    threshold = p_main / max(p_draft, 1e-10)
    if torch.rand(1).item() < min(threshold, 1.0):
        accepted += 1
        print(f"  位置 {i}: 接受 token '{tokenizer.decode([draft_tok])}' "
              f"(p_main={p_main:.4f})")
    else:
        # 拒绝后从主模型分布重新采样,后续 draft 全部丢弃
        corrected = torch.multinomial(torch.softmax(main_logits, dim=-1), 1)
        print(f"  位置 {i}: 拒绝,修正为 '{tokenizer.decode([corrected])}'")
        break

print(f"\n接受率: {accepted}/{k} = {accepted/k:.2%}")

这段代码是教学性质的简化实现——真正的 MTP 头会为每个偏移位置产出独立 logits,验证时主模型也会对整段 draft 做一次完整前向。但逻辑骨架是一样的:起草 → 逐 token 比对 → 接受或裁剪。

速度提升的上限与实际落差

理论上,如果 drafter 每次起草 k 个 token 且全部被接受,吞吐提升接近 k 倍。Gemma 4 报告的"约 3 倍"意味着:

  • k 值大约在 4-5,平均接受率在 60%-75% 左右,等效加速 ≈ 3×。
  • 接受率受 prompt 类型影响很大——格式固定、重复性高的任务(代码补全、模板填充)接受率更高;开放式创意写作则偏低。

几个影响实际加速比的因素:

因素 影响
k 值设置 k 越大,单次潜在收益越高,但 drafter 准确率通常随位置递减,浪费的算力也更多
batch size 大 batch 下推测解码的 GPU 利用率收益递减,因为主模型本身已经填满算力
drafter 推理成本 MTP 头比独立小模型便宜,但仍有一次前向开销;k 过大时 drafter 成本会吃掉加速收益
温度采样 temperature=0(贪心)时接受率最高;温度越高,随机性越大,drafter 和主模型越容易分歧

什么时候该用,什么时候不该用

适合的场景:

  • 单请求、低 batch 的在线对话服务——延迟敏感,GPU 常常在等 token。
  • 代码生成、结构化输出——token 分布集中,drafter 命中率高。
  • 已在用 Gemma 4 系列——MTP drafter 是同架构扩展,切换成本极低。

需要谨慎的场景:

  • 高 batch 离线推理——主模型已经跑满,推测解码的额外 drafter 前向反而拖慢整体吞吐。
  • 高温度创意生成——接受率下降,有效加速比可能只有 1.5× 甚至更低。
  • 非 Gemma 系列模型——MTP drafter 是和主模型联合训练的,跨模型组合需要自己训练 drafter 头,工程量不小。

上线前的快速检查清单:

  1. 确认推理框架支持推测解码(vLLM ≥ 0.6、TensorRT-LLM 最新版、或自建 pipeline)。
  2. 在典型 prompt 集上测量实际接受率——低于 50% 时加速收益有限。
  3. 对比 drafter 前向延迟与主模型前向延迟——drafter 延迟不应超过主模型的 1/k,否则得不偿失。
  4. 监控 GPU 显存——MTP 头虽然共享参数,但 k 个预测头的 logits 缓存仍占额外空间。
  5. 先在低流量环境灰度,观察 P99 延迟是否真的下降——理论加速和实际尾部延迟未必一致。

Gemma 4 把 MTP drafter 做成架构级能力而不是外部拼凑,这是它最大的工程优势:你不需要维护两个模型的版本对齐和部署一致性,一个模型包里就包含了起草和验证两套能力。对于已经在 Gemma 生态里的团队,这几乎是一个零摩擦的加速选项。


相关推荐