ONNX 模型格式分析与使用


前言

本文主要介绍ONNX基础知识已经ONNX的模型组成,另外补充了一些关于模型部署工作的常用流程,本文主要知识点在介绍ONNX的模型组成,包括Graph、Node和Tensor,后续将补充代码例程部分。


一、ONNX是什么?

在这里插入图片描述

ONNX(Open Neural Network Exchange)是一个由微软提出的一种开放的神经网络交换格式,用于在不同的深度学习框架之间进行模型的转换和交流。它的设计目标是提供一个中间表示格式,使得用户可以在不同的深度学习训练和推理框架之间无缝地转换模型。

使用ONNX,你可以使用不同的深度学习框架(如PyTorch、TensorFlow等)进行模型的训练和定义,然后将模型导出为ONNX格式。导出后的ONNX模型包含了模型的结构和权重参数等信息

一旦模型导出为ONNX格式,你可以使用ONNX Runtime或其他支持ONNX的框架将模型转换为目标设备所支持的模型格式,如TensorRT、Core ML、OpenVINO等。这样,你可以在不同的设备上部署和运行模型,无需重新训练或重新实现模型。

ONNX的优势在于它提供了跨框架和跨平台的灵活性,使得深度学习模型在不同的环境中更易于部署和集成。它还支持许多常见的深度学习操作和网络架构,使得模型转换过程更加方便和高效。
注意:ONNX模型文件存储的只是网络的拓扑结构和权重,不保存模型的硬件信息。

二、模型部署工作流程

下面是一个典型的深度学习模型部署工作流程,涵盖了使用PyTorch或TensorFlow训练模型、转换为ONNX中间格式,然后将其转换为TensorRT或OpenVINO等支持的格式进行推理的步骤:

  • 模型训练:使用PyTorch、TensorFlow或其他深度学习框架进行模型训练。在此阶段,你可以定义模型结构、选择损失函数和优化器,并在训练数据上进行迭代优化。

  • 导出为ONNX格式:一旦模型训练完成,将模型导出为ONNX格式。PyTorch和TensorFlow等框架提供了相应的导出功能,可以将已训练的模型保存为ONNX文件。导出的ONNX文件包含模型的结构和权重参数等信息。

  • 模型转换:使用ONNX转换工具,如ONNX Runtime、TensorRT或OpenVINO等,将ONNX模型转换为目标设备和框架所支持的格式。这些转换工具提供了特定设备和框架的优化功能,以提高推理性能。具体的转换过程取决于所选择的工具,但通常涉及加载ONNX模型、执行优化和转换操作,最终生成目标格式的模型文件。

  • 部署和推理:将转换后的模型部署到目标设备上,并使用相应的推理引擎进行推理。TensorRT和OpenVINO等引擎提供了与硬件加速器(如GPU、VPU等)的集成,以实现高性能的深度学习推理。在部署和推理过程中,你需要按照引擎的要求加载和配置模型,并使用提供的API进行推理操作。
    在这里插入图片描述

本文的重点是模型的部署推理,因此对于训练期的深度学习框架不做过多介绍,下面主要介绍一下常用的推理引擎:

  • ONNX Runtime:ONNX Runtime是一个跨平台的高性能推理引擎,支持将ONNX模型转换为多种设备和框架所支持的格式,如TensorFlow、TensorRT、Core ML等。它提供了一套API和工具,使得在不同平台上部署和运行ONNX模型更加便捷。

  • TensorRT:TensorRT是英伟达(NVIDIA)的推理加速库,专为深度学习推理而设计。它支持将ONNX模型转换为针对NVIDIA GPU进行优化的TensorRT模型。TensorRT可以提供高性能的推理加速,并支持 INT8/FP16 等精度的量化和优化。

  • OpenVINO(Open Visual Inference & Neural Network Optimization):OpenVINO是英特尔(Intel)的深度学习推理引擎,旨在提供针对英特尔硬件的高性能推理。它支持将ONNX模型转换为适用于英特尔CPU、VPU、GPU等硬件设备的OpenVINO模型。

  • Core ML:Core ML是苹果公司的机器学习框架,用于在iOS和macOS设备上进行推理。Core ML支持将ONNX模型转换为Core ML模型,以便在苹果设备上进行高效的机器学习推理。

补充:
目前常用的模型转换方法包括两种:
(1)使用pytorch、tensorflow自带的API直接导出相应的推理模型,比如通过torch2trt(NVIDIA维护)
(2)使用ONNX作为中间表示再导出推理模型

三、ONNX模型组成

ONNX模型主要由三部分组成:Graph、Node、Tensor

1.Graph

在这里插入图片描述

opset 算子集合:ONNX模型其实本质上就是将源模型通过各种基础算子来搭建出来,所以算子集合中包括了各种基础算子,当模型中使用到该算子时,则直接调用即可,但是随着模型复杂度的提升,模型可能会使用到算子集合中没有的算子,所以算子集合也是需要不断更新的,因此opset可以理解为version,当将模型转成ONNX失败时,可以尝试提高opset的版本。

2.Node

在这里插入图片描述

  • op:该节点执行的操作,表示该节点是什么算子,如:加算子、卷积算子等
  • name:节点名字
  • attrs:将属性名称映射到属性值的字典。可以理解为节点的参数,如:加算子没有参数,但是对于FC算子,他有output_number的参数。
  • inputs:节点的输入。需要注意的是:如FC算子,他是有权重weight和偏置bias的,这部分权值ONNX是将其当成节点的输入的,以Tensor的形式进行保存。

注意:
node.input()返回的是Tensor,但node.i()返回的是Node。
node.i(tensor_idx=0,producer_idx=0),其中tenosr_idx表示输入的Tensor序列(第几个input),producer_idx表示这个input tensor是由哪个node生产的。

