白话扩散模型系列一:一文搞懂扩散模型DDPM

469 阅读6分钟

各位佬看文章之前,可以先去看看这个视频,并给这位up主点赞投币,这位佬讲解的太好了:大白话AI

背景

扩散概率模型(Denoising Diffusion Probabilistic Models, DDPM)是一类生成模型,近年来在图像生成、合成等任务中引起了广泛关注。DDPM 的主要思想是通过逐步对数据添加噪声,使数据逐渐逼近高斯分布,然后在生成过程中通过去噪的方式逐步还原出高质量的数据样本。

1.前置知识的学习

1.1 正态分布特性

(1)正态分布的概率密度函数

f(x)=12πσe(xμ)22σ2,记为N(μ,σ2)f(x) = {1 \over \sqrt{2 \pi } \sigma} e^{-{{(x-\mu)^2} \over {2 \sigma^2}}} ,记为N(\mu, \sigma^2)

<img src="DDPM推导笔记.assets/image-20231220205100147.png" alt="image-20231220205100147" style="zoom: 50%;" />

当\mu = 0, \sigma^2=1时,则记为标准正态分布,记为N(0, 1), 又称为高斯分布。

(2)正态分布的基本性质

N(μ1,σ12)+N(μ2,σ22)=N(μ1+μ2,σ12+σ22)aN(μ,σ)=N(aμ,(aσ)2)N(\mu_1, \sigma_1^2) + N(\mu_2, \sigma_2^2) = N(\mu_1+\mu2, \sigma_1^2+\sigma_2^2) \\ a*N(\mu, \sigma) = N(a*\mu, (a*\sigma)^2)

1.2 贝叶斯定理

A, B是两个随机事件, P(A)表示事件A发生的概率,P(B|A)表示A事件发生的情况下B事件发生的概率,则贝叶斯定理如下:

P(AB)=P(BA)P(A)P(B)P(A|B) = {{P(B|A) * P(A)} \over P(B)}

2. 前向过程(加噪)

在这里插入图片描述

如图所示,前向过程则是一个加载过程,在每个时间步,都从正态分布中随机采样一个和图片等大的噪声(也可以理解为噪声图片),则加噪过程:

x1=β1ϵ1+1β1x0x_1 = \sqrt{\beta_1} * \epsilon_1 + \sqrt{1-\beta_1} * x_0

其中x_0表示原始图片,\epsilon_1 表示随机噪声,\beta_1表示扩散速度,T表示扩散的次数,则可以一次推导:

x1=β1ϵ1+1β1x0x2=β2ϵ2+1β2x1x3=β3ϵ3+1β3x2xT=βTϵT+1βTxT1前后关系就可以记为:xt=βtϵt+1βtxt1x_1 = \sqrt{\beta_1} * \epsilon_1 + \sqrt{1-\beta_1} * x_0 \\ x_2 = \sqrt{\beta_2} * \epsilon_2 + \sqrt{1-\beta_2} * x_1 \\ x_3 = \sqrt{\beta_3} * \epsilon_3 + \sqrt{1-\beta_3} * x_2 \\ ······ \\ x_T = \sqrt{\beta_T} * \epsilon_T + \sqrt{1-\beta_T} * x_{T-1} \\ 前后关系就可以记为: \\ x_t = \sqrt{\beta_t} * \epsilon_t + \sqrt{1-\beta_t} * x_{t-1} \\

\beta_0接近0,\beta_T接近1,原因是越到最后扩散速度越快, 而且是自己事先就要定义好的常数,为简化后续运算,令\alpha_t = 1 - \beta_t, 则有:

xt=1αtϵt+αtxt1x_t = \sqrt{1- \alpha_t} * \epsilon_t + \sqrt{\alpha_t} * x_{t-1}

思考:如何能更快的得到x_T?因为如果加噪1000步,岂不是要计算1000次上述的运算!好的,下面介绍怎样依赖正态分布的可加性来简化运算,从而推导出x_0到x_t的关系:

由:xt=1αtϵt+αtxt1xt1=1αt1ϵt1+αt1xt2xt1代入到xt中可以推导出:xt=1αtϵt+αt(1αt1ϵt1+αt1xt2)=at(1at1)ϵt1+1atϵt+atat1xt2其中:ϵt1ϵt是两个随机噪声,且两者是两个独立的随机变量。打个比喻:我们有一个骰子掷两次分别得到ϵt1ϵt,完全可以等效于我们有两个骰子掷一次。即:一个骰子掷两次的概率分布等同于两个骰子掷一次的概率分布,所以,如果我们知道两个骰子掷一次的概率分布,然后进行一次采样即可。由: \\ x_t = \sqrt{1- \alpha_t} * \epsilon_t + \sqrt{\alpha_t} * x_{t-1} \\ x_{t-1} = \sqrt{1- \alpha_{t-1}} * \epsilon_{t-1} + \sqrt{\alpha_{t-1}} * x_{t-2} \\ 把x_{t-1}代入到x_t中可以推导出: \\ x_t = \sqrt{1- \alpha_t} * \epsilon_t + \sqrt{\alpha_t} * (\sqrt{1- \alpha_{t-1}} * \epsilon_{t-1} + \sqrt{\alpha_{t-1}} * x_{t-2}) \\ = \sqrt{a_t(1-a_{t-1})} * \epsilon_{t-1} + \sqrt{1-a_t} * \epsilon_t + \sqrt{a_t a_{t-1}} * x_{t-2} \\ 其中:\epsilon_{t-1} 和 \epsilon_{t} 是两个随机噪声,且两者是两个独立的随机变量。\\ 打个比喻:我们有一个骰子掷两次分别得到\epsilon_{t-1} 和 \epsilon_{t},完全可以等效\\ 于我们有两个骰子掷一次。即:一个骰子掷两次的概率分布等同于两个骰子掷一次的概率分布,所以,\\ 如果我们知道两个骰子掷一次的概率分布,然后进行一次采样即可。 \\
由正态分布的基本性质可知:ϵtϵt1服从N(0,1),即:ϵtN(0,1),ϵt1N(0,1)可以推导出:1atϵtN(0,1αt)at(1at1)ϵt1N(0,atatat1))由正态分布的基本性质可知:\\ \epsilon_t和\epsilon_{t-1}服从N(0, 1),即:\epsilon_t \sim N(0,1), \epsilon_{t-1} \sim N(0,1) \\ 可以推导出: \sqrt{1-a_t} * \epsilon_t \sim N(0, 1- \alpha_t) \\ \sqrt{a_t(1-a_{t-1})} * \epsilon_{t-1} \sim N(0, a_t-a_t*a_{t-1}))
从而推导出:at(1at1)ϵt1+1atϵtN(0,1atat1)从而推导出: \\ \sqrt{a_t(1-a_{t-1})} * \epsilon_{t-1} + \sqrt{1-a_t} * \epsilon_t \sim N(0, 1-a_t*a_{t-1})
进而推导出:xt=1atat1ϵ+atat1xt2,其中:ϵN(0,1atat1)进而推导出:\\ x_t = \sqrt{1-a_t*a_{t-1}} * \epsilon + \sqrt{a_t*a_{t-1}}*x_{t-2}, 其中:\epsilon \sim N(0, 1-a_t*a_{t-1})
这里就可到了xtxt2之间的关系,然后依靠上面的方法就可以一次推导出xtx0的关系(数学归纳法证明),具体如下:xt=1atat1at2...a1ϵ+atat1at2...a1x0其中,ϵN(0,1atat1at2...a1)这里就可到了x_t和x_{t-2}之间的关系,然后依靠上面的方法就可以一次推导出x_t到x_0的关系(数学归纳法证明),具体如下: \\ x_t = \sqrt{1 - a_ta_{t-1}a_{t-2}...a_1} * \epsilon + \sqrt{a_ta_{t-1}a_{t-2}...a_1} * x_0 \\ 其中,\epsilon \sim N(0, 1 - a_ta_{t-1}a_{t-2}...a_1)
为了方便表示,记:aˉt=atat1at2...a1则:xt=1aˉtϵ+aˉtx0为了方便表示,记: \bar{a}_t = a_ta_{t-1}a_{t-2}...a_1 \\ 则: x_t = \sqrt{1 - \bar{a}_t} * \epsilon + \sqrt{\bar{a}_t} x_0

至此,前向过程就记录完成了,我们得到x_0到x_t的关系,并且可以只通过一次采样就能得到。

3. 反向过程(去噪)

在这里插入图片描述

去噪过程就是从x_T一步步反推回x_0。

3.1 反向原理推导

由贝叶斯定理:

P(AB)=P(BA)P(A)P(B)P(A|B) = {{P(B|A) * P(A)} \over P(B)}

我们可以令:

由于xtxt1是一个随机过程,则令:P(xt1xt):表示在给定xt的情况下,xt1的概率。套用贝叶斯定理得:P(xt1xt)=P(xtxt1)P(xt1)P(xt)其中,P(xt)P(xt1)分别表示xttt1的概率,也就是从x0原图得到它们的概率。由于x_t到x_{t-1}是一个随机过程,则令: \\ P(x_{t-1}|x_t): 表示在给定x_t的情况下,x_{t-1}的概率。 \\ 套用贝叶斯定理得: \\ P(x_{t-1} | x_t) = { P(x_t | x_{t-1}) * P(x_{t-1}) \over P(x_t)} \\ 其中,P(x_t)和P(x_{t-1})分别表示x_t和t_{t-1}的概率,也就是从x_0原图得到它们的概率。
所以,可以在每个式子后面添加一个先验x0,即:P(xt1xt,x0)=P(xtxt1,x0)P(xt1x0)P(xtx0)所以,可以在每个式子后面添加一个先验x0,即: \\ P(x_{t-1} | x_t,x_0) = { P(x_t | x_{t-1},x_0) * P(x_{t-1} | x_0) \over P(x_t | x_0)} \\
有:P(xtxt1,x0)给定xt1xt的概率。前向过程中可知:xt=1αtϵt+αtxt1xt=1aˉtϵ+aˉtx0ϵtϵ分别服从N(0,1)从而推导出:xtN(atxt1,1at)或:xtN(aˉtx0,1aˉt)以及:xt1N(aˉt1x0,1aˉt1)有: \\ P(x_t|x_{t-1}, x_0) 给定x_{t-1}到x_t的概率。 \\ 前向过程中可知: \\ x_t = \sqrt{1- \alpha_t} * \epsilon_t + \sqrt{\alpha_t} * x_{t-1} \\ x_t = \sqrt{1 - \bar{a}_t} * \epsilon + \sqrt{\bar{a}_t} x_0 \\ \epsilon_t和\epsilon分别服从N(0, 1) \\ 从而推导出: \\ x_t \sim N(\sqrt{a_t} x_{t-1}, 1-a_t) \\ 或: \\ x_t \sim N(\sqrt{\bar{a}_t} x_0, 1-\bar{a}_t) \\ 以及: \\ x_{t-1} \sim N(\sqrt{\bar{a}_{t-1}} x_0, 1-\bar{a}_{t-1}) \\

然后就可以把他们分别写成概率密度形式:

<img src="DDPM推导笔记.assets/image-20231221221557918.png" alt="image-20231221221557918" style="zoom:50%;" />

然后将概率密度函数带入到贝叶斯定理中,就可以得到:

在这里插入图片描述

化简成高斯分布得:

P(x_{t-1}|x_t, x_0) =

<img src="DDPM推导笔记.assets/image-20231221222858789.png" alt="image-20231221222858789" style="zoom:50%;" />

由此推导出:

在这里插入图片描述

我们的目的是通过xt求出xt1,然后由xt1推导出xt2直到求出x0但现在的式子中出现了x0,怎么办?没关系,我们之前由xtx0的关系:xt=1aˉtϵ+aˉtx0我们的目的是通过x_t求出x_{t-1},然后由x_{t-1}推导出x_{t-2}···直到求出x_0,\\ 但现在的式子中出现了x_0,怎么办? \\ 没关系,我们之前由x_t和x_0的关系: \\ x_t = \sqrt{1 - \bar{a}_t} * \epsilon + \sqrt{\bar{a}_t} x_0 \\

变换可以得到:

<img src="DDPM推导笔记.assets/image-20231221223547841.png" alt="image-20231221223547841" style="zoom:50%;" />

将它带入到P(x_{t-1}|x_t, x_0)的概率密度函数中可得:

在这里插入图片描述

它表示的是:对于任意x_t的图像都可以用x_0加载而来;而只要知道了从x_0到x_t加入的噪声\epsilon,就能得到它前一时刻x_{t-1}的概率分布,即:P(x_{t-1}|x_t, x_0) 。

其中,可以通过数学变换将P(x_{t-1}|x_t, x_0)中的均值部分(即\mu)变换成如下形式,更利于代码实现:

在这里插入图片描述

这样P(x_{t-1}|x_t, x_0)服从概率分布如下:

P(xt1xt,x0)N(1at(xt1at1aˉtϵ),(βt(1aˉt1)1aˉt)2)P(x_{t-1}|x_t, x_0) \sim N({1 \over \sqrt{a_t}} (x_t - {{1-a_t} \over \sqrt{1-\bar{a}_t}} \epsilon), (\sqrt{{\beta_t (1-\bar{a}_{t-1}) \over {1- \bar{a}_t}}})^2)

这里我们就需要使用神经网络,输入x_t时刻的图像,预测此图像相对于某个x_0原图加入的噪声\epsilon。

如图所示,也就是说:

<img src="DDPM推导笔记.assets/image-20231221224402408.png" alt="image-20231221224402408" style="zoom: 50%;" />

Step1: 在神经网络中,输入x_t时刻图像,训练得到此图像相对于某个x_0原图加入的噪声\epsilon。

*Step2: *将噪声\epsilon带入到x_{t-1}的概率密度函数P(x_{t-1}|x_t, x_0)中;

*Step3: *从x_{t-1}的概率密度函数P(x_{t-1}|x_t, x_0)中随机采样,得到x_{t-1}(即t-1时刻对应的图像);

Step4: 将x_{t-1}作为神经网络的输入,带入到Step1中,循环Step1 ~ Step3,直到得到x_0

