页面树结构

2017-11-09 ApacheCN 开源组织,第二期邀请成员活动,一起走的更远 : http://www.apachecn.org/member/209.html


MachineLearning 优酷地址 : http://i.youku.com/apachecn

转至元数据结尾
转至元数据起始

注意:本教程面向TensorFlow 的高级用户,并假定用户有机器学习相关领域的专业知识和经验。

概述

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

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

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

目标

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

  1. 重点介绍规范的网络架构,训练和进行评估。
  2. 提供一个用于构建更大和更复杂的模型样例。

选择CIFAR-10是因为它的复杂程度足以用来检验TensorFlow中的大部分功能,并可将其扩展为更大的模型。同时,该模型足够小,可以快速训练,这对于尝试新想法和尝试新技术是非常理想的。

教程重点

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

我们还提供了一个多GPU版本 的模型:

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

我们希望本教程为TensorFlow上的视觉任务构建更大的CNN提供一个起点。

模型架构

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

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

 

代码

本教程的代码位于 tensorflow_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个操作。我们发现我们可以通过使用以下模块构建图来使代码实现最好的复用率:

  1. 模型输入:inputs()distorted_inputs()分别用于读取CIFAR的图像并进行预处理,做为后续评估和训练的输入。
  2. 模型预测: inference() 添加对提供的图像执行推论的操作,如对图像进行分类。
  3. 模型训练: loss()、train() 等操作计算损失,梯度,变量更新和可视化模型概述。

模型输入

模型的输入部分由inputs()和distorted_inputs()函数构建,并从CIFAR-10二进制数据文件读取图像。这些文件包含固定的字节长度,所以我们使用 tf.FixedLengthRecordReader。请参阅 Reading Data 以了解有关Reader类的工作原理。

图像的处理如下:

  • 它们被裁剪成24 x 24像素,裁剪中心区域用于评估或随机裁剪用于训练。
  • 对它们进行白化处理 ,使模型对动态范围变化不敏感。

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

请参阅 Images页面列表中了解可用变化。我们也将 tf.summary.image附加到图像,以便我们可以在TensorBoard中可视化它们。这是验证被构建的输入是否正确的良好做法。

从磁盘读取图像并变化需要一定的处理时间。为了防止这些操作减慢训练,我们在16个独立的线程中运行它们,它们不断地填充TensorFlow 队列

模型预测

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

图层名称描述
conv1卷积修正线性激活。
pool1最大池化
norm1局部响应规一化
conv2卷积修正线性激活。
norm2局部响应规一化
pool2最大池化。
local3具有线性激活的全连接层
local4具有线性激活的全连接层
softmax_linear线性变换输出logits

这是从TensorBoard生成的用来描述推理过程操作的图:

练习inference的输出是未归一化的logits。尝试使用tf.nn.softmax编辑网络架构以返回归一化预测 。

inputs()inference()函数提供对模型进行评估的必要组成部分。我们现在将重点转移到构建模型的训练上。

练习:inference()模型架构与cuda-convnet中指定的CIFAR-10模型略有不同。尤其Alex原始模型的顶层是局部连接的,并没有全连接。尝试编辑架构以精确地复现顶层中的局部连接的体系结构。

模型训练

训练网络进行N个分类的通常方法是 多项式Logistic回归,又称softmax回归。Softmax回归将softmax非线性应用于网络的输出,并计算归一化预测与标签的one-hot编码之间的交叉熵。对于正则化,我们还将权重衰减损失运用到所有学习变量中 。模型的目标函数是交叉熵损失和所有这些权重衰减项的和。通过loss()函数返回。

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

我们使用标准梯度下降 算法(参见训练其他方法)训练模型 ,学习率随时间呈指数衰减

train()函数通过计算渐变和更新学习变量来最小化目标函数(详见tf.train.GradientDescentOptimizer )。它返回一个对一批图像执行所有计算的操作步骤,以便训练并更新模型。

 

启动和训练模型

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

python cifar10_train.py 

注意:首次在CIFAR-10教程中运行任何目标时,CIFAR-10数据集将自动下载。数据集大约160MB,所以首次运行时你可以泡杯咖啡。

你应该看到输出:

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周期性的将所有模型参数保存在 检查点文件中, 但不会对模型进行评估。cifar10_eval.py使用检查点文件来预测性能(请参阅下面的评估模型)。

