PyTorch开放神经网络交换(Open Neural Network Exchange)ONNX通用格式模型的熟悉

news2024/11/8 20:40:34

我们在深度学习中可以发现有很多不同格式的模型文件,比如不同的框架就有各自的文件格式:.model、.h5、.pb、.pkl、.pt、.pth等等,各自有标准就带来互通的不便,所以微软、Meta和亚马逊在内的合作伙伴社区一起搞一个ONNX(Open Neural Network Exchange)文件格式的通用标准,这样就可以使得模型在不同框架之间方便的进行互操作了。
在上节的YOLOv8的目标对象的分类,分割,跟踪和姿态估计的多任务检测实践(Netron模型可视化) 我们在最后有接触到这个格式文件,而且给出了一个 https://netron.app/站点,可以将这个文件的计算图和相关属性都能可视化的给呈现出来。YOLO的模型有自带的方法:

from ultralytics import YOLO
model = YOLO('yolov8n-cls.pt')
model.export(format="onnx")

或者命令行的方式
yolo export model=yolov8n-cls.pt format=onnx

1、PyTorch演示onnx

这里我们来熟悉下在PyTorchonnx是怎么样的。看一个简单示例:

import torch

class myModel(torch.nn.Module):
    def __init__(self):
        super(myModel, self).__init__()

    def forward(self, x):
        return x.reshape(1,3,64,64)

model = myModel()
x = torch.randn(64,64,3)
torch.onnx.export(model, x, 'newmodel.onnx', input_names=['images'], output_names=['newimages'])

修改输入进来的形状,可以看到通过torch.onnx.export就可以生成onnx格式的模型文件。我们将它上传到上面的站点,将会生成如下的流程图:

 我们打印看下export方法有哪些参数:

export(model: 'Union[torch.nn.Module, torch.jit.ScriptModule, torch.jit.ScriptFunction]', args: 'Union[Tuple[Any, ...], torch.Tensor]', f: 'Union[str, io.BytesIO]', export_params: 'bool' = True, verbose: 'bool' = False, training: '_C_onnx.TrainingMode' = <TrainingMode.EVAL: 0>, input_names: 'Optional[Sequence[str]]' = None, output_names: 'Optional[Sequence[str]]' = None, operator_export_type: '_C_onnx.OperatorExportTypes' = <OperatorExportTypes.ONNX: 0>, opset_version: 'Optional[int]' = None, do_constant_folding: 'bool' = True, dynamic_axes: 'Optional[Union[Mapping[str, Mapping[int, str]], Mapping[str, Sequence[int]]]]' = None, keep_initializers_as_inputs: 'Optional[bool]' = None, custom_opsets: 'Optional[Mapping[str, int]]' = None, export_modules_as_functions: 'Union[bool, Collection[Type[torch.nn.Module]]]' = False) -> 'None'

2、加载onnx模型

2.1、安装onnx库

为了能够正确的加载onnx格式文件,需要先安装onnx库,依然推荐加豆瓣镜像安装

pip install onnx -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com

安装好了之后,我们看下是否成功安装:

import onnx
dir(onnx)
'''
['Any', 'AttributeProto', 'EXPERIMENTAL', 'FunctionProto', 'GraphProto', 'IO', 'IR_VERSION', 'IR_VERSION_2017_10_10', 'IR_VERSION_2017_10_30', 'IR_VERSION_2017_11_3', 'IR_VERSION_2019_1_22', 'IR_VERSION_2019_3_18', 'IR_VERSION_2019_9_19', 'IR_VERSION_2020_5_8', 'IR_VERSION_2021_7_30', 'MapProto', 'ModelProto', 'NodeProto', 'ONNX_ML', 'OperatorProto', 'OperatorSetIdProto', 'OperatorSetProto', 'OperatorStatus', 'Optional', 'OptionalProto', 'STABLE', 'SequenceProto', 'SparseTensorProto', 'StringStringEntryProto', 'TensorAnnotation', 'TensorProto', 'TensorShapeProto', 'TrainingInfoProto', 'TypeProto', 'TypeVar', 'Union', 'ValueInfoProto', 'Version', '_Proto', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '__version__', '_deserialize', '_get_file_path', '_load_bytes', '_save_bytes', '_serialize', 'checker', 'compose', 'convert_model_to_external_data', 'defs', 'external_data_helper', 'gen_proto', 'google', 'helper', 'hub', 'load', 'load_external_data_for_model', 'load_from_string', 'load_model', 'load_model_from_string', 'load_tensor', 'load_tensor_from_string', 'mapping', 'numpy_helper', 'onnx_cpp2py_export', 'onnx_data_pb', 'onnx_data_pb2', 'onnx_ml_pb2', 'onnx_operators_ml_pb2', 'onnx_operators_pb', 'onnx_pb', 'os', 'parser', 'printer', 'save', 'save_model', 'save_tensor', 'shape_inference', 'typing', 'utils', 'version', 'version_converter', 'write_external_data_tensors']
'''

