当前位置: 首页 > news >正文

DALL·E 2(内含扩散模型介绍)-生成式模型【学习笔记】

视频链接:DALL·E 2(内含扩散模型介绍)【论文精读】_哔哩哔哩_bilibili(up主讲的非常好,通俗易懂,值得推荐)

1、GAN模型

        GAN部分约在视频的第28分钟位置处开始。

        GAN就是左右手互搏。GAN需要训练两个网络,一个是生成器Generator,一个是判别器Discriminator。生成器:给定一个随机噪声z,生成器会生成一些东西。在这里希望生成器能生成一个比较真实的图片x‘,再将生成的图片x’给判别器,同时也给一些真实的图片x给判别器。让判别器判断哪个是真图片,哪个是假图片。判别器其实是一个0/1的二分类问题。

        通过Generator和Discriminator这两个网络之间的互相较量,判别器和生成器不断的提高自己,最后生成比较真实的图片。事实上,因为GAN的目标函数就是用来以假乱真的,所以截止到目前, GAN生成的图片保真度也是非常高,人眼难以区分生成的图片是真是假,所以这才有了Deepfakes的火爆。不光是真实,经过这么多年对GAN模型的改造,GAN现在依然比较好用,需要的数据不是那么多,能在各个场景下使用,优点还是蛮多的。

        GAN有一个最致命的缺点就是训练不够稳定。最主要的原因在于它要同时训练Generator和Discriminator这两个网络,存在一个平衡的问题。如果训练的不好,模型就训练坍塌了。此外,由于GAN的主要优化目标就是让图片尽可能真实,因此,它生成图片的多样性就不太好。它的多样性主要来自于刚开始的随机噪声,简单来说就是GAN的创造性不太好。最后,GAN不是一个概率模型,它的生成都是隐式的,它就是通过一个网络去完成的,研究人员也不知道它做了什么,也不知道它遵循什么分布,所以说GAN在数学上就不如后续的VAE或者扩散模型优美。

2、VAE模型

2.1、AE(Auto-Encoder

        AE部分约在视频的第30分30秒位置处开始。

​        AE比较简单,是很早之前的技术了。大概意思是给定一个输入x,经过一个编码器E,就能得到一个特征Z,这个特征的维度一般都会小很多,所以也管它叫bottleneck。再从bottleneck开始,经过一个解码器D,最终得到一个图像x'。

        训练的目标函数是希望重构图像x'能尽可能的重建之前的x(x'尽可能接近原始输入数据x)。由于是自己重建自己,因此叫Auto-Encoder,就是自编码器。在自编码器AE出来之后,紧接着就出来了去噪自编码器(Denoising Auto-Encoder,DAE)。

​        DAE就是先把原图进行一定程度的打乱(输入数据中通常包含噪声),比如说变成xc(corrupted x),再将经过扰乱后的输入传给编码器E,后续操作和AE一样。此时,得到一个 bottleneck的特征,再通过解码器D得到了一个输出x'。同样,希望输出x'能够重建原始的x,而不是重建经过扰动之后的xc。后续证明这个改进非常的有用,尤其是对视觉领域更加有用,会让训练出来的模型非常的稳健,也不容易过拟合。部分原因是因为图像像素冗余性较高,即使对原来的图片做一些污染,模型还能抓住它的本质,然后把它重建出来。这和何凯明的掩码自编码器(Masked Auto-Encoder,MAE)比较相似。在训练的时候能够mask掉75%的图像区域,还能把这个图像很好的重建出来,说明了图像的冗余性确实高,从侧面证明了DAE和MAE的有效性。

        不论是AE、DAE还是MAE,他们的主要目的都是为了学习中间的bottleneck特征,并通过这个特征去做一些分类、检测、分割等任务,它并不是用来做生成的,原因是因为bottleneck特征中学到的不是一个概率分布,没法对它进行采样。这个Z并不像GAN里那样是一个随机噪声,它是一个专门用来重建的特征。这种encoder-decoder的形式确实是一个很好的结构,怎么使用这种结构去做图像生成呢?所以就有了变分自编码器(Variational Auto-Encoder,VAE)。

