算子IR注册
简介
算子的原型(即IR)用于进行算子的描述,包括算子输入输出信息,属性信息等,用于把算子注册到算子原型库中。
算子的IR注册需要在算子的工程目录的/op_proto/算子名称.h 文件中进行实现。
下面详细讲解如何进行算子IR定义头文件的实现。
IR 注册头文件实现
- 宏定义。
使用如下语句进行算子IR注册宏的定义,宏名称固定为GE_OP_OPERATORTYPE_H,OPERATORTYPE为使用REG_OP(OpType)语句中OpType的大写。
#ifndef GE_OP_OPERATORTYPE_H //条件编译 #define GE_OP_OPERATORTYPE_H //进行宏定义
- 包含头文件。
在算子IR实现文件的头部使用预编译命令“#include”将算子注册的头文件包含到算子IR实现的文件中。
#include "graph/operator_reg.h"
operator_reg.h存在于CANN软件安装后文件存储路径的“include/graph/”路径下,包含此头文件,可使用算子类型注册相关的函数、宏、结构体等。
- 原型注册。
Graph Engine(GE)提供REG_OP宏,以“.”链接INPUT、OUTPUT、ATTR等接口注册算子的输入、输出和属性信息,最终以OP_END_FACTORY_REG接口结束,完成算子的注册。
注册代码实现如下所示:
namespace ge{ REG_OP(OpType) //算子类型名称 .INPUT(x1, TensorType({ DT_FLOAT, DT_INT32 })) .INPUT(x2, TensorType({ DT_FLOAT, DT_INT32 })) // .OPTIONAL_INPUT(b, TensorType{DT_FLOAT}) // .DYNAMIC_INPUT(x, TensorType{DT_FLOAT, DT_INT32}) .OUTPUT(y, TensorType({ DT_FLOAT, DT_INT32 })) // .DYNAMIC_OUTPUT(y, TensorType{DT_FLOAT, DT_INT32}) .ATTR(x, Type, DefaultValue) // .REQUIRED_ATTR(x, Type) // .GRAPH(z1) // .DYNAMIC_GRAPH(z2) .OP_END_FACTORY_REG(OpType) }
- 注册算子类型
REG_OP(OpType)
OpType:注册到昇腾AI处理器的自定义算子库的算子类型,可以任意命名但不能和已有的算子命名冲突。
- 注册算子输入
算子输入包括三种类型:必选输入,可选输入,动态多输入(指算子的输入个数不固定),每一个输入都需要根据自身实际类型选择如下三种注册方式的一种进行注册。
表1 输入注册 输入类型
注册方式与描述
必选输入
INPUT(x1, TensorType({ DT_FLOAT,DT_UINT8,... }))
功能说明:
注册算子的必选输入信息。
- x:宏参数,算子的输入名称,用户自定义。
- TensorType({ DT_FLOAT,DT_UINT8,... }):“{ }”中为此输入支持的数据类型的列表,支持的数据类型请参见DataType,TensorType提供了一些接口指定支持的数据类型,详细定义请参见TensorType。
若算子有多个必选输入,每个输入需要使用一条INPUT(x, TensorType({ DT_FLOAT,DT_UINT8,... }))语句进行描述。
可选输入
OPTIONAL_INPUT(x, TensorType{DT_FLOAT, ...})
功能说明:
若算子输入为可选输入,可使用此接口进行算子输入的注册。- x:宏参数,算子输入的名称。
- TensorType{DT_FLOAT, ...}:“{ }”中为此输入支持的数据类型的列表,支持的数据类型请参见DataType,TensorType提供了一些接口指定支持的数据类型,详细定义请参见TensorType。
动态多输入
DYNAMIC_INPUT(x, TensorType{DT_FLOAT, DT_INT32, ...})
功能说明:
算子为动态多输入场景下的输入信息注册。动态多输入指算子的输入个数不固定,具体的输入个数是在算子运行时才能确定的,例如AddN算子。- x:宏参数,算子的输入名称,图运行时,会根据输入的个数自动生成x0、x1、x2……,序号依次递增。
.DYNAMIC_INPUT(x, TensorType::NumberType()
- TensorType({ DT_FLOAT,DT_UINT8,... }):“{ }”中为此输入支持的数据类型的列表,支持的数据类型请参见DataType,TensorType提供了一些接口指定支持的数据类型,详细定义请参见TensorType。
- 注册算子输出
算子输出包括两种类型:必选输出与动态多输出(指算子的输出个数不固定),每一个输出都需要根据自身实际类型选择如下两种注册方式的一种进行注册。
表2 输出注册 输出类型
注册方式与描述
必选输出
OUTPUT(y, TensorType({ DT_FLOAT,DT_UINT8,... }))
功能说明:
注册算子的输出信息。- y:宏参数,算子的输出名称,用户自定义。
- TensorType({ DT_FLOAT,DT_UINT8,... }):“{ }”中为此输出支持的数据类型的列表,支持的数据类型请参见DataType,TensorType提供了一些接口指定支持的数据类型,详细定义请参见TensorType。
若算子有多个必选输出,每个输出需要使用一条OUTPUT(x, TensorType({ DT_FLOAT,DT_UINT8,... }))语句进行注册。
动态多输出
DYNAMIC_OUTPUT(y, TensorType{DT_FLOAT, DT_INT32})
功能说明:
算子为动态多输出场景下的输出信息注册。- y:宏参数,算子的输出名称,图运行时,会根据输出的个数自动生成y0、y1、y2……,序号依次递增。
- TensorType({ DT_FLOAT,DT_UINT8,... }):“{ }”中为此输出支持的数据类型的列表,支持的数据类型请参见DataType,TensorType提供了一些接口指定支持的数据类型,详细定义请参见TensorType。
- 注册算子属性
算子属性包括两种类型:必选属性与可选属性,每一个属性都需要根据自身实际类型选择如下两种注册方式的一种进行注册。
表3 属性注册 属性类型
注册方式与描述
可选属性
ATTR(x, Type, DefaultValue)
功能说明:
注册算子的可选属性,包括算子的属性名称,属性类型以及属性值的默认值,当开发者不设置算子对象的属性值时需要使用默认值。ATTR接口中Type的取值与对应的属性类型请参见原型定义接口(REG_OP)。
例如:ATTR(mode, Int, 1),注册属性mode,属性类型为int64_t,默认值为1。
若算子有多个可选属性,每个可选属性都需要使用一条ATTR(x, Type, DefaultValue)语句进行注册。
必选属性
REQUIRED_ATTR(x, Type)
功能说明:
注册算子的必选属性,包括算子的属性名称与属性类型,无默认值,开发者必须设置算子对象的属性值。此接口中Type的取值与对应的属性类型请参见原型定义接口(REG_OP)。
若算子有多个必选属性,每个必选属性需要使用一条REQUIRED_ATTR(x, Type)语句进行注册。
- 注册算子包含的子图信息
若算子为一个大算子,里面包含多个小算子,即为小算子组成的子图,则需要进行子图注册。子图注册一般用于控制类算子(分支算子/循环算子等),子图包含静态子图与动态子图两种类型,开发者可根据自身实际类型选择如下两种注册方式的一种进行注册。
表4 子图注册 子图类型
注册方式与描述
静态算子子图
GRAPH(z1)
功能说明:
注册算子中包含的子图信息,输入z1为子图名称,一般用于控制类算子(分支算子/循环算子等)。
注册完成后,会自动生成子图相关的接口,用户获取子图名称、获取子图描述信息、设置子图描述信息等,具体接口可参见GRAPH,用户可使用生成的相关接口进行IR模型的构建。对于同一个算子,注册的算子子图名称需要保持唯一。
动态算子子图
DYNAMIC_GRAPH(z2)
功能说明:
注册动态算子子图信息,输入z2为子图名称,一般用于控制类算子(分支算子/循环算子等)。
注册完成后,会自动生成动态算子子图的相关接口,用于创建动态子图、设置子图描述信息等,具体接口可参见DYNAMIC_GRAPH,用户可使用生成的相关接口进行IR模型的构建。对于同一个算子,注册的算子子图名称需要保持唯一。
- 结束算子注册。
OP_END_FACTORY_REG(OpType)
OpType与REG_OP(OpType)中的OpType保持一致。
- 注册算子类型
- 结束条件编译。
#endif