推理与性能模型架构

DeepSeek DSpark:speculative decoding 终究要靠底层硬件调度

大模型为什么慢,speculative decoding 怎么加速

用大模型 API 做产品的人,基本都体验过回复慢的痛苦。这背后的物理原因大家可能都清楚,就是大模型得一个 token 一个 token 地往外吐,每生一个 token 就要跑一轮完整模型的前向传播。一个回复要是长达几百 token,就得老老实实跑几百次串行计算,延迟就是这么累加出来的。到了 Agent 工作流里情况更糟糕,多轮工具调用每一步都要干等模型出完结果,延迟一层层叠上去。这不光影响用户体验,甚至直接卡住了很多商业模式。

DeepSeek 最近发了一篇关于 DSpark 的论文。根据论文的数据,它能把推理延迟降低 60% 到 85%,整体吞吐量最高能翻五倍。这组数字听上去挺亮眼,但它到底是真有突破,还是一篇只在 benchmark 里好看、放到实际生产里就缩水的学术论文?我们要弄懂它的成色,得先看看它用的是哪种加速路子。

DSpark 走的是 speculative decoding 的路子。这个思路其实挺直白:既然大模型慢在串行,那能不能找一个又小又快的草稿模型,提前帮大模型猜出接下来的几个 token,然后再让大模型一次性把这整串草稿给验了?大模型自己验一串 token 只需要做一轮前向传播。只要草稿模型猜得够准,一次前向传播就能抵掉原本好几次串行生成,延迟自然就降下去了。如果猜错,就从错的那一步开始扔掉,主模型补一个对的 token,接着进行下一轮。

我们之前在 全能医院到智慧分诊 里,用医生看病备药的比喻聊过 DeepSeek V3 的多令牌预测。主治医生看到常见症状,一方面开化验单,另一方面让药房提前配药,检查如果对得上直接拿药,对不上就回滚,药房提前备的药直接作废。speculative decoding 本质上就是这个比喻的系统工程版本。

高并发下,speculative decoding 的核心在于该验证多少 token

要想让 speculative decoding 真的起作用,大前提是草稿模型得猜得准。但要是只盯着准确率,就会忽略另一半关键成本,因为主模型做验证并不是免费的。每次送去验证的 token,都会占用前向传播时 GPU 的 batch 容量。在单用户单请求的场景下,GPU 很多计算单元其实闲着,多验几个 token 几乎不需要额外成本。但一旦到了高并发的生产环境,每个没必要的验证 token 都会挤占其他请求的 batch 位置,结果就是大家一起变慢。所以,问题的焦点其实不在于猜得多准,而在于根据实时系统负载,动态决定这一步该验几个 token。这种收益与成本的权衡是实时变动的,一刀切的静态规则根本解决不了。

这就是 DSpark 要啃的硬骨头。它在算法上改的半自回归模型只是手段,真正的突破在系统层。它把 speculative decoding 的验证长度,从猜完就全送去验证的原始做法,改成了根据实时负载动态调度的全局优化。这个方向的改变,也解释了为什么 DeepSeek 能把它推进生产环境,而多数学术工作只能停在纸面上。这套调度要转起来,需要连同草稿模型、系统调度器以及底层推理 kernel 放在一起改。只有把整套推理栈都抓在自己手里的团队,才有动力和可能跑通这种深度优化。

这也说明 speculative decoding 正在从一个可有可无的加速外挂,变成大模型推理栈的标配。如果是直接调 API 做应用的开发者,DSpark 会完全透明,因为 DeepSeek 已经在服务端跑起来了。但对于需要自建推理栈的工程团队,这套调度逻辑就是必学内容。这也契合 DeepSeek 的一贯作风,不靠单点理论创新,而是通过扎实的系统工程整合成套路,去换取成本和速度上的绝对优势。我们在之前的 DeepSeek R1 使用随感DeepSeek V4 agentic workload 解读 里聊过,他们习惯筛出最管用的外围方案,然后靠重度工程整合去打磨复杂系统,DSpark 只是这条路线的又一次印证。

speculative decoding 的前缀匹配规则

我们在 全能医院到智慧分诊 里用看病的比喻聊过多令牌预测。这就像老医生看到典型症状的病人,一边开化验单,一边叫药房先把常见药抓好。化验结果出来如果对得上,病人拿药直接走,省了排队时间。如果没对上,就得推翻重新抓药,之前提前配好的药只能扔掉。

