Tensorflow(1)IT男识别玫瑰

这是一个关于IT男的故事

IT男开始学习如何使用Inception代码库识别玫瑰

背景知识

   在机器学习领域,卷积神经网络是大多数最先进的计算机视觉解决方案的核心,适用于各种任务。其中Tensorflow的Inception代码库也是基于此网络解决了图像分类问题。Inception网络实现了2015年发表的论文《重新思考计算机视觉的初始架构》(Rethinking the Inception Architecture for Computer Vision)。
   在论文中探索了通过适当的分解卷积和积极的正则化,尽可能有效地利用增加的算力,而达到相比现有水平更好的实质性收益。 在论文中也描述了一些具有指导意义的网络设计原则,尽管这些基于大规模试验的设计原则的实用性是推测的,将来需要更多的实验数据来评估其准确性和有效性,但经验证如严重偏离这些原则会往往导致网络质量的下降,并且按照原则执行修复偏差也会使整体架构得到改善。

原则一,网络设计早期不应过度压缩输入输出数据。在设计网络的时候需要根据特征图的各个维度的数据粗略的提取其中的特征,通常到达网络层的特征图数据的大小从输入到输出逐渐减小,但如果早期就过度压缩数据,就会导致信息的大量丢失。信息内容不仅仅通过特征图的维度进行评估,也需要相关结构等重要因素。信息丢失将会影响网络训练的质量。
原则二,高纬度的特征图表示可以在本地用网络代替。在卷积神经网络中逐步增加非线性激活响应可以获得更多特征,加快网络训练的速度。
原则三,在卷积网络之前对多通道的低维特征进行降维,不会降低特征的信息。 例如,在执行(例如3×3)卷积之前,可以在空间聚合之前减小输入表示的维度但并不会产生严重的不利影响。基于假设其原因是相邻单元之间的强相关性导致在降维期间信息损失小得多。鉴于这些原理,应可以进行数据的压缩,尺寸的减小应该可以促进更快的学习。
原则四,找到最佳的网络结构,平衡网络的宽度和深度,使网络的性能达到最优。平衡每级的滤波器数量和网络深度,可以提高网络的最佳性能。增加网络的宽度和深度可以提高网络质量。如果两者并行增加,可以达到恒定计算量的最佳优化结果。 因此,计算预算应以平衡的方式分布在网络的深度和宽度之间。

   虽然这些原则可能有意义,但直接应用它们来提高网络质量并非易事。Inception网络也只是在逐步的靠近这些设计原则,模模糊糊中使用它们。
   关于论文部分不再细述,请参考该论文:Rethinking the Inception Architecture for Computer Vision
   ICLR 2017年的一篇分析论文 An analysis of deep neural network models for practical applications 对实际应用中的重要技术进行了全面分析:精度,内存占用,参数,操作计数,推理时间和功耗。其中在精度上,Inception网络获得了最佳表现,当然在其他维度并没有获得所有的最佳表现力。精度评测结果如下:

