diffusion 相关阅读笔记

Diffusion Models A Comprehensive Survey of Methods and Applications.pdf

Understanding Diffusion Models A Unified Perspective.pdf

Denoising Diffusion Probabilistic Models.pdf

diffusion模型的公式挺多的,codes内也有很多的公式,直接看codes还是看不懂的,codes内的公式太多了,diffusion主要包括了加噪声的过程,以及去噪声的过程。加噪声服从正态分布,去噪声也服从正态分布。

加噪声的codes是这个:np.sqrt(aprodd).reshape(n, 1, 1, 1) * inputs + np.sqrt((1 - aprodd)).reshape(n, 1, 1, 1) * etamul

inputs是干净的输入图片,etamul是服从标准正态分布的 噪声,aprodd是逐渐递减到0的值,所以最后的输出就是正态分布的。

也就是首先给一个图片加随机的噪声,然后网络来predict噪声、或者输入的图片。看具体的公式

前向的Markov chain就是不断地加入噪声,而且前后两个图片加入噪声是相关的,加入噪声没有参数需要learn

逆向的Markov chain就是不断地去除噪声,去除噪声需要learn网络的参数才行。
在这里插入图片描述

class myddpm_noise(object):
    def __init__(self, n_steps, embed_dim, minbeta = 0.0001, maxbeta = 0.03, shape = (1, 30 - 2, 30 - 2)):
        self.n_steps = n_steps
        self.embed_dim = embed_dim
# self.beta array([0.0001    , 0.00113103, 0.00216207, 0.0031931 , 0.00422414,
       0.00525517, 0.00628621, 0.00731724, 0.00834828, 0.00937931,
       .........
       0.01556552, 0.01659655, 0.01762759, 0.01865862, 0.01968966,
       0.02072069, 0.02175172, 0.02278276, 0.02381379, 0.02484483,
       0.02587586, 0.0269069 , 0.02793793, 0.02896897, 0.03      ])
        self.beta = np.linspace(minbeta, maxbeta, n_steps)
#self.alpha array([0.9999    , 0.99886897, 0.99783793, 0.9968069 , 0.99577586,
       0.99474483, 0.99371379, 0.99268276, 0.99165172, 0.99062069,
       .........
       0.98443448, 0.98340345, 0.98237241, 0.98134138, 0.98031034,
       0.97927931, 0.97824828, 0.97721724, 0.97618621, 0.97515517,
       0.97412414, 0.9730931 , 0.97206207, 0.97103103, 0.97      ])
        self.alpha = 1 - self.beta
# self.prod_alpha  array([0.9999    , 0.99876908, 0.99660967, 0.99342739, 0.98923102,
       0.98403244, 0.97784661, 0.97069147, 0.96258787, 0.95355946,
       .........
       4.43118813e-07, 4.30063974e-07, 4.17380875e-07, 4.05059324e-07,
       3.93089395e-07, 3.81461425e-07, 3.70166005e-07, 3.59193973e-07,
       3.48536411e-07, 3.38184636e-07, 3.28130193e-07, 3.18364855e-07,
       3.08880609e-07, 2.99669660e-07, 2.90724415e-07, 2.82037488e-07,
       2.73601688e-07, 2.65410015e-07, 2.57455658e-07, 2.49731988e-07])])
        self.prod_alpha = np.array([np.prod(self.alpha[: i + 1]) for i in range(len(self.alpha))])
    
    def forward(self, inputs, fixposition = None, etamul = None):
        n, c, h, w = inputs.shape

        aprodd = self.prod_alpha[fixposition]
        
        noisy = np.sqrt(aprodd).reshape(n, 1, 1, 1) * inputs + np.sqrt((1 - aprodd)).reshape(n, 1, 1, 1) * etamul

        return noisy

前向Markov chain的过程,用到了相关的 重采样方式,也就是 概率分布是不可导的,直接使用概率分布不可导,但是通过概率分布的性质,通过加或者乘,就可导了的,具体的可见: 九是否随意的称呼:重参数采样Reparameterization Trick和Gumbel-Softmax

