1. 从噪声到图像:扩散模型到底在做什么
第一次接触扩散模型的人,多半会被那一堆公式和“加噪、去噪”的说法绕晕。我刚开始也是,看论文里满屏的马尔可夫链、变分下界,头都大了。但真正把代码跑起来、自己动手实现一遍之后才发现,它的核心思想其实朴素得惊人——把一张清晰图片一步步加噪变成纯噪声,再训练一个网络学会把这个过程倒过来。就这么简单。
扩散模型(Diffusion Models)属于生成模型家族,和GAN、VAE、流模型是同一个赛道上的选手。它解决的问题只有一个:如何让机器学会真实数据的分布,从而生成以假乱真的新样本。放到图像领域,就是让模型“凭空”画出一张从来没存在过、但看起来又无比真实的图片。适合谁来学?只要你会一点Python、懂基本的神经网络概念,就能上手。哪怕你只是想搞明白Stable Diffusion背后到底发生了什么,理解扩散模型的来龙去脉也是绕不开的一步。
我写这篇东西,不是要复述论文,而是想以一个实际写过、调过、踩过坑的从业者视角,把扩散模型从2020年到现在这几年的发展脉络捋清楚。你会看到它是怎么从一个冷门想法,变成今天图像生成领域事实标准的。中间哪些工作是真正的转折点,哪些设计是拍脑袋想出来的,哪些坑是后来才被填上的,我都会尽量讲透。
2. 扩散模型的思想源头与数学骨架
2.1 为什么是“扩散”这个名字
“扩散”这个词借自热力学。想象一滴墨水滴进清水里,刚开始墨迹集中,随着时间推移,墨分子随机运动,最终均匀散布到整杯水中。这个过程是不可逆的、熵增的——你不可能指望墨水自己重新聚成一滴。
扩散模型就是把这个物理直觉搬到了数据分布上。前向过程:对一张真实图片不断加高斯噪声,经过足够多步之后,图片变成完全的高斯白噪声,原始信息彻底丢失。反向过程:训练一个神经网络,让它学会从噪声里一步步“去噪”,最终还原出一张清晰图片。关键在于,反向过程不是真的逆转物理,而是学习一个近似的条件分布。
这里有个容易被忽略的点:前向加噪是没有可学习参数的,它就是一个固定的马尔可夫链,每步加一点噪声。真正需要学习的只有反向去噪网络。这个设计非常聪明,因为它把“生成”这个难题转化成了“去噪”这个监督学习问题——而监督学习是我们最擅长的。
2.2 数学骨架:变分下界与简化损失
扩散模型的数学基础是变分推断。具体来说,它优化的是数据对数似然的变分下界(ELBO)。推导过程比较长,但结论很关键:这个下界可以分解成每一项对应一个时间步的KL散度,最终化简成一个预测噪声的均方误差。
我用大白话翻译一下:训练的时候,你随机选一个时间步t,对图片加噪到第t步,然后把加噪后的图片和t一起喂给网络,让网络预测“我加进去的噪声是什么”。损失函数就是预测噪声和真实噪声之间的MSE。就这么直接。
提示:很多人第一次看论文会被ELBO的推导吓退,其实完全可以先跳过推导,直接看最终损失函数。理解“预测噪声”这个训练目标,比理解推导过程重要一百倍。
这个简化损失(simple loss)是Ho等人在2020年DDPM论文里明确提出的,它去掉了ELBO里那些复杂的加权系数,直接用等权MSE。实验证明效果反而更好,训练也更稳定。这是一个典型的“理论指导方向,工程简化落地”的案例。
2.3 从DDPM到DDIM:采样加速的关键一步
DDPM的原始采样过程有个致命问题:太慢了。生成一张图需要跑1000步甚至更多,每步都要过一遍网络。这在2020年或许还能忍,但放到实际应用里完全不可接受。
2021年Song等人提出的DDIM(Denoising Diffusion Implicit Models)解决了这个问题。它的核心洞察是:前向过程不一定非得是马尔可夫链。你可以构造一个非马尔可夫的、确定性的前向过程,只要边缘分布保持一致,反向采样就可以跳步。
DDIM把采样步数从1000步压缩到50步甚至20步,速度提升几十倍,而生成质量几乎不降。这个工作直接让扩散模型从“实验室玩具”变成了“可用的工具”。我实测下来,DDIM 50步和DDPM 1000步的FID差距通常在1以内,但速度快了20倍,性价比极高。
| 特性 | DDPM | DDIM |
|---|---|---|
| 前向过程 | 马尔可夫链 | 非马尔可夫 |
| 采样步数 | 1000+ | 20-100 |
| 采样确定性 | 随机 | 可确定性 |
| 生成质量 | 高 | 几乎持平 |
| 实际可用性 | 低 | 高 |
3. 架构演进:从U-Net到Transformer的路线之争
3.1 U-Net为什么成为默认选择
扩散模型的反向去噪网络,早期几乎清一色用U-Net。原因很直接:去噪任务本质上是image-to-image的密集预测,输入和输出都是同尺寸的特征图,而U-Net的编码器-解码器结构加跳跃连接,天然适合这种任务。
U-Net的编码器逐层下采样,提取语义信息;解码器逐层上采样,恢复空间细节;跳跃连接把编码器的高分辨率特征直接拼到解码器对应层,避免细节丢失。这套结构在医学图像分割里已经被验证过无数次,搬到扩散模型里同样好使。
但U-Net也不是没有缺点。它的感受野受限于卷积核大小,虽然可以通过堆叠层数扩大,但全局建模能力始终不如注意力机制。这就引出了后来的Transformer路线。
3.2 DiT:Transformer接管扩散模型
2022年底,Peebles和Xie的DiT(Diffusion Transformer)工作是一个分水岭。他们直接把U-Net换成了纯Transformer架构,把图像切成patch当作token序列处理,用adaLN-Zero做条件注入。
结果很震撼:DiT在ImageNet 256x256上刷新了FID记录,而且模型越大效果越好,展现出和语言模型类似的scaling law。这意味着扩散模型也可以像GPT一样“堆参数换性能”。
DiT的成功直接影响了后续几乎所有主流工作。Stable Diffusion 3、Sora、SDXL的后续版本,底层架构都转向了Transformer或混合架构。我个人的判断是:U-Net在低分辨率、小数据场景下仍有优势,但大规模预训练场景下Transformer是更优解。
3.3 条件注入机制:从cross-attention到adaLN
无条件生成只是玩具,真正有用的是条件生成——给定文本、类别、深度图等条件,生成对应内容。条件注入方式经历了几个阶段:
- Cross-attention:把条件编码成序列,通过交叉注意力注入U-Net中间层。这是Stable Diffusion 1.x/2.x的做法,灵活但计算量大。
- adaLN:自适应层归一化,把条件编码成缩放和平移系数,直接调制每层特征。DiT用的就是这种,计算效率高。
- adaLN-Zero:在adaLN基础上把残差分支初始化为零,训练更稳定。这个技巧在DiT里被证明很关键。
注意:条件注入方式的选择会显著影响训练稳定性和最终效果。如果你在复现时发现模型不收敛,先检查条件注入模块的初始化,adaLN-Zero的零初始化往往能救你一命。
4. 潜在扩散模型:让扩散模型真正跑进消费级显卡
4.1 像素空间扩散的算力困境
在潜在扩散模型(Latent Diffusion Models, LDM)出现之前,扩散模型都在像素空间操作。一张512x512x3的图片,直接在上面跑U-Net,显存占用和计算量都大得吓人。训练一个像样的模型需要几十张A100跑好几周,普通人根本玩不起。
问题出在维度上。像素空间的数据维度太高,而图像的信息熵其实远低于像素数量。换句话说,大部分像素值是可以压缩的,没必要在原始像素上做扩散。
4.2 VAE压缩:把扩散搬到潜空间
LDM的核心思路是:先用一个预训练的自编码器(通常是VAE)把图片压缩到潜空间,在潜空间里做扩散,生成完再解码回像素空间。压缩率通常是8倍下采样,也就是说512x512的图变成64x64的潜变量。
这一下就把计算量降了64倍。原本需要几十张A100的任务,现在一张消费级显卡就能跑。Stable Diffusion之所以能开源并迅速引爆社区,LDM是最大的功臣。
| 维度 | 像素空间扩散 | 潜在空间扩散 |
|---|---|---|
| 操作空间 | 512x512x3 | 64x64x4 |
| 计算量 | 极高 | 降低约64倍 |
| 训练成本 | 数十张A100 | 单卡可训练 |
| 代表工作 | DDPM, Imagen | Stable Diffusion |
4.3 交叉注意力文本条件:文生图的基石
LDM另一个关键设计是把文本条件通过交叉注意力注入U-Net。文本先用CLIP等模型编码成序列,然后在U-Net的每个注意力层里,让图像特征去“查询”文本特征。这样文本的每个token都能影响图像的不同区域,实现细粒度的语义对齐。
这个设计直接催生了Stable Diffusion。你输入“一只戴墨镜的柴犬在冲浪”,模型真的能生成对应画面,而且不同概念之间的组合关系基本正确。当然,早期的SD 1.x在复杂组合、数量关系上经常翻车,这是CLIP文本编码器的局限,后来SDXL换用更大的文本编码器才有所改善。
5. 训练与采样的实操细节
5.1 噪声调度:线性还是余弦
噪声调度决定了每个时间步加多少噪声。DDPM原始论文用的是线性调度,从1e-4到0.02均匀增加。但后来发现线性调度在低噪声端加噪太快,高噪声端又太慢,导致中间时间步的训练信号不够好。
Nichol和Dhariwal提出的余弦调度解决了这个问题。它让信噪比(SNR)随时间更平滑地下降,训练更稳定,生成质量也更好。现在大部分实现默认用余弦调度。
import numpy as np def cosine_beta_schedule(timesteps, s=0.008): steps = timesteps + 1 x = np.linspace(0, timesteps, steps) alphas_cumprod = np.cos(((x / timesteps) + s) / (1 + s) * np.pi * 0.5) ** 2 alphas_cumprod = alphas_cumprod / alphas_cumprod[0] betas = 1 - (alphas_cumprod[1:] / alphas_cumprod[:-1]) return np.clip(betas, 0.0001, 0.9999)5.2 采样器选择:DDIM、DPM-Solver与Euler
采样器的选择直接影响生成速度和质量的平衡。我整理了一个实用对比:
| 采样器 | 步数需求 | 质量 | 确定性 | 适用场景 |
|---|---|---|---|---|
| DDPM | 1000+ | 高 | 随机 | 研究基准 |
| DDIM | 20-100 | 高 | 可确定 | 通用 |
| DPM-Solver | 10-20 | 很高 | 可确定 | 快速生成 |
| Euler | 20-50 | 高 | 可确定 | 社区常用 |
| Euler a | 20-50 | 高 | 随机 | 创意生成 |
DPM-Solver是2022年的工作,把扩散ODE的求解器理论引入采样,10步就能达到DDIM 50步的质量。Euler和Euler a是社区实现里最常用的,后者带随机性,每次生成略有不同,适合探索。
实操心得:如果你在做产品原型,优先用DPM-Solver++或Euler,20步左右就能出不错的结果。如果追求极致质量,DDIM 100步仍然稳。别迷信“步数越多越好”,超过一定步数后质量提升微乎其微,纯属浪费算力。
5.3 无分类器引导:CFG的威力与代价
无分类器引导(Classifier-Free Guidance, CFG)是条件生成里的关键技术。训练时随机丢弃条件(比如10%概率把文本置空),让模型同时学会有条件生成和无条件生成。采样时把两者的预测做外推:
noise_pred = noise_uncond + guidance_scale * (noise_cond - noise_uncond)guidance_scale通常在7-15之间。值越大,生成结果越贴合条件,但多样性和真实感会下降,容易出现过度饱和、伪影。值太小则条件遵循度不够。
我踩过的坑:CFG scale设到20以上,图片颜色会明显过饱和,人脸容易崩。一般7.5是安全起点,需要强条件遵循时调到10-12,再高就要小心了。
6. 扩散模型发展中的关键转折与踩坑记录
6.1 从DDPM到Stable Diffusion的时间线
把关键节点串一下,方便你建立整体认知:
- 2015年:Sohl-Dickstein等人首次提出扩散概率模型,但当时效果不如GAN,没引起关注。
- 2020年:Ho等人的DDPM论文,首次生成质量媲美GAN,引爆学术界。
- 2021年:DDIM加速采样;LDM提出潜空间扩散;Classifier-Free Guidance成为标配。
- 2022年:Stable Diffusion开源,文生图进入大众视野;DPM-Solver进一步加速;DiT探索Transformer架构。
- 2023年:SDXL、DeepFloyd IF等更大规模模型出现;视频扩散模型开始爆发。
- 2024年至今:Sora展示视频生成能力;SD3换用Transformer架构;扩散模型与自回归模型路线融合。
6.2 那些年我们踩过的坑
坑一:训练loss不降反升。最常见原因是噪声调度设置不当,或者时间步采样策略有问题。检查beta的上下界,确保alphas_cumprod在最后接近0。
坑二:生成图片灰蒙蒙。多半是VAE解码器的问题,或者潜空间缩放系数没设对。Stable Diffusion的VAE缩放系数是0.18215,这个值不能随便改。
坑三:CFG导致颜色崩坏。前面说过,scale太高会过饱和。另外,如果训练时条件丢弃概率设得太低,CFG效果会打折。一般0.1-0.2比较合适。
坑四:采样步数和调度器不匹配。用DDIM调度器配Euler采样器,结果会很奇怪。确保采样器和调度器配套使用。
坑五:显存爆炸。潜空间扩散虽然省显存,但注意力层的显存占用是O(n²)。生成高分辨率图时,用分块注意力或Flash Attention能显著降低显存。
6.3 常见问题速查表
| 问题现象 | 可能原因 | 排查方向 |
|---|---|---|
| 生成全黑/全白 | 噪声调度错误 | 检查beta范围 |
| 图片模糊 | VAE解码问题 | 检查缩放系数 |
| 条件不生效 | CFG未启用 | 检查guidance_scale |
| 训练不收敛 | 学习率过高 | 降到1e-5试试 |
| 采样极慢 | 步数过多 | 换DPM-Solver |
| 颜色过饱和 | CFG过高 | 降到7-10 |
| 显存不足 | 分辨率过高 | 启用梯度检查点 |
7. 扩散模型当前的能力边界与后续方向
扩散模型在图像生成上已经相当成熟,但远不是终点。目前几个明显的边界:采样速度仍然偏慢,即使有DPM-Solver,生成一张1024x1024的图仍需数秒;长视频生成的一致性还没完全解决,Sora展示了可能性但离稳定可用还有距离;精确可控性不足,比如指定具体姿态、精确数量,仍然依赖ControlNet等外挂模块。
后续方向我个人比较看好几个:一是与自回归模型的融合,比如用Transformer统一建模离散和连续数据;二是蒸馏加速,把大模型的能力蒸馏到少步模型里,实现实时生成;三是多模态统一,一个模型同时处理图像、视频、音频甚至动作。
我在实际项目里的体会是,扩散模型不是万能药。如果你的任务对生成速度要求极高、或者需要精确的几何控制,传统方法或GAN可能更合适。扩散模型的优势在于生成多样性和质量的上限极高,适合创意探索、内容填充、超分辨率这类场景。
最后分享一个小技巧:如果你在微调自己的扩散模型,先用小分辨率、小数据集跑通全流程,确认loss正常下降、采样能出合理结果,再放大规模。我见过太多人一上来就怼512x512全量数据,结果训练三天发现loss是nan,回头排查成本极高。小步快跑,永远是工程落地最稳的策略。