Skip to content
Published on

DDPM 论文完全解析:从噪声生成图像的扩散模型的数学与原理

分享
Authors

1. 论文概要

"Denoising Diffusion Probabilistic Models"(DDPM)是 2020 年在 NeurIPS 上发表的论文,由 UC Berkeley 的 Jonathan HoAjay JainPieter Abbeel 共同撰写。这篇论文以实证方式证明了通过扩散概率模型(Diffusion Probabilistic Model)可以实现高质量图像合成,是一项具有里程碑意义的研究。

核心思路出奇地简单。学习一个对数据逐步添加高斯噪声的 Forward Process,以及逐步去除该噪声、从而复原原始数据的 Reverse Process。最终的训练目标归结为"模型预测的噪声"与"实际添加的噪声"之间的简单 MSE 损失

DDPM 在 CIFAR-10 上取得了 FID 3.17Inception Score 9.46 的成绩,展现出与当时基于 GAN 的模型相当甚至更优的性能。更重要的是,这篇论文成为了此后 DALL-E 2ImagenStable DiffusionMidjourney 等现代图像生成 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:具有复杂结构的状态 \rightarrow 无序的平衡状态(信息的破坏)
  • Reverse:从平衡状态 \rightarrow 恢复为具有结构的状态(信息的生成)

Sohl-Dickstein 等(2015)首次将这一思路应用于机器学习,发表了 "Deep Unsupervised Learning using Nonequilibrium Thermodynamics"。其思路是:定义一个将复杂数据分布转换为简单已知分布(高斯分布)的扩散过程,再学习其逆过程,就得到一个生成模型。

2.2 与 Score Matching 的联系

Diffusion Model 的另一条理论支柱是 Score Matching。Score function 定义为对数概率密度的梯度。

xlogp(x)\nabla_x \log p(x)

如果能够估计出这一 score function,就可以通过 Langevin Dynamics 生成样本。

xt+1=xt+ϵ2xlogp(xt)+ϵz,zN(0,I)x_{t+1} = x_t + \frac{\epsilon}{2} \nabla_x \log p(x_t) + \sqrt{\epsilon} \, z, \quad z \sim \mathcal{N}(0, I)

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 描述如下。

dx=f(x,t)dt+g(t)dwdx = f(x, t) \, dt + g(t) \, dw

这里 ff 是 drift coefficient,gg 是 diffusion coefficient,ww 是标准 Wiener process。与该 SDE 对应的 Reverse-time SDE 存在如下形式。

dx=[f(x,t)g(t)2xlogpt(x)]dt+g(t)dwˉdx = \left[ f(x, t) - g(t)^2 \nabla_x \log p_t(x) \right] dt + g(t) \, d\bar{w}

关键在于,求解反向 SDE 所需要的,仅仅是随时间变化的 score function xlogpt(x)\nabla_x \log p_t(x)。DDPM 的噪声预测网络 ϵθ\epsilon_\theta 实质上等价于对这一 score function 的估计。

ϵθ(xt,t)1αˉtxtlogp(xt)\epsilon_\theta(x_t, t) \approx -\sqrt{1 - \bar{\alpha}_t} \, \nabla_{x_t} \log p(x_t)

这一关系正是从理论上统一 DDPM 与 Score Matching 的关键纽带。


3. Forward Process:系统性地添加噪声

3.1 作为 Markov Chain 的 Forward Process

Forward Process(或称 Diffusion Process)是对原始数据 x0x_0 逐步添加高斯噪声的固定 Markov Chain。它没有可学习的参数,完全由预先定义好的 Variance Schedule {β1,β2,...,βT}\{\beta_1, \beta_2, ..., \beta_T\} 决定。

每个时间步 tt 的转移概率定义如下。

q(xtxt1)=N(xt;1βtxt1,βtI)q(x_t | x_{t-1}) = \mathcal{N}(x_t; \sqrt{1 - \beta_t} \, x_{t-1}, \, \beta_t I)

展开来说,每一步都把上一时刻的数据缩放 1βt\sqrt{1 - \beta_t} 倍,再加上方差为 βt\beta_t 的高斯噪声。

xt=1βtxt1+βtϵt1,ϵt1N(0,I)x_t = \sqrt{1 - \beta_t} \, x_{t-1} + \sqrt{\beta_t} \, \epsilon_{t-1}, \quad \epsilon_{t-1} \sim \mathcal{N}(0, I)