speculative decoding 在工程上就是把这个比喻落地。它用一个计算代价低、跑得飞快的草稿模型去往后猜几个 token,再用参数量庞大的主模型跑一次前向传播来统一验证。对的 token 就接收,错的 token 从发生错位的那一步起,后面即使猜对了也必须全部扔掉。

这种校验背后的刚性约束,是 prefix matching。大模型对 token 的验证是顺着序列从左往右挨个比对的,一旦在某个位置发生错位,后面所有草稿 token 的命运就结束了。正因为如此,草稿模型第一位 token 的预测准确率,直接决定了 speculative decoding 的加速效果。如果开头第一步就错了,后面哪怕全中,主模型也必须全部扔掉,回滚回来老老实实重新计算。这也意味着,即使草稿模型的整体 token 接受率还不错,只要第一步频繁出错,speculative decoding 就会经常失效,甚至可能比正常的一步步解码还要慢。

speculative decoding 的前缀匹配机制(prefix matching),以及 parallel 和 autoregressive 两种草稿模型在不同位置的准确率衰减对比。

并行预测为什么击败了自回归

在草稿模型的架构选择上,DSpark 论文的 4.3.1 节给出了一个违反直觉的实测结果。按常理推断,自回归草稿模型也就是一步一步用前一步生成的 token 做下一步输入来预测,应该比并行草稿模型更准,因为并行模型不依赖前面自己预测的 token,而是一次性把后面几步全预测出来。自回归草稿模型在猜下一个 token 的时候,好歹参考了刚才自己猜出来的上下文。

但实测数据显示,并行草稿模型在第一位 token 上的准确率反而更高。比如在数学任务上,并行草稿模型首位的准确率能到 0.88,而自回归模型只有 0.81。

造成这个现象的原因,在于两者的延迟约束完全不同。并行草稿模型只需要做一次前向传播,延迟成本是一个固定值,这让它的网络结构能设计得更宽、更深,表征能力更强。而自回归模型每多猜一步都要做一次完整的前向传播。为了不让草稿预测的延迟把主模型省下来的时间给抵消掉,自回归模型的参数量和深度不得不缩得很小,导致它在首位 token 的表现反而被限制住了。

由于 prefix matching 决定了首位 token 的准确率最重要,并行模型在首位上的准确率优势,直接补足了它在后续 token 上的短板,使其在平均接受长度上胜出。

不过,并行模型也有自己的硬伤,就是预测位置越往后越容易发生冲突。并行预测因为把后续的每个位置当成独立的任务来跑,各位置之间并不考虑其他位置的采样结果。如果一句话往后接,可以走第一种路线说 of course,也可以走第二种路线说 no problem,这两个续写方向在语法上都是合理的。但并行草稿模型因为各位置之间没有沟通,可能把第一种路线的词和第二种路线的词拼在了一起,变成 of problem 或者 no course。这种多模冲突会让第二步之后的准确率迅速走低,而自回归模型因为能看到前面采样了什么,越往后预测反而越稳。

DSpark 在算法层要解决的问题,正是怎么把并行模型在首位 token 上的高准确率留住,同时不让它后面的准确率衰减得太快。

用一阶 Markov 换 lossless 约束

并行模型预测时最大的硬伤在于各个预测位置孤立,越往后走,预测准确率掉得越快。DSpark 要想把后面位置的准确率拉回来,就必须在并行骨干网络上挂一个轻量模块,让后面的预测位置能看到前面已经采样出来的实际 token。

但是,这个模块面临一个硬性数学约束:它输出的概率必须精确。投机解码之所以能保证生成分布完全无损,全靠 rejection sampling(拒绝采样,一种通过对比草稿模型和主模型概率来决定是否接受 token 的验证机制)来把关。rejection sampling 要求草稿模型对每个位置的 token 都能给出精确的概率分布 p_d(x_k)。如果给不出这个精确的单步概率分布,后续的拒绝采样验证就无法进行。这把多数常见的序列建模方案挡在了门外。

在非自回归生成领域,为了让位置之间产生依赖,大家习惯用 CRF(条件随机场,一种引入全局邻近 token 约束的概率图模型)或者 CTC(联结主义时间分类,一种通过累加所有可能对齐路径来做序列对齐的算法)。但这些方案在投机解码里都行不通。CRF 计算时需要做全局归一化去计算所有路径的配分函数,CTC 则需要合并累加所有对齐路径的隐变量。这些计算虽然能给出序列级的分数或边缘概率,却无法还原成单个 token 在当前上下文下的精确单步 softmax 概率。

