Fix boxes dim calculation when scores dynamic rank (#19097)
* Fix boxes dim calculation when scores dynamic rank * NMS shape infer improve upper bound calculation * Calculate boxes if required shapes has static rank * Optimize shape_infer for NMS v4 * Reorder checks in nms v4 for selected boxes
This commit is contained in:
1 parent
29ad3e8c92
commit
2e78eec502
3 files changed
+71
-41
No files matched your search
@@ -115,7 +115,7 @@ std::vector<TRShape> shape_infer(const Node* op,
|
||||
const auto& boxes_shape = input_shapes[0];
|
||||
const auto& scores_shape = input_shapes[1];
|
||||
|
||||
auto output_shapes = std::vector<TRShape>{TRShape{TDim(-1), 3}};
|
||||
auto output_shapes = std::vector<TRShape>{TRShape{TDim(dim::inf_bound), 3}};
|
||||
if (boxes_shape.rank().is_static()) {
|
||||
const auto max_out_boxes_per_class = get_input_const_data_as<TRShape, int64_t>(op, 2, ta);
|
||||
auto max_out_class_boxes =
|
||||
@@ -147,6 +147,7 @@ std::vector<TRShape> shape_infer(const Node* op,
|
||||
NODE_VALIDATION_CHECK(op, cmp::Between<size_t>(1, 7)(inputs_size));
|
||||
using TDim = typename TRShape::value_type;
|
||||
using V = typename TDim::value_type;
|
||||
using namespace ov::util;
|
||||
|
||||
nms::validate::boxes_shape(op, input_shapes);
|
||||
nms::validate::scores_shape(op, input_shapes);
|
||||
@@ -180,44 +181,31 @@ std::vector<TRShape> shape_infer(const Node* op,
|
||||
}
|
||||
|
||||
const auto& boxes_shape = input_shapes[0];
|
||||
const auto& scores_shape = input_shapes[1];
|
||||
const auto boxes_rank = boxes_shape.rank();
|
||||
const auto scores_rank = scores_shape.rank();
|
||||
|
||||
auto out_shape = TRShape{TDim(-1), 3};
|
||||
if (boxes_rank.is_static()) {
|
||||
int64_t max_out_boxes_per_class_val;
|
||||
if (const auto max_out_boxes_per_class = get_input_const_data_as<TRShape, int64_t>(op, 2, ta)) {
|
||||
max_out_boxes_per_class_val = max_out_boxes_per_class->front();
|
||||
} else {
|
||||
max_out_boxes_per_class_val = -1;
|
||||
}
|
||||
const auto& num_boxes = boxes_shape[1];
|
||||
auto& selected_boxes = out_shape[0];
|
||||
if (num_boxes.is_static()) {
|
||||
const auto min_selected_boxes =
|
||||
std::min(num_boxes.get_length(), static_cast<V>(max_out_boxes_per_class_val));
|
||||
selected_boxes = static_output ? TDim{min_selected_boxes} : TDim{0, min_selected_boxes};
|
||||
} else if (scores_rank.is_static() && num_boxes.get_max_length() != -1 &&
|
||||
scores_shape[0].get_max_length() != -1 && scores_shape[1].get_max_length() != -1) {
|
||||
const auto min_selected_boxes =
|
||||
std::min(num_boxes.get_max_length(), static_cast<V>(max_out_boxes_per_class_val));
|
||||
selected_boxes = static_output ? TDim{min_selected_boxes} : TDim{0, min_selected_boxes};
|
||||
}
|
||||
auto out_shape = TRShape{TDim(dim::inf_bound), 3};
|
||||
if (boxes_shape.rank().is_static()) {
|
||||
const auto& scores_shape = input_shapes[1];
|
||||
|
||||
if (scores_rank.is_static()) {
|
||||
if (scores_shape.rank().is_static()) {
|
||||
nms::validate::num_batches(op, input_shapes);
|
||||
nms::validate::num_boxes(op, input_shapes);
|
||||
|
||||
auto& selected_boxes = out_shape[0];
|
||||
if (const auto max_out_boxes_per_class = get_input_const_data_as<TRShape, int64_t>(op, 2, ta)) {
|
||||
const auto& num_boxes = boxes_shape[1];
|
||||
const auto min_selected_boxes =
|
||||
std::min(num_boxes.get_max_length(), static_cast<V>(max_out_boxes_per_class->front()));
|
||||
selected_boxes = static_output ? TDim{min_selected_boxes} : TDim{0, min_selected_boxes};
|
||||
}
|
||||
|
||||
selected_boxes *= scores_shape[0].get_max_length();
|
||||
selected_boxes *= scores_shape[1].get_max_length();
|
||||
}
|
||||
|
||||
nms::validate::boxes_last_dim(op, input_shapes);
|
||||
}
|
||||
|
||||
auto output_shapes = std::vector<TRShape>(2, out_shape);
|
||||
output_shapes.emplace_back(std::initializer_list<typename TRShape::value_type>{1});
|
||||
output_shapes.emplace_back(std::initializer_list<V>{1});
|
||||
return output_shapes;
|
||||
}
|
||||
} // namespace nms
|
||||
@@ -257,20 +245,17 @@ std::vector<TRShape> shape_infer(const NonMaxSuppression* op,
|
||||
const auto& boxes_shape = input_shapes[0];
|
||||
const auto& scores_shape = input_shapes[1];
|
||||
|
||||
auto output_shapes = std::vector<TRShape>{TRShape{TDim(-1), 3}};
|
||||
if (boxes_shape.rank().is_static()) {
|
||||
const auto max_out_boxes_per_class = get_input_const_data_as<TRShape, int64_t>(op, 2, ta);
|
||||
const auto max_out_class_boxes = max_out_boxes_per_class ? max_out_boxes_per_class->front() : dim::inf_bound;
|
||||
auto output_shapes = std::vector<TRShape>{TRShape{TDim(dim::inf_bound), 3}};
|
||||
|
||||
if (boxes_shape.rank().is_static() && scores_shape.rank().is_static()) {
|
||||
const auto& num_boxes = boxes_shape[1];
|
||||
auto& selected_boxes = output_shapes[0][0];
|
||||
if (num_boxes.is_static()) {
|
||||
selected_boxes = std::min(num_boxes.get_length(), static_cast<V>(max_out_class_boxes));
|
||||
}
|
||||
|
||||
if (scores_shape.rank().is_static()) {
|
||||
selected_boxes *= scores_shape[0].get_max_length();
|
||||
selected_boxes *= scores_shape[1].get_max_length();
|
||||
if (const auto max_out_boxes_per_class = get_input_const_data_as<TRShape, int64_t>(op, 2, ta)) {
|
||||
auto& selected_boxes = output_shapes[0][0];
|
||||
selected_boxes = std::min(num_boxes.get_length(), static_cast<V>(max_out_boxes_per_class->front()));
|
||||
selected_boxes *= scores_shape[0].get_max_length();
|
||||
selected_boxes *= scores_shape[1].get_max_length();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -368,6 +368,29 @@ TYPED_TEST_P(NMSDynamicOutputTest, interval_shapes_labels) {
|
||||
EXPECT_THAT(get_shape_labels(op->get_output_partial_shape(2)), Each(no_label));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(NMSDynamicOutputTest, num_box_dynamic_dim_max_boxes_per_class_as_const) {
|
||||
auto boxes_shape = PartialShape{2, -1, 4};
|
||||
auto scores_shape = PartialShape{2, {0, 5}, {1, 7}};
|
||||
set_shape_labels(boxes_shape, 10);
|
||||
set_shape_labels(scores_shape, 20);
|
||||
|
||||
const auto boxes = make_shared<op::v0::Parameter>(element::f32, boxes_shape);
|
||||
const auto scores = make_shared<op::v0::Parameter>(element::f32, scores_shape);
|
||||
const auto max_output_boxes_per_class = op::v0::Constant::create(element::i16, Shape{}, {5});
|
||||
const auto iou_threshold = make_shared<op::v0::Parameter>(element::f32, Shape{});
|
||||
const auto score_threshold = make_shared<op::v0::Parameter>(element::f32, Shape{});
|
||||
|
||||
const auto op = this->make_op(boxes, scores, max_output_boxes_per_class, iou_threshold, score_threshold);
|
||||
|
||||
EXPECT_THAT(op->outputs(),
|
||||
ElementsAre(Property("Indicies shape", &Output<Node>::get_partial_shape, PartialShape({-1, 3})),
|
||||
Property("Scores shape", &Output<Node>::get_partial_shape, PartialShape({-1, 3})),
|
||||
Property("Outputs shape", &Output<Node>::get_partial_shape, PartialShape({1}))));
|
||||
EXPECT_THAT(get_shape_labels(op->get_output_partial_shape(0)), Each(no_label));
|
||||
EXPECT_THAT(get_shape_labels(op->get_output_partial_shape(1)), Each(no_label));
|
||||
EXPECT_THAT(get_shape_labels(op->get_output_partial_shape(2)), Each(no_label));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(NMSDynamicOutputTest, output_shape_i32) {
|
||||
const auto boxes = make_shared<op::v0::Parameter>(element::f32, Shape{2, 7, 4});
|
||||
const auto scores = make_shared<op::v0::Parameter>(element::f32, Shape{2, 5, 7});
|
||||
@@ -429,6 +452,25 @@ TYPED_TEST_P(NMSDynamicOutputTest, dynamic_types) {
|
||||
Property("Outputs shape", &Output<Node>::get_partial_shape, PartialShape({1}))));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(NMSDynamicOutputTest, scores_shape_is_dynamic_rank) {
|
||||
const auto boxes = make_shared<op::v0::Parameter>(element::dynamic, Shape{5, 2, 4});
|
||||
const auto scores = make_shared<op::v0::Parameter>(element::dynamic, PartialShape::dynamic());
|
||||
const auto max_output_boxes_per_class = op::v0::Constant::create(element::i16, Shape{}, {3});
|
||||
const auto iou_threshold = make_shared<op::v0::Parameter>(element::f32, Shape{});
|
||||
const auto score_threshold = make_shared<op::v0::Parameter>(element::f32, Shape{});
|
||||
|
||||
const auto op = this->make_op(boxes, scores, max_output_boxes_per_class, iou_threshold, score_threshold);
|
||||
|
||||
EXPECT_THAT(op->outputs(),
|
||||
ElementsAre(Property("Indicies type", &Output<Node>::get_element_type, element::i64),
|
||||
Property("Scores type", &Output<Node>::get_element_type, element::f32),
|
||||
Property("Outputs type", &Output<Node>::get_element_type, element::i64)));
|
||||
EXPECT_THAT(op->outputs(),
|
||||
ElementsAre(Property("Indicies shape", &Output<Node>::get_partial_shape, PartialShape({-1, 3})),
|
||||
Property("Scores shape", &Output<Node>::get_partial_shape, PartialShape({-1, 3})),
|
||||
Property("Outputs shape", &Output<Node>::get_partial_shape, PartialShape({1}))));
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_SUITE_P(NMSDynamicOutputTest,
|
||||
scalar_inputs_check,
|
||||
boxes_scores_static_other_defaults,
|
||||
@@ -436,8 +478,10 @@ REGISTER_TYPED_TEST_SUITE_P(NMSDynamicOutputTest,
|
||||
num_boxes_lt_max_out_boxes,
|
||||
max_out_boxes_is_zero,
|
||||
interval_shapes_labels,
|
||||
num_box_dynamic_dim_max_boxes_per_class_as_const,
|
||||
output_shape_i32,
|
||||
dynamic_boxes_and_scores,
|
||||
dynamic_types);
|
||||
dynamic_types,
|
||||
scores_shape_is_dynamic_rank);
|
||||
using NMSDynamicOutputTypes = testing::Types<op::v5::NonMaxSuppression, op::v9::NonMaxSuppression>;
|
||||
INSTANTIATE_TYPED_TEST_SUITE_P(type_prop, NMSDynamicOutputTest, NMSDynamicOutputTypes);
|
||||
@@ -35,11 +35,12 @@ namespace SubgraphTestsDefinitions {
|
||||
\ /
|
||||
\ /
|
||||
\ /
|
||||
MatMul
|
||||
MatMul
|
||||
|
|
||||
Result
|
||||
|
||||
This test is needed to cover logic that allows to avoid computational error for subgraph: "[I32] -> Convert -> [F32] -> Range" due to precision lowering for floating point path inside "EnforceInferencePrecision" pass".
|
||||
This test is needed to cover logic that allows to avoid computational error for subgraph: "[I32] -> Convert -> [F32]
|
||||
-> Range" due to precision lowering for floating point path inside "EnforceInferencePrecision" pass".
|
||||
TODO: Incorrect subgraph is generated by ONNX FE + ticket 117861.
|
||||
*/
|
||||
|
||||
|
||||
Reference in new issue
Block a user