你是一家创意工作室的老板。王老师是你最资深的文案专家,每个字都精雕细琢,可惜写得太慢——每写一个字都要停下来反复斟酌,客户已经等得不耐烦了。新来的实习生小李则风风火火,几分钟就能甩出一大段初稿,只是错别字、病句时有发生。你灵机一动:干脆让小李先飞快地起草,王老师不再亲自动笔逐字写,而是像审稿一样一次性扫过整页草稿,满意的地方直接放行,不满意的地方当场改写。这样一来,王老师用“审稿”代替“逐字写作”,速度自然快得多。这就是大模型推理加速领域大名鼎鼎的“投机解码”(Speculative Decoding)。

岗位关联

掌握投机解码,你就能在不牺牲生成质量的前提下把大模型推理延迟降低 2-3 倍,是部署工程师和算法工程师优化推理成本最实用的工具之一。

目录
  1. 可视化演示
  2. 核心原理:先猜后审
  3. 草稿模型:选对实习生
  4. 猜测长度:一次交几页
  5. 接受率优化:让实习生更靠谱
  6. 加速比:效率账本
  7. 工程实现:流水线细节
  8. 适用场景:哪些工作室适合
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示投机解码通过草稿模型快速生成候选Token、主模型批量验证并行接受的加速流程,动态对比标准自回归与投机解码的性能差异。

本节配有交互动效(进入视口后自动加载,约 3KB)。

标准推理:自回归串行生成 青色为主模型生成 绿色为已生成Token 红色为延迟累积 Latency = N x Forward Pass 标准自回归每步仅生成1个Token,N个Token需要N次前向传播

核心原理:先猜后审

王老师打字奇慢但字字珠玑,小李打字飞快但错漏百出。项目经理发现,王老师“审稿”的速度比“亲自写稿”快得多,于是设计了新流程:小李先快速起稿一整页,王老师一次性扫读整页,写得顺眼的地方直接放行,不顺眼的地方亲笔改写。这样既保住了王老师的文字水准,又省下了逐字斟酌的时间。

这套流程正是投机解码的骨架。自回归大模型在生成 token 时必须逐字串行,每一步都做一次昂贵的前向传播,这是延迟的根源。投机解码引入一个又快又小的草稿模型(draft model),让它一口气猜出 N 个候选 token;然后主模型(target model,也就是被加速的大模型)对这些候选做“批量验证”——只花一次前向传播的时间,同时得到 N 个位置的预测分布,并按照投机采样规则接受或拒绝候选。

验证规则非常优雅:主模型按概率接受草稿 token;一旦遇到第一个被拒绝的 token,就从这个位置开始由主模型重新采样一个 token,并丢弃它身后的所有草稿。因为“审稿”只花一次前向传播的时间,却能换来多个被接受的 token,推理延迟显著下降。假设每个 token 的接受概率为 \(\gamma\),每轮猜 N 个,那么每轮期望生成 token 数为:

这套“先猜后审”的思路,本质就是把专家的时间从“逐字写作”变成“整页审稿”。任何依赖自回归逐 token 生成的大模型推理场景,都能借用这条流水线。

E=1−γN+11−γ\displaystyle E = \frac{1 - \gamma^{N+1}}{1 - \gamma}
这个公式说明:接受率越高、猜测长度越长,单轮验证能“顺手带走”的 token 就越多,加速效果越好。
  1. 第一个 token 永远安全验证时第一个位置本身由主模型采样或必然接受,贡献 1 个 token。
    1=γ01 = \gamma^0
  2. 后续草稿逐个衰减第二个候选要被接受,需要连续通过概率 \(\gamma\);第 i 个候选的期望贡献是 \(\gamma^i\)。
    γ+γ2+⋯+γN\gamma + \gamma^2 + \cdots + \gamma^N
  3. 等比数列求和把从 \(\gamma^0\) 到 \(\gamma^N\) 的贡献全部相加,得到每轮期望生成数。
    ∑i=0Nγi=1−γN+11−γ\sum_{i=0}^{N}\gamma^i = \frac{1-\gamma^{N+1}}{1-\gamma}

草稿模型:选对实习生

实习生不是随便招的。小李每天模仿王老师的措辞风格,三个月后与王老师的“口味”越来越接近。选草稿模型也一样——关键不是单纯地小,而是它的输出分布要足够接近主模型。如果实习生只会写火星文,王老师每行都要重写,新流程反而比原来更慢。

