Generative Adversarial Network 生成式对抗网络

更新:我用Keras加一点点Tensorflow实现了一个非常快的GAN,详见 <fast_gan_in_keras.html>

常见的神经网络可以分为“生成式模型”和“区分式模型”。区分式模型(discriminative model)尝试在输入特征之间建立近似的and或者or的关系,以实现对输入进行分类的目的。

比如我们用猫和老虎的脸部图片,训练一个神经网络对物种进行分类,网络通常会这么做:

也就是通过条纹的强度,来区分猫和老虎。

如果我们有意增加一些带有条纹的猫的图片,对网络进行训练,为了更明确地区分猫和老虎,网络可能会这么做:

我们发现,区分式模型具有“特征惰性(feature laziness)”,也就是神经网络跟人一样善于偷懒,倾向于用最明显、最简单的特征完成分类任务。假如我们现在用这个神经网络对猫和老虎的躯干图片进行分类,准确率会非常低。

为了提高区分式模型的性能,常见的做法就是准备成千上万张不同角度、不同品种的猫和老虎的图片,对网络进行训练。通常会得到这样的结果:

通过增加训练数据的量,模型能从数据中学习到更多用于区分物种的特征。

问题是,模型仍然只学到了猫和老虎的各种区别,而无法学习猫和老虎共有的特征(比如都有尾巴,腿都长在躯干下面)。

如果这时我们将这个网络用作识别狮子和豹,准确率会很低,于是又要再准备大量的训练数据。相比之下,人类只需要几张狮子和豹的图片就足够了。这种对人工标记训练数据的无限制的需求,是区分式模型的噩梦。

Data Shortage

正是由于“特征惰性”,很多做机器学习的“数据科学家”们经常会跟其他部门的同事发生如下对话:

Unsupervised Learning came to be rescued

自然界中带有明确分类标签的数据是非常稀少的,特别是这些标签只对人类有意义,因此只能由人类来进行标示,产生了很大的工作量。然而人类在了解世界的过程中,并不需要将一切所见所闻都打上标签,那么人类是怎样实现高效学习的呢?

神经科学理论认为,人类学习源自对周围环境的预测。如果身边的一切事物跟预想的一样规律运作,学习就不会发生;如果所预测的运作与观测不符,学习就会发生。这种能力能够帮助我们逐渐适应并利用环境。

回到对猫、老虎、狮子、豹进行分类的例子上来。人类通过大量观察各种不同的动物(河马、大象、狗、驴等等),可以在大脑中建立这样的神经网络:

即便这些训练数据都不带标签,人类也能从中学到一些关于动物的知识,比如动物都是一个躯干旁边四条腿,如果在躯干四周看不到腿,或者看不到尾巴,很可能就不是动物(图中的not_animal)。

在掌握“腿”和“躯干”之间的互相依赖关系这样的抽象特征之后,再去对猫、老虎、狮子、豹进行分类,人类就能够将这些概念与图中的具体动物进行匹配,从而减少需要学习的特征数量,降低学习难度。例如,我们看到图片中的毛发,就可以根据毛发位于躯干四周的具体位置,来决定毛发究竟是属于躯干,还是属于腿部、尾部、耳朵,而不需要再从数据中专门学习“腿部毛发”、“尾部毛发”这样的概念。

结果就是,对于新的分类任务,只需要使用很少的带标签数据,就能训练出非常高效的分类器。历史上有一位长者常说他“见的多了”,“哪个国家没去过”,不管是跟找茬的美国记者还是跟赛跑的香港记者一样能“谈笑风生”,其实是一样的原理。

在ML领域,这类对不带标签的数据进行学习并掌握概括性特征的方法,被归类为Unsupervised Learning(非监督式学习)。由于这方面商业兴趣不大,所以应用一直滞后于Supervised Learning(监督式学习,或带标签学习)。

GAN

可以这么说:监督式学习是用神经网络拟合 p(标签|数据),而非监督式学习是用神经网络拟合 p(数据),即从数据中寻找具有代表性、概括性的特征(或者说,适应数据特征之间的条件概率分布)。

在没有标签的情况下,我们无法通过标签提供的误差梯度对网络进行训练,必须要通过其他方法定义误差函数以产生误差梯度。

这方面的先驱是Hinton提出的Restricted Boltzmann Machine;其他方法还包括 Variational Auto Encoder等等。在此略过不做介绍。

真正让人眼前一亮的,是最近搞起的Generative Adversarial Network,即GAN。

GAN方法需要两个神经网络,一个生成网络G和一个区分网络D。

生成网络G的输入是一个矢量,输出一张图片; 区分网络D的输入是一张图片,输出一个(0,1)之间的概率。

区分网络D的任务是辨别输入的真伪。如果输入图片来自训练样本(x),则应该输出接近1的概率:如果输入图片来自生成网络G,则应该输出接近0的概率。

即: D(G(z)) -> 0, D(x) -> 1

首先训练D:

maximize log(D(x)) + log(1-D(G(随机矢量)))

这会提高D对训练样本和生成样本的区分能力。

然后训练G:

maximize log(D(G(随机矢量)))

这会提高G生成样本对D的欺骗能力。

如此循环下去,G会生成在特征上越来越接近训练样本的图片;而D会对训练样本和生成样本之间的差异(也就是训练样本不同特征之间的相互依赖关系)越来越敏感。于是很多人将GAN中的G用作图像生成、图像修补、图像超采样等领域,获得了非常好的效果。

2017-03-04: DCGAN已经不是state-of-the-art,请参考本博客另一篇LSGAN.

我根据DCGAN的Torch源码,利用Keras实现了一个GAN。训练样例是CIFAR-10中央16x16。以下是经过训练之后,G生成的样本:

从远处来看,这些样本非常像真实的自然照片,近看才发现其实什么也不像。这说明G网络已经大致掌握了训练样例各个像素之间的条件概率分布,例如背景前景颜色的分布,动植物特征的分布等等。这同时也说明D网络现在已经掌握了训练样例中的这些特征(并能够利用这些特征区分真假图片)。而整个训练过程并不需要提供与图像内容相关的任何标签。

很多GAN相关的paper也提到:在大量无标签数据上用GAN方法进行训练之后,将D网络用于分类,只需要很少标签就可以在短时间内达到非常高的准确率。

Network Capacity

由于GAN的拟合对象是p(data)而不是p(label|data),即data中与label无关的部分也得拟合,因此需要的网络容量会大大超过对data按label分类的分类器网络,不然生成的样本质量会很差。

这其实就类似于:一位优秀的艺术家和一位普通人经过一个房间,要求他们用笔画出房间里的内容。

这也可以解释为什么很多同学的英语填空选择很高分,但是作文和口语却很差:前者是区分式模型,后者是生成式模型,所需的训练量和容量差两个数量级。

GAN Training Tricks

在所有的tricks里面,亲测最有效的是batch discrimination和single-sided label smoothing.

G网络有一个取胜策略:令生成的每张图像都长得很像训练样例中的某(几)张图片,简称mode collapse。后果就是每次G网络生成的结果全都一样,D网络却分辨不出来。

解决方法:在D网络中的每一层,计算G网络生成的图像之间的相似度,并把相似度作为feature map输入到下一层,这样D网络就可以利用相似度信息识别出G网络生成的相似图片,以鼓励G网络生成具有多样性的图片。

最后

推荐看Ian Goodfellow对GAN的专题视频。目前效果最好的2D图像生成式模型是PPGN,不妨关注。

file: gan.md

last modified: 2017-03-04 01:19