为什么要用 1βt\sqrt{1 - \beta_t} 来缩放? 是为了让每一步的总方差保持不变。若 xt1x_{t-1} 的方差为 1,则 1βtxt1\sqrt{1-\beta_t} \cdot x_{t-1} 的方差为 1βt1-\beta_t,再加上方差为 βt\beta_t 的噪声后,总方差就变为 (1βt)+βt=1(1-\beta_t) + \beta_t = 1

TT 足够大、且 βt\beta_t 设置得当时,xTx_T 会收敛到近乎纯粹的各向同性高斯噪声 N(0,I)\mathcal{N}(0, I)

3.2 完整 Forward Process

跨越 TT 步的整个 Forward Process 的联合分布如下。

q(x1:Tx0)=t=1Tq(xtxt1)q(x_{1:T} | x_0) = \prod_{t=1}^{T} q(x_t | x_{t-1})

这是由 Markov 性质决定的,即每一步都只依赖于紧邻的前一步。DDPM 中使用 T=1000T = 1000βt\beta_tβ1=104\beta_1 = 10^{-4} 线性递增βT=0.02\beta_T = 0.02


4. 核心数学:Reparameterization Trick

4.1 一步跳到任意时间 tt

Forward Process 最强大的数学性质在于:可以不经过中间步骤,直接x0x_0 计算出任意时间 tt 下的 xtx_t。这正是让训练变得高效的关键。

先定义记号。

αt=1βt,αˉt=s=1tαs\alpha_t = 1 - \beta_t, \qquad \bar{\alpha}_t = \prod_{s=1}^{t} \alpha_s

αˉt\bar{\alpha}_tαs\alpha_s 的累乘,表示到时间 tt 为止原始信号还保留了多少。

4.2 推导过程

x1x_1 开始,用归纳法推导。

x1=α1x0+1α1ϵ0x_1 = \sqrt{\alpha_1} \, x_0 + \sqrt{1 - \alpha_1} \, \epsilon_0 x2=α2x1+1α2ϵ1x_2 = \sqrt{\alpha_2} \, x_1 + \sqrt{1 - \alpha_2} \, \epsilon_1

x1x_1 代入 x2x_2,得到

x2=α2(α1x0+1α1ϵ0)+1α2ϵ1x_2 = \sqrt{\alpha_2} \left( \sqrt{\alpha_1} \, x_0 + \sqrt{1 - \alpha_1} \, \epsilon_0 \right) + \sqrt{1 - \alpha_2} \, \epsilon_1 =α1α2x0+α2(1α1)ϵ0+1α2ϵ1= \sqrt{\alpha_1 \alpha_2} \, x_0 + \sqrt{\alpha_2(1-\alpha_1)} \, \epsilon_0 + \sqrt{1-\alpha_2} \, \epsilon_1

这里要用到独立高斯分布之和的法则:两个独立的高斯分布 N(0,σ12I)\mathcal{N}(0, \sigma_1^2 I)N(0,σ22I)\mathcal{N}(0, \sigma_2^2 I) 之和服从 N(0,(σ12+σ22)I)\mathcal{N}(0, (\sigma_1^2 + \sigma_2^2)I)

把噪声项的方差相加,得到

α2(1α1)+(1α2)=α2α1α2+1α2=1α1α2=1αˉ2\alpha_2(1-\alpha_1) + (1-\alpha_2) = \alpha_2 - \alpha_1\alpha_2 + 1 - \alpha_2 = 1 - \alpha_1\alpha_2 = 1 - \bar{\alpha}_2

因此,

x2=αˉ2x0+1αˉ2ϵ,ϵN(0,I)x_2 = \sqrt{\bar{\alpha}_2} \, x_0 + \sqrt{1 - \bar{\alpha}_2} \, \epsilon, \quad \epsilon \sim \mathcal{N}(0, I)

将其一般化,可得到如下结果。

4.3 最终结果:Closed-form Expression

q(xtx0)=N(xt;αˉtx0,(1αˉt)I)\boxed{q(x_t | x_0) = \mathcal{N}(x_t; \sqrt{\bar{\alpha}_t} \, x_0, \, (1 - \bar{\alpha}_t) I)}

也就是说,任意时间 tt 下的 xtx_t 可以一次性采样得到,如下所示。

xt=αˉtx0+1αˉtϵ,ϵN(0,I)x_t = \sqrt{\bar{\alpha}_t} \, x_0 + \sqrt{1 - \bar{\alpha}_t} \, \epsilon, \quad \epsilon \sim \mathcal{N}(0, I)