2.2、onnx模型信息

正确安装之后,就可以加载模型了。

import onnx

myModel = onnx.load("newmodel.onnx")
#打印整个模型信息
#print(myModel)
output = myModel.graph.output
#打印输出层的信息
print(output)

[name: "newimages"
type {
  tensor_type {
    elem_type: 1
    shape {
      dim {
        dim_value: 1
      }
      dim {
        dim_value: 3
      }
      dim {
        dim_value: 64
      }
      dim {
        dim_value: 64
      }
    }
  }
}
]

2.3、加载外部数据

需要注意的是,外部数据如果跟模型文件不是在同一个目录里面的话,需要使用load_external_data_for_model来加载外部数据

import onnx
from onnx.external_data_helper import load_external_data_for_model

mymodel = onnx.load('xx/model.onnx', load_external_data=False)
load_external_data_for_model(mymodel, 'datasets/')

这样就可以通过mymodel这个模型来加载指定目录的数据了。

3、保存新模型

我们可以试着在模型的基础上做一些修改,然后保存为一个新的模型文件。

import onnx
from onnx import helper

model = onnx.load('newmodel.onnx')
prob_info = helper.make_tensor_value_info('xx',onnx.TensorProto.FLOAT, [1,3,128,128])
model.graph.output.insert(0, prob_info)
onnx.save(model, 'newmodel2.onnx')

将一个新的节点插入到输出层,我们来看下生成的图:

其中helper里面有很多用法,比如增加节点:

node = helper.make_node("Range",inputs=["start", "limit", "delta"],outputs=["output"])
start = np.float32(1)
limit = np.float32(15)
delta = np.float32(2)
output = np.arange(start, limit, delta, dtype=np.float32)
print(output)#[ 1.  3.  5.  7.  9. 11. 13.]

这里的Range是其中一个操作类型(算子),用法:Operators 更多的操作类型,有兴趣的可以进去查阅

4、常见对象

在onnix常出现的几个对象,AttributeProto,TensorProto,GraphProto,NodeProto一起来了解下:

4.1、AttributeProto 

属性

import onnx
from onnx import helper
from onnx import AttributeProto, TensorProto, GraphProto

arg = helper.make_attribute("this_is_an_int", 1701)
print(arg)
'''
name: "this_is_an_int"
type: INT
i: 1701
'''

当然类型还可以是浮点数、字符串、数组等

4.2、NodeProto

节点

node_proto = helper.make_node("Relu", ["X"], ["Y"])
print(node_proto)
'''
input: "X"
output: "Y"
op_type: "Relu"
'''

其中op_type的算子挺多的,比如上面那个Range的用法。

4.3、AttributeProto和NodeProto结合

看下两者结合使用的一个例子,卷积核为3,步幅为1,填充为1的一个卷积。 

node_proto = helper.make_node(
    "Conv", ["X", "W", "B"], ["Y"],
    kernel=3, stride=1, pad=1)
# 属性按顺序打印
node_proto.attribute.sort(key=lambda attr: attr.name)
print(node_proto)
'''
input: "X"
input: "W"
input: "B"
output: "Y"
op_type: "Conv"
attribute {
  name: "kernel"
  type: INT
  i: 3
}
attribute {
  name: "pad"
  type: INT
  i: 1
}
attribute {
  name: "stride"
  type: INT
  i: 1
}
'''

