概述
ONNX全称Open Neural Network Exchange,是微软设计的一个开放式深度学习神经网络模型的格式。旨在通过一个统一的模型格式标准,建立一个强大的人工智能生态。
深度神经网络的实现是通过数据流图实现的,数据(张量等)从输入,流过一个个集选节点,最终在输出结点得到推理结果。不同的框架实现数据流图的的方式不尽相同,有的使用静态图,有的在运行的过程中动态创建。但是不管哪种方式,最终都会得到一个神经网络模型的结构图以及权重。通常,神经网络模型的结构、权重等信息不会一直在内存里,通常需要将它们保存到文件中,用于部署、转换等。而每一种框架都有他们自己的一套专有的模型表示方法,拥有自己的一套标准去操作、运行他们自己的模型。由于AI 研究正在迅猛发展当中,每种框架都有自己的侧重点,比如有的框架特别适合于做研究,能够快速的搭建验证模型;而有的框架则最特定硬件做了大量性能优化,特别适合生产部署。
这时候,一个通用的模型格式标准应运而生,它就是ONNX。有了这样一个统一的模型格式标准,你就可以使用能够快速的框架去验证你的模型,然后将模型导出到ONNX格式,再用有特殊优化的推理引擎进行推理或者转换到可以在移动端进行推理的特殊格式。
ONNX还有另一个变种,ONNX-ML,它额外增加了一些传统的标准机器学习操作。
组成
ONNX是一个开放的标准,这个标准主要有以下三部分组成:
- 一个可扩展的计算图模型的定义,它主要确定了一套用于序列化模型的格式标准。这个序列化后的模型可以不遵循原有框架在内存中的表示,序列化或者使用ONNX模型的框架可以处于效率等的目的使用不同的内存布局;
- 一个标准数据类型的定义,它主要定义了模型中的数据如权重、计算中间结果等的表示方法;
- ONNX自带的操作,它定义了一套原子操作和函数。
版本号表示
版本号有两种表示方法:简单数字表示和语义表示,用8个字节存储版本信息。
简单数字表示全部字节用于表示一个数,表现形式为XXX,如0x0000000000000001
表示数字1;语义表示则将这八个字节分开,最高位两个字节表示主版本号,次高位两个字节表示此版本好,剩下四个字节表示补丁、编译等版本号,最终的表现形式为MAJOR.MINOR.PATCH,例如0x0001000200000003
表示主版本号为1,此版本号为2,补丁版本号等为3。两种表示方法的区分方法是查看最高四个字节内容,如果最高四个字节为0,则使用的是简单数字表示;如果最高四个字节不为零,则使用的是语义表示。例如0x0000000000000001
最高四个字节为0,所以表示这个版本号是用简单数字表示;而0x000000010000000
最高四个字节不为0,则表示这是语义版本号。
值得注意的是,ONNX标准中规定,IR和OP的版本号必须用简单数字来表示,版本数值单调递增,而对于模型版本,并未作出规定,可以随意二选一。
模型结构
Model
处于模型结构顶层的是一个被称为Model的结构,它的主要目的是将一个包含模型所有执行元素的图和它的元数据关联起来。元数据可以在模型被读取的时候告诉读取方一些重要信息,比如版本、执行该模型所需要的操作集(Operators Set)等信息,读取方根据这些信息决定下一步是继续执行该模型还是选择报错等操作。另外,有些工具,例如模型查看工具等可以根据元数据告诉人们模型的信息和模型的作用等。Model的组成结构如下:
Name | Type | Description |
---|---|---|
ir_version | int64 | The ONNX version assumed by the model. |
opset_import | OperatorSetId | A collection of operator set identifiers made available to the model. An implementation must support all operators in the set or reject the model. |
producer_name | string | The name of the tool used to generate the model. |
producer_version | string | A string representing the version of the generating tool. |
domain | string | A reverse-DNS name to indicate the model namespace or domain, for example, ‘org.onnx’ |
model_version | int64 | A version of the model itself, encoded in an integer. |
doc_string | string | A human-readable documentation for this model. Markdown is allowed. |
graph | Graph | The parameterized graph that is evaluated to execute the model. |
metadata_props | map<string,string> | Named metadata values; keys should be distinct. |
training_info | TrainingInfoProto[] | An optional extension that contains information for training. |
每个Model都必须指定它所属机构的域名,使用类似Java包结构的反向域名表示。此外,Model的metadata_props
字段可以用于定义其他额外的元数据信息,例如下表定义了一些额外的元数据属性:
Name | Type | Format | Description |
---|---|---|---|
model_author | string | A comma-separated list of names. | The personal name of the author(s) of the model, and/or their organizations. |
model_license | string | Name or URL. | The well-known name or URL of the license under which the model is made available. |
Operator Sets
每个模型必须明确的指出它所以来的操作集,操作集定义了可用的操作以及他们的版本。模型通过他们的域定义了需要导入的操作集,如果没有特别指定,模型将默认导入默认的ONNX操作集。
操作集的属性如下:
Name | Type | Description |
---|---|---|
magic | string | The value ‘ONNXOPSET’ |
ir_version | int32 | The ONNX version corresponding to the operators. |
ir_version_prerelease | string | The prerelease component of the SemVer of the IR. |
ir_build_metadata | string | The build metadata of this version of the operator set. |
domain | string | The domain of the operator set. Must be unique among all sets. |
opset_version | int64 | The version of the set of operators. |
doc_string | string | A human-readable documentation for this set of operators. Markdown is allowed. |
operator | Operator[] | The operators of this operator set. |
Operators
图(Graph)中的任何一个操作(Operator)都必须是在模型导入了的操作集中有明确声明了的。
操作的属性如下:
Name | Type | Description |
---|---|---|
op_type | string | The name of the operator, as used in graph nodes. MUST be unique within the operator set’s domain. |
since_version | int64 | The version of the operator set when this operator was introduced. |
status | OperatorStatus | One of ‘EXPERIMENTAL’ or ‘STABLE.’ |
doc_string | string | A human-readable documentation string for this operator. Markdown is allowed. |
Graphs
图用于表示一个计算过程,它由元数据字段、模型参数以及计算结点三部分组成。计算结点按照一定拓扑结构组成了一个有向无环图,每个结点表示一个操作。每个结点可以有0到多个输入以及至少一个输出。
图的属性如下:
Name | Type | Description |
---|---|---|
name | string | The name of the model graph. |
node | Node[] | A list of nodes, forming a partially ordered computation graph based on input/output data dependencies. |
initializer | Tensor[] | A list of named tensor values. When an initializer has the same name as a graph input, it specifies a default value for that input. When an initializer has a name different from all graph inputs, it specifies a constant value. |
doc_string | string | A human-readable documentation for this model. Markdown is allowed. |
input | ValueInfo[] | The input “parameters” of the graph, possibly initialized by a default value found in ‘initializer.’ |
output | ValueInfo[] | The output parameters of the graph. Once all output parameters have been written to by a graph execution, the execution is complete. |
value_info | ValueInfo[] | Used to store the type and shape information of values that are not inputs or outputs. |
Nodes
计算节点由结点名字、这个结点的操作的名字、输入的名字、输出的名字以及一系列属性组成。结点的输入输出和操作的输入输出通过位置相关联,例如第一个输入是上一个结点的输出,第二个输入是权重,第三个输入是偏置等,结点属性名字和操作属性通过名字相关联。
结点属性如下:
Name | Type | Description |
---|---|---|
name | string | An optional name of the node, used for diagnostic purposes only. |
input | string[] | Names of the values used by the node to propagate input values to the node operator. It must refer to either a graph input or a graph initializer or a node output. |
output | string[] | Names of the outputs used by the node to capture data from the operator invoked by the node. It either introduces a value in the graph or refers to a graph output. |
op_type | string | The symbolic identifier of the operator to invoke. |
domain | string | The domain of the operator set that contains the operator named by the op_type. |
attribute | Attribute[] | Named attributes, another form of operator parameterization, used for constant values rather than propagated values. |
doc_string | string | A human-readable documentation for this value. Markdown is allowed. |
数据类型
ONNX有两个变种:ONNX和ONNX-ML。ONNX只识别张量,ONNX-ML除了张量还能识别序列以及字典。
总结
总的来说,ONNX就是定义了一套标准,这套标准使得不同机器学习框架的数据流图有了一个统一的表示。
它定义了如何将一个内存的模型序列化到磁盘,也定义了如何去读取这个序列化的模型进入内存。
References
[1] Open Neural Network Exchange - ONNX
本文首发于个人微信公众号TensorBoy。如果你觉得内容还不错,欢迎分享并关注我的微信公众号TensorBoy,扫描下方二维码获取更多精彩原创内容!