DSpark 最终选择退一步,采用了一阶 Markov 关系来破局。一阶 Markov 指的是下一个 token 的概率只依赖上一个 token,不再看更远的历史。在数学上,每个 token 的概率可以写成 p(x_k | x_{k-1}) = softmax(base_logit_k + transition_bias(x_{k-1}, x_k))。这里的 base_logit_k 来自并行骨干网络,而 transition_bias 来自一个查表操作,即用前一个 token 查一个 V×V 的低秩转移矩阵。

因为依赖关系只限于一阶,DSpark 不需要进行全局归一化,也不用去合并路径隐变量,每个 token 的概率依然是一次高效的 softmax 计算。这套方案建模能力虽然比那些复杂的循环神经网络或者 CRF 弱,但它恰好落在了能建模依赖且能给出精确概率的甜蜜点上。在实际工程里,一个能满足所有硬性约束的弱模型,远比一个会破坏概率一致性的强模型管用。

在工程实现上,这套一阶 Markov 机制几乎没有成本。它只包含一个低秩参数维度为 r=256 的 V×V 转移矩阵,运行时拿前一个 token 查表加到当前 logit 上即可。由于计算量极小,DSpark 跑起来带来的额外延迟开销仅有 0.2% 到 1.3%,相当于给并行骨干网络打上了一个低成本的纠偏补丁。

论文数据表明,加上这个纠偏补丁后,DSpark 相比 Eagle3,在 Qwen3-4B、8B、14B 模型上的接受长度分别提升了 30.9%、26.7% 和 30.0%。比起 DFlash,接受长度也分别高出了 16.3%、18.4% 和 18.3%。

系统层:把验证长度变成全局优化问题

如果只是在模型结构和算法上折腾,DSpark 大概率也会像其他 speculative decoding 方案一样,卡在实际生产环境之外。因为它真正的突破点不仅在算法本身,更在系统层的置信度调度。这套设计把验证长度这个决策,从静态的一刀切,变成了结合硬件吞吐的动态调度。

在传统的 speculative decoding 里,验证决策多是静态的。比如通过测试发现草稿长度选 7 效果最好,那就每次都让草稿模型猜 7 个 token。这种静态规则在单用户时问题不大,但在高并发生产环境里会遇到两个难关。

一个难关是不同任务的特征其实是分化的。像写代码、算数学题这种逻辑严密、结构性强的任务,大模型的输出非常确定,草稿模型预测的接受率通常很高。但如果是开放式闲聊,遣词造句千奇百怪,接受率就会迅速走低。对这两种任务用同样的固定长度去验证,会白白浪费不少计算资源。

另一个难关是系统负载会随时波动。我们在之前的 Prompt Caching 分析中聊过这个问题,高并发下能否跑得动,直接关系到调度机制。参考 Prompt Caching 作为一等约束。轻载时 GPU 算力还有富余,多验证几个哪怕没猜中的 token,开销也可以忽略不计。但是在重载或者请求排队时,GPU 资源已经被填满。这时如果草稿模型还盲目多猜并送去验证,就会占满 batch 通道,导致其他排队请求干等,拖慢系统吞吐。

DSpark 把验证长度从固定数字改成了根据实时负载动态决定。为了让这个想法落地,他们重构了调度链路。

首先是预测草稿的真实接受概率。他们在草稿模型尾部挂了一个轻量的置信度头,专门预测每个草稿 token 连同前面所有 token 一起被主模型接受的生存概率。由于模型预测出来的原始数值往往不够精准,他们用了一个叫 STS 的校准算法,在离线集上对置信度输出进行温度平滑,让估计概率能对齐真实接受率。

最后一步是结合硬件吞吐来做调度。调度器会提前测好一张吞吐量曲线 SPS(B),用来描述在不同 batch 规模下整个推理集群每秒能跑多少步。高并发流量进来时,调度器搜集当前批次所有请求生成的草稿 token,按校准后的生存概率排队。它会先挑概率最高的 token 送进验证池,一直加到如果再加就会因为 batch 变大、踩中吞吐曲线 SPS(B) 的性能拐点,导致每秒总步数变少时,调度器就会在这个拐点前收手。

通过这种方式,DSpark 成功地把应该验证多少个 token,变成了一个在系统层根据实时并发状态、请求类型以及 GPU 硬件特性动态调整的全局吞吐优化问题。

硬件感知调度器的工作机制:从草稿置信度评估、STS校准、全局排序,再到基于引擎吞吐曲线动态调整 admission 的完整流程。

生产部署的两个工程问题

要把这套置信度调度塞进实际推理引擎里,得解决两个工程难题。

