ensorFlow 智能移动项目:6~10(1)

本文涉及的产品
NLP自然语言处理_基础版,每接口每天50万次
NLP 自学习平台,3个模型定制额度 1个月
NLP自然语言处理_高级版,每接口累计50万次
简介: ensorFlow 智能移动项目:6~10(1)


六、用自然语言描述图像

如果图像分类和物体检测是明智的任务,那么用自然语言描述图像绝对是一项更具挑战性的任务,需要更多的智能-请片刻考虑一下每个人如何从新生儿成长(他们学会了识别物体并检测它们的位置)到三岁的孩子(他们学会讲述图片故事)。 用自然语言描述图像的任务的正式术语是图像标题。 与具有长期研究和发展历史的语音识别不同,图像字幕(具有完整的自然语言,而不仅仅是关键词输出)由于其复杂性和 2012 年的深度学习突破而仅经历了短暂而令人兴奋的研究历史。

在本章中,我们将首先回顾基于深度学习的图像字幕模型如何赢得 2015 年 Microsoft COCO(大规模对象检测,分割和字幕数据集),我们在第 3 章,“检测对象及其位置”中简要介绍了该有效模型。 然后,我们将总结在 TensorFlow 中训练模型的步骤,并详细介绍如何准备和优化要在移动设备上部署的复杂模型。 之后,我们将向您展示有关如何构建 iOS 和 Android 应用以使用该模型生成描述图像的自然语言语句的分步教程。 由于该模型同时涉及计算机视觉和自然语言处理,因此您将首次看到两种主要的深度神经网络架构 CNN 和 RNN 如何协同工作,以及如何编写 iOS 和 Android 代码以访问经过训练的网络并进行多个推理。 总而言之,我们将在本章介绍以下主题:

  • 图像字幕 – 工作原理
  • 训练和冻结图像字幕模型
  • 转换和优化图像字幕模型
  • 在 iOS 中使用图像字幕模型
  • 在 Android 中使用图像字幕模型

图像字幕 – 工作原理

Show and Tell:从 2015 年 MSCOCO 图像字幕挑战赛中汲取的经验教训。 在讨论训练过程之前,TensorFlow 的 im2txt 模型文档网站中也对此进行了很好的介绍,让我们首先基本了解一下解模型的工作原理。 这也将帮助您了解 Python 中的训练和推理代码,以及本章稍后将介绍的 iOS 和 Android 中的推理代码。

获奖的 Show and Tell 模型是使用端到端方法进行训练的,类似于我们在上一章中简要介绍的最新的基于深度学习的语音识别模型。 它使用 MSCOCO 图像字幕 2014 数据集,可从这里下载,该数据集包含超过 82,000 个训练图像,并以描述它们的自然语言句子为目标。 训练模型以使为每个输入图像输出目标自然语言句子的可能性最大化。 与使用多个子系统的其他更复杂的训练方法不同,端到端方法优雅,简单,并且可以实现最新的结果。

为了处理和表示输入图像,Show and Tell 模型使用预训练的 Inception v3 模型,该模型与我们在第 2 章,“通过迁移学习对图像进行分类”所使用的相同。 Inception v3 CNN 网络的最后一个隐藏层用作输入图像的表示。 由于 CNN 模型的性质,较早的层捕获更多的基本图像信息,而较后的层捕获更高级的图像概念。 因此,通过使用输入图像的最后一个隐藏层来表示图像,我们可以更好地准备具有高级概念的自然语言输出。 毕竟,我们通常会开始用诸如“人”或“火车”之类的词来描述图片,而不是“带有尖锐边缘的东西”。

为了表示目标自然语言输出中的每个单词,使用了单词嵌入方法。 词嵌入只是词的向量表示。 TensorFlow 网站上有一个不错的教程,介绍如何构建模型来获取单词的向量表示。

现在,在既表示输入图像又表示输出单词的情况下(每个这样的单词对构成一个训练示例),给定的最佳训练模型可用于最大化在目标输出中生成每个单词w的概率,给定输入图像和该单词w之前的先前单词,它是 RNN 序列模型,或更具体地说,是长短期记忆LSTM)的 RNN 模型类型。 LSTM 以解决常规 RNN 模型固有的消失和爆炸梯度问题而闻名。 为了更好地了解 LSTM,您应该查看这个热门博客

梯度概念在反向传播过程中用于更新网络权重,因此它可以学习生成更好的输出。 如果您不熟悉反向传播过程,它是神经网络中最基本,功能最强大的算法之一,那么您绝对应该花些时间来理解它-只是 Google 的“反向传播”,排名前五的结果都不会令人失望。 消失的梯度意味着,在深度神经网络反向传播学习过程中,早期层中的网络权重几乎没有更新,因此网络永不收敛。 梯度爆炸意味着这些权重更新得过分疯狂,从而导致网络差异很大。 因此,如果某人头脑封闭,从不学习,或者某人对新事物疯狂而又失去兴趣就快,那么您就会知道他们似乎遇到了什么样的梯度问题。

训练后,可以将 CNN 和 LSTM 模型一起用于推理:给定输入图像,该模型可以估计每个单词的概率,从而预测最有可能为输出语句生成哪n个最佳单词; 然后,给定输入图像和n个最佳单词,可以生成n个最佳的下一个单词,然后继续进行,直到模型返回句子的特定结尾单词,或达到了生成的句子的指定单词长度(以防止模型过于冗长)时,我们得到一个完整的句子。

在每次生成单词时使用n个最佳单词(意味着在末尾具有n个最佳句子)被称为集束搜索。 当n(即集束大小)为 1 时,它仅基于模型返回的所有可能单词中的最高概率值,就成为贪婪搜索或最佳搜索。 TensorFlow im2txt 官方模型的下一部分中的训练和推理过程使用以 Python 实现的集束大小设置为 3 的集束搜索; 为了进行比较,我们将开发的 iOS 和 Android 应用使用更简单的贪婪或最佳搜索。 您将看到哪种方法可以生成更好的字幕。

