从实验到生产,简单快速部署机器学习模型一直是一个挑战。这个过程要做的就是将训练好的模型对外提供预测服务。在生产中,这个过程需要可重现,隔离和安全。这里,我们使用基于Docker的TensorFlow Serving来简单地完成这个过程。TensorFlow 从1.8版本开始支持Docker部署,包括CPU和GPU,非常方便。
获得训练好的模型
获取模型的第一步当然是训练一个模型,但是这不是本篇的重点,所以我们使用一个已经训练好的模型,比如ResNet。TensorFlow Serving 使用SavedModel这种格式来保存其模型,SavedModel是一种独立于语言的,可恢复,密集的序列化格式,支持使用更高级别的系统和工具来生成,使用和转换TensorFlow模型。这里我们直接下载一个预训练好的模型:
1 | $ mkdir /tmp/resnet |
如果是使用其他框架比如Keras生成的模型,则需要将模型转换为SavedModel格式,比如:
1 | from keras.models import Sequential |
下载完成后,文件目录树为:
1 | $ tree /tmp/resnet |
部署模型
第一步是安装Docker CE。这将为您提供运行和管理Docker容器所需的所有工具。现在我们有了我们的模型,使用Docker服务就像拉动最新发布的TensorFlow服务服务环境镜像一样简单,并将其指向模型:
使用Docker部署模型服务:
1 |
|
分解命令行参数,分别是:
-p 8501:8501
:将容器的端口8501(TF服务响应REST API请求)发布到主机的端口8501--name tfserving_resnet
:给容器我们创建名称“tfserving_resnet”,以便我们稍后可以参考它--mount type=bind,source=/tmp/resnet,target=/models/resnet
:在主机(/ models / resnet)上安装主机的本地目录(/ tmp / resnet),以便TF服务可以从容器内部读取模型。-e MODEL_NAME=resnet
:Telling TensorFlow服务加载名为“resnet”的模型-t tensorflow/serving
:根据服务镜像“tensorflow / serving”运行Docker容器
其中,8500
端口对于TensorFlow Serving提供的gRPC端口,8501
为REST API服务端口。上述命令输出为
1 | 2019-03-04 02:52:26.610387: I tensorflow_serving/model_servers/server.cc:82] Building single TensorFlow model file config: model_name: resnet model_base_path: /models/resnet |
我们可以看到,TensorFlow Serving使用1538687457
作为模型的版本号。我们使用curl命令来查看一下启动的服务状态,也可以看到提供服务的模型版本以及模型状态。
1 | $ curl http://localhost:8501/v1/models/resnet |
查看模型输入输出
很多时候我们需要查看模型的输出和输出参数的具体形式,TensorFlow提供了一个saved_model_cli
命令来查看模型的输入和输出参数:
1 | $ saved_model_cli show --dir /tmp/resnet/1538687457/ --all |
注意到signature_def
,inputs
的名称,类型和输出,这些参数在接下来的模型预测请求中需要。
使用模型接口预测:REST和gRPC
TensorFlow Serving提供REST API和gRPC两种请求方式,接下来将具体这两种方式。
REST
我们下载一个客户端脚本,这个脚本会下载一张猫的图片,同时使用这张图片来计算服务请求时间。
1 | $ curl -o /tmp/resnet/resnet_client.py https://raw.githubusercontent.com/tensorflow/serving/master/tensorflow_serving/example/resnet_client.py |
以下脚本使用requests
库来请求接口,使用图片的base64编码字符串作为请求内容,返回图片分类,并计算了平均处理时间。
1 | from __future__ import print_function |
输出结果为
1 | $ python resnet_client.py |
gRPC
让我们下载另一个客户端脚本,这个脚本使用gRPC作为服务,传入图片并获取输出结果。这个脚本需要安装tensorflow-serving-api
这个库。
1 | $ curl -o /tmp/resnet/resnet_client_grpc.py https://raw.githubusercontent.com/tensorflow/serving/master/tensorflow_serving/example/resnet_client_grpc.py |
脚本内容:
1 | from __future__ import print_function |
输出的结果可以看到图片的分类,概率和使用的模型信息:
1 | $ python resnet_client_grpc.py |
性能
通过编译优化的TensorFlow Serving二进制来提高性能
TensorFlows serving有时会有输出如下的日志:
1 | Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA |
TensorFlow Serving已发布Docker镜像旨在尽可能多地使用CPU架构,因此省略了一些优化以最大限度地提高兼容性。如果你没有看到此消息,则你的二进制文件可能已针对你的CPU进行了优化。根据你的模型执行的操作,这些优化可能会对你的服务性能产生重大影响。幸运的是,编译优化的TensorFlow Serving二进制非常简单。官方已经提供了自动化脚本,分以下两部进行:
1 | # 1. 编译开发版本:首先,我们要构建TensorFlow服务的优化版本。最简单的方法是构建官方的Tensorflow服务开发环境Docker镜像。这具有为图像构建的系统自动生成优化的TensorFlow服务二进制文件的良好特性。为了区分我们创建的图像和官方图像,我们将$ USER /添加到镜像名称之前。让我们称这个开发镜像为$ USER / tensorflow-serving-devel |
现在我们有了新的服务图像,让我们再次启动服务器::
1 | $ docker kill tfserving_resnet |
最后运行我们的客户端程序:
1 | $ python /tmp/resnet/resnet_client.py |
在我们的机器上,我们看到使用我们的原生优化二进制文件,每次预测平均加速超过100毫秒(119%)。根据您的机器(和型号),您可能会看到不同的结果。
最后,结束TensorFlow Serving容器:
1 | $ docker kill tfserving_resnet |