对这个式子做直观解读,如下表所示。

含义随时间的变化
αˉtx0\sqrt{\bar{\alpha}_t} \, x_0原始信号(signal)tt \uparrowαˉt\bar{\alpha}_t \downarrow,信号减弱
1αˉtϵ\sqrt{1 - \bar{\alpha}_t} \, \epsilon新加入的噪声tt \uparrow1αˉt1-\bar{\alpha}_t \uparrow,噪声增强

t=0t = 0αˉ0=1\bar{\alpha}_0 = 1,故等于 x0x_0 本身;t=Tt = TαˉT0\bar{\alpha}_T \approx 0,故几乎为纯噪声。这种 Signal-to-Noise Ratio(SNR)的逐步下降,正是 Forward Process 的本质。

SNR(t)=αˉt1αˉt\text{SNR}(t) = \frac{\bar{\alpha}_t}{1 - \bar{\alpha}_t}

5. Reverse Process:从噪声中复原图像

5.1 Reverse Process 的定义

Reverse Process 是从纯噪声 xTN(0,I)x_T \sim \mathcal{N}(0, I) 出发,逐步去除噪声、生成数据 x0x_0 的过程。核心假设是:如果 Forward Process 的每一步都是微小的高斯扰动,那么它的逆过程也可以用高斯来近似。(在 βt\beta_t 足够小的前提下)

pθ(x0:T)=p(xT)t=1Tpθ(xt1xt)p_\theta(x_{0:T}) = p(x_T) \prod_{t=1}^{T} p_\theta(x_{t-1} | x_t) pθ(xt1xt)=N(xt1;μθ(xt,t),Σθ(xt,t))p_\theta(x_{t-1} | x_t) = \mathcal{N}(x_{t-1}; \mu_\theta(x_t, t), \Sigma_\theta(x_t, t))

这里 μθ\mu_\thetaΣθ\Sigma_\theta 是神经网络需要学习的均值方差。DDPM 并不学习方差 Σθ\Sigma_\theta,而是将其固定为 σt2I\sigma_t^2 I,使用 σt2=βt\sigma_t^2 = \beta_tσt2=β~t=1αˉt11αˉtβt\sigma_t^2 = \tilde{\beta}_t = \frac{1-\bar{\alpha}_{t-1}}{1-\bar{\alpha}_t} \beta_t

5.2 Posterior q(xt1xt,x0)q(x_{t-1}|x_t, x_0) 的推导

训练的核心在于:给定 x0x_0 时的反向条件分布(posterior)可以用闭式(closed form)计算出来。应用贝叶斯定理,

q(xt1xt,x0)=q(xtxt1,x0)q(xt1x0)q(xtx0)q(x_{t-1} | x_t, x_0) = \frac{q(x_t | x_{t-1}, x_0) \, q(x_{t-1} | x_0)}{q(x_t | x_0)}

由 Markov 性质可知 q(xtxt1,x0)=q(xtxt1)q(x_t|x_{t-1}, x_0) = q(x_t|x_{t-1}),因此右边三项都是高斯分布。高斯分布的乘积仍是高斯分布,把指数部分展开、按 xt1x_{t-1} 整理成二次式,可得到

q(xt1xt,x0)=N(xt1;μ~t(xt,x0),β~tI)q(x_{t-1} | x_t, x_0) = \mathcal{N}(x_{t-1}; \tilde{\mu}_t(x_t, x_0), \tilde{\beta}_t I)

这里 posterior 均值为,

μ~t(xt,x0)=αˉt1βt1αˉtx0+αt(1αˉt1)1αˉtxt\tilde{\mu}_t(x_t, x_0) = \frac{\sqrt{\bar{\alpha}_{t-1}} \beta_t}{1 - \bar{\alpha}_t} x_0 + \frac{\sqrt{\alpha_t}(1 - \bar{\alpha}_{t-1})}{1 - \bar{\alpha}_t} x_t

posterior 方差为,

β~t=1αˉt11αˉtβt\tilde{\beta}_t = \frac{1 - \bar{\alpha}_{t-1}}{1 - \bar{\alpha}_t} \beta_t

5.3 用 ϵ\epsilon 替换 x0x_0