训练和冻结图像字幕模型

在本部分中,我们将首先总结训练训练名为 im2txt 的 Show and Tell 模型的过程,该模型记录在这个页面中, 一些提示,以帮助您更好地了解该过程。 然后,我们将展示 im2txt 模型项目随附的 Python 代码的一些关键更改,以便冻结该模型以准备在移动设备上使用。

训练和测试字幕生成

如果您已按照第 3 章“检测对象及其位置”中的“设置 TensorFlow 对象检测 API”部分进行操作,那么您已经安装im2txt文件夹; 否则,只需将cd移至您的 TensorFlow 源根目录,然后运行:

git clone https://github.com/tensorflow/models

您可能尚未安装的一个 Python 库是 自然语言工具包NLTK),这是最流行的用于自然语言处理的 Python 库之一。 只需访问其网站以获得安装说明。

现在,请按照以下步骤来训练模型:

  1. 通过打开终端并运行以下命令来设置保存 2014 MSCOCO 图像字幕训练和验证数据集的位置:
MSCOCO_DIR="${HOME}/im2txt/data/mscoco"

请注意,尽管 2014 年要下载和保存的原始数据集约为 20GB,但该数据集将转换为 TFRecord 格式(我们还在第 3 章 “检测对象及其位置”来转换对象检测数据集,这是运行以下训练脚本所需的,并添加了大约 100GB 数据。 因此,使用 TensorFlow im2txt 项目总共需要约 140GB 的训练自己的图像字幕模型。

  1. 转到您的 im2txt 源代码所在的位置,然后下载并处理 MSCOCO 数据集:
cd <your_tensorflow_root>/models/research/im2txt
bazel build //im2txt:download_and_preprocess_mscoco
bazel-bin/im2txt/download_and_preprocess_mscoco "${MSCOCO_DIR}"

download_and_preprocess_mscoco脚本完成后,您将在$MSCOCO_DIR文件夹中看到所有 TFRecord 格式的训练,验证和测试数据文件。

$MSCOCO_DIR文件夹中还生成了一个名为word_counts.txt 的文件。 它总共有 11,518 个单词,每行包含一个单词,一个空格以及该单词出现在数据集中的次数。 文件中仅保存计数等于或大于 4 的单词。 还保存特殊词,例如句子的开头和结尾(分别表示为 )。 稍后,您将看到我们如何在 iOS 和 Android 应用中专门使用和解析文件来生成字幕。

  1. 通过运行以下命令来获取 Inception v3 检查点文件:
INCEPTION_DIR="${HOME}/im2txt/data"
mkdir -p ${INCEPTION_DIR}
cd ${INCEPTION_DIR}
wget "http://download.tensorflow.org/models/inception_v3_2016_08_28.tar.gz"
tar -xvf inception_v3_2016_08_28.tar.gz -C ${INCEPTION_DIR}
rm inception_v3_2016_08_28.tar.gz

之后,您将在${HOME}/im2txt/data文件夹中看到一个名为inception_v3.ckpt的文件,如下所示:

jeff@AiLabby:~/im2txt/data$ ls -lt inception_v3.ckpt
-rw-r----- 1 jeff jeff 108816380 Aug 28  2016 inception_v3.ckpt
  1. 现在,我们准备使用以下命令来训练我们的模型:
INCEPTION_CHECKPOINT="${HOME}/im2txt/data/inception_v3.ckpt"
MODEL_DIR="${HOME}/im2txt/model"
cd <your_tensorflow_root>/models/research/im2txt
bazel build -c opt //im2txt/...
bazel-bin/im2txt/train \
 --input_file_pattern="${MSCOCO_DIR}/train-?????-of-00256" \
 --inception_checkpoint_file="${INCEPTION_CHECKPOINT}" \
 --train_dir="${MODEL_DIR}/train" \
 --train_inception=false \
 --number_of_steps=1000000

即使在 GPU 上(例如第 1 章, “移动 TensorFlow 入门”中设置的 Nvidia GTX 1070),整个步骤(在前面的--number_of_steps参数中指定)也会超过 5 个昼夜,因为运行 5 万步大约需要 6.5 个小时。 幸运的是,您很快就会看到,即使以大约 50K 的步长,图像字幕的结果也已经相当不错了。 另请注意,您可以随时取消train脚本,然后稍后重新运行它,该脚本将从最后保存的检查点开始; 默认情况下,检查点会每 10 分钟保存一次,因此在最坏的情况下,您只会损失 10 分钟的训练时间。

经过几个小时的训练,取消前面的train脚本,然后查看--train_dir指向的位置。 您将看到类似这样的内容(默认情况下,将保存五组检查点文件,但此处仅显示三组):

ls -lt $MODEL_DIR/train
-rw-rw-r-- 1 jeff jeff 2171543 Feb 6 22:17 model.ckpt-109587.meta
-rw-rw-r-- 1 jeff jeff 463 Feb 6 22:17 checkpoint
-rw-rw-r-- 1 jeff jeff 149002244 Feb 6 22:17 model.ckpt-109587.data-00000-of-00001
-rw-rw-r-- 1 jeff jeff 16873 Feb 6 22:17 model.ckpt-109587.index
-rw-rw-r-- 1 jeff jeff 2171543 Feb 6 22:07 model.ckpt-109332.meta
-rw-rw-r-- 1 jeff jeff 16873 Feb 6 22:07 model.ckpt-109332.index
-rw-rw-r-- 1 jeff jeff 149002244 Feb 6 22:07 model.ckpt-109332.data-00000-of-00001
-rw-rw-r-- 1 jeff jeff 2171543 Feb 6 21:57 model.ckpt-109068.meta
-rw-rw-r-- 1 jeff jeff 149002244 Feb 6 21:57 model.ckpt-109068.data-00000-of-00001
-rw-rw-r-- 1 jeff jeff 16873 Feb 6 21:57 model.ckpt-109068.index
-rw-rw-r-- 1 jeff jeff 4812699 Feb 6 14:27 graph.pbtxt

您可以告诉每 10 分钟生成一组检查点文件(model.ckpt-109068.*model.ckpt-109332.*model.ckpt-109587.*)。 graph.pbtxt是模型的图定义文件(以文本格式),model.ckpt-??????.meta文件还包含模型的图定义,以及特定检查点的其他一些元数据,例如model.ckpt-109587.data-00000-of-00001(请注意, 大小几乎为 150MB,因为所有网络参数都保存在此处)。

  1. 测试字幕生成,如下所示:
CHECKPOINT_PATH="${HOME}/im2txt/model/train"
VOCAB_FILE="${HOME}/im2txt/data/mscoco/word_counts.txt"
IMAGE_FILE="${HOME}/im2txt/data/mscoco/raw-data/val2014/COCO_val2014_000000224477.jpg"
bazel build -c opt //im2txt:run_inference
bazel-bin/im2txt/run_inference \
 --checkpoint_path=${CHECKPOINT_PATH} \
 --vocab_file=${VOCAB_FILE} \
 --input_files=${IMAGE_FILE}

CHECKPOINT_PATH被设置为与--train_dir被设置为相同的路径。 run_inference脚本将生成类似以下内容(不完全相同,具体取决于已执行了多少训练步骤):

Captions for image COCO_val2014_000000224477.jpg:
 0) a man on a surfboard riding a wave . (p=0.015135)
 1) a person on a surfboard riding a wave . (p=0.011918)
 2) a man riding a surfboard on top of a wave . (p=0.009856)

