卷积神经网络

来自CloudWiki
跳转至: 导航搜索

先进的卷积神经网络

概述

CIFAR-10分类是机器学习中常见的基准问题。 问题是将RGB 32x32像素图像分为10类:

飞机,汽车,鸟,猫,鹿,狗,青蛙,马,船和卡车。

有关更多详细信息,请参阅CIFAR-10页面和Alex Krizhevsky的技术报告。

https://www.cs.toronto.edu/~kriz/cifar.html

https://www.cs.toronto.edu/~kriz/learning-features-2009-TR.pdf


目标

本教程的目标是构建一个相对较小的卷积神经网络(CNN)来识别图像。 在这个过程中,本教程:

  • 突出显示了一个用于网络架构、训练和评估的规范组织。
  • 提供用于构建更大和更复杂模型的模板。

选择CIFAR-10的原因在于它足够复杂,可以运用大部分TensorFlow扩展到大型模型的能力。 同时,该模型足够小,可以快速训练,这是尝试新想法和尝试新技术的理想选择。


教程的亮点

CIFAR-10教程演示了在TensorFlow中设计更大和更复杂模型的几个重要结构:

  • 核心数学组件包括卷积(wiki),纠正线性激活(wiki),最大池化(wiki)和本地响应规范化(AlexNet论文中的第3.3章)。
  • 在训练期间可视化网络活动,包括输入图像,激活和梯度的损失和分布。
  • 用于计算学习参数的移动平均值并在评估期间使用这些平均值来提高预测性能的例程。
  • 实施学习率计划,随着时间的推移系统地减少。
  • 预取输入数据的队列,以隔离模型与磁盘延迟和昂贵的图像预处理。

我们还提供了该模型的多GPU版本,演示了:

  • 配置模型以并行训练多个GPU卡。
  • 在多个GPU之间共享和更新变量。

我们希望本教程提供一个启动点,用于在TensorFlow上构建用于视觉任务的更大的CNN。


模型架构

该CIFAR-10教程中的模型是一个由交替卷积和非线性组成的多层架构。 这些层之后是完全连接的层,通向softmax分类器。 该模型遵循Alex Krizhevsky描述的架构,前几个层次有一些差异。

该模型在GPU上的几小时训练时间内实现了约86%准确度的峰值性能。 请参阅下面的代码和详细信息。 它由1,068,298个可学习参数组成,需要大约19.5M乘法加法运算来计算单个图像的推断。


代码组织

本教程的代码位于models / tutorials / image / cifar10 /中。

文件 目的
cifar10_input.py 读取本机CIFAR-10二进制文件格式。
cifar10.py 构建CIFAR-10模型。
cifar10_train.py 在CPU或GPU上训练CIFAR-10模型。
cifar10_multi_gpu_train.py 在多个GPU上训练CIFAR-10模型。
cifar10_eval.py 评估CIFAR-10模型的预测性能。

CIFAR-10模型

CIFAR-10网络主要包含在cifar10.py中。 完整的训练图包含大约765个操作。 我们发现通过使用以下模块构建图形,我们可以使代码最具可重用性:

  • 模型输入(model inputs):inputs()和distorted_inputs()分别添加读取和预处理CIFAR图像以进行评估和训练的操作。
  • 模型预测(model prediction):inference()添加对所提供的图像执行推理(即分类)的操作。
  • 模型训练(Model training):loss()和train()添加计算损失,梯度,变量更新和可视化摘要的操作。


模型输入

