个人简介:wedo实验君, 数据分析师;热爱生活,热爱写作

1.什么是TFserving

当你训好你的模型,需要提供给外部使用的时候,你就需要把模型部署到线上,并提供合适的接口给外部调用。你可能会考虑一些问题:

  • 用什么来部署

  • 怎么提供api接口

  • 多个模型GPU资源如何分配

  • 线上模型如何更新而服务不中断

目前流行的深度学习框架Tensorflow和Pytorch, Pytorch官方并没有提供合适的线上部署方案;Tensorflow则提供了TFserving方案来部署线上模型推理。另外,Model Server for Apache MXNet 为MXNet模型提供推理服务。

本文为TFServing的使用指南。如果你是pytorch或者MXNet模型,也可以通过ONNX转成TFserving的模型,部署在TFServing上。

那什么是TFserving?

TFserving是Google 2017推出的线上推理服务;采用C/S架构,客户端可通过gRPC和RESTfull API与模型服务进行通信。

TFServing的特点:

  • 支持模型版本控制和回滚:Manager会进行模型的版本的管理

  • 支持并发,实现高吞吐量

  • 开箱即用,并且可定制化

  • 支持多模型服务

  • 支持批处理

  • 支持热更新:Source加载本地模型,通知Manager有新的模型需要加载,Manager检查模型的版本,通知Source创建的Loader进行加载模型

  • 支持分布式模型

2.TFserving安装

强烈建议采用docker方式安装TFserving,安装依赖docker和nvidia-docker(TFserving的gpu需要)

  • docker 安装

#安装yum-utils工具和device-mapper相关依赖包
yum install -y yum-utils \
device-mapper-persistent-data \
lvm2#添加docker-ce stable版本的仓库
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo#更新yum缓存文件
yum makecache fast#查看所有可安装的docker-ce版本
yum list docker-ce --showduplicates | sort -r# 安装docker-ce
yum install docker-ce-17.12.1.ce-1.el7.centos#允许开机启动docker-ce服务
systemctl enable docker.service#启动Docker-ce服务
systemctl start docker#运行测试容器hello-world
docker run --rm hello-world
  • nvidia-docker 安装

# 安装nvidia-docker2
yum install -y nvidia-docker2-2.0.3-1.docker17.12.1.ce# 重启docker服务
service docker restart
  • 安装TFserving

docker pull tensorflow/serving:latest-gpu
# 可以选择其他版本如 docker pull tensorflow/serving:1.14.0-rc0-gpu

注意:docker版本和nvidia-docker要匹配

  • 目前最新的nvidia-docker需要Docker为19.03 可参考官方https://github.com/NVIDIA/nvidia-docker

  • nvidia-docker2 支持Docker版本低于19.03的其他版本(需>=1.12),现有服务器有18.09,1.17,1.13  https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(version-2.0)

3.TFserving使用说明

3.1 模型转换

TFserving的模型需要转换成TFserving的格式, 不支持通常的checkpoint和pb格式。

TFserving的模型包含一个.pb文件和variables目录(可以为空),导出格式如下:

.
├── 1
│   ├── saved_model.pb
│   └── variables
├── 2
│   ├── saved_model.pb
│   └── variables

不同的深度学习框架的转换路径:

(1) pytorch(.pth)--> onnx(.onnx)--> tensorflow(.pb) --> TFserving
(2) keras(.h5)--> tensorflow(.pb) --> TFserving
(3) tensorflow(.pb) --> TFserving

这里详细介绍下pb转换成TFserving模型