模型无法直接知道 x0x_0,因此把 Reparameterization 公式 xt=αˉtx0+1αˉtϵx_t = \sqrt{\bar{\alpha}_t} x_0 + \sqrt{1-\bar{\alpha}_t} \epsilon 反解出 x0x_0

x0=1αˉt(xt1αˉtϵ)x_0 = \frac{1}{\sqrt{\bar{\alpha}_t}} \left( x_t - \sqrt{1-\bar{\alpha}_t} \, \epsilon \right)

把这个结果代入 posterior 均值 μ~t\tilde{\mu}_t,得到

μ~t=1αt(xtβt1αˉtϵ)\tilde{\mu}_t = \frac{1}{\sqrt{\alpha_t}} \left( x_t - \frac{\beta_t}{\sqrt{1-\bar{\alpha}_t}} \, \epsilon \right)

只要模型学习到一个预测噪声 ϵ\epsilon 的网络 ϵθ(xt,t)\epsilon_\theta(x_t, t),Reverse Process 的均值就可以按下式计算。

μθ(xt,t)=1αt(xtβt1αˉtϵθ(xt,t))\mu_\theta(x_t, t) = \frac{1}{\sqrt{\alpha_t}} \left( x_t - \frac{\beta_t}{\sqrt{1-\bar{\alpha}_t}} \, \epsilon_\theta(x_t, t) \right)

这就是为什么在 DDPM 的 Reverse Process 中,预测噪声等价于预测均值


6. 训练目标的推导:从 ELBO 到 Simplified Loss

6.1 最大似然与 ELBO

生成模型的终极目标是最大化数据的对数似然 logpθ(x0)\log p_\theta(x_0)。但这个量难以直接计算,因此转而优化变分下界(Evidence Lower Bound, ELBO)。

应用 Jensen 不等式,

logpθ(x0)Eq(x1:Tx0)[logpθ(x0:T)q(x1:Tx0)]=ELBO\log p_\theta(x_0) \geq \mathbb{E}_{q(x_{1:T}|x_0)} \left[ \log \frac{p_\theta(x_{0:T})}{q(x_{1:T}|x_0)} \right] = \text{ELBO}

6.2 ELBO 的分解

把 ELBO 分解为 KL divergence 各项,如下所示。

ELBO=Eq[logpθ(x0x1)]L0:Reconstruction termDKL(q(xTx0)p(xT))LT:Prior matching termt=2TEq[DKL(q(xt1xt,x0)pθ(xt1xt))]Lt1:Denoising matching term\text{ELBO} = \underbrace{\mathbb{E}_q[\log p_\theta(x_0 | x_1)]}_{L_0: \text{Reconstruction term}} - \underbrace{D_{\text{KL}}(q(x_T | x_0) \| p(x_T))}_{L_T: \text{Prior matching term}} - \sum_{t=2}^{T} \underbrace{\mathbb{E}_q \left[ D_{\text{KL}}(q(x_{t-1}|x_t, x_0) \| p_\theta(x_{t-1}|x_t)) \right]}_{L_{t-1}: \text{Denoising matching term}}

各项的含义如下。

LTL_T(Prior Matching):衡量 q(xTx0)q(x_T|x_0) 与先验分布 p(xT)=N(0,I)p(x_T) = \mathcal{N}(0, I) 之间的一致程度。当 TT 足够大时,该项收敛到 0,且不含可学习参数,因此作为常数被忽略

L0L_0(Reconstruction):衡量从 x1x_1 复原 x0x_0 的能力。由于 x0x_0x1x_1 非常相近,它对整体训练的影响很小。

Lt1L_{t-1}(Denoising Matching):衡量模型的 Reverse 转移 pθ(xt1xt)p_\theta(x_{t-1}|x_t) 与真实 posterior q(xt1xt,x0)q(x_{t-1}|x_t, x_0) 之间的一致程度,是核心的训练信号

6.3 KL Divergence 的计算

两个高斯分布之间的 KL divergence 可以用闭式计算。由于 q(xt1xt,x0)=N(μ~t,β~tI)q(x_{t-1}|x_t, x_0) = \mathcal{N}(\tilde{\mu}_t, \tilde{\beta}_t I)pθ(xt1xt)=N(μθ,σt2I)p_\theta(x_{t-1}|x_t) = \mathcal{N}(\mu_\theta, \sigma_t^2 I),因此

