添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

onnx的基本操作

最近在对模型进行量化时候,模型格式转变为onnx模型了,因此需要对onnx进行加载、运行以及量化(权重/输入/输出)。故,对onnx模型的相关操作进行简单的学习,并写下了这边博客,若有错误请指出,谢谢。

一、onnx的配置环境

onnx的环境主要包含两个包onnx和onnxruntime,我们可以通过pip安装这两个依赖包。

pip install onnxruntime
pip install onnx

二、获取onnx模型的输出层

import onnx
# 加载模型
model = onnx.load('onnx_model.onnx')
# 检查模型格式是否完整及正确
onnx.checker.check_model(model)
# 获取输出层,包含层名称、维度信息
output = self.model.graph.output
print(output)

三、获取中节点输出数据

  onnx模型通常只能拿到最后输出节点的输出数据,若想拿到中间节点的输出数据,需要我们自己添加相应的输出节点信息;首先需要构建指定的节点(层名称、数据类型、维度信息);然后再通过insert的方式将节点插入到模型中。

import onnx
from onnx import helper
# 加载模型
model = onnx.load('onnx_model.onnx')
# 创建中间节点:层名称、数据类型、维度信息
prob_info =  helper.make_tensor_value_info('layer1',onnx.TensorProto.FLOAT, [1, 3, 320, 280])
# 将构建完成的中间节点插入到模型中
model.graph.output.insert(0, prob_info)
# 保存新的模型
onnx.save(model, 'onnx_model_new.onnx')
# 扩展:
# 删除指定的节点方法: item为需要删除的节点
# model.graph.output.remove(item)

四、onnx前向InferenceSession的使用

  关于onnx的前向推理,onnx使用了onnxruntime计算引擎。
  onnx runtime是一个用于onnx模型的推理引擎。微软联合Facebook等在2017年搞了个深度学习以及机器学习模型的格式标准–ONNX,顺路提供了一个专门用于ONNX模型推理的引擎(onnxruntime)。

import onnxruntime
# 创建一个InferenceSession的实例,并将模型的地址传递给该实例
sess = onnxruntime.InferenceSession('onnxmodel.onnx')
# 调用实例sess的润方法进行推理
outputs = sess.run(output_layers_name, {input_layers_name: x})

1. 创建实例,源码分析

class InferenceSession(Session):
    This is the main class used to run a model.
    def __init__(self, path_or_bytes, sess_options=None, providers=[]):
        :param path_or_bytes: filename or serialized model in a byte string
        :param sess_options: session options
        :param providers: providers to use for session. If empty, will use
            all available providers.
        self._path_or_bytes = path_or_bytes
        self._sess_options = sess_options
        self._load_model(providers)
        self._enable_fallback = True
        Session.__init__(self, self._sess)
    def _load_model(self, providers=[]):
        if isinstance(self._path_or_bytes, str):
            self._sess = C.InferenceSession(
                self._sess_options if self._sess_options else C.get_default_session_options(), self._path_or_bytes,
                True)
        elif isinstance(self._path_or_bytes, bytes):
            self._sess = C.InferenceSession(
                self._sess_options if self._sess_options else C.get_default_session_options(), self._path_or_bytes,
                False)
        # elif isinstance(self._path_or_bytes, tuple):
        # to remove, hidden trick
        #   self._sess.load_model_no_init(self._path_or_bytes[0], providers)
        else:
            raise TypeError("Unable to load from type '{0}'".format(type(self._path_or_bytes)))
        self._sess.load_model(providers)
        self._sess_options = self._sess.session_options
        self._inputs_meta = self._sess.inputs_meta
        self._outputs_meta = self._sess.outputs_meta
        self._overridable_initializers = self._sess.overridable_initializers
        self._model_meta = self._sess.model_meta
        self._providers = self._sess.get_providers()
        # Tensorrt can fall back to CUDA. All others fall back to CPU.
        if 'TensorrtExecutionProvider' in C.get_available_providers():
            self._fallback_providers = ['CUDAExecutionProvider', 'CPUExecutionProvider']
        else:
            self._fallback_providers = ['CPUExecutionProvider']

  在_load_model函数,可以发现在load模型的时候是通过C.InferenceSession,并且将相关的操作也委托给该类。从导入语句from onnxruntime.capi import _pybind_state as C可知其实就是一个c++实现的Python接口,其源码在onnxruntime\onnxruntime\python\onnxruntime_pybind_state.cc中。

2. 模型推理run,源码分析

    def run(self, output_names, input_feed, run_options=None):
        Compute the predictions.
        :param output_names: name of the outputs
        :param input_feed: dictionary ``{ input_name: input_value }``
        :param run_options: See :class:`onnxruntime.RunOptions`.
            sess.run([output_name], {input_name: x})
        num_required_inputs = len(self._inputs_meta)
        num_inputs = len(input_feed)
        # the graph may have optional inputs used to override initializers. allow for that.
        if num_inputs < num_required_inputs:
            raise ValueError("Model requires {} inputs. Input Feed contains {}".format(num_required_inputs, num_inputs))
        if not output_names:
            output_names = [output.name for output in self._outputs_meta]
        try:
            return self._sess.run(output_names, input_feed, run_options)
        except C.EPFail as err:
            if self._enable_fallback:
                print("EP Error: {} using {}".format(str(err), self._providers))
                print("Falling back to {} and retrying.".format(self._fallback_providers))
                self.set_providers(self._fallback_providers)
                # Fallback only once.
                self.disable_fallback()
                return self._sess.run(output_names, input_feed, run_options)
            else:
                raise

  在run函数中,数据的推理是通过调用self._sess.run来进行前向推理的。同理该函数的具体实现实在c++的InferenceSession类中实现的。

