Serving a TensorFlow Model

导语:
   本文是 tensorflow 手册翻译系列的第二篇。
   原文链接:https://www.tensorflow.org/tfx/serving/serving_basic
   本文讲述如何使一个 TensorFlow 模型作为一个服务启用。

目录

  • 训练和导出 Tensorflow 模型
  • 使用标准的模型服务加载导出模型
  • 测试服务

这本手册展示了怎么使用 Tensorflow 服务组件取导出一个 Tensorflow 模型,并使用一个标准的 Tensorflow 模型服务 tensorflow_model_server 来实现服务的功能。如果你已经熟悉 Tensorflow 服务了,希望知道更多服务内部的工作原理,可以参见Tensorflow 服务高级手册

这本手册使用了简单的 Softmax 回归模型,该模型在 MNIST data 手写数字图像分类的讲解中介绍过。如果你还不知道什么是 Tensorflow 或者 MNIST,参见MNIST初识 Softmax: 该函数是元素指数和所有元素指数的比值。通常应用于多分类问题。

在本节的介绍中,代码分为以下两个部分:

  • mnist_saved_model.py, 用于训练和导出模型的 python 文件
  • 二进制模型服务文件,可以用于 apt 安装或者使用 C++ 文件进行编译(eg. main.cc)。Tensorflow 服务的模型服务会发现新导入的模型并将其作为一个 gRPC 服务运行它们。

在开始前,记得先安装 Docker。

训练并导出 Tensorflow 模型 正如在 mnist_saved_model.py 中看到的那样,训练以在“MNIST初识”同样的方式完成了。Tensorflow 会话 session 中启动了 Tensorflow 图,张量图片以x作为输入,Softmax 分数以y作为输出张量。

之后,使用 Tensorflow 的保存模型构建器模块 SavedModelBuilder 进行导出。保存模型构建器会保存一个训练模型的快照到可靠的存储器中,这样方便在后续的推理中加载。

关于保存模型格式的细节,参见文档SavedModel README.md

以下是从 mnist_saved_model.py 中截取的代码片段,解释了一般的保存模型到硬盘的过程。

export_path_base = sys.argv[-1]
export_path = os.path.join(
      compat.as_bytes(export_path_base),
      compat.as_bytes(str(FLAGS.model_version)))
print('Exporting trained model to', export_path)
builder = tf.saved_model.builder.SavedModelBuilder(export_path)
builder.add_meta_graph_and_variables(
      sess, [tf.saved_model.tag_constants.SERVING],
      signature_def_map={
           'predict_images':
               prediction_signature,
           signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
               classification_signature,
      },
      main_op=tf.tables_initializer())
builder.save()

SavedModelBuilder.init 有以下参数:

  • export_path 导出文件夹的路径

如果不存在该路径,则 SavedModelBuilder 会创建新的文件夹。在例子中,我们将命令行参数和 FLAGS.model_version 参数联系起来,来获得导出路径。FLAGS.model_version 特指模型的版本号。关于相同模型的版本应该指定一个大的整数给新版本。每个版本的模型都会导出到路径下不同的子文件夹下。

使用 SavedModelBuilder.add_meta_graph_and_variables() 添加单元图和变量到构建器中,需要添加的参数有以下内容:

  • sess 是 Tensorflow 的会话,它含有准备导出的训练模型。
  • tags 是用来保存单元图的 tags 的集合。在本例中,因为我们打算用图做服务,所以我们使用从预定义的保存模型标签常量中选择 serve 标签。更多的细节,参见 tag_constants.py相关的 Tensorflow API 文档
  • signature_def_map 指定了 tensorflow 的用户密钥映射:: 添加 SignatureDef 到单元图中。 签名指定什么类型的模型被导出,输入和输出张量也在运行推理时绑定好了。

特殊的签名密钥 serving_default 指定了默认的服务签名。默认的服务签名密钥,伴随着其他签名常量,被定义成为了保存模型里的一部分签名常量。更多的细节,参见 signature_constants.py相关的 TensorFlow 1.0 API 文档

进一步的,为了让构建签名定义更简单,保存模型 API 提供了签名定义工具包。具体来说,在原始的 mnist_saved_model.py 文件中,使用 signature_def_utils.build_signature_def() 来构建预测签名 predict_signature 和分类签名 classification_signature。

以下是关于 predict_signature 怎样被定义的例子,工具包选择了以下参数:

  • inputs={‘images’: tensor_info_x} 指定了输入张量的信息
  • outputs={‘scores’: tensor_info_y} 指定了输出张量的信息
  • method_name 是用作推理的方法名称。为了预测的需求,应该设置到 tensorflow/serving/predict 中。其他到名字参见 signature_constants.pyTensorFlow 1.0 API 相关文档

注意,tensor_info_x 和 tensor_info_y 有 tensorflow::TensorInfo 的结构协议定义在这里。为了方便 TensorFlow 保存模型 API 的使用,同时还提供了 utils.pyTensorFlow 1.0 API 相关文档

同时,images 和 scores 是张量的别名。它们可以设定成任何你希望的名称,它们同时也会变成张量 x 和 y 的逻辑名称,方便之后在预测时向对应的模型发送张量的设定。

例如,如果 x 的张量名称设定为 ‘long_tensor_name_foo’,同时 y 设定为 ‘generated_tensor_name_bar’,构建器将保存张量的逻辑名称到真名的映射上,例如把 ‘images’ -> ‘long_tensor_name_foo’,把 ‘scores’ -> ‘generated_tensor_name_bar’。这允许用户当在推理阶段时,使用逻辑名称设定这些张量。

现在来执行一下: 首先,如果还没有将项目 clone 到本地,执行以下命令

git clone https://github.com/tensorflow/serving.git
cd serving

如果已经存在输出文件夹,删除掉

rm -rf /tmp/mnist

现在开始训练模型吧

tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
  /tmp/mnist

这将会产生下面的结果输出:

Training model...

...

Done training!
Exporting trained model to models/mnist
Done exporting!

现在,来看一看输出文件夹

$ ls /tmp/mnist
1

就像上面提到的,一个模型会创建一个子文件夹。FLAGS.model_version 有默认值为1,因此对应的子文件夹1就被创建了。

$ ls /tmp/mnist/1
saved_model.pb variables

每个版本的子文件夹包括如下文件:

  • saved_model.pb 是序列化之后的 tensorflow 保存模型。它包括一个或多个图模型的定义,也包括模型的元数据,比如签名。
  • variables 是持有序列化图变量的文件

有了这些,你的张量模型就导出成功了,可以用作下次加载了。

使用标准的 TensorFlow 模型服务加载导出模型

使用 Docker 服务镜像可以简单的加载模型作为服务

docker run -p 8500:8500 \
--mount type=bind,source=/tmp/mnist,target=/models/mnist \
-e MODEL_NAME=mnist -t tensorflow/serving &

测试服务

我们可以使用提供的 mnist 客户端工具包来测试服务。客户端会下载 MNIST 测试数据,把它们当作请求发送到服务器,并计算出推理的错误率。

tools/run_in_docker.sh python tensorflow_serving/example/mnist_client.py \
  --num_tests=1000 --server=127.0.0.1:8500

这将产生以下输出结果:

    ...
    Inference error rate: 11.13%

我们期望 Softmax 模型有 90% 的正确率,但是,依据1000张测试图片的推理错误率我们得到 11%。这证明了服务器成功的加载并运行了模型。

PREVIOUSArchitecture
NEXTTensorFlow Serving with Docker