from:https://www.sohu.com/a/159976204_717210

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 地址:NELSONZHAO/zhihu

建议将代码 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,它对于图片的生成会取得更好的效果。

GAN初步——本质上就是在做优化,对于生成器传给辨别器的生成图片,生成器希望辨别器打上标签 1,体现在loss上!的更多相关文章

  1. 服务器小白的我,是如何将 node+mongodb 项目部署在服务器上并进行性能优化的

    前言 本文讲解的是:做为前端开发人员,对服务器的了解还是小白的我,是如何一步步将 node+mongodb 项目部署在阿里云 centos 7.3 的服务器上,并进行性能优化,达到页面 1 秒内看到 ...

  2. 主要从架构上来做优化,负载均衡、CDN、静态化、数据库的水平切割和纵向切割、读写分离、分布式缓存着手

    语言知识一种工具,甚至技术本身也只是一种工具,本身并不值钱,关键在于用于何种行业,产生了什么价值. 但从语言来看,我个人更喜欢php,然后是C#,然后是java从框架而言,先是java,然后C#,再次 ...

  3. mysql在高内存、IO利用率上的几个优化点 (sync+fsync) 猎豹移动技术博客

    http://dev.cmcm.com/archives/107 Posted on 2014年10月16日 by liuding | 7条评论 以下优化都是基于CentOS系统下的一些优化整理,有不 ...

  4. 【官网翻译】性能篇(四)为电池寿命做优化——使用Battery Historian分析电源使用情况

    前言 本文翻译自“为电池寿命做优化”系列文档中的其中一篇,用于介绍如何使用Battery Historian分析电源使用情况. 中国版官网原文地址为:https://developer.android ...

  5. MySQL在高内存、IO利用率上的几个优化点

    以下优化都是基于CentOS系统下的一些MySQL优化整理,有不全或有争议的地方望继续补充完善. 一.mysql层面优化 1. innodb_flush_log_at_trx_commit 设置为2设 ...

  6. MySQL 上亿大表优化实践

    目录 背景 分析 select xxx_record语句 delete xxx_record语句 测试 实施 索引优化后 delete大表优化为小批量删除 总结 背景 XX实例(一主一从)xxx告警中 ...

  7. 乔布斯在位时,库克实质上已经在做CEO的工作了:3星|《蒂姆·库克传》

    “ 一些人认为艾夫是接替乔布斯的热门人选,他对苹果的原晃和产品来说至关重要,但他本人对管理企业却毫无兴趣.艾夫想继统做设计.在苹果,他拥有所有设计师都梦寐以求的工作环境——无限的资源和自由创作的空间. ...

  8. FMX相当于在界面上自己又做了一个小操作系统

    FMX的自画界面我也不看好,比如复制粘贴,太丑了,系统做得很好很精细的复制粘贴界面,就是无法调出,比如MIUI,复制粘贴还能有个放大镜,可以选择到屏幕边缘的文字,可以选择剪贴板内多个可粘贴的文字:还有 ...

  9. 20165221-week2课上测试补做

    week2-课上测试补做 测试一: 参考附图代码,编写一个程序 "week0201学号.c",判断一下你的电脑是大端还是小端. 提交运行结果"学号XXXX的笔记本电脑是X ...

随机推荐

  1. [Java][读书笔记]多线程编程

    前言:最近复习java,发现一本很好的资料,<J​a​v​a​2​参​考​大​全​ ​(​第​五​版​)​> ​ ​H​e​r​b​e​r​t​.Schildt.书比较老了,06年的,一些 ...

  2. MySQL主从复制——主库已有数据的解决方案

    在上篇文章中我们介绍了基于Docker的Mysql主从搭建,一主多从的搭建过程就是重复了一主一从的从库配置过程,需要注意的是,要保证主从库my.cnf中server-id的唯一性.搭建完成后,可以在主 ...

  3. VMware部署ubuntu后开机提示piix4_smbus: Host SMBus controller not enabled!

    在虚拟机部署ubuntu10.04-server,每次启动完成之后,出现“piix4_smbus0000:00:07.3: Host SMBus controller not enabled!”提示信 ...

  4. 将 Windows VM 移到其他 Azure 订阅或资源组

    本文逐步说明如何在资源组或订阅之间移动 Windows VM. 如果最初在个人订阅中创建了 VM,现在想要将其移到公司的订阅以继续工作,则在订阅之间移动 VM 可能很方便. Important 不可在 ...

  5. 使用 Azure PowerShell 管理 Azure 虚拟网络和 Windows 虚拟机

    Azure 虚拟机使用 Azure 网络进行内部和外部网络通信. 本教程介绍了如何在虚拟网络中创建多个虚拟机 (VM),以及如何在虚拟机之间配置网络连接. 你将学习如何执行以下操作: 创建虚拟网络 创 ...

  6. Saltstack安装配置过程

    一.安装配置 1.服务器配置情况 三台服务器,均需要关闭iptables和selinux(否则salt执行指令无效) master: 192.168.60.139 centos slave: 192. ...

  7. Qt与PyQT中设置ToolBar在AllowedArea的显示

    因为个人对传统的软件GUI界面不是太喜欢,最近又在学习Qt和PyQt5,所以就有了设置ToolBar在窗口的不同地方的想法,经过浪里淘沙,最终在Qt官网里找到了,原来再添加toolBar的时候是由设置 ...

  8. IE 出现stack overflow 报错的原因归纳

    1. 重定义了系统的触发事件名称作为自定义函数名如:  onclick / onsubmit ...  都是系统保留的事件名称,不允许作为重定义函数名称: 2. IE缓存满了,无法写入.解决办法:清空 ...

  9. Windows窗体数据抓取详解

    最近在客户项目上刚好遇到一个问题,项目需求是要获取某台机床的实时状态,问题点刚好就在于该机床不是传统意义上的数控机床,也不是PLC控制器,只有一个上传下载程序文件的应用程序,上面刚好有几个按钮可以大概 ...

  10. SDN 第四次作业

    阅读 了解SDN控制器的发展 http://www.sdnlab.com/13306.html http://www.docin.com/p-1536626509.html 了解ryu控制器 http ...