DKL(qpθ)=12σt2μ~t(xt,x0)μθ(xt,t)2+CD_{\text{KL}}(q \| p_\theta) = \frac{1}{2\sigma_t^2} \|\tilde{\mu}_t(x_t, x_0) - \mu_\theta(x_t, t)\|^2 + C

这里 CC 是与方差相关的常数项。若把方差固定,则训练目标只剩下均值之差

6.4 向噪声预测的再参数化

把前面推导出的 μ~t\tilde{\mu}_tμθ\mu_\theta 的表达式代入,

μ~tμθ2=βt2(1αˉt)αtϵϵθ(xt,t)2\|\tilde{\mu}_t - \mu_\theta\|^2 = \frac{\beta_t^2}{(1-\bar{\alpha}_t)\alpha_t} \|\epsilon - \epsilon_\theta(x_t, t)\|^2

去掉权重系数后得到的 Simplified Loss 如下。

Lsimple=Et,x0,ϵ[ϵϵθ(xt,t)2]\boxed{L_{\text{simple}} = \mathbb{E}_{t, x_0, \epsilon} \left[ \|\epsilon - \epsilon_\theta(x_t, t)\|^2 \right]}

这里 tUniform({1,...,T})t \sim \text{Uniform}(\{1, ..., T\})x0q(x0)x_0 \sim q(x_0)ϵN(0,I)\epsilon \sim \mathcal{N}(0, I)

这正是 DDPM 最重要的贡献。从复杂的 ELBO 出发,最终抵达"真实噪声 ϵ\epsilon 与预测噪声 ϵθ\epsilon_\theta 之间的 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. 噪声调度:βt\beta_t 的设计

7.1 Linear Schedule(DDPM 原始方案)

Ho 等人使用了让 βt\beta_tβ1=104\beta_1 = 10^{-4} 线性递增βT=0.02\beta_T = 0.02 的调度方案。

βt=β1+t1T1(βTβ1)\beta_t = \beta_1 + \frac{t-1}{T-1}(\beta_T - \beta_1)

这一调度方案的直观思路是:初期添加较小的噪声,缓慢破坏数据结构;后期添加更大的噪声,快速收敛到高斯分布。

7.2 Linear Schedule 的问题

Nichol & Dhariwal(2021,"Improved Denoising Diffusion Probabilistic Models")指出了 Linear Schedule 的两个问题。

第一,早期信息破坏得太快。 αˉt\bar{\alpha}_t 在早期急剧下降,即使在 tt 取较小值时也已经加入了相当多的噪声。这对高分辨率图像来说尤其成问题。

第二,后期时间步被浪费。tt 取较大值时,αˉt0\bar{\alpha}_t \approx 0xtx_t 已经近乎纯噪声,对训练贡献不了多少有意义的信号。

7.3 Cosine Schedule

Nichol & Dhariwal 提出的 Cosine Schedule 直接定义了 αˉt\bar{\alpha}_t

αˉt=f(t)f(0),f(t)=cos(t/T+s1+sπ2)2\bar{\alpha}_t = \frac{f(t)}{f(0)}, \qquad f(t) = \cos\left(\frac{t/T + s}{1 + s} \cdot \frac{\pi}{2}\right)^2

这里 s=0.008s = 0.008 是一个较小的偏移量,用于防止 βt\beta_tt=0t=0 附近变得过小。

Cosine Schedule 的核心特性如下。

  • αˉt\bar{\alpha}_t中段近乎线性地下降,在所有时间步上都能提供同样有用的训练信号
  • 防止早期加入过多噪声,从而保留精细的细节
  • 在后期也能平滑地过渡到完全的噪声
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 ScheduleCosine Schedule
αˉt\bar{\alpha}_t 下降模式早期骤降,后期平缓中段近乎线性
早期信息保留
后期时间步利用率低效(已接近纯噪声)高效
高分辨率图像适用性
原始 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:初始化。xTN(0,I)x_T \sim \mathcal{N}(0, I) 中采样纯高斯噪声,这是生成过程的起点。

Step 2:噪声预测。 把当前带噪图像 xtx_t 和时间步 tt 输入网络 ϵθ\epsilon_\theta,预测 xtx_t 中含有的噪声。

Step 3:均值计算。 用预测出的噪声,计算 Reverse 转移的均值。

μθ(xt,t)=1αt(xtβt1αˉtϵθ(xt,t))\mu_\theta(x_t, t) = \frac{1}{\sqrt{\alpha_t}} \left( x_t - \frac{\beta_t}{\sqrt{1-\bar{\alpha}_t}} \epsilon_\theta(x_t, t) \right)

