扩散模型(Diffusion Model)原理与图像生成实战
为什么需要扩散模型
传统的生成对抗网络(GAN)虽然经典,但训练过程往往不稳定,容易出现模式崩溃。相比之下,扩散模型通过逐步添加噪声和逐步去除噪声的双向过程,实现了更稳定的训练和高质量的生成效果。它的灵感来源于非平衡热力学,核心在于将复杂的生成问题拆解为多个简单的马尔可夫链步骤。
在图像生成、文本生成及语音合成等领域,扩散模型的表现已经超越了传统方法。本文将带你深入理解其数学原理,并用 PyTorch 从零搭建一个 DDPM 模型,完成手写数字的生成任务。
核心思想:前向与反向扩散
扩散模型包含两个核心过程:
- 前向扩散过程:从真实数据出发,逐步向数据中添加高斯噪声。经过 T 步后,数据会变成完全随机的噪声。
- 反向扩散过程:从随机噪声出发,训练一个神经网络逐步去除噪声。经过 T 步后,噪声会还原为真实的数据分布。
整个过程遵循马尔可夫链假设,即每一步的状态只与前一步有关。
前向扩散过程详解
前向扩散是一个固定的、无需训练的过程。目标是通过逐步添加噪声,将真实图像 $x_0$ 转换为随机噪声 $x_T$。
数学原理
每一步按照以下公式添加噪声:
$$ x_t = \sqrt{\alpha_t} x_{t-1} + \sqrt{1 - \alpha_t} \epsilon_t $$
其中 $x_t$ 是第 t 步添加噪声后的图像,$\alpha_t$ 是预先设定的噪声系数($0 < \alpha_t < 1$),$\epsilon_t$ 服从标准正态分布。
为了计算方便,通常定义累计乘积系数:
$$ \bar{\alpha}t = \prod{i=1}^t \alpha_i $$
利用累计系数,可以直接从 $x_0$ 计算出任意步的 $x_t$:
$$ x_t = \sqrt{\bar{\alpha}_t} x_0 + \sqrt{1 - \bar{\alpha}_t} \epsilon $$
注意:前向扩散的步数 T 是一个超参数。T 越大,前向扩散越充分,反向扩散的效果越好,但训练和生成的时间也会越长。
代码实现
这里我们使用 PyTorch 来模拟前向扩散过程。首先定义超参数并生成 beta 序列。
import torch
import numpy as np
import matplotlib.pyplot as plt
from torchvision.datasets import MNIST
from torchvision.transforms import ToTensor
# 定义扩散过程的超参数
T = 1000 # 扩散步数
beta_start = 0.0001
beta_end = 0.02
# 生成线性变化的 beta 序列
beta = torch.linspace(beta_start, beta_end, T)
alpha = - beta
alpha_bar = torch.cumprod(alpha, dim=)
():
eps = torch.randn_like(x0).to(device)
alpha_bar_t = alpha_bar[t].reshape(-, , , ).to(device)
xt = torch.sqrt(alpha_bar_t) * x0 + torch.sqrt( - alpha_bar_t) * eps
xt, eps
dataset = MNIST(root=, train=, download=, transform=ToTensor())
x0, _ = dataset[]
x0 = x0.unsqueeze()
device = torch.device( torch.cuda.is_available() )
plt.figure(figsize=(, ))
i, t ([, , , , , ]):
xt, _ = forward_diffusion(x0, torch.tensor([t]), device)
xt = xt.squeeze().cpu().detach().numpy()
plt.subplot(, , i + )
plt.imshow(xt, cmap=)
plt.title()
plt.axis()
plt.show()


