没有手怎么画画?在线等,挺急的

· · 科技·工程

扩散模型原理浅析

阅读完 DDPM 写的笔记,边学边写喵~,有错误请在评论区指正喵~

0x01 背景

如何画出一张以假乱真的图片?现在你有这几种方法:

人类画画,就是这么简单直观。我们可以观察物体的形状、颜色、光影,然后用手中的画笔在纸上重现出来。即使技法不够娴熟,但我们至少知道从何下手。

那现在的电脑呢?它们没有眼睛,无法真正"看见"事物;没有手,无法握笔作画;更没有大脑的艺术感知能力。然而,当我们使用 AI 绘图工具时,只需输入一段文字描述,就能得到一张《栩栩如生》的图像(确信)。这些图像甚至能让很多人误以为是真人拍摄的照片。

这就引出了一个有趣的问题:没有感官、没有肢体的计算机,到底是如何创造出如此逼真图像的呢?它们内部究竟发生了什么神奇的过程,才能让一堆冰冷的数字和算法变成富有艺术感的画面?

接下来,我们将介绍在一切背后的故事。

0x02 引言:扩散模型

扩散模型(Diffusion Model)是一种基于概率分布的图像生成模型,它通过生成一个概率分布来模拟图像生成过程。其基本灵感来自非平衡热力学,通过定义一个扩散步骤的马尔可夫链,逐步为图片添加噪声,然后反转添加噪声的过程,最终得到训练数据。

所以在深入了解扩散模型之前,让我们先认识一下马尔可夫链和概率分布。

0x03 马尔可夫链和概率分布

马尔可夫链(Markov Chain)是一种概率图模型,它描述了系统在某一个状态下的下一个状态的概率。可以说是机器学习和人工智能的基石,在强化学习、自然语言处理、金融领域、天气预测、语音识别方面都有着极其广泛的应用。

The future is independent of the past given the present 未来独立于过去,只基于当下。

这句格言很贴切地描述了马尔可夫链的基本原理。所有过去的状态都被保留到了当前的状态,所以基于当下,就可预测未来。

虽然这么说可能有些极端,但是却可以大大简化模型的复杂度,因此马尔可夫链在很多时间序列模型中得到广泛的应用,比如循环神经网络 RNN,隐式马尔可夫模型 HMM 等,当然 MCMC 也需要它。

我们以一个经典的例子来说明:股票专家通过当前股市状态预测未来股票价格。 :::align{center}

:::

以上面这个概率分布为例,假设当前三种状态的概率分布为:[0.3, 0.4, 0.3],我们可以轻松地构造出一个转移矩阵:

P = \begin{bmatrix} 0.9 & 0.075 & 0.025\\ 0.15 & 0.8 & 0.05\\ 0.25 & 0.25 & 0.5 \end{bmatrix}

与矩阵优化 DP 类似,矩阵 P 的每一行表示当前状态,每一列表示下一状态,P_{ij} 表示从状态 i 转移到状态 j 的概率。同样的,与矩阵优化的 DP 相同,求若干轮的概率分布,也可以通过矩阵乘法求解。

:::info[可以简单地用下面的程序来实现:]{open}

import numpy as np
P = np.array([[0.9, 0.075, 0.025], [0.15, 0.8, 0.05], [0.25, 0.25, 0.5]], dtype=float)
current_state = np.array([[0.3, 0.4, 0.3]], dtype=float)  
for i in range(100):
    current_state = np.dot(current_state, P)  # 或者 current_state @ P
    print(f"Current round {i + 1}: ")
    print(current_state)

:::

:::info[运行结果如下:]{open}

Current round: 1
[[ 0.3975  0.4175  0.185 ]]
Current round: 2
[[ 0.463375  0.398375  0.13825 ]]
Current round: 3
[[ 0.507944  0.38548   0.106576]]
...
Current round: 55
[[ 0.624999  0.3125  0.0625]]
Current round: 56
[[ 0.625  0.3125  0.0625]]
Current round: 57
[[ 0.625  0.3125  0.0625]]
...
Current round: 100
[[ 0.625  0.3125  0.0625]]

:::

不难发现,在若干轮后,概率分布已经收敛到某一个值,这个值就是模型所生成的概率分布。因此得出,满足一定条件的马尔可夫链具有稳定性。

什么不是马尔可夫链可以实现的?

现在你有一个袋子,里面装有 n 颗球,有 m 种颜色,每种颜色球数量为 a_in_i \ge 1。求每次抽球,概率分布。

对于这个问题,显然我们无法使用马尔可夫链,因为当前状态不仅取决于上一状态,还取决于此前每一次抽球的结果。

0x04 扩散

回到往照片上撒沙子这回事。首先介绍噪声的扩散,在数据当中,不断地加入具有高斯分布的噪声,最开始还具有原始图片的特征,但是随着噪声的不断加入,最后会变为一个纯噪声图片,如图所示:

:::align{center} :::

