ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

CANN ops-nn 中 aclnnSmoothL1LossBackward 反向算子深度解析:两段式接口、参数约束与 NPU 实现原理

CANN ops-nn 中 aclnnSmoothL1LossBackward 反向算子深度解析:两段式接口、参数约束与 NPU 实现原理 人工智能算子库深度学习CANNAscend【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址https://gitcode.com/cann/ops-nn点击查看免费下载SmoothL1LossHuber Loss是目标检测、回归任务中常用的损失函数其反向计算是训练链路中不可或缺的一环。本文以 CANN ops-nn 开源仓库中 smooth_l1_loss_grad_v2 算子目录 下的核心接口文档 aclnnSmoothL1LossBackward.md 为主线完整讲解aclnnSmoothL1LossBackward的功能定位、数学原理、两段式调用范式、逐参数约束、错误码语义并结合仓库源码ACLNN 封装层、L0 算子、Tiling 逻辑、DAG 内核与测试用例剖析其在 NPU 上的真实实现链路。读完本文你将能够独立完成该算子的参数构造、Workspace 申请与两段式调用并理解其确定性计算与 Broadcast 推导机制。一、算子定位SmoothL1Loss 的反向传播接口1.1 功能说明aclnnSmoothL1LossBackward是 CANN 神经网络算子库中SmoothL1Loss 前向算子 aclnnSmoothL1Loss 的反向传播接口。前向接口负责计算 SmoothL1 损失本身而本接口根据上游传入的损失梯度gradOut计算出对输入self预测值 x的梯度供自动微分/反向训练使用。前向算子aclnnSmoothL1Loss.md中 SmoothL1Loss 的定义为Batch 为 Nreduction为 none 时$$ \ell(self,target) L {l_1,\dots,l_N}^\top,\quad l_n \begin{cases} 0.5(self_n-target_n)^2/beta, if\ |self_n-target_n| beta \ |self_n-target_n| - 0.5*beta, otherwise \end{cases} $$当reduction为mean或sum时分别取mean(L)或sum(L)。反向接口的职责正是对上述表达式关于 x 求导并乘以上游梯度。1.2 产品支持情况依据 接口文档 与目录 README.md 中的产品支持声明该算子的硬件支持矩阵如下产品是否支持Ascend 950PR / Ascend 950DT支持Atlas A3 训练系列产品 / Atlas A3 推理系列产品支持Atlas A2 训练系列产品 / Atlas A2 推理系列产品支持Atlas 200I/500 A2 推理产品不支持Atlas 推理系列产品支持Atlas 训练系列产品支持二、数学原理分段求导与符号函数反向传播通过对前向表达式关于 x 求导得到。接口文档给出了两种情况的导数情况一$|x-y| 1$处于 L2 平滑区间$$ \frac{\partial SmoothL1Loss(x,y)}{\partial x} x - y $$情况二$|x-y| \geq 1$处于 L1 线性区间$$ \frac{\partial SmoothL1Loss(x,y)}{\partial x} sign(x - y) $$其中 $sign(x)$ 为符号函数$$ sign(x) \begin{cases} 1, if\ x0 \ 0, if\ x0 \ -1, if\ x0 \end{cases} $$说明文档中的公式以 beta 缺省值 1.0 展示。实际算子以属性beta图编译阶段记为sigma为分段阈值——当 $|x-y|beta$ 时梯度为 $(x-y)/beta$否则为 $sign(x-y)$。这一通用化处理在 Tiling 与内核代码中有明确体现见下文。三、函数原型与两段式接口调用范式与 CANN 其他算子一致aclnnSmoothL1LossBackward采用两段式接口可参见 两段式接口说明第一段aclnnSmoothL1LossBackwardGetWorkspaceSize完成入参校验、构建算子计算流程并返回计算所需的 workspace 大小与执行器第二段aclnnSmoothL1LossBackward使用第一段返回的 workspace 与执行器在指定 stream 上真正执行计算。aclnnStatus aclnnSmoothL1LossBackwardGetWorkspaceSize( const aclTensor* gradOut, // 上游梯度Loss 值 const aclTensor* self, // 预测值 x const aclTensor* target, // 标签 y int64_t reduction, // 缩减方式 0/1/2 float beta, // L1/L2 分界阈值 aclTensor* gradInput, // 输出对 x 的梯度 uint64_t* workspaceSize, aclOpExecutor** executor)aclnnStatus aclnnSmoothL1LossBackward( void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)两段接口的声明与实现位于 op_api/aclnn_smooth_l1_loss_backward.cpp 与 op_api/aclnn_smooth_l1_loss_backward.h。从源码看第二段接口的实现非常轻量直接调用框架能力完成计算aclnnStatus aclnnSmoothL1LossBackward(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream) { L2_DFX_PHASE_2(aclnnSmoothL1LossBackward); return CommonOpExecutorRun(workspace, workspaceSize, executor, stream); }四、第一段接口参数详解4.1 参数表GetWorkspaceSize依据接口文档各参数定义与约束如下参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续TensorgradOutaclTensor*输入梯度反向输入公式中的 SmoothL1Lossshape 需与 self、target 满足 broadcast 关系dtype 与二者满足数据类型推导规则FLOAT、FLOAT16、BFLOAT16ND1-8√selfaclTensor*输入输入张量公式中的 xshape 需与 gradOut、target 满足 broadcast 关系dtype 与二者满足推导规则FLOAT、FLOAT16、BFLOAT16ND1-8√targetaclTensor*输入真实标签公式中的 yshape 需与 gradOut、self 满足 broadcast 关系dtype 与二者满足推导规则FLOAT、FLOAT16、BFLOAT16ND1-8√reductionint64_t输入指定应用到输出的缩减支持 0(none)/1(mean)/2(sum)none 不缩减mean 输出总和除以元素数sum 输出求和INT64--√betafloat输入L1 与 L2 损失之间的分界值该值必须非负FLOAT---gradInputaclTensor*输出计算输出对 x 的梯度shape 为 gradOut、self、target 的 broadcast 结果FLOAT、FLOAT16、BFLOAT16ND1-8√workspaceSizeuint64_t*输出需在 Device 侧申请的 workspace 大小-----executoraclOpExecutor**输出包含算子计算流程的执行器-----几个关键点的补充说明数据类型推导Promote规则三个输入gradOut、self、target不必强制同 dtype但需满足互推导规则参见 互推导关系。推导出的公共类型必须落在算子支持列表内且最终能转换为输出gradInput的 dtype。源码在 CheckPromoteType 中通过op::PromoteType逐步两两合并完成推导。Broadcast 约束三输入 shape 两两必须可广播且广播结果 shape 必须与预分配的输出gradInput完全相等。该检查实现在CheckShapeBroadcast中先对 gradOut 与 self 做BroadcastInferShape再与 target 合并最后与输出 shape 逐维比较。ND 格式与多平台 dtype 差异所有 Tensor 均要求 ND 格式从 acl nn 封装层源码 可见Ascend 910 平台支持列表为 FLOAT/FLOAT16Ascend 910B 及以上平台A2/A3/950额外支持 BF16与文档中 BFLOAT16、FLOAT16、FLOAT32 的支持声明一致。非连续 Tensor三个输入与输出均支持非连续 Tensor。封装层会先通过l0op::Contiguous将输入规整为连续 Tensor计算完成后若输出为非连续再通过l0op::ViewCopy将结果写回原视图见 aclnn_smooth_l1_loss_backward.cpp 第 209-252 行。4.2 空 Tensor 与确定性约束源码中还有两个容易被忽略的细节空 Tensor 快速返回当gradOut、self、target任一为空 Tensor 时第一段接口直接返回workspaceSize 0并释放执行器不进入实际计算aclnn_smooth_l1_loss_backward.cpp 第 203-207 行。确定性计算文档明确说明aclnnSmoothL1LossBackward默认采用确定性实现即相同输入在同一平台上的计算结果可复现这对调试与精度对齐具有重要意义。4.3 返回值与错误码第一段接口完成入参校验返回aclnnStatus状态码完整状态码定义参见 aclnn 返回码。出现以下场景时报错返回值错误码描述ACLNN_ERR_PARAM_NULLPTR161001传入的 self、target、gradOut 或 gradInput 为空指针ACLNN_ERR_PARAM_INVALID161002self、target、gradOut 或 gradInput 的数据类型不在支持范围内ACLNN_ERR_PARAM_INVALID161002self、target、gradOut 或 gradInput 的 shape 不符合约束ACLNN_ERR_PARAM_INVALID161002reduction 不符合约束ACLNN_ERR_PARAM_INVALID161002self、target、gradOut 的 shape 不满足参数说明中的要求Broadcast 失败或与输出 shape 不一致这些校验逻辑与源码一一对应CheckNotNull检查空指针、CheckDtypeValid检查 dtype 支持列表、CheckShape检查维度数上限MAX_SUPPORT_DIMS_NUMS对应文档中的 1-8 维、CheckReduction检查 reduction ∈ [0,2]、CheckBeta检查 beta ≥ 0均在 aclnn_smooth_l1_loss_backward.cpp 的CheckParams中按序执行。五、第二段接口参数说明参数名输入/输出描述workspace输入在 Device 侧申请的 workspace 内存地址workspaceSize输入在 Device 侧申请的 workspace 大小由第一段接口获取executor输入op 执行器包含算子计算流程stream输入指定执行任务的 Stream第二段接口同样返回aclnnStatus状态码。六、源码级实现原理从 ACLNN 到 AiCore 内核的完整调用链接口文档之外仓库源码清晰呈现了该算子的完整实现链路可以分为四层。6.1 ACLNN 封装层contiguous、cast 与 l0 算子编排op_api/aclnn_smooth_l1_loss_backward.cpp 中aclnnSmoothL1LossBackwardGetWorkspaceSize的执行流程为创建OpExecutor执行参数校验空指针 → dtype → shape → reduction → beta做 dtype Promote 推导与 shape Broadcast 推导空 Tensor 快速返回对三个输入依次做Contiguous非连续转连续与Cast转 Promote 类型通过CheckReformat将 format 统一为 ND调用 l0 算子l0op::SmoothL1LossGradV2(selfCasted, targetCasted, gradOutputCasted, REDUCTION_STR[reduction], beta, resultShape, executor)完成核心计算将结果Cast回gradInput的数据类型若输出非连续则做ViewCopy回写通过uniqueExecutor-GetWorkspaceSize()返回 workspace 大小。其中reduction的 int64 枚举值会通过REDUCTION_STR[] {none, mean, sum}映射为字符串属性见 aclnn_smooth_l1_loss_backward.cpp 第 31-33 行。6.2 L0 算子层任务下发op_api/smooth_l1_loss_grad_v2.cpp 中l0op::SmoothL1LossGradV2通过executor-AllocTensor按 broadcast 后的outputShape与self的 dtype 分配输出gradInput随后调用ADD_TO_LAUNCHER_LIST_AICORE(SmoothL1LossGradV2, OP_INPUT(self, target, gradOut), OP_OUTPUT(gradInput), OP_ATTR(beta, reduction.c_str()))将 AiCore 算子加入任务队列。注释同时说明SmoothL1LossGradV2 暂无 AICPU 分支即该算子只走 NPU AiCore 执行路径。6.3 算子定义与 Tiling动态 shape、mean 系数与 sigmaop_host/smooth_l1_loss_grad_v2_def.cpp 中注册了SmoothL1LossGradV2的算子定义三个输入predict、label、dout与输出gradient均为 REQUIRED数据类型支持ge::DT_BF16、ge::DT_FLOAT16、ge::DT_FLOAT格式为 ND属性sigma即接口层的 betaOPTIONAL默认 1.0与reductionOPTIONAL默认 meanAICore 配置开启动态编译DynamicCompileStaticFlag、动态 rank、动态 shape 支持PrecisionReduceFlag(false)表明不做精度削减与文档“确定性实现”约束吻合。op_host/arch35/smooth_l1_loss_grad_v2_tiling.cpp 则展示了 Tiling 阶段的关键逻辑dtype 一致性校验predict、label、dout、gradient四者 dtype 必须一致否则报错GetShapeAttrsInfomean 缩减系数当 reduction 为 mean 时CalcReduceMeanCof会遍历 predict 的 storage shape 计算元素总数并求出reduceMeanCof 1/元素数同时校验 reduction 取值必须为 none/sum/mean 三者之一且 mean 模式下输入不能为空 Tensorsigma 预处理CalcSigma读取sigmabeta属性要求非负并预计算出negSigma -sigma与invertSigma 1/sigmasigma 接近 0 时为 NAN供内核直接使用dout 标量识别GetDoutIsScalar判断dout是否为标量storage shape 为标量或 size 为 1从而选择 Scalar DAG 还是 Tensor DAG 的内核模板。6.4 AiCore 内核DAG 算子图op_kernel/arch35/smooth_l1_loss_grad_v2_dag.h 以 DAG有向无环算子图方式描述内核计算注释给出了与接口文档等价的通用公式norm 1 x predict - label if x -sigma: return -norm * dout else if x sigma: return norm * dout else: return norm * x * dout / sigma图中各节点依次完成CopyInBrc带广播的搬入→Cast到 float 中间精度 →Sub求差 →Abs求绝对值 →Compare与 ±sigma 比较→Select分段选择 →Add合并 →Mul乘 dout→Muls乘 norm 系数 reduceMeanCof→Cast回原 dtype →CopyOut写出。其中 norm 即 Tiling 阶段算出的reduceMeanCofmean 时为 1/Nnone/sum 时为 1。Scalar DAG 变体在 dout 为标量时用Duplicate展开标量避免无谓的向量搬入。内核入口 op_kernel/smooth_l1_loss_grad_v2.cpp 根据编译期模板参数doutIsScalar与schMode选择对应的 DAG 实例并通过Ops::Base::BroadcastSchschMode, OpDag调度执行完成 predict/label/dout 三路广播输入到输出 y 的计算。七、调用示例完整可运行的 aclnn 样例接口文档提供了完整的 C 调用示例examples/arch35/test_aclnn_smooth_l1_loss_backward.cpp 亦含同款样例核心流程如下初始化aclInit→aclrtSetDevice(deviceId)→aclrtCreateStream构造张量通过aclrtMallocaclrtMemcpy将 host 数据拷入 device用aclCreateTensor创建 ND 格式的aclTensorshape 为{4, 2}类型ACL_FLOAT示例中reduction 0none、beta 1.0两段式调用先调aclnnSmoothL1LossBackwardGetWorkspaceSize获取 workspaceSize 与 executor若workspaceSize 0则aclrtMalloc申请 workspace再调aclnnSmoothL1LossBackward(workspaceAddr, workspaceSize, executor, stream)同步与取数aclrtSynchronizeStream等待任务结束将gradInput从 device 拷回 host 并打印result[i]资源释放依次aclDestroyTensor、aclrtFree各 device 内存与 workspace、aclrtDestroyStream、aclrtResetDevice、aclFinalize。文档给出的核心代码片段缩略展示关键路径完整可运行代码见 接口文档 或 示例文件#include acl/acl.h #include aclnnop/aclnn_smooth_l1_loss_backward.h // ... Init(deviceId, stream) 与 CreateAclTensor(...) 见文档/示例 int64_t reduction 0; float beta 1.0; // 构造 gradOutput/self/target/gradInput 四个 aclTensorshape {4,2}ACL_FLOAT uint64_t workspaceSize 0; aclOpExecutor* executor; // 第一段接口获取 workspace 大小与执行器 ret aclnnSmoothL1LossBackwardGetWorkspaceSize(gradOutput, self, target, reduction, beta, gradInput, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, return ret); // 根据 workspaceSize 申请 device 内存 void* workspaceAddr nullptr; if (workspaceSize 0) { ret aclrtMalloc(workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret ACL_SUCCESS, return ret); } // 第二段接口执行计算 ret aclnnSmoothL1LossBackward(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret ACL_SUCCESS, return ret); // 同步、拷贝结果至 host 并打印 result[i] ret aclrtSynchronizeStream(stream); // ... aclrtMemcpy(resultData.data(), ..., gradInputDeviceAddr, ..., ACL_MEMCPY_DEVICE_TO_HOST)具体编译与运行方式可参考仓库文档 编译与运行样例。该算子头文件为aclnnop/aclnn_smooth_l1_loss_backward.h可运行样例存放于 examples/arch35。八、测试与精度验证仓库内可复现的验证手段仓库为反向算子提供了多层级测试可作为接入与精度验证的参考ST系统测试tests/st/aclnnSmoothL1LossBackward/executor_aclnnSmoothL1LossBackward.py 使用 PyTorch 作为基准torch.nn.SmoothL1Loss(reductionreduction, betabeta)前向后调用y.backward(gradOut)取self.grad作为期望梯度与 NPU 计算结果对齐同目录下的atk_aclnnSmoothL1LossBackward.json定义了输入用例含gradOut/self/target/reduction/beta参数组合tests/st/arch35/ttk_kernel_smooth_l1_loss_grad_v2_st.csv 覆盖内核级 ST 用例。UT单元测试tests/ut/op_api/test_aclnn_smooth_l1_loss_backward_l2.cpp 覆盖 API 层调用tests/ut/op_host/test_smooth_l1_loss_grad_v2_infershape.cpp 验证 shape 推导tests/ut/op_host/arch35/test_smooth_l1_loss_grad_v2_tiling.cpp 覆盖 Tiling 逻辑含 dout 标量/张量、mean 系数、sigma 边界等场景。此外op_host/config/ascend950/smooth_l1_loss_grad_v2_binary.json 提供了 ascend950 平台的算子二进制配置反映该算子在最新平台上的编译注册方式。九、使用建议与注意事项结合文档约束与源码实现实际使用时建议关注以下要点reduction 与 mean 语义reduction1mean时最终梯度会乘以1/NN 为 predict 的元素总数见 smooth_l1_loss_grad_v2_tiling.cpp 的CalcReduceMeanCof且 mean 模式下 predict 不允许为空 Tensor。none/sum 模式下 norm 系数为 1。beta 必须非负接口层与 Tiling 层均对 betasigma做非负校验beta 过小会导致invertSigma趋向无穷内核中按 NAN 处理属于边界场景需谨慎使用。输入输出 dtype 一致性Tiling 阶段要求 predict、label、dout、gradient 四者 dtype 完全一致接口层则允许三输入通过 Promote 推导出公共类型后参与计算最终输出会 Cast 回gradInput的声明 dtype——因此建议上层调用时让四者的 dtype 保持一致避免不必要的隐式转换。输出 shape 预分配gradInput的 shape 必须恰好等于三输入 Broadcast 后的结果否则第一段接口返回ACLNN_ERR_PARAM_INVALID161002。确定性保证算子默认确定性实现可在多轮训练/推理中稳定复现但这也意味着不会启用精度削减类优化。综上aclnnSmoothL1LossBackward是 CANN ops-nn 中一个结构完整、约束清晰、实现链路可追溯的反向损失算子。无论是直接通过两段式 aclnn 接口调用还是参考其 ACLNN 封装、Tiling 与 DAG 内核实现来理解 CANN 算子开发范式本文所述的文档要点与源码佐证均可作为可靠的技术依据。赞分享人工智能算子库深度学习CANNAscend【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址https://gitcode.com/cann/ops-nn点击查看免费下载相关推荐CANN ops-nn aclnnIndexFillTensor/aclnnInplaceIndexFillTensor 算子指南两段式接口、参数约束与 NPU 实现原理CANN ops nn aclnnIndexFillTensor/aclnnInplaceIndexFillTensor 算子指南两段式接口、参数约束与 NP人工智能算子库深度学习CANNAscendCANN ops-nn aclnnGluBackward 算子深度解析GLU 反向传播的两段式接口、参数约束与 NPU 计算路径CANN ops nn aclnnGluBackward 算子深度解析GLU 反向传播的两段式接口、参数约束与 NPU 计算路径 导读 aclnnGluBac人工智能算子库深度学习CANNAscendCANN ops-nn aclnnScatterMul 算子全解析两段式接口、参数约束与 NPU 内核实现CANN ops nn aclnnScatterMul 算子全解析两段式接口、参数约束与 NPU 内核实现 aclnnScatterMul 是 CANN op人工智能算子库深度学习CANNAscend创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表