HelloAI
📄 论文精读 🏆 必读经典 ⭐ 本周精选 · 2020 · NeurIPS 2020

Denoising Diffusion Probabilistic Models (DDPM)

Jonathan Ho, Ajay Jain, Pieter Abbeel
TL;DR
提出 DDPM —— 用"加噪 → 去噪"的范式做图像生成。Stable Diffusion、Sora 都基于这个思路。
#Diffusion#生成模型#图像#必读

为什么这篇论文重要

2014-2020 年间,生成模型的”主角”轮换过几次:

  • VAE(2013):质量平平
  • GAN(2014):训练不稳定
  • Flow-based models(2015-2018):表现一般

直到 2020 年这篇 DDPM —— 它让 diffusion 一跃成为生成模型最强方法

之后:

  • 2021 GLIDE(OpenAI 文生图)
  • 2022 DALL·E 2 / Imagen / Stable Diffusion
  • 2024 Sora
  • 2026 主流图/视频生成全用 diffusion

这一篇是当代 AIGC 的源头之一

论文核心:把生成 = 反向去噪

反直觉的目标

直接训”生成图像”很难——所有 GAN 都在这上面挣扎。

DDPM 换了思路:

训练一个网络,让它学”如何去噪声”。然后从纯噪声开始,反向走,就能生成图像

前向过程(已知)

T=1000T = 1000 步往图像里加噪:

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)

βt\beta_t 是预设的噪声 schedule。 TT 步后图像变成接近高斯噪声。

反向过程(要学的)

学一个网络 pθ(xt1xt)p_\theta(x_{t-1} | x_t) —— 给一个噪声图,输出”少一点噪声的图”。

数学推导(论文里展开了几页)后,训练目标简化到

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

翻译

网络要做的事:接收一个加噪图 + 时间步 t,预测出加进去的噪声。 损失 = 预测噪声和真实噪声的 MSE。

就这一行

为什么这个目标这么好

1. 训练稳定

不像 GAN 需要对抗训练——DDPM 就是普通的回归任务。100% 稳定

2. 数学优雅

虽然推导复杂——实现起来就几十行代码

3. 质量高

CIFAR-10 上的 FID 远超当时的 GAN。

4. 多样性好

GAN 容易 mode collapse(只生成同类图)。DDPM 不会——它能覆盖整个数据分布。

实验结果

CIFAR-10

模型FID(越低越好)
BigGAN14.7
StyleGAN28.0
DDPM3.17

直接成为新 SOTA

高质量样本

论文里展示了在 LSUN 数据集上的样本——质量明显超过当时的 GAN

但生成速度慢:1000 步采样意味着 1000 次网络前向。 早期 DDPM 生成一张图要几分钟。 后续的 DDIM、DPM-Solver 把它压到几十步——速度提升 50 倍。

论文的关键洞察

洞察 1:简化训练目标

完整 ELBO 目标很复杂—— 论文证明 简化为 MSE 后,质量更好。 这是个反直觉的工程发现。

洞察 2:固定方差

理论上反向过程的方差也应该学。 论文发现固定方差效果就够。后续 OpenAI 的”Improved DDPM” 加回了可学方差,又提升了一点。

洞察 3:U-Net 架构

去噪网络用 U-Net(带 skip connection 的 encoder-decoder)。 这成了 diffusion 模型的标准设计——Stable Diffusion 至今用。

论文之后

DDPM 启发了一系列扩展:

论文贡献
DDIM (2020)非马尔可夫采样,50 步出图
Improved DDPM (2021)学习方差、cosine schedule
Classifier Guidance (2021)用分类器引导生成(早期 prompt)
CFG (2021)Classifier-free guidance(无需分类器)
LDM / Stable Diffusion (2022)Latent space 上做扩散,速度提升 64 倍
GLIDE / DALL·E 2 (2022)文生图
Imagen (2022)Google 版文生图
Sora (2024)视频生成
Flux (2024)Flow Matching

从 DDPM 到 Sora 只用了 4 年——AI 行业的进化速度。

一些有意思的细节

Jonathan Ho

第一作者,UC Berkeley 博士生。 做 DDPM 时还是博士第三年。论文发表后被 Google Brain 抢走, 后来成立了 Hourly.ai,做 AI 视频生成。

“Why didn’t anyone do this before”

DDPM 用的数学(基于 Sohl-Dickstein 2015 年的工作)已经存在 5 年了。 但直到 2020 年 Ho 等人找到对训练目标的”简化”,diffusion 才真正起飞。

“好想法常常需要多轮重新发现”——这是 AI 史上反复出现的故事。

论文与 GAN 之争

2020 年 GAN 还是图像生成的霸主。 DDPM 论文当时不算特别火——大多数人觉得”又一个 generative model 变体”。 直到 2022 年 Stable Diffusion 火爆,所有人才回过头说:“2020 那篇论文真神”。

延迟认可 —— 这也是 AI 论文常见的命运。

代码实现

最简 DDPM 训练循环:

import torch
import torch.nn as nn
import torch.nn.functional as F

# Noise schedule
T = 1000
beta = torch.linspace(0.0001, 0.02, T)
alpha = 1 - beta
alpha_bar = torch.cumprod(alpha, dim=0)

# Training step
def train_step(model, x_0):
    batch = x_0.shape[0]
    # 1. Sample random timestep
    t = torch.randint(0, T, (batch,))
    # 2. Sample noise
    noise = torch.randn_like(x_0)
    # 3. Forward diffusion (jump to step t directly)
    sqrt_alpha_bar_t = alpha_bar[t].sqrt().view(-1, 1, 1, 1)
    sqrt_one_minus = (1 - alpha_bar[t]).sqrt().view(-1, 1, 1, 1)
    x_t = sqrt_alpha_bar_t * x_0 + sqrt_one_minus * noise
    # 4. Predict noise
    predicted_noise = model(x_t, t)
    # 5. MSE loss
    return F.mse_loss(predicted_noise, noise)

# Sampling (DDPM)
def sample(model, shape):
    x = torch.randn(shape)
    for t in reversed(range(T)):
        z = torch.randn_like(x) if t > 0 else 0
        predicted_noise = model(x, torch.tensor([t]))
        x = (x - beta[t] / (1 - alpha_bar[t]).sqrt() * predicted_noise) / alpha[t].sqrt()
        x += beta[t].sqrt() * z
    return x

核心算法约 30 行代码——简洁到不像支撑了整个生成 AI 革命。

推荐配套阅读

  • HelloAI: L5-02 Diffusion 数学
  • HelloAI: Diffusion 去噪可视化
  • Stable Diffusion paper(2022)—— Latent Diffusion
  • Lilian Weng 的 “What are Diffusion Models?” —— 最好的导读之一
  • Hugging Face Diffusion Course —— 实战教程
💡 一个观察

最重要的论文不一定是当时最受关注的。 DDPM 在 2020 NeurIPS 上是 poster——不是 oral。 2 年后才被全行业认可。

做研究的耐心 —— 比追热点重要。

📬

想要更多论文精读

订阅每周精选 —— 下一篇论文笔记直接送邮箱。

💬

讨论区

· 用 GitHub 账号登录评论
⚠️ Giscus 评论未配置 —— 在 src/components/Comments.astro 顶部填入 仓库 ID 和分类 ID(见组件注释里的配置步骤)。