← 返回

投机解码:草稿长度不是越长越好,接受率上升反而可能是坏消息

2026-09 · 在一台 32GB 显存的机器上,对两条不同的投机解码路径做参数扫描的记录

为什么开始测这个

投机解码(speculative decoding)的直觉很顺:草稿模型一次多猜几个 token,主模型并行验证,猜中了就等于白赚。 那么"猜得越多越快"听起来理所当然。我一开始也是这么配的,直到发现默认值附近的性能差异比想象中小得多, 而有些参数一旦调错,是纯粹在亏速度。

测试环境是单张 32GB 卡、27B 量级的模型、200K 上下文、KV 用 4 bit 量化、四个并发槽共享一个统一 KV 池。 每换一次参数都要重启进程(这些是启动期参数),所以只能串行测,一个格子大约四十多秒。

结论一:草稿长度是一条有峰的曲线

第一条路径(外挂的扩散式草稿模型)在 4 个并发槽下的实测:

草稿长度上限吞吐 (tok/s)接受率平均接受长度
295.0553.7%2.06
399.6344.9%2.33
497.4233.9%2.33
5 及以上起不来(草稿的并行预填充计算缓冲还要约 1.08 GiB,显存不够)

接受率从 53.7% 一路掉到 33.9%,而"平均接受长度"在 2.33 就封顶了——也就是说草稿猜得再长, 主模型也不认,多猜的部分只是白白占用一次前向。峰值出现在 3,不是 1(浪费验证算力)也不是 5(放不下)。

这里有个坑:n≥5 起不来,很容易让人以为"峰值是被显存墙砍出来的,如果能跑起来肯定更快"。 所以我降了一个并发槽换出约 3.2 GiB 余量,让 n=5 和 n=6 真的跑起来——结果是 94.4 和 88.1,更慢。 峰值是真的,不是被显存限制假性截断的。

结论二:那个"置信度门"参数在这条路径上单调有害

两条路径都有一个草稿侧的置信度门(低于阈值就提前截断草稿链)。在第一条路径上扫下来:

阈值00.50.750.9
吞吐 (tok/s)99.687.379.572.2
接受率44.9%67.5%88.3%96.7%

接受率涨到 96.7%,吞吐掉到 72%。因为它是靠砍短草稿链换来高接受率的——报表上那个数字变好看了,实际产出变少了。 这是我在整个测试里最不满意的一条:如果只看接受率调参,方向会完全反。

有意思的是另一条路径(模型自带的多 token 预测头)上,同样的参数在 0.2 附近是"免费"的:0.0 与 0.2 的实测吞吐差在 0.8% 以内。 也就是说这个参数该不该设,取决于草稿是怎么产生的,不能跨路径照搬。

结论三:单轮数字不能信,必须交错复测

同一份配置、同一批 prompt,第一轮扫出来的中位数是 133.7,第二轮 128.9,而交错复测四轮稳定在 99.6 上下—— 差别来自 prompt 本身:三条测试文本(写代码、讲技术概念、中文描写)的接受率天生不同, 取中位数等于在比"哪条 prompt 排中间"。

我最后用的方法:

  1. 粗扫定形状:单轮、固定 prompt 集,只用来排序,不用来报数
  2. 挑出候选后做 order-rotated 复测:N 个候选跑 4 轮,每轮打乱起始位置,避免"越跑越热"的顺序偏差
  3. 只有复测的轮间极差足够小才下结论。最终那一轮极差是 0.2%,接受率与平均长度逐轮一致

顺带一条:投机解码本身会改变输出。固定 seed、温度 0 的情况下,"完全不跑投机"和任何投机配置大约在第 40 个字开始分叉, 而调那个置信度门反而不会改输出(它只决定要不要提供草稿,不否决主模型已经接受的东西)。 动文本的是投机这件事本身,不是门限。

剩下的疑问

扩散式草稿的置信度门我没有扫(只扫了另一条路径),两条路径的绝对速度差也还没有在同一台机器上做过严格对照。 如果后面补了会直接改在这一篇里。