Inception代码介绍

   Google在开源Tensorflow的同时开源了一个名为 Models的代码库。该代码库包含了[TensorFlow](https://www.tensorflow.org)中实现的许多不同模型,结构如下:
   - official:使用TensorFlow的高级API的示例模型的集合。旨在通过最新最稳定的TensorFlow API进行开发,经过测试并保持代码最新。官方推荐新的TensorFlow用户从这里开始学习。
   - research:是研究人员在TensorFlow中实施的大量模型集合。它们没有得到官方支持,是由个体研究人员来维护模型,但也是最活跃的代码目录。
   - samples:包含代码片段和较小的模型,用于演示TensorFlow的功能,包括各种博客文章中提供的代码。
   - tutorials:是TensorFlow教程中描述的模型集合。
   其中,本文介绍的 Inception 代码库就是research的一部分,文件结构及说明如下:

├── README.md  #非常全面的inception代码库的描述
├── WORKSPACE #bazel编译使用
├── g3doc
│   └── inception_v3_architecture.png #inception_v3网络体系结构的说明图示
└── inception
    ├── BUILD
    ├── data #训练数据的标注和代码目录
    │   ├── build_image_data.py #使用protos将图片数据转换为TFRecord文件格式
    │   ├── build_imagenet_data.py #使用protos将ImageNet图片数据集转换为TFRecord文件格式
    │   ├── download_and_preprocess_flowers.sh #下载花朵数据集并将数据集转化为TFRecord文件格式
    │   ├── download_and_preprocess_flowers_mac.sh 
    │   ├── download_and_preprocess_imagenet.sh #下载2012ImageNet训练和评估数据集并将数据集转化为TFRecord文件格式
    │   ├── download_imagenet.sh # 下载2012ImageNet训练和评估数据集
    │   ├── imagenet_2012_validation_synset_labels.txt #训练数据的标签与preprocess_imagenet_validation_data.py一起对数据进行处理
    │   ├── imagenet_lsvrc_2015_synsets.txt #训练数据的标签
    │   ├── imagenet_metadata.txt #训练数据的标签和对应的语义
    │   ├── preprocess_imagenet_validation_data.py #将2012 ImageNet图片和标签相关联
    │   └── process_bounding_boxes.py #将图片数据和标签数据相关联的脚本
    ├── dataset.py # 轻量级的管理训练数据集合的库
    ├── flowers_data.py # 使用DataSet管理的花朵训练数据
    ├── flowers_eval.py # 对花朵分类训练模型的评估脚本,对inception_eval.py的封装
    ├── flowers_train.py # 对花朵分类的训练脚本,对inception_train.py的封装
    ├── image_processing.py #处理单张图片的库,支持多个线程并行和预处理图片。
    ├── imagenet_data.py # 使用DataSet管理的ImageNet训练数据
    ├── imagenet_distributed_train.py #支持分布式系统进行ImageNet训练的库,对inception_distributed_train.py的封装
    ├── imagenet_eval.py # 对ImageNet数据集训练模型的评估脚本
    ├── imagenet_train.py #对ImageNet数据集的训练脚本
    ├── inception_distributed_train.py # 支持分布式系统进行inception的网络的训练
    ├── inception_eval.py # inception网络训练模型的评估验证库
    ├── inception_model.py # 构建inception v3网络的模型在数据集上
    ├── inception_train.py # inception网络训练脚本库
    └── slim  #Tensorflow中一个轻量级的包含设计,训练和评估模型的代码库,本文不做讨论。
复制代码

本文仅对inception_train.py(此脚本的后续更新已经转移到slim代码库中,参考注意事项)的核心代码进行分析,其他文件请参考源代码。

首先,对inception网络训练脚本使用的标志参数进行说明。

标志参数如下:
   train_dir: 用来写入事件日志和检查点(checkpoint),即训练产生的events.out.xxx和model.ckpt-xxxx的文件,默认值'/tmp/imagenet_train’。
   max_steps: 训练最大的步数,默认值10000000。
   subset: 描述是训练还是验证。默认值是'train' 。

   用于管理运行tensorflow使用的硬件
   num_gpus: 管理用于运行tensorflow的硬件,该参数规定使用的GPU数量,默认值为1。
   log_device_placement: 设置是否记录设备,默认值是False。

   用于管理训练的类型
   fine_tune: 管理训练类型,如果设置将随机初始化最后一层权重,以便在新任务上训练网络。默认值是False,即可以在预训练模型上继续训练。
   pretrained_model_checkpoint_path: 在一个新的训练任务开始时指定预训练模型存放的路径。

   下面是关于学习速率的调整参数,这些参数的调整在很大程度上依赖于硬件架构,批大小以及对模型体系结构规范的更改。选择一个精细调整的学习率是需要一些实验的经验过程的。
   initial_learning_rate: 初始学习速率。默认值是0.1。
   num_epochs_per_decay: 学习速率衰减的调整周期。
   learning_rate_decay_factor: 学习速率调整的参数因子。

其次,针对脚本中定义的tower_loss方法做一些分析。

函数: _tower_loss
   用于计算训练模型单个塔上的总损失。在训练时程序会将批量图片任务进行拆分,一个批量的图片拆分到不同的塔上。即如果batch_size = 32,num_gpus = 2,那么每个塔就会处理16张图像。
1,使用inception构建网络推理图。

with tf.variable_scope(tf.get_variable_scope(), reuse=reuse_variables):
    logits = inception.inference(images, num_classes, for_training=True,
                                 restore_logits=restore_logits,
                                 scope=scope)
复制代码

2,构建推理图中计算损失的部分。

split_batch_size = images.get_shape().as_list()[0]
inception.loss(logits, labels, batch_size=split_batch_size)
复制代码

3,仅组装当前塔中的所有损失。

losses = tf.get_collection(slim.losses.LOSSES_COLLECTION, scope)
复制代码

其中slim来自inception中slim目录中的losses.py文件。这个方法获取网络的所有损失值。其中,LOSSES_COLLECTION = '_losses'

4,计算当前塔的所有损失。

regularization_losses = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
total_loss = tf.add_n(losses + regularization_losses, name='total_loss')
复制代码

在损失函数上加上正则项是防止过拟合的一个重要方法,通过获取tf.GraphKeys.REGULARIZATION_LOSSES集合中的所有变量获得正则化的损失值。

5,调整参数,初始衰减速率为0.9,计算所有损失的移动平均值和总损失。

loss_averages = tf.train.ExponentialMovingAverage(0.9, name='avg')
loss_averages_op = loss_averages.apply(losses + [total_loss])
复制代码

通过tf.train.ExponentialMovingAverage函数创建移动平均而更新参数,控制模型的更新速度。将所有的loss存储在一个全局变量(GraphKeys.MOVING_AVERAGE_VARIABLES)中,再通过apply对每一个变量进行每一次的迭代移动平均计算。

最后,针对Inception的训练函数进行一些分析。

函数:train 在数据集上进行训练。

#创建一个变量global_step来计算train调用的数量。这等于处理的批次数* FLAGS.num_gpus。

global_step = tf.get_variable(
        'global_step', [],
        initializer=tf.constant_initializer(0), trainable=False)
复制代码

#计算获得学习速率的调整方案。

num_batches_per_epoch = (dataset.num_examples_per_epoch() / FLAGS.batch_size)
decay_steps = int(num_batches_per_epoch * FLAGS.num_epochs_per_decay)
复制代码

#根据步数以指数方式衰减学习速率。

lr = tf.train.exponential_decay(FLAGS.initial_learning_rate,
                                    global_step,
                                    decay_steps,
                                    FLAGS.learning_rate_decay_factor,
                                    staircase=True)
复制代码

#使用RMSProp算法创建一个执行梯度下降的优化器。

opt = tf.train.RMSPropOptimizer(lr, RMSPROP_DECAY,
                                    momentum=RMSPROP_MOMENTUM,
                                    epsilon=RMSPROP_EPSILON)
复制代码

#获取ImageNet的图像和标签,并在GPU之间拆分批处理。

split_batch_size = int(FLAGS.batch_size / FLAGS.num_gpus)
复制代码

#覆盖预处理线程的数量,以解决塔数量增加的问题。

num_preprocess_threads = FLAGS.num_preprocess_threads * FLAGS.num_gpus
images, labels = image_processing.distorted_inputs(
        dataset,
        num_preprocess_threads=num_preprocess_threads)
复制代码

#Dataset标签集中的类数加1.标签0保留给(未使用的)后台类。

num_classes = dataset.num_classes() + 1
复制代码

#拆分塔的图像和标签批次。

images_splits = tf.split(axis=0, num_or_size_splits=FLAGS.num_gpus, value=images)
labels_splits = tf.split(axis=0, num_or_size_splits=FLAGS.num_gpus, value=labels)
复制代码

#计算每个模型塔的梯度。
#强制所有变量驻留在CPU上,计算ImageNet模型的一个塔的损失,此函数构造整个ImageNet模型,但在所有塔中共享变量。

with slim.arg_scope([slim.variables.variable], device='/cpu:0'):
	loss = _tower_loss(images_splits[i], labels_splits[i], num_classes,
                           scope, reuse_variables)
复制代码

#重用下一个塔的变量。

reuse_variables = True
复制代码

#保留最终塔的摘要。

summaries = tf.get_collection(tf.GraphKeys.SUMMARIES, scope)
复制代码

#仅保留最终塔的批量标准化更新操作。理想情况下,我们应该从所有塔中获取更新,但这些统计数据累积得非常快,因此我们可以忽略其他塔的统计数据,而不会造成重大损失。

batchnorm_updates = tf.get_collection(slim.ops.UPDATE_OPS_COLLECTION, scope)
复制代码

#计算此塔上ImageNet批量数据的梯度。

grads = opt.compute_gradients(loss)
复制代码

#跟踪所有塔的梯度。

tower_grads.append(grads)
复制代码

#计算每个梯度的平均值。请注意,这是所有塔开始同步的地方。

grads = _average_gradients(tower_grads)
复制代码

#添加摘要以跟踪学习率。

summaries.append(tf.summary.scalar('learning_rate', lr))
复制代码

#添加渐变的直方图。

for grad, var in grads:
      if grad is not None:
        summaries.append(
            tf.summary.histogram(var.op.name + '/gradients', grad))
复制代码

#应用渐变来调整共享变量。

apply_gradient_op = opt.apply_gradients(grads, global_step=global_step)
复制代码

#为可训练变量添加直方图。

for var in tf.trainable_variables():
      summaries.append(tf.summary.histogram(var.op.name, var))
复制代码

#跟踪所有可训练变量的移动平均值。维护BatchNormalization全局统计信息的“双倍平均值”。这比需要的更复杂,但是使用它与之前的模型向后兼容。

variable_averages = tf.train.ExponentialMovingAverage(
        inception.MOVING_AVERAGE_DECAY, global_step)
variables_to_average = (tf.trainable_variables() +  tf.moving_average_variables())
variables_averages_op = variable_averages.apply(variables_to_average)
复制代码

#将所有更新分组到一个训练中。

batchnorm_updates_op = tf.group(*batchnorm_updates)
train_op = tf.group(apply_gradient_op, variables_averages_op, batchnorm_updates_op)
复制代码

#创建一个保存器。

saver = tf.train.Saver(tf.global_variables())
复制代码

#从最后的塔摘要中构建摘要操作。

summary_op = tf.summary.merge(summaries)
复制代码

#构建一个初始化操作以在下面运行。

init = tf.global_variables_initializer()
复制代码

#开始在Graph上运行操作。必须将allow_soft_placement设置为True才能在GPU上构建塔,因为某些操作系统没有GPU实现。

sess = tf.Session(config=tf.ConfigProto(
        allow_soft_placement=True,
        log_device_placement=FLAGS.log_device_placement))
    sess.run(init)

    if FLAGS.pretrained_model_checkpoint_path:
      …
      variables_to_restore = tf.get_collection(slim.variables.VARIABLES_TO_RESTORE)
      restorer = tf.train.Saver(variables_to_restore)
      restorer.restore(sess, FLAGS.pretrained_model_checkpoint_path)
      …
复制代码

#启动队列运行。

tf.train.start_queue_runners(sess=sess)

    # 创建写入器
    summary_writer = tf.summary.FileWriter(FLAGS.train_dir, graph=sess.graph)
    for step in range(FLAGS.max_steps):
      …
      # 执行本步的训练操作
      start_time = time.time()
      _, loss_value = sess.run([train_op, loss])

     …

      # 每100步更新一次摘要信息
      if step % 100 == 0:
        summary_str = sess.run(summary_op)
        summary_writer.add_summary(summary_str, step)

      # 周期的保存checkpoint文件,这里是5000步执行一次
      if step % 5000 == 0 or (step + 1) == FLAGS.max_steps:
        checkpoint_path = os.path.join(FLAGS.train_dir, 'model.ckpt')
        saver.save(sess, checkpoint_path, global_step=step)
复制代码

理解train方法后即可对网络进行微整。

实战验证

实战参考Inception的 README 文档,本文只介绍其中的4个部分: ###如何在新任务上对预训练模型进行微调

一,入门

   在调用训练方法前,必须对图片和标签数据进行预处理,即将一个新的数据集转换为分片的TFRecord格式,每个条目都是一个序列化的tf.Example proto结构。代码库提供了一个脚本,演示如何为5个标签上分布的几千幅花卉图像的小数据集做到这一点。

daisy, dandelion, roses, sunflowers, tulips

   代码库提供自动脚本(download_and_preprocess_flowers.sh)下载数据集并将其转换为TFRecord格式。与ImageNet数据集非常相似,TFRecord格式中的每条记录都是序列化的tf.Example proto结构,其条目包括JPEG编码的字符串和整数标签。有关详细信息,请参阅parse_example_proto。
   该脚本只需几分钟即可运行,具体取决于您的网络连接速度以下载和处理图像。您的硬盘需要200MB的免费存储空间(这比完整的500GB+的2012 ImageNet数据集少太多了)。在这里我们选择DATA_DIR = / tmp / flowers-data /作为这样一个位置,但随意编辑。

# 设置flower数据存储位置 
FLOWERS_DATA_DIR=/tmp/flowers-data/

# 构建预处理脚本
cd tensorflow-models/inception
bazel  
build //inception:download_and_preprocess_flowers

# 运行脚本下载并处理数据 
bazel-bin/inception/download_and_preprocess_flowers "${FLOWERS_DATA_DIR}"
复制代码

如果脚本成功运行,终端输出的最后一行应如下所示:

2016-02-24 20:42:25.067551: Finished writing all 3170 images in data set.
复制代码

   当脚本结束时,将在DATA_DIR中找到2个用于训练和验证文件的分片。这些文件类似train-?????-of-00002和validation-?????-of-00002,分别代表训练数据集和验证数据集。
注意:
   如果准备自定义图像数据集,则需要在自定义数据集上调用build_image_data.py。

另外,可以选择下载代码库提供的预训练模型

# 指定下载模型要存储的路径
INCEPTION_MODEL_DIR=$HOME/inception-v3-model
  
mkdir -p ${INCEPTION_MODEL_DIR}

cd ${INCEPTION_MODEL_DIR}

# 通过curl命令下载模型压缩包
curl -O http://download.tensorflow.org/models/image/imagenet/inception-v3-2016-03-01.tar.gz
tar xzf inception-v3-2016-03-01.tar.gz

# 将会在目录中创建一个名为inception-v3的目录,并包含下面的文件
> ls inception-v3

README.txt

checkpoint

model.ckpt-157585
复制代码

现在可以使用花朵数据集对预先训练好的Inception v3模型进行微调。

二,如何在花卉数据上重新训练模型

准备在花朵数据集上微调预先训练好的Inception-v3模型,需要修改训练脚本的2个参数:
   - pretrained_model_checkpoint_path: 指向预先训练的Inception-v3模型的路径。如果指定了此标志,它将在脚本开始训练之前从检查点加载整个模型。
   - fine_tune: 一个布尔值,指示最后一个分类层是应该随机初始化还是恢复。如果您希望从检查点继续训练预先训练好的模型,则可以将此标志设置为false。如果将此标志设置为true,则可以从头开始培训新的分类层。

综合起来,可以使用以下命令重新训练花卉数据集上的预先训练的Inception-v3模型。

# 通过bazel构建flowers_train网络,该网络在源码上封装了对inception_train的调用。
cd tensorflow-models/inception

bazel build //inception:flowers_train

# 设置下载好的预训练的模型路径.

MODEL_PATH="${INCEPTION_MODEL_DIR}/inception-v3/model.ckpt-157585"

# 设置数据保存的路径,该数据已经是TFRecord文件格式
FLOWERS_DATA_DIR=/tmp/flowers-data/

# 设置保存训练中输出的事件日志和检查点数据
TRAIN_DIR=/tmp/flowers_train/

# 通过flowers_train网络开始使用预训练的模型重新训练花朵数据,fine_tune设置为True。
bazel-bin/inception/flowers_train --train_dir="${TRAIN_DIR}" 
--data_dir="${FLOWERS_DATA_DIR}" 
--pretrained_model_checkpoint_path="${MODEL_PATH}" 
--fine_tune=True 
--initial_learning_rate=0.001 
--input_queue_memory_factor=1
复制代码

在培训过程中增加了一些额外选项。

  • 将模型微调为单独的数据集要求显着降低初始学习速率。我们将初始学习率设置为0.001。
  • 鲜花数据集非常小,所以我们缩小了示例的队列的大小。有关更多详细信息,请参阅调整内存需求。

训练脚本只会报告损失。要评估微调模型的质量,您需要运行验证脚本flowers_eval:

# 开始构建flowers_eval模型
cd tensorflow-models/inception

bazel build //inception:flowers_eval

# 设置训练中输出的事件日志和检查点的目录
TRAIN_DIR=/tmp/flowers_train/

# 设置训练数据集所在目录,该数据集是TFRecord文件格式
FLOWERS_DATA_DIR=/tmp/flowers-data/

# 设定保存验证结果日志文件的目录
EVAL_DIR=/tmp/flowers_eval/

# 通过flowers_eval开始验证flowers_train训练的结果
bazel-bin/inception/flowers_eval 
--eval_dir="${EVAL_DIR}" 
--data_dir="${FLOWERS_DATA_DIR}" 
--subset=validation 
--num_examples=500 
--checkpoint_dir="${TRAIN_DIR}" 
--input_queue_memory_factor=1 
--run_once
复制代码

训练中发现在模型运行2000步后,评估的精确度达到大约93.4%。

Successfully loaded model from /tmp/flowers/model.ckpt-1999 at step=1999.
2016-03-01 16:52:51.761219: starting evaluation on (validation).
2016-03-01 16:53:05.450419: [20 batches out of 20] (36.5 examples/sec; 0.684sec/batch)
2016-03-01 16:53:05.450471: precision @ 1 = 0.9340 recall @ 5 = 0.9960 [500 examples]
复制代码
三,如何构建一个新的数据集进行再训练

   使用该模型提供的现有脚本来构建用于训练或微调的新数据集。主要脚本是build_image_data.py。 简而言之,这个脚本需要一个结构化的图像目录,并将其转换为可由Inception模型读取的分片TFRecord。 具体来说,您需要创建一个指定结构的训练图像目录,这些图像位于TRAIN_DIR和 VALIDATION_DIR中,其排列方式如下:

$TRAIN_DIR/dog/image0.jpeg

$TRAIN_DIR/dog/image1.jpg

$TRAIN_DIR/dog/image2.png

...

$TRAIN_DIR/cat/weird-image.jpeg

$TRAIN_DIR/cat/my-image.jpeg

$TRAIN_DIR/cat/my-image.JPG

...

$VALIDATION_DIR/dog/imageA.jpeg

$VALIDATION_DIR/dog/imageB.jpg

$VALIDATION_DIR/dog/imageC.png

...

$VALIDATION_DIR/cat/weird-image.PNG

$VALIDATION_DIR/cat/that-image.jpg

$VALIDATION_DIR/cat/cat.JPG
...
复制代码

注意:该脚本将附加一个索引为0的额外背景类,因此您的类标签范围从0到num_labels。使用上面的例子,从build_image_data.py生成的相应类标签如下所示:

0
  
1 dog
 
2 cat
复制代码

TRAIN_DIR和VALIDATION_DIR中的每个子目录对应于驻留在该子目录内的图像的唯一标签,图像可能是JPEG或PNG图像,目前不支持其他图像类型。 数据安排在这个目录结构中,可以在数据上运行build_image_data.py来生成分片的TFRecord数据集。 build_image_data.py的注释中描述了tf.Example中包含的完整信息列表。 要运行build_image_data.py,可以运行以下命令行:

# 设置生成TFRecord文件的目录
OUTPUT_DIRECTORY=$HOME/my-custom-data/

# 构建脚本build_image_data
cd tensorflow-models/inception
bazel 
build //inception:build_image_data

# 运行脚本进行转化
bazel-bin/inception/build_image_data 
--train_directory="${TRAIN_DIR}" 
--validation_directory="${VALIDATION_DIR}" 
--output_directory="${OUTPUT_DIRECTORY}" 
--labels_file="${LABELS_FILE}" 
--train_shards=128 
--validation_shards=24 
--num_threads=8
复制代码

OUTPUT_DIRECTORY是分片TFRecords的位置。
LABELS_FILE将是一个由脚本读取的文本文件,该文件提供了所有标签的列表。例如,在鲜花数据集的情况下, LABELS_FILE包含以下数据:
daisy

dandelion

roses

sunflowers

tulips
请注意,每个标签的每一行都与模型中最终分类器中的条目相对应。也就是说,雏菊对应于条目1的分类器;蒲公英是条目2等。我们跳过标签0作为背景类。 运行此脚本后,将生成如下所示的文件:

$TRAIN_DIR/train-00000-of-00128

$TRAIN_DIR/train-00001-of-00128

...

$TRAIN_DIR/train-00127-of-00128
and
$VALIDATION_DIR/validation-00000-of-00024

$VALIDATION_DIR/validation-00001-of-00024

...

$VALIDATION_DIR/validation-00023-of-00024
复制代码

其中128和24分别是为每个数据集指定的分片数。目标是选择碎片的数量,使每个碎片大约有1024个图像。一旦建立了这个数据集,就可以在这个数据集上训练或微调一个Inception模型。 另外,如果您使用训练脚本,请修改flowers_data.py中的num_classes()和num_examples_per_epoch()以与新建的数据对应。

四,训练模型的实际考虑因素

   模型架构和训练过程严重依赖于用来训练模型的硬件。如果你想在你的机器上训练或微调这个模型,你需要调整和经验地确定一套适合你的设置的训练超参数。

1)寻找好的超参数

