news 2026/9/20 23:22:53

CANN ops-nn 中 SwishGrad 算子解析:原理、实现与 aclnnSwishBackward 调用指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CANN ops-nn 中 SwishGrad 算子解析:原理、实现与 aclnnSwishBackward 调用指南

CANN ops-nn 中 SwishGrad 算子解析:原理、实现与 aclnnSwishBackward 调用指南

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

导读

SwishGrad 是 CANN 神经网络算子库(ops-nn)中用于计算 Swish 激活函数梯度的反向算子,实现在仓库的 experimental/activation/swish_grad 目录下,面向 Atlas A2 训练系列产品/Atlas 800I A2 推理产品提供 fp16、fp32、bf16 三种精度的梯度计算能力。本文以 swish_grad/README.md 为核心骨架,结合仓库中算子定义、Host 侧 tiling、Kernel 侧昇腾 AI Core 实现与单元测试,完整讲解 SwishGrad 的数学原理、参数约束、两段式 aclnn 接口调用流程与源码级实现机制,帮助开发者快速上手在 NPU 上完成 Swish 反向传播的接入与调试。

一、算子功能与数学原理

1.1 功能定位

SwishGrad 算子是 Swish 激活函数(activation/swish)的反向传播算子,求 Swish 函数的梯度。它接收反向传播传入的梯度grad、正向输入x以及可调节参数scale,输出对输入x的梯度grad_x

从算子库的接口关系来看,上层对外暴露的 API 名为aclnnSwishBackward,其功能说明文档 docs/aclnnSwishBackward.md 明确指出它是 aclnnSwish(仓库实际路径为 activation/swish/docs/aclnnSwish.md)激活函数的反向传播,用于计算 Swish 激活函数的梯度。这与 torch 生态中的swish_backward语义一一对应。

1.2 计算公式

根据 swish_grad/README.md 的"功能说明",SwishGrad 的计算公式如下:

$$ y = sigmoid(scalex) + xsigmoid(scale*x) $$

$$ sigmoid = sigmoid*(1 - sigmoid) $$

其中scale为可调节的斜率参数。更精确的推导形式见 docs/aclnnSwishBackward.md:

Swish 正向函数:

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

其导数:

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

最终输出梯度:

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

其中 Sigmoid 函数定义为:

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

可见 README 中的两条公式本质是"先算 sigmoid 值,再算 1 - sigmoid(即导数因子),最后与梯度逐元素相乘"这一计算链的简写。对照 op_kernel/swish_grad.h 的Compute实现,可以逐行印证该公式:

σ(βx) = 1 / (1 + exp(-βx)) σ'(βx) = σ(βx) * (1 - σ(βx)) s'(x) = σ(βx) + βx * σ'(βx) // 即 σ(βx) * (1 + βx(1 - σ(βx))) grad_x = grad * s'(x)

1.3 参数说明

README 中对算子原语的参数定义如下:

参数名输入/输出/属性描述数据类型数据格式
grad输入待进行 SwishGrad 计算的入参,公式中的 gradfp16、fp32、bf16ND, FRACTAL_NZ, NC1HWC0
x输入待进行 SwishGrad 计算的入参,公式中的 xfp16、fp32、bf16ND, FRACTAL_NZ, NC1HWC0
scale输入待进行 SwishGrad 计算的入参,公式中的 scalefp321(标量)
y输入待进行 SwishGrad 计算的入参,暂时不参与运算fp16、fp32、bf16ND, FRACTAL_NZ, NC1HWC0
grad_x输出待进行 SwishGrad 计算的出参,公式中的输出fp16、fp32、bf16ND, FRACTAL_NZ, NC1HWC0

约束说明:无。

需要指出两点值得注意的细节:

  1. 算子定义中的y输入"暂时不参与运算"。这在 op_kernel/swish_grad.cpp 的 kernel 入口中可以看到:swish_grad内核函数虽然接收GM_ADDR y,但 op_kernel/swish_grad.h 的Init只为gradxgrad_x建立了 GlobalBuffer,y并未被读取,属于为后续版本预留的入参。
  2. 上述表格描述的是底层算子的参数形态;对上层用户而言,真正接触的是aclnnSwishBackward接口的参数(见第三节)。

二、算子源码结构

SwishGrad 在仓库中采用标准的 CANN 算子工程布局:

experimental/activation/swish_grad/ ├── docs/aclnnSwishBackward.md # aclnn 接口使用文档 ├── examples/test_aclnn_swish_grad.cpp # 可运行调用样例 ├── op_host/ │ ├── op_api/ # l0 算子接口封装(l0op::SwishGrad) │ │ ├── aclnn_swish_backward.cpp/h # 对外 aclnn 两段式接口 │ │ └── swish_grad.cpp/h # l0 算子封装与 launcher │ ├── swish_grad_def.cpp # 算子原语注册(OpDef) │ ├── swish_grad_infershape.cpp # 输出 shape 推导 │ └── swish_grad_tiling.cpp # Host 侧 tiling 计算 ├── op_kernel/ │ ├── swish_grad.cpp # AI Core 内核入口(__global__ __aicore__) │ ├── swish_grad.h # Kernel 类实现(双缓冲流水) │ ├── swish_grad_tiling_data.h # tiling 参数结构体 │ └── swish_grad_tiling_key.h # tiling key └── tests/ut/ # op_api / op_host / op_kernel 三级单测

整个调用链为:aclnnSwishBackwardGetWorkspaceSizel0op::SwishGrad(Host 侧拼装算子)→ADD_TO_LAUNCHER_LIST_AICORE下发 → AI Core 内核swish_grad执行。下面逐层展开。

2.1 算子定义注册(op_def)

swish_grad_def.cpp 中通过OP_TYPE_REGISTER/OP_ADD注册名为SwishGrad的算子:

  • 四个数据对象:输入gradxy,输出grad_x,数据类型支持DT_FLOAT16DT_FLOATDT_BF16,格式支持NDNC1HWC0FRACTAL_NZ三种;
  • 属性sconfAttrType(OPTIONAL).Float(1.0),即可选的 float 型斜率参数,默认值为 1.0,对应公式中的scale/β
  • AICore 配置:DynamicCompileStaticFlag(true)DynamicRankSupportFlag(true)DynamicShapeSupportFlag(true)PrecisionReduceFlag(true),注册到ascend910bSoC(对应 Atlas A2 系列),并通过ExtendCfgInfo("opFile.value", "swish_grad")指定 kernel 入口文件名为swish_grad.cpp

2.2 输出 shape 推导(infershape)

swish_grad_infershape.cpp 的实现非常直接:读取输入x的 shape,并将输出grad_x的 shape 赋值为与之完全相同(*yShape = *xShape),即逐元素反向算子,输出与输入同 shape、同 dtype。这与 README 中"grad、x 与 grad_x 的 shape/数据类型一致"的约束一致。

2.3 Host 侧 tiling(swish_grad_tiling.cpp)

swish_grad_tiling.cpp 负责在 Host 侧根据输入规模与硬件资源计算切分方案:

  • GetPlatformInfo:通过platform_ascendc::PlatformAscendC获取 UB(Unified Buffer)大小、AI Core 核数以及块对齐粒度(GetUbBlockSize);
  • GetWorkspaceSize:查询系统库 API 所需 workspace 大小并回填给框架;
  • GetShapeAttrsInfo:根据输入存储 shape 与数据类型字节数计算总数据量,结合 UB 容量与双缓冲需求(BUFFER_NUM = 2)确定每个核负责的数据量(bigCoreDataNum/smallCoreDataNum)、tile 内数据量(tileDataNum)以及尾部数据(tailDataNum)。

最终产出的 tiling 数据结构定义在 swish_grad_tiling_data.h:

struct SwishGradTilingData { uint64_t smallCoreDataNum; uint64_t bigCoreDataNum; uint64_t finalBigTileNum; uint64_t finalSmallTileNum; uint64_t tileDataNum; uint64_t smallTailDataNum; uint64_t bigTailDataNum; uint64_t tailBlockNum; float sconf; };

其核心思想是多核负载均衡 + 尾部数据处理:把总数据量按核数均分,若不能整除,则前tailBlockNum个核多承担bigCoreDataNum个数据,其余核承担smallCoreDataNum个数据,每个核内部再按tileDataNum切成多个 tile 循环处理,最后的余量作为尾 tile 单独处理。

2.4 AI Core 内核实现(op_kernel)

Kernel 入口 swish_grad.cpp 通过REGISTER_TILING_DEFAULT读取 tiling 数据,实例化NsSwishGrad::KernelSwishGrad<DTYPE_X>并调用InitProcess

核心实现位于 swish_grad.h,其设计要点如下:

(1)双缓冲流水线TPipe上建立了 VECIN 队列inQueueGradinQueueXinQueueY与 VECOUT 队列outQueueGrad,缓冲区个数均为BUFFER_NUM = 2,实现 CopyIn → Compute → CopyOut 三阶段重叠执行。

(2)fp16/bf16 与 fp32 两条计算路径

  • float16_t/bfloat16_t:先把x通过Cast提升到 float 计算(使用临时缓冲区tmpQueue0/1/2),经历Muls(乘 β)→Muls(-1.0)ExpAdds(1.0)Div(得到 σ(βx))→Sub(得到 1-σ(βx))→Mul(得到 βx·σ'(βx))→Add(1.0)(得到 1+βx(1-σ(βx)))→Mul与 σ(βx) 相乘 → 再与 grad 相乘,最后以CAST_RINT舍入模式转回半精度输出;
  • float:直接在浮点路径上完成同样序列的运算,全程使用 float 精度,输出不降精度。

(3)多核数据切片Init中根据coreIdtailBlockNum的关系,选择大核/小核的数据区间与 GlobalBuffer 偏移,每个核只处理自己负责的连续数据段。

内核从sconf(即 scale/β)读取斜率参数,其值由 Host 侧在aclnnSwishBackwardGetWorkspaceSize中从betaOptional标量转换而来(缺省为 1.0f)。

2.5 测试用例佐证

仓库为算子提供了三级单元测试,可用于验证实现与本文结论:

  • op_api 层:tests/ut/op_api/test_aclnn_swish_backward.cpp,覆盖 float32、float16、bf16 等场景,构造{2,5}的 gradOutput、self(值域 [-1,1])与 beta(如 1.1f、0.01f),断言aclnnSwishBackwardGetWorkspaceSize返回ACLNN_SUCCESS并设置了精度容差;
  • op_host 层:tests/ut/op_host/test_swish_grad_tiling.cpp,验证 tiling 计算产物(各核数据量、tile 数等)符合预期;
  • op_kernel 层:tests/ut/op_kernel/test_swish_grad.cpp,直接对 AI Core 内核做数值验证。

三、aclnnSwishBackward 接口详解

3.1 产品支持情况

产品是否支持
Atlas A2 训练系列产品/Atlas 800I A2 推理产品

对应到 SoC 层面,算子原语注册于ascend910b平台(见 swish_grad_def.cpp),且 aclnn_swish_backward.cpp 中的CheckSocVersionIsSupportBf16显示 bf16 支持范围限定在ASCEND910BASCEND910E之间的 SoC 版本。

3.2 两段式接口模型

与 CANN 其他 aclnn 算子一致,aclnnSwishBackward采用两段式接口(详见 docs/zh/context/two_phase_api.md):先调用GetWorkspaceSize接口完成入参校验、算子拼装并获取所需 workspace 大小与执行器,再调用执行接口真正下发计算。

第一段接口原型:

aclnnStatus aclnnSwishBackwardGetWorkspaceSize( const aclTensor* gradOutput, // 正向输出梯度,公式中的 gradOutput const aclTensor* self, // Swish 激活函数输入,公式中的 x const aclScalar* betaOptional, // 可调节参数 β(标量),空指针时按 1.0 计算 aclTensor* gradInput, // 输出:对输入的梯度 uint64_t* workspaceSize, aclOpExecutor** executor)

第二段接口原型:

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

3.3 第一段接口参数说明

参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续 Tensor
gradOutput输入Swish 激活函数正向输出的梯度,公式中的 gradOutput支持空 Tensor;gradOutput、self 与 gradInput 的 shape 一致;三者的数据类型一致BFLOAT16、FLOAT16、FLOATND0-8
self输入用于计算激活函数的张量,公式中的 x支持空 Tensor;同上BFLOAT16、FLOAT16、FLOATND0-8
betaOptional输入可调节参数,控制 Swish 函数的形状和斜率,公式中的 β数据类型需可转换为 FLOAT(参见 docs/zh/context/deduction_relationship.md 的互推导关系);空指针时以 1.0 计算----
gradInput输出backward 计算的输出,Swish 正向输入的梯度值支持空 Tensor;shape 与数据类型同前两者BFLOAT16、FLOAT16、FLOATND0-8
workspaceSize输出返回需要在 Device 侧申请的 workspace 大小-----
executor输出返回 op 执行器,包含算子计算流程-----

返回值(aclnnStatus):具体返回码参见 docs/zh/context/aclnn_return_code.md。第一段接口会完成入参校验,以下场景会报错:

返回码错误码描述
ACLNN_ERR_PARAM_NULLPTR161001传入的 gradOutput、self 或 gradInput 是空指针
ACLNN_ERR_PARAM_INVALID161002gradOutput、self、betaOptional 或 gradInput 的数据类型不在支持范围之内
ACLNN_ERR_PARAM_INVALID161002gradOutput、self 和 gradInput 的数据类型不同
ACLNN_ERR_PARAM_INVALID161002gradOutput、self 和 gradInput 的 shape 不同

3.4 第二段接口参数说明

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

返回值同样为aclnnStatus。约束说明:无。

3.5 接口内部实现要点

aclnn_swish_backward.cpp 的实现清晰展示了接口层的处理流程,可作为阅读模板:

  1. 参数校验CheckParams依次执行空指针检查(CheckNotNull)、数据类型检查(CheckDtypeValid,支持列表为 FLOAT16/FLOAT/BF16,且校验 betaOptional 可转 FLOAT、三个张量 dtype 一致、bf16 受 SoC 版本约束)与 shape 检查(CheckShapeValid,维度上限为MAX_SUPPORT_DIMS_NUMS,三个张量 shape 一致);
  2. 空 Tensor 短路:当gradOutputself为空时,workspaceSize直接置 0 返回,不执行计算;
  3. 连续性处理:对非连续输入调用l0op::Contiguous转为连续 Tensor(对应参数表中"非连续 Tensor √"的支持能力);
  4. 高维 reshape:当输入维度超过 8 时,将输入展平为 1 维长 Tensor 交给 kernel,计算完后再Reshape回原维度;
  5. β 转换betaOptional通过ToFloat()转为 float,空指针时取默认值1.0f
  6. 下发与收尾:调用l0op::SwishGrad完成算子拼装,通过l0op::ViewCopy将结果拷贝到可能非连续的输出gradInput上,最终以GetWorkspaceSize()汇总整体 workspace 需求;第二段接口则直接调用框架通用执行函数CommonOpExecutorRun完成异步下发。

四、完整调用示例与运行指引

4.1 可运行样例

仓库提供了可直接参考的完整样例 examples/test_aclnn_swish_grad.cpp,编译与运行方法可参照 docs/zh/context/compile_and_run_sample.md。样例的核心流程如下(为便于阅读做了精简,完整代码以仓库文件为准):

#include "acl/acl.h" #include "aclnn_swish_backward.h" int main() { // 1. 固定写法:device/stream 初始化 int32_t deviceId = 0; aclrtStream stream; auto ret = Init(deviceId, &stream); // aclInit + aclrtSetDevice + aclrtCreateStream // 2. 构造输入与输出(示例 shape 均为 {2, 3}) std::vector<int64_t> gradOutputShape = {2, 3}; std::vector<int64_t> selfShape = {2, 3}; std::vector<int64_t> gradInputShape = {2, 3}; std::vector<float> gradOutHostData = {1, 1, 1, 1, 1, 1}; std::vector<float> selfHostData = {1, 2, 3, 4, 5, 6}; float betaValue = 1.1f; // 用 aclrtMalloc/aclrtMemcpy 把 host 数据搬到 device,并 aclCreateTensor 创建 aclTensor aclTensor* gradOut = CreateAclTensor(gradOutHostData, gradOutputShape, ..., ACL_FLOAT, ...); aclTensor* self = CreateAclTensor(selfHostData, selfShape, ..., ACL_FLOAT, ...); aclTensor* gradInput = CreateAclTensor(/* 输出占位 */, gradInputShape, ..., ACL_FLOAT, ...); aclScalar* betaOptional = aclCreateScalar(&betaValue, aclDataType::ACL_FLOAT); // 3. 两段式调用 uint64_t workspaceSize = 0; aclOpExecutor* executor; ret = aclnnSwishBackwardGetWorkspaceSize(gradOut, self, betaOptional, gradInput, &workspaceSize, &executor); void* workspaceAddr = nullptr; if (workspaceSize > 0) { aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); } ret = aclnnSwishBackward(workspaceAddr, workspaceSize, executor, stream); // 4. 同步等待执行结束 aclrtSynchronizeStream(stream); // 5. 将 device 侧结果拷回 host 并打印(本例输出为 gradInput = grad * s'(x)) std::vector<float> outData(6, 0); aclrtMemcpy(outData.data(), ..., gradInputDeviceAddr, ..., ACL_MEMCPY_DEVICE_TO_HOST); // 6-7. 释放 aclTensor / aclScalar / device 内存 / stream,并 aclFinalize return 0; }

样例中gradOutput = {1,1,1,1,1,1}self = {1,2,3,4,5,6}beta = 1.1,执行后打印的 6 个输出值即为对应位置的grad * s'(x)数值,可直接对照第一节的公式手工验算。

4.2 调用步骤要点

  1. 初始化aclInit(nullptr)aclrtSetDevice(deviceId)aclrtCreateStream(&stream)
  2. 构造 Tensor:shape/stride 一致、数据类型为 FLOAT16/FLOAT/BF16、格式为 ND;支持非连续 Tensor(接口内部会自动Contiguous);支持空 Tensor;
  3. 两段式调用:第一段拿到workspaceSizeexecutor,若workspaceSize > 0则在 device 侧申请内存,然后调用第二段aclnnSwishBackward
  4. 同步与取数aclrtSynchronizeStream后通过aclrtMemcpy(DEVICE_TO_HOST)读取输出;
  5. 资源释放:依次释放aclTensor/aclScalar、device 内存、workspace、stream,最后aclrtResetDevice+aclFinalize

4.3 注意事项

  • 三个张量(gradOutput、self、gradInput)的shape 与数据类型必须完全一致,否则第一段接口返回ACLNN_ERR_PARAM_INVALID(161002);
  • betaOptionalnullptr时按β = 1.0计算,此时算子退化为 PyTorch 中默认swish的梯度形式;传入时其数据类型需可互推导为 FLOAT;
  • bf16 输入仅在支持 bf16 的 SoC 版本(ASCEND910B~ASCEND910E)上可用;
  • 该算子底层为逐元素计算,输出与输入同 shape;y入参为预留项,当前版本不参与运算。

五、总结

SwishGrad 算子是 ops-nn 仓库中一个典型的逐元素反向算子样例,完整展示了 CANN 算子的标准五件套:OpDef 注册(swish_grad_def.cpp)、InferShape(swish_grad_infershape.cpp)、Host 侧 tiling(swish_grad_tiling.cpp)、AI Core 内核(op_kernel/swish_grad.h)与 aclnn 两段式对外接口(aclnn_swish_backward.cpp)。理解其数学推导(σ(βx)·(1+βx(1-σ(βx))))、多核均衡 tiling 策略、半精度转浮点计算的精度处理,以及两段式接口的调用范式,即可举一反三地接入 ops-nn 中其他同构的激活函数反向算子(如 SiluGrad)。实际开发中若需验证算子行为,可参考仓库 tests/ut 下的 op_api、op_host、op_kernel 三级测试用例,或直接编译运行 examples/test_aclnn_swish_grad.cpp 样例。

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

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 23:20:41

跨库关联查询的技术债:业务拆分后数据冗余同步与 Canal 监听实战

跨库关联查询的技术债&#xff1a;业务拆分后数据冗余同步与 Canal 监听实战在单体架构&#xff08;Monolith&#xff09;时代&#xff0c;处理复杂的前端展示需求极其轻松&#xff1a;一条包含四五个 LEFT JOIN 的 SQL 语句&#xff0c;就能把订单表、用户资料表、商家信息表与…

作者头像 李华
网站建设 2026/9/20 23:20:19

深圳GEO优化服务商哪家靠谱?生成式引擎优化选型指南

1. 先搞清楚“靠谱”到底在问什么“深圳GEO优化服务商哪家靠谱”这个问题&#xff0c;我在过去大半年里被问过不下二十次。问的人有做跨境电商的、有做本地生活服务的、也有做SaaS工具的&#xff0c;行业五花八门&#xff0c;但焦虑点出奇地一致&#xff1a;钱花出去了&#xf…

作者头像 李华
网站建设 2026/9/20 23:16:15

HR SOP手册怎么写?从流程拆解到落地实操指南

简介&#xff1a;这是一份面向酒店/企业人力资源部门及行政管理人员的标准操作手册&#xff0c;涵盖行政办公与人力管理两大板块。资源以doc文档形式提供&#xff0c;共1个文件&#xff0c;压缩包大小约402KB&#xff0c;内容按TY-EO-SOP和TY-HR-SOP系列编号组织&#xff0c;系…

作者头像 李华
网站建设 2026/9/20 23:13:40

401 invalid_api_key?TaoToken + Cline 这样核对 DeepSeek V4.1 Flash 模型 ID

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华