2.2、VAEVariational Auto-Encoder

        VAE部分约在视频的第33分钟位置处开始。

        VAE跟AE有很大的差别,虽然它的整体框架看起来还是一个输入x进了一个编码器E,得到了一些东西,然后出解码器D,最后得到一个输出x'。VAE的目标函数还是让输出x'尽可能的去重建原来的x。

        看起来好像一样,但其实有一个非常重要的区别,就是VAE的中间不再是学习一个固定的bottleneck特征,而是去学习一个分布。作者假设这个分布是高斯分布,高斯分布可以用均值和方差来描述。具体而言,当得到从编码器E输出的特征后,在后面加一些FC层,去预测均值和方差,得到对应的均值和方差之后,用公式Z=μ+σε采样一个Z,这样VAE就可以用来做图像生成了。因为在训练好模型以后,完全可以把前面的编码器E扔掉,此时的Z就是一个可以从高斯随机噪声里抽样出来的样本。将Z给解码器D,这样就能生成一张照片了。

        因为VAE预测的是一个分布。从贝叶斯概率的角度来看,前面的这一过程就是给定x,得到 z 的过程(q(z|x)),其实就是一个后验概率。学出来的distribution就是一个先验分布。后面的给定z去预测一张图片x的时候(p(x|z)),它其实就是likelihood,就是说这里做的就是Maximum likelihood(最大似然估计),从数学上看就干净很多、优美很多。

        VAE也有一些不错的性质,比如:由于VAE学的是一个概率分布,它从这个分布里面去抽样,所以它生成的图像多样性就比GAN要好得多。这也就是为什么研究人员后续做了很多基于VAE的工作,包括VQ-VAE,还有VQ-VAE-2,以及后来的DALL·E第1版模型也是在VQ-VAE的基础上做的。

