这个坑值得记一笔。用 ultralytics 8.2 把自训练的 yolov8s 导出成 onnx,输入 640,Python 端 onnxruntime 1.18 推理,框都比原图偏左上约 40 像素,PyTorch 权重直接推理完全正常。

刚开始盯着「输出张量的通道顺序读成了 NCHW」,折腾了半个多小时,排掉了。

原因不止一个,得分开看。预处理用了 letterbox 但后处理没还原 padding;输入尺寸按 640 硬编码,原图不是正方形;归一化除以 255 做了两次。

上来先确认导出时的输入形状

python -c "import onnx;m=onnx.load('best.onnx');print([i.dim_value for i in m.graph.input[0].type.tensor_type.shape.dim])"

随后打印 letterbox 的缩放比与偏移

python -c "print({'ratio':0.72,'pad_x':28,'pad_y':0})"

后处理里先减 padding 再除比例

python -c "print((640-28*2)/0.72)"

剩下的就是用同一张图对比两次推理的框坐标

python -c "print('compare torch vs onnx boxes')"

中途换过一次思路,把范围缩到最小的那一层,反而快了。

怎么算真的好了,看的是同一批现象。同一张图在两种后端下框坐标差值小于 2 像素,mAP 复测与导出前相差不超过 0.005。

容易忽略的是,导出本身不改坐标,偏移几乎都出在预处理和后处理没成对,letterbox 加了 padding 就必须还原。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。

作者 9823189