原文:
如何训练Inception的最后一层新的类别?
现代物体识别模型有上百万个参数,可以花上几周时间来充分训练。学习迁移是一个捷径,很多这样的工作,以充分的训练模式的一组类如ImageNet,和retrain新的类从现有的权重。在这个例子中,我们将再培训的最后一层从头开始,而让所有其它的不变。有关该方法的更多信息,您可以看到此页http://arxiv.org/pdf/1310.1531v1.pdf。
虽然它作为一个完整的训练,跑的不好,这对于许多应用是出奇的有效,并可以运行在短短的三十分钟内,在笔记本电脑上,而不需要一个GPU。本教程将向你展示如何在你自己的图像上运行这个示例脚本,并解释一些你需要帮助控制训练过程的选项。
内容
1、花卉训练
2、bottleneck
3、训练
4、使用的训练模式
5、训练您自己的类别
6、创建一组训练图像
7、训练步骤
8、扭曲
9、超参数
10、培训,验证和测试集
1、花卉训练
在你开始任何训练之前,你需要一组图像来教你想要认识的新课程的网络。后面有一段解释如何准备你自己的图像,但要使它变得容易,我们已经创建了一个创造性的共享文件的存档许可的花照片最初使用。要获得一组花的照片,运行这些命令:
cd ~
curl -O http://download.tensorflow.org/example_images/flower_photos.tgz
tar xzf flower_photos.tgz
一旦你有了图片,你可以建立retrainer像这样,从你的tensorflow源代码根目录:
bazel build tensorflow/examples/image_retraining:retrain
如果你有一台支持的机器the AVX instruction set :https://en.wikipedia.org/wiki/Advanced_Vector_Extensions(在过去的几年里所生产的常见的X86处理器)你可以通过建立一种架构来提高再培训的运行速度,就像这样:
bazel build -c opt --copt=-mavx tensorflow/examples/image_retraining:retrain
然后retrainer可以这样:
bazel-bin/tensorflow/examples/image_retraining/retrain --image_dir ~/flower_photos
这个脚本加载预训练Inception V3模型,除去旧的顶层,并训练新一层,用你下载了花的照片。花的品种没有在原来培训的ImageNet全网络里。传递学习的法宝是,经过训练来区分一些对象的低层可以重复使用许多识别任务,而无需任何改动
2、Bottlenecks
该脚本可以采取三十分钟或更多的完成,取决于你的机器的速度。第一阶段分析了所有的磁盘上的图像,并计算每个的bottleneck值。‘bottleneck‘是一个非正式的术语,我们经常在最后的输出层,实际上做分类的层使用。这倒数第二层已经训练输出值集,这对于分类器采用区分所有的物类是足够好的。这意味着这些照片必须是一个有意义的和紧凑的图像集,因为它必须包含足够的信息,在一个非常小的一组值,是一个很好的选择。我们重新训练最后一层的原因是要工作在新的物类上面,结果是,在辨别ImageNet里的1000个类的信息,对于辨别新的物类也是有用的。
因为每一个图像被重复使用多次的训练和计算在每一个bottleneck,需要大量的时间,它加速缓存这些瓶颈值在磁盘上,他们不需要反复重新计算。默认情况下,它们保存在/tmp/bottleneck,如果你运行脚本,他们会重复使用,所以你不必再等待这部分。
3、训练
一旦bottleneck完成,训练网络的最上层的工作真正开始。你会看到一系列的步输出,每一个显示训练的准确性,验证精度,和交叉熵。训练准确率显示当前训练批次所使用的图像被label正确的百分比。验证精度是一个随机选择的组的不同图像集合的精度。关键的区别是,训练精度是基于图像,网络已经能够学习使网络能过度拟合训练数据中的噪声。衡量网络性能的一个真正衡量标准是在训练数据中不包含数据集的性能--这是衡量验证精度。如果训练精度高,但验证精度仍然很低,这意味着网络和训练图像,不利于更多的一般特点记忆。交叉熵是一种损失函数,它提供了一个了解学习过程的进展如何。训练的目标是尽可能使损失尽可能小,所以,如果训练学习起作用,着重是,损失是否保持下降,忽视短期的噪声。
默认情况下,这个脚本将运行4000个训练步骤。每一步从训练集随机选择十个图像,从缓存中找到它们的bottleneck,并将它们放入最后一层,以获得预测。这些预测进行比较,针对实际标签更新的最后一层的权重,通过反向传播过程。随着过程的继续,你应该看到报告的准确性提高,所有的步骤都完成了,最后的测试精度评估是在一组图像上运行的,与训练和验证图片保持分开的。此测试评估的训练模型将是如何执行的分类任务的最佳估计。你应该看到一个准确值在90%和95%之间,虽然在训练过程中,精确的值会有所不同,但在训练过程中有随机性。这个数字是根10、培训,验证和测试集 据在测试集上的图像的百分比,得到正确的标签后,该模型是完全训练。
4、使用的训练模式
该脚本会输出一个带有retrained的最后一层的Inception v3的一个版本到你的目录/tmp/output_graph.pb,及包含该标签/tmp/output_labels.txt文本文件。两者是用一个格式C++ and Python image classification examples: https://www.tensorflow.org/versions/master/tutorials/image_recognition/index.html都能够读取到,所以你可以立即开始使用你的新模式。既然你已经更换了最上面的一层,你需要在脚本中指定新的名称,例如用标示——output_layer = final_result来指定如果你使用label_image程序。
这里有一个例子,如何建立和运行label_image使用你的图表:
bazel build tensorflow/examples/label_image:label_image && \
bazel-bin/tensorflow/examples/label_image/label_image \
--graph=/tmp/output_graph.pb --labels=/tmp/output_labels.txt \
--output_layer=final_result \
--image=$HOME/flower_photos/daisy/21652746_cc379e0eea_m.jpg
你应该看到一个列花的标签,在大多数情况下,菊花在上面(尽管每个训练模式可能略有不同)。你可以用自己的图片去替换--image参数,并使用C++代码为模板,用你自己的应用程序集成。
5、训练您自己的类别
如果你正在着手使用这个脚本运行在花例子的照片,你可以开始训练教它识别你想要的物类。理论上讲,你需要做的只是指定它到一个有多个子目录的路径,每一个目录包含着照片。如果你如上面的做法,然后把物类的根目录作为--iamge_dir的参数,这脚本就会像训练花一样训练您的物类。
这是实例花的文件结构,给你一个这的例子。
在实践中,它可能需要一些工作,为了得到你想要的精度。我会引导你经历一些常见的问题,那些你在接下来可能遇到的。
6、创建一组训练图像
第一个开始的地方是看你收集的图像,因为我们看到的最常见的问题是来自于被输入的数据。为了训练的结果工作得很好,你应该收集每种至少一百张你想认识物体的照片。图片你收集得越多,你训练的模型的准确性就越好。你还需要确保照片是一个很好的代表性,你的应用程序实际上会遇到什么。例如,如果你把所有的照片都是在室内,你的用户都在尝试在户外识别物体,你可能在部署时不会看到很好的效果。
另一个陷阱需要避免的是在学习过程中会挑出现任何有共同的标记的图像,如果不要担心,这可能是一些没有用的东西。例如,如果你在一个蓝色的房间里拍摄一种对象,另一个在绿色的,那么这个模型将基于它的背景颜色预测,而不是你真正关心的对象的功能。为了避免这个,你尽可能在在各种宽阔的场景拍照片,不同的时间和不同的设备。如果你想要了解更多这些问题,你可以阅读此类(and possibly apocryphal):http://www.jefftk.com/p/detecting-tanks.
你可能也要考虑你使用的类别。它可能是一个值得拆分的大类,涵盖了许多不同的物理形式的小类,更直观地不同。例如交通工具,你可以使用“汽车”、“摩托车”和“卡车”。这也是值得思考的是你是否有一个“封闭的世界”或“开放的世界”的问题。在一个封闭的世界中,你所要做的唯一的事情就是你所了解的对象的类别。这可能适用于一个植物识别应用程序,你知道用户很可能会采取一个花的图片,所以你要做的就是决定哪些品种。相反,漫游机器人可能会看到各种不同的东西,通过自己的相机漫游世界各地。在这种情况下,你要分类报告,如果它不知道它是什么看到。这可能是很难做的,但通常如果你收集了大量的典型的“背景”的照片,没有相关的对象,你可以添加到一个额外的‘未知‘类在你的图像文件夹。
这也值得检查,以确保您的所有图像被正确标记。通常用户生成的标签对于我们而言是不可靠的,例如使用Daisy命名照片,然而一个人名叫Daisy。如果你通过你的图像和清除任何错误,它可以为你的整体精度带来奇迹
7、训练步骤
如果你对你的图像感到满意,你可以通过改变学习过程的细节来改善你的结果。最简单的一个尝试是--how_many_training_steps。 这个默认值为4000,但如果你将它增加到8000,它将需要双倍的时间来训练。提高精度的速度会减慢你训练的时间,而且在某些时候会完全停止,但是你可以实验,看看它什么时候发生,也是你模型的局限。
8、扭曲
提高图像的训练结果的一种常用方法是通过变形、剪切、或光亮投入在随机的的训练方式。这有助于扩大有效的训练数据的大小,由于相同的图像的所有可能的变化,并趋向于帮助网络学习,以应付所有的扭曲,将发生在现实生活中使用的分类。在我们的脚本中,使这些扭曲的最大缺点是,瓶颈缓存不再是有用的,因为输入的图像永远不会重复使用。这意味着训练过程需要更长的时间,所以我建议你试着把这作为一种微调的方式,一旦你有了一个,你是合理的,你会感到很快乐。
你使这些扭曲的通过--random_crop, --random_scale和--random_brightness在脚本里。这些都是百分比的值,控制每个图像的失真被施加到每个图像。对他们每个都有5个或10个开始的值是合理的,然后实验看到他们的应用程序有哪些帮助。--flip_left_right将随机的对半水平地镜像图像,那变得有意义,只要这些倒有可能发生在您的应用程序。举例来说,如果你试图辨认字母的话,这不是一个好主意,因为它会破坏他们的意思。
9、超参数
有几个其他的参数,你可以尝试调整,看看他们是否有助于你的结果。--learning_rate在训练过程中,控制更新到最后一层的幅度。直观地说,如果这是较小的,那么学习将需要更长的时间,但它可以最终帮助整体精度。不过,这并不总是如此,所以你需要仔细的实验,看看你的情况如何工作。--train_batch_size控制在一个训练步骤中检查了多少图像,并且由于每个批处理的学习速率被应用,如果你有更大的批次得到相同的整体效果,你需要减少它。
10、培训,验证和测试集
当你把它放在一个图像的文件夹中的情况下,该脚本是把它们分为三个不同的集合。最大的通常是训练集,这是所有的图像输入到网络中训练时,用以更新模型的权重。你可能会奇怪,为什么我们不使用所有的图像进行培训?一个大的潜在问题,当我们做机器学习的是,我们的模型可能只是记忆无关的训练图像的细节,拿出正确的答案。例如,你可以想象一个网络在每一张照片的背景下,记得一个图案,并使用,以匹配标签与对象。它可以产生良好的效果,在所有的图像,这是在训练前,但后来失败了新的图像,因为它没有学到的一般特征的对象,只是记忆的训练图像的不重要的细节。
这个问题被称为过度拟合,并避免我们保持我们的一些数据的训练过程中,使模型无法记住他们。 然后我们使用这些图片作为一个检查以确保没有发生过,因为如果我们看到好的精度,这对他们是一个很好的信号网络不是过度拟合。通常的分裂是把80%的图像纳入主要训练集,保持10%,一边在训练过程中经常进行验证,然后有一个最后的10%,使用较少的测试集预测的真实世界的性能的分类。这些比例可以控制使用--testing_percentage和--validation_percentage标志。脚本所做的一个微妙的事情是,它使用图像的文件名来确定它被放置到哪个。这是为了确保图像不被移动之间的训练和测试套在不同的运行,因为这可能是一个问题,如果图像被用于训练一个模型,随后在验证集使用。一般来说,你应该能够在他们的默认值中离开这些值,因为你通常不会发现任何优势来调整它们。