3.Tensor

Tenosr是一个基类,有两种实现:VariableConstant

Tensor参数:

在这里插入图片描述

四、ONNX与TensorRT的不同努力方向

ONNX作为一种中间格式,其主要努力方向是提供更好的兼容性,使得各种深度学习框架能够将模型转换为ONNX格式,并在不同的推理引擎中进行部署和推理。为了实现更好的兼容性,ONNX会努力通过一个或多个常规的算子来模拟复杂的算子,以支持更多类型的模型和算子。这意味着即使某些推理引擎本身不直接支持某些复杂的算子,但通过ONNX中的算子模拟,仍然可以成功将模型转换为ONNX格式,极大地提高了模型转成ONNX格式的成功率,并在其他支持ONNX的推理引擎中进行推理。

相反地,推理引擎如TensorRT的主要努力方向是提高模型推理的速度和效率。TensorRT使用各种优化技术,包括算子合并,将多个常规算子合并成一个更大的算子,从而减少计算和内存访问的开销,提高推理性能。这种算子合并技术可以减少推理过程中的冗余计算和数据传输,以实现更高效的推理。

ONNX与TensorRT的不同努力方向在模型部署中起着不同的作用。ONNX专注于提供通用的中间格式,以便各种深度学习框架和推理引擎之间的互操作性。而TensorRT等推理引擎则更注重于性能优化,通过针对特定硬件和平台的优化以及算子合并技术,提供高性能的深度学习推理。两者的目标不同,但在整个模型部署流程中起到了互补的作用

补充:TensorRT的Myelin技术
(由于TensorRT并未开源这部分技术,因此在网上的相关资料特别少,这里也只是简单介绍一下Myelin的基础知识)
Myelin可以理解为一个深度学习算子的核函数代码生成器,TensorRT自动筛选可以合并优化的子模型,Myelin生成该子模型的Kernel核函数,自动实现算子合并,但需要注意的是,自动合并的算子可能会加重fp16/int8模式下的精度损失


总结

需要注意的是,虽然ONNX提供了一种通用的中间表示格式,但在实际转换中仍可能会出现一些兼容性和限制性问题。因此,在进行模型转换时,建议仔细了解目标设备和框架的要求,并进行必要的适配和调整。

  • 32
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
YOLOv7是一种目标检测算法,可以在一张图片中快速地识别出多个不同类别的物体,并给出它们的位置和大小信息。 ONNX是一种开放的深度学习模型交换格式,可以将深度学习模型从一个框架转移到另一个框架。YOLOv7的ONNX模型可以在不同的平台和框架之间进行交互和部署。 为了分析解读YOLOv7的ONNX模型,我们可以采用以下步骤: 1. 加载ONNX模型 使用ONNX库加载YOLOv7的ONNX模型,代码如下: ```python import onnx model = onnx.load("yolov7.onnx") ``` 2. 查看模型结构 使用以下代码可以查看模型的输入、输出以及各层的参数: ```python print(model.graph.input) print(model.graph.output) print(model.graph.value_info) print(model.graph.node) ``` 3. 解析模型输出 YOLOv7模型的输出包含了目标检测的结果,需要进行解析才能得到物体的位置、类别和置信度等信息。通常情况下,可以使用以下代码来解析模型输出: ```python import numpy as np import onnxruntime as rt ort_session = rt.InferenceSession("yolov7.onnx") def to_numpy(tensor): return tensor.detach().cpu().numpy() if tensor.requires_grad else tensor.cpu().numpy() def postprocess(result, num_classes, conf_thres=0.7, nms_thres=0.4): if isinstance(result, tuple): result = result[0] # 确定输出维度和大小 assert result.ndim == 4 assert result.shape[1] == (5 + num_classes) # 将输出转换为numpy数组 pred = result[0].reshape((-1, result.shape[2], result.shape[3])) # 根据置信度过滤结果 pred_boxes = pred[:, :, :4] pred_conf = pred[:, :, 4:5] pred_cls = pred[:, :, 5:] score = pred_conf * pred_cls keep = (score > conf_thres).nonzero() # 应用非极大抑制 boxes = [] scores = [] classes = [] for i in range(keep[0].shape[0]): box = pred_boxes[keep[0][i], keep[1][i], :] score = pred_conf[keep[0][i], keep[1][i], 0] * pred_cls[keep[0][i], keep[1][i], keep[2][i]] cls = keep[2][i] boxes.append(box) scores.append(score) classes.append(cls) boxes = np.array(boxes) scores = np.array(scores) classes = np.array(classes) idxs = cv2.dnn.NMSBoxes(boxes.tolist(), scores.tolist(), conf_thres, nms_thres) if len(idxs) > 0: boxes = boxes[idxs[:, 0]] scores = scores[idxs[:, 0]] classes = classes[idxs[:, 0]] return boxes, scores, classes ``` 4. 进行目标检测 使用ONNXRuntime库对输入图像进行预处理,然后将其传递给YOLOv7模型进行目标检测。最后,使用解析函数对输出进行解析,得到物体的位置、类别和置信度等信息。代码如下: ```python import cv2 # 加载图像 img = cv2.imread("test.jpg") # 缩放图像 img = cv2.resize(img, (416, 416)) # 将图像转换为输入张量 input_tensor = np.expand_dims(img.transpose((2, 0, 1)), axis=0) # 运行模型 result = ort_session.run(None, {"input": to_numpy(input_tensor)}) # 解析输出 boxes, scores, classes = postprocess(result, num_classes=80) ``` 以上是解析YOLOv7 ONNX模型的基本步骤,根据需要可以进行进一步的分析和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值