# 使用 TensorFlow 服务
在本节中,我们将向您展示如何设置 RNN 模型以预测 TensorFlow 上的垃圾邮件或火腿文本消息。我们将首先说明如何以 protobuf 格式保存模型,然后将模型加载到本地服务器,监听端口`9000`以进行输入。
## 做好准备
我们通过鼓励读者阅读 [https://www.tensorflow.org/serving/serving_basic](https://www.tensorflow.org/serving/serving_basic) 上提供的 TensorFlow 服务网站上的官方文档和简短教程来开始本节。
对于这个例子,我们将在[第 9 章](../Text/68.html),循环神经网络中重用我们在预测垃圾邮件中使用的大部分 RNN 代码和 RNNs 秘籍。我们将更改模型保存代码,以便将 protobuf 模型保存在使用 TensorFlow 服务所需的正确文件夹结构中。
> 请注意,本章中的所有脚本都应该从命令行 bash 提示符执行。
有关更新的安装说明,请访问官方安装站点: [https://www.tensorflow.org/serving/setup](https://www.tensorflow.org/serving/setup) 。正常安装就像向 Linux 源添加 gpg-key 并运行以下安装命令一样简单:
```py
$ sudo apt install tensorflow-model-server
```
## 操作步骤
1. 在这里,我们将以与以前相同的方式开始,通过加载必要的库并设置 TensorFlow 标志,如下所示:
```py
import os
import re
import io
import sys
import requests
import numpy as np
import tensorflow as tf
from zipfile import ZipFile
from tensorflow.python.framework import ops
ops.reset_default_graph()
# Define App Flags
tf.flags.DEFINE_string("storage_folder", "temp", "Where to store model and data.")
tf.flags.DEFINE_float('learning_rate', 0.0005, 'Initial learning rate.')
tf.flags.DEFINE_float('dropout_prob', 0.5, 'Per to keep probability for dropout.')
tf.flags.DEFINE_integer('epochs', 20, 'Number of epochs for training.')
tf.flags.DEFINE_integer('batch_size', 250, 'Batch Size for training.')
tf.flags.DEFINE_integer('rnn_size', 15, 'RNN feature size.')
tf.flags.DEFINE_integer('embedding_size', 25, 'Word embedding size.')
tf.flags.DEFINE_integer('min_word_frequency', 20, 'Word frequency cutoff.')
tf.flags.DEFINE_boolean('run_unit_tests', False, 'If true, run tests.')
FLAGS = tf.flags.FLAGS
```
1. 我们将以完全相同的方式继续完成脚本。为简洁起见,我们只会在训练脚本中包含差异,这就是我们如何保存 protobuf 模型。这是通过在训练完成后插入以下代码来完成的:
> 请注意此代码与教程代码的相似之处。这里的主要区别在于模型名称,版本号以及我们正在保存 RNN 而不是 CNN 的事实。
```py
# Save the finished model for TensorFlow Serving (pb file)
# Here, it's our storage folder / version number
out_path = os.path.join(tf.compat.as_bytes(os.path.join(storage_folder, '1')))
print('Exporting finished model to : {}'.format(out_path))
builder = tf.saved_model.builder.SavedModelBuilder(out_path)
# Build the signature_def_map.
classification_inputs = tf.saved_model.utils.build_tensor_info(x_data_ph)
classification_outputs_classes = tf.saved_model.utils.build_tensor_info(rnn_model_outputs)
classification_signature = (tf.saved_model.signature_def_utils.build_signature_def(
inputs={tf.saved_model.signature_constants.CLASSIFY_INPUTS:
classification_inputs},
outputs={tf.saved_model.signature_constants.CLASSIFY_OUTPUT_CLASSES:
classification_outputs_classes},
method_name=tf.saved_model.signature_constants.CLASSIFY_METHOD_NAME))
tensor_info_x = tf.saved_model.utils.build_tensor_info(x_data_ph)
tensor_info_y = tf.saved_model.utils.build_tensor_info(y_output_ph)
prediction_signature = (
tf.saved_model.signature_def_utils.build_signature_def(
inputs={'texts': tensor_info_x},
outputs={'scores': tensor_info_y},
method_name=tf.saved_model.signature_constants.PREDICT_METHOD_NAME))
legacy_init_op = tf.group(tf.tables_initializer(), name='legacy_init_op')
builder.add_meta_graph_and_variables(
sess, [tf.saved_model.tag_constants.SERVING],
signature_def_map={
'predict_spam': prediction_signature,
tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
classification_signature,
},
legacy_init_op=legacy_init_op)
builder.save()
print('Done exporting!')
```
1. 对我们来说,重要的是要意识到 TensorFlow Serving 需要特定的文件或文件夹结构来加载模型。该脚本将以以下格式安装文件:
![](https://img.kancloud.cn/d8/ec/d8ecfb33a993023a625a65d75ba6f918_380x136.png)
A screenshot of the directory structure that TensorFlow Serving expects.
上面的屏幕截图显示了所需的目录结构。在其中,我们有我们定义的数据目录`temp`,然后是我们的模型版本号`1`。在版本号目录中,我们保存我们的 protobuf 模型和一个包含要保存的所需变量的`variables`文件夹。
> 我们应该知道,在我们的数据目录中,TensorFlow 服务将查找整数文件夹。 TensorFlow 服务将自动启动并在最大整数下获取模型。这意味着要部署新模型,我们需要将其标记为版本 2,并将其粘贴在也标记为`2`的新文件夹下。然后,TensorFlow 服务将自动获取模型。
1. 要启动我们的服务器,我们使用端口,`model_name`和`model_base_path`参数调用命令`tensorflow_model_server`。然后,TensorFlow Serving 查找版本号文件夹并选择最大版本编号的模型。然后它将它部署到机器上,命令通过作为参数给出的端口运行。在以下示例中,我们在本地计算机(`0.0.0.0`)上运行,并且接受的默认端口是`9000`:
```py
$ tensorflow_model_server --port=9000 --model_name=spam_ham --model_base_path=<directory of our code>/tensorflow_cookbook/10_Taking_TensorFlow_to_Production/06_Using_TensorFlow_Serving/temp/
2018-08-09 12:05:16.206712: I tensorflow_serving/model_servers/main.cc:153] Building single TensorFlow model file config: model_name: spam_ham model_base_path: .../temp/
2018-08-09 12:05:16.206874: I tensorflow_serving/model_servers/server_core.cc:459] Adding/updating models.
2018-08-09 12:05:16.206903: I tensorflow_serving/model_servers/server_core.cc:514] (Re-)adding model: spam_ham
2018-08-09 12:05:16.307681: I tensorflow_serving/core/basic_manager.cc:716] Successfully reserved resources to load servable {name: spam_ham version: 1}
2018-08-09 12:05:16.307744: I tensorflow_serving/core/loader_harness.cc:66] Approving load for servable version {name: spam_ham version: 1}
2018-08-09 12:05:16.307773: I tensorflow_serving/core/loader_harness.cc:74] Loading servable version {name: spam_ham version: 1}
2018-08-09 12:05:16.307829: I external/org_tensorflow/tensorflow/contrib/session_bundle/bundle_shim.cc:360] Attempting to load native SavedModelBundle in bundle-shim from: .../temp/1
2018-08-09 12:05:16.307867: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:242] Loading SavedModel with tags: { serve }; from: .../temp/1
2018-08-09 12:05:16.313811: I external/org_tensorflow/tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2018-08-09 12:05:16.325866: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:161] Restoring SavedModel bundle.
2018-08-09 12:05:16.329290: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:196] Running LegacyInitOp on SavedModel bundle.
2018-08-09 12:05:16.332936: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:291] SavedModel load for tags { serve }; Status: success. Took 25074 microseconds.
2018-08-09 12:05:16.332972: I tensorflow_serving/servables/tensorflow/saved_model_warmup.cc:83] No warmup data file found at .../temp/1/assets.extra/tf_serving_warmup_requests
2018-08-09 12:05:16.333335: I tensorflow_serving/core/loader_harness.cc:86] Successfully loaded servable version {name: spam_ham version: 1}
2018-08-09 12:05:16.334678: I tensorflow_serving/model_servers/main.cc:323] Running ModelServer at 0.0.0.0:9000 ...
```
1. 我们现在可以将二进制数据提交给`<host>:9000`并返回显示结果的 JSON 响应。我们可以通过任何机器和任何编程语言来完成。不必依赖客户端拥有 TensorFlow 的本地副本是非常有用的。
## 工作原理
如果我们将早期的生产规模部分与前一部分进行比较,主要区别在于我们在主机上部署了可以响应传入请求的模型服务器。前面的部分是一个很好的设置示例,用于执行批量结果或在可以加载 TensorFlow 的机器上工作,但秘籍不是很擅长部署可用的模型,可以进行计算,并将结果返回给任何客户。在本节中,我们将了解如何处理这种体系结构,如下表所示:
| | 第 5 节 - 批量生产 | 第 6 节 - 通过 TensorFlow 服务生产 |
| --- | --- | --- |
| 优点 | 不依赖于网络连接或主机 | 结果与客户端结构无关,唯一的要求是 Numpy 数组的正确格式化二进制文件 |
| 缺点 | 客户端必须具有 TensorFlow 和模型文件 | 依靠主机可用 |
| 理想的用途 | 大批量数据 | 生产服务始终可用,通常是小的请求 |
当然,每种方法的优缺点都值得商榷,两者都能满足每种情况的要求。还有许多其他可用的架构可以满足不同的需求,例如 Docker,Kubernetes,Luigi,Django / Flask,Celery,AWS 和 Azure。
## 更多
本章未涉及的体系结构工具和资源的链接如下:
* 在 Docker 中使用 TensorFlow 服务: [https://www.tensorflow.org/serving/docker](https://www.tensorflow.org/serving/docker)
* 在 Kubernetes 中使用 TensorFlow 服务: [https://www.tensorflow.org/serving/serving_inception](https://www.tensorflow.org/serving/serving_inception)
* Luigi,批量作业的管道工具: [https://github.com/spotify/luigi](https://github.com/spotify/luigi)
* 在 Flask 中使用 TensorFlow: [https://guillaumegenthial.github.io/serving.html](https://guillaumegenthial.github.io/serving.html)
* 用于分布式任务排队的 Python 框架: [http://www.celeryproject.org/community/](http://www.celeryproject.org/community/)
* 如何在 TensorFlow 模型中使用 AWS lambdas: [https://aws.amazon.com/blogs/machine-learning/how-to-deploy-deep-learning-models-with-aws-lambda-and-tensorflow/](https://aws.amazon.com/blogs/machine-learning/how-to-deploy-deep-learning-models-with-aws-lambda-and-tensorflow/)
- TensorFlow 入门
- 介绍
- TensorFlow 如何工作
- 声明变量和张量
- 使用占位符和变量
- 使用矩阵
- 声明操作符
- 实现激活函数
- 使用数据源
- 其他资源
- TensorFlow 的方式
- 介绍
- 计算图中的操作
- 对嵌套操作分层
- 使用多个层
- 实现损失函数
- 实现反向传播
- 使用批量和随机训练
- 把所有东西结合在一起
- 评估模型
- 线性回归
- 介绍
- 使用矩阵逆方法
- 实现分解方法
- 学习 TensorFlow 线性回归方法
- 理解线性回归中的损失函数
- 实现 deming 回归
- 实现套索和岭回归
- 实现弹性网络回归
- 实现逻辑回归
- 支持向量机
- 介绍
- 使用线性 SVM
- 简化为线性回归
- 在 TensorFlow 中使用内核
- 实现非线性 SVM
- 实现多类 SVM
- 最近邻方法
- 介绍
- 使用最近邻
- 使用基于文本的距离
- 使用混合距离函数的计算
- 使用地址匹配的示例
- 使用最近邻进行图像识别
- 神经网络
- 介绍
- 实现操作门
- 使用门和激活函数
- 实现单层神经网络
- 实现不同的层
- 使用多层神经网络
- 改进线性模型的预测
- 学习玩井字棋
- 自然语言处理
- 介绍
- 使用词袋嵌入
- 实现 TF-IDF
- 使用 Skip-Gram 嵌入
- 使用 CBOW 嵌入
- 使用 word2vec 进行预测
- 使用 doc2vec 进行情绪分析
- 卷积神经网络
- 介绍
- 实现简单的 CNN
- 实现先进的 CNN
- 重新训练现有的 CNN 模型
- 应用 StyleNet 和 NeuralStyle 项目
- 实现 DeepDream
- 循环神经网络
- 介绍
- 为垃圾邮件预测实现 RNN
- 实现 LSTM 模型
- 堆叠多个 LSTM 层
- 创建序列到序列模型
- 训练 Siamese RNN 相似性度量
- 将 TensorFlow 投入生产
- 介绍
- 实现单元测试
- 使用多个执行程序
- 并行化 TensorFlow
- 将 TensorFlow 投入生产
- 生产环境 TensorFlow 的一个例子
- 使用 TensorFlow 服务
- 更多 TensorFlow
- 介绍
- 可视化 TensorBoard 中的图
- 使用遗传算法
- 使用 k 均值聚类
- 求解常微分方程组
- 使用随机森林
- 使用 TensorFlow 和 Keras