ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

扩散模型进化史:从DDPM到Stable Diffusion的工程实践与避坑指南

扩散模型进化史:从DDPM到Stable Diffusion的工程实践与避坑指南 扩散模型这两个词放在不同圈子里指向完全不同的东西。气象那边说的是高斯烟羽模型描述污染物随风飘散的浓度分布人工智能领域说的则是生成模型核心思想简单到让不少人第一反应是就这给一张图反复加噪声直到它彻底变成雪花点再训练一个网络把加噪过程一步步倒回去。过去两年里你看到的那些以假乱真的AI绘画、图像编辑、视频生成绝大多数底层都站着这套思路。这篇博文只讲后者梳理它是怎么从物理学论文里一步步走到今天这个位置的中间哪些论文是绕不开的里程碑哪些工程细节决定了它能否被普通人生搬硬套地跑起来以及我在复现这些模型时踩过的坑。作为一名常年跟生成模型打交道的从业者我觉得扩散模型的发展史几乎是近五年深度学习领域最值得复盘的一条线。它不像之前某些技术那样靠单个爆点一战成名而是从理论到工程再到生态一层一层磨出来的。对新手来说理解这条线能帮你少走很多弯路对想上手做项目的人来说搞清楚它为什么这样设计比单纯跑通一个开源仓库重要得多。1. 扩散模型的前传从热力学假设到生成模型雏形1.1 为什么所有人都从非平衡热力学讲起扩散模型的名字很直白直觉就来自物理里的扩散现象——一滴墨水滴进清水最终会均匀散开。把这个过程反过来就是从均匀的噪声里聚拢出一张清晰图像。2015年之前很少有人认真想过这种逆向过程可以被神经网络学会。当时的生成模型主流是两派一派是GAN靠生成器和判别器互相对抗训练技巧多得像玄学动不动就崩另一派是VAE求的是潜在空间的概率分布生成的图总有种糊了一层滤镜的感觉。扩散模型最初的定位很尴尬它的采样速度慢得惊人生成质量又不如GAN尤其在高清图像上根本没有优势因此学术界之外几乎没人关注它。这条线的真正源头要追溯到2015年ICLR上的一篇论文题目是《Deep Unsupervised Learning using Nonequilibrium Thermodynamics》。作者是Sohl-Dickstein等人他们从非平衡统计力学的角度提出了一个框架前向过程是逐步加噪直到完全变成噪声反向过程则由一个参数化的马尔可夫链来逼近真实逆过程。论文里其实已经写清楚了训练目标是最大化对数似然的一个变分下界也就是后来DDPM里那套损失函数的前身。但当时这篇文章的落点非常学术实验也仅仅停留在MNIST这种玩具数据集上生成的数字模糊得只能勉强辨认。最要命的是训练需要反复模拟完整马尔可夫链计算开销大得吓人。这篇论文被引用了很多年但真正复活它的是2019到2020年那批把推导和工程细节补齐的人。1.2 扩散模型和高斯扩散不是一回事在往下讲之前有必要先做个名词澄清。网络上搜扩散模型经常蹦出来python 大气污染高斯扩散模型 代码这类结果。气象和环境领域所说的高斯扩散模型解决的是污染物在大气中如何稀释扩散核心公式推导出来是一个烟羽浓度分布表达式参数包括风速、源强、扩散系数。它和我们现在讨论的AI生成模型除了共享扩散这个物理意象之外几乎没有交集。如果你是为了做AI绘画或文生图来找资料看到高斯烟羽的代码可以直接跳过反过来如果是为了毕业论文里的大气污染模拟搜索也别点进Diffusion Models的论文列表浪费时间。这个区分在刚开始接触的人中几乎每天都能见一次。2. DDPM登场扩散模型第一次变得可用2.1 Ho等人究竟改了什么2020年Jonathan Ho等人发表了《Denoising Diffusion Probabilistic Models》缩写DDPM。这篇论文可以被视为扩散模型真正进入深度学习主流的转折点。网上几乎所有扩散模型代码教程都以这篇为起点不是没有原因的。DDPM的核心贡献不是提出全新的理论而是把之前那套复杂框架做了大量简化让它能实打实地跟GAN扳手腕。具体来说有三个关键改动。第一个改动是前向过程固定下来不再用学习到的方差参数而是用一组预先设计好的方差调度表variance schedule从接近0的噪声逐步增加到一个很大的值。这一步让加噪过程变成了一个完全确定、没有可学习参数的流程训练时只需要直接采样任意时间步的带噪图像就够了。第二个改动是把逆向过程重新参数化。学习直接预测噪声而不是预测图像均值。这个设计初看很奇怪但效果非常实模型只需要学会预测当前图像里混入了多少噪声损失函数就是简单的MSE均方误差。后面大量实验证明这种间接路径比直接预测图像本身更容易优化尤其在图像域上收敛速度明显更快。第三个改动是发现了使用简单的均方误差损失、配合足够多的扩散时间步论文默认1000步模型能生成出当时几乎与GAN持平的高质量图像。这在CIFAR-10和CelebA等数据集上都得到了验证而训练过程比GAN稳定太多了——没有判别器、没有对抗损失、没有模式坍塌。你只需要一个U-Net加一个简单的MSE损失剩下的就是等它慢慢收敛。2.2 为什么U-Net成了标准选择DDPM里负责去噪的网络是U-Net这个选择被后来的几乎所有扩散模型继承下来。为什么偏偏是它可以从任务性质来理解去噪任务需要输入和输出分辨率一致这和图像分割很像。U-Net的编码器-解码器结构加跨层跳跃连接可以在下采样捕捉高阶语义信息的同时通过跳跃连接保留局部细节避免生成图像糊掉。以我跑DDPM的经验U-Net里的时间步嵌入time embedding对质量影响非常大。许多初学者复现DDPM时只用简单的常数把时间步喂给网络效果明显不如论文里那种正弦位置编码再经过两层MLP的方式。时间步嵌入的作用是让网络知道现在处理的噪声水平有多大模型在去噪初期和末期做的事情完全不同——初期偏向恢复整体轮廓末期偏向精修细节。它在训练时使用越来越大的正弦变换值本质上是一种条件输入。这个模块看似不起眼但丢掉之后训练损失会掉得很慢生成样本质量也大打折扣。DDPM训练也可以看作是一个纯粹的配方玩法给定一个从0到T均匀采样的时间步从训练集抽取一张图按对应方差注入噪声然后让网络预测加入的噪声。整个训练集被反复利用随机的时间步骤给网络提供了不同难度级别的去噪任务。这种训练方式的好处是极其均匀、极其稳定坏处是推理时你必须从T到0跑满一千步一步一算速度自然慢得让人怀疑人生。2.3 加速采样从DDIM到扩散模型的工程优化DDPM虽然有质量但采样速度太慢。于是很快出现了一大批围绕加速采样的优化研究。其中绕不开的是2020年底提出的DDIMDenoising Diffusion Implicit Models。DDIM的核心思想是把采样过程从马尔可夫链改成非马尔可夫过程允许跳步采样——比如原来1000步现在可以只取50步、20步结果也不会差太多。常见做法是在采样时用一个更粗的时间步子集配合不同的随机种子组合。从从业者角度看DDIM更大的意义是提供了一个确定性的采样映射同样的初始噪声走同样的采样轨迹得到的生成结果基本一致。这个性质让潜空间编辑成为可能也就是在噪声空间中插值或微调输出端产生平滑的视频效果或风格混合。如果没有DDIM今天很多花式玩扩散模型的技巧几乎都不成立。另一个重要的加速方案是蒸馏类的思路比如通过多个teacher模型逐步蒸馏到一个student模型让采样步数降到几步甚至一步。这类方法在学术界很热但从工程落地角度目前主流Stable Diffusion生态里大家更常用的是DDIM或DPM-Solver这类基于常微分方程数值求解器的采样器训练好的模型不需要额外蒸馏直接在采样阶段替换求解器就能提速。DPM-Solver这类方法把扩散模型的反向过程看作一个常微分方程利用多项式的数值积分近似20步就能得到可接受的图像。这部分优化是实际应用中性价比最高的一项因为你什么都没改只换了一个采样器速度就能翻好几倍。3. 潜在扩散模型Stable Diffusion的工程飞跃3.1 高分辨率困境与感知压缩的思路DDPM质量不错但有一个致命短板直接在高分辨率像素空间上训练内存和时间开销都大到不可接受。尝试在512×512甚至1024×1024上长时间训练的人都知道那种痛苦——一张显卡顶着上限跑batch size调不下来生成一张图要等几分钟。要想把扩散模型推到产品级别必须压缩计算域。2022年初的《High-Resolution Image Synthesis with Latent Diffusion Models》给出了解决路线先训练一个自编码器通常是VQ-GAN或KL-VAE把图像压缩到一个低维潜在空间然后在潜在空间里跑扩散过程。这就是潜在扩散模型Latent Diffusion ModelLDM。图片尺寸缩小到原来的1/8甚至1/16计算量自然大幅下降而自编码器的解码器负责把潜在表示还原回高清图像。这个设计的精妙之处在于它把感知压缩和生成两件事拆开了。感知压缩负责把图像压缩成人类视觉上几乎无损的低维潜码扩散过程的每一步不需要关心单个像素值只需要学习在潜空间里的概率分布。就像写文章不需要先考虑每个字的肌肉运动而是先在语义层组织语言。这个分离让扩散模型在高分辨率场景下从实验室玩具变成了可落地的工业化方案。3.2 Stable Diffusion生态从LDM到开源大爆发潜在扩散模型论文一经发布配套的代码和预训练权重就开放出来后来正式入了Stable Diffusion这个名字。在我看来Stable Diffusion对行业的最大贡献不是模型效果本身而是一套可复用的工程标准U-Net的计算完全放在潜在空间文本提示词通过CLIP文本编码器变成向量后注入去噪过程调度器支持多种采样策略权重分模块加载可以像积木一样插拔。这个设计让社区涌现出大量二创玩法。比如ControlNet通过给一张条件图深度图、线稿、姿势骨架单独训练一个冻结主干之外的控制分支实现对生成图像的细粒度控制。再比如LoRA在冻结原始权重的大前提下通过在部分矩阵上插入低秩适应模块做轻量微调让普通玩家用一张不算好的显卡就能训练出某个特定风格或人物。这些围绕潜在扩散模型的周边生态已经远远超出了论文作者最初的想象。我必须承认潜在扩散模型的实际训练门槛其实不低——自编码器的压缩和解码质量直接决定了最终画质。想要跑通一整套训练流程至少需要熟悉Transformers、卷积架构、注意力机制、CLIP编码器等多套组件。好在社区已经把这些都集齐了初学者更常见的使用路径是直接拿Stable Diffusion开源的模型权重用Diffusers库的几行代码完成文本到图像的推理。这是不是在做研究另说但对于产品原型验证和内容生产来说性价比极高。3.3 条件生成与无分类器引导为什么提示词能影响画风扩散模型早期的无条件生成纯粹是随机噪声到随机图像的过程。但真实场景需要可控生成于是条件生成成了热点。所谓条件生成就是给去噪网络额外输入一个条件变量比如类别、文本描述、深度图。Stable Diffusion里最常用的做法是交叉注意力cross-attention在U-Net的每个分辨率层级把文本嵌入向量与图像特征做交叉注意力计算让文本语义引导图像的生成方向。还有一项至关重要的技巧叫无分类器引导Classifier-free GuidanceCFG。它不额外训练分类器而是在训练时随机将条件置空让网络同时学会有条件的去噪和无条件的去噪。推理时整个生成方向被推向条件与无条件之间的差异控制力度由一个scale参数决定。scale越大生成结果越文本一致但过度增加会损失多样性甚至出现画质崩坏。这个技巧让提示词对输出效果的控制变得非常明确也是为什么同样的模型调高CFG scale之后画面会变得细节锐利但有些用力过猛的原因。在实际复现Stable Diffusion风格迁移时我发现条件注入的位置和时机可以玩出很多花样。有人喜欢把文本条件同时喂到多个尺度生成结果全局语义更强有人只在低分辨率阶段注入保持细节自然。但最基本的原则是条件信息必须与去噪网络当前看到的噪声水平匹配否则网络会在不该受到强烈文本影响的时间步被拉扯结果往往是主体正确但细节一团乱。3.4 采样调度器与推理参数的选择跑扩散模型你可能听过cheduler、sampler这些词。调度器决定每个时间步用的是哪种噪声幅度采样器决定步长和更新公式。同一个模型换不同的采样器画面风格和收敛速度都会有明显差异。比如DPM-Solver用20步就能接近DDIM100步的效果而如果只要快速预览有些采样器支持8步甚至4步出图虽然细节会略有损失。从我个人的经验看生产环境里最常用的组合是训练时用线性linear或scaled linear调度推理时优先尝试DPM-Solver或Euler采样器。如果你生成的图总是偏灰或者偏白大概率是调度器设置和模型训练时不统一造成的——这个问题在社区里非常常见根本原因不是你网络写得不对而是噪声尺度定义不一致。Diffusers库已经帮用户屏蔽了多数细节但当你开始改造源码或自定义训练流程时就必须认真对照论文里的beta schedule定义。4. 实战从零复现一个轻量级扩散模型4.1 数据集与基础架构选择现在网上各种Stable Diffusion二次封装工具很多但从学习角度讲亲手复现一个在MNIST或CIFAR-10上的DDPM还是很有必要的。它能帮你真正理解时间步嵌入、噪声调度、去噪网络的相互作用。我一般建议的路径是先在MNIST上跑通无条件DDPM再增加简单条件如类别标签最后再切换到潜空间和文本条件。数据准备阶段有个容易被忽略的点归一化一定要做好。图像像素值应缩放到[-1, 1]而不是[0, 1]这样加噪后信息才能对称地淹没在噪声中。如果你只缩放到[0, 1]梯度在经过激活函数之后很容易出现偏移。我自己调试时最常遇到的不收敛问题有一半都源于这个看似不起眼的细节。网络结构方面新手可以直接用一个四层下采样和四层上采样的U-Net注意力模块先在最低分辨率层加入以减少计算量。时间步嵌入用正弦位置编码加MLP所有残差块都加上它。这个规模在单块消费级显卡上跑MNIST大概几百个epoch就能得到不错的效果。4.2 训练步骤与损失函数细节训练循环非常简单伪代码层面从训练集中采一个batch图像对每张图随机采一个时间步t均匀分布根据预定义噪声调度计算出对应噪声强度将图像加噪得到x_t把x_t和时间步嵌入送入U-Net输出预测噪声计算预测噪声与真实噪声之间的MSE损失并回传看似简单但里面藏着一个关键细节训练过程中时间步t的采样要尽量覆盖整个0到T区间否则网络对某些噪声水平的去噪能力会明显偏弱。更优的做法是使用重要性采样或time step grouped采样让低频段和时间步分布更均匀。不过对小数据集来说均匀采样已经够用。损失函数的缩放也很微妙。论文里用的是标准的MSE但在实际实现中有人会在损失前面乘以时间步相关的权重。这个权重在推导时可以来自变分下界的展开项。多数现成代码直接不做额外缩放也照样能收敛。我的经验是初期不要引入太多花活先让标准MSE稳定下降再逐步尝试变种。训练时还要注意学习率和batch size的关系。DDPM对batch size比较敏感过小的batch会让梯度噪声变大生成样本在细节上容易不稳定。我用MNIST时batch size 64起步CIFAR-10则至少128。如果显存不够宁可调小模型通道数也别硬扛。这一点和GAN很不一样GAN经常小batch也能跑但扩散模型的经验是batch size明显影响收敛质量。4.3 推理采样与图像质量评测训练完成后推理过程就是反向跑马尔可夫链从纯高斯噪声出发按时间步从T到0逐步去噪。标准DDPM采样要跑1000步非常慢。与训练时完全一致每一步都加入一个小的随机项保证生成多样性。如果你用DDIM就可以把时间步压缩到50步甚至20步质量损失在可控范围内。评估生成质量最常用的指标是FIDFréchet Inception Distance。它把生成图像和真实图像分别用预训练网络提取特征计算两组特征分布之间的Wasserstein距离数值越低代表分布越接近。FID之外还有ISInception Score更侧重单张图的可识别性和多样性。但因为FID计算方式更符合人类对图像分布相似度的感知实际用得更广。我在实测中见过不少FID漂亮但肉眼效果一般的情况尤其在特定小数据集上。因为FID对样本数量、图像分辨率都比较敏感。**建议在训练过程中定期采样几条固定种子链直接目测去噪过程比只看指标更接地气。**这个习惯我保持到现在——数值可以骗人但采样轨迹骗不了你的眼睛。4.4 代码实现中的常见坑跑扩散模型有几类问题几乎每个人都会遇到。第一类是训练损失正常下降但采样结果全是噪声。这个通常是采样器和噪声调度不匹配。比如训练时beta从0.0001线性增到0.02推理时却用了cosine调度那就对不上。还有采样时忘了累加噪声项或者时间步方向搞反也容易出现一地鸡毛。第二类是生成图像整体偏暗或偏亮。排查思路很简单检查图像归一化是否存在双重处理。比如模型内部已经做了tanh激活外部又做了一次[0,1]缩放就会导致灰度偏移。第三类是训练时间太长但效果提升缓慢。先别急着加模型容量而是要确认是否每个batch里时间步覆盖率足够。如果大多数时间步都集中在噪声很小或很大的区域模型的中间难度学习就会很差。我发现一个很好用的技巧训练时记录每个时间步的损失输出一张损失-时间步曲线。如果曲线在中间段高得离谱说明时间步采样分布需要调整。另外需要注意随机种子管理。扩散模型训练对随机种子的敏感度不算极端但推理时如果你想稳定复现某个效果或做AB测试最好固定噪声种子并且把采样器设置固定下来。否则看起来是同一个模型两颗不同的随机噪声种子可以生成完全不同的画面容易让人误判为模型问题。我还想强调一点多GPU训练时全局batch大小对BN层影响很大而U-Net里常常有Group Normalization而不是Batch Normalization很多开箱即用的框架对BN处理得很好但对GroupNorm的分布式同步反而需要格外小心。如果你是自己搭工程建议直接使用GroupNorm否则跨卡训练时精度和行为很容易漂移。5. 模型选型与落地建议不同需求怎么选5.1 从DDPM到LDM技术选择的取舍学完基础面对真实项目时大家最常见的困惑是我到底该用Stable Diffusion还是从头训练一个自己的扩散模型答案取决于你的数据和任务。如果你的需求是“给特定风格数据做定向生成”那用Stable Diffusion加LoRA微调是最经济的路径如果你的数据非常特殊比如医学影像、工业缺陷检测预训练权重和领域不匹配那就需要从头或者从中间层开始高强度的微调。LDM系列中还有SDXL这类进一步放大基础模型规模的方案。它引入了更大的U-Net主干和更精细的文本编码组合效果比早期的SD1.4/1.5更细腻但显存和推理开销也明显上升。实际选型时要考虑部署场景To C的实时交互产品更看重低延迟可能需要蒸馏蒸馏后的轻量模型面向内容质量的工作流则愿意多花几秒换更好的画面。这个权衡不是越新越好而是要跟业务指标绑定。5.2 小团队或个人玩家的实操心得对于个人开发者或者三五人的小团队我没有太多建议要讲大道理只说最实在的几点。不要一开始就尝试全流程复现LDM那个工程量很大其中包括自编码器、CLIP文本编码、U-Net、采样器等模块任何一个环节出问题都会把你拖垮。直接用现成Diffusers库起步先跑通文生图推理再研究细粒度控制比如通过lora、Textual Inversion之类的方案学习风格。数据管理一定要自动化。AI绘画模型的文本-图像数据对质量要求极高清洗、去重、打标这三个环节占用的时间往往比训练还多。一条标签混乱的数据比十条低分辨率数据更伤模型。显卡推荐至少在16GB显存以上否则训练LoRA都很勉强。用小显存不是不能跑但迭代速度和实验效率会让人非常痛苦。Cloud GPU按时计费反而是小团队更好的一种选择很多商业平台支持一键开启训练环境省去环境配置的老大难问题。还有一个容易犯的错把开发环境和推理环境混在一起。**强烈建议训练和推理分开管理因为训练时对CUDA、PyTorch版本的要求和推理时不一样混用很容易出现玄学问题比如dataloader worker段错误、显存碎片化等。**我自己维护项目的习惯是训练用一台大显存机器推理部署用容器镜像固定环境两者之间只通过模型权重文件对接。5.3 最后再分享一个实际工作中的小技巧如果你做的是类似“风格迁移”或者“人物一致性生成”的任务可以先跑一次高质量的图像重构直接观察自编码器的压缩瓶颈在哪。很多时候生成的图像主体很好但细节比如文字、细条纹总是一塌糊涂这不是扩散模型的问题而是潜在空间压缩阶段丢掉的细节太多。尝试换用更高分辨率的自编码器或者增加重构阶段的损失权重往往比拼命调U-Net更有效。这个经验是我在一次产品原型迭代中踩了大坑才发现的。当时团队花了大量精力调CFG scale和采样步数画面依然有微妙的纹理畸变最后把注意力转向autoencoder问题在一周内就解决了。扩散模型是一个“木桶效应”非常明显的技术栈训练质量、文本编码、潜空间重构、采样调度器每一环都会成为短板。你在学习它的发展史时也要记住这个教训——单点突破很难系统性理解才能让你真正驾驭它。
返回列表