这很酷。 如果我们可以在智能手机上运行此模型,会不会更酷? 但是在此之前,由于模型的相对复杂性以及 Python 中trainrun_inference脚本的编写方式,我们还需要采取一些额外的步骤。

冻结图像字幕模型

在第 4 章,“转换具有惊人艺术风格的图片”,和第 5 章,“了解简单语音命令”中,我们使用了一个名为freeze.py的脚本的两个略有不同的版本,将受过训练的网络权重与网络图定义合并到一个自足的模型文件中,这是我们可以在移动设备上使用的好处。 TensorFlow 还带有freeze脚本的更通用版本,称为freeze_graph.py,位于tensorflow/python/tools文件夹中,可用于构建模型文件。 要使其正常运行,您需要为其提供至少四个参数(要查看所有可用参数,请查看 tensorflow/python/tools/freeze_graph.py):

  • --input_graph--input_meta_graph:模型的图定义文件。 例如,在上一节的第 4 步的命令ls -lt $MODEL_DIR/train的输出中,model.ckpt-109587.meta是一个元图文件,其中包含模型的图定义和其他与检查点相关的元数据,而graph.pbtxt只是模型的图定义。
  • --input_checkpoint :特定的检查点文件,例如 model.ckpt-109587 。 注意,您没有指定大型检查点文件 model.ckpt-109587.data-00000-of-00001 的完整文件名。
  • --output_graph:冻结模型文件的路径–这是在移动设备上使用的路径。
  • --output_node_names:输出节点名称列表,以逗号分隔,告诉freeze_graph工具冻结模型中应包括模型的哪一部分和权重,因此生成特定输出不需要的节点名称和权重将保留。

因此,对于该模型,我们如何找出必备的输出节点名称以及输入节点名称,这些对推理也至关重要,正如我们在上一章的 iOS 和 Android 应用中所见到的那样? 因为我们已经使用run_inference脚本来生成测试图像的标题,所以我们可以看到它是如何进行推理的。

转到您的 im2txt 源代码文件夹models/research/im2txt/im2txt:您可能想在一个不错的编辑器(例如 Atom 或 Sublime Text)中打开它,或者在 Python IDE(例如 PyCharm)中打开它。 在run_inference.py中,对inference_utils/inference_wrapper_base.py中的build_graph_from_config进行了调用,在inference_wrapper.py中调用了build_model,在show_and_tell_model.py中进一步调用了build方法。 最后,build方法将调用build_input方法,该方法具有以下代码:

if self.mode == "inference":
    image_feed = tf.placeholder(dtype=tf.string, shape=[], name="image_feed")
    input_feed = tf.placeholder(dtype=tf.int64,
        shape=[None], # batch_size
        name="input_feed")

还有build_model方法,它具有:

if self.mode == "inference":
    tf.concat(axis=1, values=initial_state, name="initial_state")
    state_feed = tf.placeholder(dtype=tf.float32,
        shape=[None, sum(lstm_cell.state_size)],
        name="state_feed")
...
tf.concat(axis=1, values=state_tuple, name="state")
...
tf.nn.softmax(logits, name="softmax")

因此,名为image_feedinput_feedstate_feed的三个占位符应该是输入节点名称,而initial_statestatesoftmax应当是输出节点名称。 此外,inference_wrapper.py中定义的两种方法证实了我们的侦探工作–第一种是:

def feed_image(self, sess, encoded_image):
    initial_state = sess.run(fetches="lstm/initial_state:0",
                             feed_dict={"image_feed:0": encoded_image})
    return initial_state

因此,我们提供image_feed并返回initial_statelstm/前缀仅表示该节点在lstm范围内)。 第二种方法是:

def inference_step(self, sess, input_feed, state_feed):
    softmax_output, state_output = sess.run(
        fetches=["softmax:0", "lstm/state:0"],
        feed_dict={
            "input_feed:0": input_feed,
            "lstm/state_feed:0": state_feed,
        })
    return softmax_output, state_output, None

我们输入input_feedstate_feed,然后返回softmaxstate。 总共三个输入节点名称和三个输出名称。

注意,仅当mode为“推断”时才创建这些节点,因为train.pyrun_inference.py都使用了 show_and_tell_model.py。 这意味着在运行run_inference.py脚本后,将修改在步骤 5 中使用train生成的--checkpoint_path中模型的图定义文件和权重。 那么,我们如何保存更新的图定义和检查点文件?

