- 算子库
- 人工智能
- CANN
【免费下载链接】ops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
AddV2 是 CANN ops-math 数学算子库中用于执行逐元素加法的基础算子,兼容 TensorFlow AddV2 语义,支持广播与动态 shape。本文以 math/add_v2/README.md 为主体,结合仓库内算子原型(proto)、宿主侧定义(OpDef)、InferShape、Tiling 与 Kernel 源码,完整梳理 AddV2 的功能说明、参数规格、产品差异、广播规则,并给出基于算子 IR(GE 图模式)的可运行调用示例,帮助开发者在 Ascend 系列产品上正确使用与验证该算子。
一、算子功能与语义说明
1.1 功能概述
AddV2 对输入张量x1和x2执行逐元素加法,并将结果写入输出张量y,支持 NumPy 风格的广播(broadcast)语义,兼容 TensorFlow AddV2 图节点行为。
1.2 版本说明(V2 的含义)
名称中的 "V2" 仅用于对应 TensorFlow 的AddV2图节点,并不表示加法运算或广播规则发生了变化。在 AddV2 与 Add 共同支持的数据类型范围内,两者的数学语义一致;AddV2 的数据类型与调用通路以本文为准。
1.3 计算公式
$$ y_i = x_{1,i} + x_{2,i} $$
其中 $i$ 遍历广播结果的全部元素,$x_{1,i}$ 与 $x_{2,i}$ 表示广播后对应位置的元素。该逐元素语义在 Kernel 层由Vec::Add实现(见 math/add_v2/op_kernel/arch35/add_v2_dag.h),所有元素按同一规则并行计算。
1.4 广播规则与示例
广播时从末尾维度向前对齐,每组对应维度的长度必须相等,或至少有一路的维度长度为 1。仓库文档给出的典型示例:
x1 shape (3, 4), x2 shape (1, 4) -> y shape (3, 4) x1 shape (3, 1), x2 shape (1, 4) -> y shape (3, 4)从源码看,广播的 shape 推导由宿主侧 InferShape 统一完成。在 math/add_v2/op_host/add_v2_infershape.cpp 中,InferShapeAddV2直接调用Ops::Base::InferShape4Broadcast(context),即输出 shape 完全由通用广播推导工具计算,确保输出 shape 等于x1与x2按广播规则对齐后的 shape。单元测试 math/add_v2/tests/ut/op_host/test_add_v2_infershape.cpp 验证了(8, 8)与(1)广播得到(8, 8)的场景。
二、产品支持情况
根据仓库 README,AddV2 在以下产品上均获得支持:
| 产品 | 是否支持 |
|---|---|
| Ascend 950PR / Ascend 950DT | √ |
| Atlas A3 训练系列产品 / Atlas A3 推理系列产品 | √ |
| Atlas A2 训练系列产品 / Atlas A2 推理系列产品 | √ |
| Atlas 200I/500 A2 推理产品 | √ |
| Atlas 推理系列产品 | √ |
| Atlas 训练系列产品 | √ |
其中 Ascend 950 平台(架构代号 arch35)的宿主与 Kernel 实现均落在 math/add_v2/op_host/arch35/ 与 math/add_v2/op_kernel/arch35/ 目录下,并通过 math/add_v2/op_host/config/ascend950/add_v2_binary.json 配置每种数据类型的算子二进制文件(bin)。
三、参数说明
AddV2 共包含两个输入张量与一个输出张量,均为必选(REQUIRED),数据格式统一为 ND:
| 参数名 | 输入/输出/属性 | 描述 | 数据类型 | 数据格式 |
|---|---|---|---|---|
| x1 | 输入 | 加法运算的第一个输入张量,对应公式中的 x1 | BFLOAT16、FLOAT16、FLOAT、INT32、INT16、UINT8、INT8、INT64、COMPLEX64 | ND |
| x2 | 输入 | 加法运算的第二个输入张量,对应公式中的 x2。数据类型与 x1 一致 | BFLOAT16、FLOAT16、FLOAT、INT32、INT16、UINT8、INT8、INT64、COMPLEX64 | ND |
| y | 输出 | 加法运算的输出张量,对应公式中的 y。数据类型与 x1 一致,shape 为 x1 与 x2 的广播结果 | BFLOAT16、FLOAT16、FLOAT、INT32、INT16、UINT8、INT8、INT64、COMPLEX64 | ND |
3.1 参数约束的源码印证
- 数据类型一致性:算子原型 math/add_v2/op_graph/add_v2_proto.h 通过
REG_OP(AddV2)声明x1、x2、y三个端口,并限制为同 dtype 集合;同时宿主侧定义 math/add_v2/op_host/add_v2_def.cpp 为三个端口注册了完全相同的 9 组同 dtype 组合。 - 运行期校验:图推断阶段 math/add_v2/op_graph/add_v2_graph_infer.cpp 的
InferDataTypeAddV2会显式检查x1与x2dtype 是否相同,若不同则报错x1 and x2 must have the same dtype并返回失败;输出 dtype 直接继承x1。该算子不注册异类型组合,因此不做类型提升(type promotion)。 - 数据格式:所有端口统一声明为
FORMAT_ND,并标记AutoContiguous(),表示输入为连续排布的 ND 张量。
四、产品差异说明(重点)
不同产品在数据类型、动态 shape 能力与空 Tensor 支持上存在差异,使用时须严格对照下表:
| 产品 | 数据类型 | 静态 shape 能力 | 动态 shape 能力 | shape/rank 及空 Tensor 限制 |
|---|---|---|---|---|
| Ascend 950PR / Ascend 950DT | BFLOAT16、FLOAT16、FLOAT、INT32、INT16、UINT8、INT8、INT64、COMPLEX64 | 输入 ND → 输出 ND | 输入 ND → 输出 ND;支持固定 rank 动态 shape 和 dynamic rank | rank 取值范围为 [1, 8];支持空 Tensor,输出 y 的 shape 仍必须是两路输入的广播结果 |
| Atlas A3 训练系列 / A3 推理系列、Atlas A2 训练系列 / A2 推理系列 | BFLOAT16、FLOAT16、FLOAT、INT32、INT64 | 输入 ND → 输出 ND | 输入 ND → 输出 ND;支持固定 rank 动态 shape,不支持 dynamic rank | rank 取值范围为 [0, 8],rank 为 0 时表示标量;空 Tensor 仅支持两路输入 shape 相同,或其中一路输入为单元素张量的广播场景 |
| Atlas 200I/500 A2 推理产品、Atlas 推理系列、Atlas 训练系列 | FLOAT16、FLOAT、INT32、INT64 | 输入 ND → 输出 ND | 输入 ND → 输出 ND;支持固定 rank 动态 shape,不支持 dynamic rank | rank 取值范围为 [0, 8],rank 为 0 时表示标量;空 Tensor 仅支持两路输入 shape 相同,或其中一路输入为单元素张量的广播场景 |
4.1 差异的源码依据
- 数据类型注册差异:完整的 9 种 dtype(含 COMPLEX64、INT16、UINT8、INT8)注册在算子定义中,但不同产品实际支持范围不同。Tiling 侧的
IsSupportedDtype(见 math/add_v2/op_host/arch35/add_v2_tiling_arch35.cpp)对 arch35 平台校验DT_FLOAT16/DT_BF16/DT_FLOAT/DT_INT64/DT_COMPLEX64/DT_UINT8/DT_INT8/DT_INT32/DT_INT16,与 README 中 Ascend 950 的数据类型列一致;而其他产品按产品能力裁剪。 - rank 范围与 dynamic rank:Ascend 950 平台在 Tiling 中通过
CheckRank强制 rank 落在 [1, 8](见 math/add_v2/op_host/arch35/add_v2_tiling_arch35.cpp),且add_v2_def.cpp中aicoreConfig.DynamicRankSupportFlag(true)、DynamicShapeSupportFlag(true)分别开启 dynamic rank 与动态 shape 支持;而 Atlas A2/A3 等系列不支持 dynamic rank,仅支持固定 rank 动态 shape。 - 空 Tensor 支持:Ascend 950 平台专门为空 Tensor 设计了独立处理通路(详见下文第六节),因此支持范围更宽;其他产品仅允许两路输入 shape 相同或单元素广播这两种空 Tensor 场景。
五、调用说明:GE 图模式
AddV2 的调用方式如下表:
| 调用方式 | 调用样例 | 说明 |
|---|---|---|
| GE 图模式 | test_geir_add_v2.cpp | 通过算子 IR(add_v2_proto.h)构图方式调用 AddV2 算子 |
注意:本算子不提供同名 aclnn 接口,仅支持上表的 GE 图模式调用。这意味着用户无法通过
aclnnAddV2这类接口直接调用,必须经由 GE(Graph Engine)构图后在图上运行。
5.1 构图与运行流程
仓库示例 math/add_v2/examples/test_geir_add_v2.cpp 完整演示了 GE 图模式的调用步骤,核心流程为:
- 初始化 GE:通过
ge::GEInitialize(global_options)初始化 GE 全局环境,示例中使用{"ge.exec.deviceId", "0"}指定设备、{"ge.graphRunMode", "1"}指定图运行模式。 - 创建图与算子节点:
ge::Graph graph(graph_name)创建图,op::AddV2("add1")创建 AddV2 算子节点。 - 构造输入数据节点:使用
op::Data(...)构造占位输入节点,并通过ADD_INPUT宏为每个输入创建TensorDesc(shape、FORMAT_ND、dtype),调用GenOnesDataFloat32生成全 2 的浮点测试数据,最后通过add1.set_input_x1(...)/add1.set_input_x2(...)将输入节点接入 AddV2 算子。 - 设置图输入输出:
graph.SetInputs(inputs).SetOutputs(outputs)声明图的输入输出。 - 创建会话并建图:
new Session(build_options)创建会话,session->AddGraph(graph_id, graph, graph_options)将计算图加入会话。 - 运行图:
session->RunGraph(graph_id, input, output)执行计算。 - 保存结果:
SaveInputOutput将输入/输出张量以 bin 文件落盘,并逐元素打印输出结果。 - 资源清理:删除会话并调用
ge::GEFinalize()结束 GE 环境。
其中示例默认使用{4, 2}的输入 shape(std::vector<int64_t> xShape = {4, 2};),即两路4x2张量相加,输出同样为4x2。关键代码片段:
auto add1 = op::AddV2("add1"); std::vector<int64_t> xShape = {4, 2}; ADD_INPUT(1, x1, inDtype, xShape); ADD_INPUT(2, x2, inDtype, xShape); outputs.push_back(add1);ADD_INPUT宏内部会完成占位节点、TensorDesc(FORMAT_ND+ dtype)、测试数据生成、set_input_xN接线等全部工作,是理解 GE 图模式入参构造的关键入口。
5.2 图模式下的算子端口与校验链路
在 GE 图模式下,AddV2 的端口契约由算子 IR 原型 math/add_v2/op_graph/add_v2_proto.h 声明,构图后经过以下链路完成推导与校验:
- InferDataType(add_v2_graph_infer.cpp):校验
x1、x2同 dtype,并将y的 dtype 置为x1的 dtype。 - InferShape(add_v2_infershape.cpp):调用
InferShape4Broadcast计算广播后的输出 shape。 - OpDef 定义(add_v2_def.cpp):声明端口 dtype/format 集合与 AICore 配置(开启动态 shape、dynamic rank、精度降低标志等)。
- Tiling(add_v2_tiling_arch35.cpp):根据实际 shape、dtype 与编译信息生成切分策略。
六、源码级实现原理(以 Ascend 950 / arch35 为例)
6.1 Kernel 入口与模板分派
Kernel 入口位于 math/add_v2/op_kernel/arch35/add_v2.cpp,采用模板参数schMode(调度模式)与userDef(用户自定义分支开关)做编译期分派:
userDef == 1:空 Tensor 通路。由于输出元素个数为 0,无任何数据需要搬运,Kernel 直接返回;Tiling 侧已把blockDim设为 1。- 否则按 dtype 选择计算 DAG:浮点类 dtype(
half/bfloat16_t/float)走AddWithCastCompute,其余类型走AddWithoutCastCompute,再统一交给BroadcastSch<schMode, OpDag> sch(tiling)完成广播调度。
6.2 计算 DAG 设计
在 math/add_v2/op_kernel/arch35/add_v2_dag.h 中定义了两种计算图(DAG):
- AddWithoutCastCompute(免精度转换通路):
CopyInBrc(广播搬入)→Vec::Add<T>(逐元素加)→CopyOut(写回),适用于整型等可直接相加的 dtype。 - AddWithCastCompute(精度转换通路):先将输入
Cast到float做加法,再把结果Cast回原 dtype(CAST_RINT_MODE使用就近取整),适用于half/bfloat16_t/float类型,对应PrecisionReduceFlag(true)的配置。
两个 DAG 均使用MemOptCfg<MemLevel::LEVEL_2>进行二级内存(L2)级的访存优化,并由DAGSch统一调度。
6.3 空 Tensor 专用通路
空 Tensor 场景在 math/add_v2/op_kernel/arch35/add_v2_struct_arch35.h 中被专门处理:常规广播通路使用 schMode 取值表(1、2、101…999 等)中的普通模式,而空 Tensor 走自定义schMode = 999+userDef = 1的模板分支。原因在于 ATVOSS 的BroadcastBaseTiling在合轴后会显式拒绝 0 元素("tensor check is empty"),因此空 Tensor 必须复用该自定义分支;Tiling 侧对应定义ADD_V2_SCH_MODE_EMPTY = 999、ADD_V2_USER_DEF_EMPTY = 1(见 add_v2_tiling_arch35.cpp)。
单元测试 math/add_v2/tests/ut/op_host/arch35/test_add_v2_tiling.cpp 对该分支给出了精确注释:空 Tensor 分支的 tiling key 为65550 = 0x1000E,其低 16 位0x000E = 14是 schMode 999 在取值表中的序号,第 16 位userDef = 1;常规通路userDef = 0,key 仍为 8,不受影响。
七、约束说明与使用建议
- 仓库 README 明确 AddV2 的约束说明为无("约束说明:无"),但这仅指算子层面的通用约束;实际使用时仍需遵守上文第四节产品差异表中的产品级限制(数据类型范围、rank 范围、dynamic rank 支持度、空 Tensor 场景等)。
- 输入
x1、x2必须同 dtype,输出y的 dtype 与x1一致,shape 为广播结果。 - 由于本算子不提供 aclnn 接口,涉及动态 shape 或 dynamic rank 的图模式调用,建议在 test_add_v2_tiling.cpp 与 test_add_v2_infershape.cpp 中选取对应的 shape 组合先做宿主侧单测验证,再上板运行。
八、验证与测试参考
仓库为 AddV2 提供了完整的宿主侧单元测试,可用于验证 shape 推导与 tiling 逻辑:
- InferShape 单测:math/add_v2/tests/ut/op_host/test_add_v2_infershape.cpp 覆盖了同 shape 相加(
(8,8)+(8,8)->(8,8))、广播相加((8,8)+(1)->(8,8))以及动态 shape 等场景。 - Tiling 单测:math/add_v2/tests/ut/op_host/arch35/test_add_v2_tiling.cpp 使用
TilingContextFaker/TilingCaseExecutor构造DT_FLOAT等 dtype、8x8等 shape 的 tiling 上下文,并验证空 Tensor 分支的 tiling key(65550)等关键数值。
结合这些测试与上文的源码链路,开发者可以在修改 shape、dtype 或产品形态后快速回归验证 AddV2 的广播推导与切分策略是否符合预期。
- 算子库
- 人工智能
- CANN
【免费下载链接】ops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
相关推荐
CANN ops-math ClipByValue 算子深度解析:功能、参数、GE IR 图模式调用与源码实现
CANN ops math ClipByValue 算子深度解析:功能、参数、GE IR 图模式调用与源码实现 ClipByValue(裁剪取值)是 CANN
算子库人工智能CANNCANN ops-math MatrixDiagPart 算子深度解析:功能、约束与 GE 图模式调用实战
CANN ops math MatrixDiagPart 算子深度解析:功能、约束与 GE 图模式调用实战 MatrixDiagPart 是 CANN ops
算子库人工智能CANNCANN ops-math 算子解读:AsStrided 张量视图算子(as_strided)功能、参数与 GE 图模式调用实战
CANN ops math 算子解读:AsStrided 张量视图算子(as_strided)功能、参数与 GE 图模式调用实战 AsStrided(as_st
算子库人工智能CANN
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考