DSpark 与 MTP:DeepSeek 投机解码调研
结论
DSpark 是 DeepSeek 在 DeepSeek-V4 上使用的投机解码框架。它不是一个新的基础模型,而是在同一 V4 checkpoint 上挂了额外 speculative decoding 模块。Hugging Face 的 DeepSeek-V4-Pro-DSpark 和 DeepSeek-V4-Flash-DSpark 模型卡也明确说明:DSpark 版本和原模型是同一 checkpoint,只是附加了投机解码模块。
它要解决的问题不是“能不能一次猜多个 token”,而是两个更工程化的问题:
- 长 draft block 怎么保持接受率。
- 高并发 serving 下,哪些 draft token 值得送给 target model 验证。
MTP-1 是 DeepSeek 之前的生产基线:每轮只多预测一个 token,保守但稳定。DSpark 把最大 draft 长度扩到 5,并通过半自回归草稿模型提高后缀 token 的质量,再用置信度调度器按请求和负载裁剪验证长度。论文报告,在 DeepSeek-V4 live traffic 中,相比 MTP-1,DSpark 在 matched throughput 下让 V4-Flash 的 per-user generation speed 提升 60%-85%,V4-Pro 提升 57%-78%。
一个简化判断:
- MTP-1 是“短 draft + 固定验证”的稳态基线。
- DSpark 是“长 draft + 动态验证”的系统级投机解码。
- DSpark 的价值来自模型结构和 serving scheduler 的组合,不只是把 speculative token 数从 1 改成 5。
背景:投机解码的三个控制量
投机解码每轮包含 draft 和 verify:
draft model 先提出 gamma 个候选 token
target model 一次 forward 验证这些候选
从左到右接受最长前缀;第一次拒绝后,后续候选全部丢弃
论文把单 token 平均延迟写成:
L = (T_draft + T_verify) / tau
其中:
T_draft:草稿模型生成候选的耗时。T_verify:目标模型验证候选的耗时。tau:每轮平均接受 token 数,通常包含 target model 在拒绝处补出的 bonus token。
所有投机解码优化都围绕这三个量:
| 优化方向 | 目标 | 典型方法 |
|---|---|---|
降低 T_draft | draft 更便宜 | 小 draft model、并行 drafter、共享 embedding/head |
提高 tau | 猜得更准 | EAGLE、MTP、DSpark 半自回归头 |
降低有效 T_verify | 少验低价值 token | 置信度阈值、动态验证长度、硬件感知调度 |
MTP 主要落在“提高 tau”和“降低独立 draft 成本”上;DSpark 同时处理三个方向,尤其把第三个方向做成生产调度问题。
MTP 是什么
MTP 是 Multi-Token Prediction。以 DeepSeek-V3 报告中的描述为例,模型训练时加入额外预测头,让隐藏状态学习未来多个 token 的分布。推理时,这些头可以作为 speculative decoding 的候选来源。
需要分清三层含义:
| 层次 | MTP 的作用 | 容易混淆的点 |
|---|---|---|
| 训练目标 | 让模型同时学习 next token 和更远 token 的监督信号 | 训练收益不等于线上加速 |
| 草稿产生 | 用额外 MTP 模块给出未来 token 候选 | 候选 token 不一定被接受 |
| serving 加速 | target model 批量验证候选前缀 | 加速取决于接受率、验证成本和 batch 状态 |
在 DeepSeek 的 DSpark 论文里,MTP-1 是线上旧基线。这里的关键是 1:它是单 token 的 speculative setup。论文说明,固定多 token drafter 在高并发下可能因为验证开销过大而拖垮 aggregate throughput,所以生产上保留了更保守的 MTP-1。
DSpark 的核心设计
DSpark 有两部分:半自回归生成和置信度调度验证。
1. 半自回归生成
完全并行的 drafter 能一次产出 gamma 个位置的 logits,T_draft 接近常数。但它有一个问题:每个位置不知道同一个 block 里前面实际采样了什么 token。
论文举的典型问题是多模态续写。上下文可能同时支持 of course 和 no problem。完全并行预测时,第二个位置看到的是“各种可能前缀”的混合分布,可能组合出 of problem 或 no course。这些组合在局部概率上不一定离谱,但作为连续前缀会被 target model 很快拒绝,导致后缀接受率衰减。
DSpark 把草稿生成拆成两段:
parallel backbone:
一次 forward 生成每个 draft 位置的 hidden state 和 base logits
lightweight sequential head:
从左到右采样,每一步根据已经采样的前缀给 logits 加一个 transition bias
源码中这个结构落在 DeepSpec 的 Qwen3DSparkModel:
fc + hidden_norm把 target model 多层 hidden states 投影到 draft hidden space。Qwen3DSparkDecoderLayer作为并行 backbone。lm_head先产生 base logits。markov_head.apply_block_logits(...)或markov_head.sample_block_tokens(...)给每个位置加前缀相关 bias。
默认 Qwen3-4B DSpark 配置是:
model = dict(
target_model_name_or_path="Qwen/Qwen3-4B",
block_size=7,
num_draft_layers=5,
target_layer_ids=[1, 9, 17, 25, 33],
mask_token_id=151669,
num_anchors=512,
markov_rank=256,
markov_head_type="vanilla",
confidence_head_alpha=1.0,
confidence_head_with_markov=True,
loss_decay_gamma=4.0,
ce_loss_alpha=0.1,
l1_loss_alpha=0.9,
)
这说明开源训练配置里的 DSpark 不是一个完整小模型替代 target model,而是一个读取 target hidden states 的 drafter。它复用 target 的 embedding/head,并训练较浅的 draft layers 与 Markov/confidence 模块。
2. Markov head 和 RNN head
DeepSpec 里有三种顺序头:
| 实现 | 文件 | 机制 |
|---|---|---|
VanillaMarkov | deepspec/modeling/dspark/markov_head.py | 只看前一个 token,用低秩 W1[token] -> W2 -> vocab bias 修正 logits |
GatedMarkovHead | 同上 | 用 hidden state 和前 token embedding 算 gate,再控制 Markov bias |
RNNHead | 同上 | 在 block 内维护 recurrent state,让当前位置看到更长前缀历史 |
最简单的 Markov head 近似一个 V x V 转移矩阵,但不直接存完整矩阵,而是做低秩分解:
bias(prev_token, vocab) = W1[prev_token] @ W2
默认 rank 是 256。这个头很轻,所以可以在 draft block 内逐位置采样,同时让整体 draft 延迟仍主要由并行 backbone 决定。
RNN head 更强一些。源码里 _rnn_step 把上一状态、前一个 token embedding、当前位置 hidden state 拼起来,经过一个线性层拆成 gate、candidate、output 三部分:
state_k = gate * state_{k-1} + (1 - gate) * candidate
bias_k = W2(tanh(output))
论文结果里默认线上部署使用 Markov head。RNN head提供了一个更强但更贵的结构选项。
3. 置信度头
DSpark 不是把所有 draft token 都送去验证。它给每个 draft 位置预测一个条件接受概率:
c_k = P(position k survives | positions < k already accepted)
源码中 AcceptRatePredictor 是一个线性层;当 confidence_head_with_markov=True 时,输入是:
[output_hidden_k ; markov_embedding(prev_token)]
训练目标来自 draft 分布和 target 分布的 total variation distance:
c*_k = 1 - 0.5 * ||p_draft_k - p_target_k||_1
这点在 deepspec/modeling/dspark/loss.py 里能看到:代码对 outputs.draft_logits 和 aligned_target_logits 做 softmax,计算 L1 距离,再把 accept_rate_3d 作为 confidence head 的 BCE target。
论文还加了 Sequential Temperature Scaling。原因是调度器需要概率的绝对值,而不是只要排序。神经网络 confidence 容易过度自信,直接用会错误估计 tau。
4. 硬件感知 prefix scheduler
这是 DSpark 和普通“多猜几个 token”最大的差别。
对于 batch 中的每条请求 r,DSpark 有一串置信度:
c_{r,1}, c_{r,2}, ..., c_{r,gamma}
因为 speculative decoding 只能接受连续前缀,所以第 j 个 draft token 的 survival probability 是累计乘积:
a_{r,j} = product(c_{r,i}), i <= j
调度器要决定每条请求验证多少个 token:
ell_r in [0, gamma]
它用一个预先 profile 的硬件吞吐表 SPS(B) 估算当前 target forward batch size 下每秒能跑多少 step,然后最大化:
Theta = expected_accepted_tokens * SPS(B)
直觉是:
- 低负载时,GPU 还有余量,可以多验证几个低一些置信度的 token,提高单用户 tok/s。
- 高负载时,target batch capacity 紧张,只验证 survival probability 高的前缀,避免低质量后缀挤占其他请求。
论文的线上实现还做了异步调度,原因是生产 serving 需要兼容 CUDA graph replay 和 zero-overhead scheduling。调度器用两步前的预测估算下一步 capacity,但当前候选 token 仍按最新 cumulative confidence 排序。这个设计把调度延迟藏起来,同时避免“用未来 token 信息决定是否验证当前 token”的分布偏置。
DSpark vs MTP
| 维度 | MTP-1 | DSpark |
|---|---|---|
| 目标 | 保守地多预测 1 个 token | 用更长 draft block 提高每轮接受 token 数 |
| draft 长度 | 固定短长度,论文生产基线是 1 | V4 线上 DSpark-5,开源 Qwen/Gemma 配置常见 block_size=7 |
| draft 结构 | MTP 头/模块给出候选 | 并行 backbone + 轻量顺序 head |
| 前缀依赖 | 弱,尤其多 token 静态扩展时容易后缀衰减 | Markov/RNN head 在 block 内注入前缀依赖 |
| 验证策略 | 固定验证长度 | 置信度 + 硬件吞吐表动态裁剪 |
| 高并发行为 | 稳定但加速上限低 | 动态缩短验证长度,减少低价值 token 占 batch |
| 主要风险 | 加速有限 | 需要训练 drafter、校准 confidence、改 serving scheduler/kernel |
| 论文线上结果 | 作为 DeepSeek-V4 旧生产基线 | V4-Flash matched throughput 下 per-user speed +60%-85%;V4-Pro +57%-78% |
如果只看“每轮最多能提出几个 token”,很容易把 DSpark 理解成 MTP-5。但这个理解不准。DSpark 的关键不在 gamma=5,而在:
- 用半自回归头缓解长 block 后缀质量下降。
- 用 confidence 估计每个前缀的 expected return。
- 用硬件吞吐曲线按负载分配 target verification budget。
源码实现拆解
DeepSpec 是 DeepSeek 开源的训练和评测仓库,支持 DSpark、DFlash、Eagle3。当前仓库不是一个完整生产 serving engine,但足够看清 DSpark drafter 的训练结构。
训练入口
deepspec/trainer/dspark_trainer.py 的训练 batch 做三件事:
outputs = self.model(
input_ids=batch["input_ids"],
target_hidden_states=batch["target_hidden_states"],
loss_mask=batch["loss_mask"],
target_last_hidden_states=batch["target_last_hidden_states"],
)
loss = compute_dspark_loss(...)
这说明训练数据已经提前缓存了 target model 的 hidden states。README 也提醒,默认 Qwen3-4B 数据准备可能需要约 38 TB target cache。DSpark 训练不是拿 prompt 现场跑 target model,而是通过 target cache 做离线监督。
采样 anchor
Qwen3DSparkModel.forward 不对整段序列每个位置都训练完整 block,而是从 sequence 中随机采样多个 anchor:
sample_anchor_positions(...)
create_noise_embed(...)
create_dspark_attention_mask(...)
这对应论文里的 anchor-bounded sequence packing:从长序列中抽固定数量 anchor,把多个独立 draft block 打包成密集训练 batch,避免 draft 计算随完整上下文长度线性膨胀。
Attention mask
create_dspark_attention_mask 让 draft query 可以看两类 KV:
1. anchor 之前的 target context
2. 同一个 draft block 内的 draft positions
不同 anchor block 之间不互相看。这样一个 batch 可以塞多个 anchor,同时保持每个 block 的因果边界。
Loss
compute_dspark_loss 由三类项组成:
| Loss | 作用 |
|---|---|
| CE loss | 让 draft logits 预测真实 target token |
| L1 loss | 让 draft distribution 靠近 target distribution |
| confidence loss | 让 confidence head 预测解析接受率 |
loss_decay_gamma=4.0 给 block 后面的位置更低权重。这个细节合理:越靠后的 token 越容易受前面采样路径影响,训练时不应让远位置噪声主导梯度。
已发布 checkpoint
DeepSpec README 列出 Qwen3 和 Gemma4 上的 released checkpoints,包括:
deepseek-ai/dspark_qwen3_4b_block7deepseek-ai/dspark_qwen3_8b_block7deepseek-ai/dspark_qwen3_14b_block7deepseek-ai/dspark_gemma4_12b_block7
Hugging Face API 还显示了 DeepSeek-V4 对应的 DSpark 版本:
deepseek-ai/DeepSeek-V4-Pro-DSparkdeepseek-ai/DeepSeek-V4-Flash-DSpark
V4 模型卡说 DSpark 版本不是新模型,而是同 checkpoint 加 speculative decoding module。这个说法对工程判断很重要:如果要复现实测收益,需要推理框架支持 DSpark 模块和动态验证,不是只下载一个普通 causal LM checkpoint 就能自动提速。
性能数据怎么读
论文的离线结果关闭 confidence scheduler,只比较 draft quality。Table 1 报告 accepted length tau:
| Target | 对比 | 结果 |
|---|---|---|
| Qwen3-4B | DSpark vs Eagle3 | macro-average accepted length +30.9% |
| Qwen3-8B | DSpark vs Eagle3 | +26.7% |
| Qwen3-14B | DSpark vs Eagle3 | +30.0% |
| Qwen3-4B | DSpark vs DFlash | +16.3% |
| Qwen3-8B | DSpark vs DFlash | +18.4% |
| Qwen3-14B | DSpark vs DFlash | +18.3% |
离线 accepted length 只能说明 drafter 更会猜,不能直接等价为线上吞吐。线上数据要看 throughput 和 per-user generation speed 的 Pareto frontier。
论文线上结果:
- V4-Flash:80 tok/s/user SLA 下 aggregate throughput 比 MTP-1 高 51%;matched throughput 下 per-user generation speed 提升 60%-85%。
- V4-Pro:35 tok/s/user SLA 下 aggregate throughput 高 52%;matched system capacities 下 per-user generation speed 提升 57%-78%。
- 更严格 SLA 下,MTP-1 进入低并发边界,DSpark 相对吞吐优势很大。论文也提醒,这类极端点更应该理解为 DSpark 扩展了可行交互性边界,而不是稳定乘法加速。
对推理系统的启发
1. 接受率要按 prefix survival 看
MTP 或 DSpark 的收益不能只看 proposed token 数。真正应该看:
accepted tokens per verification step
如果 gamma=5 但后缀 survival probability 很低,验证 5 个 token 会浪费 target batch。DSpark 的调度器本质上是在每一步问:多验证这个 token 的 expected accepted token 增益,是否大于它占用的 batch capacity 成本。
2. 高并发下,验证 token 也是稀缺资源
低并发时,target model forward 可能没吃满,额外验证 token 的边际成本低。高并发时,每个验证 token 都可能挤掉另一条请求的一步 decode。固定 MTP-3 或 MTP-5 在这种情况下可能比 MTP-1 更差。
DSpark 的价值是让 verification budget 随负载变化:
低负载:多验,换更高单用户速度
高负载:少验,只保留高置信前缀,保护吞吐
3. 训练 drafter 和 serving scheduler 必须一起看
只训练一个更准的 drafter 不够。生产系统还要解决:
- confidence 校准是否准确。
- scheduler 是否能拿到实时或近实时的 capacity curve。
- variable-length prefix verification 是否会破坏 CUDA graph、batch layout、attention kernel。
- 监控里能否区分 proposed tokens、accepted tokens、verification tokens、bonus tokens。
论文里 DeepSeek-V4 为 variable-length routing 修改了 index-attention 和 compress kernels。这说明 DSpark 的线上收益依赖底层引擎配合。
学习路径
建议按这个顺序读:
- 先读 投机解码,理解 draft/verify/accept 的基本过程。
- 再读 DeepSeek-V3 Technical Report:中英对照解读 的 MTP 小节,分清训练目标和推理加速。
- 读 DSpark 论文的 Section 3,重点看半自回归生成和 Hardware-Aware Prefix Scheduler。
- 看 DeepSpec 源码:
deepspec/modeling/dspark/qwen3/modeling.pydeepspec/modeling/dspark/markov_head.pydeepspec/modeling/dspark/loss.pydeepspec/trainer/dspark_trainer.py
- 如果要做系统建模,把指标统一成:
gamma: 每轮 proposed draft tokens。verification_length: 实际送 target 验证的 token 数。accepted_length / tau: 每轮实际推进的 token 数,通常包含 bonus token。backend_step_accept_rate: 每个后端 step 的平均接受量,需确认是否含 base/bonus token。
参考资料
- DeepSpec GitHub 仓库
- DSpark paper: Confidence-Scheduled Speculative Decoding with Semi-Autoregressive Generation
- DeepSeek-V4-Pro-DSpark 模型卡
- DeepSeek-V4-Flash-DSpark 模型卡
- DeepSpec Qwen3-4B DSpark config
- DeepSpec DSpark Qwen3 model implementation
- DeepSpec DSpark Markov/RNN head implementation
- DeepSpec DSpark loss implementation
← 被以下页面引用(1)
- 推理框架对比 2026:从 Engine 到 Serving Stackai-systems · synthesis
修改历史1 次提交
- docs: add inference profiling notesxiaocheng··
6a94c5d