- 人工智能
- 算子库
- 深度学习
- CANN
- Ascend
【免费下载链接】ops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
LeakyReluV2 是 CANN ops-nn 神经网络算子库中基于昇腾 NPU 实现的一类 LeakyRelu 激活算子,其核心在于引入negative_slope(负斜率)属性,在保留 ReLU 稀疏激活特性的同时避免负区间梯度完全消失。本文以仓库内 experimental/activation/leakyrelu_v2/README.md 为主线,结合算子定义、形状推导、Tiling 与 Kernel 源码,完整讲解其数学原理、参数约束,并给出可直接复制的 aclnn 两级接口调用样例,帮助读者在 Atlas A2 系列产品上快速完成 LeakyRelu 算子的编译、调用与结果验证。
一、算子定位与数学原理
LeakyReluV2 是典型的逐元素(Elementwise)激活算子,与标准 ReLU 的最大区别是:当输入为负时不再直接输出 0,而是以negative_slope为斜率做线性缩放,从而缓解负区间神经元的“死亡”问题。
原文档给出的计算公式为:
$$ y = \begin{cases} x, & x \ge 0 \ negative_slope \times x, & x < 0 \end{cases} $$
从 Kernel 实现看,leakyrelu_v2.h 中的Compute阶段将其等价拆解为三个向量指令的组合:
AscendC::Maxs(tmpTensor1, xLocal, static_cast<T>(inputVal), this->tileDataNum); // tmp1 = max(x, 0) AscendC::Mins(tmpTensor2, xLocal, static_cast<T>(inputVal), this->tileDataNum); // tmp2 = min(x, 0) AscendC::Muls(tmpTensor2, tmpTensor2, static_cast<T>(this->negativeSlope), ...); // tmp2 = min(x, 0) * negative_slope AscendC::Add(yLocal, tmpTensor1, tmpTensor2, this->tileDataNum); // y = max(x, 0) + min(x, 0) * negative_slope即y = max(x, 0) + min(x, 0) * negative_slope,与分段公式在数学上完全等价,且避免了分支判断,更适合向量单元的流水化执行。
二、参数说明
依据原文档参数表,并结合 leakyrelu_v2_def.cpp 中的算子注册信息,参数定义如下:
| 参数名 | 输入/输出/属性 | 描述 | 数据类型 | 数据格式 |
|---|---|---|---|---|
| x | 输入 | 输入张量,任意形状(动态 Rank 支持) | FLOAT、FLOAT16 | ND |
| negative_slope | 属性 | 控制 x < 0 时的斜率,属性为可选(OPTIONAL) | FLOAT | - |
| y | 输出 | LeakyRelu 计算的结果,形状与 x 一致 | FLOAT、FLOAT16 | ND |
补充说明(来自源码佐证):
- 属性可选与默认值:
negativeSlope在算子定义中以Attr("negativeSlope").AttrType(OPTIONAL).Float()注册为可选属性。Tiling 阶段读取该属性时设置了兜底值:若属性为空,则按negativeSlope = 1.0f处理(参见 leakyrelu_v2_tiling.cpp 中float negativeSlope = 1.0f; // fallback一段),此时算子退化为恒等映射。实际使用时建议显式传入(PyTorch 等框架中 LeakyReLU 默认取 0.01)。 - 输出形状:InferShape 逻辑逐维拷贝输入形状(leakyrelu_v2_infershape.cpp),因此输出
y与输入x形状完全一致,属于形状保持(shape-preserving)算子。 - 输出数据类型:Graph 层的 InferDataType 将输入数据类型直接透传给输出(leakyrelu_v2_graph_infer.cpp),因此
y与x数据类型一致,不会发生隐式类型转换。
三、产品支持情况与数据类型约束
原文档明确:Atlas A2 训练系列产品 / Atlas A2 推理系列产品支持本算子(√)。
数据类型方面,Atlas A2 系列下支持FLOAT、FLOAT16两种类型。这一点在源码中有三重印证:
- 算子定义注册的输入/输出数据类型为
{ge::DT_FLOAT, ge::DT_FLOAT16}(leakyrelu_v2_def.cpp); - Tiling 阶段的 dtype 校验集合同样限定为
{ge::DT_FLOAT, ge::DT_FLOAT16},超出即返回GRAPH_FAILED(leakyrelu_v2_tiling.cpp); - 二进制算子配置 leakyrelu_v2_binary.json 中预生成
float32与float16两个 dtype 的 bin 条目,格式均为ND,属性negativeSlope为float类型。
约束说明:原文档标注为“无”,即算子对输入形状、维度数没有额外限制。从实现看,算子定义开启了DynamicRankSupportFlag(true)与DynamicShapeSupportFlag(true),可处理任意 Rank 与动态形状输入;Tiling 与 Kernel 对输入元素数为 0 的空张量也有专门处理(tiling 中totalIdx <= 0时仅置 1 个 block 并填充零 tiling 数据)。
四、aclnn 接口调用实战
原文档给出的调用方式是 aclnn 接口,并指向示例 test_aclnn_leakyrelu_v2.cpp。CANN 算子库的 aclnn 调用遵循标准的“两段式”流程:先通过GetWorkspaceSize接口查询并申请 workspace,再调用执行接口提交任务。完整可编译的关键流程如下(示例中以negativeSlope = 0.01f、形状{128, 8, 8, 8}、ACL_FLOAT为例):
#include "acl/acl.h" #include "aclnn_leakyrelu_v2.h" // 1. 初始化 device 与 stream aclInit(nullptr); aclrtSetDevice(0); aclrtCreateStream(&stream); // 2. 构造输入/输出 aclTensor(含申请 device 内存、host->device 拷贝、创建 strides) aclTensor* selfX = nullptr; // aclCreateTensor(shape, 4, ACL_FLOAT, strides, 0, // ACL_FORMAT_ND, shape, 4, selfXDeviceAddr) aclTensor* out = nullptr; // 输出形状与输入一致 // 3. 第一段接口:获取 workspace 大小并创建 executor uint64_t workspaceSize = 0; aclOpExecutor* executor = nullptr; ret = aclnnLeakyreluV2GetWorkspaceSize(selfX, negativeSlope, out, &workspaceSize, &executor); // 4. 按需为 workspace 申请 device 内存 void* workspaceAddr = nullptr; if (workspaceSize > 0) { aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); } // 5. 第二段接口:执行算子 ret = aclnnLeakyreluV2(workspaceAddr, workspaceSize, executor, stream); // 6. 同步等待并取回结果 aclrtSynchronizeStream(stream); aclrtMemcpy(resultData.data(), size, outDeviceAddr, size, ACL_MEMCPY_DEVICE_TO_HOST); // 7. 释放资源:aclDestroyTensor / aclrtFree / aclrtDestroyStream / aclrtResetDevice / aclFinalize调用要点:
- 接口命名:
aclnnLeakyreluV2GetWorkspaceSize(x, negativeSlope, y, &workspaceSize, &executor)与aclnnLeakyreluV2(workspaceAddr, workspaceSize, executor, stream),其中negativeSlope作为float类型直接以值参传入。 - ND 格式:示例通过
aclCreateTensor显式指定ACL_FORMAT_ND,与算子定义要求的FORMAT_ND一致。 - workspace 语义:Tiling 阶段通过
GetWorkspaceSize返回WS_SYS_SIZE(512B) + 系统库工作空间作为算子所需 workspace(leakyrelu_v2_tiling.cpp),调用方只需按第一段接口返回值申请即可,无需关心内部布局。 - 结果验证:示例中
PrintOutResult将 device 侧输出拷贝回 host 并逐元素打印,可用于与公式计算结果比对;负区间应输出x * 0.01,非负区间输出x本身。
除 aclnn 方式外,仓库还提供图模式(GEIR)调用样例 test_geir_leakyrelu_v2.cpp,适用于以构图方式接入算子的场景。
五、源码级实现原理
5.1 算子注册与属性配置
leakyrelu_v2_def.cpp 通过OpDef注册算子LeakyreluV2:输入x、输出y均为 REQUIRED,支持 ND 格式与AutoContiguous;AICore 配置绑定ascend910b平台,并开启动态编译、动态形状、动态 Rank 与精度降低(PrecisionReduceFlag)等能力。
5.2 Tiling:按核切分与多核负载均衡
Tiling 阶段(leakyrelu_v2_tiling.cpp)完成从平台信息到调度参数的换算:
- 读取 AIV 核数
coreNum与 UB 内存大小,以 32 字节BLOCK_SIZE为基本粒度、双缓冲BUFFER_NUM = 2为前提计算每个 tile 可容纳的数据量; - 按总字节数向上取整得到总 block 数,并将核数钳制到 block 总数以内;余数部分由前
tailBlockNum个核多承担一个 block(big-core),其余核为 small-core,实现多核负载均衡; - 最终把
smallCoreDataNum / bigCoreDataNum / tileDataNum / 各核 tile 数与尾部数据量 / tailBlockNum / negativeSlope写入 leakyrelu_v2_tiling_data.h 定义的LeakyreluV2TilingData结构,并通过context->SetBlockDim(finalCoreNum)设定启动核数。
tiling key 定义见 leakyrelu_v2_tiling_key.h,当前预留ELEMENTWISE_TPL_SCH_MODE_0 / _1两种调度模板;空输入场景固定使用SCH_MODE_0并只启动 1 个核。
5.3 Kernel:流水线化的三指令实现
leakyrelu_v2.cpp 是核侧入口,通过模板参数schMode与DTYPE_X实例化算子;leakyrelu_v2.h 中LeakyreluV2<T>类采用典型的“CopyIn → Compute → CopyOut”双缓冲流水:
Init根据当前核号判断 big/small-core 分支,计算全局缓冲区偏移并初始化 GM 张量与本地队列;Compute使用Maxs + Mins + Muls + Add四条向量指令完成上文所述y = max(x, 0) + min(x, 0) * negative_slope的计算;Process按 tile 数循环,最后一个 tile 使用tailDataNum处理不足一个整 tile 的尾部数据。
六、注意事项小结
negative_slope为可选属性,缺省按 1.0 处理;若需标准 LeakyReLU 行为,请显式传入如 0.01 的斜率值;- 仅支持 FLOAT/FLOAT16 与 ND 格式,其他数据类型会在 Tiling 阶段直接报错返回;
- 输出与输入形状、数据类型完全一致,无需额外指定输出属性;
- aclnn 调用必须遵循 GetWorkspaceSize → 申请 workspace → 执行 → 同步的四步流程,workspace 大小以第一段接口返回值为准;
- 本算子的当前源码实现主要面向 Atlas A2 系列(
ascend910b配置),部署前请确认运行产品型号。
通过本文,读者既可从参数层面快速上手 aclnn 调用,也可沿算子定义 → 形状推导 → Tiling → Kernel 的代码路径深入理解 CANN 算子在昇腾 NPU 上的完整落地过程。
- 人工智能
- 算子库
- 深度学习
- CANN
- Ascend
【免费下载链接】ops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
相关推荐
CANN ops-nn 算子 MaskedScatter 深度指南:功能原理、ACLNN 接口调用与源码实现解析
CANN ops nn 算子 MaskedScatter 深度指南:功能原理、ACLNN 接口调用与源码实现解析 本指南以仓库 experimental/ind
人工智能算子库深度学习CANNAscendCANN ops-nn 算子解析:SoftmaxCrossEntropyWithLogits 原理、aclnn 接口调用与源码实现
CANN ops nn 算子解析:SoftmaxCrossEntropyWithLogits 原理、aclnn 接口调用与源码实现 SoftmaxCrossEn
人工智能算子库深度学习CANNAscendCANN ops-nn 算子深度解析:TanhGrad 反向传播算子的实现原理与 aclnn 接口调用实战
CANN ops nn 算子深度解析:TanhGrad 反向传播算子的实现原理与 aclnn 接口调用实战 导读 TanhGrad 是 CANN ops nn
人工智能算子库深度学习CANNAscend
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考