五、遇到的一些问题

  1. 输入数据维度或类型不正确
    在这里插入图片描述
      从上图可以看出,该模型的输入数据的维度信息为[1, 3, 480, 640],输入数据类型为float32;所以在构建输入数据时,一定要按照该信息去构建,否则代码将会报错。

注: python调用c++代码是通过pybind11实现。

使用python实现基于onnxruntime推理框架的深度学习模型的推理功能。 可以将onnx模型转换为大多数主流的深度学习推理框架模型,因此您可以在部署模型之前测试onnx模型是否正确。 注意:此处的模型由pytorch 1.6训练,并由onnx 1.8.1转换 onnx == 1.8.1 onnxruntime == 1.7.0或onnxruntime-gpu == 1.3.0 opencv-python == 4.2.0.32 该演示以main_xxx_.py格式命名。您可以使用以下示例运行代码。 python main_pose_.py --det_model_path weights/yolov5s.onnx \ --pose_model_path data/det/zidane.jpg \ 来源:https://zhuanlan.zhihu.com/p/159379768作者:龟壳(一)Pytorch分类模型onnx 实验环境:Pytorch2.0 + Ubuntu20.041.Pytorch之保存加载模型1.1 当提到保存和加载模型时,有三个核心功能需要熟悉:1.torch.save:将序列化的对象保存到disk。这个函数使用Python的pickle实用程序进行序列化。使用这个... OpenCV不适合用于搭建模型,通常使用其他框架训练模型ONNX作为通用的模型描述格式被众多框架支持,这里推荐使用ONNX作为模型保存格式。学习模型的推理,如果在项目中使用了OpenCV,那么很容易添加深度学习支持。在工业视觉领域OpenCV使用较为广泛,其DNN模块支持。... 在部署大规模深度学习应用的时候,要想满足应用需求或者压榨模型的性能,C++可能是比python更好的选择方案。基于此,特地记录最近的C++的学习经历。其实以终为始来思考为什么学习C++,首先是为了能够很好地提升模型的性能,满足应用场景中的高可用,高并发,低时延等要求。为了提升模型的性能,需要用到一些推理框架,如TensorRT、NCNN或者Openvino(本文中以TensorRT作为案例)。TensorRT在8.0以上的版本都支持Python的API了,但还是有必要学习C++。ONNX模型转换和优化。.. 编辑ONNXpython代码一、ONNX模型基本操作1,加载ONNX模型2,保存ONNX模型3,OP节点列表4,输入节点名称5,输出节点名称6,参数节点二、ONNX模型的修改1,修改内部的变量2,创建tensor3,增加OP节点4,增加输入\输出tensor节点5,增加参数节点6,特殊节点-constant增加7,读取ONNX的参数tensor格式,转换为numpy三、例程得到第一个Conv的节点信息注意:在运行程序的时候,记得安装onnx的环境,在pycharm里面切换到onnx的解释器。关于onnx Learn the Basics — PyTorch Tutorials 1.10.1+cu102 documentation DCGAN Tutorial — PyTorch Tutorials 1.10.1+cu102 documentation EXPORTING A MODEL FROM PYTORCH TO ONNX examples/super_resolution at master · pytorch/examples (github.com).. 1. 关于ONNX:不废话了,不了解的onnx的去知乎或者百度去查询(不要杠,杠就是你赢了)。 2. 是不是还在烦恼模型的结构没有直观的感受,为什么别人对模型的理解这么深刻,讲道理,视觉上的感受一般比文字的感受更加深刻,所以神器在哪里?查看模型结构的神器在这里:Netronhttps://netron.app/ 主界面如下,比较简单的界面,但是功能很强大 如果担心模型被拷贝或者泄露,可以下载离线的版本(速度不行的话,请使用科学上网) GitHub - lutzroeder/... 这篇文章接着上一篇继续讲解如何具体使用TensorRT。 在之前已经写到过一篇去介绍什么是TensorRT:利用TensorRT对深度学习进行加速,这篇文章中大概已经基本讨论了TensorRT究竟是个什么东西以及怎么使用它。 而在这篇文章中我们主要介绍如何使用它在我们的实际任务中进行加速。 在我这里的实验结论表明,在FP32的精度下,使用Tens... speech = torch.randn(bz, seq_len, feature_size, dtype=torch.float32) speech_lens = torch.randint(low=10, high=seq_len, size=(bz,), dtype=torch.int32) model = Encoder(m. 尝试完全用 ONNXPython API 构造一个描述线性函数 output=a*x+b 的 ONNX 模型。我们将根据上面的结构,自底向上地构造这个模型。首先,我们可以用 helper.make_tensor_value_info 构造出一个描述张量信息的 ValueInfoProto 对象。如前面的类图所示,我们要传入张量名、张量的基本数据类型、张量形状这三个信息。在 ONNX 中,不管是输入张量还是输出张量,它们的表示方式都是一样的。