事实证明,在run_inference.py中,在创建 TensorFlow 会话后,还有一个调用restore_fn(sess)来加载检查点文件,并且该调用在inference_utils/inference_wrapper_base.py中定义:

def _restore_fn(sess):
      saver.restore(sess, checkpoint_path)

在启动run_inference.py之后到达saver.restore调用时,已进行了更新的图定义,因此我们可以在此处保存新的检查点和图文件,从而使_restore_fn函数如下:

def _restore_fn(sess):
      saver.restore(sess, checkpoint_path)
      saver.save(sess, "model/image2text")
      tf.train.write_graph(sess.graph_def, "model", 'im2txt4.pbtxt')
      tf.summary.FileWriter("logdir", sess.graph_def)

tf.train.write_graph(sess.graph_def, "model", 'im2txt4.pbtxt')行是可选的,因为当通过调用saver.save保存新的检查点文件时,也会生成一个元文件,freeze_graph.py可以将其与检查点文件一起使用。 但是对于那些希望以纯文本格式查看所有内容,或者在冻结模型时更喜欢使用带有--in_graph参数的图定义文件的人来说,它是在这里生成的。 最后一行tf.summary.FileWriter("logdir", sess.graph_def)也是可选的,但它会生成一个可由 TensorBoard 可视化的事件文件。 因此,有了这些更改,在再次运行run_inference.py之后(除非首先直接使用 Python 运行run_inference.py,否则请记住首先运行bazel build -c opt //im2txt:run_inference),您将在model目录中看到以下新的检查点文件和新的图定义文件:

jeff@AiLabby:~/tensorflow-1.5.0/models/research/im2txt$ ls -lt model
-rw-rw-r-- 1 jeff jeff 2076964 Feb 7 12:33 image2text.pbtxt
-rw-rw-r-- 1 jeff jeff 1343049 Feb 7 12:33 image2text.meta
-rw-rw-r-- 1 jeff jeff 77 Feb 7 12:33 checkpoint
-rw-rw-r-- 1 jeff jeff 149002244 Feb 7 12:33 image2text.data-00000-of-00001
-rw-rw-r-- 1 jeff jeff 16873 Feb 7 12:33 image2text.index

logdir目录中:

jeff@AiLabby:~/tensorflow-1.5.0/models/research/im2txt$ ls -lt logdir
total 2124
-rw-rw-r-- 1 jeff jeff 2171623 Feb 7 12:33 events.out.tfevents.1518035604.AiLabby

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)和一个输入节点名称(底部的state_feed):

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9IJBSSEp-1681653119029)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/d47ea13b-441c-4fb1-bccc-bbceaf2a8bdf.png)]

图 6.1:该图显示了三个输出节点名称和一个输入节点名称

图 6.2 显示了另一个输入节点名称image_feed

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pLuHCbVw-1681653119030)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/a7c39f91-68d3-4cd4-8e9b-0ef0b6dd11ff.png)]

图 6.2:该图显示了一个附加的输入节点名称image_feed

最后,图 6.3 显示了最后一个输入节点名称input_feed

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q2fMceyK-1681653119030)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/887360ce-b609-4f8a-95d4-c1c3d2e8f97b.png)]

图 6.3:该图显示了最后一个输入节点名称input_feed

当然,这里有很多我们不能也不会涵盖的细节。 但是,您将了解大局,同样重要的是,有足够的细节可以继续前进。 现在运行freeze_graph.py应该像轻风(双关语):

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参数:

python tensorflow/python/tools/freeze_graph.py  --input_graph=/home/jeff/tensorflow-1.5.0/models/research/im2txt/model/image2text.pbtxt --input_checkpoint=/home/jeff/tensorflow-1.5.0/models/research/im2txt/model/image2text --output_graph=/tmp/image2text_frozen2.pb --output_node_names="softmax,lstm/initial_state,lstm/state"

两个输出图文件image2text_frozen.pbimage2text_frozen2.pb的大小会稍有不同,但是在经过转换和可能的优化后,它们在移动设备上使用时,它们的行为完全相同。

转换和优化图像字幕模型

如果您真的等不及了,现在决定尝试在 iOS 或 Android 应用上尝试新近冻结的热模型,则可以,但是您会看到一个致命错误No OpKernel was registered to support Op 'DecodeJpeg' with these attrs,迫使你重新考虑你的决定。

使用转换的模型修复错误

通常,您可以使用strip_unused.py, 工具,与 tensorflow/python/tools,中的 freeze_graph.py位于相同位置,来删除不包含在 TensorFlow 核心库中的DecodeJpeg操作。但是由于输入节点image_feed需要进行解码操作(图 6.2), strip_unused之类的工具不会将DecodeJpeg视为未使用,因此不会被剥夺。 您可以先运行strip_unused命令,如下所示进行验证:

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

然后在 iPython 中加载输出图并列出前几个节点,如下所示:

import tensorflow as tf
g=tf.GraphDef()
g.ParseFromString(open("/tmp/image2text_frozen_stripped", "rb").read())
x=[n.name for n in g.node]
x[:6]

输出如下:

[u'image_feed',
 u'input_feed',
 u'decode/DecodeJpeg',
 u'convert_image/Cast',
 u'convert_image/y',
 u'convert_image']

解决您的 iOS 应用错误的第二种可能解决方案,像第 5 章, “了解简单语音命令”一样,是在 tf_op_files文件中添加未注册的操作实现,并重建 TensorFlow iOS 库。 坏消息是,由于 TensorFlow 中没有DecodeJpeg函数的实现,因此无法将DecodeJpeg的 TensorFlow 实现添加到tf_op_files中。

