↓ Skip to main content
  1. Posts/

DDPM 前向扩散:为什么加噪可以跳过中间步骤

·3722 words·8 mins
Note: This article is available in Chinese only. 本文暂无英文版本。 View original

起因
#

最近在看 DDPM(Denoising Diffusion Probabilistic Models)。前向扩散的定义写得很清楚:从原始图片出发,每一步往上面加一点噪声,一步一步把图片变成纯噪声。

$$ x_0 \rightarrow x_1 \rightarrow x_2 \rightarrow \cdots \rightarrow x_T $$

每一步都依赖前一步的结果。直觉上,要得到第 500 步的带噪图片,就得老老实实从第 0 步开始,一步一步加噪 500 次。

但是翻到训练代码,发现它根本没有跑这个循环。它直接用了一行公式:

$$ x_t = \sqrt{\bar\alpha_t}\, x_0 + \sqrt{1 - \bar\alpha_t}\, \epsilon $$

随机选一个 \(t\),一步就构造出了 \(x_t\)。

我当时卡住了:这个等式凭什么成立?一个链式依赖的随机过程,怎么能跳过中间所有步骤?

后来发现,关键在于这个随机过程里的噪声是高斯分布,而高斯分布有一个非常特殊的数学性质。这篇就是把这个性质搞清楚的过程。

前向扩散每一步在做什么
#

DDPM 的前向扩散定义是:

$$ x_t = \sqrt{\alpha_t}\, x_{t-1} + \sqrt{1 - \alpha_t}\, \epsilon_t, \quad \epsilon_t \sim \mathcal{N}(0, I) $$

逐项看一下每个符号。

\(x_0\) 是原始图片。\(x_t\) 是第 \(t\) 步之后的带噪图片。\(t\) 是时间步编号,不是物理时间。\(\alpha_t\) 是一个预先设定的系数,取值在 0 到 1 之间,控制每一步保留多少原始信号。\(\epsilon_t\) 是第 \(t\) 步采样的随机噪声,服从标准高斯分布 \(\mathcal{N}(0, I)\)。

这个公式做的事情很直接:把上一步的结果乘以一个小于 1 的系数(信号衰减),再加上一份随机噪声。随着 \(t\) 增大,原始信号的比重越来越小,噪声的比重越来越大,图片逐渐变成纯噪声。

\(\epsilon\) 为什么有下标 \(t\)
#

这是一个我一开始没想清楚的地方。

看到 \(\epsilon_t\) 时,我的第一反应是:是不是每个 timestep 使用不同的高斯分布?比如 \(\epsilon_1 \sim \mathcal{N}(0, 1)\),\(\epsilon_2 \sim \mathcal{N}(0, 4)\),分布本身在变化?

不是。每个 \(\epsilon_t\) 都服从同一个分布 \(\mathcal{N}(0, I)\)。下标 \(t\) 不是说分布不同,而是说每一步独立重新采样一次。

\(\epsilon_1\) 和 \(\epsilon_2\) 是两次独立的随机采样。它们来自同一个分布,但彼此之间没有关联。统计学里把这种关系叫 i.i.d.——independent and identically distributed(独立同分布)。

那不同 timestep 的噪声强度为什么不一样呢?强度变化不是来自 \(\epsilon\) 本身,而是来自前面的系数 \(\sqrt{1 - \alpha_t}\)。当 \(\alpha_t\) 接近 1 时,噪声系数 \(\sqrt{1 - \alpha_t}\) 很小,加的噪声很轻;当 \(\alpha_t\) 减小时,噪声系数增大,加的噪声更重。噪声的源头始终是同一个标准高斯,调节噪声强度的是系数,不是分布。

方差为什么按平方累加
#

在推导跳步公式之前,需要先理解一个概率论的基本性质。这个性质我以前学过但没认真想过它为什么成立。

先从最简单的情况开始。设 \(X\) 是一个随机变量,\(a\) 是一个常数。把 \(X\) 的所有可能取值都放大 \(a\) 倍,得到新的随机变量 \(aX\)。

均值很直觉:所有值都放大 \(a\) 倍,均值也放大 \(a\) 倍。

$$ E[aX] = a \cdot E[X] $$