另一种更有可读性的打印:

print(helper.printable_node(node_proto))
%Y = Conv[kernel = 3, pad = 1, stride = 1](%X, %W, %B)

4.4、TensorProto和GraphProto

graph_proto = helper.make_graph(
    [
        helper.make_node("FC", ["X", "W1", "B1"], ["H1"]),
        helper.make_node("Relu", ["H1"], ["R1"]),
        helper.make_node("FC", ["R1", "W2", "B2"], ["Y"]),
    ],
    "MLP",
    [
        helper.make_tensor_value_info("X" , TensorProto.FLOAT, [1]),
        helper.make_tensor_value_info("W1", TensorProto.FLOAT, [1]),
        helper.make_tensor_value_info("B1", TensorProto.FLOAT, [1]),
        helper.make_tensor_value_info("W2", TensorProto.FLOAT, [1]),
        helper.make_tensor_value_info("B2", TensorProto.FLOAT, [1]),
    ],
    [
        helper.make_tensor_value_info("Y", TensorProto.FLOAT, [1]),
    ]
)
print(helper.printable_graph(graph_proto))
'''
graph MLP (
  %X[FLOAT, 1]
  %W1[FLOAT, 1]
  %B1[FLOAT, 1]
  %W2[FLOAT, 1]
  %B2[FLOAT, 1]
) {
  %H1 = FC(%X, %W1, %B1)
  %R1 = Relu(%H1)
  %Y = FC(%R1, %W2, %B2)
  return %Y
'''

5、解析器

5.1、parse_graph

onnx.parser.parse_graph将文本表示,创建成ONNX图形

input = """
   agraph (float[N, 128] X, float[128, 10] W, float[10] B) => (float[N, 10] C)
   {
        T = MatMul(X, W)
        S = Add(T, B)
        C = Softmax(S)
   }
"""
graph = onnx.parser.parse_graph(input)
print(helper.printable_graph(graph))
'''
graph agraph (
  %X[FLOAT, Nx128]
  %W[FLOAT, 128x10]
  %B[FLOAT, 10]
) {
  %T = MatMul(%X, %W)
  %S = Add(%T, %B)
  %C = Softmax(%S)
  return %C
}
'''

 5.2、parse_model

onnx.parser.parse_model将文本表示,创建成ONNX模型

input = """
   <
     ir_version: 7,
     opset_import: ["" : 10]
   >
   agraph (float[N, 128] X, float[128, 10] W, float[10] B) => (float[N, 10] C)
   {
      T = MatMul(X, W)
      S = Add(T, B)
      C = Softmax(S)
   }
"""
model = onnx.parser.parse_model(input)
print(model)

'''
ir_version: 7
opset_import {
  domain: ""
  version: 10
}
graph {
  node {
    input: "X"
    input: "W"
    output: "T"
    op_type: "MatMul"
    domain: ""
  }
  node {
    input: "T"
    input: "B"
    output: "S"
    op_type: "Add"
    domain: ""
  }
  node {
    input: "S"
    output: "C"
    op_type: "Softmax"
    domain: ""
  }
  name: "agraph"
  input {
    name: "X"
    type {
      tensor_type {
        elem_type: 1
        shape {
          dim {
            dim_param: "N"
          }
          dim {
            dim_value: 128
          }
        }
      }
    }
  }
  input {
    name: "W"
    type {
      tensor_type {
        elem_type: 1
        shape {
          dim {
            dim_value: 128
          }
          dim {
            dim_value: 10
          }
        }
      }
    }
  }
  input {
    name: "B"
    type {
      tensor_type {
        elem_type: 1
        shape {
          dim {
            dim_value: 10
          }
        }
      }
    }
  }
  output {
    name: "C"
    type {
      tensor_type {
        elem_type: 1
        shape {
          dim {
            dim_param: "N"
          }
          dim {
            dim_value: 10
          }
        }
      }
    }
  }
}
'''

引用来源
github:https://github.com/onnx/onnx

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/709706.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis - 优惠券秒杀、库存超卖、分布式锁、Redisson

