CANN ops-nn SiluGrad(aclnnSiluBackward)算子深度解析:原理、接口调用与源码实现
2026/9/19 23:11:00 网站建设 项目流程

CANN ops-nn SiluGrad(aclnnSiluBackward)算子深度解析:原理、接口调用与源码实现

【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-nn

SiluGrad 是 CANN ops-nn 算子库中 SiLU(Sigmoid Linear Unit,又称 Swish)激活函数反向传播算子的统称,对外以aclnnSiluBackward两段式接口暴露,用于根据反向传播输入梯度gradOutput与正向输入self计算输入侧梯度gradInput。本文以 activation/silu_grad/README.md 为骨架,结合该算子完整的 op_api、op_host、op_kernel 源码与测试用例,系统讲解其数学原理、产品支持范围、参数约束、两段式调用方法以及底层实现机制,读者读完即可独立完成aclnnSiluBackward的工程接入与结果验证。

一、算子功能与数学原理

1.1 功能定位

SiluGrad是正向 aclnnSilu 接口(即 SiLU/Swish 激活函数)的反向传播实现:根据反向传播传入的梯度gradOutput与正向计算时的输入self,计算得到对输入x的梯度gradInput。它是深度神经网络中 SiLU 激活层自动求导链路的关键一环,常见于 SwiGLU 门控结构、Transformer 前馈网络等场景。

从源码注释看,算子原型定义中明确标注"Compatible with the Torch operator SiluGrad",即与 PyTorch 的SiluGrad算子对齐,见 op_graph/silu_grad_proto.h。

1.2 计算公式

SiluGrad 的计算建立在 SiLU 激活函数及其导数之上,核心公式如下:

$$ \sigma(x) = {\frac{1} {1+{e}^{-x}}} $$

$$ s(x) = x\sigma(x) $$

$$ s^\prime(x) = \sigma(x)(1+x-x\sigma(x)) $$

$$ gradInput = gradOutput * s^\prime(x) $$

其中 $\sigma(x)$ 为 sigmoid 函数,$s(x)$ 为 silu 函数,$s^\prime(x)$ 为 silu 函数的导数。

需要特别注意的是:本算子不依赖正向输出,而是直接以正向输入self(即公式中的 $x$)参与导数计算。这意味着调用方只需保留激活层的输入即可完成反向传播,无需额外缓存正向输出张量,这是与"根据正向输出反推梯度"类算子(例如部分 SwishGrad 变体)的关键区别。这一设计在 docs/aclnnSiluBackward.md 的功能说明中同样有明确描述:"根据silu反向传播梯度与正向输出计算silu的梯度输入",且参数表中self的语义为"公式中的x,且对应正向的输入参数"。

二、产品支持情况

SiluGrad 算子在不同硬件产品上的支持情况如下表(源自 activation/silu_grad/README.md):

产品是否支持
Ascend 950PR/Ascend 950DT
Atlas A3 训练系列产品/Atlas A3 推理系列产品
Atlas A2 训练系列产品/Atlas A2 推理系列产品
Atlas 200I/500 A2 推理产品×
Atlas 推理系列产品×
Atlas 训练系列产品

从算子注册配置可以印证这一支持矩阵:op_host/silu_grad_def.cpp 中仅针对ascend950ascend350两个架构添加了 AICore 配置(AICore().AddConfig("ascend950", ...)AICore().AddConfig("ascend350", ...)),而ascend350对应 Atlas A2/A3 系列产品,ascend950对应 Ascend 950 系列,与上表中支持的产品一一对应;未注册的架构(如 Atlas 200I/500 A2、Atlas 推理系列)自然不支持该算子。此外,op_host/config/ascend350/silu_grad_binary.json 与 op_host/config/ascend950/silu_grad_binary.json 两份二进制算子配置文件进一步佐证了算子在两个架构上的落地形态。

三、参数说明

3.1 输入输出参数

SiluGrad 共三个张量参数:两个输入、一个输出,全部为 ND 格式,支持 1~8 维:

参数名输入/输出/属性描述数据类型数据格式
gradOutput输入表示输入梯度。公式中的 gradOutput。BFLOAT16、FLOAT16、FLOATND
self输入表示输入数据。公式中的 x,且对应正向的输入参数。BFLOAT16、FLOAT16、FLOATND
gradInput输出表示对输入数据 self 求的梯度。公式中的 gradInput。BFLOAT16、FLOAT16、FLOATND

