【学习】GAN
机器学习/深度学习
- 一、生成式对抗网络GAN
- 为什么我们需要generator?为什么要输出一个分布呢?
- generative adversarial network(GAN)
- 1、算法algorithm
- 2、原理
- divergence跟objective function相关
- 3、训练GAN的小技巧
- JS divergence不适合
- 4、Wasserstein distance/earth mover distance
- 5、WGAN
- 6、评估
- mode collapse问题
- mode dropping问题
- memory GAN问题
- 7、conditional generator
- 用文字产生图片
- 用图片产生图片
- 从声音画出图片
- 8、GAN用在无监督学习上
- cycle GAN
- text style transfer
- 二、总结
一、生成式对抗网络GAN
把网络当成一个generator,输入会加上一个random variable 随机变量z。这个z是从某一个distribution 里面simple出来的,z和x作为网络的输入,y为输出。每次我们用这个网络的时候都是随机生成的,每次都不同。
z必须够简单!
随着每次的z不同,我们的输出y不再固定,输出的y分布是一个复杂的分布。
这种可以输出一个distribution的网络叫做generator。
为什么我们需要generator?为什么要输出一个分布呢?
如果要预测一个游戏画面,我们就可以把之前的游戏画面输入到网络里面,然后就能预测未来输出画面,这样我们就能训练我们的网络的输出跟真实值越接近越好。
但是这样的例子会有一些问题:小精灵分裂或者消失。在训练资料里面,有些相同场景会产生不一样的移动(一个向左一个向右走)!网络学到的就是结合几个画面,那就可能会产生分裂!网络学到的是向左右分开是对的,但是同时是不对的。
其实这跟之前说到的一个火车也很类似。
我们怎么解决这个问题呢?我们能不能让网络只输出一个单一输出,而是输出一个概率,决定输出应该是什么样子呢?可以,我们可以使用GAN。
什么时候我们需要distribution呢?当我们的任务需要一点“创造力”的时候。我们需要找一个方程,但是同样的输入有多种不同的输出,那我们就让机器具有自己决定的能力(应该是具有一点随机性)。
generative adversarial network(GAN)
下面的例子是一个无条件生成(unconditional generation)的例子,也就是把输入x去掉,只留下z输入,输出为y。z是一个正态分布sample出来的向量,这个向量是low-dim vector,维度自己决定。
下面是一个动漫人物脸生成的例子。其实生成一张图片相当于是生成一个高维向量(high-dim vector)。假如我们生成一个ab的彩色图片,那我们需要输出的高维向量就是ab*3的向量。当我们输入不同的z的时候,就得到不同的照片。当然,我们也可以不用正态分布,只要简单的distribution就行了,因为generator会把输入的简单的z对应到复杂的distribution。可以把选择distribution交给generator处理。
在GAN里面,除了需要训练generator(NN)之外,还要另外训练一个discriminator(也是一个NN,相当于一个方程)。discriminator的作用是把一张图片作为输入,输出是一个数值scalar(数值越大,越像一张二次元人物图)。
generator的任务是画出二次元人物图像,discriminator相当于分辨这个图像。
第一代的generator V1画出很模糊的图片,第一代的discriminator V1判断的一句是不是有眼睛。很明显就判断为没有。V2画出明显的眼睛,骗过discriminator V1,但是discriminator V2还是升级了。然后一代代升级,generator和discriminator越来越严格。以前很多人把他们说成是对抗的!
1、算法algorithm
首先要初始化generator(G)和discriminator(D),对于每一个训练迭代都有以下步骤:
step1:固定G,训练D。因为我们的输入z是随机的,所以在固定的G里面生成出俩的图像是模糊不清的。我们在一个数据集里面sample出一些样本,然后把这些样本和G产生的图片去训练D。
D的训练目标是分辨真正的图片和产生的图片之间的差异。
具体做法可以是下面的两种:
classification问题:我们可以把这个任务当成分类问题做,把真实图片标记为1,把生成图片标记为0。对于D来说,标记1的是一个类别,标记0的是另外一个类别,然后我们就可以训练一个classifier。
regression问题:对于D来说,看到真实图片输出1,看到生成图片输出0。
step 2:固定D,训练G。G需要去学习生成一些图片来“骗过”D。
操作:高斯分布sample出的向量作为输入,输出是一个图片。把这个图片输入到D里面,D会输出一个分数。因为D的参数是固定的,所以我们需要对G的参数进行更新。**怎么判别G生成图片的好坏呢?查看D的得分,我们希望得分越高越好!**在G调整参数之后,D输出的分数很高 ,那生成的图片就很接近真实图片了!也就是说,我们可以看层G和D是一个有很多层网络的网络NN,我们把D和G接起来看做是一个比较大的网络。在某个隐藏层里面,它的输出是非常宽的,大小就是ab3(像素*3)。我们希望调整参数之后,这个大网络输出的分数越大越好。
训练好这两步的时候,我们就不断反复上面的两个步骤,直到得到满意的结果。
在课程里面,2019年李宏毅老师就能实现这个模型,产生明显的动漫头像。如果想要产生人脸,可以参考progressive GAN。
输入不同的值,做内插,可以得到一张连续的脸!
2、原理
我们训练这个GAN,需要最大化或者最小化的是什么呢? 我们输入一个高斯分布随机出来的分布到G里面,然后输出PG,我们有一个真是的分布Pdata,希望PG和Pdata越接近越好。用在以为向量里面就是如下图所示,我们有一个公式来,其中Div表示PG和Pdata之间的divergence分散。如果divergence越大,就表示这个distribution(PG和Pdata)越不像。
我们希望找到下面的generator G*,得到PG和Pdata之间的分散程度最小。这个跟我们之前学习的希望找到最小的那个LOSS方程很像。
我们怎么找到一个方程来计算两个分布之间的离散度最小值呢?
GAN能够有一个很好的方案来解决这个问题。
不需要知道PG和Pdata之间的分布是什么样的,只要我们能够从PG和Pdata里面取样sample,我们就能算出divergence。
如下是sample的方法:
要实现这个方法,我们就要借助discriminator!
我们用从PG和Pdata取样出来的数据来训练D,我们希望D看到真实数据Pdata就给予高分,看到生成数据PG就给予低分。我们也可以看成是optimization的问题:我们要训练一个D,这个D可以取一个objective function V(G,D)的最大值。我们的y是从Pdata里面取样出来的,y是真实图片。我们把y放到D里面得到的分数取log;另外一批y是从PG里面取样出来的,我们也把他放到D里面,用1减去得到的分数取log。我们希望这个V(G,D)越大越好,也就是我们希望log【D(y)】越大越好。因为真是图片经过D之后分数高,但是生成图片经过D分数低。相当于训练一个二元分类问题。
divergence跟objective function相关
事实上,这个目标函数V(G,D)是跟divergence有关的!假如两组数据之间有很小的divergence,也就是说他们是很接近的,那D就很难分开这两类数据,那我们就不能让目标函数的值非常大,那我们求出的目标函数的最大值就比较小。假如我们的两组数据比较分散,那D就能很明显的分出两组数据,那目标函数的最大值就比较大。
JS散度是对称的,其取值是 0 到 1 之间。如果两个分布 P,Q 离得很远,完全没有重叠的时候,那么KL散度值是没有意义的,而JS散度值是一个常数。这在学习算法中是比较致命的,这就意味这这一点的梯度为 0。梯度消失了。
因为divergence跟objective function相关,所以我们可以把之前的G和D做一个替换!
式子G*表示:我们要找一个最大的V(G,D)使得D最大,然后找max V(G,G)使得G最小!这个式子里面跟刚才的两个步骤非常像!
我们也可以用不同的散度:
事实上我们minimize JS divergence,结果也没有很好。GAN还是没有很好训练
3、训练GAN的小技巧
JS divergence不适合
(1)PG和Pdata重叠的部分很少。
PG和Pdata是高维空间里面低维的manifold。在高维空间里面随便选择几组点是没办法构成一张二维图片的,二次元人物头像的分布在高维中是很小的。一张图片可以看做是高维空间中的一条曲线,那么这种图片之中的重叠就可以被忽略了!
(2)在我们取样的时候,如果取样的点比较小,那就会有明显的分界让两个类别分开!
这种完全没有重叠的问题对JS divergence有什么影响呢?
对于两个没有重叠的分布,JS散度总是log2。
下图是从一条轴上表示两个分布之间的距离。虽然从左到右两个分布是不断接近的,但是对于JS散度来说,他们都是log2(常数),因为他们没有重叠的部分。只有两个分布重叠才有可能是别的值(0)。
如果我们的两个分布是没有重叠的,那我们的二元分类器的精度总是100%正确的。也就是说我们的取样样本较少,很容易就能区别两种分布!那这种loss和accuracy就没有意义了,这种对我们的训练是没有用的,因为我们希望不断的训练改善我们的模型!
4、Wasserstein distance/earth mover distance
那我们能否换掉JS散度呢?Wasserstein distance。
假如我们在开一个推土机earth mover,有两个分布P和Q,把P看成是一堆土,Q看成是我们需要放土的目标target。那我们把P移动到Q的平均距离d就是Wasserstein distance。
如果是复杂的分布,我们要计算Wasserstein distance就有点困难。如果我们需要塑造P和Q的形状比较相近,那就有很多种方法来做了!Wasserstein distance穷举了所有可能的方法,然后看看哪个方法可以让推土的计划距离最小,这个最小的值才是Wasserstein distance。那这里就引入了一个optimization问题。
对比JS散度和Wasserstein distance,可以看出来从左到右我们的W是越来越小的,但是我们看JS是没有什么参考价值的!
当我们的GAN用Wasserstein distance来取代JS散度的时候就叫做WGAN
5、WGAN
下面这个式子可以用来计算Wasserstein distance:
这里把x带入distribution里面计算,得到的值算期望。可以看到我们希望Pdata里面算出来的值越大越好,PG里面的值算出来越小越好。D限制是一个1-lipschitz,也就是D是一个平滑的方程。如果我们没有限制D的话,我们算出来的两个类别的值可能无限大或者无线小。
有了这个限制,两个类别的差别就不会很大。
在早期的WGAN里面,是这样限制D的:假如参数的权重超过c,就设置为c;假如小于-c,就设置为-c。
后来出现了一个improved WGAN,在两个类别里面分别取一个值,然后连起来,取线上的一个值,保持这个值的梯度接近1。
现在最好的GAN是special normalization(SNGAN)。
虽然SNGAN好,但是GAN还是比较难训练的。
如果D和G其中一个出问题,这个网络就会一直崩坏下去。
GAN最难的是用来生成文字。cnn 是平均max 会变化,这里的max 不变所以不能做gradient descent。没有变化那我们就不能用来训练模型了。
之前说遇到不能用梯度下降的方法做训练,那我们可以试试用强化学习RL。强化学习是一类算法,让计算机从什么都不懂,通过不断尝试,从错误中学习,找到规律,从而到达目标的过程。计算机需要一位虚拟的老师,他要做的事情就是给行为打分,计算机只需要记住高分和低分对应的行为,下一次只需要执行高分行为就能得到高分(分数导向性)。类似于监督学习中学习正确标签,不同的是,强化学习最开始没有准备好的数据和标签,是在不断的尝试中得到数据和对应的标签(奖励值)。但是RL也很难训练!
下面是一个可以训练的模型:可以输出文字的GAN(scratch GAN)
除了GAN之外,还有更多的generative model,但是GAN的performance比较好。
我们能不能用监督学习的方法来做generative的任务呢?
我们可以用高斯分布随机出来的向量作为输入,代表每一张图,然后放到网络里面训练。但是我们放随机的向量可能就训练不起来了!
6、评估
以前GAN生成的图片是用人眼来看出来的,但是这样很不可信。
在图像识别的领域,输入一个图片,经过off-the-shelf 图片分类器之后输出一个概率分布。这个概率都比较肯定自己输出的是什么什么东西。
mode collapse问题
但是只用这个方法是不行的,会出现一个mode collapse问题。也就是产生的图片一直都是那几张,而真是数据分布很广。也就是出现了D的盲点,G一直生成这种图片。
BGAN解决了这个mode collapse的问题。G在训练的时候会吧train point保存下来,在出现mode collapse的时候会把训练停下,然后把之前的模型拿出来用。谷歌爆搜参数还是没有解决mode collapse问题。
mode dropping问题
虽然生成的数据很好的贴切真实数据,但是其实真实数据是更大的一个范围。比如说下面,在上一次循环里面我们虽然没有看出来什么区别,但是在下一次循环里面我们发现:同一次循环的肤色是一样的!虽然GAN生成的脸比较真实,但是还是只有几张脸,多样性好像并不是很够。而且仔细看之后也能分辨出这是一张生成的脸了。
怎么解决呢?过去的做法:不同的图片放到CNN里面训练,如果输出的图片分布的比较像(所有输出图片概率求和取平均),能很好的分辨出是哪个类别的,那可能多样性就不够了。
如果是不同的图片放进去,经过CNN之后产生的输出分布很不一样,而去概率求和平均之后得到的分布很平均,这时候我们的多样性可能就是足够了。
从图中可以看出来,初始得分inception score (IS)代表着好的quality和大的多样性。对于一张图片来说,输出的结果能很好的分出这是什么类别的,那这是good quality;一堆图片的类别平均比较平均,那diversity 就比较大。但是我们不用IS做人脸图片生成,而是使用FID。
我们取进入softmax之前的最后一层hidden layer 的输出向量代表这个图片。红色的点代表把真实图片放到CNN训练之后得到的输出向量,这个向量维度很高。而蓝色的点是G生成的图片的输出向量。假设这两种输出向量都是高斯分布,然后去计算他们之间的FID。我们希望FID越小越好。
但是当做高斯分布会有问题,而且如果要准确得到我的网络的分布,那可能需要大量的样本,需要较大运算量。在结果我们不止看FID,也看侦测出来的人脸的指标。
比较如下多种GAN和VAE,VAE对于不同的随机种子差距比较小,而不同的GAN对于不同的随机种子之间的差距大,GAN产生的结果比VAE好。不同的GAN的网络结构还是差不多的。
memory GAN问题
生成图片和真实图片一模一样,FID很小,但是我们并不希望得到这样的图片。G是对真实图片进行“背诵”了
7、conditional generator
用文字产生图片
之前将的generator的输入都是一个随机分布的。但是现在我们可以操控G的输出,我们给定一个condition x ,让他根据x和z来产生y。conditional generator可以应用在文字生成图片的任务中,这种任务是监督学习,我们需要一些监督label数据,具有图片文字描述的。在这个任务我们的x就是一段文字。虽然每次的x可能是一样的,但是因为z是随机生成的,所以每次生成的图片都是不一样的。
我们根据刚才说的GAN的步骤在G里面输入x和z,输出一张图片y,然后把输出的图片y输入到D里面,得到一个数值scalar。我们用这个数值来判断生成的图片和真实图片是否相似,真实图片是数值是1,生成图片的数值是0。但是这种方法在我们加了x进去之后就会出现一些问题:
我们输入的x是用来控制输出图片的,但是随着D和G之间逐步迭代训练,我们的G生成的图片会越来越符合D的要求来“骗”过D。但是这个过程中,会完全忽略了输入的condition x。
所以在D里面我们不仅要看y,还要加入x!我们希望这个y能跟真实图片越来越像,而且y是符合x 的描述的。所以我们需要的资料有标注label。真实的图片文字对会给1分,生成的图片和文字会给0分。
但是在应用中我们通常不止有这两种资料,还有另外一种:已经产生的图片和与图片不符的文字(0)。
用图片产生图片
当然我们也可以让x是图片。这种任务叫image translation(pix2pix)
只有GAN的时候会产生一些额外的东西,所以我们加入supervise
从声音画出图片
此外,也能用condition GAN生成可移动的图。
8、GAN用在无监督学习上
我们有一堆不成堆的x和y,他们是没有标签的。
在图像风格转换的任务里,我们要把三维世界的图片转换为二次元图片,那我们就是没有什么成对的资料。
cycle GAN
套用原来的GAN是可以的,但是还是有点问题,输出图片跟输入好像没有关系。那我们怎么强化输入和输出的关系呢?但是我们的资料没有成对的,那我们怎么套用conditional GAN呢?所以我们用另外一种办法:加入另外一个G。Gxy从输入x domain里面得到一张图片是y domain的,这张图片又用来作为另一个Gyx的输入得到一张x domain的图。我们希望输入和输出越接近越好。但是这样还是没有保证我们输出的图片是我们想要的,只能说这种问题不常见,输入和输出还是很相似的。
还能做反向的训练,从二次元图片转换为三次元的图片:
还有别的方法:但是他们是不同的团队,一样的想法
还有一种starGAN能对图片进行多种风格转换。
text style transfer
二、总结
1、我们为什么需要一个generator和distriminator呢?因为:机器学习生成结果混乱;我们希望结果出现一些随机性……
2、GAN算法的原理:generator和distriminator之间不断进行迭代更新,最终得到更好的结果。
3、训练GAN:Wasserstein distance替代JS散度,解决精度总是总是100%的情况。
4、应用:GAN用于文字生成;GAN也可以用于的输入是图片,输出是图片的任务。
5、评估:mode collapse问题(BGAN可解决)、mode dropping问题(IS评估得分或者FID)、 memory GAN问题。
6、conditional generator、cycle GAN、starGAN、 text style transfer。
LW0020: 求问这是哪里的教程。这对我很重要,研0入门
Raphael9900: 看看路径是不是对的
weixin_50894238: 运行的时候出现系统找不到相应的文件
智慧地球(AI·Earth)社区: 博主文章质量很高,,凤⭐尘必须给三连支持了。我正在参加CSDN创作者的申请,欢迎大佬给个关注三连哇! 这是我的博客链接:https://blog.csdn.net/qq_36396104?type=blog 欢迎大佬加入我创办的互粉社区 (https://bbs.csdn.net/forums/together),共同进步!
不吃香菜哇: 大佬好文章、已三连、点赞+收藏+关注。如果可以的话麻烦给个星星、谢谢:https://bbs.csdn.net/topics/611389800