Open Neural Network Exchange Intermediate Representation (ONNX IR) 规范¶
目的
本文档包含 ONNX 语义的规范说明。
onnx 文件夹下找到的 .proto 和 .proto3 文件构成了其语法的规范说明,该语法由 Protocol Buffers 定义语言编写。 .proto 和 .proto3 文件中的注释旨在提高这些文件的可读性,但如果与本文档冲突,则不具有规范性。此类冲突应报告为文档错误。
模型验证说明
提供了一个工具,用于根据此规范对模型执行一般验证。它采用 C++ 实现,带有 Python 命令行包装器。
本文档和所有相关文档的语言说明:
本文档中 SHOULD、MUST、MAY 等词语的使用与 RFC 2119 一致。
“列表”(list)一词表示项目的有序集合,“集合”(set)一词表示唯一元素的无序集合,“袋”(bag)一词表示可能包含非唯一元素的无序集合。
组件¶
ONNX 是一个开放规范,由以下组件组成
可扩展计算图模型的定义。
标准数据类型的定义。
内置算子的定义。
#1 和 #2 共同构成了本文涵盖的 ONNX 中间表示,或称“IR”规范;内置算子涵盖在末尾列出的文档中。具体来说,内置算子分为一组原始算子和函数。函数是一个算子,其语义通过扩展为使用其他算子(和函数)的子图(称为函数体)来形式化表达。从功能上讲,ONNX 兼容框架或运行时可以内联函数体以执行它,如果它没有该函数的相应实现。
ONNX 有两种官方变体;两者的主要区别在于默认算子集。 ONNX-ML 使用不基于神经网络的 ML 算法扩展了 ONNX 算子集。
在 IR 版本 6 之前,ONNX 规范和模型格式只涉及推理(也称为评分)。从 IR 版本 7 开始,ONNX 规范和模型格式也支持训练。ONNX 训练模型是推理模型的扩展。仅推理运行时可以消耗训练模型,忽略训练相关的扩展。但是,仅推理模型可能启用比训练模型更适合推理目的的表示。
运行时无关¶
ONNX 不预设或暗示任何特定的运行时实现方法。
例如,实现可能包含一个解释模型的丰富运行时;它可能是一个代码生成器,将模型完整地转换为某个目标编程语言的可执行代码;它可能是一个硬件实现;它可能是其中两种或三种的组合。
本规范中的任何内容都不应被解释为提倡一种实现方法优于任何其他方法;关于具体实现内部工作原理的任何评论都应被解释为示例。
ONNX 版本控制¶
IR 规范、单个模型和算子集都经过版本控制。此外,每个单独的算子都表明它在其包含的算子集的哪个版本中引入或稳定。
版本号可以作为简单的数字使用,也可以用于编码语义版本(AKA SemVer)。如果使用语义版本,约定是使用两个最高有效字节表示主要版本号,接下来的两个字节表示次要版本号,以及最低有效四个字节表示补丁/构建/错误修复版本号。使用语义版本控制时,主要/次要版本号中至少有一个 MUST 为非零。
IR 规范使用简单的单调递增数字作为其版本。onnx.proto 中 onnx.Version 枚举定义了有效的 IR 版本。
操作符集使用简单的版本号。每个操作符集版本都代表了操作符集及其在特定时间点的语义的快照。
本规范不提供关于模型生产者应使用何种版本控制方案的指导。
有关 IR、算子集和模型版本控制的约定和最佳实践的更多详细信息,请参见版本控制。
可扩展计算图模型¶
ONNX 指定了计算图的可移植、序列化格式。它不一定是框架选择在内部使用的形式。例如,如果优化过程中操作模型更有效,实现可能会在内存中以不同的方式表示模型。
实现 MAY 通过添加算子来扩展 ONNX,这些算子表达的语义超出了所有实现 MUST 支持的标准算子集。其机制是向依赖扩展算子的模型的 opset_import 属性添加算子集。
模型¶
ONNX 的顶层构造是“模型”,在协议缓冲区中表示为 onnx.ModelProto 类型
模型结构的主要目的是将元数据与包含所有可执行元素的图关联起来。元数据在首次读取模型文件时使用,为实现提供所需信息,以便确定它是否能够执行模型、生成日志消息、错误报告等。此外,元数据对工具(如 IDE 和模型库)很有用,这些工具需要元数据来告知人们给定模型的目的和特性。
每个模型都具有以下组件
名称 |
类型 |
描述 |
|---|---|---|
ir_version |
int64 |
模型假定的 ONNX 版本。 |
opset_import |
OperatorSetId |
可供模型使用的算子集标识符的集合。实现必须支持集合中的所有算子或拒绝模型。 |
producer_name |
字符串 |
用于生成模型的工具的名称。 |
producer_version |
字符串 |
生成工具的版本。 |
domain |
字符串 |
一个反向 DNS 名称,用于指示模型命名空间或域,例如“org.onnx” |
model_version |
int64 |
模型本身的整数编码版本。 |
doc_string |
字符串 |
此模型的人类可读文档。允许使用 Markdown。 |
graph |
图 |
用于执行模型的参数化图。 |
metadata_props |
map<string,string> |
命名元数据值;键应唯一。 |
training_info |
TrainingInfoProto[] |
包含训练信息的可选扩展。 |
functions |
FunctionProto[] |
模型的本地函数的可选列表。 |
configuration |
DeviceConfigurationProto[] |
(IR 版本 >= 11)用于分布式执行的多设备配置的可选列表。 |
模型 MUST 指定一个域,并使用基于负责组织身份的反向域名,这与命名 Java 包的约定相同。
注意:探索 ONNX 文件
您可以使用 Protocol Buffers 分发的一部分 protoc 工具来检查 ONNX 文件的内容,您可以这样做
protoc --decode=onnx.ModelProto onnx.proto < yourfile.onnx
其中 onnx.proto 是此存储库的一部分文件。
或者,您可以使用 Netron 等工具来探索 ONNX 文件。
模型语义¶
推理模型的语义是一个_无状态函数_(可能除了用于随机数生成的_状态_)。因此,每当推理模型(没有随机生成器操作)用于对相同的输入执行推理时,它都应该产生相同的输出。
训练模型的语义是_有状态对象_,状态包括已训练权重的当前值(以及任何其他所需的辅助状态,例如,学习算法使用的动量)。具体来说,其语义通过三种方法捕获:初始化方法(用于初始化或重置状态变量的值)、训练步方法(用于使用一批输入-输出对进行训练)和推理方法(用于使用当前学习权重值执行推理)。前两种方法更新对象的_状态_,而第三种方法是无副作用的。
可选元数据¶
模型的“metadata_props”字段可用于工具或模型开发者选择放置的任何可选元数据。以下是定义的模型“标准”可选元数据属性。
名称 |
类型 |
格式 |
描述 |
|---|---|---|---|
model_author |
字符串 |
逗号分隔的姓名列表。 |
模型作者的个人姓名和/或其组织。 |
model_license |
字符串 |
名称或 URL。 |
模型可用的许可证的知名名称或 URL。 |
算子集标识符¶
每个算子集都由(域、版本)对唯一标识。
名称 |
类型 |
描述 |
|---|---|---|
domain |
字符串 |
被识别算子集的域。 |
版本 |
int64 |
被识别算子集的版本。与算子集中的“opset_version”相同。 |
算子集版本是一个简单的整数值,随着新算子集版本的发布而单调递增。
除默认算子集之外的算子集 MUST 指定一个域,并且 SHOULD 使用基于负责组织身份的反向域名,这与命名 Java 包的约定相同。
算子集¶
每个模型 MUST 明确命名其功能所依赖的算子集。算子集定义了可用的算子及其版本。每个模型通过其域定义导入的算子集。所有模型都隐式导入默认的 ONNX 算子集。
每个算子集都应在单独的文档中定义,也使用 protobuf 作为序列化格式。运行时如何找到算子集文档取决于实现。
注意:截至本文档发布之日,尚无已知的 ONNX 实现处理算子集文档。
算子集的属性有
名称 |
类型 |
描述 |
|---|---|---|
魔术 |
字符串 |
值“ONNXOPSET” |
ir_version |
int32 |
对应于算子的 ONNX 版本。 |
ir_version_prerelease |
字符串 |
IR SemVer 的预发布组件。 |
ir_build_metadata |
字符串 |
此版本算子集的构建元数据。 |
domain |
字符串 |
算子集的域。在所有集合中必须唯一。 |
opset_version |
int64 |
算子集的版本。 |
doc_string |
字符串 |
此算子集的人类可读文档。允许使用 Markdown。 |
算子 |
Operator[] |
此算子集中包含的算子。 |
算子集版本是一个简单的整数值,随着新算子集版本的发布而单调递增。
除默认算子集之外的算子集 MUST 指定一个域,并且 SHOULD 使用基于负责组织身份的反向域名,这与命名 Java 包的约定相同。
算子¶
图中使用的每个算子 MUST 由模型导入的其中一个算子集显式声明。
算子定义的属性有
名称 |
类型 |
描述 |
|---|---|---|
op_type |
字符串 |
算子的名称(区分大小写),用于图节点。在算子集的域内 MUST 唯一。 |
since_version |
int64 |
此算子引入时的算子集版本。 |
状态 |
OperatorStatus |
“EXPERIMENTAL”或“STABLE”之一。 |
doc_string |
字符串 |
此算子的人类可读文档字符串。允许使用 Markdown。 |
当算子首次发布时,版本值 MUST 与算子集版本相同。算子集的后续版本 MUST NOT 更改已发布为 STABLE 的算子的签名或语义。
“状态”属性指示算子的语法、语义或存在是否处于实验或稳定阶段。一旦算子发布为 STABLE,其语法和语义在算子集的后续版本中 MUST NOT 更改。
有两种不同的方式向操作符传递信息——输入和属性。输入表示图输入或图中的其他地方计算的值,而属性用于图中是常量的值。这种区别对于某些实现实现良好的性能可能非常相关,而对其他实现则完全不相关。
函数¶
一个_函数_可以被认为是算子与使用其他更原始的算子(称为_函数体_)实现的结合。函数体由拓扑排序的节点列表组成,这些节点构成一个图。因此,函数结合了算子和图(如下所述)的各个方面。
模型中包含的每个函数(也称为模型局部函数)都充当相应算子的默认或备用实现。然而,运行时可以选择使用算子的替代实现(通常作为优化内核)。因此,函数的唯一名称很重要,因为它隐含地与语义规范相关联。
序列化的函数(_FunctionProto_)具有以下属性
名称 |
类型 |
描述 |
|---|---|---|
名称 |
字符串 |
函数的名称 |
domain |
字符串 |
此函数所属的域 |
重载 |
字符串 |
函数唯一 ID 的一部分(在 IR 版本 10 中添加) |
doc_string |
字符串 |
此函数的人类可读文档。允许使用 Markdown。 |
属性 |
string[] |
函数的属性参数 |
attribute_proto |
Attribute[] |
(IR 版本 9+)具有函数默认值的属性参数。函数属性应表示为字符串属性或属性,而不是两者兼有。 |
输入 |
string[] |
函数的输入参数 |
输出 |
string[] |
函数的输出参数。 |
节点 |
Node[] |
节点列表,形成部分有序的计算图。它必须是拓扑排序的。 |
opset_import |
OperatorSetId |
函数实现使用的算子集标识符的集合。 |
value_info |
ValueInfo[] |
(IR 版本 >= 10)用于存储函数中使用的值的类型和形状信息。 |
metadata_props |
map<string,string> |
(IR 版本 >= 10)命名元数据值;键应唯一。 |
在 IR 版本 9 之前,名称和域用于唯一标识算子。IR 版本 10 添加了 overload 字段,(name, domain, overload)三元组作为模型中存储的函数的唯一 ID。这旨在支持模型中对函数进行不同调用需要不同函数体的情况。FunctionProto 中未明确标识 opset 版本,但它由模型中包含的域的 opset 版本隐式确定。
输入、输出、属性和 attribute_proto(在 IR 版本 9 中添加)构成了算子的签名部分。签名中未显式包含类型信息。attribute_proto 字段描述了函数的属性参数及其默认值(当调用站点节点未指定时),而 attribute 字段列出了没有默认值的属性参数。这两个列表中的名称必须不同。当函数中的节点使用函数的属性参数时,如果指定了该属性,它将替换为调用站点节点(函数的)中为该属性指定的实际参数值;如果属性具有默认值,它将替换为默认值;否则省略。
opset_import 和节点字段描述了函数的实现。
value_info 字段(在 IR 版本 10 中添加)允许模型存储函数中使用的值的类型和形状信息,包括其输入和输出。请注意,这是可选的,ONNX 允许函数是多态的。
图¶
图用于描述无副作用计算(函数)。序列化图由一组元数据字段、一个模型参数列表和一个计算节点列表组成。
每个计算数据流图都构造为拓扑排序的节点列表,这些节点构成一个图,该图 MUST 不含循环。每个节点表示对算子或模型局部函数的调用。每个节点有零个或多个输入和一个或多个输出。
图具有以下属性
名称 |
类型 |
描述 |
|---|---|---|
名称 |
字符串 |
模型图的名称。 |
节点 |
Node[] |
节点列表,根据输入/输出数据依赖关系形成部分有序的计算图。它按拓扑顺序排列。 |
初始化器 |
Tensor[] |
命名张量值列表。当初始化器与图输入具有相同的名称时,它指定该输入的默认值。当初始化器具有与所有图输入不同的名称时,它指定一个常量值。列表的顺序未指定。 |
doc_string |
字符串 |
此模型的人类可读文档。允许使用 Markdown。 |
输入 |
ValueInfo[] |
图的输入参数,可能由“初始化器”中找到的默认值初始化。 |
输出 |
ValueInfo[] |
图的输出参数。一旦所有输出参数都由图执行写入,执行就完成。 |
value_info |
ValueInfo[] |
用于存储非输入或输出值的类型和形状信息。 |
metadata_props |
map<string,string> |
(IR 版本 >= 10)命名元数据值;键应唯一。 |
ValueInfo 具有以下属性
名称 |
类型 |
描述 |
|---|---|---|
名称 |
字符串 |
值/参数的名称。 |
类型 |
类型 |
值的类型,**包括形状信息**。 |
doc_string |
字符串 |
此值的人类可读文档。允许使用 Markdown。 |
每个主(顶级)图 MUST 定义其输入和输出的名称、类型和形状,这些都以“值信息”结构指定。主图输入和输出需要具有形状,指示秩,尽管不必指定精确的维度。
嵌套子图(指定为属性值)MUST 定义其输入和输出的名称,并且 MAY 定义其输入和输出的类型。
每个图 MUST 指定一个名称。
图 MUST 遵守所有节点输出的单一静态赋值(SSA);这意味着所有节点输出名称在图中 MUST 是唯一的。
图 SHOULD 填充文档字符串,这些字符串 MAY 使用 GitHub 风格的 markdown 语法进行解释。HTML 和其他文本标记语言 MAY NOT 用于文档字符串。
图内的名称¶
所有名称 SHOULD 遵守 C90 标识符语法规则。
节点、输入、输出、初始化器和属性的名称组织到几个命名空间中。在命名空间中,每个名称对于每个给定图 MUST 唯一。请参阅下文,以进一步澄清图包含嵌套子图(作为属性值)的情况。
命名空间是
命名空间 |
描述 |
|---|---|
属性 |
算子的属性名称。对于每个算子唯一。 |
值 |
值的名称——节点输入和输出、张量值(如果已命名)、图输入、输出。 |
节点 |
图节点的名称。 |
图 |
域中图的名称,在模型域中唯一。 |
Operator |
域中算子的名称。 |
Shape |
张量形状变量的名称——作用域为图的值信息记录,形状变量在此处出现。 |
节点¶
计算节点由名称、它调用的算子名称、命名输入列表、命名输出列表和属性列表组成。
输入和输出按位置与算子输入和输出关联。属性按名称与算子属性关联。
它们具有以下属性
名称 |
类型 |
描述 |
|---|---|---|
名称 |
字符串 |
节点的可选名称,仅用于诊断目的。 |
输入 |
string[] |
节点用于将输入值传播到节点算子的值的名称。它必须引用图输入、图初始化器或节点输出。 |
输出 |
string[] |
节点用于从节点调用的算子捕获数据的输出名称。它要么在图中引入一个值,要么引用一个图输出。 |
op_type |
字符串 |
要调用的算子的符号标识符。 |
domain |
字符串 |
包含由 op_type 命名的算子的算子集域。 |
属性 |
Attribute[] |
命名属性,算子参数化的另一种形式,用于常量值而非传播值。 |
doc_string |
字符串 |
此值的人类可读文档。允许使用 Markdown。 |
重载 |
字符串 |
函数唯一 ID 的一部分(在 IR 版本 10 中添加) |
metadata_props |
map<string,string> |
(IR 版本 >= 10)命名元数据值;键应唯一。 |
device_configurations |
NodeDeviceConfigurationProto[] |
(IR 版本 >= 11)此节点的多设备执行配置。 |
属于 Value 命名空间的一个名称可以出现在多个位置,即作为图输入、图初始化器、图输出、节点输入或节点输出。名称作为图输入、图初始化器或节点输出的出现被称为定义,名称作为节点输入或图输出的出现被称为使用。
图中使用的一个值名称必须具有唯一的定义,例外是相同的名称 MAY 同时出现在图输入列表和图初始化器列表中。(在存在嵌套子图的情况下,如后所述,还有进一步的例外。)
当一个名称同时出现在初始化器列表和图输入列表中时,运行时 MAY 允许调用者为这个(输入)名称指定一个值,覆盖初始化器中指定的值,并且运行时 MAY 允许用户省略为这个(输入)名称指定一个值,选择初始化器中指定的值。不打算被调用者覆盖的常量名称应该只出现在初始化器列表中,而不是图输入列表中。在 IR 版本 >= 4 的模型中,在用作属性值的嵌套子图中,用户 MUST NOT 将相同的名称用作子图初始化器和子图输入,除非相应的算子规范明确允许。在 IR 版本 <= 3 的模型中,用户 MAY 将相同的名称用作子图初始化器和子图输入,但这仅限于通过初始化器支持不打算对应于从节点传递到子图的任何实际输入的常量。特别是,控制流算子语义确定了提供给子图执行的输入集,这些输入名称 MUST NOT 作为子图初始化器出现。子图初始化器名称必须出现在图输入列表_在_实际输入之后。这允许实际输入和形式输入按位置匹配。
计算图中的边通过一个节点的输出被后续节点的输入按名称引用来建立。
给定节点的输出将新名称引入图中。节点输出的值由节点的算子计算。节点输入 MAY 引用节点输出、图输入和图初始化器。当节点输出的名称与图输出的名称一致时,图输出的值是该节点计算的相应输出值。嵌套子图中的节点输入 MAY 引用外部图中引入的名称(作为节点输出、图输入或图初始化器)。
图 MUST 对所有节点输出使用单一静态赋值,这意味着所有节点输出名称在图内 MUST 唯一。在嵌套子图的情况下,节点输出名称以及子图的输入和初始化器名称 MUST 与嵌套子图中可见的外部作用域的名称不同。也就是说,不允许变量遮蔽。
节点依赖关系 MUST NOT 在计算图中创建循环。
节点中输入和输出的数量、它们的类型、节点中指定的属性集及其类型 MUST 满足节点算子签名施加的约束。
定义顶级计算图的节点列表 MUST 按拓扑顺序排列;也就是说,如果节点 K 在图中跟随节点 N,则 N 的任何数据输入都不能引用 K 的输出。
节点属性用于向算子传递字面(静态)值。
输入和输出值¶
该表示区分两种值:静态已知的属性值和输入/输出值。这两种情况下允许的值类型不同。
输入和输出值作为图输入、输出和初始化器,以及节点输入和输出出现。它们的值在运行时确定,要么由启动模型执行的代码确定,要么由计算输出值的算子确定。
属性¶
属性值仅出现在节点中,通过名称关联传递给算子。属性值是运行时常量,因为它们的值在模型图构建时确定,因此不在运行时计算。属性的常见用途是表示模型训练期间建立的系数。
属性具有以下特性
名称 |
类型 |
描述 |
|---|---|---|
名称 |
字符串 |
属性的名称。对于任何给定算子和节点,在属性、输入和输出中必须唯一。 |
doc_string |
字符串 |
此值的人类可读文档。允许使用 Markdown。 |
类型 |
AttributeType |
属性的类型,决定了其余哪些字段用于保存属性的值。 |
f |
浮点数 |
32 位浮点值。 |
i |
int64 |
64 位整数值。 |
s |
字节数组 |
UTF-8 字符串。 |
t |
张量 |
一个张量值。 |
g |
图 |
一个图。 |
浮点数 |
float[] |
32 位浮点值列表。 |
整数 |
int64[] |
64 位整数值列表。 |
字符串 |
byte[][] |
UTF-8 字符串列表。 |
张量 |
Tensor[] |
张量值列表。 |
图 |
Graph[] |
图列表。 |
ref_attr_name |
字符串 |
父函数属性的名称。 |
所有属性都必须具有“name”和“type”属性,“doc_string”应在所有属性上使用。一个属性 MUST 只能有一个携带值的属性。
如果设置了“ref_attr_name”,则此属性不包含数据,而是对父函数给定名称属性的引用。只能在函数体内部使用。
可变参数输入和输出¶
算子的最后一个输入或输出 MAY 标记为可变参数。例如,算子“Max()”可用于计算可变数量输入值的最大值。可变参数算子具有最小元数,该元数指定必须指定的最小操作数数量。
对于每个可变参数算子输入,必须指定 N 个或更多节点输入,其中 N 是算子的最小元数。对于每个可变参数算子输出,必须指定 N 个或更多节点输出,其中 N 是算子的最小元数。
可选输入和输出¶
静态可选¶
有些算子的输入被标记为可选,这意味着引用节点 MAY 放弃为这些输入提供值。
有些算子具有可选输出。当未指定算子的实际输出参数时,算子实现 MAY 放弃计算这些输出的值。
有两种方法可以不指定可选输入或输出:第一种方法,仅适用于尾部输入和输出,是简单地不提供该输入或输出;第二种方法是使用空字符串代替输入或输出名称。
每个引用具有可选输出的算子的节点 MUST 为每个计算的输出提供名称,并且 MUST NOT 为未计算的输出提供名称。
上述这种可选输入和输出被称为_静态可选_。
动态可选(自 IR-8 起)¶
IR-8 版本引入了一种新的类型构造函数来表示_动态可选_输入和输出,除了上述较早的静态可选版本。动态可选的 INT64 张量与 INT64 张量类型是不同的类型。相反,静态可选的 INT64 张量没有不同的类型,它与 INT64 张量具有相同的类型。算子 Optional 和 OptionalGetElement MUST 明确用于在动态可选类型和底层非可选类型之间进行转换。动态可选比静态可选具有更强的表达能力。
外部张量数据¶
大型常量张量(如初始化器)的原始数据 MAY 序列化到单独的文件中。在这种情况下,张量 MUST 提供相对于模型文件的文件名,并且 MUST NOT 使用值字段。它 MAY 提供该文件内的字节偏移量和长度。它 MAY 还可以指定文件的 SHA1 摘要。一个文件 MAY 包含多个张量的数据。
更多详情请参见外部数据。
标准数据类型¶
ONNX 有两种官方变体;两者的主要区别在于支持的类型和支持的算子。
关于支持的类型,ONNX 和 ONNX-ML 定义都将张量、稀疏张量、序列、映射和可选类型识别为输入和输出类型。序列和映射从 IR 版本 6(ONNX 1.6.0 发布)开始支持。可选类型从 IR 版本 8(ONNX 1.10.0 发布)开始支持。
ONNX 支持以下数据类型用于图和节点的输入和输出以及图的初始化器。
原始数值、字符串和布尔类型 MUST 用作张量的元素。
张量定义¶
张量是向量和矩阵的推广;向量有一维,矩阵有二维,而张量可以有任意数量的维度,包括零维。零维张量在逻辑上等同于标量值。
数学上,张量可以定义为一对序列/列表(V,S),其中 S 是张量的形状(非负整数列表),V 是值列表,其长度等于 S 中维度的乘积。当且仅当 V = V' 和 S = S' 时,两个张量(V,S)和(V',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 格式、深度神经网络的 8 位数值格式和开放计算项目论文中定义的值 |
有符号整数类型 |
int2、int4、int8、int16、int32、int64 |
支持 2-64 位宽度的有符号整数。 |
无符号整数类型 |
uint2, uint4, uint8, uint16, uint32, uint64 |
支持 2-64 位宽度的无符号整数。 |
复杂类型 |
complex64、complex128 |
实部和虚部均为 32 位或 64 位的复数。 |
其他 |
字符串 |
字符串表示文本数据。所有字符串都使用 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;
}
它被 Tensor 类型消息引用
message Tensor {
optional TensorProto.DataType elem_type = 1;
optional TensorShapeProto shape = 2;
}
维度大小的空列表 [] 是一个有效的张量形状,表示零维(标量)值。零维张量不同于未知维度的张量,未知维度由 Tensor 消息中缺少的“形状”属性指示。当值类型(包括节点输入)中缺少形状属性时,表示相应的运行时值可能具有任何形状。本小节描述了如何解释缺失形状或缺少维度的形状等。但是,特定的使用上下文可能会对类型和形状施加进一步的约束。例如,模型(顶级图)的输入和输出必须_具有_形状,指示输入和输出的秩,即使不必指定精确的维度。
列表中每个大小 MAY 以整数值或“维度变量”表示,维度变量是一个字符串,表示维度的实际大小不静态约束为特定数字。这对于声明关注维度数量但不关心每个维度的精确大小的接口非常有用。维度 MAY 既没有设置 dim_value 也没有设置 dim_param。这样的维度表示与任何其他未知维度无关的未知维度。
例如,一个 NxM 矩阵的形状列表将是 [N,M]。
每个维度变量的名称 SHOULD 遵守 C90 标识符语法规则。
目前,维度变量没有作用域。维度变量“N”在模型中的整个图中表示相同的值。例如,如果图有两个输入 X 和 Y,每个的形状都是 [“N”],那么在运行时,为 X 和 Y 传入的值 MUST 是具有相同维度的秩为 1 的张量。嵌套子图目前与主图共享维度变量的相同作用域。这允许模型将子图内部张量的维度与外部图中的张量的维度相关联。
ONNX 支持诸如张量序列之类的类型。维度变量的全局作用域意味着类型为“Sequence<Tensor<float, [M,N]>”的变量表示_所有具有相同形状_的张量序列。如果该维度在序列中的所有张量中没有固定大小,则必须从上述类型中省略维度变量 M 或 N。如果序列中不同的张量可能具有不同的秩,则必须从类型中省略整个形状。
例如,执行矩阵叉积的图可以定义为接受形状为 [K,M] 和 [M,N] 的两个输入,并产生形状为 [K,N] 的输出。
形状 MAY 可以使用整数和变量的组合来定义。
_历史注释_:以下扩展在早期被考虑过,但从未实现或支持。
使用空字符串(作为维度变量)来表示与任何其他维度无关的未知维度。这被放弃了,转而使用未设置 dim_value 也未设置 dim_param 的维度。
使用字符串“*”(作为维度变量)来表示零个或多个未知基数的维度序列。这不受支持。在当前实现中,形状中的维度数量 MUST 表示张量的秩。未知秩的张量表示为没有形状的 TypeProto::Tensor 对象,这是合法的。
允许局部于子图(如循环体)的维度变量的作用域机制可能很有用,但目前不支持。
ONNX 支持诸如张量序列之类的类型。维度变量的局部于类型的作用域机制可能有助于区分以下两种类型:方矩阵序列(大小不同)与方矩阵序列(大小相同)。目前不支持此功能。
属性类型¶
用于属性的类型系统与用于输入和输出的类型系统相关,但略有不同。属性值可以是稠密张量、稀疏张量、标量数值、字符串、图,或者是上述类型之一的重复值。
其他元数据¶
ModelProto 结构,以及 IR 版本 >= 10 中,各种其他结构(GraphProto、FunctionProto、NodeProto)包含一个 metadata_props 字段,允许用户以键值对的形式存储其他元数据。建议用户使用反向 DNS 名称作为前缀(例如“ai.onnxruntime.key1”)限定键名,以避免不同用途之间的冲突。未限定的名称将来可能会被 ONNX 标准使用。
多设备配置(IR 版本 >= 11)¶
ONNX 通过设备配置规范支持多设备执行,从而实现分布式推理和训练。这包括对张量并行(跨多个设备分片张量)和管道并行(将不同的子图分发到不同的设备)的支持。
设备配置¶
模型 MAY 使用模型中包含的一个或多个 DeviceConfigurationProto 指定多设备配置。每个配置描述可用于模型执行的特定设备安排。
设备配置的属性有
名称 |
类型 |
描述 |
|---|---|---|
名称 |
字符串 |
配置的名称。对于此版本的 IR,此字段 MUST 存在。 |
num_devices |
int32 |
此配置中的设备数量。对于此版本的 IR,此字段 MUST 存在。 |
设备 |
string[] |
设备的可选名称。如果提供,MUST 为 num_devices 的长度。 |
节点设备配置¶
单个节点可以通过 NodeDeviceConfigurationProto 指定特定于设备的执行信息。这允许对计算在设备之间如何分布进行细粒度控制。
节点设备配置的属性有
名称 |
类型 |
描述 |
|---|---|---|
configuration_id |
字符串 |
配置的 ID。MUST 匹配 DeviceConfigurationProto 的名称。对于此版本的 IR,此字段 MUST 存在。 |
sharding_spec |
ShardingSpecProto[] |
节点的输入和输出的分片规范。 |
pipeline_stage |
int32 |
此节点的可选管道阶段标识符。 |
简单分片维度¶
_SimpleShardedDimProto_ 指定将 N 个块划分为 M 个分片,其中 N 可以是符号,但 M 必须是常量。
简单分片维度的属性有
名称 |
类型 |
描述 |
|---|---|---|
dim_value |
int64 |
要分片的维度值(dim_param 的替代)。 |
dim_param |
字符串 |
要分片的符号维度参数(dim_value 的替代)。 |
num_shards |
int64 |
将维度拆分为的分片数量。对于此版本的 IR,此字段 MUST 存在。 |
多设备执行语义¶
多设备注释是对执行后端的提示,不影响模型的计算语义。如果不支持或不可用指定的配置,后端 MAY 忽略这些注释。多设备执行所需的所有通信操作(例如设备之间的数据传输)都是隐式的,由运行时处理。
对于张量并行,张量可以
**沿指定轴分割**跨设备,将数据的不同部分分发到不同的设备
**复制**跨设备,其中相同张量数据在多个设备上重复
管道并行通过可选的管道阶段标识符指示,这些标识符建议如何跨设备分发子图以进行管道化执行。
有关多设备执行模式和示例的更多详细信息,请参阅多设备提案。
其他规范文档¶
ONNX 规范由本文档组成,该文档定义了 IR 和标准数据类型的语义,以及以下定义标准算子语义和 IR 语法的文档。后者指定为 Protobuf v2 和 v3 模式文件。
有关更多详细信息,请参阅元数据类别文档。