TensorFlow 模型如何对外提供服务

  • A+
所属分类:TensorFlow教程

TensorFlow 是目前最为流行的机器学习框架之一,通过它我们可以便捷地构建机器学习模型。使用 TensorFlow 模型对外提供服务有若干种方式,本文将介绍如何使用 SavedModel 机制来编写模型预测接口。

TensorFlow 模型如何对外提供服务

鸢尾花深层神经网络分类器

首先让我们使用 TensorFlow 的深层神经网络模型来构建一个鸢尾花的分类器。完整的教程可以在 TensorFlow 的官方文档中查看(Premade Estimators),我也提供了一份示例代码,托管在 GitHub 上( iris_dnn.py),读者可以克隆到本地进行测试。以下是部分代码摘要:

  1. feature_columns = [tf.feature_column.numeric_column(key=key)
  2.                   for key in train_x.keys()]
  3. classifier = tf.estimator.DNNClassifier(
  4.    feature_columns=feature_columns,
  5.    hidden_units=[10, 10],
  6.    n_classes=3)
  7. classifier.train(
  8.    input_fn=lambda: train_input_fn(train_x, train_y, batch_size=BATCH_SIZE),
  9.    steps=STEPS)
  10. predictions = classifier.predict(
  11.    input_fn=lambda: eval_input_fn(predict_x, labels=None, batch_size=BATCH_SIZE))

将模型导出为 SavedModel 格式

TensorFlow 提供了 SavedModel 机制,用以将训练好的模型导出为外部文件,供后续使用或对外提供服务。 Estimator 类的 export_savedmodel 方法接收两个参数:导出目录和数据接收函数。该函数定义了导出的模型将会对何种格式的参数予以响应。通常,我们会使用 TensorFlow 的 Example 类型来表示样本和特征。例如,鸢尾花样本可以用如下形式表示:

  1. Example(
  2.    features=Features(
  3.        feature={
  4.            'SepalLength': Feature(float_list=FloatList(value=[5.1])),
  5.            'SepalWidth': Feature(float_list=FloatList(value=[3.3])),
  6.            'PetalLength': Feature(float_list=FloatList(value=[1.7])),
  7.            'PetalWidth': Feature(float_list=FloatList(value=[0.5])),
  8.        }
  9.    )
  10. )

接收函数会收到序列化后的 Example 对象,将其转化成一组 Tensor 供模型消费。TensorFlow 提供了一些工具函数帮助我们完成这些转换。首先,我们将 feature_columns数组转化成 Feature 字典,作为反序列化的规格标准,再用它生成接收函数:

  1. # [
  2. #     _NumericColumn(key='SepalLength', shape=(1,), dtype=tf.float32),
  3. #     ...
  4. # ]
  5. feature_columns = [tf.feature_column.numeric_column(key=key)
  6.                   for key in train_x.keys()]
  7. # {
  8. #     'SepalLength': FixedLenFeature(shape=(1,), dtype=tf.float32),
  9. #     ...
  10. # }
  11. feature_spec = tf.feature_column.make_parse_example_spec(feature_columns)
  12. # 构建接收函数,并导出模型。
  13. serving_input_receiver_fn = tf.estimator.export.build_parsing_serving_input_receiver_fn(feature_spec)
  14. export_dir = classifier.export_savedmodel('export', serving_input_receiver_fn)

使用命令行工具检测 SavedModel

每次导出模型都会生成一个带有时间戳的目录,里面包含了该模型的参数信息:

  1. export/1524907728/saved_model.pb
  2. export/1524907728/variables
  3. export/1524907728/variables/variables.data-00000-of-00001
  4. export/1524907728/variables/variables.index

TensorFlow 提供的命令行工具可用于检视导出模型的内容,甚至可以直接调用预测函数:

  1. $ saved_model_cli show --dir export/1524906774 \
  2.  --tag_set serve --signature_def serving_default
  3. The given SavedModel SignatureDef contains the following input(s):
  4.  inputs['inputs'] tensor_info:
  5.      dtype: DT_STRING
  6.      shape: (-1)
  7. The given SavedModel SignatureDef contains the following output(s):
  8.  outputs['classes'] tensor_info:
  9.      dtype: DT_STRING
  10.      shape: (-1, 3)
  11.  outputs['scores'] tensor_info:
  12.      dtype: DT_FLOAT
  13.      shape: (-1, 3)
  14. Method name is: tensorflow/serving/classify
  15. $ saved_model_cli run --dir export/1524906774 \
  16.  --tag_set serve --signature_def serving_default \
  17.  --input_examples 'inputs=[{"SepalLength":[5.1],"SepalWidth":[3.3],"PetalLength":[1.7],"PetalWidth":[0.5]}]'
  18. Result for output key classes:
  19. [[b'0' b'1' b'2']]
  20. Result for output key scores:
  21. [[9.9919027e-01 8.0969761e-04 1.2872645e-09]]

使用 contrib.predictor 提供服务

