第三阶段-tensorflow项目之图像image相关--图片分类训练效率之迁移学习

时间:2022-11-22 06:35:15

现代物体识别模型有数百万个参数,可能需要数周才能完成训练。 transfer learning转移学习是一种技巧,通过为ImageNet等一系列类别提供全面训练的模型,并从现有的新类别权重中重新进行训练,从而缩短了大量工作量。 在这个例子中,我们将从头开始对最后一层进行再训练,同时将所有其他层保持原样。 有关该方法的更多信息,请参阅Decaf上的这篇论文。https://pan.baidu.com/s/1o8zdQcE

注意:本教程的这个版本主要使用bazel。 一个免费bazel版本,可以作为codelab使用。

1,Training on Flowers

第三阶段-tensorflow项目之图像image相关--图片分类训练效率之迁移学习

在开始任何培训之前,您需要一组图像来向网络传授您想要识别的新课程。后面的章节解释了如何准备自己的图像,但为了简化起见,我们创建了一个创作共享许可的花卉照片档案,以供初始使用。要获取花卉照片集,请运行以下命令:
花卉数据集百度网盘地址:https://pan.baidu.com/s/1eSEnv8m

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

有了图像之后,你可以从你的TensorFlow源代码目录的根目录中建立这样一个修剪器:

bazel build tensorflow / examples / image_retraining:retrain

如果您的计算机支持AVX指令集(过去几年中生产的x86 CPU中常见),那么可以通过构建该架构来提高再培训的运行速度,如下所示(在配置中选择适当的选项后):

bazel build --config opt tensorflow/examples/image_retraining:retrain

然后可以这样运行retrainer:

bazel-bin/tensorflow/examples/image_retraining/retrain --image_dir ~/flower_photos

该python加载预先训练的Inception v3模型,移除旧的顶层,并在您下载的花朵照片上训练一个新的顶层。 没有一个花卉种类是在原来的ImageNet类的整个网络培训。 传递学习的神奇之处在于,已经被训练以区分一些对象的较低层可以被重复用于许多识别任务,而没有任何改变。

2,Bottlenecks(瓶颈)

脚本可能需要三十分钟或更长时间才能完成,具体取决于机器的速度。第一阶段分析磁盘上的所有图像,并计算每个图像的瓶颈值。 “瓶颈”是一个非正式的术语,我们经常在最后的输出层之前使用这个层次,而这个层次实际上是进行分类的。这个倒数第二层已经被训练输出一组足够好的值,以便分类器用来区分被要求识别的所有类。这意味着它必须是一个有意义和紧凑的图像总结,因为它必须包含足够的信息,使分类器在一个非常小的值集合中作出一个好的选择。我们的最后一层重新训练可以在新类上工作的原因是,它证明了在ImageNet中所有1000个类别之间区分所需的信息通常也可以用来区分新类型的对象。

由于在训练过程中每个图像都被重复使用多次,计算每个瓶颈需要花费大量的时间,因此它可以加快速度,将这些瓶颈值缓存在磁盘上,因此不必重复计算。默认情况下,它们存储在/tmp/bottleneck目录中,如果你重新运行脚本,它们将被重用,所以你不必再等待这个部分。

3,train(训练)

一旦瓶颈完成,网络顶层的实际train就开始了。您将看到一系列步骤输出,每个输出显示训练准确性,验证准确性和交叉熵。训练准确性显示当前训练批次中使用的图像的百分比是否标有正确的分类。验证的准确性是从一个不同的集合随机选择一组图像的精度。关键的区别是训练的准确性是基于网络已经能够学习的图像,所以网络可以适应训练数据中的noise。衡量网络性能的一个真正的衡量标准就是衡量一个未包含在训练数据中的数据集的性能 - 这是通过验证的准确性来衡量的。如果列车的准确度高,但验证的准确度仍然很低,那就意味着网络过度拟合并记忆训练图像中的特定特征,这些特征对于更一般的帮助是没有帮助的。交叉熵是一种损失函数,可以窥见学习过程如何进展。train的目的是尽可能减少损失,所以你可以通过关注损失是否持续下降,忽略短期的noise来判断学习是否正常。

