利用tensorflow的image_retrain实现再训练和分类识别

现代物体识别模型有数以百万计的参数。从零开始训练需要大量的标记训练数据和强大的计算能力(数以百计的GPU小时或更多)。学习迁移是一种技术,非常快捷的使用一个在相关的任务里已训练过的模型中的一部分,在一个新的模型里重用,从新的类的现有的权重进行再训练。在本教程中,我们将重用在ImageNet上训练的强大的图像分类器的特征提取功能,并在顶层简单地训练一个新的分类层。更多信息参见Decaf文章

虽然它不如一个完整的训练运行,但对于许多应用程序来说,这是出奇的有效,适用于中等数量的训练数据(数以千计,而不是数百万的标记图像),并可以在一个没有GPU的笔记本电脑上运行三十分钟。本教程将向您演示如何在自己的图像上运行示例脚本,并将解释一些您控制训练过程需要的选项。
注:这个版本的一个教程,也可作为一个codelab

本教程使用tensorflow hub获取预训练模型或模块。首先,将使用图像特征提取模块的 InceptionV3架构在ImageNet上训练,之后继续下面的操作,包括 NASNet/PNASNet,以及 MobileNet V1V2

在开始之前,需要安装PIP包tensorflow-hub,紧随新版本的tensorflow就可以。参见TensorFlow Hub的安装说明详情。
训练花
在开始任何训练之前,需要一组图像来教网络想要识别的新类。后面有一部分解释如何准备你自己的图片,但是为了入手更容易,先使用别人已经创建的一个共享的花卉存档图片集。要获取花的图片集,请运行以下命令:

cd ~
curl -LO http://download.tensorflow.org/example_images/flower_photos.tgz
tar xzf flower_photos.tgz

一旦有了图片,可以从GitHub下载示例代码(它不是库安装的一部分):

mkdir ~/example_code
cd ~/example_code
curl -LO https://github.com/tensorflow/hub/raw/master/examples/image_retraining/retrain.py

在retrainer的最简单例子中,可以这样运行(大约需要半小时):

python retrain.py --image_dir ~/flower_photos

脚本有许多其他的选项,你可以获取完整的列表,通过如下方式:

python retrain.py -h

此脚本加载预训练模块,移除旧的顶层,并为下载的花卉照片在顶层训练一个新的分类器。花的品种没有在原来的ImageNet类的全网络训练。迁移学习的魔力在于,经过训练的较低层可以区分一些对象,这些对象可以在许多识别任务中不经任何更改即可重用。

Bottlenecks
脚本需要三十分钟或更长时间才能完成,这取决于机器的速度。第一阶段分析磁盘上的所有图像,并计算每一个瓶颈值。瓶颈是一个非正式的术语,我们经常用在层上,在实际上做分类的最后的输出层之前(TensorFlow Hub 上称之为图像特征向量)。这个倒数第二层已经被训练以输出一组足够好的分类器值,用来区分它被要求识别的所有类。这意味着它必须是一个有意义的和紧凑的总结图像,因为它必须包含足够的信息让分类器在很小的一组值里作出一个很好的选择。我们的最后一层再训练可以工作在新类的原因是原来区分ImageNet里的所有1000类需要的信息种类往往在区分新的对象种类中也是有用的。

