当前位置:   article > 正文

扩散模型Diffusion Model与DDPM_time embedding

time embedding

 diffusion model是2015年的一篇文章,

https://arxiv.org/pdf/1503.03585.pdf

但是2020年的DDPM之后,才开始逐渐火起来的,

https://arxiv.org/abs/2006.11239

diffusion model

最近Diffusion Model被用在于图片生成模型当中,当前很多的模型都在使用diffusion model作为生成范式,如GLIDE,DALLE2,Imagen,和一系列Image Editing方法等等)。diffusion model相对于VAE、GAN模型的优点在于,其具有更多的可能性。

为什么叫做diffusion model?

diffusion这个词来源于热力学的启发,在热力学里,如果有2个物质混合在一起,分别是高密度的和低密度的,那么高密度的物质就会扩散到低密度,比如喷了香水,随着时间的扩散,最后香水就会充斥着整个房间,最后趋向于平衡。

diffusion model简单理解

从概念上讲,这个diffusion model很简单,假设你有一个图片,记为X0,如下图,你每次对图像加一点噪声,加一次噪声记为Xt+1,不断对其加噪声,总共加T次以后,得到的图片基本可以说是一个噪声的图片了。我们的目标就是从噪声的图片XT,逆向扩散得到origin image,也就是X0。

forward diffusion正向扩散过程

正向扩散过程就是我们刚才所说的,不断的朝图片加入噪声,通常初始图片我们是知道的,噪声的概率分布我们是知道的(假设服从正太分布),因此用数学公式就可以采用的个固定的markov chain形式,即逐步地向图片添加高斯噪声,每一步的图片只与上一步的图片有关:

q(x_{1:T}|x_{0}):=\prod^{T}_{t=1}q(x_{t}|x_{t-1})

其中

q(x_{t}|x_{t-1}):=N(x_{t};\sqrt{1-\beta_{t}}x_{t-1},\beta_{t}I)

 因此,模型训练就是从噪声从逆推算回初始的图像。

Reverse diffusion逆向扩散过程

我们的目标就是找到一种方式,或是训练一个网络,能够慢慢的把噪声一点一点的恢复回来。在近两年的做法当中,常见的方法是用U-net。因为reverse diffusion每次的图片的尺寸大小不变,因此U-net是一个很适合的模型。

diffusion model的小总结

这种方式可以看出,有一个致命的缺陷,就是生成模型很慢。因为每一次恢复都只能一步一步的向前恢复,而不像GAN,GAN只要训练好了这个模型,只要给他一个噪声,他就能恢复出图像,做一次的模型forward就够了。

DDPM(Denoising Diffusion Probabilistic Models)

DDPM的思想其实很简单,在reverse diffusion当中,用Xt去预测X-1的图片,但这不好优化,不去优化Xt到Xt-1的转换,而是优化Xt-1到Xt的时候,噪声是怎么加的。只去预测噪声,这有点resnet的意思,本来我们可以直接用x预测y,但直接预测y太难了,应该把其理解为y=x+residual,那我们只需要预测这个residual就可以了 。

同时DDPM还加入了time embedding,time embedding的作用就是告诉U-Net现在reverse diffusion在第几步了,这和transformer中的位置编码一样,这正余弦编码或者是一个傅里叶特征。其给模型带来的提升也是明显的。

但还有一个要加Time embeding的原因是因为,U-net是参数共享的,加入time embedding能够根据不同的输入而生成不同的输出。 我们希望在reverse diffusion的过程中,U-net能先生成一些大概的轮廓,很粗糙的coarse的图像,不需要很清晰。随着reverse diffusion往前走,当在接近还原为原来的图像的时候,我们希望能够学习到物体的边边角角的信息,一些高频信息,这样才能使输出的图片更加逼真。

具体到目标函数,那loss怎么算?

给定xt图像预测Xt-1的图像,那我们的loss就是我们已知的噪声(在前向forward是我们手工加的,所以我们是知道这个噪声的)和预测出来的噪声的差值

P(x_{t-1}|x_{t})=||\varepsilon -f_{\varepsilon}(y_{t},t)||