默认情况下,这个脚本将运行4000个训练步骤。每个步骤从训练集中随机选取10幅图像,从高速缓存中找出它们的Bottlenecks,并将它们送入最终图层进行预测。然后将这些预测与实际标签进行比较,以通过反向传播过程更新最终层的权重。随着过程的继续,您应该看到报告的准确性提高,并且在完成所有步骤之后,对与训练和验证图片分开的一组图像运行最终的测试准确度评估。这个测试评估是训练模型如何在分类任务上执行的最佳估计。您应该可以看到90%到95%的准确度值,但是由于训练过程中存在随机性,所以确切的值会因运行而异。这个数字是基于在模型完全训练后给出正确标签的测试集中图像的百分比。

4,使用TensorBoard可视化再训练

该脚本包含TensorBoard摘要,使得更容易理解,调试和优化再培训。 例如,您可以将图形和统计信息可视化,例如在训练期间权重或准确性如何变化。

要启动TensorBoard,请在再培训期间或之后运行此命令:

TensorBoard--lo gdir / tmp / retrain_logs

一旦TensorBoard正在运行,浏览您的Web浏览器到localhost:6006以查看TensorBoard。

该脚本默认将TensorBoard摘要记录到/ tmp / retrain_logs。 您可以使用–summaries_dir标志更改目录。

5,Using the Retrained Model

脚本会写出Inception v3网络的一个版本,最后一层被重新训练到/tmp/output_graph.pb的类别和一个包含/tmp/output_labels.txt标签的文本文件。这些都是C ++和Python图像分类示例可以读入的格式,因此您可以立即开始使用新模型。由于您已经替换了顶层,因此您需要在脚本中指定新名称,例如,如果使用的是label_image,则使用–output_layer = final_result标志。

下面是一个如何构建和运行你的训练图的label_image示例的例子:

bazel build tensorflow/examples/image_retraining:label_image && \
bazel-bin/tensorflow/examples/image_retraining/label_image \
--graph=/tmp/output_graph.pb --labels=/tmp/output_labels.txt \
--output_layer=final_result:0 \
--image=$HOME/flower_photos/daisy/21652746_cc379e0eea_m.jpg

你应该看到一个花标签列表,在大多数情况下菊花在上面(虽然每个重新培养的模型可能会略有不同)。你可以用你自己的图像来替换–image参数来尝试这些,并使用C ++代码作为模板来与你自己的应用程序集成。

如果您想在自己的Python程序中使用再培训模型,那么上面的label_image脚本是一个合理的起点。

如果您发现默认的Inception v3模型对您的应用程序来说太大或太慢,请查看下面的“12,Other Model Architectures其他模型架构”部分,以加速和缩小您的网络。

6,根据自己的类别进行培训

如果你已经设法让这个脚本处理花图像,你可以开始看教导它来识别你关心的类别。 从理论上说,所有你需要做的就是把它指向一组子文件夹,每个子文件夹以你的一个类别命名,并且只包含那个类别的图像。 如果你这样做,并将子目录的根文件夹作为参数传递给–image_dir,那么脚本应像对花一样进行训练。

以下是鲜花存档的文件夹结构,以便为您提供脚本所寻找布局的示例:

第三阶段-tensorflow项目之图像image相关--图片分类训练效率之迁移学习
文件夹结构

在实践中,可能需要一些工作来获得所需的准确性。 我会尽力引导您解决下面可能遇到的一些常见问题。

7,创建一组训练图像

首先要看看你收集的图像,因为我们看到的培训中最常见的问题来自所馈入的数据。

为使训练工作顺利,您应该收集至少一百张您想要识别的各种物体的照片。你可以收集的越多,你的训练模型的准确性就越好。您还需要确保照片是您的应用程序实际遇到的一个很好的代表。例如,如果您将所有照片都放在室内,并且用户尝试识别室外的物体,则在部署时您可能看不到良好的效果。

