已合并
fix(bounding_box_encode): add validations in geir path and inferdatatype #1182
zhangyiyi创建于 7月27日
fix(bounding_box_encode): add validations in geir path and inferdatatype #1182
已合并
共 3 个文件变更+184-4
| @@ -0,0 +1,40 @@ | |||
| 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 | + * \file bounding_box_encode_graph_infer.cpp | ||
| 15 | + * \brief BoundingBoxEncode operator graph infer datatype resource | ||
| 16 | + */ | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +namespace ops { | ||
| 22 | +using namespace ge; | ||
| 23 | + | ||
| 24 | +static constexpr int64_t IDX_0 = 0; | ||
| 25 | + | ||
| 26 | +// delats.dtype = anchor_box.dtype | ||
| 27 | +static ge::graphStatus InferDataType4BoundingBoxEncode(gert::InferDataTypeContext* context) | ||
| 28 | +{ | ||
| 29 | + OP_LOGD(context->GetNodeName(), "Begin to do InferDataType4BoundingBoxEncode"); | ||
| 30 | + | ||
| 31 | + ge::DataType anchorBoxDtype = context->GetInputDataType(IDX_0); | ||
| 32 | + context->SetOutputDataType(IDX_0, anchorBoxDtype); | ||
| 33 | + | ||
| 34 | + OP_LOGD(context->GetNodeName(), "End to do InferDataType4BoundingBoxEncode"); | ||
| 35 | + return GRAPH_SUCCESS; | ||
| 36 | +} | ||
| 37 | + | ||
| 38 | +IMPL_OP(BoundingBoxEncode).InferDataType(InferDataType4BoundingBoxEncode); | ||
| 39 | + | ||
| 40 | +} // namespace ops | ||
| @@ -35,6 +35,7 @@ constexpr int64_t NUM_IO_BUFFERS = 3; | |||
| 35 | constexpr int64_t NUM_CALC_BUFFERS = 2; | 35 | constexpr int64_t NUM_CALC_BUFFERS = 2; |
| 36 | constexpr int64_t NUM_TOTAL_BUFFERS = 5; | 36 | constexpr int64_t NUM_TOTAL_BUFFERS = 5; |
| 37 | constexpr int64_t BLOCK_ELEM_THRESHOLD = 32768; | 37 | constexpr int64_t BLOCK_ELEM_THRESHOLD = 32768; |
| 38 | +constexpr size_t MEANS_STDS_LEN = 4; | ||
| 38 | 39 | ||
| 39 | static ge::graphStatus GetWorkspaceSize(gert::TilingContext* context) | 40 | static ge::graphStatus GetWorkspaceSize(gert::TilingContext* context) |
| 40 | { | 41 | { |
| @@ -52,6 +53,11 @@ static ge::graphStatus ParseMeansStds(gert::TilingContext* context, BoundingBoxE | |||
| 52 | const auto* stdsList = attrs->GetListFloat(1); | 53 | const auto* stdsList = attrs->GetListFloat(1); |
| 53 | OP_CHECK_IF(meansList == nullptr || stdsList == nullptr, OP_LOGE(context, "means or stds attr is null"), | 54 | OP_CHECK_IF(meansList == nullptr || stdsList == nullptr, OP_LOGE(context, "means or stds attr is null"), |
| 54 | return ge::GRAPH_FAILED); | 55 | return ge::GRAPH_FAILED); |
| 56 | + // 3a/3b: means and stds length must be exactly 4. Check before reading [0..3] to avoid OOB read. | ||
| 57 | + OP_CHECK_IF(meansList->GetSize() != MEANS_STDS_LEN, | ||
| 58 | + OP_LOGE(context, "means length must be 4, but got %zu", meansList->GetSize()), return ge::GRAPH_FAILED); | ||
| 59 | + OP_CHECK_IF(stdsList->GetSize() != MEANS_STDS_LEN, | ||
| 60 | + OP_LOGE(context, "stds length must be 4, but got %zu", stdsList->GetSize()), return ge::GRAPH_FAILED); | ||
| 55 | const float* means = meansList->GetData(); | 61 | const float* means = meansList->GetData(); |
| 56 | const float* stds = stdsList->GetData(); | 62 | const float* stds = stdsList->GetData(); |
| 57 | OP_CHECK_IF(means == nullptr || stds == nullptr, OP_LOGE(context, "means or stds data is null"), | 63 | OP_CHECK_IF(means == nullptr || stds == nullptr, OP_LOGE(context, "means or stds data is null"), |
| @@ -70,6 +76,69 @@ static ge::graphStatus ParseMeansStds(gert::TilingContext* context, BoundingBoxE | |||
| 70 | return ge::GRAPH_SUCCESS; | 76 | return ge::GRAPH_SUCCESS; |
| 71 | } | 77 | } |
| 72 | 78 | ||
| 79 | +// Shape/dtype consistency checks that the geir path cannot enforce in InferShape: | ||
| 80 | +// the built-in BoundingBoxEncode proto (libopsproto.so) registers a legacy V1 InferShape that | ||
| 81 | +// shadows the custom IMPL_OP_INFERSHAPE, so these README constraints are validated here in tiling, | ||
| 82 | +// which is the custom code path that actually executes. | ||
| 83 | +// 1b: anchor_box.dtype == ground_truth_box.dtype | ||
| 84 | +// 2a: shape[last] == 4 | ||
| 85 | +// 2b: anchor_box.shape == ground_truth_box.shape (exactly) | ||
| 86 | +// 2c: rank == 2 | ||
| 87 | +static ge::graphStatus CheckInputsConsistency(gert::TilingContext* context) | ||
| 88 | +{ | ||
| 89 | + constexpr size_t RANK_2 = 2; | ||
| 90 | + constexpr size_t LAST_DIM_IDX = 1; | ||
| 91 | + constexpr int64_t BOX_COORD_NUM = 4; | ||
| 92 | + | ||
| 93 | + auto anchorShapePtr = context->GetInputShape(0); | ||
| 94 | + OP_CHECK_NULL_WITH_CONTEXT(context, anchorShapePtr); | ||
| 95 | + auto gtShapePtr = context->GetInputShape(1); | ||
| 96 | + OP_CHECK_NULL_WITH_CONTEXT(context, gtShapePtr); | ||
| 97 | + const auto& anchorShape = anchorShapePtr->GetStorageShape(); | ||
| 98 | + const auto& gtShape = gtShapePtr->GetStorageShape(); | ||
| 99 | + | ||
| 100 | + auto anchorDesc = context->GetInputDesc(0); | ||
| 101 | + OP_CHECK_NULL_WITH_CONTEXT(context, anchorDesc); | ||
| 102 | + auto gtDesc = context->GetInputDesc(1); | ||
| 103 | + OP_CHECK_NULL_WITH_CONTEXT(context, gtDesc); | ||
| 104 | + | ||
| 105 | + // 1b: dtype consistency | ||
| 106 | + OP_CHECK_IF(anchorDesc->GetDataType() != gtDesc->GetDataType(), | ||
| 107 | + OP_LOGE(context, "anchor_box dtype (%d) and ground_truth_box dtype (%d) must be the same", | ||
| 108 | + static_cast<int>(anchorDesc->GetDataType()), static_cast<int>(gtDesc->GetDataType())), | ||
| 109 | + return ge::GRAPH_FAILED); | ||
| 110 | + | ||
| 111 | + // 2c: rank == 2 (both inputs) | ||
| 112 | + OP_CHECK_IF(anchorShape.GetDimNum() != RANK_2, | ||
| 113 | + OP_LOGE(context, "anchor_box rank must be 2 (shape (N, 4)), but got rank %zu", anchorShape.GetDimNum()), | ||
| 114 | + return ge::GRAPH_FAILED); | ||
| 115 | + OP_CHECK_IF( | ||
| 116 | + gtShape.GetDimNum() != RANK_2, | ||
| 117 | + OP_LOGE(context, "ground_truth_box rank must be 2 (shape (N, 4)), but got rank %zu", gtShape.GetDimNum()), | ||
| 118 | + return ge::GRAPH_FAILED); | ||
| 119 | + | ||
| 120 | + // 2a: last dim == 4 (both inputs) | ||
| 121 | + OP_CHECK_IF( | ||
| 122 | + anchorShape.GetDim(LAST_DIM_IDX) != BOX_COORD_NUM, | ||
| 123 | + OP_LOGE(context, "anchor_box last dim must be 4 (x1,y1,x2,y2), but got %ld", anchorShape.GetDim(LAST_DIM_IDX)), | ||
| 124 | + return ge::GRAPH_FAILED); | ||
| 125 | + OP_CHECK_IF(gtShape.GetDim(LAST_DIM_IDX) != BOX_COORD_NUM, | ||
| 126 | + OP_LOGE(context, "ground_truth_box last dim must be 4 (x1,y1,x2,y2), but got %ld", | ||
| 127 | + gtShape.GetDim(LAST_DIM_IDX)), | ||
| 128 | + return ge::GRAPH_FAILED); | ||
| 129 | + | ||
| 130 | + // 2b: shape exactly equal (rank already both 2) | ||
| 131 | + for (size_t i = 0; i < RANK_2; ++i) { | ||
| 132 | + OP_CHECK_IF(anchorShape.GetDim(i) != gtShape.GetDim(i), | ||
| 133 | + OP_LOGE(context, | ||
| 134 | + "anchor_box and ground_truth_box shapes must be exactly the same, but dim[%zu] " | ||
| 135 | + "differs (%ld vs %ld)", | ||
| 136 | + i, anchorShape.GetDim(i), gtShape.GetDim(i)), | ||
| 137 | + return ge::GRAPH_FAILED); | ||
| 138 | + } | ||
| 139 | + return ge::GRAPH_SUCCESS; | ||
| 140 | +} | ||
| 141 | + | ||
| 73 | static ge::graphStatus CalcUbSizing(gert::TilingContext* context, BoundingBoxEncodeTilingData* tiling, int64_t dim0, | 142 | static ge::graphStatus CalcUbSizing(gert::TilingContext* context, BoundingBoxEncodeTilingData* tiling, int64_t dim0, |
| 74 | ge::DataType dataType, uint64_t ubSize, int64_t coreNum, int64_t* outCoreNum) | 143 | ge::DataType dataType, uint64_t ubSize, int64_t coreNum, int64_t* outCoreNum) |
| 75 | { | 144 | { |
| @@ -148,6 +217,9 @@ static ge::graphStatus BoundingBoxEncodeTilingFunc(gert::TilingContext* context) | |||
| 148 | const std::set<ge::DataType> supportedDtype = {ge::DT_FLOAT16, ge::DT_FLOAT}; | 217 | const std::set<ge::DataType> supportedDtype = {ge::DT_FLOAT16, ge::DT_FLOAT}; |
| 149 | OP_CHECK_IF(supportedDtype.count(dataType) == 0, OP_LOGE(context, "unsupported dtype"), return ge::GRAPH_FAILED); | 218 | OP_CHECK_IF(supportedDtype.count(dataType) == 0, OP_LOGE(context, "unsupported dtype"), return ge::GRAPH_FAILED); |
| 150 | 219 | ||
| 220 | + OP_CHECK_IF(CheckInputsConsistency(context) != ge::GRAPH_SUCCESS, OP_LOGE(context, "CheckInputsConsistency error"), | ||
| 221 | + return ge::GRAPH_FAILED); | ||
| 222 | + | ||
| 151 | BoundingBoxEncodeTilingData* tiling = context->GetTilingData<BoundingBoxEncodeTilingData>(); | 223 | BoundingBoxEncodeTilingData* tiling = context->GetTilingData<BoundingBoxEncodeTilingData>(); |
| 152 | OP_CHECK_NULL_WITH_CONTEXT(context, tiling); | 224 | OP_CHECK_NULL_WITH_CONTEXT(context, tiling); |
| 153 | OP_CHECK_IF(memset_s(tiling, sizeof(BoundingBoxEncodeTilingData), 0, sizeof(BoundingBoxEncodeTilingData)) != EOK, | 225 | OP_CHECK_IF(memset_s(tiling, sizeof(BoundingBoxEncodeTilingData), 0, sizeof(BoundingBoxEncodeTilingData)) != EOK, |
| @@ -13,20 +13,88 @@ | |||
| 13 | 13 | ||
| 14 | 14 | ||
| 15 | 15 | ||
| 16 | + | ||
| 16 | 17 | ||
| 17 | using namespace ge; | 18 | using namespace ge; |
| 18 | 19 | ||
| 19 | namespace ops { | 20 | namespace ops { |
| 20 | 21 | ||
| 22 | +static constexpr int64_t IDX_ANCHOR = 0; | ||
| 23 | +static constexpr int64_t IDX_GT = 1; | ||
| 24 | +static constexpr int64_t IDX_OUT = 0; | ||
| 25 | +static constexpr size_t RANK_2 = 2; | ||
| 26 | +static constexpr size_t LAST_DIM_IDX = 1; | ||
| 27 | +static constexpr int64_t BOX_COORD_NUM = 4; | ||
| 28 | + | ||
| 29 | +// Validate one box input's shape (rank==2, last dim==4) when the shape is statically known. | ||
| 30 | +// Unknown-rank ([-2]) and unknown-dim (-1) cases are skipped to preserve dynamic-shape support. | ||
| 31 | +static ge::graphStatus CheckBoxShape(gert::InferShapeContext* context, const gert::Shape& shape, const char* name) | ||
| 32 | +{ | ||
| 33 | + if (Ops::Base::IsUnknownRank(shape)) { | ||
| 34 | + return ge::GRAPH_SUCCESS; | ||
| 35 | + } | ||
| 36 | + if (shape.GetDimNum() != RANK_2) { | ||
| 37 | + OP_LOGE(context->GetNodeName(), "%s rank must be 2 (shape (N, 4)), but got rank %zu.", name, shape.GetDimNum()); | ||
| 38 | + return ge::GRAPH_FAILED; | ||
| 39 | + } | ||
| 40 | + int64_t lastDim = shape.GetDim(LAST_DIM_IDX); | ||
| 41 | + if (lastDim != ge::UNKNOWN_DIM && lastDim != BOX_COORD_NUM) { | ||
| 42 | + OP_LOGE(context->GetNodeName(), "%s last dim must be 4 (x1,y1,x2,y2), but got %ld.", name, lastDim); | ||
| 43 | + return ge::GRAPH_FAILED; | ||
| 44 | + } | ||
| 45 | + return ge::GRAPH_SUCCESS; | ||
| 46 | +} | ||
| 47 | + | ||
| 21 | static ge::graphStatus InferShape4BoundingBoxEncode(gert::InferShapeContext* context) | 48 | static ge::graphStatus InferShape4BoundingBoxEncode(gert::InferShapeContext* context) |
| 22 | { | 49 | { |
| 23 | - const gert::Shape* inputShape = context->GetInputShape(0); | 50 | + const gert::Shape* anchorShape = context->GetInputShape(IDX_ANCHOR); |
| 24 | - OP_CHECK_NULL_WITH_CONTEXT(context, inputShape); | 51 | + OP_CHECK_NULL_WITH_CONTEXT(context, anchorShape); |
| 52 | + const gert::Shape* gtShape = context->GetInputShape(IDX_GT); | ||
| 53 | + OP_CHECK_NULL_WITH_CONTEXT(context, gtShape); | ||
| 25 | 54 | ||
| 26 | - gert::Shape* outputShape = context->GetOutputShape(0); | 55 | + gert::Shape* outputShape = context->GetOutputShape(IDX_OUT); |
| 27 | OP_CHECK_NULL_WITH_CONTEXT(context, outputShape); | 56 | OP_CHECK_NULL_WITH_CONTEXT(context, outputShape); |
| 28 | 57 | ||
| 29 | - *outputShape = *inputShape; | 58 | + // 1b: dtype of anchor_box and ground_truth_box must be identical. |
| 59 | + const auto* anchorDesc = context->GetInputDesc(IDX_ANCHOR); | ||
| 60 | + OP_CHECK_NULL_WITH_CONTEXT(context, anchorDesc); | ||
| 61 | + const auto* gtDesc = context->GetInputDesc(IDX_GT); | ||
| 62 | + OP_CHECK_NULL_WITH_CONTEXT(context, gtDesc); | ||
| 63 | + if (anchorDesc->GetDataType() != gtDesc->GetDataType()) { | ||
| 64 | + OP_LOGE(context->GetNodeName(), "anchor_box dtype (%d) and ground_truth_box dtype (%d) must be the same.", | ||
| 65 | + static_cast<int>(anchorDesc->GetDataType()), static_cast<int>(gtDesc->GetDataType())); | ||
| 66 | + return ge::GRAPH_FAILED; | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + // 2c rank==2 and 2a last-dim==4 for each box (guarded for dynamic shape). | ||
| 70 | + if (CheckBoxShape(context, *anchorShape, "anchor_box") != ge::GRAPH_SUCCESS) { | ||
| 71 | + return ge::GRAPH_FAILED; | ||
| 72 | + } | ||
| 73 | + if (CheckBoxShape(context, *gtShape, "ground_truth_box") != ge::GRAPH_SUCCESS) { | ||
| 74 | + return ge::GRAPH_FAILED; | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + // 2b: anchor_box and ground_truth_box shapes must be exactly the same (compare known dims only). | ||
| 78 | + if (!Ops::Base::IsUnknownRank(*anchorShape) && !Ops::Base::IsUnknownRank(*gtShape)) { | ||
| 79 | + if (anchorShape->GetDimNum() != gtShape->GetDimNum()) { | ||
| 80 | + OP_LOGE(context->GetNodeName(), "anchor_box rank (%zu) and ground_truth_box rank (%zu) must be the same.", | ||
| 81 | + anchorShape->GetDimNum(), gtShape->GetDimNum()); | ||
| 82 | + return ge::GRAPH_FAILED; | ||
| 83 | + } | ||
| 84 | + for (size_t i = 0; i < anchorShape->GetDimNum(); ++i) { | ||
| 85 | + int64_t aDim = anchorShape->GetDim(i); | ||
| 86 | + int64_t gDim = gtShape->GetDim(i); | ||
| 87 | + if (aDim != ge::UNKNOWN_DIM && gDim != ge::UNKNOWN_DIM && aDim != gDim) { | ||
| 88 | + OP_LOGE(context->GetNodeName(), | ||
| 89 | + "anchor_box and ground_truth_box shapes must be exactly the same, but dim[%zu] differs " | ||
| 90 | + "(%ld vs %ld).", | ||
| 91 | + i, aDim, gDim); | ||
| 92 | + return ge::GRAPH_FAILED; | ||
| 93 | + } | ||
| 94 | + } | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + *outputShape = *anchorShape; | ||
| 30 | return ge::GRAPH_SUCCESS; | 98 | return ge::GRAPH_SUCCESS; |
| 31 | } | 99 | } |
| 32 | 100 | ||