TensorFlow 智能移动项目:1~5(1)https://developer.aliyun.com/article/1426902
将 MobileNet 模型用于再训练
上一节中生成的剥离和量化模型的大小仍超过 20MB。 这是因为用于再训练的预先构建的 Inception v3 模型是大规模的深度学习模型,具有超过 2500 万个参数,并且 Inception v3 并非以移动优先为目标。
2017 年 6 月,谷歌发布了 MobileNets v1,共 16 种针对 TensorFlow 的移动优先深度学习模型。 这些模型的大小只有几 MB,具有 47 万至 424 万个参数,仍然达到了不错的精度(仅比 Inception v3 低一点)。 有关更多信息,请参见其自述文件。
上一节中讨论的retrain.py
脚本还支持基于 MobileNet 模型的重新训练。 只需运行如下命令:
python tensorflow/examples/image_retraining/retrain.py --output_graph=/tf_files/dog_retrained_mobilenet10_224.pb --output_labels=/tf_files/dog_retrained_labels_mobilenet.txt --image_dir ~/Downloads/Images --bottleneck_dir=/tf_files/dogs_bottleneck_mobilenet --architecture mobilenet_1.0_224
生成的标签文件dog_retrained_labels_mobilenet.txt
实际上与使用 Inception v3 模型进行再训练期间生成的标签文件相同。 --architecture
参数指定 16 个 MobileNet 模型之一,而值mobilenet_1.0_224
表示使用模型大小为 1.0 的模型(对于其他参数,其他三个可能的值分别为 0.75、0.50 和 0.25 – 1.0,相反,准确但最大的大小为 0.25)和 224 作为图像输入大小(其他三个值分别为 192、160 和 128)。 如果将_quantized
添加到架构值的末尾,即--architecture mobilenet_1.0_224_quantized
,则模型也将被量化,从而导致重新训练的模型大小约为 5.1MB。 非量化模型的大小约为 17MB。
您可以按以下步骤测试先前使用label_image
生成的模型:
bazel-bin/tensorflow/examples/label_image/label_image --graph=/tf_files/dog_retrained_mobilenet10_224.pb --image=/tmp/lab1.jpg --input_layer=input --output_layer=final_result --labels=/tf_files/dog_retrained_labels_mobilenet.txt --input_height=224 --input_width=224 --input_mean=128 --input_std=128 n02099712 labrador retriever (41): 0.824675 n02099601 golden retriever (64): 0.144245 n02104029 kuvasz (76): 0.0103533 n02087394 rhodesian ridgeback (105): 0.00528782 n02090379 redbone (32): 0.0035457
请注意,在运行label_image
时,input_layer
名为input
。 我们可以使用交互式 iPython 代码或之前看到的图摘要工具找到该名称:
bazel-bin/tensorflow/tools/graph_transforms/summarize_graph --in_graph=/tf_files/dog_retrained_mobilenet10_224.pb Found 1 possible inputs: (name=input, type=float(1), shape=[1,224,224,3]) No variables spotted. Found 1 possible outputs: (name=final_result, op=Softmax) Found 4348281 (4.35M) const parameters, 0 (0) variable parameters, and 0 control_edges Op types used: 92 Const, 28 Add, 27 Relu6, 15 Conv2D, 13 Mul, 13 DepthwiseConv2dNative, 10 Dequantize, 3 Identity, 1 MatMul, 1 BiasAdd, 1 Placeholder, 1 PlaceholderWithDefault, 1 AvgPool, 1 Reshape, 1 Softmax, 1 Squeeze
那么,我们什么时候应该在移动设备上使用 Inception v3 或 MobileNet 重新训练的模型? 如果您想获得最高的准确率,则应该并且可以使用基于 Inception v3 的重新训练模型。 如果速度是您的首要考虑因素,则应考虑使用具有最小参数大小和图像输入大小的 MobileNet 重训练模型,以换取一些精度损失。
benchmark_model
是为您提供模型精确基准的一种工具。 首先,将其构建如下:
bazel build -c opt tensorflow/tools/benchmark:benchmark_model
然后,针对基于 Inception v3 或 MobileNet v1 的重新训练模型运行它:
bazel-bin/tensorflow/tools/benchmark/benchmark_model --graph=/tf_files/quantized_stripped_dogs_retrained.pb --input_layer="Mul" --input_layer_shape="1,299,299,3" --input_layer_type="float" --output_layer="final_result" --show_run_order=false --show_time=false --show_memory=false --show_summary=true
您将获得相当长的输出,最后会有一行像 FLOPS 的估计值:11.42B,这意味着它将使用基于 Inception v3 的重新训练模型约 11B FLOPS(浮点运算)进行推断。 iPhone 6 运行大约 2 B FLOPS,因此在 iPhone 6 上运行模型大约需要 5–6 秒。 其他现代智能手机可以运行 10B FLOPS。
通过将图文件替换为基于 MobileNet 模型的重新训练模型dog_retrained_mobilenet10_224.pb
并重新运行基准测试工具,您将看到 FLOPS 估计值变为约 1.14B,大约快了 10 倍。
在示例 iOS 应用中使用经过重新训练的模型
我们在第 1 章,“移动 TensorFlow 入门”中看到的 iOS 简单示例使用了 Inception v1 模型。 为了使该应用使用我们经过重新训练的 Inception v3 模型和 MobileNet 模型来更好地识别狗的品种,我们需要对该应用进行一些更改。 首先,让我们看看在 iOS 简单应用中使用经过重新训练的quantized_stripped_dogs_retrained.pb
会发生什么:
- 双击
tensorflow/examples/ios/simple
中的tf_simple_example.xcworkspace
文件以 Xcode 打开应用 - 拖动我们用来测试
label_image
脚本的quantized_stripped_dogs_retrained.pb
模型文件,dog_retrained_labels.txt
标签文件和lab1.jpg
图像文件,然后拖放到项目的数据文件夹中,并确保同时选中“按需复制项目”和“添加到目标”,如以下屏幕截图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sbBZuuPp-1681653027409)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/d2e25f9d-c88d-4fe5-918d-ba7e64420682.png)]
图 2.5:将重新训练的模型文件和标签文件添加到应用
- 单击 Xcode 中的
RunModelViewController.mm
文件,该文件使用 TensorFlow C++ API 处理输入图像,通过 Inception v1 模型运行它,并获得图像分类结果,并更改行:
NSString* network_path = FilePathForResourceName(@"tensorflow_inception_graph", @"pb"); NSString* labels_path = FilePathForResourceName(@"imagenet_comp_graph_label_strings", @"txt"); NSString* image_path = FilePathForResourceName(@"grace_hopper", @"jpg");
使用正确的模型文件名,标签文件名和测试图像名称进行以下操作:
NSString* network_path = FilePathForResourceName(@"quantized_stripped_dogs_retrained", @"pb"); NSString* labels_path = FilePathForResourceName(@"dog_retrained_labels", @"txt"); NSString* image_path = FilePathForResourceName(@"lab1", @"jpg");
- 同样在
RunModelViewController.mm
中,要匹配我们的 Inception v3(从 v1)重新训练模型所需的输入图像大小,请将const int wanted_width = 224;
和const int wanted_height = 224;
中的224
值更改为299
,并同时将const float input_mean = 117.0f;
中的值 ]和const float input_std = 1.0f;
至128.0f
- 从以下项更改输入和输出节点名称的值:
std::string input_layer = "input"; std::string output_layer = "output";
为以下正确值:
std::string input_layer = "Mul"; std::string output_layer = "final_result";
- 最后,您可以编辑
dog_retrained_labels.txt
文件以删除每行中的前导nxxxx
字符串(例如,删除n02099712 labrador retriever
中的n02099712
)– 在 Mac 上,您可以通过按住Option
键然后进行选择和删除–从而使识别结果更具可读性
立即运行应用,然后单击运行模型按钮,在 Xcode 的控制台窗口或应用的编辑框中,您将看到以下识别结果,与运行label_image
脚本的结果非常一致:
Predictions: 41 0.645 labrador retriever 64 0.195 golden retriever 76 0.0261 kuvasz 32 0.0133 redbone 20 0.0127 beagle
要使用 MobileNet(mobilenet_1.0_224_quantized
)训练模型dog_retrained_mobilenet10_224.pb
,请按照与之前类似的步骤进行操作,而在步骤 2 和 3 中,我们使用dog_retrained_mobilenet10_224.pb
,但是在步骤 4 中,我们需要保留const int wanted_width = 224;
和 const int wanted_height = 224;
,仅将const float input_mean
和const float input_std
更改为128
。 最后,在步骤 5 中,我们必须使用std::string input_layer = "input";
和std::string output_layer = "final_result";
。 这些参数与dog_retrained_mobilenet10_224.pb
的label_image
脚本使用的参数相同。
再次运行该应用,您将看到类似的最佳识别结果。
在示例 Android 应用中使用经过重新训练的模型
在 Android 的“TF 分类”应用中使用经过重新训练的 Inception v3 模型和 MobileNet 模型也非常简单。 请按照此处的步骤测试两个重新训练的模型:
- 使用 Android Studio 打开位于
tensorflow/examples/android
中的示例 TensorFlow Android 应用。 - 将两个重新训练的模型
quantized_stripped_dogs_retrained .pb
和dog_retrained_mobilenet10_224.pb
以及标签文件dog_retrained_labels.txt
拖放到 android 应用的assets
文件夹中。 - 打开文件
ClassifierActivity.java
,以使用 Inception v3 训练后的模型,并替换以下代码:
private static final int INPUT_SIZE = 224; private static final int IMAGE_MEAN = 117; private static final float IMAGE_STD = 1; private static final String INPUT_NAME = "input"; private static final String OUTPUT_NAME = "output";
这些行:
private static final int INPUT_SIZE = 299; private static final int IMAGE_MEAN = 128; private static final float IMAGE_STD = 128; private static final String INPUT_NAME = "Mul"; private static final String OUTPUT_NAME = "final_result"; private static final String MODEL_FILE = "file:///android_asset/quantized_stripped_dogs_retrained.pb"; private static final String LABEL_FILE = "file:///android_asset/dog_retrained_labels.txt";
- 或者,要使用 MobileNet 训练后的模型,请用以下代码行替换代码:
private static final int INPUT_SIZE = 224; private static final int IMAGE_MEAN = 128; private static final float IMAGE_STD = 128; private static final String INPUT_NAME = "input"; private static final String OUTPUT_NAME = "final_result"; private static final String MODEL_FILE = "file:///android_asset/dog_retrained_mobilenet10_224.pb"; private static final String LABEL_FILE = "file:///android_asset/dog_retrained_labels.txt";
- 将 Android 设备连接到计算机并在其上运行该应用。 然后点击 TF 分类应用,将相机指向一些狗的照片,您将在屏幕上看到最佳结果。
这就是在示例 TensorFlow iOS 和 Android 应用中使用两个经过重新训练的模型所需要的全部。 既然您已经了解了如何在示例应用中使用经过重新训练的模型,那么您可能想知道的下一件事是如何将 TensorFlow 添加到自己的新的或现有的 iOS 或 Android 应用中,以便可以开始添加 AI 对您自己的移动应用的强大功能。 这就是本章其余部分将详细讨论的内容。
将 TensorFlow 添加到您自己的 iOS 应用
在 TensorFlow 的早期版本中,将 TensorFlow 添加到您自己的应用非常繁琐,需要使用 TensorFlow 的手动构建过程和其他手动设置。 在 TensorFlow 1.4 中,该过程非常简单,但在 TensorFlow 网站上并未详细记录详细步骤。 缺少的另一件事是缺少有关如何在基于 Swift 的 iOS 应用中使用 TensorFlow 的文档; 示例 TensorFlow iOS 应用都在 Objective-C 中,它们调用了 TensorFlow 的 C++ API。 让我们看看我们如何做得更好。
将 TensorFlow 添加到您的 Objective-C iOS 应用
首先,按照以下步骤将具有图像分类功能的 TensorFlow 添加到您的 Objective-C iOS 应用(我们将从一个新应用开始,但是如果需要将 TensorFlow 添加到现有应用,则可以跳过第一步):
- 在您的 Xcode 中,单击“文件 | 新增 | 项目 …”,选择“Single View App”,然后选择接下来的,输入
HelloTensorFlow
作为产品名称,选择 Obj-C 作为语言,然后单击接下来并选择项目的位置,然后单击创建。 关闭 Xcode 中的项目窗口(因为我们稍后将使用 Pod 来打开项目的工作区文件)。 - 打开一个终端窗口,即
cd
到项目所在的位置,然后创建一个名为Podfile
的新文件,其内容如下:
target 'HelloTensorFlow' pod 'TensorFlow-experimental'
- 运行命令
pod install
下载并安装 TensorFlow Pod。 - 在 Xcode 中打开
HelloTensorFlow.xcworkspace
文件,然后将两个文件(ios_image_load.mm
和ios_image_load.h
)拖放到 TensorFlow iOS 示例目录tensorflow/examples/ios/simple
到HelloTensorFlow
项目文件夹中。 - 将两个模型
quantized_stripped_dogs_retrained.pb
和dog_retrained_mobilenet10_224.pb
,label file dog_retrained_labels.txt
以及几个测试图像文件拖放到项目文件夹中,之后,您应该看到类似以下的内容:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KEomP26v-1681653027410)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/b89b3444-a6a9-45b4-bb02-ddf8388a6992.png)]
图 2.6:添加工具文件,模型文件,标签文件和图像文件
- 将
ViewController.m
重命名为ViewController.mm
,因为我们将在该文件中混合使用 C++ 代码和 Objective-C 代码来调用 TensorFlow C++ API 并处理图像输入和推断结果。 然后,在@interface ViewController
之前,添加以下#include
和函数原型:
#include <fstream> #include <queue> #include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/public/session.h" #include "ios_image_load.h" NSString* RunInferenceOnImage(int wanted_width, int wanted_height, std::string input_layer, NSString *model);
- 在
ViewController.mm
的末尾,添加从tensorflow/example/ios/simple/RunModelViewController.mm
复制的以下代码,对函数RunInferenceOnImage
稍作更改,以接受具有不同输入大小和输入层名称的不同再训练模型:
namespace { class IfstreamInputStream : public ::google::protobuf::io::CopyingInputStream { ... static void GetTopN( ... bool PortableReadFileToProto(const std::string& file_name, ... NSString* FilePathForResourceName(NSString* name, NSString* extension) { ... NSString* RunInferenceOnImage(int wanted_width, int wanted_height, std::string input_layer, NSString *model) {
- 仍然在
viewDidLoad
方法的ViewController.mm
中,首先添加添加标签的代码,以使用户知道他们可以使用该应用执行的操作:
UILabel *lbl = [[UILabel alloc] init]; [lbl setTranslatesAutoresizingMaskIntoConstraints:NO]; lbl.text = @"Tap Anywhere"; [self.view addSubview:lbl];
然后将标签置于屏幕中央的约束:
NSLayoutConstraint *horizontal = [NSLayoutConstraint constraintWithItem:lbl attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]; NSLayoutConstraint *vertical = [NSLayoutConstraint constraintWithItem:lbl attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]; [self.view addConstraint:horizontal]; [self.view addConstraint:vertical];
最后,在此处添加点击手势识别器:
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)]; [self.view addGestureRecognizer:recognizer];
- 在轻敲处理器中,我们首先创建两个
alert
操作,以允许用户选择重新训练的模型:
UIAlertAction* inceptionV3 = [UIAlertAction actionWithTitle:@"Inception v3 Retrained Model" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { NSString *result = RunInferenceOnImage(299, 299, "Mul", @"quantized_stripped_dogs_retrained"); [self showResult:result]; }]; UIAlertAction* mobileNet = [UIAlertAction actionWithTitle:@"MobileNet 1.0 Retrained Model" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { NSString *result = RunInferenceOnImage(224, 224, "input", @"dog_retrained_mobilenet10_224"); [self showResult:result]; }];
然后创建一个none
操作,并将所有三个alert
操作添加到警报控制器并显示它:
UIAlertAction* none = [UIAlertAction actionWithTitle:@"None" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {}]; UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Pick a Model" message:nil preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:inceptionV3]; [alert addAction:mobileNet]; [alert addAction:none]; [self presentViewController:alert animated:YES completion:nil];
- 推断的结果在方法
showResult
中显示为另一个警报控制器:
-(void) showResult:(NSString *)result { UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Inference Result" message:result preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction* action = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]; [alert addAction:action]; [self presentViewController:alert animated:YES completion:nil]; }
与调用 TensorFlow 相关的核心代码在RunInferenceOnImage
方法中,该方法基于 TensorFlow iOS 简单应用进行了略微修改,包括首先创建一个 TensorFlow 会话和一个图:
tensorflow::Session* session_pointer = nullptr; tensorflow::Status session_status = tensorflow::NewSession(options, &session_pointer); ... std::unique_ptr<tensorflow::Session> session(session_pointer); tensorflow::GraphDef tensorflow_graph; NSString* network_path = FilePathForResourceName(model, @"pb"); PortableReadFileToProto([network_path UTF8String], &tensorflow_graph); tensorflow::Status s = session->Create(tensorflow_graph);
然后加载标签文件和图像文件,并将图像数据转换为适当的 Tensor 数据:
NSString* labels_path = FilePathForResourceName(@"dog_retrained_labels", @"txt"); ... NSString* image_path = FilePathForResourceName(@"lab1", @"jpg"); std::vector<tensorflow::uint8> image_data = LoadImageFromFile([image_path UTF8String], &image_width, &image_height, &image_channels); tensorflow::Tensor image_tensor(tensorflow::DT_FLOAT, tensorflow::TensorShape({1, wanted_height, wanted_width, wanted_channels})); auto image_tensor_mapped = image_tensor.tensor<float, 4>(); tensorflow::uint8* in = image_data.data(); float* out = image_tensor_mapped.data(); for (int y = 0; y < wanted_height; ++y) { const int in_y = (y * image_height) / wanted_height; ... }
最后,使用图像张量数据和输入层名称调用 TensorFlow 会话的run
方法,获取返回的输出结果,并对其进行处理以获取置信度值大于阈值的前五个结果:
std::vector<tensorflow::Tensor> outputs; tensorflow::Status run_status = session->Run({{input_layer, image_tensor}},{output_layer}, {}, &outputs); ... tensorflow::Tensor* output = &outputs[0]; const int kNumResults = 5; const float kThreshold = 0.01f; std::vector<std::pair<float, int> > top_results; GetTopN(output->flat<float>(), kNumResults, kThreshold, &top_results);
在本书的其余部分,我们将实现RunInferenceOnxxx
方法的不同版本,以使用不同的输入来运行不同的模型。 因此,如果您不完全理解前面的一些代码,请不要担心; 通过构建更多的应用,您将为新的自定义模型编写自己的推理逻辑而感到自在。
此外,完整的 iOS 应用 HelloTensorFlow 也包含在本书的源代码存储库中。
现在,在模拟器中或实际的 iOS 设备上运行该应用,首先,您将看到以下消息框,要求您选择重新训练的模型:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p0nAa1Pm-1681653027410)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/1823f6a6-f212-4ac9-9d78-a978a234c4aa.png)]
图 2.7:选择不同的再训练模型进行推理
然后,您将在选择模型后看到推断结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KS4OFUYg-1681653027410)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/b9de1c02-8b3a-4482-b7f5-4d0d8d3e4692.png)]
图 2.8:基于不同再训练模型的推理结果
请注意,MobileNet 训练后的模型在同一款 iPhone 上的运行速度要快得多,在 iPhone 6 上要比 Inception v3 训练后的模型快约一秒钟。
将 TensorFlow 添加到您的 Swift iOS 应用
自 2014 年 6 月诞生以来,Swift 已成为最优雅的现代编程语言之一。因此,对于某些开发人员而言,将现代 TensorFlow 集成到其基于 Swift 的现代 iOS 应用中既有趣又有用。 这样做的步骤与基于 Objective-C 的应用的步骤相似,但具有一些与 Swift 相关的技巧。 如果您已经按照 Objective-C 部分的步骤进行操作,则可能会发现这里的某些步骤是重复的,但是对于那些可能会跳过 Objective-C 部分并直接进入 Swift 的用户而言,仍然提供了完整的步骤:
- 在您的 Xcode 中,单击“文件 | 新增 | 项目…”,选择“Single View App”,然后接下来的,输入
HelloTensorFlow_Swift
作为产品名称,选择 Swift 将设置为语言,然后单击接下来并选择项目的位置,然后单击创建。 关闭 Xcode 中的项目窗口(因为稍后将使用 Pod 来打开项目的工作区文件)。 - 打开一个终端窗口,即
cd
到项目所在的位置,然后创建一个名为Podfile
的新文件,其内容如下:
target 'HelloTensorFlow_Swift' pod 'TensorFlow-experimental'
- 运行命令
pod install
下载并安装 TensorFlow Pod; - 在 Xcode 中打开
HelloTensorFlow_Swift.xcworkspace
文件,然后将两个文件(ios_image_load.mm
和ios_image_load.h
)拖放到 TensorFlow iOS 示例目录tensorflow/examples/ios/simple
到HelloTensorFlow_Swift
项目文件夹中。 当将两个文件添加到项目中时,您将看到一个消息框,如以下屏幕截图所示,询问您是否要配置 Objective-C 桥接头,Swift 代码调用 C++ 头需要此头。 Objective-C 代码。 因此,单击创建桥接标题按钮:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-34n2r9ES-1681653027411)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/afa22723-f59f-4544-8a61-e73ee7c43e85.png)]
图 2.9:添加 C++ 文件时创建桥接标题
- 同样将
quantized_stripped_dogs_retrained .pb
和dog_retrained_mobilenet10_224.pb
这两个模型,标签文件dog_retrained_labels.txt
和几个测试图像文件拖放到项目文件夹中–之后,您应该会看到类似以下内容:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FEDYBpgY-1681653027411)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/8236a55a-15fe-41a1-9ff7-c7280ae6c43f.png)]
图 2.10:添加工具文件,模型文件,标签文件和图像文件
- 使用以下代码创建一个名为
RunInference.h
的新文件(一个窍门是,我们必须在下一步中使用 Objective-C 类作为RunInferenceOnImage
方法的包装,以便我们的 Swift 代码进行间接调用) 。否则,将发生构建错误):
#import <Foundation/Foundation.h> @interface RunInference_Wrapper : NSObject - (NSString *)run_inference_wrapper:(NSString *)name; @end
- 创建另一个名为
RunInference.mm
的文件,该文件以以下include
对象和原型开头:
#include <fstream> #include <queue> #include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/public/session.h" #include "ios_image_load.h" NSString* RunInferenceOnImage(int wanted_width, int wanted_height, std::string input_layer, NSString *model);
- 在以下代码中添加
RunInference.mm
,以实现在其.h
文件中定义的RunInference_Wrapper
:
@implementation RunInference_Wrapper - (NSString *)run_inference_wrapper:(NSString *)name { if ([name isEqualToString:@"Inceptionv3"]) return RunInferenceOnImage(299, 299, "Mul", @"quantized_stripped_dogs_retrained"); else return RunInferenceOnImage(224, 224, "input", @"dog_retrained_mobilenet10_224"); } @end
- 在
RunInference.mm
的末尾,添加与 Objective-C 部分中ViewController.mm
完全相同的方法,与tensorflow/example/ios/simple/RunModelViewController.mm
中的方法略有不同:
class IfstreamInputStream : public namespace { class IfstreamInputStream : public ::google::protobuf::io::CopyingInputStream { ... static void GetTopN( ... bool PortableReadFileToProto(const std::string& file_name, ... NSString* FilePathForResourceName(NSString* name, NSString* extension) { ... NSString* RunInferenceOnImage(int wanted_width, int wanted_height, std::string input_layer, NSString *model) {
- 现在打开
viewDidLoad method
末尾的ViewController.swift
,首先添加添加标签的代码,以使用户知道他们可以使用该应用做什么:
let lbl = UILabel() lbl.translatesAutoresizingMaskIntoConstraints = false lbl.text = "Tap Anywhere" self.view.addSubview(lbl)
然后将标签置于屏幕中央的约束:
let horizontal = NSLayoutConstraint(item: lbl, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1, constant: 0) let vertical = NSLayoutConstraint(item: lbl, attribute: .centerY, relatedBy: .equal, toItem: self.view, attribute: .centerY, multiplier: 1, constant: 0) self.view.addConstraint(horizontal) self.view.addConstraint(vertical)
最后,在此处添加点击手势识别器:
let recognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.tapped(_:))) self.view.addGestureRecognizer(recognizer)
- 在轻击处理器中,我们首先添加
alert
动作,以允许用户选择 Inception v3 训练后的模型:
let alert = UIAlertController(title: "Pick a Model", message: nil, preferredStyle: .actionSheet) alert.addAction(UIAlertAction(title: "Inception v3 Retrained Model", style: .default) { action in let result = RunInference_Wrapper().run_inference_wrapper("Inceptionv3") let alert2 = UIAlertController(title: "Inference Result", message: result, preferredStyle: .actionSheet) alert2.addAction(UIAlertAction(title: "OK", style: .default) { action2 in }) self.present(alert2, animated: true, completion: nil) })
然后在展示之前,为 MobileNet 重训练模型创建另一个动作以及一个none
动作:
alert.addAction(UIAlertAction(title: "MobileNet 1.0 Retrained Model", style: .default) { action in let result = RunInference_Wrapper().run_inference_wrapper("MobileNet") let alert2 = UIAlertController(title: "Inference Result", message: result, preferredStyle: .actionSheet) alert2.addAction(UIAlertAction(title: "OK", style: .default) { action2 in }) self.present(alert2, animated: true, completion: nil) }) alert.addAction(UIAlertAction(title: "None", style: .default) { action in }) self.present(alert, animated: true, completion: nil)
- 打开
HelloTensorFlow_Swift-Bridging-Header.h
文件,并向其中添加一行代码:#include "RunInference.h"
。
现在,在模拟器中运行该应用,您将看到一个警报控制器,要求您选择模型:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jnVb7EBf-1681653027411)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/098c0b7a-c32a-4ffc-bf3d-49c1ea80d36f.png)]
图 2.11:选择一个经过训练的模型进行推理
以及不同再训练模型的推理结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HA5gG3Tz-1681653027411)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/f3d05b5e-fda7-46d6-8e47-f234a1b4175e.png)]
图 2.12:不同再训练模型的推理结果
继续,既然您知道了将强大的 TensorFlow 模型添加到 iOS 应用需要做什么,无论它是用 Objective-C 还是 Swift 编写的,都没有理由阻止您将 AI 添加到您的移动应用中,除非您是 Android。 但是您知道我们当然也会照顾 Android。
将 TensorFlow 添加到您自己的 Android 应用
事实证明,将 TensorFlow 添加到自己的 Android 应用比 iOS 容易。 让我们跳到步骤:
- 如果您有现有的 Android 应用,请跳过此步骤。 否则,在 Android Studio 中,选择“文件 | 新增 | 新项目…”并接受所有默认设置,然后单击完成。
- 打开
build.gradle
(Module: app
)文件,并在依赖项{...};
内部和末尾添加编译'org.tensorflow:tensorflow-android:+'
。 - 生成
gradle
文件,您将在app
目录的位置app/build/intermediates/transforms/mergeJniLibs/debug/0/lib
的子文件夹内看到libtensorflow_inference.so
,这是 Java 代码与之对话的 TensorFlow 本机库。 - 如果这是一个新项目,则可以通过首先切换到包,然后右键单击该应用并选择“新建 | 文件夹 |
assets
文件夹”来创建assets
文件夹。 ,如以下屏幕截图所示,然后从包切换回 Android:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xTCPEphz-1681653027412)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/6cf6b889-8ecb-4837-9087-19b34d6e68ed.png)]
图 2.13:将素材文件夹添加到新项目
- 将两个重新训练的模型文件和标签文件以及几个测试图像拖放到资产文件夹中,如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SH8Sgc83-1681653027412)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/fff27710-5222-410c-8d40-f451dea548f8.png)]
图 2.14:将模型文件,标签文件和测试图像添加到素材
- 按住选项按钮,将
tensorflow/examples/android/src/org/tensorflow/demo
和Classifier.java
从tensorflow/examples/android/src/org/tensorflow/demo
拖放到项目的 Java 文件夹中,如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kharFPaj-1681653027412)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/7f41c4fe-6454-44e2-82d8-892290761eb5.png)]
图 2.15:将 TensorFlow 分类器文件添加到项目中
- 打开
MainActivity
,首先创建与重新训练的 MobileNet 模型相关的常数-输入图像大小,节点名称,模型文件名和标签文件名:
private static final int INPUT_SIZE = 224; private static final int IMAGE_MEAN = 128; private static final float IMAGE_STD = 128; private static final String INPUT_NAME = "input"; private static final String OUTPUT_NAME = "final_result"; private static final String MODEL_FILE = "file:///android_asset/dog_retrained_mobilenet10_224.pb"; private static final String LABEL_FILE = "file:///android_asset/dog_retrained_labels.txt"; private static final String IMG_FILE = "lab1.jpg";
- 现在,在
onCreate
方法内部,首先创建一个Classifier
实例:
Classifier classifier = TensorFlowImageClassifier.create( getAssets(), MODEL_FILE, LABEL_FILE, INPUT_SIZE, IMAGE_MEAN, IMAGE_STD, INPUT_NAME, OUTPUT_NAME);
然后从assets
文件夹中读取我们的测试图像,根据模型指定的大小进行调整,然后调用推理方法recognizeImage
:
Bitmap bitmap = BitmapFactory.decodeStream(getAssets().open(IMG_FILE)); Bitmap croppedBitmap = Bitmap.createScaledBitmap(bitmap, INPUT_SIZE, INPUT_SIZE, true); final List<Classifier.Recognition> results = classifier.recognizeImage(croppedBitmap);
为简单起见,我们没有向 Android 应用添加任何与 UI 相关的代码,但是您可以在获取结果后在此行设置一个断点,并调试运行该应用; 您将看到以下屏幕截图所示的结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XIyeYzNW-1681653027412)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/4c91b3a9-1a32-4288-aa75-205d0b71d584.png)]
图 2.16:使用 MobileNet 再训练模型的识别结果
如果您通过将MODEL_FILE
更改为quantized_stripped_dogs_retrained.pb
,将INPUT_SIZE
更改为299
,并且将INPUT_NAME
更改为Mul
来使用 Inception v3 训练后的模型,则调试该应用,您将获得如下所示的结果 :
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1s92KyhD-1681653027412)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/ca49452a-b256-4c9e-8e96-6de4c75effa7.png)]
图 2.17:使用 Inception v3 再训练模型的识别结果
既然您已经了解了如何将 TensorFlow 和经过重新训练的模型添加到自己的 iOS 和 Android 应用,那么如果想要添加非 TensorFlow 相关功能应该不会太难。例如使用手机的摄像头拍摄狗的照片和识别它的品种。
总结
在本章中,我们首先简要介绍了什么是迁移学习以及为什么我们能够并且应该使用它来重新训练经过预训练的深度学习图像分类模型。 然后,我们提供了有关如何重新训练基于 Inception v3 的模型和 MobileNet 模型的详细信息,以便我们可以更好地理解和认识我们最好的朋友。 之后,我们首先展示了如何在 TensorFlow 示例 iOS 和 Android 应用中使用经过重新训练的模型,然后给出了有关如何将 TensorFlow 添加到您自己的基于 Objective-C 和 Swift 的 iOS 应用中的分步教程,以及您自己的 Android 应用。
现在我们有了最好的朋友,其中涵盖了一些不错而干净的技巧,我们知道还有很多其他人,无论好坏。 在下一章中,我们将学习如何变得更聪明,如何识别图片中所有有趣的对象以及如何在智能手机上随时随地对其进行定位。
TensorFlow 智能移动项目:1~5(3)https://developer.aliyun.com/article/1426904