| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
feat: NormalizeBBox 算子 Ascend950 重实现 无aclnn Co-authored-by: raoliang_sac<raoliang4@huawei.com> # message auto-generated for no-merge-commit merge: !8130 merge feat/normalize_bbox_no_aclnn into master feat: NormalizeBBox 算子 Ascend950 重实现 无aclnn Created-by: raoliang_sac Commit-by: raoliang_sac Merged-by: cann-robot Description: ## 变更说明 NormalizeBBox 算子 Ascend950(arch35 RegBase)重实现,仅支持 GEIR 图模式通路,不提供 aclnn 接口。 ### 算子功能 将目标检测预选框的绝对像素坐标,按对应图像的高(height)与宽(width)逐 batch 归一化到 [0, 1] 区间。每个框由 4 个坐标构成,y 系坐标除以 height、x 系坐标除以 width。 计算公式: 对第 b 个 batch,令 h = shapeHw[b, 0]、w = shapeHw[b, 1](int32 转 float): y[b,i] = boxes[b,i] / [h, w, h, w] ### 实现内容 - **op_host**:算子原型定义(def)、InferShape/InferDataType、RegBase Tiling(多核切分 + UB 规划) - **op_kernel(arch35)**:Ascend950 RegBase 内核,支持 fp16/fp32/bf16 三种 dtype,normal/reversed 两种 layout - **op_graph**:GEIR proto 声明(含 DT_BF16,对齐 950 实现) - **golden**:tests/assets/golden.py(numpy 复刻 cast 链,随 PR 上库) - **UT**:infershape UT(9 case,含 -1/-2 动态 shape)+ tiling UT(41 case,含负向校验) - **GEIR 测试**:examples/arch35/test_geir_normalize_bbox.cpp(真机 RunGraph 验证) - **文档**:README.md + docs/zh/op_list.md 条目 ### 产品支持 | 产品 | 支持 | |------|------| | Ascend 950PR/Ascend 950DT | √ | | Atlas A3 训练/推理系列产品 | √(built-in TBE) | | Atlas A2 训练/推理系列产品 | √(built-in TBE) | | Atlas 200I/500 A2 推理产品 | √(built-in TBE) | | Atlas 推理系列产品 | √(built-in TBE) | | Atlas 训练系列产品 | √(built-in TBE) | 注:Ascend950 为本 PR 新实现的 RegBase 内核;A2/A3/推理/训练系列由 canndev built-in TBE 实现支持。 ### 验证结果 | 测试项 | 规模 | 结果 | |--------|------|------| | ophost UT | 50 case | 50/50 PASS | | kernel UT | - | PASS | | 单算子出包 | --pkg --soc=ascend950 | SUCCESS | | 冒烟测试 | run_example graph(NPU 真机) | PASS,精度正确 | | pre-commit | 格式/拼写/OAT | PASS | | 文档链接 | MD 链接有效性 | PASS | ### 关联 Issue #4347 See merge request: cann/ops-nn!8130 | 2 个月前 | |
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 | 2 个月前 | |
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 | 2 个月前 | |
feat: NormalizeBBox 算子 Ascend950 重实现 无aclnn Co-authored-by: raoliang_sac<raoliang4@huawei.com> # message auto-generated for no-merge-commit merge: !8130 merge feat/normalize_bbox_no_aclnn into master feat: NormalizeBBox 算子 Ascend950 重实现 无aclnn Created-by: raoliang_sac Commit-by: raoliang_sac Merged-by: cann-robot Description: ## 变更说明 NormalizeBBox 算子 Ascend950(arch35 RegBase)重实现,仅支持 GEIR 图模式通路,不提供 aclnn 接口。 ### 算子功能 将目标检测预选框的绝对像素坐标,按对应图像的高(height)与宽(width)逐 batch 归一化到 [0, 1] 区间。每个框由 4 个坐标构成,y 系坐标除以 height、x 系坐标除以 width。 计算公式: 对第 b 个 batch,令 h = shapeHw[b, 0]、w = shapeHw[b, 1](int32 转 float): y[b,i] = boxes[b,i] / [h, w, h, w] ### 实现内容 - **op_host**:算子原型定义(def)、InferShape/InferDataType、RegBase Tiling(多核切分 + UB 规划) - **op_kernel(arch35)**:Ascend950 RegBase 内核,支持 fp16/fp32/bf16 三种 dtype,normal/reversed 两种 layout - **op_graph**:GEIR proto 声明(含 DT_BF16,对齐 950 实现) - **golden**:tests/assets/golden.py(numpy 复刻 cast 链,随 PR 上库) - **UT**:infershape UT(9 case,含 -1/-2 动态 shape)+ tiling UT(41 case,含负向校验) - **GEIR 测试**:examples/arch35/test_geir_normalize_bbox.cpp(真机 RunGraph 验证) - **文档**:README.md + docs/zh/op_list.md 条目 ### 产品支持 | 产品 | 支持 | |------|------| | Ascend 950PR/Ascend 950DT | √ | | Atlas A3 训练/推理系列产品 | √(built-in TBE) | | Atlas A2 训练/推理系列产品 | √(built-in TBE) | | Atlas 200I/500 A2 推理产品 | √(built-in TBE) | | Atlas 推理系列产品 | √(built-in TBE) | | Atlas 训练系列产品 | √(built-in TBE) | 注:Ascend950 为本 PR 新实现的 RegBase 内核;A2/A3/推理/训练系列由 canndev built-in TBE 实现支持。 ### 验证结果 | 测试项 | 规模 | 结果 | |--------|------|------| | ophost UT | 50 case | 50/50 PASS | | kernel UT | - | PASS | | 单算子出包 | --pkg --soc=ascend950 | SUCCESS | | 冒烟测试 | run_example graph(NPU 真机) | PASS,精度正确 | | pre-commit | 格式/拼写/OAT | PASS | | 文档链接 | MD 链接有效性 | PASS | ### 关联 Issue #4347 See merge request: cann/ops-nn!8130 | 2 个月前 | |
test(golden): 升级三个算子的 TestSpec Co-authored-by: raoliang_sac<raoliang4@huawei.com> # message auto-generated for no-merge-commit merge: !8493 merge fix/three-ops-golden-spec-update into master test(golden): 升级三个算子的 TestSpec Created-by: raoliang_sac Commit-by: raoliang_sac Merged-by: cann-robot Description: ## 描述 本次仅更新以下三个算子的 tests/assets/golden.py: - INTrainingReduceV2 - SGD - NormalizeBBox 主要改动: - 引入 __spec__ TestSpec 注册,kernel 与 GEIR 共用 snake_case 算子键和 Spec。 - 按新 golden 规范补充 Promote 感知的 CPU true-value、独立 Torch third-party composition 以及 cross_check 容差配置。 - 保留兼容旧加载器的 __golden__,并与 TestSpec 复用同一计算核心。 - INTrainingReduceV2 使用 FP64 true-value 处理大归约;SGD 对齐 arch35 DAG 的 Nesterov 运算顺序并保持 IEEE/动量写回语义;NormalizeBBox 对齐 dtype cast 链并保留 batch=0 行为。 - 三个需求均明确不支持 ACLNN 接口,因此不注册 ACLNN 或 e2e 通路。 ## 关联的Issue 关联 Issue #4679:https://gitcode.com/cann/ops-nn/issues/4679 ## 测试 - 三个目标文件执行 pre-commit run --files:通过。 - ops-test-kit TestSpec loader/validator:通过。 - 本地语义回归:NormalizeBBox legacy/batch=0/Promote/Compose、SGD 多 dtype 与六种分支组合及特殊位模式、INTrainingReduceV2 输出契约与高精度消去场景均通过。 - 未执行依赖 NPU/GPU 的完整 TTK cross-check。 ## 文档更新 无,本次仅更新 golden 测试资产。 ## 类型标签 - [ ] Bug修复 - [ ] 新特性 - [ ] 性能优化 - [ ] 文档更新 - [x] 其他,请描述:测试 golden 规范升级 ## AI/Agent生成声明 - [x] AI辅助编写 See merge request: cann/ops-nn!8493 | 2 个月前 | |
feat: NormalizeBBox 算子 Ascend950 重实现 无aclnn Co-authored-by: raoliang_sac<raoliang4@huawei.com> # message auto-generated for no-merge-commit merge: !8130 merge feat/normalize_bbox_no_aclnn into master feat: NormalizeBBox 算子 Ascend950 重实现 无aclnn Created-by: raoliang_sac Commit-by: raoliang_sac Merged-by: cann-robot Description: ## 变更说明 NormalizeBBox 算子 Ascend950(arch35 RegBase)重实现,仅支持 GEIR 图模式通路,不提供 aclnn 接口。 ### 算子功能 将目标检测预选框的绝对像素坐标,按对应图像的高(height)与宽(width)逐 batch 归一化到 [0, 1] 区间。每个框由 4 个坐标构成,y 系坐标除以 height、x 系坐标除以 width。 计算公式: 对第 b 个 batch,令 h = shapeHw[b, 0]、w = shapeHw[b, 1](int32 转 float): y[b,i] = boxes[b,i] / [h, w, h, w] ### 实现内容 - **op_host**:算子原型定义(def)、InferShape/InferDataType、RegBase Tiling(多核切分 + UB 规划) - **op_kernel(arch35)**:Ascend950 RegBase 内核,支持 fp16/fp32/bf16 三种 dtype,normal/reversed 两种 layout - **op_graph**:GEIR proto 声明(含 DT_BF16,对齐 950 实现) - **golden**:tests/assets/golden.py(numpy 复刻 cast 链,随 PR 上库) - **UT**:infershape UT(9 case,含 -1/-2 动态 shape)+ tiling UT(41 case,含负向校验) - **GEIR 测试**:examples/arch35/test_geir_normalize_bbox.cpp(真机 RunGraph 验证) - **文档**:README.md + docs/zh/op_list.md 条目 ### 产品支持 | 产品 | 支持 | |------|------| | Ascend 950PR/Ascend 950DT | √ | | Atlas A3 训练/推理系列产品 | √(built-in TBE) | | Atlas A2 训练/推理系列产品 | √(built-in TBE) | | Atlas 200I/500 A2 推理产品 | √(built-in TBE) | | Atlas 推理系列产品 | √(built-in TBE) | | Atlas 训练系列产品 | √(built-in TBE) | 注:Ascend950 为本 PR 新实现的 RegBase 内核;A2/A3/推理/训练系列由 canndev built-in TBE 实现支持。 ### 验证结果 | 测试项 | 规模 | 结果 | |--------|------|------| | ophost UT | 50 case | 50/50 PASS | | kernel UT | - | PASS | | 单算子出包 | --pkg --soc=ascend950 | SUCCESS | | 冒烟测试 | run_example graph(NPU 真机) | PASS,精度正确 | | pre-commit | 格式/拼写/OAT | PASS | | 文档链接 | MD 链接有效性 | PASS | ### 关联 Issue #4347 See merge request: cann/ops-nn!8130 | 2 个月前 | |
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 | 2 个月前 |
NormalizeBBox
产品支持情况
| 产品 | 是否支持 |
|---|---|
| Ascend 950PR/Ascend 950DT | √ |
| Atlas A3 训练系列产品/Atlas A3 推理系列产品 | √ |
| Atlas A2 训练系列产品/Atlas A2 推理系列产品 | √ |
| Atlas 200I/500 A2 推理产品 | √ |
| Atlas 推理系列产品 | √ |
| Atlas 训练系列产品 | √ |
功能说明
-
算子功能:将目标检测预选框的绝对像素坐标,按对应图像的高(height)与宽(width)逐batch归一化到
[0, 1]区间。每个框由4个坐标构成,y系坐标除以height、x系坐标除以width。 -
计算公式:
对第b个batch,令h=shapeHw[b,0]h = shapeHw[b, 0]h=shapeHw[b,0]、w=shapeHw[b,1]w = shapeHw[b, 1]w=shapeHw[b,1](int32转float):
yb,i=boxesb,i/[h,w,h,w]y_{b,i} = boxes_{b,i} / [h, w, h, w] yb,i=boxesb,i/[h,w,h,w]
其中iii遍历该batch内的每个框。boxes第0维为batch,coord轴(大小为4)与batch之间可有任意多个中间维(其乘积为每batch的框数num),boxes的rank支持2~8。
reversedBox仅改变coord轴在内存中的位置,不改变数学语义:reversedBox = false:boxes形如(batch,…,4)(batch, \ldots, 4)(batch,…,4),coord轴在最后一维(如(batch,num,4)(batch, num, 4)(batch,num,4)、(batch,H,W,4)(batch, H, W, 4)(batch,H,W,4))。reversedBox = true:boxes形如(batch,4,…)(batch, 4, \ldots)(batch,4,…),coord轴在第1维(如(batch,4,num)(batch, 4, num)(batch,4,num)、(batch,4,H,W)(batch, 4, H, W)(batch,4,H,W))。
参数说明
| 参数名 | 输入/输出/属性 | 描述 | 数据类型 | 数据格式 |
|---|---|---|---|---|
| boxes | 输入 | 表示传入的框绝对坐标张量,公式中的boxes。rank 2-8,dim0=batch,coord轴大小为4,中间维乘积为num。 | FLOAT、FLOAT16 | ND |
| shapeHw | 输入 | 逐batch的图像尺寸,[0]=height、[1]=width。rank 2,dim1 == 3。 | INT32 | ND |
| reversedBox | 属性 | 可选,boxes坐标排布开关,默认false。 | BOOL | - |
| y | 输出 | 表示归一化后的输出张量,公式中的y。dtype/shape与boxes一致。 | FLOAT、FLOAT16 | ND |
约束说明
shapeHw的batch(dim0)必须与boxes的batch(dim0)一致。boxes的rank须在[2, 8]范围内。reversedBox = false时boxes末维须为4;reversedBox = true时boxes的dim1须为4。- 本算子不提供aclnn单算子接口,仅支持GE图模式调用。
调用说明
| 调用方式 | 样例代码 | 说明 |
|---|---|---|
| 图模式接口 | test_geir_normalize_bbox.cpp | 通过GE图模式构建NormalizeBBox算子图并执行RunGraph验证。 |