赞
踩
今天完成了生成对抗网络GAN的学习,从基本原理到数学公式,从对GAN的一知半解到了解了全貌,感觉还是收获颇多,所以趁着学习的GAN在脑海中逗留的一刻,赶紧进行总结和整理。 这样能使学习到的知识逗留的更长久一些吧。
对世界理解的最高境界就是能创造世界,作为生成模型的两座大山之一,生成式对抗网络(Generative Adversial Networks)自从问世以来就颇受瞩目。相对于变分自编码器,生成式对抗网络也可以学习图像的潜在空间表征,它可以生成与真实图像再统计上几乎无法区分的合成图像,并且现在应用之处很多,图像生成,视频预测,图片超精度转换,图图变换等都会发现GAN的身影。所以了解GAN的工作原理是非常有必要的,而今天,就一点点的剖析一下这个伟大地思想 — 生成对抗
今天的这篇文章,我想从白话和数学推导两方面进行GAN工作原理的描述,因为GAN毕竟作为生成模型的大山,肯定少不了数学公式的陪伴,但是如果单纯的讲数学公式,那么这篇文章就变得没意思了,所以数学公式固然重要,因为是理论的核心,但数学公式之前,白话一下背后的思想也挺重要的,因为这样,后面的数学公式理解才会理所当然。
所以这篇文章的逻辑是先从一个警察与系小偷的故事出发,亲身感受一下我们身边的GAN,然后回到深度学习的宏观层面,大体描述一下GAN是如何运作的,最后理解GAN的内部工作原理和数学公式。 这篇文章花了些时间整理,所以挺长的,如果能坚持读下来,我相信在学习GAN的路上,肯定能给予一些加速度,加油!
分享大纲:
OK, let’s go!
谈起生成对抗或者GAN,你可能头一次听说,但是你知道吗? GAN的学习场景其实就在我们身边,如果不信的话,我先讲个故事(哈哈,听故事了):
说某个城市啊,治安很混乱,所以很快,这个城市里就出现了无数的小偷,在这些小偷中,有的可能是盗窃高手,有的可能毫无技术可言。 但这样下去,这个城市就人心惶惶,人民没法安居乐业了。 这哪能行? 所以上面派来了高官开始整治治安,开展了一场打击犯罪的运动。
警察们开始恢复城市中的巡逻,很快,一批「学艺不精」的小偷就被捉住了,但是在这个过程中,还有一批比较强的小偷成了漏网之鱼,警察目前的这个水平已经抓不到这些人了,所以警察们开始训练自己的破案技术,去抓住那些越来越狡猾的小偷, 由于这些职业惯犯们的落网,警察们也练就了特别的本事,他们能很快能从一群人中发现可疑人员,于是上前盘查,并最终逮捕嫌犯。
而这时候,小偷的日子就不好过了,因为警察们的水平大大提高,如果还想以前那样表现得鬼鬼祟祟,那么很快就会被警察捉住。为了避免被捕,小偷们努力表现得不那么「可疑」,而魔高一尺、道高一丈,警察也在不断提高自己的水平,争取将小偷和无辜的普通群众区分开。
随着警察和小偷之间的这种「交流」与「切磋」,小偷们都变得非常谨慎,他们有着极高的偷窃技巧,表现得跟普通群众一模一样,而警察们都练就了「火眼金睛」,一旦发现可疑人员,就能马上发现并及时控制——最终,我们同时得到了最强的小偷和最强的警察。
这就是警察和小偷的故事,故事讲完了,你能有点感悟吗? 警察和小偷彼此互相对抗,然后各自学习成长,大家的水平都越来越高。
其实这个就类似于GAN的学习过程,只不过警察和小偷换成了判别器和生成器而已,所以这个过程有点感觉了吧,是不是在我们身边也会发现GAN的身影? 那么我们就具体来看看GAN吧。
GAN 的核心思想就在于两个部分:一个伪造者网络(小偷)和一个鉴定网络(警察)。二者互相对抗,共同演进,在此过程大家的水平都越来越高,伪造者网络生成的图像就足以达到以假乱真的水平(小偷伪装的和普通人很像了)。基于这个思想,我们来看一下 GAN 的原理与细节(还是先说理论,看不懂不要紧,后面会有一个例子做辅助,两者结合,肯定就懂GAN工作过程了。)
GAN 的基本原理就在于两个网络:G(Generator)和D(Discriminator),分别是生成器和判别器。
生成器网络以一个随机向量作为输入,并将其解码生成为一张图像,而判别器一张真实或者合成的图像作为输入,并预测该图像是来自于真实数据还是合成的图像。
在训练过程中,生成网络G的目标就是尽量生成真实的图片去欺骗判别网络D。而D的目标就是尽量把G生成的图片和真实的图片分别开来。这样,G和D构成了一个动态的“博弈过程”。在理想状态下,博弈的结果就是G可以生成足以以假乱真的图片G(z),而此时的 D 难以判定生成的图像到底是真是假,最后得到D(G(z)) = 0.5的结果。这块的理解跟博弈论中零和博弈非常类似,可以说 GAN 借鉴了博弈论中相关的思想和方法。
好吧,大理论总是少不了一些抽象,理解起来也不简单,那么我直接举个例子吧,来看看GAN到底在干啥吧:
假设我想让机器生成1000张手写数字的图片(注意这里不是识别手写数字是几,而是生成手写数字的图片),并且尽可能的和原来的手写数字图片一样,这时候,我们应该怎么去训练机器呢?
准备工作
首先, 我们要准备1000张真实的手写数字图片,也就是从手写数字数据集中选出1000张来。
然后,我要搭建一个生成器(就理解成一个神经网络就可以),这个生成器的任务就是我输入一个向量,你输出给我一张图片即可。 再搭建一个判别器(也是一个神经网络),这个判别器的任务就是我给你一张我生成器的图片和一张真实的图片,你给我做一个二分类问题就可以了。
然后我们开始训练两个网络(这是重点,看看究竟怎么训练让它们变强的)
首先,我先让生成器V1随机生成1000张图片(不管图片内容,随机生成即可)并给这些图片打上0标签,然后我把1000张真实的图片打上1标签和上面1000张混合组成一个训练集,去训练我的判别器V1,由于这两种图片相差很大,判别器V1很快就能够看出来哪些是真正的手写数字图片,哪些生成器V1伪造的假图片。
然后,我们得训练生成器V1,让它提高一下伪造图片的技能(这样一下子就露馅了可不好),怎么做呢? 这时候我们冻结住判别器V1的参数不让他训练,只训练生成器V1的参数(先理解成生成器和判别器是可以搭建到一块的),训练的方式就是不断的调整生成器V1的参数,让判别器V1生成1(目前不是手写数字识别生成的是0),这样训练完了之后,就说明生成器V1生成的图片判别器V1已经判别成真实的手写数字图片了,这样生成器V1的伪造水平提高,我们赋予它一个新的名字生成器V2
接下来,我们得提高判别器V1的判别水平了,因为它已经无法判别出生成器V2生成的图片和真实的图片的区别。这时候,我们冻结住生成器V2的参数不进行训练,只训练判别器V1的参数,方式就是生成器V2生成的图片为0, 真实图片为1,混合作为训练集让判别器V1做二分类的问题进行参数调整,这样,当准确率很高的时候,判别器V1的判别能力提高了,能够区分出生成器V2生成的图片和真实图片了。 我们把这个判别器赋予新的名字:判别器V2。
这样我们就完成了一轮生成器和判别器的训练,两者都升级到了V2水平,接下来和上面的思想一样,冻结判别器V2的参数,以判别器V2输出1为目标去调生成器V2的参数,直到这个目标达成,就说明生成器V2的伪造水平进一步提高,判别器V2不行了,接下来,让生成器V3生成图片标0,真实图片标1再次训练判别器V2,这样就完成了两者的又一轮升级。
重复上面的步骤,直到生成器能够达到以假乱真的地步。
这样我们的目标就达成了,当缺少手写数字训练样本的时候,就可以利用这里锻炼的生成器进行图片生成供我们使用。当然换成别的图片一个道理。
通过这个例子,然后再看理论部分是不是清晰了一些了呢? 并且这个例子中,也基本上说明了GAN训练的过程,所以GAN的工作原理也不是那么复杂吧,当然这个生成手写数字的项目我后面会用Keras完成,放到我的Keras的感知境里面去,有兴趣的也可以到时候去看,哈哈,好像说偏了哈,现在还有一个问题,就是为什么GAN可以这样工作? 这些当然是有数学作为支撑的,包括损失函数应该怎么去定义等,所以下面我们就来从内部的数学公式上去理解GAN的工作原理了,不是有句话吗?学习知识,知其然也要知其所以然,当然前方高能,会有一大波数学公式的袭击,准备好!
我们从上面已经大致上知道了GAN网络的训练过程,那么下面我们从数学的角度而这个伟大的想法找一个理论的支撑,看看为什么可以这样解决问题?
这是一个很久远的故事,我们得从极大似然开始,来看看什么是极大似然:
给定数据分布 P d a t a ( x ) P_{data}(x) Pdata(x)(这个我们就可以理解成手写数字图片遵循的一个分布, x x x就是手写数字图片),同时有一个 θ θ θ控制的分布 P G ( x ; θ ) P_G(x;θ) PG(x;θ)(这个就可以理解成生成器生成的图片遵循的一个分布,这个分布由参数 θ θ θ控制),那么我们怎么找到一个最好的 θ θ θ,使得生产的数据分布和原始图的分布最接近呢?
emmm…this is a question。根据极大似然的思想,我们可以这样做:
解释一下,这个 L L L最大,也就是我们模型产生的这样的数据的概率分布最大,由于这组数据是从真实图片中得到的,所以模型产生的数据概率分布最大就意味着我们的模型能够产生和真实图片差不多的图片了, 你从真实世界给我一些样本,我们模型以最大概率的方式去近似得到这些样本的原始分布,这就是极大似然干的事情。我们需要找到一组合适的参数,去保证这个最大的可能性发生。
下面,我们得再介绍一个概念:KL散度, 这个概念描绘的是2个分布的差异度, 如果我们想表示
P
d
a
t
a
(
x
)
P_{data}(x)
Pdata(x)和
P
G
(
x
;
θ
)
P_G(x;\theta)
PG(x;θ)这两个分布的差异度,就可以写成:
K
L
(
P
d
a
t
a
(
x
)
∣
∣
P
G
(
x
;
θ
)
=
∫
x
P
d
a
t
a
(
x
)
l
o
g
P
d
a
t
a
(
x
)
P
G
(
x
;
θ
)
KL(P_{data}(x) || P_G(x;\theta) = \int_xP_{data}(x)log\frac{P_{data}(x)}{P_G(x;\theta)}
KL(Pdata(x)∣∣PG(x;θ)=∫xPdata(x)logPG(x;θ)Pdata(x)
好了,我们把上面的极大似然的最后一步拿下来,并进行化简,就会得到下面的那部分:
这其实就是我们的目标,就是最小化
K
L
(
P
d
a
t
a
(
x
)
∣
∣
P
G
(
x
;
θ
)
KL(P_{data}(x) || P_G(x;\theta)
KL(Pdata(x)∣∣PG(x;θ),因为这个东西就是这两个数据分布之间的差异程度。
下面的问题是这个
P
G
(
x
;
θ
)
P_G(x;\theta)
PG(x;θ)表示的是什么呢?看下面的图片
这个
P
G
(
x
;
θ
)
P_G(x;\theta)
PG(x;θ)上面我们说过,这是可以理解成生成器生成真实图片x的概率, 但是我们这个x是来自真实世界的图片,而我们的生成器的任务还记得吗? 是给定一个向量, 通过一段神经网络之后,我可以生成
x
x
x, 这里说的向量其实就是我们的z, 也可以称之为噪声,它也事先会有一个先验分布,那么问题来了,我这么多向量z,应该会有很多可以通过生成器产生
x
x
x, 那么究竟哪些可以产生
x
x
x,我并不知道,那么想要求这个
P
G
(
x
)
P_G(x)
PG(x), 其实,就是找到那些能够通过生成器产生
x
x
x的那些噪声z, 把它的先验概率进行积分就OK了,所以
P
G
(
x
)
P_G(x)
PG(x)可以表示成下面的式子,看看能不能理解:
P
G
(
x
;
θ
)
=
∫
z
P
p
r
i
o
r
(
z
)
I
[
G
(
z
)
=
x
]
d
z
P_G(x;\theta) = \int\limits_zP_{prior}(z)I_{[G(z)=x]}dz
PG(x;θ)=z∫Pprior(z)I[G(z)=x]dz
这个公式能理解吗? 这里的
I
[
G
(
z
)
=
x
]
I_{[G(z)=x]}
I[G(z)=x]表示示性函数,就是如果噪声z可以通过生成器生成
x
x
x,这个值就为1,否则就为0(我们不就是找可以通过生成器生成的
x
x
x的z吗? 这个示性函数就是一个条件限制), 这个公式的意思就是说我生成器的输入向量或者说噪声z中有很多会通过神经网络产生
x
x
x,那么把能通过神经网络产生
x
x
x的这些z先验概率进行积分其实就是生成器能产生
x
x
x的概率,也就是
P
G
(
x
;
θ
)
P_G(x;\theta)
PG(x;θ)。
但这是理论上能够写的一个公式,真实情况我们是求不出来的。因为真实世界的向量z很难穷尽,我们怎么知道哪些z可以通过生成器生成 x x x? 并且引入了神经网络之后,我们更不知道哪些具体的z会通过神经网络取到 x x x了,所以这个概率直接求是求不出来的。
So, 那怎么办? 无解了吗? 哈哈,上面做了那么多铺垫,终于进入了我们的正题, 我们看看GAN是如何解决这个问题的:
我们都知道,GAN里面有Generator G和Discriminator D
这个地方就有点难理解了,先从这个公式的宏观角度尝试理解一下:
这样一次更新迭代完成,接下来我们又去找使得
V
(
G
1
∗
,
D
)
V(G_1^*,D)
V(G1∗,D)最大的
D
1
∗
D_1^*
D1∗, 然后找使得
V
(
G
,
D
1
∗
)
V(G, D_1^*)
V(G,D1∗)最小的
G
2
∗
G_2^*
G2∗,这样一步一步的下去…,上面的一轮过程也可以结合下面的图片理解一下,应该更加直观一些:
这其实就是上面那个数学公式的宏观把握,是不是和理论方面解释的那个例子差不多?
好,如果知道了这个公式到底在干嘛之后,下面我们再进一步,看看这个
V
(
G
,
D
)
V(G,D)
V(G,D)到底是个什么?
V
=
E
x
∼
P
d
a
t
a
[
l
o
g
D
(
x
)
]
+
E
x
∼
P
G
[
l
o
g
(
1
−
D
(
x
)
)
]
V = E_{x\sim P_{data}}[logD(x)] + E_{x\sim P_G}[log(1-D(x))]
V=Ex∼Pdata[logD(x)]+Ex∼PG[log(1−D(x))]
这个
V
V
V函数简单的说就是两个数学期望的和
好,这一步明白了,我们看看给定一个生成器
G
G
G之后,如何去最大化这个
V
(
G
,
D
)
V(G, D)
V(G,D)(因为我们知道
G
0
G_0
G0是随机初始化参数得到的,所以肯定是我们先有
G
G
G开始)
最大化这个积分,其实相当于最大化积分号里面这个
P
d
a
t
a
(
x
)
l
o
g
D
(
x
)
+
P
G
(
x
)
l
o
g
(
1
−
D
(
x
)
)
P_{data}(x)logD(x) + P_G(x)log(1-D(x))
Pdata(x)logD(x)+PG(x)log(1−D(x))
因为这一个好算啊,
P
d
a
t
a
(
x
)
和
P
G
(
x
)
P_{data}(x)和P_G(x)
Pdata(x)和PG(x)是概率,是已知的,可以看成常数a和b, 然后我们的未知参数只有
D
(
x
)
D(x)
D(x),我们令成
D
D
D, 就可以表示成下面这样:
这样,我们就求出了
D
∗
(
x
)
D^*(x)
D∗(x)其实就等于
P
d
a
t
a
(
x
)
P
d
a
t
a
(
x
)
+
P
G
(
x
)
\frac{P_{data}(x)}{P_{data}(x)+P_G(x)}
Pdata(x)+PG(x)Pdata(x) 这个数是个概率,大于0小于1
这样,我们就找到了能使得
V
(
G
,
D
)
V(G,D)
V(G,D)达到最大的
D
∗
D^*
D∗了。即
在这又得先介绍一个概念,才能继续后面的化简工作:JS散度, 上面我们提到了KL散度是衡量两个分布之间差异程度的,那么这个JS散度是有KL散度计算得到的,也是衡量两个分布之间的差异程度,只不过KL散度是不对称的,JS散度变成对称的了。 公式如下:
J
S
(
P
1
∣
∣
P
2
)
=
1
2
K
L
(
P
1
∣
∣
P
1
+
P
2
2
)
+
1
2
K
L
(
P
2
∣
∣
P
1
+
P
2
2
)
JS(P_1||P_2) = \frac{1}{2}KL(P_1||\frac{P_1+P_2}{2}) + \frac{1}{2}KL(P_2||\frac{P_1+P_2}{2})
JS(P1∣∣P2)=21KL(P1∣∣2P1+P2)+21KL(P2∣∣2P1+P2)
所以我们下面继续化简上上面那个
V
(
G
,
D
∗
)
V(G, D^*)
V(G,D∗), 由
l
o
g
1
2
P
d
a
t
a
(
x
)
P
d
a
t
a
(
x
)
+
P
G
(
x
)
2
=
l
o
g
1
2
+
l
o
g
P
d
a
t
a
(
x
)
P
d
a
t
a
(
x
)
+
P
G
(
x
)
2
log\frac{\frac{1}{2}P_{data}(x)}{\frac{P_{data}(x)+P_G(x)}{2}} = log\frac{1}{2}+log\frac{P_{data}(x)}{\frac{P_{data}(x)+P_G(x)}{2}}
log2Pdata(x)+PG(x)21Pdata(x)=log21+log2Pdata(x)+PG(x)Pdata(x)
后面那个也可以拆开,并且把常数最终提出来,这样的话最终就得到
其实这个地方我觉得应该是约等于,因为忽略掉了两个概率之后乘以前面的常数,但不管怎么说,前面那部分是常数。
也就是说,我们把
m
a
x
D
V
(
G
,
D
)
\mathop{max}\limits_DV(G,D)
DmaxV(G,D)的最优值
D
∗
D^*
D∗带到V函数里面,最后会得到
G
∗
=
a
r
g
m
i
n
G
m
a
x
D
V
(
G
,
D
)
=
a
r
g
m
i
n
G
(
2
J
S
D
(
P
d
a
t
a
(
x
)
∣
∣
P
G
(
x
)
+
C
)
G^* = arg \mathop{min}\limits_G\mathop{max}\limits_DV(G,D) = arg\mathop{min}\limits_G(2JSD(P_{data}(x)||P_G(x)+C)
G∗=argGminDmaxV(G,D)=argGmin(2JSD(Pdata(x)∣∣PG(x)+C)
的形式, 而后面的
2
J
S
D
(
P
d
a
t
a
(
x
)
∣
∣
P
G
(
x
)
+
C
2JSD(P_{data}(x)||P_G(x)+C
2JSD(Pdata(x)∣∣PG(x)+C正好可以衡量生成器
G
G
G生成的数据分布和真实数据分布之间的差异性。
所以下面我们的目标就是找到一个优秀的 G ∗ G^* G∗使得 2 J S D ( P d a t a ( x ) ∣ ∣ P G ( x ) + C 2JSD(P_{data}(x)||P_G(x)+C 2JSD(Pdata(x)∣∣PG(x)+C最小,也就是生成器 G G G生成的数据分布和真实数据分布之间的差异最小。
那么如何去找
G
∗
G^*
G∗呢? 我们可以定义损失函数为:
L
(
G
)
=
V
(
G
,
D
∗
)
L(G) = V(G, D^*)
L(G)=V(G,D∗)
下面我们的目标就是最小化这个
L
(
G
)
L(G)
L(G), 我们需要使用那些优化算法了,比如梯度下降法:
关于梯度下降法的知识在这里就不提了,总之这里可以用梯度下降法一步一步的去求生成器
G
G
G的
θ
\theta
θ值,这样就得到了新的生成器
G
∗
G^*
G∗。
这样,一步更新完成,后面就重复这个操作就行啦。最后,我们看看梳理一下最终的过程:
到这里,我们基本上就把GAN的数学部分给搞定了,不知道你懂了没? 如果没懂得话也没有关系, 但是你得明白,GAN的这个过程是有上面这个背后的理论在支撑的,嘿嘿,就是那句话伟大的思想后面都是赤果果的数学了
下面再看一个神奇的地方,也算是细节吧, 但是看这个地方之前,我们先把
V
(
G
,
D
)
V(G,D)
V(G,D)的公式拿过来:
上面看到,
V
(
G
,
D
)
V(G,D)
V(G,D)的这个公式,是两个积分之和,但是在实际中,我们都是采样过来的,也就是说,
x
x
x都是离散的值, 我们应该怎么计算
m
a
x
D
V
(
G
,
D
)
\mathop{max}\limits_DV(G,D)
DmaxV(G,D)
这个公式有没有点感觉? 如果看不出来的话,我提示一下,我们看看逻辑回归的损失函数:
J
(
w
,
b
)
=
−
[
1
m
∑
i
=
1
m
(
y
l
o
g
(
y
h
a
t
i
)
+
1
m
∑
i
=
1
m
(
1
−
y
i
)
l
o
g
(
1
−
y
h
a
t
i
)
J(w,b) =-[ \frac{1}{m}\sum_{i=1}^m(ylog(y_{hat}^i) +\frac{1}{m}\sum_{i=1}^m(1-y^i)log(1-y_{hat}^i)
J(w,b)=−[m1i=1∑m(ylog(yhati)+m1i=1∑m(1−yi)log(1−yhati)
这样看出来了吗? 原来这个
m
a
x
D
V
(
G
,
D
)
\mathop{max}\limits_DV(G,D)
DmaxV(G,D),就是最小化一个二分类问题的损失函数
哈哈,有时候数学就是这么的神奇? 现在也知道为啥让GAN的判别器在做二分类问题了吧。
好了,GAN的数学部分,到这就结束了。如果你看到这,应该会对GAN的细节部分理解的更加清晰了吧, 下面就轻松了,简单说一点GAN的小细节
这篇文章,主要是上面的GAN的白话理论和数学公式推导,下面这部分可以做一个拓展或者简单了解,不是在这篇文章的重点,所以我直接放图。
这个也是Ian Goodfellow的论文Generative Adversarial Networks中提到的,如果真实图片服从一个多态分布的话,生成器不知道,可能只会生成其中的某一类图片,即使很逼真。
下面在看优化上的一些问题:
所以,针对GAN的不稳定性,后面提出了各种各样的GAN
终于到了结尾了,这就是我目前了解的GAN的工作原理了,简单再梳理一下这篇文章的内容,首先,讲了一个警察和小偷的故事,先感受一下GAN离我们并不是很遥远, 然后,介绍了GAN的宏观层面的工作过程, 举了一个生成手写数字的例子来进行了描述(后面也会用Keras搭建DCGAN来玩这个小项目
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。