开发 | 看完立刻理解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 条评论
登录 后参与评论

相关文章

来自专栏SIGAI学习与实践平台

基于内容的图像检索技术综述 传统经典方法

原创声明:本文为 SIGAI 原创文章,仅供个人学习使用,未经允许,不得转载,不能用于商业目的。

1437
来自专栏技术专栏

Python3入门机器学习(七)- PCA

PCA(Principal Component Analysis):也是一个梯度分析的应用,不仅是机器学习的算法,也是统计学的经典算法

873
来自专栏大数据挖掘DT机器学习

基于图像视觉词汇的文本分类方法(完整项目)

一年多以前我脑子一热,想做一款移动应用:一款给学生朋友用的“错题集”应用,可以将错题拍照,记录图像的同时,还能自动分类。比如拍个题目,应用会把它自动分类为"物理...

3175
来自专栏人工智能LeadAI

译文 | 与TensorFlow的第一次接触 第五章:多层神经网络

本章中,我们继续使用之前章节中的MNIST数字识别问题,与读者一起编码实现一个简单的深度学习神经网络。 如我们所了解的,一个深度学习神经网络由相互叠加的多层组成...

3244
来自专栏算法channel

深度学习|卷积神经网络(CNN)介绍(后篇)

01 — 回顾 昨天介绍了CNN的卷积操作,能减少权重参数的个数,卷积操作涉及到三个超参数: 深度(Depth) 步长(Stride) 零填充(Zero-pad...

4065
来自专栏AI研习社

「Deep Learning」读书系列分享第二章:线性代数 | 分享总结

「Deep Learning」这本书是机器学习领域的重磅书籍,三位作者分别是机器学习界名人、GAN 的提出者、谷歌大脑研究科学家 Ian Goodfellow,...

3215
来自专栏智能算法

机器学习三人行(系列十)----机器学习降压神器(附代码)

系列九我们从算法组合的角度一起实战学习了一下组合算法方面的知识,详情戳下链接: 机器学习三人行(系列九)----千变万化的组合算法(附代码) 但是,我们也知道算...

3689
来自专栏Spark学习技巧

【深度学习】②--细说卷积神经网络

1. 神经网络与卷积神经网络 先来回忆一下神经网络的结构,如下图,由输入层,输出层,隐藏层组成。每一个节点之间都是全连接,即上一层的节点会链接到下一层的每一个节...

3578
来自专栏程序生活

文本分类(下)-卷积神经网络(CNN)在文本分类上的应用

原先写过两篇文章,分别介绍了传统机器学习方法在文本分类上的应用以及CNN原理,然后本篇文章结合两篇论文展开,主要讲述下CNN在文本分类上的应用。前面两部分内容主...

712
来自专栏企鹅号快讯

卷积神经网络CNN原理详解(一)——基本原理

作者:Charlotte77数学系的数据挖掘民工 博客专栏:http://www.cnblogs.com/charlotte77/ 个人公众号:Charlott...

2625

扫描关注云+社区