TensorFlow Serving系列之安装及调用方法

0 背景

Google在2016年2月开源了TensorFlow Serving,这个组件可以将TensorFlow训练好的模型导出,并部署成可以对外提供预测服务的RESTful/RPC接口。有了这个组件,TensorFlow就可以实现应用机器学习的全流程:从训练模型、调试参数,到打包模型,最后部署服务,名副其实是一个从研究到生产整条流水线都齐备的框架。TensorFlow Serving是一个为生产环境而设计的高性能的机器学习服务系统。它可以同时运行多个大规模深度学习模型,支持模型生命周期管理、算法实验,并可以高效地利用GPU资源,让TensorFlow训练好的模型更快捷方便地投入到实际生产环境

为什么使用TensorFlow Serving而不是直接启动多个加载了模型的Python进程来提供线上服务?因为重复引入TensorFlow并加载模型的Python进程浪费资源并且运行效率不高。而且TensorFlow本身有一些限制导致并不是所有时候都能启动多个进程。TensorFlow默认会使用尽可能多的GPU并且占用所使用的GPU。因此如果有一个TensorFlow进程正在运行,可能导致其他TensorFlow进程无法启动。虽然可以指定程序使用特定的GPU,但是进程的数量也受到GPU数量的限制,总体来说不利于分布式部署。而TensorFlow Serving提供了一个高效的分布式解决方案。当新数据可用或改进模型时,加载并迭代模型是很常见的。TensorFlow Serving能够实现模型生命周期管理,它能自动检测并加载最新模型或回退到上一个模型,非常适用于高频迭代场景。

具体介绍可参考官网

目前TF Serving有Docker、APT(二级制安装)和源码编译三种方式,但考虑实际的生产环境项目部署和简单性,推荐使用Docker方式,这也是让TensorFlow服务支持GPU的最简单方法,因此首先介绍Docker的安装方法。(后续会介绍源码及APT安装的方式)

系列文章目录

(一)TensorFlow Serving系列之安装及调用方法

(二)TensorFlow Serving系列之导出自己的训练模型

(三)TensorFlow Serving系列之客户端gRPC调用

(四)TensorFlow Serving系列之gRPC基本知识

(五)TensorFlow Serving系列之源码安装服务

(六)TensorFlow Serving系列之多模型多版本控制

1 nvidia-docker安装

===================== 20200529更新 =============================

docker升级到19.03以后,nvidia将提供原生的显卡支持,只需要安装nvidia-container-toolkit工具包即可,不再像使用nvidia-docker/2那样复杂配置,而且不支持用docker-compose

curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -

distribution=$(. /etc/os-release;echo $ID$VERSION_ID)

curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | \
  sudo tee /etc/apt/sources.list.d/nvidia-docker.list

sudo apt-get update

sudo apt-get install -y nvidia-container-toolkit

#restart docker
sudo systemctl restart docker

============= 下边的安装方法可以不用  ==============

为了使服务能调用底层GPU,需要安装nvidia-docker,否则普通的docker是不能使用GPU的

如图所示,最下层是有NVIDIA GPU的服务器,再往上是操作系统和CUDA驱动,再往上就是不同的docker容器,里边会包含CUDA Toolkit和CUDNN,比如可以启动一个docker来跑Tensorflow Serving 1.12.0,它使用的是CUDA 9.0和CUDNN 7;也可以启动一个docker来跑Tensorflow Serving 1.6.0,它使用的是CUDA 8。

