跳转到主要内容

DSpark 与 MTP:DeepSeek 投机解码调研

· 约 11 分钟阅读

结论

DSpark 是 DeepSeek 在 DeepSeek-V4 上使用的投机解码框架。它不是一个新的基础模型,而是在同一 V4 checkpoint 上挂了额外 speculative decoding 模块。Hugging Face 的 DeepSeek-V4-Pro-DSparkDeepSeek-V4-Flash-DSpark 模型卡也明确说明:DSpark 版本和原模型是同一 checkpoint,只是附加了投机解码模块。

它要解决的问题不是“能不能一次猜多个 token”,而是两个更工程化的问题:

  1. 长 draft block 怎么保持接受率。
  2. 高并发 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_draftdraft 更便宜小 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 courseno problem。完全并行预测时,第二个位置看到的是“各种可能前缀”的混合分布,可能组合出 of problemno 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 里有三种顺序头:

实现文件机制
VanillaMarkovdeepspec/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_logitsaligned_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-1DSpark
目标保守地多预测 1 个 token用更长 draft block 提高每轮接受 token 数
draft 长度固定短长度,论文生产基线是 1V4 线上 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,而在:

  1. 用半自回归头缓解长 block 后缀质量下降。
  2. 用 confidence 估计每个前缀的 expected return。
  3. 用硬件吞吐曲线按负载分配 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_block7
  • deepseek-ai/dspark_qwen3_8b_block7
  • deepseek-ai/dspark_qwen3_14b_block7
  • deepseek-ai/dspark_gemma4_12b_block7

Hugging Face API 还显示了 DeepSeek-V4 对应的 DSpark 版本:

  • deepseek-ai/DeepSeek-V4-Pro-DSpark
  • deepseek-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-4BDSpark vs Eagle3macro-average accepted length +30.9%
Qwen3-8BDSpark vs Eagle3+26.7%
Qwen3-14BDSpark vs Eagle3+30.0%
Qwen3-4BDSpark vs DFlash+16.3%
Qwen3-8BDSpark vs DFlash+18.4%
Qwen3-14BDSpark 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-3MTP-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 的线上收益依赖底层引擎配合。

学习路径

建议按这个顺序读:

  1. 先读 投机解码,理解 draft/verify/accept 的基本过程。
  2. 再读 DeepSeek-V3 Technical Report:中英对照解读 的 MTP 小节,分清训练目标和推理加速。
  3. 读 DSpark 论文的 Section 3,重点看半自回归生成和 Hardware-Aware Prefix Scheduler。
  4. 看 DeepSpec 源码:
    • deepspec/modeling/dspark/qwen3/modeling.py
    • deepspec/modeling/dspark/markov_head.py
    • deepspec/modeling/dspark/loss.py
    • deepspec/trainer/dspark_trainer.py
  5. 如果要做系统建模,把指标统一成:
    • gamma: 每轮 proposed draft tokens。
    • verification_length: 实际送 target 验证的 token 数。
    • accepted_length / tau: 每轮实际推进的 token 数,通常包含 bonus token。
    • backend_step_accept_rate: 每个后端 step 的平均接受量,需确认是否含 base/bonus token。

参考资料

修改历史1 次提交