GAN的诞生
在讲GAN的内容之前想先讲一下GAN诞生的故事。GAN的创造者是Ian Goodfellow,有一天为了庆祝一个朋友Razvan Pascanu获得了博士学位,他和一些朋友在蒙特利尔一家酒吧嗨。他们开始讨论一个新的研究方向,通过数学的方法确定图片内容,大概意思是把图片都喂给机器,通过统计之类的方法,机器可以自己生成图片。我们的主角Goodfellow也喝高了,表示这种方法不会work,有太多统计数据需要考虑,没人能把这些东西都记录下来。但是他有更好的方法:使用神经网络构建逼真的照片。
然后Goodfellow就说了他的思路,一个网络在学习如何生成一个逼真的图片的同时,另一个网络可以作为他的对手,试图确定这些图片的真假,通过这种方法,可以生成与真实图片无法区分的图像。
然后这两个人就发生了争执,都认为对方的方法不行。Goodfellow晚上回家就开始干这件事。
“我回家的时候还有点醉,我的女朋友已经睡了。酒吧里的朋友们错了!”他回忆道。“我熬夜并在笔记本电脑上开始写GAN”。
非常幸运的是,代码第一次跑起来就成功了。
“这真的非常幸运,”他说,“因为如果它没有奏效,我可能会放弃这个想法。”
之后他和其他一些研究人员在晚一些的时候发表了描述这个方法的论文。而在这之后,GAN就火了,几年里出了几百篇和GAN有关的论文。
在这里可以找到大部分的关于GAN的文章:
https://github.com/hindupuravinash/the-gan-zoo
这篇文章就是要讲一讲这个论文,也是GAN的开山之作,不过我觉得除了论文本身,它诞生的过程也有很多值得我们学习的地方。比如Goodfellow大胆的想法,比如他喝完了酒,嗨完了,回到家就开始验证他的想法的行动力,比如他为证明自己的想法不服输的精神。
我觉的这个过程换一个我们平常这些人还真不一定也能创造个GAN出来,我们平常出去嗨完了,肯定没心情再去搞研究去了,有些好的想法可能拖一段时间没做就给忘了之类的。总之,Goodfellow对于学术,对自己的要求,不断探索的精神都很值得我们学习。
GAN的公式
闲话不多说,现在开始讲GAN的论文。这里也贴一下原文下载地址:
https://arxiv.org/abs/1406.2661
另外,这篇文章公式推导部分会涉及到KL散度,JS散度之类的内容,如果之前没什么了解,也可以看一下我之前发的博客:
https://blog.csdn.net/qian99/article/details/85845292
首先说一下GAN的大体流程吧,网络主要由两部分构成,一个是生成器,负责生成图片,另一个是判别器,负责判断图片是否是真实图片,先生成一个噪声,这个噪声作为生成器的输入,生成器通过神经网络给出一个生成的图片,然后判别器会判断这张图片是否是真实图片。生成器可以通过判别器的结果知道自己生成的到底“像不像”,判别器可以通过真实图片与生成图片的判断结果知道自己的判断“准不准”,这样,两者就可以互相博弈,不断提高自己的能力,在论文中,会给出证明,两者最终会达到一个平衡状态,这个时候两者达到了纳什均衡。
在给出公式之前,先说一下符号定义。
这里先说一下,论文中公式带g下标或者G的符号,基本上都和生成器(Generator)有关。而公式中带d或者带D的符号,基本上都和判别器(Discriminator)有关。
data : 这里指的就是训练数据,也可以说是一个真实数据的数据分布。
pg :生成器的数据分布。
z :噪声
pz(z) :噪声的概率分布。
G(z;θg) :表示将噪声
z映射到
data这个空间的生成器函数
G,它的参数是
θg,输出的在论文中的任务上是一张图片(其实可以推广到其他问题,也可以是其他输出)。
D(x;θd) :判断输入
x来源于
data这个数据分布的概率的判别器函数,
x这里对应一张图片,输出是一个标量,
θd是判别器的参数。
下面是论文中给出的优化的目标函数:
GminDmaxV(D,G)=Ex∼pdata(x)[logD(x)]+Ez∼pz(z)[log(1−D(G(z)))]
乍一看挺复杂哈,没关系,我们把公式拆开了一部分一部分看。
首先是:
Ex∼pdata(x)[logD(x)]
这个形式的话,在我看来其实与交叉熵差不多,只不过少了一个负号,对这块东西不了解的同学可以参考上一篇博客:https://blog.csdn.net/qian99/article/details/85845292
简单来理解的话,就是判别器
D认为
x属于真实的数据分布的这一事件的负交叉熵,从数值上看的话,判别器越好,这个值就越大。
然后是:
Ez∼pz(z)[log(1−D(G(z)))]
这一项与上一项类似,输入项改为了生成的数据,简单来说,就是生成数据属于生成数据分布的负的交叉熵,从数值上看的话,当判别器
D固定,生成器越好,越像真实数据,这个值就越小,当生成器
G固定,判别器越好,这个值越大。
综合来看,这两部分的和在
D或者
G的某一个固定时,变化是一致的。
最后,我们看一下等式左边的那一项:
GminDmaxV(D,G)
V(D,G)表示我们要优化的值,由于生成器与判别器优化方向是不同的,这两个东西在不断的对抗,所以训练的时候肯定是固定一个,训练另一个,而
min和
max则指出了训练对应的网络时的训练方向。
公式推导与证明
接下来是推导公式,我们要证明,上面给出的公式是可以优化到一个最优解的,并给出这个最优解是什么。
当
G固定时,
D的最优解是:
DG∗(x)=pdata(x)+pg(x)pdata(x)
接下来是证明,当
G固定,我们要求解
V(D,G)的最大值:
V(D,G)=Ex∼pdata(x)[logD(x)]+Ez∼pz(z)[log(1−D(G(z)))]=∫xpdata(x)log(D(x))dx+∫zpz(z)log(1−D(g(z)))dz=∫x[pdata(x)log(D(x))+pg(x)log(1−D(x))]dx
关于上面的推导有一些问题需要解释一下,首先是积分,这里应该是把数据看作是连续的,而在真实世界我们显然不能把整个数据分布都获取到,不过这里是证明,自然是没什么问题。
下一个是关于
pg(x),这个东西其实看起来会有些迷惑的,这个东西基本可以认为是生成的数据与真实分布重叠的部分。差不多是这个意思:
接下来我们设:
a=pdata(x)
b=pg(x)
y=D(x)
那么我们就是求
f(y)=alog(y)+blog(1−y)在[0,1]的最大值。我们求一下导:
dydf(y)=ya−1−yb=0
可以推出:
y=a+ba
可以发现,这个结果正是
DG∗(x)。
接下来,我们用一个新的符号
C(G)表示这个最优化的结果:
C(G)=DmaxV(G,D)=Ex∼pdata[logDG∗(x)]+Ez∼pz[log(1−DG∗(G(z)))] =Ex∼pdata[logDG∗(x)]+Ex∼pg[log(1−DG∗(x))]=Ex∼pdata[logpdata(x)+pg(x)pdata(x)]+Ex∼pg[logpdata(x)+pg(x)pg(x)]
我们继续下一个推论:
C(G)这个训练目标达到最优,当且仅当
pg=pdata,
C(G) 此时等于
−log4。
证明:
pg=pdata很好理解,就是我们生成的数据分布与真实的数据分布相同,那么当
pg=pdata,
DG∗(x)=21,则
C(G)=log21+log21=−log4。
接下来是从公式推导来说明,首先看
C(G)的公式,我们给
log内的分母除一个2,在公式后面加一个
−log(4),保证等式相等。
C(G)=Ex∼pdata[logpdata(x)+pg(x)pdata(x)]+Ex∼pg[logpdata(x)+pg(x)pg(x)]=Ex∼pdata[log2pdata(x)+pg(x)pdata(x)]+Ex∼pg[log2pdata(x)+pg(x)pg(x)]−log(4)=−log(4)+KL(pdata∣∣2pdata+pg)+KL(pg∣∣2pdata+pg)=−log(4)+2JSD(pdata∣∣pg)
不了解KL散度和JS散度的话,可以看一下我之前发的文章,下面附上,KL散度与JS散度的公式:
DKL(P∣∣Q)=x∑P(x)logQ(x)P(x)
JS(P∣∣Q)=21KL(P∣∣2P+Q)+21KL(Q∣∣2P+Q)
根据上面的公式就可以得出推论的结论,因为JS散度非负,并且当且仅当两个分布相等时等于0,因此,
C(G)的最大值就是
−log(4),并且条件是
pg=pdata。这个时候生成模型生成的数据与真实数据完全相同。