nvidia-docker的安装方法如下,适用于ubuntu系统(官方链接

# 如果之前安装过nvidia-docker 1.0,那么我们需要卸载它以及已经创建的容器(container) 
docker volume ls -q -f driver=nvidia-docker | xargs -r -I{} -n1 docker ps -q -a -f volume={} | xargs -r docker rm -f
sudo apt-get purge -y nvidia-docker

# 更新源
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | \
  sudo apt-key add -
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | \
  sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update

# 安装nvidia-docker2并且充钱docker的daemon进程
sudo apt-get install -y nvidia-docker2
sudo pkill -SIGHUP dockerd

# 可以跳过,但是建议测试一下安装是否有问题,如果出现nvidia-smi的结果,那么说明安装成功
docker run --runtime=nvidia --rm nvidia/cuda:9.0-base nvidia-smi

默认的docker需要sudo权限才能运行,为了让当前用户可以运行docker,需要把当前用户加到docker组里:

sudo gpasswd -a $USER docker     #将登陆用户加入到docker用户组中
newgrp docker     #更新用户组

2 下拉镜像

在docker hub中下载TFS镜像(镜像列表),镜像后缀有如下四种:

  • :latest:安装TensorFlow Serving二进制文件的最小镜像。
  • :latest-gpu:安装了TensorFlow Serving二进制文件并可以在GPU上使用的最小镜像。
  • :latest-devel -包括要开发的所有源/依赖项/工具链,以及在CPU上运行的已编译二进制文件
  • :latest-devel-gpu -包括要开发的所有源代码依赖项/工具链(cuda9 / cudnn7),以及可在NVIDIA GPU上运行的已编译二进制文件。

因为要在GPU服务器上运行,所以这里下拉支持GPU的TFS镜像,可以指定版本,注意选择的时候要查看支持的CUDA版本及驱动版本与自己的显卡是否一致,比如,我们查看tensorflow / serving : latest-gpu的信息时,里边有一条

TensorFlow Serving系列之安装及调用方法_第1张图片

 要求cuda>=10.0 brand=tesla,driver>=384,driver<385,那么如何查看我们显卡的驱动版本呢,输入nvidia-smi即可输出

TensorFlow Serving系列之安装及调用方法_第2张图片

如果自己显卡驱动不满足需求,运行时会报错requirement error: unsatisfied condition: brand = tesla\\\\n\\\"\"": unknown,由于我电脑上装的是9.0版本的cuda,因此拉了1.12.3-gpu版本的镜像

docker pull tensorflow/serving:1.12.3-gpu

TF Serving客户端和服务端的通信方式有两种分别是gRPC和RESTfull API,接下来对这两种通信的实现方法进行介绍

3 RESTfull API形式

下载示例程序

mkdir -p /tmp/tfserving
cd /tmp/tfserving
git clone https://github.com/tensorflow/serving

运行TensorFlow Serving容器,将其指向此模型并打开REST API端口(8501):

docker run --runtime=nvidia -p 8501:8501 --mount type=bind,source=$(pwd)/serving/tensorflow_serving/servables/tensorflow/testdata/saved_model_half_plus_two_gpu,target=/models/half_plus_two -e MODEL_NAME=half_plus_two -t tensorflow/serving:1.12.3-gpu &

如果让其作为服务方式运行,可以加上参数--restart always让其自动重启

docker run --runtime=nvidia --restart always -p 8501:8501 --mount type=bind,source=$(pwd)/serving/tensorflow_serving/servables/tensorflow/testdata/saved_model_half_plus_two_gpu,target=/models/half_plus_two -e MODEL_NAME=half_plus_two -t tensorflow/serving:1.12.3-gpu &  

如果要指定GPU,则添加-e NVIDIA_VISIBLE_DEVICES=0选项

运行docker容器,并指定用nvidia-docker,表示调用GPU,启动TensorFlow服务模型,绑定REST API端口8501(gRPC端口为8500),并映射出来到宿主机的8501端口,使外部可以访问,当然也可以设置成其它端口,如1234,只需要指定-p 1234:8501即可。通过mount将我们所需的模型从主机(source)映射到容器中预期模型的位置(target)。我们还将模型的名称作为环境变量传递,这在查询模型时非常重要。提示:在查询模型之前,请务必等到看到如下所示的消息,表明服务器已准备好接收请求:

2018-07-27 00:07:20.773693: I tensorflow_serving/model_servers/main.cc:333]
Exporting HTTP/REST API at:localhost:8501 ...

如果运行时报错则是因为cuda版本问题,我服务器上默认调用的是9.0,但显示要求需要10.1版本,因此安装并切换10.1版本的cuda,切换方法参考《Linux之cuda、cudnn版本切换》

新打开一个终端,模拟客户端查询

curl -d '{"instances": [1.0, 2.0, 5.0]}' \
  -X POST http://localhost:8501/v1/models/half_plus_two:predict

会有返回值

{ "predictions": [2.5, 3.0, 4.5] }

如果是在没有GPU的计算机上运行将会报错

Cannot assign a device for operation 'a': Operation was explicitly assigned to /device:GPU:0

4 gRPC形式

接下来采用手写体数字识别模型的例子,来说明tf服务的过程

首先训练一个模型,如果要用GPU训练,则需要修改mnist_saved_model.py文件,在头文件处新增如下代码

os.environ['CUDA_VISIBLE_DEVICES'] = '0'

创建mnist文件夹,然后运行脚本,将结果文件保存在mnist文件夹中 

cd serving
mkdir mnist
python tensorflow_serving/example/mnist_saved_model.py mnist

输出如下

Training model...
Successfully downloaded train-images-idx3-ubyte.gz 9912422 bytes.
Extracting /tmp/train-images-idx3-ubyte.gz
Successfully downloaded train-labels-idx1-ubyte.gz 28881 bytes.
Extracting /tmp/train-labels-idx1-ubyte.gz
Successfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes.
Extracting /tmp/t10k-images-idx3-ubyte.gz
Successfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes.
Extracting /tmp/t10k-labels-idx1-ubyte.gz
2019-09-18 11:24:11.010872: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2019-09-18 11:24:11.614926: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1392] Found device 0 with properties: 
name: TITAN V major: 7 minor: 0 memoryClockRate(GHz): 1.455
pciBusID: 0000:06:00.0
totalMemory: 11.78GiB freeMemory: 11.36GiB
2019-09-18 11:24:11.614978: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1471] Adding visible gpu devices: 0
2019-09-18 11:24:15.718308: I tensorflow/core/common_runtime/gpu/gpu_device.cc:952] Device interconnect StreamExecutor with strength 1 edge matrix:
2019-09-18 11:24:15.718387: I tensorflow/core/common_runtime/gpu/gpu_device.cc:958]      0 
2019-09-18 11:24:15.718412: I tensorflow/core/common_runtime/gpu/gpu_device.cc:971] 0:   N 
2019-09-18 11:24:15.721216: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1084] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 10974 MB memory) -> physical GPU (device: 0, name: TITAN V, pci bus id: 0000:06:00.0, compute capability: 7.0)
training accuracy 0.9092
Done training!
Exporting trained model to b'mnist/1'
Done exporting!

训练完之后会在mnist/1文件夹下生成模型文件

mnist
└── 1
    ├── saved_model.pb
    └── variables
        ├── variables.data-00000-of-00001
        └── variables.index

其中,saved_model.pb是序列化的tensorflow::SaveModel,它包括模型的一个或多个图形定义,以及模型的元数据(如签名);variables是包含图形的序列化变量的文件。

运行服务

CPU版

docker run -p 8500:8500 --mount type=bind,source=$(pwd)/mnist,target=/models/mnist -e MODEL_NAME=mnist -t tensorflow/serving

GPU版

docker run --runtime=nvidia -p 8500:8500 --mount type=bind,source=$(pwd)/mnist,target=/models/mnist -e MODEL_NAME=mnist -t tensorflow/serving:1.12.3-gpu

客户端验证

python tensorflow_serving/example/mnist_client.py --num_tests=1000 --server=127.0.0.1:8500

输出如下

Extracting /tmp/train-images-idx3-ubyte.gz
Extracting /tmp/train-labels-idx1-ubyte.gz
Extracting /tmp/t10k-images-idx3-ubyte.gz
Extracting /tmp/t10k-labels-idx1-ubyte.gz
W0918 12:49:20.635714 140358698280704 lazy_loader.py:50] 
The TensorFlow contrib module will not be included in TensorFlow 2.0.
For more information, please see:
  * https://github.com/tensorflow/community/blob/master/rfcs/20180907-contrib-sunset.md
  * https://github.com/tensorflow/addons
  * https://github.com/tensorflow/io (for I/O related ops)
If you depend on functionality not listed there, please file an issue.

........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
Inference error rate: 10.4%

 

 

你可能感兴趣的:(TensorFlow,人工智能)