日期:2019年07月21日   

概述

D判别网络和G生成网络,是2个网络,但是给他们接到一起。他们的训练也是分开的,先训练D(这个时候,要固定住G的参数们),让他有足够强的识别生成图片和真实图片的分辨能力,训练好了D,这个时候,G才登场,他尽量训练自己(D在这个时候参数要固定住),可以骗过D,让D觉得他是真实图片,而不是生成图片。这2个过程,也就是先训练D,后训练G,不停的来,到一定阶段,D和G,就训练好了,这个时候的G,就是我们要的一个需要的生成网络。

原始论文:这里,中文版

有一些问题需要澄清:

  • G的输入是啥?答案是啥都行,比如高斯分布的初始化数据,或者随机初始化的等等。初始化的数据的维度也是无所谓的。别太少就成。
  • 每次训练D和G到什么程度?一般是固定一个固定的次数,训练这么多次,就切换到另外一个,这个次数是一个超参

基本原理

恩,推倒 8)

假设生成分布是$P_G(x;\theta)$,真实分布是$P_{data}(x)$

从中真实分布$P_{data}(x)$中采用${x^1,x^2,…,x^m}$,

这是俩分布哈。

那么,我把真实样本(${x^1,x^2,…,x^m}$)带入到生成分布$P_G(x;\theta)$当中,可以求个似然概率吧。

$L=\prod_{i=1}^m P_G(x^i;\theta)$

那么生成分布是要是尽量靠近真实分布的话,那这个似然概率$L$也应该最大吧。然后找出这个使之最大的$\theta$就可以了。

不过,这事真是没太想明白,这里有2个变量,一个是到底是啥分布,第二个是确定分布后的参数,不过,如果是是GAN,您不是默认就认为真实分布就应该是生成分布了吧,那就相当于俩变数里确定了一个,那剩下的就一个了,就是参数$\theta$了啊。恩。。。。这么想,这个似然概率有点道理….恩,可以可以可以可以。<—–你丫嘚啵嘚啵自言自语啥呢╮(╯▽╰)╭

继续继续….推倒

$\theta = \mathop{\arg\max}\limits_{\theta} \prod_{i=1}^m P_G(x_i;\theta)$

把上面的式子抄下来

$=\mathop{\arg\max}\limits_\theta \log \prod_{i=1}^m P_G(x_i;\theta)$

取个log,不犯法

$=\mathop{\arg\max}\limits_\theta \sum_{i=1}^m \log P_G(x_i;\theta)$

${x_1,x_2,…,x_m}$来自于真实样本哈,对,你使用真实样本放到了生成的模型里,诡异哈?!我还是那个理解:就是如果咱俩像,那我$P_{data}$的数据代入到你$P_G$里面也应该似然最大

$\approx \mathop{\arg\max}\limits_\theta E_{x\sim P_{data}} [ \log P_G(x;\theta)]$

我靠,怎么就约定于了,这画风转变也忒突然了点了吧,李宏毅老师也没有解释,其实这个就是一阶矩估计均值近似于期望的意思,来,看个参考

$=\mathop{\arg\max}\limits_\theta \int_x P_{data}(x) log P_G(x;\theta) dx$

这个没啥,就是标准的期望的原始定义

$=\mathop{\arg\max}\limits_\theta [ \int_x P_{data}(x) log P_G(x;\theta) dx - \int_x P_{data}(x) log P_{data}(x;\theta) dx ]$

“接下来,加一项没有什么用的东西”,宏毅老师如是说,确实是,这个骚操作确实对argmax这个求最大没啥影响,因为后一项和参数$\theta$确实没啥鸟关系,但是总是觉得怪怪的,可能也是Ian Goodfollow这种大神的神来之笔吧,丫这么骚操作,就是为了凑KL散度,那你又要问了,为何要凑KL散度,没啥,就是想说明,你从极大似然,居然可以推出一个KL散度,而已。而已?!恩,至少我是这么理解的。

$=\mathop{\arg\max}\limits_\theta \int_x P_{data}(x) log \frac{P_G(x;\theta)}{P_{data}(x;\theta)}dx$

$=- \mathop{\arg\max}\limits_\theta \int_x P_{data}(x) log \frac{P_{data}(x;\theta)}{P_G(x;\theta)}dx$