方差呢?方差衡量的是随机变量相对于均值的偏离程度。如果所有值放大 3 倍,每个值相对于均值的偏差也放大了 3 倍。但方差计算的是偏差的平方,所以:

$$ \text{Var}(3X) = 3^2 \cdot \text{Var}(X) = 9 \cdot \text{Var}(X) $$

一般地:

$$ \text{Var}(aX) = a^2 \cdot \text{Var}(X) $$
方差按平方放大的直觉

接下来是两个独立随机变量之和。如果 \(X\) 和 \(Y\) 相互独立,它们的波动互不干扰。\(X\) 偏大的时候 \(Y\) 可能偏大也可能偏小,没有系统性的关联。所以:

$$ \text{Var}(X + Y) = \text{Var}(X) + \text{Var}(Y) $$

把两条性质合在一起,对于独立的 \(X\) 和 \(Y\):

$$ \text{Var}(aX + bY) = a^2 \text{Var}(X) + b^2 \text{Var}(Y) $$

这就是后面推导的核心工具。

两个高斯噪声怎么合并成一个
#

这里是我卡最久的地方。

设 \(X \sim \mathcal{N}(0, 1)\),\(Y \sim \mathcal{N}(0, 1)\),\(X\) 和 \(Y\) 相互独立。定义一个新的随机变量:

$$ Z = 3X + 4Y $$

\(Z\) 是两个独立标准高斯随机变量的线性组合。它的均值和方差可以直接算:

$$ E[Z] = 3 \cdot 0 + 4 \cdot 0 = 0 $$$$ \text{Var}(Z) = 3^2 \cdot 1 + 4^2 \cdot 1 = 9 + 16 = 25 $$

到这里只用了上一节的工具。但接下来有一个不是所有分布都具备的性质:

独立高斯随机变量的线性组合,仍然服从高斯分布。

也就是说,\(Z\) 不只是均值为 0、方差为 25 的"某个分布",它具体就是 \(\mathcal{N}(0, 25)\)。

$$ Z = 3X + 4Y \sim \mathcal{N}(0, 25) $$

这个性质叫高斯分布在线性组合下的封闭性。它不是显然的——很多分布在做线性组合之后,形状会变得完全不同。高斯是少数做完线性组合之后仍然保持同一族分布的特例。

这意味着什么?\(\mathcal{N}(0, 25)\) 也可以写成 \(5\epsilon\) 的分布,其中 \(\epsilon \sim \mathcal{N}(0, 1)\)。因为 \(\text{Var}(5\epsilon) = 25\),均值为 0,而且 \(5\epsilon\) 作为高斯随机变量的线性变换仍然是高斯。

于是:

$$ 3X + 4Y \sim \mathcal{N}(0, 25), \quad 5\epsilon \sim \mathcal{N}(0, 25) $$

两者服从完全相同的概率分布。

“同分布"到底是什么意思
#

这个地方我停下来想了一会儿。\(3X + 4Y\) 和 \(5\epsilon\) 服从相同的分布,但它们显然不是"相等"的——左边涉及两个随机变量 \(X\) 和 \(Y\),右边只有一个 \(\epsilon\)。

这里需要区分三个不同的符号。

普通等号 \(=\):数值相等。\(2 + 3 = 5\),没有歧义。

服从符号 \(\sim\):表示一个随机变量遵循某个概率分布。\(X \sim \mathcal{N}(0, 1)\) 的意思是 \(X\) 的概率规律是标准高斯。

同分布 \(\overset{d}{=}\):表示两个随机变量的概率规律完全一样。不是说它们每次采样的数值相同,而是说它们落入任何区间的概率都相同。

用具体数字来说。假设某一次采样:

$$ 3X + 4Y = 2.7 $$

同时独立采样:

$$ 5\epsilon = -4.1 $$

数值完全不同。但如果重复采样很多很多次,\(3X + 4Y\) 的值落在 \([-1, 1]\) 之间的概率,和 \(5\epsilon\) 落在 \([-1, 1]\) 之间的概率,是一样的。落在 \([3, 5]\) 之间的概率也一样。落在任何区间的概率都一样。

所以写成:

$$ 3X + 4Y \overset{d}{=} 5\epsilon $$
3X + 4Y 与 5ε 的等价关系