草稿模型的选择通常有三条路线。第一条是“同族小模型”:从主模型蒸馏、剪枝或缩小层数得到的小版本,比如用 Llama 系小模型给 Llama-2-70B 打草稿,师出同门、分布天然亲近。第二条是“独立小模型”:任何分布接近主模型的小模型都可以,即使架构不同。第三条是“训练对齐”:无论选哪个小模型,都要用主模型的输出分布做蒸馏,让草稿模型学会“专家的笔迹”。

参数规模上,草稿模型一般取主模型的 0.1 到 1 倍。太小则猜测质量差、接受率低;太大则草稿阶段的计算成本反客为主。训练草稿模型的核心目标函数是蒸馏损失,也就是让草稿分布 \(q\) 尽量贴合主模型分布 \(p\):

请一个和王老师口风一致的实习生,审稿通过率才高。这也解释了为什么投机解码论文里,草稿模型一定要“像”主模型,而不是随便拿个通用小模型硬凑。

L=−∑xptarget(x)log⁡qdraft(x)\displaystyle \mathcal{L} = -\sum_{x} p_{\text{target}}(x) \log q_{\text{draft}}(x)
交叉熵损失的本质是“让实习生照着专家的批改痕迹临摹”,越临摹越像,审稿通过率越高。
  1. 目标分布 \(p_{\text{target}}\)主模型在给定上下文后认为每个词适合的概率,是“标准答案”。
    ptarget(x)p_{\text{target}}(x)
  2. 草稿分布 \(q_{\text{draft}}\)实习生认为每个词该出现的概率,是“待纠偏的初稿”。
    qdraft(x)q_{\text{draft}}(x)
  3. 交叉熵求和对词表中所有词,用专家的概率加权惩罚实习生的偏差,总和越小越像专家。
    L=−∑xp(x)log⁡q(x)\mathcal{L} = -\sum_x p(x) \log q(x)

猜测长度:一次交几页

项目经理渐渐发现,交一页草稿省不了多少时间,交十页又容易在后几页大量出错被王老师划掉重写,得找到一个折中。这个“折中”就是投机解码里的猜测长度 \(N\)——每轮草稿模型一口气生成的候选 token 数量。

\(N\) 越大,单轮潜在收益越大,但超过一定长度后,后续 token 的接受概率会随 \(\gamma^N\) 指数衰减。比如 \(\gamma=0.8\) 时,第 5 个候选被全部接受的联合概率只有 \(0.8^5 \approx 0.33\),后半段草稿几乎全是无效劳动,还白白占用草稿模型的计算时间。反过来,\(N\) 太小,专家省下的时间有限。

实践中 \(N\) 一般取 4 到 8。更聪明的实现会自适应调整:记录最近若干轮的接受率,接受率高就加长猜测长度,接受率低就缩短。最优长度可以通过最大化“每轮收益与成本之比”来刻画:

一次传两盘菜效率高,一次传二十盘则很容易洒。猜测长度就是传菜盘数,既要让专家一次审得够多,又不能贪多嚼不烂。

N∗=arg⁡max⁡N  1−γN+1N+1\displaystyle N^{*} = \arg\max_{N} \; \frac{1 - \gamma^{N+1}}{N+1}
这个式子在告诉我们:不要只看单轮收获了多少 token,还要看为了收获它们,团队一共花了多少“步数”。
  1. 分子是期望收益接受率为 \(\gamma\) 时长度的期望生成 token 数。
    1−γN+11 - \gamma^{N+1}
  2. 分母是每轮步数\(N\) 个草稿步加上 1 次主模型验证,共 \(N+1\) 次前向传播。
    N+1N+1
  3. 挑选最大值在所有候选长度中,选出“平均每一步产出 token 最多”的那个 \(N\)。
    arg⁡max⁡NE(N)N+1\arg\max_N \frac{E(N)}{N+1}

接受率优化:让实习生更靠谱

小李的靠谱程度决定一切。若他写的每句话都能让王老师点头,整页草稿几乎全通过;若满纸荒唐言,王老师疲于改稿,流水线反而拖垮产能。在数学上,草稿模型的靠谱程度被量化成接受率 \(\gamma\)。

接受率 \(\gamma\) 等于草稿模型分布 \(q\) 与主模型分布 \(p\) 的“重叠面积”。两个分布重叠得越多,草稿 token 越容易通过验证;完全一致时 \(\gamma=1\),完全不相干时趋向 0。用公式表达:

影响接受率的因素主要有三个。第一是任务熵:代码补全、数学推导这类“低熵”任务,下一个 token 几乎被语境锁死,草稿容易猜中;而开放性创意写作是“高熵”任务,每个位置都有大量合理选择,草稿很难与主模型重合,接受率自然偏低。第二是解码温度:温度过高会让分布趋于均匀、更“散”,草稿更难命中;温度过低则分布过于尖锐,草稿一旦偏离就几乎必然被拒。第三是训练:通过蒸馏让草稿模型沿着主模型的分布走,直接抬高重叠面积。

温度就像是给实习生“自由发挥程度”的拨盘——拨太高变成自由创作,拨太低则死板照搬。想提高接受率,最根本的办法还是让实习生吃透专家的“批改笔记”。

γ=∑xmin⁡(p(x), q(x))=1−12∑x∣p(x)−q(x)∣\displaystyle \gamma = \sum_{x} \min\big(p(x),\, q(x)\big) = 1 - \tfrac{1}{2}\sum_{x}\big|p(x) - q(x)\big|
  1. 重叠面积对每个词取两个分布中较小的概率,相当于两个分布“交叠”的部分。
    min⁡(p(x),q(x))\min(p(x), q(x))
  2. 加总成全貌把所有词的重叠部分加起来,就是总接受率。
    ∑xmin⁡(p(x),q(x))\sum_x \min(p(x), q(x))
  3. 等价视角1 减去两个分布总变差距离的一半,偏离越大,接受率越低。
    1−12∑x∣p(x)−q(x)∣1 - \tfrac{1}{2}\sum_x |p(x)-q(x)|

加速比:效率账本

流水线省下的时间到底有多少?作为项目经理,你得会算这笔账。每轮投机解码的迭代成本是 \(N\) 次草稿模型前向加 1 次主模型验证;而基准方法生成 \(E\) 个 token 需要 \(E\) 次主模型前向。设主模型单步耗时是草稿模型的 \(r\) 倍,那么理论加速比为:

其中 \(E=(1-\gamma^{N+1})/(1-\gamma)\)。这个公式讲了两件事:分子是“每轮审稿能带走多少 token”(收益),分母是“每轮要花多少时间”(成本)。当草稿模型极快(\(r\) 很大)时,分母趋近 1,加速比接近期望生成数;当草稿模型太慢(\(r\) 小),分母变大,加速被草稿成本吃掉。

实际落地时,主流实现报告 2 到 3 倍加速,优化到位的系统(如 Medusa、EAGLE)在低熵任务上可以跑到 3 倍以上。影响实测加速比的因素包括接受率 \(\gamma\)、猜测长度 \(N\)、主模型与草稿模型的速度比 \(r\),以及批量验证是否真正利用了并行计算。

让王老师从“逐字写作”的瓶颈中解放出来,团队整体产能自然飞跃。但前提是实习生够快、够像,否则这笔账就亏了。

S=E1+N/r\displaystyle S = \frac{E}{1 + N / r}
  1. 分子是每轮收益每轮验证平均产出的 token 数,由接受率与长度决定。
    E=1−γN+11−γE = \frac{1 - \gamma^{N+1}}{1 - \gamma}
  2. 分母是每轮成本\(N\) 个草稿步 \(N \cdot t_{\text{draft}}\) 加 1 次主模型验证 \(t_{\text{large}}\),统一折算成“主模型时间单位”。
    1+Nr1 + \frac{N}{r}
  3. 收益除以成本得到相对原方案“逐字写”的加速倍数。
    S=E1+N/rS = \frac{E}{1+N/r}

工程实现:流水线细节

纸上谈兵的流程要落地,还得解决三个工程细节。第一个细节是“批量验证”:王老师审稿之所以快,是因为他能一眼扫过一整页;主模型要复现这种“一眼扫过”,就不能逐个 token 重新做前向传播。实现上,Transformer 可以利用因果掩码(causal mask)把 N 个候选位置拼进同一个序列,一次 forward 同时拿到 N 个位置的预测分布。这就是投机解码中“批量验证”的真正含义。

