非常教程

TensorFlow Guide参考手册

教程 | Tutorials

Convolutional Neural Networks(卷积神经网络)

注意:本教程面向TensorFlow的高级用户,并假设具备机器学习方面的专业知识和经验。

概述

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

airplane, automobile, bird, cat, deer, dog, frog, horse, ship, and truck.

想了解更多详情,请参阅CIFAR-10页面和Alex Krizhevsky 的技术报告。

目标

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

  1. 突出了网络架构,训练和评估的规范结构。

2. 为构建更大更复杂的模型提供模板。

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

教程的亮点

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

  • 核心数学组件包括卷积(维基),纠正线性激活(维基,最大池(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/

File

Purpose

cifar10_input.py

Reads the native CIFAR-10 binary file format.

cifar10.py

Builds the CIFAR-10 model.

cifar10_train.py

Trains a CIFAR-10 model on a CPU or GPU.

cifar10_multi_gpu_train.py

Trains a CIFAR-10 model on multiple GPUs.

cifar10_eval.py

Evaluates the predictive performance of a CIFAR-10 model.

CIFAR-10模型

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

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

模型输入

模型的输入部分由函数构建,inputs()distorted_inputs()从CIFAR-10二进制数据文件读取图像。这些文件包含固定的字节长度记录,所以我们使用tf.FixedLengthRecordReader。请参阅阅读数据以了解更多关于Reader课程是如何运作的。

图像处理如下:

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

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

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

请参阅图像页面以查看可用失真的列表。我们也附加一个tf.summary.image图像,以便我们可以在TensorBoard中将它们可视化。这是验证输入是否正确构建的良好实践。

Convolutional Neural Networks(卷积神经网络)

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

模型预测

模型的预测部分由inference()添加操作来计算预测的逻辑的函数构建。该模型的这部分组织如下:

图层名称

描述

CONV1

卷积和整流线性激活。

POOL1

最大池。

NORM1

本地响应正常化。

CONV2

卷积和整流线性激活。

NORM2

本地响应正常化。

POOL2

最大池。

local3

具有整流线性激活的完全连接层。

LOCAL4

具有整流线性激活的完全连接层。

softmax_linear

线性转换来产生logits。

以下是由TensorBoard生成的描述推理操作的图表:

Convolutional Neural Networks(卷积神经网络)

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

inputs()inference()功能提供所有必要的执行模型的评估的组件。我们现在将重点转向训练模型的操作。

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

模型训练

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

我们用TensorBoard把它想象成tf.summary.scalar

Convolutional Neural Networks(卷积神经网络)

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

Convolutional Neural Networks(卷积神经网络)

train()功能通过计算梯度和更新学习变量(参见tf.train.GradientDescentOptimizer详细信息),添加通过最小化目标所需的操作。它返回一个执行所有计算的操作,以训练和更新一批图像的模型。

启动和训练模型

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

python cifar10_train.py

注意:第一次在CIFAR-10教程中运行任何目标时,将自动下载CIFAR-10数据集。数据集大约为160MB,因此您可能需要抢先在第一次运行。

你可以看到输出如下t:

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提供此功能,通过tf.summary.FileWriter显示cifar10_train.py。定期导出的数据。

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

Convolutional Neural Networks(卷积神经网络)

Convolutional Neural Networks(卷积神经网络)

随着时间的推移,个人损失函数以及总损失对跟踪特别有意义。但是,由于培训使用的批量较小,损耗会产生相当大的噪音。在实践中,我们发现除了原始值之外,还可以看到它们的移动平均值。了解脚本如何应用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中可视化的摘要。这些总结在评估过程中提供了对模型的更多了解。

训练脚本计算所有学习变量的移动平均版本。评估脚本将所有学习的模型参数替换为移动平均版本。这种替代提高了评估时的模型性能。

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

Training a Model Using Multiple GPU Cards

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

以平行分布的方式培训模型需要协调训练流程。对于下面的内容,我们称模型副本为数据子集模型训练的副本。

简单地使用模型参数的异步更新导致次优的训练性能,因为单个模型副本可能在模型参数的陈旧副本上被训练。相反,采用完全同步更新将会与最慢的模型副本一样慢。

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

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

这是这个模型的图表:

Convolutional Neural Networks(卷积神经网络)

请注意,每个GPU都会对独特批次数据进行计算、推断。这种设置有效地允许在GPU上划分更大量的数据。

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

GPU在操作中同步。所有梯度都从GPU中累积并取平均值(请参阅绿色框)。模型参数使用所有模型复本平均的梯度进行更新。

在设备上设置变量和操作

Placing operations and variables on devices requires some special abstractions.

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

  • 塔内所有操作的唯一名称。tf.name_scope通过预先设定范围来提供这个独特的名称。例如,第一个塔楼的所有操作都会预先设定好tower_0,例如tower_0/conv1/Conv2D
  • 在塔内运行操作的首选硬件设备。tf.device指定这一点。例如,第一个塔中的所有操作都驻留在device('/device:GPU:0')范围内,表示它们应该在第一个GPU上运行。

所有变量都固定在CPU上并通过访问tf.get_variable在多GPU版本中共享它们。查看如何共享变量。

在多个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的批处理大小运行cifar10_multi_gpu_train.py。尝试在批处理大小为64的2个GPU上运行并比较训练速度。

下一步

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

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

练习:下载街景门牌号码(SVHN)数据集。分叉CIFAR-10教程并在SVHN中交换输入数据。尝试调整网络架构以提高预测性能。

TensorFlow Guide

TensorFlow是谷歌基于DistBelief进行研发的第二代人工智能学习系统,其命名来源于本身的运行原理。Tensor(张量)意味着N维数组,Flow(流)意味着基于数据流图的计算,TensorFlow为张量从流图的一端流动到另一端计算过程。TensorFlow是将复杂的数据结构传输至人工智能神经网中进行分析和处理过程的系统。

主页 https://www.tensorflow.org/
源码 https://github.com/tensorflow/tensorflow
版本 Guide
发布版本 1.4

TensorFlow Guide目录

1.指南 | Guide
2.教程 | Tutorials
3.配置 | Deploy
4.扩展 | Extend
5.开始 | Get Started
6.表现 | Performance