Generative and Diffusion Models: GANs, Conditional Generation, and Diffusion Training

Hyacehila

生成模型

本章介绍生成模型(generative model)。到目前为止,我们学习到的网络本质上都是一个函数,即提供一个输入 xx,网络就可以输出一个结果 yy。其中输出 yy 既可以是数值、类别,也可以是一个序列。目前,这些网络已经可以涵盖多数我们日常会遇到的问题了。本章我们将介绍另一类模型,他的作用是生成一段内容。

生成对抗网络

生成器

生成模型中网络会被作为一个生成器(generator)来使用。具体来说,在模型输入时会将一个随机变量 zz 与原始输入 xx 一并输入到模型中,这个变量是从随机分布中采样得到。输入时可以采用向量拼接的方式将 xxzz 一并输入,或在 xxzz 长度一样时,将二者的加和作为输入。

这个变量 zz 特别之处在于其非固定性,即每一次我们使用网络时都会从一个随机分布中采样得到一个新的 zz。通常,我们对于该随机分布的要求是其足够简单,可以较为容易地进行采样,或者可以直接写出该随机分布的函数,例如高斯分布(Gaussian distribution)、均匀分布(uniform distribution)等等。所以每次有一个输入 xx 的同时,我们都从随机分布中采样得到 zz,来得到最终的输出 yy。随着采样得到的 zz 的不同,我们得到的输出 y 也会不一样。同理,对于网络来说,其输出也不再固定,而变成了一个复杂的分布,我们也将这种可以输出一个复杂分布的网络称为生成器。

首先我们需要介绍为什么要研究生成器,我们现在给出一个背景,视频的插帧技术,我们希望从前几帧图像预测下一帧,也就是说网络的输入是几帧图像,输出是下一帧图像。如果我们此时就采用前面介绍过的监督学习方法来训练这个模型,我们会发现很多地方出现残影的情况。

这是因为监督学习中的训练数据对于同样的转角同时存储有角色向左转和向右转两种输出。当我们在训练的时候,对于一条向左转的训练数据,网络得到的指示就是要学会游戏角色向左转的输出。同理,对于一条向右转的训练数据,网络得到的指示就是学会角色向右转的输出。但是实际上这两种数据可能会被同时训练,所以网络就会学到的是“两面讨好”。也就是产生了残影

所以我们应该如何解决这个问题呢?答案是让网络有概率的输出一切可能的结果,或者说输出一个概率的分布,而不是原来的单一的输出。当我们给网络一个随机分布时,网络的输入会加上是一个 zz,这时输出就变成了一个非固定的分布,其包含了向左转和向右转的可能。此时就解决了这种非固定答案的问题。

回到生成器的讨论中,我们什么需要这类的生成模型呢?答案是当我们的任务需要“创造性”的输出,或者我们想知道一个可以输出多种可能的模型,且这些输出都是对的模型的时候。在生成模型中,非常知名的就是生成式对抗网络(generative adversarial network),我们通常缩写为 GAN。

首先介绍的是无限制生成(un-conditional generation),也就是我们不需要原始输入 xx。其对应的就是需要原始输入 xx 的条件型生成(conditional generation)。对于无限制的GAN,我们只需要输出随机向量zz,模型会根据曾经学习的结果生成图像(一般是图像)。

判别器

在 GAN 中,除了生成器以外,我们要多训练一个判别器(discriminator),其通常是一个神经网络。判别器会输入一张图片,输出一个标量,其数值越大就代表现在输入的图片越符合我们的生成需求。

判别器从本质来说与生成器一样也是神经网络,是由我们自己设计的,可以用卷积神经网络,也可以用 Transformer,只要能够产生出我们要的输入输出即可。

在模型训练的过程中,第一代生成器的参数几乎是完全随机的,所以它根本就不知道要怎么画出我们的目标,所以其画出来的东西就是一些莫名其妙的噪音。那判别器学习的目标是成功分辨生成器输出的图片。随着判别器的判别,生成器就要逐渐进化,努力骗过判别器。当然同时判别器也会逐渐的进步,会越来越严苛,来“逼迫”生成器产生出来的图片越来越符合需求。所以生成器和判别器彼此之间是一直的互动、促进关系,和我们所说的“内卷”一样。最终,生成器会学会画出符合需求的图像,而判别器也会学会分辨真假图片,这就是 GAN 的训练过程。