其中,\varepsilon代表我们前向forward已知的噪声,f_{\varepsilon}(\cdot)代表的是U-net神经网络,y_{t}代表的是当前的输入图片,t代表的是time embedding。

DDPM还有第二个贡献,就是我们只需要预测出加的噪声的均值和方差就可以了,不需要完全预测其正态分布。

------------------------------------2022.8.22补充-------------------

重参数技巧得到迭代公式

我们是如何利用重参数技巧得到每一次高斯噪声的?最开始我以为training的过程是一步一步的计算得到,例如,x_{0}经过一个encoder得到x_{1},x_{1}经过encoder得到x_{2},....,但后面发现不是。forward process添加的噪声是服从高斯分布变换的。这是一个以根号1-βtxt-1为均值,βt为方差的高斯分布。那forward的公式是显示的,那我们就可以直接通过x0,直接得到xt。

q(x_{t}|x_{t-1}=N(x_{t};\sqrt{1-\beta_{t}}x_{t-1},\beta_{t}I)))

每次Xt加噪的公式如下:

x_{t}=\sqrt{1-\beta_{t}}X_{t-1}+\sqrt{\beta_{t}}Z_{t}

  • X_{t}表示t时刻的数据分布。
  • Z_{t}表示t时刻添加的高斯噪音,一般固定是均值为0方差为1的高斯分布。
  • \sqrt{1-\beta_{t}}X_{t-1}表示当前时刻分布的均值
  • \sqrt{\beta_{t}}表示当前时刻分布的标准差。

 因此,我们可以根据公式进行推导:

X_{t}=\sqrt{1-\beta_{t}}X_{t-1}+\sqrt{\beta_{t}}Z_{t}

\alpha_{t}=1-\beta_{t},则

\sqrt{\beta_{t}}=\sqrt{1-\alpha_{t}}

 于是

X_{t}=\sqrt{\alpha_{t}}X_{t-1}+\sqrt{1-\alpha_{t}}Z_{t}

X_{t-1}=\sqrt{\alpha_{t-1}}X_{t-2}+\sqrt{1-\alpha_{t-1}}Z_{t-1}

...

由上,可以组成一个Xt由X0组成的式子,即

X_{t}=\sqrt{\bar{\alpha_{t}}}x_{0}+\sqrt{1-\bar{\alpha_{t}}}\bar{z}_{t}                                                                                                (1)

(注意一下这个公式,后面会有用到) 

我们就得到了一个只与X0有关的式子。

diffusion reverse process

如果前向过程是加噪的话,逆向过程就是去噪,我们先来看看论文对逆向过程的定义:

p_{\theta}(X_{0:T})=p(X_{T})\prod ^{T}_{t=1} p_{\theta}(X_{t-1}|X_{t})

p_{\theta}(X_{t-1}|X_{t})=\mathcal{N}(X_{t-1};\mu_{\theta}(X_{t},t),\Sigma_{\theta}(X_{t},t))

p_{\theta}(X_{t-1}|X_{t})满足高斯分布,均值为带有参数\theta、以X_{t}t为输入的\mu_{\theta}(X_{t},t),和方差\Sigma_{\theta}(X_{t},t)(PS:这里的\Sigma是一个方差符号,不是求和符号),。

我们要求出后验的扩散条件概率q(X_{t-1}|X_{t},X_{0}),这个扩散条件概率是可以用公式表达的,也就是是说,给定X_{t}X_{0},我们是可以计算出X_{t-1}的。

我们现在开始计算q(X_{t-1}|X_{t},X_{0})