要避免的另一个缺陷是,学习过程会在标签图像彼此共有的像素上特征,如果你不小心,这可能是没用的东西。例如,如果您在蓝色房间中拍摄一种物体,而另一种物体则以绿色物体拍摄,则模型将根据背景颜色预测结果,而不是您实际关心的物体的特征。为避免这种情况,请尝试在各种情况下尽可能在不同的时间和不同的设备下拍摄照片。如果你想知道更多关于这个问题,你可以阅读关于经典(也可能是伪装)坦克识别问题。

您可能还想考虑您使用的类别。将大量不同的物理形式分成较小的物体可能是有价值的,这些小物体在视觉上更加独特。例如,可以使用“汽车”,“摩托车”和“卡车”来代替“车辆”。同样值得一提的是,你是否有“封闭的世界”或“开放世界”的问题。在一个封闭的世界里,你唯一需要分类的东西就是你所了解的对象的类别。这可能适用于植物识别应用程序,你知道用户可能正在拍摄一朵花,所以你所要做的就是决定哪些物种。相比之下,漫游机器人可能会通过其相机在世界各地漫游时看到各种不同的东西。在这种情况下,您希望分类器报告它是否不确定它所看到的内容。这可能很难做到,但是如果您经常收集大量没有相关对象的典型“背景”照片,则可以将它们添加到图像文件夹中额外的“未知”类。

这也是值得检查,以确保所有的图像被正确标记。通常用户生成的标签对于我们的目的来说是不可靠的,例如使用#daisy来表示名为Daisy的人的照片。如果你仔细阅读你的图片并清除任何错误,那么你的整体准确性可能会令人惊叹。

8,培训步骤

如果您对图片感到满意,可以通过改变学习过程的细节来改善您的结果。最简单的尝试是–how_many_training_steps。默认值是4000,但是如果你增加到8000,它会训练两倍。准确度提高的速度会减慢你训练的时间,并且在某些时候会完全停止,但是你可以尝试看看你什么时候达到了你的模型的极限。

9,扭曲

改善图像训练结果的一种常见方式是以随机方式对训练输入进行变形,裁剪或增亮。由于相同图像的所有可能的变化,这具有扩展训练数据的有效大小的优点,并且倾向于帮助网络学习应对在分类器的实际使用中将发生的所有失真。在我们的脚本中实现这些扭曲的最大缺点是瓶颈缓存不再有用,因为输入图像从来不会重复使用。这意味着培训过程需要更长的时间,所以我建议您尝试这种方法来微调您的模型,一旦你有一个合理的满意的模型。

您可以通过将–random_crop,–random_scale和–random_brightness传递给脚本来启用这些扭曲。这些都是控制每个图像应用了多少失真的百分比值。对每个人开始5或10的值是合理的,然后尝试看看他们中哪些人帮助你的应用程序。 –flip_left_right将水平地随机镜像一半的图像,只要这些反转很可能在您的应用程序中发生,这是有意义的。例如,如果你试图识别字母,这不是一个好主意,因为翻转它们会破坏它们的意思。

10,超参数

还有其他几个参数可以尝试调整,看看他们是否帮助你的结果。 –learning_rate控制在训练期间更新到最后一层的大小。直观地说,如果这比学习要花费的时间更长,但最终可能会帮助整体的精确度。但情况并非总是如此,所以您需要仔细试验以查看适合您的情况。 –train_batch_size控制在一个训练步骤中检查多少个图像,并且由于每个批次应用的学习速率,如果您有更大的批次以获得相同的整体效果,则需要将其减少。

11,培训,验证和测试集

当你将脚本指向一个图像文件夹时,脚本所做的一件事就是把它们分成三组。最大的通常是训练集,它们是在训练期间输入网络的所有图像,结果用于更新模型的权重。你可能想知道为什么我们不使用所有的图像进行培训?当我们进行机器学习时,一个很大的潜在问题就是我们的模型可能只是记住训练图像中不相关的细节来提出正确的答案。例如,您可以想象一个网络在每个照片的背景中记住一个模式,并使用它来将标签与对象进行匹配。它可以在训练期间看到的所有图像上产生良好的效果,但是由于没有学习到对象的一般特征而只能记住训练图像的不重要的细节,因此在新图像上失败。