生成器与辨别器的训练过程

下面,我们从算法角度来解释生成器和判别器是如何运作的。生成器和判 别器是两个网络,在训练前我们要先分别进行参数初始化。

训练的第一步是固定生成器,只训练判别器。因为生成器的初始参数是随机初始化的,所以它什么都没有学习到,输入一系列采样得到的向量给它,它的输出肯定都是些随机、混乱的图片。

同时,我们会有一个符合需求的图像数据库,可以通过爬虫等方法得到。我们会从这个图库中采样一些图片出来,来与生成器产生出来的结果对比从而训练判别器。判别器的训练目标是要分辨真实图像与生成器产生出来的图像间的差异。 具体来说,我们把真正的图片都标 1,生成器产生出来的图片都标 0。接下来对于判别器来说,这就是一个分类或回归的问题。

我们训练完判别器以后,接下来第二步,固定判别器,训练生成器。训练生成器的目的就是让生成器想办法去骗过判别器,因为在第一步中判别器已经学会分辨真图和假图间的差异。生成器如果可以骗过判别器,那生成器产生出来的图片可能就可以以假乱真。具体的操作如下:首先生成器输入一个向量,其可以来源于我们之前介绍的高斯分布中采样数据,并产生一个图片。接着我们将这个图片输入到判别器中,判别器会给这个图片一个打分。这里判别器是固定的,它只需要给更“真”的图片更高的分数即可,生成器训练的目标就是让图片更加真实,也就是提高分数。

对于真实场景中生成器和判别器都是有很多层的神经网络,我们通常将两者一起当作一个比较大的网络来看待,但是不会调整判别器部分的模型参数。训练方法与前几章介绍的网络训练方法基本一致。

总结一下,GAN 算法的两个步骤。步骤一,固定生成器训练判别器;步骤二,固定判别器训练生成器。接下来就是重复以上的训练,训练完判别器固定判别器训练生成器。训练完生成器以后再用生成器去产生更多的新图片再给判别器做训练。训练完判别器后再训练生成器,如此反覆地去执行。当其中一个进行训练的时候,另外一个就固定住,期待它们都可以在自己的目标处达到最优。

GAN应用案例

根据前面的思路训练模型,随着训练轮次的增多,图像的质量会越来越高,整个训练的过程中只需要利用一个图像数据库无须重新进行标注。在经过几万轮的训练之后,基本上生成的图像就可以以假乱真了。

同样,我们可以用 GAN 产生我们从没有看过的人脸。先前我们介绍的 GAN 中的生成器,就是输入一个向量,输出一张图片。此外,我们还可以把输入的向量做内差,在输出部分我们就会看到两张图片之间连续的变化。

比如我们输入一个向量通过 GAN 产生一个看起来非常严肃的男人,同时输入另一个向量通过 GAN 产生一个微笑着的女人。那我们输入这两个向量中间的数值向量,就可以看到这个男人逐渐地笑了起来。

另一个例子,输入一个向量产生一个往左看的人,同时输入一个向量产生一个往右看的人,我们在之间做内差,机器并不会傻傻地将两张图片叠在一起,而是生成一张正面的脸。神奇的是,我们在训练的时候其实并没有真的输入正面的人脸,但机器可以自己学到把这两张左右脸做内差,应该会得到一个往正面看的人脸。

不过如果我们不加约束,GAN 会产生一些很奇怪的图片,完全不符合人类的认知,但是能够骗过由复杂的神经网络组成的判别器。

GAN的理论介绍

这一小节我们将从理论层面介绍 GAN,即为什么生成器与判别器的交互可以产生人脸图片。GAN训练的目标是通过调整模型参数从而最小化损失函数。

生成器的输入是一系列的从分布中采样出的向量,生成器就会产生一个比较复杂的分布,我们称之为 PGP_G 另外我们还有一系列的数据,这些原始的数据本身会形成另外一个分布,我们称之为 PdataP_{data}。训练的效果是希望PGP_GPdataP_{data} 尽可能的相似。我们现在的目标就是训练一组生成器模型中的网络参数,可以让生成的PGP_GPdataP_{data}之间的差异越小越好,这个最优生成器称为 GG^∗

