查看原文
其他

【综述专栏】对抗网络:李宏毅GAN课程笔记

在科学研究中,从方法论上来讲,都应“先见森林,再见树木”。当前,人工智能学术研究方兴未艾,技术迅猛发展,可谓万木争荣,日新月异。对于AI从业者来说,在广袤的知识森林中,系统梳理脉络,才能更好地把握趋势。为此,我们精选国内外优秀的综述文章,开辟“综述专栏”,敬请关注。

作者:知乎—我在妳身后

地址:https://www.zhihu.com/people/jin-ji-de-he-cheng-shi

此专栏将记录个人学习李宏毅老师GAN课程的笔记,全文约1.9w字,希望大家可以认真学习。
今天要讲Generative Adversarial Network,缩写是GAN。一开始要做的第一件事情是要先知道GAN要怎么正确的发音。
有一个人在Quora这个论坛问,最近在Unsupervised Learning的领域有什么样的breakthrough。然后Yann LeCun就亲自来回答表示,GAN这项技术是有史以来最酷的东西(在过去卖吐司面包的时候是没有切片的,所以家庭主妇买吐司面包回去后要自己切片就觉得很麻烦,然后有人就发明了切片的吐司,大家就觉得很高兴。所以有一个好东西要问世的时候,就会说since sliced bread,可以翻译成有史以来的意思。)
还有另外一个问题,在Deep learning领域,最近有没有什么breakthrough,Yann LeCun回答表示,GAN的种种变形是近十年来他觉得ML领域最有趣的idea,所以Yann LeCun给GAN这项技术非常高的评价。
在网络上可以找到GAN的动物园,直接Google GAN加上 zoo GAN就可以找到各式各样相关的技术。现在如果发明了一个新的跟GAN有关的技术,就会在GAN前面加一些英文的字,可以英文的字母只有26个,所以很快地名字就通通被用尽了。比如说有两个LSGAN,一个是Least Sqaure GAN,一个是Loss Sensitive GAN,这完全是不一样的东西,但是英文字母是有限的,所以很快地名字就都被用尽了。
这张图表示,在这个GAN的动物园里面,收录了各种有名有姓的GAN,里面光SGAN基于有四个以上。它就统计了一下,到目前为止,已经有接近三百种不同的GAN,因为英文字母是有限的所以会发生这样的情形。比如这篇Variational Approaches for Auto-Encoding Generative Adversarial Networks,按照它的名字应该被称为AGAN或者是AEGAN。但是作者在paper里面表示AEGAN已经被用掉了,看起来其他的英文字母也通通被用掉了,只好把它叫做alphaGAN。
在其他领域,不止是Machine Learning的领域GAN也是非常重要的。在其他领域GAN其实也有很多的应用。在Image Processing会看到很多GAN应用,但在其他和Image Processing没有那么直接相关的领域,也可以看到很多GAN的应用。
我最近刚去了ICASSP(Signal Processing的conference),在ICASSP里面我给了一个GAN的tutorial,在tutorial的开场我统计了一下今年ICASSP跟GAN有关的paper,看看哪些paper是跟这些关键字是有关系的。我用generative这个关键字会发现从2012年到2017年和generative有关的paper都很少。因为generative的model不是只有GAN而已,他们用其它的generative model但是没有非常多。
如果用adversarial这个词汇对照,在2013年的时候有两篇paper,它的title有adversarial这个词汇,不过它跟GAN是完全没有关系的,2016年也有一篇,它跟GAN也是没有关系的,2017年有两篇,它们是跟GAN有关系的,但到2018就有四十篇了,所以它成长的速度是20倍。我其实也用了reinforement这个词汇来当作对照组,就会发现reinforcement这个词汇它的成长速度就没有adversarial成长速度这么快,所以GAN变成了一项非常重要的技术。
接下来的四周都要来讲GAN这项技术,今天要讲的是最basic的idea(假设你不知道GAN是什么,给你一个概念让你知道这项技术运作起来大概是什么样子),接下来我们就从GAN最基本的概念说起。
在GAN里面想要让机器做到的事情是要让机器来生成东西,比如让机器生产影像。或者是假设在文字处理的领域,你会让机器来写诗,让它产生文章。在generation这样的process里面,你需要做的事情就是训练处一个generator。如果你要做的是要影像生成,那这个generator要做的事情就是:假设有一个Gaussian Disreibution,从Gaussian Disreibution里面random sample一个vector,把这个vector丢到generator,generator就要产生一张image。丢入不同的vector就应该产生不同image,这个是image的generator。在文字的generator、sentence的generator也是一样的,丢入一个vector,generator就输出How are you?丢入另外一个vector,就会输出Good morning,丢入另外一个vector,就输出Good afternoon等等。
我们要用GAN来达成的目标就是要训练出这样NN的generator。你可能会有点困惑说,输入一个random的vector,让它output一张image或者是output一段词汇,有什么用,具体而言就是没有什么用。我认为比较有用的是Conditional Generation,也就是可以输入一些条件,比如说输入文字让机器产生对应的图片,输入图片让机器产生另外一张对应的图片,这个之后会讲到。
如果不是输入random的东西,而是输入一个你了解的,可以control的东西,比如说文字、影像,让机器产生对应的东西,那这项技术就有非常多的应用。今天就只focus让机器吃一个随机的向量,它就要output你想要的object,这样的application上。
刚才讲过在GAN里面,想要训练的东西就是一个generator,这个generator是一个Neural Network。我们都知道所谓的Neural Network它就是一个function,input一个东西,output一个东西。在GAN里面它的input就是一个vector,如果是影像的生成,它的output就是一张image。或是讲得更具体一点,在影像生成的话,generator output就是一个high-dimensional的向量。generator output是一个向量,这个向量非常非常的长,这向量的每一个dimension就对应到影像中的一个pixel的颜色,把这个high-dimensional向量排成一张影像的样子,就可以让generator产生一张图片。
假设想要让机器做二次元头像的生成,那得到的结果可能就是这样。有一个generator,随便给它一个向量,它的输出就是一个二次元人物的头像(这张图是机器真正生成的,是用右上角这个程式生成的)。而通常输入的向量它每一个dimension会对应到图片的某种特征,也就是说改变了其中一个dimension的数值,就会发现产生出来的图片的某种特征有所改变。
假设第一个dimension对应的是头发的长度,将vector它的第一个dimension的值从0.1调整到3,generator的output就会是一个长头发的角色;假设vector的倒数第二个dimension对应到头发是不是蓝色的,值越大代表头发越蓝,将这个值从2.4调到5.4,产生出来的角色就会变成蓝头发。这两个角色看起来非常像,因为只改了倒数第二个dimension而已,其它维度的值固定不变的。所以它只改变了头发的颜色,其它的特征仍然是很相似的。假设最后一个维度代表的是嘴巴的大小,本来这个值很小,所以它是无口的状态,把这个值调大,然后它看来就像笑起来了。
在GAN里面比较神奇的地方就是同时会训练一个discriminator,等一下会讲discriminator和generator之间有什么样的关系,先来看这个discriminator做的事情是什么。
这个discriminator也是一个Nerual Netework,Nerual Netework就是一个function,吃一个东西当作input,就会输出一个东西。discriminator是吃一张图片当作input(假设产生的是图片,它就是吃图片当作input,假设要产生的不是图片,是句子的话,它就是吃句子当作input),它的输出是一个scalar,这个数值代表产生出来的这张图片的quality。这个数值越大,就代表产生出来的这张图片的quality越高,那么看起来越像是真实的图片(产生出来的数值越大(discriminator output数值越大),就表示输入的图片越真实)。
假设要做二次元人物头像的生成,让机器吃这张图片,因为这张图画的很好所以output就是1.0(假设1.0就是它可以输出最大的值)。假设这张图画的很差,机器就给它0.1分,这个就是discriminator做的事情。
在GAN里面有一个generator和一个discriminator,它们之间的关系就好像是猎食者和他的猎物之间的关系。右上角这个是一只枯叶蝶(不是枯叶,而是枯叶蝶跟枯叶长得非常的相似),为什么枯叶蝶会长的跟枯叶非常的相似呢?那么因为有天择的压力,枯叶蝶的祖先其实是彩色的,因为麻雀会吃枯叶蝶,所以枯叶蝶在天择的压力之下就变成棕色的。因为麻雀判断蝴蝶能不能吃的标准就是它是什么颜色(如果是彩色就会被吃掉,如果是棕色就不会被吃掉)。
在天择的压力下,枯叶蝶的祖先就变成是棕色,但是枯叶蝶天地也是会演化的。波波会进化为比比鸟,比比鸟判断一个东西能不能吃的标准并不是看颜色,而是看有没有叶脉的纹路,如果没有叶脉的纹路还是被吃掉的。所以枯叶蝶在天择的压力之下就产生了看起来像是叶脉的条纹,它可以骗过比比鸟。但是比比鸟也会再进化,进化之后它可能有别的标准来判断这个东西是不是可以吃的,枯叶蝶也会再不断地进化。所以猎食者和天敌就会再互相拮抗之中变得越来越强。而这个枯叶蝶就像是generator,而它的天敌就像是discriminator。
所以假设要让机器做二次元人物头像的生成,首先要准备一个database,这个database里面有很多真实的二次元人物的头像。一开始generator的参数是随机的(generator是一个network),所以一开始generator也不知道怎么产生二次元人物的头像,它只能产生看起来像是杂讯的东西。discriminator做的事情就是给它一张图片,判断这张图片像是generator生成的还是像是真实的图片。接下来generator就是要想办法骗过第一代的discriminator(第一代discriminator可以分辨第一代generator的output和真实图片之间的差异,它可能就用有没有颜色来判断它是真实的还是被生成的图片)。
第二代的generator进化了,它想要骗过第一代的discriminator,所以它就会产生有色彩的图片。但是discriminator跟着也会再进化,第一代的discriminator会被第二代的generator产生的图片骗过,但是第二代的discriminator会学着去分辨这两种图片之间的差异,它可能会发现真实的图片是有嘴巴的,如果是第二代generator产生的图片是没有嘴巴的,它就用这个标准来判断一张图片是不是真正的图片。generator就会跟在再进化,变成第三代的generator,第三代的generator产生出来的图片,会骗过第二代的discriminator,第二代的discriminator会进化为第三代的discriminator。所以generator和discriminator之间是会不断的进化,所以generator产生出来的图片就会越来越真实。
因为generator和discriminator之间有一种对抗的关系(它们像是天敌与被猎食者之间的关系),所以用adversarial(对抗)这个词汇来命名这个技术(Generative Adversarial Network)。
但有人就会问为什么是让两个network互相对抗,为什么不能彼此合作。其实这只是一种拟人化的说法而已,现在的想法让你觉得它们是在对抗(GAN这项技术是Ian Goodfellow在14年提出来的),原始的paper是用作假钞跟警察的例子(generator不断的做假钞,discriminator是警察,它要去判断这张钞票是真钞还是假钞,最后generator做的钞票会越来越像真钞,直到discriminator完全没有办法分辨为止),从这个例子看起来generator和discriminator是对抗的关系。
但是只要换一个例子,generator和discriminator其实可以看作是合作的关系。可以想象generator是学生,discriminator是老师。generator要学习怎么画二次元人物的头像,discriminator看过很多二次元人物的头像,它知道二次元人物的头像应该长什么样子。所以一开始第一代的generator就是一年级的学生,它不知道怎么画二次元人物的头像,所以它画出来的东西就非常的模糊、奇怪。它就把这些图片拿给老师看,一年级的老师会给他feedback并告诉他,你这些图片跟真实图片差异是,真实图片有两个圈圈(这只是一种拟人化的讲法,等一下会具体的告诉你实际上在train network是什么样子)。
它就会把这个资讯feedback给generator,告诉generator你画的这些图片跟真实图片的差异是没有画两个圈圈。这个generator接下来就升上二年级,它会记得老师的教诲,它知道在画二次元人物头像的时候,应该要把两个圈圈点上去。然后它就把画出来的头像再给二年级的老师看,二年级的老师变得严格了,二年级的老师会告诉它,你画的跟真实的图片仍然有很大的差异,因为真实的图片是彩色的,你画的没有彩色的。所以generator接下来到三年级以后,它产生的图片就会变成彩色的。generator会不断的进步,而discriminator就会变得越来越严格,学习画的越来越好,老师越来越严格,最后学生就可以画出非常像是真的人所画的二次元人物的头像。
在互动的过程中,其实会发现有两个问题,第一个问题是为什么generator没有办法自己学呢,为什么一定要有一个discriminator介入,为什么generator没有办法直接从这些范例里面学习怎么产生二次元人物的头像,为什么一定要透过discriminator才能学习呢?等一下会试着来回答这个问题。第二个问题是discriminator这么会批评,为什么它不自己做呢?我想大家都会有这个困惑对不对(老师为什么都不自己coding呢?老师为什么都只用嘴巴coding呢?)等一下要来回答这个问题。
所以generator根discriminate之间的关系就是写作敌人、念作朋友,就是塔矢亮和近藤光的关系,或者像是佐助与鸣人的关系,所以他们是朋友也是敌人。
接下来就正式讲一下Generator Adversarial Network的演算法是怎么运作的,我们之后会讲到他的原理,还有它背后的理论。今天先不讲理论,就只讲它操作起来、看起来是什么样子。就算你对它的理论还没有任何的了解,其实从这个操作的过程、演算法,其实也可以体会到它为什么是个有用的方法。
有一个generator和一个discriminator,它们都是network。我们知道train network一开始参数是random initialized的(random initialized generator跟discriminator的network的参数)。接下来要iterative的去train这个generator和discriminator,要跑很多个iteration。在每一个iteration里面要做两件事,有两个步骤。第一个步骤是把generator参数固定住,只去调discriminator参数(只需train discriminator,把generator固定住)。
怎么做呢?有一个固定住的generator,然后把一大堆random vector丢到generator里面,这个generator就会产生很多图片。因为一开始generator参数是随机的,所以产生出来的图片并不会特别好,可能是非常糟的。(刚才讲过如果要让机器产生某种东西,你要搜集那种东西的范例。你要让它产生二次元人物的头像,你要搜集很多二次元人物的头像当作范例。你要让机器写诗你要搜集很多的诗词作为范例)接下来有一个database里面都是二次元人物的头像,从这个二次元头像里面sample出一些example。现在有两组图片,一组是从database里面sample出来的,另外一组图片是generator所生成的。
接下来就要去训练discriminator,去调整discriminator的参数。怎么调discriminator的参数呢?你的目标就是,如果这个image是realistic的,就给它比较高的分数。如果这个image是generator所产生的,就给它比较低的分数。如果是从database sample出来的image就是高分,从generator产生出来的image就是低分。你可以把它当作是regression的problem,可以把它当作是classification的problem,反正不管怎么做,就是要训练这个network。把这组图片丢进去,output的分数就是大的,把这组图片丢进去,output的分数就是小的。讲得更具体一点,训练的目标就是,把这张图片丢进discriminator,output的值要离1越接近越好,把这四张图片丢进discriminator,output的值要离0越接近越好,就用这criteria去训练discriminator。
我相信这个在实作上对大家来说都不是问题,就跟一般训练network作regression,或是训练一个network classification意思是一样的。
下一步就是固定住discriminator,我们只去调节generator的参数。前一步是固定generator只调discriminator,discriminator训练好了就固定住discriminator,只调节generator。怎么调generator的参数呢?先把一个vector丢到generator里面,generator会产生一张图片,接下来把这张图片丢到discriminator里面,discriminator会给它一个分数。generator训练的目标就是要去骗过discriminator(所谓的骗是一个拟人化的讲法)。实际上做的事情是希望generator产生出来的图片,discriminator可以给它比较高的分数。固定住discriminator的参数,只去调节generator的参数,希望generator的output丢到discriminator以后,它output的值可以越大越好。
(那你可以想见说)刚才在前一步骤已经把discriminator训练好了,这个训练好的discriminator看到好的image就会给它比较大的分数。既然generator可以调整它的参数,使得它的output的image,discriminator会给它高分,但显然generator产生出来的image会是比较真实的,因为discriminator是看到真实的图片才会给它高分。generator既然可以调整参数产生出来的图片,discriminator会给其高分的,但显然generator产生出来的比较真实。
实际上在implement这个code怎么做呢?实际上在implement的时候你会把generator跟discriminator合起来,当作是一个巨大的network。假设generator是五层,discriminator也是五层,就是把前面的五层跟后面的五层接在一起,变成一个有十层的network。这个十层的network input是一个vector,它的output就是一个数字。
但是在这个十层的network里面其中的hidden layer,它很宽,它的output就是一张image(假设这个是64 x 64 的image,那就会有其中一个hidden layer的output是64 x 64的数值(维),把那个hidden layer拿出来,就可以把它看作是一张image)。在train这个network的时候,就是固定最后几个hidden layer,只调前面几个Hidden Layer,让它output的只越大越好。因为我们现在是让它output越大越好(不是Gradient Descent,Gradient Descent是让你的目标越小越好),其实你做的事情是Gradient Ascent,不过Gradient Descent跟 Gradient Ascent其实意思是一样的,只是把Objective Function添加一个负号而已。
实际上在作的时候,就是把generator跟discriminator接起来变成一个巨大的network,把这个巨大的network最后几个layer fix住,只train前面几个layer,目标是要让整个network output的值越大越好。你会发现因为你的目标是要让整个network的值output越大越好,所以固定住最后几个layer是非常有道理的。假设不固定住最后几个layer会发生什么事呢?因为目标是要让output越大越好,其实它只要调output最后这个scalar(只要调最后一个layer的weight),让它的值越大越好,马上就可以让最后的output爆表。但是因为最后这几个layer是固定住的,只能够调前面几个layer,想办法让最后的output越大越好。
接下来正式的把这个algorithm再讲一次,有一个discriminator参数是\thead_d,有一个generator参数是\thead_g,整个演算法就是这个样子。
有一个database(好几万张二次元人物头像的图片),接下来从这个database里面sample出m张image,这个m其实就是batch size,就像train network的batch size。同时有一个distribution,这个distribution我个人觉得没有这么的重要,所以可以在作业里面verify这个distribution对你的结果有多大的影响。这个distribution可以是一个Uniform Distribution,也可以是Gaussian Distribution。假设它是Gaussian Distribution,从Gaussian Distribution里面sample出m个vector,至于这个vector dimension要五维、十维、还是一百维,这个你自己决定,这是一个参数要调节的。
接下来就根据这个m个vector去产生m张image,刚才有说generator就是吃一个vector ,然后output一个image。把generator产生出来的image用x tilde来表示,把这m个vector丢到generator里面让它产生m张图片。
接下来就要去调整discriminator,前半部是在训练discriminator。怎么调discriminator呢?底下这个式子只是一个范例,你可以用这个式子也可以用别的,之后会讲也许用别的结果会更好。这个只是最原始的GAN的paper,它的式子是这样写的:它说要去maximize这个Objective Function,这个Objective Function是什么意思呢?
首先把m张真实的图片拿出来,把它们都通过discriminator得到分数。然后取一个log,再把m个图片得到的分数通通平均起来,我们要让这个Objective Function的值越大越好,就意味着要让log D(x)越大越好,也就是要让D(x)越大越好。所以这式子告诉我们要训练discriminator让它可以给这些真实的image的值越大越好,这是第一项。
第二项是将这些假的图片(generator产生出来的x tilde图片)丢到discriminator里面产生一个value。discriminator的output会通过sigmoid,它的值介于0到1之间。不要sigmoid也可以,不过如果没有sigmoid的话,1减掉大于的值再取log会有问题,所以就给一个sigmoid(D的值一定是落在0到1之间)。你可能会问为什么一定要这样,之后在接下来的课程会告诉你这样做其实不是最好的方法,这个只是最原始的方法。
今天把这个generator出来的image丢到discriminator里面,它会给一个分数,1减掉这个分数再取log然后取平均值,希望这一项越大越好。希望这一项越大越好的意思就是,希望1-D(x tilde)的值越大越好。希望1-D(x tilde)的值越大越好就是希望D(x tilde)越小越好。
第二项的意思就是希望训练discriminator,这些discriminator如果把这些generator出来的image当作input的话,它output的值要越小越好。
我们现在要去maximize这个Objective Function。怎么maximize这个Objective Function呢?可以套用Gradient Descent。如果Gradient Descent这边是减的,如果要让loss function越小越好的话,你会取gradient然后乘learning Rate然后把它减掉。但是现在要让它越大越高,所以这边是加的。对你的Objective Function算它的gradient,然后乘上Learning Rate,再加上原来的参数,就得到新的参数\thead_d。至于Learning Rate要怎么调,可以用一些Adam等等技术来设定Learning Rate。
在这个式子里我们只把\thead update一次参数,至于要update几次参数,这就是另外一个hyperparameter,是你要调的。你可以执行这一项三次,执行这一项五次都可以,这是个参数要去调它。这个是训练discriminator,把discriminator训练好以后,接下来要训练generator,怎么训练generator呢?
一样去sample出m笔data(m个random vector),这m个random vector不需要跟这m个random vector(Learning D的samples)。训练的目标是generator要想办法骗过discriminator,它的式子写出来就是这样的。
把这个random vector丢到generator里面,generator会产生一张image。这看起来可能有点复杂(log(D(G(z)))log(D(G(z)))),接下来我们一项一项来看。
G(Z)G(Z)就是一张图片(把z丢到generator让它产生一张图片),把这张图片丢到discriminator里面,(D(G(z)))(D(G(z)))就是一个数值,然后再对它去log,再对所有sample出来的data取平均(一个batch里面的data),希望这个值越大越好。也就是希望generator output出来的这个image丢到discriminator以后,输出来的值越大越好,这个是训练的目标。接下来用Gradient Ascent去调generator参数,希望它可以让Objective Function的output值越大越好。
红色的部分就是训练generator,这两个步骤就会反复的执行(训练好discriminator,接下来训练generator,再回头去训练discriminator,再训练generator)。
这个是我实际上做的Anime Face Generation,在网络上可以找到database,在做的其实用的不是这个database,等下告诉你那个database是哪来的。下载好database之后就可以用GAN开始去train它,这个是update一百次参数以后的结果。
update一千次之后,这个时候generator就知道二次元的人物应该是有眼睛的,所以它就把眼睛点出来。
update两千次,这个时候我发现它把嘴巴也点出来了。
update五千次以后,这个时候machine发现动画人物就是要有水汪汪的大眼睛,这个眼睛都变得很大。
update一万次得到的结果是这样的,看起来像是水彩画的感觉,看起来比较有二次元人物头像的样子了,只是感觉没有画的很好。
这个是update两万次的结果。
这是update五万次的结果,会发现这边有很多头像已经看起来非常真实了,但这个并不是真的做的特别好。
这是二次元人物的生成,当然也可以做三次元人物的生成。可以做真实人脸生成,这些人脸都是机器生成的。你可能会问产生真实的人脸有什么用,基本上没有什么用,随便去路边拍一个人都会比机器产生的更加真实。有趣的是机器可以产生你没有见过的头像。
刚才有说input的vector代表了输出图片的特性,假设input是【0,0】output是这个人,input是【0.9,0.9】output是这个人(实际上input的vector不会是二维,至少是十维、五十维、一百维之类的。)。接下来可以input这两个vector之间的内差(interpolation)就会得到这样的结果,就会看到这两个人脸之间连续的变化,上面是更多的示例。
可以机器真的可以学到,这个人脸它是朝右看的,这个人脸是朝左看的。当机器要产生这个朝右看的人脸和朝左看的人脸之间的内差的时候,它并不是把两张人脸叠起来变成一个双面人,它自己知道朝右看的脸和朝左看的脸如果内差的话,就是朝正面看。所以机器自己知道把这个脸转正,然后再转过来。机器要学到这件事完全不需要handcrafting,就不需要规则、物理模型。看很多真实的照片以后,它自己就可以学到这些事情了,这个是很神奇的。
刚才讲的是GAN的操作,如果你知道那些操作就可以做出作业3-1了。接下来将花一些时间从概念上讲一下GAN的原理,为什么它是这样运作的。
之前就有讲过GAN其实可以被视为一种Structured Learning的技术,什么是Structured Learning呢?其实之间就有讲过的,我们现在非常快的复习一下。所谓Structured Learning的意思是:我们都知道Machine Learning就是找到function,input一个东西,output另外一个东西。
如果是regression task,machine就是output一个数值;如果是classification task,machine就是output一个class。如果遇到的问题是更复杂的:要机器的output不是一个数值也不是一个class,它可能是一个sequence、可能是一个matrix、可能是一个graph、可能是一个tree,这个时候这个任务就叫做Structured Learning。
举例来说,translation就是Structured Learning的问题,因为machine要输出一个句子。语言辨识是Structured Learning的问题,因为machine也要输出一个句子。chat-box其实也是一种Structured Learning的问题,也是input一个sequence,output一个sequence。你可能会想说GAN是一个可以用在Structured Learning的技术,可不可以把GAN用在chatbox上呢?是可以的。如果sequence to sequence可以train得起来的话,其实可以再加上discriminator,可以让它的回答更好。
也可以让机器输出一个matrix,什么要机器产生matrix呢?如果要让机器画一张图,那就是产生matrix。之前有讲过如果输入这种图案,让它产生这样真实的房子。或是输入黑白的图片,让它产生彩色的图片。甚至可以输入文字让机器产生image。在作业3-2要做的就是要让大家输入一些二次元人物头像的特征(比如头发颜色、眼睛的颜色),输出对应的二次元人物的头像。
为什么Structured Learning是一个特别具有挑战性的问题呢?首先我觉得Structured Learning它可以被视为是一个One Shot Learning或者是Zero Shot Learning。什么叫作One Shot Learning或者是Zero Shot Learning呢?假设有一个分类的问题,在做分类问题的时候每一个类别都要给机器一些例子。举例来说要机器辨别苹果和橘子之间的差异,你就要给它一百张苹果的图片、一百张橘子的图片,它才能够分辨。所谓个One Shot Learning或者是Zero Shot Learning的意思是假设有些类别根本没有任何范例,或者只有非常非常少的范例,那能不能够做得起来。
我觉得Structured Learning这个问题它可想成是一个极端的One Shot Learning或者是Zero Shot Learning的problem。因为在Structured Learning里面,output的东西是一个structure(比如说一个句子)。在整个training data里面,没有任何句子是重复的。testing data跟training data它们的句子可能也是完全没有重叠的。假设把各种不同可能的每一种output都视为一个class的话,在training data里面每一个class可能就只出现一次,在testing data出现的那些class更惨,它根本在training data里面根本就没有出现过。假设把每一种机器可能的output视为一个class的话,那么其实Structured Learning是一个极端的One Shot Learning或者是Zero Shot Learning。
因为这些class它都会只出现一次,所以在这种Structured Learning的task里面,如何学到一般话、如何学着去输出从来没有看过的东西,就变成一个很重要的问题。你可以想象让机器做到这件事情,要让机器可以输出它在training的时候从来没有看过的东西,那这个机器是需要一定程度的智慧的。机器必须要学会创造,它才能够解Structured Learning的问题。因为它在testing的时候,它需要输出的正确答案很有可能是training的时候它一次也没有看过的,这个东西就可以把它视为是创造。
如果机器要解决Structured Learning的问题的话。它必须要有规划的概念,它必须要有大局观。因为机器要产生很复杂的物件,而这个复杂的物件,是由几个比较简单的component所组成的。
如果是影像生成的话,机器是产生一个一个pixel,但是所有的pixel合起来,必须要能够变成一张人脸。那机器在产生这张图片的时候,它一定要在心里分辨清楚,点这个pixel上去代表是眼睛,点这个pixel上去代表是嘴巴。才不会变成三只眼睛、两张嘴巴等等。
所以在Structured Learning里面,真正重要的不是产生了什么component,而是component和component之间的关系。假设要让机器学会写一个数字出来,机器一开始在整张图上中间点一个点,点一个点这件事情本身是中性的,它不见得代表结果会是好的,也不见得代表结果会是不好的。因为假设机器最后画出来的数字长这样,那结果是好的;画出来的数字长这样,那整个就是坏掉的。
文字的生成也是一样的,机器要产生的是一个完整的句子,甚至是一篇完整的文章,单看生成的一部分是没有办法判断它是好的还是不好的。这让我想到一个纪晓岚的故事:有一天纪晓岚去帮翰林的老婆祝寿,然后就写了一个诗。诗的开头就是:“这个婆娘不是人”(大家都很生气),下一句:九天玄女下凡尘(然后大家都很高兴)。这就告诉我们如果只看第一个句子(它是一个负面的句子),但是把第一个句子和第二个句子合起来,如果有大局观的话,如果可以看到完整输出的话,它就变成一个正面的句子。而这个东西是机器在做Structured Learning的时候必须要学会的,所以想要表达的是Structured Learning是有趣而富有挑战性的问题。
我觉得GAN它其实是一个Structured Learning的solution,在传统的Structured Learning文件里面有两套方法。一套方法是Bottom Up的方法,一套方法是Top Down的方法。所谓Bottom Up的方法是我们要产生一个完整的物件,机器是一个一个component分开去产生这个物件,这样的缺点就是很容易失去大局观。所谓Top Down的方法是从产生一个完整的物件以后,再去从整体来看看这个产生的物件好不好。这样讲可能有点抽象,等下会具体地告诉大家这件事情是怎么做的。
这个方法的坏处是很难做generation的,generator可以视为是一个Bottom Up的方法,discriminator可以视为是一个Top Down的方法,把这两个方法结合起来就是Generative Adversarial Network,就是GAN。
刚才说是有两个问题的,第一个问题是为什么generator不能够自己学,接下来看看generator是不是可以自己学。
事实上generator是可以自己学的,generator的学习就是input一个vector,output一个image。假设用手写数字当作例子,input一个vector,output一个数字的图片,output就要产生不同的图片。要训练这样一个network的generator怎么做呢?
我们知道在传统的Supervised Learning里面,就给network input跟output的pair,然后train下去就得到结果了。今天要generator输入就是vector,输出就是图片,能不能够搜集这样的pair呢?答案是可以的。因为假设有一个database里面都是一大堆数字的图片,接下来给每一个数字assign一个vector就结束了。
因为接下来你就可以说,我train一个network,然后看这个1的vector是【0.1,0.9】。所以输入【0.1,0.9】丢到generator里面,就要output一张图片,这个图片跟它的目标也就是跟这个1越接近越好。这完全跟一般train Supervised Learning是一模一样的,就用Gradient Descent train下去就结束了。一般的分类就相反了,一般的分类是输入一张图片,然后输出一个向量,这个向量每一个维度代表对应到的某一个数字。
generator training 和classifier training其实根本可以用同样的方式来train,但是问题是怎么产生这些数字呢?虽然你可以随机产生,但是如果随机产生的话,到时候这个generator training可能非常困难,因为这两个1是很像的。但如果它们input vector非常不一样的话,可能很难learn出一个network(input非常不一样的东西,却output非常像的东西)。你可能会希望这两张图片有共同的特征,对应到的vector就应该有某些相似之处(在这边的vector,1的第一维都给它是0.1,2的第一维给它0.2,3的第一维给它0.3,向左斜就给它负的值,向右斜第二维就给它正的值等等)。你可能会希望input的vector跟output的特征还是有有关系的,那么这件事情是怎么做到的呢?
怎么样产生这样的vector呢?可以learn一个encoder,这个encoder是给它一张图片,它把这张图片的特征用一个向量来表示,这个向量就是这个code。怎么train这样一个encoder呢?
记不记得在讲Machine learning的时候,有讲过一个技术叫作Auto-encoder,在这里很快的复习一下。
Auto-encoder做的就是给它一张图片,然后把这张图片变成一个code。Auto-encoder里面有一个encoder,也有一个decoder。encoder做的事情是给它一张图片,它把这个图片变成一个code。但是encoder本身不能够自己train,一定要再加一个decoder才有办法train。decoder吃一个code,它会把这个code变成一张图片,在training的时候给一张image,这张image被encoder变成一个vector,然后decoder会把这个vector解回原来的image,希望input跟output越接近越好。
在train Auto-encoder的时候就随便选一张图片,这张图片变成code,这个code通过decoder变回原来的image,会希望input跟output越接近越好。你仔细想想这个decoder其实就是一个generator,刚才说那个generator做的事情就是给它一个code,要它产生一张对应的图片。现在已经告诉你有一个encoder,它的工作就是产生一个图片的code,decoder的学习就是看到这个code,要产生这个code对应的图片。这个decoder就是我们要学的generator,事实上learn好一个Auto-encoder以后,把decoder拿出来就是我们的generator,它就可以拿来产生image。你就可以随便丢一些东西进来,它就会output你想要的object。
举例来说,你完全可以learn一个数字的产生器,这个非常的简单。就learn一个Auto-encoder,它中间的code是两维。然后把decoder拿出来随便给它一个两维的vector,它的output就是一个数字。
假设给它【-1.5,0】,它就输出这样的image(0);给它【1.5,0】,它就输出这样的image(1).如果在四方形的范围内,等距的sample,就可以看到一堆数字的连续变化。
举例来说第一维它可能跟有没有圈圈有关,越往左就有圈圈,往右就是棍子。如果是看纵轴的变化,可能跟它的方向有关(本来是朝左偏的,往上以后就会变成朝右偏的),这个是Auto-encoder可以做的事情。
那用Auto-encoder会有什么样的问题呢?你可能会遇到这样子的一个问题:因为training data里面的image是有限的,generator可能可以learn到,vector a产生这张图片,看到vector b产生这张图片。但是vector a跟vector b的平均会产生什么样的图片呢?你可能觉得vector a对应到的1是向左的,vector b对应到的1是向右的,将这两者合起来应该是产生正的1。但是实际上并不是这个样子,因为NN generator是一个network,它是非线性的。a可以产生这个图片,b可以产生这个图片,把它们平均以后丢进去之后未必产生出来的就是数字,可能output出来的就是noise。
要怎么解决这个问题呢?这个也是在Machine Learning那门课讲过的技术,这个技术就是Variational Auto-encoder(VAE)。在ariational Auto-encoder里面,encoder不只是产生一个code(m代表它产生出来的code)。它不只是产生一个code,不只是产生一个vector,它还会产生一个dimension的variance。接下来从normal distribution里面去sample一堆noise出来,把这个noise跟variance相乘,把这个noise加到code上面去,再把有加noise的code丢到decoder里面,decoder要跟具有noise的code还原出来的图片。
如果有这个技术的话,machine就会知道它不只看到vector a要产生的数字、看到vector b也要产生数字,看到vector a加一些noise、看到vector b加一些noise产生出来的东西也必须要是数字。所以有了Variational Auto-encoder,可以把你的decoder train的更加稳定,就算input的这个vector在training的时候从来没有看过的vector,它output的东西仍然可能是合理的object。
这个都是复习在Machine Learning那门课曾经讲过的东西,接下来要讲的是这整套技术少了什么样的东西。通常code它会是一个low dimension的东西,假设你要做的是image的generation你的decoder output是image,虽然image是一个high dimension的vector。我们相信这个image它在high dimension当中其实是一个low-dimension的variable,本质上它的分布式low dimension的。所以今天要产生这个image,你input的code不需要是high dimension,它只需要一个low dimension的vector就好了。但是dimension到底应该是多少(五维、十维还是十五维),这个是需要调一下的。
train不起来增加dimension会有效果。但是增加dimension以后未必会得到你要的结果。因为train的是一个Auto-encoder,训练的目标是要让input跟output越接近越好,要达到这个目标其实很简单,把中间那个code开得跟input一样大,那你就不会有任何loss。因为machine只要学着一直copy就好了,但这个并不是我们想要的结果。虽然说input的vector开得越大。loss可以压得越低,但loss压得越低并不代表performance会越好。
接下李要讲的是这个Auto-encoder的training到底少了什么样的东西,你仔细想想看,generator在train的时候它的目标是希望它的output跟某一张图片越像越好。举例来说这个2是你input的图片,希望generator的output跟这个2越像越好。但什么叫做越像越好呢?通常计算的就是这两张图片它们pixel by pixel的差距,通常每一个pixxel就是一个数字。所以真的在算这两张图片的相似度做的事情就是,把这两张图片表示成两个vector,接下来计算这两个vector的euclidean distance,这个东西就是要去minimize的对象。这两个vector euclidean distance,就代表这两张图片差异的程度。希望这两张图片它们的L1distance、L2distance越小越好。
假设generator它确实可以完全copy你的target,可能就没有什么太大的问题。但真正在training的时候,generator是会犯一些错的。generator的capacity不会大到output的image一定跟它的target一模一样,它势必会有一些取舍。它没有办法完全copy这个output,它会选择在某些地方不得不做一些妥协,没有办法跟它的目标一模一样。但是这个时候选择在什么地方做妥协就会变得非常的重要。
举例来会所这个是你的目标,有四个不同的generator,它们产生四张这样子的图片。如果是看这个图片跟这个图片在pixel上相似的程度,你会发现这两张图片差了一个pixel、这两张图片差了一个pixel、而下面这个图片跟它差了六个pixel,这个图片跟它差了六个pixel。对一个generator来说,假设learning的时候是希望output的图片跟目标越像越好。但如果它不得不犯一些错误,它会倾向于这样的图片(差一个pixel的图片),这样的图片它的错误有六个pixel。但事实上从人的观点来看你会知道,这个是不行的(差一个pixel的图片),这个错一个pixel整个图片看起来就不对了,看起来就不像是人手写的数字,看起来就是错的。但是下面的case,它只是把笔画弄得长一些而已,这个你是可以接受的。
所以你不能够单纯的去让你的output跟目标越像越好。单纯的让你的output跟目标越像越好,可能generator就会产生这种图片。
而在做Structured Learning的时候,我们讲过Structured Learning的output就是个比较复杂的结构,里面有很多很多的component,component和component之间的关系是非常重要的。
我们觉得这张图片是不行的,并不是因为这边放了一个pixel有什么不好,在这边放一个pixel这件事情本身是没有错的。因为如果这边放一个pixel但是可以把这边补满,它仍然是一个人手写的数字。并不是说在这边涂黑是有错的,而是把这边涂黑以后在相邻的地方没有把它跟着涂黑。所以在一个Structured Learning里面component和component之间的关系是非常重要的。但其实在train一个generator去生成图片的时候会发现一个network的架构其实没有那么容易让我们把component和component之间的关系放进去。
假设你是做图片的生成,Layer L就是整个generator的最后一个layer(这个Layer L可以产生一张图片),这个Layer L的每一个neural显然就对应到图片的每一个pixel,它output的数值就是那个pixel图的颜色的深浅。你会发现在这整个架构里面,假设Layer L-1的值是给定的,那事实上每一个dimension的output其实是independent(weight也是给定的)
假设这个neural它产生了颜色,它希望旁边的人也跟着产生颜色,产生像是realistic的image,实际上这件事情是没有办法做到的。因为它们之间没有办法互相影响,它就自己产生自己。它们并没有办法互相配合去产生一个好的image,所以这个就是单纯的learn一个generator困难的地方。这个问题也不是没有解决的,虽然只看一个dimension,你没有办法考虑pixel和pixel之间的correlation,如果再多加几个hidden layer,就可以把这种correlation考虑进来。
如果你不想要用discriminator,只单纯用Auto-encoder的技术想要做generator这件事情,根据我们的经验,如果有同样的network,一个是用GAN train,一个是用Auto-encoder train。往往就是GAN的那个可以产生图片,但是Auto-encoder那个需要更大的network才能够产生跟GAN接近的结果。所以你要把correlation考虑进去,你会需要比较深的network。
这个是一个toy的example,这个试验要做的是train一个generator,而generator的input是一个二维的Gaussian的noise,它的output就是蓝色的这些点。它在output的时候目标是希望能够学会output(output是蓝色的点,绿色的点是它学习的目标)。我们希望generator产生出来的像绿色这样的distribution,但实际上如果用Variational Auto-encoder的技术learn下去以后,你会发现最好能够让这个generator产生蓝色的这些点,因为对generator来说要考虑pixel和pixel(dimension 1和dimension 2)之间的correlation是有点困难的,它并不知道如果x_1x1值很大的时候,x_2x2的值很大是好的,值很小也是好的,但如果值介于不大不小中间是不好的,它不太容易学到这件事。
你会发现在这个distribution跟这个distribution之间还有一大堆的点散布,而这两个distribution它们的mixture靠的太近了,generator根本就没有办法把它们区分开来,这个是用variational Auto-encoder可能会遇到的问题。
接下来第二个问题就是为什么discriminator它没有办法自己产生image,其实discriminator它可以自己产生image,只是它非常的卡。
复习一下discriminator是什么,discriminator就是输入一个object输出一个分数,这个分数代表输入的东西有多好。事实上这个discriminator在不同的文献上它可能有不同的名字,它可能叫做Evaluation Function、可能叫Potential Function、可能叫Energy Function。如果在其它的领域曾经看过这些名字,比如说Potential Function,它是不是也是吃一个input然后就output一个scalar,这个scalar就决定这个input有多好或是多不好。所以discriminator在不同的领域其实是有不同的名字的。
能不能用discriminator来生成object,其实是可以的。怎么用discriminator来做generator呢?你就套下面这个式子。不过在讲它怎么做之前,先来讲discriminator相较于generator有什么样的优势。
刚才有说过generator在产生object的时候,它的每一个component是一个一个独立去生成。所以对它来说要考虑component和component之间的correlation是比较困难的,但对discriminator来说,要考虑component和component之间的correlation就比较容易了。对discriminator来说,因为是产生一张完整的image以后,再把这张image丢给discriminator,让discriminator去给它评价好不好。
所以对discriminator来说它是可以轻易地告诉你这张图片就是不好的,应该得到低分。给它这张图片是好的,就应该拿到高分。实际上怎么做到这件事呢?可能discriminator也是一个Convolutional Neural Network,这个Convolutional Neural Network有一个filter是长这样的,这个filter会去detect有没有isolated的pixel,有没有pixel它的周围都没有其它的pixel,若有这种就给它低分。
所以对discriminator来说当产生完一张完整的图片以后,要检查这张图片里面1component和component之间的correlation对不对是比较容易的。在生成的时候因为是一个一个component独立生成,不容易考虑它们之间的关系,但是等整张图片已经生成完以后要检查这关系对不对是比较容易的。
这个就是discriminator所占到的优势,接下来要讲怎么使用discriminator来产生东西呢?就套用下面这个式子。假设已经有一个discriminator,这个discriminator它确实可以鉴别input一个x它是好的还是不好的。怎么拿这个discriminator来做生成呢?穷举所有可能的x,一个一个丢到discriminator里面,看哪一个x discriminator会给它最高的分数,discriminator会给它高分的x就是生成的结果。
你可能会觉得非常的surprise穷举所有的x,一个一个去检查它丢到discriminator以后会得到高分还是低分。假设x是一张image,image就是由一堆pixel所组成的。有可能穷举所有pixel颜色的组合,看怎么样pixel颜色的组合会得到高分吗?仔细想想好像有一些难度。
但这边要给你的答案不是这个问题,先假设这一个穷举所有的x,在哪个x可以得到高分这件事情,somehow就是有某一个演算法可以做到这件事情。假设你很仔细的考虑以后,也许你可以想出一个演算法来解这个arg max的problem,如果你可以解这个arg max的problem,那就可以用discriminator来做生成。但是这个生成是非常痛苦的,因为这个discriminator擅长的就是批评,它不擅长做有建设性的鉴别。它只擅长批评就跟政治节目的名嘴一样,你给它什么东西它都说这个是不好的,你叫它真的想一个好的东西,它是很难想出来的。
现在假设说它就是有办法生成东西,接下来的问题是:在它有办法生成东西的前提之下,我们怎么样训练这个discriminator。
当我们在训练discriminator的时候,简单来说就是要给它很多好的example,告诉它这好的example是高分的。给它一大堆烂的example告诉它烂的example就是低分的。但实际上手上只有好的example,手上真正有的data是人生成的data(假设做二次元人物的生成),是人画出来的二次元任务的头像。这些东西通通都是好的,这些东西discriminator都应该给它高分。但是这个时候discriminator只有positive的example,只有正面的例子,完全没有反面的例子。
如果只拿正面的例子去train discriminator会发生什么样的问题呢?你会发现这个discriminator之后学到看到什么东西,它就会觉得是正面的例子,都给高分。它训练的时候只有高分的东西,从来没有看过任何低分的东西,它就会学到看到什么东西,都给它高分就是对的,这显然不是我们要的。
所以怎么办呢?需要给machine一些negative example,但是从哪里找negative example就变得非常的关键了。如果找出来的negative example非常的差(你跟机器说人画的就是好的,就是要给高分),然后随机产生一大堆的noise,这些noise就是要给它低分。对机器来说当然可以分辨这两张图片的差别,看到这种给它高分,看到这种给它低分。但之后给它这种图片(画的很差),但是机器觉得这个还是比noise好很多,会给它高分,这个不是我们要的。
所以怎么产生好的negative example就变得很重要,假设可以产生非常真实的negative example,这样discriminator才能够真的学会鉴别好的image跟坏的image。但是现在问题就是怎么产生这些好的negative example,要产生这些好的negative example,也需要一个很好的process去产生这些negative example。但是现在就是不知道怎么产生image才要train model,这样就变成一个鸡生蛋,蛋生鸡的问题。
要有好的negative example才能够训练discriminator,要有好的discriminator才能够帮我们找出好的negative example,这样就陷入一个鸡生蛋,蛋生鸡的问题。
实际上怎么解这个问题呢,可以用iterative的方法来解这个问题。要怎么训练discriminator呢?
假设有一堆positive example,有一堆negative example。一开始positive example是人画的image,negative example是random sample出来的一堆noise。在每一个iteration里面,discriminator学会做的事情就是给这些positive example高的分数,给这些negative example低的分数。
接下来当你学出一个discriminator以后,可以用这个discriminator去做generation,我们刚才说discriminator是可以做generator的,只要会解这个arg max的problem,就可以用这个discriminator做generation。就用这个discriminator generate出一些它觉得是做好的image,这些image我们用x tilde来表示它。有了这些原来的discriminator觉得是好的image以后,在下一个iteration把原来random的image换成这些第一代的discriminator觉得是好的image,接下来再update discriminator参数告诉它这些是好的,这些是不对。
用了新的discriminator,新的discriminator再解一次arg max的problem。因为discriminator变了,所以它可能会产生更好的image,这个process就一直反复的循环下去。只有一个discriminator去分辨图片的好坏,它参数update以后可以去产生更好的image,接下来就可以learn更好的discriminator,不断反复这个process。
这边是一个图示化的方式来讲这个运作看起来像是什么样子,这个红色的线代表discriminator的value,input一个object,这个object如果是image的话,它是分布在一个很高维的空间中。现在为了简化起见,就假设object分布在一维中,object随着分布的位置不同,discriminator会给它不同的分数。
假设real example是落在这个地方,discriminator当然要给落在这个区域的东西高的分数。它应该要给其它的区域,不再这个高分的区域低的分数。实际上这整个object可以分布的space是非常巨大的,如果在一维空间里面你可能会觉得这个地方是高分的,那两边就应该给它低分。但如果是一个高维的空间,高维空间里面没有出现real example的地方的分数都把它压低。
实际上的做法看起来像这个样子,刚才讲discriminator子train的时候,它是iterative去train的。假设一开始real data分布长这个样子,有一些generator出来的data是绿色的这个,有一些negative example的分数是蓝色的这个。接下来discriminator会去学着给绿色的点高分,给蓝色的点低分。因为它只知道给这个区域高分,给这个区域低分。它可能没有学到要给这个区域多少分数,所以搞不好learn完以后,这个区域的分数还比real data分数要高。这个是有可能的,因为并没有给机器constrain这个地方的分数是怎样,你只说这边分数要高,这边分数要低,这个地方要怎样其实是不知道。
接下来learn出第一个discriminator以后,用这个discriminator去产生example,也就是说去找出这个discriminator的弱点。刚才说在这个iteration的process里面learn discriminator,接下来用discriminator去产生negative example,用discriminator去找出自己的弱点。用discriminator产生negative example的时候,我们有说怎么让discriminator做生成,就是看那些图片discriminator会给它高分,那些东西就是negative example。
如果是看这个例子的话,discriminator是给这些图片高分(蓝色的线),这些图片就是discriminator自己产生出来的negative example。在下一步骤里面,discriminator产生出这些negative example以后,它又要学到它给这些example低分(蓝色的线),这些example高分(绿色的线)。discriminator形状就会改变,可能就变成这个样子。
这个process就反复继续下去,这就好像是discriminator不断去寻找它的function里面的弱点,看看哪边分数特别高。某个地方如果不是real example,它又凸起来,在那些sample一些negative example。然后再下一个iteration,discriminator就会把那个区域的值压下去。
这样久不会overfit吗?这个问题还是蛮难回答的。因为machine在做生成的时候,它就是看它的real data长什么样子,它要产生像real data的东西。所以如果你的data很少,确实有可能overfit。
但是train出来那些图片的就是database里面的图片,你会希望你给他的图片够多,它可以学到generalize的东西产生database里面没有的图片。这个又跟一般的training和testing不太一样,所以在做GAN生成的时候,其实很难知道到底有没有overfit。
最后希望训练到,对discriminator来说在这个input space上面只有出现real data的地方分数才是最高的。这个时候negative example跟positive example它们的distribution就会重合在一起。当negative example和positive example它们的distribution重合在一起的时候,train的process就会停下来,这个是discriminator的training。假设知道discriminator可以拿来做生成,其实根本就不需要generator,光凭借着discriminator也可以做生成这件事。
你可能会想说有人真的拿discriminator做生成吗?答案是有的。假设你熟悉整个graphic model的work的话,你仔细回去想一下,刚才讲的那个train discriminator的process其实就是general的Graphical Model的training,只是在不同的method里面讲法会略有不同而已。
Graphical Model其实就是Structured Learning的一种,Graphical Model里面又分成很多类。比如说Bayesian Network、Markov Random Field等等。这里其实没有列完所有和Graphical Model有关的技术,这边列的是古曲MLDS会讲的东西。MLDS的名字是Machine Learning Having Deep and Structured。本来这门课是有一半时间会将Structured Learning这个技术,只是发现讲到后来大家都不想听了,大家都只想听Deep Learning。Structured Learning大家都不知道是什么东西,所以后面就不太讲Structured Learning的东西。
但是GAN其实也可以被视为Structured Learning的一种技术,而在Structured Learning的技术里面,其中非常具有代表性的东西就是Graphical Model。如果你熟悉Graphical Model,比如说Markov Random Field或Bayesian Network的话,你想想看在Markov Random Field、Bayesian Network里面,你是定一个graph,这个graph上面有一个Potential Function,这个东西就是你的discriminator。
然后输入你的observation,那个graph会告诉你这组data产生出来的机率有多少,那个机率就是discriminator assign的分数。假设你不熟Graphical Model的话,Graphical Model里面的那个graph、你的Potential Function、你的Markov Random Field、你的Bayesian Network其实就是discriminator。回想一下你去train Markov Random Field或者train Structured SVM、train种种Graphical Model的时候、种种和Structured Learning有关技术的时候,是不是iterative的去train。你做的事情是不是有positive有negative example训练你的model,接下来用model sample出negative example再去update model,其实就跟我刚才讲的training discriminator的流程是一样的。只是把同样的事情换个名词来讲,让你觉得不太一样而已。
已经讲了generator和discriminator,接下来比较一下generator和discriminator各自所遇到的问题。generator的优势就是,它很容易做生成,generator在生成很快。这个是Feedforward Network,很快就可以生一个东西。它的缺点就是它不容易考虑component和component之间的correlation,它在学习的时候只是去模仿某一个目标,所以它只学到了那个目标的表象,它没有学到精神,因为它只学pixel和pixel之间相似的程度。
discriminator的优势就是可以考虑大局,它的劣势就是你要叫discriminator生一个东西,这是比较困难的。我们要去解一个arg max的problem,而要解那个arg max的problem势必就必须要对你的discriminator的model做一些假设。在传统的文献里面,必须要假设discriminator的model是线性的,才有办法解那个arg max的problem。你限制它是线性的意味着你限制了它的能力,如果它是非线性的,你不知道要怎么解arg max的problem,所以这是一个大问题。
过去在讲Structured Learning的时候讲到这段要解arg max的problem,通常只能假设,大家听了就生气了,所以后来都没有人要听这一段。
但是现在不一样的就是我们有了generator,generator就是取代了这个arg max的problem。想象成本来想要一个algorithm来解这个arg max的problem,往往我们都不知道要怎么解arg max的problem。使得这一套framework听起来没有问题但就是你不能解,所以听起来就有很多的问题。但是现在用generator来产生negative example,用generator来解arg max的problem。generator可以产生出x tilde,产生出来的x tilde就是那些可以让discriminator给它高分的image。记不记得generator是怎么train的,generator在training的时候,它是不是就是去学着产生一些image,这些image是discriminator给它高分的。
所以可以想象generator在学怎么解arg max这个problem,它在学习的过程中,它就是在学怎么产生discriminator会给它高分的那些image。过去是解这样一个optimization的problem,现在比较不一样,是用一个intelligent的方法(用network来解这个arg max的problem)。
GAN有什么好处呢,从discriminate的角度来看,过去不知道怎么解arg max的problem,现在用generator来解arg max的problem,显然是比这个方法更加有效,而且更容易一般化。对generator来说在产生object的时候,仍然是component by component的产生,但是它得到的feedback不再是L1 L2的loss,不再是pixel by pixel的去算两张图片的相似度,它的loss将是来自于一个有大局观的discriminator。希望透过discriminator带领generator可以学会产生大局观的结果。
这是一个用GAN来产生的toy example,这个example跟刚才讲VAE看到的example其实是一模一样的,只是换了一下颜色而已。蓝色的点是我们要generator去产生的discriminator,是generator学习的目标,红色的点是最终可以得到的结果。这边用的generator的架构跟前一页的VAE用的generator架构师一样的,但你发现学习之后有了discriminator这边的generator学出来的结果是比VAE的generator还要更好的,你会发现这个mixture个mixture之间是几乎没有点的。
而对应到真实的应用,假设要让machine产生图片,产生人脸,如果用VAE产生的人脸就会比较糊。假设真实的人脸、亲戚的人脸是一个mixture,因为VAE会产生那种mixture和mixture之间的sample,所以它就会产生这些比较糊的人脸,如果是用GAN就会产生比较清晰的人脸。
这一页是要比较一下GAN和VAE之间的差别,这是来自Google的paper,这篇paper主要的内容时想要比较各种不同GAN的技术。它比较了MM GAN、NS GAN、LSGAN、WGAN、WGAN GP、DRAGON还有BEGAN,各式各样的GAN,它得到的结论是所有不同的GAN其实performance都差不多,之间做的事情都是白忙一场。
纵轴是算一个FID Score,FID Score越小代表产生出来的图片越像真实的图片,所以这个值是越小越好。对于不同的GAN它们都试了各种不同的参数,GAN在training的时候是非常sensitive的,往往可能只有特定某一组参数才train得起来。它会发现GAN用不同的参数之后,它的performance有一个非常巨大的range。这是两个不同的corpus,一个是MNIST、一个是CIFAR10,生成数字跟生成十种类别的图案。发现如果比较这个corpus,看不出不同的GAN有什么样的不同,只知道它们的range都非常大,可以产生很好的图也可以产生很坏的图。
有件事情它们paper没有强调但我觉得是蛮有意思的,如果比较VAE跟这些GAN的话可以发现,VAE倒是明显的跟GAN有非常大的差别。什么样的差别呢?首先VAE比较稳,发现给它不同的参数,VAE的分数是非常的集中。
刚才讲VAE产生的图片是比较模糊的,虽然它比较稳,但它比较难做到最好。所以比较每一个model可以产生最好结果的话,会发现VAE相较于GAN还是输了一截的。

本文目的在于学术交流,并不代表本公众号赞同其观点或对其内容真实性负责,版权归原作者所有,如有侵权请告知删除。


“综述专栏”历史文章


更多综述专栏文章,

请点击文章底部“阅读原文”查看



分享、点赞、在看,给个三连击呗!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存