文章目录
- 1 -> 引言
- 2 -> 逐个生成是一种建模选择,不是语言的物理规律
- 3 -> 同时填多个位置,难点在于它们要彼此兼容
- 4 -> 一次写得多,不代表完成同一道题就一定更快
- 5 -> 比较要落到具体任务上
1 -> 引言
聊天窗口里,答案通常从左往右一点点出现。这个使用习惯很容易让人产生一种直觉:语言模型本来就应该先写第一个词,再写第二个词,直到句子结束。如果突然告诉你,另一些模型会先留下一排空位,再同时填入几个位置,甚至重新修改已经提出的候选内容,这件事听起来就有点像把文字生成变成了填空。
这种“填空”并不轻松。一个位置选了什么,会影响其他位置该填什么;同一轮里看起来不错的候选,拼起来也可能互相矛盾。扩散语言模型的关键,就在于怎样组织这些预测、接受哪些结果,以及什么时候还得回头修改。并行带来的收益,要扣掉反复修订的成本之后才算数。
2 -> 逐个生成是一种建模选择,不是语言的物理规律
常见的自回归语言模型把一段文本的概率分解为一连串条件概率:第一个 Token 根据提示生成,第二个 Token 根据提示和第一个 Token 生成,后面的 Token 继续依赖已有前缀。这里的 Token 是分词器处理后的单位,并不一定对应一个汉字或一个完整单词。
这种设计的好处很直接。训练目标清楚,可以利用大量现成文本;推理时只需要继续已有前缀;流式输出也很自然,前面的内容可以先交给用户看。代价则在于,后一个位置通常要等前一个位置确定之后才能继续。即使 GPU 内部能执行很多并行计算,跨生成位置的依赖仍然存在。
扩散式生成尝试了另一种组织方法。本文主要讨论离散、掩码式的语言扩散:训练时把文本的一部分位置遮住,让模型根据可见上下文恢复被遮住的内容;推理时从大量未知位置开始,通过若干轮预测逐步形成答案。不同研究也会采用连续空间扩散或其他设计,不能把所有扩散语言模型都简化成同一种填空算法。
还要注意,扩散与 Transformer 并不是两个互斥选项。前者描述的是一类生成与训练方式,后者是一类网络架构。一个扩散语言模型完全可以使用 Transformer 作为预测网络。因此,“扩散模型出现了,所以 Transformer 要被淘汰了”并不是一个成立的推论。
LLaDA 的公开实现提供了理解掩码式语言生成的具体入口。阅读这类项目时,最值得先看的不是模型最终得分,而是输入怎样被遮盖、哪些位置参与损失、推理代码如何决定本轮保留哪些预测。LLaDA 官方实现
3 -> 同时填多个位置,难点在于它们要彼此兼容
假设需要补全一句话:“这个方案的主要优点是……,但它的限制是……”。自回归模型写到后半句时,能够看到前半句已经选定的内容。掩码式模型可能在同一轮里对两个位置同时提出候选,这些候选分别看起来合理,却未必放在一起仍然合理。
这就解释了为什么并行预测之后通常还需要迭代。某些位置一旦变得可信,就能给其他位置提供更明确的条件;另一些不确定的位置,需要继续等待更多上下文。部分方法会重新遮住低置信度预测,部分方法只在当前块内反复处理,还有的方法使用不同的提交策略。是否允许修改已经填入的内容,属于具体算法选择,而不是所有扩散模型共有的保证。
置信度也不是事实正确率。模型给一个词很高的概率,可能只是因为它在当前上下文中很常见,并不说明这个词对应的事实真实。尤其是人名、数字、代码变量和领域术语,局部选择看起来顺畅,整体含义却可能错误。
以代码里的变量声明和引用为例。假设只有两种合法组合:声明sensor_id并引用sensor_id,或者声明device_id并引用device_id,两种组合概率各为一半。单看任一位置,两个名字都各有 50% 的概率;如果按这两个边际分布独立抽样,四种结果中却有两种前后不一致。这是一个人为简化的例子,但它指出了问题:每个位置分别合理,并不保证联合结果合理。后续迭代让已确定的位置成为条件,正是处理这类依赖的一条途径。具体模型是否独立采样、怎样耦合位置,需要另看实现。
为了在并行性与依赖关系之间取得平衡,一些实现采用分块方式:先处理一个块,在块内并行预测,再继续下一个块。这样既没有完全放弃顺序,也没有把整个答案都交给逐 Token 生成。不同块大小、不同提交数量和不同重新遮盖策略,都会影响实际速度与输出质量。
输出长度也是一个不能忽略的问题。自回归模型可以持续生成,直到遇到停止条件;某些掩码式采样流程需要先指定生成区域或块长度,再处理结束标记和多余位置。部署时应检查具体实现,不能默认两种生成方式在长度控制上完全相同。
这种生成组织方式也让“中间补写”变得值得研究。比如一份配置文件已经确定开头和结尾,只允许补全中间缺失的字段,生成时能够同时利用两侧条件,与只接着前缀往后写,任务形式并不完全相同。但这不意味着自回归模型不能处理补全任务:它也可以通过特定训练和输入格式学习利用后缀。真正需要比较的是同样约束下的完成质量,而不是仅根据生成顺序判断谁一定更好。
若把扩散式生成放进编辑器,还需要定义哪些区域允许改变。保留用户原文、修改指定片段和自由重写整段,是三种不同权限。模型能够重新预测某个位置,不代表应用应该允许它随意覆盖已确认内容。最好在输入与输出之间保留区域映射,检查不可修改部分是否原样保留;否则一个看似有益的改写,也可能破坏代码标识符或合同里的固定用语。
先把网络预测拿掉,只看提交顺序。下面用已知答案和人为置信度演示调度:一种每轮提交一个位置,另一种每轮提交两个位置。这不是语言模型,不能用来测生成准确率或速度。
# Python 3.10+; scheduling demonstration, not a language model.target=["The","sensor","reports","a","stable","signal"]confidence=[0.91,0.64,0.88,0.52,0.75,0.95]defreveal(order,per_round):state=["[MASK]"]*len(target)snapshots=[]forstartinrange(0,len(order),per_round):forindexinorder[start:start+per_round]:state[index]=target[index]snapshots.append(state.copy())assertstate==targetreturnsnapshots left_to_right=list(range(len(target)))by_confidence=sorted(left_to_right,key=lambdai:confidence[i],reverse=True)forlabel,order,widthin[("sequential",left_to_right,1),("parallel_commit",by_confidence,2),]:print(label)fornumber,stateinenumerate(reveal(order,width),1):print(number," ".join(state))运行后,两种方式都填了六个位置,区别是前者有六轮,后者有三轮。并行方式第一轮先确定句首的The和句尾的signal,中间仍有空缺;下一轮才补入reports和stable。这比单看最终句子更能说明:生成过程不一定存在一段不断延长的稳定前缀。
轮数减少还不能直接换算成速度。假设顺序方式一轮耗时 c,并行方式一轮耗时 2.5c,那么三轮仍然比六轮慢。这里的 2.5 只是算例;真实单轮成本要看处理范围、缓存复用和硬件利用率。减少串行依赖与减少总计算,是两件相关但不同的事。
4 -> 一次写得多,不代表完成同一道题就一定更快
比较生成系统时,最容易误导人的指标是孤立的 Token 速度。对于自回归模型,生成步数与输出长度之间通常有较直观的关系;对于扩散式模型,同样长度的输出可能需要不同轮数的修正。若只统计最后留下的 Token,内部重复预测的工作就被隐藏了。
2026 年 10 月的一项研究比较了扩散语言模型在不同任务和语言中的解码成本。作者观察到,依赖输入复制或轻量修改的任务,与开放式写作的计算开销并不相同。这是特定模型与实验设置下的发现,适合提醒我们检查工作负载,不能当作“所有纠错任务都更快”的保证。Diffusion Language Models Change Speed Across Tasks and Languages
实际测试至少需要同时记录以下几类信息:
| 观察项 | 它回答的问题 | 常见误读 |
|---|---|---|
| 端到端耗时 | 用户多久得到完整可用结果 | 只看解码内核,不算准备与后处理 |
| 前向调用数与处理位置数 | 内部到底做了多少工作 | 把提交轮数当成完整计算量 |
| 输出正确性 | 快速生成的内容是否可用 | 只比较速度,不检查答案 |
| 输出长度与 Tokenizer | 两边处理的单位是否相同 | 直接横比不同分词器的 Token/s |
| 并发与显存占用 | 多请求运行时是否仍有收益 | 用单请求结果推断服务容量 |
流式体验也需要单独看。自回归生成往往能够较早交付一个稳定前缀;某些扩散式结果在生成中间还会变化。如果界面展示的是尚未确定的内容,就需要明确它是草稿状态。完整答案返回得更早,与用户更早看到一个不会再变化的词,并不是同一个指标。
缓存策略同样不能直接照搬。自回归模型的已确定前缀通常不会在后续步骤中改写;若某种迭代生成方式改变了先前位置,其相关中间表示是否仍可复用,就需要重新判断。某些实现通过分块或近似策略降低重复计算,但应该检查近似条件及质量影响。只说“模型一次预测很多位置”,没有说明每轮重算哪些内容,仍然无法估算真正的工作量。
还应避免把扩散生成与投机解码混为一谈。投机解码通常使用草稿机制为既定目标模型加速,并通过验证决定接受哪些候选;扩散语言模型则改变了生成问题本身的组织方式。它们可能在某些系统中组合使用,但原理不能互换解释。
5 -> 比较要落到具体任务上
一组小实验可以从三类任务开始:保留原文大部分内容的纠错、输出格式严格的补全,以及需要大量新内容的解释写作。每类任务都准备固定输入和验收办法,不要只展示最有利于某种模型的例子。
模型、硬件、采样参数和预热过程都要记录。不同模型之间无法做到所有因素完全相同,因此结果应解释为“这两套系统在这些任务上的表现”,而不是从一次对比推出某种生成范式的全面优越性。冷启动、首次编译与稳定运行的时间最好分开报告,长短输出也不要混成一个平均数。
对于代码任务,测试通过率比文字是否流畅更重要;对于纠错任务,需要检查是否擅自改动原意;对于知识问答,需要核对事实。重复运行可以观察波动,但多跑几次后只挑最快或最正确的一次,会把结果变成挑样展示。
回到编辑器补全这个场景,用户可能愿意等一小段时间,换来一次完整、可编译的修改;聊天场景则可能更看重稳定文字尽早出现。即使使用同一个模型,这两种界面也未必该采用同一种提交策略。测试记录里应该留下修订轮数、首个稳定输出时间和最终验收结果,否则很难解释一次加速到底改善了哪种体验。