目前的PGP_GPdataP_{data}都是非常复杂的结构,想要直接度量他们之间的差异很困难。在GAN中 获取PGP_GPdataP_{data}的采样是不困难的,前者可以经过生成器生成,后者可以通过在图库中采样获取。那么GAN的灵魂就是通过这两个采样,在没有度量差异的公式的情况下来估算差异,也就是判别器的引入。

在有了PGP_GPdataP_{data}的采样的采样后,我们会去训练一个判别器,其训练目标是看到真实数据就给它比较高的分数,看到生成的数据就给它比较低的分数。我们可以把它当做是一个优化问题。这个问题是很容易解决的。实际上就是构造了一个二分类的分类器。最基础的GAN的损失函数和JS散度密切相关。

至于具体的指标选取,这里我们不在讨论,对于GAN,我们能够理解其思想就足够了。

JS散度本身存在很多问题,由于我们不知道PGP_GPdataP_{data}的具体分布,而只拥有采样,由于采样数量或者他们本身的问题,重叠实际上非常少。首先,对于两个没有重叠的分布,JS 散度的值都为 Log2,与具体的分布无关。另外,对于两个有重叠的分布,JS 散度的值也不一定能够很好地反映两个分布的差异。因为 JS 散度的值是有上限的,所以当两个分布的重叠部分很大时,JS 散度不好区分不同分布间的差异。所以我们需要一个更好的衡量两个分布差异的指标。

既然是 JS 散度的问题,肯定有人就想问说会不会换一个衡量两个分布相似程度的方式,就可以解决这个问题了呢?是的,于是就有了 Wasserstein,或使用 Wasserstein 距离的想法。Wasserstein 距离也称为推土机距离(Earth Mover’s Distance,EMD),他考虑了两个分布之间各个样本之间的距离,也就是所有的可能性。他可以更好的度量两个分布之间的偏差,比JS散度好得多。

所以 WGAN 实际上就是用 Wasserstein 距离来取代 JS 距离,这个 GAN 就叫做 WGAN。

GAN 的性能评估方法

为了评估一个GAN生成出来的内容的质量,有一个方法是训练一个图像的分类系统,然后把 GAN 产生出来的图片输入到这个图像的分类系统里面,看它产生什么样的结果,这个图像分类系统的输入是一张图片,输出是一个概率分布,这个概率分布代表说这张图片是猫的概率、狗的概率、斑马的概率等等。如果这个概率分布越集中,就代表现在产生的图片可能越好。如果生成出来的图片是一个四不像,图像识别系统就会非常地困惑,它产生出来的这个概率分布就会是非常平均地分布。

这个是靠图像识别系统来判断产生出来的图片好坏,这是一个可能的做法,但是光用这个做法是不够的。光用这个做法会被一个叫做模式崩塌(mode collapse)的问题骗过去。模式崩塌是指在训练 GAN 的过程中遇到的一个状况,我们会发现生成式的模型它输出来的图片来来去去就是那几张,可能单一张拿出来你觉得好像还做得不错,但让它多产生几张就露出马脚,产生出来就只有那几张图片而已,这就是模式崩塌的问题。

发生模式崩塌的原因,从直觉上理解可以想成这个地方就是判别器的一个盲点,当生成器学会产生这种图片以后,它就永远都可以骗过判别器,判别器没办法看出来图片是假的。

不过模型崩塌这种问题,我们至少是知道有这个问题,是可以看得出的,生成器总是产生这张脸的时候,你不会说你的生成器是个好的生成器。

但是有一些问题是你不知道的并且更难侦测到的,即你不知道生成器产生出来的图片是不是真的有多样性。这个问题叫做模式丢失,指 GAN 能很好地生成训练集中的数据,但难以生成非训练集的数据,“缺乏想象力”。你的产生出来的数据,只有真实数据的一部分,单纯看产生出来的数据,你可能会觉得还不错,而且分布的这个多样性也够,但你不知道真实数据的多样性的分布其实是更大的。

虽然存在以上模式坍塌、模式丢失等等的问题,但是我们需要去度量生成器产生出来的图片到底多样性够不够。有一个做法是借助我们之前介绍过的图像分类,把一系列图片都丢到图像分类器里,看它被判断成哪一个类别,如图 8.27 所示。每张图片都会给我们一个分布,我们将所有的分布平均起来,接下来看看平均的分布长什么样子。如果平均的分布非常集中,就代表现在多样性不够,如果平均的分布非常平坦,就代表现在多样性够了。

