原文链接:
Open Neural Network Exchange Intermediate Representation (ONNX IR) Specification
开放神经网络交换中间表示(ONNX IR)规范
目的
本文档包含ONNX语义的规范性规范。
在onnx文件夹下的.proto和.proto3文件构成了其语法的规范性规范,这些文件使用Protocol Buffers定义语言编写。.proto和.proto3文件中的注释旨在提高这些文件的可读性,但如果与本文档冲突,则不具有规范性。此类冲突应报告为文档错误。
关于模型验证的说明
提供了一个工具来根据此规范对模型进行一般验证。它使用C++实现,并带有Python命令行包装器。
关于本文档及所有相关文档中语言的说明:
-
本文档中使用的SHOULD、MUST、MAY等术语与RFC 2119一致。
-
使用“列表”表示项目的有序集合,“集合”表示唯一元素的无序集合,“包”表示可能包含非唯一元素的无序集合。
组件
ONNX是一个开放规范,由以下组件组成:
-
可扩展计算图模型的定义。
-
标准数据类型的定义。
-
内置运算符的定义。
#1和#2共同构成了ONNX中间表示(IR)规范,本文档涵盖了这些内容;内置运算符在文档末尾列出的文档中涵盖。具体来说,内置运算符分为一组原始运算符和函数。函数是一个运算符,其语义通过扩展为使用其他运算符(和函数)的子图(称为函数体)来正式表达。功能上,如果ONNX兼容框架或运行时没有相应的函数实现,则可以内联函数体来执行它。
有两个官方的ONNX变体;两者之间的主要区别在于默认的运算符集。__ONNX-ML__扩展了__ONNX__运算符集,包含了不基于神经网络的机器学习算法。
直到IR版本6,ONNX规范和模型格式仅支持推理(也称为评分)。从IR版本7开始,ONNX规范和模型格式还支持训练。ONNX训练模型是推理模型的扩展。仅支持推理的运行时可以忽略训练相关的扩展来使用训练模型。然而,仅支持推理的模型可能比训练模型更适合推理目的。
运行时无关性
ONNX不预设或暗示任何特定的运行时实现方法。
例如,实现可能包括一个丰富的运行时来解释模型;它可能是一个代码生成器,将模型整体翻译为某种目标编程语言的可执行代码;它可能是一个硬件实现;它可能是上述两种或三种的组合。
本规范中的任何内容都不应被解释为提倡一种实现方法优于其他方法;任何关于具体实现内部工作的评论都应被解释为示例。
ONNX版本控制
IR规范、各个模型和运算符集都有版本控制。此外,每个单独的运算符都指示了它在其包含的运算符集中引入或稳定的版本。
版本号可以作为一个简单的数字使用,也可以用于编码语义版本(也称为SemVer)。如果使用语义版本,约定是使用两个最高有效字节表示主版本号,接下来的两个字节表示次版本号,最低有效的四个字节表示补丁/构建/修复版本号。使用语义版本控制时,主版本号或次版本号中至少有一个必须为非零。
IR规范使用简单的单调递增数字作为其版本。有效的IR版本由onnx.proto中的onnx.Version枚举定义。
运算符集使用简单的版本号。每个运算符集版本表示一组运算符及其在特定时间点的语义的快照。
本规范未提供模型生产者应使用何种版本控制方案的指导。
有关IR、运算符集和模型版本控制的约定和最佳实践的更多详细信息,请参阅版本控制。
可扩展的计算图模型
ONNX指定了计算图的可移植、序列化格式。它不必是框架内部使用的形式。例如,实现可以在内存中以不同的方式表示模型,如果在优化过程中更高效。
实现可以通过添加表达超出标准运算符集语义的运算符来扩展ONNX。其机制是在依赖扩展运算符的模型中向opset_import属性添加运算符集。
模型 Models
ONNX的顶层结构是“模型”,在协议缓冲区中表示为onnx.ModelProto类型。
模型结构的主要目的是将元数据与包含所有可执行元素的图关联起来。元数据在首次读取模型文件时使用,为实现提供确定是否能够执行模型、生成日志消息、错误报告等所需的信息。此外,元数据对工具(如IDE和模型库)非常有用,这些工具需要它来向人类传达给定模型的用途和特征。
每个模型具有以下组件:
| 名称 | 类型 | 描述 |
|---|---|---|
| ir_version | int64 | 模型假设的ONNX版本。 |
| opset_import | OperatorSetId | 模型可用的运算符集标识符集合。实现必须支持集合中的所有运算符或拒绝模型。 |
| producer_name | string | 用于生成模型的工具名称。 |
| producer_version | string | 生成工具的版本。 |
| domain | string | 表示模型命名空间或域的反向DNS名称,例如’org.onnx’ |
| model_version | int64 | 模型本身的版本,编码为整数。 |
| doc_string | string | 此模型的人类可读文档。允许使用Markdown。 |
| graph | Graph | 评估以执行模型的参数化图。 |
| metadata_props | map<string,string> | 命名的元数据值;键应唯一。 |
| training_info | TrainingInfoProto[] | 包含训练信息的可选扩展。 |
| functions | FunctionProto[] | 模型本地的可选函数列表。 |
模型必须指定一个域,并使用基于负责组织身份的反向域名,与命名Java包使用的约定相同。
注意:探索ONNX文件
您可以使用Protocol Buffers发行版中的protoc工具来检查ONNX文件的内容,如下所示:
$ protoc --decode=onnx.ModelProto onnx.proto < yourfile.onnx
其中onnx.proto是此存储库中的文件。
或者,您可以使用Netron等工具来探索ONNX文件。
模型语义 Model Semantics
推理模型的语义是一个_无状态函数_(除了可能用于随机数生成的状态)。因此,每当使用推理模型(没有随机生成器操作)对相同输入执行推理时,预期会产生相同的输出。
训练模型的语义是一个_有状态对象_,状态由当前训练权重值(以及学习算法所需的任何其他辅助状态,例如动量)组成。具体来说,其语义通过三种方法捕获:初始化方法(用于初始化或重置状态变量的值)、训练步骤方法(用于使用一批输入-输出对进行训练)和推理方法(使用当前学习到的权重值执行推理)。前两种方法更新对象的状态,而第三种方法是无副作用的。
可选元数据 Optional Metadata
模型中的’metadata_props’字段可用于工具或模型开发者选择放置的任何类型的可选元数据。以下是模型定义的“标准”可选元数据属性。
| 名称 | 类型 | 格式 | 描述 |
|---|---|---|---|
| model_author | string | 逗号分隔的名称列表。 | 模型的作者的个人姓名和/或他们的组织。 |
| model_license | string | 名称或URL。 | 模型提供的许可证的知名名称或URL。 |
运算符集标识符 Operator Set Identifiers
每个运算符集由(域,版本)对唯一标识。
| 名称 | 类型 | 描述 |
|---|---|---|
| domain | string | 被标识的运算符集的域。 |
| version | int64 | 被标识的运算符集的版本。与运算符集中的’opset_version’相同。 |
运算符集版本是一个简单的整数值,随着运算符集新版本的发布而单调递增。
默认运算符集以外的运算符集必须指定一个域,并且应使用基于负责组织身份的反向域名,与命名Java包使用的约定相同。
运算符集 Operator Sets
每个模型必须明确命名其依赖的运算符集。运算符集定义了可用的运算符及其版本。每个模型通过其域定义导入的运算符集。所有模型隐式导入默认的ONNX运算符集。
每个运算符集应在单独的文档中定义,也使用protobuf作为序列化格式。如何在运行时找到运算符集文档是实现相关的。
注意:截至本文档发布,尚未知有任何ONNX实现处理运算符集文档。
运算符集的属性为:
| 名称 | 类型 | 描述 |
|---|---|---|
| magic | string | 值‘ONNXOPSET’ |
| ir_version | int32 | 与运算符对应的ONNX版本。 |
| ir_version_prerelease | string | IR的SemVer的预发布组件。 |
| ir_build_metadata | string | 此运算符集版本的构建元数据。 |
| domain | string | 运算符集的域。在所有集合中必须唯一。 |
| opset_version | int64 | 运算符集的版本。 |
| doc_string | string | 此运算符集的人类可读文档。允许使用Markdown。 |
| operator | Operator[] | 此运算符集中包含的运算符。 |
运算符集版本是一个简单的整数值,随着运算符集新版本的发布而单调递增。
默认运算符集以外的运算符集必须指定一个域,并且应使用基于负责组织身份的反向域名,与命名Java包使用的约定相同。
运算符 Operators
图中使用的每个运算符必须由模型导入的运算符集之一明确声明。
运算符定义的属性为:
| 名称 | 类型 | 描述 |
|---|---|---|
| op_type | string | 运算符的名称(区分大小写),如图节点中使用。在运算符集的域内必须唯一。 |
| since_version | int64 | 引入此运算符时的运算符集版本。 |
| status | OperatorStatus | ‘EXPERIMENTAL’或‘STABLE’之一。 |
| doc_string | string | 此运算符的人类可读文档字符串。允许使用Markdown。 |
版本值必须是首次发布运算符时的运算符集版本值。运算符集的后续版本不得更改已发布为STABLE的运算符的签名或语义。
‘status’属性指示运算符的语法、语义或存在是否处于实验或稳定阶段。一旦运算符发布为STABLE,其语法和语义在运算符集的后续版本中不得更改。
有两种不同的方式将信息传递给运算符——输入和属性。输入表示图输入或在图中其他地方计算的值,而属性用于图中常量的值。这种区别可能对某些实现实现良好性能非常相关,而对其他实现则完全无关。
函数 Functions
函数_可以被视为一个运算符与使用其他更原始的操作符实现的组合,称为_函数体。函数体由形成图的拓扑排序节点列表组成。因此,函数结合了运算符和图(如下所述)的各个方面。
模型中包含的每个函数(也称为模型本地函数)作为相应运算符的默认或后备实现。然而,运行时可以选择使用运算符的替代实现(通常作为优化的内核)。因此,函数的唯一名称很重要,因为它隐式地与语义规范相关联。
序列化函数(FunctionProto)具有以下属性:
| 名称 | 类型 | 描述 |
|---|---|---|
| name | string | 函数的名称 |
| domain | string | 此函数所属的域 |
| overload | string | 函数唯一ID的一部分(在IR版本10中添加) |
| doc_string | string | 此函数的人类可读文档。允许使用Markdown。 |
| attribute | string[] | 函数的属性参数 |
| attribute_proto | Attribute[] | (IR版本9+) 函数的属性参数及其默认值。函数属性应表示为字符串属性或Attribute,而不是两者。 |
| input | string[] | 函数的输入参数 |
| output | string[] | 函数的输出参数。 |
| node | Node[] | 节点列表,形成部分有序的计算图。必须按拓扑顺序排列。 |
| opset_import | OperatorSetId | 函数实现使用的运算符集标识符集合。 |
| value_info | ValueInfo[] | (IR版本 >= 10) 用于存储函数中使用的值的类型和形状信息。 |
| metadata_props | map<string,string> | (IR版本 >= 10) 命名的元数据值;键应唯一。 |
名称和域在IR版本9及以下用于唯一标识运算符。IR版本10添加了overload字段,三元组(名称,域,overload)作为模型中存储的函数之间的唯一ID。这旨在支持在模型内对函数的不同调用需要不同函数体的情况。
函数原型中没有明确标识运算符集版本,但它由模型中包含的域的运算符集版本隐式确定。
输入、输出、属性和attribute_proto(在IR版本9中添加)构成运算符的签名部分。签名中未明确包含类型信息。attribute_proto字段描述函数的属性参数及其默认值(当调用站点节点未指定时),而attribute字段列出没有默认值的属性参数。这两个列表中的名称必须不同。当函数中的节点使用函数的属性参数时,如果调用站点节点指定了属性的实际参数值,则替换为该值;如果属性指定了默认值,则替换为默认值;否则省略。
opset_import和node字段描述函数的实现。
value_info字段(在IR版本10中添加)允许模型存储函数中使用的值的类型和形状信息,包括其输入和输出。请注意,这是可选的,ONNX允许函数是多态的。
图 Graphs
图用于描述无副作用的计算(函数)。
序列化图由一组元数据字段、模型参数列表和计算节点列表组成。
每个计算数据流图结构化为形成图的拓扑排序节点列表,必须是无环的。每个节点表示对运算符或模型本地函数的调用。每个节点有零个或多个输入和一个或多个输出。
图具有以下属性:
| 名称 | 类型 | 描述 |
|---|---|---|
| name | string | 模型图的名称。 |
| node | Node[] | 节点列表,基于输入/输出数据依赖关系形成部分有序的计算图。按拓扑顺序排列。 |
| initializer | Tensor[] | 命名的张量值列表。当初始化器与图输入同名时,它指定该输入的默认值。当初始化器名称与所有图输入不同时,它指定一个常量值。列表的顺序未指定。 |
| doc_string | string | 此模型的人类可读文档。允许使用Markdown。 |
| input | ValueInfo[] | 图的输入参数,可能由‘initializer’中的默认值初始化。 |
| output | ValueInfo[] | 图的输出参数。一旦所有输出参数由图执行写入,执行完成。 |
| value_info | ValueInfo[] | 用于存储不是输入或输出的值的类型和形状信息。 |
| metadata_props | map<string,string> | (IR版本 >= 10) 命名的元数据值;键应唯一。 |
ValueInfo具有以下属性:
| 名称 | 类型 | 描述 |
|---|---|---|
| name | string | 值/参数的名称。 |
| type | Type | 值的类型包括形状信息。 |
| doc_string | string | 此值的人类可读文档。允许使用Markdown。 |
每个主(顶层)图必须定义其输入和输出的名称、类型和形状,这些信息指定为‘value info’结构。主图输入和输出必须具有形状,指示秩,即使确切的维度不需要指定。
嵌套子图(指定为属性值)必须定义其输入和输出的名称,并且可以定义其输入和输出的类型。
每个图必须指定一个名称。
图必须对所有节点输出使用单一静态赋值(SSA);这意味着所有节点输出名称在图中必须是唯一的。
图应填充文档字符串,可以使用GitHub风格的Markdown语法解释。HTML和其他文本标记语言不得用于文档字符串。
图中的名称 Names Within a Graph
所有名称应遵循C90标识符语法规则。
节点、输入、输出、初始化器和属性的名称组织到多个命名空间中。在命名空间内,每个名称在给定图中必须是唯一的。如果图包含嵌套子图(作为属性值),请参阅下文以进一步澄清。
命名空间为:
| 命名空间 | 描述 |
|---|---|
| 属性 | 运算符属性的名称。每个运算符唯一。 |
| 值 | 值的名称——节点输入和输出、张量值(如果命名)、图输入、输出。 |
| 节点 | 图中节点的名称。 |
| 图 | 域内图的名称,在模型域内唯一。 |
| 运算符 | 域内运算符的名称。 |
| 形状 | 张量形状变量的名称——限定在图的值信息记录中,这是形状变量出现的地方。 |
节点 Nodes
计算节点由名称、调用的运算符名称、命名输入列表、命名输出列表和属性列表组成。
输入和输出与运算符的输入和输出位置相关联。属性通过名称与运算符属性相关联。
它们具有以下属性:
| 名称 | 类型 | 描述 |
|---|---|---|
| name | string | 节点的可选名称,仅用于诊断目的。 |
| input | string[] | 节点用于将输入值传播到节点运算符的值的名称。它必须引用图输入、图初始化器或节点输出。 |
| output | string[] | 节点用于从节点调用的运算符捕获数据的输出的名称。它要么在图中引入一个值,要么引用图输出。 |
| op_type | string | 要调用的运算符的符号标识符。 |
| domain | string | 包含op_type命名的运算符的运算符集的域。 |
| attribute | Attribute[] | 命名属性,运算符参数化的另一种形式,用于常量值而不是传播值。 |
| doc_string | string | 此值的人类可读文档。允许使用Markdown。 |
| overload | string | 函数唯一ID的一部分(在IR版本10中添加) |
| metadata_props | map<string,string> | (IR版本 >= 10) 命名的元数据值;键应唯一。 |
属于值命名空间的名称可能出现在多个地方,即作为图输入、图初始化器、图输出、节点输入或节点输出。名称作为图输入、图初始化器或节点输出的出现称为定义,名称作为节点输入或图输出的出现称为使用。
图中使用的值名称必须具有唯一的定义,除非同一名称可能出现在图输入列表和图初始化器列表中。(在存在嵌套子图的情况下,适用进一步的例外情况,如下所述。)
当名称同时出现在初始化器列表和图输入列表中时,运行时可能允许调用者为此(输入)名称指定一个值,覆盖初始化器中指定的值,运行时可能允许用户省略为此(输入)名称指定值,选择初始化器中指定的值。不应由调用者覆盖的常量名称应仅出现在初始化器列表中,而不应出现在图输入列表中。在IR版本 >= 4的模型中,在用作属性值的嵌套子图中,用户不得将同一名称同时用作子图初始化器和子图输入,除非相应运算符的规范明确允许。在IR版本 <= 3的模型中,用户可以将同一名称同时用作子图初始化器和子图输入,但这仅限于通过初始化器支持常量,这些常量不打算对应于从节点传递到子图的任何实际输入。特别是,控制流运算符语义确定提供给子图执行的输入集,这些输入名称不得作为子图初始化器出现。子图初始化器名称必须出现在图输入列表中_实际输入之后_。这允许实际输入和形式输入按位置匹配。
计算图中的边通过一个节点的输出被后续节点的输入按名称引用建立。
给定节点的输出在图中引入新名称。节点输出的值由节点的运算符计算。节点输入可能引用节点输出、图输入和图初始化器。当节点输出名称与图输出名称一致时,图输出的值是该节点计算的相应输出值。嵌套子图中的节点输入可能引用外部图中引入的名称(作为节点输出、图输入或图初始化器)。
图必须对所有节点输出使用单一静态赋值,这意味着所有节点输出名称在图中必须是唯一的。在嵌套子图的情况下,节点输出名称必须与嵌套子图中可见的外部作用域中的名称不同。
节点依赖关系不得在计算图中创建循环。
节点中的输入和输出数量、它们的类型、节点中指定的属性集及其类型必须满足节点运算符签名施加的约束。
定义顶层计算图的节点列表必须按拓扑顺序排列;即,如果节点K在图中跟随节点N,则N的数据输入不得引用K的输出。
节点属性用于将字面量(静态)值传递给运算符。
输入和输出值
表示区分两种值:属性值,它们是静态已知的,和输入/输出值。允许在两种情况下的值的类型不同。
输入和输出值作为图输入、输出和初始化器,以及节点输入和输出找到。它们的值在运行时确定,要么由启动模型执行的代码确定,要么由计算输出值的运算符确定。
属性
属性值仅在节点中找到,通过名称关联传递给运算符。属性值是运行时常量,因为它们的值在构建模型图时确定,因此在运行时不会计算。属性的常见用途是表示在模型训练期间建立的系数。
属性具有以下属性:
| 名称 | 类型 | 描述 |
|---|---|---|
| name | string | 属性的名称。在任何给定运算符和节点的属性、输入和输出中必须唯一。 |
| doc_string | string | 此值的人类可读文档。允许使用Markdown。 |
| type | AttributeType | 属性的类型,确定使用其余字段中的哪一个来保存属性的值。 |
| f | float | 32位浮点值。 |
| i | int64 | 64位整数值。 |
| s | byte[] | UTF-8字符串。 |
| t | Tensor | 张量值。 |
| g | Graph | 图。 |
| floats | float[] | 32位浮点值列表。 |
| ints | int64[] | 64位整数值列表。 |
| strings | byte[][] | UTF-8字符串列表。 |
| tensors | Tensor[] | 张量值列表。 |
| graphs | Graph[] | 图列表。 |
| ref_attr_name | string | 父函数属性的名称。 |
属性必须具有‘name’和‘type’属性,并且‘doc_string’应用于所有属性。属性必须只有一个值携带属性。
如果设置了‘ref_attr_name’,则此属性不包含数据,而是对父函数指定名称属性的引用。只能在函数体内使用。
可变输入和输出
运算符的最后一个输入或输出可能被标记为可变。例如,运算符’Max()'可用于计算多个输入值的最大值。可变运算符具有最小元数,指定必须指定的最小操作数。
对于每个可变运算符输入,必须指定N个或更多节点输入,其中N是运算符的最小元数。对于每个可变运算符输出,必须指定N个或更多节点输出,其中N是运算符的最小元数。
可选输入和输出
静态可选
一些运算符的输入被标记为可选,这意味着引用节点可能不提供此类输入的值。
一些运算符的输出是可选的。当未指定运算符的实际输出参数时,运算符实现可能不计算此类输出的值。
有两种方法可以省略可选输入或输出:第一种,仅适用于尾随输入和输出,是简单地不提供该输入或输出;第二种方法是使用空字符串代替输入或输出名称。
每个引用具有可选输出的运算符的节点必须为每个计算的输出提供名称,并且不得为未计算的输出提供名称。
上述类型的可选输入和输出称为_静态可选_。
动态可选(自IR-8起)
IR-8版本引入了一个新的类型构造函数来表示_动态可选_输入和输出,除了上述的静态可选版本。动态可选的INT64张量与INT64张量类型不同。相比之下,静态可选的INT64张量没有不同的类型,它与INT64张量具有相同的类型。运算符Optional和OptionalGetElement必须显式用于在动态可选类型和底层非可选类型之间转换。动态可选比静态可选更具表现力。
外部张量数据
大型常量张量(如初始化器)的原始数据可能序列化在单独的文件中。在这种情况下,张量必须提供相对于模型文件的文件名,并且不得使用值字段。它可能提供该文件中的字节偏移量和长度。它还可能指定文件的SHA1摘要。一个文件可能包含多个张量的数据。
更多详细信息可以在外部数据中找到。
标准数据类型 Standard data types
有两个官方的ONNX变体;两者之间的主要区别在于支持的类型和支持的运算符。
关于支持的类型,__ONNX__和__ONNX-ML__定义都识别张量、稀疏张量、序列、映射和可选作为输入和输出类型。序列和映射从IR版本6(ONNX 1.6.0发布)开始支持。可选类型从IR版本8(ONNX 1.10.0发布)开始支持。
ONNX支持以下数据类型用于图和节点的输入和输出以及图的初始化器。
原始数字、字符串和布尔类型必须用作张量的元素。
张量定义 Tensor Definition
张量是向量和矩阵的泛化;向量有一个维度,矩阵有两个,张量可以有任意数量的维度,包括零。零维张量在逻辑上等同于标量值。
数学上,张量可以定义为一对序列/列表(V,S),其中S是张量的形状(非负整数列表),V是具有长度等于S中维度乘积的值列表。两个张量(V,S)和(V’,S’)相等当且仅当V = V’且S = S’。S的长度称为秩。
- 如果S的长度为0,V的长度必须为1,因为空积定义为1。在这种情况下,张量表示标量。
- S可以包含值为0的维度。如果任何维度为0,V的长度必须为0。
- 如果S的长度为1,V的长度等于S中的单个维度。在这种情况下,张量表示向量。
- 表示长度为1的向量的张量具有形状[1],而表示标量的张量具有形状[]。它们都有一个元素,但标量_不是_长度为1的向量。
张量的形状S是一个列表,但可以表示为具有值S和形状[R]的张量,其中R是张量的秩。
- 对于张量(V,S),表示其形状的张量为(S,[R])。
- 标量的形状为[]。表示为张量,[]具有形状[0]。
表示
通常将张量表示为嵌套列表。这通常工作良好,但在涉及零维度时会有问题。形状为(5,0)的张量可以表示为[[], [], [], [], []],但(0,5)表示为[],这丢失了第二个维度为5的信息。
- 嵌套列表不是具有值为零维度的张量的完整表示。
张量元素类型
| 组 | 类型 | 描述 |
|---|---|---|
| 浮点类型 | float16, float32, float64, bfloat16, float8e4m3fn, float8e5m2, float8e4m3fnuz, float8e5m2fnuz, float4e2m1 | 符合IEEE 754-2008标准的浮点数据表示或FP8 Formats for Deep Learning、8-bit Numerical Formats for Deep Neural Networks和Open Compute Project中定义的值 |
| 有符号整数类型 | int4, int8, int16, int32, int64 | 支持4-64位宽度的有符号整数。 |
| 无符号整数类型 | uint4, uint8, uint16, uint32, uint64 | 支持4-64位宽度的无符号整数。 |
| 复数类型 | complex64, complex128 | 具有32位或64位实部和虚部的复数。 |
| 其他 | string | 字符串表示文本数据。所有字符串使用UTF-8编码。 |
| 其他 | bool | 布尔值表示只有两个值的数据,通常为true和false。 |
输入/输出数据类型
以下类型用于定义图和节点输入和输出的类型。
| 变体 | 类型 | 描述 |
|---|---|---|
| ONNX | 密集张量 | 表示张量。参见上面的定义。 |
| ONNX | 序列 | 序列是密集的、有序的、元素类型相同的集合。 |
| ONNX | 映射 | 映射是关联表,由键类型和值类型定义。 |
| ONNX | 可选 | 可选是包装器,可能包含张量、序列或映射类型的元素,或者可能为空(不包含任何内容)。详细信息 |
静态张量形状
除了元素类型,张量类型还具有静态形状。张量变量的静态形状与张量值的运行时(动态)形状相关但不同。静态张量形状是一个记录列表,指示张量是向量、矩阵还是更高维的值。例如,100x100矩阵的形状为[100,100]。
静态形状由’TensorShapeProto’定义:
message TensorShapeProto {
message Dimension {
oneof value {
int64 dim_value = 1;
string dim_param = 2;
};
};
repeated Dimension dim = 1;
}
它由张量类型消息引用:
message Tensor {
optional TensorProto.DataType elem_type = 1;
optional TensorShapeProto shape = 2;
}
维度大小的空列表[]是有效的张量形状,表示零维(标量)值。零维张量与未知维度的张量不同,后者由张量消息中缺少’shape’属性表示。当值的类型(包括节点输入)中缺少形状属性时,表示相应的运行时值可能具有任何形状。本小节描述了如何解释缺少形状或形状中缺少维度等。然而,特定使用上下文可能对类型和形状施加进一步的约束。例如,模型(顶层图)的输入和输出必须具有形状,指示输入和输出的秩,即使确切的维度不需要指定。
列表中的每个大小可以表示为整数值或“维度变量”,一个字符串表示维度的实际大小不受特定数字的静态约束。这对于声明关心维度数量但不关心每个维度确切大小的接口非常有用。维度可能既没有dim_value也没有dim_param设置。这样的维度表示与其他未知维度无关的未知维度。
例如,NxM矩阵的形状列表为[N,M]。
每个维度变量的名称应遵循C90标识符语法规则。
目前,维度变量没有作用域。维度变量“N”表示模型中整个图的相同值。例如,如果图有两个输入X和Y,每个形状为[“N”],则在运行时为X和Y传递的值必须是具有相同维度的秩1张量。嵌套子图目前与主图共享相同的维度变量作用域。这允许模型将子图中的张量维度与外部图中的张量维度相关联。
ONNX支持诸如张量序列之类的类型。维度变量的全局作用域意味着类型为"Sequence<Tensor<float, [M,N]>"的变量表示所有具有相同形状的张量序列。如果该维度在序列中的所有张量中没有固定大小,则必须从上述类型中省略维度变量M或N。如果序列中的不同张量可能具有不同的秩,则必须从类型中省略整个形状。
例如,执行矩阵叉积的图可以定义为接受两个形状为[K,M]和[M,N]的输入,并生成形状为[K,N]的输出。
形状可以使用整数和变量的组合定义。
历史注释:早期考虑了以下扩展,但从未实现或支持。
- 使用空字符串(作为维度变量)表示与其他任何维度无关的未知维度。这被丢弃,转而使用既没有dim_value也没有dim_param设置的维度。
- 使用字符串"*"(作为维度变量)表示零个或多个未知基数的维度序列。这不支持。在当前实现中,形状中的维度数量必须表示张量的秩。未知秩的张量使用没有形状的TypeProto::Tensor对象表示,这是合法的。
- 允许维度变量局部于子图(如循环体)的作用域机制可能有用,但目前不支持。
- ONNX支持诸如张量序列之类的类型。类型局部维度变量的作用域机制可能有助于区分以下两种类型:不同大小的方阵序列与所有大小相同的方阵序列。目前不支持。
属性类型
用于属性的类型系统与用于输入和输出的类型系统相关但略有不同。属性值可以是密集张量、稀疏张量、标量数值、字符串、图或上述类型之一的重复值。
其他元数据
ModelProto结构,以及在IR版本 >= 10中,各种其他结构(GraphProto, FunctionProto, NodeProto)包含一个metadata_props字段,允许用户以键值对的形式存储其他元数据。建议用户使用带有反向DNS名称前缀的键名(如"ai.onnxruntime.key1")以避免不同用途之间的冲突。未来ONNX标准可能使用非限定名称。
训练相关信息 Training Related Information
训练相关信息由模型中包含的一个或多个_TrainingInfoProto_实例描述。每个TrainingInfoProto包含描述初始化步骤和训练步骤的信息。
初始化步骤使用图(TrainingInfoProto.initialization)和初始化绑定映射(TrainingInfoProto.initialization_binding)描述。初始化步骤通过评估图执行,并将图生成的输出分配给训练模型的状态变量,如初始化绑定中指定的。初始化绑定在概念上是一个映射,指定为键值对列表,其中每个键是状态变量的名称,值是(初始化)图的输出名称。绑定中指定为键的每个名称必须是出现在主推理图(即ModelProto.graph.initializer)中的初始化器的名称,或出现在TrainingInfoProto.algorithm.initializer中的初始化器的名称。绑定中指定为值的每个名称必须是TrainingInfoProto.initialization图的输出名称。在重复的initialization_binding字段中指定的键值必须唯一。
训练步骤类似地使用图(TrainingInfoProto.algorithm)和更新绑定映射(TrainingInfoProto.update_binding)描述。训练步骤通过评估图执行,并将图生成的输出分配给状态变量,如更新绑定中指定的。上述初始化的约束和描述同样适用于训练步骤。
因此,训练模型的状态变量由主推理图(即ModelProto.graph.initializer)和训练算法图(TrainingInfoProto.algorithm.initializer)的初始化器子集组成,如绑定(在TrainingInfoProto.initialization_binding和TrainingInfoProto.update_binding中)的键所标识。请注意,状态变量在训练上下文中不是常量值。它们表示由多个图共享的可变变量(隐式声明在顶层训练模型作用域中)。这种共享可变变量的隐式声明用于代替显式声明,以便与推理图表示向后兼容。
所有状态变量都预初始化为相应初始化器中指定的值。随后调用执行初始化步骤(使用运行时暴露的适当API)如上所述更新状态变量的值。如果训练模型有多个TrainingInfoProto实例,则按顺序执行每个的初始化步骤。TrainingInfoProto.initialization可以省略(仅当没有initialization_bindings时)。对于训练步骤,运行时可能允许用户调用任何一个TrainingInfoProto.algorithm,允许训练过程根据需要交错不同的算法。调用不同TrainingProto.algorithm的顺序影响训练结果,调用者有责任按正确顺序调用它们。
其他规范文档
ONNX规范由本文档组成,定义了IR和标准数据类型的语义,以及以下定义标准运算符语义和IR语法的文档。后者指定为Protobuf v2和v3模式文件。
有关更多详细信息,请参阅元数据类别文档。
1778

被折叠的 条评论
为什么被折叠?



