| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
feat(in_training_reduce_v2): 新增 Ascend 950 AscendC 实现 无aclnn Co-authored-by: raoliang_sac<raoliang4@huawei.com> # message auto-generated for no-merge-commit merge: !8129 merge INTrainingReduceV2-no-aclnn into master feat(in_training_reduce_v2): 新增 Ascend 950 AscendC 实现 无aclnn Created-by: raoliang_sac Commit-by: raoliang_sac Merged-by: cann-robot Description: ## 描述 在 Ascend 950(arch35 / DAV_3510)平台用 AscendC 实现 InTrainingReduceV2 算子。 InTrainingReduceV2 是 Instance Normalization 训练前向的 reduce 阶段算子,与 INTrainingUpdateV2 配对使用:对每个 (N, C) 实例,在空间维度(4D: H,W;5D: D,H,W)上求和与平方和,输出两个统计量 sum = Σx 与 square_sum = Σx²(keepdims,输出恒 fp32)。 **关键语义**:Reduce 阶段输出原始求和,不做 1/num 缩放(均值/方差的除法在下游 Update 阶段完成)。移植时已删除参考算子 InstanceNorm 的 Muls(avgFactor) 除 R 与 Sub(x, mean) 中心化步骤。 **实现范围**: - dtype:fp16 / fp32 / bf16(输出恒 fp32) - format:4D NCHW / 4D ND / 5D NCDHW - 计算路径:R 全载(AR_FULL_REDUCE,按 R 阈值 64/128/8192 分档折叠)/ sub-R 分块累加(任意大 R,跨块 fp32 独立累加器)/ R=0 空 Tensor(host 侧零填充) - 通路:GE 图模式(proto + infershape + GEIR example),不含 aclnn 接口 **产品支持**:950(本PR新增AscendC实现)+ A2/A3/310p/310b(canndev已有TBE实现) ## 关联的Issue #4349 ## 测试 真实 NPU(Ascend 950PR_9579)验证: - **op_host UT**:16/16 通过(InferShape / InferDataType / Tiling 分支,含动态 shape -1/-2 用例) - **TTK 全量泛化测试**:500 kernel 全部 PASS,精度 100.0% - **GEIR 通路冒烟测试**:NPU 真机运行 test_geir_in_training_reduce_v2 通过 - **本地 CI 全项通过**:pre-commit / 文档链接 / 编译出包 / ophost UT / kernel UT / 冒烟测试 ## 文档更新 新增算子文档:README.md(完整6节)、docs/zh/op_list.md 算子条目。 ## 类型标签 - [x] 新特性 ## AI/Agent生成声明 - [x] AI辅助编写 See merge request: cann/ops-nn!8129 | 1 个月前 | |
fix(in_training_reduce_v2/sgd/normalize_bbox): 修复原型重定义与InferDataType放置,落地三算子检视整改 Co-authored-by: raoliang_sac<raoliang4@huawei.com> # message auto-generated for no-merge-commit merge: !8402 merge fix/three-ops-review-issue-4553 into master fix(in_training_reduce_v2/sgd/normalize_bbox): 修复原型重定义与InferDataType放置,落地三算子检视整改 Created-by: raoliang_sac Commit-by: raoliang_sac Merged-by: cann-robot Description: ## 描述 本 PR 一次性落地两块内容:Issue #4553 提出的交付件划分/原型重定义问题,以及 INTrainingReduceV2、SGD、NormalizeBBox 三个算子的代码检视意见。 ### 一、Issue #4553 **1. 原型重定义防护** 三个算子的原型都是从 canndev built-in 头( reduce_ops.h / nn_detect_ops.h / nn_training_ops.h,迁移后落在 ops_proto_legacy.h)挪出来的,两侧头文件被同一编译单元同时包含时会 REG_OP 重定义。已给三个 proto.h 的 REG_OP 补上防重定义宏,宏名沿用 ops_proto_legacy.h 自身的 OPS_PROTO_DEF_<OPTYPE> 约定: - OPS_PROTO_DEF_INTRAININGREDUCEV2 - OPS_PROTO_DEF_NORMALIZEBBOX - OPS_PROTO_DEF_SGD **2. InferDataType 交付件划分** InferDataType 仅图场景使用,从 op_host/*_infershape.cpp 挪到 op_graph/*_graph_infer.cpp(IMPL_OP 注册);InferShape 图与单算子共用,保留在 op_host(IMPL_OP_INFERSHAPE)。对齐仓内 norm/bn_infer_grad、norm/lp_norm_update、norm/in_infer_v2 的既有做法。add_graph_plugin_sources() 按 *_graph*.cpp 通配收集,无需改 CMakeLists。 ### 二、检视意见整改 **[高] INTrainingReduceV2 sub-R 路径 UB 越界** DoSubRTiling 只按 usable / 8 固定预留部分和缓存,算出 numChunks 后从不回验总占用。R 特别大时实际会撑破预留。按 Ascend950 实测参数(Ascend950*.ini 的 ub_size=253952,减 RESERVE_FOR_ALIGN=512 得 usable=253440B,VL_FP32=64): | dtype | 越界起点 R | 首版公式的 rFactor / numChunks | 实际申请 | 越界量 | |---|---|---|---|---| | fp32 | 109707265(上一个安全值 109707264) | 27648 / 3969 | **253568B** | 128B | | fp16 | 219668481(上一个安全值 219668480) | 55360 / 3969 | **253824B** | 384B | 越界可能导致 InitBuffer 失败或 Buffer 互相踩踏。 > 早先版本的本节按 UB=245760 举了 [1, 1, 104439809] 这个算例,该值取自仓内 arch35 UT 的 compile_info(activation/、norm/ 下几十个算子沿用的同一份旧模板),**不是 Ascend950 的真实 UB**。按真实 UB 复核,那个 shape 只占 252032B ≤ 253440B,并不越界(实测其 rFactor=27648 就是首版公式值,联合求解根本没触发)。缺陷成立,但触发点在上表,算例已更正。 修法不是简单加校验后拒绝(那会把本来能算的 shape 变成不支持),而是联合求解:用与 Kernel InitSubR() 逐项一致的公式(新增 CalcSubRUbBytes())复核总占用,超了就按实际 partial 占用回缩 rFactor 并重算 numChunks。rFactor 变小时输入双缓冲省下的字节多于 numChunks 增加所需的槽位,故迭代单调收敛(fp32 R=109707265 一轮收敛到 rFactor=27584 / numChunks=3978 / 253056B)。确实无解的超大 R 则明确返回失败,不再下发越界 tiling。 迭代上限 SUB_R_SOLVE_MAX_ITER 取 **32**。最初取 8 并注释为"正常 1~2 轮收敛,只作死循环兜底",但那只对 R 不太大时成立:R 逼近 UB 容量上限时 rFactor 已被 partial 挤得很小,每轮只能再缩一点点,轮数急剧上升。穷举实测收敛所需轮数峰值为 fp32 19 轮 / fp16 24 轮,出现在真正无解点(fp32 R≈2.50e8、fp16 R≈5.01e8,即 0.93GiB 输入)附近。上限取 8 会产生一段**误拒区间**——明明有可行解却报 cannot fit UB 拒绝下发:fp32 R ∈ [237502465, 249892865)、fp16 R ∈ [473001985, 500797441)。失败方向是安全的(拒绝而非下发越界 tiling),但仍是错判,故提到 32 并补 UT 016 锁死(该 UT 在上限为 8 时会 FAIL,已实测验证)。 **[高] INTrainingReduceV2 空 tensor 契约冲突** 图原型声明"支持空 tensor,允许空间规约轴为 0",但唯一注册的 AR_FULL_REDUCE 模板在 r <= 0 时直接 return false(代码注释亦写明"R=0 由后续 REDUCE_EMPTY 承接,本迭代不含")。本迭代确定不支持,故按实现修正 proto 与 README 表述,并补空间轴为 0 的拒绝 UT。 **[中] sub-R 路径 64→32 位收窄保护** Kernel ProcessSubR() 把 numN / numC / numR / perCoreCnt 收窄成 uint32_t,Host 侧此前未证明其落在 32 位内。新增 CheckSubRNarrowable() 显式校验 N / C / R / N*C。同时修正 in_training_reduce_v2_sub_r.h 中 static_cast<uint64_t>(numN_ * numC_)——这是先做 uint32 乘法再转宽,回绕后再 cast 已经晚了,改为两个操作数各自提升 64 位再相乘。 **[合规] SGD 注释命名红线 R8** 源码注释中的团队私下叫法 A2 / A5 改为规范名 ascend910b / ascend950,涉及 sgd_def.cpp、sgd_infershape.cpp、sgd_tiling.cpp、sgd_tiling_key.h。README 产品表中的正式产品名"Atlas A2"属于规范用法,未改动。 **[中] NormalizeBBox golden 不支持 batch=0** golden.py 的 shape_hw.reshape(batch, -1) 在 batch=0 时 torch 无法推导 -1,直接抛 RuntimeError;而 Host Tiling 有 batch == 0 的空 tensor 快速路径、UT 中也有对应用例,golden 与算子支持域不一致。改为直接索引契约已限定为二维 (batch, 3) 的 shape_hw。 **[中] SGD 标量 shape 实现与文档不一致** CheckScalarShape 实际接受任意 numel == 1 的 shape([1,1]、[1,1,1] 均通过,错误文案本身也写的是 "scalar(0D) or have shape size 1"),而 README 写死"只能是 [1] 或 0 维标量"。选择按实现放宽文档而非收紧代码:收紧会拒掉 [1,1] 等已有图中可能存在的写法,属破坏性变更;放宽文档零风险。README 与 proto 表述已同步,并补上 0D / [1,1] / [1,1,1] 的接受 UT。 **[低] ParseShapeByFormat 超 CodeCheck 行数阈值** ParseShapeByFormat() 实测 51 个有效代码行,超本地 CodeCheck 的 50 行阈值。抽出三分支共用的 ParseAndCheckNC(),主函数降至 39 行。 **其他** INTrainingReduceV2 与 NormalizeBBox 的 README 补充"本算子不提供 aclnn 单算子接口,仅支持 GE 图模式调用",减少后续扫描与评审歧义。 ### 三、评估后未采纳的检视建议 - **NormalizeBBox TilingData 的 usedCoreNum 字段**:该字段已注释声明为诊断用途(Host 用于设置 blockDim),且是 20 余条 Host UT 的核心观测点。为节省 8 字节而重写大量断言,代价大于收益。 - **两个 GEIR 样例的 10 行重复代码**:为 10 行样板在 norm/ 与 vfusion/ 之间新建跨目录共享头,维护代价大于收益;样例代码应保持自包含可读。 ## 关联的Issue 关联Issue #4553 ## 测试 - **NormalizeBBox golden 实跑验证**:fp16/fp32 × normal/reversed × batch=0/batch=2 共 8 组组合全部通过;修改前 batch=0 确认抛 RuntimeError: cannot reshape tensor of 0 elements into shape [0, -1]。 - **新增 UT 用例**: - tiling_ar_full_reduce_nchw_r0_empty_rejected_012:空间轴为 0 时 Tiling 明确失败。 - tiling_ar_full_reduce_sub_r_partial_buf_fits_ub_013:原越界 shape 下断言分块参数自洽,且按 Kernel 公式复算的 UB 占用不越界。 - tiling_ar_full_reduce_sub_r_unfittable_rejected_014:任何 rFactor 都放不下的超大 R 被明确拒绝。 - tiling_ar_full_reduce_sub_r_r_over_uint32_rejected_015:R 超 UINT32_MAX 被 Host 拒绝。 - sgd_tiling_accept_scalar_shape_any_single_element:0D / [1,1] / [1,1,1] 标量入参被接受。 - **静态检查**:Ruff 检查(check + format)通过;改动行宽全部 ≤ 120 列(含中文按显示宽度计)。 - **未执行项(需 CI 覆盖)**:本地无 CANN 构建链,C++ 未编译、UT 未实跑;本地 clang-format 仅 21.x 而仓库固定 18.1.8,为避免引入无关重排未执行格式化。 ### 需评审关注 InferDataType 挪到 op_graph 后,原有的 InferDataType UT 用例已下线。原因是 cmake/ut.cmake 中 op_graph UT 模块只链接 graph_plugin_obj,不含 tests/ut/common 的 infershape 公共对象(InferDataTypeTest / InferDataTypeContextFaker 位于仅 OP_HOST_UT 才编译的 _common_obj),用例挪过去无法链接。仓内所有把 InferDataType 放 op_graph 的算子目前均无此层覆盖。若需保住覆盖,需改动全仓共用的 add_op_graph_ut_modules,已在各 UT 文件头注明原因,未在本 PR 中改动构建基础设施。 ## 文档更新 - 更新 norm/in_training_reduce_v2/README.md:补充不支持空 tensor 的约束、无 aclnn 接口说明。 - 更新 optim/sgd/README.md:learning_rate / momentum 的 shape 约束表述与实现对齐。 - 更新 vfusion/normalize_bbox/README.md:补充无 aclnn 接口说明。 - 更新三个算子 proto.h 中的接口注释(空 tensor 支持面、标量 shape 接受面)。 ## 类型标签 <!-- [x] 表示选中 --> - [x] Bug修复 - [ ] 新特性 - [ ] 性能优化 - [x] 文档更新 - [ ] 其他,请描述: ## AI/Agent生成声明 <!-- [x] 表示选中 --> - [x] AI辅助编写 See merge request: cann/ops-nn!8402 | 26 天前 | |
feat(in_training_reduce_v2): sub-R分组折叠解除规约轴R的上限 Co-authored-by: raoliang_sac<raoliang4@huawei.com> # message auto-generated for no-merge-commit merge: !8862 merge feat/in-training-reduce-v2-lift-r-limit into master feat(in_training_reduce_v2): sub-R分组折叠解除规约轴R的上限 Created-by: raoliang_sac Commit-by: raoliang_sac Merged-by: cann-robot Description: ## 描述 解除 INTrainingReduceV2 规约轴长度 R 的上限。 ### 问题 sub-R 分块路径把 numChunks = ceil(R / rFactor) 个部分和**全部常驻 UB**,于是"输入分块双缓冲"与"随 R 增长的部分和数组"争抢同一块 UB: 2·e·rFactor + 8·(R/rFactor) ≤ usable ⟹ e·R ≤ (usable/8)² (e = 元素字节宽度) 按 Ascend 950 的 ub_size=253952 复算 DoSubRTiling() 并二分求临界点,上限为 **FLOAT32 R ≤ 249,892,864 / FLOAT16 R ≤ 500,797,440**(均约 0.93 GiB 输入),超出即在 Host Tiling 阶段返回失败。上游反馈的用例 InTrainingReduceV2_L1_upboundary_highpre_047(N=1, C=1, R=4294967296)正是因此失败: EZ9999: sub-R tiling requires N, C, R and N*C to fit in uint32: N=1 C=1 R=4294967296. [FUNC:CheckSubRNarrowable][FILE:in_training_reduce_v2_tiling_ar_full_reduce_arch35.cpp][LINE:127] 这个上限并非硬件或算法固有,而是实现耦合。同族对照支持"该能力本应具备":canndev 的 A2/A3 实现(TBE tuple_reduce)在类型与架构上均不设 R 上限;本仓 batch_norm_v3 的 block_split_r 也通过分级归约避开了同样的耦合。 ### 方案:分组折叠 给部分和缓存一个**固定**的分组预算:每 chunksPerGroup 个 chunk 折叠一次,结果写入 carry 槽并参与下一组的树形折叠,使 UB 占用与 R 完全解耦。 runningFold = 0 for g in [0, numGroups): for c in [0, chunksInGroup): CopyIn / ReduceChunk → partial[c] foldCnt = chunksInGroup + (g > 0 ? 1 : 0) # g>0 时含上一组的 carry FoldGroupSubR(partial[0, foldCnt)) → 末组写输出,否则写下一组的 carry 槽 实测 UB 用量恒为 **253,056 / 253,440 字节**,R 从 2.6×10⁸ 到 4.29×10⁹ 完全不变。**R 不再有上限,仅受设备内存约束。** ### 三点设计取舍 1. **保留原有求解作为快路径。** 装得下即 numGroups == 1,tiling 参数与 Kernel 行为逐位不变,存量 shape 零影响;分组仅在原本会被拒绝的 R 上启用。TTK 851 条泛化用例**全部走快路径**,这既解释了它们全绿,也印证了改造对存量行为无影响。 2. **chunksPerGroup 取"VL 对齐值 − 1"**,使 CeilAlign(chunksPerGroup + 1, VL) 恰好等于该对齐值,carry 槽不额外多吃一个 VL —— 分组路径的 UB 开销为零。 3. **carry 与本组 chunk 走同一次向量折叠**,而非标量顺序累加,精度优于顺序加。 ### 附带 sub-R 路径的 numN / numC / numR / perCoreCnt 由 uint32_t 放宽到 uint64_t,并移除 CheckSubRNarrowable() 中对 numR 的守卫(N / C / N×C 的 uint32 约束保留)。顺带修正 ar_full_reduce.h 中 perCoreCnt_ 的隐式收窄(同段其余字段均有显式 static_cast)。 README 未作改动:R 的上限是被**删除**的,不是被补充的,「约束说明」无需新增条目。 ## 关联的Issue 关联Issue #4872 —— 该 Issue 原诉求是把 R 上限写入文档;排查后确认上限可解除,故改为直接解除,Issue 将同步说明。原 PR !8838(文档化该上限)已因此关闭。 ## 测试 **op_host UT:22/22 通过** 新增 / 改写: - ..._sub_r_r_over_uint32_015:R=2³²(即上游失败用例的 R),改造前被拒,现须出 tiling - ..._sub_r_r_far_over_uint32_fp16_017:R=2³⁴ fp16,验证上限是"解除"而非"抬高一档" - ..._sub_r_nc_over_uint32_rejected_018:N×C=2³²,验证 N/C 的 uint32 守卫仍生效 - ..._sub_r_grouped_fold_2e9_014:原为"断言拒绝",改为"断言分组后接受" - 新增 ExpectSubRSelfConsistent():断言 numChunks/tailLen/numGroups/tailChunks 彼此自洽,且 Kernel 按该组参数申请的 UB 不越界 - 存量用例 013 / 016 增加 numGroups == 1 断言,守住"快路径不变" **TTK kernel 泛化:851 / 851 全部 PASS**(Ascend 950PR_9579) | 项 | 结果 | |---|---| | precision_status | PASS × 851,0 FAIL | | bin_precision | 100.0%,100.0% × 851 | | bin_compile_s | BINARY_MATCH × 851(跑的是部署的预编译 .o,非 JIT 兜底) | | memory_oob | PASS × 851 | 命令:ttk kernel -i in_training_reduce_v2_full.csv -d=false -b=release --compare close --plugin <op>/tests/assets **超限用例实测**(这批是唯一能覆盖新增分组路径的用例,851 条泛化全部走快路径) | R | dtype | numGroups | 结果 | |---:|---|---:|---| | 260,000,000 | fp32 | 2 | PASS,精度 100% | | 600,000,000 | fp32 | 3 | PASS,精度 100% | | 520,000,000 | fp16 | 2 | PASS,精度 100% | | 1,200,000,000 | fp16 | 3 | 跑批中 | | 4,294,967,296 | fp16 | 9 | 跑批中 | | 4,294,967,296 | fp32 | 18 | 跑批中 | 前三条均已超过改造前的上限(改造前会被 Host Tiling 拒绝)。后三条规模较大(fp64 golden 需 32 GiB),结果出来后补充到评论。 **本地门禁**:pre-commit 全项 Passed(含 clang-format / codespell / OAT 合规)。 ## 文档更新 无。R 的上限被解除而非文档化,README 无需改动。 ## 类型标签 <!-- [x] 表示选中 --> - [ ] Bug修复 - [x] 新特性 - [ ] 性能优化 - [ ] 文档更新 - [ ] 其他,请描述: ## AI/Agent生成声明 <!-- [x] 表示选中 --> - [x] AI辅助编写 See merge request: cann/ops-nn!8862 | 18 天前 | |
feat(in_training_reduce_v2): sub-R分组折叠解除规约轴R的上限 Co-authored-by: raoliang_sac<raoliang4@huawei.com> # message auto-generated for no-merge-commit merge: !8862 merge feat/in-training-reduce-v2-lift-r-limit into master feat(in_training_reduce_v2): sub-R分组折叠解除规约轴R的上限 Created-by: raoliang_sac Commit-by: raoliang_sac Merged-by: cann-robot Description: ## 描述 解除 INTrainingReduceV2 规约轴长度 R 的上限。 ### 问题 sub-R 分块路径把 numChunks = ceil(R / rFactor) 个部分和**全部常驻 UB**,于是"输入分块双缓冲"与"随 R 增长的部分和数组"争抢同一块 UB: 2·e·rFactor + 8·(R/rFactor) ≤ usable ⟹ e·R ≤ (usable/8)² (e = 元素字节宽度) 按 Ascend 950 的 ub_size=253952 复算 DoSubRTiling() 并二分求临界点,上限为 **FLOAT32 R ≤ 249,892,864 / FLOAT16 R ≤ 500,797,440**(均约 0.93 GiB 输入),超出即在 Host Tiling 阶段返回失败。上游反馈的用例 InTrainingReduceV2_L1_upboundary_highpre_047(N=1, C=1, R=4294967296)正是因此失败: EZ9999: sub-R tiling requires N, C, R and N*C to fit in uint32: N=1 C=1 R=4294967296. [FUNC:CheckSubRNarrowable][FILE:in_training_reduce_v2_tiling_ar_full_reduce_arch35.cpp][LINE:127] 这个上限并非硬件或算法固有,而是实现耦合。同族对照支持"该能力本应具备":canndev 的 A2/A3 实现(TBE tuple_reduce)在类型与架构上均不设 R 上限;本仓 batch_norm_v3 的 block_split_r 也通过分级归约避开了同样的耦合。 ### 方案:分组折叠 给部分和缓存一个**固定**的分组预算:每 chunksPerGroup 个 chunk 折叠一次,结果写入 carry 槽并参与下一组的树形折叠,使 UB 占用与 R 完全解耦。 runningFold = 0 for g in [0, numGroups): for c in [0, chunksInGroup): CopyIn / ReduceChunk → partial[c] foldCnt = chunksInGroup + (g > 0 ? 1 : 0) # g>0 时含上一组的 carry FoldGroupSubR(partial[0, foldCnt)) → 末组写输出,否则写下一组的 carry 槽 实测 UB 用量恒为 **253,056 / 253,440 字节**,R 从 2.6×10⁸ 到 4.29×10⁹ 完全不变。**R 不再有上限,仅受设备内存约束。** ### 三点设计取舍 1. **保留原有求解作为快路径。** 装得下即 numGroups == 1,tiling 参数与 Kernel 行为逐位不变,存量 shape 零影响;分组仅在原本会被拒绝的 R 上启用。TTK 851 条泛化用例**全部走快路径**,这既解释了它们全绿,也印证了改造对存量行为无影响。 2. **chunksPerGroup 取"VL 对齐值 − 1"**,使 CeilAlign(chunksPerGroup + 1, VL) 恰好等于该对齐值,carry 槽不额外多吃一个 VL —— 分组路径的 UB 开销为零。 3. **carry 与本组 chunk 走同一次向量折叠**,而非标量顺序累加,精度优于顺序加。 ### 附带 sub-R 路径的 numN / numC / numR / perCoreCnt 由 uint32_t 放宽到 uint64_t,并移除 CheckSubRNarrowable() 中对 numR 的守卫(N / C / N×C 的 uint32 约束保留)。顺带修正 ar_full_reduce.h 中 perCoreCnt_ 的隐式收窄(同段其余字段均有显式 static_cast)。 README 未作改动:R 的上限是被**删除**的,不是被补充的,「约束说明」无需新增条目。 ## 关联的Issue 关联Issue #4872 —— 该 Issue 原诉求是把 R 上限写入文档;排查后确认上限可解除,故改为直接解除,Issue 将同步说明。原 PR !8838(文档化该上限)已因此关闭。 ## 测试 **op_host UT:22/22 通过** 新增 / 改写: - ..._sub_r_r_over_uint32_015:R=2³²(即上游失败用例的 R),改造前被拒,现须出 tiling - ..._sub_r_r_far_over_uint32_fp16_017:R=2³⁴ fp16,验证上限是"解除"而非"抬高一档" - ..._sub_r_nc_over_uint32_rejected_018:N×C=2³²,验证 N/C 的 uint32 守卫仍生效 - ..._sub_r_grouped_fold_2e9_014:原为"断言拒绝",改为"断言分组后接受" - 新增 ExpectSubRSelfConsistent():断言 numChunks/tailLen/numGroups/tailChunks 彼此自洽,且 Kernel 按该组参数申请的 UB 不越界 - 存量用例 013 / 016 增加 numGroups == 1 断言,守住"快路径不变" **TTK kernel 泛化:851 / 851 全部 PASS**(Ascend 950PR_9579) | 项 | 结果 | |---|---| | precision_status | PASS × 851,0 FAIL | | bin_precision | 100.0%,100.0% × 851 | | bin_compile_s | BINARY_MATCH × 851(跑的是部署的预编译 .o,非 JIT 兜底) | | memory_oob | PASS × 851 | 命令:ttk kernel -i in_training_reduce_v2_full.csv -d=false -b=release --compare close --plugin <op>/tests/assets **超限用例实测**(这批是唯一能覆盖新增分组路径的用例,851 条泛化全部走快路径) | R | dtype | numGroups | 结果 | |---:|---|---:|---| | 260,000,000 | fp32 | 2 | PASS,精度 100% | | 600,000,000 | fp32 | 3 | PASS,精度 100% | | 520,000,000 | fp16 | 2 | PASS,精度 100% | | 1,200,000,000 | fp16 | 3 | 跑批中 | | 4,294,967,296 | fp16 | 9 | 跑批中 | | 4,294,967,296 | fp32 | 18 | 跑批中 | 前三条均已超过改造前的上限(改造前会被 Host Tiling 拒绝)。后三条规模较大(fp64 golden 需 32 GiB),结果出来后补充到评论。 **本地门禁**:pre-commit 全项 Passed(含 clang-format / codespell / OAT 合规)。 ## 文档更新 无。R 的上限被解除而非文档化,README 无需改动。 ## 类型标签 <!-- [x] 表示选中 --> - [ ] Bug修复 - [x] 新特性 - [ ] 性能优化 - [ ] 文档更新 - [ ] 其他,请描述: ## AI/Agent生成声明 <!-- [x] 表示选中 --> - [x] AI辅助编写 See merge request: cann/ops-nn!8862 | 18 天前 | |
feat(in_training_reduce_v2): sub-R分组折叠解除规约轴R的上限 Co-authored-by: raoliang_sac<raoliang4@huawei.com> # message auto-generated for no-merge-commit merge: !8862 merge feat/in-training-reduce-v2-lift-r-limit into master feat(in_training_reduce_v2): sub-R分组折叠解除规约轴R的上限 Created-by: raoliang_sac Commit-by: raoliang_sac Merged-by: cann-robot Description: ## 描述 解除 INTrainingReduceV2 规约轴长度 R 的上限。 ### 问题 sub-R 分块路径把 numChunks = ceil(R / rFactor) 个部分和**全部常驻 UB**,于是"输入分块双缓冲"与"随 R 增长的部分和数组"争抢同一块 UB: 2·e·rFactor + 8·(R/rFactor) ≤ usable ⟹ e·R ≤ (usable/8)² (e = 元素字节宽度) 按 Ascend 950 的 ub_size=253952 复算 DoSubRTiling() 并二分求临界点,上限为 **FLOAT32 R ≤ 249,892,864 / FLOAT16 R ≤ 500,797,440**(均约 0.93 GiB 输入),超出即在 Host Tiling 阶段返回失败。上游反馈的用例 InTrainingReduceV2_L1_upboundary_highpre_047(N=1, C=1, R=4294967296)正是因此失败: EZ9999: sub-R tiling requires N, C, R and N*C to fit in uint32: N=1 C=1 R=4294967296. [FUNC:CheckSubRNarrowable][FILE:in_training_reduce_v2_tiling_ar_full_reduce_arch35.cpp][LINE:127] 这个上限并非硬件或算法固有,而是实现耦合。同族对照支持"该能力本应具备":canndev 的 A2/A3 实现(TBE tuple_reduce)在类型与架构上均不设 R 上限;本仓 batch_norm_v3 的 block_split_r 也通过分级归约避开了同样的耦合。 ### 方案:分组折叠 给部分和缓存一个**固定**的分组预算:每 chunksPerGroup 个 chunk 折叠一次,结果写入 carry 槽并参与下一组的树形折叠,使 UB 占用与 R 完全解耦。 runningFold = 0 for g in [0, numGroups): for c in [0, chunksInGroup): CopyIn / ReduceChunk → partial[c] foldCnt = chunksInGroup + (g > 0 ? 1 : 0) # g>0 时含上一组的 carry FoldGroupSubR(partial[0, foldCnt)) → 末组写输出,否则写下一组的 carry 槽 实测 UB 用量恒为 **253,056 / 253,440 字节**,R 从 2.6×10⁸ 到 4.29×10⁹ 完全不变。**R 不再有上限,仅受设备内存约束。** ### 三点设计取舍 1. **保留原有求解作为快路径。** 装得下即 numGroups == 1,tiling 参数与 Kernel 行为逐位不变,存量 shape 零影响;分组仅在原本会被拒绝的 R 上启用。TTK 851 条泛化用例**全部走快路径**,这既解释了它们全绿,也印证了改造对存量行为无影响。 2. **chunksPerGroup 取"VL 对齐值 − 1"**,使 CeilAlign(chunksPerGroup + 1, VL) 恰好等于该对齐值,carry 槽不额外多吃一个 VL —— 分组路径的 UB 开销为零。 3. **carry 与本组 chunk 走同一次向量折叠**,而非标量顺序累加,精度优于顺序加。 ### 附带 sub-R 路径的 numN / numC / numR / perCoreCnt 由 uint32_t 放宽到 uint64_t,并移除 CheckSubRNarrowable() 中对 numR 的守卫(N / C / N×C 的 uint32 约束保留)。顺带修正 ar_full_reduce.h 中 perCoreCnt_ 的隐式收窄(同段其余字段均有显式 static_cast)。 README 未作改动:R 的上限是被**删除**的,不是被补充的,「约束说明」无需新增条目。 ## 关联的Issue 关联Issue #4872 —— 该 Issue 原诉求是把 R 上限写入文档;排查后确认上限可解除,故改为直接解除,Issue 将同步说明。原 PR !8838(文档化该上限)已因此关闭。 ## 测试 **op_host UT:22/22 通过** 新增 / 改写: - ..._sub_r_r_over_uint32_015:R=2³²(即上游失败用例的 R),改造前被拒,现须出 tiling - ..._sub_r_r_far_over_uint32_fp16_017:R=2³⁴ fp16,验证上限是"解除"而非"抬高一档" - ..._sub_r_nc_over_uint32_rejected_018:N×C=2³²,验证 N/C 的 uint32 守卫仍生效 - ..._sub_r_grouped_fold_2e9_014:原为"断言拒绝",改为"断言分组后接受" - 新增 ExpectSubRSelfConsistent():断言 numChunks/tailLen/numGroups/tailChunks 彼此自洽,且 Kernel 按该组参数申请的 UB 不越界 - 存量用例 013 / 016 增加 numGroups == 1 断言,守住"快路径不变" **TTK kernel 泛化:851 / 851 全部 PASS**(Ascend 950PR_9579) | 项 | 结果 | |---|---| | precision_status | PASS × 851,0 FAIL | | bin_precision | 100.0%,100.0% × 851 | | bin_compile_s | BINARY_MATCH × 851(跑的是部署的预编译 .o,非 JIT 兜底) | | memory_oob | PASS × 851 | 命令:ttk kernel -i in_training_reduce_v2_full.csv -d=false -b=release --compare close --plugin <op>/tests/assets **超限用例实测**(这批是唯一能覆盖新增分组路径的用例,851 条泛化全部走快路径) | R | dtype | numGroups | 结果 | |---:|---|---:|---| | 260,000,000 | fp32 | 2 | PASS,精度 100% | | 600,000,000 | fp32 | 3 | PASS,精度 100% | | 520,000,000 | fp16 | 2 | PASS,精度 100% | | 1,200,000,000 | fp16 | 3 | 跑批中 | | 4,294,967,296 | fp16 | 9 | 跑批中 | | 4,294,967,296 | fp32 | 18 | 跑批中 | 前三条均已超过改造前的上限(改造前会被 Host Tiling 拒绝)。后三条规模较大(fp64 golden 需 32 GiB),结果出来后补充到评论。 **本地门禁**:pre-commit 全项 Passed(含 clang-format / codespell / OAT 合规)。 ## 文档更新 无。R 的上限被解除而非文档化,README 无需改动。 ## 类型标签 <!-- [x] 表示选中 --> - [ ] Bug修复 - [x] 新特性 - [ ] 性能优化 - [ ] 文档更新 - [ ] 其他,请描述: ## AI/Agent生成声明 <!-- [x] 表示选中 --> - [x] AI辅助编写 See merge request: cann/ops-nn!8862 | 18 天前 | |
feat(in_training_reduce_v2): 新增 Ascend 950 AscendC 实现 无aclnn Co-authored-by: raoliang_sac<raoliang4@huawei.com> # message auto-generated for no-merge-commit merge: !8129 merge INTrainingReduceV2-no-aclnn into master feat(in_training_reduce_v2): 新增 Ascend 950 AscendC 实现 无aclnn Created-by: raoliang_sac Commit-by: raoliang_sac Merged-by: cann-robot Description: ## 描述 在 Ascend 950(arch35 / DAV_3510)平台用 AscendC 实现 InTrainingReduceV2 算子。 InTrainingReduceV2 是 Instance Normalization 训练前向的 reduce 阶段算子,与 INTrainingUpdateV2 配对使用:对每个 (N, C) 实例,在空间维度(4D: H,W;5D: D,H,W)上求和与平方和,输出两个统计量 sum = Σx 与 square_sum = Σx²(keepdims,输出恒 fp32)。 **关键语义**:Reduce 阶段输出原始求和,不做 1/num 缩放(均值/方差的除法在下游 Update 阶段完成)。移植时已删除参考算子 InstanceNorm 的 Muls(avgFactor) 除 R 与 Sub(x, mean) 中心化步骤。 **实现范围**: - dtype:fp16 / fp32 / bf16(输出恒 fp32) - format:4D NCHW / 4D ND / 5D NCDHW - 计算路径:R 全载(AR_FULL_REDUCE,按 R 阈值 64/128/8192 分档折叠)/ sub-R 分块累加(任意大 R,跨块 fp32 独立累加器)/ R=0 空 Tensor(host 侧零填充) - 通路:GE 图模式(proto + infershape + GEIR example),不含 aclnn 接口 **产品支持**:950(本PR新增AscendC实现)+ A2/A3/310p/310b(canndev已有TBE实现) ## 关联的Issue #4349 ## 测试 真实 NPU(Ascend 950PR_9579)验证: - **op_host UT**:16/16 通过(InferShape / InferDataType / Tiling 分支,含动态 shape -1/-2 用例) - **TTK 全量泛化测试**:500 kernel 全部 PASS,精度 100.0% - **GEIR 通路冒烟测试**:NPU 真机运行 test_geir_in_training_reduce_v2 通过 - **本地 CI 全项通过**:pre-commit / 文档链接 / 编译出包 / ophost UT / kernel UT / 冒烟测试 ## 文档更新 新增算子文档:README.md(完整6节)、docs/zh/op_list.md 算子条目。 ## 类型标签 - [x] 新特性 ## AI/Agent生成声明 - [x] AI辅助编写 See merge request: cann/ops-nn!8129 | 1 个月前 | |
fix(in_training_reduce_v2/sgd/normalize_bbox): 修复原型重定义与InferDataType放置,落地三算子检视整改 Co-authored-by: raoliang_sac<raoliang4@huawei.com> # message auto-generated for no-merge-commit merge: !8402 merge fix/three-ops-review-issue-4553 into master fix(in_training_reduce_v2/sgd/normalize_bbox): 修复原型重定义与InferDataType放置,落地三算子检视整改 Created-by: raoliang_sac Commit-by: raoliang_sac Merged-by: cann-robot Description: ## 描述 本 PR 一次性落地两块内容:Issue #4553 提出的交付件划分/原型重定义问题,以及 INTrainingReduceV2、SGD、NormalizeBBox 三个算子的代码检视意见。 ### 一、Issue #4553 **1. 原型重定义防护** 三个算子的原型都是从 canndev built-in 头( reduce_ops.h / nn_detect_ops.h / nn_training_ops.h,迁移后落在 ops_proto_legacy.h)挪出来的,两侧头文件被同一编译单元同时包含时会 REG_OP 重定义。已给三个 proto.h 的 REG_OP 补上防重定义宏,宏名沿用 ops_proto_legacy.h 自身的 OPS_PROTO_DEF_<OPTYPE> 约定: - OPS_PROTO_DEF_INTRAININGREDUCEV2 - OPS_PROTO_DEF_NORMALIZEBBOX - OPS_PROTO_DEF_SGD **2. InferDataType 交付件划分** InferDataType 仅图场景使用,从 op_host/*_infershape.cpp 挪到 op_graph/*_graph_infer.cpp(IMPL_OP 注册);InferShape 图与单算子共用,保留在 op_host(IMPL_OP_INFERSHAPE)。对齐仓内 norm/bn_infer_grad、norm/lp_norm_update、norm/in_infer_v2 的既有做法。add_graph_plugin_sources() 按 *_graph*.cpp 通配收集,无需改 CMakeLists。 ### 二、检视意见整改 **[高] INTrainingReduceV2 sub-R 路径 UB 越界** DoSubRTiling 只按 usable / 8 固定预留部分和缓存,算出 numChunks 后从不回验总占用。R 特别大时实际会撑破预留。按 Ascend950 实测参数(Ascend950*.ini 的 ub_size=253952,减 RESERVE_FOR_ALIGN=512 得 usable=253440B,VL_FP32=64): | dtype | 越界起点 R | 首版公式的 rFactor / numChunks | 实际申请 | 越界量 | |---|---|---|---|---| | fp32 | 109707265(上一个安全值 109707264) | 27648 / 3969 | **253568B** | 128B | | fp16 | 219668481(上一个安全值 219668480) | 55360 / 3969 | **253824B** | 384B | 越界可能导致 InitBuffer 失败或 Buffer 互相踩踏。 > 早先版本的本节按 UB=245760 举了 [1, 1, 104439809] 这个算例,该值取自仓内 arch35 UT 的 compile_info(activation/、norm/ 下几十个算子沿用的同一份旧模板),**不是 Ascend950 的真实 UB**。按真实 UB 复核,那个 shape 只占 252032B ≤ 253440B,并不越界(实测其 rFactor=27648 就是首版公式值,联合求解根本没触发)。缺陷成立,但触发点在上表,算例已更正。 修法不是简单加校验后拒绝(那会把本来能算的 shape 变成不支持),而是联合求解:用与 Kernel InitSubR() 逐项一致的公式(新增 CalcSubRUbBytes())复核总占用,超了就按实际 partial 占用回缩 rFactor 并重算 numChunks。rFactor 变小时输入双缓冲省下的字节多于 numChunks 增加所需的槽位,故迭代单调收敛(fp32 R=109707265 一轮收敛到 rFactor=27584 / numChunks=3978 / 253056B)。确实无解的超大 R 则明确返回失败,不再下发越界 tiling。 迭代上限 SUB_R_SOLVE_MAX_ITER 取 **32**。最初取 8 并注释为"正常 1~2 轮收敛,只作死循环兜底",但那只对 R 不太大时成立:R 逼近 UB 容量上限时 rFactor 已被 partial 挤得很小,每轮只能再缩一点点,轮数急剧上升。穷举实测收敛所需轮数峰值为 fp32 19 轮 / fp16 24 轮,出现在真正无解点(fp32 R≈2.50e8、fp16 R≈5.01e8,即 0.93GiB 输入)附近。上限取 8 会产生一段**误拒区间**——明明有可行解却报 cannot fit UB 拒绝下发:fp32 R ∈ [237502465, 249892865)、fp16 R ∈ [473001985, 500797441)。失败方向是安全的(拒绝而非下发越界 tiling),但仍是错判,故提到 32 并补 UT 016 锁死(该 UT 在上限为 8 时会 FAIL,已实测验证)。 **[高] INTrainingReduceV2 空 tensor 契约冲突** 图原型声明"支持空 tensor,允许空间规约轴为 0",但唯一注册的 AR_FULL_REDUCE 模板在 r <= 0 时直接 return false(代码注释亦写明"R=0 由后续 REDUCE_EMPTY 承接,本迭代不含")。本迭代确定不支持,故按实现修正 proto 与 README 表述,并补空间轴为 0 的拒绝 UT。 **[中] sub-R 路径 64→32 位收窄保护** Kernel ProcessSubR() 把 numN / numC / numR / perCoreCnt 收窄成 uint32_t,Host 侧此前未证明其落在 32 位内。新增 CheckSubRNarrowable() 显式校验 N / C / R / N*C。同时修正 in_training_reduce_v2_sub_r.h 中 static_cast<uint64_t>(numN_ * numC_)——这是先做 uint32 乘法再转宽,回绕后再 cast 已经晚了,改为两个操作数各自提升 64 位再相乘。 **[合规] SGD 注释命名红线 R8** 源码注释中的团队私下叫法 A2 / A5 改为规范名 ascend910b / ascend950,涉及 sgd_def.cpp、sgd_infershape.cpp、sgd_tiling.cpp、sgd_tiling_key.h。README 产品表中的正式产品名"Atlas A2"属于规范用法,未改动。 **[中] NormalizeBBox golden 不支持 batch=0** golden.py 的 shape_hw.reshape(batch, -1) 在 batch=0 时 torch 无法推导 -1,直接抛 RuntimeError;而 Host Tiling 有 batch == 0 的空 tensor 快速路径、UT 中也有对应用例,golden 与算子支持域不一致。改为直接索引契约已限定为二维 (batch, 3) 的 shape_hw。 **[中] SGD 标量 shape 实现与文档不一致** CheckScalarShape 实际接受任意 numel == 1 的 shape([1,1]、[1,1,1] 均通过,错误文案本身也写的是 "scalar(0D) or have shape size 1"),而 README 写死"只能是 [1] 或 0 维标量"。选择按实现放宽文档而非收紧代码:收紧会拒掉 [1,1] 等已有图中可能存在的写法,属破坏性变更;放宽文档零风险。README 与 proto 表述已同步,并补上 0D / [1,1] / [1,1,1] 的接受 UT。 **[低] ParseShapeByFormat 超 CodeCheck 行数阈值** ParseShapeByFormat() 实测 51 个有效代码行,超本地 CodeCheck 的 50 行阈值。抽出三分支共用的 ParseAndCheckNC(),主函数降至 39 行。 **其他** INTrainingReduceV2 与 NormalizeBBox 的 README 补充"本算子不提供 aclnn 单算子接口,仅支持 GE 图模式调用",减少后续扫描与评审歧义。 ### 三、评估后未采纳的检视建议 - **NormalizeBBox TilingData 的 usedCoreNum 字段**:该字段已注释声明为诊断用途(Host 用于设置 blockDim),且是 20 余条 Host UT 的核心观测点。为节省 8 字节而重写大量断言,代价大于收益。 - **两个 GEIR 样例的 10 行重复代码**:为 10 行样板在 norm/ 与 vfusion/ 之间新建跨目录共享头,维护代价大于收益;样例代码应保持自包含可读。 ## 关联的Issue 关联Issue #4553 ## 测试 - **NormalizeBBox golden 实跑验证**:fp16/fp32 × normal/reversed × batch=0/batch=2 共 8 组组合全部通过;修改前 batch=0 确认抛 RuntimeError: cannot reshape tensor of 0 elements into shape [0, -1]。 - **新增 UT 用例**: - tiling_ar_full_reduce_nchw_r0_empty_rejected_012:空间轴为 0 时 Tiling 明确失败。 - tiling_ar_full_reduce_sub_r_partial_buf_fits_ub_013:原越界 shape 下断言分块参数自洽,且按 Kernel 公式复算的 UB 占用不越界。 - tiling_ar_full_reduce_sub_r_unfittable_rejected_014:任何 rFactor 都放不下的超大 R 被明确拒绝。 - tiling_ar_full_reduce_sub_r_r_over_uint32_rejected_015:R 超 UINT32_MAX 被 Host 拒绝。 - sgd_tiling_accept_scalar_shape_any_single_element:0D / [1,1] / [1,1,1] 标量入参被接受。 - **静态检查**:Ruff 检查(check + format)通过;改动行宽全部 ≤ 120 列(含中文按显示宽度计)。 - **未执行项(需 CI 覆盖)**:本地无 CANN 构建链,C++ 未编译、UT 未实跑;本地 clang-format 仅 21.x 而仓库固定 18.1.8,为避免引入无关重排未执行格式化。 ### 需评审关注 InferDataType 挪到 op_graph 后,原有的 InferDataType UT 用例已下线。原因是 cmake/ut.cmake 中 op_graph UT 模块只链接 graph_plugin_obj,不含 tests/ut/common 的 infershape 公共对象(InferDataTypeTest / InferDataTypeContextFaker 位于仅 OP_HOST_UT 才编译的 _common_obj),用例挪过去无法链接。仓内所有把 InferDataType 放 op_graph 的算子目前均无此层覆盖。若需保住覆盖,需改动全仓共用的 add_op_graph_ut_modules,已在各 UT 文件头注明原因,未在本 PR 中改动构建基础设施。 ## 文档更新 - 更新 norm/in_training_reduce_v2/README.md:补充不支持空 tensor 的约束、无 aclnn 接口说明。 - 更新 optim/sgd/README.md:learning_rate / momentum 的 shape 约束表述与实现对齐。 - 更新 vfusion/normalize_bbox/README.md:补充无 aclnn 接口说明。 - 更新三个算子 proto.h 中的接口注释(空 tensor 支持面、标量 shape 接受面)。 ## 类型标签 <!-- [x] 表示选中 --> - [x] Bug修复 - [ ] 新特性 - [ ] 性能优化 - [x] 文档更新 - [ ] 其他,请描述: ## AI/Agent生成声明 <!-- [x] 表示选中 --> - [x] AI辅助编写 See merge request: cann/ops-nn!8402 | 26 天前 |
INTrainingReduceV2
产品支持情况
| 产品 | 是否支持 |
|---|---|
| Ascend 950PR/Ascend 950DT | √ |
| Atlas A3 训练系列产品/Atlas A3 推理系列产品 | √ |
| Atlas A2 训练系列产品/Atlas A2 推理系列产品 | √ |
| Atlas 200I/500 A2 推理产品 | √ |
| Atlas 推理系列产品 | √ |
| Atlas 训练系列产品 | √ |
功能说明
-
算子功能:INTrainingReduceV2是Instance Normalization(实例归一化)训练前向的reduce(规约)阶段算子,与InTrainingUpdateV2配对使用。对每个实例通道 (n, c),在其空间维度(4D NCHW的H、W;5D NCDHW的D、H、W)上分别求和与求平方和,输出统计量
sum(Σx)与square_sum(Σx²),规约轴保留(keepdims)。规约仅沿空间轴,N与C保留(区别于BatchNorm沿N规约);输出为原始和,不做1/R缩放(均值/方差由下游InTrainingUpdateV2阶段计算)。 -
计算公式(以4D NCHW为例,5D NCDHW沿D、H、W规约同理):
sum(n,c)=∑h=0H−1∑w=0W−1x(n,c,h,w)sum_{(n,c)} = \sum_{h=0}^{H-1} \sum_{w=0}^{W-1} x_{(n,c,h,w)} sum(n,c)=h=0∑H−1w=0∑W−1x(n,c,h,w)
squareSum(n,c)=∑h=0H−1∑w=0W−1x(n,c,h,w)2squareSum_{(n,c)} = \sum_{h=0}^{H-1} \sum_{w=0}^{W-1} x_{(n,c,h,w)}^2 squareSum(n,c)=h=0∑H−1w=0∑W−1x(n,c,h,w)2
其中 xxx 为输入特征图,sumsumsum、squareSumsquareSumsquareSum 为per-(N,C) 的统计量(保留N、C,空间轴规约为1)。
参数说明
| 参数名 | 输入/输出/属性 | 描述 | 数据类型 | 数据格式 |
|---|---|---|---|---|
| x | 输入 |
|
FLOAT32、FLOAT16 | NCHW/NCDHW/ND |
| sum | 输出 |
|
FLOAT32 | ND |
| square_sum | 输出 |
|
FLOAT32 | ND |
约束说明
- 输出
sum、square_sum的数据类型恒为FLOAT32,与输入x的dtype无关;FLOAT16输入全程提升FLOAT32计算与累加。 - 输出为原始和(Σx、Σx²),不做1/R缩放;均值/方差由下游
InTrainingUpdateV2计算。 - 输出
sum、square_sum的空间(规约)轴大小为1,N、C与输入x一致。 - 不支持空tensor:输入
x的任意轴为0(含空间规约轴)均判非法,在Host Tiling阶段返回失败。 - 本算子不提供aclnn单算子接口,仅支持GE图模式调用。
调用说明
| 调用方式 | 样例代码 | 说明 |
|---|---|---|
| 图模式接口 | test_geir_in_training_reduce_v2 | 通过GE图模式构建INTrainingReduceV2算子图并执行RunGraph验证。 |