当我们用这个图像分类器来做评估的时候,对于结果的多样性和质量好像是有点互斥的。因为我们刚才在讲质量的时候说,分布越集中代表质量越高,多样性的分布越平均。但是如果分布越平均,那质量就会越低,因为分布越平均,代表图片都不太像,所以质量就会越低。这里要强调一下质量和多样性的评估范围不一样,质量是只看一张图片,一张图片丢到分类器的时候,分布有没有非常地集中。而多样性看的是一堆图片分布的平均,一堆图片中图像分类器输出的越平均,那就代表现在的多样性越大。

过去有一个非常常被使用的分数,叫做 Inception 分数。其顾名思义就是用 Inception 网络来做评估,用 Inception 网络度量质量和多样性。如果质量高并且多样性又大,那 Inception 分数就会比较大。目前研究人员通常会采取另外一个评估方式,叫 Fréchet Inception distance (FID)。具体来讲,先把生成器产生出来的人脸图片,丢到 InceptionNet 里面,让 Inception 网络输出它的类别。这里我们需要的不是最终的类别,而是进入 Softmax 之前的隐藏层的输出向量,这个向量的维度是上千维的,代表这个图片,如图 8.28 所示。图中所有红色点代表把真正的图片丢到 Inception 网络以后,拿出来的向量。这个向量其实非常高维度,甚至是上千维的,我们就把它降维后画在二维的平面上。蓝色点是 GAN 的生成器产生出来的图片,它丢到 Inception 网络以后进入 Softmax 之前的向量。接下来,我们假设真实的图片和生成的图片都服从高斯分布,然后去计算这两个分布之间的 Fréchet 的距离。两个分布间的距离越小越好,距离越小越代表这两组图片越接近,也就是产生出来的品质越高。这里还有几个细节问题,首先,假设为高斯分布没问题吗?另外一个问题是如果要准确的得到网络的分布,那需要产生大量的采样样本才能做到,这需要一点运算量,也是做 FID 不可避免的问题。

此外,还有一个状况。假设 GAN 产生出来的图片,跟真实的图片长得一模一样,那此时FID 会是零,因为两个分布是一模一样的。如果你不知道真实数据长什么样子,光看这个生成器的输出可能会觉得太棒了,那 FID 算出来一定是非常小的,但是如果它产生出来的图片都跟数据库里面的训练数据的一模一样的话,那干脆直接从训练数据集里面采样一些图像出来不是更好,也就不需要训练生成器了。我们训练生成器其实是希望它产生新的图片,也就是训练集里面没有的人脸。

对于这种问题,就不是普通的度量标准可以侦测的。那怎么解决呢?其实有一些方法,例如可以用一个分类器,这个分类器是用来判断这张图片是不是真实的,是不是来自于你的训练集的。这个分类器的输入是一张图片,输出是一个概率,这个概率代表说这张图片是不是来自于你的训练集。如果这个概率是 1,那就代表说这张图片是来自于你的训练集,如果这个概率是 0,那就代表说这张图片不是来自于你的训练集。但是另外一个问题,假设生成器学到的是把所有训练数据里面的图片都左右反转呢,那它也是什么事都没有做。但是你的分类器会觉得说,这张图片是来自于你的训练集,因为它是来自于你的训练集的图片,只不过是左右反转而已。进行分类时或者进行相似度的比较时,又比不出来。所以 GAN 的评估是非常地困难的,还甚至如何评估一个生成器做得好不好都是一个可以研究的题目。

条件型生成

下面,我们要介绍条件型生成(conditional generation)。我们之前讲的 GAN 中的生成器,它没有输入任何的条件,它只是输入一个随机的分布,然后产生出来一张图片。我们现在想要更进一步的是希望可以操控生成器的输出,我们给它一个条件 x,让他根据条件 x 跟输入 z 来产生输出 y。比如做文字对图片的生成,这就是一个条件生成的问题。我们现在一般会采用将条件(比如文字约束)进行编码,然后放到生成器中。

在条件形GAN中,我们需要让判别器也有处理条件的能力,我们需要文字和图像成对的数据来训练判别器,所以条件型的 GAN,一般的训练是需要这个成对的标注数据的。所以当看到这些真正的成对数据,就给它 1 分,看到红色眼睛但是文字叙述是黑色头发,就给它 0 分,看到黑色头发但是文字叙述是红色眼睛,也给它 0 分,这样就可以训练判别器了

