从数学原理到生产部署,一次讲透投机解码的核心思想与最佳实践。
你有没有想过,为什么 ChatGPT 生成回复时是一个字一个字蹦出来的?明明 GPU 有几千个核心,为什么不能并行输出?
答案藏在自回归解码的机制里。想象一条高速公路,所有车辆必须通过同一个收费站,一次只能放行一辆。大语言模型的推理就像这条公路:每个 token 的生成必须等前一个完全结束,GPU 算力再强也只能排队等待。
随着模型规模膨胀到数千亿参数,这个串行瓶颈已经从"有点烦人"变成"难以忍受"。DeepSeek-V4 的线上服务曾经受此拖累,直到一套新机制的引入彻底改变了局面。
这套机制叫 DSpark。在同样的服务等级协议(SLA)下,它将引擎吞吐量提升了 51%,每位用户的实际响应速度加快了 60% 到 85%。在高交互场景下,吞吐量甚至可以提升 661%。
它的核心是投机解码(Speculative Decoding)。本文将从直觉到公式,逐步拆解这项技术,并解释 DSpark 为什么选择了第三条路。
一、投机解码的数学本质
1.1 大模型推理为什么慢
大模型推理的本质是串行自回归(Autoregressive Generation)。给定前 k 个 token,模型计算第 k+1 个 token 的概率分布,采样后再作为下一步的输入。
这个过程无法并行,因为第 k+1 个 token 的输入依赖于第 k 个 token 的输出。模型参数量越大(如 DeepSeek-V4),单次前向计算的延迟越高,串行瓶颈就越严重。
(图注:每个 token 必须等待前一个完成,形成串行依赖链,GPU 利用率受限。)
1.2 投机解码的核心直觉
投机解码的核心思想可以用一个职场类比概括:让实习生(Draft Model)快速写出草稿,老板(Target Model)只做批量审核和签字。
具体来说,一个轻量级的小模型先一次性猜测接下来的若干个 token。然后大模型将候选 token 打包验证,用拒绝采样(Rejection Sampling)保证输出分布与直接自回归完全一致。
只要小模型猜得够准,大模型就能一次性"批准"多个 token,原本串行的多步压缩成一步。更重要的是,这种加速是数学上无损的,输出质量不会下降。
1.3 加速比公式与两个维度
加速比由以下公式严格定义:
\eta = \frac{T_{\text{target}}}{(T_{\text{draft}} + T_{\text{verify}}) / \tau
其中各符号含义如下:
| 符号 | 含义 |
|---|---|
| 加速比 | |
| T_{\text{target} | target model 自回归单 token 延迟 |
| T_{\text{draft} | draft model 生成候选的延迟 |
| T_{\text{verify} | target model 验证候选的延迟 |
| 期望接受的 token 数(含 bonus token) |
从公式可以清晰看出,加速比取决于两个独立维度。第一是算法层面的接受率, 越大越好;第二是系统层面的延迟比,T_{\text{draft} 与 T_{\text{verify} 的比值越小越好。
不同 draft 策略在这两个维度上的表现截然不同。因此选择什么样的 draft 生成方式,直接决定了投机解码方案的理论天花板和实际落地效果。
二、Draft 策略的三种范式
目前学术界和工业界的 draft 策略可以归纳为三大范式。它们在延迟和接受率之间做着不同的权衡,没有一种能在所有场景下通吃。
理解这三种范式的差异,是理解 DSpark 设计选择的前提。
2.1 自回归 Draft:以 EAGLE-3 为代表
自回归 draft(Autoregressive Draft)沿用与 target model 相同的生成方式:逐个 token 顺序预测。EAGLE-3 是该路线的代表方法。
它的延迟随 draft 长度线性增长,公式为 T_{\text{draft}} = \gamma \times t_{\text{step}。为了控制总延迟,自回归 draft 通常只能使用极浅的网络(EAGLE-3 往往只有 1 层)。
因为每一层 draft 网络都必须等待前一层的输出,计算图是严格串行的。这是自回归范式的结构性代价。
这种策略的优点是保持了 token 间的自然依赖,接受率较高。缺点是 draft 长度和模型深度都被延迟严格限制,难以扩展到更长的候选序列。
2.2 并行 Draft:以 DFlash 为代表
并行 draft(Parallel Draft)采用完全不同的思路:用单次前向传播同时预测整个 block 内的所有 token。DFlash 是该范式的典型代表。
它的最大优势是延迟近似常数,T_{\text{draft}} \approx t_{\text{parallel},与 block 长度基本无关。这使得 draft 模型可以做得更深、预测得更远,而不必担心延迟线性膨胀。
但纯并行预测存在一个致命缺陷——后缀衰减(Suffix Decay)。越靠后的位置,预测质量越差,因为每个位置的预测条件独立,没有利用到已经生成的左侧 token 信息。
当 block 长度增加到 5 个以上时,DFlash 的远端 token 接受率会急剧下滑,这直接限制了它能带来的实际加速。
(图注:三种策略在延迟-接受率平面上的分布示意。)
2.3 半自回归 Draft:DSpark 的答案
DSpark 的答案是半自回归(Semi-Autoregressive)draft。它在并行 backbone 的基础上,叠加极低开销的顺序校正,试图兼得低延迟与高接受率。
具体而言,DSpark 先用一个 5 层的小型 Transformer 并行预测整个 block,再通过轻量的 Markov 顺序校正头在相邻 token 之间引入依赖。总延迟仍近似常数,仅增加一个极小的 。
实验表明,DSpark 在延迟与接受率的二维平面上处于帕累托前沿(Pareto Frontier)。它既享有并行 draft 的低延迟,又接近自回归 draft 的高接受率,从而在生产环境中取得了显著优势。
这种"先并行、后校正"的混合思路,正是 DSpark 区别于现有方案的核心创新。下一部分将深入其架构细节。
(图注:DSpark 位于帕累托前沿,打破了"低延迟 vs 高接受率"的权衡困境。)
三、DSpark 架构深度解析
3.1 架构总览
DSpark 的 draft 模型由三个组件精密协作而成。
第一个是 Parallel Backbone,负责一次性并行预测整个 token block 的独立分布。
第二个是 Markov 顺序校正头,在并行预测结果上叠加 token 间依赖,实现半自回归效果。
第三个是信心头,预估每个 draft token 被目标模型接受的概率,为调度器提供决策依据。
三者协同的核心公式可概括为:
\text{Draft}(x_k | x_
Backbone 提供上下文相关的先验分布,Markov 头注入序列依赖的修正量,信心头则量化预测可信度。
这条公式揭示了 DSpark 的半自回归本质:backbone 负责"并行猜",Markov 头负责"顺序修",两者叠加后既保留了并行速度,又获得了接近自回归的质量。
3.2 并行 Backbone
并行 Backbone 的核心任务是用一次前向传播预测整个 block。
为了告诉模型"这些位置有待预测",DSpark 借用了 Qwen3 预训练中的 Fill-in-the-Middle 特殊 token <|fim_middle|>(token_id=151669)。
它的 embedding 天然编码了"此处内容未知,需要推断"的语义,比普通 mask 更具表达力。
这里有一个关键直觉:普通的 mask token 在预训练中很少出现,模型看到它时未必知道该做什么。而 FIM token 在 Qwen3 的代码补全场景中被大量使用,其向量空间中已经形成了稳定的"待填充"语义。
具体构造方式非常简洁:选取一个真实锚点 token,后面紧跟 7 个 <|fim_middle|> mask token,组成 8 长度的预测窗口。
训练时,每份样本从 response 部分随机采样 512 个锚点位置,相当于做了大规模数据增强。
锚点的选择不是均匀的,而是限定在 response 区域内,确保 draft 模型学习的是真实生成分布,而非前缀提示的分布。
Backbone 本身是一个 5 层的小型 Transformer,参数量远小于目标模型。
这 5 层网络是可训练参数的主体,其余部分如 embedding 和 lm_head 均从目标模型拷贝并冻结。
它的 attention 设计尤为关键:Q 只来自 draft token 自身,K/V 则拼接了目标模型的上下文 hidden states 与 draft block 内部的 hidden states。
双源 attention 的巧妙之处在于分工明确:draft token 通过 Q 查询自己需要什么信息,而通过 K/V 从两个信息源中获取答案。
一个源是目标模型深层抽取的上下文语义,另一个源是 draft block 内部的横向交互。两者拼接后供给 attention 计算。
这种设计让 draft 模型无需重新编码长上下文,直接复用目标模型已计算好的深层特征。
目标 hidden 从 Qwen3 的第 [1, 9, 17, 25, 33] 层提取,融合后通过 RMSNorm 和线性投影注入 attention 的 K/V 路径。
既省计算又保精度,这是 DSpark 能在生产环境立足的工程基础。
5 层的深度是经过消融实验验证的:再深一层带来的质量增益有限,但延迟显著上升;再浅一层则无法充分提取 block 内的复杂模式。
3.3 Markov 顺序校正头
并行预测有一个根本缺陷:block 内每个位置的输出彼此条件独立。
数学上,backbone 给出的是 ,每个 $$$$ 互不影响。
这导致越靠后的 token 预测质量越差,也就是上文提到的后缀衰减问题。
实验数据显示,纯并行方案在位置 5 到 7 的接受率会急剧下跌,因为模型完全不知道前面已经生成了什么。
真实文本中,相邻 token 之间存在强依赖。DSpark 的核心假设是:x_ 的分布主要由前一个 token x_{k-1 决定。
这一假设被称为 Markov 性质,它让极轻量的顺序校正成为可能。
校正操作非常直接:在 backbone 输出的独立 logits 上,叠加一个基于前序 token 的偏差项。
论文探索了三种 Markov 头的实现变体:
| 类型 | 公式 | 参数量 | 特点 |
|---|---|---|---|
| VanillaMarkov | 78M | 低秩分解,仅看前一个 token | |
| GatedMarkovHead | + | 用 backbone hidden 做门控调制 | |
| RNNHead | GRU(state, W_1(x_{k-1}), h_) | + 3r(2r+d) | 累积全部历史信息 |
GatedMarkovHead 在 Vanilla 基础上增加了门控机制,允许 backbone 的当前 hidden state 调制偏差强度。
RNNHead 则更为复杂,它在 block 内部维护一个循环状态,理论上能捕获更长距离的依赖,但延迟也相应增加。
实际部署中,VanillaMarkov 以极简的结构和极低的延迟成为默认选择。78M 的参数量对整体吞吐影响极小。
训练时采用 teacher forcing:Markov 头总是看到真实的前序 token,而非自己上一轮的预测结果。
这意味着训练过程中梯度传递稳定,模型学习的是最理想的条件分布。
推理时则改为自回归采样:每步用上一时刻采样的 token 作为下一步的输入,循环 8 次完成整个 block。
整个过程没有 attention,没有 MLP,只有两次矩阵乘法,生成 8 个 token 仅需约 50μs。
相比 backbone 的前向传播,这个开销可以忽略不计,却显著提升了远端 token 的预测质量。
实验表明,加入 Markov 校正后,位置 5 到 7 的接受率明显优于纯并行方案,接近自回归 draft 的水平。
这正是半自回归范式的核心价值:用极小的顺序开销,换取显著的质量提升。
3.4 信心头
信心头是 DSpark 中最轻量的组件,仅由一个线性层构成。
它接收 backbone 的 hidden states,输出每个 draft token 被目标模型接受的预估概率 a_。
这个概率是硬件感知调度器的核心输入。调度器需要依据 a_ 动态决定每轮验证多少 token。
验证太少浪费并行度,验证太多则拖慢 throughput,这是一个精细的权衡。
如果信心估计不准,调度器就会做出错误决策。因此,校准质量直接决定系统收益。
DSpark 使用 BCE(Binary Cross Entropy)损失训练信心头,让预测分数与实际观察到的接受率尽可能一致。
BCE 损失比较预测概率与实际二值标签(接受为 1,拒绝为 0),通过梯度下降强迫模型输出经过 Sigmoid 后落入合理区间。
未经校准的信心估计常常过于乐观或悲观,导致调度器系统性地高估或低估验证收益。
上图是可靠性图(Reliability Diagram),横轴为预测信心分桶,纵轴为对应桶内的真实接受率。
理想情况下,所有点应落在对角线上。经过 BCE 校准后,信心头的输出与实际接受率高度吻合。
离对角线越远的点,意味着模型在该信心区间内的估计越不靠谱,调度器据此做决策就会犯错。
论文还扫描了不同信心阈值对系统的影响。
校准后的信心头让调度器能在「激进」与「保守」之间找到最优平衡点——阈值设太低混入低质量 draft,设太高则浪费并行预测能力。
4. 训练策略
4.1 损失函数设计
训练 draft 模型的目标,是尽可能模仿目标模型(Target Model)的输出分布。DSpark 没有使用单一的交叉熵(Cross Entropy, CE),而是设计了一个三项加权复合损失。
公式如下:
\mathcal{L}_{\text{DSpark}} = \alpha_{\text{CE}} \cdot \mathcal{L}_{\text{CE}} + \alpha_{\text{L1}} \cdot \mathcal{L}_{\text{L1}} + \alpha_{\text{conf}} \cdot \mathcal{L}_{\text{BCE}
三项损失各司其职:
| 损失项 | 含义 | 权重 | 作用 |
|---|---|---|---|
| \mathcal{L}_{\text{CE} | 交叉熵 token 预测 | 0.1 | 预测正确 token |
| \mathcal{L}_{\text{L1} | \sum\|\text{softmax(draft)} - \text{softmax(target)}\ | 0.9 | 分布对齐(核心) |
| \mathcal{L}_{\text{BCE} | 信心头校准 | 1.0 | 准确估计接受率 |
最反直觉的是:L1 权重为 0.9,是 CE 的九倍。为什么?
投机解码的接受率取决于 draft 分布与 target 分布之间的 TV 距离,而不是 token 是否精确匹配。即使 draft 猜错了具体 token,只要两个分布足够接近,验证时依然大概率通过。
L1 损失直接优化的是分布距离而非 token 匹配精度,因此权重远高于 CE。
为了让模型更关注近期预测,DSpark 对位置 $$$$ 施加指数衰减权重:
w_k = e^{-k/\gamma
其中 。越靠后的位置权重越低——远处的 token 本来就难预测,不必分配同等监督强度。
训练时,每个样本随机采样 512 个锚点位置。锚点必须落在 response 区域内,确保模型只学习生成答案,而非模仿用户提问。
4.2 训练流程
DSpark 的训练依赖一个关键前提:目标模型的隐藏状态需要提前算好并缓存下来。
它被称为 Target Cache。以 Qwen3-4B 为例,完整缓存约 38TB。尽管存储开销巨大,它省去了训练时反复运行目标模型前向,显著提升迭代效率。
整个训练流程分为三步:数据准备、模型训练、效果评估。
在数据准备阶段,系统先用目标模型重新生成答案,再提取第 1、9、17、25、33 层的隐藏状态写入缓存。训练阶段直接读取缓存,配合锚点采样策略进行迭代。
关键超参数如下:
| 参数 | 值 | 说明 |
|---|---|---|
| 学习率 | 6.0 \times 10^{-4 | AdamW |
| Warmup 比例 | 0.04 | 线性 warmup |
| 全局 batch size | 512 | 8 卡数据并行 |
| 训练轮数 | 10 | 覆盖充分 |
| Block size | 7 | Draft 长度 |
| Draft 层数 | 5 | Backbone 深度 |
| Markov rank | 256 | 低秩维度 |
| 精度 | bf16 | 混合精度 |
| 最大长度 | 4096 | 序列截断 |
所有配置均已开源在 DeepSpec 仓库中。修改 config/dspark/dspark_qwen3_4b.py 即可复现或调整实验。
5. 硬件感知前缀调度器
5.1 调度核心:应该验证多少 token?
投机解码每轮都要回答一个问题:这次验证几个 draft token?
静态长度显然不够聪明。验证太少,浪费并行能力;验证太多,可能拖垮系统吞吐。
DSpark 的调度器将这个问题转化为一个优化目标:
左边 是期望吞吐。右边第一项是预期接受的 token 数,第二项 \text{SPS(Steps Per Second) 是目标模型在验证 个 token 时的实际硬件步频。
注意 不是平滑曲线。它在 附近会出现一个硬件悬崖:
这是因为 GPU kernel 会在序列长度超过阈值时切换实现,比如从 FlashAttention 降级到标准 attention。吞吐量瞬间腰斩。
例如,设信心头给出 ,而 SPS 剖面为 。
逐项计算结果:
最优解是 。即使后面还有可用的 draft token,验证它们反而降低整体效率。没有硬件感知就会错选 。
搜索策略采用因果贪心:从 开始递增,一旦发现 \Theta_\ell < \Theta_{\ell-1 立刻终止。
这个 early-stop 不是工程偷懒,而是数学必需。Appendix A 的证明指出,如果去掉 early-stop 做全局最优搜索,调度器会向后窥视未来 token 的取值,引入选择偏差,破坏无损解码的理论保证。
此外,调度器还会根据当前负载自适应调整:
低并发时延长验证长度到 4-6 个 token,充分利用闲置算力。高并发时自动缩回至 2 个 token 左右,防止 batch 被低质量候选撑爆。
5.2 零开销调度 (ZOS)
调度器本身的计算极其轻量:不到 1μs,仅十次浮点运算。
它藏在哪儿?GPU 从 backbone forward 切换到 target verify 时,kernel launch gap 约 10μs。调度器就在这 10μs 内完成全部决策。
信心分数 a_ 并非额外计算,而是 backbone forward 的副产品。对 backbone 的最后一个隐藏状态做一次 sigmoid 即可得到,甚至不用等 Markov 采样结束。
数据从 GPU 拷贝到 CPU 也是异步的,non_blocking=True 让传输与后续计算重叠。
更大的并发发生在 target verify 阶段:target model 的验证过程是 memory-bound,GPU 计算单元大量空闲。
此时 CPU 可并行准备下一轮:确定新的锚点、构造 noise embedding、预取 target hidden states。
这样一来,调度完全没有占用额外的时间片,故称为 Zero-Overhead Scheduling。
6. 实验结果
6.1 离线 benchmark 与生产部署
在离线评测中,DSpark 相比 EAGLE-3 的 macro-average accepted length 提升了 30.9% (Qwen3-4B)、26.7%(8B)和 30.0%(14B)。
相比 DFlash,提升幅度为 16.3% (4B)、18.4%(8B)和 18.3%(14B)。
从位置维度看,DSpark 在 position 5-7 的远端位置依然维持高接受率。纯并行方案(DFlash)在这些位置急剧衰减,而 DSpark 的 Markov 头有效抑制了后缀衰减。
论文中的 fig02、fig03、fig04 分别展示了按位置接受率、drafter 深度影响以及 proposal length 的影响,读者可对照原文查看细节。
在生产环境 DeepSeek-V4 上,DSpark 已完成全量替换。以下是线上实测数据:
| 引擎 | SLA 锚点 | 吞吐量增益 | 每用户速度提升 |
|---|---|---|---|
| V4-Flash | 80 tok/s/user | +51% | +60%~85% |
| V4-Flash | 120 tok/s/user(高交互) | +661% | — |
| V4-Pro | 35 tok/s/user | +52% | +57%~78% |
| V4-Pro | 50 tok/s/user(高交互) | +406% | — |
高 SLA 点的增益看起来惊人,原因是基线 MTP-1 在这些位置已接近操作极限。DSpark 的实际意义是扩展了可行交互性前沿。
这里需要解释一个常见疑问:为什么生产对比的是 MTP-1,而不是论文离线实验里的 DFlash?
因为 MTP(Multi-Token Prediction)-1 才是 DeepSeek-V4 发布前的生产基线。它是一个附着在目标模型上的单 token 预测头。在高并发下,MTP-3/5 的静态多 token 验证会严格降低吞吐,所以 MTP-1 长期是唯一不会崩的选择。
DFlash 则没有跑在 DeepSeek-V4 的自研推理引擎上。V4 使用 index-attention 和 compress kernel,与标准 Transformer 不同。因此生产部署只能对比同引擎内可替换的基线。
6.2 方法对比总结
把 DSpark 与 EAGLE-3、DFlash 放在一起比较,差异一目了然:
| 维度 | EAGLE-3 | DFlash | DSpark |
|---|---|---|---|
| 生成方式 | 自回归 | 块扩散(并行) | 半自回归(并行+顺序) |
| Draft 延迟 | 随长度线性增长 | 近似常数 | 近似常数 |
| 顺序校正 | 有(串行) | 无 | 有(Markov 低秩) |
| 信心头 | 无 | 无 | 有 |
| 硬件感知调度 | 无 | 无 | 有 |
| 生产部署 | 仅开源 | 仅开源 | DeepSeek-V4 线上 |
| 适用场景 | 离线实验 | 离线实验 | 生产服务 |
EAGLE-3 的接受率不低,但自回归 draft 的延迟随 block size 线性增长,限制了它在高并发下的扩展性。DFlash 的并行延迟极低,但没有顺序校正,远端位置质量衰减严重。
DSpark 同时解决了这两个痛点:用并行 backbone 保证低延迟,用 Markov 头恢复 token 依赖,再用信心头和硬件感知调度器把整套系统推进到生产环境。
结论
回顾全文,DSpark 的核心贡献可以总结为三点。
第一,算法层面提出了半自回归范式。它打破了"并行低质量"与"自回归高延迟"之间的传统权衡,在延迟-接受率的二维平面上达到了 Pareto 更优。
第二,系统层面引入了硬件感知前缀调度器。它将投机解码的目标从"加速单个请求"提升为"优化整个服务的吞吐量-交互性帕累托前沿"。SPS 悬崖的发现和 early-stop 的理论保证,让调度器既快又正确。
第三,工程层面完成了从论文到生产的闭环。DSpark 在论文发表后两周内即完成 DeepSeek-V4 的线上全量替换,覆盖 Flash 和 Pro 两条产品线。
如果你想复现或改进这套方案,欢迎访问 DeepSpec 开源仓库。所有训练配置、损失实现和调度逻辑均已开放。
如果这篇文章帮你理清了投机解码的思路,欢迎点赞收藏,下次回顾更方便。
参考资料
- DSpark 论文: DeepSpec 仓库同级
DSpark_paper.pdf - DFlash 论文: arXiv:2602.06036 (ICML 2026)
- EAGLE-3 论文: arXiv:2503.01840
- DeepSpec 代码仓库: GitHub
- SpecForge (训练框架基础): GitHub