因为在训练中每一个图像被重复使用多次,且计算每一个瓶颈需要大量的时间,缓存这些瓶颈值在磁盘上加速了训练的过程,因为他们不需要反复重新计算。默认情况下,他们被存储在/ tmp /bottleneck目录,如果你重新运行脚本,他们将被重用,所以你不必再等待这个部分了。
Training
一旦瓶颈完成,网络顶层涉及的训练就开始了。你将看到一系列的每一个步骤的输出,每一条显示训练精度,验证精度和交叉熵。训练精度显示当前训练批次中标记正确的类所使用的图像的百分比。验证精度是从不同的集合随机选择一组图像的准确度。关键的区别是,训练精度是基于网络已经能够学习的图像,因此网络能过拟合训练数据中的噪声。一个真正衡量网络性能的规则是衡量其在不包含训练数据的数据集上的性能-这是由验证精度衡量的。如果训练精度高但验证准确率仍然很低,这意味着网络过拟合,记忆了训练图像独有的特征,这一般是更无用的。交叉熵是一个损失函数,能看到一个学习过程是如何进行的。训练的目的是使损失尽可能小,忽略短期噪音,通过查看损失是否是不断降低的趋势 ,你就可以知道学习是否在进行。
默认情况下,此脚本将运行4000个训练步骤。每一步从训练集随机选择十个图像,从缓存找到他们的瓶颈,并将其输入到最后一层以获得预测。然后,这些预测和实际标签对比,通过反向传播过程更新最后层的权重。随着过程的继续,你应该看到输出的准确性提高,所有的步骤完成后,一个最后的测试精度评价运行在一组图像上,这组图像保持训练和验证图片分开。这个测试评估是训练模型将如何执行分类任务的最好估计。你应该能看到一个准确值介于90%和95%之间,虽然确切的值在多次运行时会有所不同,因为在训练过程中有随机性。这个数字是基于测试集中图像的百分比,在模型被完全训练后给出正确的标签。
TensorBoard可视化再训练
脚本包括tensorboard摘要,让人更容易理解、调试和优化训练。例如,您可以可视化图和统计,比如在训练过程中的权重或精度如何变化。

要启动tensorboard,再训练期间或完成之后运行这个命令:

tensorboard --logdir /tmp/retrain_logs

一旦TensorBoard运行,可以在你的web浏览器中输入localhost:6006来浏览TensorBoard。
retrain.py脚本将TensorBoard摘要日志默认保存到/tmp/retrain_logs。你可以使用–summaries_dir参数更改目录。
TensorBoard 的GitHub 仓库有关于TensorBoard使用的更多信息,包括建议、技巧和调试信息。
使用再训练模型
脚本写了InceptionV3网络的一个版本,其最后一层再训练你的类别到/tmp/ output_graph.pb,及一个文本文件包含标签到/tmp/ output_labels.txt。这些都是在一个格式为C++和Python图像分类的例子里可以阅读,所以你可以立即开始使用你的新模型。既然你已经更换了最顶层,你需要在脚本中指定新的名称,例如如果你使用label_image,使用——output_layer = final_result。

这有一个例子,怎样用你再训练的图像编译和运行label_image。按照惯例,所有的tensorflow Hub模块接受在固定范围[0,1]的颜色值的图像输入,所以你不需要设置–input_mean或–input_std参数。

curl -LO https://github.com/tensorflow/tensorflow/raw/master/tensorflow/examples/label_image/label_image.py
python label_image.py \
--graph=/tmp/output_graph.pb --labels=/tmp/output_labels.txt \
--input_layer=Placeholder \
--output_layer=final_result \
--image=$HOME/flower_photos/daisy/21652746_cc379e0eea_m.jpg

你应该能看到花标签的一个列表,大部分例子中daisy在最顶部(虽然每个再训练模型可能稍有不同)。你可以尝试用你自己的图像替换–image参数,使用c++代码作为一个模板去整合你自己的程序。
如果喜欢使用再训练模型在Python项目,那么上述label_image脚本是一个合理的出发点。label_image目录也包含C++代码,可以用它作为模板,集成tensorflow与自己的应用程序。

如果发现默认的初始V3模块对应用程序来说太大或太慢,请查看下面的其他模型架构部分,以了解如何加速和精简网络。

训练你自己的类别
如果已经设法让脚本工作在花的例子图像,可以开始让它识别你关心的类别。理论上,你需要做的是将它指向一组子文件夹,每一个文件夹都是以一个类别命名的,只包含该类别的图像。如果你这样做,通过子目录的根文件夹作为参数–image_dir,脚本的执行应该像训练花一样。

