开放神经网络交换中间表示(ONNX IR)规范

目的

本文档包含ONNX语义的规范性说明。

onnx文件夹下找到的.proto.proto3文件构成了其语法的规范性规范,这些文件是用Protocol Buffers定义语言编写的。.proto.proto3文件中的注释旨在提高这些文件的可读性,但如果它们与本文件冲突,则不具有规范性。此类冲突应报告为文档错误。

模型验证注意事项

有一个工具可用于根据此规范对模型进行一般验证。它是用C++实现的,并带有Python命令行包装器。

关于本文件及所有相关文件中的语言说明

  1. 本文档中使用的SHOULD、MUST、MAY等词汇与RFC 2119一致。

  2. 使用“list”表示一个有序的项目集合,“set”表示一个无序的唯一元素集合,而“bag”表示一个可能包含非唯一元素的无序集合。

组件

ONNX 是一个开放规范,由以下组件组成:

  1. 可扩展计算图模型的定义。

  2. 标准数据类型的定义。

  3. 内置操作符的定义。

#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、操作集和模型版本控制的约定和最佳实践的更多详细信息,请参阅Versioning

可扩展的计算图模型

ONNX 指定了计算图的可移植、序列化格式。它不必是框架内部选择使用的形式。例如,实现可能在内存中以不同的方式表示模型,如果在优化过程中操作更高效的话。

实现可以通过添加表达超出所有实现必须支持的标准操作符集的语义的操作符来扩展ONNX。这种机制是将操作符集添加到依赖于扩展操作符的模型中的opset_import属性中。

模型

顶层的ONNX结构是一个‘Model.’,在协议缓冲区中表示为类型onnx.ModelProto

模型结构的主要目的是将元数据与包含所有可执行元素的图关联起来。元数据在首次读取模型文件时使用,为实现提供所需的信息,以便确定是否能够执行模型、生成日志消息、错误报告等。此外,元数据对工具(如IDE和模型库)也很有用,这些工具需要它来向人类告知给定模型的用途和特性。

每个模型都有以下组件:

Name

类型

描述

ir_version

int64

模型假设的ONNX版本。

opset_import

操作符集ID

提供给模型的操作符集合标识符的集合。实现必须支持集合中的所有操作符或拒绝模型。

producer_name

字符串

用于生成模型的工具名称。

producer_version

字符串

生成工具的版本。

域名

字符串

一个反向DNS名称,用于指示模型命名空间或域,例如,‘org.onnx’

模型版本

int64

模型本身的版本,编码为一个整数。

文档字符串

字符串

此模型的人类可读文档。允许使用Markdown。

图表

图表

用于执行模型的参数化图。

元数据属性

映射<字符串,字符串>

命名的元数据值;键应该是唯一的。

训练信息

TrainingInfoProto[]

一个可选的扩展,包含用于训练的信息。

函数

函数原型数组

模型本地的可选函数列表。

模型必须指定一个域,并使用基于负责组织身份的反向域名,这与用于命名Java包的约定相同。

注意:探索一个ONNX文件

您可以使用Protocol Buffers发行版中的protoc工具来检查ONNX文件的内容,您可以这样做:

$ protoc --decode=onnx.ModelProto onnx.proto < yourfile.onnx

其中 onnx.proto 是这个仓库中的文件。

或者,您可以使用像Netron这样的工具来探索ONNX文件。

模型语义

推理模型的语义是一个无状态函数(除了可能用于随机数生成的状态)。因此,每当使用推理模型(没有随机生成器操作)对相同的输入执行推理时,预期会产生相同的输出。

训练模型的语义是一个有状态对象,其状态由训练权重的当前值(以及学习算法所需的任何其他辅助状态,例如动量)组成。具体来说,其语义通过三种方法捕获:初始化方法(用于初始化或重置状态变量的值)、训练步骤方法(用于使用一批输入输出对进行训练)和推理方法(用于使用学习到的权重的当前值进行推理)。前两种方法更新对象的状态,而第三种方法是无副作用的。

可选元数据

模型中的‘metadata_props’字段可用于工具或模型开发者选择放置的任何类型的可选元数据。以下是模型定义的“标准”可选元数据属性。

Name

类型

格式

描述

模型作者

字符串

一个以逗号分隔的名称列表。

模型的作者的个人姓名,以及/或者他们的组织。

model_license

