稳定扩散模型
参考资料
- 稳定扩散模型
- 一文读懂「Diffusion Model,DM」扩散模型
- DDPM: Denoising Diffusion Probabilistic Models 2020
diffusion model
写在前面
为了生成丰富的图像, 一个图像生成程序要根据随机数来生成图像
通常这种随机数是一个满足标准正态分布的随机向量, 每次要生成新图像时, 只需要从标准正态分布里随机生成一个向量并输入给程序就行了
对于图像生成任务, 神经网络的训练数据一般是一些同类型的图片。比如一个绘制人脸的神经网络会用人脸照片来训练
也就是说, 神经网络会学习如何把一个向量映射成一张图片, 并确保这个图片和训练集的图片是一类图片
在其他 AI 任务中, 比如对于图像分类任务, 训练集会给出每一幅图像的类别;对于人脸验证任务, 训练集会给出两张人脸照片是不是同一个人;对于目标检测任务, 训练集会给出目标的具体位置
而图像生成任务对神经网络来说更加困难一点, 因为图像生成任务缺乏有效的指导, 是没有标准答案的。图像生成数据集里只有一些同类型图片, 却没有指导 AI 如何画得更好的信息
为了解决这一问题, 人们专门设计了一些用于生成图像的神经网络架构。这些架构中比较出名的有生成对抗模型(GAN)和变分自编码器(VAE)
GAN 的想法是, 既然不知道一幅图片好不好, 就干脆再训练一个神经网络, 用于辨别某图片是不是和训练集里的图片长得一样
生成图像的神经网络叫做 生成器, 鉴定图像的神经网络叫做 判别器。两个网络互相对抗, 共同进步
VAE 则使用了逆向思维:学习向量生成图像很困难, 那就再同时学习怎么用图像生成向量
这样, 把某图像变成向量, 再用该向量生成图像, 就应该得到一幅和原图像一模一样的图像。每一个向量的绘画结果有了一个标准答案, 可以用一般的优化方法来指导网络的训练了
VAE 中, 把图像变成向量的网络叫做 编码器, 把向量转换回图像的网络叫做 解码器
一直以来, GAN 的生成效果较好, 但训练起来比 VAE 麻烦很多。而扩散模型能做到即易于训练, 生成效果又好
简介
扩散模型的原理类似给图片去噪, 通过学习给一张图片去噪的过程来理解有意义的图像是如何生成
因此扩散模型生成的图片相比 GAN 模型精度更高, 更符合人类视觉和审美逻辑
同时随着样本数量和深度学习时长的累积, 扩散模型展现出对艺术表达风格较好的模仿能力
扩散模型拟合的是加噪图片, 并通过反向过程(去噪)生成原始图片。而 GAN 通过判别器拟合原始图片
扩散模型是一种特殊的 VAE, 其灵感来自于热力学:一个分布可以通过不断地添加噪声变成另一个分布
放到图像生成任务里, 就是来自训练集的图像可以通过不断添加噪声变成符合标准正态分布的图像
扩散模型由正向过程和反向过程这两部分组成, 对应 VAE 中的编码和解码
数学原理
假设真实图像的分布为 $P_{\mathrm{data}}(x)$, 通常无法明确知道其具体形式
实际操作中需要采集大量真实图像来近似这一分布,所采集的图像即服从 $P_{\mathrm{data}}(x)$ 的样本
影像生成模型的目标是学习一个参数化的概率分布 $P_{\theta}(x)$ 去近似真实图像的分布
用最大似然估计转化优化目标
从真实数据分布 $ P_{\text{data}}(x) $ 中随机采样 m 个图像:
$$ { x^1, x^2, \ldots, x^m } $$
定义参数估计目标:
$$ \theta^* = \arg \max_{\theta} \prod_{i=1}^m P_\theta(x^i) $$
其中 $ P_\theta(x^i) $ 表示在参数 $\theta$ 下,模型对数据点 $ x^i $ 的概率密度
下面将最大似然估计转化成最小化 KL 散度
- 取对数简化乘积
$$ \theta^* = \arg \max_{\theta} \prod_{i=1}^m P_\theta(x^i) = \arg \max_{\theta} \log \prod_{i=1}^m P_\theta(x^i) $$
- 转为求和形式
$$ = \arg \max_{\theta} \sum_{i=1}^m \log P_\theta(x^i) $$
- 近似为期望形式(当 m 足够大时)
$$ \approx \arg \max_{\theta} \mathbb{E}{x \sim P{\text{data}}} [\log P_\theta(x)] $$
- 引入真实数据分布的熵项(不减目标值)
$$ = \arg \max_{\theta} \int_x P_{\text{data}}(x) \log P_\theta(x) , dx - \int_x P_{\text{data}}(x) \log P_{\text{data}}(x) , dx $$
- 整理为 KL 散度形式
$$ = \arg \max_{\theta} \int_x P_{\text{data}}(x) \log \frac{P_\theta(x)}{P_{\text{data}}(x)} , dx $$
$$ = \arg \min_{\theta} KL(P_{\text{data}} \parallel P_\theta) $$
KL 散度衡量的是用 $ P*\theta $ 近似 $ P*{\text{data}} $ 时,信息量上的损失或不准确性
通过以上推导,最大似然估计被转化为最小化 KL 散度的优化问题
但是,我们无法直接去最小化这个 KL 散度,因为会遇到无法计算的高维积分问题
并且生成分布 $P_{\text{\theta}}(x)$ 通常由复杂的神经网络定义,直接优化难以提供有效的梯度信息
为了绕过直接优化这个 KL 散度,DDPM 采用变分推断的框架,通过最大化证据下界(Evidence Lower Bound, ELBO)来间接优化模型
推导变分下界
第一步,就是为了简化计算,我们不再计算 $\arg \max_{\theta} \sum_{i=1}^m \log P_\theta(x^i)$,而是直接最大化单个采样点 $x_0$ 的 $\log P_\theta(x_0)$,由此我们可以学习到规律并推广到其它采样点。
那么,如何最大化 $P_\theta(x)$ 呢?我们先来看看纯数学上 $P_\theta(x)$ 如何表示:
对于真实世界的一张图像 $x_0$,若想通过 DDPM 生成它,需要经过 $T$ 个时间步,其中某个时间步 $t$ 发生的事情是:图像 $x_t$ 经过一次 denoise 生成出 $x_{t-1}$。而实际上发生的事情是图像 $x_t$ 经过一次 denoise 生成出了 $G(x_t)$,在这里我们假设 $G(x_t)$ 是一个高斯分布的均值,那么就有 $P_\theta(x_{t-1}|x_t) \propto \exp(-|G(x_t)-x_{t-1}|2)$,从图像 $x_t$ 经过一次 denoise 生成出 $x{t-1}$ 的概率密度正比于 $G(x_t)$ 和 $x_{t-1}$ 的欧式距离的相反数。直观的理解就是,$G(x_t)$ 和 $x_{t-1}$ 越接近,从图像 $x_t$ 经过一次 denoise 生成出 $x_{t-1}$ 的概率越大。
$$ P_\theta(x_0) = \int_{x_1:x_T} P(x_T)P_\theta(x_{T-1}|x_T) \ldots P_\theta(x_{t-1}|x_t) \ldots P_\theta(x_0|x_1) , dx_1 : x_T $$
注:这里为什么要积分呢,因为我们计算的是在模型参数 $\theta$ 下,图像 $x_0$ 的总体概率,也就是说 $P_\theta(x_0)$ 实际上是边缘概率。$x_T$ 只是从高斯噪声中采样的一个点而已,我们想要求的是从高斯噪声生成 $x_0$ 的可能性,因此需要对所有可能的 $x_T$ 做积分,而为了计算 $P_\theta(x_0)$,需要对所有的 $x_T$ 开始的所有可能的中间变量路径 $(x_T, x_{T-1}, \ldots, x_1, x_0)$ 进行积分
stable diffusion
一种基于扩散模型的 文本到图像生成模型,于 2022 年发布,能够根据文本描述生成高质量、逼真的图像
模型组成
用户输入文本,依次经过以下模型,最终得到图片
-
Text Encoder
将文字转化为特征向量
-
Generation Model
负责在潜在空间中从随机噪声生成潜在表示(latent representation)
-
Decoder
将潜在表示转换为高质量图像
上述三个模型分开训练,再组合起来
Text Encoder
常使用 CLIP 的文本编码器
Generation Model
使用 diffusion model
-
工作流程
从标准正态分布中采样一个初始噪声向量 $Z_{\mathrm{T}}$
将 Text Encoder 生成的特征向量作为条件向量 $c$,用于指导生成过程(使最后生成的图像符合文本描述),然后生成模型逐步去除噪声,得到潜在表示 $Z_{0}$(称为逆向扩散) -
训练过程
训练目标是学习一个逆向扩散过程,使得从正态分布中采样的噪声逐步逼近真实的潜在表示分布
1、将 真实的潜在表示(?) 逐步添加噪声,模拟数据到噪声的转化
2、逆向扩散过程学习:借助 denoise model 来近似逆向过程,将噪声恢复到真实的潜在表示
denoise model 通过训练一个 noise predicter 来预测噪声
输入:当前的带噪声的图像 + 当前所在步数 + 文本特征向量
输出:预测的噪声信号
之后用当前的带噪声的图像减去输出的噪声得到下一步的图像
损失函数使用的是:MSE、KL 散度损失、对抗损失等
正向过程
训练阶段中,会在不同时间步添加噪声,训练模型在带噪图像上去噪,让模型学会在各种噪声级别下复原始数据,并学习数据的分布
- 从分布 $q(x_0)$ 中采样得到 $x_0$, 这里的 $x_0$ 即真实图像
- 从离散均匀分布 $Uniform({1, \cdot, T})$ 中随机均匀采样一个值 $t$
- 从标准正态噪声 $e ~ N(0,I)$ 中随机采样得到一个噪声 $t$
- 计算噪声加权组合得到带噪图像 $x_t = \sqrt{avg \alpha_t}x_0 + \sqrt{1 - avg \alpha_t}e$
- 使用 noise predicter 模型预测噪声 $e_{\theta}(\sqrt{avg \alpha_t}x_0 + \sqrt{1 - avg \alpha_t}e)$
- 计算均方误差损失 $||e - e_{\theta}(\sqrt{avg \alpha_t}x_0 + \sqrt{1 - avg \alpha_t}e) ||^{2}$
- 使用梯度下降最小化损失函数
逆向过程
采样阶段,使用训练好的模型从噪声中逐步去噪,生成潜在表示
- 采样一个初始噪声 $x_T$ 服从标准正态分布
- 对 $t = T, T-1, \cdot, 1$ 逐步进行去噪采样, 每一步都是根据训练好的去噪模型 $e*{\theta}$ 预测当前噪声,生成 $x*{t-1}$
$$ x_{t-1} = \frac{1}{\sqrt{\alpha_t}}(x_t - \frac{1-\alpha_t}{\sqrt{1- avg \alpha_t}} e_{\theta}(x_{t}, t)) + \sigma_t · z $$
Decoder
输入的是潜在表示,故需要训练一个 Autoencoder 自动编码器
自动编码器由两个部分组成:
- encoder:将高维图像 $x$ 压缩为低维的潜在表示 $z$
- decoder:将潜在表示 $z$ 解码回高维的图像 $\hat x$
训练目标是最小化 $x$ 与 $\hat x$ 之间的差异,训练完成后取出自动编码器中的 decoder
如何评价生成的图片
量化生成图像与真实图像的差异,比较它们之间在 某个特征空间 的统计特性
先各准备 N 张生成图像和真实图像(通常需要很多张)
为了提取生成图像与真实图像的特征,我们使用 Inception V3 网络 最后的平均池化层的输出 作为图像的特征向量
N 张图片可得到 N 个特征向量,这 N 个特征向量构成其特征矩阵的 N 列
分别计算生成图像和真实图像的均值向量和协方差矩阵:
-
均值向量
生成图像:$\mu_{g} = \frac{1}{N} \sum_{i=1}^{N} g_{i}$
真实图像:$\mu_{r} = \frac{1}{N} \sum_{i=1}^{N} r_{i}$
-
协方差矩阵
生成图像:$C_{g} = \frac{1}{N-1} \sum_{i=1}^{N} (g_{i}-\mu_{g})(g_{i}-\mu_{g})^{\mathrm{T}}$
真实图像:$C_{r} = \frac{1}{N-1} \sum_{i=1}^{N} (r_{i}-\mu_{r})(r_{i}-\mu_{r})^{\mathrm{T}}$
然后计算 Frechet 距离
$$ \mathrm{FID} = \left | \mu_{r}-\mu_{g} \right | ^{2} + Tr(C_{r}+C_{g}-2(C_{r}C_{g})^{1/2}) $$
$\left | \mu_{r} - \mu_{g} \right | ^{2}$ 是生成图像和真实图像的均值向量的欧氏距离的平方
$Tr$ 用于求矩阵的迹(对角线元素之和)
$(C_{r}C_{g})^{1/2}$ 是生成图像和真实图像的协方差矩阵乘积的矩阵平方根
矩阵平方根 $(C_{r}C_{g})^{1/2}$ 的计算方法
先计算其中的矩阵乘积,再对乘积矩阵进行特征值分解或者奇异值分解
FID 距离利用了 Inception V3 网络的高层特征,捕捉图像的高层语义信息,并直接用于衡量生成图像和真实图像的数据分布之间的距离
FID 值越小,图片质量越高
此外 CLIP Score 也可以作为评价方式
先将文本和图像分别进行编码,得到两个特征向量,然后使用余弦相似度计算两个特征向量之间的距离
余弦相似度越接近 1,表示文本和图像越相似,反之越接近-1 则越不相似
$$ \cos(\theta) = \frac{v_{\mathrm{text}} \cdot v_{\mathrm{img}}}{\left | v_{\mathrm{text}} \right | \cdot \left | v_{\mathrm{img}} \right |} $$