扩散模型是当前图像生成领域的主流技术之一,其中DDPM和DDIM是两个基础且重要的模型。DDPM通过模拟马尔可夫链逐步添加和去除噪声,生成过程具有随机性;DDIM则在同一训练目标下推导出非马尔可夫的反向过程,实现了确定性的快速采样。理解两者的区别,对于优化生成速度和设计可控的图像编辑算法至关重要。

DDPM的随机采样机制
DDPM由Ho等人在2020年提出,其核心思想是定义一个前向扩散过程,将数据分布逐步破坏为高斯噪声。前向过程是一个固定的马尔可夫链,每一步按照方差计划向数据中添加高斯噪声。给定原始图像x0,经过T步后,xT接近标准正态分布。前向过程的每一步可以写作:q(x_t | x_{t-1}) = N(x_t; sqrt(1-beta_t) * x_{t-1}, beta_t * I),其中beta_t是预设的噪声调度参数。
反向过程则学习一个参数化的马尔可夫链,逐步从噪声恢复数据。模型需要预测每一步的噪声或均值,通常使用U-Net架构。反向过程的每一步定义为p_theta(x_{t-1} | x_t) = N(x_{t-1}; mu_theta(x_t, t), sigma_t^2 * I)。在采样时,从纯噪声x_T ~ N(0, I)开始,依次从p_theta中采样得到x_{T-1}, x_{T-2}, ..., x_0。由于每一步都从条件高斯分布中采样,整个生成过程是随机的:即使使用相同的初始噪声,每次运行也会产生不同的结果。
DDPM的马尔可夫假设保证了训练目标的对数似然下界可以简化,但导致采样步数必须足够大(通常T=1000)才能获得高质量图像。每一步都需要经过神经网络前向计算,计算成本很高。此外,随机采样虽然增加了多样性,但在某些需要精确控制或内容编辑的任务中,随机性反而成了障碍。
DDIM的确定性采样原理
DDIM(Denoising Diffusion Implicit Models)提出了一种非马尔可夫的前向过程,它共享与DDPM相同的边缘分布,但不再要求逐步转移满足马尔可夫性质。DDIM定义了一族更一般的推断分布:q_sigma(x_{t-1} | x_t, x_0),其中sigma是一个可调参数。当sigma为某个特定值时,该过程退化为DDPM;当sigma=0时,反向过程变为确定性的。
在DDIM中,反向过程的更新公式为:x_{t-1} = sqrt(alpha_{t-1}) * ( (x_t - sqrt(1-alpha_t) * epsilon_theta(x_t, t)) / sqrt(alpha_t) ) + sqrt(1-alpha_{t-1} - sigma_t^2) * epsilon_theta(x_t, t) + sigma_t * z,其中z是随机噪声。当sigma_t=0时,z项消失,给定x_T和模型参数后,整个采样序列是确定性的。这意味着从同一个初始噪声出发,无论运行多少次,生成的图像完全一致。
这种确定性采样带来了几个显著的优点。首先,采样步数可以大幅减少,因为不需要逐步模拟随机游走,DDIM可以在几十步甚至更少步内生成质量不错的图像。其次,确定性使得潜变量与图像之间存在可逆映射,便于进行插值、编辑和反演操作。例如,可以通过DDIM反演将真实图像编码到潜空间,然后进行语义编辑后再解码回来。此外,DDIM的推导并不需要重新训练模型,可以直接复用DDPM训练好的权重,只需改变采样方式即可。
两者对比与工程实践
从生成质量来看,在足够多的采样步数下,DDPM和DDIM的质量相当;但在少步数时,DDIM通常优于DDPM,因为它避免了随机噪声的累积扰动。从采样速度来看,DDIM由于减少了步数,推理时间可以缩短一个数量级。从随机性角度,DDPM提供更丰富的多样性,适合创意生成;DDIM的确定性则更适合需要精确控制或可复现的任务,如图像编辑、超分辨率等。
在工程实现中,许多扩散模型框架(如Hugging Face Diffusers)都支持通过设置采样器来切换DDPM与DDIM。下面通过Python代码展示两者的采样函数差异:
import torch
import numpy as np
def ddpm_sample(model, x_T, alphas, betas, T):
"""DDPM采样:每一步从高斯分布中采样"""
model.eval()
x_t = x_T
for t in reversed(range(T)):
t_tensor = torch.full((x_t.shape[0],), t, dtype=torch.long)
eps_theta = model(x_t, t_tensor)
alpha_t = alphas[t]
alpha_bar_t = np.prod(alphas[:t+1])
alpha_bar_prev = np.prod(alphas[:t]) if t > 0 else torch.tensor(1.0)
sqrt_alpha_bar_t = torch.sqrt(alpha_bar_t)
sqrt_one_minus_alpha_bar_t = torch.sqrt(1 - alpha_bar_t)
# 预测x_0
x_0_pred = (x_t - sqrt_one_minus_alpha_bar_t * eps_theta) / sqrt_alpha_bar_t
# 计算均值
if t > 0:
beta_t = betas[t]
sqrt_alpha_t = torch.sqrt(alpha_t)
sqrt_one_minus_alpha_bar_prev = torch.sqrt(1 - alpha_bar_prev)
posterior_mean = sqrt_alpha_t * (1 - alpha_bar_prev) / (1 - alpha_bar_t) * x_t + \
beta_t * sqrt_alpha_bar_prev / (1 - alpha_bar_t) * x_0_pred
else:
posterior_mean = sqrt_alpha_bar_t * x_0_pred
# 添加噪声
if t > 0:
noise = torch.randn_like(x_t)
sigma_t = torch.sqrt(beta_t)
x_t = posterior_mean + sigma_t * noise
else:
x_t = posterior_mean
return x_t
def ddim_sample(model, x_T, alphas, T, eta=0.0):
"""DDIM采样:eta=0时为确定性采样"""
model.eval()
x_t = x_T
for t in reversed(range(T)):
t_tensor = torch.full((x_t.shape[0],), t, dtype=torch.long)
eps_theta = model(x_t, t_tensor)
alpha_t = alphas[t]
alpha_bar_t = np.prod(alphas[:t+1])
alpha_bar_prev = np.prod(alphas[:t]) if t > 0 else torch.tensor(1.0)
sqrt_alpha_bar_t = torch.sqrt(alpha_bar_t)
sqrt_one_minus_alpha_bar_t = torch.sqrt(1 - alpha_bar_t)
# 预测x_0
x_0_pred = (x_t - sqrt_one_minus_alpha_bar_t * eps_theta) / sqrt_alpha_bar_t
# 方向指向x_t
dir_xt = torch.sqrt(1 - alpha_bar_prev) * eps_theta
# 计算x_{t-1}
x_t = torch.sqrt(alpha_bar_prev) * x_0_pred + dir_xt
if eta > 0:
sigma_t = eta * torch.sqrt((1 - alpha_bar_prev) / (1 - alpha_bar_t) * (1 - alpha_bar_t / alpha_bar_prev))
noise = torch.randn_like(x_t)
x_t = x_t + sigma_t * noise
return x_t
上述代码中,DDPM采样在每一步加入随机噪声,而DDIM在eta=0时不加入任何随机项,因此成为确定性过程。实际使用时,我们可以通过调整eta值在随机性和确定性之间插值。
需要注意的是,DDIM的反演过程也很容易实现,只需将采样方向反转,即从x_0逐步推导出x_T。这种可逆性在图像编辑任务中非常有用。
总结
DDPM和DDIM共享相同的训练目标,但采样机制截然不同。DDPM依赖马尔可夫链的逐步随机采样,生成质量高但速度慢且不可复现;DDIM通过非马尔可夫推断实现了确定性快速采样,并保留了与DDPM相当的性能。在实际项目中,选择哪种采样方式取决于任务需求:追求多样性和创意生成时可使用DDPM;追求速度、可控性或可复现性时优先考虑DDIM。理解二者的数学本质,能够帮助开发者在扩散模型应用中做出更合适的设计决策。