各参数在 docs/aclnnSiluBackward.md 中有更细粒度的约束:

  • gradOutput(输入):支持空 Tensor;gradOutput、self 与 gradInput 的数据类型和 shape 一致;三者的 shape 满足 broadcast 关系;维度(shape)为 1~8;支持非连续 Tensor。
  • self(输入):支持空 Tensor;约束与 gradOutput 相同,且对应正向算子的输入参数。
  • gradInput(输出):gradOutput、self 与 gradInput 的数据类型和 shape 一致;三者的 shape 满足 broadcast 关系;维度(shape)为 1~8;支持非连续 Tensor。

3.2 平台相关的数据类型差异

  • Atlas 训练系列产品:数据类型仅支持 FLOAT16、FLOAT,不支持 BFLOAT16(见 README.md 与 docs/aclnnSiluBackward.md 中的平台标注)。

3.3 约束说明

README 中标注该算子约束说明:无,即对调用方没有额外的格式、对齐或特殊 shape 限制,只需满足上述参数数据类型与 shape 约束即可。确定性计算方面,aclnnSiluBackward默认采用确定性实现(见 docs/aclnnSiluBackward.md 约束说明小节)。

四、两段式接口:aclnnSiluBackward 调用说明

与其他 CANN aclnn 算子一致,aclnnSiluBackward采用两段式接口设计:必须先调用aclnnSiluBackwardGetWorkspaceSize获取计算所需 workspace 大小以及包含算子计算流程的执行器,再调用aclnnSiluBackward执行计算。

4.1 第一段接口:aclnnSiluBackwardGetWorkspaceSize

aclnnStatus aclnnSiluBackwardGetWorkspaceSize( const aclTensor* gradOutput, const aclTensor* self, aclTensor* gradInput, uint64_t* workspaceSize, aclOpExecutor** executor)

参数明细:

参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续Tensor
gradOutput(aclTensor*)输入表示输入梯度。公式中的 gradOutput。支持空 Tensor;gradOutput、self 与 gradInput 的数据类型和 shape 一致;三者的 shape 满足 broadcast 关系。BFLOAT16、FLOAT16、FLOATND1-8
self(aclTensor*)输入表示输入数据。公式中的 x,且对应正向的输入参数。支持空 Tensor;gradOutput、self 与 gradInput 的数据类型和 shape 一致;三者的 shape 满足 broadcast 关系。BFLOAT16、FLOAT16、FLOATND1-8
gradInput(aclTensor*)输出表示对输入数据 self 求的梯度。公式中的 gradInput。gradOutput、self 与 gradInput 的数据类型和 shape 一致;三者的 shape 满足 broadcast 关系。BFLOAT16、FLOAT16、FLOATND1-8
workspaceSize(uint64_t*)输出返回需要在 Device 侧申请的 workspace 大小。-----
executor(aclOpExecutor**)输出返回 op 执行器,包含了算子计算流程。-----

注:Atlas 训练系列产品上数据类型仅支持 FLOAT16、FLOAT。

返回值与错误码:返回aclnnStatus状态码,具体参见 aclnn返回码。第一段接口会完成入参校验,以下场景会报错:

返回码错误码描述
ACLNN_ERR_PARAM_NULLPTR161001传入的 gradOutput、self 或 gradInput 是空指针。
ACLNN_ERR_PARAM_INVALID161002gradOutput、self 或 gradInput 的数据类型不在支持的范围之内。
ACLNN_ERR_PARAM_INVALID161002gradOutput、self 或 gradInput 的数据类型不同或不满足要求。
ACLNN_ERR_PARAM_INVALID161002gradOutput、self 或 gradInput 的 shape 不同或不满足 broadcast 关系。

这些错误码的校验逻辑可以在 op_api/aclnn_silu_backward.cpp 的CheckParams中逐条对应:先检查空指针(CheckNotNull,返回ACLNN_ERR_PARAM_NULLPTR),再检查数据类型是否在DTYPE_SUPPORT_LIST(FLOAT16/FLOAT/BF16)内且三者 dtype 是否一致(混合精度场景校验输出是否为 FLOAT),最后检查 shape 是否一致或满足 broadcast 关系(CheckShapeValid,均返回ACLNN_ERR_PARAM_INVALID)。

4.2 第二段接口:aclnnSiluBackward

