最近在用PyTorch训练一个语义分割模型,准备部署到Jetson上,所以想把模型转成TensorRT。但折腾了两天,各种报错快把我整懵了。比如动态shape怎么处理?有些自定义算子(像F.interpolate)在onnx导出时总警告,转trt后直接报错。还有量化精度掉得厉害,int8比fp32掉了5个点,不知道是不是校准集没选好。另外,有没有办法在不重写网络结构的情况下,让TensorRT自动融合一些算子?我看官方文档说支持Layer Fusion,但实际效果好像不明显。希望有经验的大佬能分享下实战经验,特别是从PyTorch->ONNX->TensorRT这条链路下的常见坑和优化技巧,先谢过了!
PyTorch转TensorRT时,有哪些常见的踩坑点和优化思路?
全部回复
共 1 条同感,PyTorch转TensorRT这条链路确实是坑多路滑,尤其是语义分割模型,自定义算子一多就各种翻车。我前阵子搞一个U2Net的变体,也卡在F.interpolate上,ONNX导出时那个警告其实已经暗示了——TRT对双线性插值的支持在动态shape下特别敏感。我后来是把上采样层全换成torch.nn.Upsample,然后在ONNX里把mode设成nearest或bilinear,再配合opset版本12以上,才勉强跑通。不过你这个报错具体是啥?是解析阶段崩还是推理时段错误?如果是后者,多半是shape推导的问题,建议先固定输入尺寸试试。
量化掉点5个确实有点多,校准集大概率是主因。我踩过类似的坑,一开始用验证集随机抽100张,结果int8直接崩。后来换成训练集里均匀采样,并且保证每类像素占比接近训练分布,掉点才压到1-2个点。另外TRT的calibration cache很关键,第一次跑完会把校准结果存下来,后面可以复用,但注意如果换校准集一定要删掉缓存。还有个小技巧:你可以先用fp16跑一下,如果fp16比fp32掉点不多,那int8的校准问题可能性更大。
关于Layer Fusion,说实话TRT的自动融合对语义分割这种多尺度特征网络效果有限,尤其是用了很多skip connection或者concatenate的模型。我试过手动用trtexec加--layerPrecision参数指定部分层用fp16,或者把一些ReLU和卷积手动合并,但收益不大。后来发现真正有效的反而是优化ONNX导出阶段:比如把dropout、identity这些无意义节点去掉,或者用torch.onnx.export时指定dynamic_axes只对batch维度生效,其他维度固定,这样ONNX图干净了,TRT自动融合的成功率会高不少。
另外Jetson平台内存有限,建议你在TRT转完模型后,用trtexec测一下实际延迟和内存占用,有时候模型能转但推理时显存爆了。可以试试开启--workspace参数限制内存,或者对不需要梯度计算的层强制用fp16。别问我怎么知道的,都是泪(手动狗头)。