大约5-10个超参数控制网络训练的速度。除了--batch_size和–num_gpus之外,在inception_train.py中定义了几个常量,它们规定了学习任务。

RMSPROP_DECAY = 0.9 # RMSProp算法的衰减项.

MOMENTUM = 0.9 # RMSProp算法的Momentum值.

RMSPROP_EPSILON = 1.0 # RMSProp算法的Epsilon项.

INITIAL_LEARNING_RATE = 0.1 # 学习速录初始化时的值.

NUM_EPOCHS_PER_DECAY = 30.0 # 学习速率开始衰减的时期Epochs.

LEARNING_RATE_DECAY_FACTOR = 0.16 # 学习速率衰减因子.
复制代码

在训练中下面参数的调整对结果有较大的影响。

  • INITIAL_LEARNING_RATE:较高的学习率可以加快训练速度。但速率太高会导致不稳定,使模型参数发散到无穷大或NaN。
  • batch_size:较大的批量大小可以提高梯度的质量估算,并可对较高学习率的模型进行训练。
  • num_gpus:通常GPU内存是阻止采用更大批量的瓶颈,使用更多的GPU允许使用更大的批量。
2)调整内存需求

   训练这个模型在CPU和GPU方面有很大的内存需求,与CPU内存相比,GPU内存相对较小。两个项目决定了GPU内存使用量——模型架构和批量大小(batch_size)。假设您保持模型架构不变,训练对GPU需求的唯一控制参数就是批量大小。