字符串

名称或URL。

模型所依据的许可证的知名名称或URL。

操作符集标识符

每个操作符集由(域,版本)对唯一标识。

Name

类型

描述

域名

字符串

正在识别的运算符集的域。

版本

int64

正在识别的操作符集的版本。与操作符集中的‘opset_version’相同。

操作符集版本是一个简单的整数值,随着操作符集新版本的发布而单调递增。

除了默认的操作符集之外,操作符集必须指定一个域,并且应该使用基于负责组织身份的反向域名,这与用于命名Java包的约定相同。

操作符集合

每个模型必须明确命名其功能所依赖的操作符集。操作符集定义了可用的操作符及其版本。每个模型通过其域定义导入的操作符集。所有模型隐式导入默认的ONNX操作符集。

每个操作符集应在单独的文件中定义,同样使用protobuf作为序列化格式。运行时如何找到操作符集文件取决于具体实现。

注意:截至本文档发布时,尚未有已知的ONNX实现能够处理操作符集文档。

操作符集的属性是:

Name

类型

描述

魔法

字符串

值 'ONNXOPSET'

ir_version

int32

与操作符对应的ONNX版本。

ir_version_prerelease

字符串

IR 的 SemVer 的预发布组件。

ir_build_metadata

字符串

此版本操作符集的构建元数据。

域名

字符串

操作符集的域。在所有集合中必须是唯一的。

opset_version

int64

操作符集的版本。

文档字符串

字符串

此操作符集的人类可读文档。允许使用Markdown。

操作符

操作符[]

此操作符集中包含的操作符。

操作符集版本是一个简单的整数值,随着操作符集新版本的发布而单调递增。

除了默认的操作符集之外,操作符集必须指定一个域,并且应该使用基于负责组织身份的反向域名,这与用于命名Java包的约定相同。

运算符

图中使用的每个操作符必须由模型导入的操作符集之一明确声明。

操作符定义的属性包括:

Name

类型

描述

操作类型

字符串

操作符的名称(区分大小写),用于图节点中。在操作符集的域内必须是唯一的。

自版本

int64

引入此操作符时的操作符集版本。

状态

操作员状态

其中之一是‘EXPERIMENTAL’或‘STABLE.’

文档字符串

字符串

此操作符的人类可读文档字符串。允许使用Markdown。

版本值必须与操作符首次发布时的操作符集版本值相同。一旦操作符作为STABLE发布,操作符集的后续版本不得更改操作符的签名或语义。

'status' 属性指示操作符的语法、语义或存在是否处于实验或稳定阶段。一旦操作符被发布为 STABLE,其语法和语义在操作符集的后续版本中不得更改。

有两种不同的方式向操作符传递信息——输入和属性。输入表示图形输入或在图形其他位置计算的值,而属性用于图形中为常量的值。这种区分对于某些实现实现良好性能可能非常相关,而对于其他实现则完全无关。

函数

一个函数可以被认为是一个操作符与使用其他更原始的操作符实现的操作符的组合,称为函数体。函数体由形成图的拓扑排序节点列表组成。因此,一个函数结合了操作符和图(如下所述)的各个方面。

模型中包含的每个函数(也称为模型本地函数)作为相应操作符的默认或备用实现。然而,运行时可能会选择使用操作符的替代实现(通常作为优化内核)。因此,函数的唯一名称很重要,因为它隐式地与语义规范相关联。

一个序列化的函数(一个FunctionProto)具有以下属性:

Name

类型

描述

名称

字符串

函数的名称

域名

字符串

该函数所属的域

重载

字符串

函数唯一ID的一部分(在IR版本10中添加)

文档字符串

字符串

此函数的人类可读文档。允许使用Markdown格式。

属性

字符串数组

函数的属性参数

属性原型

属性[]

(IR 版本 9+) 带有默认值的函数属性参数。函数属性应表示为字符串属性或属性,不能同时表示为两者。

输入

字符串数组

函数的输入参数

输出

字符串数组

函数的输出参数。

节点

节点数组

节点列表,形成一个部分有序的计算图。它必须是拓扑顺序的。

opset_import

操作符集ID

函数实现使用的操作符集标识符的集合。

值信息

ValueInfo[]

(IR 版本 >= 10) 用于存储函数中使用的值的类型和形状信息。

元数据属性

映射<字符串,字符串>

