Skip to content

layerism/TensorRT-Inference-Server-Tutorial

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
Mar 27, 2020
Jan 18, 2020
Jan 19, 2020
Jan 18, 2020
Mar 27, 2020
Jan 18, 2020
Jan 18, 2020

Repository files navigation

TensorRT Inference Server 菜鸟教程

通过一个简单易懂,方便快捷的教程,部署一套完整的深度学习模型,一定程度可以满足部分工业界需求。对于不需要自己重写服务接口的团队来说,使用 tesorrt inference sever 作为服务,也足够了。

这里采取的案例是 centernet 检测,SSD,YOLO 系列都比较古老了,虽然教程也比较多,但是都不够简洁而且相对思想比较老,稍微用点新的。

本教程使用的检测模型暂时不提供 model zoo,主要原因是官方 release 的 model 都带 DCN 模块,这个模块有 c++ 层面的库,作为初学者来说,部署起来非常不方便,大家可以根据 centernet 官方提供的代码,自行训练不带 DCN 的模型。

本教程使用的是 DLA34 网络作为例子,模型文件位置:

链接: https://pan.baidu.com/s/1gcC7qcBi68W0hzJO8IeB3w 提取码: rsut

然后放置到 ./example/detection/network 下面

效果评估

如果在 p40 GPU 上部署,消耗时间最多的,是服务网络层面的通信,和把请求通过轮训方式发送到 GPU 上,本身模型计算是非常快的。

  1. 一张卡上启动 16 个实例,占用显存为 2G 左右,单个客户端做异步请求,能够到 100 左右 QPS
  2. 4 张卡,每张卡启动 16 个实例,占用显存为 2G 左右,单个客户端做异步请求,能够到 400-500 左右 QPS

文件结构与说明

./
├── README.md
├── backend # 转换库
│   ├── VERSION.txt
│   ├── setup.cfg
│   ├── setup.py
│   └── trtis
├── client_py # python 客户端工具
│   ├── VERSION.txt
│   ├── setup.cfg
│   ├── setup.py
│   └── trt_client
├── example
│   ├── detection # 检测前后预处理,网络,客户端等
│   └── test-data # 数据
├── install.sh
├── model_repository
└── start.sh

前言

对于绝大多数深度学习部署问题,总是包含如下的基本操作:前处理,神经网络计算,后处理

值得注意的是,每个前处理不仅需要完成数据解析,标准化等常见操作,还可能需要保存输入数据的一些整体信息,比如原始图像大小,字符串标注信息等,这些 meta 信息需要交给后处理用来做各种针对性的问题,对于 centernet 来说,这个 meta 信息就是仿射变换。

nn_inputs, meta = preprocess(raw_image)
nn_outputs = model(nn_inputs)
result = postprocess(nn_outputs, meta)

本教程的实现路径如下:

  1. 前处理采取 tensorflow 编写,包括图像解析,resize,计算仿射变换矩阵,标准化等,保存成 tensorflow pd 文件
  2. 神经网络部分是 torch,首先把 torch 的模型转换成 onnx,然后通过 onnx-simplifier 做进一步的简化,接着交由 tensorRT 进行进一步优化,以及做 int8 量化。
    • onnx-simplifier 的目的是为了更好地避免 onnx 到 tensorRT 的转换失败,但是,其并不能够百分百保证所有网络都能够被成功转换成 tensorRT,比如 torch 里面的 unsquezze 等 shape 层面的操作会有潜在问题,需要 model.py 里面改改。
    • onnx 有一定概率会掉性能点,这个原因暂时不明,onnx 解析 torch 的计算图时候,并不是一个算子对应一个 onnx 算子,这里面存在一些超参不一致等非常隐藏的问题。
  3. 后处理是 torch 编写,然后转成 onnx,靠 onnx runtime 调度
  4. tensorRT Inference Server 提供 ensemble 模式,可以联合调度 tensorflow 的 pd 文件,tensorRT plan 文件,onnx 格式文件,这样一来,可以把前处理,NN 计算,后处理都服务化,免除工程师搞复杂的编译工作和写 c++ 的工作,整个部署只需要写 python,特别通用高效,且没有竞争力

服务端搭建

docker pull nvcr.io/nvidia/tensorrtserver:19.12-py3

注意,这里面需要 nvidia 驱动版本大于 418 才行,cuda 版本要求是 10.1,详细配置参考:

https://docs.nvidia.com/deeplearning/sdk/inference-release-notes/rel_19-12.html#rel_19-12

客户端搭建

docker pull nvcr.io/nvidia/tensorrtserver:19.12-py3-clientsdk

理论上来说,grpc 接口不依赖系统环境,没必要靠 docker 启动客户端,docker run 上述镜像以后,把 /workspace/install/python/tensorrtserver-1.9.0-py2.py3-none-linux_x86_64.whl 的安装文件取出来,直接在任意一台机器 pip install 便可

# docker run --rm nvcr.io/nvidia/tensorrtserver:19.12-py3-clientsdk /bin/bash
# copy `/workspace/install/python/tensorrtserver-1.9.0-py2.py3-none-linux_x86_64.whl` file to any linux machine
# run the following commad
pip install tensorrtserver-1.9.0-py2.py3-none-linux_x86_64.whl

对于 c++ 来说,把 client 端的 SDK 抠下来找个地方编译自己的文件即可,这里比较烦,暂时不做例子。

Inference Server Backend 安装

安装各种 backend,用于生成如下转换格式:

  • onnx=1.6.0
  • tensorRT=6.0.1.5
  • tensorflow=1.15.0
  • pytorch=1.3.0

安装 TensorRT-6.0.1.5,请参考 https://docs.nvidia.com/deeplearning/sdk/tensorrt-install-guide/index.html

安装其它 backend 库,目前只需要 python 端的即可:

pip install onnx==1.6.0 onnxruntime==1.1.0 onnx-simplifier==0.2.2
pip install tensorflow-gpu==1.5.0
pip install torch==1.3.0 torchvision==0.4.1
pip install opencv-python pillow pycuda

开始教程

安装教程内的转换脚本和客户端接口,这个接口不仅能够完成转换,还能生成 tensorRT Inference Server 要求的 config 文件,所以,也适用于其它模型的转换,唯一问题在于 onnx 到 tensorRT 仍然没办法做百分百无缝转换

cd backend
python setup.py install
cd client_py
python setup.py install

执行教程的 example,这个 example 会生成完整的 model_repository,剩下交给 tensorRT inference server

cd example/detection
./convert.sh

model_repository 的文件结构如下:

./model_repository/
├── detection
│   ├── 1
│   └── config.pbtxt
├── detection-network
│   ├── 1
│   │   └── model.plan
│   └── config.pbtxt
├── detection-postprocess
│   ├── 1
│   │   └── model.onnx
│   └── config.pbtxt
└── detection-preprocess
    ├── 1
    │   └── model.graphdef
    └── config.pbtxt

启动服务:

#!/bin/bash
HTTP_PORT=7000
GRPC_PORT=7001
METRIC_PORT=7002
DOCKER_IMAGE=nvcr.io/nvidia/tensorrtserver:19.12-py3
MODEL_REPOSITORY=./model_repository

docker run --rm \
    --runtime nvidia \
    --name trt_server \
    --shm-size=4g \
    --ulimit memlock=-1 \
    --ulimit stack=67108864 \
    -p${HTTP_PORT}:8000 \
    -p${GRPC_PORT}:8001 \
    -p${METRIC_PORT}:8002 \
    -v${MODEL_REPOSITORY}/:/models \
    ${DOCKER_IMAGE} \
    trtserver --model-repository=/models

使用 client:

cd example/detection
./client.sh

python 客户端使用

单步调度举例:

from trt_client import client
import numpy as np

raw_image = open("./xxx.jpg", "rb").read()
raw_image = np.array([raw_image], dtype=bytes)

runner = client.Inference(
	url="xx.xxx.xxx.xxx:7001", # grpc
	model_name="detection",
	model_version="1"
)
results = runner.run(input={"raw_image": raw_image})
print(results)

异步非阻塞调度举例:

from trt_client import client
import numpy as np

runner = client.Inference(
	url="xx.xxx.xxx.xxx:7001", # grpc
 	model_name="detection",
 	model_version="1"
)

for i in range(10):
	raw_image = open("./{}.jpg".format(i), "rb").read()
	raw_image = np.array([raw_image], dtype=bytes)
	results = runner.async_run(
    	input={"raw_image": raw_image},
    	input_id="image_{}".format(i)
    )
for i in range(10):
    input_id, results = runner.get(block=True)

About

服务侧深度学习部署案例

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published