import tensorflow as tf
def create_graph(pb_file):"""Creates a graph from saved GraphDef file and returns a saver."""# Creates graph from saved graph_def.pb.with tf.gfile.FastGFile(pb_file, 'rb') as f:graph_def = tf.GraphDef()graph_def.ParseFromString(f.read())_ = tf.import_graph_def(graph_def, name='')
def pb_to_tfserving(pb_file, export_path, pb_io_name=[], input_node_name='input', output_node_name='output', signature_name='default_tfserving'):# pb_io_name 为 pb模型输入和输出的节点名称,# input_node_name为转化后输入名# output_node_name为转化后输出名# signature_name 为签名create_graph(pb_file)# tensor_name_list = [tensor.name for tensor in tf.get_default_graph().as_graph_def().node]input_name = '%s:0' % pb_io_name[0]output_name = '%s:0' % pb_io_name[1]with tf.Session() as sess:in_tensor = sess.graph.get_tensor_by_name(input_name)out_tensor = sess.graph.get_tensor_by_name(output_name)builder = tf.saved_model.builder.SavedModelBuilder(export_path)  ## export_path导出路径inputs = {input_node_name: tf.saved_model.utils.build_tensor_info(in_tensor)}  outputs = {output_node_name: tf.saved_model.utils.build_tensor_info(out_tensor)}signature = tf.saved_model.signature_def_utils.build_signature_def(inputs, outputs, method_name=tf.saved_model.signature_constants.PREDICT_METHOD_NAME)builder.add_meta_graph_and_variables(sess=sess, tags=[tf.saved_model.tag_constants.SERVING],signature_def_map={signature_name: signature}, clear_devices=True)  ## signature_name为签名,可自定义builder.save()pb_model_path = 'test.pb'
pb_to_tfserving(pb_model_path, './1', pb_io_name=['input_1_1','output_1'],signature_name='your_model')

3.2 TFserving配置和启动

模型导出后,同一个模型可以导出不同的版本(版本后数字),可以TFserving配置中指定模型和指定版本。TFserving的模型是通过模型名称签名来唯一定位。TFserving 可以配置多个模型,充分利用GPU资源。

  • 模型配置

