当前位置: 首页 > news >正文

YOLO 模型从 PyTorch 转换为 ONNX 并优化

YOLO 模型从 PyTorch 转换为 ONNX 并优化

在深度学习部署中,ONNX(Open Neural Network Exchange) 已成为跨框架与跨平台的标准格式。我们经常需要将 YOLOv8 在 PyTorch 中训练好的模型转换为 ONNX,并进行优化,以便在 CPU、GPU 或边缘设备 上高效推理。

本文将详细介绍:

  1. 如何从 PyTorch 导出 YOLOv8 为 ONNX
  2. 如何用 onnxruntime 优化模型(包含新旧版本对比)
  3. 每个操作的意义
  4. 优化选项与参数说明

1. 为什么要优化 ONNX 模型?

导出的原始 ONNX 文件里,可能包含很多“冗余算子”或“不适合推理加速的计算方式”。
比如:

  • 多余的 TransposeIdentity 节点。
  • 可合并的 Conv → BatchNorm → Relu
  • 未展开的常量。

优化的目的就是:减少节点数、合并算子、提升推理速度,同时不改变模型的计算逻辑。


2. onnxruntime 的优化机制

onnxruntime 里,优化是在 InferenceSession 初始化 时完成的,控制参数就是:

options = ort.SessionOptions()
options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL

2.1 优化级别(GraphOptimizationLevel)

onnxruntime 提供 4 种优化级别:

选项作用典型场景
ORT_DISABLE_ALL完全不做优化调试/测试
ORT_ENABLE_BASIC基础优化:常量折叠、消除无用节点保守优化,结果最安全
ORT_ENABLE_EXTENDED扩展优化:算子融合(Conv+BN+Relu),节点重排序性能更好,常用
ORT_ENABLE_ALL启用所有可用优化,包括 layout 优化、内存重用生产环境推荐

默认是 ORT_ENABLE_ALL,你可以按需求调节。

2.2 其他常用参数(SessionOptions)

options.intra_op_num_threads = 4   							# 单个算子内部使用的线程数
options.inter_op_num_threads = 2   							# 不同算子之间的并行线程数
options.execution_mode = ort.ExecutionMode.ORT_PARALLEL  	# 启用并行执行
options.enable_mem_pattern = True  							# 内存复用模式
options.enable_cpu_mem_arena = True  						# CPU 内存分配优化

📌 意义

  • 线程数控制可以充分利用 CPU 多核。
  • 内存优化选项可以减少内存占用,适合边缘设备。

3. 优化的保存方式

旧版本(≤1.16):

  • 优化只存在于内存,不会保存到 .onnx 文件。
  • 即使你 onnx.save(),保存的还是原始模型

新版本(≥1.17):

  • 可以用:

    options.optimized_model_filepath = "yolov8n_optimized.onnx"
    

    这样在 Session 初始化时,会把优化后的图写入文件。

👉 这就是新版和旧版最大的区别。


4. 环境准备

安装必要依赖:

pip install ultralytics onnx onnxruntime

如果需要高级优化(算子融合、量化),还可以安装:

pip install onnxruntime-tools

确认版本(非常关键,因为 API 有变化):

pip show onnxruntime
  • 旧版 onnxruntime:≤ 1.16.x
  • 新版 onnxruntime:≥ 1.17.0

5. 从 PyTorch 导出 YOLOv8 为 ONNX

from ultralytics import YOLO
from pathlib import PathMODELS_DIR = Path("models")# 加载 YOLOv8 模型
model = YOLO(str(MODELS_DIR / "yolov8n.pt"))# 导出为 ONNX 格式
model.export(format="onnx")
  • 输入:PyTorch 的 .pt 模型
  • 输出yolov8n.onnx
  • 意义:ONNX 模型是跨平台的,可以在不同推理引擎(onnxruntime、TensorRT、OpenVINO)中运行。

👉 导出后,你可以用 Netron 查看模型结构,检查输入/输出 shape 是否正确。

在这里插入图片描述

5.1 什么是 Netron?

Netron 是一个 神经网络模型可视化工具,用来查看 .onnx.pt.h5.tflite 等模型的网络结构。

  • 你可以 直观查看每一层的算子(Conv、Relu、FC 等)。
  • 支持 模型输入输出 shape、权重信息
  • 非常适合在导出 ONNX 后,检查网络结构是否符合预期。