aclnnStatus aclnnSiluBackward( void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream)

参数明细:

参数名输入/输出描述
workspace输入在 Device 侧申请的 workspace 内存地址。
workspaceSize输入在 Device 侧申请的 workspace 大小,由第一段接口 aclnnSiluBackwardGetWorkspaceSize 获取。
executor输入op 执行器,包含了算子计算流程。
stream输入指定执行任务的 Stream。

返回值仍为aclnnStatus状态码,参见 aclnn返回码。

4.3 源码视角:两段接口内部做了什么

从 op_api/aclnn_silu_backward.cpp 可以还原两段接口的完整行为:

  1. 第一段(GetWorkspaceSize)依次执行:创建OpExecutorCheckParams参数校验 → 空 Tensor 快速路径(gradOutputself为空时直接返回 workspaceSize=0,见 L165-L169)→ 通过l0op::Contiguous将两个输入转换为连续 Tensor → 调用l0op::SiluGrad构建算子计算节点 → 通过l0op::ViewCopy将中间结果拷贝到可能非连续的输出gradInput上 → 汇总并返回 workspace 大小与执行器。
  2. 第二段(aclnnSiluBackward)则是调用CommonOpExecutorRun(workspace, workspaceSize, executor, stream)完成实际计算(见 L194-L199)。

l0op::SiluGrad(定义于 op_api/silu_grad.cpp)先对两个输入做 broadcast 形状推导,再决定输出数据类型:当gradOutputself的 dtype 不同时,输出gradInput提升为DT_FLOAT(混合精度中间计算),否则与输入保持一致;随后调用SiluGradAiCore通过ADD_TO_LAUNCHER_LIST_AICORE(SiluGrad, ...)下发到 AICore 执行。

五、完整调用示例

仓库在 examples/test_aclnn_silu_grad.cpp 提供了可直接编译运行的完整样例,docs/aclnnSiluBackward.md中也给出了同款示例代码。以下为完整代码(以 2×3 的 FLOAT 张量为例,输入梯度全 1、输入数据 1~6):

#include <iostream> #include <vector> #include "acl/acl.h" #include "aclnnop/aclnn_silu_backward.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::vector<int64_t>& shape) { int64_t shapeSize = 1; for (auto i : shape) { shapeSize *= i; } return shapeSize; } 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::vector<T>& hostData, const std::vector<int64_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::vector<int64_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_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); // 2. 构造输入与输出,需要根据API的接口自定义构造 std::vector<int64_t> gradOutputShape = {2, 3}; std::vector<int64_t> selfShape = {2, 3}; std::vector<int64_t> gradInputShape = {2, 3}; void* gradOutDeviceAddr = nullptr; void* selfDeviceAddr = nullptr; void* gradInputDeviceAddr = nullptr; aclTensor* gradOut = nullptr; aclTensor* self = nullptr; aclTensor* gradInput = nullptr; std::vector<float> gradOutHostData = {1, 1, 1, 1, 1, 1}; std::vector<float> selfHostData = {1, 2, 3, 4, 5, 6}; std::vector<float> gradInputHostData = {0, 0, 0, 0, 0, 0}; // 创建gradOut aclTensor ret = CreateAclTensor(gradOutHostData, gradOutputShape, &gradOutDeviceAddr, aclDataType::ACL_FLOAT, &gradOut); CHECK_RET(ret == ACL_SUCCESS, return ret); // 创建self aclTensor ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self); CHECK_RET(ret == ACL_SUCCESS, return ret); // 创建gradInput aclTensor ret = CreateAclTensor(gradInputHostData, gradInputShape, &gradInputDeviceAddr, aclDataType::ACL_FLOAT, &gradInput); CHECK_RET(ret == ACL_SUCCESS, return ret); // 3. 调用CANN算子库API,需要修改为具体的API名称 int64_t dim = 0; uint64_t workspaceSize = 0; aclOpExecutor* executor; // 调用aclnnSiluBackward第一段接口 ret = aclnnSiluBackwardGetWorkspaceSize(gradOut, self, gradInput, &workspaceSize, &executor); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSiluBackwardGetWorkspaceSize 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); } // 调用aclnnSiluBackward第二段接口 ret = aclnnSiluBackward(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSiluBackward 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(gradInputShape); std::vector<float> outData(size, 0); ret = aclrtMemcpy(outData.data(), outData.size() * sizeof(outData[0]), gradInputDeviceAddr, size * sizeof(outData[0]), 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("out result[%ld] is: %f\n", i, outData[i]); } // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改 aclDestroyTensor(gradOut); aclDestroyTensor(self); aclDestroyTensor(gradInput); // 7. 释放device资源,需要根据具体API的接口定义修改 aclrtFree(gradOutDeviceAddr); aclrtFree(selfDeviceAddr); aclrtFree(gradInputDeviceAddr); if (workspaceSize > 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }

示例代码的编译与执行过程请参考 编译与运行样例。对上述样例做一次手工验算可以直观验证公式:当gradOutput全为 1、self = {1,2,3,4,5,6}时,每个位置的输出即为 $s^\prime(x)=\sigma(x)(1+x-x\sigma(x))$,例如 $x=1$ 时 $s^\prime(1)\approx0.9093\times(1+1-1\times0.9093)\approx0.9917$。

5.1 关于非连续 Tensor 与空 Tensor

  • 非连续 Tensor:接口层会通过l0op::Contiguous将非连续输入归一化为连续 Tensor 后参与计算,并通过l0op::ViewCopy把结果写回非连续的输出张量,因此调用方无需自己预处理非连续张量(docs/aclnnSiluBackward.md 参数表中"非连续Tensor"一列为 √)。
  • 空 Tensor:当gradOutputself为空 Tensor 时,第一段接口直接返回workspaceSize = 0与一个可用的执行器,第二段接口空转完成,不触发实际计算,调用方可按正常流程继续(无需额外分支处理)。

六、源码级实现解析:从图协议到 AICore Kernel

6.1 图协议层(op_graph)

op_graph/silu_grad_proto.h 使用REG_OP宏定义算子原型:输入dy(即 gradOutput)、输入x(即 self)、输出dx(即 gradInput),三者均支持DT_FLOAT16DT_FLOATDT_BF16,格式为 ND,默认支持 1~8 维,并标注与 Torch 的SiluGrad算子兼容。

6.2 Host 侧算子定义与 Infershape(op_host)

  • op_host/silu_grad_def.cpp 通过OpDef注册算子:输入dy/x与输出dx均要求必填,并声明了 9 种数据类型组合(含同 dtype 三组与混合精度六组);AICore 配置开启动态编译、动态 rank、动态 shape 支持,且PrecisionReduceFlag(true)表明允许精度降低优化。
  • op_host/silu_grad_infershape.cpp 定义 shape/dtype 推导规则:InferShape复用 elewise 通用推导(InferShape4Elewise);InferDataTypeForSiluGrad则实现"两输入 dtype 相同则输出同型,否则输出提升为 FLOAT"的规则,与 op_api 层silu_grad.cpp中的 dtype 决策逻辑完全一致。

6.3 Tiling 与算子分档(op_host/arch35)

op_host/arch35/silu_grad_tiling.cpp 完成 tiling 计算,是算子性能的关键:

  • GetOpKey依据dyxdx三者的 dtype 组合返回 9 档 opKey(OP_KEY_1 ~ OP_KEY_9),例如FLOAT16×FLOAT16→FLOAT16为 OP_KEY_1、FLOAT16×BF16→FLOAT为 OP_KEY_4、FLOAT×BF16→FLOAT为 OP_KEY_9 等;
  • GetComputeMap为每档组合配置 broadcast 计算的位宽与 buffer 参数(maxDtypeBits/minDtypeBits/bufferDivisor等);
  • DoOpTiling收集输入/输出 storage shape 与 strides,调用通用BroadcastTiling生成 block 切分、UB 切分与尾部处理参数,并最终生成 tilingKey、blockDim 与 workspace(固定 32 字节)。
  • Tiling 过程会读取平台信息(AIV 核数、UB 大小),支持从SiluGradCompileInfo获取编译期信息,兼顾动态 shape 场景。

6.4 Kernel 实现与 tilingKey 分发(op_kernel)

op_kernel/silu_grad_apt.cpp 是 AICore Kernel 的入口函数silu_grad,其核心特征是按 tilingKey 静态分发到 18 个模板特化实现(见 L37-L71):

  • 同 dtype 三组:SiluGradF16SiluGradBf16SiluGradF32,各分nddma_with_loopsnddma_without_loops两个变体;
  • 混合精度六组:SiluGradDtypeComb0~SiluGradDtypeComb5,同样各分 loops / without_loops 两个变体。