(IR 版本 >= 10) 命名的元数据值;键应该是唯一的。

名称和域用于在IR版本9及以下唯一标识操作符。IR版本10增加了字段overload,三元组(名称,域,overload)作为存储在模型中的函数的唯一标识符。这是为了支持在模型中对函数的不同调用需要不同函数体的情况。 FunctionProto中没有明确标识opset版本,但它由模型中包含的域的opset版本隐式确定。

输入、输出、属性和attribute_proto(在IR版本9中添加)构成了操作符的签名部分。签名中没有显式包含类型信息。attribute_proto字段描述了函数的属性参数及其默认值(当调用站点节点未指定时),而attribute字段列出了没有默认值的属性参数。这两个列表中的名称必须是唯一的。当函数中的节点使用函数的属性参数时,如果指定了该属性,则将其替换为调用站点节点(函数的)为该属性指定的实际参数值;如果属性指定了默认值,则将其替换为默认值;否则,将省略该属性。

opset_import 和 node 字段描述了函数的实现。

value_info字段(在IR版本10中添加)允许模型存储函数中使用的值的类型和形状信息,包括其输入和输出。请注意,这是可选的,ONNX允许函数是多态的。

图表

图形用于描述无副作用的计算(函数)。 序列化的图形由一组元数据字段、模型参数列表和计算节点列表组成。

每个计算数据流图都被结构化为一个拓扑排序的节点列表,这些节点形成一个图,该图必须是无环的。每个节点代表对操作符或模型本地函数的调用。每个节点有零个或多个输入和一个或多个输出。

图表具有以下属性:

Name

类型

描述

名称

字符串

模型图的名称。

节点

节点数组

节点列表,基于输入/输出数据依赖关系形成部分有序的计算图。它是按拓扑顺序排列的。

初始化器

张量数组

一个命名的张量值列表。当初始化器的名称与图输入的名称相同时,它为该输入指定一个默认值。当初始化器的名称与所有图输入的名称都不同时,它指定一个常数值。列表的顺序未指定。

文档字符串

字符串

此模型的人类可读文档。允许使用Markdown。

输入

ValueInfo[]

图的输入参数,可能由在'initializer'中找到的默认值初始化。

输出

ValueInfo[]

图的输出参数。一旦图执行将所有输出参数写入,执行即完成。

值信息

ValueInfo[]

用于存储不是输入或输出的值的类型和形状信息。

元数据属性

映射<字符串,字符串>

(IR 版本 >= 10) 命名的元数据值;键应该是唯一的。

ValueInfo 具有以下属性:

Name

类型

描述

名称

字符串

值/参数的名称。

类型

类型

值的类型包括形状信息

文档字符串

字符串

此值的人类可读文档。允许使用Markdown。

每个主(顶级)图必须定义其输入和输出的名称、类型和形状,这些信息被指定为“值信息”结构。主图的输入和输出必须具有形状,表示其秩,即使不需要指定确切的维度。

嵌套子图(指定为属性值)必须定义其输入和输出的名称,并且可以定义其输入和输出的类型。

每个图表必须指定一个名称。

图必须遵守所有节点输出的单一静态赋值(SSA);这意味着所有节点输出名称在图中必须是唯一的。

图表应该填充文档字符串,这些字符串可以使用GitHub风格的Markdown语法进行解释。HTML和其他文本标记语言不应在文档字符串中使用。

图中的名称

所有名称必须遵守C90标识符语法规则

节点、输入、输出、初始化器和属性的名称被组织到几个命名空间中。在一个命名空间内,每个名称对于每个给定的图必须是唯一的。如果图中包含嵌套子图(作为属性值),请参阅以下内容以进一步澄清。

命名空间有:

命名空间

描述

属性

操作符的属性名称。每个操作符都是唯一的。

值的名称——节点输入和输出、张量值(如果已命名)、图输入、输出。

节点

图形节点的名称。

图表

域内图的名称,在模型域内是唯一的。

操作符

域内操作符的名称。

Shape

张量形状变量的名称——限定在图的数值信息记录范围内,这是形状变量出现的地方。

节点

计算节点由一个名称、它调用的操作符名称、一组命名的输入、一组命名的输出和一组属性组成。

输入和输出与操作符的输入和输出在位置上相关联。属性通过名称与操作符的属性相关联。

它们具有以下属性:

Name

类型