5.2 怎么使用 Netron?

  1. 安装(桌面应用 / 浏览器版):

    • 桌面版下载地址:https://github.com/lutzroeder/netron
    • 浏览器版直接打开:https://netron.app
  2. 打开模型:

    • 在桌面应用里,直接拖拽 yolov8n.onnx 文件进去。
    • 在网页端,点击 Open Model 上传模型。
  3. 查看结构:

    • 你会看到类似一张「流程图」,每一层算子(Conv、BN、Relu、Concat 等)都展示出来。
    • 可以点选层节点,查看 输入/输出 shape权重参数

在这里插入图片描述

5.3 为什么要用 Netron?

  • 确认 ONNX 导出是否成功(有时候导出会缺少算子或层)。
  • 检查 输入输出 shape 是否正确(例如 YOLO 输入是否是 1x3x640x640)。
  • 验证 模型优化前后层结构是否保持一致

它就像模型的「显微镜」,帮我们把黑盒的 .onnx 文件拆开看清楚。


6. 优化 ONNX 模型(onnxruntime)

6.1 新旧版本对比

对比项旧版 onnxruntime (≤1.16.x)新版 onnxruntime (≥1.17.0)
导入方式from onnxruntime import GraphOptimizationLevel, SessionOptionsimport onnxruntime as ort
设置优化级别options.graph_optimization_level = GraphOptimizationLevel.ORT_ENABLE_ALLoptions.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL
创建 Sessionsession = ort.InferenceSession("model.onnx", options)session = ort.InferenceSession("model.onnx", sess_options=options)
保存优化模型❌ 不支持,优化仅存在内存options.optimized_model_filepath = "optimized.onnx"
是否推荐⚠️ 已过时✅ 官方推荐

6.2 新版写法(推荐,onnxruntime ≥ 1.17)

import onnxruntime as ort
from pathlib import PathMODELS_DIR = Path("models")
onnx_path = str(MODELS_DIR / "yolov8n.onnx")
optimized_path = str(MODELS_DIR / "yolov8n_optimized.onnx")# 设置优化选项
options = ort.SessionOptions()
options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL
options.optimized_model_filepath = optimized_path# 创建 Session(会触发优化并保存)
session = ort.InferenceSession(onnx_path, sess_options=options)print(f"优化后的模型已保存到: {optimized_path}")

📌 意义

  • 优化发生在 Session 初始化 阶段。
  • 优化图会被写入文件,避免每次加载时重复优化。
  • 部署时直接加载优化好的 .onnx,加快推理启动速度。

在这里插入图片描述

6.3 旧版写法(已过时,onnxruntime ≤ 1.16.x)

from onnxruntime import GraphOptimizationLevel, SessionOptions
import onnxruntime as ortoptions = SessionOptions()
options.graph_optimization_level = GraphOptimizationLevel.ORT_ENABLE_ALLsession = ort.InferenceSession("yolov8n.onnx", options)

⚠️ 问题

  • 优化仅存在内存,不会保存到 .onnx 文件。
  • 部署时需要每次重新优化,影响启动性能。

7. 高级优化(可选,onnxruntime-tools)

如果需要进一步优化(算子融合、Transformer 专用优化、量化),可以用:

from onnxruntime_tools import optimizer
from pathlib import PathMODELS_DIR = Path("models")
onnx_path = str(MODELS_DIR / "yolov8n.onnx")
optimized_path = str(MODELS_DIR / "yolov8n_tools_optimized.onnx")# YOLO 没有专用类型,"transformer" 或 "bert" 都能工作
optimized_model = optimizer.optimize_model(onnx_path,model_type="bert",opt_level=99
)optimized_model.save_model_to_file(optimized_path)
print(f"进一步优化后的模型已保存到: {optimized_path}")

在这里插入图片描述


8. InferenceSession 和 onnxruntime-tools 对比

方法优点缺点
onnxruntime-tools支持更多优化策略(图融合、量化),可控性强需要额外安装
options.optimized_model_filepath依赖少,直接在 onnxruntime 里完成只做 onnxruntime 的图级优化,不包含高级策略

9. 验证优化后的模型

优化后需要验证模型是否能正确推理:

import numpy as np# 加载优化模型
session = ort.InferenceSession(str(MODELS_DIR / "yolov8n_optimized.onnx"))# 构造随机输入 (1, 3, 640, 640)
input_data = np.random.randn(1, 3, 640, 640).astype(np.float32)# 获取输入/输出名称
input_name = session.get_inputs()[0].name
output_name = session.get_outputs()[0].name# 运行推理
outputs = session.run([output_name], {input_name: input_data})print(outputs)

