アカリの部屋

生成对抗网络

神经网络的无监督学习

机器学习模型可以大体分为生成模型和判别模型两种,判别模型就是学到一个判别器f输出一个概率,比如LR,而生成模型则是得到一个联合概率。通过CNN分类能识别一张图片只是一个判别,而能根据知识创造出一个东西,才是真正学会了一样东西。

无监督的意图是为了让数据自己驱动自己来学得一些东西,以前有一种叫做autoencoder的网络进行无监督学习,即对一张输入图片自己,用一个很简单的NN进行编码映射成一个向量,之后解码,即映射回原先大小的矩阵,使用最小化均方误差损失对输入输出之间的差距最小化,之后取出Decoder,即可拿来对比新的输入和输出。但是这种算法存在很多问题,比如在基于像素对像素的均方误差的评判标准,很难从图片整体上像人一样识别图片中的细微不同。

logo

GAN的结构

为解决这个问题有了生成对抗网络(GAN),GAN是一个层次比较深的网络,它有两个部分,一个叫Generator(生成器),负责生成样本,直到网络的某个层,另一个部分叫Discriminator(判别器),它是个二分类器,负责判断这个样本是伪造生成的还是实际的,在训练的时候,固定住某些层的权重,二者轮流训练,相互促进,使得生成的结果越来越真实,最终取出Generator来用。

对于整个网络的执行流程来说,首先,Generator随机生成一万张图片作为负样本,然后联合一万张真实世界的图片也就是正样本,一起训练Discriminator做二分类的效果来判断谁1谁0。
Generator要进步,训练好Discriminator之后,固定住它的权重,训练Generator,使得原本被判定为是假的概率很大(如0.05)的那些向量最终经过Discriminator判定输出的结果是1,这样Generator就完成了一次更新。
然后,固定住Generator的权重,再生成一万张加图片,重复上述过程,就得到了第二代的Discriminator,之后再固定住Discriminator,去训练Generator,如此反复下去。最终的目的是得到一个效果很好的Generator。

logo

为什么要使用GAN

从数学上来讲,对于一张真实世界的图片 $ X $ ,都有一个概率分布 $ P{_{data}}(X) $,比如猫多还是狗多,同时,我们可以有一个 $ θ $ 控制的复杂分布(比如混合高斯模型GMM生成的分布),那么,生成模型的目的就是找到合适的 $ θ $ ,使得生成的结果分布和原始分布最接近。

由于真实世界中的数据是无穷多的,所以可以对这个实际的分布做采样,得到的这些样本又可以构成一个新的GMM分布,我们希望 $ θ $ 在这份样本集产生的分布上的表现能达到最优,即似然概率 $ L = \prod_{i=i}^m P{_G}(x^i;θ) $ 最大,也就是要最小化这个分布和真实世界分布之间的散度,如KL散度,即 $ arg min{_θ} KL(P{_{data}}(x)||P{_G}(x;θ)) $ 。

这个我们要造出来分布就是Generator产出的分布,由于只用GMM的话描述能力不够强,所以可以用神经网络。神经网络是个能把一个向量映射为另一个向量的映射,可以认为对某个任意分布 $ z $ ,存在一个神经网络的变换 $ G(z)=x $,使得生成的分布 $ P{_G}(x;θ) $ 和真实世界的 $ P{_{data}}(x;θ) $ 最接近。由于神经网络很复杂,很多的 $ z $ 都能生成 $ x $,所以不能直接从数学上求解KL散度,因为没法把这些 $ z $ 都拿出来做积分 $ P{_G}(X) = \int P{_{prior}}(z)I{_{[G(z)=x]}} dz $ 。

logo

GAN的数学原理

对于GAN,整个神经网络分为前后两部分,前半部分的Generator会从先验分布 $ P{_{prior}}(z) $ 中产生出分布 $ z $ ,生成向量 $ x $ ,$ x $ 的分布为 $ P{_G}(x) $ ;后半部分的Discriminator输入向量 $ x $ ,输出一个值,用于评估 $ P{_G}(x) $ 和 $ P{_{data}}(z) $ 的差异,GAN的结果并不是通过loss的大小来评估的,因为无论如何它都会趋于0,GAN当中差异度叫做 $ V(G,D) $。

对于不同的GAN,有不同的 $ V(G,D) $ 函数定义方式,效果最好的Generator满足 $ G^* = arg min{_G} max{_D} V(G,D) $ 。

