扩散模型的开山之作Denoising Diffusion Probabilistic Models ↗。这篇帖子并不把重心放在详细的公式推导上,在看见树木之前我们最好先看得见森林。
什么是diffusion model?#
现在假如我们想要生成一张256x256x3的图片,那么我们需要知道其中每一个像素点需要安放在哪一个位置上。换句话说,我们需要得知像素x和其对应位置p之间的函数关系f(x)。但事实上这个分布函数是非常复杂,或者几乎是不可能获取的。
这时候我们就需要换一种思路,找到能够满足我们的数据分布的基本似然函数。这就是diffusion model的最初构想。diffusion model(扩散模型)来源于物理学中热力学扩散的概念,核心有正向扩散和反向扩散两部分,分别对应加噪和去噪的过程。扩散模型的核心思想来源于模拟物质在空间中的扩散过程,只不过在具体任务中“物质”对应的是样本点,“空间”指的是数据空间。
正向扩散#
为什么要加噪(正向扩散)呢?因为原有的图像数据具有非常复杂的特征,数据分布难以把握,加噪可以简化训练流程,对图像加噪最后形成纯高斯噪声的过程也是一种数据加强的过程,模型更容易学习到鲁棒的图像特征。同时加噪过程也可以看做是一个马尔科夫链,每一步加上去的噪声都是基于当前状态的。在一步步加噪过程中模型的学习量更丰富,训练过程更稳健。
反向扩散#
反向扩散是正向扩散的逆过程,也可以看做逆马尔科夫链,逐步从当前的数据中去处噪声直到恢复原来的数据分布。每一次去噪都基于当前的状态,在去噪过程中模型就可以有效学习数据的核心特征,并学习如何一步步从完全随机的状态出发,复原得到原始图片或者生成其他的图片。
扩散细节#
前扩散核与反向扩散核#
q(xt∣xt−1)是前扩散核,表示在已知给定图像xt−1的情况下推出新加噪图像xt的过渡函数。同样地,反扩散核pθ(xt−1∣xt)表示模型在通过降噪还原图像的时候,已知xt的条件下推出xt−1分布的过渡函数,θ表示模型学习反向扩散过程分布的参数。
正向扩散的细节#
正向扩散可表示为一个马尔科夫链,定义为:
q(xt∣xt−1)=N(xt;1−βtxt−1,βtI)
q(x1:T∣x0)=∏t=1Tq(xt∣xt−1)
首先从数据集中获取一张图像x0,模型需要对其累加噪声T次获得x1,x2,x3......xT,这里再额外给定中间叠加噪声的高斯分布方差超参数βt∈(0,1)t=1T.随着t的增大,x越来越接近纯高斯噪声。每一步更新的xt都可以看做是与原本的xt−1有一定关联,但是又在原基础上叠加了一定的噪声。各个时间段的图像为各向同性高斯分布。
在diffusion正向扩散过程中能通过x0和β直接计算xt对于快速扩散非常重要。但是在正式开始计算之前,我们还需要引入另一个概念:重参数。重参数在众多技术中都有应用(gumbel softmax, VAE)。重参数(reparameter)的初衷是,如果我们需要从某一个分布中随机选取一个样本,这样的选取方式是无法计算梯度的。例如我们先前约定的加噪过程,每次随机加上的βt满足高斯分布,但是对于β的梯度我们无从计算。因此我们可以通过引入另一个变量将随机性引导过去,来使得式子可微。例如还是从高斯分布中选取一个样本(约定叫做z)这个例子,我们通过引入ϵ将式子改写成这样:
z=μθ+σθ⊙ϵ,ϵ∼N(0,I)
整个采样过程依旧可导,但是随机性被转嫁到了ϵ上。
了解了重参数技术,我们现在将它应用于往数据上一步步加噪的过程。现在开始正向扩散过程精确计算每一步xt的推导。
约定:at=1−βt,并且αt=∏i=1Tαi(当然对z也是同理),将xt展开:
xt=αtxt−1+1−αtz1wherez1,z2,…∼N(0,I)
=αt(αt−1xt−2+1−αt−1z2)+1−αtz1
=αtαt−1xt−2+(αt(1−αt−1)z2+1−αtz1)
=αtαt−1xt−2+1−αtαt−1zˉ2wherezˉ2∼N(0,I)
=⋯
=αˉtx0+1−αˉtzt
反向扩散的细节#
反向扩散是正向扩散的逆过程,它不太像和正向扩散一样独立进行的运算,它更像是正向扩散的完全逆过程,登山路途中的按照原路返回。意思是我们需要一步步“撤销”正向传播的操作。和FDK一样,我们也使用高斯分布来定义RDK的参数情况。如果一步步按部就班的删除加上的噪声,我们就会回到原始分布;而在中间学习新的轨迹,我们就能学习如何从纯高斯噪声开始生成相似的但是全新的样本。
本质上反向扩散就是逐步得到逆转之后的q(xt−1∣xt)。直接求得分布是困难的,因此使用RDK预测这样一个逆向的分布pθ. 对于每一次去噪,本质是让模型学习一个条件分布pθ(xt−1∣xt).这个分布通常被假设为高斯分布:
q(xt−1∣xt,x0)=N(xt−1;μ~(xt,x0),β~tI)
展开如下:
q(xt−1∣xt,x0)=q(xt∣xt−1,x0)q(xt∣x0)q(xt−1∣x0)(7-1)
∝exp(−21(βt(xt−αtxt−1)2+1−αt−1(xt−1−αt−1x0)2−1−αt(xt−αtx0)2))(7-2)
=exp(−21((βtαt+1−αt−11)xt−12−2(βtαtxt+1−αt−1αt−1x0)xt−1+C(xt,x0)))(7-3)
可以发现(7-1)将过程由逆向又转换成了前向。再根据:
exp(−2σ2(x−μ)2)=exp(−21(σ21x2−σ22μx+σ2μ2))
我们对(7-3)稍作整理可以得出来μ~(xt,x0)的值(之前提过,xt−1的均值就是这个函数):
σ21=βt1=(βtαt+1−αt−1)1;β~t=1−αt1−αt−1⋅βt
σ22μ=βˉt2μˉt(xt,x0)=(−βt2αtxt+1−αt−12αt−1x0)
联立解得μ为:
μ~t(xt,x0)=1−αˉtat(1−αˉt−1)xt+1−αˉtαˉt−1βtx0.
我们知道xt是可以仅由t和x0算出来的,那么代入有:
μθ(xt,t)=αt1(xt−1−αˉtβtzθ(xt,t)).
总结一下,反向扩散的过程可以总结为:
- 首先通过xt和t预测噪声zθ(t)(后期在神经网络学习如何预测),并计算得出μ(xt,x0).
- 至于方差,通常认为β~t=1−αˉt1−αt−1代入计算。在GLIDE中采用另一种范式。
- 得到q(xt−1∣xt), 利用重参数得到xt−1。
训练扩散#
这部分的公式非常非常多,具体细节可以看论文原文,在此仅总结论文提供的流程,够用。
总体来说训练是:
- 获取输入 (x0),从1...T随机采样一个(t).
- 从标准高斯分布采样一个噪声 (zˉt∼N(0,I)).
- 最小化 (∣∣zˉt−zθ(αˉtx0+1−αˉtzˉt,t)∣∣).