最近在部署一个YOLOv8-seg模型,用TensorRT的ONNX转换,FP16模式跑出来的mAP比原始PyTorch低了将近3个点,尤其小目标漏检变多。我试过关闭某些层的FP16(用trtexec的--fp16加--precision控制),但效果不明显。也试过用onnx-simplifier清理图结构,还是没改善。
PyTorch转TensorRT后精度掉得厉害,是量化问题还是我转换姿势不对?
全部回复
共 70 条fp16掉3个点其实挺常见的,尤其是seg头那边对精度敏感。你试试把mask分支单独跑fp32,或者用tensorrt的per-channel量化看看,比layer-wise好使。另外onnx-simplifier有时候会把reshape合并掉,反而影响tensorrt的tensor格式推导,我上次就是栽在这。你检查下onnx里有没有奇怪的reshape节点?小目标漏检也可能跟输入尺寸预处理有关,确认下letterbox的padding参数跟pytorch侧一致。
FP16掉3个点其实挺常见的,尤其是seg头那种上采样+逐像素预测的部分对精度特别敏感。建议你试试per-channel量化或者给敏感层单独设FP32,但更直接的是检查一下ONNX里有没有一些奇怪的reshape或者transpose导致TensorRT优化出了问题。我之前遇到过类似情况,最后发现是某个Crop层在TRT里被错误融合了,手动关掉那一层才恢复。你试过用Polygraphy对比中间层输出吗?找差异点比盲调快很多。
FP16掉点正常,尤其seg头对精度敏感,试试INT8+PTQ校准,或者关键层保FP32。
3个点的mAP差距在FP16下其实不算离谱,YOLOv8-seg的mask分支对精度本来就敏感。你光用trtexec控层可能不够,试试把seg头整个切成FP32,主干保留FP16,我这么搞过,小目标漏检能回来不少。另外check一下预处理,onnx里如果带了归一化,TensorRT的scale模式有坑,容易在低值区域产生偏差。你量化校准集用的啥?如果跟验证集分布差太多,比FP16本身影响还大。
FP16掉3个点其实挺常见的,尤其YOLOv8-seg这种带mask分支的,小目标对精度敏感度比纯检测高不少。你试过trtexec的per-layer控制但没效果,我猜可能是某些关键层(比如proto头的卷积)在FP16下数值溢出,但你又没精准定位到具体哪几层。可以试试用polygraphy或者TensorRT的layer-wise精度对比工具,把每个层的输出和onnx的逐层比对一下,找找是哪个op开始偏差变大的。
另外onnx-simplifier有时候反而会把一些对精度有影响的融合结构给拆掉或者重排,不一定全是好事。我遇到过类似情况,后来改用trtexec的--layerPrecision直接指定可疑层为FP32,而不是用--precision范围控制,效果会精准一些。还有个偏门思路:检查一下你的预处理和后处理是不是在转TensorRT时被隐式改了,比如normalize的缩放系数或者letterbox的填充方式,有时候精度掉根本不是模型问题,是输入分布变了。
小目标漏检多,你可以考虑试试INT8加上calibration,虽然听起来比FP16更激进,但如果你能找到好的校准数据集,有时候反而比FP16更稳,因为校准过程会动态调整每个激活的scale,比一刀切FP16要聪明。最后实在不行就混合精度手动调,把mask分支单独拎出来跑FP32,主干和检测头保持FP16,代价是推理慢一点但精度能保住。
试试INT8+PTQ校准集多放点小目标,FP16对seg头影响挺大的,我上次是单独给这层留FP32才拉回来。
FP16掉3个点其实挺常见的,尤其seg头那块对精度敏感,建议先单独看下mask分支的误差是不是主要来源。另外小目标漏检不一定全是精度问题,也可能是TensorRT的算子融合改了特征分布,试试给backbone和neck单独设FP32。还有,ONNX转的时候注意下opset版本和动态shape,有时候简化器会把某些敏感结构改坏。你跑一下逐层输出对比,能更快定位是哪几层漂移大。
大概率是FP16的问题,小目标对精度敏感,试试INT8加校准集,或者保留前几层FP32。
FP16对小目标确实不友好,试试per-channel量化或者关键层保留FP32,比全局调精度管用。
FP16掉点挺常见的,尤其分割头对数值精度比检测头敏感,小目标漏检多半是特征图量化误差累积。你可以先跑一下逐层对比,把seg分支那几个卷积强制保持FP32试试,别全局一刀切。另外ONNX导出时opset版本和动态轴设置也有坑,我上次改成opset 12加固定batch才稳住。trtexec的--precision有时不生效,建议用polygraphy看每层实际精度。