容易发现,每一个噪声都是在上一噪声基础上生成的,从最初的 x_0 不断迭代到噪声 x_T。那么添加噪声的目的是什么?扩散模型的本质是去噪,将一张含有噪声的图片甚至是纯噪声的图片,通过不断去噪甚,变成一张无噪声的图片。而去噪的逆过程加噪声其实就是不断构造标签的过程——如果能够从当前状态预测下一个状态,就能很轻松地反过来实现还原操作。所以你可以大致把扩散模型分为两部分——即扩散过程还原过程

从概率角度看,扩散模型的联合分布 p_\theta(\mathbf{x}_{0:T}) 被定义为马尔可夫链,其起始分布为 p(\mathbf{x}_T) = \mathcal{N}(\mathbf{x}_T; \mathbf{0}, \mathbf{I}),也就是标准正态分布,这意味着最终的纯噪声符合该分布特性。而扩散过程(也叫前向过程)作为近似后验 q(\mathbf{x}_{1:T}|\mathbf{x}_0),是固定的马尔可夫链,它会依据方差调度 \beta_1, ..., \beta_T 逐步给数据添加高斯噪声,这个方差调度决定了每一步添加噪声的强度,保证了噪声添加过程的有序性和可控性。

0x05 硬的要来了

接下来,让我们细致分析一下其中的每一步,当然,可能会有很多公式,我尽可能把它讲明白。

0x05.1 前向过程的数学表达

在扩散模型的前向过程中,我们从原始数据 \mathbf{x}_0(即真实图像)出发,逐步添加高斯噪声得到一系列含噪数据 \mathbf{x}_1, \mathbf{x}_2, ..., \mathbf{x}_T。为了方便计算,我们定义 \alpha_t = 1 - \beta_t,其中 \beta_t 是第 t 步的噪声方差,同时定义累积乘积 \bar{\alpha}_t = \prod_{s=1}^{t} \alpha_s,这个累积乘积能很好地反映前 t 步噪声添加对数据的整体影响 —— \bar{\alpha}_t 越大,说明前 t 步添加的噪声总量越少,数据保留原始特征越多;反之则噪声越多,数据越接近纯噪声。

基于上述定义,前向过程中从 \mathbf{x}_{t-1}\mathbf{x}_t 的条件分布可表示为 q(\mathbf{x}_t|\mathbf{x}_{t-1}) = \mathcal{N}(\mathbf{x}_t; \sqrt{\alpha_t} \mathbf{x}_{t-1}, (1-\alpha_t)\mathbf{I})。这一分布表明,第 t 步的含噪数据 \mathbf{x}_t 是由第 t-1 步的含噪数据 \mathbf{x}_{t-1} 经过均值为 \sqrt{\alpha_t} \mathbf{x}_{t-1}、方差为 (1-\alpha_t)\mathbf{I} 的高斯分布采样得到的。由于高斯分布具有可加性,我们可以推导出从 \mathbf{x}_0 直接得到任意步 \mathbf{x}_t 的闭式表达式:\mathbf{x}_t = \sqrt{\bar{\alpha}_t} \mathbf{x}_0 + \sqrt{1-\bar{\alpha}_t} \boldsymbol{\epsilon},其中 \boldsymbol{\epsilon} \sim \mathcal{N}(\mathbf{0},\mathbf{I}) 是标准高斯噪声。这个闭式表达式非常关键,它让我们无需逐步计算 \mathbf{x}_1\mathbf{x}_{t-1},就能直接获取任意步的含噪数据,大大提高了计算效率,尤其在模型训练时,可以随机选择任意时间步的 \mathbf{x}_t 进行训练,而不用遍历所有步骤。

0x05.2 反向过程的核心

反向过程是扩散模型生成图像的关键,它的目标是从纯噪声 \mathbf{x}_T 出发,逐步去除噪声,最终恢复出接近原始数据 \mathbf{x}_0 的生成图像。反向过程的条件分布被定义为 p_\theta(\mathbf{x}_{t-1}|\mathbf{x}_t) = \mathcal{N}(\mathbf{x}_{t-1}; \boldsymbol{\mu}_\theta(\mathbf{x}_t,t), \boldsymbol{\Sigma}_\theta(\mathbf{x}_t,t)),其中 \boldsymbol{\mu}_\theta(\mathbf{x}_t,t) 是均值函数,\boldsymbol{\Sigma}_\theta(\mathbf{x}_t,t) 是方差函数,二者都由神经网络参数化,通过训练学习从含噪数据 \mathbf{x}_t 中恢复前一步数据 \mathbf{x}_{t-1} 的规律。

在实际训练中,为了简化模型并提升性能,通常对反向过程的方差和均值做特殊处理。对于方差 \boldsymbol{\Sigma}_\theta(\mathbf{x}_t,t),实验发现将其设置为与时间相关的固定常数(如 \sigma_t^2 = \beta_t\tilde{\sigma}_t^2 = \tilde{\beta}_t = \frac{1 - \bar{\alpha}_{t-1}}{1 - \bar{\alpha}_t} \beta_t)时,模型表现良好,且避免了学习方差带来的训练不稳定性——如果让方差也由神经网络学习,容易出现方差预测不准确,导致生成的图像要么噪声残留过多,要么细节丢失严重的问题。