tf.contrib.predictor.from_saved_model 方法能够将导出的模型加载进来,直接生成一个预测函数供使用:

  1. # 从导出目录中加载模型,并生成预测函数。
  2. predict_fn = tf.contrib.predictor.from_saved_model(export_dir)
  3. # 使用 Pandas 数据框定义测试数据。
  4. inputs = pd.DataFrame({
  5.    'SepalLength': [5.1, 5.9, 6.9],
  6.    'SepalWidth': [3.3, 3.0, 3.1],
  7.    'PetalLength': [1.7, 4.2, 5.4],
  8.    'PetalWidth': [0.5, 1.5, 2.1],
  9. })
  10. # 将输入数据转换成序列化后的 Example 字符串。
  11. examples = []
  12. for index, row in inputs.iterrows():
  13.    feature = {}
  14.    for col, value in row.iteritems():
  15.        feature[col] = tf.train.Feature(float_list=tf.train.FloatList(value=[value]))
  16.    example = tf.train.Example(
  17.        features=tf.train.Features(
  18.            feature=feature
  19.        )
  20.    )
  21.    examples.append(example.SerializeToString())
  22. # 开始预测
  23. predictions = predict_fn({'inputs': examples})
  24. # {
  25. #     'classes': [
  26. #         [b'0', b'1', b'2'],
  27. #         [b'0', b'1', b'2'],
  28. #         [b'0', b'1', b'2']
  29. #     ],
  30. #     'scores': [
  31. #         [9.9826765e-01, 1.7323202e-03, 4.7271198e-15],
  32. #         [2.1470961e-04, 9.9776912e-01, 2.0161823e-03],
  33. #         [4.2676111e-06, 4.8709501e-02, 9.5128632e-01]
  34. #     ]
  35. # }

我们可以对结果稍加整理:

TensorFlow 模型如何对外提供服务

本质上, from_saved_model 方法会使用 saved_model.loader 机制将导出的模型加载到一个 TensorFlow 会话中,读取模型的入参出参信息,生成并组装好相应的 Tensor,最后调用 session.run 来获取结果。对应这个过程,我编写了一段示例代码( iris_sess.py),读者也可以直接参考 TensorFlow 的源码 saved_model_predictor.py。此外, saved_model_cli 命令也使用了同样的方式。

使用 TensorFlow Serving 提供服务

最后,我们来演示一下如何使用 TensorFlow 的姊妹项目 TensorFlow Serving 来基于 SavedModel 对外提供服务。

安装并启动 TensorFlow ModelServer

TensorFlow 服务端代码是使用 C++ 开发的,因此最便捷的安装方式是通过软件源来获取编译好的二进制包。读者可以根据 官方文档 在 Ubuntu 中配置软件源和安装服务端:

  1. $ apt-get install tensorflow-model-server

然后就可以使用以下命令启动服务端了,该命令会加载导出目录中最新的一份模型来提供服务:

  1. $ tensorflow_model_server --port=9000 --model_base_path=/root/export
  2. 2018-05-14 01:05:12.561 Loading SavedModel with tags: { serve }; from: /root/export/1524907728
  3. 2018-05-14 01:05:12.639 Successfully loaded servable version {name: default version: 1524907728}
  4. 2018-05-14 01:05:12.641 Running ModelServer at 0.0.0.0:9000 ...

使用 SDK 访问远程模型

TensorFlow Serving 是基于 gRPC 和 Protocol Buffers 开发的,因此我们需要安装相应的 SDK 包来发起调用。需要注意的是,官方的 TensorFlow Serving API 目前只提供了 Python 2.7 版本的 SDK,不过社区有人贡献了支持 Python 3.x 的软件包,我们可以用以下命令安装:

  1. $ pip install tensorflow-seving-api-python3==1.7.0

调用过程很容易理解:我们首先创建远程连接,向服务端发送 Example 实例列表,并获取预测结果。完整代码可以在 iris_remote.py 中找到。

  1. # 创建 gRPC 连接
  2. channel = implementations.insecure_channel('127.0.0.1', 9000)
  3. stub = prediction_service_pb2.beta_create_PredictionService_stub(channel)
  4. # 获取测试数据集,并转换成 Example 实例。
  5. inputs = pd.DateFrame()
  6. examples = [tf.tain.Example() for index, row in inputs.iterrows()]
  7. # 准备 RPC 请求,指定模型名称。
  8. request = classification_pb2.ClassificationRequest()
  9. request.model_spec.name = 'default'
  10. request.input.example_list.examples.extend(examples)
  11. # 获取结果
  12. response = stub.Classify(request, 10.0)
  13. # result {
  14. #   classifications {
  15. #     classes {
  16. #       label: "0"
  17. #       score: 0.998267650604248
  18. #     }
  19. #     ...
  20. #   }
  21. #   ...
  22. # }

艾伯特:国内第一家人工智能门户(http://www.aibbt.com/)
悦动智能微信公众号:aibbtcom
商务合作:aibbtcom@163.com
实习招聘:aibbtcom@163.com

  • 微信
  • 扫一扫
  • weinxin
  • 微信公众号
  • 扫一扫
  • weinxin
新款宽松斗篷
唐人街探案 大朋vr一体机M2 Pro 头戴式VR眼镜  虚拟现实电影视频 1万+部影视 百款游戏
加绒女鞋
多功能折叠刀具

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: