jjzjj

突然火起来的diffusion model是什么?

51Ann 2023-03-28 原文

模型起源

2015年的时候,有几位大佬基于非平衡热力学提出了一个纯数学的生成模型 (Sohl-Dickstein et al., 2015)。不过那个时候他们没有用代码实现,所以这篇工作并没有火起来。

直到后来斯坦福大学(Song et al., 2019) 和谷歌大脑 (Ho et al., 2020) 有两篇工作延续了15年的工作。再到后来2020年谷歌大脑的几位大佬又把这个模型实现了出来(Ho et al., 2020),因为这个模型一些极其优秀的特性,所以它现在火了起来。

扩散模型可以做什么?呢它可以做一些。条件生成和非条件生成。在图像、语音、文本三个方向都已经有了一些应用,并且效果比较突出。

比较出圈的工作有我刚介绍的text to image的生成工作比如

什么是扩散模型?

Diffusion model 和 Normalizing Flows, GANs or VAEs 一样,都是将噪声从一些简单的分布转换为一个数据样本,也是神经网络学习从纯噪声开始逐渐去噪数据的过程。 包含两个步骤:

  • 一个我们选择的固定的(或者说预定义好的)前向扩散过程 $q$ ,就是逐渐给图片添加高斯噪声,直到最后获得纯噪声。
  • 一个需要学习的反向的去噪过程 $p_\theta$,训练一个神经网做图像去噪,从纯噪声开始,直到获得最终图像。

前向和反向过程都要经过时间步$t$,总步长是$T$(DDPM中$T=1000$)。

你从$t=0$开始,从数据集分布中采样一个真实图片$x_0$。比如你用cifar-10,用cifar-100,用ImageNet,总之就是从你数据集里随机采样一张图片作为$x_0$。

前向过程就是在每一个时间步$t$中都从一个高斯分布中采样一个噪声,将其添加到上一时间步的图像上。给出一个足够大的$T$,和每一时间步中添加噪声的表格,最终在$T$时间步你会获得一个isotropic Gaussian distribution

我要开始上公式了!

我们令$q(x_0)$是真实分布,也就是真实的图像的分布。

我们可以从中采样一个图片,也就是$x_0 \sim q(x_0)$ 。

我们设定前向扩散过程$q(x_t|x_{t-1})$是给每个时间步$t$添加高斯噪声,这个高斯噪声不是随机选择的,是根据我们预选设定好的方差表($0 < \beta_1 < \beta_2 < ... < \beta_T < 1$)的高斯分布中获取的。

然后我们就可以得到前向过程的公式为: $$ q({x}t | {x}{t-1}) = \mathcal{N}({x}t; \sqrt{1 - \beta_t} {x}{t-1}, \beta_t \mathbf{I}). $$

$$ \mathcal{N}({x}t; \sqrt{1 - \beta_t} {x}{t-1}, \beta_t \mathbf{I}) 就是{x}t \sim \mathcal{N}( \sqrt{1 - \beta_t} {x}{t-1}, \beta_t \mathbf{I}). $$

回想一下哦。一个高斯分布(也叫正态分布)是由两个参数决定的,均值$\mu$和方差$\sigma^2 \geq 0$。

然后我们就可以认为每个时间步$t$的图像是从一均值为${\mu}t = \sqrt{1 - \beta_t} {x}{t-1}$、方差为$\sigma^2_t = \beta_t$的条件高斯分布中画出来的。借助参数重整化(reparameterization trick)可以写成

$$ {x}t = \sqrt{1 - \beta_t}{x}{t-1} + \sqrt{\beta_t} \mathbf{\epsilon} $$

其中$\mathbf{\epsilon} \sim \mathcal{N}(\mathbf{0}, \mathbf{I})$,是从标准高斯分布中采样的噪声。

$\beta_t$在不用的时间步$t$中不是固定的,因此我们给$\beta$加了下标。对于$\beta_t$的选择我们可以设置为线性的、二次的、余弦的等(有点像学习率计划)。

比如在DDPM中$\beta_1 = 10^{-4}$,$\beta_T = 0.02$,在中间是做了一个线性插值。而在Improved DDPM中是使用余弦函数。

从$x_0$开始,我们通过$\mathbf{x}_1, ..., \mathbf{x}_t, ..., \mathbf{x}_T$,最终获得${x}_T$ ,如果我们的高斯噪声表设置的合理,那最后我们获得的应该是一个纯高斯噪声。

现在,如果我们能知道条件分布$p({x}_{t-1} | {x}_t)$,那我们就可以将这个过程倒过来:采样一个随机高斯噪声$x_t$,我们可以对其逐步去噪,最终得到一个真实分布的图片$x_0$。

但是我们实际上没办法知道$p({x}{t-1} | {x}t)$。因为它需要知道所有可能图像的分布来计算这个条件概率。因此,我们需要借助神经网络来近似(学习)这个条件概率分布。 也就是$p\theta ({x}{t-1} | {x}_t)$,其中, $\theta$是神经网络的参数,需要使用梯度下降更新。

所以现在我们需要一个神经网络来表示逆向过程的(条件)概率分布。如果我们假设这个反向过程也是高斯分布,那么回想一下,任何高斯分布都是由两个参数定义的:

  • 一个均值$\mu_\theta$;
  • 一个方差$\Sigma_\theta$。
所以我们可以把这个过程参数化为

$$ p_\theta (\mathbf{x}{t-1} | \mathbf{x}t) = \mathcal{N}(\mathbf{x}{t-1}; \mu\theta(\mathbf{x}{t},t), \Sigma\theta (\mathbf{x}_{t},t)) $$

其中均值和方差也取决于噪声水平$t$。

从上边我们可以知道,逆向过程我们需要一个神经网络来学习(表示)高斯分布的均值和方差。

带DDPM中作者固定方差,只让神经网络学习条件概率分布的均值。

First, we set $\Sigma_\theta ( \mathbf{x}_t, t) = \sigma^2_t \mathbf{I}$ to untrained time dependent constants. Experimentally, both $\sigma^2_t = \beta_t$ and $\sigma^2_t = \tilde{\beta}_t$ (see paper) had similar results.

之后再Improved diffusion models这篇文章中进行了改进,神经网络既需要学习均值也要学习方差。

通过重新参数化平均值定义目标函数

为了推导出一个目标函数来学习逆向过程的均值,作者观察到$q$和$p_\theta$可以看做是一个VAE模型 (Kingma et al., 2013).

因此,变分下界(ELBO)可以用来最小化关于ground truth$x_0$的负对数似然。

这个过程的ELBO是每个时间步$t$的损失总,$L=L_0+L_1+…+L_?$。

通过构建正向?过程和反向过程,损失的每一项(除了$L_0$)是两个高斯分布之间的KL散度,可以明确地写为关于平均值的$L_2$损失!

因为高斯分布的特性,我们不需要在正向$q$过程中迭代$t$步就可以获得$x_t$的结果:

$$ q({x}_t | {x}_0) = \cal{N}({x}_t; \sqrt{\bar{\alpha}_t} {x}_0, (1- \bar{\alpha}_t) \mathbf{I}) $$

其中$\alpha_t := 1 - \beta_t$ and $\bar{\alpha}t := \Pi{s=1}^{t} \alpha_s$。

这是一个很优秀的属性。这意味着我们可以对高斯噪声进行采样并适当缩放直接将其添加到$x_0$中就可以得到$x_t$。请注意,$\bar{\alpha}_t$是方差表$\beta_t$的函数,因此也是已知的,我们可以对其预先计算。这样可以让我们在训练期间优化损失函数$L$的随机项(换句话说,在训练期间随机采样$t$就可以优化$L_t$)。

这个属性的另一个优美之处this excellent blog post) 在于对均值进行参数重整化,使神经网络学习(预测)添加的噪声(通过网络$\epsilon_\theta(x_t,t)$),在KL项中构成损失的噪声级别$t$。这意味着我们的神经网络变成了噪声预测器,而不是直接去预测均值了。均值的计算方法如下:

$$ {\mu}_\theta({x}_t, t) = \frac{1}{\sqrt{\alpha_t}} \left( {x}_t - \frac{\beta_t}{\sqrt{1- \bar{\alpha}t}} {\epsilon}\theta({x}_t, t) \right)$$

最后的目标函数$L_t$ 长这样,给定随机的时间步 $t$ 使${\epsilon} \sim \mathcal{N}({0}, {I})$ ):

$$ | {\epsilon} - {\epsilon}_\theta({x}t, t) |^2 = | {\epsilon} - {\epsilon}\theta( \sqrt{\bar{\alpha}_t} {x}_0 + \sqrt{(1- \bar{\alpha}_t) } {\epsilon}, t) |^2.$$

其中$x_0$是初始图像,我们看到噪声$t$样本由固定的前向过程给出。$\epsilon$是在时间步长$t$采样的纯噪声,$\epsilon_\theta(x_t,t)$是我们的神经网络。神经网络的优化使用一个简单的均方误差(MSE)之间的真实和预测高斯噪声。 训练算法如下

  1. 从位置且复杂的真实数据分布$q(x_0)$中随机采样$x_0$,
  2. 我们在1和$T$之间均匀采不同时间步的噪声,
  3. 我们从高斯分布采样一些噪声,并在$?$时间步上使用前边定义的优良属性来破坏输入分布,
  4. 神经网络根据损坏的图像$x_t$进行训练,目的是预测施加在图片上的噪声,也就是基于已知方差表$\beta_t$作用在$x_0$上的噪声
所有这些都是在批量数据上完成的,和使用随机梯度下降法来优化神经网络一样。

有关突然火起来的diffusion model是什么?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  4. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  5. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  6. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

  7. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  8. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  9. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

  10. ruby - 当使用::指定模块时,为什么 Ruby 不在更高范围内查找类? - 2

    我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or

随机推荐