如果您遵循上述步骤,那么您现在已经开始训练CIFAR-10模型了。恭喜!

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

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

TensorBoard提供此功能,通过cifar10_train.py中的tf.summary.FileWriter 周期性导出数据

例如,在训练过程中我们可以看到local3特征的激活分布和稀疏度如何发展:

 

单项损失以及总损失在过去的训练过程中进行跟踪是有意义的。然而,由于训练所使用的小批量,损失值中含有相当大的干扰。实际上,相比于原始值,损失值的移动平均值显得更为有意义。 查看脚本如何使用tf.train.ExponentialMovingAverage达到此目的。

 

评估模型

现在让我们来评估训练模型在另一个数据集上的表现。该模型由cifar10_eval.py脚本进行评估。它使用inference()函数构建模型,并使用CIFAR-10评估集中的所有10,000个图像。它计算精度为1:H(H=预测值中置信度最高的一项与图片真实标签匹配的频率)。

为了监控模型在训练过程中如何改进,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中显示summaries。summaries在评估过程中提供了对模型的更多分析。

训练脚本会为所有学习变量计算其 移动均值。评估脚本用移动均值代替所有学习的模型参数。这种替代在评估时提升了模型的性能。

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

使用多个GPU训练模型

现在的工作站可能包含多个用于科学计算的GPU。TensorFlow可以利用这种环境在多个GPU上同时运行训练操作。

以并行,分布式方式训练模型需要协调训练过程。接下来,我们称model replica为在一个数据子集中训练出来的一个模型副本。

通过模拟参数的异步更新,会导致次优训练性能,因为我们可能会基于一个旧的模型参数副本去训练一个模型。相反,采用完全同步的更新将与最慢的模型副本一样慢。

在具有多个GPU的工作站中,每个GPU将具有相似的速度并包含足够的内存来运行整个CIFAR-10模型。因此,我们选择以下方式设计训练系统:

  • 在每个GPU上放置单个模型副本。
  • 等待所有GPU完成一批数据的处理,同步更新模型参数。

这是模型图:

请注意,每个GPU会用一批独立的数据计算梯度和估计值。该设置有效地在GPU之间将更大批量的数据分割。

此设置要求所有GPU共享模型参数。一个众所周知的事实是从GPU传输数据相当慢。因此,我们决定在CPU上存储和更新所有模型参数(参见绿色框)。当新的一批数据由所有GPU处理完成时,一组新的模型参数将传输到GPU。

GPU同步运行。所有GPU的梯度会累积并平均(见绿色框)。模型参数用所有模型副本的平均梯度进行更新。

在多设备上设置变量和操作

在多设备上设置操作和变量需要一些特殊的抽象。

我们需要的第一个抽象是用于计算单个模型副本的推理过程和梯度的函数。在代码中,我们将这个抽象称为“tower”。我们必须为每个tower设置两个属性:

  • tower内所有操作设置唯一名称。 tf.name_scope通过前置一个范围前缀来提供这个唯一的名称。例如,第一个tower中的所有操作都有前缀tower_0,例如tower_0/conv1/Conv2D

  • 在tower内运行操作的优先硬件设备。用 tf.device指定。例如,第一个tower中的所有操作都位于范围device('/gpu:0') 内,表明它们应该在第一个GPU上运行。

为在多GPU中共享它们,所有变量都绑定在CPU上,并通过 tf.get_variable访问 。请参阅如何共享变量

在多个GPU上启动和训练模型

如果您的机器上安装了多个GPU,则可以使用cifar10_multi_gpu_train.py脚本更快地对模型进行训练。该版本的训练脚本将多个GPU上的模型并行化。

python cifar10_multi_gpu_train.py --num_gpus=2

请注意,使用的GPU的数量默认为1。此外,如果您的计算机上只有1个GPU可用,所有计算都将放在其上,即使您要求更多。

练习:cifar10_train.py默认设置是以128的批量运行。尝试在2个GPU,批量大小为64上运行cifar10_multi_gpu_train.py,并比较训练速度。

下一步

恭喜!您已完成CIFAR-10教程。

如果您现在有兴趣开发和训练自己的图像分类系统,我们推荐你新建一个基于该教程的分支,并修改其中的内容以构建您需要处理的图像分类系统。

练习:下载 Street View House Numbers (SVHN)数据集。新建一个CIFAR-10教程的分支,并将输入数据替换成SVHN。尝试调整网络架构以提高预测性能。

  • 无标签