已关闭
[Requirement|需求建议]: [CANNBot]新增rotated_box_encode算子 #818
huangzhiyuan创建于  8月25日关闭于  8月26日
huangzhiyuan
huangzhiyuan成员
8月25日 创建

Thanks for sending an requirement! Please fill in the following template to help quickly solve your problem.

Backgroud(背景信息)

RotatedBoxEncode 是旋转目标检测(Rotated Object Detection)训练阶段的核心算子。在主流旋转检测框架(如 RoI Transformer、 Oriented R-CNN、DOTA 系列检测器)中,网络需要对锚框(anchor_box)与 ground-truth 旋转框之间的几何偏差进行回归监督。RotatedBoxEncode 负责将这对旋转框的几何偏差编码为 5 通道回归 delta 目标 (dx, dy, dw, dh, dθ),供网络损失函数计算使用。它是已有 RotatedBoxDecode 算子的逆运算,两者共同构成旋转框回归的编解码闭环。

当前 Ascend 950(arch35)平台尚无该算子的原生 AscendC 实现,旋转检测训练管线在此平台上存在算子缺口。

Origin(信息来源)

NA

Benefit / Necessity (价值/作用)

  1. 补齐算子链路:为 Ascend 950 平台提供 RotatedBoxEncode 的原生 AscendC 实现,与已交付的 RotatedBoxDecode 配套,使旋转目标检测训练管线(anchor 编码 → 网络回归 → delta 解码)在 Ascend 950 上端到端可用。
  2. 性能收益:通过多核并行 + UB 流水 + VF 向量融合实现高性能编码,替代框架侧 CPU fallback 或通用计算图拼接,降低端到端训练耗时。
  3. 精度保障:FP16 输入内部升精度到 FP32 完成对数、三角与除法计算,并采用数值稳定性恒等变形(ln(a)−ln(b) 替代 ln(a/b)、sin(Δθ)/(cos·cos) 替代 tan(a)−tan(b)),规避硬件 FTZ 与奇点消去导致的精度偏差。
  4. 规格完备:覆盖 FP16/FP32 双 dtype、动态 shape、空 tensor 短路、ND 格式等完整规格,配套 InferShape/InferDataType/Tiling UT 及 GEIR 调用示例,满足交付质量要求。

Design(设计方案)

1. 算子接口

参数名 输入/输出/属性 描述 数据类型 数据格式
anchor_box 输入 参考旋转框,3D 张量 (B, 5, N),5 = [x0, y0, x1, y1, θ_deg],角度单位为度 FLOAT16、FLOAT ND
gt_box 输入 ground-truth 旋转框,3D 张量 (B, 5, N),结构与 anchor_box 一致 FLOAT16、FLOAT ND
y 输出 编码后的 5 通道 delta,(B, 5, N) = [dx, dy, dw, dh, dθ],shape/dtype 与 anchor_box 恒等 FLOAT16、FLOAT ND
weight 可选属性 5 通道编码权重 [wx, wy, ww, wh, wa],各 delta 通道分别乘以对应权重,默认 [1, 1, 1, 1, 1] ListFloat -

约束:anchor_box / gt_box / y 三者 dtype 必须一致;anchor_box 与 gt_box shape 完全一致(无广播),秩为 3,第 1 维必须为 5;weight 若提供长度必须为 5;空 tensor(B=0 或 N=0)直接短路返回空输出。

2. 计算公式

角点形式 (x0, y0, x1, y1, θ_deg) 转中心 (cx, cy, w, h) 后逐通道编码:

w_a = max(x1_a - x0_a, 1.0),  h_a = max(y1_a - y0_a, 1.0)
cx_a = x0_a + w_a/2,          cy_a = y0_a + h_a/2
w_g = max(x1_g - x0_g, 1.0),  h_g = max(y1_g - y0_g, 1.0)
cx_g = x0_g + w_g/2,          cy_g = y0_g + h_g/2

dx = (cx_g - cx_a) / w_a · wx
dy = (cy_g - cy_a) / h_a · wy
dw = (ln(w_g) - ln(w_a)) · ww
dh = (ln(h_g) - ln(h_a)) · wh
dθ = (tan(θ_g) - tan(θ_a)) · wa

max(·, 1.0) 防止退化框导致除零与 log(0),并按 np.maximum 语义传播 NaN。

3. Host 侧设计

  • OpDef 注册(rotated_box_encode_def.cpp):声明双输入/单输出/可选属性,AICore 配置 ascend950,开启动态编译静态、动态格式、动态 shape 支持。
  • InferDataType(rotated_box_encode_graph_infer.cpp):y.dtype = anchor_box.dtype = gt_box.dtype,拒绝 dtype 不一致。
  • InferShape(rotated_box_encode_infershape.cpp):y.shape = anchor_box.shape,恒等映射,无广播。
  • Tiling(rotated_box_encode_tiling_arch35.h/.cpp):
    • 编译期 TilingParse 解析平台信息(AIV 核数、UB 大小)。
    • 运行时 Tiling 按 dtype 分两条分支:
      • Branch-0(FP16-upcast):perBoxBytes=70(1 个 fp16 IO 缓冲 + 3 个 fp32 计算缓冲),UB 对齐因子 128 box,多核对齐 512 box。
      • Branch-1(FP32-direct):perBoxBytes=60(3 个 fp32 缓冲,无 Cast),UB 对齐因子 64 box,多核对齐 512 box。
    • 多核数估算:coreNum = ceil(dim0 × minDtypeBits / 32768),上限为平台 AIV 核数;每核 box 数对齐到 ELEM_ALIGN_FACTOR=512。
    • UB tile:ubFormer = alignDown(ubSize / perBoxBytes, alignFactor);首 block / 尾 block 各自的 UB 循环数与尾块大小均预计算写入 TilingData。
    • 空 tensor 短路:dim0==0 时置 coreNum=0、SetBlockDim(0),kernel 不执行。

4. Kernel 侧设计(rotated_box_encode_kernel.h)

  • 模板特化:通过 DTYPE 模板参数(FP16=0 / FP32=1)编译期生成两个 binary,由 tilingKey 选择,if constexpr 分支调度。
  • UB 布局:通道分离布局 [5, ubStride],ubStride = ceilAlign(boxCount, 16) 保证每通道起始地址 32B 对齐(满足 LoadAlign/StoreAlign 要求)。
  • 流水线:
    • FP16 路径(S1–S8):CopyIn(MTE2) → Cast fp16→fp32(V) → CopyIn gt → Cast → dθ 预计算 → VF C1–C9 → Cast fp32→fp16 → CopyOut(MTE3)。P=4 TBuf(B0 fp16 IO / B1 fp32 anchor / B2 fp32 gt / B3 fp32 output)。
    • FP32 路径(S1–S5):CopyIn(MTE2) → CopyIn gt → dθ 预计算 → VF C1–C9 → CopyOut(MTE3)。P=3 TBuf(B0 fp32 anchor / B1 fp32 gt / B2 fp32 output),无 Cast。
  • VF 向量函数(3 个 __simd_vf__ 函数,FP32-only,双分支共享):
    • DxDwVF:计算 dx(ch0)与 dw(ch2),链路 C1+C3+C4+C5+C7,峰值 5 个活跃 RegTensor。
    • DyDhVF:计算 dy(ch1)与 dh(ch3),链路 C2+C3'+C4'+C6+C8,峰值 5 个活跃 RegTensor。
    • DThetaVF:计算 dθ(ch4),读取预计算的 dθ_prewa 乘以 wa,链路 C9,峰值 3 个活跃 RegTensor。
  • 数据搬运:GM 布局 [B, 5, N] 行优先,按 per-batch-segment per-channel 拆分拷贝。N 对齐时走 DataCopyPad 快速路径(fp16 需 N%16==0,fp32 需 N%8==0),否则回退到标量 GetValue/SetValue。
  • 多核调度:GetBlockIdx → 首/尾 block 双层循环 → ProcessTile;超配核(blockIdx >= blockNum)直接跳过。

5. 数值稳定性设计

问题 方案 原理
dw/dh = ln(w_g/w_a) 比值下溢 改用 ln(w_g) − ln(w_a) ln(a/b)=ln(a)−ln(b) 恒等变形;两操作数 ≥1.0(Maxs 下限),Ln 输入 ≥0,无非规格数
dθ = tan(θ_g) − tan(θ_a) 90° 奇点消去 改用 sin(Δθ) / (cos(θ_g)·cos(θ_a)) tan 差角恒等变形;避免两个大 tan 值相减丢失有效位
硬件 Sin/Cos 超范围(|θ_rad|>65504)返回 ±Inf dθ_prewa + 0 × dθ_prewa → NaN IEEE-754 inf×0=NaN 恒等式;将超范围 Inf 转为 NaN,与 golden 行为对齐

6. 测试与验证

  • InferShape UT:覆盖正常 shape、空 tensor、动态 shape 等场景。
  • Tiling UT:覆盖 FP16/FP32 双分支、多核切分、首/尾 block 边界、空 tensor 短路。
  • Golden:基于 PyTorch 的参考实现(golden.py),使用 torch.maximum 传播 NaN 语义、torch.log 差值计算 dw/dh。
  • GEIR 示例:图模式端到端调用样例,验证算子在实际图编译流程中的可用性。
likedislike
huangzhiyuanhuangzhiyuan成员
8月25日 添加了label:requirement
huangzhiyuanhuangzhiyuan成员
8月25日 关联了pull request:[CANNBot]新增rotated_box_encode算子
Ssunhao_hw成员
8月25日 将 h1234515 设为负责人
huangzhiyuanhuangzhiyuan成员
8月25日 修改了issue 的描述
CANN-robotCANN-robot成员
8月26日 关闭了 issue
CANN-robotCANN-robot成员
8月26日 添加了label:resolved