- 人工智能
- 算子库
- 深度学习
- CANN
- Ascend
【免费下载链接】ops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
FusedBiasLeakyRelu 是 CANN ops-nn 仓库中面向 NPU(Ascend 910B)提供的一个融合激活算子,它将「加偏置(Bias Add)」与「带负斜率与缩放因子的 LeakyReLU 激活」合并为一次内核计算,用于减少访存与算子下发开销。本文以 experimental/activation/fused_bias_leaky_relu/docs/aclnnFusedBiasLeakyRelu.md 为骨架,结合 experimental/activation/fused_bias_leaky_relu 目录下的 ACLNN L2 接口实现、Tiling 逻辑、AscendC Kernel 与单元测试,完整讲解其数学定义、两段式 ACLNN 调用流程、参数约束与底层实现原理,帮助你快速在业务代码中接入该算子并理解其工作机制。
算子定位与目录结构
在 CANN ops-nn 中,FusedBiasLeakyRelu 目前以aclnn 接口形态提供(即面向应用侧的 L2 API),仓库目录 experimental/activation/fused_bias_leaky_relu 中包含了完整的接口声明、实现、Tiling、Kernel 与测试代码:
docs/aclnnFusedBiasLeakyRelu.md:官方接口说明文档;op_api/:ACLNN L2 API 声明与实现(aclnn_fused_bias_leaky_relu.h/.cpp、fused_bias_leaky_relu.h/.cpp);op_graph/:算子图协议定义fused_bias_leaky_relu_proto.h;op_host/:算子定义(fused_bias_leaky_relu_def.cpp)、Shape 推导(fused_bias_leaky_relu_infershape.cpp)以及 arch35 平台的 Tiling 实现;op_kernel/:AscendC 内核入口(fused_bias_leaky_relu_apt.cpp)与内核类实现、TilingData 结构、模板参数定义;examples/test_aclnn_fused_bias_leaky_relu.cpp:完整的端到端调用示例;tests/ut/:覆盖 op_api、op_host(Tiling/Infershape)、op_kernel 的单元测试。
该算子的语义是计算「融合的 Bias Add + LeakyReLU 激活」:对输入张量 x 加上偏置 bias 后,再应用带缩放因子 scale 的 LeakyReLU 激活。将原本需要两次算子调用(Add 与 LeakyReLU)的流程合并为一次,是典型的访存优化型融合算子。
数学定义与计算公式
对输入张量 x 与偏置张量 bias 逐元素相加得到 t,再按 t 的符号应用带负斜率的激活与统一缩放:
t = x + bias 当 t >= 0 时:y = t * scale 当 t < 0 时:y = t * negative_slope * scale其中:
- x:输入数据张量;
- bias:偏置张量,shape 与 x 完全相同(不支持广播);
- negative_slope:LeakyReLU 负半轴斜率(float 类型属性,默认 0.2);
- scale:缩放因子(float 类型属性,默认 1.414213562373,即 √2);
- y:输出张量,shape 和 dtype 与 x 相同。
从 Kernel 实现看,该公式在 op_kernel/arch35/fused_bias_leaky_relu.h 的 Compute 阶段被逐元素执行;而 CPU 侧的黄金参考(golden)实现在 examples/test_aclnn_fused_bias_leaky_relu.cpp 的ComputeGolden函数中,逻辑与上式完全一致,可用于精度比对。
支持的产品型号
| 产品系列 | 芯片型号 | 支持状态 |
|---|---|---|
| Atlas A2 训练系列 | Ascend910B | YES |
同时,从 op_host/fused_bias_leaky_relu_def.cpp 的算子注册信息可以看到,该算子注册的 AICore 配置名为ascend950(对应 Ascend 910B 芯片平台),支持动态编译、动态 Rank、动态 Shape,并开启PrecisionReduceFlag(允许精度降低以换取性能),内核文件指定为fused_bias_leaky_relu_apt。
函数原型:两段式 ACLNN 接口
ACLNN(Ascend Computing Language NN API)的 L2 接口采用两段式设计:第一阶段计算 workspace 大小并创建执行器,第二阶段真正下发执行。FusedBiasLeakyRelu 的函数原型如下:
aclnnStatus aclnnFusedBiasLeakyReluGetWorkspaceSize( const aclTensor *x, const aclTensor *bias, double negativeSlope, double scale, const aclTensor *out, uint64_t *workspaceSize, aclOpExecutor **executor); aclnnStatus aclnnFusedBiasLeakyRelu( void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream);接口声明位于 op_api/aclnn_fused_bias_leaky_relu.h,以extern "C"+ACLNN_API导出,可直接被 C/C++ 应用调用。
参数说明
aclnnFusedBiasLeakyReluGetWorkspaceSize
| 参数名 | 输入/输出 | 类型 | 说明 |
|---|---|---|---|
| x | 输入 | const aclTensor* | 输入数据张量。数据类型支持 FLOAT16、FLOAT。数据格式支持 ND。最高支持 8 维。 |
| bias | 输入 | const aclTensor* | 偏置张量。数据类型和 shape 必须与 x 一致。数据格式支持 ND。 |
| negativeSlope | 输入 | double | LeakyReLU 负半轴斜率系数。可选,默认值 0.2。 |
| scale | 输入 | double | 缩放因子。可选,默认值 1.414213562373(即 √2)。 |
| out | 输入 | const aclTensor* | 输出张量(需预分配)。数据类型和 shape 必须与 x 一致。数据格式支持 ND。 |
| workspaceSize | 输出 | uint64_t* | 返回执行算子所需的 workspace 大小(字节)。 |
| executor | 输出 | aclOpExecutor** | 返回算子执行器。 |
注意:negativeSlope与scale在接口层是double 类型,但在算子属性注册(fused_bias_leaky_relu_def.cpp)与 TilingData 中均以float存储,Tiling 阶段会完成 double → float 的转换(见 fused_bias_leaky_relu_tiling.cpp 的GetShapeAttrsInfo,读取后转换为 float 写入 TilingData)。
aclnnFusedBiasLeakyRelu
| 参数名 | 输入/输出 | 类型 | 说明 |
|---|---|---|---|
| workspace | 输入 | void* | 在 Device 侧申请的 workspace 内存地址。 |
| workspaceSize | 输入 | uint64_t | workspace 内存大小(字节),由第一阶段接口 aclnnFusedBiasLeakyReluGetWorkspaceSize 获取。 |
| executor | 输入 | aclOpExecutor* | 算子执行器,由第一阶段接口 aclnnFusedBiasLeakyReluGetWorkspaceSize 获取。 |
| stream | 输入 | aclrtStream | ACL stream 流。 |
返回值
| 返回值 | 说明 |
|---|---|
| ACLNN_SUCCESS (0) | 成功 |
| ACLNN_ERR_PARAM_NULLPTR | 输入参数中存在空指针 |
| ACLNN_ERR_PARAM_INVALID | 输入参数不合法(dtype 不匹配、shape 不一致、不支持的 dtype、不支持的 format、维度超限等) |
| ACLNN_ERR_INNER_CREATE_EXECUTOR | 内部创建执行器失败 |
| ACLNN_ERR_INNER_NULLPTR | 内部操作返回空指针 |
其中参数校验相关的错误码在 op_api/aclnn_fused_bias_leaky_relu.cpp 的CheckParams链路中逐类触发:CheckNotNull对应ACLNN_ERR_PARAM_NULLPTR,CheckDtypeValid/CheckFormat/CheckShape均返回ACLNN_ERR_PARAM_INVALID。
约束说明
- x、bias、out 三者的数据类型(dtype)必须一致,仅支持FLOAT16和FLOAT。此约束同时体现在接口层(aclnn_fused_bias_leaky_relu.cpp 中
AICORE_DTYPE_SUPPORT_LIST = {DT_FLOAT16, DT_FLOAT})、算子定义层(fused_bias_leaky_relu_def.cpp的DataType({ge::DT_FLOAT16, ge::DT_FLOAT}))以及 Tiling 层(fused_bias_leaky_relu_tiling.cpp的supportedDtype集合)。 - x 和 bias 的 shape 必须完全相同,不支持广播。接口层
CheckShape会逐维比对 x 与 bias 的 shape;Tiling 层也会校验三者的元素总数一致。 - out 的 shape 必须与 x 相同(Shape 推导实现见 fused_bias_leaky_relu_infershape.cpp,直接拷贝输入 x 的 shape 作为输出 shape)。
- negativeSlope 和 scale 为 double 类型可选属性,带默认值(negative_slope=0.2,scale=1.414213562373)。
- 支持的数据格式为ND,不支持 Private format。接口层
CheckFormat会通过IsPrivateFormat校验三个张量的 storage format。 - 张量最高支持8 维(接口层通过
ACLNN_MAX_SHAPE_RANK = 8与OP_CHECK_MAX_DIM校验)。 - 当输入张量为空张量(包含 0 元素)时,workspaceSize 返回 0,直接返回成功(见
HasEmptyTensor的短路逻辑)。
调用示例:完整的两段式流程
仓库提供了可直接编译运行的完整示例 examples/test_aclnn_fused_bias_leaky_relu.cpp,其运行前提是:已安装 CANN toolkit(设置 ASCEND_HOME_PATH)、已安装算子包、存在可用的 NPU 设备。示例通过bash run.sh --eager构建运行(对应 scripts 目录下的算子包构建与安装流程)。完整调用步骤如下:
- 初始化 ACL 环境:
aclInit(nullptr)、aclrtSetDevice(deviceId)、aclrtCreateStream(&stream); - 准备输入数据并创建 aclTensor:通过
aclrtMalloc申请 Device 内存,aclrtMemcpy将 Host 数据拷入,再调用aclCreateTensor以 ND 格式创建张量描述(示例使用了 shape{2, 4},x 为混合正负值的浮点数据,bias 为常数偏置,属性取negativeSlope=0.2、scale=1.414213562373); - 调用第一阶段接口
aclnnFusedBiasLeakyReluGetWorkspaceSize获取 workspace 大小与 executor; - 分配 workspace 内存:若
workspaceSize > 0,通过aclrtMalloc在 Device 侧申请; - 调用第二阶段接口
aclnnFusedBiasLeakyRelu(workspace, workspaceSize, executor, stream)执行计算; - 同步流并拷贝结果回 Host:
aclrtSynchronizeStream(stream)后用aclrtMemcpy(DEVICE_TO_HOST)取回输出; - 清理资源:释放 workspace、销毁 tensor、释放 Device 内存、销毁 stream、
aclrtResetDevice与aclFinalize。
示例还实现了CPU golden 参考比对:ComputeGolden逐元素计算期望值,CompareResults以atol=1e-4、rtol=1e-4、失配率小于 0.01% 为通过阈值,并对每个元素打印 x、bias、t=x+bias、Golden 与 NPU 输出,便于肉眼核对与精度分析。
底层实现解析:从 L2 接口到 NPU 内核
L2 接口内部调用链
aclnn_fused_bias_leaky_relu.cpp 的aclnnFusedBiasLeakyReluGetWorkspaceSize完整展示了 L2 接口的组装过程:
- 创建 executor(失败返回
ACLNN_ERR_INNER_CREATE_EXECUTOR); - 执行
CheckParams参数校验(空指针、dtype、format、shape); - 空张量短路:x 或 bias 为空时直接返回 workspaceSize=0 与成功;
- 对 x、bias 分别调用
l0op::Contiguous保证内存连续; - 调用
l0op::FusedBiasLeakyRelu(xContiguous, biasContiguous, negativeSlope, scale, ...)构建计算图节点; - 通过
l0op::ViewCopy(opResult, out, ...)将计算结果搬运到用户预分配的输出张量; - 通过
uniqueExecutor->GetWorkspaceSize()返回所需 workspace 大小。
第二阶段aclnnFusedBiasLeakyRelu则通过CommonOpExecutorRun(workspace, workspaceSize, executor, stream)统一完成执行,代码中亦通过L2_DFX_PHASE_1/2宏记录 DFX 日志,便于问题定位。
Tiling:多核切分与双缓冲决策
arch35 平台的 Tiling 实现位于 op_host/arch35/fused_bias_leaky_relu_tiling.cpp,核心步骤:
- 平台信息获取:通过
PlatformAscendC获取 AIV 核数(GetCoreNumAiv)与 UB 内存大小(GetCoreMemSize(UB)); - 多核切分:
blockFactor = CeilAlign(CeilDiv(totalNum, coreNum), ubBlockSize),将总元素数按 32 字节对齐粒度均分到各核,usedCoreNum = CeilDiv(totalNum, blockFactor)作为实际 block dim; - 双缓冲决策:计算单核每轮 UB 循环次数,若至少 2 次(
loopCountIfDouble >= 2)则启用双缓冲(useDoubleBuffer=1),否则单缓冲; - UB 拆分:
bufferNum = TENSOR_NUM * (useDoubleBuffer ? 2 : 1)(即 6 或 3 个 buffer),ubFactor为每次 UB 循环处理的元素数,并按ubBlockSize向下对齐; - 写入 TilingData:
totalNum / blockFactor / ubFactor / negativeSlope / scale五个字段写入 fused_bias_leaky_relu_tiling_data.h 定义的结构体; - TilingKey 下发:通过
ASCENDC_TPL_SEL_PARAM(context, dTypeX, useDoubleBuffer)将数据类型与缓冲模式作为模板参数下发到内核,实现同一内核的编译期特化。
值得一提的是,该算子的 workspace 需求为 0(WS_SYS_SIZE = 0),因此接口层的 workspaceSize 主要来自 L0 图执行框架本身的系统开销。
AscendC Kernel:流水线与模板特化
内核入口 fused_bias_leaky_relu_apt.cpp 以template <typename D_T_X, int BUFFER_MODE>形式实例化,通过REGISTER_TILING_DEFAULT与GET_TILING_DATA_WITH_STRUCT读取 TilingData,并调用 fused_bias_leaky_relu.h 中NsFusedBiasLeakyRelu::FusedBiasLeakyRelu内核类的Init与Process:
- Init:根据
GetBlockIdx() * blockFactor计算当前核的 GM 偏移与处理长度(blockLength_),推导 UB 循环次数loopCount_与尾块元素数tailNum_,将 double 型属性转换为模板类型 T(half/float),初始化三个 GlobalTensor(x、bias、y)与三组队列(VECIN 双队列 + VECOUT 单队列,队列深度由BUFFER_NUM = BUFFER_MODE ? 2 : 1决定); - Process:采用经典的 CopyIn → Compute → CopyOut 三段流水,先循环处理完整块,再处理尾块;若当前核
blockLength_ <= 0(元素数少于核数)则直接返回; - Compute:逐元素计算
y = (t >= 0) ? t * scale : t * negativeSlope * scale,其中t = x + bias。
测试与验证
仓库为该算子提供了分层的单元测试(tests/ut/目录):
- op_api 层:tests/ut/op_api/test_aclnn_fused_bias_leaky_relu.cpp 验证 L2 接口的调用与结果;
- op_host 层:tests/ut/op_host/arch35/test_fused_bias_leaky_relu_tiling.cpp 验证 Tiling 参数的切分正确性,tests/ut/op_host/test_fused_bias_leaky_relu_infershape.cpp 验证 Shape 推导;
- op_kernel 层:tests/ut/op_kernel/test_fused_bias_leaky_relu_apt.cpp 验证内核计算逻辑。
结合 examples/test_aclnn_fused_bias_leaky_relu.cpp 中的 golden 比对逻辑,可以形成「接口调用 → 内核执行 → 精度校验」的完整验证闭环,这也是将该算子集成进自有业务前推荐的最低验证标准。
小结
FusedBiasLeakyRelu 以融合算子形态(Bias Add + LeakyReLU + Scale)减少了中间张量的读写,配合 ACLNN 两段式接口在 Ascend 910B 上运行。接入时重点关注三点:dtype 仅支持 FLOAT16/FLOAT、x 与 bias 的 shape 必须逐维一致(不支持广播)、输入格式为 ND 且最高 8 维。通过阅读 接口文档 与本文给出的源码路径,你可以快速定位到 L2 接口校验、Tiling 切分、双缓冲决策与内核流水线的每一处实现细节,为后续调试、性能分析或参考其模式贡献新的融合算子(贡献 AscendC 实现的流程见仓库根目录的 CONTRIBUTING.md)打下基础。
- 人工智能
- 算子库
- 深度学习
- CANN
- Ascend
【免费下载链接】ops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
相关推荐
CANN ops-nn 中 aclnnFusedBiasLeakyRelu 融合算子:Bias Add + LeakyReLU 的 ACLNN 两段式调用指南
CANN ops nn 中 aclnnFusedBiasLeakyRelu 融合算子:Bias Add + LeakyReLU 的 ACLNN 两段式调用指南
人工智能算子库深度学习CANNAscendCANN ops-nn 中 LeakyRelu 算子解析:从 aclnn 两段式接口调用到 NPU 内核实现
CANN ops nn 中 LeakyRelu 算子解析:从 aclnn 两段式接口调用到 NPU 内核实现 本篇技术文章围绕 CANN 开源算子库 ops n
人工智能算子库深度学习CANNAscendCANN ops-nn EmbeddingDenseGrad 算子深度解析:scatter-add 语义、ACLNN 两段式接口与 310P 部署实战
CANN ops nn EmbeddingDenseGrad 算子深度解析:scatter add 语义、ACLNN 两段式接口与 310P 部署实战 Embe
人工智能算子库深度学习CANNAscend
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考