- 1. 论文概要
- 2. 背景:从热力学到生成模型
- 3. Forward Process:系统性地添加噪声
- 4. 核心数学:Reparameterization Trick
- 5. Reverse Process:从噪声中复原图像
- 6. 训练目标的推导:从 ELBO 到 Simplified Loss
- 7. 噪声调度:$\beta_t$ 的设计
- 8. 采样算法
- 9. 架构:Time-conditioned U-Net
- 10. 实验结果
- 11. 后续研究总结:Diffusion 的演进
- 12. PyTorch 代码示例:简单的 DDPM 实现
- 13. Diffusion Model vs GAN vs VAE:对比分析
- 14. Diffusion Model 的现状与未来
- 15. References
1. 论文概要
"Denoising Diffusion Probabilistic Models"(DDPM)是 2020 年在 NeurIPS 上发表的论文,由 UC Berkeley 的 Jonathan Ho、Ajay Jain、Pieter Abbeel 共同撰写。这篇论文以实证方式证明了通过扩散概率模型(Diffusion Probabilistic Model)可以实现高质量图像合成,是一项具有里程碑意义的研究。
核心思路出奇地简单。学习一个对数据逐步添加高斯噪声的 Forward Process,以及逐步去除该噪声、从而复原原始数据的 Reverse Process。最终的训练目标归结为"模型预测的噪声"与"实际添加的噪声"之间的简单 MSE 损失。
DDPM 在 CIFAR-10 上取得了 FID 3.17、Inception Score 9.46 的成绩,展现出与当时基于 GAN 的模型相当甚至更优的性能。更重要的是,这篇论文成为了此后 DALL-E 2、Imagen、Stable Diffusion、Midjourney 等现代图像生成 AI 的基础。
论文信息
- 标题:Denoising Diffusion Probabilistic Models
- 作者:Jonathan Ho, Ajay Jain, Pieter Abbeel
- 会议:NeurIPS 2020
- arXiv:2006.11239
- 官方代码:hojonathanho/diffusion
2. 背景:从热力学到生成模型
2.1 源自非平衡热力学的启发
Diffusion Model 的思想源头在于非平衡统计力学(Non-equilibrium Thermodynamics)。在物理学中,扩散(Diffusion)是指粒子从浓度高的地方向浓度低的地方随机移动,最终达到热力学平衡状态(最大熵)的过程。这一过程的核心洞见如下。
- Forward:具有复杂结构的状态 无序的平衡状态(信息的破坏)
- Reverse:从平衡状态 恢复为具有结构的状态(信息的生成)
Sohl-Dickstein 等(2015)首次将这一思路应用于机器学习,发表了 "Deep Unsupervised Learning using Nonequilibrium Thermodynamics"。其思路是:定义一个将复杂数据分布转换为简单已知分布(高斯分布)的扩散过程,再学习其逆过程,就得到一个生成模型。
2.2 与 Score Matching 的联系
Diffusion Model 的另一条理论支柱是 Score Matching。Score function 定义为对数概率密度的梯度。
如果能够估计出这一 score function,就可以通过 Langevin Dynamics 生成样本。
Yang Song 与 Stefano Ermon(2019)在 "Generative Modeling by Estimating Gradients of the Data Distribution" 中提出了 Noise Conditional Score Networks(NCSN),给出了在不同噪声水平下估计 score function 的方法。Ho 等人的 DDPM 与这一 Score Matching 视角有着深刻的联系,论文本身也把"与 denoising score matching with Langevin dynamics 之间的新联系"列为其核心贡献之一。
2.3 SDE 视角:统一框架
Song 等(2021)在 "Score-Based Generative Modeling through Stochastic Differential Equations" 中,用随机微分方程(SDE)这一统一框架,把 DDPM 与 Score Matching 联系了起来。将 Forward Process 用连续时间 SDE 描述如下。
这里 是 drift coefficient, 是 diffusion coefficient, 是标准 Wiener process。与该 SDE 对应的 Reverse-time SDE 存在如下形式。
关键在于,求解反向 SDE 所需要的,仅仅是随时间变化的 score function 。DDPM 的噪声预测网络 实质上等价于对这一 score function 的估计。
这一关系正是从理论上统一 DDPM 与 Score Matching 的关键纽带。
3. Forward Process:系统性地添加噪声
3.1 作为 Markov Chain 的 Forward Process
Forward Process(或称 Diffusion Process)是对原始数据 逐步添加高斯噪声的固定 Markov Chain。它没有可学习的参数,完全由预先定义好的 Variance Schedule 决定。
每个时间步 的转移概率定义如下。
展开来说,每一步都把上一时刻的数据缩放 倍,再加上方差为 的高斯噪声。
为什么要用 来缩放? 是为了让每一步的总方差保持不变。若 的方差为 1,则 的方差为 ,再加上方差为 的噪声后,总方差就变为 。
当 足够大、且 设置得当时, 会收敛到近乎纯粹的各向同性高斯噪声 。
3.2 完整 Forward Process
跨越 步的整个 Forward Process 的联合分布如下。
这是由 Markov 性质决定的,即每一步都只依赖于紧邻的前一步。DDPM 中使用 , 从 线性递增到 。
4. 核心数学:Reparameterization Trick
4.1 一步跳到任意时间
Forward Process 最强大的数学性质在于:可以不经过中间步骤,直接从 计算出任意时间 下的 。这正是让训练变得高效的关键。
先定义记号。
是 的累乘,表示到时间 为止原始信号还保留了多少。
4.2 推导过程
从 开始,用归纳法推导。
把 代入 ,得到
这里要用到独立高斯分布之和的法则:两个独立的高斯分布 与 之和服从 。
把噪声项的方差相加,得到
因此,
将其一般化,可得到如下结果。
4.3 最终结果:Closed-form Expression
也就是说,任意时间 下的 可以一次性采样得到,如下所示。
对这个式子做直观解读,如下表所示。
| 项 | 含义 | 随时间的变化 |
|---|---|---|
| 原始信号(signal) | 则 ,信号减弱 | |
| 新加入的噪声 | 则 ,噪声增强 |
时 ,故等于 本身; 时 ,故几乎为纯噪声。这种 Signal-to-Noise Ratio(SNR)的逐步下降,正是 Forward Process 的本质。
5. Reverse Process:从噪声中复原图像
5.1 Reverse Process 的定义
Reverse Process 是从纯噪声 出发,逐步去除噪声、生成数据 的过程。核心假设是:如果 Forward Process 的每一步都是微小的高斯扰动,那么它的逆过程也可以用高斯来近似。(在 足够小的前提下)
这里 与 是神经网络需要学习的均值与方差。DDPM 并不学习方差 ,而是将其固定为 ,使用 或 。
5.2 Posterior 的推导
训练的核心在于:给定 时的反向条件分布(posterior)可以用闭式(closed form)计算出来。应用贝叶斯定理,
由 Markov 性质可知 ,因此右边三项都是高斯分布。高斯分布的乘积仍是高斯分布,把指数部分展开、按 整理成二次式,可得到
这里 posterior 均值为,
posterior 方差为,
5.3 用 替换
模型无法直接知道 ,因此把 Reparameterization 公式 反解出 。
把这个结果代入 posterior 均值 ,得到
只要模型学习到一个预测噪声 的网络 ,Reverse Process 的均值就可以按下式计算。
这就是为什么在 DDPM 的 Reverse Process 中,预测噪声等价于预测均值。
6. 训练目标的推导:从 ELBO 到 Simplified Loss
6.1 最大似然与 ELBO
生成模型的终极目标是最大化数据的对数似然 。但这个量难以直接计算,因此转而优化变分下界(Evidence Lower Bound, ELBO)。
应用 Jensen 不等式,
6.2 ELBO 的分解
把 ELBO 分解为 KL divergence 各项,如下所示。
各项的含义如下。
(Prior Matching):衡量 与先验分布 之间的一致程度。当 足够大时,该项收敛到 0,且不含可学习参数,因此作为常数被忽略。
(Reconstruction):衡量从 复原 的能力。由于 与 非常相近,它对整体训练的影响很小。
(Denoising Matching):衡量模型的 Reverse 转移 与真实 posterior 之间的一致程度,是核心的训练信号。
6.3 KL Divergence 的计算
两个高斯分布之间的 KL divergence 可以用闭式计算。由于 、,因此
这里 是与方差相关的常数项。若把方差固定,则训练目标只剩下均值之差。
6.4 向噪声预测的再参数化
把前面推导出的 与 的表达式代入,
去掉权重系数后得到的 Simplified Loss 如下。
这里 、、。
这正是 DDPM 最重要的贡献。从复杂的 ELBO 出发,最终抵达"真实噪声 与预测噪声 之间的 MSE"——机器学习中最朴素的一种损失函数。实验也表明,这一 simplified loss 比加权后的原始 variational bound 能生成更好的样本质量。
6.5 训练算法总结
Algorithm 1: Training
─────────────────────────────────
repeat
x_0 ~ q(x_0) # 从数据集中采样
t ~ Uniform({1, ..., T}) # 随机选择时间步
ε ~ N(0, I) # 采样标准高斯噪声
x_t = √ᾱ_t · x_0 + √(1-ᾱ_t) · ε # 生成带噪图像
∇_θ ||ε - ε_θ(x_t, t)||² # 计算梯度并更新
until converged
7. 噪声调度: 的设计
7.1 Linear Schedule(DDPM 原始方案)
Ho 等人使用了让 从 线性递增到 的调度方案。
这一调度方案的直观思路是:初期添加较小的噪声,缓慢破坏数据结构;后期添加更大的噪声,快速收敛到高斯分布。
7.2 Linear Schedule 的问题
Nichol & Dhariwal(2021,"Improved Denoising Diffusion Probabilistic Models")指出了 Linear Schedule 的两个问题。
第一,早期信息破坏得太快。 在早期急剧下降,即使在 取较小值时也已经加入了相当多的噪声。这对高分辨率图像来说尤其成问题。
第二,后期时间步被浪费。 当 取较大值时,, 已经近乎纯噪声,对训练贡献不了多少有意义的信号。
7.3 Cosine Schedule
Nichol & Dhariwal 提出的 Cosine Schedule 直接定义了 。
这里 是一个较小的偏移量,用于防止 在 附近变得过小。
Cosine Schedule 的核心特性如下。
- 在中段近乎线性地下降,在所有时间步上都能提供同样有用的训练信号
- 防止早期加入过多噪声,从而保留精细的细节
- 在后期也能平滑地过渡到完全的噪声
import torch
import math
def cosine_beta_schedule(timesteps, s=0.008):
"""Cosine schedule as proposed in Nichol & Dhariwal (2021)."""
steps = timesteps + 1
t = torch.linspace(0, timesteps, steps) / timesteps
alphas_cumprod = torch.cos((t + s) / (1 + s) * math.pi * 0.5) ** 2
alphas_cumprod = alphas_cumprod / alphas_cumprod[0]
betas = 1 - (alphas_cumprod[1:] / alphas_cumprod[:-1])
return torch.clip(betas, 0.0001, 0.9999)
def linear_beta_schedule(timesteps, beta_start=1e-4, beta_end=0.02):
"""Linear schedule as proposed in Ho et al. (2020)."""
return torch.linspace(beta_start, beta_end, timesteps)
7.4 调度方案对比
| 属性 | Linear Schedule | Cosine Schedule |
|---|---|---|
| 下降模式 | 早期骤降,后期平缓 | 中段近乎线性 |
| 早期信息保留 | 低 | 高 |
| 后期时间步利用率 | 低效(已接近纯噪声) | 高效 |
| 高分辨率图像适用性 | 低 | 高 |
| 原始 DDPM 是否采用 | 是 | 否 |
| Improved DDPM 是否采用 | 否 | 是 |
8. 采样算法
8.1 DDPM Sampling
训练完成后,用于生成新图像的 DDPM 采样算法如下。
Algorithm 2: Sampling
─────────────────────────────────
x_T ~ N(0, I) # 从纯噪声开始
for t = T, T-1, ..., 1:
z ~ N(0, I) if t > 1, else z = 0 # 最后一步不添加噪声
x_{t-1} = 1/√α_t · (x_t - β_t/√(1-ᾱ_t) · ε_θ(x_t, t)) + σ_t · z
return x_0
8.2 逐步解读
Step 1:初始化。 从 中采样纯高斯噪声,这是生成过程的起点。
Step 2:噪声预测。 把当前带噪图像 和时间步 输入网络 ,预测 中含有的噪声。
Step 3:均值计算。 用预测出的噪声,计算 Reverse 转移的均值。
Step 4:随机转移。 在算出的均值上加上经过缩放的高斯噪声 ,生成 。在最后一步()不添加噪声。
Step 5:重复。 从 到 重复上述过程。
8.3 采样的局限
DDPM 采样最大的缺点在于速度。因为需要 步的顺序去噪,生成单张图像也需要1000 次神经网络前向传播。相比 GAN 单次前向传播,这极为缓慢,也正因如此,才催生了 DDIM、DPM-Solver 等加速采样器方面的后续研究。
9. 架构:Time-conditioned U-Net
9.1 基于 U-Net 的设计
DDPM 的噪声预测网络 以 U-Net 架构为基础。U-Net 最初是 Ronneberger 等(2015)为医学影像分割提出的结构,其特点是在 Encoder-Decoder 结构中加入 Skip Connection,从而结合不同分辨率下的特征。
DDPM 的 U-Net 以 PixelCNN++ 的结构为基础,并做了以下修改。
9.2 核心组成部分
Time Embedding:为了把时间步 注入网络,使用了 Transformer 的 Sinusoidal Positional Encoding。
这个 embedding 经过一个 MLP 后,被注入到每个 ResNet Block 中。具体来说,是先对 time embedding 做线性变换,再以相加(additive)或缩放(FiLM conditioning)的方式应用到 ResNet Block 中间的 feature map 上。
ResNet Block:每个 block 按以下顺序构成。
- Group Normalization
- SiLU(Swish)Activation
- Convolution
- 注入 Time Embedding
- Group Normalization
- SiLU Activation
- Dropout
- Convolution
- Residual Connection
Self-Attention:在 分辨率的 feature map 上应用 Multi-Head Self-Attention。把空间维度 展开成长度为 的序列,执行标准的 Scaled Dot-Product Attention。
Group Normalization:用 Group Normalization 取代 Batch Normalization。它不依赖 batch size,能为生成模型提供更稳定的训练。
9.3 具体架构规格
输入: x_t ∈ R^(C×H×W), t ∈ {1,...,T}
Encoder:
[128] → [128] → ↓2 →
[256] → [256] → ↓2 →
[256] → [256] → ↓2 → (+ Self-Attention at 16×16)
[512] → [512] → ↓2
Bottleneck:
[512] → Self-Attention → [512]
Decoder (with skip connections):
[512] → [512] → ↑2 →
[256] → [256] → ↑2 → (+ Self-Attention at 16×16)
[256] → [256] → ↑2 →
[128] → [128] → ↑2
输出: ε_θ ∈ R^(C×H×W) (与输入维度相同的预测噪声)
DDPM 在 分辨率下使用了约 114M 参数。
10. 实验结果
10.1 定量评估
DDPM 在以下基准上进行了评估。
CIFAR-10(Unconditional,):
| 模型 | FID() | IS() |
|---|---|---|
| DDPM | 3.17 | 9.46 |
| StyleGAN2 + ADA | 2.92 | 9.83 |
| NCSN | 25.32 | 8.87 |
| ProgressiveGAN | 15.52 | 8.80 |
| NVAE | 23.5 | - |
DDPM 在当时的 unconditional 生成模型中达到了 SOTA 的 FID,展现出与基于 GAN 的 StyleGAN2 可相比拟的品质水准。
LSUN():
| 数据集 | FID |
|---|---|
| LSUN Bedroom | 4.90 |
| LSUN Cat | - |
| LSUN Church | 7.89 |
10.2 定性分析
DDPM 的生成样本相较于 GAN,表现出几个明显的特点。
高多样性:GAN 因 mode collapse 问题而生成多样性受限,DDPM 则能均衡地覆盖数据分布中的各个模式。
渐进式生成:可以将从噪声到图像的渐进转化过程可视化,从中可以看到模型先形成全局结构、再补充细节的 coarse-to-fine 生成模式。
稳定的训练:不存在 GAN 固有的训练不稳定问题(mode collapse、training oscillation),仅凭简单的 MSE 损失就能稳定收敛。
10.3 Progressive Lossy Compression 解读
Ho 等人认为,DDPM 本质上实现了一种自然的渐进式有损压缩方案(Progressive Lossy Decompression)。在每一个 Reverse 步骤中,信息都是逐步被加入的,这可以看作是 Autoregressive Decoding 的一种推广。在 Rate-Distortion 曲线分析中,可以看到大部分比特被分配给了整体结构,而非感知上无关紧要的细节。
11. 后续研究总结:Diffusion 的演进
11.1 DDIM(Denoising Diffusion Implicit Models)
Song et al., 2021 | arXiv: 2010.02502
这项研究解决了 DDPM 最大的局限——缓慢的采样速度。核心思路是把 Forward Process 推广为 Non-Markovian 形式。
DDIM 使用与原来相同的已训练模型 ,只改变采样过程。
把 设为 0,就得到完全确定性(deterministic)的采样,由此可获得以下好处。
- 加速采样:只需 步,而非 步,即可生成品质相近的图像(加速 10~20 倍)
- 语义插值:由于映射是确定性的,latent space 中的插值能带来有意义的图像变换
- 一致性:从同一初始噪声出发,始终生成相同的图像,保证结果可复现
11.2 Improved DDPM
Nichol & Dhariwal, 2021 | arXiv: 2102.09672
这项研究对原始 DDPM 做了两方面改进。
可学习的方差:DDPM 把 固定为 或 ,而 Improved DDPM 让它变为可学习的。具体来说,把 参数化为 与 之间的插值。
这里 是网络输出的值。
Cosine Schedule:引入前面介绍过的 Cosine Variance Schedule,在高分辨率图像上大幅改善了训练效率。
Hybrid Loss:在 上少量加入 variational lower bound ,从而也改善了 log-likelihood。
11.3 Classifier Guidance
Dhariwal & Nichol, 2021 | arXiv: 2105.05233
这是 "Diffusion Models Beat GANs on Image Synthesis" 中提出的技术,把预训练分类器的梯度注入到 Reverse Process 中,从而实现条件生成。
这里 是 guidance scale, 是在带噪图像上训练出的分类器。增大 会降低多样性,但提高对特定类别的保真度(fidelity)。这篇论文首次让 Diffusion Model 在 FID 上超越了 GAN(CIFAR-10 FID 2.97,ImageNet 256x256 FID 4.59)。
局限:需要在带噪数据上单独训练一个分类器,这让训练流水线变得更复杂。
11.4 Classifier-Free Guidance(CFG)
Ho & Salimans, 2022 | arXiv: 2207.12598
这是一种不需要额外分类器就能获得 guidance 效果的创新技术,已成为现代 Diffusion Model 的事实标准。
其核心思路是让同一个网络同时学习条件生成与无条件生成。训练时以一定概率(通常为 10~20%)把条件信息 替换为 null token 。
推理时,把条件预测与无条件预测做线性组合。
这里 是 guidance weight。 时为标准的条件生成, 时对条件的保真度会提高。
把它重新整理,可以做如下解读。
可以理解为把无条件预测朝条件方向推, 越大,这种推力就越强。DALL-E 2、Stable Diffusion、Imagen 等几乎所有最新的 Text-to-Image 模型都在使用 CFG。
11.5 Latent Diffusion Models(LDM)/ Stable Diffusion
Rombach et al., 2022 | arXiv: 2112.10752
LDM 把 Diffusion Process 从像素空间转移到潜在空间(Latent Space)中执行,从而极大地提升了计算效率。
核心结构:
-
Perceptual Compression:用预训练 Autoencoder(VQ-VAE 或 KL-regularized VAE)的 Encoder ,把图像 压缩为低维 latent 。通常 的图像会被压缩为 的 latent(约压缩 48 倍维度)。
-
Latent Diffusion:在这个 latent space 中执行 DDPM 的 Forward/Reverse Process。相比像素空间,计算量大幅降低。
-
Cross-Attention Conditioning:通过 Cross-Attention 把文本、分割图等条件信息注入 U-Net。文本条件通常使用 CLIP 或 BERT 的 embedding。
这里 ,,, 是条件信息的编码。
Stable Diffusion 正是把这套 LDM 架构与 CLIP text encoder、大规模数据集(LAION-5B)结合训练而成的模型,已成为开源 Text-to-Image 模型事实上的标准。
11.6 Score SDE
Song et al., 2021 | arXiv: 2011.13456
这项在 ICLR 2021 上作 Oral 报告的研究,用随机微分方程(SDE)这一统一框架,把 DDPM 与 Score Matching 连接了起来。
核心贡献如下。
- Variance Exploding(VE)SDE:对应 NCSN/SMLD 系列
- Variance Preserving(VP)SDE:对应 DDPM
- Sub-VP SDE:能提供更好 likelihood 的变体
通过向连续时间的扩展,实现了精确的 log-likelihood 计算(借助 ODE)、更灵活的采样器设计,以及 Inpainting、Colorization 等条件生成。
11.7 Consistency Models
Song et al., 2023 | arXiv: 2303.01469
由 OpenAI 的 Yang Song 提出的 Consistency Models,是一次从根本上解决 Diffusion Model 多步采样问题的尝试。
其核心思路是学习一个函数 ,把 ODE trajectory 上的所有点都映射到同一个起点(原始数据)。
凭借这一 self-consistency 属性,无论从哪个时间 的带噪样本出发,都能用一次网络推理复原数据,也就是说,1-step 生成成为可能。
有两种训练方式。
- Consistency Distillation(CD):从预训练的 Diffusion Model 中蒸馏
- Consistency Training(CT):不依赖预训练,独立训练
2024 年出现了 Easy Consistency Models(ECM),以 iCT 33% 的训练成本,取得了更好的 2-step 生成性能。
11.8 Flow Matching / Rectified Flow
Lipman et al., 2023; Liu et al., 2023 | arXiv: 2210.02747, arXiv: 2209.03003
Flow Matching 是 Diffusion Model 的一种替代方案,直接学习连接数据分布与噪声分布的概率流(Probability Flow)。
核心思路:定义一条从噪声 到数据 的直线路径(straight path)。
学习沿着这条路径的速度场(velocity field)。
Rectified Flow 通过反复"拉直"这条直线路径的过程(reflow),在更少的步数下也能生成高品质的样本。
Stable Diffusion 3 采用了 Rectified Flow,伴随着从 U-Net 向 Transformer 的转变,提出了 Diffusion Model 的新范式。
11.9 DiT(Diffusion Transformer)
Peebles & Xie, 2023 | arXiv: 2212.09748
DiT 是把 Diffusion Model 的 backbone 从 U-Net 替换为 Vision Transformer(ViT)的研究。
核心设计选择:
- 把图像切分为 patch,作为 token 处理
- 用 Adaptive Layer Normalization(adaLN-Zero)注入时间步 与类别标签
- 由 层 Transformer Block 构成
DiT 与 Latent Diffusion 结合后,在 ImageNet class-conditional 生成任务上取得了 FID 2.27,超越了此前所有的 Diffusion Model。
DiT 的意义:它实证了 Transformer 的 scaling law 同样适用于 Diffusion Model。随着模型规模与训练算力的增加,性能会持续提升。这一发现直接影响了 Sora(OpenAI,视频生成)、Stable Diffusion 3 等最新大规模生成模型的架构选择。
12. PyTorch 代码示例:简单的 DDPM 实现
以下是用 PyTorch 实现的 DDPM 核心组件的简化示例。实际训练还需要更精细的 U-Net 与超参数调优。
12.1 Noise Schedule 与 Forward Process
import torch
import torch.nn as nn
import torch.nn.functional as F
import math
class DDPMScheduler:
"""管理 DDPM Forward Process 的调度器。"""
def __init__(self, num_timesteps=1000, beta_start=1e-4, beta_end=0.02, schedule='linear'):
self.num_timesteps = num_timesteps
if schedule == 'linear':
self.betas = torch.linspace(beta_start, beta_end, num_timesteps)
elif schedule == 'cosine':
self.betas = self._cosine_schedule(num_timesteps)
else:
raise ValueError(f"Unknown schedule: {schedule}")
# 预先计算核心变量
self.alphas = 1.0 - self.betas
self.alphas_cumprod = torch.cumprod(self.alphas, dim=0) # ᾱ_t
self.alphas_cumprod_prev = F.pad(self.alphas_cumprod[:-1], (1, 0), value=1.0)
# Forward process 系数
self.sqrt_alphas_cumprod = torch.sqrt(self.alphas_cumprod) # √ᾱ_t
self.sqrt_one_minus_alphas_cumprod = torch.sqrt(1.0 - self.alphas_cumprod) # √(1-ᾱ_t)
# Reverse process 系数
self.sqrt_recip_alphas = torch.sqrt(1.0 / self.alphas) # 1/√α_t
self.posterior_variance = (
self.betas * (1.0 - self.alphas_cumprod_prev) / (1.0 - self.alphas_cumprod)
) # β̃_t
def _cosine_schedule(self, timesteps, s=0.008):
steps = timesteps + 1
t = torch.linspace(0, timesteps, steps) / timesteps
alphas_cumprod = torch.cos((t + s) / (1 + s) * math.pi * 0.5) ** 2
alphas_cumprod = alphas_cumprod / alphas_cumprod[0]
betas = 1 - (alphas_cumprod[1:] / alphas_cumprod[:-1])
return torch.clip(betas, 0.0001, 0.9999)
def add_noise(self, x_0, t, noise=None):
"""Forward process: 一次性计算 q(x_t | x_0)。"""
if noise is None:
noise = torch.randn_like(x_0)
sqrt_alpha_cumprod = self.sqrt_alphas_cumprod[t].view(-1, 1, 1, 1)
sqrt_one_minus_alpha_cumprod = self.sqrt_one_minus_alphas_cumprod[t].view(-1, 1, 1, 1)
# x_t = √ᾱ_t · x_0 + √(1-ᾱ_t) · ε
x_t = sqrt_alpha_cumprod * x_0 + sqrt_one_minus_alpha_cumprod * noise
return x_t
12.2 简化版 U-Net
class SinusoidalPositionEmbedding(nn.Module):
"""Transformer 风格的 Sinusoidal Time Embedding。"""
def __init__(self, dim):
super().__init__()
self.dim = dim
def forward(self, t):
device = t.device
half_dim = self.dim // 2
emb = math.log(10000) / (half_dim - 1)
emb = torch.exp(torch.arange(half_dim, device=device) * -emb)
emb = t[:, None].float() * emb[None, :]
emb = torch.cat([emb.sin(), emb.cos()], dim=-1)
return emb
class ResBlock(nn.Module):
"""带时间条件的 Residual Block。"""
def __init__(self, in_ch, out_ch, time_emb_dim):
super().__init__()
self.norm1 = nn.GroupNorm(8, in_ch)
self.conv1 = nn.Conv2d(in_ch, out_ch, 3, padding=1)
self.time_mlp = nn.Sequential(
nn.SiLU(),
nn.Linear(time_emb_dim, out_ch),
)
self.norm2 = nn.GroupNorm(8, out_ch)
self.conv2 = nn.Conv2d(out_ch, out_ch, 3, padding=1)
self.skip = nn.Conv2d(in_ch, out_ch, 1) if in_ch != out_ch else nn.Identity()
def forward(self, x, t_emb):
h = self.conv1(F.silu(self.norm1(x)))
h = h + self.time_mlp(t_emb)[:, :, None, None] # 注入 Time embedding
h = self.conv2(F.silu(self.norm2(h)))
return h + self.skip(x) # Residual connection
class SimpleUNet(nn.Module):
"""用于 DDPM 训练的简化版 U-Net。"""
def __init__(self, in_channels=3, base_channels=64, time_emb_dim=256):
super().__init__()
# Time embedding
self.time_mlp = nn.Sequential(
SinusoidalPositionEmbedding(base_channels),
nn.Linear(base_channels, time_emb_dim),
nn.SiLU(),
nn.Linear(time_emb_dim, time_emb_dim),
)
# Encoder
self.enc1 = ResBlock(in_channels, base_channels, time_emb_dim)
self.enc2 = ResBlock(base_channels, base_channels * 2, time_emb_dim)
self.enc3 = ResBlock(base_channels * 2, base_channels * 4, time_emb_dim)
self.pool = nn.MaxPool2d(2)
# Bottleneck
self.bot = ResBlock(base_channels * 4, base_channels * 4, time_emb_dim)
# Decoder (with skip connections)
self.dec3 = ResBlock(base_channels * 8, base_channels * 2, time_emb_dim)
self.dec2 = ResBlock(base_channels * 4, base_channels, time_emb_dim)
self.dec1 = ResBlock(base_channels * 2, base_channels, time_emb_dim)
self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)
# Output
self.out = nn.Conv2d(base_channels, in_channels, 1)
def forward(self, x, t):
t_emb = self.time_mlp(t)
# Encoder
e1 = self.enc1(x, t_emb)
e2 = self.enc2(self.pool(e1), t_emb)
e3 = self.enc3(self.pool(e2), t_emb)
# Bottleneck
b = self.bot(self.pool(e3), t_emb)
# Decoder with skip connections
d3 = self.dec3(torch.cat([self.up(b), e3], dim=1), t_emb)
d2 = self.dec2(torch.cat([self.up(d3), e2], dim=1), t_emb)
d1 = self.dec1(torch.cat([self.up(d2), e1], dim=1), t_emb)
return self.out(d1) # 预测的噪声 ε_θ
12.3 训练循环
def train_ddpm(model, dataloader, scheduler, epochs=100, lr=2e-4, device='cuda'):
"""DDPM 训练循环(Algorithm 1 的实现)。"""
optimizer = torch.optim.Adam(model.parameters(), lr=lr)
model.train()
for epoch in range(epochs):
total_loss = 0
for batch_idx, (x_0, _) in enumerate(dataloader):
x_0 = x_0.to(device)
# 1. 随机选择时间步: t ~ Uniform({1, ..., T})
t = torch.randint(0, scheduler.num_timesteps, (x_0.shape[0],), device=device)
# 2. 采样噪声: ε ~ N(0, I)
noise = torch.randn_like(x_0)
# 3. Forward process: x_t = √ᾱ_t · x_0 + √(1-ᾱ_t) · ε
x_t = scheduler.add_noise(x_0, t, noise)
# 4. 预测噪声: ε_θ(x_t, t)
noise_pred = model(x_t, t)
# 5. Simplified loss: L = ||ε - ε_θ(x_t, t)||²
loss = F.mse_loss(noise_pred, noise)
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_loss += loss.item()
avg_loss = total_loss / len(dataloader)
print(f"Epoch {epoch+1}/{epochs}, Loss: {avg_loss:.4f}")
12.4 采样
@torch.no_grad()
def sample_ddpm(model, scheduler, image_shape, device='cuda'):
"""DDPM 采样(Algorithm 2 的实现)。"""
model.eval()
# x_T ~ N(0, I)
x = torch.randn(image_shape, device=device)
for t in reversed(range(scheduler.num_timesteps)):
t_batch = torch.full((image_shape[0],), t, device=device, dtype=torch.long)
# 预测噪声
predicted_noise = model(x, t_batch)
# Reverse process 系数
alpha_t = scheduler.alphas[t]
alpha_cumprod_t = scheduler.alphas_cumprod[t]
beta_t = scheduler.betas[t]
# 均值计算: μ_θ = 1/√α_t · (x_t - β_t/√(1-ᾱ_t) · ε_θ)
mean = (1.0 / torch.sqrt(alpha_t)) * (
x - (beta_t / torch.sqrt(1.0 - alpha_cumprod_t)) * predicted_noise
)
if t > 0:
# 添加随机噪声(最后一步除外)
noise = torch.randn_like(x)
sigma_t = torch.sqrt(scheduler.posterior_variance[t])
x = mean + sigma_t * noise
else:
x = mean
return x
12.5 使用示例
# 超参数
device = 'cuda' if torch.cuda.is_available() else 'cpu'
image_size = 32
batch_size = 128
num_timesteps = 1000
# 初始化调度器与模型
scheduler = DDPMScheduler(num_timesteps=num_timesteps, schedule='cosine')
model = SimpleUNet(in_channels=3, base_channels=64).to(device)
# 数据集(例如 CIFAR-10)
from torchvision import datasets, transforms
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)), # 归一化到 [-1, 1]
])
dataset = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, shuffle=True)
# 训练
train_ddpm(model, dataloader, scheduler, epochs=100, device=device)
# 采样
samples = sample_ddpm(model, scheduler, (16, 3, image_size, image_size), device=device)
# samples: [-1, 1] 范围内生成的 16 张图像
13. Diffusion Model vs GAN vs VAE:对比分析
13.1 综合对比表
| 特性 | Diffusion Model (DDPM) | GAN | VAE |
|---|---|---|---|
| 训练方式 | 噪声预测(MSE) | 对抗训练(Min-Max) | 变分推断(ELBO) |
| 训练稳定性 | 非常稳定 | 不稳定(mode collapse、oscillation) | 稳定 |
| 生成质量 | 非常高 | 非常高 | 一般(模糊) |
| 多样性 | 高(覆盖整体分布) | 低(存在 mode collapse 风险) | 高 |
| 生成速度 | 慢(1000 步) | 非常快(1 步) | 快(1 步) |
| Log-likelihood | 可计算(ELBO) | 不可计算 | 可计算(ELBO) |
| Latent Space | 隐式 | 无(或有限) | 显式、连续 |
| 模式覆盖率 | 高 | 低 | 高 |
| 条件生成 | CFG 效果非常好 | cGAN 可行 | 条件 VAE 可行 |
| 分辨率扩展 | LDM 高效 | 需要渐进式训练 | 需要层级 VAE |
| 理论基础 | 热力学、Score Matching | 博弈论 | 变分贝叶斯 |
| 代表模型 | Stable Diffusion, DALL-E 2 | StyleGAN, BigGAN | VQ-VAE-2, NVAE |
| CIFAR-10 FID | ~2.0(最新) | ~2.9(StyleGAN2) | ~23.5(NVAE) |
13.2 该如何选择模型?
适合选择 Diffusion Model 的情形:
- 生成质量与多样性都很重要时
- 需要文本-图像生成等复杂的条件生成时
- 训练稳定性很重要时
- 生成速度不是最优先考量时
适合选择 GAN 的情形:
- 需要实时生成时
- 需要特定领域的高质量图像时(人脸、风景等)
- 数据集相对较小且较为均匀时
适合选择 VAE 的情形:
- 需要有意义的 Latent Space 操控时
- 需要基于 Likelihood 的异常检测时
- 需要快速编码/解码时
- 主要目标是半监督学习或表示学习时
14. Diffusion Model 的现状与未来
14.1 2024~2025 年的主要趋势
架构转变:从 U-Net 到 Transformer。 Stable Diffusion 3、FLUX、Sora 等最新模型都采用了基于 DiT 的架构。Transformer 的 scaling law 已被证实同样适用于 Diffusion Model,模型规模扩张(8B+ 参数)正在积极推进中。
采样效率化。 得益于 Consistency Models、Flow Matching、DPM-Solver 等的发展,1~4 步生成已成为可能。Rectified Flow 通过学习直线路径,在更少的步数下也能达到高品质。
多模态扩展。 Diffusion Model 已从图像扩展到视频(Sora、Runway Gen-3)、音频(AudioLDM)、3D(DreamFusion、Zero-1-to-3)、机器人(Diffusion Policy)等多个领域。
加速与优化。 借助 Distillation、Quantization、Caching 等技术,推理速度已大幅提升,正逐步逼近可以实时生成图像的水平。
14.2 DDPM 的历史意义
DDPM 在生成模型的历史上是一个转折点,体现在以下几个方面。
- 在由 GAN 主导的图像生成领域,实证了基于 Likelihood 的模型的竞争力
- 展示了用极其简单的训练目标()也能实现高质量生成
- 建立了连接热力学与 Score Matching 的理论框架
- 成为 Stable Diffusion、DALL-E 2、Midjourney 等现代 AI 革命的直接基础
15. References
-
Ho, J., Jain, A., & Abbeel, P. (2020). Denoising Diffusion Probabilistic Models. NeurIPS 2020. arXiv:2006.11239
-
Sohl-Dickstein, J., Weiss, E., Maheswaranathan, N., & Ganguli, S. (2015). Deep Unsupervised Learning using Nonequilibrium Thermodynamics. ICML 2015. arXiv:1503.03585
-
Song, J., Meng, C., & Ermon, S. (2021). Denoising Diffusion Implicit Models (DDIM). ICLR 2021. arXiv:2010.02502
-
Nichol, A. & Dhariwal, P. (2021). Improved Denoising Diffusion Probabilistic Models. ICML 2021. arXiv:2102.09672
-
Dhariwal, P. & Nichol, A. (2021). Diffusion Models Beat GANs on Image Synthesis. NeurIPS 2021. arXiv:2105.05233
-
Ho, J. & Salimans, T. (2022). Classifier-Free Diffusion Guidance. NeurIPS Workshop 2021. arXiv:2207.12598
-
Rombach, R., Blattmann, A., Lorenz, D., Esser, P., & Ommer, B. (2022). High-Resolution Image Synthesis with Latent Diffusion Models. CVPR 2022. arXiv:2112.10752
-
Song, Y., Sohl-Dickstein, J., Kingma, D.P., Kumar, A., Ermon, S., & Poole, B. (2021). Score-Based Generative Modeling through Stochastic Differential Equations. ICLR 2021. arXiv:2011.13456
-
Song, Y., Dhariwal, P., Chen, M., & Sutskever, I. (2023). Consistency Models. ICML 2023. arXiv:2303.01469
-
Lipman, Y., Chen, R.T.Q., Ben-Hamu, H., Nickel, M., & Le, M. (2023). Flow Matching for Generative Modeling. ICLR 2023. arXiv:2210.02747
-
Peebles, W. & Xie, S. (2023). Scalable Diffusion Models with Transformers (DiT). ICCV 2023. arXiv:2212.09748
-
Song, Y. & Ermon, S. (2019). Generative Modeling by Estimating Gradients of the Data Distribution. NeurIPS 2019. arXiv:1907.05600
-
Weng, L. (2021). What are Diffusion Models? lilianweng.github.io
-
Hugging Face. The Annotated Diffusion Model. huggingface.co/blog/annotated-diffusion
현재 단락 (1/561)
"Denoising Diffusion Probabilistic Models"(DDPM)是 2020 年在 NeurIPS 上发表的论文,由 UC Berkeley 的 **Jonathan ...