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

发布于:2025-09-11 ⋅ 阅读:(26) ⋅ 点赞:(0)

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 Path

MODELS_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. 安装(桌面应用 / 浏览器版):

  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, SessionOptions import onnxruntime as ort
设置优化级别 options.graph_optimization_level = GraphOptimizationLevel.ORT_ENABLE_ALL options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL
创建 Session session = 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 Path

MODELS_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 ort

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

session = ort.InferenceSession("yolov8n.onnx", options)

⚠️ 问题

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

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

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

from onnxruntime_tools import optimizer
from pathlib import Path

MODELS_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 可做更激进的算子融合与量化。

网站公告

今日签到

点亮在社区的每一天
去签到