|
Download misc/onnx_export_guide.md from wqzh/DocLayout-PageNumDet: direct link, hf CLI and curl.
- Browser
- Download file 7.83 kB
-
https://huggingface.co/wqzh/DocLayout-PageNumDet/resolve/main/misc/onnx_export_guide.md
- Command line
-
hf download hf://wqzh/DocLayout-PageNumDet/misc/onnx_export_guide.md
-
curl -L -o onnx_export_guide.md https://huggingface.co/wqzh/DocLayout-PageNumDet/resolve/main/misc/onnx_export_guide.md
7.83 kB
| # 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 低,问题主要在**定位精度**。 |