最近在做一个端侧部署的小项目,模型是ResNet18改的,训练时用PyTorch,FP16大概2ms一张图。转成ONNX后用onnxruntime跑,CPU和GPU都试了,结果比PyTorch直接推理慢了将近一倍,简直离谱。我试过opset_version从11调到17,也试过optimize=True,甚至关了dynamic_axes,还是没改善。网上说ONNX有图优化,但我看日志好像很多fusion都没触发。有没有人遇到过类似情况?是不是我导出的时候漏了什么参数,或者runtime的session配置有问题?求指点,谢谢!
PyTorch转ONNX后推理速度反而变慢,是哪里设置不对吗?
全部回复
共 6 条这问题我当初也踩过坑,先说结论:大概率不是你导出参数的问题,而是onnxruntime的线程配置和pytorch的cudnn autotune差太多了。PyTorch推理时默认会用cudnn benchmark自动选最合适的卷积算法,但ONNX转出来之后,很多算子在ORT里走的是一套通用实现,尤其ResNet这种带shortcut的残差结构,如果onnxruntime没把conv+bn+relu这些完全融合,memory access模式会变差,速度掉一半很正常。你试试在session options里把intra_op_num_threads设成物理核心数,然后开enable_cpu_mem_arena,GPU的话看看是不是没走tensorrt或者cuda的ep,纯CUDA EP对某些pytorch导出的transpose布局处理很笨。另外有个很阴间的点:检查一下onnx模型里有没有多余的identity节点或者cast操作,有时候torch导出会自动插一堆没用的cast到float32再转回float16,这玩意会打断图优化。最后实在不行,可以试一下onnx-simplifier把模型过一遍,经常能删掉20%的冗余算子,速度会有肉眼可见的提升。
我之前也踩过这个坑,大概率不是导出参数的问题,而是onnxruntime的线程数和执行模式没调。你试试session options里把intra_op_num_threads设成物理核心数,然后跑CPU时关掉arena策略,GPU的话检查下是不是没走TensorRT EP,默认的CUDA EP对很多算子反而没优化。另外ResNet18这种小模型,ONNX的图优化有时候会把算子融合成更慢的batch norm+conv组合,你可以用onnxsim精简下再转,或者干脆对比下onnxruntime的disable_optimization选项,我这边当时关了优化反而快了一截。
试下onnxruntime的session加enable_all_optimization,另外你转的时候是不是没把模型切成推理模式?
试试用onnxruntime的profiling看看瓶颈在哪,有时候是内存拷贝或者线程数没设对。
FP16在onnxruntime里不一定自动开,得手动设session options,不然可能还在跑FP32。
FP16下PyTorch 2ms其实已经很快了,ONNX变慢一倍挺常见的,尤其ResNet这种带残差的结构。你试试导出时加do_constant_folding=True,然后runtime里把graph_optimization_level设成ORT_ENABLE_ALL,另外intra_op_num_threads手动设成物理核数,别用默认值。还有个坑是GPU上onnxruntime默认可能没开cudnn的benchmark,session options里加enable_cudnn_conv_algo_search会好不少。