文章目录 一、优惠券秒杀1.1 全局唯一ID概述1.2 Redis实现全局唯一ID1.3 添加优惠券1.3.1 entity1.3.2 Controller1.3.3 Service层1.3.4 测试 1.4 优惠券秒杀下单1.4.1 entity1.4.2 Controller1.4.3 Service1.4.3 测试 1.5 库存超卖问题1.5.1 库存超卖原因1.5.2 介绍乐观锁1.5.…

【博学谷学习记录】超强总结,用心分享 | 架构师 Jenkins学习总结

文章目录 Jenkins介绍背景应用场景主从集群 Jenkins使用访问Jenkins获取管理员密码进入jenkins主页修改管理员密码 安装插件插件安装 全局工具配置 企业实战pipeline(重点)创建PipelinePipeline语法语法示例 Jenkins介绍 背景 ​ Jenkins&#xff0c;之前叫做Hudson&#xff…

php开发人员信息搜索查询系统 名单查询系统后台 php增删改查功能

php实现人员信息搜索的功能的方法&#xff1a;1、创建conn.php文件连接人员信息数据库&#xff1b;2、创建index.php文件&#xff1b;3、通过“ if(isset($_POST[“flag”])){…}”等语句实现人员搜索功能即可。 1、首次登录需要输入访问的密码 <?php /*** 登录 **/ $mo…

git的基础总结

写在前面&#xff1a; 前天搞了个面试&#xff0c;发现好多都是会使用&#xff0c;但是要我说&#xff0c;难得说出来&#xff0c;现在对基础进行巩固总结。其实我感觉要求背出来一样的没必要吧&#xff0c;ide基本上可视化了会用就行吧。 文章目录 介绍git的状态 使用/安装/…

php使用PhpSpreadsheet导出Excel表格详解

本文会介绍php使用PhpSpreadsheet操作Excel&#xff0c;供大家参考&#xff0c;具体内容如下&#xff1a; PhpSpreadsheet介绍 1、简介 PhpSpreadsheet 是一个用纯PHP编写的库&#xff0c;提供了一组类&#xff0c;使您可以读取和写入不同的电子表格文件格式 PhpSpreadsheet …

Jetson查CPU/GPU等的占用情况——jtop的安装和使用

Jtop的安装 (1) 安装JTOP查看可查CPU等的占用情况 sudo apt-get updatesudo apt-get full-upgradesudo apt install curlsudo apt install nanocurl https://bootstrap.pypa.io/get-pip.py -o get-pip.py #下载安装脚本sudo python3 get-pip.py # 运行安装脚本sudo pip3 insta…

0401锁详解-MySQL-数据库

1 概述 介绍 锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中&#xff0c;除传统的计算资源&#xff08;CPU、RAM、I/O&#xff09;外&#xff0c;数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的问题&#x…

解决QtCreator安卓平台原生C++代码无法输出日志问题

1.需求,因原生C++调用std::cout ,std::cerr,及C函数prinf输出要显示在控制台, 问题: 在QtCreator中只看到qDebug输的日志,并没有看到 cout,cerr,printf的输出日志 2.最终已解决如下 在QtCreator中显示了C++原生日志 在Android Studio 的Logcat中显示了C++原生日志 模拟器 …

c++11 标准模板(STL)(std::basic_ostream)(三)

定义于头文件 <ostream> template< class CharT, class Traits std::char_traits<CharT> > class basic_ostream : virtual public std::basic_ios<CharT, Traits> 类模板 basic_ostream 提供字符流上的高层输出操作。受支持操作包含有格式…

印刷企业WMS仓储管理系统解决方案

在数字化转型的浪潮中&#xff0c;印刷企业也积极寻求适合自身发展的解决方案。作为印刷业的重要环节&#xff0c;仓储管理对于提高效率、降低成本至关重要。而印刷企业WMS仓储管理系统的应用&#xff0c;为印刷企业带来了全新的解决方案。 印刷WMS仓储管理系统是一种基于信息技…

简单认识Tomcat的部署和优化