q(X_{t-1}|X_{t},X_{0})      =\frac{q(X_{t}|X_{t-1},X_{0}) q(X_{t-1}|X_{0})q(X_{0})}{q(X_{t},X_{0})}

                                =\frac{q(X_{t}|X_{t-1},X_{0}) q(X_{t-1}|X_{0}))}{\frac{q(X_{t},X_{0})}{q(X_{0}}}

                                =q(X_{t}|X_{t-1})\frac{ q(X_{t-1}|X_{0})}{q(X_{t}|X_{0})}

                         

因为q(X_{t}|X_{t-1})q(X_{t-1}|X_{0}){q(X_{t}|X_{0})都服从高斯分布,因此正比于:

q(X_{t-1}|X_{t},X_{0})      \propto exp(-\frac{1}{2} \frac{(X_{t}-\sqrt{\alpha_{t}}X_{t-1})^{2}}{​{​{\beta_{t}}} } +\frac{(X_{t-1}-\sqrt{\bar{\alpha}_{t-1}}X_{0})^{2}}{​{​{1-\bar{\alpha}_{t-1}}} }-\frac{(X_{t}-\sqrt{\bar{\alpha}_{t}}X_{0})^{2}}{​{​{1-\bar{\alpha}_{t}}} }

把其整理为一元二次方程的形式

 =exp(-\frac{1}{2}((\frac{\alpha_{t}}{\beta_{t}}+\frac{1}{1-\bar{\alpha}_{t-1}}) X_{t-1}^2-(\frac{2\sqrt{\alpha_{t}}}{\beta_{t}}X_{t}+\frac{2\sqrt{\bar{\alpha_{t}}}}{1-\bar{\alpha_{t}}}X_{0}) +C(X_{t},X_{0}) ))

 这里值得注意的是,q(X_{t-1}|X_{t},X_{0})也是服从高斯分布的,因此,根据这个公式,我们可以计算出均值和方差。

\tilde{\beta_{t}}=1/(\frac{\alpha_{t}}{\beta_{t}}+\frac{1}{1-\bar{\alpha}_{t-1}})=\frac{1-\bar{\alpha}_{t-1}}{1-\bar{\alpha}_{t}}\cdot \beta_{t}

\tilde{\mu}_{t}(X_{t},X_{0})=(\frac{\sqrt{\alpha_{t}}}{\beta_{t}}X_{t}+\frac{\sqrt{\bar{\alpha_{t}}}}{1-\bar{\alpha_{t}}}X_{0}) /(\frac{\alpha_{t}}{\beta_{t}}+\frac{1}{1-\bar{\alpha}_{t-1}})=\frac{\sqrt{\alpha_{t}}(1-\bar{\alpha}_{t-1})}{1-\bar{\alpha}_{t}}X_{t}+\frac{\sqrt{\bar{\alpha}_{t-1}}\beta_{t}}{1-\bar{\alpha}_{t}}X_{0}

因为q(X_{t-1}|X_{t},X_{0})是一个逆向的过程,我们无法知道X0,所以要把X0替换为X_t,根据上面公式1,可以得到公式X_0 = \frac{1}{\sqrt{\bar{\alpha_t}}} (x_t - \sqrt{1 - \bar{\alpha}_t} z_t)

=\frac{\sqrt{\alpha_t}(1-\bar{\alpha}_{t-1})}{1-\bar{\alpha}_{t}}x_t + \frac{\sqrt{\bar{\alpha}_{t-1}}\beta_t}{1-\bar{\alpha}_{t}} {\color{red}x_0}

=\frac{\sqrt{\alpha_t}(1-\bar{\alpha}_{t-1})}{1-\bar{\alpha}_{t}}x_t + \frac{\sqrt{\bar{\alpha}_{t-1}}\beta_t}{1-\bar{\alpha}_{t}} \cdot {\color{red}\frac{1}{\sqrt{\bar{\alpha}_t}} (x_t - \sqrt{1 - \bar{\alpha}_t} z_t)}

=\frac{​{\color{green}\sqrt{\alpha_t}}\cdot\sqrt{\alpha_t}(1-{\color{green}\bar{\alpha}_{t-1}})}{​{ {\color{green}\sqrt{\alpha_t}}}\cdot( 1-\bar{\alpha}_{t})}x_t + \frac{​{\color{blue}\sqrt{\bar{\alpha}_{t-1}}}\beta_t}{1-\bar{\alpha}_{t}} \cdot \frac{1}{\color{blue}\sqrt{\bar{\alpha}_t}} (x_t - \sqrt{1 - \bar{\alpha}_t} z_t)

=\frac{​{\alpha_t}-\color{green}\bar{\alpha}_{t}}{​{\sqrt{\alpha_t}}(1-\bar{\alpha}_{t})}x_t + \frac{\beta_t}{(1-\bar{\alpha}_{t})\color{blue}\sqrt{​{\alpha_t}}} (x_t - \sqrt{1 - \bar{\alpha}_t} z_t)

=\frac{​{1}-\bar{\alpha}_{t}}{​{\sqrt{\alpha_t}}(1-\bar{\alpha}_{t})}x_t - \frac{\beta_t}{(1-\bar{\alpha}_{t})\sqrt{​{\alpha_t}}} (\sqrt{1 - \bar{\alpha}_t} z_t)

=\frac{1}{​{\sqrt{\alpha_t}}}x_t - \frac{\beta_t}{\sqrt{(1-\bar{\alpha}_{t})}\sqrt{​{\alpha_t}}} z_t

=\frac{1}{​{\sqrt{\alpha_t}}}\big(x_t - \frac{\beta_t}{\sqrt{(1-\bar{\alpha}_{t})}} z_t )

最后我们得到

\tilde{\mu}_{t}(X_{t},X_{0})=\frac{1}{​{\sqrt{\alpha_t}}}\big(x_t - \frac{\beta_t}{\sqrt{(1-\bar{\alpha}_{t})}} z_t )                                                                              (2)

也就是q(X_{t-1}|X_{t},X_{0})的均值,

我们总结以上的reverse diffusion process的推导,我们得到了:

\tilde{\mu}_{t}(X_{t},X_{0})=\frac{1}{​{\sqrt{\alpha_t}}}\big(x_t - \frac{\beta_t}{\sqrt{(1-\bar{\alpha}_{t})}} z_t )   

\Sigma_{\theta}(X_{t},t)=\tilde{\beta_{t}}=1/(\frac{\alpha_{t}}{\beta_{t}}+\frac{1}{1-\bar{\alpha}_{t-1}})=\frac{1-\bar{\alpha}_{t-1}}{1-\bar{\alpha}_{t}}\cdot \beta_{t}

----------

csdn真的很难用,以后不用csdn了,写的全部丢失

代码

  1. import matplotlib.pyplot as plt
  2. import numpy as np
  3. from sklearn.datasets import make_s_curve
  4. import torch
  5. # TODO 实验数据
  6. s_curve , _ = make_s_curve(10**4 , noise = 0.1)
  7. s_curve = s_curve[:,[0,2] ]/10.0
  8. print("shape of moons :",np.shape(s_curve))
  9. data = s_curve.T
  10. fig,ax = plt.subplots()
  11. ax.scatter(*data ,color='red',edgecolor='white')
  12. ax.axis('off')
  13. plt.show()
  14. dataset = torch.Tensor(s_curve).float() # shape of moons : (10000, 2)
  15. # TODO 确定超参数的值
  16. num_steps = 100 # 可以由beta alpha 分布 均值 标准差 进行估算
  17. # 学习的超参数 动态的在(01)之间逐渐增大
  18. betas = torch.linspace(-6,6,num_steps)
  19. betas = torch.sigmoid(betas)* (0.5e-2 - 1e-5) + 1e-5
  20. # 计算 alpha , alpha_prod , alpha_prod_previous , alpha_bar_sqrt 等变量的值
  21. alphas = 1 - betas
  22. alphas_prod = torch.cumprod( alphas ,dim=0 ) # 累积连乘 https://pytorch.org/docs/stable/generated/torch.cumprod.html
  23. alphas_prod_p = torch.cat([torch.tensor([1]).float() ,alphas_prod[:-1]],0) # p means previous
  24. alphas_bar_sqrt = torch.sqrt(alphas_prod)
  25. one_minus_alphas_bar_log = torch.log(1-alphas_prod)
  26. one_minus_alphas_bar_sqrt = torch.sqrt(1-alphas_prod)
  27. assert alphas_prod.shape == alphas_prod.shape == alphas_prod_p.shape \
  28. == alphas_bar_sqrt.shape == one_minus_alphas_bar_log.shape \
  29. == one_minus_alphas_bar_sqrt.shape
  30. print("all the same shape:",betas.shape) #
  31. # TODO 确定扩散过程中任意时刻的采样值
  32. def q_x(x_0 ,t):
  33. noise = torch.randn_like(x_0) # noise 是从正太分布中生成的随机噪声
  34. alphas_t = alphas_bar_sqrt[t] ## 均值 \sqrt{\bar \alpha_t}
  35. alphas_l_m_t = one_minus_alphas_bar_sqrt[t] ## 标准差 \sqrt{ 1 - \bar \alpha_t}
  36. # alphas_t = extract(alphas_bar_sqrt , t, x_0) # 得到sqrt(alphas_bar[t]) ,x_0的作用是传入shape
  37. # alphas_l_m_t = extract(one_minus_alphas_bar_sqrt , t, x_0) # 得到sqrt(1-alphas_bart[t])
  38. return (alphas_t * x_0 + alphas_l_m_t * noise)
  39. # TODO 演示原始数据分布加噪100步后的效果
  40. num_shows = 20
  41. fig , axs = plt.subplots(2,10,figsize=(28,3))
  42. plt.rc('text',color='blue')
  43. # 共有10000个点,每个点包含两个坐标
  44. # 生成100步以内每隔5步加噪声后的图像
  45. for i in range(num_shows):
  46. j = i // 10
  47. k = i % 10
  48. t = i*num_steps//num_shows # t=i*5
  49. q_i = q_x(dataset ,torch.tensor( [t] )) # 使用刚才定义的扩散函数,生成t时刻的采样数据 x_0为dataset
  50. axs[j,k].scatter(q_i[:,0],q_i[:,1],color='red',edgecolor='white')
  51. axs[j,k].set_axis_off()
  52. axs[j,k].set_title('$q(\mathbf{x}_{'+str(i*num_steps//num_shows)+'})$')
  53. plt.show()
  54. # TODO 编写拟合逆扩散过程 高斯分布 的模型
  55. # \varepsilon_\theta(x_0,t)
  56. import torch
  57. import torch.nn as nn
  58. class MLPDiffusion(nn.Module):
  59. def __init__(self,n_steps,num_units=128):
  60. super(MLPDiffusion,self).__init__()
  61. self.linears = nn.ModuleList([
  62. nn.Linear(2,num_units),
  63. nn.ReLU(),
  64. nn.Linear(num_units,num_units),
  65. nn.ReLU(),
  66. nn.Linear(num_units, num_units),
  67. nn.ReLU(),
  68. nn.Linear(num_units, 2),]
  69. )
  70. self.step_embeddings = nn.ModuleList([
  71. nn.Embedding(n_steps,num_units),
  72. nn.Embedding(n_steps, num_units),
  73. nn.Embedding(n_steps, num_units)
  74. ])
  75. def forward(self,x,t):
  76. for idx,embedding_layer in enumerate(self.step_embeddings):
  77. t_embedding = embedding_layer(t)
  78. x = self.linears[2*idx](x)
  79. x += t_embedding
  80. x = self.linears[2*idx +1](x)
  81. x = self.linears[-1](x)
  82. return x
  83. # TODO loss 使用最简单的 loss
  84. def diffusion_loss_fn(model,x_0,alphas_bar_sqrt,one_minus_alphas_bar_sqrt,n_steps):# n_steps 用于随机生成t
  85. '''对任意时刻t进行采样计算loss'''
  86. batch_size = x_0.shape[0]
  87. # 随机采样一个时刻t,为了体检训练效率,需确保t不重复
  88. # weights = torch.ones(n_steps).expand(batch_size,-1)
  89. # t = torch.multinomial(weights,num_samples=1,replacement=False) # [barch_size, 1]
  90. t = torch.randint(0,n_steps,size=(batch_size//2,)) # 先生成一半
  91. t = torch.cat([t,n_steps-1-t],dim=0) # 【batchsize,1
  92. t = t.unsqueeze(-1)# batchsieze
  93. # print(t.shape)
  94. # x0的系数
  95. a = alphas_bar_sqrt[t]
  96. # 生成的随机噪音eps
  97. e = torch.randn_like(x_0)
  98. # eps的系数
  99. aml = one_minus_alphas_bar_sqrt[t]
  100. # 构造模型的输入
  101. x = x_0* a + e *aml
  102. # 送入模型,得到t时刻的随机噪声预测值
  103. output = model(x,t.squeeze(-1))
  104. # 与真实噪声一起计算误差,求平均值
  105. return (e-output).square().mean()
  106. # TODO 编写逆扩散采样函数(inference过程)
  107. def p_sample_loop(model ,shape ,n_steps,betas ,one_minus_alphas_bar_sqrt):
  108. '''从x[T]恢复x[T-1],x[T-2],……,x[0]'''
  109. cur_x = torch.randn(shape)
  110. x_seq = [cur_x]
  111. for i in reversed(range(n_steps)):
  112. cur_x = p_sample(model,cur_x, i ,betas,one_minus_alphas_bar_sqrt)
  113. x_seq.append(cur_x)
  114. return x_seq
  115. def p_sample(model,x,t,betas,one_minus_alphas_bar_sqrt):
  116. '''从x[T]采样时刻t的重构值'''
  117. t = torch.tensor(t)
  118. coeff = betas[t] / one_minus_alphas_bar_sqrt[t]
  119. eps_theta = model(x,t)
  120. mean = (1/(1-betas[t].sqrt()) * (x-(coeff * eps_theta)))
  121. z = torch.randn_like(x)
  122. sigma_t = betas[t].sqrt()
  123. sample = mean + sigma_t * z
  124. return (sample)
  125. # TODO 模型的训练
  126. seed = 1234
  127. class EMA():
  128. '''构建一个参数平滑器'''
  129. def __init__(self,mu = 0.01):
  130. self.mu =mu
  131. self.shadow = {}
  132. def register(self,name,val):
  133. self.shadow[name] = val.clone()
  134. def __call__(self, name, x): # call函数?
  135. assert name in self.shadow
  136. new_average = self.mu * x +(1.0 -self.mu) * self.shadow[name]
  137. self.shadow[name] = new_average.clone()
  138. return new_average
  139. print('Training model ……')
  140. '''
  141. '''
  142. batch_size = 128
  143. dataloader = torch.utils.data.DataLoader(dataset,batch_size=batch_size,shuffle = True)
  144. num_epoch = 4000
  145. plt.rc('text',color='blue')
  146. model = MLPDiffusion(num_steps) # 输出维度是2 输入是x 和 step
  147. optimizer = torch.optim.Adam(model.parameters(),lr = 1e-3)
  148. for t in range(num_epoch):
  149. for idx,batch_x in enumerate(dataloader):
  150. loss = diffusion_loss_fn(model,batch_x,alphas_bar_sqrt,one_minus_alphas_bar_sqrt,num_steps)
  151. optimizer.zero_grad()
  152. loss.backward()
  153. torch.nn.utils.clip_grad_norm(model.parameters(),1.) #
  154. optimizer.step()
  155. # for name ,param in model.named_parameters():
  156. # if params.requires_grad:
  157. # param.data = ems(name,param.data)
  158. # print loss
  159. if (t% 100 == 0):
  160. print(loss)
  161. x_seq = p_sample_loop(model,dataset.shape,num_steps,betas,one_minus_alphas_bar_sqrt)# 共有100个元素
  162. fig ,axs = plt.subplots(1,10,figsize=(28,3))
  163. for i in range(1,11):
  164. cur_x = x_seq[i*10].detach()
  165. axs[i-1].scatter(cur_x[:,0],cur_x[:,1],color='red',edgecolor='white');
  166. axs[i-1].set_axis_off()
  167. axs[i-1].set_title('$q(\mathbf{x}_{'+str(i*10)+'})$')

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/554041
推荐阅读
相关标签
  

闽ICP备14008679号