CANN ops-math 算子详解:InvGrad 倒数反向梯度算子的实现原理与调用指南
CANN ops-math 算子详解InvGrad 倒数反向梯度算子的实现原理与调用指南【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-mathInvGrad 是 CANN ops-math 数学算子库中为Inv取倒数前向算子配套的反向梯度算子用于在 NPU 上完成y 1/x的梯度回传计算。本文以 math/inv_grad/README.md 为核心骨架结合 op_graph、op_host、op_kernel 与 op_kernel_aicpu 的源码实现完整介绍该算子的数学定义、参数约束、多产品支持情况、多核 Tiling 策略、按数据类型的计算路径分工以及图模式调用方法帮助开发者在反向传播中正确使用并深入理解该算子的底层机制。算子功能与数学原理InvGrad 算子计算Inv取倒数算子的反向梯度。设前向算子为Inv其前向输出为$$ x \frac{1}{\mathrm{original_x}} $$则 InvGrad 依据链式法则对原始输入original_x的梯度按下式计算$$ y_i -1 \cdot x_i \cdot x_i \cdot grad_i $$其中$x_i$ 为前向Inv算子的输出即 $1 / \mathrm{original_x}_i$$grad_i$ 为上游反向传播链中靠后一层传入的梯度$y_i$ 为最终输出即对原始输入 $\mathrm{original_x}_i$ 的梯度。该公式的推导非常直观前向函数 $f(t) 1/t$ 的导数为 $f(t) -1/t^2$。将前向输出 $x 1/t$ 代入可得 $f(t) -x^2$再乘以链式法则中的上游梯度 $grad$即得到 $y -x \cdot x \cdot grad$。这与 op_graph/inv_grad_proto.h 中的注释表述完全一致dx -1*dy*y*y, where y 1/x。从实现角度看整个计算被等价地分解为两次逐元素乘法和一次标量乘法Mul/Muls指令不涉及除法或取倒数运算因此具有很好的数值稳定性与向量化执行效率。产品支持情况InvGrad 算子已在当前 CANN 数学算子库中完成适配支持的硬件产品如下产品是否支持Ascend 950PR/Ascend 950DT√Atlas A3 训练系列产品/Atlas A3 推理系列产品√Atlas A2 训练系列产品/Atlas A2 推理系列产品√Atlas 200I/500 A2 推理产品√Atlas 推理系列产品√Atlas 训练系列产品√其中Ascend 950 系列产品走 AscendCAI Core加速路径对应源码目录 op_kernel/arch35其余产品由 AICPU 路径承接对应 op_kernel_aicpu两条路径共享同一套算子定义与形状推断逻辑保证行为一致。参数说明InvGrad 是一个无属性无 attr算子仅包含两个输入与一个输出参数详情如下表所示参数名输入/输出/属性描述数据类型数据格式x输入输入张量即前向 Inv 算子的输出FLOAT16, FLOAT32, BFLOAT16, INT32, INT8NDgrad输入对应的输入梯度FLOAT16, FLOAT32, BFLOAT16, INT32, INT8NDy输出输入张量 x 的导数梯度FLOAT16, FLOAT32, BFLOAT16, INT32, INT8ND从算子注册源码可以进一步确认这些约束的底层实现op_graph/inv_grad_proto.h 通过REG_OP(InvGrad)声明输入x、grad与输出y三者均限定为DT_FLOAT, DT_BF16, DT_FLOAT16, DT_INT32, DT_INT8五种类型op_host/inv_grad_def.cpp 中的 OpDef 注册将三个张量均标记为REQUIRED必选、FORMAT_ND并声明了UnknownShapeFormat与AutoContiguous()保证动态 shape 场景下也能正确推导该 OpDef 同时为 AI Core 路径配置了DynamicShapeSupportFlag(true)、DynamicRankSupportFlag(true)、DynamicCompileStaticFlag(true)等能力开关并关闭了PrecisionReduceFlag说明算子支持动态 shape 与动态 rank且不依赖精度降级开关详见 inv_grad_def.cpp。关于数据类型的实现细节需要特别说明的是不同数据类型的实际计算路径存在分工FLOAT32 / INT32在 AscendC AI Core 上以原生精度直接计算Mul(x, x) → Mul(grad, xx) → Muls(-1)见 arch35/inv_grad.hFLOAT16 / BFLOAT16在 AI Core 上先无损上行Cast至 FP32计算再以银行家舍入CAST_ROUND下行回原精度以获得更高计算精度见 arch35/inv_grad.hINT8算子接口层面支持但 arch35 上 AscendC 用户层 Cast API 不提供转 int8方向直接转换需寄存器级CastMicro编程因此 INT8 场景由 AICPU 路径承接见 arch35/inv_grad.h 的注释说明AICPU 路径除上述类型外还额外支持 DOUBLE、COMPLEX64、COMPLEX128见 op_kernel_aicpu/inv_grad_aicpu.cpp。约束说明根据算子 READMEInvGrad 无额外约束。但结合实现源码存在以下两点隐含约束值得使用者注意输入x与grad的数据类型必须一致。tiling 阶段与 AICPU 参数检查阶段都会校验二者 dtype 一致见 inv_grad_tiling_arch35.cpp 与 inv_grad_aicpu.cpp不一致时直接返回失败形状推断支持广播。AI Core 路径要求x与grad的存储 shape 完全一致见 inv_grad_tiling_arch35.cpp而 InferShape 阶段使用广播工具推断输出 shape见下节AICPU 路径则内置了广播计算分支。源码级实现原理1. 算子注册与 IR 定义算子 IR 定义位于 op_graph/inv_grad_proto.h兼容 TensorFlow 的InvGrad算子协议注释中明确标注Compatible with the TensorFlow operator InvGrad便于框架侧图转换与对接。同时 op_host/inv_grad_def.cpp 提供了新的 OpDef 注册二者共同完成算子在前端 IR 与后端执行调度两个层面的登记。2. 形状推断广播语义形状推断实现在 op_host/inv_grad_infershape.cpp直接调用Ops::Base::InferShape4Broadcast(context)完成x与grad的广播推断。这意味着当两个输入 shape 不一致时输出 shape 遵循 NumPy 广播规则取二者广播后的结果与前向Inv的广播行为保持一致。3. Tiling多核切分与 UB 分块Tiling 逻辑位于 op_host/arch35/inv_grad_tiling_arch35.cpp策略分两层多核切分将展平后的总元素数totalElements按 AI Core 数量均分blockFactor CeilDiv(totalElements, coreNum)并对blockFactor按 32 字节对齐元素数上按32/typeSize对齐最终通过context-SetBlockDim(usedCoreNum)启动实际使用的核数UB 分块每个核上按统一缓冲UB容量进一步切分单元素开销为bytesPerElem 3 * sizeof(T) 2 * sizeof(float)三个T队列x/grad/y加两个 FP32 中间缓冲区由此计算ubFactor并受单次搬运UINT16_MAX / typeSize上限约束见 inv_grad_tiling_arch35.cpp。最终 tiling 数据由三字段组成定义在 op_kernel/arch35/inv_grad_tiling_data.hstruct InvGradTilingData { int64_t totalElements 0; // 展平后的总元素数 int64_t blockFactor 0; // 每个 AI Core 处理的元素数 int64_t ubFactor 0; // 每次 UB 迭代处理的元素数 };4. AI Core Kernel三种计算路径Kernel 入口在 op_kernel/inv_grad_apt.cpp通过DTYPE_X宏按 dtype 实例化模板类NsInvGrad::InvGradT主循环在 arch35/inv_grad.h 中实现采用CopyIn → Compute → CopyOut的流水结构CopyIn使用DataCopyPad将x、grad从 Global Memory 搬运到 UB 队列Compute内部通过if constexpr按类型分发到三条路径见 arch35/inv_grad.hFLOAT32 原生路径xx x * xy grad * xxy -y三次向量指令完成全程 FP32INT32 原生路径同样三步复用tmpBuf1按 4 字节分配可同时承载 FP32 与 INT32 视图FLOAT16/BFLOAT16 路径先CastCAST_NONE无损上行 FP32 计算再CastCAST_ROUND银行家舍入下行回原精度CopyOut将结果写回 Global Memory。值得关注的是Compute直接以currentNum作为向量指令 count不再向上对齐到整块以避免对 UB 中未初始化区域做读运算以及非 32 字节对齐时Duplicate触发VEC_ERROR的问题见 arch35/inv_grad.h 的注释这体现了对 cpp-secure 规范与硬件边界条件的精细处理。5. AICPU 路径更宽的类型覆盖与广播支持AICPU 实现位于 op_kernel_aicpu/inv_grad_aicpu.cpp核心计算同样为output input1 * input1 * input2 * (-1)见SpecialComputeinv_grad_aicpu.cpp。其特点是数据类型覆盖 FP16、FP32、DOUBLE、COMPLEX64、COMPLEX128内置三种计算分支形状相同的NoBcastCompute、标量/单元素输入的特殊计算SpecialCompute以及形状不同的广播计算大数据量≥ 7×1024 元素时基于aicpu::CpuKernelUtils::GetCPUNum进行多 CPU 核并行切分超过 35×1024 元素时放开核数上限兼顾小数据量与大数据量的执行效率见 inv_grad_aicpu.cpp 与 inv_grad_aicpu.cpp。调用方式InvGrad 支持图模式调用即通过算子 IR 构图的方式在图中显式构造InvGrad节点。完整示例见 examples/test_geir_inv_grad.cpp核心构图流程如下通过op::Data创建输入占位节点placeholder并设置FORMAT_ND格式与对应 dtype 的 TensorDesc调用invGrad.set_input_x(...)、invGrad.set_input_grad(...)将两个输入接入算子节点将占位节点与InvGrad节点加入graph随后交由 GEGraph Engine构图、编译并下发执行。示例中还包含动态 shape 版本 examples/arch35/test_geir_inv_grad_dynamic.cpp展示了动态 shape 场景下的构图方式与算子 OpDef 中DynamicShapeSupportFlag(true)的能力声明相互印证。测试与验证仓库为该算子提供了覆盖各实现层的单元测试tests/ut/op_host/test_inv_grad_infershape.cpp验证形状推断含广播逻辑tests/ut/op_host/arch35/test_inv_grad_tiling_arch35.cpp验证 arch35 tiling 参数计算tests/ut/op_kernel_aicpu/test_inv_grad.cpp使用 gtest 框架覆盖 FP16 等多数据类型的 AICPU 计算正确性测试数据覆盖正数、负数、接近零值等典型输入见 test_inv_grad.cpp可用于回归验证算子行为。小结InvGrad 是Inv算子的反向配套算子数学定义简洁y -x²·grad却在工程实现上体现了完整的算子开发链路IR 定义proto→ OpDef 注册 → 广播形状推断 → 多核/UB 双层 Tiling → 按 dtype 分派的 AscendC 计算路径与 AICPU 兜底路径 → 单元测试闭环。理解该算子的实现有助于举一反三地掌握 CANN ops-math 库中其他逐元素反向算子的通用开发模式与性能优化思路。【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-math创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →