TensorRT Hackathon 2022 —— Transformer模型优化笔记 2023-05-21
笔记摘录自2022年的某期nvidia-tensorrt优化黑客松活动:
https://www.bilibili.com/video/BV1i3411G7vN/
一些技术手段
- 使用 onnx-graphsurgeon 调整节点,解决.onnx 不能被 TensorRT 解析的问题
- 用一些现成的计算图优化库 (Polygraphy,onnx-optimizer,onnx-onnx simplifier)》优化计算图
- 优化计算图,将部分运行期计算提前到构建期完成
- 使用FP16和INT8 模式,并使用 strict type 显式控制某些 layer 计算精度以控制误差
- Layer Normalization Plugin
- Attention Plugin 以提高性能 (超越 Myelin 自动融合效果
- Mask Plugin + SkipSigmoid Plugin
- 尺寸对其
修改计算图的一般方法
强调一下,onnx-graphsurgeon读取的graph 和model是两回事,api不同两个东西不能混用。
(注释,这里面的bNot就是开关)
来看一下调整节点的用处,比如:
(用trtexec转encoder经常出现这样的报错。。。。。
解决.onnx不能被trt解析的问题
以下是优化过程:
需要注意的是,张量的数据类型和形状因为tensorrt自带形状推理器,这些东西都能自动推理; 另外,cast的目标数据类型是枚举类型,可以使用右边代码的onnx.Tensorxxxxx来指定,也可以按照枚举数字来指定。
接下来再看看计算图优化库,实际效果要按照性能测试最终决定。
计算图优化库 polygraphy,onnx-optimizer,onnx-simplifier
(这里的ogs手工优化指的是onnxgraphsurgeon)
为什么没有显著改善最终性能?因为trt有形状推理器,构建期会仔细推理每个节点的数据类型和形状,可以一次性消除计算图中的形状操作等(所以做不做形状操作相关的优化对结果基本不会有影响的)在优化中我们不需要浪费时间在这些。
对于图1,左侧是poly的,右侧是onnxsim的结果,对于这个节点,我们发现里面包含一个常张量562号他的值是0,对于poly如果整个计算图有两百个节点都包含常张量0他就会生成200个常张量,但onnxsim会把他合成一个。另外,onnxsim干的工作是删除cast节点,比如对于圈3,左边是poly右边是sim,对于sim的话他会把输出的张量数据类型直接转为下一个的输入,就不需要cast了;所以sim会改变大量节点就会这样的(有时候删除了反而让他不能被tensorrt很好的应用)
3DMM 2DMM
再来看一个比较“取巧“的操作,我们来看看3D矩阵乘和2D矩阵乘的区别:
一般来说,有可能2DMM是比3DMM要快的。
再来看看squeeze和transpose节点相关的东西
一般来说,消除了这些操作(影响conv add relu融合)甚至可以提高100%性能(从左边优化到右边)
另外再来看一个可能相关的优化:
形象来看就是这样的效果:
实现这个技术的核心代码:
另外,我们来看一个手工优化的例子(比如这里看到两个slice,而我们知道rt对slice的效率是很低的,所以我们想要把两个slice合成一个slice。)