描述

名称

字符串

节点的可选名称,仅用于诊断目的。

输入

字符串数组

节点用于将输入值传播到节点操作符的值的名称。它必须引用图形输入、图形初始化器或节点输出。

输出

字符串数组

节点用于从节点调用的操作符捕获数据的输出名称。它要么在图中引入一个值,要么引用图输出。

操作类型

字符串

要调用的运算符的符号标识符。

域名

字符串

包含由op_type命名的操作符的操作符集合的域。

属性

属性[]

命名属性,操作符参数化的另一种形式,用于常量值而非传播值。

文档字符串

字符串

此值的人类可读文档。允许使用Markdown。

重载

字符串

函数唯一ID的一部分(在IR版本10中添加)

元数据属性

映射<字符串,字符串>

(IR 版本 >= 10) 命名的元数据值;键应该是唯一的。

属于Value命名空间的名称可能出现在多个地方,即作为图形输入、图形初始化器、图形输出、节点输入或节点输出。名称作为图形输入、图形初始化器或节点输出的出现被称为定义,而名称作为节点输入或图形输出的出现被称为使用。

在图中使用的值名称必须具有唯一的定义,除非相同的名称可能同时出现在图输入列表和图初始化程序列表中。(在存在嵌套子图的情况下,适用进一步的例外情况,如后文所述。)

当一个名称同时出现在初始化列表和图输入列表中时,运行时可能允许调用者为这个(输入)名称指定一个值,覆盖初始化中指定的值,并且运行时可能允许用户省略为这个(输入)名称指定值,选择初始化中指定的值。不打算被调用者覆盖的常量名称应仅出现在初始化列表中,而不应出现在图输入列表中。在IR版本>=4的模型中,在用作属性值的嵌套子图中,用户不得将相同的名称同时用作子图初始化器和子图输入,除非相应的操作规范明确允许。在IR版本<=3的模型中,用户可以将相同的名称同时用作子图初始化器和子图输入,但这仅限于通过初始化器支持常量,这些初始化器不打算对应于从节点传递到子图的任何实际输入。特别是,控制流操作符语义决定了提供给子图执行的输入集,这些输入名称不得作为子图初始化器出现。子图初始化器名称必须出现在实际输入之后的图输入列表中。这允许实际输入和形式输入按位置匹配。

计算图中的边是通过一个节点的输出在后续节点的输入中被引用名称来建立的。

给定节点的输出将新名称引入图中。节点输出的值由节点的操作符计算。节点输入可以引用节点输出、图输入和图初始化器。当节点输出的名称与图输出的名称相同时,图输出的值是由该节点计算的相应输出值。嵌套子图中的节点输入可以引用外部图中引入的名称(作为节点输出、图输入或图初始化器)。

图形必须对所有节点输出使用单一静态赋值,这意味着所有节点输出名称在图形内必须是唯一的。在嵌套子图的情况下,节点输出名称必须与在嵌套子图中可见的外部作用域中的名称不同。

节点依赖关系不得在计算图中创建循环。

节点中的输入和输出数量、它们的类型、节点中指定的属性集及其类型必须满足节点操作符签名所施加的约束。

定义顶层计算图的节点列表必须按拓扑顺序排列;也就是说,如果图中节点K在节点N之后,那么N的任何数据输入都不能引用K的输出。

节点属性用于将字面量(静态)值传递给操作符。

输入和输出值

表示区分两种值:属性值,这些值是静态已知的,以及输入/输出值。这两种情况下允许的值类型是不同的。

输入和输出值可以在图的输入、输出和初始化器以及节点的输入和输出中找到。它们的值在运行时确定,要么由启动模型执行的代码确定,要么由计算输出值的操作符确定。

属性

属性值仅存在于节点中,通过名称关联传递给操作符。属性值是运行时常量,因为它们的值在模型图构建时确定,因此在运行时不会计算。属性的一个常见用途是表示在模型训练期间建立的系数。

属性具有以下特性:

Name

类型

描述

名称

字符串

属性的名称。对于任何给定的操作符和节点,必须在属性、输入和输出之间保持唯一。

文档字符串

字符串

此值的人类可读文档。允许使用Markdown。

类型

属性类型

属性的类型,决定使用哪个剩余字段来保存属性的值。

f

浮点数

一个32位浮点数值。

int64

一个64位整数值。

s