一个是硬件底座的问题。真实的 GPU 在跑批处理推理时,它的吞吐曲线并不是连续、平滑的。因为 Tensor 核心对齐以及硬件缓存的物理限制,吞吐曲线 SPS(B) 呈现出阶梯状突变。这就意味着在数学上没法直接用公式算最优解。更麻烦的是,如果要在当前推理步做置信度的全局排序,就得先拿到当前步所有请求的置信度。这样一来,模型计算和调度逻辑就会产生互相等待的因果依赖,引入不可忽视的延迟,也会影响 CUDA graph 的编译回放。此外,如果处理不当,这种实时决策还可能泄露未来的 token 信息,从而破坏无损验证的要求。

DeepSeek 采用的是异步设计。调度器在决定这一批次能验证多少 token 时,不使用当前正在计算的置信度,而是使用退后两步的置信度信息来预测系统可能承受的 batch 空间。而在挑选具体让哪些 token 进池子时,依然按当前真实的置信度排序。这两步的步长差起到了安全隔离的作用,既避开了信息泄露的风险,也让 GPU 能正常回放 CUDA graph。

另一个难题是变长验证对底层算子的性能损耗。由于每个请求的草稿 token 被验证的长度在不停变化,送去验证的 token 长度各不相同,属于变长查询。如果用市面上的静态 decode kernel,为了对齐序列就必须做 padding,也就是拿 0 补齐空位。但这会导致大量计算资源白白花在 0 矩阵的乘法上,GPU 利用率会明显下跌。

为了解决这个问题,DeepSeek 重新编写了推理栈底层的 index-attention 算子和 compress 算子这两个 kernel。他们不给输入做 padding,而是把批次里的变长 token 全部打平,变成一维的扁平 tensor。序列内部的位置依赖和因果关系,则通过一套位置标记 tensor 传给底层的自注意力计算。这也意味着 DSpark 不是那种下载一个开源模型就能直接插在通用 vLLM 上的挂件。它是算法与推理引擎底层算子深度融合、专门针对特定硬件调优出来的系统。

DSpark 性能提升概览:左图为在相同吞吐下的每用户加速(V4-Flash 60%-85%,V4-Pro 57%-78%),右图为接受长度提升(vs Eagle3 和 vs DFlash),底部标注 Markov head 延迟开销仅 0.2%-1.3%。

边界与对 AI builder 的含义

DSpark 有三个边界需要注意。

首先是低接受率场景下的额外开销。虽然 DSpark 能通过 STS 校准和置信度调度来控制无效验证,但在一些天然发散、接受率低的流量场景中,比如开放式闲聊,草稿模型的前向传播开销仍然省不掉。在这些任务下,speculative decoding 不仅带不来加速,甚至可能微幅推高整体的 token 成本。

另一个边界是 STS 校准面对分布漂移时的表现。置信度调度能起作用,前提是估计的置信度能对齐真实接受率。但校准依赖于离线验证集,一旦线上流量遇到不常见的数据格式或特定语法,置信度估计就很可能失准。如果调度器因此把不该验的拉进来,或者漏掉该验的,表现就会下降。目前论文还没给出在数据分布漂移下的鲁棒性数据。

此外,异步调度也依赖一个强假设,即线上流量和请求状态在两个生成步的极短时间窗口内,不会发生爆发式的剧烈波动。如果遇到高并发流量的瞬间涌入,这种假设能否扛得住,会不会导致调度队列发生阻塞,还需要在真实生产环境中进一步测试。

至于 DSpark 对普通的 AI builder 意味着什么,我们需要按不同的计算资源获取模式分开来看。

如果你只是调用大模型 API 来做上层开发的工程师,DSpark 基本上是透明的。你不用改代码,也不需要懂底层算子,DeepSeek 已经在自己的 API 服务端部署了这套调度。它带来的直观好处就是 API 时延更低,以及未来的降价空间。特别是在需要快速响应、多步交互的 Agent 场景里,延迟降低会明显提升交互体验。

但如果你是一个自建 LLM 推理栈的工程团队,DSpark 则给出了一个非常清晰的结论:speculative decoding 的收益大头在系统调度层,而不在草稿模型的算法层。自建推理栈如果只是拿开源的 Eagle3 挂在引擎上,而没有结合自己 GPU 集群的具体吞吐曲线去写一套硬件感知的动态调度器,遇到生产环境的高并发负载时,你会发现 speculative decoding 带来的收益,很快就会在 GPU 排队等待里被消耗光。要想释放它的潜力,就得像 DeepSeek 这样,走到底层,重构适合自己硬件的调度和算子。

鸭哥每日手记

日更的深度AI新闻和分析