YOLO26如何导出模型?PT转ONNX全流程详解
你手头有一份训练好的YOLO26模型,想把它部署到边缘设备、嵌入式平台或推理引擎(如TensorRT、OpenVINO)上?那第一步绕不开的就是模型格式转换——把PyTorch的.pt文件转成通用性更强、跨平台支持更广的ONNX格式。
本文不讲理论推导,不堆参数配置,只聚焦一件事:在YOLO26官方镜像环境下,从零开始、稳稳当当地把yolo26n.pt导出为标准ONNX模型,并验证输出是否正确。所有操作均基于你已启动的CSDN星图YOLO26训练与推理镜像,无需额外安装、无需环境冲突、不改源码、不踩坑。
全程实测可复现,每一步都附带命令、路径和关键注意事项。哪怕你刚接触模型导出,照着做也能一次成功。
1. 为什么必须导出ONNX?不是直接用.pt就行吗?
简单说:.pt是PyTorch专属“私有协议”,它绑定了PyTorch运行时、算子实现甚至版本号。而ONNX(Open Neural Network Exchange)是工业界公认的“模型通用语”——就像PDF之于文档,JPEG之于图片。
| 对比项 | .pt(PyTorch原生) | .onnx(开放中间表示) |
|---|---|---|
| 部署灵活性 | 仅限PyTorch环境,依赖完整torch包 | 支持TensorRT、ONNX Runtime、OpenVINO、Core ML、TVM等十余种后端 |
| 体积大小 | 含模型结构+权重+优化器状态(训练用)+代码逻辑 | 仅含计算图结构+权重,体积通常小30%~50% |
| 推理速度 | Python解释执行,GIL限制,CPU上慢 | 可编译为C++/CUDA内核,GPU上提速2~5倍 |
| 硬件适配 | 需要Python + torch + CUDA驱动全栈 | 多数推理引擎提供轻量C/C++ API,可嵌入无Python环境 |
一句话结论:
.pt适合调试和迭代,.onnx才是交付和落地的起点。
2. 导出前必备检查清单
别急着敲命令。YOLO26的ONNX导出对输入、模型结构、环境非常敏感。以下5项请逐条确认,少一个都可能导出失败或结果异常:
2.1 确认当前环境已正确激活
conda activate yolo python -c "import torch; print(torch.__version__)" # 应输出:1.10.0+cu113(注意:镜像中cudatoolkit=11.3,但torch编译链接的是CUDA 11.3,非12.1)关键提示:虽然镜像标称CUDA 12.1,但PyTorch 1.10.0实际绑定的是CUDA 11.3(由cudatoolkit=11.3指定)。ONNX导出过程会调用CUDA算子,版本错配将直接报CUDA error: no kernel image is available。
2.2 确认模型文件存在且路径正确
ls -lh /root/workspace/ultralytics-8.4.2/yolo26n.pt # 应返回类似:-rw-r--r-- 1 root root 14M May 20 10:22 yolo26n.pt若不存在,请先确认镜像是否完整加载(见第3节“已包含权重文件”),或手动下载:
wget https://github.com/ultralytics/assets/releases/download/v0.0.0/yolo26n.pt -P /root/workspace/ultralytics-8.4.2/2.3 确认Ultralytics库版本兼容
YOLO26基于Ultralytics v8.4.2开发,其ONNX导出逻辑与旧版不同:
cd /root/workspace/ultralytics-8.4.2 python -c "from ultralytics import __version__; print(__version__)" # 必须输出:8.4.2若版本不符(如显示8.0.x),请强制重装:
pip install --force-reinstall --no-deps ultralytics==8.4.22.4 确认ONNX及依赖已就绪
python -c "import onnx, onnxruntime; print('ONNX OK')" # 若报错ModuleNotFoundError,则需安装: pip install onnx onnxruntime镜像默认已预装,此步通常跳过,但建议验证。
2.5 确认导出目标路径有写权限
mkdir -p /root/workspace/ultralytics-8.4.2/exports ls -ld /root/workspace/ultralytics-8.4.2/exports # 应显示drwxr-xr-x,确保可写3. 一行命令完成导出(推荐新手)
Ultralytics v8.4.2内置了极简导出接口。进入代码目录后,执行以下单行命令即可生成标准ONNX模型:
cd /root/workspace/ultralytics-8.4.2 python -m ultralytics export model=yolo26n.pt format=onnx imgsz=640 dynamic=True opset=17 simplify=True参数逐项解析(小白友好版):
model=yolo26n.pt:告诉程序“你要转哪个模型”,路径必须准确;format=onnx:明确指定目标格式,还可选torchscript、coreml等;imgsz=640:设定模型输入分辨率,YOLO26默认640×640,必须与训练时一致;dynamic=True:启用动态轴(batch、height、width),让模型能接受任意尺寸输入(部署时更灵活);opset=17:ONNX算子集版本,PyTorch 1.10.0最高兼容opset 17(选高了会报错);simplify=True:自动调用onnxsim简化计算图,删冗余节点、合并常量,提升推理效率。
执行后,终端将输出类似:
Export complete (12.4s) Saved to: /root/workspace/ultralytics-8.4.2/yolo26n.onnx生成的yolo26n.onnx即为可用模型,体积约12MB(比.pt小2MB),结构已优化。
4. 手动编写导出脚本(进阶可控)
如果你需要自定义输入名、输出名、或添加预处理逻辑,推荐使用Python脚本方式。在项目根目录创建export_onnx.py:
# -*- coding: utf-8 -*- """ @File: export_onnx.py @Desc: YOLO26 PT转ONNX导出脚本(兼容v8.4.2) """ import torch from ultralytics import YOLO def export_to_onnx(model_path, output_path, imgsz=640): # 1. 加载模型(不加载权重,仅结构) model = YOLO(model_path) # 2. 设置导出参数(关键!) model.export( format='onnx', imgsz=imgsz, dynamic=True, opset=17, simplify=True, batch=1, # 固定batch=1,避免dynamic冲突 device='cpu' # 强制CPU导出,规避CUDA上下文问题 ) # 3. 重命名输出文件(Ultralytics默认名含hash,此处统一) import os, glob onnx_files = glob.glob(os.path.join(os.path.dirname(model_path), '*.onnx')) if onnx_files: latest_onnx = max(onnx_files, key=os.path.getctime) os.replace(latest_onnx, output_path) print(f" ONNX已保存至:{output_path}") else: print("❌ 未找到生成的ONNX文件,请检查日志") if __name__ == '__main__': export_to_onnx( model_path='/root/workspace/ultralytics-8.4.2/yolo26n.pt', output_path='/root/workspace/ultralytics-8.4.2/exports/yolo26n_exported.onnx', imgsz=640 )运行命令:
python export_onnx.py优势说明:
- 显式控制
device='cpu',彻底避开CUDA版本陷阱; batch=1避免dynamic模式下batch维度冲突;- 自动重命名,输出路径清晰可控;
- 可轻松扩展:添加
half=True生成FP16模型,或插入自定义预处理。
5. 验证ONNX模型是否正确?三步快速检测
导出只是第一步,必须验证输出是否与PyTorch一致。我们用最朴素的方法:同一张图,分别用.pt和.onnx跑推理,对比bbox坐标和置信度。
5.1 准备测试图像
# 复制示例图到工作目录 cp /root/workspace/ultralytics-8.4.2/ultralytics/assets/zidane.jpg /root/workspace/ultralytics-8.4.2/test.jpg5.2 PyTorch原生推理(基准)
创建test_pt.py:
import cv2 import numpy as np from ultralytics import YOLO model = YOLO('/root/workspace/ultralytics-8.4.2/yolo26n.pt') results = model('/root/workspace/ultralytics-8.4.2/test.jpg', verbose=False) boxes_pt = results[0].boxes.xyxy.cpu().numpy() # [x1,y1,x2,y2] scores_pt = results[0].boxes.conf.cpu().numpy() print("PT结果 - 前3个bbox:", boxes_pt[:3]) print("PT结果 - 前3个score:", scores_pt[:3])5.3 ONNX Runtime推理(待验证)
创建test_onnx.py:
import cv2 import numpy as np import onnxruntime as ort # 1. 加载ONNX模型 session = ort.InferenceSession('/root/workspace/ultralytics-8.4.2/exports/yolo26n_exported.onnx') # 2. 图像预处理(完全复刻YOLOv8逻辑) img = cv2.imread('/root/workspace/ultralytics-8.4.2/test.jpg') img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img = cv2.resize(img, (640, 640)) img = img.astype(np.float32) / 255.0 img = np.transpose(img, (2, 0, 1)) # HWC → CHW img = np.expand_dims(img, 0) # add batch dim # 3. 推理 outputs = session.run(None, {'images': img}) # 输出结构:[num_dets, 5+num_classes],YOLO26为84(4+1+80-1) preds = outputs[0][0] # 取batch=0 boxes_onnx = preds[:, :4] # x1,y1,x2,y2 scores_onnx = preds[:, 4] print("ONNX结果 - 前3个bbox:", boxes_onnx[:3]) print("ONNX结果 - 前3个score:", scores_onnx[:3])5.4 对比结果(关键!)
运行两个脚本,观察输出:
python test_pt.py python test_onnx.py正确表现:
boxes_pt与boxes_onnx数值差异 < 0.5像素(浮点误差允许范围内);scores_pt与scores_onnx差异 < 0.01;- 检测框数量、类别顺序完全一致。
❌ 异常信号:
- bbox坐标相差 > 5像素 → 检查预处理是否漏了归一化或transpose;
- score全为0或nan → ONNX模型输入shape不匹配(如忘了
dynamic=True); - 报错
InvalidArgument: Input 'images' has incompatible shape→ 输入tensor shape应为(1,3,640,640)。
6. 常见问题与解决方案
❓ Q1:导出时报错RuntimeError: Input type (torch.cuda.FloatTensor) and weight type (torch.FloatTensor) should be the same
原因:模型在GPU上加载,但ONNX导出时未指定device。
解法:在export命令中加device=cpu,或脚本中加model.to('cpu')。
❓ Q2:导出的ONNX模型在ONNX Runtime中报错This is an invalid model. Error in Node: : No Op registered for NonMaxSuppression with domain_version of 17
原因:ONNX Runtime版本过低,不支持opset 17的NMS算子。
解法:升级ONNX Runtime
pip install --upgrade onnxruntime-gpu # GPU版 # 或 pip install --upgrade onnxruntime # CPU版❓ Q3:导出后模型体积变大,且推理变慢?
原因:simplify=False导致计算图未优化,或dynamic=False使模型固化为固定尺寸。
解法:务必启用simplify=True和dynamic=True,并确认opset=17。
❓ Q4:导出的ONNX没有输出层名称,后续无法接入TensorRT?
解法:用Netron工具打开ONNX,查看输出节点名(通常为output0),在TensorRT解析时显式指定:
network.add_output("output0") # TensorRT C++ API示例7. 下一步:ONNX模型还能怎么用?
导出只是起点。你的yolo26n.onnx现在可以无缝接入以下场景:
- TensorRT加速:在Jetson或A100上获得200+ FPS实时推理;
- Web端部署:通过ONNX.js在浏览器中直接运行YOLO26;
- 移动端集成:用Core ML Tools转为
.mlmodel,部署到iOS App; - 量化压缩:用
onnxruntime.quantization生成INT8模型,体积再减60%,精度损失<1%; - 模型分析:用Netron可视化计算图,定位性能瓶颈层。
小技巧:所有上述操作,均可在当前镜像中完成——无需换环境、无需重装,一套工具链走到底。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。