Open
【代码侦探Challenge13】 DingLabChina - exercises #5647
【代码侦探Challenge13】 DingLabChina - exercises #5647
Open
JeffDingAdd on 1 day ago
JeffDing
JeffDing
1 day ago

DingLabChina

团队信息

成员

算子: exercises

PyTorch 原生算子:torch.nn.functional.leaky_relu,即 y = max(x, 0) + negative_slope * min(x, 0),负半轴斜率 negative_slope 默认 0.01
参考文档:https://docs.pytorch.org/docs/2.13/generated/torch.nn.functional.leaky_relu.html

likedislike
Merge blocked
JeffDingJeffDing
1 day ago Created pull request, commit a25a739b
atomgit-bot
atomgit-bot
1 day ago Comments:

变更摘要

本 PR 为 Challenge13 的 exercises 算子提交,围绕 PyTorch 原生 torch.nn.functional.leaky_relu(y = max(x,0) + negative_slope * min(x,0))实现了一套完整的 AscendC 自定义算子工程:包含算子原型定义、形状推导、host 侧 tiling、kernel 侧计算实现,以及配套的构建脚本、aclnn 示例、样本生成/校验脚本和 UT 测试框架。核心设计是将 negative_slope 的 IEEE-754 位模式编码进 tiling 数据传给 kernel,并按 dtype 区分 float16/float32 两条计算路径。

主要改动

  • 算子原型与形状推导:新增 op_host/leakyrelu_def.cpp,注册 Leakyrelu 的输入 x、输出 y(DT_FLOAT/DT_FLOAT16、FORMAT_ND、AutoContiguous)、Float 属性 negative_slope 及 ascend910b AICore 配置;op_host/leakyrelu_infershape.cpp 通过 IMPL_OP_INFERSHAPE 将输入 shape 直接透传到输出。
  • Tiling 策略与参数编码:op_host/leakyrelu_tiling.cpp 中 LeakyreluTilingFunc 读取 negative_slope 属性并在缺失/非法(位模式判断非有限数)时回退默认 0.01;把 slope 位模式编码到 ubFactor 高 32 位,并约定位模式 0 为“未设置”哨兵、slope == 0 编码为 denormal 位 1;同时按 MIN_SPLIT_THRESHOLD 与 UB_BYTES_PER_ELEM(16 字节/元素)计算 blockDim、blockFactor、UB 分块元素数,并按输入 dtype 分别设置 LEAKYRELU_TPL_SCH_MODE_0/1 的 tilingKey。
  • Kernel 计算实现:op_kernel/leakyrelu.h 的 NsLeakyrelu::Leakyrelu<T> 实现 Init/CopyIn/Compute/CopyOut/Process,使用双缓冲 TQue 与 DataCopyPad 处理非对齐尾块;half 输入走 Cast → LeakyRelu(float32) → Cast 的 float32 中间路径,float 输入直接原地计算;op_kernel/leakyrelu.cpp 按 schMode 模板参数实例化 half/float 两个 kernel。
  • 样本与示例链路:新增 samples/case.json(x/y 均为 8x2048 float32、negative_slope=0.01、rtol/atol=1e-4)、samples/reference.py(float64 中间计算后回写原 dtype)与 samples/sample.py(generate/verify 生成与比对 golden);examples/test_aclnn_leakyrelu.cpp 调用 aclnnLeakyreluGetWorkspaceSize/aclnnLeakyrelu 完成端到端验证。
  • 构建与 UT 框架:build.sh 提供 -j、--make_clean、-u/--ut、-e/--example 选项并基于源码指纹做增量构建;tests/ut 下新增 tiling_context_faker、infershape_context_faker、tiling_case_executor/infershape_case_executor 及 AnyValue 等测试基础设施,并配套 test_leakyrelu_tiling.cpp(tiling 用例断言)与基于 tikicpulib 的 test_leakyrelu.cpp kernel UT。
likedislike
Incorrect?
JeffDing
JeffDing
1 day ago Comments:

/compile

likedislike
atomgit-bot
atomgit-bot
1 day ago Comments:

代码审查

