![]()
机器之心编辑部
这两年,扩散语言模型(Diffusion LLM)一直是个很有讨论度的方向。
和传统自回归模型不同,扩散模型不是严格按从左到右一个 token 一个 token 往外吐,它在生成方式上更灵活,也天然更适合并行建模。可问题也一直摆在那里:这条路很有潜力,但真正把效果做上去并不容易。
最近有一篇来自华为诺亚方舟实验室的工作,探究了扩散模型训练中的 “默认设置”。论文标题叫 Mask Is What DLLM Needs: A Masked Data Training Paradigm for Diffusion LLMs。作者没有先去改模型结构,而是把目光放回了训练过程里一个看起来很基础、但其实一直被默认接受的设定:masking 到底该怎么做
![]()
论文链接:https://arxiv.org/abs/2603.15803数据集链接:https://huggingface.co/datasets/malr07/opc-sft-stage2-dense-extracted
这篇文章给出的判断是,现有很多离散扩散语言模型在训练时采用的均匀随机 masking,其实有点 “平均用力” 了。
这个问题在一般文本里可能还没那么明显,但到了代码和数学推理任务上,就会变得很突出。因为这类数据里,真正决定模型能不能做对的,往往只是少数几个关键位置:在代码任务里,可能是关键的分支条件、判断逻辑;在数学里,可能是关键的化简步骤、函数替换,这些东西显然比连接词或者格式内容更重要。事实上,真实序列里的信息密度本来就不是均匀分布的,而传统随机 masking 却默认每个位置都差不多,这会被动地让模型把不少优化资源花在不那么关键的地方。
说白了,就是模型学的时候没太分清主次,所有东西都一样对待了。
不是所有 token 都一样重要
这篇工作的核心想法其实一句话就能概括:
既然不同 token 的信息量不一样,那训练时就不该对它们一视同仁。
围绕这个想法,作者提出了一个更加 Smart(Input Information Density Aware)的 Noise Scheduler。它做了一件很简单且直观的事情:先想办法把样本里那些 “信息密度高” 的位置找出来,然后在训练时更优先地 mask 掉这些位置,逼着模型去学会恢复真正关键的部分。
这套做法背后的直觉其实很自然,人做完形填空的时候,也不会觉得补一个逗号和补一句关键结论的难度是一样的。真正能拉开差距的,通常就是那些牵一发而动全身的地方。论文里也提到,这种设计的直觉和人类的挖空练习很接近:更高效的学习,往往不是去恢复冗余内容,而是去恢复核心概念。
![]()
先找 “重点”,再决定怎么 mask
具体做法上,作者先做了一步高信息密度区域提取(Step 1)。
![]()
对于代码数据和数学数据,作者设计了一些不同的 criteria。将数据中的关键信息区域提取出来之后,这些区域会在原始序列中被高亮标记出来,后面训练时的噪声调度就会参考这些特殊标记。
接下来进入真正的 masking 阶段(Step 2)。和传统做法不同,这里不是所有位置都按同样概率被 mask。作者把序列分成两类:一类是优先区域,也就是那些信息密度高的 token;另一类是普通区域。前者会被赋予更高的 mask 概率,后者保持较低概率。与此同时,整体的 mask 比例仍然会被控制住,不会因为 “偏心” 了某些位置就把整个噪声调度搞乱。
这个设计最关键的一点在于,它不是单纯 “多遮一点”,而是把训练难点往真正值得学的地方推。模型被反复要求补全的,不再只是随机缺失的内容,而是那些决定代码是否成立、推理是否走通的关键片段。
另一个小巧思:一条数据,两种学法
如果只是优先 mask 掉高信息区域,很容易让人担心另一个问题:模型会不会变得更会 “做题”,但对语言结构本身?
所以这里引入了扩散模型训练中常用的 Complementary Masking。
思路是:对同一条样本,Trainer 不只根据前文的 token-level 优先标记构造一个 priority mask,还会构造它的完全逻辑互补版本。也就是说,一份样本会变成两种互补的训练视角:一种把重点放在逻辑骨架上,另一种则更多保留这些关键位置,转而让模型去处理结构、语法和上下文连贯性。
这种将互补掩码与优先级掩码结合的设计得到了一种 1+1>2 的效果,因为它没有把问题简化成 “只要盯住重点就行”,而是承认:语言模型最终还是既要会推理,也得会组织语言。前一种视角更像是在逼模型抓住关键逻辑,后一种视角则是在防止它把句子写散、把上下文关系学丢。论文把这种效果称为一种基于信息密度的 decoupling,本质上是在把一条训练样本里的不同学习目标拆开。
改改噪声调度就能直接提点
实验部分,作者使用 LLaDA-2.0-mini 作为基础模型,在代码和数学数据上进行训练,最后在 HumanEval、MBPP、GSM8K、MATH500 四个 benchmark 上做评测。结果显示,相比标准的随机 masking baseline,这套方法的平均成绩提升了大约 4%。
![]()
这个幅度不属于那种一眼看上去特别炸裂的数字,但放在这里其实挺有说服力。原因在于,这项工作并没有去改 backbone,也没有上特别重的额外模块,它动的是训练范式本身,两个数字之间唯一的差异只有噪声调度。换句话说,它不是靠 “再堆一点结构” 把结果抬上去,而是证明了只要训练信号分配得更合理,扩散模型本身还有不少潜力没被用出来。
有个消融结果很值得注意:不是越狠越好
论文里另一个有启发性的部分,其实是关于 hard masking 和 soft masking 的比较。
直觉上你可能会觉得,既然高信息区域重要,那就干脆把这些位置狠狠遮掉,让模型专门练这个,不是更好吗?但实验结果并不是这样。作者发现,确定性的 hard masking 反而容易把训练搞坏,效果反而不如带概率的 soft masking。
![]()
![]()
他们给出的解释也挺合理。代码和数学里的高信息区域,很多时候在文本里是连续出现的。如果把这一整段连续内容都直接硬遮掉,那么在 block diffusion 的训练过程中,就相当于突然挖掉了一大片局部锚点,出现了一大片连续的 “内容黑洞”。论文把这个现象叫做 contextual collapse:局部参照一旦没了,训练过程就容易失稳,梯度轨迹也会变得很难控制。相比之下,soft mask 虽然也提高了这些位置被遮掉的概率,但毕竟还保留了随机性,不至于每次都把关键部分整个掏空,因此优化会平滑得多。
这一点其实挺像很多训练技巧最后都会落到的那个结论:方向对了不代表力度越大越好,给模型留一点缓冲,往往更重要。
只处理一小部分数据,就已经能看到收益
另一个比较实用的发现,是这套方法的数据效率。
作者没有要求对全部训练数据都做离线的信息密度提取,而是做了不同比例的数据实验。结果显示,只对 10% 的代码数据做这一步处理,就已经能把平均成绩从 55.32 拉到 59.45。再继续往上加到 30%,甚至加到 100%,性能提升会逐渐趋于饱和;到了 100% 时,虽然代码类指标还能冲高,但数学推理表现反而会掉下来。论文把这种现象归因于 domain shift:代码侧结构先验加得太多,反而挤占了模型在其他推理任务上的泛化空间。
这部分结果挺重要,因为它说明这件事并不一定是个 “高成本、重工程” 的方案。相反,作者给出的结论很明确:不需要全量标注,也不需要把整个训练流水线推倒重来,只要在一小部分数据上引入这种结构化先验,就能把基础扩散模型往上推一截。
扩散模型的训练过程还有很多细节可供挖掘
从结果上看,这篇工作当然是在讲一个 masked data training 的新做法。但如果再往后退一步看,它其实碰到了一个更根本的问题:扩散语言模型到底应该怎样分配自己的学习注意力。
过去很多工作习惯从模型结构、采样策略或者推理机制上找突破,这篇文章反而提醒了一件很朴素的事:你让模型学什么、在哪些位置上用力,本身就会决定它最后学成什么样。对于 DLLM 这种本来就高度依赖 noising /denoising 过程的模型来说,masking 不是配角,某种程度上它就是训练逻辑本身的一部分。
论文最后也提到,当前这套信息密度提取流程还是偏离线、偏启发式的。后面可以继续往几个方向走,比如基于 AST 的规则提取、基于模型自身置信度的自适应提取,或者干脆引入 GAN 的思想做成端到端可学习的对抗式 mask 模块。
如果这些方向后面能继续推进,那这篇工作的意义可能就不只是 “提出了一个有效的小改动”,而是在给 Diffusion LLM 提供一种更像样的训练思路:
先别急着让模型学会所有东西,先让它学会什么东西值得优先学。





京公网安备 11011402013531号