Step 4:随机转移。 在算出的均值上加上经过缩放的高斯噪声 σtz\sigma_t z,生成 xt1x_{t-1}。在最后一步(t=1t=1)不添加噪声。

Step 5:重复。t=Tt = Tt=1t = 1 重复上述过程。

8.3 采样的局限

DDPM 采样最大的缺点在于速度。因为需要 T=1000T = 1000 步的顺序去噪,生成单张图像也需要1000 次神经网络前向传播。相比 GAN 单次前向传播,这极为缓慢,也正因如此,才催生了 DDIM、DPM-Solver 等加速采样器方面的后续研究。


9. 架构:Time-conditioned U-Net

9.1 基于 U-Net 的设计

DDPM 的噪声预测网络 ϵθ(xt,t)\epsilon_\theta(x_t, t)U-Net 架构为基础。U-Net 最初是 Ronneberger 等(2015)为医学影像分割提出的结构,其特点是在 Encoder-Decoder 结构中加入 Skip Connection,从而结合不同分辨率下的特征。

DDPM 的 U-Net 以 PixelCNN++ 的结构为基础,并做了以下修改。

9.2 核心组成部分

Time Embedding:为了把时间步 tt 注入网络,使用了 Transformer 的 Sinusoidal Positional Encoding

TE(t)2i=sin(t100002i/d),TE(t)2i+1=cos(t100002i/d)\text{TE}(t)_{2i} = \sin\left(\frac{t}{10000^{2i/d}}\right), \quad \text{TE}(t)_{2i+1} = \cos\left(\frac{t}{10000^{2i/d}}\right)

这个 embedding 经过一个 MLP 后,被注入到每个 ResNet Block 中。具体来说,是先对 time embedding 做线性变换,再以相加(additive)或缩放(FiLM conditioning)的方式应用到 ResNet Block 中间的 feature map 上。

ResNet Block:每个 block 按以下顺序构成。

  1. Group Normalization
  2. SiLU(Swish)Activation
  3. Convolution
  4. 注入 Time Embedding
  5. Group Normalization
  6. SiLU Activation
  7. Dropout
  8. Convolution
  9. Residual Connection

Self-Attention:在 16×1616 \times 16 分辨率的 feature map 上应用 Multi-Head Self-Attention。把空间维度 (h,w)(h, w) 展开成长度为 h×wh \times w 的序列,执行标准的 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 在 256×256256 \times 256 分辨率下使用了约 114M 参数


10. 实验结果

10.1 定量评估

DDPM 在以下基准上进行了评估。

CIFAR-10(Unconditional,32×3232 \times 32)

模型FID(\downarrow)IS(\uparrow)
DDPM3.179.46
StyleGAN2 + ADA2.929.83
NCSN25.328.87
ProgressiveGAN15.528.80
NVAE23.5-

DDPM 在当时的 unconditional 生成模型中达到了 SOTA 的 FID,展现出与基于 GAN 的 StyleGAN2 可相比拟的品质水准。

LSUN(256×256256 \times 256)

数据集FID
LSUN Bedroom4.90
LSUN Cat-
LSUN Church7.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 使用与原来相同的已训练模型 ϵθ\epsilon_\theta,只改变采样过程。

xt1=αˉt1(xt1αˉtϵθ(xt,t)αˉt)predicted x0+1αˉt1σt2ϵθ(xt,t)+σtϵtx_{t-1} = \sqrt{\bar{\alpha}_{t-1}} \underbrace{\left( \frac{x_t - \sqrt{1-\bar{\alpha}_t} \, \epsilon_\theta(x_t, t)}{\sqrt{\bar{\alpha}_t}} \right)}_{\text{predicted } x_0} + \sqrt{1-\bar{\alpha}_{t-1} - \sigma_t^2} \cdot \epsilon_\theta(x_t, t) + \sigma_t \epsilon_t

σt\sigma_t 设为 0,就得到完全确定性(deterministic)的采样,由此可获得以下好处。

  • 加速采样:只需 5010050 \sim 100 步,而非 T=1000T=1000 步,即可生成品质相近的图像(加速 10~20 倍)
  • 语义插值:由于映射是确定性的,latent space 中的插值能带来有意义的图像变换
  • 一致性:从同一初始噪声出发,始终生成相同的图像,保证结果可复现

11.2 Improved DDPM