“一个很好的经验法则是尝试使用尽可能大的批量大小以适应GPU。”

   如果用完GPU内存,请降低--batch_size或在工作机上使用更多GPU。该模型在GPU之间执行批量分割,因此N个GPU可以处理N倍于1个GPU的批量。 该模型也需要大量的CPU内存。Inception调整了这个模型来使用大约20GB的CPU内存。因此,获得大约40GB的CPU内存将是理想的。
   如果这不可行,可以通过降低——input_queue_memory_factor来调低模型的内存需求。相对于跨–num_preprocess_threads线程的主要训练对图像进行异步预处理。
   预处理的图像存储在队列中,其中每个GPU执行出队操作以接收批量图像。 为了保证数据的良好序列,我们维护一个1024 x input_queue_memory_factor图像的大型队列。对于当前的模型架构,这相当于大约4GB的CPU内存。 可以通过降低input_queue_memory_factor以减少内存占用量。但大幅降低此值可能会导致模型在从头开始训练时预测精度略低。
   有关更多详细信息,请参阅image_processing.py中的注释。

通过上面的学习和实战验证,IT男使用训练好的模型终于可以大概率的识别出什么事玫瑰。

引用及注意事项

引用:
1.Inception
2.Rethinking the Inception Architecture for Computer Vision
3.An analysis of deep neural network models for practical applications
4.ImageNet 是机器学习中用于训练图像识别系统的常用学术数据集。
5.Inception的模型架构图如下:

6.RMSProp算法是一种梯度下降法,全称是Root Mean Square Prop。 7.tower: 这个概念在tensorflow中并没有明确的定义,我的理解tower是tensorflow神经网络模型的一部分,是在梯度渐变计算中抽象出来可独立计算的函数。可以在单GPU上进行计算,也支持在多GPUs上进行独立计算。

注意:
   对于Research中开源的Inception代码库,谷歌的开发者们将大部分的后续改进工作转移到了 slim 代码库中。即可以在 slim 中找到此代码库的最新版本,持续学习可以参考。

PS. 本人作为机器学习的新鸟一只,在学习过程中对很多概念和算法都不明觉厉,如有错误请批评指正。

扫描二维码,关注公众号。 获得最新的移动开发技术干货。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值