首先我们会有多个生成器 $ G $ ,对于每个固定的生成器 $ G{_i} $ ,把它看做常量,会有多个对应的判别器 $ D $ 给它作评价,以 $ D $ 作为变量,会得到多个函数 $ V(G{_i}, D) = f{_i}(D) $ ,那么每个 $ G{_i} $ 对应的函数 $ f{_i} $ 都能找到使得其函数值最大的那个 $ D $ ,这些最大的 $ V $ 函数值构成了一个集合,找到这个集合中 $ V $ 值最小的一个 $ f $ ,再找出其对应的 $ G{_i} $,即最优的生成器。

其中一个 $ V(G,D) $ 的形式是:
$ V = E{_{x \sim P{_{data}}}}[logD(x)] + E{_{x \sim P{_G}}}[log(1-D(x))] $

直观的理解是,对于真实世界中采样出来的 $ x $ ,对 $ logD(x) $ 求数学期望,然后对生成器产出的 $ x $ ,对 $ log(1-D(x)) $ 求数学期望。可以看出它是 $ G $ 和 $ D $ 的函数。

这个公式等价于积分:
$ V = \int_x [ P{_{data}}(x)logD(x) + P{_G}(x)log(1-D(x)) ] dx $

因为这个积分没法直接求,问题就转化成找到最好的 $ D(x) $ ,使得
$ P{_{data}}(x)logD(x) + P{_G}(x)log(1-D(x)) $
这一坨积分里面的东西最大。

因为 $ P{_{data}}(x) $ 和 $ P{_G}(x) $ 分别是可知的现实世界和生成器的分布,所以定义为常量 $ a $ 和 $ b $,可以动的只有 $ D $ 。即最大化
$ f(D) = a * log(D) + b * log(1-D) $
所以求导得0,得到 $ D^{*} = \frac {a}{a + b} $
即 $ D^{*} = \frac {P{_{data}}(x)}{P{_{data}}(x) + P{_G}(x)} $
这个结果显然在0到1之间,这很符合分类器输出一个概率的特点。

这个点,恰好就是前面提到的“每个 $ G{_i} $ 对应的函数 $ f{_i} $ ,使得其函数值最大的那个 $ D $ ”。

logo

把这个 $ D^{*} $ 带入 $ V(G,D) $ ,能拿到内部最大的 $ max{_D} V(G,D) $,并且改造公式,即得到:
$ -2log2 + \int_x P{_{data}}(x)log(\frac {P{_{data}}(x)}{(P{_{data}}(x) + P{_G}(x))/2})dx + \int_x P{_G}(x)log(\frac {P{_{G}}(x)}{(P{_{data}}(x) + P{_G}(x))/2})dx $
这个结果就相当于两个KL散度:
$ -2log2 - KL(P{_{data}} || \frac{P{_{data}}(x) + P{_G}(x)}{2} ) + KL(P{_G} || \frac{P{_{data}}(x) + P{_G}(x)}{2} ) $
KL是非对称散度,这个公式等价于一个对称的JS散度:
$ -2log2 + 2JSD(P{_{data}(x)}||P{_G}(x)) $
其中JS散度在0到log2之间,如果两个分布一样就是0。

所以说 $ V(G,D) $ 之所以这样定义,就是为了能把问题转化为求两个分布的JS散度,这里我们先找到了最好的分类器 $ D^{*} $ 。事情结束了一半,之后要找到一个生成器,能把两个分布差异最小化,这是个梯度下降的过程,但是因为 $ G^{*} = arg min{_G} max{_D} V(G,D) $ 存在max操作,所以需要分段梯度下降调参。

从整个过程来看,我们有一个 $ G{_0} $ ,算得了一个 $ D{_0}^{*} $ ,通过梯度下降拿到了 $ G{_1} $ ,之后再找到 $ D{_1}^{*} $ ,梯度下降得到 $ G{_2} $ ,反复迭代下去,就能得到一个理想的 $ G $ 。

对于前面公式中的积分,由于取不到整个现实中的样本没法做积分,所以转化为离散问题,会分别从现实世界和生成图片中采样出很多图片,所以 $ V $ 函数就转化为了通过 $ m $ 个样本去拟合这个积分。那么 $ V $ 的离散版本就是最小化:
$ \tilde{V} = - \frac{1}{m} \sum_{i=1}^m logD(\tilde{x}^i) - \frac{1}{m} \sum_{i=1}^m log(1-D(\tilde{x}^i)) $
如果现实世界的数据是正样本,生成的样本是负样本,从公式上来看,实际上就是在最小化二分类器的交叉熵损失函数。

在实际应用当中,由于 $ log(1-D(x)) $ 在初始点斜率很小,很难训练,所以都使用单调性一致的 $ -log(D(x)) $ 的形式来优化,它在初始点斜率极大。