Nichol & Dhariwal, 2021 | arXiv: 2102.09672

这项研究对原始 DDPM 做了两方面改进。

可学习的方差:DDPM 把 σt2\sigma_t^2 固定为 βt\beta_tβ~t\tilde{\beta}_t,而 Improved DDPM 让它变为可学习的。具体来说,把 σt2\sigma_t^2 参数化为 βt\beta_tβ~t\tilde{\beta}_t 之间的插值。

Σθ(xt,t)=exp(vlogβt+(1v)logβ~t)\Sigma_\theta(x_t, t) = \exp(v \log \beta_t + (1-v) \log \tilde{\beta}_t)

这里 vv 是网络输出的值。

Cosine Schedule:引入前面介绍过的 Cosine Variance Schedule,在高分辨率图像上大幅改善了训练效率。

Hybrid Loss:在 LsimpleL_\text{simple} 上少量加入 variational lower bound LvlbL_\text{vlb},从而也改善了 log-likelihood。

Lhybrid=Lsimple+λLvlbL_\text{hybrid} = L_\text{simple} + \lambda L_\text{vlb}

11.3 Classifier Guidance

Dhariwal & Nichol, 2021 | arXiv: 2105.05233

这是 "Diffusion Models Beat GANs on Image Synthesis" 中提出的技术,把预训练分类器的梯度注入到 Reverse Process 中,从而实现条件生成。

ϵ^θ(xt,t,y)=ϵθ(xt,t)s1αˉtxtlogpϕ(yxt)\hat{\epsilon}_\theta(x_t, t, y) = \epsilon_\theta(x_t, t) - s \cdot \sqrt{1-\bar{\alpha}_t} \cdot \nabla_{x_t} \log p_\phi(y|x_t)

这里 ss 是 guidance scale,pϕp_\phi 是在带噪图像上训练出的分类器。增大 ss降低多样性,但提高对特定类别的保真度(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%)把条件信息 cc 替换为 null token \varnothing

推理时,把条件预测与无条件预测做线性组合。

ϵ^θ(xt,t,c)=(1+w)ϵθ(xt,t,c)wϵθ(xt,t,)\hat{\epsilon}_\theta(x_t, t, c) = (1 + w) \cdot \epsilon_\theta(x_t, t, c) - w \cdot \epsilon_\theta(x_t, t, \varnothing)

这里 ww 是 guidance weight。w=0w = 0 时为标准的条件生成,w>0w > 0 时对条件的保真度会提高。

把它重新整理,可以做如下解读。

ϵ^θ=ϵθ(xt,t,)+(1+w)(ϵθ(xt,t,c)ϵθ(xt,t,))向条件方向的移动\hat{\epsilon}_\theta = \epsilon_\theta(x_t, t, \varnothing) + (1 + w) \cdot \underbrace{(\epsilon_\theta(x_t, t, c) - \epsilon_\theta(x_t, t, \varnothing))}_{\text{向条件方向的移动}}

可以理解为把无条件预测朝条件方向推ww 越大,这种推力就越强。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)中执行,从而极大地提升了计算效率。

核心结构:

  1. Perceptual Compression:用预训练 Autoencoder(VQ-VAE 或 KL-regularized VAE)的 Encoder E\mathcal{E},把图像 xx 压缩为低维 latent z=E(x)z = \mathcal{E}(x)。通常 256×256×3256 \times 256 \times 3 的图像会被压缩为 32×32×432 \times 32 \times 4 的 latent(约压缩 48 倍维度)。

  2. Latent Diffusion:在这个 latent space 中执行 DDPM 的 Forward/Reverse Process。相比像素空间,计算量大幅降低。

  3. Cross-Attention Conditioning:通过 Cross-Attention 把文本、分割图等条件信息注入 U-Net。文本条件通常使用 CLIP 或 BERT 的 embedding。

Attention(Q,K,V)=softmax(QKTd)V\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d}}\right) V

这里 Q=WQφ(zt)Q = W_Q \cdot \varphi(z_t)K=WKτθ(y)K = W_K \cdot \tau_\theta(y)V=WVτθ(y)V = W_V \cdot \tau_\theta(y)τθ(y)\tau_\theta(y) 是条件信息的编码。

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 的变体
VP-SDE:dx=12β(t)xdt+β(t)dw\text{VP-SDE}: \quad dx = -\frac{1}{2}\beta(t) x \, dt + \sqrt{\beta(t)} \, dw