前向加噪声的过程,每个图片的产生都服从正态分布: q ( x t ∣ x t − 1 ) = N ( x t ; α t x t − 1 , ( 1 − α t ) I ) q(x_t|x_{t−1}) = N (x_t;\sqrt{α_t}x_{t−1},(1 − α_t)I) q(xtxt1)=N(xt;αt xt1,(1αt)I)

也就是条件概率的,已知上一个加了噪声的图片,怎么产生下一个加噪声的图片

已知前一个,那么下一个加噪声图片的产生,就服从正态分布。而且均值是 α t x t − 1 \sqrt{α_t}x_{t−1} αt xt1 ,方差是 ( 1 − α t ) I (1 − α_t)I (1αt)I I I I 是 (0, 1) 标准正态分布。

所以前向Markov chain的转移公式就是上面的条件概率。

而且到了最后一个时间点T,产生的基本是噪声了,没有图片了的,也就是 p ( x T ) = N ( x T ; 0 , 1 ) p(x_T)=N(x_T;0,1) p(xT)=N(xT;0,1)

在这里插入图片描述

所以逆向过程的joint分布就是: p ( x 0 : T ) = p ( x T ) ∏ t = 1 T p θ ( x t − 1 ∣ x t ) p(x_{0:T})=p(x_T)\prod_{t=1}^{T}p_{\theta}(x_{t-1}|x_t) p(x0:T)=p(xT)t=1Tpθ(xt1xt) θ \theta θ 就是网络需要learn的参数。

前向过程也就是上面的条件概率,也可以转写到: x t = α t x t − 1 + 1 − α t ϵ x_t =\sqrt{α_t}x_{t−1} +\sqrt{1 − α_t}\epsilon xt=αt xt1+1αt ϵ ϵ \epsilon ϵ 服从标准正态分布。

也就是 均值加上标准差 的,得到的就是下一个噪声图片。类似的 x t − 1 = α t − 1 x t − 2 + 1 − α t − 1 ϵ x_{t-1} =\sqrt{α_{t-1}}x_{t−2} +\sqrt{1 − α_{t-1}}\epsilon xt1=αt1 xt2+1αt1 ϵ

将上面的式子带入,然后不断地迭代最后就可以得到: x t = α ˉ t x 0 + 1 − α ˉ t ϵ 0 x_t =\sqrt{\barα_t}x_0 +\sqrt{1 − \barα_t}\epsilon_0 xt=αˉt x0+1αˉt ϵ0 ,也就是 x t x_t xt 可以直接使用 x 0 x_0 x0 求出来,而不需要用到前一个噪声图片。 x t − N ( x t ; α ˉ t x 0 , ( 1 − α ˉ t ) I ) x_t-N(x_t;\sqrt{\bar \alpha_t}x_0,(1-\bar\alpha_t)I) xtN(xt;αˉt x0,(1αˉt)I)

在这里插入图片描述

上面这个公式就是codes内需要用到的加噪声的公式,加噪声就是按照这个公式来计算的。

加完噪声以后,就送入到网络,来train网络,让网络可以更好的learn相关的参数 p ( x 0 : T ) = p ( x T ) ∏ t = 1 T p θ ( x t − 1 ∣ x t ) p(x_{0:T})=p(x_T)\prod_{t=1}^{T}p_{\theta}(x_{t-1}|x_t) p(x0:T)=p(xT)t=1Tpθ(xt1xt)

train

通过不同的公式推导,可以得到网络train的三种方式:

1、predict输入的图片

2、predict加入的噪声

3、predict相应的评分

这三种predict方式都可以用来train网络,通常第二种比较常用。

predict

q ( x t − 1 ∣ x t , x 0 ) − N ( x t − 1 ; u q ( x t , x 0 ) , δ ) q(x_{t−1}|x_t, x_0)-N(x_{t-1};u_q(x_t,x_0),\delta) q(xt1xt,x0)N(xt1;uq(xt,x0),δ) ,也就是逆向的图片恢复过程,是服从正态分布的

也就是sample的过程,有很多种采样的方式,像DDPM,DDIM等等,通常的采样公式,也就是逆向转移公式包括这一个:去噪声的转移均值: µ q ( x t , x 0 ) = 1 α t x t − 1 − α t 1 − α ˉ t α t ϵ 0 µ_q(x_t, x_0)=\frac{1}{\sqrt{\alpha_t}}x_t-\frac{1-\alpha_t}{\sqrt{1-\bar\alpha_t}\sqrt{\alpha_t}}\epsilon_0 µq(xt,x0)=αt 1xt1αˉt αt 1αtϵ0 ,去噪声的转移方差是: δ = ( 1 − α t ) ( 1 − α ˉ t − 1 ) 1 − α ˉ t I \delta=\frac{(1-\alpha_t)(1-\bar\alpha_{t-1})}{1-\bar\alpha_t}I δ=1αˉt(1αt)(1αˉt1)I ,上面的 ϵ 0 \epsilon_0 ϵ0 就是网络输出的噪声,不是采样得到的,是网络predict的噪声。网络的输入是 x t x_t xt

所以sample采样的时候,从标准正态分布开始,然后将 x t x_t xt 送入到网络 predict 噪声 ϵ 0 \epsilon_0 ϵ0 ,然后使用这个噪声 ϵ 0 \epsilon_0 ϵ0 求均值 µ q ( x t , x 0 ) = 1 α t x t − 1 − α t 1 − α ˉ t α t ϵ 0 µ_q(x_t, x_0)=\frac{1}{\sqrt{\alpha_t}}x_t-\frac{1-\alpha_t}{\sqrt{1-\bar\alpha_t}\sqrt{\alpha_t}}\epsilon_0 µq(xt,x0)=αt 1xt1αˉt αt 1αtϵ0 ,加上标准差 δ = ( 1 − α t ) ( 1 − α ˉ t − 1 ) 1 − α ˉ t I \delta=\frac{(1-\alpha_t)(1-\bar\alpha_{t-1})}{1-\bar\alpha_t}I δ=1αˉt(1αt)(1αˉt1)I ,就是下一次采样需要用到的 x t − 1 x_{t-1} xt1 ,也就是下一次送入到网络的输入: x t − 1 x_{t-1} xt1

上面的公式对应到的就是下面的codes。

    inputs = np.random.rand(n_sample, c, h, w)
    for id, fixposition in enumerate(np.arange(noisegen.n_steps)[::-1]):
        array_fixpos = np.ones((n_sample, 1), dtype=np.uint) * fixposition
        predict_noisy = myunet.forward(inputs, array_fixpos)
        fix_alpha = noisegen.alpha[fixposition]
        fixprod_alpha = noisegen.prod_alpha[fixposition]
        
        inputs = (1 / np.sqrt(fix_alpha)) * (inputs - (1 - fix_alpha) / np.sqrt(1 - fixprod_alpha) * predict_noisy)

        if fixposition > 0:
            z = np.random.rand(n_sample, c, h, w)
            
            #0
            fixbeta = noisegen.beta[fixposition]
            # fix_sigma = np.sqrt(fixbeta)
            
            #1
            preprod_alpha = noisegen.prod_alpha[fixposition - 1] if fixposition > 0 else noisegen.prod_alpha[0]
            prebeta = ((1 - preprod_alpha) / (1 - fixprod_alpha)) * fixbeta
            fix_sigma = np.sqrt(prebeta)
            
            inputs = inputs + fix_sigma * z

很多工作都是在sample这的

条件diffusion

条件diffusion,通常是加了额外信息的diffusion,像多出来的向量用来放置其他条件

文本条件通常是embedding到向量空间,然后和图片做cross attention,拿到条件信息。

通过额外的输入,就可以控制diffusion输出的结果。

reference

Diffusion Models in AI - Everything You Need to Know - Unite.AI

Understanding Stable Diffusion from “Scratch” | Binxu Wang (harvard.edu)

Mathematical Foundation of Diffusion Generative Models | Binxu Wang (harvard.edu)

Research | Binxu Wang (harvard.edu)

Note on Variants of Diffusion Scheduler, DDPM DDIM PNDM | The mind palace of Binxu (animadversio.github.io)

Note on Diffusion Generative Models | The mind palace of Binxu (animadversio.github.io)

Kempner Institute - For the Study of Natural & Artificial Intelligence at Harvard University


https://zhuanlan.zhihu.com/p/695932400

Logo

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。

更多推荐