合并受阻
变更摘要
本 PR 为 CANN「代码侦探」第十三期 exercises 算子题目提交,围绕自定义 Leakyrelu 算子补全了一套完整实现:包含算子定义与形状推导、Host 侧 Tiling、AscendC Kernel 实现、aclnn 样例调用、参考实现与数据校验脚本,以及基于 gtest 的 Host/Kernel UT 与构建脚本。整体上形成从算子注册、tiling 下发、kernel 计算到样例与单测验证的闭环。
主要改动
- 算子定义与注册: 新增
op_host/leakyrelu_def.cpp,通过OpDef注册Leakyrelu,输入x、输出y均声明REQUIRED且支持DT_FLOAT/DT_FLOAT16、格式FORMAT_ND并启用AutoContiguous,属性negative_slope为Float,AI Core 配置为ascend910b;leakyrelu_infershape.cpp中InferShapeLeakyrelu将输入 shape 直接传给输出。 - Tiling 与模板键:
op_host/leakyrelu_tiling.cpp的LeakyreluTilingFunc依据 AIV 核数、UB 容量和 32B 对齐做多核与 UB 两级切分,读取negative_slope属性(缺失时回退默认值),写入LeakyreluTilingData并通过SetTilingKey按 dtype 选择LEAKYRELU_TPL_SCH_MODE_0(half)或MODE_1(float);leakyrelu_tiling_key.h用ASCENDC_TPL_ARGS_DECL声明schMode模板参数。 - Kernel 计算实现:
op_kernel/leakyrelu.h的NsLeakyrelu::Leakyrelu<T>使用TQue双缓冲搬运并按blockFactor/ubFactor循环,按max(x,0) + negative_slope * min(x,0)计算;half 分支先Cast到 float 再计算以降低精度损失,leakyrelu.cpp按 tilingKey 分派half/float模板实例。 - Tiling 数据结构与兼容标记:
leakyrelu_tiling_data.h定义LeakyreluTilingData(totalNum、blockFactor、ubFactor、slopeTag、negativeSlope、reserved),并引入LEAKYRELU_DEFAULT_SLOPE与LEAKYRELU_SLOPE_TAG标记;kernel 在slopeTag不匹配时回退默认斜率,保证直接构造 tiling 数据的 Kernel UT 仍可正确计算。 - 样例、构建与测试链路: 新增
build.sh(支持-j、--make_clean、-u、-e,含源码指纹增量重建与产物检查)、examples/下基于aclnnLeakyreluGetWorkspaceSize/aclnnLeakyrelu的 NPU 样例和samples/sample.py的generate/verify(含 rtol/atol 比对与reference.impl参考实现),以及tests/ut下TilingContextFaker、InferShapeContextFaker、case executor 等测试基础设施和test_leakyrelu_tiling.cpp、test_leakyrelu.cpp等 Host/Kernel UT 用例。


/compile


代码审查
审查结论
- [建议]
2026/CANN-Code-Detective/Challenge13-LeakyReluCustom/PR_code/ZY_weixin_48190404_13/code/exercises/CMakeLists.txt:14fix: 默认 ASCEND_COMPUTE_UNIT 覆盖三个 SoC 而算子仅注册 ascend910b - [建议]
2026/CANN-Code-Detective/Challenge13-LeakyReluCustom/PR_code/ZY_weixin_48190404_13/code/exercises/op_kernel/leakyrelu.h:112fix: 尾块按 32B 对齐多读会越过输入张量 GM 边界 - [建议]
2026/CANN-Code-Detective/Challenge13-LeakyReluCustom/PR_code/ZY_weixin_48190404_13/code/exercises/op_kernel/leakyrelu.h:160fix: 尾块写回使用未按 32B 对齐的元素个数 - [阻塞]
2026/CANN-Code-Detective/Challenge13-LeakyReluCustom/PR_code/ZY_weixin_48190404_13/code/exercises/tests/ut/op_host/test_leakyrelu_tiling.cpp:36fix: op_host UT 的 expectTilingData 期望值与实际 tiling 输出不一致
| 类型 | 数量 |
|---|---|
| 🔴 阻塞 | 1 |
| 🟡 建议 | 3 |
⛔ 需要修改


Thanks for your pull-request.
The full list of commands accepted by me can be found at here.
You can get sig-info at here.
You can self-configure the PR merge rules for this repository. For more details, please refer to Here.
For more, you also can visit HICANN.
PR Approval Progress
⚠️ This PR does not yet meet the following requirements:lgtm (requires ≥ 2 person(s) per module)、approve (requires ≥ 1 person(s) per module)
Module Approval Details
| module | lgtm status | approve status |
|---|---|---|
| repo-cann/cann-outreach | ❌ (0/2)(You can also ask: Carolina_yuan, li-shengxian3, shaoyf, 王艳秋, 颜亚文) | ❌ (0/1)(You can also ask: shaoyf, 田晓亮, Carolina_yuan, 颜亚文, gcw_tgPdOLZT) |
💡 Tip:
- Committer can comment
/approveor/lgtm- Commenting
/approveimplies both code review (lgtm) and intent to merge (approve)
CLA Signature Pass
weixin_48190404, thanks for your pull request. All authors of the commits have signed the CLA. 👍


