生成手写字体,手写制作
chanong
|安妮(Anne) 编辑自O'Reilly
量子比特出品| 公众号QbitAI
生成对抗网络是过去20 年来机器学**领域最酷的想法。第——章
自从Ian Goodfellow 和蒙特利尔大学的同事两年前提出这一概念以来,生成对抗网络(GAN) 的发展势头一直强劲。
在O'Reilly 上发表的这篇文章中,作者为初学者解答了有关GAN 基础知识的问题,并教大家如何使用GAN 创建一个可以生成手写数字的程序。
本教程由Jon Bruner(管理硬件、互联网、制造和电子领域出版物的O'Reilly 编辑团队成员)和Adit Deshpande(加州大学洛杉矶分校计算机科学专业二年级学生)创建。
Qubit 提示:本文中描述的所有代码都可以在GitHub 上下载。
https://github.com/jonbruner/generative-adversarial-networks
立即开始您的GAN 之旅——
简介GAN 是学**创建类似于已知输入数据的合成数据的神经网络。研究人员现在能够使用GAN 来合成从卧室到专辑封面的照片序列,并且它们还表现出了反映高阶语义逻辑的不可思议的能力。
虽然这些例子相当复杂,但构建一个可以生成简单图像的GAN 并不困难。在本教程中,您将从头开始学**如何构建一个分析手写数字图像的GAN,以及如何训练它生成新图像。其实说白了,就是教神经网络如何写字。
上图是本教程中构建的GAN 生成的示例图像。
GAN 架构GAN 包括两种模型:生成模型和判别模型。
判别模型是一种分类器,用于确定特定图像是数据集中的真实图像还是人工创建的假图像。这基本上是卷积神经网络(CNN)形式的二元分类器。
生成模型通过反卷积神经网络将随机输入值转换为图像。
在几次训练迭代的过程中,鉴别器和生成器的权重和偏差通过反向传播进行训练。鉴别器学**如何从生成器生成的一堆假数字图像中找到真正的数字图像。同时,生成器学**如何通过鉴别器的反馈生成欺骗性图像,从而阻止鉴别器识别。
准备工作我们将创建一个可以生成手写数字的GAN,旨在愚弄最好的分类器(当然包括人类)。使用Google 的开源TensorFlow 在GPU 上轻松训练神经网络。
TensorFlow下载地址:
https://www.tensorflow.org/
我们希望您在学**本教程之前对TensorFlow 有一定的了解。如果您以前没有遇到过这种情况,我们建议您先阅读相关文章和教程。
加载MNIST 数据首先,我们需要将一系列真实的手写数字图像输入到分类器中。这可以被认为是判别器的参考。这里使用的深度学**基准数据集MNIST是一个手写数字图片的数据库,其中每张图片都是0到9的单个数字,并且每张图片都有抗锯齿,这是一张灰度图像。该数据库包含由美国国家标准技术研究所收集、由人口普查局员工和高中生编写的70,000 张数字图像。
MNIST 数据集链接(英文):
http://yann.lecun.com/exdb/mnist/
让我们首先导入TensorFlow 和其他有用的数据库。首先,我们需要使用TensorFlow 的便捷函数导入MNIST 图像。该函数也可以称为read_data_sets。
您创建的MNIST 变量包含图像和标签,数据集分为训练集和验证集(尽管标签不是本教程的关注点)。可以通过调用mnist中的next_batch来获取,所以我们加载图片来看一下。
该图像最初格式化为784 像素列,可以转换为28x28 像素图像并在PyPlot 中显示。
如果我们再次运行上面的单元格,我们将看到来自MNIST 训练集的不同图像。
判别网络判别器采用图像大小为28x28x1 的输入图像,并返回单个标量值,该标量值描述输入图像—— 的置信度,并确定其是否来自MNIST 图像的卷积神经网络。集或发电机。
判别器的结构与TensorFlow中的样本CNN分类模型密切相关。它有两个具有5 5 像素特征的卷积层和两个计算图像中每个像素的权重增量的全连接层。
创建神经网络后,您通常需要初始化权重和偏差,您可以使用tf.get_variable 完成该任务。权重用截断正态分布初始化,偏差用0 初始化。
tf.nn.conv2d() 是TensorFlow 的标准卷积函数。它包含四个参数:第一个参数是输入图像(输入体积)(本例中为28x28像素图像),第二个参数是滤波器/权重矩阵,最后:您还可以更改“stride”和“padding”的卷积。这两个参数控制输出图像的大小。
事实上,上面是一个常规的简单二元分类器,所以如果你是CNN 的新手,你应该熟悉它。
定义了判别器之后,我们需要回顾一下生成模型。模型的整个结构基于Tim O’Shea 编写的简单生成器代码。
代码链接:
https://github.com/osh/KerasGAN
事实上,您可以将生成器视为一种反卷积神经网络。判别器是典型的CNN,可以将2D 或3D 像素值矩阵转换为概率。然而,生成器需要d 维向量,并且需要转换为28*28 图像。 ReLU 和批量归一化通常用于稳定每一层的输出。
该神经网络使用三个卷积层和插值,直到形成28*28 像素的图像。
向输出层添加了tf.sigmoid() 激活函数。这会压缩灰度以显示白色或黑色,从而产生更清晰的图像。
生成样本图像定义了生成器和判别函数后,我们来看看未经训练的生成器会生成什么样的样本。
首先,打开TensorFlow 并为生成器创建一个占位符。占位符的形式为None x z_dimensions,其中关键字None 表示其值可以在会话期间确定。通常,您使用None 作为第一个维度,因此批量大小是可变的。如果使用关键字None,则不需要指定batch_size。
接下来,创建一个变量来保存生成器的输出( generated_image_output ) 并使用输入随机噪声向量对其进行初始化。 np.random.normal() 函数具有三个参数,前两个参数定义正态分布的平均值和标准差,最后一个定义向量的形状(1 x 100) 。
接下来,您需要初始化所有变量,将z_batch 放入占位符中,并运行这部分代码。
sess.run() 函数有两个参数。第一个参数称为“get”参数,定义计算所需的值。在这种情况下,我想看看生成器输出什么。如果您查看最后一个代码片段,您可以看到生成函数的输出存储在generated_image_output 中。使用generated_image_output 作为第一个参数。
第二个参数对应输入字典,可以在运行时替换计算图。这就是您在占位符中输入的内容。在此示例中,我们需要在之前定义的z_placeholder 中输入z_batch 变量,并在PyPlot 中将图像大小调整为28*28 像素。
看起来是正确的噪音。接下来,我们需要训练生成网络的权重和偏差,将随机数转换为可辨别的数字。我们再看一下损失函数和优化。
训练GAN 由于存在两个损失函数,构建和调试GAN 变得很复杂。一种鼓励生成器创建更好的图像,另一种鼓励标识符区分哪些图像是真实的,哪些是由生成器生成的。
同时训练生成器和鉴别器。如果鉴别器善于区分图像来自何处,则生成器还可以适当调整权重和偏差以产生更真实的图像。
该网络的输入和输出是:
因此,首先让我们考虑一下您的网络需要什么。判别器的目标是将MNIST 图像正确标记为真,而判别器生成的标签为假。计算鉴别器的两个损失。一种是损失Dx和1(代表MNIST真实图像),另一种是损失Dg和0(代表生成图像)。在TensorFlow的tf.nn.sigmoid_cross_entropy_with_logits()函数中运行该函数,计算Dx和0以及Dg和1之间的交叉熵损失。
sigmoid_cross_entropy_with_logits 在未缩放的值上运行,而不是在0 和1 之间的概率值。查看鉴别器的最后一行。这里没有softmax或sigmoid函数层。如果鉴别器变得“饱和”,或者有足够的信心在给定生成的图像的情况下返回0,则鉴别器的梯度下降变得毫无用处。
tf.reduce_mean() 函数选择交叉熵函数返回的矩阵中所有元素的平均值。这是一种将损失减少到单个标量值而不是向量或矩阵的方法。
接下来,让我们设置生成器的损失函数。我希望生成的网络图像能够欺骗鉴别器。给定生成的图像,判别器可以输出接近1 的值并计算Dg 和1 之间的损失。
现在损失函数已经完成,我们需要定义优化器。生成网络优化器只需要升级生成器权重,而不需要升级判别器。同样,在训练判别器时,我们需要修改生成器的权重。
为了使它们不同,我们需要创建两个变量列表。一个包含鉴别器权重和偏差,另一个包含生成器权重和偏差。因此,命名TensorFlow 变量需要仔细考虑。
接下来,您需要制定两个优化器,通常选择具有自适应学**率和动量的Adam 优化算法。调用Adam 最小值函数并指定要更新的变量——。这是训练生成器时的生成器权重和偏差,以及训练判别器时的判别器权重和偏差。
我们为鉴别器设置了两种不同的训练方案。一种使用真实图像来训练鉴别器,另一种使用生成的“假图像”来训练鉴别器。有时你需要使用不同的学**率或单独使用它们来调整学**的其他方面。
你说的其他方面是什么意思?代码下载链接:
https://github.com/jonbruner/ezgan
GAN 收敛很困难,通常需要很长时间来训练。 TensorBoard 允许您跟踪训练过程。您可以绘制标量属性(例如损失)、查看训练中的样本图像以及查看神经网络内的拓扑。
想了解更多关于TensorBoard 的信息吗?链接:
https://www.tensorflow.org/get_started/summaries_and_tensorboard
如果您在自己的计算机上运行此脚本,请确保包含以下单元格:接下来,在终端窗口中运行tensorboard —logdir=tensorboard/,并在浏览器中输入http://localhost:6006以打开TensorBoard。
接下来,给鉴别器一些简单的原始训练迭代。这种方法有助于形成对生成器有用的梯度。
接下来,继续主训练循环。在训练生成器时,我们需要向生成器输入一个随机z 向量,并将其输出传递给判别器(这是前面定义的Dg 变量)。生成器的权重和偏差的改变主要是为了产生可以欺骗鉴别器的图像。
要训练判别器,请从MNIST 数据集中为其提供一组正例,并将它们用作负例,以便在生成的图像上再次训练判别器。
训练GAN 通常需要很长时间,因此如果您是本教程的新手,我们建议您暂时不要运行此代码块。但是,您可以首先运行以下代码块来生成预训练模型。
如果您想自己运行这段代码,请做好长时间等待的准备。在相对较快的GPU 上大约需要3 小时,在桌面CPU 上可能需要更长的时间10 倍。
所以我建议你跳过上面的内容,直接运行下一个单元格。您可以将经过10 小时训练的模型加载到快速GPU 机器上,并尝试经过训练的GAN。
训练并不容易众所周知,训练GAN 很困难。如果没有正确的超参数、网络架构和训练过程,鉴别器将压倒生成器。
一种常见的失败模式是鉴别器压倒了生成器,生成的图像被明确定义为假图像。如果判别器是绝对确定的,则生成器就没有斜率可以减小。这就是为什么我们构建一个产生未缩放输出的判别器,而不是通过sigmoid 函数将输出推至0 或1。
在另一种常见的故障模式(模态崩溃)中,生成器发现并利用鉴别器中的弱点。当生成大量相似图像时,无论生成器的输入z 变量如何,都可以识别这一点。模态崩溃可以通过“加强”鉴别器来修复,例如通过调整训练速率或重新配置层。
研究人员已经找到了几种帮助构建稳定GAN 的小方法。
想让你的GAN也稳定吗?代码链接:
https://github.com/soumith/ganhacks
结论GAN 具有重塑我们每天互动的数字世界的巨大潜力。这个领域还很年轻,因此下一个新的GAN 发现可能来自您。
附加信息1. Ian Goodfellow 及其合作伙伴于2014 年发表的GAN 论文
论文链接:
https://arxiv.org/abs/1406.2661
2. Goodfellow 最近的教程揭开了GAN 的神秘面纱。
教程链接:
https://arxiv.org/abs/1701.00160
3. Alec Radford、Luke Metz、Soumith Chintala 等人的论文。它介绍了本教程生成器中使用的复杂GAN 的基本结构。
论文链接:
https://arxiv.org/abs/1511.06434
GitHub 上的DCGAN 代码:
https://github.com/Newmu/dcgan_code
【就这样】
笔记
量子比特组建了一个针对自动驾驶相关领域学**的学生和一线工程师的自动驾驶技术小组。任何人都可以添加量子比特微信(qbitbot),关注“自动驾驶”申请参与~
招聘
Qubit正在招聘编辑、记者、运营、产品等职位,办公地点将位于北京中关村。相关详情请在公众号对话界面回复“招募”。