扩散模型,特别是U-Net,被训练来预测在时间步$t$时含噪输入$x_t$中的噪声$\epsilon$。利用这个训练好的模型,可以生成新的数据。去噪扩散概率模型(DDPM)算法为此生成过程提供了原始的基本方法。正如本章引言中所述,核心思想是从纯噪声开始,并使用学到的去噪步骤逐步对其进行精细化。我们首先从标准高斯分布中采样一个初始张量$x_T$,即$x_T \sim \mathcal{N}(0, \mathbf{I})$。这个$x_T$表示最大熵、纯噪声,对应于前向扩散过程的最终状态。DDPM采样算法随后迭代应用学到的逆向过程,从时间步$t=T$逐步向后退到$t=1$。在每一步中,目标是给定当前状态$x_t$,采样得到一个噪声稍小的版本$x_{t-1}$。去噪步骤回顾第3章,逆向转换$p_\theta(x_{t-1} | x_t)$由一个高斯分布近似,其均值$\mu_\theta(x_t, t)$取决于$x_t$和预测噪声$\epsilon_\theta(x_t, t)$,其方差$\sigma_t^2$与噪声调度$\beta_t$相关。模型$\epsilon_\theta(x_t, t)$接收当前含噪图像$x_t$和时间步$t$作为输入,并输出它对从$x_0$到$x_t$过程中添加的噪声成分的预测。使用这个预测,我们可以估计前一状态$x_{t-1}$的分布均值。均值$\mu_\theta(x_t, t)$的方程是从前向和逆向过程的属性推导出来的:$$ \mu_\theta(x_t, t) = \frac{1}{\sqrt{\alpha_t}} \left( x_t - \frac{1 - \alpha_t}{\sqrt{1 - \bar{\alpha}t}} \epsilon\theta(x_t, t) \right) $$此处,$\alpha_t = 1 - \beta_t$和$\bar{\alpha}t = \prod{i=1}^t \alpha_i$是从前向过程中使用的噪声调度$\beta_t$派生出的参数。这个方程本质上是取当前含噪样本$x_t$,并减去按比例缩放的预测噪声$\epsilon_\theta$,以估计前一个噪声较小状态$x_{t-1}$的均值。逆向步骤的方差$\sigma_t^2$也由噪声调度决定。一个常用的选择,为了匹配前向过程后验分布$q(x_{t-1} | x_t, x_0)$的方差而推导出的,是:$$ \sigma_t^2 = \tilde{\beta}t = \frac{1 - \bar{\alpha}{t-1}}{1 - \bar{\alpha}_t} \beta_t $$注意,当$t=1$时,$\sigma_t^2 = 0$。为了执行一个去噪步骤并从$x_t$采样得到$x_{t-1}$,我们使用模型的预测计算均值$\mu_\theta(x_t, t)$,然后添加按标准差$\sigma_t$缩放的高斯噪声:$$ x_{t-1} = \mu_\theta(x_t, t) + \sigma_t z $$其中$z \sim \mathcal{N}(0, \mathbf{I})$是标准高斯噪声。这个添加的噪声$z$为生成过程引入了随机性,使得模型即使从相同的初始$x_T$开始也能生成多样化的样本(尽管通常我们从不同的$x_T$样本开始)。然而,对于最后一步($t=1$),我们通常将$z=0$以获得最终的确定性均值预测作为我们的输出$x_0$。完整的DDPM算法将这些步骤结合起来,完整的DDPM采样算法如下进行:初始化:采样初始噪声张量$x_T \sim \mathcal{N}(0, \mathbf{I})$。这个张量应与期望的输出数据(例如,图像的高度、宽度、通道数)具有相同的维度。迭代去噪:从时间步$t = T, T-1, \dots, 1$开始,向后循环。采样标准高斯噪声$z \sim \mathcal{N}(0, \mathbf{I})$。如果$t=1$,则设置$z=0$。使用训练好的神经网络$\epsilon_\theta$预测当前状态中存在的噪声:$\epsilon_{pred} = \epsilon_\theta(x_t, t)$。使用预测噪声计算逆向分布的均值: $$ \mu_\theta(x_t, t) = \frac{1}{\sqrt{\alpha_t}} \left( x_t - \frac{1 - \alpha_t}{\sqrt{1 - \bar{\alpha}t}} \epsilon{pred} \right) $$计算方差$\sigma_t^2 = \tilde{\beta}_t$(从噪声调度中预先计算)。使用计算出的均值和方差采样下一个状态(噪声较小): $$ x_{t-1} = \mu_\theta(x_t, t) + \sigma_t z $$输出:循环结束后(在$t=1$时),得到的张量$x_0$就是生成的样本。此过程可视化如下:digraph G { rankdir=RL; node [shape=box, style=rounded, fontname="sans-serif", color="#495057", fillcolor="#e9ecef", style="filled,rounded"]; edge [color="#868e96"]; xT [label="x_T ~ N(0,I)", shape=ellipse, style=dashed, color="#adb5bd"]; xTminus1 [label="x_{T-1}"]; xTminus2 [label="x_{T-2}"]; x1 [label="x_1"]; x0 [label="x_0 (最终样本)", shape=ellipse, style=solid, color="#1c7ed6", fillcolor="#a5d8ff"]; model [label="噪声预测器\nε_θ(x_t, t)", shape=component, color="#f76707", fillcolor="#ffd8a8"]; sampler [label="采样器\nμ_θ + σ_t * z", shape=cds, color="#ae3ec9", fillcolor="#eebefa"]; xT -> sampler [label=" t=T", fontsize=10]; model -> sampler [label=" ε_pred", style=dashed, fontsize=10]; xT -> model [label=" 输入 x_T", style=dashed, fontsize=10]; sampler -> xTminus1 [label=" 已采样", fontsize=10]; xTminus1 -> sampler [label=" t=T-1", fontsize=10]; xTminus1 -> model [label=" 输入 x_{T-1}", style=dashed, fontsize=10]; sampler -> xTminus2 [label=" 已采样", fontsize=10]; node_dots [label="...", shape=plaintext]; xTminus2 -> node_dots [arrowhead=none]; node_dots -> x1 [arrowhead=none]; x1 -> sampler [label=" t=1", fontsize=10]; x1 -> model [label=" 输入 x_1", style=dashed, fontsize=10]; sampler -> x0 [label=" 已采样 (z=0)", fontsize=10]; }图表说明了迭代的DDPM采样过程。从噪声$x_T$开始,每一步都使用噪声预测器$\epsilon_\theta$来计算前一状态的均值$\mu_\theta$,然后通过添加缩放噪声$\sigma_t z$来采样$x_{t-1}$(除了最后一步$z=0$)。最终样本$x_0$的质量在很大程度上取决于训练好的噪声预测器$\epsilon_\theta$的准确性以及所选的噪声调度($\beta_t$)和扩散步数($T$)。DDPM通常需要大量的步骤(例如$T=1000$)才能获得高质量结果,这可能导致采样相对缓慢。我们将在后续章节中讨论像DDIM这样更快的替代方法。