1. 从网络结构上来说,Generative Adversarial Networks(GAN)并没有创造什么全新的东西。以生成图像为例,GAN其实就是一个反向的CNN用于生成图片加上一个DNN用于决策判别。

  2. GAN的训练过程比较微妙,因为它涉及到两个相对独立的神经网络的训练:生成网络(generator)的训练依赖于判别网络(discriminator)的输出,而判别网络的训练又依赖于生成网络的输出。感觉似乎是一个死循环,但实际上却是可以训练的,具体过程如下:

    Step 1) Set the discriminator trainable

    Step 2) Train the discriminator with the real MNIST digit images and the images generated by the generator to classify the real and fake images.

    Step 3) Set the discriminator non-trainable

    Step 4) Train the generator as part of the GAN. We feed latent samples into the GAN and let the generator to produce digit images and use the discriminator to classify the image.

    在上述四个步骤完成之后(即步骤2训练的判别网络和步骤4训练的生成网络的损失都达到了比较小的值),需要再回到步骤1,以此反复地训练判别网络和生成网络。最终的目标是无论如何训练判别网络,它都很难区分出生成网络的输出和真实的样本(即任意输入一个真实样本或生成网络的输出,判别网络输出它的真实概率均为0.5(概率范围为0到1))。 所谓“Set the discriminator non-trainable”是指反向传播时不改变判别网络中的参数(weights和bias),即训练生成网络就只改变生成网络中的参数,保持判别网络中参数不变,反之训练判别网络时就只改变判别网络中的参数,保持生成网络中的参数不变。

  3. 对于生成图像的反向CNN,它是如何从少量的输入扩展到一张高分辨率的图片的呢?因为是反向的,卷积层其实也要“反”过来,具体做法以输入为4x4的图像为例,假设正向卷积时选取的是3x3的卷积核,且没有填补图像边缘,那么卷积完成后得到的是一个2x2的矩阵;反过来要从一个2x2的矩阵得到一幅4x4的图像/矩阵,如果也是使用3x3的卷积核,就需要对2x2的矩阵边缘做填补(一般直接填0),填补到一个6x6的矩阵,再做卷积就得到了4x4的矩阵(如下图所示)。这样的卷积层叫做transposed convolutional layer。 transposed convolutional layer

  4. GAN的超参数选择有很多坑,一旦选择不好就会出现训练很慢或不稳定的情况,至于为何选择某些超参数效果会比较好,确实很难理解(深度学习深入下去就是门玄学~)。这里列一些比较重要的超参数:

    • 损失函数选择很重要,比较保险的方式是参考已证明有效的函数,比如交叉熵损失。

    • 使用batch normalization可以很大程度上提升训练的效率(解决了反向传播时梯度弥散的问题,不光是GAN,对于其他深度的网络都可以考虑使用batch normalization)。

    • pooling的选择:

      GAN的稳定性会因为引入稀疏梯度受到很大影响,尽量使用LeakyReLU作为激活函数;对于下采样,使用:Average Pooling或者Conv2d + stride;对于上采样,使用:PixelShuffle或者ConvTranspose2d + stride

    • 甚至对于生成网络的输入的噪声也可以讲究:输入可以是多维的噪声,且噪声的分布可以是高斯分布的。

  5. 因为两个网络是交替训练的,每个网络在一轮中分别需要训练迭代多少次也是一个比较难定的超参数。原论文作者是一轮分别各训练一次,但实践中有时候为了节省时间,可以让loss特别大的网络相对另外的网络得到更频繁的训练(一个网络损失下降很大概率会导致另一个网络的损失增加,所以是“对抗”的)。

Reference

  1. Understanding Generative Adversarial Networks
  2. https://github.com/FelixMohr/Deep-learning-with-Python/blob/master/DCGAN-MNIST.ipynb