这个区分在后面推导 DDPM 时会直接用到。把多步噪声合并成一步噪声时,合并的是概率分布,不是某一次具体的噪声采样值。 我不需要知道第 1 步实际采到了什么噪声、第 2 步实际采到了什么噪声。我只需要知道:把它们按系数组合之后,整体服从什么分布——然后从这个分布直接采样一次就行。

回到 DDPM:把两步展开看看
#

准备工作做完了。回到前向扩散公式,把前两步显式展开。

第一步:

$$ x_1 = \sqrt{\alpha_1}\, x_0 + \sqrt{1 - \alpha_1}\, \epsilon_1 $$

第二步:

$$ x_2 = \sqrt{\alpha_2}\, x_1 + \sqrt{1 - \alpha_2}\, \epsilon_2 $$

把 \(x_1\) 代入 \(x_2\):

$$ x_2 = \sqrt{\alpha_2}\bigl(\sqrt{\alpha_1}\, x_0 + \sqrt{1 - \alpha_1}\, \epsilon_1\bigr) + \sqrt{1 - \alpha_2}\, \epsilon_2 $$

展开:

$$ x_2 = \sqrt{\alpha_1 \alpha_2}\, x_0 + \sqrt{\alpha_2(1 - \alpha_1)}\, \epsilon_1 + \sqrt{1 - \alpha_2}\, \epsilon_2 $$

现在 \(x_2\) 被拆成了两部分:一部分是原始图片 \(x_0\) 乘以系数 \(\sqrt{\alpha_1 \alpha_2}\),另一部分是两个独立高斯噪声的线性组合。

x_2 展开与噪声合并

噪声部分的方差:

$$ \text{Var}\bigl(\sqrt{\alpha_2(1 - \alpha_1)}\, \epsilon_1 + \sqrt{1 - \alpha_2}\, \epsilon_2\bigr) = \alpha_2(1 - \alpha_1) + (1 - \alpha_2) $$

展开:

$$ = \alpha_2 - \alpha_1 \alpha_2 + 1 - \alpha_2 = 1 - \alpha_1 \alpha_2 $$

因为 \(\epsilon_1\) 和 \(\epsilon_2\) 都是独立的标准高斯,它们的线性组合仍然是高斯(上面讨论的封闭性)。所以整个噪声部分服从 \(\mathcal{N}(0, (1 - \alpha_1 \alpha_2) I)\)。

根据同分布的概念,这和 \(\sqrt{1 - \alpha_1 \alpha_2}\, \epsilon\)(\(\epsilon \sim \mathcal{N}(0, I)\))服从完全相同的概率分布。

于是:

$$ x_2 \overset{d}{=} \sqrt{\alpha_1 \alpha_2}\, x_0 + \sqrt{1 - \alpha_1 \alpha_2}\, \epsilon $$

两步加噪,变成了一步。

推广到任意步
#

同样的逻辑可以递推下去。定义:

$$ \bar\alpha_t = \prod_{i=1}^{t} \alpha_i = \alpha_1 \cdot \alpha_2 \cdots \alpha_t $$

\(\prod\) 表示连乘,和 \(\sum\) 表示求和是一回事,只是把加法换成了乘法。

每往前展开一步,\(x_0\) 的系数多乘一个 \(\sqrt{\alpha_i}\),噪声项多出一个独立高斯分量。但每次都可以用封闭性把所有噪声分量合并成一个。最终:

$$ \boxed{x_t \overset{d}{=} \sqrt{\bar\alpha_t}\, x_0 + \sqrt{1 - \bar\alpha_t}\, \epsilon, \quad \epsilon \sim \mathcal{N}(0, I)} $$

这就是开头训练代码里的那行公式。它不是近似,不是截断,而是数学上严格的等价——给定 \(x_0\),从右边公式采样出的 \(x_t\),和从链式过程跑 \(t\) 步得到的 \(x_t\),服从完全相同的条件分布。

这个性质在工程上解决了什么
#

训练 DDPM 时,每个 training step 需要做的事情是:拿一张训练图片 \(x_0\),随机选一个时间步 \(t\),构造出对应的 \(x_t\),然后让网络学着从 \(x_t\) 预测噪声 \(\epsilon\)。

如果没有跳步公式,构造 \(x_t\) 就得从 \(x_0\) 开始,跑 \(t\) 步前向扩散。假设 \(T = 1000\),平均每个样本要跑 500 步,每步都涉及一次矩阵乘法和一次随机采样。这个计算开销会让训练变得极其缓慢。