第二个细节是 KV 缓存复用。草稿模型生成 N 个 token 时,主模型验证时可以把上下文部分的 KV cache 直接复用,避免重复计算;验证通过的前缀也能继续贡献给后续轮次。第三个细节是采样一致性。被拒绝的 token 必须从修正分布中重新采样,而不能简单取概率最大的 token——否则生成分布会悄悄偏离主模型。候选序列的联合概率可以写成链式分解,但工程上由一次并行前向高效近似:

流水线的细节决定成败:批量验证让“审稿”快起来,KV 缓存复用让“改稿”不重复劳动,重采样保证“定稿”仍然是专家的真实品味。

pθ(x^1,…,x^N∣x<t)=∏i=1Npθ(x^i∣x<t,x^<i)\displaystyle p_\theta(\hat{x}_1, \ldots, \hat{x}_N \mid x_{<t}) = \prod_{i=1}^{N} p_\theta(\hat{x}_i \mid x_{<t}, \hat{x}_{<i})
这个式子说明:第 i 个候选依赖它前面的所有内容,但借助注意力掩码,这些条件概率可以在同一次前向传播中批量算出来。
  1. 候选序列草稿模型一口气交出的 N 个 token。
    x^1,…,x^N\hat{x}_1, \ldots, \hat{x}_N
  2. 链式分解每个候选的概率都条件于真实前缀和它之前的草稿 token。
    ∏i=1Npθ(x^i∣x<t,x^<i)\prod_{i=1}^{N} p_\theta(\hat{x}_i \mid x_{<t}, \hat{x}_{<i})
  3. 一次前向实现用块状注意力掩码把 N 个位置“摊开”并行计算,让批量验证真正省时。
    一次 forward 同时得到 N 个位置的分布\text{一次 forward 同时得到 N 个位置的分布}

适用场景:哪些工作室适合

不是所有工作室都适合这套流水线。如果王老师本身写字快如复印(推理不是瓶颈),或者小李水平太差(\(\gamma\) 太低),流水线反而添乱。判断是否值得上投机解码,核心指标是延迟降幅:

三类场景最受益。第一类是延迟敏感型交互服务:聊天机器人、语音助手、实时翻译,用户每多等一秒都在流失,用投机解码把每次回复的 token 生成延迟砍半,体验提升立竿见影。第二类是高并发 Token 吞吐服务:当服务端被海量请求压满时,减少主模型调用次数直接提升 QPS 和吞吐,摊薄单次请求的 GPU 成本。第三类是端侧与资源受限部署:手机、嵌入式设备算力有限,可以让小草稿模型在本地快速起草,把更少的验证请求发给云端或更大的主模型,兼顾速度与质量。

让王老师从逐字写作的瓶颈中解放出来,团队整体产能飞跃。衡量标准很简单:延迟敏感、并发高、算力紧,这三个信号出现任意一个,投机解码就值得纳入方案选型。

Latency=(1−1S)×100%\displaystyle \text{Latency} = \left(1 - \frac{1}{S}\right) \times 100\%
  1. 新延迟是原延迟的 \(1/S\)加速 \(S\) 倍意味着耗时变为原来的 \(1/S\)。
    Tnew=ToldST_{\text{new}} = \frac{T_{\text{old}}}{S}
  2. 省下的比例1 减去剩余比例,就是被优化的延迟部分。
    1−1S1 - \frac{1}{S}
  3. 转成百分比方便向老板汇报“延迟降低了百分之多少”。
    ×100%\times 100\%

AI 应用场景

在线对话服务的延迟优化

阶段:推理部署与性能优化

解决的问题:大模型对话服务逐 token 串行生成,TPOT(每个 token 的生成时间)动辄 60-100ms,用户感知明显卡顿。传统思路是换更小的模型或量化,但会牺牲质量。投机解码在保持主模型不变的前提下,用草稿模型猜测 + 批量验证,把每次前向传播的产出从 1 个 token 提升到 2-3 个,直接降低 TPOT。

具体案例:某 LLM API 服务商在 7B 主模型上接入 0.5B 草稿模型后,经蒸馏对齐,TPOT 从 80ms/token 降到约 35ms/token,延迟降低 56%,同时输出分布几乎不变,客户无感知切换。

代码补全工具的实时响应

阶段:低延迟交互式推理

解决的问题:代码补全 IDE 插件要求 200ms 内给出候选,但大型代码模型自回归生成很慢。代码任务的低熵特性让草稿模型接受率很高,投机解码在代码场景尤其高效,能让大模型“装成”小模型的速度响应。