"with_loops / without_loops" 对应两种内存搬运策略:当张量维数较大(UB 内最大维数达 8)且需要 NDDMA 多轮搬运时走 loops 版本;当维数较小时(UB 内最大维数为 5)走无循环的展开版本,后者通过减少循环开销提升小 shape 场景的吞吐。kernel 入口还做了 AIC 核守卫(g_coreType == AscendC::AIC直接返回)与KERNEL_TYPE_AIV_ONLY任务类型声明,表明该算子仅在 AIV 核上执行。具体的逐元素导数计算模板实现位于 op_kernel/arch35/ 目录下的 18 个头文件中。

6.5 二进制算子配置(op_host/config)

op_host/config/ascend950/silu_grad_binary.json 与 op_host/config/ascend350/silu_grad_binary.json 记录了算子二进制分档(bin_filename)与输入输出规格:所有分档的 shape 均为[-2](表示动态 shape),format 为 ND,paramType 为 required;dtype 组合包括bf16×bf16→bf16fp16×fp16→fp16fp32×fp32→fp32以及六种混合精度组合(输出一律为 fp32),与 tiling 层的 opKey 分档一一对应。

七、测试与验证

仓库为 SiluGrad 提供了覆盖各层的测试用例,可用于验证算子正确性:

  • op_api 单测:tests/ut/op_api/test_aclnn_silu_backward.cpp,直接调用aclnnSiluBackward两段接口并比对结果;
  • op_host 单测:tests/ut/op_host/arch35/test_silu_grad_tiling.cpp 验证 tiling 数据生成,tests/ut/op_host/test_silu_grad_infershape.cpp 验证 shape/dtype 推导;
  • op_kernel 单测:tests/ut/op_kernel/test_silu_grad_apt.cpp 验证 kernel 计算正确性;
  • 系统测试(ST):tests/st/aclnnSiluBackward/ 目录下提供atk_aclnnSiluBackward.jsonexecutor_aclnnSiluBackward.py,以及 arch35 下的 CSV 用例清单(ttk_aclnn_silu_backward_st.csvttk_kernel_silu_grad_st.csv),可配合 ATK/TTK 工具做端到端验收;
  • golden 数据生成:tests/assets/golden.py 用于生成期望输出,可作为手工验算公式 $gradInput = gradOutput \cdot \sigma(x)(1+x-x\sigma(x))$ 的参考实现。

八、常见问题速查

现象/诉求处理方式
报错 161001(ACLNN_ERR_PARAM_NULLPTR)检查 gradOutput、self、gradInput 三个 aclTensor 是否都已正确创建,未空指针传入。
报错 161002(ACLNN_ERR_PARAM_INVALID)依次排查:dtype 是否在 FLOAT16/FLOAT/BF16 范围内;三者 dtype 是否一致(混合精度下输出必须为 FLOAT);shape 是否一致或满足 broadcast 关系。
Atlas 训练系列产品上使用 BF16不支持。Atlas 训练系列产品仅支持 FLOAT16、FLOAT,需先做类型转换。
输入为高维(>8 维)张量接口层通过MAX_SUPPORT_DIMS_NUMS(8 维)上限校验拒绝;高维张量建议先 reshape 到 ≤8 维再调用。
非连续张量 / 空张量无需预处理,接口内部自动处理(Contiguous 归一化、空 Tensor 短路)。
需要确定性的梯度结果aclnnSiluBackward默认即确定性实现,无需额外开关。

总结

SiluGrad 算子以aclnnSiluBackward两段式接口承载 SiLU 激活函数的反向传播计算,数学上即gradInput = gradOutput * σ(x)(1+x-xσ(x)),覆盖 FLOAT16/FLOAT/BF16 三种数据类型与九种 dtype 组合,支持 1~8 维 ND 张量、broadcast、非连续与空 Tensor。从图协议(op_graph)、算子定义与推导(op_host)、tiling 分档(op_host/arch35)到按 tilingKey 静态分发的 AICore Kernel(op_kernel),整个实现链路完整可追溯,并配有从单测到端到端 ST 的验证体系。开发者可直接参考 examples/test_aclnn_silu_grad.cpp 完成接入,并按 编译与运行样例 的指引构建运行。

【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-nn

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询