模型的输入部分,由函数inputs()和distorted_inputs()构建,这些函数从CIFAR-10二进制数据文件中读取图像。这些文件包含固定的字节长度记录,因此我们使用tf.FixedLengthRecordReader。请参阅Reading Data(https://www.tensorflow.org/api_guides/python/reading_data#reading-from-files)

以了解有关Reader类如何工作的更多信息。

图像处理如下:

  • 它们被裁剪为24 x 24像素,集中用于评估或随机进行训练。
  • 它们近似变白,使模型对动态范围不敏感。

对于训练,我们还应用一系列随机失真来人为地增加数据集大小:

  • 随机翻转图像从左到右。
  • 随机扭曲图像亮度。
  • 随机扭曲图像对比度。

请参阅Image页面(https://www.tensorflow.org/api_guides/python/image)

以获取可用的扭曲列表。我们还在图像上附加了一个tf.summary.image,以便我们可以在TensorBoard中对它们进行可视化。这是验证输入是否正确构建的好方法。

Tf1-4.png

从磁盘读取图像并扭曲它们可以使用非常少量的处理时间。为了防止这些操作减慢训练速度,我们在16个独立的线程中运行它们,这些线程不断填充TensorFlow队列。


模型预测

模型的预测部分由inference()函数构造,该函数添加操作以计算预测的logits。模型的这一部分组织如下:

图层名称 描述
conv1 卷积和修正线性激活。
pool1 最大池。
norm1 本地响应归一化。
conv2 卷积和修正线性激活。
norm2 本地响应归一化。
pool2 最大池。
local3 具有修正线性激活的完全连接层。
local4 具有修正线性激活的完全连接层。
softmax_linear 线性转换以产生logits。

这是从TensorBoard生成的图形,描述了推理操作:

Tf1-5.png

   练习:inference()的输出是非标准化的logits。通过使用tf.nn.softmax,尝试编辑网络体系结构,以返回标准化预测。

inputs()和inference()函数提供执行模型评估所需的所有组件。我们现在将重点转向为训练一个模型建立操作。

   练习:inference()中的模型体系结构与cuda-convnet中指定的CIFAR-10模型略有不同。特别是,Alex的原始模型的顶层是本地连接的,并没有完全连接。尝试编辑体系结构以准确再现顶层中的本地连接体系结构。

模型训练

训练网络执行N路分类的常用方法是多项逻辑回归,也就是说 softmax回归。 Softmax回归将softmax非线性应用于网络的输出,并计算归一化预测和标签索引之间的交叉熵。对于正则化,我们还将通常的权重衰减损失应用于所有学习变量。模型的目标函数是交叉熵损失和所有这些权重衰减项的总和,由loss()函数返回。

我们使用tf.summary.scalar在TensorBoard中将其可视化:

Tf1-6.png

我们使用标准梯度下降算法训练模型(参见其他方法的Training(https://www.tensorflow.org/api_guides/python/train)),学习率随着时间的推移呈指数衰减。

Tf1-7.png

train()函数通过计算梯度和更新学习变量,来添加最小化目标所需的操作(有关详细信息,请参阅tf.train.GradientDescentOptimizer(https://www.tensorflow.org/api_docs/python/tf/train/GradientDescentOptimizer))。它返回一个操作,该操作为一批图像执行训练和更新模型所需的所有计算。

启动和训练模型

我们已经构建了模型,让我们现在启动模型,并使用脚本cifar10_train.py运行训练操作。

python cifar10_train.py
   注意:第一次在CIFAR-10教程中运行任何目标时,将自动下载CIFAR-10数据集。数据集约为160MB,因此您可能需要在第一次运行时获取一杯速溶咖啡。

你应该看到输出:

在开始训练之前填充20000 CIFAR图像的队列。这将需要几分钟。

Filling queue with 20000 CIFAR images before starting to train. This will take a few minutes.
2015-11-04 11:45:45.927302: step 0, loss = 4.68 (2.0 examples/sec; 64.221 sec/batch)
2015-11-04 11:45:49.133065: step 10, loss = 4.66 (533.8 examples/sec; 0.240 sec/batch)
2015-11-04 11:45:51.397710: step 20, loss = 4.64 (597.4 examples/sec; 0.214 sec/batch)
2015-11-04 11:45:54.446850: step 30, loss = 4.62 (391.0 examples/sec; 0.327 sec/batch)
2015-11-04 11:45:57.152676: step 40, loss = 4.61 (430.2 examples/sec; 0.298 sec/batch)
2015-11-04 11:46:00.437717: step 50, loss = 4.59 (406.4 examples/sec; 0.315 sec/batch)

...

该脚本报告每10个步骤的总损失以及处理最后一批数据的速度。一些评论:

  • 第一批数据可能非常慢(例如几分钟),因为预处理线程用20,000个处理过的CIFAR图像填充混洗队列。
  • 报告的损失是最近一批的平均损失。请记住,这种损失是交叉熵和所有权重衰减项的总和。
  • 密切关注批次的处理速度。上面显示的数字是在Tesla K40c上获得的。如果您在CPU上运行,则期望性能降低。

练习:在进行实验时,第一次训练步骤可能需要很长时间,这有时令人讨厌。尝试减少最初填满队列的图像数量。在cifar10_input.py中搜索min_fraction_of_examples_in_queue。

cifar10_train.py会定期将所有模型参数保存在检查点文件(checkpoint files(https://www.tensorflow.org/guide/saved_model))中,但不会评估模型。 cifar10_eval.py将使用检查点文件来测量预测性能(请参阅下面的评估模型)。

如果您按照前面的步骤操作,那么您现在已经开始训练CIFAR-10模型。恭喜!

从cifar10_train.py返回的终端文本提供了对模型如何训练的最小信息。我们希望在训练期间更深入地了解模型:

  • 损失真的在减少还是仅仅是噪音?
  • 模型是否提供了合适的图像?
  • 梯度,激活和权重值是否合理?
  • 目前的学习率是多少?

TensorBoard提供了一个功能,显示通过tf.summary.FileWriter定期从cifar10_train.py导出的数据。

例如,我们可以观察在训练过程中local3特征的激活分布和稀疏程度如何演变:

Tf1-8.png

随着时间的推移,个人损失函数以及总损失特别有趣。然而,由于训练所用的小批量,损失表现出相当大的噪音。在实践中,我们发现除了原始值之外,可视化他们的变化的平均值非常有用。请参阅脚本如何使用tf.train.ExponentialMovingAverage实现此目的(https://www.tensorflow.org/api_docs/python/tf/train/ExponentialMovingAverage)。


评估模型

现在让我们评估训练模型在保持数据集上的表现。该模型由脚本cifar10_eval.py评估。它使用inference()函数构造模型,并使用CIFAR-10评估集中的所有10,000个图像。它计算精度为1:顶部预测与图像的真实标签匹配的频率。

为了监视模型在训练期间如何改进,评估脚本定期在cifar10_train.py创建的最新检查点文件上运行

python cifar10_eval.py

注意不要在同一GPU上运行评估和训练二进制文件,否则可能会耗尽内存。考虑在单独的GPU上运行评估(如果可用),或者在同一GPU上运行评估时暂停训练二进制文件。

你应该看到输出:

2015-11-06 08:30:44.391206: precision @ 1 = 0.860
...

该脚本仅定期返回精度@ 1 - 在这种情况下,它返回86%的准确性。 cifar10_eval.py还会导出可在TensorBoard中显示的摘要。这些摘要提供了在评估期间对模型的进一步了解。

训练脚本计算所有学习变量的变化平均值(the moving average version )。评估脚本用移变化平均值替换所有学习的模型参数。此替换可在评估时提升模型性能。

练习:使用平均参数,可以通过精度@ 1测量,将预测性能提高约3%。编辑cifar10_eval.py以不使用模型的平均参数并验证预测性能下降。


下一步

如果您现在对开发和训练自己的图像分类系统感兴趣,我们建议您使用本教程并更换组件以解决图像分类问题。

练习:下载街景房号(SVHN)数据集(http://ufldl.stanford.edu/housenumbers/)。 分叉CIFAR-10教程并交换SVHN作为输入数据。 尝试调整网络架构以提高预测性能。

参考文档:https://www.tensorflow.org/tutorials/deep_cnn

返回 人工智能