- 人工智能
- 算子库
- 深度学习
- CANN
- Ascend
【免费下载链接】ops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
GaussianNllLossGrad 是 CANN ops-nn 神经网络算子库中 GaussianNLLLoss 损失函数的反向算子,用于在 NPU(Atlas A2 训练系列产品 / Atlas 800I A2 推理产品)上同时计算损失对均值预测input与方差var的梯度。本文以 关联文档 为骨架,结合仓库内的算子定义、tiling 与 kernel 源码及测试用例,深入讲解其数学公式、广播与规约语义、ACLNN 两段式调用方式、约束条件与本地编译验证方法,帮助读者既能在业务中正确调用该算子,也能从源码层面理解其实现机制。
产品支持情况与定位
GaussianNllLossGrad 属于实验目录(experimental/loss)下的反向算子,产品支持情况如下:
| 产品 | 是否支持 |
|---|---|
| Atlas A2 训练系列产品/Atlas 800I A2 推理产品 | √ |
从仓库结构看,该算子位于 experimental/loss/gaussian_nll_loss_grad 目录,与同目录下其他算子一致,采用标准的四段式工程结构:docs(接口文档)、examples(ACLNN 调用样例)、op_host(算子定义、shape 推导与 tiling)、op_kernel(AscendC 核函数实现)、tests(UT 测试)。算子注册使用的 AICore 配置为ascend910b(见 gaussian_nll_loss_grad_def.cpp),与文档所述 Atlas A2 系列平台对应。
功能说明:梯度数学原理
GaussianNLLLoss 的前向损失为负对数高斯似然,其反向算子 GaussianNllLossGrad 计算损失对input(均值预测)和var(方差)的梯度,不计算对target的梯度。设d = input - target、v = max(var, eps),则每个逻辑元素的梯度为:
gradInput = gradOutput * d / v gradVar = gradOutput * 0.5 * (1 / v - d² / v²)几个关键语义点:
reduction="mean"时两项梯度额外乘以1/N,其中N为input的逻辑元素数;reduction与gradOutput的关系:"sum"与"mean"接收单元素标量gradOutput(上游已聚合的标量梯度),"none"接收与input同 shape 的逐元素梯度;var广播时的归约:当var以广播形式参与计算时,gradVar需要把每个广播维度上的贡献求和,归约回原始varshape 输出;full仅保持前后向接口一致:该属性对应前向中“是否包含完整高斯常数项”的开关,但不影响梯度计算结果;- 低精度转 FLOAT 计算:FLOAT16 与 BFLOAT16 输入会先转换为 FLOAT 参与运算,结果再转换回输入 dtype 输出,以保证数值精度。
上述公式在 op_kernel/gaussian_nll_loss_grad.h 中可直接验证:ComputeGradInput(第 193–208 行)依次执行Sub(input, target)得到d、Maxs(var, eps)得到v、Div(d, v)再Mul(gradOutput),与gradInput = gradOutput * d / v完全对应;ComputeGradVar(第 210–235 行)则先计算d² / v²与1 / v的差,再乘gradOutput与0.5,与gradVar公式一致。
参数说明
算子的完整参数定义见 gaussian_nll_loss_grad_def.cpp,其中 4 个输入、3 个属性与 2 个输出的数据类型、格式与 shape 规格如下:
| 参数名 | 输入/输出/属性 | 描述 | 数据类型 | 数据格式 | Shape 规格 |
|---|---|---|---|---|---|
| gradOutput | 输入 | 上游梯度。 | FLOAT、FLOAT16、BFLOAT16 | ND | none时与input相同;sum/mean时为单元素标量。 |
| input | 输入 | Gaussian 分布均值预测。 | 与gradOutput相同 | ND | 任意维静态 shape。 |
| target | 输入 | 目标值。 | 与gradOutput相同 | ND | 与input相同,或同 rank 且恰有一个广播维为 1。 |
| var | 输入 | 方差。 | 与gradOutput相同 | ND | 与input相同、最后一维为 1、缺少最后一维,或单元素标量。 |
| full | 属性 | 是否包含完整高斯常数项;不影响梯度。默认false。 | BOOL | - | - |
| eps | 属性 | 方差下限。默认1e-6。 | FLOAT | - | 必须大于 0。 |
| reduction | 属性 | 规约方式,默认"mean"。 | STRING | - | "none"、"mean"或"sum"。 |
| gradInput | 输出 | 对input的梯度。 | 与gradOutput相同 | ND | 与input相同。 |
| gradVar | 输出 | 对var的梯度;广播贡献已归约。 | 与gradOutput相同 | ND | 与var相同。 |
在算子定义源码中,四个输入与两个输出均声明为REQUIRED,数据类型限定为{ge::DT_FLOAT, ge::DT_FLOAT16, ge::DT_BF16},格式限定为FORMAT_ND;三个属性full(默认false)、eps(默认1e-6)、reduction(默认"mean")均为 OPTIONAL。所有输入输出均标记了AutoContiguous(),保证 NPU 侧按连续内存访问。
广播语义的源码级分类
target与var的广播形式在 tiling 阶段被精确分类并编码进 tiling 数据,见 gaussian_nll_loss_grad_tiling.cpp:
target分类(ClassifyTarget,第 73–102 行):仅允许两种形式——与input完全同 shape(BROADCAST_NONE),或同 rank 且恰有一个维度为 1(BROADCAST_TARGET_AXIS,记录广播轴大小targetAxisSize与该轴之后的内侧步长targetInnerStride);var分类(ClassifyVar,第 117–151 行):支持四种形式——与input同 shape(VAR_SAME)、最后一维为 1(VAR_LAST_DIM_ONE)、缺少最后一维即前缀匹配(VAR_MISSING_LAST_DIM)、单元素标量(VAR_SCALAR),并记录每个var元素对应的归约规模varReduceSize。
对应地,tiling 数据结构 gaussian_nll_loss_grad_tiling_data.h 中保存了targetBroadcastMode、targetBroadcastAxisSize、targetInnerStride、varBroadcastMode、varReduceSize等字段。该分类逻辑在 UT test_gaussian_nll_loss_grad_tiling.cpp 中通过 4 组典型 case(同 shape、target 单维广播、var 缺末维、var 标量)逐一断言验证。
约束说明
结合 README.md 与 aclnnGaussianNllLossGrad.md 的约束章节,使用该算子需满足:
- 仅支持 Atlas A2 平台、ND 数据格式,以及 FLOAT、FLOAT16、BFLOAT16 三种数据类型;
- 所有输入与输出的 dtype 必须一致;实现不创建 dtype-only tiling key(即同一 tiling 逻辑复用于三种 dtype,计算前统一转 FLOAT);
target仅允许同 shape,或在一个维度上从 1 广播到input;var仅允许同 shape、最后一维为 1、缺少最后一维或单元素标量;eps必须大于 0;var的值约束为非负;- clamp(
v = max(var, eps))对梯度透明:即使var < eps,gradVar仍按 clamp 后的v参与公式计算; full不改变gradInput或gradVar的任何结果;- 空
input不产生gradInput元素;存在单元素var时(广播到空 input 之外),gradVar为 0; "none"时gradOutput必须与input同 shape,"sum"/"mean"时gradOutput必须为单元素标量;- 输出
gradInput、gradVar分别严格匹配input与var的 shape;动态未知维在 tiling 前必须具体化。
这些校验在 tiling 阶段全部落地:ValidateDtypes(tiling 源码)检查所有输入输出 dtype 一致且属于受支持集合;ClassifyTarget/ClassifyVar校验广播合法性;eps <= 0、reduction非法字符串、gradOutput shape 与 reduction 不匹配等均返回GRAPH_FAILED并记录错误日志(第 216–242 行)。
调用说明
当前仓库对该算子提供ACLNN 调用(两段式接口),暂不提供 GE 与 PyTorch 直接调用方式。
| 调用方式 | 调用样例 | 说明 |
|---|---|---|
| ACLNN 调用 | 接口文档、样例 | 两段式接口。 |
| GE | - | 暂不提供。 |
| PyTorch | - | 暂不提供。 |
两段式接口与函数原型
ACLNN 采用与 CANN 其他算子一致的两段式调用模式(详见 两段式接口说明):先调用aclnnGaussianNllLossGradGetWorkspaceSize完成算子准备并获取 workspace 大小与执行器,再调用aclnnGaussianNllLossGrad真正执行计算。
aclnnStatus aclnnGaussianNllLossGradGetWorkspaceSize( const aclTensor* gradOutput, const aclTensor* input, const aclTensor* target, const aclTensor* var, bool full, float eps, const char* reduction, aclTensor* gradInput, aclTensor* gradVar, uint64_t* workspaceSize, aclOpExecutor** executor) aclnnStatus aclnnGaussianNllLossGrad( void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream)第一段接口各参数的详细说明(来自 aclnnGaussianNllLossGrad.md):
| 参数名 | 输入/输出 | 描述 | 使用说明 | 数据类型 | 数据格式 | 维度(shape) |
|---|---|---|---|---|---|---|
| gradOutput(aclTensor*) | 输入 | 上游梯度。 | 非空;dtype 与其他张量一致。 | FLOAT、FLOAT16、BFLOAT16 | ND | none 时与 input 相同;sum/mean 时单元素。 |
| input(aclTensor*) | 输入 | 均值预测。 | 非空指针。 | FLOAT、FLOAT16、BFLOAT16 | ND | 任意维静态 shape。 |
| target(aclTensor*) | 输入 | 目标值。 | 非空;可按一个 size-1 维广播。 | FLOAT、FLOAT16、BFLOAT16 | ND | 同 input,或同 rank 且一个维度为 1。 |
| var(aclTensor*) | 输入 | 非负方差。 | 非空;支持限定广播。 | FLOAT、FLOAT16、BFLOAT16 | ND | 同 input、最后一维为 1、缺少最后一维或单元素。 |
| full(bool) | 输入 | 保留的前向一致性属性。 | 不影响梯度;默认 false。 | BOOL | - | - |
| eps(float) | 输入 | 方差下限。 | 必须大于 0;默认 1e-6。 | FLOAT | - | - |
| reduction(char*) | 输入 | 规约模式。 | none、sum 或 mean;默认 mean。 | STRING | - | - |
| gradInput(aclTensor*) | 输出 | input 梯度。 | 非空;dtype 与 gradOutput 一致。 | FLOAT、FLOAT16、BFLOAT16 | ND | 与 input 相同。 |
| gradVar(aclTensor*) | 输出 | var 梯度。 | 非空;dtype 与 gradOutput 一致。 | FLOAT、FLOAT16、BFLOAT16 | ND | 与 var 相同。 |
| workspaceSize(uint64_t*) | 输出 | 返回 Device workspace 大小。 | - | - | - | - |
| executor(aclOpExecutor**) | 输出 | 返回 op 执行器。 | - | - | - | - |
第二段接口参数:workspace(Device workspace 地址,输入)、workspaceSize(由第一段接口获取,输入)、executor(第一段接口返回的执行器,输入)、stream(执行任务的 Stream,输入)。
返回值:aclnnStatus状态码,具体含义参见 aclnn 返回码说明。输入为空指针、dtype 不一致、shape/广播不合法、eps <= 0或reduction非法时,第一段接口返回错误。
需要特别说明的是:虽然该算子当前实现不申请用户 workspace(tiling 中workspace[0] = 0,见 gaussian_nll_loss_grad_tiling.cpp),但框架仍按两段式接口返回实际 workspace 大小,调用方应统一按workspaceSize分配并传入(样例代码对workspaceSize > 0才执行aclrtMalloc)。
最小调用示例
仓库提供的完整可运行样例见 test_aclnn_gaussian_nll_loss_grad.cpp,其核心调用片段如下(full=true、eps=1e-6、reduction="none"):
uint64_t workspaceSize = 0; aclOpExecutor* executor = nullptr; aclnnStatus ret = aclnnGaussianNllLossGradGetWorkspaceSize( gradOutput, input, target, var, false, 1e-6f, "mean", gradInput, gradVar, &workspaceSize, &executor); if (ret == ACL_SUCCESS) { ret = aclnnGaussianNllLossGrad(workspace, workspaceSize, executor, stream); }样例的运行流程可以归纳为五步,同时也是验证算子正确性的完整闭环:
- 环境初始化:
aclInit→aclrtSetDevice(0)→aclrtCreateStream; - 张量构造:通过
CreateTensor在 Device 上aclrtMalloc并aclrtMemcpy数据,再用aclCreateTensor按 ND 格式创建aclTensor。样例采用inputShape={2,3}、targetShape={2,1}、varShape={2,1},即target、var各在第二维上从 1 广播到 3 的典型场景; - 两段式调用:先
GetWorkspaceSize获取 workspace 与 executor,必要时分配 workspace,再执行aclnnGaussianNllLossGrad,最后aclrtSynchronizeStream同步; - 结果回拷:将
gradInput、gradVar通过ACL_MEMCPY_DEVICE_TO_HOST拷回 Host 并打印; - Golden 对比验证:样例在 Host 侧按公式
d = input - target、v = max(var, eps)手工计算goldenInput与goldenVar,其中gradVar按行累加广播贡献,再与 NPU 输出逐元素比较最大误差,阈值1e-5内判定PASS,最终按passed ? 0 : 1作为进程退出码。
值得注意的是样例中gradOutputHost使用reduction="none"时与input同 shape 的 6 个元素,且 Golden 计算中goldenVar[row] += ...的累加逻辑与 kernel 中ProcessBroadcastGradVar的归约行为一致,可作为理解广播归约语义的直观参照。
本地编译运行 UT
该算子已纳入 CANN 的 build.sh 单算子构建体系,可分别构建 host(tiling/infershape)与 kernel 两部分。先 source 匹配的 CANN 环境(仓库 README 以 cann-9.0.0 为例),再执行:
source /usr/local/Ascend/cann-9.0.0/set_env.sh bash build.sh -u --ophost --ops=gaussian_nll_loss_grad --soc=ascend910b --experimental bash build.sh -u --opkernel --ops=gaussian_nll_loss_grad --soc=ascend910b --experimental命令要点:
--ops=gaussian_nll_loss_grad指定单算子构建范围,避免全量编译;--soc=ascend910b与算子定义中AddConfig("ascend910b")一致;--experimental表示该算子位于 experimental 实验目录;-u表示构建并运行 UT(单元测试)。
仓库内的 UT 覆盖情况:Host 侧包含 test_gaussian_nll_loss_grad_infershape.cpp(验证输出 shape 继承input/var、dtype 继承gradOutput,对应 infershape 实现)与 test_gaussian_nll_loss_grad_tiling.cpp(覆盖 4 种广播组合、reduction 校验、workspace=0、tilingKey=0);Kernel 侧 test_gaussian_nll_loss_grad.cpp 通过 tikicpulib 的ICPU_RUN_KF在 CPU 上仿真运行核函数,并对 FLOAT/Half/BF16 三种 dtype 分别设置容差(如 Half 容差2e-2),配合 gen_data.py 与 compare_data.py 进行数据生成与结果比对。
本地自测 UT 覆盖率
若普通 UT 已通过且本机安装了lcov,可附加--cov生成代码覆盖率报告:
bash build.sh -u --ophost --ops=gaussian_nll_loss_grad --soc=ascend910b --experimental --cov bash build.sh -u --opkernel --ops=gaussian_nll_loss_grad --soc=ascend910b --experimental --cov该参数对 host 与 kernel 两个构建目标分别统计行覆盖率,便于在新增用例时评估测试充分度。
eager 调用前置条件
如需在 eager 模式下运行样例(如带 Python 前端或自定义 vendor 的集成场景),前置条件为:
- 先
source匹配的 CANN 环境; - 使用
--experimental构建并安装最新 custom package; - 以
cust及匹配的vendor_name=custom运行样例。
也就是说,样例默认基于随 CANN 分发的算子包运行;要加载本仓库实验目录下新编译的算子实现,必须走 custom package 安装流程并显式指定custvendor,否则无法命中本仓库内的算子二进制。
参考资源
- 算子 README:experimental/loss/gaussian_nll_loss_grad/README.md
- ACLNN 接口文档:experimental/loss/gaussian_nll_loss_grad/docs/aclnnGaussianNllLossGrad.md
- 两段式接口通用说明:docs/zh/context/two_phase_api.md
- aclnn 返回码:docs/zh/context/aclnn_return_code.md
- 编译与运行样例指南:docs/zh/context/compile_and_run_sample.md
- 前向损失语义参考:PyTorch GaussianNLLLoss(GaussianNLLLossGrad 为其反向对应实现)
- 人工智能
- 算子库
- 深度学习
- CANN
- Ascend
【免费下载链接】ops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
相关推荐
CANN ops-nn SigmoidGrad 算子深度解析:Sigmoid 反向传播的梯度计算原理与 aclnn 调用实战
CANN ops nn SigmoidGrad 算子深度解析:Sigmoid 反向传播的梯度计算原理与 aclnn 调用实战 本文以 CANN ops nn 仓
人工智能算子库深度学习CANNAscendCANN ops-nn 仓库 EluGrad 算子解析:ELU 反向传播梯度计算原理与 aclnn 接口调用实战
CANN ops nn 仓库 EluGrad 算子解析:ELU 反向传播梯度计算原理与 aclnn 接口调用实战 本篇技术指南围绕 CANN 神经网络算子库(o
人工智能算子库深度学习CANNAscendCANN ops-math 中的 AtanGrad 算子:反正切梯度计算的原理、实现与 aclnn 调用实战
CANN ops math 中的 AtanGrad 算子:反正切梯度计算的原理、实现与 aclnn 调用实战 本文以 CANN ops math 仓库中 exp
算子库人工智能CANN
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考