具体案例:某 Copilot 类产品在 13B 代码模型上使用同族小模型做草稿,接受率可达 0.7-0.8,单次验证平均推进 3 个 token,候选补全延迟从 350ms 降到 180ms。

端侧助手与云边协同

阶段:端云协同推理

解决的问题:手机端部署大模型内存与算力都吃紧,纯云端推理又受网络延迟困扰。投机解码允许端侧跑一个极小草稿模型快速起草,云端主模型只做批量验证,既保护了模型质量又大幅减少云端调用次数。

具体案例:某语音助手在手机端部署 200M 草稿模型,云端 7B 主模型验证,每轮平均 1 次云端请求推进 2.5 个 token,端到端响应时间降低 40%。

Python 演示

python121 行
# -*- coding: utf-8 -*-"""投机解码(Speculative Decoding)简化模拟草稿模型=实习生(快速但粗糙) 主模型=专家(准确但缓慢)通过批量验证,专家一次审阅 N 个草稿字符,只在自己不满意处改写本示例用字符级 bi-gram 模拟两档"模型",直观对比两种解码方式""" import random  class DraftModel:    """草稿模型(实习生):极轻量,只按单字频率均匀地猜下一个字符"""     def __init__(self, vocab, seed=42):        self.vocab = vocab        self.unigram = {c: 1.0 / len(vocab) for c in vocab}        self.rng = random.Random(seed)        self.gc_count = 0   # 调用次数计数器     def sample(self, context):        # 实习生从不看上下文,uniform 乱猜(教学简化)        self.gc_count += 1        return self.rng.choices(self.vocab, [self.unigram[c] for c in self.vocab])[0]  class TargetModel:    """主模型(资深专家):bi-gram 条件分布,更聪明但更贵"""     def __init__(self, vocab, seed=7):        self.vocab = vocab        self.trans = {            'a': {'a': 0.15, 'b': 0.85},            'b': {'a': 0.90, 'b': 0.10},        }        self.rng = random.Random(seed)        self.gc_count = 0   # 调用次数计数器     def next_dist(self, context):        last = context[-1]        return self.trans.get(last, {c: 1.0 / len(self.vocab) for c in self.vocab})     def verify(self, draft_seq, context):        """批量验证:一次调用同时审阅 N 个草稿字符"""        self.gc_count += 1        accepted = []        q = 1.0 / len(self.vocab)        for ch in draft_seq:            dist = self.next_dist(context + tuple(accepted))            p = dist.get(ch, 1e-9)            if self.rng.random() < min(1.0, p / q):                accepted.append(ch)          # 通过,留下            else:                # 被否决:从修正分布 (p - q)_+ 重新采样,模拟无偏回退                residual = {k: max(v - q, 0.0) for k, v in dist.items()}                total = sum(residual.values())                if total <= 0:                    residual = dist                accepted.append(self.rng.choices(                    list(residual.keys()), list(residual.values()))[0])                break        return accepted     def sample(self, context):        self.gc_count += 1        dist = self.next_dist(context)        return self.rng.choices(list(dist.keys()), list(dist.values()))[0]  def speculative_decode(draft, target, seed_text, max_len=30, N=4):    """跑一轮投机解码,返回生成文本与迭代轮数"""    context = list(seed_text)    steps = 0    while len(context) < max_len:        draft_seq = [draft.sample(tuple(context)) for _ in range(N)]        accepted = target.verify(draft_seq, tuple(context))        context.extend(accepted)        if not accepted:                     # 防御:至少前进 1 步            context.append(target.sample(tuple(context)))        steps += 1    return "".join(context), steps  def baseline_decode(target, seed_text, max_len=30):    """标准自回归:专家一个字一个字写,调用次数等于生成的字符数"""    context = list(seed_text)    while len(context) < max_len:        context.append(target.sample(tuple(context)))    return "".join(context)  def main():    vocab = ['a', 'b']    seed_text = "a"    max_len = 30     t1 = TargetModel(vocab, seed=7)    text1 = baseline_decode(t1, seed_text, max_len)    base_calls = t1.gc_count     d2 = DraftModel(vocab, seed=42)    t2 = TargetModel(vocab, seed=7)    text2, steps = speculative_decode(d2, t2, seed_text, max_len, N=4)    spec_calls = t2.gc_count    draft_calls = d2.gc_count     print("==== 标准自回归 ====")    print("主模型调用次数:", base_calls)    print("生成文本:", text1)    print()    print("==== 投机解码 ====")    print("主模型调用次数:", spec_calls, ",草稿模型调用:", draft_calls)    print("迭代轮数:", steps)    print("生成文本:", text2)    print()    print("主模型调用次数降低: %.1f 倍" % (base_calls / spec_calls))    print("说明:投机解码用大量廉价草稿调用换来了昂贵主模型调用的减少")  if __name__ == "__main__":    main()
目的:用字符级模型模拟“实习生草稿 + 专家批量验证”,直观展示投机解码如何用大量廉价草稿调用换取主模型串行调用的减少。
  1. self.gc_count += 1每调用一次采样就计数一次,用来统计两类模型各自的开销。
  2. dist = self.next_dist(context + tuple(accepted))验证第 i 个草稿时,条件要带上已经通过的前缀,体现自回归的链式依赖。
  3. if self.rng.random() < min(1.0, p / q)投机采样的接受判定:草稿概率相对主模型概率越高越容易通过,超过 1 则必然接受。
  4. residual = {k: max(v - q, 0.0) for k, v in dist.items()}被拒后从修正分布重采样,保证最终输出分布与主模型一致。
  5. context.extend(accepted)把这一轮通过的 token 接进真实序列,继续下一轮猜测。

