
算子库人工智能CANN【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址https://gitcode.com/cann/ops-math点击查看免费下载aclnnGroupedBiasAddGrad 是 CANN ops-math 数学算子库中 GroupedBiasAdd分组偏置加法算子的反向传播接口用于对分组通道的偏置梯度进行归约求和。本文以 math/grouped_bias_add_grad/docs/aclnnGroupedBiasAddGrad.md 为主体结合仓库内 op_api、op_host、op_kernel 各层源码完整讲解该接口的功能语义、两段式调用流程、参数约束、返回码与可复用的完整调用示例帮助读者在 Atlas 系列训练/推理产品上快速接入该反向算子。产品支持情况GroupedBiasAddGrad 算子的设备支持情况如下与 算子 README 中的支持矩阵一致产品是否支持Ascend 950PR / Ascend 950DT支持Atlas A3 训练系列产品 / Atlas A3 推理系列产品支持Atlas A2 训练系列产品 / Atlas A2 推理系列产品支持Atlas 200I/500 A2 推理产品不支持Atlas 推理系列产品不支持Atlas 训练系列产品不支持从算子定义文件 grouped_bias_add_grad_def.cpp 可以看到该算子通过OpAICoreConfig为ascend910b、ascend910_93、ascend950、ascend350注册了 AICore 配置与上表支持的平台一一对应其中 950/350 平台走grouped_bias_add_grad_apt算子文件其余平台走默认 aicore 配置。功能说明接口定位该接口完成 GroupedBiasAdd 的反向计算将反向传播梯度 gradY 按分组进行行方向归约求和得到 bias 的梯度 out。本接口的扩展接口是 aclnnGroupedBiasAddGradV2V2 版本在参数基础上额外暴露了可选属性groupIdxType见下文分组语义。计算公式1有可选输入 groupIdxOptional 时$$ out(G,H) \begin{cases} \sum_{igroupIdxOptional(j-1)}^{groupIdxOptional(j)} gradY(i, H), 1 \leq j \leq G-1 \ \sum_{i0}^{groupIdxOptional(j)} gradY(i, H), j 0 \end{cases} $$其中gradY 共 2 维H 表示 gradY 最后一维的大小G 表示 groupIdxOptional 第 0 维的大小即 groupIdxOptional 有 G 个数groupIdxOptional(j) 表示第 j 个数的大小计算后 out 为 2 维shape 为 (G, H)。2无可选输入 groupIdxOptional 时$$ out(G, H) \sum_{i0}^{C} gradY(G, i, H) $$其中gradY 共 3 维G、C、H 依次表示 gradY 第 0-2 维的大小计算后 out 为 2 维shape 为 (G, H)。该场景等价于将每一组共 G 组每组 C 行内的行全部累加输出第 j 行对应第 j 组内所有行的求和结果。分组语义groupIdxType本接口 aclnnGroupedBiasAddGrad 在无groupIdxType参数时固定按结束索引语义groupIdxType 0解释 groupIdxOptionalgroupIdxOptional(j)是第 j 组的结束位置索引数组需递增且末元素等于 gradY 第 0 维大小。其扩展接口 aclnnGroupedBiasAddGradV2 通过属性groupIdxType支持两种语义见 grouped_bias_add_grad_def.cpp 中Attr(group_idx_type).AttrType(OPTIONAL).Int(0)的默认定义0groupIdxOptional 中的值为每个 group 的结束索引1groupIdxOptional 中的值为每个 group 的大小需先累加得到结束索引且总和必须等于 gradY 第 0 维大小。该属性在 op_api 层经 aclnn_grouped_bias_add_grad.cpp 的checkAttrValid校验取值只能为 0 或 1非法取值返回ACLNN_ERR_PARAM_INVALID。示例1有可选输入 groupIdxOptional 时gradY 的 shape 为 (1000, 30)groupIdxOptional 为 (400, 600, 1000)将 gradY 分为 3 组每组累加的行数依次为 400、200、400计算后 out 的 shape 为 (3, 30)。2无可选输入 groupIdxOptional 时gradY 的 shape 为 (10, 100, 30)将 gradY 分为 10 组每组累加的行数均为 100计算后 out 的 shape 为 (10, 30)。函数原型两段式接口每个算子分为两段式接口必须先调用aclnnGroupedBiasAddGradGetWorkspaceSize接口获取计算所需 workspace 大小以及包含了算子计算流程的执行器再调用aclnnGroupedBiasAddGrad接口执行计算。aclnnStatus aclnnGroupedBiasAddGradGetWorkspaceSize( const aclTensor* gradY, const aclTensor* groupIdxOptional, aclTensor* out, uint64_t* workspaceSize, aclOpExecutor** executor)aclnnStatus aclnnGroupedBiasAddGrad( void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream)两段式接口的实际流程在 aclnn_grouped_bias_add_grad.cpp 中体现第一段ExecGroupedBiasAddGradGetWorkspaceSize完成参数检查、构建算子执行图含非连续 Tensor 的连续化处理并通过uniqueExecutor-GetWorkspaceSize()返回 workspace 大小第二段aclnnGroupedBiasAddGrad通过CommonOpExecutorRun框架能力真正在指定 Stream 上驱动计算。aclnnGroupedBiasAddGradGetWorkspaceSize 参数说明参数表参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续TensorgradYaclTensor*输入反向传播梯度公式中的 gradY。有可选输入 groupIdxOptional 时shape 仅支持 2 维无可选输入 groupIdxOptional 时shape 仅支持 3 维。FLOAT、FLOAT16、BFLOAT16ND2-3√groupIdxOptionalaclTensor*输入每个分组结束位置公式中的 groupIdxOptional。只支持一维INT32、INT64ND1√outaclTensor*输出bias 的梯度公式中的 out。数据类型必须与 gradY 的数据类型一致shape 仅支持 2 维。如果输入为三维 (G, C, H)则输出 shape 为 (G, H)如果输入为二维 (GB, H)、group_idx 为 (G)则输出 shape 为 (G, H)。FLOAT、FLOAT16、BFLOAT16ND2√workspaceSizeuint64_t*输出返回需要在 Device 侧申请的 workspace 大小。-----executoraclOpExecutor**输出返回 op 执行器包含了算子计算流程。-----关于非连续 Tensor可参考 non_contiguous_tensor.md 了解其在 aclnn 接口中的通用语义。源码中的参数校验逻辑第一段接口的入参校验集中封装在CheckParams中aclnn_grouped_bias_add_grad.cpp依次执行空指针检查CheckNotNullgradY、out 为空时返回ACLNN_ERR_PARAM_NULLPTR数据类型检查CheckDtypeValidgradY/out 必须属于 {FLOAT16, FLOAT, BF16} 且二者一致groupIdxOptional 必须属于 {INT32, INT64}对应源码中的group_bias_in_out_dtype_list与group_idx_dtype_listshape 检查CheckShapeValid无 groupIdxOptional 时 gradY 必须为 3 维有 groupIdxOptional 时 gradY 必须为 2 维且 groupIdxOptional 必须为 1 维groupIdxOptional 第 0 维组数不得超过 2048out 必须为 2 维且 shape 精确等于推导出的 (G, H)属性检查checkAttrValidgroupIdxType 必须为 0 或 1格式告警CheckFormatNZ若输入为 FRACTAL_NZ 格式仅打印告警提示可能存在精度风险不阻断执行。图模式下同样的约束由 grouped_bias_add_grad_infershape.cpp 的GroupedBiasAddGradInferShape在 shape 推导阶段强制检查其中MAX_GROUP_NUM 2048与 op_api 层一致。返回值aclnnStatus返回状态码具体参见 aclnn返回码。第一段接口完成入参校验出现以下场景时报错返回码错误码描述ACLNN_ERR_PARAM_NULLPTR161001传入的 gradY、out 是空指针时。ACLNN_ERR_PARAM_INVALID161002gradY 或 out 的数据类型/维度不在支持的范围内。ACLNN_ERR_PARAM_INVALID161002gradY、groupIdxOptional、out 的维度关系不匹配。ACLNN_ERR_PARAM_INVALID161002group 组数超过 2048。说明op_api 层还有ACLNN_ERR_INNER_CREATE_EXECUTOR、ACLNN_ERR_INNER_NULLPTR等内部错误码分别对应 executor 创建失败与非连续化处理、l0 算子调用过程中的内部空指针场景见 aclnn_grouped_bias_add_grad.cpp。aclnnGroupedBiasAddGrad 参数说明参数表参数名输入/输出描述workspace输入在 Device 侧申请的 workspace 内存地址。workspaceSize输入在 Device 侧申请的 workspace 大小由第一段接口 aclnnGroupedBiasAddGradGetWorkspaceSize 获取。executor输入op 执行器包含了算子计算流程。stream输入指定执行任务的 Stream。返回值aclnnStatus返回状态码具体参见 aclnn返回码。约束说明确定性计算aclnnGroupedBiasAddGrad 默认确定性实现即相同输入在多次执行中产生一致结果。可进一步参考 determinism_compute.md 了解 CANN 算子确定性计算的通用约定。groupIdxOptional 最大支持 2048 个数对应源码中 op_api 层INPUT_MAX_GROUP、infershape 层MAX_GROUP_NUM均为 2048。有可选输入 groupIdxOptional 时需要保证 Tensor 数据是递增排列且最后一个数值需要等于 gradY 第 0 维的大小groupIdxType 0 语义下。有可选输入 groupIdxOptional 时需要保证 Tensor 数值不超过 INT32 最大值并且是非负数。使用 V2 接口且 groupIdxType 1 时需确保 groupIdxOptional 总和等于 gradY 第 0 维大小见 README。调用示例示例代码如下仅供参考具体编译和执行过程请参考编译与运行样例。仓库内还提供了可直接对照的完整样例 examples/test_aclnn_grouped_bias_add_grad.cpp 与配套的 op_api 单测 tests/ut/op_api/test_aclnn_grouped_bias_add_grad.cpp。#include iostream #include vector #include acl/acl.h #include aclnnop/aclnn_grouped_bias_add_grad.h #define CHECK_RET(cond, return_expr) \ do { \ if (!(cond)) { \ return_expr; \ } \ } while (0) #define LOG_PRINT(message, ...) \ do { \ printf(message, ##__VA_ARGS__); \ } while (0) int64_t GetShapeSize(const std::vectorint64_t shape) { int64_t shape_size 1; for (auto i : shape) { shape_size * i; } return shape_size; } int Init(int32_t deviceId, aclrtStream* stream) { // 固定写法资源初始化 auto ret aclInit(nullptr); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclInit failed. ERROR: %d\n, ret); return ret); ret aclrtSetDevice(deviceId); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtSetDevice failed. ERROR: %d\n, ret); return ret); ret aclrtCreateStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtCreateStream failed. ERROR: %d\n, ret); return ret); return 0; } template typename T int CreateAclTensor(const std::vectorT hostData, const std::vectorint64_t shape, void** deviceAddr, aclDataType dataType, aclTensor** tensor) { auto size GetShapeSize(shape) * sizeof(T); // 调用aclrtMalloc申请device侧内存 auto ret aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtMalloc failed. ERROR: %d\n, ret); return ret); // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 ret aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtMemcpy failed. ERROR: %d\n, ret); return ret); // 计算连续tensor的strides std::vectorint64_t strides(shape.size(), 1); for (int64_t i shape.size() - 2; i 0; i--) { strides[i] shape[i 1] * strides[i 1]; } // 调用aclCreateTensor接口创建aclTensor *tensor aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); return 0; } int main() { // 1.固定写法device/stream初始化参考acl API手册 // 根据自己的实际device填写deviceId int32_t deviceId 0; aclrtStream stream; auto ret Init(deviceId, stream); // check根据自己的需要处理 CHECK_RET(ret 0, LOG_PRINT(Init acl failed. ERROR: %d\n, ret); return ret); // 2. 构造输入与输出需要根据API的接口自定义构造 std::vectorint64_t gradYShape {40, 10}; std::vectorint64_t groupIdxShape {4}; std::vectorint64_t outShape {4, 10}; void* gradYDeviceAddr nullptr; void* groupIdxDeviceAddr nullptr; void* outDeviceAddr nullptr; aclTensor* gradY nullptr; aclTensor* groupIdx nullptr; aclTensor* out nullptr; std::vectorfloat gradYHostData(400, 1.0); std::vectorint32_t groupIdxHostData {5, 15, 30, 40}; std::vectorfloat outHostData(40, 0.0); // 创建gradY aclTensor ret CreateAclTensor(gradYHostData, gradYShape, gradYDeviceAddr, aclDataType::ACL_FLOAT, gradY); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建groupIdxOptional aclTensor ret CreateAclTensor(groupIdxHostData, groupIdxShape, groupIdxDeviceAddr, aclDataType::ACL_INT32, groupIdx); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建out aclTensor ret CreateAclTensor(outHostData, outShape, outDeviceAddr, aclDataType::ACL_FLOAT, out); CHECK_RET(ret ACL_SUCCESS, return ret); // 3. 调用CANN算子库API需要修改为具体的API uint64_t workspaceSize 0; aclOpExecutor* executor; // 调用aclnnGroupedBiasAddGrad第一段接口 ret aclnnGroupedBiasAddGradGetWorkspaceSize(gradY, groupIdx, out, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnGroupedBiasAddGradGetWorkspaceSize failed. ERROR: %d\n, ret); return ret); // 根据第一段接口计算出的workspaceSize申请device内存 void* workspaceAddr nullptr; if (workspaceSize 0) { ret aclrtMalloc(workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(allocate workspace failed. ERROR: %d\n, ret); return ret); } // 调用aclnnGroupedBiasAddGrad第二段接口 ret aclnnGroupedBiasAddGrad(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnGroupedBiasAddGrad failed. ERROR: %d\n, ret); return ret); // 4.固定写法同步等待任务执行结束 ret aclrtSynchronizeStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtSynchronizeStream failed. ERROR: %d\n, ret); return ret); // 5. 获取输出的值将device侧内存上的结果拷贝至host侧需要根据具体API的接口定义修改 auto size GetShapeSize(outShape); std::vectorfloat resultData(size, 0); ret aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(copy result from device to host failed. ERROR: %d\n, ret); return ret); for (int64_t i 0; i size; i) { LOG_PRINT(result[%ld] is: %f\n, i, resultData[i]); } // 6. 释放aclTensor需要根据具体API的接口定义修改 aclDestroyTensor(gradY); aclDestroyTensor(groupIdx); aclDestroyTensor(out); // 7. 释放device资源需要根据具体API的接口定义修改 aclrtFree(groupIdxDeviceAddr); aclrtFree(outDeviceAddr); aclrtFree(gradYDeviceAddr); if (workspaceSize 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }代码执行路径说明示例中 gradY shape 为 (40, 10)groupIdxOptional 为 (5, 15, 30, 40)即 4 组各组合并行数依次为 5、10、15、10输出 out shape 为 (4, 10)每一列的值等于对应分组内各行的累加结果。源码级实现原理输出 shape 的自动推导l0 算子实现 op_api/grouped_bias_add_grad.cpp 展示了输出张量的推导规则有 groupIdxOptional 时outShape (groupIdxOptional 第 0 维大小, gradY 最后一维大小)无 groupIdxOptional 时outShape (gradY 第 0 维大小, gradY 最后一维大小)输出张量由executor-AllocTensor按 gradY 的数据类型与 ND 格式自动分配随后通过ADD_TO_LAUNCHER_LIST_AICORE将输入、输出与groupIdxType属性注册到算子启动流程中。这也解释了为什么调用方传入的 out 必须与推导结果严格一致——op_api 层CheckShapeValid与 host 层CheckOutput会双重校验。非连续 Tensor 的处理虽然参数表标注 gradY、groupIdxOptional、out 均支持非连续 Tensor但实际计算在连续内存上完成aclnn_grouped_bias_add_grad.cppgradY 与 groupIdxOptional 先经l0op::Contiguous转为连续张量空指针 groupIdxOptional 跳过计算得到连续的 gradBias 后若出参 out 本身非连续再经l0op::ViewCopy把结果写回 out 的视图空 TensorgradY-IsEmpty()场景直接返回当前 executor 的 workspace 大小不进入实际计算。算子定义与平台注册grouped_bias_add_grad_def.cpp 定义了算子的 IR 形态输入grad_y必选、group_idx可选、输出grad_bias属性group_idx_type可选默认 0并声明了支持动态 shape、动态 rank、编译期静态 flag 等能力。Graph 模式的调用方式可参考 examples/test_geir_grouped_bias_add_grad.cpp 与算子 IR 定义 op_graph/grouped_bias_add_grad_proto.h。Tiling 切分策略Host 侧 tiling 实现arch22/grouped_bias_add_grad_tiling.cpp按是否有 groupIdx 走不同模板无 groupIdxgradY 3 维C 等长按baseC对 C 维循环切分loopCNum ceil(dimC / baseC)每个循环单位对应一份 workspace有 groupIdx 且组间大小不等按baseC对 GB 维切分并根据 G 的规模、H 与核数的比例关系判断是否进入高性能模板performance 1双核协作处理一组dimGB INT32_MAX为前提workspace 大小由PostTiling统一计算WORKSPACE_BASE_CAL wsUnitNum * H_BASE_SIZE * usedCoreNum。最终通过GetTilingKey将数据类型、是否使用 groupIdx、是否高性能模板、groupIdx 的 INT32/INT64 类型、是否使用 UB 求和等维度编码为 tiling keyKernel 入口op_kernel/grouped_bias_add_grad.cpp据此分发到GroupedBiasAddGradEqualCC 等长、GroupedBiasAddGradUnequalCC 不等长、GroupedBiasAddGradUnequalCPerf高性能等不同模板实例执行模板实现位于 op_kernel/arch22 目录下。测试与验证仓库为该算子提供了多级验证手段ST 场景tests/st/aclnnGroupedBiasAddGrad 下的 atk 测试用例配置与 executor 脚本以及 arch35/ttk_kernel_grouped_bias_add_grad_st.csvUT 单测tests/ut/op_api/test_aclnn_grouped_bias_add_grad.cpp、tests/ut/op_host/arch22/test_grouped_bias_add_grad_infershape.cpp 等覆盖 infershape、tiling 与 kernel 计算数据生成tests/ut/op_kernel/grouped_bias_add_grad_data 下的gen_data.py、gen_tiling.py与compare_data.py用于构造测试数据与比对 goldengolden.py定义了参考实现。小结aclnnGroupedBiasAddGrad 是 ops-math 中结构清晰、约束明确的一类分组归约反向算子通过两段式 aclnn 接口完成 workspace 探测与异步执行以可选 groupIdxOptional 覆盖分组结束索引与分组大小两种语义后者由 V2 扩展接口提供并在 op_api、infershape、tiling、kernel 各层落实了完整的数据类型、shape、组数与确定性约束校验。开发者可直接复用上文完整示例代码并参照 编译与运行样例 在支持的 Atlas 产品上完成编译与验证。赞分享算子库人工智能CANN【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址https://gitcode.com/cann/ops-math点击查看免费下载相关推荐CANN ops-nn 算子详解SwigluGroupQuantGrad 分组量化 SwiGLU 反向接口 swiglu_group_quant_backward 使用指南CANN ops nn 算子详解 SwigluGroupQuantGrad 分组量化 SwiGLU 反向接口 swiglu_group_quant_backw人工智能算子库深度学习CANNAscendCANN ops-math 算子剖析aclnnCdistBackward 两段式接口与 CdistGrad 反向算子完整解读CANN ops math 算子剖析aclnnCdistBackward 两段式接口与 CdistGrad 反向算子完整解读 本文以 CANN 数学算子库 o算子库人工智能CANNCANN ops-math 算子接口详解aclnnBitwiseXorScalar 与 aclnnInplaceBitwiseXorScalar 使用指南CANN ops math 算子接口详解aclnnBitwiseXorScalar 与 aclnnInplaceBitwiseXorScalar 使用指南 本算子库人工智能CANN创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考