已合并
修复iou3d算子精度问题 #1197
yulianjie创建于 23 天前
修复iou3d算子精度问题 #1197
已合并
yulianjie创建于 23 天前
4 个文件变更+196-155
Mobjdetect/iou3d/op_host/arch35/iou3d_tiling_arch35.cpp+24-1
@@ -26,6 +26,7 @@
26#include "op_common/log/log.h"26#include "op_common/log/log.h"
27#include "op_common/op_host/util/math_util.h"27#include "op_common/op_host/util/math_util.h"
28#include "op_common/op_host/util/platform_util.h"28#include "op_common/op_host/util/platform_util.h"
29+#include "lib/math/cos_tiling.h"
29#include "../../op_kernel/arch35/iou3d_tiling_data.h"30#include "../../op_kernel/arch35/iou3d_tiling_data.h"
30 31 
31namespace optiling {32namespace optiling {
@@ -41,6 +42,9 @@ constexpr int64_t IOU3D_DOF = 7; // 7-DoF 通道
41// 单批处理的 (i,j) 对数(UB 批大小)。保守取 256(UB 预算 ~180KB < 248KB)。42// 单批处理的 (i,j) 对数(UB 批大小)。保守取 256(UB 预算 ~180KB < 248KB)。
42constexpr uint32_t IOU3D_TILE_LEN = 256U;43constexpr uint32_t IOU3D_TILE_LEN = 256U;
43 44 
45+// 对齐 kernel 侧配置:仅 Cos 使用高精度角度归约算法,Sin 路径保持不变。
46+constexpr AscendC::CosConfig IOU3D_HIGH_PRECISION_COS_CONFIG{AscendC::CosAlgo::RADIAN_REDUCTION};
47+ 
44// 获取平台信息(coreNum, ubSize)。48// 获取平台信息(coreNum, ubSize)。
45static ge::graphStatus GetPlatformInfo(gert::TilingContext* context, uint64_t* ubSize, int64_t* coreNum)49static ge::graphStatus GetPlatformInfo(gert::TilingContext* context, uint64_t* ubSize, int64_t* coreNum)
46{50{
@@ -86,7 +90,7 @@ static ge::graphStatus GetShapeInfo(gert::TilingContext* context, int64_t* batch
86 gShape.GetDim(0)),90 gShape.GetDim(0)),
87 return ge::GRAPH_FAILED);91 return ge::GRAPH_FAILED);
88 // D5 对标 mmcv:移除 K≤2000 上限(mmcv 无 K 限制)。多核切分按 totalPairs=B*N*K(int64)均分,92 // D5 对标 mmcv:移除 K≤2000 上限(mmcv 无 K 限制)。多核切分按 totalPairs=B*N*K(int64)均分,
89- // UB 批处理按固定 tileLen(256) 分批,Sort32 固定 32 元素(多边形顶点 <=8),均与 K 无耦合,任意 K 成立。93+ // UB 批处理按固定 tileLen(256) 分批,Sort32 固定 32 元素(有效顶点 <=16),均与 K 无耦合,任意 K 成立。
90 94 
91 // dtype 校验(float32)。dtype 由 def 文件驱动展开 kernel 变体,此处仅运行时友好报错,95 // dtype 校验(float32)。dtype 由 def 文件驱动展开 kernel 变体,此处仅运行时友好报错,
92 // 不再编码进 tiling_key(避免与 def 的 DataType 声明重复编码 dtype 维度)。96 // 不再编码进 tiling_key(避免与 def 的 DataType 声明重复编码 dtype 维度)。
@@ -162,6 +166,25 @@ static ge::graphStatus Iou3DTilingFunc(gert::TilingContext* context)
162 tiling->tileLen = tileLen;166 tiling->tileLen = tileLen;
163 tiling->tailLen = (tileLen == 0U) ? 0U : static_cast<uint32_t>(pairsPerCore % static_cast<int64_t>(tileLen));167 tiling->tailLen = (tileLen == 0U) ? 0U : static_cast<uint32_t>(pairsPerCore % static_cast<int64_t>(tileLen));
164 168 
169+ // 使用与 kernel 相同的 RADIAN_REDUCTION 配置计算最大临时空间。
170+ // kernel 的向量长度按 32B 对齐,所以这里也使用对齐后的 tile shape。
171+ const uint32_t alignedTileLen = ((tileLen + 7U) / 8U) * 8U;
172+ const ge::Shape cosTileShape({static_cast<int64_t>(alignedTileLen)});
173+ uint32_t cosMaxTmpSize = 0U;
174+ uint32_t cosMinTmpSize = 0U;
175+ AscendC::GetCosMaxMinTmpSize(IOU3D_HIGH_PRECISION_COS_CONFIG, cosTileShape, sizeof(float), false, cosMaxTmpSize,
176+ cosMinTmpSize);
177+ // 部分 CANN 版本 CosConfig 重载可能返回 0(stub 未实现),回退到无 config 重载。
178+ // 无 config 重载返回 POLYNOMIAL_APPROXIMATION 的 max tmp,该值 >= RADIAN_REDUCTION 的 max tmp
179+ // (实测 8 elem: 768 vs 288;256 elem: 3072 vs 2080),作为上界安全。
180+ if (cosMaxTmpSize == 0U) {
181+ AscendC::GetCosMaxMinTmpSize(cosTileShape, sizeof(float), false, cosMaxTmpSize, cosMinTmpSize);
182+ }
183+ OP_CHECK_IF(cosMaxTmpSize == 0U || cosMaxTmpSize > ubSize,
184+ OP_LOGE(context, "Iou3D: invalid high-precision Cos tmp size %u (UB=%lu)", cosMaxTmpSize, ubSize),
185+ return ge::GRAPH_FAILED);
186+ tiling->cosTmpSize = cosMaxTmpSize;
187+ 
165 context->SetBlockDim(static_cast<uint32_t>(usedCoreNum));188 context->SetBlockDim(static_cast<uint32_t>(usedCoreNum));
166 189 
167 return ge::GRAPH_SUCCESS;190 return ge::GRAPH_SUCCESS;
Mobjdetect/iou3d/op_kernel/arch35/iou3d.h+167-154
@@ -21,20 +21,16 @@
21 * Z 轴重叠 clamp 非负 → epsilon 除法 → 普通 DataCopyPad 写回((b,i,j) 单点不相交写,无需原子加)。21 * Z 轴重叠 clamp 非负 → epsilon 除法 → 普通 DataCopyPad 写回((b,i,j) 单点不相交写,无需原子加)。
22 *22 *
23 * 编程模型:RegBase(arch35) kernel-shell + Scalar 混合。23 * 编程模型:RegBase(arch35) kernel-shell + Scalar 混合。
24- * - 向量批算:AscendC::Sin / AscendC::Cos(4/pair 顶点 theta,adv_api math)。24+ * - 向量批算:AscendC::Sin / AscendC::Cos(pair theta,adv_api math)。
25 * - 硬件排序:>3 顶点走 AscendC::Sort32 + Extract(diamond-angle 极角键,替代标量选择排序)。25 * - 硬件排序:>3 顶点走 AscendC::Sort32 + Extract(diamond-angle 极角键,替代标量选择排序)。
26- * - 标量几何:分支密集(corners_num∈{0..8}),逐对用 LocalTensor::GetValue 读标量控制。26+ * - 标量几何:分支密集(corners_num∈{0..24}),逐对用 LocalTensor::GetValue 读标量控制。
27 * - 数值稳定三守卫:27 * - 数值稳定三守卫:
28 * epsilon_guard_division : iou = interVol / max(union, 1e-6)(对标 mmcv clamp,golden.py:37728 * epsilon_guard_division : iou = interVol / max(union, 1e-6)(对标 mmcv clamp,golden.py:377
29 * clamp_z_overlap_nonneg : real_d = max(min-max, 0)29 * clamp_z_overlap_nonneg : real_d = max(min-max, 0)
30 * degenerate_polygon_guard : corners_num < 3 → area = 030 * degenerate_polygon_guard : corners_num < 3 → area = 0
31- * - 近同旋转框 bowtie 半面积退化修复fp32 特有31+ * - 候选点语义:CollectCorners 不去重,按 golden 顺序完整保留 16 组边交点、再收集 8 次包含点最多 24 点
32- * 幅值相对强去重 : CollectCorners 去重容差 tol=max(1e-6, 1e-4·max(1,|x|,|y|))32+ * - MMCV fan area: SortPolygonArea 以排序后首顶点为基准做有符号扇形累加末尾一次 abs。
33- * 坍缩 fp32 向量 Sin/Cos lane 微差产生的近重复顶点(m=6/8→4),33+ * - 红线 : 面积层严禁任何 NaN 守卫;NaN/inf IEEE754 自然传播。
34- * 相对幅值以兼容大坐标场景(不误并真顶点)。
35- * signed shoelace: SortPolygonArea 面积用有符号鞋带(不 per-triangle 取 abs,末尾一次 abs),
36- * 对残留错序/自交鲁棒(错序正负抵消,不放大成半面积)。
37- * 红线 : 面积层严禁任何 NaN 守卫;NaN/inf 按 IEEE754 自然传播。
38 *34 *
39 * 布局:bboxes[B,7,N] 索引(b,c,i)=b*7*N + c*N + i;gtboxes[B,7,K] 同理;iou[B,N,K] 索引(b,i,j)=b*N*K + i*K + j。35 * 布局:bboxes[B,7,N] 索引(b,c,i)=b*7*N + c*N + i;gtboxes[B,7,K] 同理;iou[B,N,K] 索引(b,i,j)=b*N*K + i*K + j。
40 * 每核负责 flatten (b,i,j) 的一段连续区间(不相交),每元素只被一个核写一次,输出连续段用普通 DataCopyPad 写回36 * 每核负责 flatten (b,i,j) 的一段连续区间(不相交),每元素只被一个核写一次,输出连续段用普通 DataCopyPad 写回
@@ -52,28 +48,32 @@ namespace NsIou3D {
52 48 
53using namespace AscendC;49using namespace AscendC;
54 50 
55-constexpr uint32_t IOU3D_DOF = 7; // 7-DoF 通道数51+constexpr uint32_t IOU3D_DOF = 7; // 7-DoF 通道数
56-constexpr uint32_t IOU3D_CORNERS = 4; // 每框 BEV 顶点数52+constexpr uint32_t IOU3D_CORNERS = 4; // 每框 BEV 顶点数
57-constexpr uint32_t IOU3D_MAX_INTER = 8; // 交集多边形顶点数上限(两凸四边形交集 <= 8)53+// 对齐 MMCV iou3d_cuda_kernel.cuh Point cross_points[16]。
58-constexpr float IOU3D_EPSILON = 1e-6f; // IoU 分母 clamp 下限(对标 mmcv golden.py:37 EPS_IOU=1e-6)54+constexpr uint32_t IOU3D_MAX_INTER = 16;
59-// 对标 mmcv:边相交退化判据阈值。|s5-s1|>EPS_KERNEL 用叉积公式,否则退化一般式直线方程55+constexpr float IOU3D_EPSILON = 1e-6f; // IoU 分母 clamp 下限(对标 mmcv golden.py:37 EPS_IOU=1e-6)
60-// mmcv golden.py:35/153 EPS_KERNEL=1e-8)56+// MMCV CUDA intersection 的退化分支阈值
61constexpr float IOU3D_EPS_KERNEL = 1e-8f;57constexpr float IOU3D_EPS_KERNEL = 1e-8f;
58+// float32 最大有限值:仅用于区分有限输入与 NaN/Inf,不改变 NaN/Inf 传播语义。
59+constexpr float IOU3D_MAX_FINITE = 3.402823466e38f;
62// 对标 mmcv:顶点包含测试绝对容差。反向旋转到框局部系后判 |rot|<half+MARGIN60// 对标 mmcv:顶点包含测试绝对容差。反向旋转到框局部系后判 |rot|<half+MARGIN
63// (对标 mmcv golden.py:36/194-195 MARGIN=1e-2,严格 <)。61// (对标 mmcv golden.py:36/194-195 MARGIN=1e-2,严格 <)。
64constexpr float IOU3D_MARGIN = 1e-2f;62constexpr float IOU3D_MARGIN = 1e-2f;
65-constexpr float IOU3D_DEDUP_TOL = 1e-6f; // 顶点去重绝对容差下限(小坐标场景,D6 保留现状)
66-// 幅值相对强去重容差(D6 保留现状)。fp32 向量 Sin/Cos 逐 lane 微差使「同一角点」在 bbox/gtbox 两通道间
67-// 偏差 ~1e-7~1e-5·幅值,叠加近共线边额外交点,使 identical box 去重后仍残留 m∈{6,8} 近重复
68-// 顶点 → Sort32 tie-break bowtie → 半面积 → IoU=1/3。用相对幅值容差 tol=max(ABS, REL·max(1,|x|,|y|))
69-// 把近重复坍缩回 4 真角点;相对而非绝对以兼容大坐标(1e20 场景不被误并——真顶点间距 >> REL·幅值)。
70-constexpr float IOU3D_DEDUP_REL = 1e-4f; // 顶点去重相对幅值容差(D6 保留现状)
71// fp32 32B(one data block) = 8 元素。RegBase(arch35) 向量 adv_api Sin/Cos 要求 src/dst 32B 对齐63// fp32 32B(one data block) = 8 元素。RegBase(arch35) 向量 adv_api Sin/Cos 要求 src/dst 32B 对齐
72// (sin_3510_impl 用 Reg::StoreAlign<..,DIST_PACK_B32>),故所有参与向量计算的 UB 子段起址与长度按 8 对齐。64// (sin_3510_impl 用 Reg::StoreAlign<..,DIST_PACK_B32>),故所有参与向量计算的 UB 子段起址与长度按 8 对齐。
73constexpr uint32_t IOU3D_ALIGN_ELEM = 8; // fp32 一个 datablock 的元素数(32B / 4B)65constexpr uint32_t IOU3D_ALIGN_ELEM = 8; // fp32 一个 datablock 的元素数(32B / 4B)
66+// Cos 精度修复只覆盖已确认存在默认角度归约缺口的窄角度域,并仅替换至少相差约 1 ULP 的结果。
67+// 其他角度完整保留默认 Cos;Sin 路径始终不变。
68+constexpr float IOU3D_COS_FIX_MIN_ABS_ANGLE = 2.8f;
69+constexpr float IOU3D_COS_FIX_MAX_ABS_ANGLE = 3.0f;
70+constexpr float IOU3D_COS_FIX_MIN_DELTA = 5.9e-8f;
74// 硬件极角排序(Sort32)常量。71// 硬件极角排序(Sort32)常量。
75-constexpr uint32_t IOU3D_SORT32_LEN = 32U; // Sort32 一趟固定处理 32 元素(8 有效 + 24 padding 沉底)72+constexpr uint32_t IOU3D_SORT32_LEN = 32U; // Sort32 一趟固定处理 32 元素(最多 16 有效,其余 padding 沉底)
76-constexpr float IOU3D_NEG_INF_KEY = -1.0e30f; // padding 槽键值(沉底到排序末尾)73+// 高精度 Cos:使用角度归约算法;默认 Cos Sin 仍先按原路径计算。
74+constexpr AscendC::CosConfig IOU3D_HIGH_PRECISION_COS_CONFIG{AscendC::CosAlgo::RADIAN_REDUCTION};
75+ 
76+constexpr float IOU3D_NEG_INF_KEY = -1.0e30f; // padding 槽键值(沉底到排序末尾)
77constexpr uint32_t IOU3D_IDX_MASK = 0x07FFFFFFu; // Sort32 index 位宽 27bit,回读时按位与还原原始下标77constexpr uint32_t IOU3D_IDX_MASK = 0x07FFFFFFu; // Sort32 index 位宽 27bit,回读时按位与还原原始下标
78 78 
79// 向上取整对齐到 IOU3D_ALIGN_ELEM 的倍数(32B 对齐)79// 向上取整对齐到 IOU3D_ALIGN_ELEM 的倍数(32B 对齐)
@@ -100,26 +100,24 @@ private:
100 // 判 |rot_x|<halfDx+MARGIN && |rot_y|<halfDy+MARGIN(MARGIN=1e-2 绝对,严格 <)。100 // 判 |rot_x|<halfDx+MARGIN && |rot_y|<halfDy+MARGIN(MARGIN=1e-2 绝对,严格 <)。
101 __aicore__ inline bool PointInRect(float px, float py, float cx, float cy, float halfDx, float halfDy, float sinT,101 __aicore__ inline bool PointInRect(float px, float py, float cx, float cy, float halfDx, float halfDy, float sinT,
102 float cosT);102 float cosT);
103- // 线段相交 mmcv check_rect_cross + 跨立实验 + 直线求交 golden.py:104-168),相交返回 true 并写 (ox, oy)103+ // 线段相交:逐分支 MMCV check_rect_cross + 跨立实验 + 直线求交
104 __aicore__ inline bool SegIntersect(float a1x, float a1y, float a2x, float a2y, float b1x, float b1y, float b2x,104 __aicore__ inline bool SegIntersect(float a1x, float a1y, float a2x, float a2y, float b1x, float b1y, float b2x,
105 float b2y, float& ox, float& oy);105 float b2y, float& ox, float& oy);
106- // 收集交集点(去重),返回顶点数。box1/box2 各传 (cx,cy,halfDx,halfDy,sinT,cosT) 供反向旋转包含测试。106+ // 收集交集候选点(去重,MMCV 固定 16 槽),返回候选数。
107+ // box1/box2 各传 (cx,cy,halfDx,halfDy,sinT,cosT) 供反向旋转包含测试。
107 __aicore__ inline uint32_t CollectCorners(const float c1x[IOU3D_CORNERS], const float c1y[IOU3D_CORNERS],108 __aicore__ inline uint32_t CollectCorners(const float c1x[IOU3D_CORNERS], const float c1y[IOU3D_CORNERS],
108 const float c2x[IOU3D_CORNERS], const float c2y[IOU3D_CORNERS],109 const float c2x[IOU3D_CORNERS], const float c2y[IOU3D_CORNERS],
109 float box1cx, float box1cy, float box1hx, float box1hy, float box1sin,110 float box1cx, float box1cy, float box1hx, float box1hy, float box1sin,
110 float box1cos, float box2cx, float box2cy, float box2hx, float box2hy,111 float box1cos, float box2cx, float box2cy, float box2hx, float box2hy,
111 float box2sin, float box2cos, float px[IOU3D_MAX_INTER],112 float box2sin, float box2cos, float px[IOU3D_MAX_INTER],
112 float py[IOU3D_MAX_INTER]);113 float py[IOU3D_MAX_INTER]);
113- // 三角形面积(叉积114+ // 多边形面积(0/1/2→0;>=3 均对齐 MMCV:质心极角排序 + 首顶点扇形叉积
114- __aicore__ inline float TriArea(float x1, float y1, float x2, float y2, float x3, float y3);
115- // 多边形面积(0/1/2→0 守卫;3→三角形直算;>3→质心分解 + 硬件 Sort32 极角排序 + 三角形叉积和)
116 __aicore__ inline float PolygonArea(float px[IOU3D_MAX_INTER], float py[IOU3D_MAX_INTER], uint32_t m);115 __aicore__ inline float PolygonArea(float px[IOU3D_MAX_INTER], float py[IOU3D_MAX_INTER], uint32_t m);
117- // >3 顶点:硬件 Sort32 极角排序(diamond-angle )+ 质心分解叉积面积。116+ // >=3 顶点:硬件 Sort32 极角排序(diamond-angle 单调等价 atan2)+ MMCV 首顶点扇形面积。
118 __aicore__ inline float SortPolygonArea(float px[IOU3D_MAX_INTER], float py[IOU3D_MAX_INTER], uint32_t m);117 __aicore__ inline float SortPolygonArea(float px[IOU3D_MAX_INTER], float py[IOU3D_MAX_INTER], uint32_t m);
119 // 读取一个框的 7-DoF 标量(layout [B,DOF,D])118 // 读取一个框的 7-DoF 标量(layout [B,DOF,D])
120 __aicore__ inline void LoadBox(const GlobalTensor<DTYPE_BBOXES>& gm, int64_t b, int64_t idx, int64_t dimSize,119 __aicore__ inline void LoadBox(const GlobalTensor<DTYPE_BBOXES>& gm, int64_t b, int64_t idx, int64_t dimSize,
121 float box[IOU3D_DOF]);120 float box[IOU3D_DOF]);
122- 
123 __aicore__ inline float ScalarAbs(float v) { return v < 0.0f ? -v : v; }121 __aicore__ inline float ScalarAbs(float v) { return v < 0.0f ? -v : v; }
124 __aicore__ inline float ScalarMax(float a, float b) { return a > b ? a : b; }122 __aicore__ inline float ScalarMax(float a, float b) { return a > b ? a : b; }
125 __aicore__ inline float ScalarMin(float a, float b) { return a < b ? a : b; }123 __aicore__ inline float ScalarMin(float a, float b) { return a < b ? a : b; }
@@ -145,10 +143,11 @@ private:
145 uint32_t numN_ = 0;143 uint32_t numN_ = 0;
146 uint32_t numK_ = 0;144 uint32_t numK_ = 0;
147 uint32_t tileLen_ = 0;145 uint32_t tileLen_ = 0;
148- uint32_t alignedTl_ = 0; // 32B 对齐后的单批粒度(各 UB 子段步长)146+ uint32_t alignedTl_ = 0; // 32B 对齐后的单批粒度(各 UB 子段步长)
149- uint32_t isEmpty_ = 0; // 空 Tensor 标志(从 tilingData 读取,用于运行时判断)147+ uint32_t isEmpty_ = 0; // 空 Tensor 标志(从 tilingData 读取,用于运行时判断)
150- int64_t pairStart_ = 0; // 本核 flatten (b,i,j) 起始148+ uint32_t cosTmpSize_ = 0; // 高精度 Cos 显式 sharedTmpBuffer 字节数
151- int64_t pairCount_ = 0; // 本核 flatten 对数149+ int64_t pairStart_ = 0; // 本核 flatten (b,i,j) 起始
150+ int64_t pairCount_ = 0; // 本核 flatten 对数
152 int64_t totalPairs_ = 0;151 int64_t totalPairs_ = 0;
153};152};
154 153 
@@ -163,6 +162,7 @@ __aicore__ inline void Iou3D::Init(GM_ADDR bboxes, GM_ADDR gtboxes, GM_ADDR iou,
163 numK_ = tilingData->numGtboxes;162 numK_ = tilingData->numGtboxes;
164 tileLen_ = tilingData->tileLen;163 tileLen_ = tilingData->tileLen;
165 isEmpty_ = tilingData->isEmpty; // 保存空 Tensor 标志164 isEmpty_ = tilingData->isEmpty; // 保存空 Tensor 标志
165+ cosTmpSize_ = tilingData->cosTmpSize;
166 166 
167 totalPairs_ = static_cast<int64_t>(batch_) * numN_ * numK_;167 totalPairs_ = static_cast<int64_t>(batch_) * numN_ * numK_;
168 const int64_t pairsPerCore = tilingData->pairsPerCore;168 const int64_t pairsPerCore = tilingData->pairsPerCore;
@@ -186,8 +186,8 @@ __aicore__ inline void Iou3D::Init(GM_ADDR bboxes, GM_ADDR gtboxes, GM_ADDR iou,
186 uint32_t tl = (tileLen_ == 0U) ? 1U : tileLen_;186 uint32_t tl = (tileLen_ == 0U) ? 1U : tileLen_;
187 alignedTl_ = Iou3DCeilAlign(tl);187 alignedTl_ = Iou3DCeilAlign(tl);
188 pipe.InitBuffer(angleBuf, 6U * alignedTl_ * sizeof(float));188 pipe.InitBuffer(angleBuf, 6U * alignedTl_ * sizeof(float));
189- // Sin/Cos fp32 主路径不消耗 sharedTmpBuffer,但显式提供 32B 对齐的 tmp 以规避 PopStackBuffer 栈依赖189+ // RADIAN_REDUCTION Cos 消耗 Host tiling API 计算的显式 sharedTmpBuffer
190- pipe.InitBuffer(tmpBuf, alignedTl_ * sizeof(float));190+ pipe.InitBuffer(tmpBuf, cosTmpSize_);
191 pipe.InitBuffer(outBuf, alignedTl_ * sizeof(float));191 pipe.InitBuffer(outBuf, alignedTl_ * sizeof(float));
192 192 
193 // 硬件极角排序(Sort32)缓冲:一次分配、跨对复用(>3 顶点分支)。193 // 硬件极角排序(Sort32)缓冲:一次分配、跨对复用(>3 顶点分支)。
@@ -213,32 +213,36 @@ __aicore__ inline void Iou3D::LoadBox(const GlobalTensor<DTYPE_BBOXES>& gm, int6
213}213}
214 214 
215// ---------------------------------------------------------------------------215// ---------------------------------------------------------------------------
216-// BoxCorners( golden BoxCorners 顺序一致P1 上, P2 上, P3 右, P4 216+// BoxCorners(严格对齐 MMCV:左下、右下、右上、上,先轴对齐后逐点旋转
217// ---------------------------------------------------------------------------217// ---------------------------------------------------------------------------
218 218 
219__aicore__ inline void Iou3D::BoxCorners(float x, float y, float w, float h, float sinT, float cosT,219__aicore__ inline void Iou3D::BoxCorners(float x, float y, float w, float h, float sinT, float cosT,
220 float cx[IOU3D_CORNERS], float cy[IOU3D_CORNERS])220 float cx[IOU3D_CORNERS], float cy[IOU3D_CORNERS])
221{221{
222- float halfW = 0.5f * w;222+ float halfW = w / 2.0f;
223- float halfH = 0.5f * h;223+ float halfH = h / 2.0f;
224- float hwCos = halfW * cosT;224+ float x1 = x - halfW;
225- float hwSin = halfW * sinT;225+ float y1 = y - halfH;
226- float hhCos = halfH * cosT;226+ float x2 = x + halfW;
227- float hhSin = halfH * sinT;227+ float y2 = y + halfH;
228 228 
229- float xSubW = x - hwCos;229+ cx[0] = x1;
230- float ySubW = y - hwSin;230+ cy[0] = y1;
231- float xAddW = x + hwCos;231+ cx[1] = x2;
232- float yAddW = y + hwSin;232+ cy[1] = y1;
233+ cx[2] = x2;
234+ cy[2] = y2;
235+ cx[3] = x1;
236+ cy[3] = y2;
233 237 
234- cx[0] = xSubW - hhSin;238+ for (uint32_t k = 0; k < IOU3D_CORNERS; ++k) {
235- cy[0] = ySubW + hhCos; // P1 左上239+ float dx = cx[k] - x;
236- cx[1] = xAddW - hhSin;240+ float dy = cy[k] - y;
237- cy[1] = yAddW + hhCos; // P2 右上241+ float newX = dx * cosT - dy * sinT + x;
238- cx[2] = xAddW + hhSin;242+ float newY = dx * sinT + dy * cosT + y;
239- cy[2] = yAddW - hhCos; // P3 右下243+ cx[k] = newX;
240- cx[3] = xSubW + hhSin;244+ cy[k] = newY;
241- cy[3] = ySubW - hhCos; // P4 左下245+ }
242}246}
243 247 
244// ---------------------------------------------------------------------------248// ---------------------------------------------------------------------------
@@ -262,60 +266,51 @@ __aicore__ inline bool Iou3D::PointInRect(float px, float py, float cx, float cy
262}266}
263 267 
264// ---------------------------------------------------------------------------268// ---------------------------------------------------------------------------
265-// SegIntersect(对 mmcv intersection golden.py:104-168,逐分支复刻269+// SegIntersect(逐分支 MMCV intersection)
266-// ⚠️ 已知会重引入 θ=π fp32 伪交点风险(用户明确接受,为逐分支对标 mmcv 的权衡)270+// p0=(a1x,a1y), p1=(a2x,a2y), q0=(b1x,b1y), q1=(b2x,b2y)
267-// 变量映射(我方边 a=(a1→a2) 对应 mmcv p0→p1,边 b=(b1→b2) 对应 q0→q1):271+// check_rect_cross AABB 快速排斥;
268-// p0=(a1x,a1y) p1=(a2x,a2y) q0=(b1x,b1y) q1=(b2x,b2y)272+// s1*s2>0 && s3*s4>0 严格跨立;
269-// check_rect_cross 快速排斥(golden.py:104-112 / 139)273+// |s5-s1|>1e-8 用叉积公式,否则使用一般式直线方程。
270-// ② 跨立实验 s1*s2>0 && s3*s4>0(严格 >,共线/相切拒绝)(golden.py:143-149)
271-// cross_3pts(a,b,c)=(a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y)(golden.py:120)
272-// ③ |s5-s1|>EPS_KERNEL 用叉积公式,否则退化一般式直线方程(不判 D==0)(golden.py:152-166)
273// ---------------------------------------------------------------------------274// ---------------------------------------------------------------------------
274 275 
275__aicore__ inline bool Iou3D::SegIntersect(float a1x, float a1y, float a2x, float a2y, float b1x, float b1y, float b2x,276__aicore__ inline bool Iou3D::SegIntersect(float a1x, float a1y, float a2x, float a2y, float b1x, float b1y, float b2x,
276 float b2y, float& ox, float& oy)277 float b2y, float& ox, float& oy)
277{278{
278- // p0=(a1x,a1y) p1=(a2x,a2y) q0=(b1x,b1y) q1=(b2x,b2y)
279- // ① check_rect_cross 快速排斥(AABB 包围盒重叠判定),对标 golden.py:104-112
280 if (!(ScalarMin(a1x, a2x) <= ScalarMax(b1x, b2x) && ScalarMin(b1x, b2x) <= ScalarMax(a1x, a2x) &&279 if (!(ScalarMin(a1x, a2x) <= ScalarMax(b1x, b2x) && ScalarMin(b1x, b2x) <= ScalarMax(a1x, a2x) &&
281 ScalarMin(a1y, a2y) <= ScalarMax(b1y, b2y) && ScalarMin(b1y, b2y) <= ScalarMax(a1y, a2y))) {280 ScalarMin(a1y, a2y) <= ScalarMax(b1y, b2y) && ScalarMin(b1y, b2y) <= ScalarMax(a1y, a2y))) {
282 return false;281 return false;
283 }282 }
284 283 
285- // cross_3pts(a,b,c) = (a.x-c.x)*(b.y-c.y) - (b.x-c.x)*(a.y-c.y),对标 golden.py:115-120284+ float s1 = (b1x - a1x) * (a2y - a1y) - (a2x - a1x) * (b1y - a1y);
286- // 跨立实验(叉积判别),对标 golden.py:143-146285+ float s2 = (a2x - a1x) * (b2y - a1y) - (b2x - a1x) * (a2y - a1y);
287- float s1 = (b1x - a1x) * (a2y - a1y) - (a2x - a1x) * (b1y - a1y); // cross(q0, p1, p0)286+ float s3 = (a1x - b1x) * (b2y - b1y) - (b2x - b1x) * (a1y - b1y);
288- float s2 = (a2x - a1x) * (b2y - a1y) - (b2x - a1x) * (a2y - a1y); // cross(p1, q1, p0)287+ float s4 = (b2x - b1x) * (a2y - b1y) - (a2x - b1x) * (b2y - b1y);
289- float s3 = (a1x - b1x) * (b2y - b1y) - (b2x - b1x) * (a1y - b1y); // cross(p0, q1, q0)
290- float s4 = (b2x - b1x) * (a2y - b1y) - (a2x - b1x) * (b2y - b1y); // cross(q1, p1, q0)
291 288 
292- // 严格 >:共线/相切被拒(对标 golden.py:148)
293 if (!(s1 * s2 > 0.0f && s3 * s4 > 0.0f)) {289 if (!(s1 * s2 > 0.0f && s3 * s4 > 0.0f)) {
294 return false;290 return false;
295 }291 }
296 292 
297- // 交点坐标计算(对标 golden.py:152-166)293+ float s5 = (b2x - a1x) * (a2y - a1y) - (a2x - a1x) * (b2y - a1y);
298- float s5 = (b2x - a1x) * (a2y - a1y) - (a2x - a1x) * (b2y - a1y); // cross(q1, p1, p0)
299 if (ScalarAbs(s5 - s1) > IOU3D_EPS_KERNEL) {294 if (ScalarAbs(s5 - s1) > IOU3D_EPS_KERNEL) {
300 ox = (s5 * b1x - s1 * b2x) / (s5 - s1);295 ox = (s5 * b1x - s1 * b2x) / (s5 - s1);
301 oy = (s5 * b1y - s1 * b2y) / (s5 - s1);296 oy = (s5 * b1y - s1 * b2y) / (s5 - s1);
302 } else {297 } else {
303- // 退化情况:一般式直线方程(mmcv 不判 D==0,可产 inf/nan 并自然传播)
304 float a0 = a1y - a2y;298 float a0 = a1y - a2y;
305 float b0 = a2x - a1x;299 float b0 = a2x - a1x;
306 float c0 = a1x * a2y - a2x * a1y;300 float c0 = a1x * a2y - a2x * a1y;
307- float a1c = b1y - b2y;301+ float a1 = b1y - b2y;
308- float b1c = b2x - b1x;302+ float b1 = b2x - b1x;
309- float c1c = b1x * b2y - b2x * b1y;303+ float c1 = b1x * b2y - b2x * b1y;
310- float D = a0 * b1c - a1c * b0;304+ float d = a0 * b1 - a1 * b0;
311- ox = (b0 * c1c - b1c * c0) / D;305+ 
312- oy = (a1c * c0 - a0 * c1c) / D;306+ ox = (b0 * c1 - b1 * c0) / d;
307+ oy = (a1 * c0 - a0 * c1) / d;
313 }308 }
314 return true;309 return true;
315}310}
316 311 
317// ---------------------------------------------------------------------------312// ---------------------------------------------------------------------------
318-// CollectCorners(框1顶点∈框2 + 框2顶点∈框1 + 16 边相交含去重)313+// CollectCorners(16 边相交 + 8 次顶点包,不去重;追加顺序对齐 golden
319// ---------------------------------------------------------------------------314// ---------------------------------------------------------------------------
320 315 
321__aicore__ inline uint32_t Iou3D::CollectCorners(const float c1x[IOU3D_CORNERS], const float c1y[IOU3D_CORNERS],316__aicore__ inline uint32_t Iou3D::CollectCorners(const float c1x[IOU3D_CORNERS], const float c1y[IOU3D_CORNERS],
@@ -325,26 +320,9 @@ __aicore__ inline uint32_t Iou3D::CollectCorners(const float c1x[IOU3D_CORNERS],
325 float box2sin, float box2cos, float px[IOU3D_MAX_INTER],320 float box2sin, float box2cos, float px[IOU3D_MAX_INTER],
326 float py[IOU3D_MAX_INTER])321 float py[IOU3D_MAX_INTER])
327{322{
328- float rawX[IOU3D_MAX_INTER + IOU3D_MAX_INTER + 16];
329- float rawY[IOU3D_MAX_INTER + IOU3D_MAX_INTER + 16];
330 uint32_t rawCnt = 0;323 uint32_t rawCnt = 0;
331 324 
332- // 框1顶点 框2(反向旋转到框2局部系测试),对 mmcv golden.py:245 check_in_box2d(box_b, corners_a[k])325+ // Golden 先追加 4x4 边交点再追加包含点;不去重时保持该顺序可齐质心累加与排序 tie。
333- for (uint32_t i = 0; i < IOU3D_CORNERS; ++i) {
334- if (PointInRect(c1x[i], c1y[i], box2cx, box2cy, box2hx, box2hy, box2sin, box2cos)) {
335- rawX[rawCnt] = c1x[i];
336- rawY[rawCnt] = c1y[i];
337- ++rawCnt;
338- }
339- }
340- // 框2顶点 ∈ 框1,对标 mmcv golden.py:241 check_in_box2d(box_a, corners_b[k])
341- for (uint32_t i = 0; i < IOU3D_CORNERS; ++i) {
342- if (PointInRect(c2x[i], c2y[i], box1cx, box1cy, box1hx, box1hy, box1sin, box1cos)) {
343- rawX[rawCnt] = c2x[i];
344- rawY[rawCnt] = c2y[i];
345- ++rawCnt;
346- }
347- }
348 for (uint32_t i = 0; i < IOU3D_CORNERS; ++i) {326 for (uint32_t i = 0; i < IOU3D_CORNERS; ++i) {
349 float a1x = c1x[i], a1y = c1y[i];327 float a1x = c1x[i], a1y = c1y[i];
350 float a2x = c1x[(i + 1) % IOU3D_CORNERS], a2y = c1y[(i + 1) % IOU3D_CORNERS];328 float a2x = c1x[(i + 1) % IOU3D_CORNERS], a2y = c1y[(i + 1) % IOU3D_CORNERS];
@@ -353,71 +331,52 @@ __aicore__ inline uint32_t Iou3D::CollectCorners(const float c1x[IOU3D_CORNERS],
353 float b2x = c2x[(j + 1) % IOU3D_CORNERS], b2y = c2y[(j + 1) % IOU3D_CORNERS];331 float b2x = c2x[(j + 1) % IOU3D_CORNERS], b2y = c2y[(j + 1) % IOU3D_CORNERS];
354 float ox, oy;332 float ox, oy;
355 if (SegIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y, ox, oy)) {333 if (SegIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y, ox, oy)) {
356- rawX[rawCnt] = ox;334+ px[rawCnt] = ox;
357- rawY[rawCnt] = oy;335+ py[rawCnt] = oy;
358 ++rawCnt;336 ++rawCnt;
359 }337 }
360 }338 }
361 }339 }
362 340 
363- // 去重(幅值相对强去重)。tol = max(ABS_TOL, REL·max(1,|x|,|y|))341+ // 每个 k 先收框2顶点 ∈ 框1,再收框1顶点 ∈ 框2,对齐 golden.py::_box_overlap。
364- // 顶点自身幅值决定容差:小坐标退化为绝对 1e-6,大坐标(1e20)随幅值放大避免误并真顶点,342+ for (uint32_t k = 0; k < IOU3D_CORNERS; ++k) {
365- // fp32 近重复顶点(identical box m=6/8)被坍缩回 4 真角点 Sort32 键分离 → 稳定环序。343+ if (PointInRect(c2x[k], c2y[k], box1cx, box1cy, box1hx, box1hy, box1sin, box1cos)) {
366- // 最多保留 IOU3D_MAX_INTER 个。344+ px[rawCnt] = c2x[k];
367- uint32_t m = 0;345+ py[rawCnt] = c2y[k];
368- for (uint32_t k = 0; k < rawCnt; ++k) {346+ ++rawCnt;
369- float magK = ScalarMax(1.0f, ScalarMax(ScalarAbs(rawX[k]), ScalarAbs(rawY[k])));
370- float tolK = ScalarMax(IOU3D_DEDUP_TOL, IOU3D_DEDUP_REL * magK);
371- bool dup = false;
372- for (uint32_t u = 0; u < m; ++u) {
373- if (ScalarAbs(rawX[k] - px[u]) < tolK && ScalarAbs(rawY[k] - py[u]) < tolK) {
374- dup = true;
375- break;
376- }
377 }347 }
378- if (!dup && m < IOU3D_MAX_INTER) {348+ if (PointInRect(c1x[k], c1y[k], box2cx, box2cy, box2hx, box2hy, box2sin, box2cos)) {
379- px[m] = rawX[k];349+ px[rawCnt] = c1x[k];
380- py[m] = rawY[k];350+ py[rawCnt] = c1y[k];
381- ++m;351+ ++rawCnt;
382 }352 }
383 }353 }
384- return m;354+ return rawCnt;
385}355}
386 356 
387// ---------------------------------------------------------------------------357// ---------------------------------------------------------------------------
388-// TriArea(叉法)358+// PolygonArea:0/1/2 顶点 → 0;>=3 均进入 MMCV 的质心排序 + 首顶点扇形面路径。
389-// ---------------------------------------------------------------------------
390- 
391-__aicore__ inline float Iou3D::TriArea(float x1, float y1, float x2, float y2, float x3, float y3)
392-{
393- float v = x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2);
394- return ScalarAbs(v) * 0.5f;
395-}
396- 
397-// ---------------------------------------------------------------------------
398-// PolygonArea:0/1/2 顶点 → 0(degenerate_polygon_guard);3 → 三角形;
399-// >3 → 硬件 Sort32 极角排序(SortPolygonArea)
400// ---------------------------------------------------------------------------359// ---------------------------------------------------------------------------
401 360 
402__aicore__ inline float Iou3D::PolygonArea(float px[IOU3D_MAX_INTER], float py[IOU3D_MAX_INTER], uint32_t m)361__aicore__ inline float Iou3D::PolygonArea(float px[IOU3D_MAX_INTER], float py[IOU3D_MAX_INTER], uint32_t m)
403{362{
404 if (m < 3)363 if (m < 3)
405 return 0.0f; // degenerate_polygon_guard364 return 0.0f; // degenerate_polygon_guard
406- if (m == 3)
407- return TriArea(px[0], py[0], px[1], py[1], px[2], py[2]);
408 if (m > IOU3D_MAX_INTER)365 if (m > IOU3D_MAX_INTER)
409- m = IOU3D_MAX_INTER; // 顶点数上限守卫(两凸四边形交集 <=8)366+ m = IOU3D_MAX_INTER;
410 return SortPolygonArea(px, py, m);367 return SortPolygonArea(px, py, m);
411}368}
412 369 
413// ---------------------------------------------------------------------------370// ---------------------------------------------------------------------------
414-// SortPolygonArea:>3 顶点,硬件 Sort32 极角排序(diamond-angle 键)+ 质心分解叉积面积。371+// SortPolygonArea:>=3 顶点,硬件 Sort32 极角排序(diamond-angle 键)+ MMCV 首顶点扇形面积。
415// 1. 质心 (xc,yc);相对质心坐标 (xr,yr)。372// 1. 质心 (xc,yc);相对质心坐标 (xr,yr)。
416-// 2. diamond-angle 键 key = (xr>=0)? t : (2-t),t = yr/(|xr|+|yr|),与 atan2(yr,xr) 单调同序;373+// 2. diamond-angle 键 CUDA atan2(yr,xr) [-pi,pi] 分支切点一致:
417-// Sort32 为降序,故送 -key 得 angle 升序(逆时针)padding 槽(idx>=m) 键置 -INF 沉底。374+// xr>=0 key=txr<0,yr>=0 key=2-t;xr<0,yr<0 时 key=-2-t,
375+// 其中 t=yr/(|xr|+|yr|)。Sort32 为降序,故送 -key 得 angle 升序(逆时针);
376+// padding 槽(idx>=m) 键置 -INF 沉底。
418// 3. Sort32 + Extract 得排序后原始下标序 order[0..m-1](逆时针环序)。377// 3. Sort32 + Extract 得排序后原始下标序 order[0..m-1](逆时针环序)。
419-// 4. 质心分解相邻 (C, v[order[i]], v[order[i+1]]) 三角形叉积绝对值累加。378+// 4. 面积 order[0] 为基准,按 MMCV 顺序累加相邻顶点有符号叉积,末尾一次 abs / 2
420-// 面积对环方向(顺/逆)不敏感(叉积取绝对值),与 atan2 等价379+// 与 atan2 单调同;面积累加的 float32 运算顺序与 MMCV box_overlap 对齐
421// ---------------------------------------------------------------------------380// ---------------------------------------------------------------------------
422 381 
423__aicore__ inline float Iou3D::SortPolygonArea(float px[IOU3D_MAX_INTER], float py[IOU3D_MAX_INTER], uint32_t m)382__aicore__ inline float Iou3D::SortPolygonArea(float px[IOU3D_MAX_INTER], float py[IOU3D_MAX_INTER], uint32_t m)
@@ -447,7 +406,15 @@ __aicore__ inline float Iou3D::SortPolygonArea(float px[IOU3D_MAX_INTER], float
447 float yr = py[i] - yc;406 float yr = py[i] - yc;
448 float s = ScalarAbs(xr) + ScalarAbs(yr);407 float s = ScalarAbs(xr) + ScalarAbs(yr);
449 float t = (s < 1.0e-20f) ? 0.0f : (yr / s);408 float t = (s < 1.0e-20f) ? 0.0f : (yr / s);
450- float keyRaw = (xr >= 0.0f) ? t : (2.0f - t);409+ float keyRaw;
410+ if (xr >= 0.0f) {
411+ keyRaw = t;
412+ } else if (yr >= 0.0f) {
413+ keyRaw = 2.0f - t;
414+ } else {
415+ // 对齐 atan2 的负半轴分支:第三象限必须排在 [-pi,-pi/2),不能循环移到 +pi 之后。
416+ keyRaw = -2.0f - t;
417+ }
451 k = -keyRaw; // Sort32 降序 == angle 升序(逆时针)418 k = -keyRaw; // Sort32 降序 == angle 升序(逆时针)
452 } else {419 } else {
453 k = IOU3D_NEG_INF_KEY; // padding 槽沉底420 k = IOU3D_NEG_INF_KEY; // padding 槽沉底
@@ -471,19 +438,19 @@ __aicore__ inline float Iou3D::SortPolygonArea(float px[IOU3D_MAX_INTER], float
471 order[i] = rawIdx;438 order[i] = rawIdx;
472 }439 }
473 440 
474- // 面积(signed shoelace 收尾)。质心分解累加**有符号**叉积(不 per-triangle 取 abs),441+ // 面积严格对齐 MMCV box_overlap:以排序后第一个顶点为基准,依次累加
475- // 末尾对总和取一次 abs。去重已保证只剩真顶点、Sort32 环序为简单多边形,signed-shoelace442+ // cross(points[k] - points[0], points[k + 1] - points[0]),末尾一次 abs / 2。
476- // per-triangle abs-fan 结果一致(对方向鲁棒);但对「万一残留的近重复点/方向错」多一层符号443+ // 不以质心为基准,避免数学等价但 float32 运算顺不同而产生 1 ULP 偏差。
477- // 自洽保护——错序下正负三角形自然抵消,不会像 per-triangle abs-fan 那样把 bowtie 放大成半面积。
478 // ⚠️ 严禁任何面积层 NaN 守卫;NaN/inf 必须按 IEEE754 自然传播到输出。444 // ⚠️ 严禁任何面积层 NaN 守卫;NaN/inf 必须按 IEEE754 自然传播到输出。
479- float signedTwice = 0.0f; // 2·有符号面积(相对质心的鞋带和)445+ uint32_t base = order[0];
480- for (uint32_t k = 0; k < m; ++k) {446+ float signedTwice = 0.0f;
447+ for (uint32_t k = 0; k + 1U < m; ++k) {
481 uint32_t a = order[k];448 uint32_t a = order[k];
482- uint32_t bnext = order[(k + 1U == m) ? 0U : (k + 1U)];449+ uint32_t bnext = order[k + 1U];
483- float ax = px[a] - xc;450+ float ax = px[a] - px[base];
484- float ay = py[a] - yc;451+ float ay = py[a] - py[base];
485- float bx = px[bnext] - xc;452+ float bx = px[bnext] - px[base];
486- float by = py[bnext] - yc;453+ float by = py[bnext] - py[base];
487 signedTwice += ax * by - ay * bx;454 signedTwice += ax * by - ay * bx;
488 }455 }
489 return ScalarAbs(signedTwice) * 0.5f;456 return ScalarAbs(signedTwice) * 0.5f;
@@ -517,6 +484,21 @@ __aicore__ inline float Iou3D::ComputePairIou(int64_t b, int64_t i, int64_t j, f
517 float z2Max = rect2[2] + 0.5f * rect2[5];484 float z2Max = rect2[2] + 0.5f * rect2[5];
518 float realD = ScalarMax(ScalarMin(z1Max, z2Max) - ScalarMax(z1Min, z2Min), 0.0f);485 float realD = ScalarMax(ScalarMin(z1Max, z2Max) - ScalarMax(z1Min, z2Min), 0.0f);
519 486 
487+ // 对有限输入,Z 轴无交集时 3D 交体积必为 0,与 BEV 形状无关。必须在
488+ // PolygonArea 前短路,否则超大但有限的坐标/尺寸可能先在 fp32 BEV 几何中
489+ // 溢出为 NaN/Inf,随后形成 NaN * 0,导致本应为 0 的 IoU 变成 NaN。
490+ // 仅有限输入允许短路;包含 NaN/Inf 的输入继续走原路径,保持既定传播语义。
491+ if (realD == 0.0f) {
492+ bool allFinite = true;
493+ for (uint32_t c = 0; c < IOU3D_DOF; ++c) {
494+ allFinite = allFinite && (rect1[c] == rect1[c]) && (rect2[c] == rect2[c]) &&
495+ (ScalarAbs(rect1[c]) <= IOU3D_MAX_FINITE) && (ScalarAbs(rect2[c]) <= IOU3D_MAX_FINITE);
496+ }
497+ if (allFinite) {
498+ return 0.0f;
499+ }
500+ }
501+ 
520 float px[IOU3D_MAX_INTER], py[IOU3D_MAX_INTER];502 float px[IOU3D_MAX_INTER], py[IOU3D_MAX_INTER];
521 // 反向旋转包含测试需框中心/半尺寸/sin/cos:halfDx=0.5*w, halfDy=0.5*h。503 // 反向旋转包含测试需框中心/半尺寸/sin/cos:halfDx=0.5*w, halfDy=0.5*h。
522 uint32_t m = CollectCorners(c1x, c1y, c2x, c2y, rect1[0], rect1[1], 0.5f * rect1[3], 0.5f * rect1[4], sin1, cos1,504 uint32_t m = CollectCorners(c1x, c1y, c2x, c2y, rect1[0], rect1[1], 0.5f * rect1[3], 0.5f * rect1[4], sin1, cos1,
@@ -551,7 +533,7 @@ __aicore__ inline void Iou3D::Process()
551 LocalTensor<float> sin2Buf = angle[4U * atl];533 LocalTensor<float> sin2Buf = angle[4U * atl];
552 LocalTensor<float> cos2Buf = angle[5U * atl];534 LocalTensor<float> cos2Buf = angle[5U * atl];
553 LocalTensor<float> outTile = outBuf.Get<float>();535 LocalTensor<float> outTile = outBuf.Get<float>();
554- LocalTensor<uint8_t> sinTmp = tmpBuf.Get<uint8_t>(); // 显式 sharedTmpBuffer(32B 对齐)536+ LocalTensor<uint8_t> sinTmp = tmpBuf.Get<uint8_t>(); // 默认与高精度 Cos 共用显式临时空间
555 537 
556 const int64_t nk = static_cast<int64_t>(numN_) * static_cast<int64_t>(numK_);538 const int64_t nk = static_cast<int64_t>(numN_) * static_cast<int64_t>(numK_);
557 539 
@@ -601,6 +583,37 @@ __aicore__ inline void Iou3D::Process()
601 // Sin/Cos(向量写 UB) → GetValue(标量读 UB) 之间插同步,确保向量结果对标量可见。583 // Sin/Cos(向量写 UB) → GetValue(标量读 UB) 之间插同步,确保向量结果对标量可见。
602 PipeBarrier<PIPE_ALL>();584 PipeBarrier<PIPE_ALL>();
603 585 
586+ // 仅修复 Cos:用 RADIAN_REDUCTION API 生成候选值到 outTile,
587+ // Sin 缓冲始终保留 AscendC Sin 的默认结果。
588+ Cos<float, false, IOU3D_HIGH_PRECISION_COS_CONFIG>(outTile, theta1, sinTmp, alignedCnt);
589+ PipeBarrier<PIPE_ALL>();
590+ for (uint32_t t = 0; t < curNum; ++t) {
591+ float th1 = theta1.GetValue(t);
592+ float absTh1 = ScalarAbs(th1);
593+ if (absTh1 >= IOU3D_COS_FIX_MIN_ABS_ANGLE && absTh1 <= IOU3D_COS_FIX_MAX_ABS_ANGLE) {
594+ float nativeCos1 = cos1Buf.GetValue(t);
595+ float highPrecisionCos1 = outTile.GetValue(t);
596+ if (ScalarAbs(highPrecisionCos1 - nativeCos1) > IOU3D_COS_FIX_MIN_DELTA) {
597+ cos1Buf.SetValue(t, highPrecisionCos1);
598+ }
599+ }
600+ }
601+ PipeBarrier<PIPE_ALL>();
602+ 
603+ Cos<float, false, IOU3D_HIGH_PRECISION_COS_CONFIG>(outTile, theta2, sinTmp, alignedCnt);
604+ PipeBarrier<PIPE_ALL>();
605+ for (uint32_t t = 0; t < curNum; ++t) {
606+ float th2 = theta2.GetValue(t);
607+ float absTh2 = ScalarAbs(th2);
608+ if (absTh2 >= IOU3D_COS_FIX_MIN_ABS_ANGLE && absTh2 <= IOU3D_COS_FIX_MAX_ABS_ANGLE) {
609+ float nativeCos2 = cos2Buf.GetValue(t);
610+ float highPrecisionCos2 = outTile.GetValue(t);
611+ if (ScalarAbs(highPrecisionCos2 - nativeCos2) > IOU3D_COS_FIX_MIN_DELTA) {
612+ cos2Buf.SetValue(t, highPrecisionCos2);
613+ }
614+ }
615+ }
616+ 
604 // 3) 逐对标量几何计算 IoU617 // 3) 逐对标量几何计算 IoU
605 for (uint32_t t = 0; t < curNum; ++t) {618 for (uint32_t t = 0; t < curNum; ++t) {
606 int64_t flat = pairStart_ + processed + static_cast<int64_t>(t);619 int64_t flat = pairStart_ + processed + static_cast<int64_t>(t);
Mobjdetect/iou3d/op_kernel/arch35/iou3d_tiling_data.h+2-0
@@ -20,6 +20,7 @@
20 * - coreNum/pairsPerCore : 多核切分(总 (b,i,j) 对按核均分为不相交子集)20 * - coreNum/pairsPerCore : 多核切分(总 (b,i,j) 对按核均分为不相交子集)
21 * - tileLen/tailLen : 单核内 UB 批处理粒度((i,j) 对数)21 * - tileLen/tailLen : 单核内 UB 批处理粒度((i,j) 对数)
22 * - isEmpty : 空 Tensor 标志(batch==0 || N==0 || K==0),用于 TPL_EMPTY 短路22 * - isEmpty : 空 Tensor 标志(batch==0 || N==0 || K==0),用于 TPL_EMPTY 短路
23+ * - cosTmpSize : RADIAN_REDUCTION Cos 显式 sharedTmpBuffer 字节数
23 *24 *
24 * 注:极角排序(Sort32)临时 buffer 由 kernel 侧按固定 IOU3D_SORT32_LEN(32) 分配,与逻辑规模无关,25 * 注:极角排序(Sort32)临时 buffer 由 kernel 侧按固定 IOU3D_SORT32_LEN(32) 分配,与逻辑规模无关,
25 * 故无需 Host 侧动态精算 sortTmpSize(历史遗留字段已移除)。26 * 故无需 Host 侧动态精算 sortTmpSize(历史遗留字段已移除)。
@@ -39,5 +40,6 @@ struct Iou3DTilingData {
39 uint32_t tileLen = 0; // 单批处理的 (i,j) 对数(UB 批大小)40 uint32_t tileLen = 0; // 单批处理的 (i,j) 对数(UB 批大小)
40 uint32_t tailLen = 0; // 尾批 (i,j) 对数41 uint32_t tailLen = 0; // 尾批 (i,j) 对数
41 uint32_t isEmpty = 0; // 空 Tensor 标志(batch==0 || N==0 || K==0)42 uint32_t isEmpty = 0; // 空 Tensor 标志(batch==0 || N==0 || K==0)
43+ uint32_t cosTmpSize = 0; // 高精度 Cos 临时空间(字节)
42};44};
43#endif // _IOU3D_TILING_DATA_H_45#endif // _IOU3D_TILING_DATA_H_
Mobjdetect/iou3d/tests/ut/op_kernel/test_iou3d.cpp+3-0
@@ -72,6 +72,9 @@ void FillTiling(Iou3DTilingData* t, uint32_t batch, uint32_t numN, uint32_t numK
72 t->pairsPerCore = total;72 t->pairsPerCore = total;
73 t->tileLen = total < 256U ? total : 256U;73 t->tileLen = total < 256U ? total : 256U;
74 t->tailLen = (t->tileLen == 0U) ? 0U : (total % t->tileLen);74 t->tailLen = (t->tileLen == 0U) ? 0U : (total % t->tileLen);
75+ // Cos/Sin sharedTmpBuffer: host uses GetCosMaxMinTmpSize; UT(CPU sim) 用安全上界。
76+ // 8 elem: 768B, 256 elem: 3072B (POLYNOMIAL_APPROXIMATION max); 4096B 覆盖 tileLen≤256。
77+ t->cosTmpSize = 4096U;
75}78}
76} // namespace79} // namespace
77 80