有了跳步公式,构造 \(x_t\) 只需要一次乘法和一次采样——和 \(t\) 是 1 还是 1000 无关。\(\bar\alpha_t\) 可以在训练开始前预计算好,存成一个长度为 \(T\) 的数组,用的时候直接查表。

逐步加噪 vs 直接采样

这不是"近似地跳过了中间步骤”。随机过程本身没有被跳过——它仍然是一个 \(T\) 步的马尔可夫链。被跳过的是计算过程,因为这个特定的马尔可夫链存在解析形式的边际分布。

写在最后
#

回到最初的问题:为什么 DDPM 可以跳过中间加噪步骤?

整个推导走下来,我觉得真正值得记住的有三件事。

第一,随机过程的顺序结构不意味着计算时必须逐步模拟。 很多随机过程确实只能一步一步跑,但 DDPM 的前向扩散不在此列。能不能跳步,取决于过程的数学结构是否允许直接写出任意时刻的分布。

第二,高斯分布在这个推导中起到的作用非常具体:独立高斯随机变量的线性组合仍然是高斯。 这使得每一步合并噪声项时,合并后的分布形式已知,可以继续递推。如果噪声换成别的分布——比如均匀分布——线性组合之后就不再是均匀分布了,整个递推会断掉。

第三,训练代码里那行看起来理所当然的公式 \(x_t = \sqrt{\bar\alpha_t}\, x_0 + \sqrt{1 - \bar\alpha_t}\, \epsilon\),背后依赖的是同分布这个概念。合并的不是某一次具体的噪声值,而是概率分布本身。这也是之前写 VAE 那篇里反复出现的主题——理解生成模型,离不开对"随机变量"和"概率分布"这两个层面的区分。

参考资料
#

Related

从条件概率到贝叶斯定理:再理解全概率与全期望

·6128 words·13 mins
起因 # 上一篇讨论了 Markov Property,提到 Bellman Equation 需要它作为前提。 准备看 Bellman Equation 的推导时,我卡在了一个叫 Law of Total Expectation(全期望公式)的地方。它的核心思想是:计算整体期望时,可以先按某个变量的不同取值分组,分别算各组的条件期望,再按组别的概率加权平均。之前那篇定义的 State Value \(V^\pi(s) = \mathbb{E}_\pi[G_t \mid S_t = s]\),在 Bellman Equation 里正是用这个思路按"下一个 State"分组来展开。

从马尔可夫性质出发:DP 无后效性、HMM 与 VAE 的知识联想

·4970 words·10 mins
起因 # 继续跟着 MIT 6.S191 Lecture 5 学强化学习。上一篇理解了 Return、State Value Function \(V^\pi(s)\) 和 Action Value Function \(Q^\pi(s,a)\)。 接下来要学的是 Bellman Equation。 我之前隐约知道它能把 \(V^\pi(s)\) 写成递归形式——当前状态的长期价值,等于下一步的期望 Reward 加上折扣后下一状态的期望长期价值。但刚准备细看推导时,发现它有一个前提条件:

GAN 的对抗到底发生在哪里:从 D(G(z)) 到 Distribution Matching

·7620 words·16 mins
上一篇讲完 VAE,走到一条因果链:VAE 通过把 Encoder 的输出从确定点变成概率分布,让 latent space 服从已知 prior,于是可以从 prior 采样、交给 Decoder 生成新样本。 整个过程很精巧,但回头看,它对概率计算的依赖很重:Encoder 参数化 \(q(z|x)\),训练目标里有 KL divergence、有 reconstruction likelihood,每一步都在和 density 打交道。

从伯努利分布推到二元交叉熵:二分类损失为什么长这样

·6016 words·13 mins
起因 # 最近在看 GAN 的时候,判别器的训练目标里反复出现两项: \(\log D(x)\) 和 \(\log(1 - D(G(z)))\) 我能看出 \(\log D(x)\) 越大越好——\(D(x)\) 越接近 1,判别器越确信这是真实样本。也能看出 \(\log(1-D(G(z)))\) 在 \(D(G(z))\) 接近 0 的时候最大——判别器越确信生成的是假样本。