DDPM中的神经网络选用的UNet.

3.2 疑难点注解

(1)在反向传播的过程中,训练的\epsilon是个固定的值,还是根据t的变化而变化的值?

是个固定的值!

理由:在推导反向传播时,为了去掉x_0而引入了x_t与x_0的关系,

xt=1aˉtϵ+aˉtx0其中,ϵN(0,1atat1at2...a1)x_t = \sqrt{1 - \bar{a}_t} * \epsilon + \sqrt{\bar{a}_t} x_0 \\ 其中,\epsilon \sim N(0, 1 - a_ta_{t-1}a_{t-2}...a_1)

<img src="DDPM推导笔记.assets/image-20240105104637095.png" alt="image-20240105104637095" style="zoom:50%;" />

而x_t = \sqrt{1 - \bar{a}_t} * \epsilon + \sqrt{\bar{a}_t} x_0中的\epsilon在前向传播中已经确定好了,所以神经网络训练的\epsilon就是要去接近它。因为在训练过程中的损失函数就是使用的MES_Loss使两个\epsilon尽可能一致。

(2)很多代码中x_t = \sqrt{1 - \bar{a}t} * \epsilon + \sqrt{\bar{a}t} x_0的\epsilon并不是从\epsilon \sim N(0, 1 - a_ta{t-1}a{t-2}...a_1)采样的,而是直接从N(0,1)中采样的,这是为什么?

理由:因为a_ta_{t-1}a_{t-2}...a_1非常趋近于0, 所以1-a_ta_{t-1}a_{t-2}...a_1非常趋近于1。故直接从N(0,1)中采样。

(3)训练过程中的Step3: 从x_{t-1}的概率密度函数P(x_{t-1}|x_t, x_0)中随机采样,得到x_{t-1}(即t-1时刻对应的图像),其中的采样是怎么完成的?

千万不要被什么"采样"、"概率分布"等字眼吓到,其实非常简单!从代码的角度解释就是:

1)我们已知:

P(xt1xt,x0)N(1at(xt1at1aˉtϵ),(βt(1aˉt1)1aˉt)2)P(x_{t-1}|x_t, x_0) \sim N({1 \over \sqrt{a_t}} (x_t - {{1-a_t} \over \sqrt{1-\bar{a}_t}} \epsilon), (\sqrt{{\beta_t (1-\bar{a}_{t-1}) \over {1- \bar{a}_t}}})^2)

其中我们输入的是x_t, 而式子中的\epsilon是神经网络需要预测的,其中的a_t、 \bar{a}_t、 \beta_t都是事先定义好的。

2)从概率分布中采样

我们现在有了x_t, \epsilon和概率分布,怎样得到x_{t-1}呢?很简单:

*Step1: *从N(0,1)中随机采样一个噪声,代码如下:


noise = torch.randn_like(x_t) # randn_like(x_t)表示从标准正态分布中采样一个和x_t同维度的noise

*Step2: *获取概率中的方差var

var=βt(1aˉt1)1aˉtvar = { \beta_t (1-\bar{a}_{t-1}) \over {1- \bar{a}_t} }

里面的参数都是已知的。

*Step3: *获取概率分布中的均值mean

1at(xt1at1aˉtϵ){1 \over \sqrt{a_t}} (x_t - {{1-a_t} \over \sqrt{1-\bar{a}_t}} \epsilon)

里面的x_t是输入,\epsilon是神经网络预测的,其他的都是已知的。

*Step4: *从概率分布中采样

很简单的,就是x_{t-1}=mean + noise * sqrt(var)即可,这样就表示从:

P(xt1xt,x0)N(1at(xt1at1aˉtϵ),(βt(1aˉt1)1aˉt)2)P(x_{t-1}|x_t, x_0) \sim N({1 \over \sqrt{a_t}} (x_t - {{1-a_t} \over \sqrt{1-\bar{a}_t}} \epsilon), (\sqrt{{\beta_t (1-\bar{a}_{t-1}) \over {1- \bar{a}_t}}})^2)

进行采样,即得到了x_{t-1}, 然后把x_{t-1}带入到神经网络,重新预测\epsilon,重复上述步骤,就可以得到x_{t-2},一直持续,就可以得到x_0。

(4)前向加噪是不是只需要一步即可,而反向去噪则需要T步?

对!

理由:前向加噪过程本来是需要T步的,但通过正态分布的性质,让我们一次采样就可以得到和T次采样一样的效果,所以只需要一次即可!

而反向传播中,则需要T步,即:若T=1000,则需要进行1000次预测。因为反向传播依赖马尔科夫链,需要已知x_{t}才能得到x_{t-1},只能这样一次次推导才能得出x_0。这也是DDPM很大的一个缺点,推理太慢!后面才有DDIM的改进。

至此,本文结束!