算子优化总结(resnet18中的upsample算子反向为例)
发现问题
模型训练,从输出打印来看,每次迭代耗时约1.03s;
ixprof收集性能数据,看到upsample_bilinear2d_backward_nhwc_out_frame这个kernel耗时占比高达22.56%,推测有可优化空间;
shape获取
获取方式:
1.保存为onnx模型直接查看,有些特殊op无法看到,比如本例中的upsample
2.通过hook获取,需要知道网络结构,和对应的调用kernel的算子的名称,本例中找不到kernel调用函数interpolate在结构中对应的算子名称;
分析模型,interpolate的调用应该是在这个heads结构中的,但是没有具体的算子体现;
3.在模型定义的地方添加打印,获取到如下几种shape,但是存在一个问题,这个模型的upsample算子有两种kernel,
upsample_bilinear2d_backward_nhwc_out_frame和upsample_bilinear2d_backward_out_frame,他们都是由interpolate函数实现的,
这边无法分清那个shape对应那个kernel;
4.在pytorch的kernel源码实现处添加打印,这个方法最直接,一开始没想到,在模型结构那边研究半天找不到upsample;
结果
单算子测试
测试方法一:构造单算子模型
这个方法太笨拙,而且我的shape都写死了,每重换一个shape,都要重建一个模型,太费事,且不合理;
模型
测试结果
测试方法二:单算子测试脚本
缺点:不支持nhwc格式的输入format格式,解决方法见问题总结
测试结果
[16, 23, 31, 172]shape,scale_factor=16
[16, 45, 61, 172]shape,scale_factor=8
kernel 优化(upsample_bilinear2d_backward_nhwc_out_frame)
分析:BI架构的设计特点,block之间的切换代价远大于warp之间的切换,所以在保证资源的情况下,增大blockSize,减少gridSize,延长warp在CU上的驻留时间,增加单个线程的计算量;
对提取的shape进行不同的线程结构测试,为了找到最优的grid和block组合;
block固定最大4096;grid在原基础上分别除以2的次方倍
结论
从数据上看,当grid缩小到原来的128倍左右,性能的提升趋于饱和;
对于scaler_factor参数较大的算子,这种优化带来的性能提升更大;
BI最优结构与NV进行性能对比
结果:
[16, 45, 61, 172]shape经过优化BI耗时从原来是NV的2.34倍下降到1.48倍;
[16, 23, 31, 172]shape经过优化BI耗时从原来是NV的10.63倍下降到0.73倍;
整网测试
优化upsample算子反向之后的整网性能,整网性能提升约124.09%
优化前upsample_bilinear2d_backward_nhwc_out_frame在整网中的总耗时117.189s
优化后upsample_bilinear2d_backward_nhwc_out_frame在整网中的总耗时3.75s,提升了31倍