各位佬看文章之前,可以先去看看这个视频,并给这位up主点赞投币,这位佬讲解的太好了:大白话AI
背景
扩散概率模型(Denoising Diffusion Probabilistic Models, DDPM)是一类生成模型,近年来在图像生成、合成等任务中引起了广泛关注。DDPM 的主要思想是通过逐步对数据添加噪声,使数据逐渐逼近高斯分布,然后在生成过程中通过去噪的方式逐步还原出高质量的数据样本。
1.前置知识的学习
1.1 正态分布特性
(1)正态分布的概率密度函数
f(x)=2πσ1e−2σ2(x−μ)2,记为N(μ,σ2)

当\mu = 0, \sigma^2=1时,则记为标准正态分布,记为N(0, 1), 又称为高斯分布。
(2)正态分布的基本性质
N(μ1,σ12)+N(μ2,σ22)=N(μ1+μ2,σ12+σ22)a∗N(μ,σ)=N(a∗μ,(a∗σ)2)
1.2 贝叶斯定理
A, B是两个随机事件, P(A)表示事件A发生的概率,P(B|A)表示A事件发生的情况下B事件发生的概率,则贝叶斯定理如下:
P(A∣B)=P(B)P(B∣A)∗P(A)
2. 前向过程(加噪)

如图所示,前向过程则是一个加载过程,在每个时间步,都从正态分布中随机采样一个和图片等大的噪声(也可以理解为噪声图片),则加噪过程:
x1=β1∗ϵ1+1−β1∗x0
其中x_0表示原始图片,\epsilon_1 表示随机噪声,\beta_1表示扩散速度,T表示扩散的次数,则可以一次推导:
x1=β1∗ϵ1+1−β1∗x0x2=β2∗ϵ2+1−β2∗x1x3=β3∗ϵ3+1−β3∗x2⋅⋅⋅⋅⋅⋅xT=βT∗ϵT+1−βT∗xT−1前后关系就可以记为:xt=βt∗ϵt+1−βt∗xt−1
\beta_0接近0,\beta_T接近1,原因是越到最后扩散速度越快, 而且是自己事先就要定义好的常数,为简化后续运算,令\alpha_t = 1 - \beta_t, 则有:
xt=1−αt∗ϵt+αt∗xt−1
思考:如何能更快的得到x_T?因为如果加噪1000步,岂不是要计算1000次上述的运算!好的,下面介绍怎样依赖正态分布的可加性来简化运算,从而推导出x_0到x_t的关系:
由:xt=1−αt∗ϵt+αt∗xt−1xt−1=1−αt−1∗ϵt−1+αt−1∗xt−2把xt−1代入到xt中可以推导出:xt=1−αt∗ϵt+αt∗(1−αt−1∗ϵt−1+αt−1∗xt−2)=at(1−at−1)∗ϵt−1+1−at∗ϵt+atat−1∗xt−2其中:ϵt−1和ϵt是两个随机噪声,且两者是两个独立的随机变量。打个比喻:我们有一个骰子掷两次分别得到ϵt−1和ϵt,完全可以等效于我们有两个骰子掷一次。即:一个骰子掷两次的概率分布等同于两个骰子掷一次的概率分布,所以,如果我们知道两个骰子掷一次的概率分布,然后进行一次采样即可。
由正态分布的基本性质可知:ϵt和ϵt−1服从N(0,1),即:ϵt∼N(0,1),ϵt−1∼N(0,1)可以推导出:1−at∗ϵt∼N(0,1−αt)at(1−at−1)∗ϵt−1∼N(0,at−at∗at−1))
从而推导出:at(1−at−1)∗ϵt−1+1−at∗ϵt∼N(0,1−at∗at−1)
进而推导出:xt=1−at∗at−1∗ϵ+at∗at−1∗xt−2,其中:ϵ∼N(0,1−at∗at−1)
这里就可到了xt和xt−2之间的关系,然后依靠上面的方法就可以一次推导出xt到x0的关系(数学归纳法证明),具体如下:xt=1−atat−1at−2...a1∗ϵ+atat−1at−2...a1∗x0其中,ϵ∼N(0,1−atat−1at−2...a1)
为了方便表示,记:aˉt=atat−1at−2...a1则:xt=1−aˉt∗ϵ+aˉtx0
至此,前向过程就记录完成了,我们得到x_0到x_t的关系,并且可以只通过一次采样就能得到。
3. 反向过程(去噪)

去噪过程就是从x_T一步步反推回x_0。
3.1 反向原理推导
由贝叶斯定理:
P(A∣B)=P(B)P(B∣A)∗P(A)
我们可以令:
由于xt到xt−1是一个随机过程,则令:P(xt−1∣xt):表示在给定xt的情况下,xt−1的概率。套用贝叶斯定理得:P(xt−1∣xt)=P(xt)P(xt∣xt−1)∗P(xt−1)其中,P(xt)和P(xt−1)分别表示xt和tt−1的概率,也就是从x0原图得到它们的概率。
所以,可以在每个式子后面添加一个先验x0,即:P(xt−1∣xt,x0)=P(xt∣x0)P(xt∣xt−1,x0)∗P(xt−1∣x0)
有:P(xt∣xt−1,x0)给定xt−1到xt的概率。前向过程中可知:xt=1−αt∗ϵt+αt∗xt−1xt=1−aˉt∗ϵ+aˉtx0ϵt和ϵ分别服从N(0,1)从而推导出:xt∼N(atxt−1,1−at)或:xt∼N(aˉtx0,1−aˉt)以及:xt−1∼N(aˉt−1x0,1−aˉt−1)
然后就可以把他们分别写成概率密度形式:

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

化简成高斯分布得:
P(x_{t-1}|x_t, x_0) =

由此推导出:

我们的目的是通过xt求出xt−1,然后由xt−1推导出xt−2⋅⋅⋅直到求出x0,但现在的式子中出现了x0,怎么办?没关系,我们之前由xt和x0的关系:xt=1−aˉt∗ϵ+aˉtx0
变换可以得到:

将它带入到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(xt−1∣xt,x0)∼N(at1(xt−1−aˉt1−atϵ),(1−aˉtβt(1−aˉt−1))2)
这里我们就需要使用神经网络,输入x_t时刻的图像,预测此图像相对于某个x_0原图加入的噪声\epsilon。
如图所示,也就是说:

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=1−aˉt∗ϵ+aˉtx0其中,ϵ∼N(0,1−atat−1at−2...a1)

而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(xt−1∣xt,x0)∼N(at1(xt−1−aˉt1−atϵ),(1−aˉtβt(1−aˉt−1))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=1−aˉtβt(1−aˉt−1)
里面的参数都是已知的。
*Step3: *获取概率分布中的均值mean
at1(xt−1−aˉt1−atϵ)
里面的x_t是输入,\epsilon是神经网络预测的,其他的都是已知的。
*Step4: *从概率分布中采样
很简单的,就是x_{t-1}=mean + noise * sqrt(var)即可,这样就表示从:
P(xt−1∣xt,x0)∼N(at1(xt−1−aˉt1−atϵ),(1−aˉtβt(1−aˉt−1))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的改进。
至此,本文结束!