240

深度卷积GAN之图像生成 - 知乎专栏

 6 years ago
source link: https://zhuanlan.zhihu.com/p/28329335?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

深度卷积GAN之图像生成

计算广告/信贷风控/花呗算法

前言

在我们之前的文章中,我们学习了如何构造一个简单的GAN来生成MNIST手写图片。对于图像问题,卷积神经网络相比于简单地全连接的神经网络更具优势,因此,我们这一节我们将继续深入GAN,通过融合卷积神经网络来对我们的GAN进行改进,实现一个深度卷积GAN。如果还没有亲手实践过GAN的小伙伴可以先去学习一下上一篇专栏:生成对抗网络(GAN)之MNIST数据生成

专栏中的所有代码都在我的GitHub中,欢迎star与fork。

本次代码在NELSONZHAO/zhihu/dcgan,里面包含了两个文件:

  • dcgan_mnist:基于MNIST手写数据集构造深度卷积GAN模型
  • dcgan_cifar:基于CIFAR数据集构造深度卷积GAN模型

本文主要以MNIST为例进行介绍,两者在本质上没有差别,只在细微的参数上有所调整。由于穷学生资源有限,没有对模型增加迭代次数,也没有构造更深的模型。并且也没有选取像素很高的图像,高像素非常消耗计算量。本节只是一个抛砖引玉的作用,让大家了解DCGAN的结构,如果有资源的小伙伴可以自己去尝试其他更清晰的图片以及更深的结构,相信会取得很不错的结果。

工具

  • Python3
  • TensorFlow 1.0
  • Jupyter notebook

正文

整个正文部分将包括以下部分:

- 数据加载

- 模型输入

- Generator

- Discriminator

- Loss

- Optimizer

- 训练模型

数据加载

数据加载部分采用TensorFlow中的input_data接口来进行加载。关于加载细节在前面的文章中已经写了很多次啦,相信看过我文章的小伙伴对MNIST加载也非常熟悉,这里不再赘述。

模型输入

在GAN中,我们的输入包括两部分,一个是真实图片,它将直接输入给discriminator来获得一个判别结果;另一个是随机噪声,随机噪声将作为generator来生成图片的材料,generator再将生成图片传递给discriminator获得一个判别结果。

上面的函数定义了输入图片与噪声图片两个tensor。

Generator

生成器接收一个噪声信号,基于该信号生成一个图片输入给判别器。在上一篇专栏文章生成对抗网络(GAN)之MNIST数据生成中,我们的生成器是一个全连接层的神经网络,而本节我们将生成器改造为包含卷积结构的网络,使其更加适合处理图片输入。整个生成器结构如下:

我们采用了transposed convolution将我们的噪声图片转换为了一个与输入图片具有相同shape的生成图像。我们来看一下具体的实现代码:

上面的代码是整个生成器的实现细节,里面包含了一些trick,我们来一步步地看一下。

首先我们通过一个全连接层将输入的噪声图像转换成了一个1 x 4*4*512的结构,再将其reshape成一个[batch_size, 4, 4, 512]的形状,至此我们其实完成了第一步的转换。接下来我们使用了一个对加速收敛及提高卷积神经网络性能中非常有效的方法——加入BN(batch normalization),它的思想是归一化当前层输入,使它们的均值为 0 和方差为 1,类似于我们归一化网络输入的方法。它的好处在于可以加速收敛,并且加入BN的卷积神经网络受权重初始化影响非常小,具有非常好的稳定性,对于提升卷积性能有很好的效果。关于batch normalization,我会在后面专栏中进行一个详细的介绍。

完成BN后,我们使用Leaky ReLU作为激活函数,在上一篇专栏中我们已经提过这个函数,这里不再赘述。最后加入dropout正则化。剩下的transposed convolution结构层与之类似,只不过在最后一层中,我们不采用BN,直接采用tanh激活函数输出生成的图片。

在上面的transposed convolution中,很多小伙伴肯定会对每一层size的变化疑惑,在这里来讲一下在TensorFlow中如何来计算每一层feature map的size。首先,在卷积神经网络中,假如我们使用一个k x k的filter对m x m x d的图片进行卷积操作,strides为s,在TensorFlow中,当我们设置padding='same'时,卷积以后的每一个feature map的height和width为[公式];当设置padding='valid'时,每一个feature map的height和width为[公式]。那么反过来,如果我们想要进行transposed convolution操作,比如将7 x 7 的形状变为14 x 14,那么此时,我们可以设置padding='same',strides=2即可,与filter的size没有关系;而如果将4 x 4变为7 x 7的话,当设置padding='valid'时,即[公式],此时s=1,k=4即可实现我们的目标。

上面的代码中我也标注了每一步shape的变化。

Discriminator

Discriminator接收一个图片,输出一个判别结果(概率)。其实Discriminator完全可以看做一个包含卷积神经网络的图片二分类器。结构如下:

实现代码如下:

上面代码其实就是一个简单的卷积神经网络图像识别问题,最终返回logits(用来计算loss)与outputs。这里没有加入池化层的原因在于图片本身经过多层卷积以后已经非常小了,并且我们加入了batch normalization加速了训练,并不需要通过max pooling来进行特征提取加速训练。

Loss Function

Loss部分分别计算Generator的loss与Discriminator的loss,和之前一样,我们加入label smoothing防止过拟合,增强泛化能力。

Optimizer

GAN中实际包含了两个神经网络,因此对于这两个神经网络要分开进行优化。代码如下:

这里的Optimizer和我们之前不同,由于我们使用了TensorFlow中的batch normalization函数,这个函数中有很多trick要注意。首先我们要知道,batch normalization在训练阶段与非训练阶段的计算方式是有差别的,这也是为什么我们在使用batch normalization过程中需要指定training这个参数。上面使用tf.control_dependencies是为了保证在训练阶段能够一直更新 moving averages。具体参考A Gentle Guide to Using Batch Normalization in Tensorflow - Rui Shu

训练

到此为止,我们就完成了深度卷积GAN的构造,接着我们可以对我们的GAN来进行训练,并且定义一些辅助函数来可视化迭代的结果。代码太长就不放上来了,可以直接去我的GitHub下载。

我这里只设置了5轮epochs,每隔100个batch打印一次结果,每一行代表同一个epoch下的25张图:

我们可以看出仅仅经过了少部分的迭代就已经生成非常清晰的手写数字,并且训练速度是非常快的。

上面的图是最后几次迭代的结果。我们可以回顾一下上一篇的一个简单的全连接层的GAN,收敛速度明显不如深度卷积GAN。

总结

到此为止,我们学习了一个深度卷积GAN,并且看到相比于之前简单的GAN来说,深度卷积GAN的性能更加优秀。当然除了MNST数据集以外,小伙伴儿们还可以尝试很多其他图片,比如我们之前用到过的CIFAR数据集,我在这里也实现了一个CIFAR数据集的图片生成,我只选取了马的图片进行训练:

刚开始训练时:

训练50个epochs:

这里我只设置了50次迭代,可以看到最后已经生成了非常明显的马的图像,可见深度卷积GAN的优势。

我的GitHub:NELSONZHAO (Nelson Zhao)

上面包含了我的专栏中所有的代码实现,欢迎star,欢迎fork。

转载请联系作者获得授权。

往期回顾:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK