开发 | 看完立刻理解GAN!初学者也没关系

AI 科技评论按:本文原作者天雨粟,原文载于作者的知乎专栏——机器不学习,经授权发布。

前言

GAN 从 2014 年诞生以来发展的是相当火热,比较著名的 GAN 的应用有 Pix2Pix、CycleGAN 等。本篇文章主要是让初学者通过代码了解 GAN 的结构和运作机制,对理论细节不做过多介绍。我们还是采用 MNIST 手写数据集(不得不说这个数据集对于新手来说非常好用)来作为我们的训练数据,我们将构建一个简单的 GAN 来进行手写数字图像的生成。

认识 GAN

GAN 主要包括了两个部分,即生成器 generator 与判别器 discriminator。生成器主要用来学习真实图像分布从而让自身生成的图像更加真实,以骗过判别器。判别器则需要对接收的图片进行真假判别。在整个过程中,生成器努力地让生成的图像更加真实,而判别器则努力地去识别出图像的真假,这个过程相当于一个二人博弈,随着时间的推移,生成器和判别器在不断地进行对抗,最终两个网络达到了一个动态均衡:生成器生成的图像接近于真实图像分布,而判别器识别不出真假图像,对于给定图像的预测为真的概率基本接近 0.5(相当于随机猜测类别)。

对于 GAN 更加直观的理解可以用一个例子来说明:造假币的团伙相当于生成器,他们想通过伪造金钱来骗过银行,使得假币能够正常交易,而银行相当于判别器,需要判断进来的钱是真钱还是假币。因此假币团伙的目的是要造出银行识别不出的假币而骗过银行,银行则是要想办法准确地识别出假币。

因此,我们可以将上面的内容进行一个总结。给定真 = 1,假 = 0,那么有:

  • 对于给定的真实图片(real image),判别器要为其打上标签 1;
  • 对于给定的生成图片(fake image),判别器要为其打上标签 0;
  • 对于生成器传给辨别器的生成图片,生成器希望辨别器打上标签 1。

有了上面的直观理解,下面就让我们来实现一个 GAN 来生成手写数据吧!还有一些细节会在代码部分进行介绍。

说明

  • TensorFlow 1.0
  • Python 3
  • Jupyter Notebook
  • GitHub 地址: https://github.com/NELSONZHAO/zhihu/tree/master/mnist_gan

建议将代码 pull 下来,有部分代码实现没有写在文章中。

代码部分

数据加载与查看

数据我们使用 TensorFlow 中给定的 MNIST 数据接口。

在构建模型之前,我们首先来看一下我们需要完成的任务:

  • Inputs
  • generator
  • discriminator
  • 定义参数
  • loss & optimizer
  • 训练模型
  • 显示结果

输入 inputs

输入函数主要来定义真实图片与生成图片两个 tensor。

定义生成器

我们的生成器结构如下:

我们使用了一个采用 Leaky ReLU 作为激活函数的隐层,并在输出层加入 tanh 激活函数。

下面是生成器的代码。注意在定义生成器和判别器时,我们要指定变量的 scope,这是因为 GAN 中实际上包含生成器与辨别器两个网络,在后面进行训练时是分开训练的,因此我们要把 scope 定义好,方便训练时候指定变量。

在这个网络中,我们使用了一个隐层,并加入 dropout 防止过拟合。通过输入噪声图片,generator 输出一个与真实图片一样大小的图像。

在这里我们的隐层激活函数采用的是 Leaky ReLU(中文不知道咋翻译),这个函数在 ReLU 函数基础上改变了左半边的定义。

图片来自维基百科。Andrej Karpathy 在 CS231n 中也提到有模型通过这个函数取得了不错的效果。