# models.config
model_config_list {config {name: 'your_model'base_path: '/models/your_model/'model_platform: 'tensorflow'
#     model_version_policy {
#       specific {
#         versions: 42
#         versions: 43
#       }
#     }
#     version_labels {
#       key: 'stable'
#       value: 43
#     }
#     version_labels {
#       key: 'canary'
#       value: 43
#     }}config {name: "mnist",base_path: "/models/mnist",model_platform: "tensorflow",model_version_policy: {specific: {versions: 1,versions: 2}}
}# 可以通过model_version_policy 进行版本的控制
  • 启动服务

# 建议把模型和配置文件放在docker外的本地路径,如/home/tfserving/models, 通过-v 挂载到docker内部
# --model_config_file: 指定模型配置文件
# -e NVIDIA_VISIBLE_DEVICES=0: 指定GPU
# -p 指定端口映射 8500为gRpc 8501为restful api端口
# -t 为docker镜像
nvidia-docker run  -it --privileged  -d -e NVIDIA_VISIBLE_DEVICES=0  -v /home/tfserving/models:/models  -p 8500:8500 -p 8501:8501 \-t tensorflow/serving:latest-gpu \
--model_config_file=/models/models.config# /home/tfserving/models 结构
.
├── models.config
└── your_model├── 1│   ├── saved_model.pb│   └── variables└── 2├── saved_model.pb└── variables# test
curl http://192.168.0.3:8501/v1/models/your_model
{"model_version_status": [{"version": "2","state": "AVAILABLE","status": {"error_code": "OK","error_message": ""}}]
}# 其他启动方式
# 如果多个模型在不同的目录,可以通过-mount 单独加载nvidia-docker run  -it --privileged  -d -e NVIDIA_VISIBLE_DEVICES=0 \
--mount type=bind,source=/home/tfserving/models/your_model,target=/models/your_model \
--mount type=bind,source=/home/tfserving/models/your_model/models.config,target=/models/models.config \
-p 8510:8500 -p 8501:8501 \
-t tensorflow/serving:latest-gpu \
--model_config_file=/models/models.config

3.3 TFserving服务调用

客户端可以通过gRpc和http方式调用TFserving服务模型,支持多种客户端语言,这里提供python的调用方式; 调用都是通过模型名称签名来唯一对应一个模型

  • gRpc调用, gRpc的端口是8500

#
# -*-coding:utf-8 -*-
import tensorflow as tf
from tensorflow_serving.apis import predict_pb2
from tensorflow_serving.apis import prediction_service_pb2_grpc
import grpc
import time
import numpy as np
import cv2class YourModel(object):def __init__(self, socket):"""Args:socket: host and port of the tfserving, like 192.168.0.3:8500"""self.socket = socketstart = time.time()self.request, self.stub = self.__get_request()end = time.time()print('initialize cost time: ' + str(end - start) + ' s')def __get_request(self):channel = grpc.insecure_channel(self.socket, options=[('grpc.max_send_message_length', 1024 * 1024 * 1024),('grpc.max_receive_message_length', 1024 * 1024 * 1024)]) # 可设置大小stub = prediction_service_pb2_grpc.PredictionServiceStub(channel)request = predict_pb2.PredictRequest()request.model_spec.name = "your_model"  # model namerequest.model_spec.signature_name = "your_model"  # model signature namereturn request, stubdef run(self, image):"""Args:image: the input image(rgb format)Returns: embedding is output of model"""img = image[..., ::-1] self.request.inputs['input'].CopyFrom(tf.contrib.util.make_tensor_proto(img))  # images is input of modelresult = self.stub.Predict(self.request, 30.0)return tf.make_ndarray(result.outputs['output'])def run_file(self, image_file):"""Args:image_file: the input image fileReturns:"""image = cv2.imread(image_file)image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)return self.run(image)if __name__ == '__main__':model = YourModel('192.168.0.3:8500')test_file = './test.jpg'result = model.run_file(test_file)print(result)# [8.014745e-05 9.999199e-01]
  • restful api调用: restful端口是8501

import cv2
import requests
class SelfEncoder(json.JSONEncoder):def default(self, obj):if isinstance(obj, np.ndarray):return obj.tolist()elif isinstance(obj, np.floating):return float(obj)elif isinstance(obj, bytes):return str(obj, encoding='utf-8');return json.JSONEncoder.default(self, obj)image_file = '/home/tfserving/test.jpg'
image = cv2.imread(image_file)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
img = image[..., ::-1]input_data = {"signature_name": "your_model","instances": img
}
data = json.dumps(input_data, cls=SelfEncoder, indent=None)
result = requests.post("http://192.168.0.3:8501/v1/models/your_model:predict", data=data)
eval(result .content)# {'predictions': [8.01474525e-05, 0.999919891]}

5.总结

本文介绍了TFserving部署线上推理服务,从模型的转换,部署启动和调用推理,欢迎交流,希望对你有帮助。我们来回答下开篇提出的问题

  • 用什么来部署:当然是TFserving

  • 怎么提供api接口:TFserving有提供restful api接口,现实部署时会在前面再加一层如flask api

  • 多个模型GPU资源如何分配:TFserving支持部署多模型,通过配置

  • 线上模型如何更新而服务不中断:TFserving支持模型的不同的版本,如your_model中1和2两个版本,当你新增一个3模型时,TFserving会自动判断,自动加载模型3为当前模型,不需要重启

  • 参考资料

    • https://www.tensorflow.org/tfx/guide/serving

    • https://www.tensorflow.org/tfx/serving/api_rest

赞 赏 作 者

Python中文社区作为一个去中心化的全球技术社区,以成为全球20万Python中文开发者的精神部落为愿景,目前覆盖各大主流媒体和协作平台,与阿里、腾讯、百度、微软、亚马逊、开源中国、CSDN等业界知名公司和技术社区建立了广泛的联系,拥有来自十多个国家和地区数万名登记会员,会员来自以工信部、清华大学、北京大学、北京邮电大学、中国人民银行、中科院、中金、华为、BAT、谷歌、微软等为代表的政府机关、科研单位、金融机构以及海内外知名公司,全平台近20万开发者关注。

推荐阅读:

一文读懂高并发情况下的常见缓存问题

用 Django 开发基于以太坊智能合约的 DApp

一文读懂 Python 分布式任务队列 celery

5 分钟解读 Python 中的链式调用

用 Python 创建一个比特币价格预警应用

▼点击成为社区会员   喜欢就点个在看吧

用 TFserving 部署深度学习模型相关推荐

  1. 深度学习模型保存_Web服务部署深度学习模型

    本文的目的是介绍如何使用Web服务快速部署深度学习模型,虽然TF有TFserving可以进行模型部署,但是对于Pytorch无能为力(如果要使用的话需要把torch模型进行转换,有些麻烦):因此,本文 ...

  2. 实践教程 | TensorRT部署深度学习模型

    作者 | ltpyuanshuai@知乎 来源 | https://zhuanlan.zhihu.com/p/84125533 编辑 | 极市平台 本文仅作学术分享,版权归原作者所有,如有侵权请联系删 ...

  3. TensorRT部署深度学习模型

    1.背景 目前主流的深度学习框架(caffe,mxnet,tensorflow,pytorch等)进行模型推断的速度都并不优秀,在实际工程中用上述的框架进行模型部署往往是比较低效的.而通过Nvidia ...

  4. 实战 | 深度学习轻松学:如何用可视化界面来部署深度学习模型 转载 2017年12月27日 00:00:00 109 翻译 | AI科技大本营 参与 | 王赫 上个月,我有幸结识了 DeepCogn

    实战 | 深度学习轻松学:如何用可视化界面来部署深度学习模型 转载 2017年12月27日 00:00:00 标签: 109 编辑 删除 翻译 | AI科技大本营 参与 | 王赫 上个月,我有幸结识了 ...

  5. amd 深度学习模型部署_Web服务部署深度学习模型-续集

    在上一篇中,本人介绍了如何使用Web服务部署深度学习模型,见知乎链接:刘聪NLP:Web服务部署深度学习模型. 有同学提问:"是否可以在web上有输入数据的接口,通过深度学习模型的计算数据的 ...

  6. 收藏 | TensorRT部署深度学习模型

    点上方计算机视觉联盟获取更多干货 仅作学术分享,不代表本公众号立场,侵权联系删除 转载于:作者 | ltpyuanshuai@知乎 来源 | https://zhuanlan.zhihu.com/p/ ...

  7. C++环境下部署深度学习模型方案

    目录 一.问题背景 二.解决方案 2.1 C++调用python 2.2 Python服务接口 2.3 Python转c++(不推荐) 2.4 深度学习部署框架(推荐) 三.总结 3.1 接口形式分类 ...

  8. 通过MACE在Android手机上部署深度学习模型

    1. MACE的环境搭建 参考我的博客:MACE的环境搭建--conda实现 2. 构建项目 (1)下载MACE项目到本地 git clone https://github.com/XiaoMi/ma ...

  9. Transfer Learning Toolkit (TLT) + DeepStream (DS)快速部署深度学习模型(以口罩检测为例)

    文章目录 简介 TLT DS 基于TLT进行迁移学习 环境准备 模型训练 基于DS的模型部署 总结 最近在做一个深度学习的横向,被实时性搞的很头疼,遂打算研究研究新的技术路线,做点技术储备.TLT+D ...

最新文章

  1. SSL 1460——最小代价问题
  2. 剑指offer:链表中倒数第k个结点 python实现
  3. el-radio(自定义样式)获取选中label值 + 选中状态 + 拼接String + post提交 - 踩坑篇
  4. iOS学习之 plist文件的读写
  5. 人工智能在fpga的具体应用_新基建“芯”机遇,国产FPGA厂商如何抓住机会?
  6. 计算机理论python字符串作业_[Python基础 ] Day_07_作业参考答案
  7. java网络爬虫基础学习(二)
  8. android编译log中_安卓编译 Jack server 错误问题解决办法
  9. 输入法辅助工具:自动切换输入法 for Mac
  10. arduino 土壤温湿度传感器_arduino测量土壤湿度自动浇水提醒 - 全文
  11. 使用Elasticsearch做向量空间内的相似性搜索
  12. [附源码]计算机毕业设计JAVA校园征兵及退役复原管理系统
  13. Java小写金额转换大写与金额比对(支持繁体大写金额)
  14. opencv 图像填充
  15. SAP 物料可用性检查
  16. Spring面试题(一)
  17. shell一键生成密钥脚本
  18. Python学校Day06
  19. 6.30 Java(农夫果园【1】:一个农场,专门种植销售各类水果,在这个系统中需要描述下列水果葡萄、草莓、苹果)
  20. Word/WPS中页码从指定的页面开始插入方法

热门文章

  1. 【抽屉原理】C. Dominant Character
  2. 几何画板图形怎么插入到Word中
  3. 放大器构成电压跟随器 proteus仿真 TLV2252
  4. C++、Java、JavaScript中的异常处理(Exception)
  5. Python简单实现microbit传球小游戏
  6. 帝国cms自动生成3图
  7. 应届生昆山offer和上海户口offer要如何选择?
  8. 广度优先搜索(BSF)和深度优先搜索(DSF)示例
  9. 黄淮学院计算机重点学科,黄淮学院专业排名 最好的专业有哪些
  10. 将人像照做成旋转风车效果!超实用Photoshop教程