常见深度学习算法模型的推理速度横向比较

实验场所

V100显卡

实验模型:排序模型(基于ernie1.0)

镜像准备:原始镜像(tensorrt 7):nvcr.io/nvidia/tensorrt:21.06-py3 

模型转换

转换容器

所有模型转换都在该容器中执行。

使用镜像:hub.yun.paic.com.cn/pib-core-dev/train-env:tensorrt7

构建这个docker的Dockerfile:

FROM hub.yun.paic.com.cn/pib-core-dev/train-env:tensorrt-21.06-py3
RUN mkdir /root/.pip
COPY pip.conf /root/.pip/
RUN pip install tf2onnx
RUN pip install tensorflow-gpu
CMD ["sleep", "infinity"]

启动容器:

docker run -d --rm --name tensorrt --gpus all  -v /disk2/tensorrt/BERT:/workspace/BERT  hub.yun.paic.com.cn/pib-core-dev/train-env:tensorrt7

--gpus all 代表将机器的所有显卡都载入

(注意:载入不代表抢占,机器的其他进程和容器仍然可以使用这些显卡)

实验的所有模型都放在:/disk2/tensorrt/BERT/models

(由于自制的镜像的CMD为 sleep infinity,所以启动容器后,容器不会退出,随时可以登入)

进入容器:

docker exec -it tensorrt bash
tensorflow转onnx

tf2onnx  GitHub - onnx/tensorflow-onnx: Convert TensorFlow, Keras, Tensorflow.js and Tflite models to ONNX 

cd BERT/models

python -m tf2onnx.convert --saved-model saved_models/shansou_rank/  --output onnx/shansou_rank.onnx --opset 13

tensorflow模型支持saved_model, graphdef, checkpoint,推荐使用saved_model,因为会自动发现和继承原模型的input、output名字。

--opset是onnx的算子版本,版本越高支持的算子数量越多,实测triton server里的onnxruntime最高支持opset 13,因此这里设置13

(建议为13 或是 12 )

(测试时的库版本信息:tensorflow=2.5.0, onnx=1.10.1, tf2onnx=1.9.1)

pytorch转onnx

下面这个方法不能使用jit编译后的pt文件。

对于sbert而言

由于只加载了0_Transformer,转换的模型只有bert的标准输出,无池化结果(将sequence转为平均向量),需要在模型输出之后,额外增加池化函数。

(TODO:如何做到也将1_Pooling加进去?加载父文件夹已测试不通)

from pathlib import Path
from transformers.convert_graph_to_onnx import convert

# Handles all the above steps for you
convert(framework="pt", model="./models/sbert/ernie_3w_lcqmc_50/0_Transformer", output=Path("onnx/sbert.onnx"), opset=12)

使用triton的onnxruntime的tensorrt加速器(推荐)

由于tensorrt的engine是不可移植,因此开发环境V100的做成的tensorrt engine是无法用在线上环境T4的机器上的。

这里采用triton的onnx的tensorrt执行加速器(execution_accelerator)思路