字节数组

UTF-8 字符串。

t

张量

一个张量值。

g

图表

一张图。

浮点数

浮点数数组

一个32位浮点数值的列表。

整数

int64[]

一个64位整数值的列表。

字符串

字节数组

UTF-8字符串列表。

张量

张量数组

张量值的列表。

图表

图表[]

图表列表。

ref_attr_name

字符串

父函数属性的名称。

所有属性都必须包含‘name’和‘type’属性,并且所有属性都应使用‘doc_string’。一个属性只能有一个携带值的属性。

如果设置了‘ref_attr_name’,此属性不包含数据,而是对父函数指定名称属性的引用。只能在函数体内使用。

可变输入和输出

操作符的最后一个输入或输出可以标记为可变参数。例如,操作符‘Max()’可以用于计算多个输入值的最大值。可变参数操作符有一个最小数量,指定必须指定的操作数的最小数量。

对于每个可变参数运算符输入,必须指定N个或更多的节点输入,其中N是运算符的最小参数数量。对于每个可变参数运算符输出,必须指定N个或更多的节点输出,其中N是运算符的最小参数数量。

可选输入和输出

静态可选

一些操作符的输入被标记为可选的,这意味着引用节点可以选择不为这些输入提供值。

一些操作符的输出是可选的。当操作符的实际输出参数未指定时,操作符实现可以选择不为这些输出计算值。

有两种方法可以指定一个可选的输入或输出:第一种方法,仅适用于尾随的输入和输出,是简单地不提供该输入或输出;第二种方法是使用空字符串代替输入或输出名称。

每个引用具有可选输出的操作符的节点必须为每个计算的输出提供一个名称,并且不得为未计算的输出提供名称。

上述类型的可选输入和输出被称为静态可选的

动态可选(自IR-8起)

IR-8 版本引入了一种新的类型构造器来表示动态可选输入和输出,除了之前描述的静态可选版本外。动态可选的 INT64 张量与 INT64 张量类型是不同的类型。相比之下,静态可选的 INT64 张量没有不同的类型,它与 INT64 张量具有相同的类型。必须显式使用 OptionalOptionalGetElement 操作符在动态可选类型和基础的非可选类型之间进行转换。动态可选比静态可选具有更强的表达能力。

外部张量数据

对于大型常量张量的原始数据,例如初始化器,可以序列化在一个单独的文件中。在这种情况下,张量必须提供相对于模型文件的文件名,并且不得使用值字段。它可以提供该文件中的字节偏移量和长度。它还可以指定文件的SHA1摘要。一个文件可以包含多个张量的数据。

更多详情可以在External Data中找到。

标准数据类型

有两种官方的ONNX变体;两者之间的主要区别在于支持的类型和支持的操作符。

关于支持的类型,ONNXONNX-ML 定义都识别张量、稀疏张量、序列、映射和可选类型作为输入和输出类型。序列和映射从 IR 版本 6(ONNX 1.6.0 发布)开始支持。可选类型从 IR 版本 8(ONNX 1.10.0 发布)开始支持。

ONNX 支持以下数据类型,用于图和节点的输入输出以及图的初始化器。

原始的数字、字符串和布尔类型必须用作张量的元素。

张量定义

张量是向量和矩阵的泛化;向量有一个维度,矩阵有两个维度,而张量可以有任意数量的维度,包括零维。零维张量在逻辑上等同于标量值。

在数学上,张量可以定义为一对序列/列表(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 的信息。

  • 嵌套列表不是具有零值维度的张量的完整表示。

张量元素类型

Types

描述

浮点类型

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位实部和虚部的复数。

Other

字符串

字符串表示文本数据。所有字符串都使用UTF-8编码。

Other

布尔

布尔值表示只有两个值的数据,通常为真和假。

输入 / 输出数据类型

以下类型用于定义图和节点的输入和输出类型。

变体

类型

描述

ONNX

密集张量

表示一个张量。参见上面的定义。

ONNX

sequence

序列是密集的、有序的、由同类型元素组成的集合。

ONNX

地图

映射是关联表,由键类型和值类型定义。

ONNX

可选的

Optionals 是可能包含张量、序列或映射类型元素的包装器,也可能是空的(不包含任何内容)。Details

静态张量形状

除了元素类型外,张量类型还有一个静态形状。张量变量的静态形状与张量值的运行时(动态)形状相关,但不同。静态张量形状是一个记录列表,指示张量是向量、矩阵还是更高维的值。例如,一个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;
  }