$= \mathop{\arg\min}\limits_\theta \int_x P_{data}(x) log \frac{P_{data}(x;\theta)}{P_G(x;\theta)}dx$

整理一下,我去,这个就是KL散度啊,恩,去复习一下交叉熵、散度概念们

$=\mathop{\arg\min}\limits_\theta KL(P_{data}\|P_G)$

结论是啥,我骚推倒一通后,就是想得到一个结论:其实,你呀忙了半天,就是想找一个$P_G$,让他和$P_{data}$越接近越好(KL散度尽量小),你是不是觉得好有道理啊。不够,瞬间,你是不是有一种被忽悠的感觉,“这不是废话么?!我就是要找一个跟真实分布越相近越好的生成模型嘛”,哈哈。对,你反应过来了,Ian Goodfollow,用一堆数学来证明了,这事是可行的而已。

* 你按照真实分布中的样本带入生成分布中得到似然概率极大化,推出最终这事儿就是使两种分布的KL散度最小。

问题来了,咋个找这个$P_G$

如果这个$P_G$是个具体的分布,而且和真实分布$P_{data}$一致,也就是我们知道他的密度函数,那就好办了,我们就用极大似然,求出对应的参数,这事就结了。

但是,残酷的事实是,你不知道$P_{data}$长什么样子,那么,你也不知道自己该如何准备怎样的一个$P_G$,那怎么办呢?即时我搞出来一个$P_G$,我怎么就能做到让这个$P_G$就和真是分布$P_{data}$很接近呢?en,就是这2个问题:

  • $P_G$应该搞成啥样?
  • 搞出来的$P_G$到底多像真实分布$P_{data}$呀

那来吧,我们来尝试解决它:

  • 用深度网络来表示$P_G$,恩,神奇的深度网络,理论上可以拟合任意的函数,也即是可以模拟任意的分布,是一个泛函的空间吧,你可以理解。
  • 把$P_G$和$P_{data}$灌给一个分类器,让他来分辨差异性,如果分表不出来的时候,就说明$P_G$非常非常像$P_{data}$了,对,灌给一个分类器D,2分类,灌进去的是生成的样本和真实的样本,分类结果是你们有多像?0是不像,1是完全一样。

看这段话,我们可以得出:你只要造一个神迹网络(模拟$P_G$),再采样来一堆的$P_G$生成样本,和一堆的$P_{data}$真实样本,这事貌似就可以干了。

好,那我们把这问题,形式化表达一下:

$G^*= \mathop{\arg\min}\limits_\theta Divergence(P_{data},P_G)$

对,我们就是要找到这样一个$G^*$,为了找到这个最大的G,我们就需要引入一个判别器 D,就是上面提到的那个2分类器(像还是不像的分类器),最终的输出是一个sigmod的分类器就可以了,对,不过它其实也是个神经网络,最不过最后的输出是一个2分类(像,还是不像),然后这就变成了一个优化问题,那还是老规矩,交给“梯度下降”大法来搞定了。

这个时候,我们需要停顿一下,回魂一下。 思考问题的时候,要保持清醒,清醒的知道:我是谁?我从哪里来?我要去往哪里? 那,回到我们这里,我们在干嘛呢?我们是要找一个生成模型$P_G$去尽可能的靠近真实数据$P_{data}$,那么为了做这事,我引入了一个神经网络$G$来表示$P_G$,然后我又需要一个神经网络$D$来判断我$P_G$是不是越来越靠近真实分布$P_{data}$了。恩,对,就是这么一个事。

* 这是神来之笔啊,Ian Goodfellow“设计”(我认为是灵光乍现)出这么一个结构,用个神网来表达$P_G$,而真实分布无需啥神网表示,而是引入了一个判别器D。这个结构,在我看来,相当屌。

谈谈判别器D

对,我们就是要构建一个判别器,可以尽可能的分别$P_G$生成的样本,和真实样本$P_{data}$,那我们来单独先看看这个判别器,怎么能做好一个判别器,有个好的判别器,就可以逼着生成器不断改进了。

这个判别器,是一个神经网络。既然是神经网络,就得整个损失函数出来吧,这样就可以做梯度下降,做最优化了呀。损失函数来了:

$V(G,D)= E_{x\sim P_{data}} [ \log P_G(x;\theta)] + E_{x\sim P_G} [ \log (1 - D(x))] $