通过向连续时间的扩展,实现了精确的 log-likelihood 计算(借助 ODE)、更灵活的采样器设计,以及 Inpainting、Colorization 等条件生成

11.7 Consistency Models

Song et al., 2023 | arXiv: 2303.01469

由 OpenAI 的 Yang Song 提出的 Consistency Models,是一次从根本上解决 Diffusion Model 多步采样问题的尝试。

其核心思路是学习一个函数 fθf_\theta,把 ODE trajectory 上的所有点都映射到同一个起点(原始数据)

fθ(xt,t)=x0,t[0,T]f_\theta(x_t, t) = x_0, \quad \forall t \in [0, T]

凭借这一 self-consistency 属性,无论从哪个时间 tt 的带噪样本出发,都能用一次网络推理复原数据,也就是说,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)。

核心思路:定义一条从噪声 x1N(0,I)x_1 \sim \mathcal{N}(0, I) 到数据 x0x_0直线路径(straight path)。

xt=(1t)x0+tϵ,t[0,1]x_t = (1-t) x_0 + t \, \epsilon, \quad t \in [0, 1]

学习沿着这条路径的速度场(velocity field)vθ(xt,t)v_\theta(x_t, t)

LFM=Et,x0,ϵ[vθ(xt,t)(x0ϵ)2]L_{\text{FM}} = \mathbb{E}_{t, x_0, \epsilon} \left[ \| v_\theta(x_t, t) - (x_0 - \epsilon) \|^2 \right]

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)注入时间步 tt 与类别标签 yy
  • LL 层 Transformer Block 构成

DiT 与 Latent Diffusion 结合后,在 ImageNet 256×256256 \times 256 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)GANVAE
训练方式噪声预测(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 2StyleGAN, BigGANVQ-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 在生成模型的历史上是一个转折点,体现在以下几个方面。

  1. 在由 GAN 主导的图像生成领域,实证了基于 Likelihood 的模型的竞争力
  2. 展示了用极其简单的训练目标(LsimpleL_\text{simple})也能实现高质量生成
  3. 建立了连接热力学与 Score Matching 的理论框架
  4. 成为 Stable Diffusion、DALL-E 2、Midjourney 等现代 AI 革命的直接基础

15. References

  1. Ho, J., Jain, A., & Abbeel, P. (2020). Denoising Diffusion Probabilistic Models. NeurIPS 2020. arXiv:2006.11239

  2. Sohl-Dickstein, J., Weiss, E., Maheswaranathan, N., & Ganguli, S. (2015). Deep Unsupervised Learning using Nonequilibrium Thermodynamics. ICML 2015. arXiv:1503.03585

  3. Song, J., Meng, C., & Ermon, S. (2021). Denoising Diffusion Implicit Models (DDIM). ICLR 2021. arXiv:2010.02502

  4. Nichol, A. & Dhariwal, P. (2021). Improved Denoising Diffusion Probabilistic Models. ICML 2021. arXiv:2102.09672

  5. Dhariwal, P. & Nichol, A. (2021). Diffusion Models Beat GANs on Image Synthesis. NeurIPS 2021. arXiv:2105.05233

  6. Ho, J. & Salimans, T. (2022). Classifier-Free Diffusion Guidance. NeurIPS Workshop 2021. arXiv:2207.12598

  7. Rombach, R., Blattmann, A., Lorenz, D., Esser, P., & Ommer, B. (2022). High-Resolution Image Synthesis with Latent Diffusion Models. CVPR 2022. arXiv:2112.10752

  8. 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

  9. Song, Y., Dhariwal, P., Chen, M., & Sutskever, I. (2023). Consistency Models. ICML 2023. arXiv:2303.01469

  10. Lipman, Y., Chen, R.T.Q., Ben-Hamu, H., Nickel, M., & Le, M. (2023). Flow Matching for Generative Modeling. ICLR 2023. arXiv:2210.02747

  11. Peebles, W. & Xie, S. (2023). Scalable Diffusion Models with Transformers (DiT). ICCV 2023. arXiv:2212.09748

  12. Song, Y. & Ermon, S. (2019). Generative Modeling by Estimating Gradients of the Data Distribution. NeurIPS 2019. arXiv:1907.05600

  13. Weng, L. (2021). What are Diffusion Models? lilianweng.github.io

  14. Hugging Face. The Annotated Diffusion Model. huggingface.co/blog/annotated-diffusion