常见误区

误区草稿模型生成了大部分 token,主模型只是走个过场,最后输出的质量肯定比直接让大模型生成要差。

正解投机采样有严格的分布保持性质。每个 token 都必须通过主模型的概率验证,被拒绝的地方由主模型从修正分布重新采样。换句话说,实习生负责“提案”,专家负责“定稿”,最终每个 token 的分布与直接用主模型逐字生成完全一致,是无偏加速。

为何常见:只看到“草稿是小模型写的”,忽略了“验证与重采样都由主模型完成”这一关键环节,把过程误当成了结果。

误区草稿模型如果跟主模型一样大,猜测准确率肯定高,接受率上去了,加速自然更快。

正解接受率的提升不是线性的,而草稿模型每轮要生成 N 个 token,其耗时随参数规模线性增长。当草稿模型太大时,分母 \(1+N/r\) 迅速变大,加速比不升反降。实践上草稿模型一般取主模型的 0.1-1 倍,并需要实测权衡。

为何常见:直观地以为“更强的模型 = 更好的效果”,忽略了投机解码里草稿模型的核心定位是“够快且够像”,而不是“最强”。

误区既然主模型一次验证能审 N 个 token,那 N 设成 100 甚至 1000,一次就能生成一大堆,加速肯定拉满。

正解后续 token 接受概率随 \(\gamma^N\) 指数衰减,长度超过 8 之后,尾部草稿几乎必然被拒,这些无效草稿白白消耗计算时间。最优 N 一般落在 4-8 之间,还要根据近期接受率动态调整。

为何常见:只看到单轮理想收益,忽略了长尾失败带来的浪费,属于“贪多嚼不烂”。

误区看到论文里 2-3 倍加速,以为只要部署投机解码,任何任务、任何模型都能复现这个数字。

正解加速效果高度依赖接受率 \(\gamma\) 和速度比 \(r\)。低熵任务(代码、数学)接受率可达 0.7-0.8,效果明显;高熵任务(自由创作、头脑风暴)\(\gamma\) 可能只有 0.3-0.4,加速十分有限,甚至可能负优化。

为何常见:被宣传数字打动,却忽略了数字背后的前置条件,忘了回到加速比公式去评估自己的场景。

面试题

Q1. 投机解码的核心思想是什么?

单选题 · easy

  • A.用多个大模型并行生成再投票选出最佳结果
  • B.草稿模型快速猜测再由主模型批量验证← 正确答案
  • C.把大模型剪枝成小模型直接部署上线
  • D.在推理时只计算注意力矩阵的一半

答案:B。投机解码的精髓是“先猜后审”:小草稿模型快速猜出 N 个候选,主模型一次前向批量验证并接受/回退。A 是集成方法,C 是模型压缩,D 是稀疏注意力,都与投机解码无关。

Q2. 在投机解码中,草稿模型扮演的角色是什么?

单选题 · easy

  • A.最终拍板的资深专家
  • B.快速打草稿的实习生← 正确答案
  • C.负责保存缓存的存储层
  • D.负责纠错的编译器

