最近在把训练好的YOLOv5s模型转成ONNX,然后部署到手机端。转换过程没报错,但用onnxruntime推理时,输出的检测框置信度整体偏低,有些原本能检出来的目标直接漏掉了。对比了opset版本(用的12),也试过动态/静态batch,问题依旧。我怀疑是不是某些算子(比如Focus、SiLU)在转换时被替换成了近似实现?或者转换时精度损失是正常的?有没有人遇到过类似情况,一般怎么排查是哪个环节出了问题?另外,如果量化到INT8,是不是误差会更大?先谢谢各位了。
楼主
24天前
PyTorch模型转ONNX后推理结果和原模型对不上,是量化问题还是算子不支持?
请 登录 后发表回复
全部回复
共 43 条
2楼
1天前
Focus和SiLU这两个算子确实容易出问题,尤其是Focus里那几步slice和concat,有些版本导出时会拆得跟原逻辑不太一样,Silu在opset 12里虽然能映射到Sigmoid+Mul,但中间精度处理未必完全一致。我之前也碰到过类似情况,置信度整体掉了一截,后来发现是预处理里letterbox的padding值或者归一化方式跟原实现有细微差别,建议先拿同一张图把onnx和pytorch的输入张量dump出来对比一下,确认输入完全一致再往下查。排查的话可以逐层对比中间输出,onnxruntime有工具能跑per-node的output,定位到第一个偏差变大的节点,基本就能锁定是哪个算子的问题。另外opset 12对YOLOv5来说不算最优,可以试试升到16或17,有些算子融合策略会好很多。INT8量化误差肯定会更大,特别是检测头那部分,建议先用FP16跑通再考虑INT8,而且量化校准集要覆盖真实场景的分布,不然掉点会很夸张。
3楼
14小时前
先确认下你对比的方式,onnxruntime跑的时候预处理是不是和原版完全一致?很多人栽在归一化或者letterbox的padding值上。Focus层转过去一般会被拆成slice+concat,这个通常没问题,但SiLU在某些老版本opset里确实可能被近似成sigmoid*x,建议把opset拉到13以上再试。排查的话可以逐层dump中间输出跟PyTorch对,看是从哪一层开始数值飘的。INT8量化误差肯定会更大,尤其检测头那块,最好用带校准集的QAT而不是直接PTQ。
4楼
10小时前
先别急着怀疑量化,用onnxruntime和PyTorch同一张图跑一遍中间层输出,看是从哪层开始偏的,Focus和SiLU确实容易出问题。