由于 TensorFlow 中没有这个函数的实现,在这里我们通过函数定义实现了 Leaky ReLU,其中 alpha 是一个很小的数。在输出层我们使用 tanh 函数,这是因为 tanh 在这里相比 sigmoid 的结果会更好一点(在这里要注意,由于生成器的生成图片像素限制在了 (-1, 1) 的取值之间,而 MNIST 数据集的像素区间为 [0, 1],所以在训练时要对 MNIST 的输入做处理,具体见训练部分的代码)。到此,我们构建好了生成器,它通过接收一个噪声图片输出一个与真实图片一样 size 的图像。

定义判别器

判别器的结构如下:

判别器接收一张图片,并判断它的真假,同样隐层使用了 Leaky ReLU,输出层为 1 个结点,输出为 1 的概率。代码如下:

在这里,我们需要注意真实图片与生成图片是共享判别器的参数的,因此在这里我们留了 reuse 接口来方便我们后面调用。

定义参数

img_size 是我们真实图片的 size=32*32=784。

smooth 是进行 Label Smoothing Regularization 的参数,在后面会介绍。

构建网络

接下来我们来构建我们的网络,并获得生成器与判别器返回的变量。

我们分别获得了生成器与判别器的 logits 和 outputs。注意真实图片与生成图片是共享参数的,因此在判别器输入生成图片时,需要 reuse 参数。

定义 Loss 和 Optimizer

有了上面的 logits,我们就可以定义我们的 loss 和 Optimizer。在这之前,我们再来回顾一下生成器和判别器各自的目的是什么:

  • 对于给定的真实图片,辨别器要为其打上标签 1;
  • 对于给定的生成图片,辨别器要为其打上标签 0;
  • 对于生成器传给辨别器的生成图片,生成器希望辨别器打上标签 1。

我们来把上面这三句话转换成代码:

d_loss_real 对应着真实图片的 loss,它尽可能让判别器的输出接近于 1。在这里,我们使用了单边的 Label Smoothing Regularization,它是一种防止过拟合的方式,在传统的分类中,我们的目标非 0 即 1,从直觉上来理解的话,这样的目标不够 soft,会导致训练出的模型对于自己的预测结果过于自信。因此我们加入一个平滑值来让判别器的泛化效果更好。

d_loss_fake 对应着生成图片的 loss,它尽可能地让判别器输出为 0。

d_loss_real 与 d_loss_fake 加起来就是整个判别器的损失。

而在生成器端,它希望让判别器对自己生成的图片尽可能输出为 1,相当于它在于判别器进行对抗。

下面我们定义了优化函数,由于 GAN 中包含了生成器和判别器两个网络,因此需要分开进行优化,这也是我们在之前定义 variable_scope 的原因。

训练模型

由于训练部分代码太长,我在这里就不贴出来了,请前往我的 GitHub 下载代码。在训练部分,我们记录了部分图像的生成过程,并记录了训练数据的 loss 变化。

我们将整个训练过程的 loss 变化绘制出来:

从图中可以看出来,最终的判别器总体 loss 在 1 左右波动,而 real loss 和 fake loss 几乎在一条水平线上波动,这说明判别器最终对于真假图像已经没有判别能力,而是进行随机判断。

查看过程结果

我们在整个训练过程中记录了 25 个样本在不同阶段的 samples 图像,以序列化的方式进行了保存,我们的将 samples 加载进来。samples 的 size=epochs x 2 x n_samples x 784,我们的迭代次数为 300 轮,25 个样本,因此,samples 的 size=300 x 2 x 25 x 784。我们将最后一轮的生成结果打印出来:

这就是我们的 GAN 通过学习真实图片的分布后生成的图像结果。

那么有同学可能会问了,我们如果想要看这 300 轮中生成图像的变化是什么样该怎么办呢?因为我们已经有了 samples,存储了每一轮迭代的结果,我们可以挑选几次迭代,把对应的图像打出来:

