赞
踩
图中: x 0 x_0 x0为图像, z z z为采样自正态分布的噪音
扩散模型**是受非平衡热力学的启发。它们定义一个扩散步骤的马尔可夫链,逐渐向数据添加随机噪声,然后学习逆扩散过程,从噪声中构建所需的数据样本。与VAE或流动模型不同,扩散模型是用固定的程序学习的,而且隐变量具有高维度。
训练阶段,是在图片中添加噪声,给网络输入这一张添加噪声的图片,网络需要预测的则是添加的噪声。
使用阶段,由随机生成的噪声,使用网络预测添加了什么噪声,然后逐步去除噪声,直到还原。
、
添加噪声的过程:
这里定义了两个参数 α t \alpha_t αt、 β t \beta_t βt;( t t t的范围为0~ T T T之间的整数, β t \beta_t βt 从 β 1 \beta_1 β1变化到 β T \beta_T βT,是逐渐变大的,论文中是从0.0001等量的增加 T T T次,直到0.002 )
而 α t \alpha_t αt与 β t \beta_t βt的关系为:
α t = 1 − β t \alpha_t = 1- \beta_t αt=1−βt (1)
T T T表示的是,由图片通过逐步添加噪声直至完全变为纯噪声的过程所需要经历的次数,也就是图片需要总计需要添加噪声的步数。而 t t t则代表的是 T T T中具体的某一步。
则给图像添加噪声的过程的表达式可以写为:
x t = α t x t − 1 + 1 − α t z t x_t=\sqrt{\alpha_t}x_{t-1}+\sqrt{1-\alpha_t}z_t xt=αt xt−1+1−αt zt (2)
x t x_t xt表示的是第 t t t扩散步时,添加噪声后的图片,而 x t − 1 x_{t-1} xt−1是第 t − 1 t-1 t−1时刻所获得的图片; z t z_t zt表示的是 t t t时刻所添加的噪声,该噪声采样自标准正态分布 N ( 0 , 1 ) N(0,1) N(0,1)
那么可以依照公式(2)依次从原始图像 x 0 x_0 x0逐步添加噪声,扩散至 x T x_T xT:
x 1 = α 1 x 0 + 1 − α 1 z 1 x_1=\sqrt{\alpha_1}x_{0}+\sqrt{1-\alpha_1}z_1 x1=α1 x0+1−α1 z1
x 2 = α 2 x 1 + 1 − α 2 z 2 x_2=\sqrt{\alpha_2}x_{1}+\sqrt{1-\alpha_2}z_2 x2=α2 x1+1−α2 z2
……
x t = α t x t − 1 + 1 − α t z t x_t=\sqrt{\alpha_t}x_{t-1}+\sqrt{1-\alpha_t}z_t xt=αt xt−1+1−αt zt
……
x T = α T x T − 1 + 1 − α T z T x_T=\sqrt{\alpha_T}x_{T-1}+\sqrt{1-\alpha_T}z_T xT=αT xT−1+1−αT zT
由此可以看出 β t \beta_t βt逐渐增加,相应的 α t \alpha_t αt逐渐减小, 1 − α t 1-\alpha_t 1−αt则是逐渐增大的,也就是说,添加的噪声是逐步增加的,而原始图像的比例是逐渐减小的,并且噪声添加的程度是逐次扩大的。
但对网络的训练,数据是需要随机采样的,每次采样到 t t t时刻的时候,都从 x 0 x_0 x0开始递推则太过于繁琐。
所以需要一次就计算出来:
将式 : x t − 1 = α t − 1 x t − 2 + 1 − α t − 1 z t − 1 x_{t-1}=\sqrt{\alpha_{t-1}}x_{t-2}+\sqrt{1-\alpha_{t-1}}z_{t-1} xt−1=αt−1 xt−2+1−αt−1 zt−1带入(2)式中,可得
x t = α t ( α t − 1 x t − 2 + 1 − α t − 1 z t − 1 ) + 1 − α t z t x_t=\sqrt{\alpha_t}(\sqrt{\alpha_{t-1}}x_{t-2}+\sqrt{1-\alpha_{t-1}}z_{t-1})+\sqrt{1-\alpha_t}z_t xt=αt (αt−1 xt−2+1−αt−1 zt−1)+1−αt zt
式子展开为:
x t = α t α t − 1 x t − 2 + α t 1 − α t − 1 z t − 1 + 1 − α t z t x_t=\sqrt{\alpha_t}\sqrt{\alpha_{t-1}}x_{t-2}+\sqrt{\alpha_t}\sqrt{1-\alpha_{t-1}}z_{t-1}+\sqrt{1-\alpha_t}z_t xt=αt αt−1 xt−2+αt 1−αt−1 zt−1+1−αt zt
= α t α t − 1 x t − 2 + ( α t ( 1 − α t − 1 ) z t − 1 + 1 − α t z t ) =\sqrt{\alpha_t}\sqrt{\alpha_{t-1}}x_{t-2}+(\sqrt{\alpha_t (1- \alpha_{t-1})}z_{t-1}+\sqrt{1-\alpha_t}z_t) =αt αt−1 xt−2+(αt(1−αt−1) zt−1+1−αt zt)
其中每次加入的噪声—— z 1 , z 2 , . . . , z t − 1 , z t , . . . z T z_1,z_2,...,z_{t-1},z_t,...z_T z1,z2,...,zt−1,zt,...zT——都是服从正态分布 N ( 0 , 1 ) N(0,1) N(0,1)
所以可以将
z t − 1 z_{t-1} zt−1和 z t z_t zt之间的系数合并在一起,因为正太分布乘以一个系数,只改变方差,而 N ( 0 , σ 1 2 ) + N ( 0 , σ 2 2 ) ∼ N ( 0 , σ 1 2 + σ 2 2 ) N(0,\sigma_1^2)+N(0,\sigma_2^2) \sim N(0,\sigma_1^2+\sigma_2^2 ) N(0,σ12)+N(0,σ22)∼N(0,σ12+σ22)
所以
x t = α t α t − 1 x t − 2 + ( α t ( 1 − α t − 1 ) z t − 1 + 1 − α t z t ) x_t=\sqrt{\alpha_t}\sqrt{\alpha_{t-1}}x_{t-2}+(\sqrt{\alpha_t (1- \alpha_{t-1})}z_{t-1}+\sqrt{1-\alpha_t}z_t) xt=αt αt−1 xt−2+(αt(1−αt−1) zt−1+1−αt zt)
= α t α t − 1 x t − 2 + ( a t ( 1 − a t − 1 ) + 1 − a t ) z =\sqrt{\alpha_t}\sqrt{\alpha_{t-1}}x_{t-2}+(\sqrt{a_t(1-a_{t-1})+1-a_t})z =αt αt−1 xt−2+(at(1−at−1)+1−at )z
= α t α t − 1 x t − 2 + ( 1 − a t a t − 1 ) z =\sqrt{\alpha_t\alpha_{t-1}}x_{t-2}+(\sqrt{1-a_t a_{t-1}})z =αtαt−1 xt−2+(1−atat−1 )z
再将 x t − 2 = α t − 2 x t − 3 + 1 − α t − 2 z t − 2 x_{t-2}=\sqrt{\alpha_{t-2}}x_{t-3}+\sqrt{1-\alpha_{t-2}}z_{t-2} xt−2=αt−2 xt−3+1−αt−2 zt−2带入上式,循环往复,将 x 1 x_1 x1带入,可得
x t = α t α t − 1 . . . α 2 α 1 x t − 1 + ( 1 − α t α t − 1 . . . α 2 α 1 ) z x_t=\sqrt{\alpha_t\alpha_{t-1}...\alpha_2 \alpha_1}x_{t-1}+(\sqrt{1-\alpha_t\alpha_{t-1}...\alpha_2 \alpha_1})z xt=αtαt−1...α2α1 xt−1+(1−αtαt−1...α2α1 )z
= α t ‾ x 0 + ( 1 − a t ‾ ) z =\sqrt{\overline{\alpha_t}}x_{0}+(\sqrt{1-\overline{a_t}})z =αt x0+(1−at )z (3)
其中 α t ‾ \overline{\alpha_t} αt表示从 α 1 \alpha_1 α1到 α t \alpha_t αt的连乘
、
因此,扩散模型的训练过程如下:
详细训练过程的代码过程如下:
for i, (x_0) in enumerate(tqdm_data_loader): # 由数据加载器加载数据,
x_0 = x_0.to(device) # 将数据加载至相应的运行设备(device)
t = torch.randint(1, T, size=(x_0.shape[0],), device=device) # 对每一张图片随机在1~T的扩散步中进行采样
sqrt_alpha_t_bar = torch.gather(sqrt_alphas_bar, dim=0, index=t).reshape(-1, 1, 1, 1) # 取得不同t下的 根号下alpha_t的连乘
"""取得不同t下的 根号下的一减alpha_t的连乘"""
sqrt_one_minus_alpha_t_bar = torch.gather(sqrt_one_minus_alphas_bar, dim=0, index=t).reshape(-1, 1, 1, 1)
noise = torch.randn_like(x_0).to(device) # 从标准正态分布中采样得到z
x_t = sqrt_alpha_t_bar * x_0 + sqrt_one_minus_alpha_t_bar * noise # 计算x_t
out = net_model(x_t, t) # 将x_t输入模型,得到输出
loss = loss_function(out, noise) # 将模型的输出,同添加的噪声做损失
optimizer.zero_grad() # 优化器的梯度清零
loss.backward() # 由损失反向求导
optimizer.step() # 优化器更新参数
、
使用过程是从 x T x_T xT一步一步取出噪声,推测出 x 0 x_0 x0
也就是说,需要在已知 x T x_T xT的情况下,先反推 x t − 1 x_{t-1} xt−1,然后推 x t − 2 x_{t-2} xt−2……最终推测得到 x 0 x_0 x0
根据贝叶斯公式推导为:
x
t
−
1
=
1
α
t
(
x
t
−
1
−
α
t
1
−
α
t
‾
M
(
x
t
,
t
)
)
+
β
t
z
x_{t-1}=\frac{1}{\sqrt{\alpha_t}}(x_t-\frac{1-\alpha_t}{\sqrt{1-\overline{\alpha_t}}}M(x_t, t))+\sqrt{\beta_t}z
xt−1=αt
1(xt−1−αt
1−αtM(xt,t))+βt
z
则整个算法为:
具体代码如下:
for t_step in reversed(range(T)): # 从T开始向零迭代
t = t_step
t = torch.tensor(t).to(device)
z = torch.randn_like(x_t,device=device) if t_step > 0 else 0 # 如果t大于零,则采样自标准正态分布,否则为零
"""按照公式计算x_{t-1}"""
x_t_minus_one = torch.sqrt(1/alphas[t])*(x_t-(1-alphas[t])*model(x_t, t.reshape(1,))/torch.sqrt(1-alphas_bar[t]))+torch.sqrt(betas[t])*z
x_t = x_t_minus_one
、
因为设备有限,训练网红人脸数据,测试时网络生成的结果如下:这是在一张3080ti上训练得到的结果
、
模型使用UNet,并具有第t扩散步的位置编码信息。
、
github:https://github.com/HibikiJie/Diffusion-Models
权重
链接:https://pan.baidu.com/s/19PuZr6duixJaSU1kvmn8Vg
码:yhR9
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。