已合并
修复iou3d算子精度问题 #1197
yulianjie创建于 23 天前
修复iou3d算子精度问题 #1197
已合并
共 4 个文件变更+196-155
| @@ -26,6 +26,7 @@ | |||
| 26 | 26 | ||
| 27 | 27 | ||
| 28 | 28 | ||
| 29 | + | ||
| 29 | 30 | ||
| 30 | 31 | ||
| 31 | namespace optiling { | 32 | namespace 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)。 |
| 42 | constexpr uint32_t IOU3D_TILE_LEN = 256U; | 43 | constexpr 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)。 |
| 45 | static ge::graphStatus GetPlatformInfo(gert::TilingContext* context, uint64_t* ubSize, int64_t* coreNum) | 49 | static 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; |
| @@ -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:377) | 28 | * 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 = 0 | 30 | * 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 | ||
| 53 | using namespace AscendC; | 49 | using 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 的退化分支阈值。 |
| 61 | constexpr float IOU3D_EPS_KERNEL = 1e-8f; | 57 | constexpr float IOU3D_EPS_KERNEL = 1e-8f; |
| 58 | +// float32 最大有限值:仅用于区分有限输入与 NaN/Inf,不改变 NaN/Inf 传播语义。 | ||
| 59 | +constexpr float IOU3D_MAX_FINITE = 3.402823466e38f; | ||
| 62 | // 对标 mmcv:顶点包含测试绝对容差。反向旋转到框局部系后判 |rot|<half+MARGIN | 60 | // 对标 mmcv:顶点包含测试绝对容差。反向旋转到框局部系后判 |rot|<half+MARGIN |
| 63 | // (对标 mmcv golden.py:36/194-195 MARGIN=1e-2,严格 <)。 | 61 | // (对标 mmcv golden.py:36/194-195 MARGIN=1e-2,严格 <)。 |
| 64 | constexpr float IOU3D_MARGIN = 1e-2f; | 62 | constexpr 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 对齐。 |
| 73 | constexpr uint32_t IOU3D_ALIGN_ELEM = 8; // fp32 一个 datablock 的元素数(32B / 4B) | 65 | constexpr 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 槽键值(沉底到排序末尾) | ||
| 77 | constexpr uint32_t IOU3D_IDX_MASK = 0x07FFFFFFu; // Sort32 index 位宽 27bit,回读时按位与还原原始下标 | 77 | constexpr 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-120 | 284 | + float s1 = (b1x - a1x) * (a2y - a1y) - (a2x - a1x) * (b1y - a1y); |
| 286 | - // ② 跨立实验(叉积判别),对标 golden.py:143-146 | 285 | + 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_guard | 364 | 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=t;xr<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-shoelace | 442 | + // 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) 逐对标量几何计算 IoU | 617 | // 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); |
| @@ -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 | 45 | ||
| @@ -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 | } // namespace | 79 | } // namespace |
| 77 | 80 | ||