这里我挑选了第 0, 5, 10, 20, 40, 60, 80, 100, 150, 250 轮的迭代效果图,在这个图中,我们可以看到最开始的时候只有中间是白色,背景黑色块中存在着很多噪声。随着迭代次数的不断增加,生成器制造 “假图” 的能力也越来越强,它逐渐学得了真实图片的分布,最明显的一点就是图片区分出了黑色背景和白色字符的界限。

生成新的图片

如果我们想重新生成新的图片呢?此时我们只需要将我们之前保存好的模型文件加载进来就可以啦。

总结

整篇文章基于 MNIST 数据集构造了一个简单的 GAN 模型,相信小伙伴看完代码会对 GAN 有一个初步的了解。从最终的模型结果来看,生成的图像能够将背景与数字区分开,黑色块噪声逐渐消失,但从显示结果来看还是有很多模糊区域的。

对于这里的图片处理,相信很多小伙伴会想到卷积神经网络,那么后面我们还会将生成器和判别器改为卷积神经网络来构造深度卷积 GAN,它对于图片的生成会取得更好的效果。

如果觉得不错,请给 GitHub 点个 Star 吧~

原文发布于微信公众号 - AI科技评论(aitechtalk)

原文发表时间:2017-07-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏小小挖掘机

推荐系统遇上深度学习(二)--FFM模型理论和实践

推荐系统遇上深度学习系列: 推荐系统遇上深度学习(一)--FM模型理论和实践 1、FFM理论 在CTR预估中,经常会遇到one-hot类型的变量,one-ho...

8474
来自专栏GAN&CV

训练GAN的16个trick

本文转载自:https://mp.weixin.qq.com/s/d_W0O7LNqlBuZV87Ou9uqw 新智元公众号 本文来自ICCV 20...

2092
来自专栏新智元

不可错过的 GAN 资源:教程、视频、代码实现、89 篇论文下载

【新智元导读】这是一份生成对抗(神经)网络的重要论文以及其他资源的列表,由 Holger Caesar 整理,包括重要的 workshops,教程和博客,按主题...

76210
来自专栏机器之心

教程 | 在Keras上实现GAN:构建消除图片模糊的应用

选自Sicara Blog 作者:Raphaël Meudec 机器之心编译 参与:陈韵竹、李泽南 2014 年,Ian Goodfellow 提出了生成对抗网...

4113
来自专栏AI研习社

看完立刻理解 GAN!初学者也没关系

前言 GAN 从 2014 年诞生以来发展的是相当火热,比较著名的 GAN 的应用有 Pix2Pix、CycleGAN 等。本篇文章主要是让初学者通过代码了...

3215
来自专栏Deep learning进阶路

深度学习论文(八)---DeepLabV1-SEMANTIC IMAGE SEGMENTATION WITH DEEP CONVOLUTIONAL NETS AND FULLY CONNECTED C

注:本篇算是半讲解半翻译吧,我真的觉得这篇论文写的很难理解.......可能是我水平不够,也可能作者省略了一些具体信息,主要是提供了他的idea吧。 但是De...

7181
来自专栏大数据文摘

手把手 | OpenAI开发可拓展元学习算法Reptile,能快速学习(附代码)

1223
来自专栏AI2ML人工智能to机器学习

矩有四子

在讨论一些方法的几何意义之前需要理解一下线性代数的一个基础知识,就是矩阵和它代表的空间的含义。

893
来自专栏机器之心

教程 | 详解如何使用Keras实现Wassertein GAN

选自Deeply Random 机器之心编译 参与:晏奇、李泽南 在阅读论文 Wassertein GAN 时,作者发现理解它最好的办法就是用代码来实现其内容。...

42710
来自专栏PPV课数据科学社区

机器学习系列:(四)从线性回归到逻辑回归

从线性回归到逻辑回归 在第2章,线性回归里面,我们介绍了一元线性回归,多元线性回归和多项式回归。这些模型都是广义线性回归模型的具体形式,广义线性回归是一种灵活的...

4916

扫码关注云+社区