维度大小的空列表,[],是一个有效的张量形状,表示零维度(标量)值。零维度张量与未知维度的张量不同,后者由张量消息中缺少的“形状”属性表示。当值的类型(包括节点输入)中缺少形状属性时,表示相应的运行时值可能具有任何形状。本小节描述了如何解释缺少形状或缺少维度的形状等。然而,特定的使用上下文可能会对类型和形状施加进一步的限制。例如,模型(顶层图)的输入和输出需要具有形状,指示输入和输出的秩,即使不需要指定确切的维度。

列表中的每个大小可以表示为整数值或“维度变量”,即表示维度的实际大小不静态约束为特定数字的字符串。这对于声明关心维度数量但不关心每个维度的确切大小的接口非常有用。一个维度可能既没有设置dim_value也没有设置dim_param。这样的维度表示与其他未知维度无关的未知维度。

例如,一个NxM矩阵的形状列表为[N,M]。

每个维度变量的名称必须遵守C90标识符语法规则

目前,维度变量没有作用域。一个维度变量“N”在模型的整个图中代表相同的值。例如,如果图有两个输入X和Y,每个输入的形状为[“N”],那么在运行时,传递给X和Y的值必须是具有相同维度的1阶张量。目前,嵌套子图与主图共享相同的维度变量作用域。这使得模型能够将子图中张量的维度与外部图中张量的维度关联起来。

ONNX 支持诸如张量序列之类的类型。维度变量的全局作用域意味着,类型为“Sequence”的变量表示一个张量序列,这些张量都具有相同的形状。如果序列中所有张量的某个维度没有固定大小,则必须从上述类型中省略维度变量 M 或 N。如果序列中的不同张量可能具有不同的秩,则必须从类型中省略整个形状。

例如,执行矩阵叉积的图可以被定义为接受形状为 [K,M] 和 [M,N] 的两个输入,并生成形状为 [K,N] 的输出。

形状可以使用整数和变量的组合来定义。

历史记录: 以下扩展在早期被考虑过,但从未被实现或支持。

  • 使用空字符串(作为维度变量)来表示与任何其他维度无关的未知维度。这种做法已被弃用,转而使用既未设置dim_value也未设置dim_param的Dimension。

  • 使用字符串“*”(作为维度变量)来表示零个或多个未知基数的维度序列。这是不支持的。在当前实现中,形状中的维度数量必须表示张量的秩。未知秩的张量使用没有形状的TypeProto::Tensor对象表示,这是合法的。

  • 一种作用域机制,允许在子图(如循环体)中局部使用的维度变量可能很有用,但目前不支持。

  • ONNX 支持诸如张量序列之类的类型。对于类型本地的维度变量的作用域机制可能有助于区分以下两种类型:不同大小的方阵序列与相同大小的方阵序列。目前尚不支持此功能。

属性类型

用于属性的类型系统与用于输入和输出的类型系统相关,但略有不同。属性值可以是密集张量、稀疏张量、标量数值、字符串、图或上述类型之一的重复值。

其他元数据

ModelProto结构,以及在IR版本>=10中,各种其他结构(GraphProto、FunctionProto、NodeProto)包含一个metadata_props字段,允许用户以键值对的形式存储其他元数据。建议用户使用带有反向DNS名称作为前缀的键名(例如“ai.onnxruntime.key1”),以避免不同用途之间的冲突。未限定的名称可能在将来被ONNX标准使用。

其他规范文档

ONNX 规范由本文档组成,该文档定义了 IR 的语义和标准数据类型,以及定义标准运算符语义和 IR 语法的以下文档。后者被指定为 Protobuf v2 和 v3 模式文件。

有关更多详细信息,请参阅元数据类别文档

操作符

神经网络运算符

经典机器学习操作符

语法

ONNX 模型和图 - protobuf v2

ONNX 模型和图 - protobuf v3

ONNX-ML 模型和图 - protobuf v2

ONNX-ML 模型和图 - protobuf v3

ONNX 操作符集 - protobuf v2

ONNX 操作符集 - protobuf v3

ONNX-ML 操作符集 - protobuf v2

ONNX-ML 操作符集 - protobuf v3

版本控制约定和最佳实践

版本控制