实际上,在图 6.2 中也暗示了对此烦恼的解决方法,其中convert_image节点用作image_feed输入的解码版本。 为了更准确,单击 TensorBoard 图中的转换和解码节点,如图 6.4 所示,您将从右侧的 TensorBoard 信息卡中看到输入转换(名为convert_image/Cast)的输出为decode/DecodeJpegconvert_image,解码的输入和输出为image_feedconvert_image/Cast

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l7B550bD-1681653119031)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/eeb4e7ad-04ef-4ad5-ac89-a9a4a1e2f1e4.png)]

图 6.4:调查解码和conver_image节点

实际上,在im2txt/ops/image_processing.py中有一行image = tf.image.convert_image_dtype(image, dtype=tf.float32)将解码的图像转换为浮点数。 让我们用convert_image/Cast代替 TensorBoard 中显示的名称image_feed,以及前面代码片段的输出,然后再次运行strip_unused

bazel-bin/tensorflow/python/tools/strip_unused --input_graph=/tmp/image2text_frozen.pb  --output_graph=/tmp/image2text_frozen_stripped.pb --input_node_names="convert_image/Cast,input_feed,lstm/state_feed" --output_node_names="softmax,lstm/initial_state,lstm/state"  --input_binary=True

现在,重新运行代码片段,如下所示:

g.ParseFromString(open("/tmp/image2text_frozen_stripped", "rb").read())
x=[n.name for n in g.node]
x[:6]

并且输出不再具有decode / DecodeJpeg节点:

[u'input_feed',
 u'convert_image/Cast',
 u'convert_image/y',
 u'convert_image',
 u'ExpandDims_1/dim',
 u'ExpandDims_1']

如果我们在 iOS 或 Android 应用中使用新的模型文件image2text_frozen_stripped.pb,则No OpKernel was registered to support Op 'DecodeJpeg' with these attrs. 肯定会消失。 但是发生另一个错误, Not a valid TensorFlow Graph serialization: Input 0 of node ExpandDims_6 was passed float from input_feed:0 incompatible with expected int64。 如果您通过名为 TensorFlow for Poets 2 的不错的 Google TensorFlow 代码实验室,可能会想起来,还有另一个名为optimize_for_inference的工具,其功能类似于strip_unused,并且可以很好地用于代码实验室中的图像分类任务。 您可以像这样运行它:

bazel build tensorflow/python/tools:optimize_for_inference
bazel-bin/tensorflow/python/tools/optimize_for_inference \
--input=/tmp/image2text_frozen.pb \
--output=/tmp/image2text_frozen_optimized.pb \
--input_names="convert_image/Cast,input_feed,lstm/state_feed" \
--output_names="softmax,lstm/initial_state,lstm/state"

但是在 iOS 或 Android 应用上加载输出模型文件 image2text_frozen_optimized.pb会导致相同的Input 0 of node ExpandDims_6 was passed float from input_feed:0 incompatible with expected int64 错误。 看起来,尽管我们试图至少在某种程度上实现福尔摩斯在本章中可以做的事情,但有人希望我们首先成为福尔摩斯。

如果您在其他模型(例如我们在前几章中看到的模型)上尝试过strip_unusedoptimize_for_inference工具,则它们可以正常工作。 事实证明,尽管官方 TensorFlow 1.4 和 1.5 发行版中包含了两个基于 Python 的工具,但在优化一些更复杂的模型时却存在一些错误。 更新和正确的工具是基于 C++ 的transform_graph工具,现在是 TensorFlow Mobile 网站推荐的官方工具。 运行以下命令以消除在移动设备上部署时的int64不兼容float的错误:

bazel build tensorflow/tools/graph_transforms:transform_graph
bazel-bin/tensorflow/tools/graph_transforms/transform_graph \
--in_graph=/tmp/image2text_frozen.pb \
--out_graph=/tmp/image2text_frozen_transformed.pb \
--inputs="convert_image/Cast,input_feed,lstm/state_feed" \
--outputs="softmax,lstm/initial_state,lstm/state" \
--transforms='
 strip_unused_nodes(type=float, shape="299,299,3")
 fold_constants(ignore_errors=true, clear_output_shapes=true) 
 fold_batch_norms
 fold_old_batch_norms'

我们将不讨论所有--transforms选项的详细信息,这些选项在这里有完整记录。 基本上,--transforms设置可以正确消除模型中未使用的节点,例如DecodeJpeg,并且还可以进行其他一些优化。

现在,如果您在 iOS 和 Android 应用中加载image2text_frozen_transformed.pb文件,则不兼容的错误将消失。 当然,我们还没有编写任何真实的 iOS 和 Android 代码,但是我们知道该模型很好,可以随时使用。 很好,但是可以更好。

优化转换后的模型

真正的最后一步,也是至关重要的一步,尤其是在运行复杂的冻结和转换模型(例如我们在较旧的 iOS 设备上训练过的模型)时,是使用位于 tensorflow/contrib/util的另一个工具convert_graphdef_memmapped_format ,将冻结和转换后的模型转换为映射格式。 映射文件允许现代操作系统(例如 iOS 和 Android)将文件直接映射到主内存,因此无需为文件分配内存,也无需写回磁盘,因为文件数据是只读的,这非常重要。 性能提高。

更重要的是,iOS 不会将已映射文件视为内存使用量,因此,当内存压力过大时,即使文件很大,使用已映射文件的应用也不会由于内存使用太大而被 iOS 杀死和崩溃。 实际上,正如我们将在下一节中很快看到的那样,如果模型文件的转换版本未转换为 memmapped 格式,则将在较旧的移动设备(如 iPhone 6)上崩溃,在这种情况下,转换是必须的, 有。

构建和运行该工具的命令非常简单:

bazel build tensorflow/contrib/util:convert_graphdef_memmapped_format
bazel-bin/tensorflow/contrib/util/convert_graphdef_memmapped_format \
--in_graph=/tmp/image2text_frozen_transformed.pb \
--out_graph=/tmp/image2text_frozen_transformed_memmapped.pb