文章目录 一、简单认识Tomcat1、简介2、构成3、Tomcat 功能组件结构4、Tomcat 请求过程&#xff1a; 二、Tomcat部署1.关闭防火墙&#xff0c;将安装 Tomcat 所需软件包传到/opt目录下2.安装JDK3.设置JDK环境变量4.测试java环境5.安装Tomcat6.启动和关闭Tomcat7.优化 tomcat 启…

synchronized锁升级以后会再降级吗?

Java对象头Markword的结构 其中&#xff0c;最低2位是10代表重量级锁&#xff0c;00代表轻量级锁&#xff0c;001代表无锁&#xff0c;101代表偏向锁。 synchronized锁在1.6的时候做了优化&#xff0c;当仅有一个线程竞争锁的时候&#xff0c;锁处于偏向锁的状态&#xff0c;当…

bim技术的发展趋势是哪些方向?

BIM在现阶段已经取得了较高的发展水平。尽管BIM在许多方面取得了显著进展&#xff0c;但仍有继续改进和发展的空间。未来&#xff0c;BIM在数字化转型、智能化应用和全生命周期管理方面的进一步推进将成为发展重点。简单聊聊BIM技术的发展趋势包括以下几个方向&#xff1a; BIM…

Java面试通关:阿里内部实战模拟面试精讲题库,竟被上传GitHub!

其实这些技术在真正的实际开发环境中真的用得到吗&#xff1f;不一定的&#xff0c;但是没办法&#xff0c;环境就是如此&#xff0c;能做的也就只有不断提升自己&#xff0c;去适应市场环境&#xff0c;提高自身技术水平&#xff01; 我的建议&#xff0c;不管自己现在是个什…

2021北大生命科学院饶毅教授毕业致辞

在祝福裹挟着告诫呼啸而来的毕业季&#xff0c;请原谅我&#xff0c;不敢祝愿每一位毕业生都成功都幸福。因为历史不幸的记载着有人的成功&#xff0c;代价是丧失良知&#xff0c;有人的幸福&#xff0c;代价是损害他人。 从物理学来说&#xff0c;无机的原子&#xff0c;逆​热…

Loadrunner怎么实现MD5加密

目录 前言&#xff1a; 1、写一个md5.h文件&#xff0c;将其放入脚本路径下 2、在globals.h中加入#include “md5.h” 3、在Action中写脚本&#xff0c;脚本示例如下&#xff1a; 前言&#xff1a; 在 LoadRunner 中实现 MD5 加密可以通过使用 LoadRunner 提供的函数来完成…

Redis发布订阅的通讯模式

这个是非常简单的,我们只需要打开两个redis就可以轻松完成 通过Xshell工具两次连接linux,同时启动两个redis: 在第一个里面进行订阅: subscribe leq 在第二个里面进行发布: publish leq hello 这样就可以在订阅的里头看到刚刚发布的信息,没看之前订阅那块也会有提示

带纵深可跳跃横版闯关游戏模版

此项目是以《卡比猎人队》为蓝本开发的横版带纵深闯关游戏模版。内涵数据表配置文件。 购买链接&#xff1a; 微店购买链接 开发环境 开发引擎&#xff1a;CocosCreator3.6.3开发语言&#xff1a;TypeScript 包含的内容&#xff1a; 逻辑实现目录介绍&#xff08;game&am…

Visdom使用

Visdom Visdom是一个面向科学研究的可视化工具&#xff0c;可以帮助你可视化和理解数据。它是 Facebook Research 开发的一个基于 Python 的可视化库&#xff0c;可以在Web浏览器中实时显示和更新图表、图像、文本等各种数据。 1 安装Visdom 可以使用以下命令安装Visdom&…

海思平台图像的IQ调试

目录 1.何为ISP何为IQ调试 1.1、ISP概念 1.2、在哪里做ISP 1.3、何为IQ 1.4、总结 2.海思MPP中ISP的实现框架 2.1、官方文档 2.2、sample中ISP相关部分 2.3、sensor注册内部细节 2.4、ISP注册内部细节 3.IQ调试相关的概念 3.1、黑电平 3.2、镜头阴影矫正 3.3、坏点…