DocLayout-PageNumDet / misc /onnx_export_guide.md
wqzh's picture
Upload 31 files
1edc459 verified
|
Raw History Blame Contribute Delete
7.83 kB

YOLO11 PT 转 ONNX 教程

一、使用命令行导出

yolo export model=path/to/model.pt format=onnx imgsz=640 half=False simplify=True

常用参数:

  • format=onnx: 导出为 ONNX 格式
  • imgsz=640: 输入图像尺寸,需与训练时一致
  • half=False: FP32 精度;设为 True 为 FP16(需设备支持)
  • simplify=True: 简化 ONNX 图结构,减小模型体积
  • dynamic=True: 支持动态 batch 和输入尺寸
  • nms=True: 将 NMS 内置到模型中
  • device=0: 指定 GPU 设备号

二、使用 Python API 导出

from ultralytics import YOLO

model = YOLO("path/to/model.pt")
model.export(
    format="onnx",
    imgsz=640,
    half=False,
    simplify=True,
    device=0,
    verbose=True
)

导出后的 ONNX 文件默认保存在与 PT 文件同级目录下,文件名为 model.onnx。

三、使用 ONNXRuntime 加载推理

import cv2
import numpy as np
import onnxruntime as ort

sess = ort.InferenceSession("model.onnx", providers=["CUDAExecutionProvider"])
input_name = sess.get_inputs()[0].name
output_name = sess.get_outputs()[0].name

# 预处理
img = cv2.imread("image.jpg")
img = cv2.resize(img, (640, 640))
img = img.astype(np.float32) / 255.0
img = np.transpose(img, (2, 0, 1))
input_tensor = np.expand_dims(img, axis=0)

# 推理
outputs = sess.run([output_name], {input_name: input_tensor})

FQA

Q1: export_to_onnx 中 imgsz 参数设置为640,意味着推理的时候,输入的图片必须要是640x640大小的吗?

答案:不是必须的。 ONNX模型导出时,imgsz=640 默认会固定输入形状为 1, 3, 640, 640。推理时需要 resize + pad 到 640x640。 但如果导出时加 dynamic=True,可以支持动态尺寸输入。 我需要解释清楚这两点,简洁回答。 不是。分两种情况:

  1. 默认导出(静态 shape):imgsz=640
  • ONNX 输入被固定为 [1, 3, 640, 640]
  • 推理时 必须 把图片处理成 640×640
  • 但原始图片可以是任意尺寸,通过 resize + 等比填充 到 640×640(我代码里已经实现了)
  1. 动态 shape 导出:加 dynamic=True model.export(format="onnx", imgsz=640, dynamic=True)
  • ONNX 输入为 [1, 3, ?, ?]
  • 推理时可以用任意尺寸输入(如 320×320、800×800)
  • 灵活性更高,但推理速度可能略慢 总结:你导出时写的 imgsz=640 只是指定训练/导出的参考尺寸,原始图片不需要是 640×640,推理前会 resize 处理。

Q2: 默认参数设置

以下是 yolo export 各参数的默认值(来自 default.yaml):

参数 默认值 说明
save name 自动 {原文件名}.{格式后缀},如 yolo11n.pt → yolo11n.onnx
nms False 不把 NMS 内置到模型,需自己后处理
simplify True 默认启用 ONNX 图简化
dynamic False 默认固定输入 shape
half False 默认 FP32 精度
batch 1 导出时固定为 batch=1(与训练默认的16不同)
device None 自动选择(优先 GPU)
verbose False 导出时静默输出(与训练默认的True不同)
int8 False 不启用 INT8 量化

所以你这行命令: yolo export model=page-nano-best-epo50.pt format=onnx imgsz=640 half=False simplify=True 等价于:

  • 保存为 page-nano-best-epo50.onnx
  • FP32,固定 shape [1,3,640,640]
  • 不带 NMS(需要自己后处理)
  • 简化 ONNX 图
  • 静默输出

Q3: 建议使用dynamic, nms 参数吗?