那其实在实际操作中,只是拿这样的负样本对和正样本对来训练判别器,得到的结果往往不够好。往往还需要加上一种不好的状况:已经产生好的图片但是文字叙述配不上的状况。所以通常会把我们的训练数据拿出来,然后故意把文字跟图片乱配,或者故意配一些错的,然后告诉判别器看到这种状况,也是要输出不匹配。用这样子的数据,才有办法把判别器训练好。然后生成器跟判别器反复的训练,最后才会得到好的结果,这个就是条件型的 GAN。

扩散模型

扩散模型(diffusion model)是一种运用了物理热力学扩散思想的生成模型。扩散模型有很多不同的变形,本章主要介绍最知名的去噪扩散概率模型(Denoising Diffusion Probabilistic Model,DDPM)。如今比较成功的用扩散模型做的图像生成的系统,比如 DALL-E、谷歌的Imagen、Stable Diffusion 基本上都是用类似的方法来作为其扩散模型。

接下来介绍下扩散模型运作方法。我们来看它是怎么生成一张图片的。在生成图片的第一步,要去采样一个都是噪声的图片,就是从高斯分布里面采样出一个向量。这个向量里面有的数字,这个向量的维度跟要生成的图片大小是一模一样的。

接下来就有一个去噪的模块,去噪的网络。输入一张都是噪声的图,输出它就会把噪声滤掉一点,就可能看到有一个猫的形状,再做去噪,猫的形状就逐渐出来。去噪越做越多,期待最终就看到一张清晰的图片,去噪的次数是事先定好的。每个去噪一般都有一个编号,越接近成品图像越小。

接下来呢就要讲这个去噪的模型。这边是把同一个去噪的模型反复进行使用,但是由于每次去噪过程噪声实际上的强度都不一样,编号越大噪声实际上越强,因此去噪的模块会额外输入一个数字,表示目前噪声强度的大小。

去噪模型里面有一个噪声预测器(noise predictor),会预测图片里面的噪声。告诉我们这个图片里的噪声长什么样子。再把它输出的图片减去噪声,就产生去噪以后的结果,所以这边去噪的模型并不是输入一张有噪声的图片。输出就直接是去噪后的图片,它其实是产生一个这个输入的图片的噪声,再把噪声扣掉输入的图片来达到去噪的效果。由于训练难度的问题,我们这里很少选择使用端到端的模型。

接下来的问题就是怎么训练这个噪声预测器呢?一个去噪的模型是根据一个噪声的图片和去噪的步数的 ID,产生去噪的结果。我们需要一个噪声的标准答案,才能实现噪声预测器的训练。也就是说我们需要成对的训练数据。

噪声预测器的训练数据是人为创造的,怎么创造呢?我们需要从数据集里面拿一张图片出来,随机从高斯分布里面采样一组噪声出来加上去,产生有点噪声的图像,能再采样一次再得到更噪声的图片,以此类推,最后整张图片就看不出来原来是什么东西。

加噪音的过程称为前向过程,也称为扩散过程。做完这个扩散过程以后,就有噪声预测器的训练数据了。对噪声预测器,其训练数据就是这一张加完噪声的图片跟现在是第几次加噪声,是网络的输入,而加入的这个噪声就是网络应该要预测的输出,就是网络输出的标准答案。所以在做完这个扩散过程以后,就有训练数据了。

刚才只是从一个噪声里面生出图,还没有考虑文字。如果要训练一个图像生成的模型,他是“吃”文字产生图片,其实还是需要图片跟文字成对的数据。在有了这样的数据以后,我们只需要把文字编码后加入噪声预测器即可。

为了获取足够扩散模型学习的数据,ImageNet就略显不足了,毕竟他缺乏文字的标签。目前主流的扩散模型数据一般来自于 LAION,LAION 有 58.5 亿张的图片,并且还拥有更全面的标签与搜索Demo,甚至包括多种语言。

  • Title: Generative and Diffusion Models: GANs, Conditional Generation, and Diffusion Training
  • Author: Hyacehila
  • Created at : 2024-11-14 14:51:39
  • Link: https://hyacehila.github.io//blog/2024/11/14/generative-and-diffusion-models/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments
On this page
Generative and Diffusion Models: GANs, Conditional Generation, and Diffusion Training