下一节将向您展示如何在 iOS 应用中使用image2text_frozen_transformed_memmapped.pb模型文件。 它也可以在使用本机代码的 Android 中使用,但是由于时间限制,我们将无法在本章中介绍它。

我们花了很多功夫才能最终为移动应用准备好复杂的图像字幕模型。 是时候欣赏使用模型的简单性了。 实际上,使用模型不仅仅是 iOS 中的单个 session->Run 调用,还是 Android 中的 mInferenceInterface.run 调用,就像我们在前面所有章节中所做的那样; 从输入图像到自然语言输出的推论(如您在上一节中研究run_inference.py的工作原理时所见)涉及到对模型的run方法的多次调用。 LSTM 模型就是这样工作的:“继续向我发送新的输入(基于我以前的状态和输出),我将向您发送下一个状态和输出。” 简单来说,我们的意思是向您展示如何使用尽可能少的简洁代码来构建 iOS 和 Android 应用,这些应用使用该模型以自然语言描述图像。 这样,如果需要,您可以轻松地在自己的应用中集成模型及其推理代码。

在 iOS 中使用图像字幕模型

由于该模型的 CNN 部分基于 Inception v3,因此我们在第 2 章,“通过迁移学习对图像进行分类”时使用的模型相同,因此我们可以并且将使用更简单的 TensorFlow Pod 进行以下操作: 创建我们的 Objective-C iOS 应用。 请按照此处的步骤查看如何在新的 iOS 应用中同时使用image2text_frozen_transformed.pbimage2text_frozen_transformed_memmapped.pb模型文件:

  1. 类似于第 2 章,“通过迁移学习对图像进行分类”,“将 TensorFlow 添加到 Objective-C iOS 应用”部分中的前四个步骤, 名为Image2Text的 iOS 项目,添加具有以下内容的名为Podfile的新文件:
target 'Image2Text'
       pod 'TensorFlow-experimental'

然后在终端上运行pod install并打开Image2Text.xcworkspace文件。 将ios_image_load.hios_image_load.mmtensorflow_utils.htensorflow_utils.mm文件从位于tensorflow/examples/ios/camera的 TensorFlow iOS 示例相机应用拖放到 Xcode 的Image2Text项目中。 之前我们已经重用了ios_image_load.*文件,此处tensorflow_utils.*文件主要用于加载映射的模型文件。 tensorflow_utils.mm中有两种方法LoadModelLoadMemoryMappedModel :一种以我们以前的方式加载非映射模型,另一种加载了映射模型 。 如果有兴趣,请看一下LoadMemoryMappedModel的实现方式,并且这个页面上的文档也可能会有用。

  1. 添加在上一节末尾生成的两个模型文件,在“训练和测试字幕生成”小节第 2 步中生成的word_counts.txt文件,以及一些测试图像–我们保存并使用 TensorFlow im2txt 模型页面顶部的四个图像,以便我们比较我们的模型的字幕结果,以及那些由使用更多步骤训练的模型所生成的结果。 还将ViewController.m重命名为.mm,从现在开始,我们将只处理ViewController.mm文件即可完成应用。 现在,您的 Xcode Image2Text项目应类似于图 6.5:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b48gBjaP-1681653119031)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/62be062e-39dc-4f0c-8a59-7e0e675bafaa.png)]

图 6.5:设置Image2Text iOS 应用,还显示如何实现LoadMemoryMappedModel

  1. 打开ViewController.mm并添加一堆 Objective-C 和 C++ 常量,如下所示:
static NSString* MODEL_FILE = @"image2text_frozen_transformed";
static NSString* MODEL_FILE_MEMMAPPED = @"image2text_frozen_transformed_memmapped";
static NSString* MODEL_FILE_TYPE = @"pb";
static NSString* VOCAB_FILE = @"word_counts";
static NSString* VOCAB_FILE_TYPE = @"txt";
static NSString *image_name = @"im2txt4.png";
const string INPUT_NODE1 = "convert_image/Cast";
const string OUTPUT_NODE1 = "lstm/initial_state";
const string INPUT_NODE2 = "input_feed";
const string INPUT_NODE3 = "lstm/state_feed";
const string OUTPUT_NODE2 = "softmax";
const string OUTPUT_NODE3 = "lstm/state";
const int wanted_width = 299;
const int wanted_height = 299;
const int wanted_channels = 3;
const int CAPTION_LEN = 20;
const int START_ID = 2;
const int END_ID = 3;
const int WORD_COUNT = 12000;
const int STATE_COUNT = 1024;

它们都是自我解释的,如果您通读了本章,则应该看起来都很熟悉,除了最后五个常量:CAPTION_LEN是我们要在标题中生成的最大单词数,START_ID是句子起始词的 ID,定义为word_counts.txt文件中的行号; 所以 2 在第二行表示,在第三行表示 3。 word_counts.txt文件的前几行是这样的:

a 969108
<S> 586368
</S> 586368
. 440479
on 213612
of 202290

WORD_COUNT是模型假设的总单词数,对于您很快就会看到的每个推理调用,模型将返回总计 12,000 的概率得分以及 LSTM 模型的 1,024 个状态值。

  1. 添加一些全局变量和一个函数签名:
unique_ptr<tensorflow::Session> session;
unique_ptr<tensorflow::MemmappedEnv> tf_memmapped_env;
std::vector<std::string> words;
UIImageView *_iv;
UILabel *_lbl;
NSString* generateCaption(bool memmapped);

此简单的与 UI 相关的代码类似于第 2 章,“通过迁移学习对图像进行分类”的 iOS 应用的代码。 基本上,您可以在应用启动后点击任意位置,然后选择两个模型之一,图像描述结果将显示在顶部。 当用户在alert操作中选择了映射模型时,将运行以下代码:

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    NSString *caption = generateCaption(true); 
    dispatch_async(dispatch_get_main_queue(), ^{
        _lbl.text = caption;
    });
});

如果选择了非映射模型,则使用generateCaption(false)

  1. viewDidLoad方法的末尾,添加代码以加载word_counts.txt并将这些单词逐行保存在 Objective-C 和 C++ 中:
NSString* voc_file_path = FilePathForResourceName(VOCAB_FILE, VOCAB_FILE_TYPE);
if (!voc_file_path) {
    LOG(FATAL) << "Couldn't load vocabuary file: " << voc_file_path;
}
ifstream t;
t.open([voc_file_path UTF8String]);
string line;
while(t){
    getline(t, line);
    size_t pos = line.find(" ");
    words.push_back(line.substr(0, pos));
}
t.close();
  1. 剩下的我们要做的就是实现generateCaption函数。 在其中,首先加载正确的模型:
tensorflow::Status load_status;
if (memmapped) 
    load_status = LoadMemoryMappedModel(MODEL_FILE_MEMMAPPED, MODEL_FILE_TYPE, &session, &tf_memmapped_env);
else 
    load_status = LoadModel(MODEL_FILE, MODEL_FILE_TYPE, &session);
if (!load_status.ok()) {
    return @"Couldn't load model";
}
  1. 然后,使用类似的图像处理代码来准备要输入到模型中的图像张量:
int image_width;
int image_height;
int image_channels;
NSArray *name_ext = [image_name componentsSeparatedByString:@"."];
NSString* image_path = FilePathForResourceName(name_ext[0], name_ext[1]);
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({wanted_height, wanted_width, wanted_channels}));
auto image_tensor_mapped = image_tensor.tensor<float, 3>();
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::uint8* in_row = in + (in_y * image_width * image_channels);
    float* out_row = out + (y * wanted_width * wanted_channels);
    for (int x = 0; x < wanted_width; ++x) {
        const int in_x = (x * image_width) / wanted_width;
        tensorflow::uint8* in_pixel = in_row + (in_x * image_channels);
        float* out_pixel = out_row + (x * wanted_channels);
        for (int c = 0; c < wanted_channels; ++c) {
            out_pixel[c] = in_pixel[c];
        }
    }
}
  1. 现在,我们可以将图像发送到模型,并获取返回的initial_state张量向量,该向量包含 1,200(STATE_COUNT)个值:
vector<tensorflow::Tensor> initial_state;
if (session.get()) {
    tensorflow::Status run_status = session->Run({{INPUT_NODE1, image_tensor}}, {OUTPUT_NODE1}, {}, &initial_state);
    if (!run_status.ok()) {
        return @"Getting initial state failed";
    }
}
  1. 定义input_feedstate_feed张量,并将它们的值分别设置为起始字的 ID 和返回的initial_state值:
tensorflow::Tensor input_feed(tensorflow::DT_INT64, tensorflow::TensorShape({1,}));
tensorflow::Tensor state_feed(tensorflow::DT_FLOAT, tensorflow::TensorShape({1, STATE_COUNT}));
auto input_feed_map = input_feed.tensor<int64_t, 1>();
auto state_feed_map = state_feed.tensor<float, 2>();
input_feed_map(0) = START_ID;
auto initial_state_map = initial_state[0].tensor<float, 2>();
for (int i = 0; i < STATE_COUNT; i++){
    state_feed_map(0,i) = initial_state_map(0,i);
}
  1. CAPTION_LEN上创建一个for循环,然后在该循环内,首先创建output_feedoutput_states张量向量,然后馈入我们先前设置的input_feedstate_feed,并运行模型以返回由softmax张量和new_state张量组成的output张量向量:
vector<int> captions;
for (int i=0; i<CAPTION_LEN; i++) { 
    vector<tensorflow::Tensor> output;
    tensorflow::Status run_status = session->Run({{INPUT_NODE2, input_feed}, {INPUT_NODE3, state_feed}}, {OUTPUT_NODE2, OUTPUT_NODE3}, {}, &output);
    if (!run_status.ok()) {
        return @"Getting LSTM state failed";
    } 
    else {
        tensorflow::Tensor softmax = output[0];
        tensorflow::Tensor state = output[1];
        auto softmax_map = softmax.tensor<float, 2>();
        auto state_map = state.tensor<float, 2>();
  1. 现在,找到可能性最大(softmax 值)的单词 ID。 如果是结束字的 ID,则结束for循环;否则,结束循环。 否则,将具有最大 softmax 值的单词id添加到向量captions中。 请注意,此处我们使用贪婪搜索,始终选择概率最大的单词,而不是像run_inference.py脚本中那样将大小设置为 3 的集束搜索。 在for循环的末尾,用最大字数id更新input_feed值,并用先前返回的state值更新state_feed值,然后再将两个输入,所有下一个单词的 softmax 值和下一个状态值,馈送到模型:
float max_prob = 0.0f;
        int max_word_id = 0;
        for (int j = 0; j < WORD_COUNT; j++){
            if (softmax_map(0,j) > max_prob) {
                max_prob = softmax_map(0,j);
                max_word_id = j;
            }
        }
        if (max_word_id == END_ID) break;
        captions.push_back(max_word_id);
        input_feed_map(0) = max_word_id;
        for (int j = 0; j < STATE_COUNT; j++){
            state_feed_map(0,j) = state_map(0,j);
        }        
    } 
}

我们可能从未详细解释过如何在 C++ 中获取和设置 TensorFlow 张量值。 但是,如果您到目前为止已经阅读了本书中的代码,那么您应该已经学会了。 这就像 RNN 学习:如果您接受了足够的代码示例训练,就可以编写有意义的代码。 总而言之,首先使用Tensor类型定义变量,并使用该变量的数据类型和形状指定,然后调用Tensor类的tensor方法,传入数据类型的 C++ 版本和形状,以创建张量的贴图变量。 之后,您可以简单地使用映射来获取或设置张量的值。

  1. 最后,只需遍历captions向量并将向量中存储的每个词 ID 转换为一个词,然后将该词添加到sentence字符串中,而忽略起始 ID 和结束 ID,然后返回该句子,希望是可读的自然语言:
NSString *sentence = @"";
for (int i=0; i<captions.size(); i++) {
    if (captions[i] == START_ID) continue;
    if (captions[i] == END_ID) break;
    sentence = [NSString stringWithFormat:@"%@ %s", sentence, words[captions[i]].c_str()];
}
return sentence;

这就是在 iOS 应用中运行模型所需的一切。 现在,在 iOS 模拟器或设备中运行该应用,点击并选择一个模型,如图 6.6 所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yeO4JaRG-1681653119031)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/dd9bd09b-1b39-47ff-8a8f-f7f180faff3c.png)]

图 6.6:运行Image2Text iOS 应用并选择模型

在 iOS 模拟器上,运行非映射模型需要 10 秒钟以上,运行映射模型则需要 5 秒钟以上。 在 iPhone 6 上,运行贴图模型还需要大约 5 秒钟,但由于模型文件和内存压力较大,运行非贴图模型时会崩溃。

至于结果,图 6.7 显示了四个测试图像结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MghzzYzK-1681653119032)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/59f462cb-59e6-4165-bd6f-80166f84bd61.png)]

图 6.7:显示图像字幕结果

图 6.8 显示了 TensorFlow im2txt 网站上的结果,您可以看到我们更简单的贪婪搜索结果看起来也不错。 但是对于长颈鹿图片,看来我们的模型或推理代码不够好。 完成本章中的工作后,希望您会在改进训练或模型推断方面有所收获:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d0KLlsdY-1681653119032)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-mobi-proj-tf/img/e08dec95-3b49-432a-bc4f-e3077151f2e9.png)]

图 6.8:字幕示例显示在 TensorFlow im2txt 模型网站上

在我们进行下一个智能任务之前,是时候给 Android 开发人员一个不错的选择了。

在 Android 中使用图像字幕模型

遵循相同的简单性考虑,我们将开发具有最小 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和一个按钮:
<ImageView
    android:id="@+id/imageview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintHorizontal_bias="0.0"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="1.0"/>
<Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="DESCRIBE ME"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintHorizontal_bias="0.5"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="1.0"/>
  1. 打开MainActivity.java,使其实现Runnable接口,然后添加以下常量,在前一节中说明了其中的最后五个,而其他则是自解释的:
private static final String MODEL_FILE = "file:///android_asset/image2text_frozen_transformed.pb";
private static final String VOCAB_FILE = "file:///android_asset/word_counts.txt";
private static final String IMAGE_NAME = "im2txt1.png";
private static final String INPUT_NODE1 = "convert_image/Cast";
private static final String OUTPUT_NODE1 = "lstm/initial_state";
private static final String INPUT_NODE2 = "input_feed";
private static final String INPUT_NODE3 = "lstm/state_feed";
private static final String OUTPUT_NODE2 = "softmax";
private static final String OUTPUT_NODE3 = "lstm/state";
private static final int IMAGE_WIDTH = 299;
private static final int IMAGE_HEIGHT = 299;
private static final int IMAGE_CHANNEL = 3;
private static final int CAPTION_LEN = 20;
private static final int WORD_COUNT = 12000;
private static final int STATE_COUNT = 1024;
private static final int START_ID = 2;
private static final int END_ID = 3;

ensorFlow 智能移动项目:6~10(2)https://developer.aliyun.com/article/1426909

相关文章
|
6月前
|
传感器 人工智能 监控
Springcloud+Vue智慧工地管理云平台源码 AI智能识别
“智慧工地管理平台”以现场实际施工及管理经验为依托,针对工地现场痛点,能在工地落地实施的模块化、一体化综合管理平台。为建筑公司、地产公司、监管单位租赁企业、设备生产厂提供了完整的数据接入和管理服务。
117 2
|
6月前
|
机器学习/深度学习 TensorFlow API
ensorFlow 智能移动项目:6~10(3)
ensorFlow 智能移动项目:6~10(3)
61 0
|
6月前
|
机器学习/深度学习 算法 TensorFlow
ensorFlow 智能移动项目:6~10(5)
ensorFlow 智能移动项目:6~10(5)
39 0
|
2月前
|
SQL 人工智能 Serverless
构建一个智能导购助手
通过百炼的Assistant API,您可以构建一个多代理架构的大模型应用,实现智能导购功能。此应用核心为规划助理(Router Agent),根据对话历史和用户输入选择合适助理回复。手机、冰箱、电视导购则根据用户偏好收集参数,智能检索商品并推荐。用户与助理的对话历史为决策提供参考。您可通过函数计算应用模板快速搭建和测试此网站,适用于全天候商品推荐。此架构也可用于智能问诊、求职推荐等场景。
46 1
|
3月前
|
机器学习/深度学习 存储 人工智能
智能化新十年,“全栈智能”定义行业“Copilot智能助手”
智能化新十年,“全栈智能”定义行业“Copilot智能助手”
|
3月前
|
人工智能 搜索推荐 API
AI智能体研发之路-工程篇(二):Dify智能体开发平台一键部署
AI智能体研发之路-工程篇(二):Dify智能体开发平台一键部署
441 2
|
6月前
|
人工智能 监控 搜索推荐
智能管理日常花销 — AI Coze打造个人财务小助手的全新体验(初版)(一)
智能管理日常花销 — AI Coze打造个人财务小助手的全新体验(初版)
269 0
|
6月前
|
存储 人工智能 搜索推荐
智能管理日常花销 — AI Coze打造个人财务小助手的全新体验(初版)(二)
智能管理日常花销 — AI Coze打造个人财务小助手的全新体验(初版)
152 0
|
6月前
|
机器学习/深度学习 TensorFlow 算法框架/工具
ensorFlow 智能移动项目:6~10(4)
ensorFlow 智能移动项目:6~10(4)
52 0
|
6月前
|
人工智能 TensorFlow 算法框架/工具
ensorFlow 智能移动项目:6~10(6)
ensorFlow 智能移动项目:6~10(6)
32 0