答案:B。草稿模型就像实习生,负责快速产出候选 token;最终每个 token 是否被接受由主模型(资深专家)决定。存储层和编译器都不是草稿模型的定位。

Q3. 主模型“批量验证”草稿时,一次前向传播可以同时处理多少个候选 token?

单选题 · easy

  • A.只能处理一个候选 token
  • B.可以同时处理 N 个候选 token← 正确答案
  • C.可以处理无穷多个候选 token
  • D.完全不需要处理任何 token

答案:B。投机解码通过因果掩码把 N 个候选位置拼进同一序列,一次 forward 同时得到 N 个位置的预测分布。因此主模型一次前向可以验证 N 个草稿 token,这是加速的关键。

Q4. 关于接受率 γ,下列说法正确的是?

单选题 · mid

  • A.两分布完全一致时 γ=0
  • B.两分布重合度越高 γ 越高← 正确答案
  • C.γ 与草稿模型质量完全无关
  • D.γ 在任何任务上都恒等于 0.5

答案:B。接受率 γ 等于草稿分布与主模型分布的“重叠面积”,重合度越高 γ 越高。两分布一致时 γ=1 而非 0,高熵任务会拉低 γ,因此 A、C、D 都不对。

Q5. 猜测长度 N 对加速效果的影响是?

单选题 · mid

  • A.N 越大加速一定越快
  • B.N 越小加速一定越快
  • C.存在最优 N,取决于接受率 γ← 正确答案
  • D.N 与加速效果完全无关

答案:C。最优长度由 \(N^*=\arg\max(1-\gamma^{N+1})/(N+1)\) 决定。N 太小收益有限,N 太大尾部接受率指数衰减,因此既不是越大越好也不是越小越好,而是存在依赖 γ 的最优值。

Q6. 投机解码(采用投机采样)能否保证输出分布与原始主模型一致?

单选题 · mid

  • A.不能,必然产生分布偏移
  • B.可以保证分布完全一致← 正确答案
  • C.只有草稿模型足够大时才能保证
  • D.只有在贪婪解码时才能保证

答案:B。投机采样通过“接受-拒绝-重采样”机制保证每个 token 最终以主模型分布采样,草稿模型只是提案方。这是理论上可证明的性质,与草稿模型大小无关,也与是否贪婪解码无关。

Q7. 高熵任务(如开放性创意写作)对接受率的影响是?

单选题 · mid

  • A.接受率通常更高
  • B.接受率通常更低← 正确答案
  • C.接受率完全不受影响
  • D.接受率恒等于 1

答案:B。高熵任务中下一个 token 的选择面很宽,草稿模型很难与主模型分布重合,重叠面积减小,接受率下降。代码、数学等低熵任务接受率更高。

Q8. 主模型单步耗时是草稿模型的 r 倍,每轮猜测 N 个 token,期望接受数为 E,则理论加速比 S 的表达式是?

单选题 · hard

  • A.S = E / (1 + N/r)← 正确答案
  • B.S = E / (1 + rN)
  • C.S = rE / (1 + N)
  • D.S = rN / (E + 1)

答案:A。每轮时间成本 = N 个草稿步 + 1 次主模型验证,折算为主模型时间单位为 \(1+N/r\);每轮收益为 E 个 token,因此 \(S=E/(1+N/r)\)。B 放大了草稿成本,C、D 量纲不对。

Q9. 以下哪些属于投机解码工程实现的关键要点?

多选题 · hard

  • A.掩码实现批量并行验证← 正确答案
  • B.草稿阶段 KV 缓存复用← 正确答案
  • C.setInterval 驱动循环提升速度
  • D.被拒 token 从修正分布重采样← 正确答案

答案:ABD。批量验证靠注意力掩码一次前向算出 N 个位置分布;KV 缓存复用避免重复计算;被拒 token 必须从修正分布重采样以保持分布无偏。setInterval 是前端动画 API,与投机解码无关。

Q10. 提升草稿模型接受率的常用手段有哪些?

多选题 · hard

  • A.对主模型输出分布做蒸馏← 正确答案
  • B.采样主模型数据训练草稿← 正确答案
  • C.把推理温度调得非常高
  • D.对草稿模型做针对性微调← 正确答案

答案:ABD。蒸馏和用主模型数据训练都是让草稿分布贴近主模型的直接方法,微调也能针对性提升对齐度。温度调高会让分布更平、熵更大,反而降低接受率。