审查结论

  • [建议] 2026/CANN-Code-Detective/Challenge13-LeakyReluCustom/PR_code/DingLabChina_JeffDing/code/exercises/build.sh:38 fix: 未加引号的 rm -rf ${BUILD_PATH}/* 在路径含空格时会删除错误目录
  • [建议] 2026/CANN-Code-Detective/Challenge13-LeakyReluCustom/PR_code/DingLabChina_JeffDing/code/exercises/op_kernel/leakyrelu.h:80 fix: negative_slope 位模式为 0 时被误判为"未设置"并回退 0.01
  • [建议] 2026/CANN-Code-Detective/Challenge13-LeakyReluCustom/PR_code/DingLabChina_JeffDing/code/exercises/op_kernel/leakyrelu.h:64 fix: 不要用 int64 ubFactor 的高低 32 位混装元素数与 slope 位模式
  • [阻塞] 2026/CANN-Code-Detective/Challenge13-LeakyReluCustom/PR_code/DingLabChina_JeffDing/code/exercises/tests/ut/op_host/test_leakyrelu_tiling.cpp:36 fix: op_host UT 的期望 tilingData 是模板占位值,必然断言失败
  • [建议] 2026/CANN-Code-Detective/Challenge13-LeakyReluCustom/PR_code/DingLabChina_JeffDing/code/exercises/tests/ut/op_kernel/test_leakyrelu.cpp:66 fix: kernel UT 未校验 GmAlloc 返回值即写入/读取
  • [建议] 2026/CANN-Code-Detective/Challenge13-LeakyReluCustom/PR_code/DingLabChina_JeffDing/code/exercises/tests/ut/run.sh:5 fix: ENABLE_INNER_KERNEL_UT 默认 OFF 却无条件执行 kernel UT
类型 数量
🔴 阻塞 1
🟡 建议 5

⛔ 需要修改

likedislike
Incorrect?
CANN-robotCANN-robotCollaborators
1 day ago Added label: cann-cla/yes
CANN-robot
CANN-robotCollaborators
1 day ago Comments:

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, shaoyf, 王艳秋) ❌ (0/1)(You can also ask: 傅涛, luzx66, 王艳秋, gcw_tgPdOLZT, jxlang)

💡 Tip:

  • Committer can comment /approve or /lgtm
  • Commenting /approve implies both code review (lgtm) and intent to merge (approve)

CLA Signature Pass

JeffDing, thanks for your pull request. All authors of the commits have signed the CLA. 👍

likedislike
CANN-robotCANN-robotCollaborators
1 day ago Set yanhf,jxlang,shaoyf,TianXL,yanyawen,fullt,gcw_tgPdOLZT,Carolina_yuan,luzx66,cherry_03,li-shengxian3 as approver
CANN-robotCANN-robotCollaborators
1 day ago Set yanhf,jxlang,shaoyf,TianXL,yanyawen,fullt,gcw_tgPdOLZT,Carolina_yuan,luzx66,cherry_03,li-shengxian3 as approver
JeffDingJeffDing
1 day ago Change title to "【代码侦探Challenge13】 DingLabChina - exercises", originally titled "[代码侦探(第十三期)] DingLabChina - exercises".
atomgit-bot
atomgit-bot1 day agoStart code review1
2026/CANN-Code-Detective/Challenge13-LeakyReluCustom/PR_code/DingLabChina_JeffDing/code/exercises/tests/ut/op_kernel/test_leakyrelu.cpp
@@ -0,0 +66,4 @@
66+ uint8_t* x = (uint8_t*)AscendC::GmAlloc(xByteSize);
67+ uint8_t* y = (uint8_t*)AscendC::GmAlloc(yByteSize);
68+ uint8_t* workspace = (uint8_t*)AscendC::GmAlloc(32);
69+ uint8_t* tiling = (uint8_t*)AscendC::GmAlloc(tilingDataSize);
atomgit-bot
atomgit-bot1 day agoComments:

🟡 Medium Priority

变更行 tests/ut/op_kernel/test_leakyrelu.cpp:66-69 连续四次 AscendC::GmAlloc(...),返回值没有任何非空判断,随后第 71 行立刻 f.read(reinterpret_cast<char*>(x), 65536) 把文件内容写进 x,第 77 行把 tiling 指针 reinterpret_cast 后解引用赋值,第 92 行 memcpy 从 y 读出。

失败模式:GmAlloc 在 CPU 模拟器/受限内存下可能返回 nullptr,此时第 71 行向 nullptr 写入 65536 字节、或第 78-80 行向 nullptr 写入字段,直接段错误(测试崩溃且无任何提示信息),而不是给出可诊断的断言失败。工作区中同文件第 64 行已经对 getenv 做了断言检查,说明作者本意是防御性写法,这里遗漏了。

修复:每个 GmAlloc 之后 ASSERT_NE(ptr, nullptr),或改用 std::unique_ptr + 自定义 deleter 托管。

建议:在四次 GmAlloc 之后分别加 ASSERT_NE(x/y/workspace/tiling, nullptr),或封装成 RAII 句柄,保证分配失败时给出明确断言而非段错误。

likedislike
Incorrect?
atomgit-bot
atomgit-bot1 day agoStart code review1
2026/CANN-Code-Detective/Challenge13-LeakyReluCustom/PR_code/DingLabChina_JeffDing/code/exercises/build.sh
@@ -0,0 +35,4 @@
35+clean_build() {
36+ if [ -d "${BUILD_PATH}" ]; then
37+ echo "Cleaning build directory..."
38+ rm -rf ${BUILD_PATH}/*
atomgit-bot
atomgit-bot1 day agoComments:

🟡 Medium Priority

变更行:build.sh:38 rm -rf ${BUILD_PATH}/*(同类问题见 :45 rm -rf ${BUILD_OUT_PATH}/*,以及 :5 未加引号的 dirname $0)。

问题链条:BUILD_PATH 由 BASE_PATH(即 $(cd "$(dirname $0)" && pwd) 的结果)拼接而成,脚本对该路径没有任何字符约束。该行 ${BUILD_PATH} 未加引号,处于命令位置的操作数会被分词并做 glob 展开。

失效模式:当脚本所在目录包含空格(例如 /home/user/my code/exercises)时,${BUILD_PATH}/* 展开为多个词:/home/user/my、code/exercises/build/*。rm -rf 于是递归删除 /home/user/my(上一个目录层级中的真实目录),并把相对路径 code/exercises/build/* 当作当前工作目录下的路径处理——前一个 [ -d "${BUILD_PATH}" ] 守卫因为是加引号的、能通过,无法拦住此破坏。--make_clean 是文档中公开的入口,触发条件明确、后果是不可恢复的误删。第 45 行同理。

修复方向:所有拼接路径的 rm 操作数都必须加引号(并可考虑用 ${BUILD_PATH:?} 防止空值),与文件内 :133 rm -rf "$BUILD_PATH" 的写法保持一致;:5 的 dirname "$0" 也应加引号。

建议:给 rm 的目标路径加引号(必要时用 ${VAR:?} 防空值);第 45 行同样处理,第 5 行改为 dirname "$0"。

Suggestions
38
- rm -rf ${BUILD_PATH}/*
38
+ rm -rf "${BUILD_PATH:?}/"*
Apply suggestion
likedislike
Incorrect?
atomgit-bot
atomgit-bot1 day agoStart code review1
2026/CANN-Code-Detective/Challenge13-LeakyReluCustom/PR_code/DingLabChina_JeffDing/code/exercises/op_kernel/leakyrelu.h
@@ -0,0 +83,4 @@
83+ union { uint32_t u; float f; } slopeConv;
84+ slopeConv.u = slopeCode;
85+ slope_ = slopeConv.f;
86+ }
atomgit-bot
atomgit-bot1 day agoComments:

🟡 Medium Priority

改动行:leakyrelu.h:80-86(配合 22 行 LEAKY_RELU_SLOPE_ZERO_CODE = 0U)。
行为/契约:代码用"slope 的 IEEE-754 位模式是否为 0"来区分"属性未设置"和"已设置",位模式为 0 时把 slope_ 覆盖成默认值 0.01f。
失效模式:0.0f 的 IEEE-754 位模式恰好就是 0x00000000,因此 negative_slope = 0 这个 PyTorch 合法取值(等价于 ReLU,负半轴全部输出 0)会被静默替换为 0.01。触发条件:用例 attributes 中 negative_slope 取 0(框架默认值与 case.json 都是 0.01,所以现有用例发现不了)。此时所有负输入会输出 0.01*x 而不是 0,出现确定性 Wrong Answer。这说明"未设置"与"值为 0"语义被混用,不能靠数值本身当哨兵。
修复方向:用一个显式的存在性标记(例如 tiling 结构体中独立的 float negativeSlope 字段,或单独的 bool hasSlope/slopeBits 哨兵取 NaN 位模式等不可能取值),确保 slopeCode==0 时按 0.0f 正常参与计算。

建议:不要用 slope 的位模式 0 表达"未设置"。在 TilingData 中新增独立字段承载 negative_slope(见另一条 finding),kernel 直接读取该字段赋值给 slope_;或使用专门的哨兵(如 0xFFFFFFFF/NaN 位模式和显式 hasSlope 标记),使 negative_slope=0 能按 0.0f 正常生效。

likedislike
Incorrect?
atomgit-bot
atomgit-bot1 day agoStart code review1
2026/CANN-Code-Detective/Challenge13-LeakyReluCustom/PR_code/DingLabChina_JeffDing/code/exercises/op_kernel/leakyrelu.h
@@ -0,0 +62,4 @@
62+ totalNum_ = tilingData->totalNum;
63+ blockLength_ = tilingData->blockFactor;
64+ ubLength_ = static_cast<uint32_t>(static_cast<uint64_t>(tilingData->ubFactor) & 0xFFFFFFFFULL);
65+ uint32_t slopeCode = static_cast<uint32_t>(static_cast<uint64_t>(tilingData->ubFactor) >> 32);
atomgit-bot
atomgit-bot1 day agoComments:

🟡 Medium Priority

改动行:leakyrelu.h:64-65 把 tilingData->ubFactor 拆成低 32 位(UB 循环元素数)与高 32 位(negative_slope 的 IEEE-754 位模式);同时新增的 leakyrelu_tiling_data.h:12 把同一字段声明并注释为"每次 UB 循环处理的元素数量"。
行为/契约:同一字段在两个文件里语义不一致——结构体声明它是纯元素数,kernel 却把它当作 64 位打包值。任何一个按结构体注释/声明生成 tiling 的生产者(host tiling、UT tiling case、按字段名取值的断言)写入纯元素数时,高 32 位为 0,kernel 侧 slopeCode 恒为 0,所有非 0.01 的 negative_slope 用例都会静默按 0.01 计算;反之若生产者真的打包,ubFactor 会变成约 4e18 的异常大值,任何把它当元素数使用/校验的宿主侧代码都会失配。
失效模式:属性取值语义漂移导致的 Wrong Answer,且当前 case.json 只用默认 0.01,无法暴露该不一致。packing 约定跨文件且不可由 kernel 单侧自洽(违反算子规范"TilingID/TilingKey 字段语义需明确"的精神,正确做法是追加显式字段而非复用位)。
修复方向:在 LeakyreluTilingData 末尾追加独立字段(如 float negativeSlope 或 int32_t slopeBits + bool hasSlope),ubFactor 恢复为纯元素数;Init 中直接按字段解包,去掉移位掩码。

建议:在 LeakyreluTilingData 末尾追加独立的 negative_slope 字段(float 或 int32 位模式 + 显式存在性标记),并让 Init 直接读取该字段;ubFactor 只表达 UB 循环元素数,不再承载 slope 位模式。需同步确认 host tiling 的写入方式(本 PR 未包含该文件,无法在此验证)。

likedislike
Incorrect?
atomgit-bot
atomgit-bot1 day agoStart code review1
2026/CANN-Code-Detective/Challenge13-LeakyReluCustom/PR_code/DingLabChina_JeffDing/code/exercises/tests/ut/op_host/test_leakyrelu_tiling.cpp
@@ -0,0 +33,4 @@
33+// expectTilingData: 参考 op_host/leakyrelu_tiling.cpp 中 TilingData 各字段的赋值
34+// expectWorkspaces: 参考 op_host/leakyrelu_tiling.cpp 中 GetWorkspaceSize 的逻辑
35+static LeakyreluTestParam testCases[] = {
36+ {"leakyrelu_0", {8, 2048}, ge::DT_FLOAT, ge::FORMAT_ND, {8, 2048}, ge::DT_FLOAT, ge::FORMAT_ND, "Ascend910B", ge::GRAPH_SUCCESS, 1UL, "0 1 0 ", {0}, 64, 262144, 4096},
atomgit-bot
atomgit-bot1 day agoComments:

🟠 High Priority

变更行(tests/ut/op_host/test_leakyrelu_tiling.cpp:36)里 case "leakyrelu_0" 期望 expectTilingData = "0 1 0 "、expectWorkspaces = {0}、expectTilingKey = 1。

证据链:

  1. 该字符串正是 LeakyreluTilingData 的成员默认值(op_kernel/leakyrelu_tiling_data.h:10-12:totalNum=0、blockFactor=1、ubFactor=0),而不是实际 tiling 输出。
  2. op_host/leakyrelu_tiling.cpp 对 shape {8,2048} float 的实际计算为:totalNum=16384(第 115 行 GetShapeSize),blockDim=min(64, CeilDiv(16384,1024))=16(第 125-131 行),blockFactor=CeilDiv(16384,16)=1024(第 132 行),ubFactor=ubElems | (slopeCode<<32),其中 slopeCode 是 0.01f 的位模式 0x3C23D70A(第 151-155 行)。
  3. common/tiling_case_executor.cpp:275-278 会用 to_string<int64_t>(rawTilingData->GetData(), GetDataSize()) 与期望串做 EXPECT_EQ。

失败模式:三个 64 位字段的实际值(16384、1024、0x3C23D70A0000xxxx)不可能等于 "0 1 0 ",op_host UT 在 EXPECT_EQ(tilingDataResult, expectTilingData) 处稳定失败,run.sh 第 2 行 set -e 会导致整个 UT 流程中断。另外第 31-34 行的 TODO 也承认该期望值来自初始模板未更新。

修复:按实现的真实输出更新期望串(或先用 ExecuteTiling 打印实际值再回填),不要保留占位值。

建议:用实现真实输出更新 expectTilingData(totalNum / blockFactor / ubFactor 三个 int64 的十进制值,空格分隔),或改为传 EMPTY_EXPECT_TILING_DATA 暂时跳过该字段校验,避免 UT 必然失败。

likedislike
Incorrect?
atomgit-bot
atomgit-bot1 day agoStart code review1
2026/CANN-Code-Detective/Challenge13-LeakyReluCustom/PR_code/DingLabChina_JeffDing/code/exercises/tests/ut/run.sh
@@ -0,0 +7,4 @@
7+"$BUILD/op_host/leakyrelu_op_host_ut"
8+python3 "$ROOT/samples/sample.py" generate --directory "$ROOT/samples/build-cpu"
9+export SAMPLE_DIR="$ROOT/samples/build-cpu"
10+"$BUILD/op_kernel/leakyrelu_op_kernel_ut"
atomgit-bot
atomgit-bot1 day agoComments:

🟡 Medium Priority

变更行 tests/ut/run.sh:5 将 ENABLE_INNER_KERNEL_UT 默认置为 OFF 传入配置,但第 10 行无条件执行 "$BUILD/op_kernel/leakyrelu_op_kernel_ut",第 8-11 行也无条件先 generate 再 verify 内核样本。

失败模式:若 tests/ut/CMakeLists.txt 用该变量控制 op_kernel 子目录是否 add_subdirectory(变量名为 "INNER_KERNEL_UT",正是内核 UT 的开关),则默认 OFF 时该可执行文件根本不生成,第 10 行在 set -e 下以 "No such file or directory" 直接终止脚本,kernel 侧 UT 完全不会被验证;反之若该变量实际不控制任何东西,它就是一个误导性的死选项。这两种情况都属于脚本与构建约定的不一致。

修复:要么把第 10 行的执行也用同一开关包裹(if [ "${ENABLE_INNER_KERNEL_UT:-OFF}" = "ON" ]; then ... fi),要么默认值改为 ON 并显式说明内核 UT 一定构建。

建议:让 ENABLE_INNER_KERNEL_UT 的默认值与后续行为一致:或默认 ON,或把第 10、11 行的内核 UT 执行与样本 verify 同样用 if [ "${ENABLE_INNER_KERNEL_UT:-OFF}" = "ON" ] 包裹,避免默认配置下执行不存在的可执行文件。

likedislike
Incorrect?