From 0d7792ff132f02b86a8491295e2f326ef682bdc9 Mon Sep 17 00:00:00 2001 From: wizardforcel <562826179@qq.com> Date: Wed, 9 Dec 2020 19:17:49 +0800 Subject: [PATCH] 2020-12-09 19:17:49 --- new/intel-mobi-proj-tf/06.md | 52 ++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/new/intel-mobi-proj-tf/06.md b/new/intel-mobi-proj-tf/06.md index 9f82fca5..1a3dfac8 100644 --- a/new/intel-mobi-proj-tf/06.md +++ b/new/intel-mobi-proj-tf/06.md @@ -6,7 +6,7 @@ 如果图像分类和物体检测是明智的任务,那么用自然语言描述图像绝对是一项更具挑战性的任务,需要更多的智能-请片刻考虑一下每个人如何从新生儿成长(谁学会了识别 物体并检测它们的位置)到三岁的孩子(他们学会讲述图片故事)。 用自然语言描述图像的任务的正式术语是图像标题。 与具有长期研究和发展历史的语音识别不同,图像字幕(具有完整的自然语言,而不仅仅是关键词输出)由于其复杂性和 2012 年的深度学习突破而仅经历了短暂而令人兴奋的研究历史。 -在本章中,我们将首先回顾基于深度学习的图像字幕模型如何赢得 2015 年 Microsoft COCO(大规模对象检测,分割和字幕数据集),我们在 中简要介绍了该模型 第 3 章 , “检测对象及其位置” ],有效。 然后,我们将总结在 TensorFlow 中训练模型的步骤,并详细介绍如何准备和优化要在移动设备上部署的复杂模型。 之后,我们将向您展示有关如何构建 iOS 和 Android 应用程序以使用该模型生成描述图像的自然语言语句的分步教程。 由于该模型同时涉及计算机视觉和自然语言处理,因此您将首次看到两种主要的深度神经网络架构 CNN 和 RNN 如何协同工作,以及如何编写 iOS 和 Android 代码以访问经过训练的网络并进行 多个推论。 总而言之,我们将在本章介绍以下主题: +在本章中,我们将首先回顾基于深度学习的图像字幕模型如何赢得 2015 年 Microsoft COCO(大规模对象检测,分割和字幕数据集),我们在第 3 章,“检测对象及其位置”中简要介绍了该有效模型。 然后,我们将总结在 TensorFlow 中训练模型的步骤,并详细介绍如何准备和优化要在移动设备上部署的复杂模型。 之后,我们将向您展示有关如何构建 iOS 和 Android 应用程序以使用该模型生成描述图像的自然语言语句的分步教程。 由于该模型同时涉及计算机视觉和自然语言处理,因此您将首次看到两种主要的深度神经网络架构 CNN 和 RNN 如何协同工作,以及如何编写 iOS 和 Android 代码以访问经过训练的网络并进行 多个推论。 总而言之,我们将在本章介绍以下主题: * 图片字幕-工作原理 * 训练和冻结图像字幕模型 @@ -26,17 +26,17 @@ 获奖的 Show and Tell 模型是使用端到端方法进行训练的,类似于我们在上一章中简要介绍的最新的基于深度学习的语音识别模型。 它使用 MSCOCO 图像字幕 2014 数据集,可从[这里](http://cocodataset.org/#download)下载,该数据集包含超过 82,000 个训练图像,并以描述它们的自然语言句子为目标。 训练模型以使为每个输入图像输出目标自然语言句子的可能性最大化。 与使用多个子系统的其他更复杂的训练方法不同,端到端方法优雅,简单,并且可以实现最新的结果。 -为了处理和表示输入图像,Show and Tell 模型使用预训练的 Inception v3 模型,该模型与我们在 第 2 章 ,*通过迁移学习*对图像进行分类。 Inception v3 CNN 网络的最后一个隐藏层用作输入图像的表示。 由于 CNN 模型的性质,较早的层捕获更多的基本图像信息,而较后的层捕获更高级的图像概念。 因此,通过使用输入图像的最后一个隐藏层来表示图像,我们可以更好地准备具有高级概念的自然语言输出。 毕竟,我们通常会开始用诸如“人”或“火车”之类的词来描述图片,而不是“带有尖锐边缘的东西”。 +为了处理和表示输入图像,Show and Tell 模型使用预训练的 Inception v3 模型,该模型与我们在第 2 章,“通过迁移学习对图像进行分类”所使用的相同。 Inception v3 CNN 网络的最后一个隐藏层用作输入图像的表示。 由于 CNN 模型的性质,较早的层捕获更多的基本图像信息,而较后的层捕获更高级的图像概念。 因此,通过使用输入图像的最后一个隐藏层来表示图像,我们可以更好地准备具有高级概念的自然语言输出。 毕竟,我们通常会开始用诸如“人”或“火车”之类的词来描述图片,而不是“带有尖锐边缘的东西”。 为了表示目标自然语言输出中的每个单词,使用了单词嵌入方法。 词嵌入只是词的向量表示。 [TensorFlow 网站上有一个不错的教程](https://www.tensorflow.org/tutorials/word2vec),介绍如何构建模型来获取单词的向量表示。 -现在,在既表示输入图像又表示输出单词的情况下(每个这样的单词对构成一个训练示例),给定的最佳训练模型可用于最大化在目标输出中生成每个单词`w`的概率 输入图像和该单词 *w,*之前的先前单词是 RNN 序列模型,或更具体地说,是**长短期记忆**(**LSTM**)的 RNN 模型类型。 LSTM 以解决常规 RNN 模型固有的消失和爆炸梯度问题而闻名。 为了更好地了解 LSTM,[您应该查看这个热门博客](http://colah.github.io/posts/2015-08-Understanding-LSTMs)。 +现在,在既表示输入图像又表示输出单词的情况下(每个这样的单词对构成一个训练示例),给定的最佳训练模型可用于最大化在目标输出中生成每个单词`w`的概率,给定输入图像和该单词`w`之前的先前单词,它是 RNN 序列模型,或更具体地说,是**长短期记忆**(**LSTM**)的 RNN 模型类型。 LSTM 以解决常规 RNN 模型固有的消失和爆炸梯度问题而闻名。 为了更好地了解 LSTM,[您应该查看这个热门博客](http://colah.github.io/posts/2015-08-Understanding-LSTMs)。 The gradient concept is used in the back propagation process to update network weights so it can learn to generate better outputs. If you're not familiar with the back propagation process, one of the most fundamental and powerful algorithms in neural networks, you should definitely spend some time understanding it – just Google "backprop" and the top five results won't disappoint. Vanishing gradient means that, during the deep neural network back propagation learning process, network weights in earlier layers barely get updated so the network never converges; exploding gradient means that those weights get updated too wildly, causing the network to diverge a lot. So, if someone has a closed mind and never learns, or if someone gets crazy about new things as fast as he loses interest, you know what kind of gradient problem they seem to have. 训练后,可以将 CNN 和 LSTM 模型一起用于推理:给定输入图像,该模型可以估计每个单词的概率,从而预测最有可能生成哪个`n`-最佳第一个单词 用于输出语句; 然后,给定输入图像和`n`-最好的第一个单词,可以生成`n`-最好的下一个单词,然后继续进行,直到模型返回时我们得到一个完整的句子 已达到句子单词的特定结尾,或达到了生成的句子的指定单词长度(以防止模型过于冗长)。 -在每次生成单词时使用 *n 个*-最佳单词(意味着在末尾具有`n`-最佳句子)被称为波束搜索。 当`n`(即波束大小)为 1 时,它仅基于模型返回的所有可能单词中的最高概率值,就成为贪婪搜索或最佳搜索。 TensorFlow im2txt 官方模型的下一部分中的训练和推理过程使用以 Python 实现的波束大小设置为 3 的波束搜索; 为了进行比较,我们将开发的 iOS 和 Android 应用使用更简单的贪婪或最佳搜索。 您将看到哪种方法可以生成更好的字幕。 +在每次生成单词时使用`n`个最佳单词(意味着在末尾具有`n`个最佳句子)被称为集束搜索。 当`n`(即集束大小)为 1 时,它仅基于模型返回的所有可能单词中的最高概率值,就成为贪婪搜索或最佳搜索。 TensorFlow im2txt 官方模型的下一部分中的训练和推理过程使用以 Python 实现的集束大小设置为 3 的集束搜索; 为了进行比较,我们将开发的 iOS 和 Android 应用使用更简单的贪婪或最佳搜索。 您将看到哪种方法可以生成更好的字幕。 @@ -56,7 +56,7 @@ The gradient concept is used in the back propagation process to update network w -如果您已按照 第 3 章 和“检测对象及其位置”中的*设置 TensorFlow 对象检测 API* 部分进行操作,那么您已经 已安装`im2txt`文件夹; 否则,只需将`cd`移至您的 TensorFlow 源根目录,然后运行: +如果您已按照 第 3 章 和“检测对象及其位置”中的“设置 TensorFlow 对象检测 API”部分进行操作,那么您已经 已安装`im2txt`文件夹; 否则,只需将`cd`移至您的 TensorFlow 源根目录,然后运行: ```py git clone https://github.com/tensorflow/models @@ -119,7 +119,7 @@ bazel-bin/im2txt/train \ --number_of_steps=1000000 ``` -即使在 GPU 上(例如第 1 章, *Mobile TensorFlow* 入门中设置的 Nvidia GTX 1070),整个[1G]步骤(在前面的`--number_of_steps`参数中指定)也会 • 超过 5 个昼夜,因为运行 5 万步大约需要 6.5 个小时。 幸运的是,您很快就会看到,即使以大约 50K 的步长,图像字幕的结果也已经相当不错了。 另请注意,您可以随时取消`train`脚本,然后稍后重新运行它,该脚本将从最后保存的检查点开始; 默认情况下,检查点会每 10 分钟保存一次,因此在最坏的情况下,您只会损失 10 分钟的训练时间。 +即使在 GPU 上(例如第 1 章, “移动 TensorFlow 入门”中设置的 Nvidia GTX 1070),整个步骤(在前面的`--number_of_steps`参数中指定)也会超过 5 个昼夜,因为运行 5 万步大约需要 6.5 个小时。 幸运的是,您很快就会看到,即使以大约 50K 的步长,图像字幕的结果也已经相当不错了。 另请注意,您可以随时取消`train`脚本,然后稍后重新运行它,该脚本将从最后保存的检查点开始; 默认情况下,检查点会每 10 分钟保存一次,因此在最坏的情况下,您只会损失 10 分钟的训练时间。 经过几个小时的训练,取消前面的`train`脚本,然后查看`--train_dir`指向的位置。 您将看到类似这样的内容(默认情况下,将保存五组检查点文件,但此处仅显示三组): @@ -271,15 +271,15 @@ total 2124 Running the `bazel build` command to build a TensorFlow Python script is optional. You can just run the Python script directly. For example, we can run `python tensorflow/python/tools/freeze_graph.py` without building it first with `bazel build tensorflow/python/tools:freeze_graph` then running `bazel-bin/tensorflow/python/tools/freeze_graph`. But be aware that running the Python script directly will use the version of TensorFlow you’ve installed via pip, which may be different from the version you’ve downloaded as source and built by the `bazel build` command. This can be the cause of some confusing errors so be sure you know the TensorFlow version used to run a script. In addition, for a C++ based tool, you have to build it first with bazel before you can run it. For example, the `transform_graph` tool, which we'll see soon, is implemented in `transform_graph.cc` located at `tensorflow/tools/graph_transforms`; another important tool called `convert_graphdef_memmapped_format`, which we'll use for our iOS app later, is also implemented in C++ located at `tensorflow/contrib/util`. -现在我们到了,让我们快速使用 TensorBoard 看一下我们的图形–只需运行`tensorboard --logdir logdir`,然后从浏览器中打开`http://localhost:6006`。 图 6.1 显示了三个输出节点名称(顶部为 **softmax** ,以及 **lstm** / **initial_state** 和 **lstm** / 突出显示的红色矩形顶部的**状态**)和一个输入节点名称(底部的 **state_feed** ): +现在我们到了,让我们快速使用 TensorBoard 看一下我们的图形–只需运行`tensorboard --logdir logdir`,然后从浏览器中打开`http://localhost:6006`。 图 6.1 显示了三个输出节点名称(顶部为`softmax`,以及`lstm/initial_state`和红色矩形顶部的突出显示的`lstm/state`)和一个输入节点名称(底部的`state_feed`): ![](img/d47ea13b-441c-4fb1-bccc-bbceaf2a8bdf.png)Figure 6.1: Diagram showing the three output node names and one input node name -图 6.2 显示了另一个输入节点名称 **image_feed** : +图 6.2 显示了另一个输入节点名称`image_feed`: ![](img/a7c39f91-68d3-4cd4-8e9b-0ef0b6dd11ff.png)Figure 6.2: Diagram showing one additional input node name image_feed -最后,图 6.3 显示了最后一个输入节点名称 **input_feed** : +最后,图 6.3 显示了最后一个输入节点名称`input_feed`: ![](img/887360ce-b609-4f8a-95d4-c1c3d2e8f97b.png)Figure 6.3: Diagram showing the last input node name input_feed @@ -289,7 +289,7 @@ Running the `bazel build` command to build a TensorFlow Python script is optiona python tensorflow/python/tools/freeze_graph.py --input_meta_graph=/home/jeff/tensorflow-1.5.0/models/research/im2txt/model/image2text.meta --input_checkpoint=/home/jeff/tensorflow-1.5.0/models/research/im2txt/model/image2text --output_graph=/tmp/image2text_frozen.pb --output_node_names="softmax,lstm/initial_state,lstm/state" --input_binary=true ``` -请注意,我们在这里使用元图文件以及将`--input_binary`参数设置为`true`,因为默认情况下它为 false,这意味着`freeze_graph`工具期望输入图或元图文件为文本格式。 +请注意,我们在这里使用元图文件以及将`--input_binary`参数设置为`true`,因为默认情况下它为`false`,这意味着`freeze_graph`工具期望输入图或元图文件为文本格式。 您可以使用文本格式的图形文件作为输入,在这种情况下,无需提供`--input_binary`参数: @@ -317,7 +317,7 @@ python tensorflow/python/tools/freeze_graph.py --input_graph=/home/jeff/tensorf -通常,您可以使用`strip_unused.py,` 工具,与 `tensorflow/python/tools,`中的 `freeze_graph.py`位于相同位置,来[删除不包含在 TensorFlow 核心库中的`DecodeJpeg`操作](https://www.tensorflow.org/mobile/prepare_models#removing_training-only_nodes)。但是由于输入节点 image_feed 需要进行解码操作(图 6.2), `strip_unused`之类的工具不会将`DecodeJpeg`视为未使用,因此不会被剥夺。 您可以先运行`strip_unused`命令,如下所示进行验证: +通常,您可以使用`strip_unused.py,` 工具,与 `tensorflow/python/tools,`中的 `freeze_graph.py`位于相同位置,来[删除不包含在 TensorFlow 核心库中的`DecodeJpeg`操作](https://www.tensorflow.org/mobile/prepare_models#removing_training-only_nodes)。但是由于输入节点`image_feed`需要进行解码操作(图 6.2), `strip_unused`之类的工具不会将`DecodeJpeg`视为未使用,因此不会被剥夺。 您可以先运行`strip_unused`命令,如下所示进行验证: ```py bazel-bin/tensorflow/python/tools/strip_unused --input_graph=/tmp/image2text_frozen.pb --output_graph=/tmp/image2text_frozen_stripped.pb --input_node_names="image_feed,input_feed,lstm/state_feed" --output_node_names="softmax,lstm/initial_state,lstm/state" --input_binary=True @@ -344,9 +344,9 @@ x[:6] u'convert_image'] ``` -解决您的 iOS 应用错误的第二种可能解决方案是,像在 中所做的那样,在 `tf_op_files`文件中添加未注册的 op 实现 t 并重建 TensorFlow iOS 库。 第 5 章, *了解简单语音命令。* 坏消息是,由于 TensorFlow 中没有`DecodeJpeg`功能的实现,因此无法将`DecodeJpeg`的 TensorFlow 实现添加到`tf_op_files`中。 +解决您的 iOS 应用错误的第二种可能解决方案是,像在 中所做的那样,在 `tf_op_files`文件中添加未注册的操作实现,并重建 TensorFlow iOS 库。 就像第 5 章, “了解简单语音命令”一样。 坏消息是,由于 TensorFlow 中没有`DecodeJpeg`功能的实现,因此无法将`DecodeJpeg`的 TensorFlow 实现添加到`tf_op_files`中。 -实际上,在图 6.2 中也暗示了对此烦恼的解决方法,其中`convert_image`节点用作`image_feed`输入的解码版本。 为了更准确,单击 TensorBoard 图中的 Cast 和**解码**节点,如图 6.4 所示,您将从右侧的 TensorBoard 信息卡中看到输入 Cast(名为`convert_image/Cast`)的输出为`decode/DecodeJpeg`和`convert_image`,解码的输入和输出为`image_feed`和`convert_image/Cast`: +实际上,在图 6.2 中也暗示了对此烦恼的解决方法,其中`convert_image`节点用作`image_feed`输入的解码版本。 为了更准确,单击 TensorBoard 图中的转换和**解码**节点,如图 6.4 所示,您将从右侧的 TensorBoard 信息卡中看到输入转换(名为`convert_image/Cast`)的输出为`decode/DecodeJpeg`和`convert_image`,解码的输入和输出为`image_feed`和`convert_image/Cast`: ![](img/eeb4e7ad-04ef-4ad5-ac89-a9a4a1e2f1e4.png)Figure 6.4: Looking into the decode and conver_image nodes @@ -389,7 +389,7 @@ bazel-bin/tensorflow/python/tools/optimize_for_inference \ 但是在 iOS 或 Android 应用上加载输出模型文件 `image2text_frozen_optimized.pb`会导致相同的`Input 0 of node ExpandDims_6 was passed float from input_feed:0 incompatible with expected int64` 错误。 看起来,尽管我们试图至少在某种程度上实现福尔摩斯在本章中可以做的事情,但有人希望我们首先成为福尔摩斯。 -如果您在其他型号(例如我们在前几章中看到的型号)上尝试过`strip_unused`或`optimize_for_inference`工具,则它们可以正常工作。 事实证明,尽管官方 TensorFlow 1.4 和 1.5 发行版中包含了两个基于 Python 的工具,但在优化一些更复杂的模型时却存在一些错误。 更新和正确的工具是基于 C++ 的`transform_graph`工具,现在是 [TensorFlow Mobile 网站](https://www.tensorflow.org/mobile)推荐的官方工具。 运行以下命令以消除在移动设备上部署时与 int64 错误不兼容的 float: +如果您在其他型号(例如我们在前几章中看到的型号)上尝试过`strip_unused`或`optimize_for_inference`工具,则它们可以正常工作。 事实证明,尽管官方 TensorFlow 1.4 和 1.5 发行版中包含了两个基于 Python 的工具,但在优化一些更复杂的模型时却存在一些错误。 更新和正确的工具是基于 C++ 的`transform_graph`工具,现在是 [TensorFlow Mobile 网站](https://www.tensorflow.org/mobile)推荐的官方工具。 运行以下命令以消除在移动设备上部署时的`int64`不兼容`float`的错误: ```py bazel build tensorflow/tools/graph_transforms:transform_graph @@ -406,7 +406,7 @@ bazel-bin/tensorflow/tools/graph_transforms/transform_graph \ fold_old_batch_norms' ``` -我们将不讨论所有`--transforms`选项的详细信息,这些选项在 [中有完整记录:https://github.com/tensorflow/tensorflow/tree/master/tensorflow/tools/ graph_transforms](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/tools/graph_transforms) 。 基本上,`--transforms`设置可以正确消除模型中未使用的节点,例如`DecodeJpeg`,并且还可以进行其他一些优化。 +我们将不讨论所有`--transforms`选项的详细信息,这些选项在[这里](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/tools/graph_transforms)有完整记录。 基本上,`--transforms`设置可以正确消除模型中未使用的节点,例如`DecodeJpeg`,并且还可以进行其他一些优化。 现在,如果您在 iOS 和 Android 应用程序中加载`image2text_frozen_transformed.pb`文件,则不兼容的错误将消失。 当然,我们还没有编写任何真实的 iOS 和 Android 代码,但是我们知道该模型很好,可以随时使用。 很好,但是可以更好。 @@ -444,7 +444,7 @@ bazel-bin/tensorflow/contrib/util/convert_graphdef_memmapped_format \ -由于该模型的 CNN 部分基于 Inception v3,因此我们在第 2 章,“通过迁移学习对图像进行分类”时使用的模型相同,因此我们可以并且将使用更简单的 TensorFlow pod 进行以下操作: 创建我们的 Objective-C iOS 应用。 请按照此处的步骤查看如何在新的 iOS 应用中同时使用`image2text_frozen_transformed.pb`和`image2text_frozen_transformed_memmapped.pb`模型文件: +由于该模型的 CNN 部分基于 Inception v3,因此我们在第 2 章,“通过迁移学习对图像进行分类”时使用的模型相同,因此我们可以并且将使用更简单的 TensorFlow Pod 进行以下操作: 创建我们的 Objective-C iOS 应用。 请按照此处的步骤查看如何在新的 iOS 应用中同时使用`image2text_frozen_transformed.pb`和`image2text_frozen_transformed_memmapped.pb`模型文件: 1. 类似于第 2 章,“通过传输学习对图像进行分类”,“将 TensorFlow 添加到 Objective-C iOS 应用”部分中的前四个步骤, 名为`Image2Text`的 iOS 项目,添加具有以下内容的名为`Podfile`的新文件: @@ -453,9 +453,9 @@ target 'Image2Text' pod 'TensorFlow-experimental' ``` -然后在终端上运行`pod install`并打开`Image2Text.xcworkspace`文件。 将`ios_image_load.h`, `ios_image_load.mm`,`tensorflow_utils.h`和`tensorflow_utils.mm`文件从位于`tensorflow/examples/ios/camera`的 TensorFlow iOS 示例相机应用程序拖放到 Xcode 的`Image2Text`项目中。 之前我们已经重用了`ios_image_load.*`文件,此处`tensorflow_utils.*`文件主要用于加载映射的模型文件。 `tensorflow_utils.mm`中有两种方法`LoadModel`和 `LoadMemoryMappedModel` :一种以我们以前的方式加载非映射模型,另一种加载了映射模型 。 如果有兴趣,请看一下`LoadMemoryMappedModel`的实现方式,并且[上的文档也可能会有用。https://www.tensorflow.org/mobile/optimizing#reducing_model_loading_time_andor_memory_footprint](https://www.tensorflow.org/mobile/optimizing#reducing_model_loading_time_andor_memory_footprint) +然后在终端上运行`pod install`并打开`Image2Text.xcworkspace`文件。 将`ios_image_load.h`, `ios_image_load.mm`,`tensorflow_utils.h`和`tensorflow_utils.mm`文件从位于`tensorflow/examples/ios/camera`的 TensorFlow iOS 示例相机应用程序拖放到 Xcode 的`Image2Text`项目中。 之前我们已经重用了`ios_image_load.*`文件,此处`tensorflow_utils.*`文件主要用于加载映射的模型文件。 `tensorflow_utils.mm`中有两种方法`LoadModel`和 `LoadMemoryMappedModel` :一种以我们以前的方式加载非映射模型,另一种加载了映射模型 。 如果有兴趣,请看一下`LoadMemoryMappedModel`的实现方式,并且[这个页面](https://www.tensorflow.org/mobile/optimizing#reducing_model_loading_time_andor_memory_footprint)上的文档也可能会有用。 -2. 添加在上一节末尾生成的两个模型文件,在小节第 2 步中生成的`word_counts.txt`文件,*训练和测试字幕生成*以及一些测试图像–我们保存了 并使用 [TensorFlow im2txt 模型页面](https://github.com/tensorflow/models/tree/master/research/im2txt) )顶部的四个图像,以便我们比较我们的字幕结果 模型,以及那些由模型训练得出的模型,需要经过更多步骤。 还将`ViewController.m`重命名为`.mm`,从现在开始,我们将只处理`ViewController.mm`文件即可完成应用程序。 现在,您的 Xcode `Image2Text`项目应类似于图 6.5: +2. 添加在上一节末尾生成的两个模型文件,在“训练和测试字幕生成”小节第 2 步中生成的`word_counts.txt`文件,以及一些测试图像–我们保存了 并使用 [TensorFlow im2txt 模型页面](https://github.com/tensorflow/models/tree/master/research/im2txt) )顶部的四个图像,以便我们比较我们的字幕结果 模型,以及那些由模型训练得出的模型,需要经过更多步骤。 还将`ViewController.m`重命名为`.mm`,从现在开始,我们将只处理`ViewController.mm`文件即可完成应用程序。 现在,您的 Xcode `Image2Text`项目应类似于图 6.5: ![](img/62be062e-39dc-4f0c-8a59-7e0e675bafaa.png)Figure 6.5: Setting up the Image2Text iOS app, also showing how LoadMemoryMappedModel is implemented @@ -487,7 +487,7 @@ const int WORD_COUNT = 12000; const int STATE_COUNT = 1024; ``` -它们都是自我解释的,如果您通读了本章,则应该看起来都很熟悉,除了最后五个常量:`CAPTION_LEN`是我们要在标题中生成的最大单词数,`START_ID`是 ID 的 ID 句子起始词``,定义为`word_counts.txt`文件中的行号; 所以 2 在第二行表示,在第三行表示 3。 `word_counts.txt`文件的前几行是这样的: +它们都是自我解释的,如果您通读了本章,则应该看起来都很熟悉,除了最后五个常量:`CAPTION_LEN`是我们要在标题中生成的最大单词数,`START_ID`是句子起始词``的 ID,定义为`word_counts.txt`文件中的行号; 所以 2 在第二行表示,在第三行表示 3。 `word_counts.txt`文件的前几行是这样的: ```py a 969108 @@ -633,7 +633,7 @@ for (int i=0; i(); ``` -11. 现在,找到可能性最大(softmax 值)的单词 ID。 如果是结束字的 ID,则结束`for`循环;否则,结束循环。 否则,将具有最大 softmax 值的单词`id`添加到向量`captions`中。 请注意,此处我们使用贪婪搜索,始终选择概率最大的单词,而不是像`run_inference.py`脚本中那样将大小设置为 3 的波束搜索。 在`for`循环的末尾,用最大字数`id`更新`input_feed`值,并用先前返回的`state`值更新[H​​TG7]值,然后再将两个输入馈送到 softmax 模型 所有下一个单词的值和下一个状态值: +11. 现在,找到可能性最大(softmax 值)的单词 ID。 如果是结束字的 ID,则结束`for`循环;否则,结束循环。 否则,将具有最大 softmax 值的单词`id`添加到向量`captions`中。 请注意,此处我们使用贪婪搜索,始终选择概率最大的单词,而不是像`run_inference.py`脚本中那样将大小设置为 3 的集束搜索。 在`for`循环的末尾,用最大字数`id`更新`input_feed`值,并用先前返回的`state`值更新`state_feed`值,然后再将两个输入馈送到 softmax 模型 所有下一个单词的值和下一个状态值: ```py float max_prob = 0.0f; @@ -700,7 +700,7 @@ return sentence; 遵循相同的简单性考虑,我们将开发具有最小 UI 的新 Android 应用,并着重于如何在 Android 中使用该模型: 1. 创建一个名为`Image2Text`的新 Android 应用,在应用`build.gradle`文件的依存关系的末尾添加`compile 'org.tensorflow:tensorflow-android:+'`,创建一个`assets`文件夹,然后将`image2text_frozen_transformed.pb`模型文件`word_counts.txt`拖放到其中 文件和一些测试图像文件。 -2. 在`activity_main.xml`文件中添加一个 ImageView 和一个按钮: +2. 在`activity_main.xml`文件中添加一个`ImageView`和一个按钮: ```py > captions = new ArrayList>(); @@ -892,7 +892,7 @@ for (int i=0; i