ONNX是开放式神经网络(Open Neural Network Exchange)的简称,主要由微软和合作伙伴社区创建和维护。很多深度学习训练框架(如Tensorflow, PyTorch, Scikit-learn, MXNet等)的模型都可以导出或转换为标准的ONNX格式,采用ONNX格式作为统一的界面,各种嵌入式平台就可以只需要解析ONNX格式的模型而不用支持多种多样的训练框架,本文主要介绍如何通过代码或JSON文件的形式来构造一个ONNX单算子模型或者整个graph,以及使用ONNX Runtime进行推理得到算子或模型的计算结果。

一. ONNX文件格式

ONNX文件是基于Protobuf进行序列化。了解Protobuf协议的同学应该知道,Protobuf都会有一个*.proto的文件定义协议,ONNX的该协议定义在 https://github.com/onnx/onnx/blob/master/onnx/onnx.proto3 文件中。

从onnx.proto3协议中我们需要重点知道的数据结构如下:

  • ModelProto:模型的定义,包含版本信息,生产者和GraphProto。
  • GraphProto: 包含很多重复的NodeProto, initializer, ValueInfoProto等,这些元素共同构成一个计算图,在GraphProto中,这些元素都是以列表的方式存储,连接关系是通过Node之间的输入输出进行表达的。
  • NodeProto: onnx的计算图是一个有向无环图(DAG),NodeProto定义算子类型,节点的输入输出,还包含属性。
  • ValueInforProto: 定义输入输出这类变量的类型。
  • TensorProto: 序列化的权重数据,包含数据的数据类型,shape等。
  • AttributeProto: 具有名字的属性,可以存储基本的数据类型(int, float, string, vector等)也可以存储onnx定义的数据结构(TENSOR, GRAPH等)。

二. Python API

2.1 搭建ONNX模型

ONNX是用DAG来描述网络结构的,也就是一个网络(Graph)由节点(Node)和边(Tensor)组成,ONNX提供的helper类中有很多API可以用来构建一个ONNX网络模型,比如make_node, make_graph, make_tensor等,下面是一个单个Conv2d的网络构造示例:

import onnx
from onnx import helper
from onnx import TensorProto
import numpy as np
weight = np.random.randn(36)
X = helper.make_tensor_value_info('X', TensorProto.FLOAT, [1, 2, 4, 4])
W = helper.make_tensor('W', TensorProto.FLOAT, [2, 2, 3, 3], weight)
B = helper.make_tensor('B', TensorProto.FLOAT, [2], [1.0, 2.0])
Y = helper.make_tensor_value_info('Y', TensorProto.FLOAT, [1, 2, 2, 2])
node_def = helper.make_node(
    'Conv', # node name
    ['X', 'W', 'B'],
    ['Y'], # outputs
    # attributes
    strides=[2,2],
graph_def = helper.make_graph(
    [node_def],
    'test_conv_mode',
    [X], # graph inputs
    [Y], # graph outputs
    initializer=[W, B],
mode_def = helper.make_model(graph_def, producer_name='onnx-example')
onnx.checker.check_model(mode_def)
onnx.save(mode_def, "./Conv.onnx")

搭建的这个Conv算子模型使用netron可视化如下图所示:

这个示例演示了如何使用helper的make_tensor_value_info, make_mode, make_graph, make_model等方法来搭建一个onnx模型。

相比于PyTorch或其它框架,这些API看起来仍然显得比较繁琐,一般我们也不会用ONNX来搭建一个大型的网络模型,而是通过其它框架转换得到一个ONNX模型。

2.2 Shape Inference

很多时候我们从pytorch, tensorflow或其他框架转换过来的onnx模型中间节点并没有shape信息,如下图所示:

我们经常希望能直接看到网络中某些node的shape信息,shape_inference模块可以推导出所有node的shape信息,这样可视化模型时将会更友好:

import onnx
from onnx import shape_inference
onnx_model = onnx.load("./test_data/mobilenetv2-1.0.onnx")
onnx_model = shape_inference.infer_shapes(onnx_model)
onnx.save(onnx_model, "./test_data/mobilenetv2-1.0_shaped.onnx")

可视化经过shape_inference之后的模型如下图:

2.3 ONNX Optimizer

ONNX的optimizer模块提供部分图优化的功能,例如最常用的:fuse_bn_into_conv,fuse_pad_into_conv等等。

查看onnx支持的优化方法:

from onnx import optimizer
all_passes = optimizer.get_available_passes()
print("Available optimization passes:")
for p in all_passes:
    print(p)
print()

应用图优化到onnx模型上进行变换:

passes = ['fuse_bn_into_conv']
# Apply the optimization on the original model
optimized_model = optimizer.optimize(onnx_model, passes)

将mobile net v2应用fuse_bn_into_conv之后,BatchNormalization的参数合并到了Conv的weight和bias参数中,如下图所示:

三. ONNX Runtime计算ONNX模型

onnx本身只是一个协议,定义算子与模型结构等,不涉及具体的计算。onnx runtime是类似JVM一样将ONNX格式的模型运行起来的解释器,包括对模型的解析、图优化、后端运行等。

安装onnx runtime:

python3 -m pip install onnxruntime
import onnx
import onnxruntime as ort
import numpy as np
import cv2
def preprocess(img_data):
    mean_vec = np.array([0.485, 0.456, 0.406])
    stddev_vec = np.array([0.229, 0.224, 0.225])
    norm_img_data = np.zeros(img_data.shape).astype('float32')
    for i in range(img_data.shape[0]):
         # for each pixel in each channel, divide the value by 255 to get value between [0, 1] and then normalize
        norm_img_data[i,:,:] = (img_data[i,:,:]/255 - mean_vec[i]) / stddev_vec[i]
    return norm_img_data
img = cv2.imread("test_data/dog.jpeg")
img = cv2.resize(img, (224,224), interpolation=cv2.INTER_AREA)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
input_data = np.transpose(img, (2, 0, 1))
input_data = preprocess(input_data)
input_data = input_data.reshape([1, 3, 224, 224])
sess = ort.InferenceSession("test_data/mobilenetv2-1.0.onnx")
input_name = sess.get_inputs()[0].name
result = sess.run([], {input_name: input_data})
result = np.reshape(result, [1, -1])
index = np.argmax(result)
print("max index:", index)
使用 ONNX 导出和 运行 模型 本教程系列将涵盖txtai的主要用例,这是一个 AI 驱动的语义搜索平台。该系列的每章都有相关代码,可也可以在colab 中使用。 colab 地址 https://dev.to/neuml/tutorial-series-on-txtai-ibg ONNX 运行 时为机器学习 模型 提供了一种通用的序列化 格式 ONNX 支持多种不同的平台/语言,并具有有助于减少推理时间的内置功能。PyTorch 对将 Torch 模型 导出到 ONNX 具有强大的支持。这使得可以将 Hugging Face Transformer 和/或其他下游 模型 直接导出到 ONNX ONNX 开辟了一条使用多种语言和平台进行直接推理的途径。例如, 模型 可以直接在 Android 上 运行 以限制发送到第三方服务的数据。 ONNX 是一个令人兴奋的发展,充满希望。 使用 C++ 的 OpenCV 接口调用 ONNX 格式 的 PyTorch 深度学习 模型 进行预测(Windows, C++, PyTorch, ONNX , Visual Studio, OpenCV) onnx 的基本操作一、 onnx 的配置环境二、获取 onnx 模型 的输出层三、获取中节点输出数据四、 onnx 前向InferenceSession的使用1. 创建实例,源码分析2. 模型 推理run,源码分析五、遇到的一些问题 最近在对 模型 进行量化时候, 模型 格式 转变为 onnx 模型 了,因此需要对 onnx 进行加载、 运行 以及量化(权重/输入/输出)。故,对 onnx 模型 的相关操作进行简单的学习,并写下了这边博客,若有错误请指出,谢谢。 一、 onnx 的配置环境 onnx 的环境主要包含两个包 onnx onnx runtime,我们 ONNX 提供了一个C ++库,可用于在 ONNX 模型 上执行任意优化,以及越来越多的预打包优化过程列表。 主要动机是在许多 ONNX 后端实现之间共享工作。 并非所有可能的优化都可以直接在 ONNX 图上实现-有些需要附加的特定于后端的信息-但是很多可以,我们的目标是与 ONNX 一起提供所有此类传递,以便可以通过单个函数调用重复使用。 您可能有兴趣调用提供的通行证,或实施新的通行证(或两者都有)。 您可以从PyPI安装 onnx optimizer: pip3 install onnx optimizer 请注意,如果遇到问题,您可能需要先升级点子: pip3 install -U pip 如果要从源代码 构建 : git clone --recursive https://github.com/ onnx /optimizer onnx optimizer cd onnx optim 文章目录 ONNX 介绍 ONNX 与Protobuf ONNX 数据结构 ONNX 模型 解析 ONNX 模型 构建 及推理 ONNX 模型 修改节点删除:节点修改: ONNX 介绍 ONNX 是一种针对机器学习所设计的开放式的文件 格式 ,用于存储训练好的 模型 。它使得不同的人工智能框架(如Pytorch, MXNet)可以采用相同 格式 存储 模型 数据。简而言之, ONNX 是一种便于在各个主流深度学习框架中迁移 模型 的中间表达 格式 ONNX 与Protobuf ONNX 采用序列化数据结构协议protobuf来存储 模型 信息。我们可以通过protobuf 为什么要说 ONNX ONNX 又是个什么东西,经常要部署神经网络应用的童鞋们可能会 ONNX 会比较熟悉,我们可能会在某一任务中将Pytorch或者TensorFlow 模型 转化为 ONNX 模型 ( ONNX 模型 一般用于中间部署阶段),然后再拿转化后的 ONNX 模型 进而转化为我们使用不同框架部署需要的类型。 典型的几个线路: Pytorch -> ONNX -> TensorRT Pytorch -> ONNX -> TVM TF – onnx – ncnn 模型 部署入门系列教程持续更新啦,在前两期教程中,我们学习了PyTorch 模型 ONNX 模型 的方法,了解了如何在原生算子表达能力不足时,为 PyTorch 或 ONNX 自定义算子。一直以来,我们都是通过 PyTorch 来导出 ONNX 模型 的,基本没有单独探究过 ONNX 模型 的构造知识。 不知道大家会不会有这样一些疑问: ONNX 模型 在底层是用什么 格式 存储的?如何不依赖深度学习框架,只用 ONNX 的 API 来构造一个 ONNX 模型 ?如果没有源代码,只有一个 ONNX 模型 ,该如何对这个 模型 .