# YOLO11 PT 转 ONNX 教程 ## 一、使用命令行导出 ```bash 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 导出 ```python 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 加载推理 ```python 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(我代码里已经实现了) 2. 动态 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 低,问题主要在**定位精度**。