这个式子咋来了?不知道。不过,直观上还是挺好理解的:如果来源$x\sim 𝑃_{𝑑𝑎𝑡𝑎}$,$D(x)$尽可能高;如果来源$x \sim 𝑃_𝐺$,$D(x)$尽可能低

我们的目标呢,就是:

$ \arg \max \limits_D V(D,G)$

对,去找一个牛逼的D,让这个D可以做到,使得$V(D,G)$最大,这里G假设是固定的了,是之前的已经稳定下来的一个生成器,我们的$D$可以最大化,使得我们最能分辨是生成式数据还是真实数据。

来,让我们更详细地分析分析这个式子:

$V(G,D)= E_{x\sim P_{data}} [ \log D(x;\theta)] + E_{x\sim P_G} [ \log (1 - D(x))] $

$= \int_x P_{data} [ \log D(x)] dx + \int_x P_G [ \log (1 - D(x))] dx $

$= \int_x[P_{data} \log D(x)] + \int_x P_G [ \log (1 - D(x))]dx $

这几步没啥,我们就是要让这个式子最大化,接下来要变态了:

宏毅老师说,为了$max V(G,D)$,G现在已经固定下来了,这个时候就是要找一个$D^*$,使得$ \arg \max \limits_D V(D,G)$,那咋玩呢?恩,这么玩:

我让上面的积分式中的每一项都最大,宏毅老师的说法是,给定某一个$x$,我觉得都是一个意思:也就是让积分项中的$P_{data} \log D(x)] + \int_x P_G [ \log (1 - D(x))$最大,这个项中,假设某一个x确定,那么变得就是一个$D$,$D$是啥,是一个函数,是一个密度函数,这事貌似就变成了一个泛函问题了,就是找到这么一个$D^*$,让这项最大化。

我理解,宏毅老师想表达的是,积分项里面,对每一个$x$,都可以选择一个$D$,让这项最大,那么积分起来,也就是每个$x$的项都加起来,也一定是最大,也就是满足了 $ \arg \max \limits_D V(D,G)$。可是,我总是觉得有些追追不安,你$x1$可以找到一个$D_1$可以使得这个式子最大,而$x2$又可以找到一个$D_2$,可是谁说$D_1,D_2$就一样呢,你没法让两者,甚至更多者统一成一个$D$呀。你这么推导,是不是,牵强呢。有时间的话,得去找Ian Goodfellow的论文看看,看看他怎么“自圆其说”的。

如果按照上面的思路继续往下,其实,就简单了:

就是优化这个式子:$P_{data} \log D(x)] + \int_x P_G [ \log (1 - D(x))$,寻找一个最优的$D$,称之为$D_*$。这个式子里,变元只有不确定的$D$,嗯,就是个泛函问题了。宏毅老师的推导也简单粗暴:

$P_{data}(x) logD(x) + P_G(x) \log (1 - D(x)$,对应:

  • $P_{data}(x)$ => a
  • $log D(x)$ => D
  • $P_G(x)$ => b

这个式子就变成了:$f(D)=a*log (D) + b * log(1-D)$

然后对$D$求偏导,求出最大值$D^*$:

$\frac{d(f(D))}{dD}= a * \frac{1}{D} + b * \frac{1}{1-D} =0$

然后解出来$D^*$:

$D^* = \frac{a}{a+b} = \frac{P_{data}(x)}{P_{data}(x)+P_G(x)}$

好,既然算出了每项中使之最大的$D^*$,那么把这个$D^*$带回到之前的$V(G,D)$中,去求求$V(G,D)$的最大值吧:

$V(G,D)= \int_x[P_{data} \log D(x)] + \int_x P_G [ \log (1 - D(x))]dx $

$= \int_x[P_{data} \log \frac{P_{data}(x)}{P_{data}(x)+P_G(x)}] + \int_x P_G [ \log (1 - \frac{P_{data}(x)}{P_{data}(x)+P_G(x)})]dx $

$= \int_x[P_{data} \log \frac{1/2 * P_{data}(x)}{(P_{data}(x)+P_G(x))/2}] + \int_x P_G [ \log (1 - \frac{1/2 * P_{data}(x)} {(P_{data}(x)+P_G(x))/2})]dx $

$= \int_x P_{data} \log * \frac{1}{2} + \int_x[P_{data} \log \frac{P_{data}(x)}{(P_{data}(x)+P_G(x))/2}] + \int_x P_G \log * \frac{1}{2} + \int_x P_G [ \log (1 - \frac{P_{data}(x)} {(P_{data}(x)+P_G(x))/2})]dx $

$= 2log \frac{1}{2} + \int_x[P_{data} \log \frac{P_{data}(x)}{(P_{data}(x)+P_G(x))/2}] + \int_x P_G [ \log (1 - \frac{P_{data}(x)} {(P_{data}(x)+P_G(x))/2})]dx $

$= 2log \frac{1}{2} + \int_x[P_{data} \log \frac{P_{data}(x)}{(P_{data}(x)+P_G(x))/2}] + \int_x P_G [ \log (\frac{P_G(x)} {(P_{data}(x)+P_G(x))/2})]dx $

$= 2log \frac{1}{2} + KL\left( P_{data} \| \frac{P_{data}(x)+P_G(x)}{2} \right) + KL\left( P_G \| \frac{P_{data}(x)+P_G(x)}{2} \right) $

$= 2log \frac{1}{2} + 2JSD(P_{data}\|P_G)$

哈,有点乱!是吧。没事,你自己也推一遍吧。我是老老实实的推了一遍,一点也不难,其实,主要工夫都花在latex的排版上了,很多推导看上去挺复杂,其实就是个机械活动,一步步的推出来就好。

关键还是别迷失,我是谁?我从哪里来?我要去往哪里?恩,我在干嘛呢。必须回顾一下:

我是在求$V(G,D)$的最大值呢,我让每一项都最大,然后把由一项导出的最大值$D^*$带回到$V(G,D)$,得到了$V^*(G,D)$:

$ V^*(G,D) = 2log \frac{1}{2} + 2JSD(P_{data} \| P_G) $

* 我们在让判别器牛逼之极(最优化)(这个时候G固定),居然发现,损失函数居然是一个$P_G$和$P_{data}$的JS散度,她的最大值$V(G,D^*)$就是一个Divergence -- JS Divergence

JSD,其实就是JS散度。嗯,嗯,你没有看错,最后这个最大值居然就是这个$V(G,D)$最后居然就是JS divergence(JS散度)。JS散度是什么鬼来着?其实很简单,就是两个分布的a->b的KL散度和b->a的KL散度的平均。这样避免KL散度有方向性的问题。

$V(G,D)$是什么来着?估计你都忘了。我提醒你一下,是判别器$D$的最大值,就是说,你这个判别器,尝试去判别生成器生成的样本$P_G$和真实样本$P_{data}$,你的极大值,也就是你最牛逼的判断力,其实就是两个分布的JS散度值,这事说明了什么?什么也不说明,哈哈。只是告诉你一种直觉,冥冥之中自有安排。

回到求解生成器G的上面来

前面提过这个公式:$G^*= \mathop{\arg\min}\limits_\theta Divergence(P_{data},P_G)$,记得吧,这是啥来着?是生成网络G,孜孜以求的目标。就是要找到这么一个G,可以让G的分布$P_G$和真实数据的$P_{data}$的可衡量的距离,尽量的小。

我们也尝试探讨了,对某个固定下来的G来说,我去寻找一个判别器$D_*$,可以让$V(G,D)$那个损失函数得到最大值,从而让这个D足够牛逼,可以分辨G出来的假东东和真实的数据。而且,这个最大值,其实就是$P_G$和$P_{data}$的JS散度值。

好啦,把这俩事儿,接到一起,其实就是Ian Goodfellow的GAN论文里的那个著名的GAN的损失函数:

\[\min_{G} \max_{D} V\left(D, G\right) = \mathbb{E}_{\boldsymbol{x} \sim p_{data}{\left(\boldsymbol{x}\right)}}{\left[\log D\left(\boldsymbol{x}\right)\right]} + \mathbb{E}_{\boldsymbol{z} \sim p_{\boldsymbol{z}}\left(\boldsymbol{z}\right)}{\left[\log \left(1 - D\left(G\left(\boldsymbol{z}\right)\right)\right)\right]}\]

也就是,先固定G优化D,使这个式子最大;然后再固定D优化G,使得这个式子达到最小;

宏毅老师在这块花了不少口舌,他其实就是尝试解释,$\arg\max\limits_D V(G,D)$,就是在衡量$P_G$和$P_{data}$的Divergence,找到了$D^*$,再去$\arg\min\limits_D V(G,D)$的过程。

左图就是说,你全局假设只有3个G,就从这里面挑一个最好的就成。那你先去看每个G,他对应的$D^*$得到的$V(G,D^*)$是多少,这个时候,这个$V(G,D^*)$就是$P_G$和$P_{data}$的散度距离。然后比较这3个G的$V(G,D^*)$,就是最好的那个$G^*$。

右图,把这个过程进一步细化,变成不断迭代的过程,特别解释了在求解$G^*$的时候,需要优化的式子里面包含一个max,包含max的优化求解有些复杂,需要分段计算梯度值,我理解,大致就是这个细节或者说是难点。

这里,宏毅老师特别强调了一个细节,就是你做梯度下降的时候,你是假设G不是剧烈变化的:

如图,左图的蓝色,是上一个迭代的D,你算了他的最大值,也就是$V(G_0,D_0^*)$,那个最大值(绿色虚线),就是就是$P_G$和$P_{data}$的散度距离 – JS散度,然后你对G做了一个梯度下降,使之成为了另外一个G:$G_1$(G其实是个泛函了,呵呵,不过用神经网络表示他你也不用太纠结了),别忘了,你的初衷是$G^*= \mathop{\arg\min}\limits_\theta Divergence(P_{data},P_G)$,如果$G_0$和$G_1$变化剧烈,就像上图一样,那你用的那个D,也就是$D_0^*$,已经不是$V(G_1,D)$对应的最大值了呀,人家的是$D_1^*$,不是最大值,这个绿线就不再表示的是JS散度了啊,那完蛋了,这事没的玩了。不过,别担心,宏毅老师的解释是,你做的G的梯度下降,会非常的小的$\delta$变化,这样的话,我们还认为变化后的$G’$,他的最大值还在$D_0^*$就好。

这样,你就可以放心的更新一遍G的参数了。所以,这也要求你不要太剧烈更新G。实际上,这个细节也深深影响到了后面的训练策略。

总之,宏毅老师废了不少口舌,来讲这个过程。其实,都是在帮着解释Ian Goodfellow的那个著名的GAN损失函数,看着是一个式子,但是其实,他是一个动态的公式,固定一个,训练另外一个,argmax、argmin,不断地交替:(恩,再放一遍这个著名公式)

\[\min_{G} \max_{D} V\left(D, G\right) = \mathbb{E}_{\boldsymbol{x} \sim p_{data}{\left(\boldsymbol{x}\right)}}{\left[\log D\left(\boldsymbol{x}\right)\right]} + \mathbb{E}_{\boldsymbol{z} \sim p_{\boldsymbol{z}}\left(\boldsymbol{z}\right)}{\left[\log \left(1 - D\left(G\left(\boldsymbol{z}\right)\right)\right)\right]}\]

* 这段总结一下,就是,要是你G每次梯度下降的别太厉害,就是得到的新的G'基本上变化不大,还是近似于G,的前提下:D的最大化,那么这种策略,在这个Ian Goodfellow设计出的这个网络中,就是在让$P_G$和$P_{data}的JS散度缩小的过程,就是让我(生成用的分布$P_G$)不断概率似然真实分布$P_{data}$的过程,也就是$P_G$越来越像$P_{data}的过程。$

不过,之前您不是推导是KL散度呢,现在怎么变成JS散度了呢,而且后面还有各种散度,比如WGAN都可以呢?恩,我也不知道,我也迷惑着这点呢?

好啦,实操训练了

实际训练的时候,你怎么算这两个期望呢?那只好靠采样了,

\[V(D, G) = \mathbb{E}_{\boldsymbol{x} \sim p_{data}{\left(\boldsymbol{x}\right)}}{\left[\log D\left(\boldsymbol{x}\right)\right]} + \mathbb{E}_{\boldsymbol{z} \sim p_{\boldsymbol{z}}\left(\boldsymbol{z}\right)}{\left[\log \left(1 - D\left(G\left(\boldsymbol{z}\right)\right)\right)\right]}\]

在生成器G固定下来的时候,就变成了

\[\arg\max\limits_D \tilde{V} = \frac{1}{m} \sum\limits_{i=1}^m log D(x^i) + \frac{1}{m} \sum\limits_{i=1}^m log (1 - D(\tilde{x}^i))\]
  • ${x_1,x_2,…,x_m}$是从真实样本$P_{data}$中采样的
  • ${\tilde{x}_1,\tilde{x}_2,…,\tilde{x}_m}$是从$P_G$产生的样本中采样的

然后你就要把$\tilde{V}$最小化,这件事,李宏毅老师说,就相当于是train一个这2个类别的分类器,这个其实不太理解,我还专门去看了看逻辑回归这种二分类器的损失函数,长的也不太一样。不过,从直观上理解,这事倒是可以理解的。宏毅老师也没打算推导,我也就不纠结了。

GAN算法
初始化 $\theta_d$ for D( discriminator) , $\theta_g$ for G( generator)

在每次迭代中:

1. 从数据集 $P_{data}(x)$中sample出m个样本点${x^1,x^2,...,x^m}$,这个m也是一个超参数,需要自己去调。

2. 从一个分布(可以是高斯,正态..., 这个不重要)中sample出m个向量${z^1,z^2,...,z^m}$

3. 将第2步中的$z$作为输入,获得m个生成的数据${\tilde{x}_1,\tilde{x}_2,...,\tilde{x}_m}(\tilde{x}_i=G(z^i))$

4. 更新discriminator的参数 $\theta_d$ 来最大化$\tilde{V}$, 我们要使得$\tilde{V}$越大越好,那么下式中就要使得$D(\tilde{x}^i)$ 越小越好,也就是去压低generator的分数,会发现discriminator其实就是一个二元分类器:
* $Maxmize(\tilde{V} = \frac{1}{m} \sum\limits_{i=1}^m log D(x^i) + \frac{1}{m} \sum\limits_{i=1}^m log (1 - D(\tilde{x}^i)) $
* $\theta_d \gets \theta_d + \eta \nabla \tilde{V}(\theta_d)$ ($\eta$也是超参数,需要自己调)

1~4步是在训练discriminator, 通常discriminator的参数可以多更新几次

5. 从一个分布中sample出m个向量 ${z^1,z^2,...,z^m}$,注意这些sample不需要和步骤2中的保持一致。

6. 更新generator的参数[公式] 来最小化:
* $ \tilde{V} = \frac{1}{m} \sum\limits_{i=1}^m log (1 - D(G(z^i))) $
* $\theta_g \gets \theta_g + \eta \nabla \tilde{V}(\theta_g)$

5~6步是在训练generator,通常在训练generator的过程中,generator的参数最好不要变化得太大,可以少update几次
  • 恩,是的G不要更新太剧烈(原因前面解释过,变化剧烈,max V就不是js散度了)
  • 反倒是D,可以多更新几次

难道只有JS散度?

咱们前面证明过,寻找$P_G$的过程,就是让$P_G$和$P_{data}$的某种divergence变小的过程(其实只给了一个KL散度,但其实可以扩展成任何的divergence,宏毅老师专门讲了一节课fGAN,我纠结要不要写写fGAN呢,….,hmmmmmmm,再说吧),现在我们就只有JS散度,JS散度好不好呢?

JS散度哪不好

先说结论,不好!

李宏毅在关于WGAN课中讲了大半节课,我还去寻找了他说的论文读了读From GAN to WGAN,下面我来大白话解释解释,我喜欢大白话,话糙理不糙,直奔主题,第一性原理(你丫怎么这么贫拿):

文中和课中,给了一个例子,其实就是一个例子,文中更详细一些:

就是俩分布$P$和$Q$,很极端的,x定义域一个在0,一个是在$\theta$,y是[0~1]均匀分布的,这么俩变态分布。这么设计就是想演示俩分布不重合的时候,JS散度的特殊性。(注意哈,y不是概率密度的值,它也是随机变量,这是个2维的概率分布)

$\forall (x,y)\in P x=0 , y\sim U(0,1)$

$\forall (x,y)\in Q x=\theta, 0\leq\theta\geq1 , y\sim U(0,1)$

好啦,看看俩人$P、Q$的KL、JS散度:

$KL(P\|Q) = \sum\limits_{x=0,y\sim U(0,1)} 1 \cdot log \frac{1}{0} = + \infty$

$KL(Q\|P) = \sum\limits_{x=\theta,y\sim U(0,1)} 1 \cdot log \frac{1}{0} = + \infty$

那,JS散度呢?

JS散度公式是啥来这:

$JS(P,Q) = \frac{1}{2} \left( KL(P\|\frac{P+Q}{2}) + KL(Q\|\frac{P+Q}{2}) \right)$

带入一算,得到:

$JS(P,Q) = \frac{1}{2} \left( \sum\limits_{x=0,y\sim U(0,1)} 1 \cdot log \frac{1}{1/2} + \sum\limits_{x=\theta,y\sim U(0,1)} 1 \cdot log \frac{1}{1/2} \right) = log2 $

那么,问题就来了,如图所示,只要你两个分布靠的很远,即时你们慢慢挪近了,你们的JS散度,还是log2,直到你们相交。

可是,在高维空间里,大部分的数据其实都集中在一个manifold(流形)上,你采样的真实样本,和生成样本,很有可能,而且,大部分时候是天各一方,木有交集的。那,你求他们的JS散度当做损失函数,还梯度下降个屁啊。

所以,我们继续另外一个方法,来让我们两颗心靠近的时候,可以给我们一个客观的逐渐贴近的衡量。这个时候,TA来了,她就是WGAN。

ae4902a73378fdf69b0b8a0b5fc349a7684dc811

WGAN

WGAN是一个真心不懂的算法,他是要找从一个分布,移动到另外一个分布的距离,就是宏毅老师说的把一个分布土堆,推成另外一个分布土堆的形象比喻。他又把这事变成了一个二维矩阵求解的问题,然后又把二维矩阵求解变成一个最优化问题,这个就是WGAN大致的思路。

我其实也没有纠结这个算法,因为,后面你会看到,你不会去真正去求解这个最优化算法,而是,通过某种方法,可以近似的进行求解就可以了。

以下这些图摘自宏毅老师的WGAN PPT:

回到我们的场景,我们要干嘛来着?

我们要求$P_G$和$P_{data}$的距离,之前用的JS散度,现在换成了WGAN散度,然后我们使之最大化,从而去优化判别器网络,记得吧。

$V(D, G) = \max \limits_{D \in 1-Lipschitz} \left\{ E_{x \sim P_{data}}[D(x)] - E_{x \sim P_G}[D(x)] \right\}$

这里啥叫1-Lipschitz,为何用这个样子的一个式子,就可以让损失函数变成WGAN距离,宏毅老师说,忒复杂,不给出证明了,我选择放弃也,哈哈。

稍微解释一下1-Lipschitz,这玩意是一种叫Lipschitz约束的一种特例情况, $\| f(x1) - f(x2) \| < K\| x1 - x2 \|$,当K=1的时候,就是1-Lipschitz约束。

再品一下这事儿,就是说,你找的那个D,要满足1-Lipschitz的约束,这样再用上面这个$V(D,G)$式子求出最大值的过程,就是在缩小Wasserstein距离的过程。

WGAN带来的算法变换

WGAN-GP

GAN使用的神经网络改进

之前光顾着讨论如何衡量$P_{data}$和$P_G$啦,还没怎么讨论过,生成网络$G$和判别网络$D$,到底用啥?是全连接的?还是长的是别的模样呢?好,那我们来说说这块:

DCGAN

生成网络$G$还有判别网络$D$都是CNN(卷积神经网络),对,这玩意就是DCGAN了。

  • 不要pooling层了,pooling层啥参数都没用,还损失了很多信息,不好,我们无论是在生成的时候(图变大),还是判别的时候(图变小),都用卷积。不过一般意义都认为卷积可以让图变小,但是卷积还能图变大呢?!恩,可以的,后面的微步幅度卷积(fractionally strided convolution)可以办到,一会儿再说。
  • 另外,一般典型那几个CNN网络,还需要一个FC(全连接)层,恩,去掉,不要了
  • 另外$G$网络的激活函数改成$Relu->tanh$,$D$网络的激活函数从$Relu->LeakyRelu$

来,看一个更形象的图,这图是个讲DCGAN的文章都配:

生成网络$G$网络图

这个网络里还是有一些细节要说的:

  • 输入是个100维度的高斯分布的z,怎么就变成了4x4x1024的feature map了呢?全连接啊,所以,得这两者之间,要有一个100x4x4x1024=1638400,大约164万个参数,乖乖
  • 你看,4个卷积,1个全连接,不是绝对的,如果数据复杂且分辨率要求高,那就多加几个卷积,否则,就减少两个

fractionally strided convolution(微步幅度卷积)

这玩意就是上面说的,可以把feature map卷大的,$G$网络里用的,其实一点也不复杂。这篇讲的挺好的,还推到了一下数学上严谨的表达,用矩阵相乘的方式表达,感兴趣的同学可以细读。

一图胜千言,可耻的盗图一下:

嗯,就是这样的卷的,下面的蓝色是输入,上面的墨绿是输出,这两种方法都可以,您二选一就成,明白了吧。

判别网络$D$

这个真心没啥好说的,就是个二分类判别器,输入是一张3通道的图,输出是2分类的判别,觉得是真图片为1,觉得是假的为0。中间,就是个CNN的卷积网络,用VGG、Resnet啥的都应该没问题。只不过有时候灌入真样本,有时候灌入假样本(也就是固定G,生成的样本)。

至于按照啥卷积核来搞,我没去看论文,估计就是跟$G$反过来就成,我是说卷积核大小和数量。

各种的GAN(干$\mathop{gan}\limits^\backprime$)

前面理论忒枯燥,我对GAN都不想干了,没兴趣了。还是直接说应用吧,看看到底这玩意怎么玩,这部分好玩。

CGAN(条件GAN - conditional GAN)

这玩意好玩!你说段文字,GAN帮你生成一个文字描述的图片。好玩吧。比如,你输入一个“好高的大楼”,GAN一会儿就给你憋出一张高楼的图片,屌爆了

又是一图胜千言,不过,还是得嘚啵嘚啵:

  • 原始GAN是输入一个随机变量z,这里还要多输入一个你的句子(一般都要先embedding好),然后你生成一张假图片
  • 判别的时候,过去就是输入一张图就可以,这图是生成的,也可以是真实图片,反正就是让判别器判别呗,现在呢,除了输入图片,还要把你的那个句子输入进去

简单吧,这思路真的是简洁,献上膝盖。

现在判别器要判别:

  • 文字是“火车”,图也是火车真图,判别为真 (,”火车”)=> 1

  • 文字是“猫”,即时图是火车真图,判别也是假 (,”猫”)=> 0

  • 文字是“火车”,但是图不是火车,或者生成的是火车但是不清楚、模糊,也判断为假 (,”火车”)=>0 或者(,”火车”)=>0

算法

损失函数

损失函数,跟之前的GAN不太一样了,多了最后一项,就是输入分类和真实负样本,判别器也应该给越小越好的分数:

\(\arg\max\limits_D \tilde{V} = \frac{1}{m} \sum\limits_{i=1}^m log D(c^i,x^i) + \frac{1}{m} \sum\limits_{i=1}^m log (1 - D(c^i,\tilde{x}^i)) + \boldsymbol{\frac{1}{m} \sum\limits_{i=1}^m log (1 - D(c^i,\hat{x}^i))}\)

  • $c^i$是条件,是分类向量或者词、句嵌入
  • $x^i$是真实图像,而且是和条件$c^i$相符的正样本
  • $\tilde{x}^i$是生成网络$G$生成图像
  • $\hat{x}^i$是真实的图片,但是他们和条件$c^i$不一致,属于负样本

CycleGAN

cycle GAN是用来做风格迁移的。

我们可以还是研习GAN的思路,不过这次,我们传的不是一个正太分布的随机变量了,而是一张图,然后我们的真实数据,变成了你想学习的风格画作,然后你就train就可以。宏毅老师说,如果生成网络比较浅,应该就可以实现这个效果,但是,如果比较深的话,这个结构会导致一个问题,就是生成网络会直接生成一张固定的真实画作,然后就总是骗过判别器了。

解决这个问题的办法,就是cycle GAN。

各种玩法

图像生成

风格迁移

StackGAN

实战一把

耍一耍宏毅老师的,二次元头像生成

参考

教程们

小文和资源们

过程中,读到的排版又漂亮,内容又干货的小文,忍不住bookmark下:

  • 一个很整洁的博客,介绍GAN的小文,很喜欢
  • 各种GAN,GAN zoo,太多了,多到我密集恐怖了,知乎上也有一个
  • 跟上面一篇一样,这个 repo多了代码
  • 10个明星GAN的讲解