这里是花卉存档的文件夹的结构,给你个正在寻找的布局脚本的例子:
这里写图片描述
在实践中,可能需要一些工作,以获得您想要的精度。下面来指导你解决以下你可能会遇到的一些常见的问题。
创建训练图片集
首先要看的是收集的图像,因为我们遇到的最常见的训练问题是来自训练的数据。
为了训练好,你想要识别的每种物体的照片,你应该至少收集一百张。你收集的越多,你训练的模型的准确性就越好。你还需要确保照片是你的应用程序实际遇到场景的一个很好呈现。例如,如果你把所有的照片放在一个室内空白的墙上,你的用户试图在户外识别物体,那么当你使用的时候,你可能看不到很好的效果。
另外一个要避免的陷阱是学习过程会学习标签图像彼此间共同的任何部分,在与对方的习惯,如果你不小心,可能是一些没有用的东西。例如,如果你在一个蓝色的房间拍摄一种对象图像,在一个绿色的房间拍摄另一种,模型会以基于其背景颜色进行预测而结束,而不是你实际关心的对象的特征。为了避免这个,尝试在不同的时间,使用不同的设备,放入尽可能多的各种情况的图片。如果关于这个问题你想知道更多,你可以阅读关于经典的(可能伪造的)坦克识别问题 .
您可能还要考虑您使用的类别。它应该是值得将涵盖了许多不同物理形式的大类别分成更直观能区分的更小类别。例如,你可以使用’汽车’,’摩托车’和’卡车’,而不是’车辆’。你是否有一个“封闭世界”或“开放世界”的问题也值得思考。在一个封闭的世界里,你唯一需要被分类的东西就是你所知道的对象的类。这可能适用于一个植物识别应用程序,你知道用户可能会采取一朵花的图片,所以所有你要做的是决定哪种。相比之下,漫游机器人通过相机可能会看到各种不同的东西,因为它徘徊在世界各地。在这种情况下,如果不知道看到什么,你希望分类记录。这可能很难做得很好,通常如果你收集了大量典型的“背景”照片,照片里没有相关的对象,你可以在您的图像文件夹里将它们添加到一个额外的“未知”类。
检查以确保您的所有图像都标记正确也是值得做的。通常用户生成的标签对于我们而言是不可靠的,例如使用的#菊花daisy为一个名叫戴茜Daisy的人的照片。如果你检查你的图像,并排除任何错误,它可以为你训练的整体精度制造奇迹。
训练步骤
如果你对自己的训练图片感到满意,你可以通过改变学习过程的细节来改进你的结果。最简单的一种尝试是how_many_training_steps。默认为4000,但如果你增加到8000,训练步骤是原来的两倍。准确率的提高减慢了你训练的时间,在某个时间点会完全停止,但是你可以试验性的看看你的模型是否达到了那个极限。
扭曲
提高图像训练效果的一种常用方法是通过随机方式对训练输入进行变形、裁剪或增强。这有利于扩大训练数据的有效尺寸,由于相同的图像所有可能的变化,并往往有助于网络学习应付使用分类器将会在现实生活中产生的所有失真。在我们的脚本中启用这些扭曲的最大缺点是瓶颈缓存不再有用,因为输入图像永远不会被重用。这意味着训练过程需要更长的时间,所以我建议尝试扭曲作为微调你的模型的一种方式,万一你能获得一个是你很满意的呢。
你可以使用扭曲通过– random_crop,– random_scale – random_brightness这些脚本。这些都是百分比值,控制每个图像的失真是多少。这是合理的开始值为5或10,为他们每个人,然后实验,看看其中有助于您的应用程序。——flip_left_right会随机镜图像的一半水平,这道理只要这些倒有可能发生在您的应用程序。例如,如果你试图认出字母,那就不是一个好主意,因为翻转字母会破坏字母的意义。
超参数
还有其他几个参数,你可以尝试调整,看看他们是否有助于您的结果。——learning_rate控件的更新幅度的最后一层在训练。直观地说,如果这是较小的,那么学习将需要更长的时间,但它可以最终帮助整体精度。但情况并非总是如此,所以你需要仔细观察,看看你的案子是如何运作的。——train_batch_size控制多少图片是一个训练阶段的研究过程中,由于学习速率应用每批你需要减少它,如果你有大批量获得同样的整体效果。
训练, 验证和测试集
当你把它指向一个图像文件夹时,脚本在引擎盖下做的事情之一是将它们分成三个不同的集合。最大的通常是训练集,这是所有的图像送入网络训练过程中,使用的结果来更新模型的权重。你可能会想知道为什么我们不使用所有的图像进行训练?当我们进行机器学习时,一个潜在的大问题是,我们的模型可能只是记住训练图像中不相关的细节,以得出正确的答案。例如,你可以想象一个网络在它所显示的每一张照片的背景中记住一个模式,并使用它与对象匹配标签。它可以产生良好的效果在所有的图像,它在训练前看到的,但在新的图像失败,因为它没有学到的对象的一般特性,只是记住了训练图像的不重要的细节。
这个问题被称为过度拟合,并避免我们保持我们的一些数据的训练过程中,使模型无法记住他们。然后我们使用这些图片作为一个检查以确保没有发生过,因为如果我们看到好的精度,这对他们是一个很好的信号网络不是过度拟合。通常的分割是把80%的图像到主训练集,保持10%旁边运行作为验证经常在训练过程中,然后有一个最终的10%使用较少作为测试集预测的分类器的现实世界的性能。这些比率可以使用– testing_percentage – validation_percentage旗。一般来说,你应该能够把这些值放在它们的默认值,因为你通常不会发现任何优势训练调整他们。
注意,脚本使用的图像文件名(而不是一个完全随机函数)将图像之间的训练,验证和测试集。这样做是为了确保在不同的运行之间的训练和测试集的图像不移动,因为这可能是一个问题,如果图像已被用于训练模型,随后在验证集中使用。
您可能会注意到验证精度在迭代之间波动。许多这种波动产生的事实,一个随机子集的验证集被选择为每个验证精度测量。波动可以大大减少,在一些训练时间增加成本,通过选择– validation_batch_size = 1,采用设置每个精度计算整个验证。
训练结束之后,你会发现它对测试集的图像分类有见地。这可以通过添加的旗帜——print_misclassified_test_images做。这可能会帮助你感觉到哪种类型的图像对模型最为混乱,哪些类别是最难区分的。例如,您可能会发现特定类别的某些子类型,或一些不寻常的照片角度,特别难以识别,这可能会鼓励您添加更多的训练图像的亚型。通常情况下,检查图像分类还可以指出在输入数据集的错误,如错误,低质量的,或模糊的图像。然而,一般应避免点固定在测试集的个别错误,因为它们可能只是反映更普遍的问题(更大)的训练集。
其他模型架构

参考文档

运行
报错:
2017-03-23 05:16:24.405772: E tensorflow/examples/label_image/main.cc:309] Running model failed: Not found: FetchOutputs node softmax: not found
参考文档:
https://github.com/tensorflow/tensorflow/blob/master/tensorflow/docs_src/tutorials/image_retraining.md
1.创建训练样本集
cd /home/ubuntu
mkdir fruit-data
将不同种类的训练样本图片按照名称分类,放到相应的文件夹中。图片为jpg格式。
[图片]
2.训练
git clone https://github.com/tensorflow/tensorflow.git
cd tensorflow
bazel build tensorflow/examples/image_retraining:retrain
bazel-bin/tensorflow/examples/image_retraining/retrain –image_dir /home/ubuntu/ fruit-data
–image_dir 为训练样本的放置目录
[图片]
训练结果保存到了/tmp目录下
graph: /tmp/output_graph.pb
labels: /tmp/output_labels.txt
logs: /tmp/retrain_logs
3.识别
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=./mg.jpg
–image为待识别的图片路径
[图片]

猜你喜欢

转载自blog.csdn.net/daydayup_668819/article/details/79972886