
人工智能算子库深度学习CANNAscend【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址https://gitcode.com/cann/ops-nn点击查看免费下载本文围绕 CANN ops-nn 仓库中 experimental/activation/hard_sigmoid_grad_v3 模块对外导出的aclnnHardsigmoidBackward算子完整讲解其功能语义、两段式 ACLNN 接口原型、参数与返回码约定、Host 侧精度提升与调用链以及 AscendC kernel 的 tiling 与向量化实现。读完本文你将掌握如何在实际工程中调用该算子完成 HardSigmoid 反向梯度计算并能基于仓库中的示例与测试用例快速搭建验证环境。产品支持情况产品是否支持Ascend 950PR / Ascend 950DT×Atlas A3 训练系列产品 / Atlas A3 推理系列产品√Atlas A2 训练系列产品 / Atlas A2 推理系列产品√Atlas 200I / 500 A2 推理产品×Atlas 推理系列产品√Atlas 训练系列产品√功能说明aclnnHardsigmoidBackward对输入gradOutput上游梯度和self前向输入执行 HardSigmoid 反向梯度计算并将结果写入独立的输出 Tensorout。目录 experimental/activation/hard_sigmoid_grad_v3 对外导出普通版aclnnHardsigmoidBackward与原始实现保持一致。计算公式如下$$ \operatorname{hardsigmoid_backward}(gradOutput, self) \begin{cases} \frac{gradOutput}{6}, -3 self 3 \ 0, \text{otherwise} \end{cases} $$即前向输入self落在开区间(-3, 3)时反向梯度为gradOutput / 6否则为 0。该逻辑与前向 HardSigmoid 分段线性函数的导数一致前向 HardSigmoid 在(-3, 3)内斜率为1/6区间外斜率为 0。关键数值特性当gradOutput与self提升后的计算 dtype 为FLOAT16时接口内部会进一步将计算精度提升到FLOAT32完成计算后再 cast 回输出 dtypeBFLOAT16路径则按提升规则直接使用BFLOAT16/FLOAT32路径计算gradOutput与self允许混合精度输入接口内部先按PromoteType(gradOutput, self)对齐计算 dtype见下文 Host 实现剖析。两段式接口与函数原型与其他 ACLNN 算子一致aclnnHardsigmoidBackward采用两段式接口必须先调用第一段接口aclnnHardsigmoidBackwardGetWorkspaceSize完成入参校验、构图并获取 workspace 大小与 op 执行器再调用第二段接口aclnnHardsigmoidBackward在指定 Stream 上执行计算。第一段接口原型aclnnStatus aclnnHardsigmoidBackwardGetWorkspaceSize( const aclTensor *gradOutput, const aclTensor *self, aclTensor *out, uint64_t *workspaceSize, aclOpExecutor **executor);第二段接口原型aclnnStatus aclnnHardsigmoidBackward( void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, const aclrtStream stream);两段接口均返回aclnnStatus状态码具体取值可参考 aclnn 返回码说明。aclnnHardsigmoidBackwardGetWorkspaceSize 参数说明第一段接口共 5 个参数前 3 个为 Tensor 参数后 2 个为输出参数参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续TensorgradOutputaclTensor*输入上游梯度张量。支持空 Tensorshape 必须与 self、out 完全一致数据类型需要在支持范围内。FLOAT16、FLOAT32BFLOAT16 仅支持 Ascend910B 及后续同代 SoCND0-8√selfaclTensor*输入前向输入张量用于生成 HardSigmoid 反向掩码。支持空 Tensorshape 必须与 gradOutput、out 完全一致数据类型需要在支持范围内。FLOAT16、FLOAT32BFLOAT16 仅支持 Ascend910B 及后续同代 SoCND0-8√outaclTensor*输出计算的出参。支持空 Tensorshape 必须与 gradOutput、self 完全一致数据类型需要支持从内部计算 dtype cast 回写。FLOAT16、FLOAT32BFLOAT16 仅支持 Ascend910B 及后续同代 SoCND0-8√workspaceSizeuint64_t*输出返回需要在 Device 侧申请的 workspace 大小。-----executoraclOpExecutor**输出返回 op 执行器包含算子计算流程。-----需要特别说明的几点空 TensorgradOutput、self、out均支持空 Tensor。从 Host 实现 可以看到当gradOutput或self为空时第一段接口直接返回workspaceSize 0并提前结束不再构造执行图。混合精度gradOutput与self可以是不同 dtype例如FLOAT16FLOAT32接口内部先按PromoteType(gradOutput, self)提升若提升结果为FLOAT16则再升到FLOAT32参与计算。非连续 Tensor三个 Tensor 均支持非连续排布接口内部通过Contiguous与ViewCopy自动适配。返回值与错误码第一段接口会完成入参校验出现以下场景时报错返回码错误码描述ACLNN_ERR_PARAM_NULLPTR161001传入的 gradOutput、self 或 out 是空指针。ACLNN_ERR_PARAM_INVALID161002gradOutput 或 self 的数据类型不在支持范围内。ACLNN_ERR_PARAM_INVALID161002gradOutput、self 和 out 的 shape 不一致。ACLNN_ERR_PARAM_INVALID161002gradOutput、self 或 out 的维度大于 8。ACLNN_ERR_PARAM_INVALID161002提升后的计算 dtype 不能转换为 out 的数据类型。这些校验逻辑可以在 aclnn_hardsigmoid_backward.cpp 中逐一对应CheckNotNull使用OP_CHECK_NULL检查三个 Tensor 指针是否为空对应 161001CheckDtypeValid先通过OP_CHECK_DTYPE_NOT_SUPPORT检查gradOutput、self的 dtype 是否在支持列表中再调用GetComputeType得到提升后的计算 dtype并用OP_CHECK_RESULT_DTYPE_CAST_FAILED检查该 dtype 能否 cast 回out的 dtype对应 161002CheckShape使用OP_CHECK_MAX_DIM限制维度不超过 8源码中MAX_DIM_LEN 8并用OP_CHECK_SHAPE_NOT_EQUAL校验gradOutput与self、out的 shape 一致。其中 dtype 支持列表由GetDtypeSupportList依据平台动态决定static const std::initializer_listop::DataType ASCEND910_DTYPE_SUPPORT_LIST { op::DataType::DT_FLOAT, op::DataType::DT_FLOAT16}; static const std::initializer_listop::DataType ASCEND910B_DTYPE_SUPPORT_LIST { op::DataType::DT_FLOAT, op::DataType::DT_FLOAT16, op::DataType::DT_BF16};在 Ascend910B 至 Ascend910E 区间以及 Regbase 平台返回ASCEND910B_DTYPE_SUPPORT_LIST含BFLOAT16其余平台返回ASCEND910_DTYPE_SUPPORT_LIST。这与 单元测试 case_003_bfloat16 的行为一致仅在 Ascend910B / Ascend910_93 / Ascend910E 上期望成功其他平台期望返回ACLNN_ERR_PARAM_INVALID。aclnnHardsigmoidBackward 参数说明第二段接口共 4 个参数参数名输入/输出描述workspace输入在 Device 侧申请的 workspace 内存地址。workspaceSize输入在 Device 侧申请的 workspace 大小由第一段接口 aclnnHardsigmoidBackwardGetWorkspaceSize 获取。executor输入op 执行器包含算子计算流程。stream输入指定执行任务的 Stream。第二段接口的返回值同样为aclnnStatus参见 aclnn 返回码说明。从实现看第二段接口内部通过CommonOpExecutorRun(workspace, workspaceSize, executor, stream)驱动执行器完成整条构图流水线的执行。Host 侧实现剖析从 ACLNN 接口到 l0op 调用链aclnnHardsigmoidBackward的 Host 入口位于 op_host/op_api/aclnn_hardsigmoid_backward.cpp第一段接口ExecHardsigmoidBackwardGetWorkspaceSize在通过参数校验后会依次向执行器aclnnOpExecutor添加以下计算节点构成完整的计算图Contiguous对gradOutput、self分别调用l0op::Contiguous将非连续输入归一为连续存储仅在需要时产生实际拷贝Cast 到计算 dtype按GetComputeType的结果PromoteType(gradOutput, self)若为FLOAT16则再提升为FLOAT将两个输入分别 cast核心算子调用l0op::HardSigmoidGradV3(gradOutputContiguousCasted, selfContiguousCasted)完成主体计算Cast 回输出 dtype将 kernel 输出 cast 为out声明的数据类型ViewCopy通过l0op::ViewCopy将结果回写到out因此支持非连续输出 Tensor。auto promoteType GetComputeType(gradOutput-GetDataType(), self-GetDataType()); auto gradOutputContiguous l0op::Contiguous(gradOutput, uniqueExecutor.get()); auto gradOutputContiguousCasted l0op::Cast(gradOutputContiguous, promoteType, uniqueExecutor.get()); auto selfContiguous l0op::Contiguous(self, uniqueExecutor.get()); auto selfContiguousCasted l0op::Cast(selfContiguous, promoteType, uniqueExecutor.get()); auto gradInput l0op::HardSigmoidGradV3(gradOutputContiguousCasted, selfContiguousCasted, uniqueExecutor.get()); auto gradInputCasted l0op::Cast(gradInput, out-GetDataType(), uniqueExecutor.get()); auto viewCopyResult l0op::ViewCopy(gradInputCasted, out, uniqueExecutor.get());需要强调的是混合精度语义只在 ACLNN 封装层处理AscendC kernel 始终接收对齐后的单一 dtype 输入kernel 内部不需要感知混合精度。l0op::HardSigmoidGradV3封装位于 op_host/op_api/hard_sigmoid_grad_v3.cpp通过OP_TYPE_REGISTER(HardSigmoidGradV3)注册算子类型为输出张量分配与gradOutput同 shape、同 dtype 的存储并通过ADD_TO_LAUNCHER_LIST_AICORE将算子加入 AICore 启动列表。与之配套的算子定义hard_sigmoid_grad_v3_def.cpp、inferShapehard_sigmoid_grad_v3_infershape.cpp与 tiling 入口hard_sigmoid_grad_v3_tiling.cpp共同构成 Host 侧完整实现。Tiling 与 Kernel 实现多核切分与向量化优化Tiling 策略Tiling 实现位于 op_host/hard_sigmoid_grad_v3_tiling.cpp整体策略为多核切分将总元素数按 AIV core 数量均匀切分。totalLengthCore由CeilDiv(totalNum, coreNum)得到再按 512B cache line 对齐为totalLengthCoreAlignCACHE_LINE_BYTE_LENGTH 512blockFactor即每个核分得的元素数实际使用的核数为CeilDiv(totalNum, totalLengthCoreAlign)UB 切分单个核内的数据再按ubFactor分片迭代处理。UB 缓冲区需容纳 5 份数据2 路输入队列 2 路临时 mask/浮点缓冲 1 路输出队列乘上 buffer 数量双缓冲当元素总数较大时启用 double buffer 流水见下文 TilingKey 说明。ubFactor的计算要点缓冲区系数bufferCoefficientFLOAT32用FP32_BUFFER_COEFFICIENT 253 个队列缓冲 3 个 FP32 临时缓冲 1 个 compare mask折合约 25 字节/元素FLOAT16用FP16_VECTOR_BUFFER_COEFFICIENT 13maxTileElements ubSize / bufferCoefficient再按对齐粒度向下取整得到tileLength对齐粒度取32 / typeSize与COMPARE_ALIGN_BYTES(256) / typeSize中的较大者保证向量化 compare 指令的对齐要求最终tileLength还会被blockTileLimit即totalLengthCoreAlign对齐后的值钳制保证ubFactor blockFactor避免中等 shape 整块退化到 tail 标量路径。空输入totalNum 0时走SetEmptyInputTiling特判blockFactor ubFactor 0、SetBlockDim(1)kernel 直接返回。TilingKey 模板参数TilingKey 定义 使用模板编程声明两个参数D_T_X数据类型从输入 0 推导支持C_DT_FLOAT16、C_DT_FLOAT、C_DT_BF16BUFFER_MODE0 表示单缓冲、1 表示双缓冲。tiling 函数通过ASCENDC_TPL_SEL_PARAM(context, dTypeX, useDoubleBuffer)选择对应的 kernel 实例。值得注意的实现细节当前实现固定启用 double bufferuseDoubleBuffer 1tiling 源码注释解释了原因——BFLOAT16full-tile kernel 与 FP32 共用同一套双缓冲 UB 模型若关闭双缓冲当fullTileNum 1时流水线Process()路径中CopyIn(next)会在Compute(curr)释放唯一队列槽位之前执行从而死锁。Kernel 计算逻辑Kernel 入口在 op_kernel/hard_sigmoid_grad_v3.cpp核心类NsHardSigmoidGradV3::HardSigmoidGradV3T, BUFFER_MODE定义于 op_kernel/hard_sigmoid_grad_v3.h采用标准 TPipe 三阶段流水CopyIn → Compute → CopyOutint64_t fullTileNum blockLength_ / ubLength_; if (fullTileNum 0) { CopyInFull(0); for (int64_t i 0; i fullTileNum - 1; i) { CopyInFull(i 1); ComputeFull(); CopyOutFull(i); } ComputeFull(); CopyOutFull(fullTileNum - 1); } int64_t tailLength blockLength_ - fullTileNum * ubLength_; if (tailLength 0) { CopyInTail(fullTileNum, tailLength); ComputeTail(tailLength); CopyOutTail(fullTileNum, tailLength); }full-tile 路径向量化FLOAT16/FLOAT32使用常量LOWER_BOUND -3.0f、UPPER_BOUND 3.0f、SCALE_VALUE 1/6通过 4 步向量指令完成计算Muls(resultLocal, gradLocal, SCALE_VALUE)梯度先整体乘以1/6Abs(selfLocal, selfLocal)对self取绝对值将-3 self 3的双重比较收敛为单次Abs(x) 3CompareScalar(compareMask, selfLocal, UPPER_BOUND, LT)与上界比较生成掩码SelectT, uint8_t(resultLocal, compareMask, resultLocal, 0)按掩码选择区间外置 0。这一优化将双 compare 收敛为单次Abs CompareScalar Select减少了指令数。BFLOAT16full-tile 路径则先 cast 到FLOAT32临时缓冲用标量循环逐元素判断区间并乘1/6再CAST_ROUND回BFLOAT16输出。tail 路径标量安全实现ComputeTail对剩余元素逐元素读取selfLocal、gradLocal在(-3, 3)内输出gradValue * SCALE_VALUE否则置 0保证边界语义精确。CopyInTail/CopyOutTail使用DataCopyPad以 0 填充补齐对齐长度避免越界访问。边界语义注意区间是严格开区间(-3, 3)即self -3或self 3时输出 0。示例数据中self 3.0对应的输出为 0可验证该边界行为。调用示例以下代码改编自 examples/test_aclnn_hard_sigmoid_grad_v3.cpp展示最小化的两段式调用流程#include aclnnop/aclnn_hardsigmoid_backward.h aclnnStatus RunHardsigmoidBackward(const aclTensor *gradOutput, const aclTensor *self, aclTensor *out, aclrtStream stream) { uint64_t workspaceSize 0; aclOpExecutor *executor nullptr; auto ret aclnnHardsigmoidBackwardGetWorkspaceSize( gradOutput, self, out, workspaceSize, executor); if (ret ! ACL_SUCCESS) { return ret; } void *workspace nullptr; if (workspaceSize 0) { ret aclrtMalloc(workspace, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); if (ret ! ACL_SUCCESS) { return ret; } } ret aclnnHardsigmoidBackward(workspace, workspaceSize, executor, stream); if (workspace ! nullptr) { aclrtFree(workspace); } return ret; }调用注意事项workspace 只在workspaceSize 0时需要申请使用aclrtMalloc的ACL_MEM_MALLOC_HUGE_FIRST模式执行完成后必须aclrtFree释放建议在第二段接口之后调用aclrtSynchronizeStream(stream)等待计算完成再进行 Device → Host 的结果拷贝完整的初始化aclInit→aclrtSetDevice→aclrtCreateStream、Tensor 构造aclCreateTensor含 ND 格式与 strides 推导、数据搬运aclrtMemcpy与资源释放aclDestroyTensor、aclrtDestroyStream、aclrtResetDevice、aclFinalize流程可参考示例源码。示例中的数据与期望结果如下shape 为{4, 2}self取值覆盖边界与区间内外self {-4, -2, -1, 0, 1, 2, 3, 4} grad { 1, 2, 3, 4, 5, 6, 7, 8} out { 0, 2/6, 3/6, 4/6, 5/6, 1, 0, 0}示例程序会逐元素与期望值比较容差1e-5全部通过后打印hard_sigmoid_grad_v3 example passed。约束说明确定性计算aclnnHardsigmoidBackward为默认确定性实现数据类型输入仅支持FLOAT32、FLOAT16、BFLOAT16其中BFLOAT16仅在 Ascend910B 及后续同代 SoC 上支持混合精度gradOutput与self允许混合精度输入内部按PromoteType(gradOutput, self)选择计算 dtype提升结果为FLOAT16时进一步升到FLOAT32计算输出 castout的 dtype 需要支持从内部计算 dtype cast 回写Shape 约束gradOutput、self和out的 shape 必须完全一致维度支持 0 到 8 维 Tensor支持标量输入Host 侧通过EnsureNotScalar适配为 shape{1}空 Tensor三个入参均支持空 Tensor非连续 Tensor支持非连续输入/输出接口内部按需执行Contiguous与ViewCopy。测试与运行验证单元测试op_api UT仓库在 tests/ut/op_api/test_aclnn_hardsigmoid_backward.cpp 中覆盖了以下用例用例场景精度容差case_001_floatFLOAT32shape{2,4}取值[-10, 10]0.0001case_002_float16FLOAT16shape{2,5}0.001case_003_bfloat16BFLOAT16按平台断言成败仅 910B 系支持0.004case_004_mixed_dtypeFLOAT16FLOAT32混合精度输入0.0001case_005_empty_tensorshape{2,0}空 Tensor0.0001case_006_not_contiguousstrides{4,5}的非连续 Tensor0.0001运行 op_api 单元测试source /usr/local/Ascend/cann/set_env.sh cd ops-nn-repo bash build.sh --experimental --opshard_sigmoid_grad_v3 -u --opapi -j8 -O2Example 运行确保 custom run 包已安装并加载 CANN 环境后执行source /usr/local/Ascend/cann/set_env.sh export LD_LIBRARY_PATH/usr/local/Ascend/cann/opp/vendors/customize_nn/op_api/lib:${LD_LIBRARY_PATH} cd ops-nn-repo/experimental/activation/hard_sigmoid_grad_v3/examples bash run.shATK 小规模标准化测试使用 tests/st/aclnnHardsigmoidBackward/all_aclnnHardsigmoidBackward.json适用于 ATK 的小规模标准化测试集与 tests/st/aclnnHardsigmoidBackward/executor_aclnnHardsigmoidBackward.pyATK CPU benchmark 执行器export ATK_BIND_CPU_TYPE2 source /usr/local/Ascend/cann/set_env.sh source /root/src/kernel/ascend-kernel/.venv/bin/activate cd testcase-repo atk node --backend npu --devices 2 \ node --backend cpu task --task accuracy \ -c ops-nn-repo/experimental/activation/hard_sigmoid_grad_v3/tests/st/aclnnHardsigmoidBackward/all_aclnnHardsigmoidBackward.json \ -p ops-nn-repo/experimental/activation/hard_sigmoid_grad_v3/tests/st/aclnnHardsigmoidBackward/executor_aclnnHardsigmoidBackward.py目录导航路径说明docs/aclnnHardsigmoidBackward.mdaclnnHardsigmoidBackward接口文档本文依据README.md模块说明、约束与运行方式op_host/op_api/aclnn_hardsigmoid_backward.cpp对外 ACLNN 接口入口与构图逻辑op_host/op_api/hard_sigmoid_grad_v3.cpp内部l0op::HardSigmoidGradV3封装op_host/hard_sigmoid_grad_v3_tiling.cppHost tiling多核切分与 UB 分片op_kernel/hard_sigmoid_grad_v3.hAscendC kernel 核心类与向量化计算examples/test_aclnn_hard_sigmoid_grad_v3.cpp完整可编译的两段式调用示例tests/ut/op_api/test_aclnn_hardsigmoid_backward.cppop_api 单元测试tests/st/aclnnHardsigmoidBackward/ATK 标准化测试集与执行器至此从接口语义、参数约束、错误码到 Host 构图与 AscendC kernel 向量化实现再到单元测试与运行验证aclnnHardsigmoidBackward的完整技术脉络已经清晰外层 ACLNN 封装负责 dtype 提升、连续性适配与回写内层HardSigmoidGradV3kernel 通过 cache line 对齐的多核切分、Abs CompareScalar Select的向量化收敛与 BF16 升精度策略在保证-3 self 3精确边界语义的前提下完成高效的 HardSigmoid 反向梯度计算。赞分享人工智能算子库深度学习CANNAscend【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址https://gitcode.com/cann/ops-nn点击查看免费下载相关推荐CANN ops-nn 算子解析aclnnHardswishBackward 两段式 ACLNN 接口实现 HardSwish 反向梯度计算CANN ops nn 算子解析aclnnHardswishBackward 两段式 ACLNN 接口实现 HardSwish 反向梯度计算 导读 aclnn人工智能算子库深度学习CANNAscendCANN ops-nn 中 aclnnHardsigmoidBackward 接口详解NPU 上 HardSigmoid 激活反向梯度计算CANN ops nn 中 aclnnHardsigmoidBackward 接口详解NPU 上 HardSigmoid 激活反向梯度计算 本文围绕 CANN人工智能算子库深度学习CANNAscendCANN ops-nn 算子详解aclnnSoftmaxGrad 两段式接口实现 Softmax 反向梯度计算CANN ops nn 算子详解aclnnSoftmaxGrad 两段式接口实现 Softmax 反向梯度计算 Softmax 反向传播是神经网络训练中最常见人工智能算子库深度学习CANNAscend创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考