第 21 · 扩散 · 9 min
通过擦除噪声来生成图像
Stable Diffusion、Midjourney、FLUX。反向去噪过程、CLIP 的作用,以及为什么 U-Net 正在让位于 Transformer。
另一个家族
到目前为止,我们看到的所有内容描述的都是预测下一个 Token 的 Transformer。这是主导了语言、代码,并且越来越主导视频和音频的架构。
但当你在 Midjourney、Stable Diffusion 或 FLUX 里输入提示词时,发生的不是这件事。图像不是从左到右一个像素一个像素地生成出来的。它是到处同时出现的,通过一连串步骤被精炼。
这是一个非常不同的模型家族的作品:扩散模型(diffusion models)。
核心思想:学习去噪
扩散建立在一种几乎过于简单的直觉上。如果我拿一张清晰的图像,逐步往里加高斯噪声,到某一刻它就会变得和纯噪声无法区分。如果我学会反过来这个过程——一点点地把噪声去掉——那我就可以从纯噪声出发,得到一张清晰的图像。
训练时:
- 从数据集里取一张图像
- 按照预定的时间表(比如 T = 1000 步)往里加噪声
- 训练一个网络,给它噪声化的图像和步数 t,让它预测被加进去的噪声
这样,模型就学会了对任意噪声水平识别哪些是"真实图像"、哪些是"添加的噪声"。
推理时反着来:从纯噪声出发,每一步模型预测噪声、我们减掉它、再继续。T 步之后,我们得到一张可信的图像——一张接近所学分布的图像。
试一试去噪
两个调节项,一个按钮。先把步数拉到最小,点生成;再拉到最大跑一次,两相对照。然后把步数放着不动,让 **guidance(CFG)**从 0 变到 15。这正是任何一个图像生成界面摆在你面前的那两个滑块。
动画从一张纯噪声图像出发,逐步去噪。每一步都沿着训练时学到的梯度前进,由 CLIP 的文本 embedding 引导。5 步时结果模糊,50 步时变得清晰。
试着改变步数。在 5 步时,图像还是颗粒感很强——模型没有时间去精炼。在 50 步时,它变得清晰,但算力是十倍。大多数现代采样器(DDIM、DPM-Solver)在 20 到 30 步内就能达到接近最优的质量。
引导朝向一张特定的图像:guidance
纯噪声对所有提示词都是一样的。模型怎么知道我们想要一个日落而不是一只狗?答案是:我们用文本**条件化(condition)**模型。
训练时,除了噪声化的图像和当前时间步,网络还会收到与图像相关联的文本的嵌入(通常是 CLIP 风格的编码器)。这样网络学到的是条件化的噪声预测:"在图像描述的是日落的前提下,噪声看起来是这样的"。
推理时,我们计算两个预测:一个有提示词的,一个没有(或用空提示词的)。**Classifier-Free Guidance(CFG,无分类器引导)**这种技术沿着提示词的方向做外推:
final_prediction = unconditional + guidance × (conditional − unconditional)
guidance 系数(CFG scale)控制我们离自然有多远、贴提示词有多近。CFG=0 时,模型忽略文本;CFG=7 时,图像忠实地跟随提示词,又不会变得不自然;超过 12 后,图像会过饱和并丢掉精细细节。
Latent diffusion:少做点工
一张 512×512 的图像是 262,144 个像素——而每个像素带三个颜色通道,也就是 786,432 个待处理的数值。在这么多像素上跑 1000 步去噪非常昂贵。Stable Diffusion 让一种小技巧流行了起来:在一个被压缩过的潜在空间里工作。
在训练扩散模型之前,我们先训练一个自编码器(一个 VAE),它把图像压缩到一个 64×64×4 的潜在空间——大约小 48 倍。然后扩散只作用在这个 latent 上,而不是像素上。去噪结束后,我们再把 latent 解码回最终的图像。
这正是让 Stable Diffusion 能在消费级 GPU 上几秒钟内跑起来的原因——而一个等价的基于像素的模型则需要一整个集群。
CLIP:文本与图像之间的桥
要在文本上做条件化,就需要一种和图像共享同一个空间的文本表示。这就是 CLIP(Contrastive Language-Image Pretraining,对比式语言-图像预训练)的角色,由 OpenAI 在 4 亿对图像/标题上训练。
CLIP 学习两个编码器——一个用于图像,一个用于文本——它们在一个共享空间里产出嵌入。一段标题和它对应的图像有相近的嵌入;一段不相关的标题则离得很远。这种对齐让扩散模型能够理解它在训练时从未一字不差见过的文本提示词。
U-Net 与 Transformer(DiT)
很长一段时间里,扩散的参考架构是 U-Net:一种 U 字形的卷积网络,带有保留精细细节的 skip connection。Stable Diffusion 1.4、1.5 和 2 全都用 U-Net。
但在 2022 年,Peebles 和 Xie 提出了 DiT(Diffusion Transformer,扩散 Transformer):用一个纯 Transformer 替代 U-Net。图像的每一个"patch"被当作一个 Token 处理,对其他所有 patch 都做完全注意力。不再有卷积金字塔,不再有 skip connection——只是堆叠的 Transformer 块。
Stable Diffusion 3、FLUX、Sora(视频)——所有近期的架构都迁移到了 Transformer 上。为什么?因为 Transformer scale 得更好:我们重新得到了和语言一样的缩放定律。在一个 DiT 上把算力翻倍能可预测地把图像变得更好。
采样器:DDPM、DDIM、DPM-Solver
**采样器(sampler)**是这样一个算法:它在每一步决定如何把噪声预测和当前状态组合起来,得到下一步的状态。
| Sampler | 典型步数 | 特点 |
|---|---|---|
| DDPM | 1000 | 随机性、忠实于训练、慢 |
| DDIM | 20–50 | 确定性、用少得多的步数就能达到接近 DDPM 的质量 |
| DPM-Solver | 10–25 | ODE 解算器,更快 |
| Euler / Heun | 20–30 | 经典 ODE 方法,简单且稳健 |
| LCM | 4–8 | 潜在一致性蒸馏(Latent Consistency),超快 |
挑选采样器是用来在速度和质量之间做权衡的最容易触及的杠杆之一。
为什么这个家族会与 Transformer 并存
你可能会问:为什么不像生成文本那样一个 Token 一个 Token 地生成图像?答案很微妙。
对文本来说,顺序是天然的:我们从左往右读,每个词都依赖之前的词。对图像来说,并没有什么规范的顺序。一个像素一个像素地生成会引入伪影(最早的像素没有最后那些像素的上下文)。扩散通过一次性并行生成整张图像、并在每一步做全局精炼,解决了这个问题。
这就是为什么基于像素的自回归方法(PixelRNN、OpenAI 早期的 ImageGPT)被放弃了:太慢,而且结果里还留着生成顺序的痕迹。
但故事并没有到此为止,而且这是一堂很好的谦虚课。自回归回来了——不再作用于像素,而是作用于图像 Token,就像 LLM 摆弄文本 Token 那样。2025 年,当 OpenAI 把图像生成直接内建进它的语言模型时,这条路线在各类对比中冲到了前面,压过了当时最好的扩散模型。此后,前沿开始把两者混着用:一个自回归 Transformer 决定画什么,一个扩散式的解码器产出最终图像。
扩散不是 Transformer:它是另一种、在数学上正交的、学习一个复杂分布的方式。在图像这一块,它至今仍统治着开源生态——但"扩散已经赢了"这个说法早就站不住脚了。两个家族正在合流。
这也正好用来收尾。你从一个预测下一个词的系统出发,顺着这根线一路走到 Token、向量、注意力、对齐、智能体、features。最后这一章提醒你:还存在另一条路——而它最终与第一条相交。这一切都还没有定型:今天占主导地位的架构,未必是三年后的那些。但你现在掌握的这些机制,本身不会有太大变动。正是它们,会让你把下一次惊喜看清楚它的本来面目:一个工程上的想法,而不是魔法。
更新于