dynamic=True:

  • 优点:推理时可以用任意尺寸,灵活性高
  • 缺点:某些部署环境不支持,推理可能稍慢,某些优化器无法优化 nms=True:
  • 优点:模型输出直接就是过滤后的结果,推理代码简单
  • 缺点:NMS 参数固化在模型中,不方便调整;某些后处理流程可能更复杂 需要根据用户是用于 ONNXRuntime 推理的场景来分析。 分场景: dynamic=True:
  • ✅ 建议开:你需要同一模型处理不同尺寸的图片
  • ❌ 不建议:
    • 固定尺寸推理(如全 640×640)
    • 部署到某些不支持动态 shape 的环境(TensorRT、部分嵌入式) nms=True:
  • ✅ 建议开:
    • 想让推理代码更简单(模型直接输出最终结果)
    • 固定 conf/iou 阈值即可
  • ❌ 不建议:
    • 需要频繁调 conf/iou(改了要重新 export)
    • 需要自定义后处理逻辑(如按类别不同阈值) 你当前场景(ONNXRuntime + 自己写后处理代码): dynamic=False # 固定 640x640 性能更好 nms=False # 你已经自己实现了后处理+NMS 如果未来想简化推理代码,可以重新 export: yolo export model=xxx.pt format=onnx nms=True conf=0.25 iou=0.45 输出直接是 N x 7 的 [x1,y1,x2,y2,conf,cls_id],省去后处理。

Q4: 如何知道目前模型的iou, conf?

这两个参数不在模型里,是你在推理时自己设定的。模型权重里只存网络参数,不存 conf/iou。 但你可以查模型训练时用的默认验证参数: from ultralytics import YOLO model = YOLO("models/page-nano-best-epo50.pt") print(model.model.args) 看 conf 和 iou(或 nms.iou_thres)字段,这是训练验证时用的参考值。 实际建议:

  • 用 yolo val 看不同阈值下的 mAP,选平衡点
  • 检测任务常用:conf=0.25, iou=0.45(Ultralytics 默认)
  • 如果你 export 时用了 nms=True,需要显式指定

Q5: mAP50-95 偏低是什么情况?

mAP50-95 < 0.5 的效果判断

不能一概而论,需要结合任务难度和模型规模来看。以下是通用参考:


不同场景下的参考标准

通用目标检测(COCO 80类,复杂场景)

mAP50-95 水平 代表模型
> 0.55 优秀 YOLOv8x、YOLOv10x
0.45 ~ 0.55 良好 YOLOv8m、YOLOv8l
0.35 ~ 0.45 中等 YOLOv8s、YOLOv8n
< 0.35 较差 小模型/训练不足

在 COCO 这种80类、复杂场景的基准上,0.5 已经是不错的水平了,YOLOv8s 也才 0.44 左右。

简单/少类别任务(工业质检、特定场景)

mAP50-95 水平
> 0.8 优秀,可上线
0.6 ~ 0.8 良好,基本可用
0.4 ~ 0.6 中等,需要优化
< 0.4 较差,不建议上线

类别少、场景简单时,0.5 只能算及格线,通常还有较大提升空间。


0.5 以下意味着什么

  1. 定位精度不足:mAP50-95 对框的位置很敏感,低于 0.5 说明很多框"检测到了但框得不准"
  2. 可能存在的问题:
    • 标注框质量差(标注本身就不准)
    • 小目标多(小目标 IoU 天然低)
    • 训练不充分(epoch 不够、数据量少)
    • 模型太小(容量不足)
    • 锚框不匹配

怎么判断能不能用

看你的业务需求:

  • **只需要"有没有"**(如安防告警、粗略计数):看 mAP50,如果 mAP50 高(>0.8),即使 mAP50-95 低也能用
  • 需要精确位置(如医疗影像、工业测量、自动驾驶):mAP50-95 < 0.5 不够用,需要继续优化
  • 需要区分密集目标:mAP50-95 低可能导致框偏移,重叠目标分不清

提升 mAP50-95 的方向

  1. 提高标注质量:检查标注框是否紧密贴合目标
  2. 增加训练轮次:通常 300 epoch 比 100 epoch 定位更准
  3. 用更大的模型:m/l/x 版本定位精度更高
  4. 数据增强:Mosaic、MixUp 有助于定位
  5. 调整锚框:用 autoanchor=True 自动计算
  6. 多尺度训练:imgsz 设大一些(如 1280)

总结:如果是 COCO 级别的复杂任务,0.5 以下属正常中等水平;如果是简单少类别任务,0.5 以下说明还有明显优化空间。关键看你的 mAP50 是多少——如果 mAP50 高但 mAP50-95 低,问题主要在定位精度。