而对于均值 \boldsymbol{\mu}_\theta(\mathbf{x}_t,t),论文提出了一种基于噪声预测的参数化方式。结合前向过程的闭式表达式,我们可以将 \mathbf{x}_0 表示为 \mathbf{x}_0 = \frac{1}{\sqrt{\bar{\alpha}_t}}(\mathbf{x}_t - \sqrt{1-\bar{\alpha}_t} \boldsymbol{\epsilon}),再将其代入前向过程中 \mathbf{x}_{t-1} 的条件均值表达式(即 \tilde{\boldsymbol{\mu}}_t(\mathbf{x}_t,\mathbf{x}_0) = \frac{\sqrt{\alpha_t}(1 - \bar{\alpha}_{t-1})}{1 - \bar{\alpha}_t} \mathbf{x}_t + \frac{\sqrt{\bar{\alpha}_{t-1}}(1 - \alpha_t)}{1 - \bar{\alpha}_t} \mathbf{x}_0),最终可得到 \boldsymbol{\mu}_\theta(\mathbf{x}_t,t) = \frac{1}{\sqrt{\alpha_t}}(\mathbf{x}_t - \frac{1-\alpha_t}{\sqrt{1-\bar{\alpha}_t}} \boldsymbol{\epsilon}_\theta(\mathbf{x}_t,t)),其中 \boldsymbol{\epsilon}_\theta(\mathbf{x}_t,t) 是神经网络预测的噪声项。这种参数化方式的巧妙之处在于,将原本复杂的均值预测问题转化为相对简单的噪声预测问题——神经网络只需要学习从含噪数据 \mathbf{x}_t 中识别出当初添加的噪声 \boldsymbol{\epsilon},就能通过上述公式计算出反向过程的均值,进而完成去噪步骤。

0x06 回归应用

有了扩散模型,让我们回归到最初的问题:我们如何用它来生成图像呢?

整体而言,需要下面三个步骤:

0x06.1 文本编码

对于刚刚的 Diffusion Model,它并不能直接处理文字这类非值数据,因此我们需要将文字编码为数值数据,也就是向量(Text Embedding 过程)。在这一步骤中,CLIP 被用来将文字编码为向量,并最终输出为一个特定维度的语义向量。

CLIP 高度依赖于 Transformer 架构,其目标是建立“文本”与“图像”的跨模态语义关联。因而采用“文本编码器 + 图像编码器”的双分支结构。两个编码器分别将文本、图像转换为统一维度的特征向量,再通过对比学习(Contrastive Learning)让“匹配的文本 - 图像对”特征更相似,“不匹配的对”特征更疏远。

你也许在登录一些网站时见过一些 Captcha 验证码,要求你选择符合要求的某张图片,其中一部分这样的验证码被用于收集 CLIP 的训练数据。

0x06.2 噪声生成与去噪

前面我们说过,扩散模型是一个逐步去噪的过程,因此我们需要生成一个包含噪声的初始数据,并逐步去除噪声,最终得到一个接近原始数据的图像。

接下来,把这个纯噪声组成的张量 \mathbf{x}_T 输入到还原过程中,不断迭代得到 \mathbf{x}_0,也就是最终图像。

0x06.3 善后工作

迭代策略与采样方法

在噪声生成与去噪的核心流程中,模型的迭代策略和采样方法直接决定了最终生成图像的质量与效率,这一步也是扩散模型图像生成的关键优化环节。

扩散模型的去噪过程需要通过多步迭代完成,迭代步数 T 的设定存在权衡关系:

在实际应用中,通常会根据场景需求选择合适的步数:

模型输出的后处理

经过多步迭代得到最终的图像张量 \mathbf{x}_0 后,通常还需要进行后处理操作以优化视觉效果:

  1. 像素值归一化:将模型输出的张量数值映射到图像显示的标准范围(如 0-255 的 RGB 像素值),确保图像能够正常渲染

  2. 超分辨率增强:对于生成的低分辨率图像,通过超分辨率模型(如 ESRGAN、Real-ESRGAN 等)提升图像分辨率,补充细节纹理,改善画面清晰度

  3. 降噪与锐化:针对图像可能存在的轻微噪声或模糊问题,采用降噪算法(如非局部均值降噪)和锐化算法(如拉普拉斯锐化)进行优化,提升图像的视觉质感

0x07 总结

所以恭喜你坚持看完了!

总结一下,读完本文,你大概率已经初步了解了扩散模型及其应用。那么接下来,去手搓一个 DALL-E 罢!

另:求赞,打公式眼睛快瞎了……

:::info[参考文献]

  1. Ho, J., Jain, A., & Abbeel, P. (2020). Denoising diffusion probabilistic models. Advances in Neural Information Processing Systems, 33, 6840-6851.

:::

:::info[关于本文]

本文初稿完成于 10/24/2025,完成后使用 Qwen LLM 校对和二次排版

依据 CC-BY-NC-SA 4.0 协议授权,欢迎转载、修改、分发,但请务必保留作者署名。

:::