📌 意义

  • 确保优化后的模型依然输出正确结果。
  • 可以进一步对比 PyTorch 原始输出和 ONNX 输出,确保差异在数值误差范围内(1e-4 ~ 1e-6)。

在这里插入图片描述


10. 总结

  • 转换:使用 Ultralytics 将 YOLOv8 .pt 导出为 .onnx
  • 优化:用 onnxruntime 的 SessionOptions,推荐设置 graph_optimization_level = ORT_ENABLE_ALL,并保存为新文件。
  • 版本差异:onnxruntime ≥ 1.17 才能保存优化模型;旧版仅内存优化。
  • 参数调整:可以通过线程数和内存选项进一步提升性能。
  • 验证:运行推理,确认优化模型与原始模型一致。
  • 高级优化:onnxruntime-tools 可做更激进的算子融合与量化。

文章转载自:

http://dwdswhLB.yLtyz.cn
http://QqWSp4rL.yLtyz.cn
http://VZIpJ7Uv.yLtyz.cn
http://6c3D3qWi.yLtyz.cn
http://CgecYKYT.yLtyz.cn
http://UIEImMgp.yLtyz.cn
http://NwCJlF6v.yLtyz.cn
http://v4i6GS60.yLtyz.cn
http://3nxwjWQP.yLtyz.cn
http://kHGQ2vI5.yLtyz.cn
http://awZJiM4Z.yLtyz.cn
http://6tOca1DI.yLtyz.cn
http://IimtzsHX.yLtyz.cn
http://1Zz53sFj.yLtyz.cn
http://uppnQl5O.yLtyz.cn
http://JBewonKZ.yLtyz.cn
http://dbyVqEqQ.yLtyz.cn
http://KehNCafG.yLtyz.cn
http://riPypucE.yLtyz.cn
http://uvXj24nD.yLtyz.cn
http://bHU5FejZ.yLtyz.cn
http://UDc0AkTx.yLtyz.cn
http://kNlNxABP.yLtyz.cn
http://7eG1AxE1.yLtyz.cn
http://SBN40hjU.yLtyz.cn
http://Ra9Z5T0w.yLtyz.cn
http://chHAmBlZ.yLtyz.cn
http://v4lLmGE9.yLtyz.cn
http://kEjfvvdQ.yLtyz.cn
http://6fdGgb7V.yLtyz.cn
http://www.dtcms.com/a/377218.html

相关文章:

  • Vue:条件渲染 (Conditional Rendering)
  • 手机版数字人分身系统源码搭建与定制化开发指南
  • 深入理解 Java 内存模型(JMM)
  • 9.10网编——项目1机械臂,TFTP手写
  • Spring Cloud Alibaba快速入门02-Nacos配置中心(下)
  • 3. 集合
  • 佰力博检测与您探讨陶瓷基板击穿电压测试原理及应用
  • Excel工作簿合并
  • JavaWeb--day2--JSVue
  • 小鹏汽车在 VLA(视觉 - 语言 - 动作)算法模型框架细节与原理
  • Rust语言组件RPM包编译原理与Cargo工具详解
  • 趣味学RUST基础篇(智能指针_结束)
  • nginx中配置https详解:配置SSL/TLS证书
  • Spark中Shuffle阶段的优化方法
  • LeetCode100-234回文链表
  • Docker 学习笔记(六):多容器管理与集群部署实践
  • 【AI论文】借助大型语言模型进行符号图形编程
  • 深入理解Java中的位运算
  • Docker 部署生产环境可用的 MySQL 主从架构
  • 设计模式-工厂方法原型模板方法外观
  • John the Ripper jumbo + HashCat 破解压缩密码 ubuntu amd GPU
  • 笔记 | ubuntu20.04离线安装Docker
  • 4.1.多线程JUC-什么是多线程?
  • 硅基计划4.0 算法 模拟
  • Android调用系统内置的UiAutomator工具实现自动化测试
  • vim 编辑器
  • RAG原理是什么?
  • 小白必看:AI智能体零基础搭建全攻略!
  • 品牌方与服务商布局 GEO 优化:差异化优势与商业价值落地路径​
  • 高防IP如何抵御CC攻击?2025年全面防护机制解析