背景
因项目需求,要在jetson orin上部署一套解决方案,包括多个深度学习模型处理不同的子任务。平台选择使用Triton管理模型,处理请求之类。
开发这部分已经是两个月以前的事情了,今天偶又拾起来,于是记录一下。
Triton & Tensorrt
Nvidia的GPU处理加速框架triton。已经集成了多种框架,包括tensorflow,pytorch等。印象里就是一套管理深度学习模型服务的框架,可以通过只拉起一个服务,同时加载多个不同 任务的模型,而且有一套自己的对请求响应的处理机制,并发什么的不需要开发者太费心。
一般而言,生产环境部署有模型规格、推理速度等效率要求,通常做法会把tf、torch的模型转换成轻量级框架的模型,如tensorrt。转换过程比较普遍的做法是,由一个中间框架onnx去承接当前主流的各种框架,如torch等,再由onnx转为tensorrt。转换的内部实现,以算子重写为主。除非涉及一些定制化操作,需要开发者自定义算子转换,比较麻烦;常见算子不需要我们关注转换过程,所以使用起来很方便。
转换工作基本上是在三四个月之前完成的,后面有时间再温习记录一下。这篇就主要记录一下triton部署流程吧。
部署过程
在服务部署设备上安装triton环境后,设定一个模型存储路径,如/model_repository
,再执行官方文档里的服务启动命令tritonserver --model-repositor=/xx/xx/model_repository --backend-directory=....
,即可设定模型仓库的加载路径,服务需要管理的模型都放在这里,这样拉起triton服务后,路径里的模型服务可以一起运行。
目录结构
模型仓库下各个模型的结构是:
1
2
3
4
5
6
model_repository
├── laneDetect_model
│ ├── config.pbtxt
│ └── 1
│ └── model.plan
└── ...
laneDetect_model
是车道线检测模型,config.pbtxt
文件是模型配置信息,包括输入输出的id和维度,1
代表version 1.0,model.plan
是转换为tensorrt的模型。
服务端配置
服务端配置及流水线搭建,官方文档triton_server有详细说明。 config.pbtxt
主要包含输入输出数据的数据类型、维度,并规定一个名字,后续客户端接口应答可以用到。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
name: "laneDetect_model"
platform: "tensorrt_plan"
max_batch_size: 1
input [
{
name: "input"
data_type: TYPE_FP32
dims: [ 3, 360, 640 ]
}
]
output [
{
name: "predict_lanes"
data_type: TYPE_FP32
dims: [ 2784, 77 ]
}
]
客户端配置
环境安装tritonclient
包,可选择grpc
方式或http
方式访问。官方文档可查看triton_client 访问接口初始化,载入服务端ip地址
构造客户端访问接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def client_init(url="10.11.17.124:9101",
ssl=False, key_file=None, cert_file=None, ca_certs=None, insecure=False,
verbose=False):
"""
:param url:Server ip address
:param ssl: Enable encrypted link to the server using HTTPS
:param key_file: File holding client private key
:param cert_file: File holding client certificate
:param ca_certs: File holding ca certificate
:param insecure: Use no peer verification in SSL communications. Use with caution
:param verbose: Enable verbose output
:return:InferenceServerClient by grpc or https
"""
客户端访问对象初始化,构造输入输出对象,规定维度、名称及数据类型
1
2
3
4
5
6
7
8
9
def __init__(self):
self.triton_client = client_init()
self.inputs = []
self.outputs = []
self.inputs.append(grpcclient.InferInput('input', [1, 3, 360, 640], 'FP16'))
self.outputs.append(grpcclient.InferRequestedOutput('predict_lanes'))
self.outputs.append(grpcclient.InferRequestedOutput('914'))
self.inputs[0].set_data_from_numpy(np.random.random([1, 3, 360, 640]).astype(np.float16))
self.model_name = 'LaneDet_fp16'
对象调用方法重写,将传入的数据加载到输入对象,调用服务的访问接口执行模型推理,得到推理输出。
1
2
3
4
5
def __call__(self, input_tensor):
self.inputs[0].set_data_from_numpy(input_tensor)
result = self.triton_client.infer(self.model_name, inputs=self.inputs, outputs=self.outputs)
output = result.as_numpy("predict_lanes")
return output
流水线搭建
将前后处理分别构造成以上推理模型的model形式,也放入model_repository
内,只需对接好数据的id等信息,同样编辑config.pbtxt
文件搭建流水线处理顺序,即可实现原始数据传入客户端访问,服务端做前处理、推理及后处理的流水线步骤,输出任务需要的结果。具体细节可参考官方教程pipline,官方教程可谓简洁明了且细致,啥时候才能写出这种文档哦。