DLoop让草稿模型自判续写,投机解码验证次数能省多少
先说一个你可能没想到的现象。现在的大模型推理普遍用一种叫投机解码的技术来加速生成,简单说就是找一个小模型先打草稿,大模型再一次性检查这些草稿对不对。听起来挺合理,草稿写得越准,大模型就越省力。但问题是,草稿模型现在已经练得相当聪明了,聪明到什么程度呢?论文作者测了一下,用Qwen3-4B配合几种主流草稿模型...
先讲个可能出乎意料的现象。
如今大模型推理加速,普遍靠投机解码:先让一个小模型打草稿,再由大模型一次性核对这些草稿对不对。道理说得通——草稿越准,大模型越省力。可眼下草稿模型已经练得相当聪明了,聪明到哪种地步?
论文作者拿
Qwen3-4B搭配几种主流草稿模型做了测试,发现不少草稿片段是被大模型一字不改全盘接收的。换句话说,草稿模型这轮写的东西,大模型根本没动。但系统照样规规矩矩停下来,让大模型完整跑一遍验证,之后才放草稿模型去写下一段。
这就像请了个特别靠谱的助理代写邮件,可助理每写完一段就非得找你签字,哪怕前十段你都是原封不动直接放行。你难免会想:既然写得这么准,能不能先多写几段,攒一起我再看一遍?
投机解码*:一种让大模型写东西更快的办法。做法是先用一个体积小、速度快的“草稿模型”预判后面可能冒出来的几个词,再把这些猜测一次性交给大个头的“目标模型”核对,猜对的直接收下,不必一个字一个字地往外挤,省掉逐个生成的消耗。
这篇论文要解决的,正是这个“该验证的时候才验证,不该验证的时候别打扰”的问题。
被验证卡住的效率
投机解码靠两个角色配合。一个是目标模型,也就是你真正要用的那个大模型,写得好不好全看它;另一个是草稿模型,体量小、跑得快,任务是“猜”大模型接下来大概率会说什么。等草稿模型把一批候选词交出来,目标模型跑一次前向计算,看这批词里哪些能过关留下。
这里有条硬规矩:草稿模型这一轮猜得再准,验证完也得先停下,等下一轮草稿。论文把草稿模型一次吐出的词称为一个“块”,块的大小一般定死,比如7个词或16个词。就算这7个词全中,系统也不会让草稿模型接着往下赶,而是照规矩先验证,再从头开始下一个块。
为什么这是个问题?
原因在于,整个流程里最费时间的是目标模型做验证这一步。跑一次完整的前向计算,验7个词和验14个词,耗时差不了多少,卡住进度的是把整个大模型跑一遍这件事,跟验多少词关系不大。研究者发现,验证词数往上加,单次验证的时间涨得很慢。这说明了什么?
如果能把原本需要两次验证的内容,合并成一次验证完成,那省下来的几乎是整整一次目标模型前向计算的时间。
打个工厂质检的比方:检验员查一箱零件和查两箱零件,花的时间差不多,因为工夫主要耗在搬箱子、开设备上,真去逐个看零件反倒快。要是每回都只搬一箱来查,检验员来回跑空趟,浪费的就是那些没用上的搬运机会。
已有的解决思路为什么不够用
这种浪费,研究者其实早就看到了,也提过一些解法,统称“自适应草稿长度”。思路说穿了就是:生成过程中随时判断写多少个草稿词再去验证,别死守一个固定的块大小。
但这里有个关键限制。这些方法基本都是针对自回归草稿模型设计的。
自回归草稿模型*:一种逐词生成的草稿模型,写完第一个词之后,才能根据这个词继续写第二个词,像接龙一样一个接一个来。
自回归模型是一个词一个词往外蹦的,理论上哪儿都能喊停,不想写就收手,这个词的成本已经花出去了,停下也不亏。可眼下业界还有一类更快的并行草稿模型,一次前向计算就把整块的几个词一口气全吐出来,不是排队一个个生成的。
并行草稿模型*:一种一次性生成整个草稿块的模型,所有词都在同一次前向计算里产出,而不是像自回归模型那样逐词排队生成。
碰到并行模型,自适应长度这套基本不管用。想不想提前停都一样,这次前向计算的钱已经花完了,早停也省不下算力。麻烦的还在后头:草稿模型要在这一块之后接着写,得知道前面这些词准确的“隐藏状态”。
隐藏状态*:神经网络内部某一层对输入信息的编码表示,可以理解成模型对一段文字的“理解摘要”,后续计算都基于这个摘要展开。
可这些隐藏状态要等大模型验证完才会出来。没验证的草稿词,大模型碰都没碰过,自然拿不到这份信息。草稿模型非要往下写,只能拿自己生成的隐藏状态凑数,而它根本没在这种设定下训练过,写出来的东西质量会一路往下掉。
DLoop:让草稿模型自己判断要不要继续写
论文给出的DLoop,想法挺朴素:草稿模型既然能感觉到“这轮写得靠不靠谱”,那就让它自己拿主意要不要再写一轮,攒够了再一起交给大模型验证。
DLoop这套方案包含两块:推理阶段的置信度门控循环机制,以及训练阶段配套的循环感知训练。
先看置信度门控循环怎么运转。草稿模型每写完一个块,就把块内每个词的对数概率累加起来,得到一个总分,这个分数体现的是它对刚写内容的把握有多大。分数一旦高过事先定好的门槛,草稿模型接着写下一块;没够着门槛就停手,把已经攒下的所有块交给目标模型一次性验证完。
对数概率*:模型给词打分的一种方式,分数越高(越接近0)说明模型越确信这个词选对了,分数为负且绝对值越大则说明越没底。
至于为什么累加而不是取平均或别的算法,论文的解释很直白:每个词的对数概率本来就是负数或零,某个位置一旦特别不确定,这个负数就会很大,把总和拽下去,别的位点分再高也"平均"不回来。这跟验证规则是一回事——只要有一个词被拒,它后面的词全部作废。用累加这种"一票否决"的算法,恰好对得上实际的验证逻辑。
打个比方。你让实习生连着处理几批文件,他每批干完自己评个分:"这批有把握,第二批也有把握,但第三批有一处拿不准。"只要有一个环节他自己都发虚,那这批连同后面所有连带的工作都得重审,不能因为前两批靠谱就把后面的也放过去。反过来,要是让他拿平均分糊弄,真出了错,后面没检查过的活儿全白干,返工代价更大。
循环感知训练:教草稿模型在"虚空"里接着写
只有判断逻辑还不够,草稿模型自己得适应这种新干法。
原先的草稿模型只学过一种情形:拿着大模型给的真实隐藏状态,预测下一块写什么。DLoop却要求它在第一个块之后,继续拿自己生成的隐藏状态当"输入材料",去写第二块、第三块。这种输入它压根没见过,直接上手,效果打折扣是意料之中的。
EAGLE-3这个草稿模型此前已有"训练时测试"的技巧,能让它在训练阶段就模拟"用自己预测的隐藏状态接着写",但范围只限一个块内部的深度。DLoop把这一思路拉长了,让草稿模型在训练时走更长的链,跨过好几个块去模拟整个循环过程。
所谓训练时测试*,指的是在训练阶段就提前模拟推理时会碰到的情形——这里的具体做法,是让草稿模型练习"用自己生成的中间结果继续往下写",而非单靠外部喂进来的准确信息。
落到操作上,每条训练数据都会随机抽一个额外草稿轮数(论文里定在1到3轮),然后实打实跑这么多轮:第一轮照旧用大模型给的隐藏状态,后面几轮接上草稿模型自己算出的隐藏状态。损失函数只盯两头——第一轮的预测效果,和最后一轮(最难、离真实信息最远的那轮)的预测效果;中间过程只管传递隐藏状态,不直接参与计分。
为什么只盯第一轮和最后一轮?
第一轮是原来的训练目标,丢了基础能力会退化,必须留着。最后一轮则是整条链上信息衰减最厉害、难度最大的一段,训练精力往这儿集中,等于专攻最薄弱的环节。中间几轮只是陪练,任务是把"自己生成隐藏状态"这条链接起来,不单独计分。
这就像带一个翻译新人:你不会让他每翻一句就打分复盘,那样太费效率。更管用的办法是让他连着翻一整段,然后重点查开头那句(看基本功退没退)和结尾那句(看长链条下误差会不会越滚越大),中间部分只负责让他熟悉"连续干活不被打断"的状态。要是每句都精雕细琢,新人反倒学不会在长篇任务里保持连贯、自我修正。
实测效果:速度提升5%到41%
论文在EAGLE-3、DFlash、Domino、DSpark这几种主流草稿模型上都跑了测试,目标模型配的是Qwen3-4B和Qwen3-8B,另外还测了Qwen3.5-9B和Gemma-4-12B自带的多词预测模块。
EAGLE-3*:这是自回归草稿模型中较有名的一个系列,做法是让体量轻的草稿模型直接取用大模型已经算好的隐藏状态,一个词一个词地往后预测。
DFlash、Domino、DSpark*:三种并行草稿模型,分别用不同方式实现一次前向计算吐出整个草稿块,去掉了自回归逐词生成的排队开销。
结果显示,这些设置下平均每次验证能接受的词数(即"接受长度")涨了12%到102%,整体实际运行速度提升5%到41%。有意思的是,涨幅最大的是DSpark,而它恰好也是前面说的"百分之百被整块接受"比例最高的草稿模型,说明它确实有最多机会多写几轮而不被打断。
论文还做了拆解实验,分别单测"只开循环不训练"和"只训练不开循环"。只开循环不训练,对自回归模型(比如EAGLE-3)仍有提升,因为它本来就习惯自己生成隐藏状态往下写;可对并行模型来说,速度提升有限甚至下降,多写几轮花掉的时间,差不多被接受长度的提升抵消了。只训练不开循环,两个指标变化都很小。两者一起启用,效果才真正明显,而且提升幅度超过各自单独效果的直接相加。
也就是说,循环感知训练并非孤立地提高每一轮草稿的质量,它是在专门为"循环"这种新工作模式做适配。
和同类自适应长度方法的对比
论文还把DLoop跟一批已有的自适应草稿长度方法做了横向比较,包括BiLD、SVIP、AdaEDL、LLMCad、SpecDec++、DISCO、PACER、AdaEAGLE、DDD等等。这些方法大多靠草稿分布的某个统计量(比如概率、熵)判断要不要提前停止生成,有的还得专门训练一个决策模块。
在DSpark这类并行模型上,实验结果显示这批方法没一个能跑赢原始草稿模型,有的还更慢。原因前文已经说过:并行模型单次前向计算成本固定,提前叫停也省不下这笔钱。换到EAGLE-3这种自回归模型上,它们确实有提升,可幅度最多0.14倍左右,跟DLoop差得远。两种草稿模型上,DLoop拿到的接受长度和速度提升都是最高的。
速度提升的来源
论文把解码时间做了细致拆解,分别统计草稿和验证各占多少,并按每次循环里跑了几轮草稿分类。数据显示,DLoop让总解码时间下降4.9%到24.3%,其中34%到71%的生成词数出自"多轮草稿共享一次验证"。单次循环里草稿轮数越多,单轮耗时确实越长,但接受词数涨得更快,平均每生成一个词的时间就一路往下走:单轮草稿时是4.6到6.4毫秒,五轮以上草稿时降到0.68到2.97毫秒。验证次数整体减少了7.6%到34.1%。
每次验证都得跑一遍完整的大模型前向计算,这是全流程最贵的开销。验证次数降下来带来的收益,把多写几轮草稿的额外成本完全盖过去了。
打个比方,快递员原本每送一件包裹就得回站点打卡登记,如今一次能带5件就多拿几件,打卡次数少了,路上找包裹多花点时间,可省下的往返站点时间远比这多。要是坚持一次只送一件就回去打卡,看着每趟都规范,实际大量时间耗在不必要的往返上。
与树形验证叠加
基础投机解码之外,业界还有一种叫"树形验证"的增强技术:草稿阶段不只生成单一路径,而是产出多个候选分支,大模型一次验证整棵树,再挑出最优路径。
树形验证*:想让投机解码更高效,可以换一种做法:草稿阶段不再只产出一条线性的候选序列,改为产出一棵带多个分支的候选树,再由大模型对整棵树做一次性验证,单次验证能覆盖的候选范围因此变大。
DLoop跟树形验证不冲突,还能叠着用。论文针对DFlash用了DDTree,针对Domino和DSpark用了DARTree。在树形验证之上再加DLoop,DFlash平均速度又提升12%到13%,Domino提升7%到8%,DSpark提升22%到25%。树形验证管的是"往哪个方向猜",DLoop管的是"猜多久才去核对",本来就是两个维度的优化,叠加起来互不打架。
写在后面
读完论文,印象最深的不是加速比数字,而是那张"全盘接受率"统计图。它提醒了一件容易被忽略的事:不少工程系统的低效,问题不在某个组件做得不够好,而在系统调度节奏没跟上组件实际能力的提升。草稿模型越练越聪明,验证节奏却还守着"保守估计它会犯错"的老规矩,这种错配本身就是浪费的来源。
还有一点值得琢磨:论文反复强调DLoop不加额外参数、不改草稿模型结构,只改了"什么时候停下来核对"的决策方式。这种不动筋骨只调节奏的思路,放在很多系统设计里都成立。有时候真正拖后腿的不是能力不够,是流程定得太死。
论文结尾那句话让人多想了一下:验证前该跑几轮草稿,不必由固定调度规则决定,完全可以留到运行时再判断。把这句话放大来看,很多我们习以为常的"固定流程",是不是都值得再问一句——这个节奏真的必要,还是只是因为大家一直这么做?
Q&A
Q1:DLoop是什么?A:它是一种改进投机解码的方法,核心是让草稿模型按自己的置信度决定要不要连着写多轮草稿,再统一交给大模型验证一次,从而减少目标模型的前向计算次数。
Q2:DLoop比普通投机解码快多少?A:论文在EAGLE-3、DFlash、Domino、DSpark等多种草稿模型上做了测试,实际运行速度提升5%到41%,生成结果和原来完全一致,准确性不打折。
Q3:并行草稿模型和自回归草稿模型都吃这一套吗?A:都有效,这正是它跟此前自适应草稿长度方法最大的区别。此前的方法只对自回归草稿模型有提升,对一次性生成整块草稿的并行模型基本无效,DLoop靠循环感知训练把这个限制解掉了。