/ DeepSeek
[DeepSeek-6] DSpark: From Draft Models to Serving-Aware Speculative Decoding
A systems-oriented deep dive into DSpark, covering semi-autoregressive drafting, Markov/RNN sequential heads, confidence heads, STS calibration, hardware-aware prefix scheduling, training objectives, DeepSpec implementation, and DeepSeek-V4 deployment tradeoffs.
DSpark 表面上是一篇投机解码论文,真正有意思的地方却不只是“又训练了一个更好的 draft model”。它把问题拆成了两半:
- 草稿怎样更像 target model:parallel drafter 一次前向能出很多 token,但 block 内 token 彼此独立,后缀很容易崩;
- 草稿应该验证多少:长 block 可以提高潜在加速,但在高并发服务里,低置信度后缀会占用 target model 的 batch capacity,反而拉低吞吐。
一句话概括:
DSpark 是一个把“半自回归草稿生成”和“负载感知验证调度”绑在一起的投机解码系统。
它既不是 DeepEP/FlashMLA 那类底层 kernel,也不是 DeepSeek-V4 的主模型结构,而是部署在 Decode 循环旁边的加速层:先用轻量 draft model 预测一段候选 token,再让 DeepSeek-V4 一次性验证一个经过调度的 prefix。官方 V4-Flash-DSpark 模型卡也把它描述为同一 checkpoint 叠加 DSpark speculative decoding 模块,而不是一个新的基础模型。模型卡 论文报告中,DSpark 已被部署到 DeepSeek-V4-Flash 和 DeepSeek-V4-Pro preview 的线上服务系统,相比此前 MTP-1 生产基线,在匹配吞吐下带来 60%–85%(V4-Flash)和 57%–78%(V4-Pro)的单用户生成速度提升。DSpark 论文
本文基于 DSpark 论文和官方开源的 DeepSpec 训练/评测仓库来拆解它的算法与系统边界。DeepSpec 仓库
1. 先从投机解码的目标函数看 DSpark#
标准自回归解码每生成一个 token 都要跑一次 target model。投机解码把一次循环改成两步:
当前上下文
|
| 轻量 draft model 生成 gamma 个候选 token
v
x1, x2, ..., x_gamma
|
| target model 一次前向并行验证这些 token
v
接受最长合法 prefix + 生成一个 bonus token如果一次循环中接受的 token 数为 ,draft 前向耗时为 ,target 验证耗时为 ,那么平均每个生成 token 的延迟可以近似写成:
所以加速只有三个方向:
| 方向 | 对应问题 | DSpark 的做法 |
|---|---|---|
| 降低 | 草稿生成不能太慢 | 保留 parallel backbone,一次前向生成整段 hidden/logits |
| 提高 | 草稿要尽量被 target 接受 | 在 parallel backbone 后加轻量 sequential head,注入 block 内依赖 |
| 降低有效 | 不要验证注定失败的后缀 | confidence head + hardware-aware prefix scheduler |
早期 autoregressive drafter 的优点是质量高,因为第 个草稿 token 能看到前面已经采样出的 token;缺点是草稿也要一步一步生成, 随 block size 线性增长。Parallel drafter 则相反:一次前向预测所有位置,draft latency 对 block size 不敏感,但每个位置都在对所有可能前缀做边缘化,容易出现“前两个 token 各自合理,连起来却不合理”的 mode collision。1
DSpark 的核心判断是:不要在 heavy backbone 上恢复完整自回归,只在输出端加一点很便宜的局部自回归。
2. 为什么纯 parallel drafter 会出现 suffix decay#
考虑一句自然语言续写:
没问题,可以 ...后面可能接“继续处理”,也可能接“帮你看看”。纯 parallel drafter 在同一次前向里同时预测多个位置:
position 1: 继续 / 帮你 / 直接 / ...
position 2: 处理 / 看看 / 执行 / ...问题在于 position 2 并不知道 position 1 最后采样成了哪个 token。它学到的是“所有可能 position 1 的混合条件分布”,因此可能把不同模式的后缀拼在一起。投机解码的验证又是严格 prefix survival:第一个 token 被拒绝,后面的 token 再好也全部作废;越靠后的 token 受到前面不确定性的连锁影响,条件接受率越容易下降。
论文把这个现象称为后缀接受衰减。离线分析里,DFlash 这类 parallel drafter 的首 token 接受率很高,但后面位置下降明显;Eagle3 这类 autoregressive drafter 首 token 容量较弱,后续位置却更稳定。DSpark 要组合两者:用 parallel backbone 抢首 token 和整体容量,用 sequential head 修补后缀一致性。1
3. Semi-Autoregressive:重前向并行,轻输出串行#
DSpark 的生成结构可以分成两级:
anchor token x0
|
v
+-----------------------------+
| Parallel Backbone |
| 一次前向产生 h1...h_gamma |
| 和 base logits U1...U_gamma |
+-----------------------------+
|
v
+-----------------------------+
| Lightweight Sequential Head |
| 按位置采样,并给 logits 加 |
| prefix-dependent bias |
+-----------------------------+
|
v
candidate block x1...x_gammaParallel backbone 在论文实现中以 DFlash 为基础。一个小改动是:DFlash 原本输入“anchor token + gamma 个 mask”并预测 mask 位置;DSpark 把 anchor 本身作为第一个预测位置,因此输入“anchor + gamma-1 个 mask”即可得到 gamma 个草稿 logits,减少一格草稿计算。1
Sequential head 不重新跑 Transformer,而是在每个位置的 base logits 上加一个很轻的偏置:
这样仍然能给出每个位置的精确 token probability,满足投机解码 rejection sampling 需要的 draft distribution;同时采样阶段只是在输出层做一个很短的串行循环,不把整个 draft backbone 变成自回归模型。
4. Markov Head:用低秩转移矩阵补一阶依赖#
DSpark 默认使用 Markov head。它假设第 个 token 的额外偏置只依赖上一个 token :
如果直接存一个 的 token transition 矩阵,词表一大就不可接受;DSpark 用低秩分解:
prev token id
|
v
W1 embedding: [vocab] -> r
|
v
W2 projection: r -> [vocab]
|
v
transition bias 加到 base logits 上论文默认 rank 为 256。DeepSpec 的 VanillaMarkov 实现也正是一个 embedding 加一个无 bias linear projection:markov_w1 查上一个 token 的低维向量,markov_w2 投到 vocab 维度,然后与 backbone logits 相加。Markov head 源码
这件事的工程含义很直接:
- heavy computation 仍然是一次 parallel backbone forward;
- 串行部分只做
gamma次低秩投影和采样; - 每一步的 draft probability 都是普通 softmax,不需要 CRF/CTC 那样的全局归一化或 latent marginalization;
- 对投机解码来说,概率可计算比“生成起来像一个序列模型”更关键。
DeepSpec 还实现了 GatedMarkovHead 和 RNNHead。RNN head 能维护 block 内 recurrent state,理论上看到更长前缀;论文实验中 RNN 在较长 proposal length 上有边际收益,但默认仍选择 Markov head,因为它更简单、更容易部署。3
5. Confidence Head:预测“这个 prefix 还能活多久”#
即使 DSpark 能生成更长、更好的草稿,也不意味着每次都应该把全部 token 交给 target model 验证。投机解码只接受连续 prefix,因此真正有价值的不是单个 token 是否看起来靠谱,而是:
DSpark 的 confidence head 为每个位置输出 ,语义是:在前面 token 都已被接受的条件下,第 个 token 通过 target 验证的概率。论文用 draft distribution 和 target distribution 的 total variation distance 构造软标签:
这和投机解码接受概率直接相关:draft 越接近 target,理论接受率越高。DeepSpec 的训练代码也会先对 draft_logits 和 aligned_target_logits 做 softmax,再计算 作为 accept_rate_3d;confidence loss 则是 binary_cross_entropy_with_logits(confidence_pred, accept_rate_3d)。loss 源码
这里有一个容易忽略的点:confidence head 不是只为了“过滤低分 token”。DSpark 后面的 scheduler 要计算 expected throughput,因此需要 confidence 的绝对数值接近真实接受率,而不仅是排序正确。论文因此引入 Sequential Temperature Scaling(STS):在验证集上从左到右校准 cumulative survival probability,降低过度自信,让 更接近经验 prefix 接受率。1
6. Hardware-Aware Prefix Scheduler:验证长度是系统问题#
如果每个请求都固定验证 7 个草稿 token,低负载时可能没问题,因为 target GPU 还有空闲算力;高负载时就会伤害吞吐,因为被拒绝概率很高的后缀仍然占用 batch slot。
DSpark 把验证长度选择写成一个全局吞吐最大化问题。设当前有 个活跃请求,第 个请求的第 个 prefix survival probability 为:
若给请求 分配验证长度 ,target 本轮要处理的 token batch size 近似为:
其中 1 是 target 自己产生 bonus/corrected token 的位置。期望产出的 token 数为:
服务引擎在不同 batch size 下的 steps-per-second 可以通过 profiling 得到,记为 。于是 scheduler 的目标是最大化:
直觉上,所有候选 prefix extension 都可以按 从高到低排队:高 survival probability 的 token 更值得验证,低 survival probability 的 token 只有在系统很空的时候才值得拿来填 GPU。由于 prefix probability 随 单调不增,这个排序天然不会破坏单个请求内部的 prefix 依赖。1
这就是 DSpark 比静态阈值更系统化的地方:
| 场景 | 静态阈值 | DSpark scheduler |
|---|---|---|
| 低并发 | 可能过早截断,浪费空闲算力 | 放宽验证预算,多吃可接受 token |
| 高并发 | 可能继续验证低价值后缀 | 收紧预算,保护 batch capacity |
| 不同领域 | 同一个阈值难适配 math/code/chat | 按每个请求的 survival probability 排序 |
| 不同硬件/engine | 不知道 batch size 对 SPS 的影响 | 直接查 engine-specific throughput curve |
7. 理论 scheduler 到线上系统之间还有一层现实#
论文中的 Algorithm 1 为了保持 lossless speculative decoding,需要注意 non-anticipating property:是否验证第 个 token,不能偷看未来 token 的 realization。否则 admission decision 会引入选择偏差,破坏 target distribution 的精确恢复。
但线上系统还有两个现实约束:
- 真实
SPS(B)不是平滑曲线,而是离散、锯齿状的硬件容量曲线; - 高性能 decode 引擎通常依赖 CUDA graph replay 和 Zero-Overhead Scheduling,下一步 batch size 需要提前知道,不能等本步全部结束后再慢慢调度。
DSpark 的生产适配采用异步近似:当前候选 token 仍按最新 confidence 排序,但用两步之前的 confidence 输出预测下一步可用的 dynamic truncation length,也就是一个动态 top- 选择。这个两步延迟看起来像近似,实际也形成了一个 causal barrier:调度容量来自历史信息,不依赖当前 token 的未来 realization,因此可以在隐藏 scheduling latency 的同时维持 lossless 性质。1
另外,变长 prefix 会给 kernel 执行带来麻烦。标准 decode kernel 常假设 batch 内 query length 较规整;如果直接 padding 到同一长度,scheduler 刚刚省下的验证预算又会被 padding 吃掉。论文提到 DeepSeek-V4 部署中把物理执行和逻辑序列跟踪解耦:kernel 层把不同请求的 token flatten 成独立元素处理,序列内依赖通过 marker tensor 传给稀疏 attention;在 V4 架构上主要需要改 index-attention 和 compress kernels。1
8. DeepSpec 代码里 DSpark 是怎样落地的#
开源仓库 DeepSpec 的定位不是生产推理引擎,而是用于训练和评测 speculative decoding draft models 的代码库,包含数据准备、draft model 实现、训练和评测脚本。README 列出的工作流是:准备数据、训练 draft model、在 benchmark 上评测接受长度;默认配置假设单节点 8 GPU,目标缓存可能非常大,例如 Qwen3-4B 默认设置下约 38 TB。2
以 config/dspark/dspark_qwen3_4b.py 为例,开源配置展示了几个关键选择:config 源码
block_size = 7
num_draft_layers = 5
target_layer_ids = [1, 9, 17, 25, 33]
num_anchors = 512
markov_rank = 256
markov_head_type = "vanilla"
confidence_head_alpha = 1.0
confidence_head_with_markov = True
ce_loss_alpha = 0.1
l1_loss_alpha = 0.9这些参数和论文主线基本对应:
- draft backbone 取 target model 多个层的 hidden states,经投影后作为上下文特征注入 draft attention;
- 训练时随机采样多个 anchor position,每个 anchor 形成一个 block;
- 输入 embedding 中 block 第一个位置放 anchor token,其余位置放 mask token;
- attention mask 允许 draft token 看 anchor 之前的 target context,以及同一个 draft block 内的位置;
- embedding 和 LM head 从 target model 拷贝并冻结,只训练 draft backbone、sequential head 和 confidence head;
- loss 由 CE、distribution matching 的 L1/TV 项、confidence BCE 项组成,且靠前位置权重更高。
这也解释了 DSpark 为什么和“直接外挂一个小模型”不同。它不是完全独立地读 raw token context,而是利用 target model 的中间 hidden features 对齐目标分布;训练时还需要 target logits 或 LM-head 前 hidden states 来做分布匹配监督。2
9. 训练目标:不只预测正确 token,还要贴近 target 分布#
如果 draft model 只做交叉熵,目标是预测数据中的 ground-truth token。但投机解码关心的是 draft distribution 和 target distribution 的匹配程度,因为 rejection sampling 的接受概率由 与 的关系决定。
DSpark 因此使用三类损失:
其中:
- 让 draft 预测真实下一个 token;
- 惩罚 ,直接推动接受率;
- 训练 confidence head 预测软接受率 ;
- 位置权重 强调靠前 token,因为 prefix 验证中前面位置的拒绝会让后面全部失效。
DeepSpec 源码里对应的是 ce_loss_alpha=0.1、l1_loss_alpha=0.9、confidence_head_alpha=1.0。命名上源码叫 l1_loss,论文里讨论的是 total variation distance;两者只差一个 系数,对优化方向一致。1
10. 结果应该怎样解读#
离线评测里,DSpark 在 Qwen3-4B/8B/14B 和 Gemma4-12B 上,相比 Eagle3 与 DFlash 都提升了 accepted length。论文报告 Qwen3 三个规模上,DSpark 相比 Eagle3 的 macro-average accepted length 提升分别为 30.9%、26.7%、30.0%;相比 DFlash 分别提升 16.3%、18.4%、18.3%。1
但我认为更值得关注的是线上结果。DeepSeek-V4 生产部署里,MTP-1 是此前稳定基线;静态 MTP-3/5 在高并发下可能因为验证开销过大而降低总吞吐。DSpark 的价值不是“永远验证更多 token”,而是:
低负载:多验证,利用闲置 target compute 提升用户 tok/s
高负载:少验证,把 batch capacity 留给更有希望的 token/请求论文在 live traffic 下报告:
| 模型 | 中等 SLA 下吞吐收益 | 匹配吞吐下单用户速度收益 | 严格 SLA 下的含义 |
|---|---|---|---|
| DeepSeek-V4-Flash | 80 tok/s/user SLA 下 +51% throughput | +60% 到 +85% TPS | 120 tok/s/user 下 baseline 接近边界,DSpark 扩展可行区间 |
| DeepSeek-V4-Pro | 35 tok/s/user SLA 下 +52% throughput | +57% 到 +78% TPS | 50 tok/s/user 下 baseline 进入低并发退化区 |
这些数字不应简单理解为所有场景固定提速几倍。更准确的解读是:DSpark 改变了吞吐与交互速度之间的 Pareto frontier,尤其是在高并发和严格 interactivity 目标同时存在时,负载感知调度比固定 draft length 更稳。1
11. 它和 MTP、DFlash、DeepSeek-V4 的关系#
可以把几条线放在同一个坐标里:
| 名称 | 角色 | 关键特征 |
|---|---|---|
| MTP-1 | DeepSeek 早期生产 baseline | 每轮只额外预测/验证少量 token,稳定但加速空间有限 |
| DFlash | parallel drafter | 一次前向出长 block,首 token 强,后缀独立性导致 suffix decay |
| DSpark | semi-autoregressive + scheduled speculative decoding | 用 Markov/RNN head 修补后缀,用 scheduler 控制验证预算 |
| DeepSeek-V4 | target model / serving system | DSpark 服务于 V4-Flash/V4-Pro decode,不改变 target 分布 |
| DeepSpec | 开源训练评测仓库 | 复现 Eagle3/DFlash/DSpark 训练与 accepted-length 评测 |
这也说明 DSpark 的边界:它不是替代 target model,而是借助 target model 的验证规则保持输出分布不变;它不是只靠一个更深的 draft model,而是把 draft quality、confidence calibration、engine profiling 和 online scheduling 合在一起。
12. 局限与工程启发#
DSpark 仍有一个固定成本:无论最终验证几个 token,parallel backbone 都要先生成最大 block。对于本身极难预测、接受率很低的请求,这部分 draft compute 可能无法回收。论文也提到未来可以做 difficulty-aware early exiting,让低收益请求跳过完整草稿生成。1
另外,开源 DeepSpec 目前更适合研究和训练 draft model;论文中的 DeepSeek-V4 生产 scheduler、异步 ZOS 集成、变长 query kernel 支持并不是完整开源推理栈的一部分。因此读 DSpark 时最好区分三层:
- 算法层:semi-autoregressive draft + confidence-scheduled verification;
- 开源训练层:DeepSpec 里可训练 Qwen/Gemma 目标模型的 DSpark draft checkpoints;
- 生产系统层:DeepSeek-V4 服务中的异步 scheduler、capacity profiling、CUDA graph/ZOS/variable-length kernel 适配。
对推理系统的启发则很清晰:投机解码不应只问“draft model accepted length 多高”,还要问“这些额外验证 token 在当前系统负载下值不值得”。当 decode 服务进入高并发、低空闲算力区域时,验证预算本身就是一种调度资源。
13. 总结#
DSpark 的设计可以压缩成三个关键词:
- Semi-autoregressive:用 parallel backbone 保持草稿吞吐,用 Markov/RNN head 在输出端补充 block 内依赖;
- Confidence-scheduled:用 calibrated confidence 估计 prefix survival probability,而不是固定验证长度;
- Serving-aware:把 engine throughput curve、并发负载、CUDA graph/ZOS 约束纳入验证预算选择。
如果说 FlashMLA 和 DeepEP 体现的是 DeepSeek 在 kernel 与通信层的系统优化,那么 DSpark 展示的是另一种系统能力:让模型侧的 speculative decoding 算法进入真实服务引擎,并且按线上负载动态改变行为。
这也是它值得放进 DeepSeek 系列的原因。它提醒我们,大模型推理加速的关键不一定是单个算子更快,也可能是把“哪些 token 值得被算”这件事做成一个可学习、可校准、可调度的系统问题。