DeepSpec发布:让大模型生成提速6倍,输出质量却一点没变差
DeepSpec不是新模型,而是给现有大模型配了一个“秘书”。秘书提前把下一段内容写完,主模型只需一次验证就能签字通过,不用再像以前那样一个字一个字地重新计算。官方在DeepSeek-V4上实测,相比传统方案,用户端生成速度可以提升60%到85%,在部分严格延迟约束下甚至能拉开数倍差距。这个框架的核心论文提出了DSpark算法,已经把代码和检查点全部开源。
大模型生成一个词就要重新跑一遍全部计算,这种低效快把GPU逼疯了
当你在聊天框里问一个问题,大模型不是一口气把答案写出来,而是一个词一个词往外蹦。每蹦一个词,它都要把整个Transformer网络从头到尾跑一遍。哪怕前面已经算过的“今天天气”这四个字,到了生成第五个字的时候,模型还得把“今天天气”这四个字的上下文重新加载,再从头开始计算第五个字是什么。
这个过程有多夸张?你让它写一篇两百字的短文,它就要把那个庞大的神经网络反复加载两百次。GPU大部分时间不是在计算,而是在等待数据搬运、调度同步、读写缓存。这就好比一个顶级厨师每次只炒一粒米,炒完一粒把锅刷干净,再炒下一粒。锅很大,火很旺,但每次只服务一粒米,吞吐量自然上不去。
行业早就发现了这个痛点,所以提出了推测解码这个方向。
思路很简单:既然主模型算一次只能出一个词,那我能不能先搞一个小模型随便猜一串词,然后让主模型一次性验证这一串?如果猜对了,主模型一次就算了好几个词,省下了大量重复计算。如果猜错了,最多浪费掉猜错的那一小段,前面的成果照样保留。
但问题在于,传统推测解码里那个负责猜词的小模型通常也是一个个词顺序生成的。它猜一串词,本身就要跑好几步,虽然比大模型快,但这套流程的加速上限很快就被卡住了。
于是出现了并行式生成,小模型一步就能吐出整个序列,但代价是词和词之间缺少依赖关系,经常猜出“今天天气真糟糕,我们一起去游泳吧”这种语义分裂的句子,后面的词很快就被主模型拒绝,前期猜的功夫白费了一大半。
并行生成之所以老猜错,根源在于每个词都闭着眼瞎蒙
并行生成是怎么回事?正常写一段话,你写第二个词的时候,脑子里已经有了第一个词。写第三个词的时候,前面两个词都定下来了。但并行生成不是这样,它一次把所有位置都填满,每个位置的预测完全独立,彼此之间没有任何信息交换。
这就导致了一个经典问题,论文里管它叫多模态碰撞。
比如上下文是“当然”,那后面可能接“可以”也可能接“没问题”。
如果并行生成,第一个位置抽到了“可以”,第二个位置却可能因为独立预测抽到了“问题”,结果拼出来就是“当然问题”,驴唇不对马嘴。
更麻烦的是,因为每个位置都是独立从概率分布里抽的,这种错位组合会随着序列变长指数级增加。
到了第五个第六个位置,猜对的概率已经跌到没法看。
很多人直觉上会觉得,一步一步顺序生成的模型肯定比并行生成的猜得更准,因为每一步都看了上一步的结果。但论文里做了一个反直觉的实验:在同样7个词的猜测窗口下,并行生成的DSpark平均能猜中5到6个词,而顺序生成的Eagle3只能猜中3.5到4个词。并行生成反而赢了。
为什么?因为顺序生成虽然每一步都看得更准,但它第一步就吃亏了。为了控制每步的计算延迟,顺序生成的小模型必须做得很浅,层数很少,第一步猜词的质量就不高。一旦第一个词猜错,后面全部作废,整个序列直接归零。并行生成的小模型可以做得非常深,五层八层往上堆,第一步猜词的命中率远高于浅层顺序模型。后面的词虽然因为缺少依赖容易出问题,但第一步的高命中率已经保住了基本盘,后面再错也有个兜底。
这个洞察就是DSpark整个设计的出发点:能不能既保留并行生成的高容量第一步,又在后续位置注入顺序依赖来抑制尾部的错误爆炸?
DSpark拆成两步走,并行负责起跑速度,顺序负责纠正跑偏
DSpark把生成过程拆成两个阶段。
第一个阶段照常使用一个深层的并行骨干网络,一次性输出整个块的隐藏状态和基础概率。这个骨干网络和之前的DFlash结构类似,但做了微调:原来需要额外塞一个锚点词加上掩码标记,现在直接把锚点词当作块内第一个预测位置,输入的长度和输出长度完全对应,省掉了一次冗余计算。
第二个阶段加了一个极轻量级的顺序头。这个头的计算量小到可以忽略不计,但它做的事情很关键:每个位置在拿到并行骨干输出的基础概率之后,额外叠加上一个依赖前文的偏置项。具体来说,当你在第二个位置的时候,顺序头会看一眼第一个位置实际采样的词是什么,然后调整第二个位置的概率分布,让那些跟前文语义连贯的词概率更高,不连贯的词概率压低。
论文里最朴素的实现叫马尔可夫头,它只依赖前一个词。假如第一个位置采到了“当然”,那第二个位置“可以”的概率就被抬上去,“问题”的概率被压下来,从根本上杜绝了“当然问题”这种组合。
更复杂一点的RNN头会维护一个隐状态,把整个前缀信息都压缩进去,理论上依赖更长。但实验显示马尔可夫头已经能解决绝大部分问题,RNN头在长块上只有微弱优势,考虑到实现复杂度,论文把马尔可夫头作为默认配置。
这个顺序头的计算开销有多低?论文测了一组数据,在批量大小128、上下文长度从512到4096变化的情况下,顺序头的额外延迟只占总轮次延迟的0.2%到1.3%。也就是说,你几乎免费获得了顺序依赖的纠偏能力,骨干网络依然是并行的,吞吐量没有明显损失,但尾部命中率大幅回升。
光猜得准还不够,验证哪些词也是一笔经济账
有了半自回归架构,DSpark能稳定猜出很长的序列。但论文里抛出一个尖锐问题:猜得长就一定要全验证吗?
传统推测解码的做法是,小模型猜了7个词,主模型就一次性验证这7个词。但在真实系统里,验证也是有成本的。主模型每验证一个额外词,都要占用一次前向计算的一部分算力,尤其是在高并发环境下,成百上千个请求同时挤在GPU上,每一个多余的验证词都在抢夺其他请求的资源。
这个成本在不同场景下差异巨大。假如系统负载很轻,GPU本来就闲着,多验证几个词几乎不增加延迟,那验证全量序列完全合理。但假如系统已经满载,每多验证一个词都可能让其他请求排队,那验证那些大概率会被拒绝的尾巴词就很不划算了。
更麻烦的是,不同任务的可预测性天然不同。写代码的时候,函数名和变量名受上下文强约束,模型猜中率很高。但开放域闲聊的话题发散性极强,后面的词谁都说不准。用固定的长度去验证所有请求,要么在结构化任务上浪费了潜力,要么在发散任务上浪费了算力。
论文里给了一组具体数字:在数学推理和代码生成任务上,固定验证7个词的平均接受长度能到5.1到5.6。但到了日常对话上,平均接受长度直接掉到3.1到3.6。这意味着尾部有大量词是注定被拒绝的,验证它们纯粹在消耗系统的生命。
自信度调度器像一个精明的采购员,只买那些最可能成交的词
DSpark的解决方案是给每个预测位置配一个自信度分数。这个自信度不是模型拍脑袋想的,而是用主模型和草稿模型在那个位置上的概率分布差异计算出来的。两个分布越接近,意味着草稿模型和主模型的判断越一致,这个词被主模型接受的概率就越高。论文里把这个真实接受率作为监督信号,训练一个额外的轻量级自信度头,直接预测每个位置的接受概率。
有了每个位置的自信度,调度器的工作就变成了一个组合优化问题。当前批次里有R个请求,每个请求都有一个预测块,每个块里每个位置都有一个自信度。调度器要从所有这些候选位置里挑选出一批最值得验证的词,使得整个系统的吞吐量最大化。
这里面有个细节很有意思:自信度是递减的。第一个位置的接受概率最高,第二个位置必须乘上第一个位置接受的概率才成立,所以累积接受概率是单调递减的。这就保证了如果你验证到第三个位置,那前两个位置肯定也在验证范围内,不会出现跳过前面直接验证后面的情况。
调度器维护一个全局候选池,把所有请求所有位置的累积接受概率排个序,从高到低依次纳入验证计划。每纳入一个词,验证批次的总规模就增加1,同时系统吞吐率的预估也会变化。因为GPU在不同批次大小下的实际处理速度是预先测好的,存在一张成本表里,调度器可以实时查表算出当前计划对应的期望吞吐量。
但这张表不是平滑曲线,GPU的实际吞吐量会随着批次大小出现阶梯状跳变。有时候增加一个词反而把吞吐量拉高,因为刚好填满了闲置的计算单元。有时候再增加一个词可能触发缓存溢出或者调度开销,吞吐量反而下降。调度器要在真实硬件曲线上找到那个最优的截断点。
调度器必须守住一条红线,否则输出质量会悄悄崩掉
上面说的调度逻辑看起来很漂亮,但它藏着一个致命的陷阱。如果调度器在决定要不要验证第一个词的时候,偷偷看了一眼第一个词采样出来的具体内容,那整个推测解码的无损保证就作废了。
论文在附录里专门用一个完整的数学反例说明了这个问题。
假设第一个词有两种可能,A和B。如果采到A,那第二个词大概率也能猜对,调度器一算,验证两个词的总吞吐最高,于是决定验证第一个词。如果采到B,那第二个词肯定猜错,调度器一算,还不如一个都不验证,于是拒绝验证第一个词。
问题出在哪里?第一个词本身被采纳的概率被污染了。原本第一个词接受与否只取决于主模型和草稿模型在那个词上的概率比值,但在上面这个例子里,接受概率还额外叠加了一层“如果第一个词是A就更可能被接受”的偏差。最终输出分布就和主模型的原始分布不一样了,推测解码不再是无损加速,变成了一个有损近似。
DSpark怎么避开这个坑?调度器在执行过程中一旦发现增加下一个词会导致预期吞吐下降,立即停止,不再往后看。这个提前停止的机制保证了决定验证到第几个位置这个动作,只依赖已经确认接受的前缀信息,不依赖任何尚未采样的未来词。之前那个例子中,验证一个词的时候吞吐已经比不验证低了,调度器当场停住,根本不会去评估第二个词,因此第一个词的采纳决策不受第二个词的任何影响。
这个因果约束在实现上又跟工业界的零开销调度产生了冲突。生产系统为了隐藏延迟,会提前两拍决定下一轮的批次规模。DSpark的工程方案是把调度器的截断长度预测建立在两拍前的自信度信息上,当前时刻的真实采样结果不参与本次截断决策,只用来更新下一轮的历史信息。这样就形成了一道因果屏障,既兼容了高性能调度框架,又保住了无损保证。
线上跑起来之后,系统能自动根据拥挤程度调节验证长度
论文把DSpark部署到了DeepSeek-V4的预览版生产引擎里,和之前一直在用的单词预测方案做了对比。单词预测是之前的生产默认配置,因为多词预测在高并发下会严重拉低总吞吐,所以生产环境一直不敢开大窗口。DSpark的目标就是打破这个僵局。
线上实测的结果很有意思。在并发请求数不到200的时候,调度器给每个请求分配的验证长度平均在4到6个词,远高于单词预测的固定2个词。验证长度增加了,每个主模型前向能接受的词数也增加了,单用户生成速度在同等系统吞吐水平下提高了60%到85%。
当并发数继续往上堆,GPU开始满负荷运转的时候,调度器自动缩短了每个请求的验证长度。尾部那些低自信度的词被主动截掉,批次里塞的都是高回报率的词,珍贵的计算资源不再浪费在注定被拒绝的猜测上。整个系统在负载波动下保持稳定,没有出现多词预测导致的总吞吐崩盘。
论文里还专门提了一个极限场景。对于延迟要求非常苛刻的交互式服务,比如要求每用户每秒至少生成120个词,传统方案因为只能维持很小的并发批次,总吞吐会掉到地板。但DSpark在同样严格约束下依然能维持有效服务,把可行域向外推了一大截。
DSpark解决的不是模型笨不笨的问题,而是模型快不快的问题
纵观整个设计,DSpark没有动主模型的一根参数。主模型该生成什么还是生成什么,质量没有任何下降。它所有的改动都发生在草稿生成和验证调度这两个外围环节。并行骨干加顺序头这个结构,本质上是在猜测质量、猜测速度和验证开销三者之间重新切了一刀。
这一刀切得值不值,看数字就知道了。
离线基准上,在数学、代码、对话三个领域,DSpark的平均接受长度都比当前最好的并行方案高出16%到30%。线上生产里,用户在同等吞吐下感受到的生成速度提升了六到八成。
更重要的是,它在高并发下能自动踩刹车,不会因为贪心验证过多词而把系统拖垮。
这个框架现在已经开源,代码、训练脚本、模型检查点全部公开。如果你在跑大模型推理,尤其是并发量不低的服务,DSpark提供了一条现成的加速路径。不需要改模型结构,不需要重新训练主模型,只需要把草稿模块挂上去,剩下的事情交给调度器。
DeepSpec解决了大模型推理中最磨人的那个环节,不是让它更聪明,而是让它不卡顿。