2.3、VQ-VAE(Vector Quantized Variational Auto-Encoder

        VQ-VAE部分约在视频的第35分钟位置处开始。

        向量量化变分自编码器(Vector Quantized Variational Auto-Encoder,VQ-VAE)从整体上看和VAE差不多。VQ的含义是Vector Quantized,就是把VAE做量化。那为什么要这么做?原因如下:现实生活中所有的这些信号,包括声音、图像等可能都是连续的,或者说大部分任务可能都是回归任务,但将它表示出来以及去解决这些问题时,其实都把它离散化了,图像变成像素了,语音也都抽样过了。大部分工作的比较好的模型也都是分类模型,又都从回归任务变成分类任务。同样,如果用之前的VAE方式,就不好把模型做大,图像的尺寸做大,而且那个分布也不好学习。因此,可以不去做那个分布的推测,而是用一个codebook(VQ-VAE能利用codebook机制把图像编码成离散向量)进行代替。这个codebook可以理解聚类的中心等,codebook的大小一般是K乘以D,K一般是8192,D一般可能是512或768(表示有8192个长度为D的向量在这个codebook 里,即有8192个聚类中心)。此时,如果有一个图片经过编码器E得到了一个特征图f(长宽分别是H和W),将这个特征图里的向量与codebook里的向量进行对比,看看它跟哪个聚类中心最接近,再将最接近聚类中心的那个编码存到Z矩阵里。因此,Z里面可能有一些编号,比如说1或者100之类的。

         一旦完成聚类的分配,就不用之前的特征f了。取而代之的是,将index对应的特征拿出来(如Z里面编号为1,就将K×D中编号为1的向量拿出来;如果编号为10,就将K×D中编号为10的向量拿出来),生成新的特征图叫做fq(就是quantized feature经过量化后的特征)。这个量化后的特征非常可控,因为它永远都是从这个codebook里来的,而不是一个随机的东西,因此优化起来相对容易。有了特征图fq以后,跟之前的AE或者VAE就差不多了,通过一个解码器,就可以去重构一张图片。目标函数还是让x'尽量跟x保持一致。这样就完成了整个VQ-VAE的训练。

         VQ-VAE非常有用,它后来不仅用在了DALL·E中,还用在视觉中做自监督学习。如BEIT这篇论文中将DALL·E训练好的codebook拿过去,将图片全都quantize成特征图fq,再通过特征图fq做ground truth(监督学习中正确的标注是ground truth)自监督训练一个视觉网络。最近BEIT又出了VL-BEIT(就是vision language的BEIT), 也是大概的思路,只不过是用一个transformer编码器去做多模态的任务。

         说完VQ-VAE后会发现这里学习的是一个固定的codebook了,意味着VQ-VAE没办法像VAE那样做随机采样,然后去生成对应的图片。准确的说VQ-VAE不像是一个VAE,更像是一个AE。VQ-VAE学的codebook和特征图fq是拿去做high level任务的,也就是做分类、检测等。如果想让VQ-VAE做生成怎么办?还需要单独再训练一个prior网络。在VQ-VAE论文中,作者又训练了一个 Pixel CNN当做prior网络,从而能够利用已经训练好的codebook去做图像的生成。

         在VQ-VAE之后又有VQ-VAE-2,这是一个简单的改进。VQ-VAE-2首先把模型变成层级式的,不仅做局部的建模,还做全局的建模,加上attention后,模型的表达能力变强了。同时,它还根据codebook又去学了一个prior,所以生成的效果也非常好。对于VQ-VAE来说,先训练了一个codebook,然后又训练了一个Pixel CNN去做这种生成,Pixel CNN其实是一个auto regressive自回归模型。那还有什么模型是自回归呢?那就是OpenAI的看家本领——GPT系列了。OpenAI将Pixel CNN换成GPT,得到了一个更好的图像生成。既然language那边做得这么好,为什么不想办法用文本去引导图像生成呢?因此就有了DALL·E。

2.4、DALL·E

        DALL·E部分约在视频的第39分40秒位置处开始。

         DALL·E从模型上来看非常简洁,如果有一个图像文本对,这个文本先通过BPE编码得到一个特征ft,这个特征有256维。还有一个256*256的图像,经过一个VQ-VAE,这个VQ-VAE中有一个训练好的codebook,在DALL·E中直接拿过来用。因此,DALL·E是一个两阶段的图像生成器,将原来的图像变成图像特征fq以后,这个维度就下降了很多,就从256*256变成了32*32,一共有1024个token,最后将文本特征和图像特征直接连接起来,变成了一个有1280个token的序列。再将这个序列扔给GPT,把该遮住的地方遮住,让GPT模型去预测就好了。 

         至于推理,只需要提供一个文本,将文本变成文本的特征ft,再通过文本的特征直接用自回归的方式把图像生成出来。

         DALL·E论文中还有很多细节,如会生成很多很多的图片,到底选哪一张?它会用CLIP模型去做一个排位,挑选出与文本最贴切的生成的图片作为最后的生成图像。DALL·E里有将近一半的篇幅都在写怎么才能把12个billion(也就是120亿)这么大的参数训练起来,以及怎样去收集了一个特别大的数据集能够支撑训练这样一个模型,这沿袭了GPT系列工作的特点,就是大力出奇迹。

3、扩散模型

3.1、扩散模型的网络结构与工作原理

        扩散模型部分约在视频的第41分30秒位置处开始。 

         假设你有一张正常的图片X0,每一步都往这个图片里加一个很小的正态分布的噪声,得到X1,这个X1就是在X0的基础上多点了几个杂的点。再给X1加噪声,一直加到T次,如果这个T特别大,如果无穷无尽的话,那最终X0就会变成一个真正的噪声,就变成一个正态分布了,更专业一点叫做各项同性的正态分布。整个过程就叫做forward diffusion(前向扩散过程)。为什么要叫扩散模型?这个名字是来自于热力学的启发就是thermodynamics,热力学中有一个名词叫diffusion。在热力学中,描述的过程是:如果有一些高密度的和低密度的物质,高密度的物质会慢慢的向低密度做扩散。比如说喷了香水,这个香水就会慢慢扩散到整个房间,最后达到一种平衡。所谓的平衡,就是这里提到各项同性的正态分布,这是趋近于随机噪声的。视觉这边就沿用了这个名字,还是叫它diffusion model。

         那这跟图像生成有什么关系?反过来想,如果现在输入的是一个随机噪声,也就是GAN里面的那个Z,如果能找到一种方式,或者训练一个网络,能慢慢的把这个噪声一点一点的再恢复到最初的图片X0,就可以做图像生成了。事实上扩散模型就是这么简单,就是通过反向过程去做图像生成的。如果随机抽样一个噪声(如XT或者是之前的任意一步),就可以训练一个模型,将XT变到XT-1。再用同样的模型将XT-1变成XT-2,一步一步的倒推回来。反向过程中使用的所有模型都是共享参数的,就只有一个模型,只不过要采样生成很多次,这也是现在扩散模型非常大的一个不足。扩散模型训练上跟别的模型比起来,是比较贵的。在推理的时候,扩散模型是最慢的一个。对于GAN,只要训练好了这个模型,接下来给它一个噪声,它就能出来一张图片,非常的快,就做一次模型的forward就可以了。对于扩散模型,尤其是最原始的扩散模型来说,一般T选1000步。即如果你随机选择一个噪声,要往回推1000步的话,就要做1000次的forward,一点一点把这个图像恢复出来,这个开销是远远大于其他生成模型的。

         撇开推理速度不谈,先来看一下reverse diffusion过程中一般使用的模型长什么样。可以看到,扩散模型的输入和输出始终是图像,其大小始终不变。因此,diffusion model就采取了一个非常常见的模型结构,就是U-Net。U-Net就是一个CNN,先通过编码器一点一点把这个图像压小,再用解码器一点一点把这个图像恢复回来。XT和XT-1这两个图像尺寸大小是一样的。为了让恢复效果更好,U-Net中还有一些skip connection操作,直接把信息从前面推过来,这样能恢复一些细节。后来对网络结构还有一些改进,如在U-Net中加上attention操作,会让图像生成变得更好。reverse diffusion中的模型不一定要用U-Net,也可以用其他的,只是大部分扩散模型中的网络都用了U-Net。

3.2、扩散模型的发展历程:DDPM

        扩散模型部分约在视频的第45分40秒位置处开始。 

        扩散模型早在2015年甚至有可能更早的时候就已经提出来了,但当时只是一个想法,并不能做到很好的图像生成。这可能与20年前的深度学习一样,想法已经有了,只不过缺了很多必要的因素,导致它不能很好的训练。

        直到2020 年6月,出来了一篇论文Denoising Diffusion Probabilistic Models(DDPM),对原始的扩散模型进行了一些改进,把优化过程变得更简单了。DDPM中最重要的两个贡献:一是之前都是用XT去预测XT-1,做这种图像到图像的转化。DDPM觉得这可能不好优化,因此,DDPM不去优化图像的转换,而是去预测从XT-1到XT,这个噪声是怎么加的?只去预测这个噪声行不行?这个思想有点像ResNet了,本来可以直接用x去预测y,但直接预测y太难,应该把这个问题理解成y等于x加上一个residual,只去predict残差residual就可以了。同样,DDPM中不去预测XT-1,而是预测forward diffusion中加了多少噪声,一下子就简化了这个问题。

        用刚才讲过的U-Net网络结构。输入是XT这个图片,输出是预测T-1时刻的X。在DDPM这篇论文中,不去预测T-1时刻的X,而是去预测添加的噪声εU-Net模型的输入,除了当前时刻的XT,还有一个输入是timing embedding,主要用来告诉U-Net模型现在到了反向扩散的第几步。time embedding的形式和Transformer中用的位置编码一样,也是一个正弦的位置编码,或者是一个傅里叶特征。time embedding怎么加到U-Net模型中?有很多种方式:可以直接加,也可以拼接起来,还可以通过更复杂的手段把它加到网络模型中,它给模型带来的提升相当明显。

        为什么要加一个time embedding呢?还有一个原因是U-Net模型全都是共享参数的。怎样让U-Net模型根据不同的输入而生成不同的输出,最后从一个完全的随机噪声变成一个有意义的图片,这是相当难的一件任务。研究人员希望U-Net模型在刚开始的反向过程中,可以生成一些物体的大概轮廓、一些很粗糙的图像,不需要很清晰,也不需要很写实,只要有那个意思就行。随着扩散模型反向过程的推进,到最后快生成逼真图像的时候,希望它学到一些高频的信息特征,如物体的边边角角、一些细小的特征等,这样会让生成的图片更加逼真。由于所有的U-Net模型都是共享参数的,因此就需要time embedding提醒U-Net模型现在走到哪一步了,现在的输出是需要粗糙一点儿的还是细致一点儿的。加time embedding对整个图像的生成和采样过程都很有帮助。

        对目标函数而言,如果我们现在给定了XT,我们要去预测这个XT减一。我们要算的 loss 就是我们已知的这个噪声和我们现在预测出来的这个噪声的差值。那对于 ground truth 的这个噪声来说,我们是知道的,因为在这个正向的扩散过程中,每一步添加的噪声都是我们自己加的,都是一个固定的过程,所以说是已知的,后面才是我们预测的。

        那这里这个 f 函数其实对应的就是下面的我们这个 unit 网络结构,那这个 x t 就是我们的输入 x t,然后这个 t 就是我们这里输入的这个timing bedding。

        通过计算这个简单的目标函数,我们就能把 DDPM 这个网络。训练起来了。

        然后 DDPM 还做了第二个贡献。具体来说就是如果你要去预测一个正态分布,其实你只要学它这个均值和方差就可以了。然后作者这里发现了,其实你只要去预测那个均值就可以,你方差都不用学你这个方差,只要变成一个常数,最后这个效果就已经很好了。所以这又再次降低了这个模型优化的难度,所以 DDPM 就工作得很好,第一次能够用这个扩散模型生成很好的图片,算是扩散模型这边的这个开山制作。

        那大概介绍完了扩散模型和DDPM,其实这里可以做个总结。DDPM跟这个 VAE 的模型其实还是有很多相似之处的,比如说你也可以把它想象成是一个编码器解码器的结构。不过在这个扩散模型中,它的这个编码器一步一步这样走过来,走到中间的这个 z 它是一个固定的过程,而对于 VAE 来说,它的那个编码器是学习。

        那第二个不同,就是说对于扩散模型来说,它的每一步的这个中间过程跟刚开始的这个输入都是同样维度大小,但是对于一般的这种AE,VAE。这种编码器解码器的结构来说,它那个中间的那个 bottleneck 特征往往是要比输入小很多。

        那第三个区别就是对于扩散模型来说,它有这么步数的一个概念。它从这个随机噪声开始,要经过很多步才能生成一个图片,所以它有这个timestep, time embedding 这些概念。而且在所有的这个 timestep 里,它的这个 unit 模型结构都是共享参数的,而在 VE 里其实就不存在这一点。

        那这个扩散模型一旦做 work 了之后,大家的兴趣一下就上来了,因为它在数学上特别的简洁美观。而且因为不论是正向还是逆向,它都是这种高斯分布。所以也能做很多推理,证明有很多很不错的性质。所以之前大家可能就担心它不能在真实的数据集上去工作得很好,它可能不能适用于很大的模型或者很大的数据集。但结果现在有人把它做 work 了。OpenAI 的人,也就是DALL·E 2,我们之前说过的二座和三座其实就立马来着手研究这个问题了。他们就仔细钻研了一下这个DDPM,提出了一些改进,然后就变成了这个 improve 的DDPM,大概就是在同年 20 年的年底放到 arxiv上的,他这边做了几个改动。其中一个改动就是 DDPM 里说这个正态分布的方差不用学,就用一个常数就可以了,但是他们觉得如果你能把这个东西学了,那可能效果会更好。然后他这边就去学了。然后确实在后面的取样还有这个生成效果上都不错。第二个就是他把怎么添加噪声的这个schedule 改了。从一个线性的schedule 变成了一个余弦的schedule,发现也工作的不错。那这个我就不细说了理解上你可以去跟那个学习率的 schedule 去做一个对比,也是从线性到余弦。

        然后最后一个贡献就是他们简单的尝试了一下,如果用这个大模型,这个扩散模型会表现的怎么样。结果发现这个扩散模型 skill 的非常好,也就是说如果给它上更大的模型,它就会给你更好的图像生成结果,那这对 OpenAI 来说那无疑是个非常好的消息,所以二座和三座立马着手去做这件事儿,所以紧接着几个月之后就出来了这一篇论文,就是 diffusion model Beats gang 就是扩散模型比杆强。

        那在这篇论文里,首先它上来就是说把模型加大加宽。然后增加自助力里这个头的数量attention head。还有 single skill的 tension 不够用了,我们就上 Multi skilled attention,所以总之就是把模型变得又大又复杂。然后他还提出了一个新的一个归一化的方式,叫做 Adaptive group normalization,就是根据这个部署去做这种自适应的归一化,那发现效果也非常不错。而且在这篇论文里,作者还使用了一个叫 classifier guidance的方法去引导这个模型做采样和生成。不仅让生成的这个图片更加的逼真,而且也加速了这个反向采样的这个速度。论文中说他们可以做到就做 25 次采样,就能从一个噪声生成一个非常好的图片。所以说是加速了相当多。那这里说的classifier guidance 方法是什么?然后后续的这个 Glide 模型和 DALL·E 2 two 里用的 classifier free 的 guidance 方法又是什么呢?那在这个扩散模型能打败 Gan 的这篇论文出现之前,其实扩散模型生成的这个图像看起来已经非常不错了,也很逼真,但是它就在算这些 inception score,就 s score 或者 FID score 那些分数的时候,他比不过Gan。如果光让大家看你生成这个图的话,那大家可能就觉得你生成这些图是不是你挑的这个结果就不够那么有信服力?而且这个当然也不好审稿,也不好中论文。所以还是把这个分儿能提上来是比较关键。同时这个扩散模型,这个采样和生成图片过程又这么慢,所以大家就在想怎么能用一些额外的帮助。或者说找一些guidance,找一些这种额外的指导来帮助这个模型进行采样和学习。

参考链接:DALL·E 2(内含扩散模型介绍)【论文精读】Hierarchical Text-ConditionalImage Generation with CLIP Latents_dalle2-CSDN博客


http://www.mrgr.cn/news/80404.html

相关文章:

  • 简单的Java小项目
  • Three.js资源-贴图材质网站推荐
  • jdk1.8安装及环境配置(最新最详细教学!!!)
  • 在Ubuntu服务器上备份文件到自己的百度网盘
  • 仿《公主连结》首页场景的制作(附资源包)
  • 音视频入门基础:MPEG2-TS专题(17)——FFmpeg源码中,解析TS program map section的实现
  • elasticsearch 使用enrich processor填充数据
  • es中段是怎么合并的
  • java中的List、数组和set
  • 电脑显示器选购指南2024
  • 如何在繁忙的生活中找到自己的节奏?
  • M3DM的autodl环境构建过程笔记
  • 【开源】使用环信UIKit for uniapp 做一个IM即时聊天应用
  • monorepo代码管理框架
  • Linux NVIDIA GPU linpack 测试
  • Timestamp Unix时间戳在线转换 - 加菲工具
  • Windows域 - Java实现用户增删改查,修改用户密码
  • 51c自动驾驶~合集41
  • DES笔记整理
  • D3 基础1
  • vue中slot插槽的使用(默认插槽,具名插槽,作用域插槽)
  • QT c++ 测控系统 一套报警规则(上)
  • 【代码随想录day59】【C++复健】 47. 参加科学大会(dijkstra(堆优化版)精讲 );94. 城市间货物运输 I
  • C语言(构造类型)
  • OpenIPC开源FPV之Adaptive-Link地面站代码解析
  • 锂电池SOH预测 | 基于BiGRU双向门控循环单元的锂电池SOH预测,附锂电池最新文章汇集