已合并
bounding_box_decode #1307
wuao创建于 11 天前
bounding_box_decode #1307
已合并
共 23 个文件变更+2481-38
| @@ -225,44 +225,6 @@ REG_OP(NonMaxSuppressionV4) | |||
| 225 | .OUTPUT(valid_outputs, TensorType({DT_INT32})) | 225 | .OUTPUT(valid_outputs, TensorType({DT_INT32})) |
| 226 | .ATTR(pad_to_max_output_size, Bool, false) | 226 | .ATTR(pad_to_max_output_size, Bool, false) |
| 227 | .OP_END_FACTORY_REG(NonMaxSuppressionV4) | 227 | .OP_END_FACTORY_REG(NonMaxSuppressionV4) |
| 228 | -/** | ||
| 229 | -*@brief Generates bounding boxes based on "rois" and "deltas". | ||
| 230 | -* It is a customized FasterRcnn operator . \n | ||
| 231 | - | ||
| 232 | -*@par Inputs: | ||
| 233 | -* Two inputs, including: | ||
| 234 | -*@li rois: Region of interests (ROIs) generated by the region proposal | ||
| 235 | -* network (RPN). A 2D Tensor of type float32 or float16 with shape (N, 4). | ||
| 236 | -* "N" indicates the number of ROIs, and the value "4" refers to "x0", "x1", | ||
| 237 | -* "y0", and "y1". | ||
| 238 | -*@li deltas: Absolute variation between the ROIs generated by the RPN and | ||
| 239 | -* ground truth boxes. A 2D Tensor of type float32 or float16 with shape (N, 4). | ||
| 240 | -* "N" indicates the number of errors, and 4 indicates "dx", "dy", "dw", and "dh" . \n | ||
| 241 | - | ||
| 242 | -*@par Attributes: | ||
| 243 | -*@li means: An index of type float32. Defaults to [0.0, 0.0, 0.0, 0.0]. | ||
| 244 | -* "deltas" = "deltas" x "stds" + "means". | ||
| 245 | -*@li stds: An index of type float32. Defaults to [1.0, 1.0, 1.0, 1.0]. | ||
| 246 | -* "deltas" = "deltas" x "stds" + "means". | ||
| 247 | -*@li max_shape: Shape [h, w], specifying the size of the image transferred to | ||
| 248 | -* the network. Used to ensure that the bbox shape after conversion does not | ||
| 249 | -* exceed "max_shape". | ||
| 250 | -*@li wh_ratio_clip: Defaults to "16/1000". The values of "dw" and "dh" fall | ||
| 251 | -* within (-wh_ratio_clip, wh_ratio_clip) . \n | ||
| 252 | - | ||
| 253 | -*@par Outputs: | ||
| 254 | -*bboxes: Bboxes generated based on "rois" and "deltas". Have the same format | ||
| 255 | -* and type as "rois". | ||
| 256 | -*/ | ||
| 257 | -REG_OP(BoundingBoxDecode) | ||
| 258 | - .INPUT(rois, TensorType({DT_FLOAT16, DT_FLOAT})) | ||
| 259 | - .INPUT(deltas, TensorType({DT_FLOAT16, DT_FLOAT})) | ||
| 260 | - .OUTPUT(bboxes, TensorType({DT_FLOAT16, DT_FLOAT})) | ||
| 261 | - .ATTR(means, ListFloat, {0.0, 0.0, 0.0, 0.0}) | ||
| 262 | - .ATTR(stds, ListFloat, {1.0, 1.0, 1.0, 1.0}) | ||
| 263 | - .REQUIRED_ATTR(max_shape, ListInt) | ||
| 264 | - .ATTR(wh_ratio_clip, Float, 0.016f) | ||
| 265 | - .OP_END_FACTORY_REG(BoundingBoxDecode) | ||
| 266 | 228 | ||
| 267 | /** | 229 | /** |
| 268 | *@brief Judges whether the bounding box is valid. It is a customized | 230 | *@brief Judges whether the bounding box is valid. It is a customized |
| @@ -576,6 +576,16 @@ | |||
| 576 | <td>AI Core</td> | 576 | <td>AI Core</td> |
| 577 | <td>计算锚框与真实边界框之间的编码偏移量,生成目标检测回归目标。</td> | 577 | <td>计算锚框与真实边界框之间的编码偏移量,生成目标检测回归目标。</td> |
| 578 | </tr> | 578 | </tr> |
| 579 | + <tr> | ||
| 580 | + <td>objdetect</td> | ||
| 581 | + <td><a href="../../objdetect/bounding_box_decode/README.md">bounding_box_decode</a></td> | ||
| 582 | + <td>✓</td> | ||
| 583 | + <td>✓</td> | ||
| 584 | + <td>✓</td> | ||
| 585 | + <td>✓</td> | ||
| 586 | + <td>AI Core</td> | ||
| 587 | + <td>将模型输出的相对于先验框(或锚点)的偏移量与缩放参数,转换为原始图像中真实的绝对边界框坐标。</td> | ||
| 588 | + </tr> | ||
| 579 | <tr> | 589 | <tr> |
| 580 | <td>objdetect</td> | 590 | <td>objdetect</td> |
| 581 | <td><a href="../../objdetect/batch_multi_class_non_max_suppression/README.md">batch_multi_class_non_max_suppression</a></td> | 591 | <td><a href="../../objdetect/batch_multi_class_non_max_suppression/README.md">batch_multi_class_non_max_suppression</a></td> |
| @@ -0,0 +1,27 @@ | |||
| 1 | +# ----------------------------------------------------------------------------------------------------------- | ||
| 2 | +# Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | +# CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | +# Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | +# See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | +# ----------------------------------------------------------------------------------------------------------- | ||
| 10 | + | ||
| 11 | +file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 12 | + | ||
| 13 | +if(NOT ENABLE_TEST AND NOT BENCHMARK) | ||
| 14 | + list(REMOVE_ITEM CURRENT_DIRS tests) | ||
| 15 | +endif() | ||
| 16 | + | ||
| 17 | +foreach(SUB_DIR ${CURRENT_DIRS}) | ||
| 18 | + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}/CMakeLists.txt") | ||
| 19 | + add_subdirectory(${SUB_DIR}) | ||
| 20 | + endif() | ||
| 21 | +endforeach() | ||
| 22 | + | ||
| 23 | +set(SUPPORT_COMPUTE_UNIT "ascend950") | ||
| 24 | +set(SUPPORT_TILING_DIR "arch35") | ||
| 25 | +add_all_modules_sources(OPTYPE bounding_box_decode ACLNNTYPE aclnn_exclude | ||
| 26 | + COMPUTE_UNIT ${SUPPORT_COMPUTE_UNIT} | ||
| 27 | + TILING_DIR ${SUPPORT_TILING_DIR}) | ||
| @@ -0,0 +1,141 @@ | |||
| 1 | +# BoundingBoxDecode | ||
C | |||
| 2 | + | ||
| 3 | +## 产品支持情况 | ||
| 4 | + | ||
| 5 | +| 产品 | 是否支持 | | ||
| 6 | +| :--- | :---: | | ||
| 7 | +| <term>Ascend 950PR/Ascend 950DT</term> | √ | | ||
| 8 | +| <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term> | × | | ||
| 9 | +| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | × | | ||
| 10 | +| <term>Atlas 200I/500 A2 推理产品</term> | × | | ||
| 11 | +| <term>Atlas 推理系列产品</term> | × | | ||
| 12 | +| <term>Atlas 训练系列产品</term> | × | | ||
| 13 | + | ||
| 14 | +## 功能说明 | ||
| 15 | + | ||
| 16 | +将目标检测回归分支预测的偏移量`deltas`结合锚框`anchor_box`解码为图像坐标空间的绝对框`boxes`,用于后续NMS、画框或COCO mAP评估。该算子是`bounding_box_encode`的逆运算,两者共享同一套`(means, stds)`标准化参数与`(x1, y1, x2, y2)`锚框坐标约定,配套使用才能保证训练与推理编码一致。 | ||
| 17 | + | ||
| 18 | +设锚框`anchor_box=(x1, y1, x2, y2)`、偏移量`deltas=(dx', dy', dw', dh')`、`means=(m0,m1,m2,m3)`、`stds=(s0,s1,s2,s3)`、`max_shape=(H, W)`,解码步骤为: | ||
| 19 | + | ||
| 20 | +$$ | ||
| 21 | +pw = x2 - x1 + 1,\quad pcx = (x1 + x2) \times 0.5 | ||
| 22 | +$$ | ||
| 23 | + | ||
| 24 | +$$ | ||
| 25 | +dx = dx' \times s0 + m0,\quad dw = dw' \times s2 + m2 | ||
| 26 | +$$ | ||
| 27 | + | ||
| 28 | +$$ | ||
| 29 | +gw = pw \times \exp(dw),\quad gx = pcx + pw \times dx | ||
| 30 | +$$ | ||
| 31 | + | ||
| 32 | +$$ | ||
| 33 | +x1_{out} = \mathrm{clip}(gx - gw \times 0.5 + 0.5,\ 0,\ W) | ||
| 34 | +$$ | ||
| 35 | + | ||
| 36 | +y维度(y1、y2)同理,裁剪上界为H。fp16输入时中间`exp`及乘加计算在fp32域进行后回cast到fp16。 | ||
| 37 | + | ||
| 38 | +## 参数说明 | ||
| 39 | + | ||
| 40 | +<table style="table-layout: fixed; width: 1576px"> | ||
| 41 | +<colgroup> | ||
| 42 | +<col style="width: 170px"> | ||
| 43 | +<col style="width: 170px"> | ||
| 44 | +<col style="width: 200px"> | ||
| 45 | +<col style="width: 200px"> | ||
| 46 | +<col style="width: 170px"> | ||
| 47 | +</colgroup> | ||
| 48 | +<thead> | ||
| 49 | +<tr> | ||
| 50 | +<th>参数名</th> | ||
| 51 | +<th>输入/输出/属性</th> | ||
| 52 | +<th>描述</th> | ||
| 53 | +<th>数据类型</th> | ||
| 54 | +<th>数据格式</th> | ||
| 55 | +</tr> | ||
| 56 | +</thead> | ||
| 57 | +<tbody> | ||
| 58 | +<tr> | ||
| 59 | +<td>anchor_box</td> | ||
| 60 | +<td>输入</td> | ||
| 61 | +<td>锚框坐标(x1,y1,x2,y2),对应公式中anchor_box。</td> | ||
| 62 | +<td>FLOAT16、FLOAT</td> | ||
| 63 | +<td>ND</td> | ||
| 64 | +</tr> | ||
| 65 | +<tr> | ||
| 66 | +<td>deltas</td> | ||
| 67 | +<td>输入</td> | ||
| 68 | +<td>回归偏移量(dx',dy',dw',dh'),对应公式中deltas。</td> | ||
| 69 | +<td>FLOAT16、FLOAT</td> | ||
| 70 | +<td>ND</td> | ||
| 71 | +</tr> | ||
| 72 | +<tr> | ||
| 73 | +<td>boxes</td> | ||
| 74 | +<td>输出</td> | ||
| 75 | +<td>解码后的绝对框(x1,y1,x2,y2),对应公式中boxes。</td> | ||
| 76 | +<td>FLOAT16、FLOAT</td> | ||
| 77 | +<td>ND</td> | ||
| 78 | +</tr> | ||
| 79 | +<tr> | ||
| 80 | +<td>means</td> | ||
| 81 | +<td>可选属性</td> | ||
| 82 | +<td>deltas反标准化均值,长度4,默认[0.0, 0.0, 0.0, 0.0]。</td> | ||
| 83 | +<td>FLOAT</td> | ||
| 84 | +<td>-</td> | ||
| 85 | +</tr> | ||
| 86 | +<tr> | ||
| 87 | +<td>stds</td> | ||
| 88 | +<td>可选属性</td> | ||
| 89 | +<td>deltas反标准化标准差,长度4且各元素非0,默认[1.0, 1.0, 1.0, 1.0]。</td> | ||
| 90 | +<td>FLOAT</td> | ||
| 91 | +<td>-</td> | ||
| 92 | +</tr> | ||
| 93 | +<tr> | ||
| 94 | +<td>max_shape</td> | ||
| 95 | +<td>属性</td> | ||
| 96 | +<td>解码框裁剪上限(H, W),长度2。</td> | ||
| 97 | +<td>INT64</td> | ||
| 98 | +<td>-</td> | ||
| 99 | +</tr> | ||
| 100 | +<tr> | ||
| 101 | +<td>wh_ratio_clip</td> | ||
| 102 | +<td>可选属性</td> | ||
| 103 | +<td>宽高比裁剪阈值,默认0.016。</td> | ||
| 104 | +<td>FLOAT</td> | ||
| 105 | +<td>-</td> | ||
| 106 | +</tr> | ||
| 107 | +</tbody> | ||
| 108 | +</table> | ||
| 109 | + | ||
| 110 | +## 约束说明 | ||
| 111 | + | ||
| 112 | +- anchor_box与deltas的shape必须完全一致(N, 4),无广播。 | ||
| 113 | +- anchor_box与deltas的dtype必须一致。 | ||
| 114 | +- means与stds长度必须为4,stds各元素不能为0。 | ||
| 115 | +- max_shape长度必须为2。 | ||
| 116 | +- wh_ratio_clip必须大于0,当前不参与核心解码公式,仅做入参校验。 | ||
| 117 | +- 输入仅支持ND数据格式。 | ||
| 118 | + | ||
| 119 | +## 调用说明 | ||
| 120 | + | ||
| 121 | +<table style="table-layout: fixed; width: 1000px"> | ||
| 122 | +<colgroup> | ||
| 123 | +<col style="width: 180px"> | ||
| 124 | +<col style="width: 200px"> | ||
| 125 | +<col style="width: 620px"> | ||
| 126 | +</colgroup> | ||
| 127 | +<thead> | ||
| 128 | +<tr> | ||
| 129 | +<th>调用方式</th> | ||
| 130 | +<th>样例代码</th> | ||
| 131 | +<th>说明</th> | ||
| 132 | +</tr> | ||
| 133 | +</thead> | ||
| 134 | +<tbody> | ||
| 135 | +<tr> | ||
| 136 | +<td>GE图模式</td> | ||
| 137 | +<td>-</td> | ||
| 138 | +<td><a href="examples/arch35/test_geir_bounding_box_decode.cpp">test_geir_bounding_box_decode.cpp</a></td> | ||
| 139 | +</tr> | ||
| 140 | +</tbody> | ||
| 141 | +</table> | ||
| @@ -0,0 +1,269 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | +using namespace ge; | ||
| 34 | +using std::map; | ||
| 35 | +using std::string; | ||
| 36 | +using std::vector; | ||
| 37 | + | ||
| 38 | + | ||
| 39 | + vector<int64_t> placeholder##intputIndex##_shape = inputShape; \ | ||
| 40 | + auto placeholder##intputIndex = op::Data("placeholder" + intputIndex).set_attr_index(0); \ | ||
| 41 | + TensorDesc placeholder##intputIndex##_desc = TensorDesc(ge::Shape(placeholder##intputIndex##_shape), FORMAT_ND, \ | ||
| 42 | + intputDtype); \ | ||
| 43 | + placeholder##intputIndex##_desc.SetPlacement(ge::kPlacementHost); \ | ||
| 44 | + placeholder##intputIndex##_desc.SetFormat(FORMAT_ND); \ | ||
| 45 | + Tensor tensor_placeholder##intputIndex; \ | ||
| 46 | + ret = GenOnesData(placeholder##intputIndex##_shape, tensor_placeholder##intputIndex, \ | ||
| 47 | + placeholder##intputIndex##_desc, intputDtype, 2); \ | ||
| 48 | + if (ret != SUCCESS) { \ | ||
| 49 | + printf("%s - ERROR - [XIR]: Generate input data failed\n", GetTime().c_str()); \ | ||
| 50 | + return FAILED; \ | ||
| 51 | + } \ | ||
| 52 | + placeholder##intputIndex.update_input_desc_x(placeholder##intputIndex##_desc); \ | ||
| 53 | + input.push_back(tensor_placeholder##intputIndex); \ | ||
| 54 | + graph.AddOp(placeholder##intputIndex); \ | ||
| 55 | + add1.set_input_##intputName(placeholder##intputIndex); \ | ||
| 56 | + inputs.push_back(placeholder##intputIndex); | ||
| 57 | + | ||
| 58 | + | ||
| 59 | + TensorDesc outputName##outputIndex##_desc = TensorDesc(ge::Shape(outputShape), FORMAT_ND, outputDtype); \ | ||
| 60 | + add1.update_output_desc_##outputName(outputName##outputIndex##_desc); | ||
| 61 | + | ||
| 62 | +string GetTime() | ||
| 63 | +{ | ||
| 64 | + time_t timep; | ||
| 65 | + time(&timep); | ||
| 66 | + char tmp[64]; | ||
| 67 | + strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S,000", localtime(&timep)); | ||
| 68 | + return string(tmp); | ||
| 69 | +} | ||
| 70 | + | ||
| 71 | +uint32_t GetDataTypeSize(DataType dt) | ||
| 72 | +{ | ||
| 73 | + uint32_t oneByte = 1; | ||
| 74 | + uint32_t twoByte = 2; | ||
| 75 | + uint32_t fourByte = 4; | ||
| 76 | + uint32_t eightByte = 8; | ||
| 77 | + | ||
| 78 | + if (dt == ge::DT_FLOAT) { | ||
| 79 | + return fourByte; | ||
| 80 | + } else if (dt == ge::DT_FLOAT16) { | ||
| 81 | + return twoByte; | ||
| 82 | + } else if (dt == ge::DT_INT16) { | ||
| 83 | + return twoByte; | ||
| 84 | + } else if (dt == ge::DT_UINT16) { | ||
| 85 | + return twoByte; | ||
| 86 | + } else if (dt == ge::DT_INT32) { | ||
| 87 | + return fourByte; | ||
| 88 | + } else if (dt == ge::DT_UINT32) { | ||
| 89 | + return fourByte; | ||
| 90 | + } else if (dt == ge::DT_INT64) { | ||
| 91 | + return eightByte; | ||
| 92 | + } else if (dt == ge::DT_UINT64) { | ||
| 93 | + return eightByte; | ||
| 94 | + } else if (dt == ge::DT_INT8) { | ||
| 95 | + return oneByte; | ||
| 96 | + } | ||
| 97 | + return fourByte; | ||
| 98 | +} | ||
| 99 | + | ||
| 100 | +int32_t GenOnesData(vector<int64_t> shapes, Tensor& input_tensor, TensorDesc& input_tensor_desc, DataType data_type, | ||
| 101 | + int value) | ||
| 102 | +{ | ||
| 103 | + input_tensor_desc.SetRealDimCnt(shapes.size()); | ||
| 104 | + size_t size = 1; | ||
| 105 | + for (uint32_t i = 0; i < shapes.size(); i++) { | ||
| 106 | + size *= shapes[i]; | ||
| 107 | + } | ||
| 108 | + uint32_t data_len = size * GetDataTypeSize(data_type); | ||
| 109 | + int32_t* pData = new (std::nothrow) int32_t[data_len]; | ||
| 110 | + if (pData == nullptr) { | ||
| 111 | + return FAILED; | ||
| 112 | + } | ||
| 113 | + for (size_t i = 0; i < size; ++i) { | ||
| 114 | + *(pData + i) = value; | ||
| 115 | + } | ||
| 116 | + input_tensor = Tensor(input_tensor_desc, reinterpret_cast<uint8_t*>(pData), data_len); | ||
| 117 | + delete[] pData; | ||
| 118 | + return SUCCESS; | ||
| 119 | +} | ||
| 120 | + | ||
| 121 | +int32_t WriteDataToFile(string bin_file, uint64_t data_size, uint8_t* inputData) | ||
| 122 | +{ | ||
| 123 | + FILE* fp = fopen(bin_file.c_str(), "wb"); | ||
| 124 | + if (fp == nullptr) { | ||
| 125 | + return FAILED; | ||
| 126 | + } | ||
| 127 | + size_t written = fwrite(inputData, sizeof(uint8_t), data_size, fp); | ||
| 128 | + fclose(fp); | ||
| 129 | + if (written != data_size) { | ||
| 130 | + return FAILED; | ||
| 131 | + } | ||
| 132 | + return SUCCESS; | ||
| 133 | +} | ||
| 134 | + | ||
| 135 | +int CreateOppInGraph(DataType inDtype, std::vector<ge::Tensor>& input, std::vector<Operator>& inputs, | ||
| 136 | + std::vector<Operator>& outputs, Graph& graph) | ||
| 137 | +{ | ||
| 138 | + Status ret = SUCCESS; | ||
| 139 | + | ||
| 140 | + auto add1 = op::BoundingBoxDecode("bounding_box_decode_1"); | ||
| 141 | + | ||
| 142 | + std::vector<int64_t> boxShape = {2, 4}; | ||
| 143 | + ADD_INPUT(1, rois, inDtype, boxShape); | ||
| 144 | + | ||
| 145 | + ADD_INPUT(2, deltas, inDtype, boxShape); | ||
| 146 | + | ||
| 147 | + std::vector<float> meansVec = {0.0f, 0.0f, 0.0f, 0.0f}; | ||
| 148 | + add1.SetAttr("means", meansVec); | ||
| 149 | + | ||
| 150 | + std::vector<float> stdsVec = {1.0f, 1.0f, 1.0f, 1.0f}; | ||
| 151 | + add1.SetAttr("stds", stdsVec); | ||
| 152 | + | ||
| 153 | + std::vector<int64_t> maxShapeVec = {768, 1280}; | ||
| 154 | + add1.SetAttr("max_shape", maxShapeVec); | ||
| 155 | + | ||
| 156 | + add1.SetAttr("wh_ratio_clip", 0.016f); | ||
| 157 | + | ||
| 158 | + ADD_OUTPUT(1, bboxes, inDtype, boxShape); | ||
| 159 | + | ||
| 160 | + outputs.push_back(add1); | ||
| 161 | + | ||
| 162 | + return SUCCESS; | ||
| 163 | +} | ||
| 164 | + | ||
| 165 | +int main(int argc, char* argv[]) | ||
| 166 | +{ | ||
| 167 | + const char* graph_name = "tc_ge_irrun_test"; | ||
| 168 | + Graph graph(graph_name); | ||
| 169 | + std::vector<ge::Tensor> input; | ||
| 170 | + | ||
| 171 | + printf("%s - INFO - [XIR]: Start to initialize ge using ge global options\n", GetTime().c_str()); | ||
| 172 | + std::map<AscendString, AscendString> global_options = {{"ge.exec.deviceId", "0"}, {"ge.graphRunMode", "1"}}; | ||
| 173 | + Status ret = ge::GEInitialize(global_options); | ||
| 174 | + if (ret != SUCCESS) { | ||
| 175 | + printf("%s - INFO - [XIR]: Initialize ge using ge global options failed\n", GetTime().c_str()); | ||
| 176 | + return FAILED; | ||
| 177 | + } | ||
| 178 | + printf("%s - INFO - [XIR]: Initialize ge using ge global options success\n", GetTime().c_str()); | ||
| 179 | + | ||
| 180 | + std::vector<Operator> inputs{}; | ||
| 181 | + std::vector<Operator> outputs{}; | ||
| 182 | + | ||
| 183 | + if (argc > 1) { | ||
| 184 | + std::cout << argv[1] << std::endl; | ||
| 185 | + } | ||
| 186 | + | ||
| 187 | + DataType inDtype = DT_FLOAT; | ||
| 188 | + | ||
| 189 | + std::cout << "Input dtype: " << inDtype << std::endl; | ||
| 190 | + | ||
| 191 | + ret = CreateOppInGraph(inDtype, input, inputs, outputs, graph); | ||
| 192 | + if (ret != SUCCESS) { | ||
| 193 | + printf("%s - ERROR - [XIR]: Create ir session using build options failed\n", GetTime().c_str()); | ||
| 194 | + return FAILED; | ||
| 195 | + } | ||
| 196 | + | ||
| 197 | + if (!inputs.empty() && !outputs.empty()) { | ||
| 198 | + graph.SetInputs(inputs).SetOutputs(outputs); | ||
| 199 | + } | ||
| 200 | + | ||
| 201 | + std::map<AscendString, AscendString> build_options = {}; | ||
| 202 | + printf("%s - INFO - [XIR]: Start to create ir session using build options\n", GetTime().c_str()); | ||
| 203 | + ge::Session* session = new Session(build_options); | ||
| 204 | + | ||
| 205 | + if (session == nullptr) { | ||
| 206 | + printf("%s - ERROR - [XIR]: Create ir session using build options failed\n", GetTime().c_str()); | ||
| 207 | + return FAILED; | ||
| 208 | + } | ||
| 209 | + printf("%s - INFO - [XIR]: Create ir session using build options success\n", GetTime().c_str()); | ||
| 210 | + printf("%s - INFO - [XIR]: Start to add compute graph to ir session\n", GetTime().c_str()); | ||
| 211 | + | ||
| 212 | + std::map<AscendString, AscendString> graph_options = {}; | ||
| 213 | + uint32_t graph_id = 0; | ||
| 214 | + ret = session->AddGraph(graph_id, graph, graph_options); | ||
| 215 | + | ||
| 216 | + printf("%s - INFO - [XIR]: Session add ir compute graph to ir session success\n", GetTime().c_str()); | ||
| 217 | + printf("%s - INFO - [XIR]: dump graph to txt\n", GetTime().c_str()); | ||
| 218 | + std::string file_path = "./dump"; | ||
| 219 | + aclgrphDumpGraph(graph, file_path.c_str(), file_path.length()); | ||
| 220 | + printf("%s - INFO - [XIR]: Start to run ir compute graph\n", GetTime().c_str()); | ||
| 221 | + std::vector<ge::Tensor> output; | ||
| 222 | + ret = session->RunGraph(graph_id, input, output); | ||
| 223 | + if (ret != SUCCESS) { | ||
| 224 | + printf("%s - INFO - [XIR]: Run graph failed\n", GetTime().c_str()); | ||
| 225 | + delete session; | ||
| 226 | + GEFinalize(); | ||
| 227 | + return FAILED; | ||
| 228 | + } | ||
| 229 | + printf("%s - INFO - [XIR]: Session run ir compute graph success\n", GetTime().c_str()); | ||
| 230 | + | ||
| 231 | + int input_num = input.size(); | ||
| 232 | + for (int i = 0; i < input_num; i++) { | ||
| 233 | + std::cout << "input " << i << " dtype : " << input[i].GetTensorDesc().GetDataType() << std::endl; | ||
| 234 | + string input_file = "./tc_ge_irrun_test_npu_input_" + std::to_string(i) + ".bin"; | ||
| 235 | + uint8_t* input_data_i = input[i].GetData(); | ||
| 236 | + int64_t input_shape = input[i].GetTensorDesc().GetShape().GetShapeSize(); | ||
| 237 | + std::cout << "this is " << i << "th input, input shape size =" << input_shape << std::endl; | ||
| 238 | + uint32_t data_size = input_shape * GetDataTypeSize(input[i].GetTensorDesc().GetDataType()); | ||
| 239 | + WriteDataToFile((const char*)input_file.c_str(), data_size, input_data_i); | ||
| 240 | + } | ||
| 241 | + | ||
| 242 | + int output_num = output.size(); | ||
| 243 | + for (int i = 0; i < output_num; i++) { | ||
| 244 | + std::cout << "output " << i << " dtype : " << output[i].GetTensorDesc().GetDataType() << std::endl; | ||
| 245 | + string output_file = "./tc_ge_irrun_test_npu_output_" + std::to_string(i) + ".bin"; | ||
| 246 | + uint8_t* output_data_i = output[i].GetData(); | ||
| 247 | + int64_t output_shape = output[i].GetTensorDesc().GetShape().GetShapeSize(); | ||
| 248 | + std::cout << "this is " << i << "th output, output shape size =" << output_shape << std::endl; | ||
| 249 | + uint32_t data_size = output_shape * GetDataTypeSize(output[i].GetTensorDesc().GetDataType()); | ||
| 250 | + WriteDataToFile((const char*)output_file.c_str(), data_size, output_data_i); | ||
| 251 | + } | ||
| 252 | + | ||
| 253 | + ge::AscendString error_msg = ge::GEGetErrorMsgV2(); | ||
| 254 | + std::string error_str(error_msg.GetString()); | ||
| 255 | + std::cout << "Error message: " << error_str << std::endl; | ||
| 256 | + ge::AscendString warning_msg = ge::GEGetWarningMsgV2(); | ||
| 257 | + std::string warning_str(warning_msg.GetString()); | ||
| 258 | + std::cout << "Warning message: " << warning_str << std::endl; | ||
| 259 | + printf("%s - INFO - [XIR]: Precision is ok\n", GetTime().c_str()); | ||
| 260 | + printf("%s - INFO - [XIR]: Start to finalize ir graph session\n", GetTime().c_str()); | ||
| 261 | + delete session; | ||
| 262 | + ret = ge::GEFinalize(); | ||
| 263 | + if (ret != SUCCESS) { | ||
| 264 | + printf("%s - INFO - [XIR]: Finalize ir graph session failed\n", GetTime().c_str()); | ||
| 265 | + return FAILED; | ||
| 266 | + } | ||
| 267 | + printf("%s - INFO - [XIR]: Finalize ir graph session success\n", GetTime().c_str()); | ||
| 268 | + return SUCCESS; | ||
| 269 | +} | ||
| @@ -0,0 +1,46 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | +using namespace ge; | ||
| 14 | + | ||
| 15 | +namespace ops { | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * InferDataTypeForBoundingBoxDecode: GE data-type inference callback. | ||
| 19 | + * | ||
| 20 | + * boxes.dtype = anchor_box.dtype (same_as_first_input). Validates that both | ||
| 21 | + * inputs have the same dtype (DESIGN §3.2, no type promotion). | ||
| 22 | + */ | ||
| 23 | +static ge::graphStatus InferDataTypeForBoundingBoxDecode(gert::InferDataTypeContext* context) | ||
| 24 | +{ | ||
| 25 | + const ge::DataType anchorDtype = context->GetInputDataType(0); | ||
| 26 | + const ge::DataType deltasDtype = context->GetInputDataType(1); | ||
| 27 | + | ||
| 28 | + if (anchorDtype != deltasDtype) { | ||
| 29 | + return ge::GRAPH_FAILED; | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + context->SetOutputDataType(0, anchorDtype); | ||
| 33 | + return ge::GRAPH_SUCCESS; | ||
| 34 | +} | ||
| 35 | + | ||
| 36 | +/** | ||
| 37 | + * IMPL_OP(BoundingBoxDecode).InferDataType(...): registers the dtype inference | ||
| 38 | + * function for the operator named "BoundingBoxDecode" at static init time. | ||
| 39 | + * When GE encounters a BoundingBoxDecode node during graph compilation, it | ||
| 40 | + * calls InferDataTypeForBoundingBoxDecode to determine the output type. | ||
| 41 | + * This static registration is required by the GE runtime to locate the op | ||
| 42 | + * implementation via the op_impl_registry. | ||
| 43 | + */ | ||
| 44 | +IMPL_OP(BoundingBoxDecode).InferDataType(InferDataTypeForBoundingBoxDecode); | ||
| 45 | + | ||
| 46 | +} // namespace ops | ||
| @@ -0,0 +1,64 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/*! | ||
| 12 | + * \file bounding_box_decode_proto.h | ||
| 13 | + * \brief decode the offset between anchor boxes and ground truth boxes. | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +namespace ge { | ||
| 22 | +/** | ||
| 23 | +*@brief Generates bounding boxes based on "rois" and "deltas". | ||
| 24 | +* It is a customized FasterRcnn operator . \n | ||
| 25 | + | ||
| 26 | +*@par Inputs: | ||
| 27 | +* Two inputs, including: | ||
| 28 | +*@li rois: Region of interests (ROIs) generated by the region proposal | ||
| 29 | +* network (RPN). A 2D Tensor of type float32 or float16 with shape (N, 4). | ||
| 30 | +* "N" indicates the number of ROIs, and the value "4" refers to "x0", "x1", | ||
| 31 | +* "y0", and "y1". | ||
| 32 | +*@li deltas: Absolute variation between the ROIs generated by the RPN and | ||
| 33 | +* ground truth boxes. A 2D Tensor of type float32 or float16 with shape (N, 4). | ||
| 34 | +* "N" indicates the number of errors, and 4 indicates "dx", "dy", "dw", and "dh" . \n | ||
| 35 | + | ||
| 36 | +*@par Attributes: | ||
| 37 | +*@li means: An index of type float32. Defaults to [0.0, 0.0, 0.0, 0.0]. | ||
| 38 | +* "deltas" = "deltas" x "stds" + "means". | ||
| 39 | +*@li stds: An index of type float32. Defaults to [1.0, 1.0, 1.0, 1.0]. | ||
| 40 | +* "deltas" = "deltas" x "stds" + "means". | ||
| 41 | +*@li max_shape: Shape [h, w], specifying the size of the image transferred to | ||
| 42 | +* the network. Used to ensure that the bbox shape after conversion does not | ||
| 43 | +* exceed "max_shape". | ||
| 44 | +*@li wh_ratio_clip: Defaults to "16/1000". The values of "dw" and "dh" fall | ||
| 45 | +* within (-wh_ratio_clip, wh_ratio_clip) . \n | ||
| 46 | + | ||
| 47 | +*@par Outputs: | ||
| 48 | +*bboxes: Bboxes generated based on "rois" and "deltas". Have the same format | ||
| 49 | +* and type as "rois". | ||
| 50 | +*/ | ||
| 51 | + | ||
| 52 | +REG_OP(BoundingBoxDecode) | ||
W 添加去重宏 ![]() ![]() | |||
| 53 | + .INPUT(rois, TensorType({DT_FLOAT16, DT_FLOAT})) | ||
| 54 | + .INPUT(deltas, TensorType({DT_FLOAT16, DT_FLOAT})) | ||
| 55 | + .OUTPUT(bboxes, TensorType({DT_FLOAT16, DT_FLOAT})) | ||
| 56 | + .ATTR(means, ListFloat, {0.0, 0.0, 0.0, 0.0}) | ||
| 57 | + .ATTR(stds, ListFloat, {1.0, 1.0, 1.0, 1.0}) | ||
| 58 | + .REQUIRED_ATTR(max_shape, ListInt) | ||
| 59 | + .ATTR(wh_ratio_clip, Float, 0.016f) | ||
| 60 | + .OP_END_FACTORY_REG(BoundingBoxDecode) | ||
| 61 | + | ||
| 62 | +} // namespace ge | ||
| 63 | + | ||
| 64 | + | ||
The file is empty
| @@ -0,0 +1,342 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | +// BoundingBoxDecodeTilingData struct (§7, 13 fields) — shared host/kernel. | ||
| 16 | + | ||
| 17 | +// gert::TilingContext — GetInputShape / GetInputDesc / GetAttrs / GetTilingData / | ||
| 18 | +// SetBlockDim / SetTilingKey / GetWorkspaceSizes / GetPlatformInfo. | ||
| 19 | + | ||
| 20 | +// gert::Tensor — GetDataType / GetStorageFormat (input tensor metadata). | ||
| 21 | + | ||
| 22 | +// ge::DataType / ge::Format — DT_FLOAT16, DT_FLOAT, FORMAT_ND, etc. | ||
| 23 | + | ||
| 24 | +// platform_ascendc::PlatformAscendC — GetCoreNumAiv / GetCoreMemSize(UB). | ||
| 25 | + | ||
| 26 | +// op_def_registry.h — IMPL_OP_OPTILING macro for tiling registration. | ||
| 27 | + | ||
| 28 | +// Own header — declares optiling::TilingFunc. | ||
| 29 | + | ||
| 30 | + | ||
| 31 | +namespace optiling { | ||
| 32 | + | ||
| 33 | +// ========================================================================= | ||
| 34 | +// Constants (DESIGN §9.3 / §9.4 / §9.5 / §9.7 / §6) | ||
| 35 | +// ========================================================================= | ||
| 36 | + | ||
| 37 | +// §6 TilingKey values — TPL key = T_value (datatype only, no BOOL param) | ||
| 38 | +// kIsEmpty TPL parameter removed (Task 41 fix): the BOOL TPL parameter | ||
| 39 | +// caused the framework's NnopbaseExecutorDoTiling to fail allocating the | ||
| 40 | +// tiling data buffer in aclnn e2e mode (chicken-and-egg: tilingKey encodes | ||
| 41 | +// the BOOL value but is set by TilingFunc, which needs the buffer first). | ||
| 42 | +// Now the kernel handles empty tensors via runtime check (td.dim0 == 0). | ||
| 43 | +// (T=FP32=0) → 0 (fp32, handles both normal and empty) | ||
| 44 | +// (T=FP16=1) → 1 (fp16, handles both normal and empty) | ||
| 45 | +constexpr uint64_t BOUNDING_BOX_DECODE_FP32 = 0; | ||
| 46 | +constexpr uint64_t BOUNDING_BOX_DECODE_FP16 = 1; | ||
| 47 | + | ||
| 48 | +// §9.3 validation constants | ||
| 49 | +constexpr int64_t MAX_RANK = 2; // spec.yaml rank_range:[2,2], fixed rank=2 | ||
| 50 | +constexpr int64_t ELEMS_PER_BOX = 4; // C=4 fixed (kElemsPerBox) | ||
| 51 | + | ||
| 52 | +// §9.5 multi-core split constants | ||
| 53 | +constexpr int64_t MIN_TILING_BITS = 32768; // 4 KB, unit: bits | ||
| 54 | +constexpr int64_t ELEM_ALIGN_FACTOR = 512; // multi-core box alignment factor | ||
| 55 | + | ||
| 56 | +// §9.4 UB split constants | ||
| 57 | +constexpr int64_t ALIGN_256 = 256; // UB alignment, unit: bytes | ||
| 58 | +constexpr int64_t RESERVED_BYTES = 8 * 1024; // UB reserved for sync/TBuf | ||
| 59 | +constexpr int64_t NUM_IO_BUFS = 3; // B_anchor, B_deltas, B_boxes (§9.1) | ||
| 60 | + | ||
| 61 | +// ========================================================================= | ||
| 62 | +// Inline math helpers (mirror DESIGN §9.4 / §9.5 formulas) | ||
| 63 | +// ========================================================================= | ||
| 64 | +static inline int64_t CeilDiv(int64_t a, int64_t b) { return (a + b - 1) / b; } | ||
| 65 | +static inline int64_t AlignUp(int64_t v, int64_t f) { return CeilDiv(v, f) * f; } | ||
| 66 | +static inline int64_t AlignDown(int64_t v, int64_t f) { return (v / f) * f; } | ||
| 67 | + | ||
| 68 | +// ========================================================================= | ||
| 69 | +// §9.5 ComputeMultiCoreSplit — by box count, 512-box alignment | ||
| 70 | +// | ||
| 71 | +// Fills: dim0, coreNum, blockFormer, blockNum. | ||
| 72 | +// coreNum = min(CeilDiv(dim0 × minDtypeBits, MIN_TILING_BITS), availableCoreNum); ≥1 | ||
| 73 | +// blockFormer = AlignUp(CeilDiv(dim0, coreNum), ELEM_ALIGN_FACTOR) | ||
| 74 | +// blockNum = CeilDiv(dim0, blockFormer) | ||
| 75 | +// ========================================================================= | ||
| 76 | +static void ComputeMultiCoreSplit(int64_t dim0, int64_t sizeofT, int64_t availableCoreNum, | ||
| 77 | + BoundingBoxDecodeTilingData* td) | ||
| 78 | +{ | ||
| 79 | + int64_t minDtypeBits = ELEMS_PER_BOX * sizeofT * 8; // bits per box | ||
| 80 | + int64_t coreNum = CeilDiv(dim0 * minDtypeBits, MIN_TILING_BITS); | ||
| 81 | + coreNum = std::min(coreNum, availableCoreNum); | ||
| 82 | + coreNum = std::max(coreNum, static_cast<int64_t>(1)); // at least 1 core | ||
| 83 | + | ||
| 84 | + int64_t blockFormer = AlignUp(CeilDiv(dim0, coreNum), ELEM_ALIGN_FACTOR); | ||
| 85 | + int64_t blockNum = CeilDiv(dim0, blockFormer); | ||
| 86 | + // 512-box alignment can enlarge blockFormer so that blockNum < coreNum; | ||
| 87 | + // cap coreNum to blockNum to avoid launching idle cores (SetBlockDim). | ||
| 88 | + coreNum = std::min(coreNum, blockNum); | ||
| 89 | + | ||
| 90 | + td->dim0 = dim0; | ||
| 91 | + td->coreNum = static_cast<int32_t>(coreNum); | ||
| 92 | + td->blockFormer = blockFormer; | ||
| 93 | + td->blockNum = blockNum; | ||
| 94 | +} | ||
| 95 | + | ||
| 96 | +// ========================================================================= | ||
| 97 | +// §9.4 ComputeUbSplit — by box count, 256B alignment | ||
| 98 | +// | ||
| 99 | +// Fills: ubFormer, ubLoopOfFormerBlock, ubTailOfFormerBlock, | ||
| 100 | +// ubLoopOfTailBlock, ubTailOfTailBlock. | ||
| 101 | +// perBoxBytes = NUM_IO_BUFS×4×sizeof(T) + K×4×sizeof(float) (§9.1) | ||
| 102 | +// alignFactor = ALIGN_256 / (4 × sizeof(T)) [box count] | ||
| 103 | +// ubFormer = max(AlignDown((ubSize-RESERVED)/perBoxBytes, alignFactor), alignFactor) | ||
| 104 | +// blockTail = dim0 - (blockNum-1)×blockFormer | ||
| 105 | +// ========================================================================= | ||
| 106 | +static void ComputeUbSplit(int64_t ubSize, int64_t sizeofT, int64_t K, int64_t blockFormer, int64_t dim0, | ||
| 107 | + int64_t blockNum, BoundingBoxDecodeTilingData* td) | ||
| 108 | +{ | ||
| 109 | + int64_t perBoxBytes = NUM_IO_BUFS * ELEMS_PER_BOX * sizeofT + K * ELEMS_PER_BOX * sizeof(float); | ||
| 110 | + int64_t alignFactor = ALIGN_256 / (ELEMS_PER_BOX * sizeofT); | ||
| 111 | + int64_t maxBoxNum = (ubSize - RESERVED_BYTES) / perBoxBytes; | ||
| 112 | + int64_t ubFormer = AlignDown(maxBoxNum, alignFactor); | ||
| 113 | + ubFormer = std::max(ubFormer, alignFactor); // floor at 1 alignment block | ||
| 114 | + | ||
| 115 | + int64_t ubLoopOfFormerBlock = CeilDiv(blockFormer, ubFormer); | ||
| 116 | + int64_t ubTailOfFormerBlock = blockFormer - (ubLoopOfFormerBlock - 1) * ubFormer; | ||
| 117 | + | ||
| 118 | + int64_t blockTail = dim0 - (blockNum - 1) * blockFormer; | ||
| 119 | + int64_t ubLoopOfTailBlock = CeilDiv(blockTail, ubFormer); | ||
| 120 | + int64_t ubTailOfTailBlock = blockTail - (ubLoopOfTailBlock - 1) * ubFormer; | ||
| 121 | + | ||
| 122 | + td->ubFormer = ubFormer; | ||
| 123 | + td->ubLoopOfFormerBlock = ubLoopOfFormerBlock; | ||
| 124 | + td->ubTailOfFormerBlock = ubTailOfFormerBlock; | ||
| 125 | + td->ubLoopOfTailBlock = ubLoopOfTailBlock; | ||
| 126 | + td->ubTailOfTailBlock = ubTailOfTailBlock; | ||
| 127 | +} | ||
| 128 | + | ||
| 129 | +// ========================================================================= | ||
| 130 | +// §9.3 BoundingBoxDecodePreCheck — 异常值校验 | ||
| 131 | +// | ||
| 132 | +// Fixed order: null → dtype → format → rank(rank==2) → attr → shape. | ||
| 133 | +// On success returns true and fills N (box count) + isEmpty (N==0). | ||
| 134 | +// On any failure returns false (caller returns GRAPH_FAILED, no kernel launch). | ||
| 135 | +// | ||
| 136 | +// Attr layout (OpDef order, indices match AppendAttr order): | ||
| 137 | +// index 0: means (ListFloat→ GetListFloat(0)) | ||
| 138 | +// index 1: stds (ListFloat→ GetListFloat(1)) | ||
| 139 | +// index 2: max_shape (ListInt → GetListInt(2)) | ||
| 140 | +// index 3: wh_ratio_clip(Float → GetFloat(3)) | ||
| 141 | +// ========================================================================= | ||
| 142 | +static bool BoundingBoxDecodePreCheck(gert::TilingContext* ctx, int64_t& N, bool& isEmpty) | ||
| 143 | +{ | ||
| 144 | + // 1. null check — GetInputShape bounds-checks (returns nullptr for missing input). | ||
| 145 | + const gert::StorageShape* aShape = ctx->GetInputShape(0); | ||
| 146 | + const gert::StorageShape* dShape = ctx->GetInputShape(1); | ||
| 147 | + if (aShape == nullptr || dShape == nullptr) { | ||
| 148 | + return false; // → null_input | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + // 2. dtype check: anchor_box/deltas ∈ {fp16,fp32} and equal. | ||
| 152 | + const gert::CompileTimeTensorDesc* aDesc = ctx->GetInputDesc(0); | ||
| 153 | + const gert::CompileTimeTensorDesc* dDesc = ctx->GetInputDesc(1); | ||
| 154 | + if (aDesc == nullptr || dDesc == nullptr) { | ||
| 155 | + return false; | ||
| 156 | + } | ||
| 157 | + ge::DataType aDt = aDesc->GetDataType(); | ||
| 158 | + ge::DataType dDt = dDesc->GetDataType(); | ||
| 159 | + if (aDt != ge::DT_FLOAT16 && aDt != ge::DT_FLOAT) { | ||
| 160 | + return false; // → dtype_not_supported | ||
| 161 | + } | ||
| 162 | + if (aDt != dDt) { | ||
| 163 | + return false; // → dtype_not_supported (mix) | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + // 3. format check: inputs must be ND. | ||
| 167 | + ge::Format aFmt = aDesc->GetStorageFormat(); | ||
| 168 | + ge::Format dFmt = dDesc->GetStorageFormat(); | ||
| 169 | + if (aFmt != ge::FORMAT_ND || dFmt != ge::FORMAT_ND) { | ||
| 170 | + return false; // → shape_mismatch (non-ND format rejected) | ||
| 171 | + } | ||
| 172 | + | ||
| 173 | + // 4. rank check: both inputs rank == 2 (MAX_RANK). | ||
| 174 | + const gert::Shape& aShp = aShape->GetStorageShape(); | ||
| 175 | + const gert::Shape& dShp = dShape->GetStorageShape(); | ||
| 176 | + if (aShp.GetDimNum() != static_cast<size_t>(MAX_RANK) || dShp.GetDimNum() != static_cast<size_t>(MAX_RANK)) { | ||
| 177 | + return false; // → shape_mismatch (rank != 2) | ||
| 178 | + } | ||
| 179 | + | ||
| 180 | + // 5. attr value-range check. | ||
| 181 | + const gert::RuntimeAttrs* attrs = ctx->GetAttrs(); | ||
| 182 | + if (attrs == nullptr) { | ||
| 183 | + return false; // → attribute_value_out_of_range (attrs missing) | ||
| 184 | + } | ||
| 185 | + const auto* meansVec = attrs->GetListFloat(0); // means ListFloat index 0 | ||
| 186 | + const auto* stdsVec = attrs->GetListFloat(1); // stds ListFloat index 1 | ||
| 187 | + const auto* maxShapeVec = attrs->GetListInt(2); // max_shape ListInt index 2 | ||
| 188 | + const float* clipPtr = attrs->GetFloat(3); // wh_ratio_clip Float index 3 | ||
| 189 | + if (maxShapeVec == nullptr || meansVec == nullptr || stdsVec == nullptr || clipPtr == nullptr) { | ||
| 190 | + return false; // → attribute_value_out_of_range (required attr missing) | ||
| 191 | + } | ||
| 192 | + // means/stds length == 4 | ||
| 193 | + if (meansVec->GetSize() != 4 || stdsVec->GetSize() != 4) { | ||
| 194 | + return false; // → attribute_value_out_of_range (length != 4) | ||
| 195 | + } | ||
| 196 | + const float* means = meansVec->GetData(); | ||
| 197 | + const float* stds = stdsVec->GetData(); | ||
| 198 | + // stds elements must be non-zero | ||
| 199 | + if (stds[0] == 0.0f || stds[1] == 0.0f || stds[2] == 0.0f || stds[3] == 0.0f) { | ||
| 200 | + return false; // → attribute_value_out_of_range (stds has zero) | ||
| 201 | + } | ||
| 202 | + // wh_ratio_clip > 0 | ||
| 203 | + if (*clipPtr <= 0.0f) { | ||
| 204 | + return false; // → attribute_value_out_of_range (wh_ratio_clip <= 0) | ||
| 205 | + } | ||
| 206 | + // max_shape length == 2 (H, W) | ||
| 207 | + if (maxShapeVec->GetSize() != 2) { | ||
| 208 | + return false; // → attribute_value_out_of_range (max_shape length != 2) | ||
| 209 | + } | ||
| 210 | + | ||
| 211 | + // 6. shape check: last dim == 4 and N (dim 0) matches across inputs. | ||
| 212 | + if (aShp.GetDim(1) != ELEMS_PER_BOX || dShp.GetDim(1) != ELEMS_PER_BOX) { | ||
| 213 | + return false; // → shape_mismatch (last dim != 4) | ||
| 214 | + } | ||
| 215 | + if (aShp.GetDim(0) != dShp.GetDim(0)) { | ||
| 216 | + return false; // → shape_mismatch (N mismatch) | ||
| 217 | + } | ||
| 218 | + | ||
| 219 | + N = aShp.GetDim(0); | ||
| 220 | + isEmpty = (N == 0); | ||
| 221 | + return true; | ||
| 222 | +} | ||
| 223 | + | ||
| 224 | +// ========================================================================= | ||
| 225 | +// §9.7 FillTilingData — empty/normal fork + attr passthrough + SetTilingKey/SetBlockDim | ||
| 226 | +// | ||
| 227 | +// empty branch: coreNum=1, compute fields=0, SetTilingKey(dtype), SetBlockDim(1). | ||
| 228 | +// normal branch: ComputeMultiCoreSplit → ComputeUbSplit, | ||
| 229 | +// SetTilingKey(dtype), SetBlockDim(coreNum). | ||
| 230 | +// tilingKey is now dtype-only (no BOOL component) — see struct.h comment. | ||
| 231 | +// Attr scalars (means/stds/maxShapeH/maxShapeW) are passed through in both branches. | ||
| 232 | +// ========================================================================= | ||
| 233 | +static void FillTilingData(gert::TilingContext* ctx, BoundingBoxDecodeTilingData* td, int64_t N, bool isEmpty, | ||
| 234 | + int64_t sizeofT, int64_t ubSize, int64_t availableCoreNum) | ||
| 235 | +{ | ||
| 236 | + td->dim0 = N; | ||
| 237 | + | ||
| 238 | + // Attr passthrough (§7 field table; aclnn-supplied, kernel Compute consumes). | ||
| 239 | + const gert::RuntimeAttrs* attrs = ctx->GetAttrs(); | ||
| 240 | + const auto* meansVec = attrs->GetListFloat(0); | ||
| 241 | + const auto* stdsVec = attrs->GetListFloat(1); | ||
| 242 | + const auto* maxShapeVec = attrs->GetListInt(2); | ||
| 243 | + const float* means = meansVec->GetData(); | ||
| 244 | + const float* stds = stdsVec->GetData(); | ||
| 245 | + const int64_t* ms = maxShapeVec->GetData(); | ||
| 246 | + for (int i = 0; i < 4; i++) { | ||
| 247 | + td->means[i] = means[i]; | ||
| 248 | + td->stds[i] = stds[i]; | ||
| 249 | + } | ||
| 250 | + td->maxShapeH = ms[0]; | ||
| 251 | + td->maxShapeW = ms[1]; | ||
| 252 | + // wh_ratio_clip is not referenced by the core formula (§1.3) — not in TilingData. | ||
| 253 | + | ||
| 254 | + if (isEmpty) { | ||
| 255 | + // empty branch: coreNum=1, compute fields=0 (kernel short-circuits via td.dim0==0). | ||
| 256 | + td->coreNum = 1; | ||
| 257 | + td->blockFormer = 0; | ||
| 258 | + td->blockNum = 1; // 1 (not 0) to avoid downstream div-by-zero | ||
| 259 | + td->ubFormer = 0; | ||
| 260 | + td->ubLoopOfFormerBlock = 0; | ||
| 261 | + td->ubTailOfFormerBlock = 0; | ||
| 262 | + td->ubLoopOfTailBlock = 0; | ||
| 263 | + td->ubTailOfTailBlock = 0; | ||
| 264 | + ctx->SetBlockDim(1); | ||
| 265 | + ctx->SetTilingKey((sizeofT == 2) ? BOUNDING_BOX_DECODE_FP16 : BOUNDING_BOX_DECODE_FP32); | ||
| 266 | + } else { | ||
| 267 | + // normal branch: K by dtype — fp32→0, fp16→2 (§9.1 NUM_CALC_BUFS). | ||
| 268 | + int64_t K = (sizeofT == static_cast<int64_t>(sizeof(float))) ? 0 : 2; | ||
| 269 | + ComputeMultiCoreSplit(N, sizeofT, availableCoreNum, td); | ||
| 270 | + ComputeUbSplit(ubSize, sizeofT, K, td->blockFormer, td->dim0, td->blockNum, td); | ||
| 271 | + ctx->SetBlockDim(static_cast<uint32_t>(td->coreNum)); | ||
| 272 | + ctx->SetTilingKey((sizeofT == 2) ? BOUNDING_BOX_DECODE_FP16 : BOUNDING_BOX_DECODE_FP32); | ||
| 273 | + } | ||
| 274 | +} | ||
| 275 | + | ||
| 276 | +// ========================================================================= | ||
| 277 | +// §9.9 TilingFunc — entry point | ||
| 278 | +// | ||
| 279 | +// Workflow: | ||
| 280 | +// 1. Get TilingData buffer (GetTilingData<T> sets data size = sizeof(T)). | ||
| 281 | +// 2. Query platform info (ubSize / availableCoreNum) via PlatformAscendC. | ||
| 282 | +// 3. BoundingBoxDecodePreCheck (§9.3) — fail → GRAPH_FAILED, no kernel. | ||
| 283 | +// 4. FillTilingData (§9.7) — empty/normal fork + attr passthrough. | ||
| 284 | +// 5. Set workspace = 0 (no cross-core partial merge, §9.6). | ||
| 285 | +// ========================================================================= | ||
| 286 | +ge::graphStatus TilingFunc(gert::TilingContext* context) | ||
| 287 | +{ | ||
| 288 | + // 1. TilingData buffer | ||
| 289 | + BoundingBoxDecodeTilingData* td = context->GetTilingData<BoundingBoxDecodeTilingData>(); | ||
| 290 | + if (td == nullptr) { | ||
| 291 | + return ge::GRAPH_FAILED; | ||
| 292 | + } | ||
| 293 | + std::memset(td, 0, sizeof(BoundingBoxDecodeTilingData)); | ||
| 294 | + | ||
| 295 | + // 2. Platform info — ubSize / availableCoreNum (never hard-coded) | ||
| 296 | + int64_t ubSize = 0; | ||
| 297 | + int64_t availableCoreNum = 0; | ||
| 298 | + fe::PlatFormInfos* platformInfo = context->GetPlatformInfo(); | ||
| 299 | + if (platformInfo != nullptr) { | ||
| 300 | + platform_ascendc::PlatformAscendC ascendcPlatform(platformInfo); | ||
| 301 | + uint64_t ub = 0; | ||
| 302 | + ascendcPlatform.GetCoreMemSize(platform_ascendc::CoreMemType::UB, ub); | ||
| 303 | + ubSize = static_cast<int64_t>(ub); | ||
| 304 | + availableCoreNum = static_cast<int64_t>(ascendcPlatform.GetCoreNumAiv()); | ||
| 305 | + } | ||
| 306 | + if (ubSize <= 0) { | ||
| 307 | + ubSize = 196608; // 192 KB fallback (ascend950 default) | ||
| 308 | + } | ||
| 309 | + if (availableCoreNum <= 0) { | ||
| 310 | + availableCoreNum = 1; | ||
| 311 | + } | ||
| 312 | + | ||
| 313 | + // 3. PreCheck (§9.3): null → dtype → format → rank → attr → shape | ||
| 314 | + int64_t N = 0; | ||
| 315 | + bool isEmpty = false; | ||
| 316 | + if (!BoundingBoxDecodePreCheck(context, N, isEmpty)) { | ||
| 317 | + return ge::GRAPH_FAILED; // validation failure → no kernel launch | ||
| 318 | + } | ||
| 319 | + | ||
| 320 | + // 4. FillTilingData (§9.7): empty/normal fork + attr passthrough | ||
| 321 | + ge::DataType aDt = context->GetInputDesc(0)->GetDataType(); | ||
| 322 | + int64_t sizeofT = (aDt == ge::DT_FLOAT) ? 4 : 2; | ||
| 323 | + FillTilingData(context, td, N, isEmpty, sizeofT, ubSize, availableCoreNum); | ||
| 324 | + | ||
| 325 | + // 5. Workspace = 0 (Elementwise, no cross-core partial merge, §9.6) | ||
| 326 | + size_t* ws = context->GetWorkspaceSizes(1); | ||
| 327 | + if (ws != nullptr) { | ||
| 328 | + ws[0] = 0; | ||
| 329 | + } | ||
| 330 | + | ||
| 331 | + return ge::GRAPH_SUCCESS; | ||
| 332 | +} | ||
| 333 | + | ||
| 334 | +// ============================================================================= | ||
| 335 | +// §9.8 Host-side registration — IMPL_OP_OPTILING | ||
| 336 | +// .Tiling(TilingFunc): registers the runtime tiling callback. | ||
| 337 | +// Platform info is queried live via GetPlatformInfo() + PlatformAscendC | ||
| 338 | +// (broadcast_tiling pattern), so no TilingParse/CompileInfo cache is required. | ||
| 339 | +// ============================================================================= | ||
| 340 | +IMPL_OP_OPTILING(BoundingBoxDecode).Tiling(TilingFunc); | ||
| 341 | + | ||
| 342 | +} // namespace optiling | ||
| @@ -0,0 +1,37 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | +namespace optiling { | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * TilingFunc: the tiling callback invoked by the CANN framework before kernel launch. | ||
| 18 | + * | ||
| 19 | + * Parameters: | ||
| 20 | + * context — [in/out] tiling context providing input shapes, dtypes, and | ||
| 21 | + * accepting the computed BoundingBoxDecodeTilingData. | ||
| 22 | + * | ||
| 23 | + * Returns: | ||
| 24 | + * ge::GRAPH_SUCCESS on success. | ||
| 25 | + * | ||
| 26 | + * Side effects: | ||
| 27 | + * - Reads input tensor metadata from context. | ||
| 28 | + * - Computes totalLength, blockLength, tileLength, numBlocks. | ||
| 29 | + * - Writes these values into BoundingBoxDecodeTilingData via context->GetTilingData. | ||
| 30 | + * - Sets the block dimension via context->SetBlockDim. | ||
| 31 | + * - Optionally sets workspace sizes via context->GetWorkspaceSizes. | ||
| 32 | + */ | ||
| 33 | +ge::graphStatus TilingFunc(gert::TilingContext* context); | ||
| 34 | + | ||
| 35 | +} // namespace optiling | ||
| 36 | + | ||
| 37 | + | ||
| @@ -0,0 +1,59 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/* Generated By CANNBot */ | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | +namespace ops { | ||
| 16 | +class BoundingBoxDecode : public OpDef { | ||
| 17 | +public: | ||
| 18 | + explicit BoundingBoxDecode(const char* name) : OpDef(name) | ||
| 19 | + { | ||
| 20 | + this->Input("rois") | ||
| 21 | + .ParamType(REQUIRED) | ||
| 22 | + .DataType({ge::DT_FLOAT16, ge::DT_FLOAT}) | ||
| 23 | + .Format({ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 24 | + .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 25 | + .AutoContiguous(); | ||
| 26 | + | ||
| 27 | + this->Input("deltas") | ||
| 28 | + .ParamType(REQUIRED) | ||
| 29 | + .DataType({ge::DT_FLOAT16, ge::DT_FLOAT}) | ||
| 30 | + .Format({ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 31 | + .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 32 | + .AutoContiguous(); | ||
| 33 | + | ||
| 34 | + this->Output("bboxes") | ||
| 35 | + .ParamType(REQUIRED) | ||
| 36 | + .DataType({ge::DT_FLOAT16, ge::DT_FLOAT}) | ||
| 37 | + .Format({ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 38 | + .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 39 | + .AutoContiguous(); | ||
| 40 | + | ||
| 41 | + this->Attr("means").AttrType(OPTIONAL).ListFloat({0.0f, 0.0f, 0.0f, 0.0f}); | ||
| 42 | + this->Attr("stds").AttrType(OPTIONAL).ListFloat({1.0f, 1.0f, 1.0f, 1.0f}); | ||
| 43 | + this->Attr("max_shape").AttrType(REQUIRED).ListInt(); | ||
| 44 | + this->Attr("wh_ratio_clip").AttrType(OPTIONAL).Float(0.016f); | ||
| 45 | + | ||
| 46 | + OpAICoreConfig aicoreConfig; | ||
| 47 | + aicoreConfig.DynamicCompileStaticFlag(true) | ||
| 48 | + .DynamicFormatFlag(false) | ||
| 49 | + .DynamicRankSupportFlag(true) | ||
| 50 | + .DynamicShapeSupportFlag(true) | ||
| 51 | + .NeedCheckSupportFlag(false) | ||
| 52 | + .PrecisionReduceFlag(false) | ||
| 53 | + .ExtendCfgInfo("opFile.value", "bounding_box_decode_apt"); | ||
| 54 | + | ||
| 55 | + this->AICore().AddConfig("ascend950", aicoreConfig); | ||
| 56 | + } | ||
| 57 | +}; | ||
| 58 | +OP_ADD(BoundingBoxDecode); | ||
| 59 | +} // namespace ops | ||
| @@ -0,0 +1,87 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +using namespace ge; | ||
| 19 | + | ||
| 20 | +namespace ops { | ||
| 21 | + | ||
| 22 | +namespace { | ||
| 23 | + | ||
| 24 | +bool IsUnknownRank(const gert::Shape* shape) | ||
| 25 | +{ | ||
| 26 | + return shape != nullptr && shape->GetDimNum() == 1 && shape->GetDim(0) == ge::UNKNOWN_DIM_NUM; | ||
| 27 | +} | ||
| 28 | + | ||
| 29 | +} // namespace | ||
| 30 | + | ||
| 31 | +/** | ||
| 32 | + * InferShapeForBoundingBoxDecode: GE shape inference callback. | ||
| 33 | + * | ||
| 34 | + * boxes.shape = anchor_box.shape (identity). Validates that both inputs are | ||
| 35 | + * non-null, rank == 2, last dim == 4, and the two input shapes are equal | ||
| 36 | + * (DESIGN §3.1). Empty tensor (N==0) is supported — the identity copy | ||
| 37 | + * propagates (0, 4) to the output. | ||
| 38 | + */ | ||
| 39 | +ge::graphStatus InferShapeForBoundingBoxDecode(gert::InferShapeContext* context) | ||
| 40 | +{ | ||
| 41 | + const gert::Shape* anchorShape = context->GetInputShape(0); | ||
| 42 | + const gert::Shape* deltasShape = context->GetInputShape(1); | ||
| 43 | + gert::Shape* boxesShape = context->GetOutputShape(0); | ||
| 44 | + if (anchorShape == nullptr || deltasShape == nullptr || boxesShape == nullptr) { | ||
| 45 | + return GRAPH_FAILED; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + if (IsUnknownRank(anchorShape) || IsUnknownRank(deltasShape)) { | ||
| 49 | + boxesShape->SetDimNum(1); | ||
| 50 | + boxesShape->SetDim(0, ge::UNKNOWN_DIM_NUM); | ||
| 51 | + return GRAPH_SUCCESS; | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + const size_t rank = anchorShape->GetDimNum(); | ||
| 55 | + if (rank != 2 || deltasShape->GetDimNum() != 2) { | ||
| 56 | + return GRAPH_FAILED; | ||
| 57 | + } | ||
| 58 | + if (anchorShape->GetDim(1) != 4 || deltasShape->GetDim(1) != 4) { | ||
| 59 | + return GRAPH_FAILED; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + // Validate anchor_box.shape == deltas.shape (no broadcast, DESIGN §3.1) | ||
| 63 | + const int64_t anchorN = anchorShape->GetDim(0); | ||
| 64 | + const int64_t deltasN = deltasShape->GetDim(0); | ||
| 65 | + if (anchorN != deltasN && anchorN != ge::UNKNOWN_DIM && deltasN != ge::UNKNOWN_DIM) { | ||
| 66 | + return GRAPH_FAILED; | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + // boxes.shape = anchor_box.shape (identity copy) | ||
| 70 | + boxesShape->SetDimNum(rank); | ||
| 71 | + for (size_t i = 0; i < rank; ++i) { | ||
| 72 | + boxesShape->SetDim(i, anchorShape->GetDim(i)); | ||
| 73 | + } | ||
| 74 | + return GRAPH_SUCCESS; | ||
| 75 | +} | ||
| 76 | + | ||
| 77 | +/** | ||
| 78 | + * IMPL_OP_INFERSHAPE(BoundingBoxDecode).InferShape(...): | ||
| 79 | + * Registers the shape inference function at static init time. When the | ||
| 80 | + * framework needs to determine the output shape of a BoundingBoxDecode node, | ||
| 81 | + * it calls InferShapeForBoundingBoxDecode. This static registration is | ||
| 82 | + * required by the GE runtime (NnopbaseExecutorDoTiling) to locate the op | ||
| 83 | + * implementation via the op_impl_registry. | ||
| 84 | + */ | ||
| 85 | +IMPL_OP_INFERSHAPE(BoundingBoxDecode).InferShape(InferShapeForBoundingBoxDecode); | ||
| 86 | + | ||
| 87 | +} // namespace ops | ||
| @@ -0,0 +1,462 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +// Cast traits for fp16<->fp32 conversion inside VF functions | ||
| 18 | +constexpr AscendC::MicroAPI::CastTrait kCastB162B32 = { | ||
| 19 | + AscendC::MicroAPI::RegLayout::ZERO, | ||
| 20 | + AscendC::MicroAPI::SatMode::UNKNOWN, | ||
| 21 | + AscendC::MicroAPI::MaskMergeMode::ZEROING, | ||
| 22 | + AscendC::RoundMode::UNKNOWN, | ||
| 23 | +}; | ||
| 24 | +constexpr AscendC::MicroAPI::CastTrait kCastB322B16 = { | ||
| 25 | + AscendC::MicroAPI::RegLayout::ZERO, | ||
| 26 | + AscendC::MicroAPI::SatMode::NO_SAT, | ||
| 27 | + AscendC::MicroAPI::MaskMergeMode::ZEROING, | ||
| 28 | + AscendC::RoundMode::CAST_RINT, | ||
| 29 | +}; | ||
| 30 | + | ||
| 31 | +constexpr int64_t kPhysNodes = 5; | ||
| 32 | +constexpr int64_t kMaxInputSlots = 2; | ||
| 33 | +constexpr int64_t kMaxOutputSlots = 1; | ||
| 34 | +static constexpr uint32_t VL_F32 = 256U / sizeof(float); // 64 | ||
| 35 | + | ||
| 36 | +// High-precision exp constants (Cody-Waite range reduction for fp32 path). | ||
| 37 | +// exp(dw) = 2^n * exp(r), where dw = n*ln2 + r, |r| <= ln2/2 ≈ 0.347. | ||
| 38 | +// The 2^n scaling is exact (power-of-2 multiply = IEEE exponent shift, zero | ||
| 39 | +// mantissa rounding). NPU Reg::Exp on the reduced range [-0.347, 0.347] is | ||
| 40 | +// more accurate than on the full input range, matching libm expf more closely. | ||
| 41 | +constexpr float kInvLn2 = 1.44269502162933349609375f; // 0x3fb8aa3b, 1/ln(2) | ||
| 42 | +constexpr float kLn2Hi = 0.693145751953125f; // 0x3f317000, ln(2) high (12 sig bits → n*ln2Hi exact for |n|<2048) | ||
| 43 | +constexpr float kLn2Lo = 1.428606765330187045e-06f; // ln(2) - kLn2Hi, low residual | ||
| 44 | +constexpr int32_t kExpBias = 127; | ||
| 45 | +constexpr int16_t kExpShift = 23; | ||
| 46 | +constexpr uint32_t kF32PInf = 0x7F800000u; | ||
| 47 | +constexpr uint32_t kF32NInf = 0xFF800000u; | ||
| 48 | + | ||
| 49 | +constexpr AscendC::MicroAPI::CastTrait kCastF2IRound = { | ||
| 50 | + AscendC::MicroAPI::RegLayout::UNKNOWN, AscendC::MicroAPI::SatMode::SAT, AscendC::MicroAPI::MaskMergeMode::ZEROING, | ||
| 51 | + AscendC::RoundMode::CAST_ROUND}; | ||
| 52 | +constexpr AscendC::MicroAPI::CastTrait kCastI2FRound = { | ||
| 53 | + AscendC::MicroAPI::RegLayout::UNKNOWN, AscendC::MicroAPI::SatMode::NO_SAT, | ||
| 54 | + AscendC::MicroAPI::MaskMergeMode::ZEROING, AscendC::RoundMode::CAST_ROUND}; | ||
| 55 | + | ||
| 56 | +// ========================================================================= | ||
| 57 | +// VF 1: AnchorPreVF — pw=aHi-aLo+1, pcx=(aLo+aHi)*0.5 | ||
| 58 | +// Loads T from channel-contiguous aChLo/aChHi (fp16 upcast to fp32), | ||
| 59 | +// stores fp32 pw/pcx to calc slots. DESIGN §5.2 S3a/S3f. | ||
| 60 | +// ========================================================================= | ||
| 61 | +template <typename T> | ||
| 62 | +__simd_vf__ inline void AnchorPreVF(__ubuf__ float* pwOut, __ubuf__ float* pcxOut, __ubuf__ T* aChLo, __ubuf__ T* aChHi, | ||
| 63 | + uint32_t count, uint16_t repeatTime) | ||
| 64 | +{ | ||
| 65 | + uint32_t remaining = count; | ||
| 66 | + for (uint16_t i = 0; i < repeatTime; ++i) { | ||
| 67 | + uint32_t off = static_cast<uint32_t>(i) * VL_F32; | ||
| 68 | + AscendC::Reg::MaskReg mask = AscendC::Reg::UpdateMask<float>(remaining); | ||
| 69 | + AscendC::Reg::RegTensor<float> aLo, aHi, pw, pcx; | ||
| 70 | + if constexpr (std::is_same_v<T, half>) { | ||
| 71 | + AscendC::Reg::RegTensor<half> hLo, hHi; | ||
| 72 | + AscendC::Reg::LoadAlign<half, AscendC::Reg::LoadDist::DIST_UNPACK_B16>(hLo, aChLo + off); | ||
| 73 | + AscendC::Reg::LoadAlign<half, AscendC::Reg::LoadDist::DIST_UNPACK_B16>(hHi, aChHi + off); | ||
| 74 | + AscendC::Reg::Cast<float, half, kCastB162B32>(aLo, hLo, mask); | ||
| 75 | + AscendC::Reg::Cast<float, half, kCastB162B32>(aHi, hHi, mask); | ||
| 76 | + } else { | ||
| 77 | + AscendC::Reg::LoadAlign(aLo, aChLo + off); | ||
| 78 | + AscendC::Reg::LoadAlign(aHi, aChHi + off); | ||
| 79 | + } | ||
| 80 | + AscendC::Reg::Sub<float>(pw, aHi, aLo, mask); | ||
| 81 | + AscendC::Reg::Adds<float>(pw, pw, 1.0f, mask); | ||
| 82 | + AscendC::Reg::Add<float>(pcx, aLo, aHi, mask); | ||
| 83 | + AscendC::Reg::Muls<float>(pcx, pcx, 0.5f, mask); | ||
| 84 | + AscendC::Reg::StoreAlign(pwOut + off, pw, mask); | ||
| 85 | + AscendC::Reg::StoreAlign(pcxOut + off, pcx, mask); | ||
| 86 | + } | ||
| 87 | +} | ||
| 88 | + | ||
| 89 | +// ========================================================================= | ||
| 90 | +// VF 2: DeltaDeStdVF — dx=dLo*stdsLo+meansLo, dw=dHi*stdsHi+meansHi | ||
| 91 | +// Loads T from channel-contiguous dChLo/dChHi (fp16 upcast), stores fp32 | ||
| 92 | +// dx/dw. DESIGN §5.2 S3b/S3g. | ||
| 93 | +// ========================================================================= | ||
| 94 | +template <typename T> | ||
| 95 | +__simd_vf__ inline void DeltaDeStdVF(__ubuf__ float* dxOut, __ubuf__ float* dwOut, __ubuf__ T* dChLo, __ubuf__ T* dChHi, | ||
| 96 | + float stdsLo, float stdsHi, float meansLo, float meansHi, uint32_t count, | ||
| 97 | + uint16_t repeatTime) | ||
| 98 | +{ | ||
| 99 | + uint32_t remaining = count; | ||
| 100 | + for (uint16_t i = 0; i < repeatTime; ++i) { | ||
| 101 | + uint32_t off = static_cast<uint32_t>(i) * VL_F32; | ||
| 102 | + AscendC::Reg::MaskReg mask = AscendC::Reg::UpdateMask<float>(remaining); | ||
| 103 | + AscendC::Reg::RegTensor<float> dLo, dHi, dx, dw; | ||
| 104 | + if constexpr (std::is_same_v<T, half>) { | ||
| 105 | + AscendC::Reg::RegTensor<half> hLo, hHi; | ||
| 106 | + AscendC::Reg::LoadAlign<half, AscendC::Reg::LoadDist::DIST_UNPACK_B16>(hLo, dChLo + off); | ||
| 107 | + AscendC::Reg::LoadAlign<half, AscendC::Reg::LoadDist::DIST_UNPACK_B16>(hHi, dChHi + off); | ||
| 108 | + AscendC::Reg::Cast<float, half, kCastB162B32>(dLo, hLo, mask); | ||
| 109 | + AscendC::Reg::Cast<float, half, kCastB162B32>(dHi, hHi, mask); | ||
| 110 | + } else { | ||
| 111 | + AscendC::Reg::LoadAlign(dLo, dChLo + off); | ||
| 112 | + AscendC::Reg::LoadAlign(dHi, dChHi + off); | ||
| 113 | + } | ||
| 114 | + AscendC::Reg::Muls<float>(dx, dLo, stdsLo, mask); | ||
| 115 | + AscendC::Reg::Adds<float>(dx, dx, meansLo, mask); | ||
| 116 | + AscendC::Reg::Muls<float>(dw, dHi, stdsHi, mask); | ||
| 117 | + AscendC::Reg::Adds<float>(dw, dw, meansHi, mask); | ||
| 118 | + AscendC::Reg::StoreAlign(dxOut + off, dx, mask); | ||
| 119 | + AscendC::Reg::StoreAlign(dwOut + off, dw, mask); | ||
| 120 | + } | ||
| 121 | +} | ||
| 122 | + | ||
| 123 | +// ========================================================================= | ||
| 124 | +// VF 3: DecodeGwGxVF<T> — gw=pw*exp(dw), gx=pcx+pw*dx (pure fp32) | ||
| 125 | +// Reads pw/pcx/dx/dw from calc slots, writes gw/gx. Slot reuse safe: | ||
| 126 | +// all inputs loaded to registers before any store. DESIGN §5.2 S3c/S3h. | ||
| 127 | +// | ||
| 128 | +// Template parameter T selects the exp implementation: | ||
| 129 | +// - T=float (fp32 path): custom Cody-Waite+Taylor FMA exp (~0.5 ULP/step, | ||
| 130 | +// matching libm expf to meet fp32 rtol=atol=1e-5, DESIGN §4.3/§7.2). | ||
| 131 | +// - T=half (fp16 path): NPU Reg::Exp hardware instruction. The fp16 | ||
| 132 | +// tolerance (rtol=atol=1e-3) is 100× more lenient than fp32, so the | ||
| 133 | +// hardware exp's ~1 ULP error is sufficient. Using Reg::Exp for fp16 | ||
| 134 | +// also aligns the kernel's exp with np.exp (which uses the same vexp | ||
| 135 | +// instruction family on SIMD platforms), reducing catastrophic- | ||
| 136 | +// cancellation-induced mare spikes at near-zero outputs. | ||
| 137 | +// ========================================================================= | ||
| 138 | +template <typename T> | ||
| 139 | +__simd_vf__ inline void DecodeGwGxVF(__ubuf__ float* gwOut, __ubuf__ float* gxOut, __ubuf__ float* pwIn, | ||
| 140 | + __ubuf__ float* pcxIn, __ubuf__ float* dxIn, __ubuf__ float* dwIn, uint32_t count, | ||
| 141 | + uint16_t repeatTime) | ||
| 142 | +{ | ||
| 143 | + uint32_t remaining = count; | ||
| 144 | + for (uint16_t i = 0; i < repeatTime; ++i) { | ||
| 145 | + uint32_t off = static_cast<uint32_t>(i) * VL_F32; | ||
| 146 | + AscendC::Reg::MaskReg mask = AscendC::Reg::UpdateMask<float>(remaining); | ||
| 147 | + AscendC::Reg::RegTensor<float> pw, pcx, dx, dw, gw, gx, expDw, tmp; | ||
| 148 | + AscendC::Reg::LoadAlign(pw, pwIn + off); | ||
| 149 | + AscendC::Reg::LoadAlign(pcx, pcxIn + off); | ||
| 150 | + AscendC::Reg::LoadAlign(dx, dxIn + off); | ||
| 151 | + AscendC::Reg::LoadAlign(dw, dwIn + off); | ||
| 152 | + // Common ±Inf/overflow correction masks and constants (shared by | ||
| 153 | + // both exp paths below). | ||
| 154 | + AscendC::Reg::MaskReg infMask, ninfMask, ovfMask, udfMask; | ||
| 155 | + AscendC::Reg::RegTensor<float> zeroReg, infReg; | ||
| 156 | + AscendC::Reg::Duplicate<float>(zeroReg, 0.0f); | ||
| 157 | + AscendC::Reg::Duplicate((AscendC::Reg::RegTensor<uint32_t>&)infReg, kF32PInf); | ||
| 158 | + constexpr float kExpOvfThreshold = 89.0f; | ||
| 159 | + constexpr float kExpUdfThreshold = -88.0f; | ||
| 160 | + AscendC::Reg::CompareScalar<float, AscendC::CMPMODE::GE>(ovfMask, dw, kExpOvfThreshold, mask); | ||
| 161 | + AscendC::Reg::CompareScalar<float, AscendC::CMPMODE::LE>(udfMask, dw, kExpUdfThreshold, mask); | ||
| 162 | + AscendC::Reg::CompareScalar<uint32_t, AscendC::CMPMODE::EQ>(infMask, (AscendC::Reg::RegTensor<uint32_t>&)dw, | ||
| 163 | + kF32PInf, mask); | ||
| 164 | + AscendC::Reg::CompareScalar<uint32_t, AscendC::CMPMODE::EQ>(ninfMask, (AscendC::Reg::RegTensor<uint32_t>&)dw, | ||
| 165 | + kF32NInf, mask); | ||
| 166 | + | ||
| 167 | + if constexpr (std::is_same_v<T, float>) { | ||
| 168 | + // ---- fp32 path: high-precision Cody-Waite+Taylor FMA exp ---- | ||
| 169 | + // dw = n*ln2 + r (|r| <= ln2/2), exp(dw) = 2^n * exp(r) | ||
| 170 | + // 2^n is exact (IEEE exponent shift). FMA Horner gives 0.5 ULP | ||
| 171 | + // per step, matching libm expf for fp32 rtol=atol=1e-5. | ||
| 172 | + // Range guards fix 2^n bit-pattern wrap for |dw| > ~88.7. | ||
| 173 | + AscendC::Reg::RegTensor<float> t, nF, r, poly, coef; | ||
| 174 | + AscendC::Reg::RegTensor<int32_t> nI, biased; | ||
| 175 | + AscendC::Reg::Muls<float>(t, dw, kInvLn2, mask); | ||
| 176 | + AscendC::Reg::Cast<int32_t, float, kCastF2IRound>(nI, t, mask); | ||
| 177 | + AscendC::Reg::Cast<float, int32_t, kCastI2FRound>(nF, nI, mask); | ||
| 178 | + AscendC::Reg::Muls<float>(r, nF, kLn2Hi, mask); | ||
| 179 | + AscendC::Reg::Sub<float>(r, dw, r, mask); | ||
| 180 | + AscendC::Reg::Muls<float>(t, nF, kLn2Lo, mask); | ||
| 181 | + AscendC::Reg::Sub<float>(r, r, t, mask); | ||
| 182 | + // exp(r) via degree-7 Taylor, FMA Horner | ||
| 183 | + AscendC::Reg::Duplicate<float>(poly, 1.9841269841269841e-04f); | ||
| 184 | + AscendC::Reg::Duplicate<float>(coef, 1.3888888888888889e-03f); | ||
| 185 | + AscendC::Reg::FusedMulDstAdd<float>(poly, r, coef, mask); | ||
| 186 | + AscendC::Reg::Duplicate<float>(coef, 8.3333333333333333e-03f); | ||
| 187 | + AscendC::Reg::FusedMulDstAdd<float>(poly, r, coef, mask); | ||
| 188 | + AscendC::Reg::Duplicate<float>(coef, 4.1666666666666667e-02f); | ||
| 189 | + AscendC::Reg::FusedMulDstAdd<float>(poly, r, coef, mask); | ||
| 190 | + AscendC::Reg::Duplicate<float>(coef, 1.6666666666666667e-01f); | ||
| 191 | + AscendC::Reg::FusedMulDstAdd<float>(poly, r, coef, mask); | ||
| 192 | + AscendC::Reg::Duplicate<float>(coef, 5.0000000000000000e-01f); | ||
| 193 | + AscendC::Reg::FusedMulDstAdd<float>(poly, r, coef, mask); | ||
| 194 | + AscendC::Reg::Duplicate<float>(coef, 1.0000000000000000e+00f); | ||
| 195 | + AscendC::Reg::FusedMulDstAdd<float>(poly, r, coef, mask); | ||
| 196 | + AscendC::Reg::Duplicate<float>(coef, 1.0000000000000000e+00f); | ||
| 197 | + AscendC::Reg::FusedMulDstAdd<float>(poly, r, coef, mask); | ||
| 198 | + AscendC::Reg::Adds<int32_t>(biased, nI, kExpBias, mask); | ||
| 199 | + AscendC::Reg::ShiftLefts<int32_t, int16_t>(biased, biased, kExpShift, mask); | ||
| 200 | + AscendC::Reg::Mul<float>(expDw, poly, (AscendC::Reg::RegTensor<float>&)biased, mask); | ||
| 201 | + } else { | ||
| 202 | + // ---- fp16 path: NPU hardware Reg::Exp ---- | ||
| 203 | + // fp16 tolerance (1e-3) is 100× more lenient than fp32 (1e-5), | ||
| 204 | + // so the hardware exp's ~1 ULP error is well within tolerance. | ||
| 205 | + // Using the same vexp instruction family as np.exp reduces | ||
| 206 | + // ULP divergence at near-zero outputs (catastrophic cancellation). | ||
| 207 | + AscendC::Reg::Exp<float>(expDw, dw, mask); | ||
| 208 | + } | ||
| 209 | + // Override for ±Inf and |dw| beyond valid exp range (both paths). | ||
| 210 | + AscendC::Reg::Select(expDw, infReg, expDw, ovfMask); // dw >= 89 → +Inf | ||
| 211 | + AscendC::Reg::Select(expDw, zeroReg, expDw, udfMask); // dw <= -88 → 0 | ||
| 212 | + AscendC::Reg::Select(expDw, infReg, expDw, infMask); // dw == +Inf → +Inf | ||
| 213 | + AscendC::Reg::Select(expDw, zeroReg, expDw, ninfMask); // dw == -Inf → 0 | ||
| 214 | + AscendC::Reg::Mul<float>(gw, pw, expDw, mask); | ||
| 215 | + AscendC::Reg::Mul<float>(tmp, pw, dx, mask); | ||
| 216 | + AscendC::Reg::Add<float>(gx, pcx, tmp, mask); | ||
| 217 | + AscendC::Reg::StoreAlign(gwOut + off, gw, mask); | ||
| 218 | + AscendC::Reg::StoreAlign(gxOut + off, gx, mask); | ||
| 219 | + } | ||
| 220 | +} | ||
| 221 | + | ||
| 222 | +// ========================================================================= | ||
| 223 | +// VF 4: BoxClipVF<T> — clip(gx+halfSign*gw+offset, clipLo, clipHi) → outCh | ||
| 224 | +// Loads fp32 gw/gx from calc, clips, casts to T on store (fp16 downcast). | ||
| 225 | +// DESIGN §5.2 S3d/e/S3i/j. clipLo=0.0f (clipped_non_negative invariant). | ||
| 226 | +// ========================================================================= | ||
| 227 | +template <typename T> | ||
| 228 | +__simd_vf__ inline void BoxClipVF(__ubuf__ T* outCh, __ubuf__ float* gwIn, __ubuf__ float* gxIn, float halfSign, | ||
| 229 | + float offset, float clipLo, float clipHi, uint32_t count, uint16_t repeatTime) | ||
| 230 | +{ | ||
| 231 | + uint32_t remaining = count; | ||
| 232 | + for (uint16_t i = 0; i < repeatTime; ++i) { | ||
| 233 | + uint32_t off = static_cast<uint32_t>(i) * VL_F32; | ||
| 234 | + AscendC::Reg::MaskReg mask = AscendC::Reg::UpdateMask<float>(remaining); | ||
| 235 | + AscendC::Reg::RegTensor<float> gw, gx, tmp, loReg, hiReg, out; | ||
| 236 | + AscendC::Reg::MaskReg nanMask; | ||
| 237 | + AscendC::Reg::LoadAlign(gw, gwIn + off); | ||
| 238 | + AscendC::Reg::LoadAlign(gx, gxIn + off); | ||
| 239 | + AscendC::Reg::Duplicate(loReg, clipLo); | ||
| 240 | + AscendC::Reg::Duplicate(hiReg, clipHi); | ||
| 241 | + AscendC::Reg::Muls<float>(tmp, gw, halfSign, mask); | ||
| 242 | + AscendC::Reg::Add<float>(tmp, gx, tmp, mask); | ||
| 243 | + AscendC::Reg::Adds<float>(tmp, tmp, offset, mask); | ||
| 244 | + AscendC::Reg::Max<float>(tmp, tmp, loReg, mask); | ||
| 245 | + AscendC::Reg::Min<float>(out, tmp, hiReg, mask); | ||
| 246 | + // NaN→0: extreme anchor_box (±3.4e38) causes Inf-Inf=NaN in coordinate | ||
| 247 | + // computation. Max/Min propagate NaN on NPU. Replace NaN with clipLo (0) | ||
| 248 | + // to satisfy clipped_non_negative invariant (DESIGN §4.3). | ||
| 249 | + // IEEE 754: NaN==NaN is false → EQ mask is false for NaN → Select picks loReg. | ||
| 250 | + AscendC::Reg::Compare<float, AscendC::CMPMODE::EQ>(nanMask, out, out, mask); | ||
| 251 | + AscendC::Reg::Select(out, out, loReg, nanMask); | ||
| 252 | + if constexpr (std::is_same_v<T, half>) { | ||
| 253 | + AscendC::Reg::RegTensor<half> hOut; | ||
| 254 | + AscendC::Reg::Cast<half, float, kCastB322B16>(hOut, out, mask); | ||
| 255 | + AscendC::Reg::StoreAlign<half, AscendC::Reg::StoreDist::DIST_PACK_B32>(outCh + off, hOut, mask); | ||
| 256 | + } else { | ||
| 257 | + AscendC::Reg::StoreAlign(outCh + off, out, mask); | ||
| 258 | + } | ||
| 259 | + } | ||
| 260 | +} | ||
| 261 | + | ||
| 262 | +// ========================================================================= | ||
| 263 | +// Kernel Class | ||
| 264 | +// buf_[0]: B_anchor [4, ubFormer] channel-contiguous (T) | ||
| 265 | +// buf_[1]: B_deltas [4, ubFormer] channel-contiguous (T) | ||
| 266 | +// buf_[2]: B_calc0 [4, ubFormer] fp32 (fp16 only; slots pw|pcx|gw|gx) | ||
| 267 | +// buf_[3]: B_calc1 [4, ubFormer] fp32 (fp16 only; slots dx|dw|..) | ||
| 268 | +// buf_[4]: B_boxes [4, ubFormer] channel-contiguous (T) | ||
| 269 | +// fp32 path: buf_[2]/buf_[3] not allocated; calc aliases IO views (K=0). | ||
| 270 | +// ========================================================================= | ||
| 271 | +template <typename T> | ||
| 272 | +class BoundingBoxDecodeKernel { | ||
| 273 | +public: | ||
| 274 | + __aicore__ inline void Init(GM_ADDR anchor_box, GM_ADDR deltas, GM_ADDR boxes, | ||
| 275 | + const BoundingBoxDecodeTilingData* td) | ||
| 276 | + { | ||
| 277 | + td_ = td; | ||
| 278 | + // Empty-tensor short-circuit (DESIGN-BRANCH-1 §3/§5, DESIGN §10.4): | ||
| 279 | + // dim0==0 (N==0) returns early, skipping all buffer allocation and | ||
| 280 | + // GM setup — no CopyIn/Compute/CopyOut, no UB occupancy. | ||
| 281 | + // (was compile-time kIsEmpty; changed to runtime check to fix aclnn | ||
| 282 | + // e2e tiling buffer allocation failure — see struct.h comment.) | ||
| 283 | + if (td_->dim0 == 0) { | ||
| 284 | + return; | ||
| 285 | + } | ||
| 286 | + gmIn_[0].SetGlobalBuffer((__gm__ T*)anchor_box); | ||
| 287 | + gmIn_[1].SetGlobalBuffer((__gm__ T*)deltas); | ||
| 288 | + gmOut_[0].SetGlobalBuffer((__gm__ T*)boxes); | ||
| 289 | + | ||
| 290 | + const int64_t cap = td_->ubFormer; // full tile capacity (box count) | ||
| 291 | + const int64_t ioBytes = cap * kElemsPerBox * sizeof(T); | ||
| 292 | + const int64_t calcBytes = cap * kElemsPerBox * sizeof(float); | ||
| 293 | + pipe_.InitBuffer(buf_[0], static_cast<uint32_t>(ioBytes)); | ||
| 294 | + pipe_.InitBuffer(buf_[1], static_cast<uint32_t>(ioBytes)); | ||
| 295 | + if constexpr (std::is_same_v<T, half>) { | ||
| 296 | + pipe_.InitBuffer(buf_[2], static_cast<uint32_t>(calcBytes)); | ||
| 297 | + pipe_.InitBuffer(buf_[3], static_cast<uint32_t>(calcBytes)); | ||
| 298 | + } | ||
| 299 | + pipe_.InitBuffer(buf_[4], static_cast<uint32_t>(ioBytes)); | ||
| 300 | + } | ||
| 301 | + | ||
| 302 | + __aicore__ inline void Process() | ||
| 303 | + { | ||
| 304 | + // Empty-tensor short-circuit (DESIGN-BRANCH-1 §3/§5, DESIGN §10.3): | ||
| 305 | + // dim0==0 (N==0) returns early — no CopyIn/Compute/CopyOut pipeline. | ||
| 306 | + if (td_->dim0 == 0) { | ||
| 307 | + return; | ||
| 308 | + } | ||
| 309 | + const int64_t blockIdx = AscendC::GetBlockIdx(); | ||
| 310 | + // 512-box alignment in ComputeMultiCoreSplit can make blockNum < coreNum; | ||
| 311 | + // idle cores (blockIdx >= blockNum) have no valid data — return early to | ||
| 312 | + // avoid GM OOB read/write beyond tensor bounds. | ||
| 313 | + if (blockIdx >= td_->blockNum) { | ||
| 314 | + return; | ||
| 315 | + } | ||
| 316 | + const int64_t isLastBlock = (blockIdx == td_->blockNum - 1); | ||
| 317 | + const int64_t boxBase = blockIdx * td_->blockFormer; | ||
| 318 | + const int64_t loopNum = isLastBlock ? td_->ubLoopOfTailBlock : td_->ubLoopOfFormerBlock; | ||
| 319 | + const int64_t tailNum = isLastBlock ? td_->ubTailOfTailBlock : td_->ubTailOfFormerBlock; | ||
| 320 | + | ||
| 321 | + int64_t offset = 0; | ||
| 322 | + for (int64_t i = 0; i < loopNum - 1; ++i) { | ||
| 323 | + ProcessTile(boxBase + offset, td_->ubFormer); | ||
| 324 | + offset += td_->ubFormer; | ||
| 325 | + } | ||
| 326 | + if (tailNum > 0) { | ||
| 327 | + ProcessTile(boxBase + offset, tailNum); | ||
| 328 | + } | ||
| 329 | + } | ||
| 330 | + | ||
| 331 | +private: | ||
| 332 | + __aicore__ inline void ProcessTile(int64_t boxOffset, int64_t boxCount) | ||
| 333 | + { | ||
| 334 | + // ===== CopyIn: NDDMA 2D stride gather, 4 channels × 2 inputs ===== | ||
| 335 | + // DESIGN §3.2 / §10.7. GM [N,4] interleaved → UB [4,N] ch-contiguous. | ||
| 336 | + // blockCount=boxCount, blockLen=sizeof(T), srcStride=(4-1)*sizeof(T) bytes, | ||
| 337 | + // dstStride=0 (UB contiguous packing). Channel view stride = ubFormer. | ||
| 338 | + CopyInChannels(buf_[0], gmIn_[0], boxOffset, boxCount); | ||
| 339 | + CopyInChannels(buf_[1], gmIn_[1], boxOffset, boxCount); | ||
| 340 | + AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(0); | ||
| 341 | + AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(0); | ||
| 342 | + | ||
| 343 | + // ===== Compute: x-chain (ch0,ch2) then y-chain (ch1,ch3) ===== | ||
| 344 | + ProcessAxis(boxCount, 0, 2, td_->stds[0], td_->stds[2], td_->means[0], td_->means[2], | ||
| 345 | + static_cast<float>(td_->maxShapeW)); | ||
| 346 | + ProcessAxis(boxCount, 1, 3, td_->stds[1], td_->stds[3], td_->means[1], td_->means[3], | ||
| 347 | + static_cast<float>(td_->maxShapeH)); | ||
| 348 | + | ||
| 349 | + // ===== CopyOut: 2D stride scatter, 4 channels → GM [N,4] ===== | ||
| 350 | + AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(0); | ||
| 351 | + AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(0); | ||
| 352 | + CopyOutChannels(buf_[4], gmOut_[0], boxOffset, boxCount); | ||
| 353 | + AscendC::SetFlag<AscendC::HardEvent::MTE3_MTE2>(0); | ||
| 354 | + AscendC::WaitFlag<AscendC::HardEvent::MTE3_MTE2>(0); | ||
| 355 | + } | ||
| 356 | + | ||
| 357 | + // One axis (x or y): chLo/chHi are the two channels for this axis. | ||
| 358 | + __aicore__ inline void ProcessAxis(int64_t boxCount, int32_t chLo, int32_t chHi, float stdsLo, float stdsHi, | ||
| 359 | + float meansLo, float meansHi, float clipHi) | ||
| 360 | + { | ||
| 361 | + const uint32_t cap = static_cast<uint32_t>(td_->ubFormer); | ||
| 362 | + const uint32_t count = static_cast<uint32_t>(boxCount); | ||
| 363 | + const uint16_t rep = static_cast<uint16_t>((count + VL_F32 - 1) / VL_F32); | ||
| 364 | + | ||
| 365 | + __ubuf__ T* aBase = (__ubuf__ T*)buf_[0].Get<T>().GetPhyAddr(); | ||
| 366 | + __ubuf__ T* dBase = (__ubuf__ T*)buf_[1].Get<T>().GetPhyAddr(); | ||
| 367 | + __ubuf__ T* oBase = (__ubuf__ T*)buf_[4].Get<T>().GetPhyAddr(); | ||
| 368 | + | ||
| 369 | + // Channel views (stride = ubFormer for 32B alignment). | ||
| 370 | + __ubuf__ T* aChLo = aBase + static_cast<uint64_t>(chLo) * cap; | ||
| 371 | + __ubuf__ T* aChHi = aBase + static_cast<uint64_t>(chHi) * cap; | ||
| 372 | + __ubuf__ T* dChLo = dBase + static_cast<uint64_t>(chLo) * cap; | ||
| 373 | + __ubuf__ T* dChHi = dBase + static_cast<uint64_t>(chHi) * cap; | ||
| 374 | + | ||
| 375 | + // Calc slot pointers. | ||
| 376 | + __ubuf__ float* pwOut; | ||
| 377 | + __ubuf__ float* pcxOut; | ||
| 378 | + __ubuf__ float* dxOut; | ||
| 379 | + __ubuf__ float* dwOut; | ||
| 380 | + __ubuf__ float* gwIn; | ||
| 381 | + __ubuf__ float* gxIn; | ||
| 382 | + if constexpr (std::is_same_v<T, half>) { | ||
| 383 | + // fp16: separate fp32 calc buffers. 4 slots in c0 (pw|pcx|gw|gx), 2 in c1 (dx|dw). | ||
| 384 | + __ubuf__ float* c0 = (__ubuf__ float*)buf_[2].Get<float>().GetPhyAddr(); | ||
| 385 | + __ubuf__ float* c1 = (__ubuf__ float*)buf_[3].Get<float>().GetPhyAddr(); | ||
| 386 | + pwOut = c0 + 0 * cap; | ||
| 387 | + pcxOut = c0 + 1 * cap; | ||
| 388 | + dxOut = c1 + 0 * cap; | ||
| 389 | + dwOut = c1 + 1 * cap; | ||
| 390 | + gwIn = c0 + 2 * cap; | ||
| 391 | + gxIn = c0 + 3 * cap; | ||
| 392 | + } else { | ||
| 393 | + // fp32: calc aliases IO buffer views (K=0, no separate calc TBuf). | ||
| 394 | + // pw→a_chLo, pcx→a_chHi, dx→d_chLo, dw→d_chHi; gw reuses pw slot, gx reuses pcx slot. | ||
| 395 | + pwOut = (__ubuf__ float*)aChLo; | ||
| 396 | + pcxOut = (__ubuf__ float*)aChHi; | ||
| 397 | + dxOut = (__ubuf__ float*)dChLo; | ||
| 398 | + dwOut = (__ubuf__ float*)dChHi; | ||
| 399 | + gwIn = (__ubuf__ float*)aChLo; | ||
| 400 | + gxIn = (__ubuf__ float*)aChHi; | ||
| 401 | + } | ||
| 402 | + | ||
| 403 | + // S3a/S3f: anchor preprocess → pw, pcx | ||
| 404 | + asc_vf_call<AnchorPreVF<T>>(pwOut, pcxOut, aChLo, aChHi, count, rep); | ||
| 405 | + // S3b/S3g: deltas de-standardize → dx, dw | ||
| 406 | + asc_vf_call<DeltaDeStdVF<T>>(dxOut, dwOut, dChLo, dChHi, stdsLo, stdsHi, meansLo, meansHi, count, rep); | ||
| 407 | + // S3c/S3h: decode gw, gx (reads pw,pcx,dx,dw; writes gw,gx) | ||
| 408 | + asc_vf_call<DecodeGwGxVF<T>>(gwIn, gxIn, pwOut, pcxOut, dxOut, dwOut, count, rep); | ||
| 409 | + // S3d: ox1/oy1 = clip(gx - gw*0.5 + 0.5, 0, clipHi) → B_boxes chLo | ||
| 410 | + asc_vf_call<BoxClipVF<T>>(oBase + static_cast<uint64_t>(chLo) * cap, gwIn, gxIn, -0.5f, 0.5f, 0.0f, clipHi, | ||
| 411 | + count, rep); | ||
| 412 | + // S3e: ox2/oy2 = clip(gx + gw*0.5 - 0.5, 0, clipHi) → B_boxes chHi | ||
| 413 | + asc_vf_call<BoxClipVF<T>>(oBase + static_cast<uint64_t>(chHi) * cap, gwIn, gxIn, 0.5f, -0.5f, 0.0f, clipHi, | ||
| 414 | + count, rep); | ||
| 415 | + } | ||
| 416 | + | ||
| 417 | + // NDDMA 2D stride gather: GM [N,4] interleaved → UB [4,N] ch-contiguous. | ||
| 418 | + // 4 DataCopyPad calls, one per channel. dst channel view stride = ubFormer. | ||
| 419 | + // PaddingMode::Compact packs sub-32B blocks contiguously in UB (Normal mode | ||
| 420 | + // would 32B-align each block, breaking channel-contiguous layout). | ||
| 421 | + __aicore__ inline void CopyInChannels(AscendC::TBuf<AscendC::TPosition::VECCALC>& buf, AscendC::GlobalTensor<T>& gm, | ||
| 422 | + int64_t boxOffset, int64_t boxCount) | ||
| 423 | + { | ||
| 424 | + AscendC::DataCopyExtParams params(static_cast<uint16_t>(boxCount), static_cast<uint32_t>(sizeof(T)), | ||
| 425 | + static_cast<int64_t>((kElemsPerBox - 1) * sizeof(T)), // srcStride bytes (GM) | ||
| 426 | + 0, // dstStride 0 (UB contiguous) | ||
| 427 | + 0); | ||
| 428 | + AscendC::DataCopyPadExtParams<T> pad(false, 0, 0, 0); | ||
| 429 | + const uint32_t cap = static_cast<uint32_t>(td_->ubFormer); | ||
| 430 | + for (int32_t c = 0; c < kElemsPerBox; ++c) { | ||
| 431 | + AscendC::DataCopyPad<T, AscendC::PaddingMode::Compact>( | ||
| 432 | + buf.Get<T>()[static_cast<uint32_t>(c) * cap], gm[static_cast<uint64_t>(boxOffset * kElemsPerBox + c)], | ||
| 433 | + params, pad); | ||
| 434 | + } | ||
| 435 | + } | ||
| 436 | + | ||
| 437 | + // MTE3 2D stride scatter: UB [4,N] ch-contiguous → GM [N,4] interleaved. | ||
| 438 | + // 4 DataCopyPad calls, one per channel. src channel view stride = ubFormer. | ||
| 439 | + // PaddingMode::Compact reads sub-32B blocks contiguously from UB. | ||
| 440 | + __aicore__ inline void CopyOutChannels(AscendC::TBuf<AscendC::TPosition::VECCALC>& buf, | ||
| 441 | + AscendC::GlobalTensor<T>& gm, int64_t boxOffset, int64_t boxCount) | ||
| 442 | + { | ||
| 443 | + AscendC::DataCopyExtParams params(static_cast<uint16_t>(boxCount), static_cast<uint32_t>(sizeof(T)), | ||
| 444 | + 0, // srcStride 0 (UB contiguous) | ||
| 445 | + static_cast<int64_t>((kElemsPerBox - 1) * sizeof(T)), // dstStride bytes (GM) | ||
| 446 | + 0); | ||
| 447 | + const uint32_t cap = static_cast<uint32_t>(td_->ubFormer); | ||
| 448 | + for (int32_t c = 0; c < kElemsPerBox; ++c) { | ||
| 449 | + AscendC::DataCopyPad<T, AscendC::PaddingMode::Compact>( | ||
| 450 | + gm[static_cast<uint64_t>(boxOffset * kElemsPerBox + c)], buf.Get<T>()[static_cast<uint32_t>(c) * cap], | ||
| 451 | + params); | ||
| 452 | + } | ||
| 453 | + } | ||
| 454 | + | ||
| 455 | + AscendC::TPipe pipe_; | ||
| 456 | + const BoundingBoxDecodeTilingData* td_; | ||
| 457 | + AscendC::GlobalTensor<T> gmIn_[kMaxInputSlots]; | ||
| 458 | + AscendC::GlobalTensor<T> gmOut_[kMaxOutputSlots]; | ||
| 459 | + AscendC::TBuf<AscendC::TPosition::VECCALC> buf_[kPhysNodes]; | ||
| 460 | +}; | ||
| 461 | + | ||
| 462 | + | ||
| @@ -0,0 +1,41 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +// DataType numeric constants (match ge::DataType enum values) | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +// --------------------------------------------------------------------------- | ||
| 21 | +// TPL parameter declarations | ||
| 22 | +// T : DATATYPE, selectable from {FP16, FP32} | ||
| 23 | +// | ||
| 24 | +// NOTE: ASCENDC_TPL_DATATYPE_* (not ASCENDC_TPL_DTYPE_*) is used so that | ||
| 25 | +// the codegen emits TypeFromId<N>::type as the template argument, which | ||
| 26 | +// resolves to the C++ type (half / float) and matches the | ||
| 27 | +// `template <typename T>` kernel signature in proto.md. | ||
| 28 | +// ASCENDC_TPL_DTYPE_* would emit raw integers, only matching `int T`. | ||
| 29 | +// --------------------------------------------------------------------------- | ||
| 30 | +ASCENDC_TPL_ARGS_DECL(BoundingBoxDecode, | ||
| 31 | + ASCENDC_TPL_DATATYPE_DECL(T, BOUNDING_BOX_DECODE_TPL_FP16, BOUNDING_BOX_DECODE_TPL_FP32)); | ||
| 32 | + | ||
| 33 | +// --------------------------------------------------------------------------- | ||
| 34 | +// TPL specialisations — tilingKey = T_value | ||
| 35 | +// (T=FP32) → tilingKey = 0 (fp32, handles both normal and empty at runtime) | ||
| 36 | +// (T=FP16) → tilingKey = 1 (fp16, handles both normal and empty at runtime) | ||
| 37 | +// --------------------------------------------------------------------------- | ||
| 38 | +ASCENDC_TPL_SEL(ASCENDC_TPL_ARGS_SEL(ASCENDC_TPL_DATATYPE_SEL(T, BOUNDING_BOX_DECODE_TPL_FP16)), | ||
| 39 | + ASCENDC_TPL_ARGS_SEL(ASCENDC_TPL_DATATYPE_SEL(T, BOUNDING_BOX_DECODE_TPL_FP32))); | ||
| 40 | + | ||
| 41 | + | ||
| @@ -0,0 +1,43 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +// bounding_box_decode TilingData — Elementwise 按 box 数切分(tiling.md §四/§七)+ 属性标量 | ||
| 17 | +// 非模板:固定 rank=2,无 broadcast,无 Group;IS_EMPTY 属 TilingKey(§6)不进本结构 | ||
| 18 | +constexpr int64_t kElemsPerBox = 4; // C=4,每 box 4 元素 (x1,y1,x2,y2) / (dx',dy',dw',dh') | ||
| 19 | + | ||
| 20 | +struct BoundingBoxDecodeTilingData { | ||
| 21 | + // —— 多核切分(按 box 数,§9 多核切分;tiling.md §一/§七)—— 单位均为 box 数(除 coreNum 为核数) | ||
| 22 | + int64_t dim0; // box 总数 N(= anchor_box.shape[0];非元素数,元素数 = dim0 × kElemsPerBox) | ||
| 23 | + int32_t coreNum; // 实际参与核数 = min(CeilDiv(dim0×minDtypeBits, MIN_TILING_BITS), availableCoreNum) | ||
| 24 | + int64_t blockFormer; // 每核基础 box 数(512 box 对齐,ELEM_ALIGN_FACTOR=512) | ||
| 25 | + int64_t blockNum; // 虚拟 block 数 = CeilDiv(dim0, blockFormer) | ||
| 26 | + // —— UB 切分(按 box 数,§9 UB 切分;tiling.md §二/§七)—— 单位均为 box 数 | ||
| 27 | + int64_t ubFormer; // 每 UB 块基础 box 数(256B 对齐;alignFactor = 256 / (kElemsPerBox × sizeof(T)),fp16=32 box / | ||
| 28 | + // fp32=16 box) | ||
| 29 | + int64_t ubLoopOfFormerBlock; // 首 block 的 UB 循环次数 = CeilDiv(blockFormer, ubFormer) | ||
| 30 | + int64_t ubTailOfFormerBlock; // 首 block 尾部 box 数 = blockFormer - (ubLoopOfFormerBlock-1)×ubFormer | ||
| 31 | + int64_t ubLoopOfTailBlock; // 尾 block 的 UB 循环次数 = CeilDiv(blockTail, ubFormer) | ||
| 32 | + int64_t ubTailOfTailBlock; // 尾 block 尾部 box 数 = blockTail - (ubLoopOfTailBlock-1)×ubFormer | ||
| 33 | + // —— 属性标量(aclnn 传入,kernel Compute 消费)—— | ||
| 34 | + float means[4]; // deltas 反标准化均值 m0..m3(spec.yaml attributes.means,默认 0) | ||
| 35 | + float stds[4]; // deltas 反标准化标准差 s0..s3(各元素 ≠ 0,Host 校验保证;默认 1) | ||
| 36 | + int64_t maxShapeH; // max_shape[0] = H,y 维度 (y1_out/y2_out) 裁剪上界 | ||
| 37 | + int64_t maxShapeW; // max_shape[1] = W,x 维度 (x1_out/x2_out) 裁剪上界 | ||
| 38 | + // 注:wh_ratio_clip 不参与核心公式(§1.3),不进 TilingData | ||
| 39 | + // 注:IS_EMPTY 不进 TilingData(属 TilingKey 模板参数,§6) | ||
| 40 | + // 注:empty 路径(IS_EMPTY=true)kernel 短路,上述计算字段填 0 不被消费 | ||
| 41 | +}; | ||
| 42 | + | ||
| 43 | + | ||
| @@ -0,0 +1,16 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| @@ -0,0 +1,50 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +template <typename T> | ||
| 17 | +__global__ __aicore__ void bounding_box_decode(GM_ADDR anchor_box, GM_ADDR deltas, GM_ADDR boxes, GM_ADDR workspace, | ||
| 18 | + GM_ADDR tiling) | ||
| 19 | +{ | ||
| 20 | + // §10.1: TilingData registration + task type (pure Vector AIV_ONLY) | ||
| 21 | + REGISTER_TILING_DEFAULT(BoundingBoxDecodeTilingData); | ||
| 22 | + GET_TILING_DATA_WITH_STRUCT(BoundingBoxDecodeTilingData, td, tiling); | ||
| 23 | + | ||
| 24 | + // §10.1: instantiate kernel class and run | ||
| 25 | + BoundingBoxDecodeKernel<T> kernel; | ||
| 26 | + kernel.Init(anchor_box, deltas, boxes, &td); | ||
| 27 | + kernel.Process(); | ||
| 28 | + | ||
| 29 | + (void)workspace; // workspaceSize=0 (DESIGN §9.6, no cross-core partial merge) | ||
| 30 | +} | ||
| 31 | + | ||
| 32 | +// [REF_SAMPLE] --- original sample kernel logic (element-wise add) --- | ||
| 33 | +// The block below is the reference sample implementation from the AddCustom | ||
| 34 | +// template, preserved for traceability. | ||
| 35 | + | ||
| 36 | + AscendC::InitSocState(); | ||
| 37 | + | ||
| 38 | + REGISTER_TILING_DEFAULT(BoundingBoxDecodeTilingData); | ||
| 39 | + | ||
| 40 | + GET_TILING_DATA(tilingData, tiling); | ||
| 41 | + | ||
| 42 | + KernelBoundingBoxDecode<DTYPE_X> op; | ||
| 43 | + | ||
| 44 | + op.Init(x, y, z, tilingData.totalLength, tilingData.blockLength, tilingData.tileLength); | ||
| 45 | + | ||
| 46 | + op.Process(); | ||
| 47 | + | ||
| 48 | + AscendC::PipeBarrier<PIPE_ALL>(); | ||
| 49 | + | ||
| 50 | +// [REF_SAMPLE] --- end --- | ||
| @@ -0,0 +1,9 @@ | |||
| 1 | +file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 2 | +if(NOT (UT_TEST_ALL OR OP_HOST_UT OR OP_API_UT OR OP_KERNEL_UT)) | ||
| 3 | + list(REMOVE_ITEM CURRENT_DIRS ut) | ||
| 4 | +endif() | ||
| 5 | +foreach(SUB_DIR ${CURRENT_DIRS}) | ||
| 6 | + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}/CMakeLists.txt") | ||
| 7 | + add_subdirectory(${SUB_DIR}) | ||
| 8 | + endif() | ||
| 9 | +endforeach() | ||
| @@ -0,0 +1,142 @@ | |||
| 1 | +#!/usr/bin/env python3 | ||
| 2 | +# -*- coding: utf-8 -*- | ||
| 3 | +# Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 4 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 5 | +# CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 6 | +# Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 7 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 8 | +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 9 | +# See LICENSE in the root of the software repository for the full text of the License. | ||
| 10 | +# ---------------------------------------------------------------------------- | ||
| 11 | + | ||
| 12 | +import numpy as np | ||
| 13 | +import torch | ||
| 14 | + | ||
| 15 | +__spec__ = {"bounding_box_decode": "BoundingBoxDecodeTestSpec"} | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +class BoundingBoxDecodeTestSpec: | ||
| 19 | + """bounding_box_decode 算子测试规范(kernel 流程) | ||
| 20 | + | ||
| 21 | + golden 和 third_party 均用 torch 算子拼接实现,供 cross_check 交叉比对 | ||
| 22 | + """ | ||
| 23 | + | ||
| 24 | + def golden( | ||
| 25 | + anchor_box, | ||
| 26 | + deltas, | ||
| 27 | + *, | ||
| 28 | + max_shape, | ||
| 29 | + means=(0.0, 0.0, 0.0, 0.0), | ||
| 30 | + stds=(1.0, 1.0, 1.0, 1.0), | ||
| 31 | + wh_ratio_clip=0.016, | ||
| 32 | + **kwargs, | ||
| 33 | + ): | ||
| 34 | + x_dtype = anchor_box.dtype | ||
| 35 | + | ||
| 36 | + means = [float(v) for v in means] | ||
| 37 | + stds = [float(v) for v in stds] | ||
| 38 | + max_h = float(max_shape[0]) | ||
| 39 | + max_w = float(max_shape[1]) | ||
| 40 | + | ||
| 41 | + a = torch.from_numpy(anchor_box.astype(np.float32)) | ||
| 42 | + d = torch.from_numpy(deltas.astype(np.float32)) | ||
| 43 | + | ||
| 44 | + a_x1, a_y1, a_x2, a_y2 = a[:, 0], a[:, 1], a[:, 2], a[:, 3] | ||
| 45 | + dx_in, dy_in, dw_in, dh_in = d[:, 0], d[:, 1], d[:, 2], d[:, 3] | ||
| 46 | + | ||
| 47 | + pw = a_x2 - a_x1 + 1.0 | ||
| 48 | + ph = a_y2 - a_y1 + 1.0 | ||
| 49 | + pcx = (a_x1 + a_x2) * 0.5 | ||
| 50 | + pcy = (a_y1 + a_y2) * 0.5 | ||
| 51 | + | ||
| 52 | + dx = dx_in * stds[0] + means[0] | ||
| 53 | + dy = dy_in * stds[1] + means[1] | ||
| 54 | + dw = dw_in * stds[2] + means[2] | ||
| 55 | + dh = dh_in * stds[3] + means[3] | ||
| 56 | + | ||
| 57 | + gw = pw * torch.exp(dw) | ||
| 58 | + gh = ph * torch.exp(dh) | ||
| 59 | + gx = pcx + pw * dx | ||
| 60 | + gy = pcy + ph * dy | ||
| 61 | + | ||
| 62 | + ox1 = gx - gw * 0.5 + 0.5 | ||
| 63 | + oy1 = gy - gh * 0.5 + 0.5 | ||
| 64 | + ox2 = gx + gw * 0.5 - 0.5 | ||
| 65 | + oy2 = gy + gh * 0.5 - 0.5 | ||
| 66 | + | ||
| 67 | + ox1 = torch.nan_to_num(ox1, nan=0.0, posinf=max_w, neginf=0.0) | ||
| 68 | + oy1 = torch.nan_to_num(oy1, nan=0.0, posinf=max_h, neginf=0.0) | ||
| 69 | + ox2 = torch.nan_to_num(ox2, nan=0.0, posinf=max_w, neginf=0.0) | ||
| 70 | + oy2 = torch.nan_to_num(oy2, nan=0.0, posinf=max_h, neginf=0.0) | ||
| 71 | + ox1 = torch.clamp(ox1, 0.0, max_w) | ||
| 72 | + oy1 = torch.clamp(oy1, 0.0, max_h) | ||
| 73 | + ox2 = torch.clamp(ox2, 0.0, max_w) | ||
| 74 | + oy2 = torch.clamp(oy2, 0.0, max_h) | ||
| 75 | + | ||
| 76 | + boxes = torch.stack([ox1, oy1, ox2, oy2], dim=1) | ||
| 77 | + return [boxes.numpy().astype(x_dtype)] | ||
| 78 | + | ||
| 79 | + class TorchImpl: | ||
| 80 | + """torch 算子拼接实现:用 torch.exp + torch.clamp + torch.nan_to_num 拼接解码公式。""" | ||
| 81 | + | ||
| 82 | + def __init__( | ||
| 83 | + self, | ||
| 84 | + *, | ||
| 85 | + max_shape, | ||
| 86 | + means=(0.0, 0.0, 0.0, 0.0), | ||
| 87 | + stds=(1.0, 1.0, 1.0, 1.0), | ||
| 88 | + wh_ratio_clip=0.016, | ||
| 89 | + **kwargs, | ||
| 90 | + ): | ||
| 91 | + self.max_h = float(max_shape[0]) | ||
| 92 | + self.max_w = float(max_shape[1]) | ||
| 93 | + self.means = [float(v) for v in means] | ||
| 94 | + self.stds = [float(v) for v in stds] | ||
| 95 | + | ||
| 96 | + def __call__(self, anchor_box, deltas, **kwargs): | ||
| 97 | + a = anchor_box.to(torch.float32) | ||
| 98 | + d = deltas.to(torch.float32) | ||
| 99 | + | ||
| 100 | + a_x1, a_y1, a_x2, a_y2 = a[:, 0], a[:, 1], a[:, 2], a[:, 3] | ||
| 101 | + dx_in, dy_in, dw_in, dh_in = d[:, 0], d[:, 1], d[:, 2], d[:, 3] | ||
| 102 | + | ||
| 103 | + pw = a_x2 - a_x1 + 1.0 | ||
| 104 | + ph = a_y2 - a_y1 + 1.0 | ||
| 105 | + pcx = (a_x1 + a_x2) * 0.5 | ||
| 106 | + pcy = (a_y1 + a_y2) * 0.5 | ||
| 107 | + | ||
| 108 | + dx = dx_in * self.stds[0] + self.means[0] | ||
| 109 | + dy = dy_in * self.stds[1] + self.means[1] | ||
| 110 | + dw = dw_in * self.stds[2] + self.means[2] | ||
| 111 | + dh = dh_in * self.stds[3] + self.means[3] | ||
| 112 | + | ||
| 113 | + gw = pw * torch.exp(dw) | ||
| 114 | + gh = ph * torch.exp(dh) | ||
| 115 | + gx = pcx + pw * dx | ||
| 116 | + gy = pcy + ph * dy | ||
| 117 | + | ||
| 118 | + ox1 = gx - gw * 0.5 + 0.5 | ||
| 119 | + oy1 = gy - gh * 0.5 + 0.5 | ||
| 120 | + ox2 = gx + gw * 0.5 - 0.5 | ||
| 121 | + oy2 = gy + gh * 0.5 - 0.5 | ||
| 122 | + | ||
| 123 | + ox1 = torch.nan_to_num(ox1, nan=0.0, posinf=self.max_w, neginf=0.0) | ||
| 124 | + oy1 = torch.nan_to_num(oy1, nan=0.0, posinf=self.max_h, neginf=0.0) | ||
| 125 | + ox2 = torch.nan_to_num(ox2, nan=0.0, posinf=self.max_w, neginf=0.0) | ||
| 126 | + oy2 = torch.nan_to_num(oy2, nan=0.0, posinf=self.max_h, neginf=0.0) | ||
| 127 | + ox1 = torch.clamp(ox1, 0.0, self.max_w) | ||
| 128 | + oy1 = torch.clamp(oy1, 0.0, self.max_h) | ||
| 129 | + ox2 = torch.clamp(ox2, 0.0, self.max_w) | ||
| 130 | + oy2 = torch.clamp(oy2, 0.0, self.max_h) | ||
| 131 | + | ||
| 132 | + boxes = torch.stack([ox1, oy1, ox2, oy2], dim=1) | ||
| 133 | + return [boxes.to(anchor_box.dtype)] | ||
| 134 | + | ||
| 135 | + third_party = { | ||
| 136 | + "torch": TorchImpl, | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + tolerance = { | ||
| 140 | + "float32": {"standard": "stat_rel_err"}, | ||
| 141 | + "float16": {"standard": "stat_rel_err"}, | ||
| 142 | + } | ||
| @@ -0,0 +1,12 @@ | |||
| 1 | +file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 2 | +if(NOT (UT_TEST_ALL OR OP_HOST_UT OR OP_API_UT)) | ||
| 3 | + list(REMOVE_ITEM CURRENT_DIRS op_host) | ||
| 4 | +endif() | ||
| 5 | +if(NOT (UT_TEST_ALL OR OP_KERNEL_UT)) | ||
| 6 | + list(REMOVE_ITEM CURRENT_DIRS op_kernel) | ||
| 7 | +endif() | ||
| 8 | +foreach(SUB_DIR ${CURRENT_DIRS}) | ||
| 9 | + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}/CMakeLists.txt") | ||
| 10 | + add_subdirectory(${SUB_DIR}) | ||
| 11 | + endif() | ||
| 12 | +endforeach() | ||
| @@ -0,0 +1,6 @@ | |||
| 1 | +if(UT_TEST_ALL OR OP_HOST_UT) | ||
| 2 | + if("${ASCEND_COMPUTE_UNIT}" STREQUAL "ascend950") | ||
| 3 | + add_modules_ut_sources(UT_NAME ${OP_TILING_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR}/arch35) | ||
| 4 | + endif() | ||
| 5 | + add_modules_ut_sources(UT_NAME ${OP_INFERSHAPE_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR}) | ||
| 6 | +endif() | ||
| @@ -0,0 +1,359 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/* Generated By CANNBot */ | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +using namespace std; | ||
| 20 | +using namespace ge; | ||
| 21 | + | ||
| 22 | +class BoundingBoxDecodeTiling : public testing::Test { | ||
| 23 | +protected: | ||
| 24 | + static void SetUpTestCase() { std::cout << "BoundingBoxDecodeTiling SetUp" << std::endl; } | ||
| 25 | + | ||
| 26 | + static void TearDownTestCase() { std::cout << "BoundingBoxDecodeTiling TearDown" << std::endl; } | ||
| 27 | +}; | ||
| 28 | + | ||
| 29 | +std::map<std::string, std::string> soc_versions_infos = {{"Short_SoC_version", "Ascend950"}}; | ||
| 30 | + | ||
| 31 | +constexpr size_t BBD_SYS_WORKSPACE_SIZE = 16777216; | ||
| 32 | + | ||
| 33 | +TEST_F(BoundingBoxDecodeTiling, bbd_fp32_normal) | ||
| 34 | +{ | ||
| 35 | + struct BoundingBoxDecodeCompileInfo { | ||
| 36 | + } compileInfo; | ||
| 37 | + gert::TilingContextPara tilingContextPara( | ||
| 38 | + "BoundingBoxDecode", | ||
| 39 | + { | ||
| 40 | + {{{8, 4}, {8, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 41 | + {{{8, 4}, {8, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 42 | + }, | ||
| 43 | + { | ||
| 44 | + {{{8, 4}, {8, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 45 | + }, | ||
| 46 | + { | ||
| 47 | + gert::TilingContextPara::OpAttr( | ||
| 48 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 49 | + gert::TilingContextPara::OpAttr( | ||
| 50 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 51 | + gert::TilingContextPara::OpAttr("max_shape", | ||
| 52 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({768, 1280})), | ||
| 53 | + gert::TilingContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 54 | + }, | ||
| 55 | + &compileInfo, "Ascend950", 64, 262144, 4096); | ||
| 56 | + uint64_t expectTilingKey = 0; | ||
| 57 | + ExecuteTestCase(tilingContextPara, ge::GRAPH_SUCCESS, expectTilingKey, | ||
| 58 | + "8 1 512 1 5280 1 512 1 8 0 0 4575657222473777152 4575657222473777152 768 1280 ", {0}); | ||
| 59 | +} | ||
| 60 | + | ||
| 61 | +TEST_F(BoundingBoxDecodeTiling, bbd_fp16_normal) | ||
| 62 | +{ | ||
| 63 | + struct BoundingBoxDecodeCompileInfo { | ||
| 64 | + } compileInfo; | ||
| 65 | + gert::TilingContextPara tilingContextPara( | ||
| 66 | + "BoundingBoxDecode", | ||
| 67 | + { | ||
| 68 | + {{{8, 4}, {8, 4}}, ge::DT_FLOAT16, ge::FORMAT_ND}, | ||
| 69 | + {{{8, 4}, {8, 4}}, ge::DT_FLOAT16, ge::FORMAT_ND}, | ||
| 70 | + }, | ||
| 71 | + { | ||
| 72 | + {{{8, 4}, {8, 4}}, ge::DT_FLOAT16, ge::FORMAT_ND}, | ||
| 73 | + }, | ||
| 74 | + { | ||
| 75 | + gert::TilingContextPara::OpAttr( | ||
| 76 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 77 | + gert::TilingContextPara::OpAttr( | ||
| 78 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 79 | + gert::TilingContextPara::OpAttr("max_shape", | ||
| 80 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({768, 1280})), | ||
| 81 | + gert::TilingContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 82 | + }, | ||
| 83 | + &compileInfo, "Ascend950", 64, 262144, 4096); | ||
| 84 | + uint64_t expectTilingKey = 1; | ||
| 85 | + ExecuteTestCase(tilingContextPara, ge::GRAPH_SUCCESS, expectTilingKey, | ||
| 86 | + "8 1 512 1 4512 1 512 1 8 0 0 4575657222473777152 4575657222473777152 768 1280 ", {0}); | ||
| 87 | +} | ||
| 88 | + | ||
| 89 | +TEST_F(BoundingBoxDecodeTiling, bbd_fp32_empty) | ||
| 90 | +{ | ||
| 91 | + struct BoundingBoxDecodeCompileInfo { | ||
| 92 | + } compileInfo; | ||
| 93 | + gert::TilingContextPara tilingContextPara( | ||
| 94 | + "BoundingBoxDecode", | ||
| 95 | + { | ||
| 96 | + {{{0, 4}, {0, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 97 | + {{{0, 4}, {0, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 98 | + }, | ||
| 99 | + { | ||
| 100 | + {{{0, 4}, {0, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 101 | + }, | ||
| 102 | + { | ||
| 103 | + gert::TilingContextPara::OpAttr( | ||
| 104 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 105 | + gert::TilingContextPara::OpAttr( | ||
| 106 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 107 | + gert::TilingContextPara::OpAttr("max_shape", | ||
| 108 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({768, 1280})), | ||
| 109 | + gert::TilingContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 110 | + }, | ||
| 111 | + &compileInfo, "Ascend950", 64, 262144, 4096); | ||
| 112 | + uint64_t expectTilingKey = 0; | ||
| 113 | + ExecuteTestCase(tilingContextPara, ge::GRAPH_SUCCESS, expectTilingKey, | ||
| 114 | + "0 1 0 1 0 0 0 0 0 0 0 4575657222473777152 4575657222473777152 768 1280 ", {0}); | ||
| 115 | +} | ||
| 116 | + | ||
| 117 | +TEST_F(BoundingBoxDecodeTiling, bbd_fp16_empty) | ||
| 118 | +{ | ||
| 119 | + struct BoundingBoxDecodeCompileInfo { | ||
| 120 | + } compileInfo; | ||
| 121 | + gert::TilingContextPara tilingContextPara( | ||
| 122 | + "BoundingBoxDecode", | ||
| 123 | + { | ||
| 124 | + {{{0, 4}, {0, 4}}, ge::DT_FLOAT16, ge::FORMAT_ND}, | ||
| 125 | + {{{0, 4}, {0, 4}}, ge::DT_FLOAT16, ge::FORMAT_ND}, | ||
| 126 | + }, | ||
| 127 | + { | ||
| 128 | + {{{0, 4}, {0, 4}}, ge::DT_FLOAT16, ge::FORMAT_ND}, | ||
| 129 | + }, | ||
| 130 | + { | ||
| 131 | + gert::TilingContextPara::OpAttr( | ||
| 132 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 133 | + gert::TilingContextPara::OpAttr( | ||
| 134 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 135 | + gert::TilingContextPara::OpAttr("max_shape", | ||
| 136 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({768, 1280})), | ||
| 137 | + gert::TilingContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 138 | + }, | ||
| 139 | + &compileInfo, "Ascend950", 64, 262144, 4096); | ||
| 140 | + uint64_t expectTilingKey = 1; | ||
| 141 | + ExecuteTestCase(tilingContextPara, ge::GRAPH_SUCCESS, expectTilingKey, | ||
| 142 | + "0 1 0 1 0 0 0 0 0 0 0 4575657222473777152 4575657222473777152 768 1280 ", {0}); | ||
| 143 | +} | ||
| 144 | + | ||
| 145 | +TEST_F(BoundingBoxDecodeTiling, bbd_fp32_non_default_attr) | ||
| 146 | +{ | ||
| 147 | + struct BoundingBoxDecodeCompileInfo { | ||
| 148 | + } compileInfo; | ||
| 149 | + gert::TilingContextPara tilingContextPara( | ||
| 150 | + "BoundingBoxDecode", | ||
| 151 | + { | ||
| 152 | + {{{16, 4}, {16, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 153 | + {{{16, 4}, {16, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 154 | + }, | ||
| 155 | + { | ||
| 156 | + {{{16, 4}, {16, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 157 | + }, | ||
| 158 | + { | ||
| 159 | + gert::TilingContextPara::OpAttr( | ||
| 160 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({-4.0f, -4.0f, -1.0f, -1.0f})), | ||
| 161 | + gert::TilingContextPara::OpAttr( | ||
| 162 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.1f, 0.1f, 0.2f, 0.2f})), | ||
| 163 | + gert::TilingContextPara::OpAttr("max_shape", | ||
| 164 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({1080, 1920})), | ||
| 165 | + gert::TilingContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.967f)), | ||
| 166 | + }, | ||
| 167 | + &compileInfo, "Ascend950", 64, 262144, 4096); | ||
| 168 | + uint64_t expectTilingKey = 0; | ||
| 169 | + ExecuteTestCase(tilingContextPara, ge::GRAPH_SUCCESS, expectTilingKey, | ||
| 170 | + "16 1 512 1 5280 1 512 1 16 -4575657218178809856 -4647714812233515008 4453159313439771853 " | ||
| 171 | + "4489188110467124429 1080 1920 ", | ||
| 172 | + {0}); | ||
| 173 | +} | ||
| 174 | + | ||
| 175 | +TEST_F(BoundingBoxDecodeTiling, bbd_fp32_large_multicore) | ||
| 176 | +{ | ||
| 177 | + struct BoundingBoxDecodeCompileInfo { | ||
| 178 | + } compileInfo; | ||
| 179 | + gert::TilingContextPara tilingContextPara( | ||
| 180 | + "BoundingBoxDecode", | ||
| 181 | + { | ||
| 182 | + {{{100000, 4}, {100000, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 183 | + {{{100000, 4}, {100000, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 184 | + }, | ||
| 185 | + { | ||
| 186 | + {{{100000, 4}, {100000, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 187 | + }, | ||
| 188 | + { | ||
| 189 | + gert::TilingContextPara::OpAttr( | ||
| 190 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 191 | + gert::TilingContextPara::OpAttr( | ||
| 192 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 193 | + gert::TilingContextPara::OpAttr("max_shape", | ||
| 194 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({1080, 1920})), | ||
| 195 | + gert::TilingContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 196 | + }, | ||
| 197 | + &compileInfo, "Ascend950", 64, 262144, 4096); | ||
| 198 | + uint64_t expectTilingKey = 0; | ||
| 199 | + ExecuteTestCase(tilingContextPara, ge::GRAPH_SUCCESS, expectTilingKey, | ||
| 200 | + "100000 49 2048 49 5280 1 2048 1 1696 0 0 4575657222473777152 4575657222473777152 1080 1920 ", {0}); | ||
| 201 | +} | ||
| 202 | + | ||
| 203 | +TEST_F(BoundingBoxDecodeTiling, bbd_fp16_nonaligned) | ||
| 204 | +{ | ||
| 205 | + struct BoundingBoxDecodeCompileInfo { | ||
| 206 | + } compileInfo; | ||
| 207 | + gert::TilingContextPara tilingContextPara( | ||
| 208 | + "BoundingBoxDecode", | ||
| 209 | + { | ||
| 210 | + {{{33, 4}, {33, 4}}, ge::DT_FLOAT16, ge::FORMAT_ND}, | ||
| 211 | + {{{33, 4}, {33, 4}}, ge::DT_FLOAT16, ge::FORMAT_ND}, | ||
| 212 | + }, | ||
| 213 | + { | ||
| 214 | + {{{33, 4}, {33, 4}}, ge::DT_FLOAT16, ge::FORMAT_ND}, | ||
| 215 | + }, | ||
| 216 | + { | ||
| 217 | + gert::TilingContextPara::OpAttr( | ||
| 218 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 219 | + gert::TilingContextPara::OpAttr( | ||
| 220 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 221 | + gert::TilingContextPara::OpAttr("max_shape", | ||
| 222 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({768, 1280})), | ||
| 223 | + gert::TilingContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 224 | + }, | ||
| 225 | + &compileInfo, "Ascend950", 64, 262144, 4096); | ||
| 226 | + uint64_t expectTilingKey = 1; | ||
| 227 | + ExecuteTestCase(tilingContextPara, ge::GRAPH_SUCCESS, expectTilingKey, | ||
| 228 | + "33 1 512 1 4512 1 512 1 33 0 0 4575657222473777152 4575657222473777152 768 1280 ", {0}); | ||
| 229 | +} | ||
| 230 | + | ||
| 231 | +TEST_F(BoundingBoxDecodeTiling, bbd_invalid_rank1) | ||
| 232 | +{ | ||
| 233 | + struct BoundingBoxDecodeCompileInfo { | ||
| 234 | + } compileInfo; | ||
| 235 | + gert::TilingContextPara tilingContextPara( | ||
| 236 | + "BoundingBoxDecode", | ||
| 237 | + { | ||
| 238 | + {{{8}, {8}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 239 | + {{{8}, {8}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 240 | + }, | ||
| 241 | + { | ||
| 242 | + {{{8}, {8}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 243 | + }, | ||
| 244 | + { | ||
| 245 | + gert::TilingContextPara::OpAttr( | ||
| 246 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 247 | + gert::TilingContextPara::OpAttr( | ||
| 248 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 249 | + gert::TilingContextPara::OpAttr("max_shape", | ||
| 250 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({768, 1280})), | ||
| 251 | + gert::TilingContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 252 | + }, | ||
| 253 | + &compileInfo, "Ascend950", 64, 262144, 4096); | ||
| 254 | + ExecuteTestCase(tilingContextPara, ge::GRAPH_FAILED); | ||
| 255 | +} | ||
| 256 | + | ||
| 257 | +TEST_F(BoundingBoxDecodeTiling, bbd_invalid_last_dim) | ||
| 258 | +{ | ||
| 259 | + struct BoundingBoxDecodeCompileInfo { | ||
| 260 | + } compileInfo; | ||
| 261 | + gert::TilingContextPara tilingContextPara( | ||
| 262 | + "BoundingBoxDecode", | ||
| 263 | + { | ||
| 264 | + {{{8, 3}, {8, 3}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 265 | + {{{8, 3}, {8, 3}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 266 | + }, | ||
| 267 | + { | ||
| 268 | + {{{8, 3}, {8, 3}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 269 | + }, | ||
| 270 | + { | ||
| 271 | + gert::TilingContextPara::OpAttr( | ||
| 272 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 273 | + gert::TilingContextPara::OpAttr( | ||
| 274 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 275 | + gert::TilingContextPara::OpAttr("max_shape", | ||
| 276 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({768, 1280})), | ||
| 277 | + gert::TilingContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 278 | + }, | ||
| 279 | + &compileInfo, "Ascend950", 64, 262144, 4096); | ||
| 280 | + ExecuteTestCase(tilingContextPara, ge::GRAPH_FAILED); | ||
| 281 | +} | ||
| 282 | + | ||
| 283 | +TEST_F(BoundingBoxDecodeTiling, bbd_invalid_shape_mismatch) | ||
| 284 | +{ | ||
| 285 | + struct BoundingBoxDecodeCompileInfo { | ||
| 286 | + } compileInfo; | ||
| 287 | + gert::TilingContextPara tilingContextPara( | ||
| 288 | + "BoundingBoxDecode", | ||
| 289 | + { | ||
| 290 | + {{{8, 4}, {8, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 291 | + {{{16, 4}, {16, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 292 | + }, | ||
| 293 | + { | ||
| 294 | + {{{8, 4}, {8, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 295 | + }, | ||
| 296 | + { | ||
| 297 | + gert::TilingContextPara::OpAttr( | ||
| 298 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 299 | + gert::TilingContextPara::OpAttr( | ||
| 300 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 301 | + gert::TilingContextPara::OpAttr("max_shape", | ||
| 302 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({768, 1280})), | ||
| 303 | + gert::TilingContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 304 | + }, | ||
| 305 | + &compileInfo, "Ascend950", 64, 262144, 4096); | ||
| 306 | + ExecuteTestCase(tilingContextPara, ge::GRAPH_FAILED); | ||
| 307 | +} | ||
| 308 | + | ||
| 309 | +TEST_F(BoundingBoxDecodeTiling, bbd_invalid_dtype_int64) | ||
| 310 | +{ | ||
| 311 | + struct BoundingBoxDecodeCompileInfo { | ||
| 312 | + } compileInfo; | ||
| 313 | + gert::TilingContextPara tilingContextPara( | ||
| 314 | + "BoundingBoxDecode", | ||
| 315 | + { | ||
| 316 | + {{{8, 4}, {8, 4}}, ge::DT_INT64, ge::FORMAT_ND}, | ||
| 317 | + {{{8, 4}, {8, 4}}, ge::DT_INT64, ge::FORMAT_ND}, | ||
| 318 | + }, | ||
| 319 | + { | ||
| 320 | + {{{8, 4}, {8, 4}}, ge::DT_INT64, ge::FORMAT_ND}, | ||
| 321 | + }, | ||
| 322 | + { | ||
| 323 | + gert::TilingContextPara::OpAttr( | ||
| 324 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 325 | + gert::TilingContextPara::OpAttr( | ||
| 326 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 327 | + gert::TilingContextPara::OpAttr("max_shape", | ||
| 328 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({768, 1280})), | ||
| 329 | + gert::TilingContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 330 | + }, | ||
| 331 | + &compileInfo, "Ascend950", 64, 262144, 4096); | ||
| 332 | + ExecuteTestCase(tilingContextPara, ge::GRAPH_FAILED); | ||
| 333 | +} | ||
| 334 | + | ||
| 335 | +TEST_F(BoundingBoxDecodeTiling, bbd_invalid_dtype_mismatch) | ||
| 336 | +{ | ||
| 337 | + struct BoundingBoxDecodeCompileInfo { | ||
| 338 | + } compileInfo; | ||
| 339 | + gert::TilingContextPara tilingContextPara( | ||
| 340 | + "BoundingBoxDecode", | ||
| 341 | + { | ||
| 342 | + {{{8, 4}, {8, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 343 | + {{{8, 4}, {8, 4}}, ge::DT_FLOAT16, ge::FORMAT_ND}, | ||
| 344 | + }, | ||
| 345 | + { | ||
| 346 | + {{{8, 4}, {8, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 347 | + }, | ||
| 348 | + { | ||
| 349 | + gert::TilingContextPara::OpAttr( | ||
| 350 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 351 | + gert::TilingContextPara::OpAttr( | ||
| 352 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 353 | + gert::TilingContextPara::OpAttr("max_shape", | ||
| 354 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({768, 1280})), | ||
| 355 | + gert::TilingContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 356 | + }, | ||
| 357 | + &compileInfo, "Ascend950", 64, 262144, 4096); | ||
| 358 | + ExecuteTestCase(tilingContextPara, ge::GRAPH_FAILED); | ||
| 359 | +} | ||
| @@ -0,0 +1,259 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/* Generated By CANNBot */ | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +class BoundingBoxDecodeInfershape : public testing::Test { | ||
| 19 | +protected: | ||
| 20 | + static void SetUpTestCase() { std::cout << "BoundingBoxDecodeInfershape SetUp" << std::endl; } | ||
| 21 | + | ||
| 22 | + static void TearDownTestCase() { std::cout << "BoundingBoxDecodeInfershape TearDown" << std::endl; } | ||
| 23 | +}; | ||
| 24 | + | ||
| 25 | +TEST_F(BoundingBoxDecodeInfershape, bbd_fp32_normal) | ||
| 26 | +{ | ||
| 27 | + gert::InfershapeContextPara infershapeContextPara( | ||
| 28 | + "BoundingBoxDecode", | ||
| 29 | + { | ||
| 30 | + {{{8, 4}, {8, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 31 | + {{{8, 4}, {8, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 32 | + }, | ||
| 33 | + { | ||
| 34 | + {{{}, {}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 35 | + }, | ||
| 36 | + { | ||
| 37 | + gert::InfershapeContextPara::OpAttr( | ||
| 38 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 39 | + gert::InfershapeContextPara::OpAttr( | ||
| 40 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 41 | + gert::InfershapeContextPara::OpAttr("max_shape", | ||
| 42 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({768, 1280})), | ||
| 43 | + gert::InfershapeContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 44 | + }); | ||
| 45 | + std::vector<std::vector<int64_t>> expectOutputShape = {{8, 4}}; | ||
| 46 | + ExecuteTestCase(infershapeContextPara, ge::GRAPH_SUCCESS, expectOutputShape); | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +TEST_F(BoundingBoxDecodeInfershape, bbd_fp16_normal) | ||
| 50 | +{ | ||
| 51 | + gert::InfershapeContextPara infershapeContextPara( | ||
| 52 | + "BoundingBoxDecode", | ||
| 53 | + { | ||
| 54 | + {{{8, 4}, {8, 4}}, ge::DT_FLOAT16, ge::FORMAT_ND}, | ||
| 55 | + {{{8, 4}, {8, 4}}, ge::DT_FLOAT16, ge::FORMAT_ND}, | ||
| 56 | + }, | ||
| 57 | + { | ||
| 58 | + {{{}, {}}, ge::DT_FLOAT16, ge::FORMAT_ND}, | ||
| 59 | + }, | ||
| 60 | + { | ||
| 61 | + gert::InfershapeContextPara::OpAttr( | ||
| 62 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 63 | + gert::InfershapeContextPara::OpAttr( | ||
| 64 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 65 | + gert::InfershapeContextPara::OpAttr("max_shape", | ||
| 66 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({768, 1280})), | ||
| 67 | + gert::InfershapeContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 68 | + }); | ||
| 69 | + std::vector<std::vector<int64_t>> expectOutputShape = {{8, 4}}; | ||
| 70 | + ExecuteTestCase(infershapeContextPara, ge::GRAPH_SUCCESS, expectOutputShape); | ||
| 71 | +} | ||
| 72 | + | ||
| 73 | +TEST_F(BoundingBoxDecodeInfershape, bbd_fp32_empty) | ||
| 74 | +{ | ||
| 75 | + gert::InfershapeContextPara infershapeContextPara( | ||
| 76 | + "BoundingBoxDecode", | ||
| 77 | + { | ||
| 78 | + {{{0, 4}, {0, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 79 | + {{{0, 4}, {0, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 80 | + }, | ||
| 81 | + { | ||
| 82 | + {{{}, {}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 83 | + }, | ||
| 84 | + { | ||
| 85 | + gert::InfershapeContextPara::OpAttr( | ||
| 86 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 87 | + gert::InfershapeContextPara::OpAttr( | ||
| 88 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 89 | + gert::InfershapeContextPara::OpAttr("max_shape", | ||
| 90 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({768, 1280})), | ||
| 91 | + gert::InfershapeContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 92 | + }); | ||
| 93 | + std::vector<std::vector<int64_t>> expectOutputShape = {{0, 4}}; | ||
| 94 | + ExecuteTestCase(infershapeContextPara, ge::GRAPH_SUCCESS, expectOutputShape); | ||
| 95 | +} | ||
| 96 | + | ||
| 97 | +TEST_F(BoundingBoxDecodeInfershape, bbd_fp32_non_default_attr) | ||
| 98 | +{ | ||
| 99 | + gert::InfershapeContextPara infershapeContextPara( | ||
| 100 | + "BoundingBoxDecode", | ||
| 101 | + { | ||
| 102 | + {{{16, 4}, {16, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 103 | + {{{16, 4}, {16, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 104 | + }, | ||
| 105 | + { | ||
| 106 | + {{{}, {}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 107 | + }, | ||
| 108 | + { | ||
| 109 | + gert::InfershapeContextPara::OpAttr( | ||
| 110 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({-4.0f, -4.0f, -1.0f, -1.0f})), | ||
| 111 | + gert::InfershapeContextPara::OpAttr( | ||
| 112 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.1f, 0.1f, 0.2f, 0.2f})), | ||
| 113 | + gert::InfershapeContextPara::OpAttr("max_shape", | ||
| 114 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({1080, 1920})), | ||
| 115 | + gert::InfershapeContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.967f)), | ||
| 116 | + }); | ||
| 117 | + std::vector<std::vector<int64_t>> expectOutputShape = {{16, 4}}; | ||
| 118 | + ExecuteTestCase(infershapeContextPara, ge::GRAPH_SUCCESS, expectOutputShape); | ||
| 119 | +} | ||
| 120 | + | ||
| 121 | +TEST_F(BoundingBoxDecodeInfershape, bbd_fp32_large) | ||
| 122 | +{ | ||
| 123 | + gert::InfershapeContextPara infershapeContextPara( | ||
| 124 | + "BoundingBoxDecode", | ||
| 125 | + { | ||
| 126 | + {{{100000, 4}, {100000, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 127 | + {{{100000, 4}, {100000, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 128 | + }, | ||
| 129 | + { | ||
| 130 | + {{{}, {}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 131 | + }, | ||
| 132 | + { | ||
| 133 | + gert::InfershapeContextPara::OpAttr( | ||
| 134 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 135 | + gert::InfershapeContextPara::OpAttr( | ||
| 136 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 137 | + gert::InfershapeContextPara::OpAttr("max_shape", | ||
| 138 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({1080, 1920})), | ||
| 139 | + gert::InfershapeContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 140 | + }); | ||
| 141 | + std::vector<std::vector<int64_t>> expectOutputShape = {{100000, 4}}; | ||
| 142 | + ExecuteTestCase(infershapeContextPara, ge::GRAPH_SUCCESS, expectOutputShape); | ||
| 143 | +} | ||
| 144 | + | ||
| 145 | +TEST_F(BoundingBoxDecodeInfershape, bbd_invalid_rank1) | ||
| 146 | +{ | ||
| 147 | + gert::InfershapeContextPara infershapeContextPara( | ||
| 148 | + "BoundingBoxDecode", | ||
| 149 | + { | ||
| 150 | + {{{8}, {8}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 151 | + {{{8}, {8}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 152 | + }, | ||
| 153 | + { | ||
| 154 | + {{{}, {}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 155 | + }, | ||
| 156 | + { | ||
| 157 | + gert::InfershapeContextPara::OpAttr( | ||
| 158 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 159 | + gert::InfershapeContextPara::OpAttr( | ||
| 160 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 161 | + gert::InfershapeContextPara::OpAttr("max_shape", | ||
| 162 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({768, 1280})), | ||
| 163 | + gert::InfershapeContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 164 | + }); | ||
| 165 | + ExecuteTestCase(infershapeContextPara, ge::GRAPH_FAILED); | ||
| 166 | +} | ||
| 167 | + | ||
| 168 | +TEST_F(BoundingBoxDecodeInfershape, bbd_invalid_rank3) | ||
| 169 | +{ | ||
| 170 | + gert::InfershapeContextPara infershapeContextPara( | ||
| 171 | + "BoundingBoxDecode", | ||
| 172 | + { | ||
| 173 | + {{{8, 4, 1}, {8, 4, 1}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 174 | + {{{8, 4, 1}, {8, 4, 1}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 175 | + }, | ||
| 176 | + { | ||
| 177 | + {{{}, {}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 178 | + }, | ||
| 179 | + { | ||
| 180 | + gert::InfershapeContextPara::OpAttr( | ||
| 181 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 182 | + gert::InfershapeContextPara::OpAttr( | ||
| 183 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 184 | + gert::InfershapeContextPara::OpAttr("max_shape", | ||
| 185 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({768, 1280})), | ||
| 186 | + gert::InfershapeContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 187 | + }); | ||
| 188 | + ExecuteTestCase(infershapeContextPara, ge::GRAPH_FAILED); | ||
| 189 | +} | ||
| 190 | + | ||
| 191 | +TEST_F(BoundingBoxDecodeInfershape, bbd_invalid_last_dim) | ||
| 192 | +{ | ||
| 193 | + gert::InfershapeContextPara infershapeContextPara( | ||
| 194 | + "BoundingBoxDecode", | ||
| 195 | + { | ||
| 196 | + {{{8, 3}, {8, 3}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 197 | + {{{8, 3}, {8, 3}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 198 | + }, | ||
| 199 | + { | ||
| 200 | + {{{}, {}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 201 | + }, | ||
| 202 | + { | ||
| 203 | + gert::InfershapeContextPara::OpAttr( | ||
| 204 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 205 | + gert::InfershapeContextPara::OpAttr( | ||
| 206 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 207 | + gert::InfershapeContextPara::OpAttr("max_shape", | ||
| 208 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({768, 1280})), | ||
| 209 | + gert::InfershapeContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 210 | + }); | ||
| 211 | + ExecuteTestCase(infershapeContextPara, ge::GRAPH_FAILED); | ||
| 212 | +} | ||
| 213 | + | ||
| 214 | +TEST_F(BoundingBoxDecodeInfershape, bbd_invalid_shape_mismatch) | ||
| 215 | +{ | ||
| 216 | + gert::InfershapeContextPara infershapeContextPara( | ||
| 217 | + "BoundingBoxDecode", | ||
| 218 | + { | ||
| 219 | + {{{8, 4}, {8, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 220 | + {{{16, 4}, {16, 4}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 221 | + }, | ||
| 222 | + { | ||
| 223 | + {{{}, {}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 224 | + }, | ||
| 225 | + { | ||
| 226 | + gert::InfershapeContextPara::OpAttr( | ||
| 227 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 228 | + gert::InfershapeContextPara::OpAttr( | ||
| 229 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 230 | + gert::InfershapeContextPara::OpAttr("max_shape", | ||
| 231 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({768, 1280})), | ||
| 232 | + gert::InfershapeContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 233 | + }); | ||
| 234 | + ExecuteTestCase(infershapeContextPara, ge::GRAPH_FAILED); | ||
| 235 | +} | ||
| 236 | + | ||
| 237 | +TEST_F(BoundingBoxDecodeInfershape, bbd_unknown_rank) | ||
| 238 | +{ | ||
| 239 | + gert::InfershapeContextPara infershapeContextPara( | ||
| 240 | + "BoundingBoxDecode", | ||
| 241 | + { | ||
| 242 | + {{{-2}, {-2}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 243 | + {{{-2}, {-2}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 244 | + }, | ||
| 245 | + { | ||
| 246 | + {{{}, {}}, ge::DT_FLOAT, ge::FORMAT_ND}, | ||
| 247 | + }, | ||
| 248 | + { | ||
| 249 | + gert::InfershapeContextPara::OpAttr( | ||
| 250 | + "means", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({0.0f, 0.0f, 0.0f, 0.0f})), | ||
| 251 | + gert::InfershapeContextPara::OpAttr( | ||
| 252 | + "stds", Ops::Cv::AnyValue::CreateFrom<std::vector<float>>({1.0f, 1.0f, 1.0f, 1.0f})), | ||
| 253 | + gert::InfershapeContextPara::OpAttr("max_shape", | ||
| 254 | + Ops::Cv::AnyValue::CreateFrom<std::vector<int64_t>>({768, 1280})), | ||
| 255 | + gert::InfershapeContextPara::OpAttr("wh_ratio_clip", Ops::Cv::AnyValue::CreateFrom<float>(0.016f)), | ||
| 256 | + }); | ||
| 257 | + std::vector<std::vector<int64_t>> expectOutputShape = {{-2}}; | ||
| 258 | + ExecuteTestCase(infershapeContextPara, ge::GRAPH_SUCCESS, expectOutputShape); | ||
| 259 | +} | ||


新增算子需同步刷新op_list.md