这个问题被称为过度拟合,为了避免这个问题,我们将一些数据保留在训练过程之外,这样模型就不能记住它们。然后,我们使用这些图像作为检查来确保没有发生过度拟合,因为如果我们看到它们有很好的准确性,那么网络就不是过度拟合的好兆头。通常的做法是将80%的图像放入主要训练集中,保留10%作为训练期间频繁的验证运行,然后最后使用10%作为测试集来预测实时性,分类器的世界性能。这些比率可以使用–testing_percentage和–validation_percentage标志进行控制。一般而言,您应该能够将这些值保留为默认值,因为您通常不会发现任何优势来进行调整。

请注意,该脚本使用图像文件名(而不是完全随机的函数)将图像划分为训练集,验证集和测试集。这样做是为了确保图像不会在不同运行的训练集和测试集之间移动,因为如果用于训练模型的图像随后用在验证集中,那么这可能是一个问题。

您可能会注意到验证准确性在迭代中波动。这种波动的大部分是由于每个验证准确度测量都选择了验证集合的随机子集。通过选择–validation_batch_size = -1,可以大大降低波动,但需要花费一定的培训时间,因为每个精度计算都使用整个验证集。

一旦训练完成,您可能会发现在测试集中检查错误分类的图像是非常有见识的。这可以通过添加标志–print_misclassified_test_images来完成。这可能有助于您了解模型中哪些类型的图像最容易混淆,哪些类别最难区分。例如,您可能会发现某个特定类别的某个子类型或一些不寻常的照片角度特别难以识别,这可能会鼓励您添加该子类型的更多训练图像。通常,检查错误分类的图像也可以指出输入数据集中的错误,如错误标记,低质量或模糊的图像。但是,通常应该避免在测试集中确定单个错误,因为它们可能仅仅反映(更大的)训练集中的更一般的问题。

12,Other Model Architectures其他模型架构

默认情况下,脚本使用Inception v3模型体系结构的预训练版本。这是一个很好的起点,因为它提供了高精度的结果,但是如果您打算在移动设备或其他资源受限的环境中部署您的模型,您可能需要对文件尺寸更小或更快的速度进行一些精确的折衷。为了解决这个问题,rebin.py脚本支持Mobilenet架构上的32种不同的变体。

这些比Inception v3精确一些,但是可能会导致更小的文件大小(小于一兆字节),并且运行速度可能会快很多倍。要用这些模式之一进行训练,请传递 - 架构标志,例如:

python tensorflow/examples/image_retraining/retrain.py \
--image_dir ~/flower_photos --architecture mobilenet_0.25_128_quantized

这将在/tmp/output_graph.pb中创建一个941KB的模型文件,其中全部Mobilenet的参数的25%,采用128x128大小的输入图像,并在磁盘上将其权重量化为8位。您可以选择’1.0’,’0.75’,’0.50’或’0.25’来控制权重参数的数量,因此文件大小(以及某种程度上的速度),’224’,’192’,’输入图像大小为“160”或“128”,较小的大小可以提供更快的速度,最后还有一个可选的“_quantized”,用于指示文件是否应包含8位或32位浮点权重。

速度和尺寸的优点当然会损失精度,但是对于许多目的来说,这并不重要。他们也可以通过改进的培训数据有所抵消。例如,即使使用上述的0.25 / 128 /量化图,扭曲训练也可使花数据集的准确度达到80%以上。

如果您要在label_image中使用Mobilenet模型或您自己的程序,则需要将转换为浮点范围的指定大小的图像输入到“输入”张量中。通常24位图像的范围是[0,255],您必须将它们转换为模型期望的[-1,1]浮点范围,并使用公式(image - 128。)/ 128。