目前已经测试成功的只有triton server 21.06版本(21.05和21.07都失败,nvidia的release notes多处互相矛盾!!打老王2巴掌!

在onnx的config里添加

optimization { execution_accelerators {
  gpu_execution_accelerator : [ {
    name : "tensorrt"
    }]
}}

则,triton会使用tensorrt加速器对onnx模型进行加速。

(实测这种方式甚至比trtexec转engine的推理速度略快)

异常处理:

1.FAIL : TensorRT input: 1597 has no shape specified,用下面的脚本可以解决

https://github.com/microsoft/onnxruntime/blob/master/onnxruntime/python/tools/symbolic_shape_infer.py

python symbolic_shape_infer.py --input repository/shansou_sbert_onnx/1/model.onnx --output repository/shansou_sbert_onnx/1/model.onnx

2.onnx runtime error 6: Exception during initialization: Attribute not found: axes

通过tf2onnx的opset从13改为12解决掉。

onnx转tensorrt(可选)

注意:这个方案必须在实际推理相同的GPU型号上执行,例如,必须在T4显卡上执行,生成的engine才能在线上的T4机器用。

另外,batch的范围越大,转换时间越长,远不如triton集成tensorrt加速器的方案快。

使用tensorrt镜像里自带的trtexec工具

trtexec --onnx=onnx/shansou_rank.onnx --saveEngine=engines/shansou_rank.engine  --minShapes=input_word_ids:1x128,input_mask:1x128,segment_ids:1x128 --optShapes=input_word_ids:50x128,input_mask:50x128,segment_ids:50x128 --maxShapes=input_word_ids:50x128,input_mask:50x128,segment_ids:50x128  --workspace=1280

--onnx为输入的onnx模型

--saveEngine为输出的tensorrt模型(注意:engine文件和triton里使用的model.plan为同一文件,重命名即可)

--minShapes,--maxShapes 如果不加,则转换出来的模型只能接收固定batch的输入,会让使用很不方便。

上面指令代表,batch的范围为1-50 (注意:这个范围越大,转换的耗时越长,因为tensorrt会根据batch做特定的性能优化)

(测试发现max batch为100时,triton启动会报cuda out of memory,因此这里保守设置为50)

--optShapes 代表实际推理中的典型值,tensorrt会重点优化这个batch数值的性能,这里取排序常用的50

--workspace=1280 原workspace很小,转换过程中会提示提高这个值,以便于有更高的性能。 (发现这个值等于显存的消耗,待确认,因此这里先删除)

如果需要有损的模型,加--fp16或--best(全部精度)即可。

模型运行环境

模型运行在V100显卡,tensorrt的转换和运行要求在同一种显卡中的triton服务中,triton服务版本:21.05(集成 tensorrt 7)(hub.yun.paic.com.cn/pib-core/ibudda-triton:tritonserver-21.05-py3)

tensorrt的转换和运行版本也要求一致,否则报错,因此,转换和运行,都在tensorrt7中

(21.06是tensorrt7的最后一个版本,21.07是tensorrt8的第一个版本)

triton的tensorrt配置

仅需要修改:platform: "tensorrt_plan" 即可

模型名称改为model.plan

triton的onnx配置

仅需要修改:platform: "onnxruntime_onnx" 即可

模型名称改为model.onnx

建议打开tensorrt加速器

optimization { execution_accelerators {
  gpu_execution_accelerator : [ {
    name : "tensorrt"
    }]
}}

triton的tensorflow的混合精度配置

optimization { execution_accelerators {
  gpu_execution_accelerator : [
    { name : "auto_mixed_precision" }
  ]
}}

triton的TFTRT(没有推理优化效果,即使是FP16),不能和混合精度一起用

optimization { execution_accelerators {
  gpu_execution_accelerator : [ {
    name : "tensorrt"
    parameters { key: "precision_mode" value: "FP16" }}]
}}

测试

tensorflow, onnx, tensorrt的性能对比(算法指标无损)

原shansou_rank的tensorflow模型性能为:

batch 1: 35 infer/sec

batch 50: 340 infer/sec 

batch 100: 400 infer/sec

打开混合精度:

batch 1: 同上

batch 50: 720 infer/sec 

batch 100: 960 infer/sec

triton的TFTRT:

batch 1 : 38

batch 50: 370

转为onnx模型的性能为:

batch 1: 48 infer/sec

batch 50: 320 infer/sec

转为onnx模型+tensorrt execution_accelerator的性能为:

batch 1: 81 infer/sec

batch 50: 470 infer/sec

batch 100: 480 infer/sec

转为tensorrt模型(FP32)的性能为:

batch 1: 181 75 infer/sec

batch 50: 460 infer/sec

pytorch, onnx的性能对比
sps_sbert(256长度)

pytorch 1.6

batch 1: 97.8

batch 50: 220

pytorch 1.9

batch 1: 87.4

batch 50: 150

onnx

batch 1: 138

batch 50: 230

onnx(dynamic sequence)

当sequence为3时

batch 1: 354

batch 50: 10510

batch 100: 12560

当sequence为7时(输入文字为5个字)

batch 1: 306

batch 50: 6300

batch 100: 7140

sequence 128

batch 1: 245

batch 50: 470

batch 100: 500

当sequence为512时

batch 1: 82

batch 50: 100

batch 100:  -(爆显存)

onnx (without pooling)(transformers convert函数)

batch 1:183

batch 50: 310

onnx (without pooling)(tensorRT)(transformers convert函数)

batch 1:153.4

batch 50: 310

ibudda_psy_pro_cls(128长度)

pytorch

batch 1:93

batch 50: 450

batch 100: 460

onnx (do_constant_folding=True/False 都是一样的性能,ops=11/12也一样性能)

batch 1: 211

(打开dynamic axes)

batch 1: 238

batch 50: 480

batch 100: 520

onnx(tensorRT)

batch 1: 182

batch 50: 470

batch 100: 480

pytorch 1.9的性能不如1.6

onnx可以指定inputname和outputname,相比pytorch的input_0, output_1具有更好的表达力。

使用tensorRT加速器无法提高性能,反而会下降。

bert的batch性能和最大长度有关,和句子相似度或分类任务无太多关系。

128长度的bert

batch 1时,onnx相比pytorch可以提升150%

batch 50时,onnx只能提高6%,几乎一样

采用动态sequence在处理短输入时,效果非常明显,大批量时可以提升10倍以上的性能

测试工具

使用triton sdk中的perf_analyzer

batch为50时的示例:

docker run --rm --net=host hub.yun.paic.com.cn/pib-core/ibudda-triton:tritonserver-21.06-py3-sdk perf_analyzer -m shansou_rank_tensorrt --percentile=95 -u localhost:8010 -b 50 -a --concurrency-range 1:4

(-b 是batch,-a是异步,防止超时失败)

--concurrency-range 1:4是从并发线程1到并发线程4的依次测试,等价于--concurrency-range 1:4:1(最后一个为step)

tensorrt的有损测试

原模型:0.889

FP32:0.889

BEST模式(使能所有精度):0.806

FP16: 0.804

踩过的坑

不要用tensorrt8,很多bug

onnx转trt时,会提示一些node无法解析,导致转换trt失败。

triton 21.07无法使能TF的混合精度(TODO:需要再次确认)

不要使用tensorrt源码里的demo/BERT里的build.py来转换tensorrt

这个builder是针对squad bert模型,无法通用,分类模型都无法转换成功,需要学习tensorrt的API函数,通用性不强。

build.py的使用可以部分参考:基于tensorRT的BERT服务部署---填坑记 - 知乎

TF代码转tensorrt

tensorflow默认集成tensorrt,可用代码将模型转换为tensorrt。

但是实际发现,在TF2官方镜像里,执行这个过程无法成功,提示cudnn的问题,生成了很多tensorrt的过程文件,但是没有最后的单一engine文件,无法使用。

参考:Accelerating Inference in TensorFlow with TensorRT User Guide - NVIDIA Docs

onnx的tensorrt加速器打开

这个功能,在官方的release notes中的21.05提到具有该功能,实际21.05中根本没有效果(浪费了很多时间在onnxruntime集成tensorrt的编译上,操操操

在21.07中,官方的release notes还张扬的提到tensorrt加速器具有FP16的设置能力,文档也配套了这个功能,实际在一个known issues角落提到,由于tensorrt8的兼容问题,tensorrt加速器的功能拿掉了!(我砍死nvidia的文档团队!)

目前只有21.06中可以打开这个功能

pytorch的perf_analyzer报错,无法进行

perf_analyzer默认的input-data为random,在测试pytorch时,会出现random的值超过token_type_ids(vocab.txt)的定义范围,导致越界。

一旦出现这个问题,还必须重启triton,否则triton无法正常提供服务。

测试pytorch,需要添加:--input-data zero

代表输入都是0,就能正常测试性能了。

perf_analyzer加-v,可以更详细的看到报错信息。

  • 19
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值