🟠 High Priority
建议:先执行一次 tiling(可用 ExecuteTiling 取 TilingInfo),把 totalNum/blockFactor/ubFactor/slopeTag/negativeSlope+reserved 这 5 个 int64 槽位的真实值填入 expectTilingData;或改用字段级断言替代整段字符串比较。


🟡 Medium Priority
变更点:本文件第 14–16 行在未传入 -DASCEND_COMPUTE_UNIT 时,把 ASCEND_COMPUTE_UNIT 默认为 ascend910b ascend910_93 ascend950(5–16 行的 ARCH32/ARCH35 列表)。
受影响契约:npu_op_package 会按 ASCEND_COMPUTE_UNIT 逐 SoC 打包,而 op_host/leakyrelu_def.cpp:26 只写了 this->AICore().AddConfig("ascend910b"),即算子仅在 ascend910b 上注册。
失效模式:一旦不显式传参(例如直接 cmake -S . -B build && cmake --build build)构建,产出的 vendor 包里 ascend910_93 / ascend950 目录没有该算子(或 arch35 下 kernel 编译/调优路径无对应 op def),在这些 SoC 上运行 examples 会报“算子未注册/找不到算子”,而不是构建期就暴露。当前 build.sh:50/114 显式传了 -DASCEND_COMPUTE_UNIT=ascend910b,所以默认路径才触发,实测概率中等。
建议:将默认值收敛为算子实际注册的 SoC(ascend910b),或在 op_host/leakyrelu_def.cpp 中为 ARCH32/ARCH35 列表中的每个 SoC 追加 AICore().AddConfig(...),避免出现“包里有 SoC 目录、但没有该算子”的不一致。


🟡 Medium Priority
变更行:leakyrelu.h:165 DataCopy(outputGMY[offset], yLocal, static_cast<int32_t>(currentNum));。
证据链:同一文件的 CopyIn(leakyrelu.h:117)刻意把搬入长度 AlignUp 到 alignElems_ 以满足 AscendC DataCopy 的 32B(datablock)长度对齐要求,而 CopyOut 却直接用未对齐的 currentNum。currentNum 来自 Process(第 177-178 行)remain < ubLength_ ? remain : ubLength_;host tiling 未对齐 totalNum(op_host/leakyrelu_tiling.cpp:96-105),所以末核最后一块的 currentNum 常常不是 alignElems_(float 8 / half 16)的整数倍。
失败模式:DataCopy 的搬运长度按 datablock 粒度处理,长度非 32B 整数倍时行为不符合接口约定——按 32B 向上取整会把 UB 中尾部未初始化/无意义数据写到 GM,对最后一个核就是写到输出张量末尾之外(破坏相邻输出或内存池数据,验证脚本按精确字节数比对时表现为越界污染);若硬件严格校验则直接报 AIC Error。
建议:尾块写回使用 DataCopyPad(按 currentNum*sizeof(T) 的真实字节长度),或统一按对齐长度写回并在 host 侧保证输出张量有对齐余量,避免向 GM 写入非 32B 对齐长度。


🟡 Medium Priority
变更行:leakyrelu.h:95-97 用 gmLength = AlignUp(blockLength_, alignElems_) 声明 GlobalTensor 长度,leakyrelu.h:117-118 再用 copyNum = AlignUp(currentNum, alignElems_) 搬入。
证据链:host 侧 tiling(op_host/leakyrelu_tiling.cpp:96-107)计算 totalNum 为各维乘积,未做 32B 对齐,只有 blockFactor = CeilAlign(CeilDiv(splitNum, usedCoreNum), alignElems) 对齐;因此最后一个核的 blockLength_ = totalNum - offset 可以是任意值(例如 float 输入 9 个元素、blockFactor=8 时,末核 blockLength_=1)。此时 gmLength = 8、copyNum = 8,但该核实际可用元素只有 1 个。
失败模式:DataCopy 会读取 x + totalNum 之后最多 alignElems_-1 个元素(float 为 28 字节、half 为 30 字节)的越界 GM 数据;SetGlobalBuffer 声明的长度本身也已超过真实张量长度,越界读到的内容依赖相邻内存,虽只用于计算不回写,但越过输入张量末尾属于典型 GM 越界访问,在尾部恰好压到内存池边界时可能触发 AIC Error/精度校验异常。
建议:把尾块搬入改为 DataCopyPad(blockLen 取 currentNum*sizeof(T),越界部分由 pad 参数补齐),并与 CopyOut 的对齐策略保持一致,避免按 AlignUp 后的长度读取输入张量之外的内存。


个人开发者
团队信息
成员
算子: exercises
算子实现介绍
采用多核并行实现,每核至少处理1024个元素,UB内按双缓冲切分,搬运与计算均按32B对齐;negative_slope属性通过TilingData由Host下发至Kernel,half类型先转为float计算以保证精度。