Cecilia/multiclass nms9/cpu impl (#11246)

* multiclass_nms opset9 spec, api, reference, paddle fe mapper, paddle fe unittest.

* multiclass_nms opset9 cpu node impl.

* multiclass_nms opset9 shape infer fix.

* multiclass_nms opset9: add transform ConvertMulticlassNms8ToMulticlassNms9.

* ConvertMulticlassNmsToMulticlassNmsIE: to MulticlassNmsIEInternal

* add test dependency package paddledet==2.1.0

* 1. fix for roisnum overflow. 2. common shape_infer private function.

Signed-off-by: jialipen <cecilia.peng@intel.com>

* 1. use common infer_shape helper. 2. fix roisnum overflow issue. 3. fix for nmsWithEta.

* test suite for opset9 multiclass_nms smoke tests pass, with both static and dynamic shapes.

code clean for unit test.

* decouple specification from this PR.

* op fuzzy: dynamic input/output

* reference impl refactor

* multiclass_nms_base no need clone_inputs.

* code clean

* restrict ppdet import

* fix clang format error

* change ppdet import to resolve CI fail issue related to its dependency.

* fix CI

* refactor: multiclass_nms_shape_inference for opset9 and reference impl.
TODO: could be applied to opset8 and even matrix_nms.

* fix CI build failure.

* CI fix for ambiguous namespace reference issue when
building static libs.

* update nms save_model python scripts.

* dynamic inputs for NMS with CPU plugin.

* copyright header for test scripts.

* op comformance test for multiclass_nms_9.

* minor update: is_type

* python opset9 and multiclass_nms

* flake8 CI fix

flake8 CI fix

flake8 CI fix

* remove NmsBase. stage1.

flake8 CI fix

remove NmsBase. stage 1 fix.

* rm NmsBase. stage2.

* more multiclass_nms prop tests and fix.

* remove unchanged ops from binding opset9.

* dependcy of paddle_tests.

* fix: add MulticlassNms to op mapper.

* clang format fix

* fix merge error.
This commit is contained in:
cecilia peng authored and GitHub committed 2022-05-31 07:56:01 +08:00
1 parent 82fdf165eb
commit 016c5f537a
63 files changed
+3776 -1142

No files matched your search

@@ -94,7 +94,7 @@ from ngraph.opset1.ops import maximum
from ngraph.opset1.ops import minimum
from ngraph.opset4.ops import mish
from ngraph.opset1.ops import mod
from ngraph.opset8.ops import multiclass_nms
from ngraph.opset9.ops import multiclass_nms
from ngraph.opset1.ops import multiply
from ngraph.opset6.ops import mvn
from ngraph.opset1.ops import negative
@@ -191,3 +191,65 @@ def irdft(
inputs = as_nodes(data, axes, signal_size)
return _get_node_factory_opset9().create("IRDFT", inputs)
@nameable_op
def multiclass_nms(
boxes: NodeInput,
scores: NodeInput,
roisnum: Optional[NodeInput] = None,
sort_result_type: Optional[str] = "none",
sort_result_across_batch: Optional[bool] = False,
output_type: Optional[str] = "i64",
iou_threshold: Optional[float] = 0.0,
score_threshold: Optional[float] = 0.0,
nms_top_k: Optional[int] = -1,
keep_top_k: Optional[int] = -1,
background_class: Optional[int] = -1,
nms_eta: Optional[float] = 1.0,
normalized: Optional[bool] = True
) -> Node:
"""Return a node which performs MulticlassNms.
:param boxes: Tensor with box coordinates.
:param scores: Tensor with box scores.
:param roisnum: Tensor with roisnum. Specifies the number of rois in each image. Required when
'scores' is a 2-dimensional tensor.
:param sort_result_type: Specifies order of output elements, possible values:
'class': sort selected boxes by class id (ascending)
'score': sort selected boxes by score (descending)
'none': do not guarantee the order.
:param sort_result_across_batch: Specifies whenever it is necessary to sort selected boxes
across batches or not
:param output_type: Specifies the output tensor type, possible values:
'i64', 'i32'
:param iou_threshold: Specifies intersection over union threshold
:param score_threshold: Specifies minimum score to consider box for the processing
:param nms_top_k: Specifies maximum number of boxes to be selected per class, -1 meaning
to keep all boxes
:param keep_top_k: Specifies maximum number of boxes to be selected per batch element, -1
meaning to keep all boxes
:param background_class: Specifies the background class id, -1 meaning to keep all classes
:param nms_eta: Specifies eta parameter for adpative NMS, in close range [0, 1.0]
:param normalized: Specifies whether boxes are normalized or not
:return: The new node which performs MuticlassNms
"""
if roisnum is None:
inputs = as_nodes(boxes, scores)
else:
inputs = as_nodes(boxes, scores, roisnum)
attributes = {
"sort_result_type": sort_result_type,
"sort_result_across_batch": sort_result_across_batch,
"output_type": output_type,
"iou_threshold": iou_threshold,
"score_threshold": score_threshold,
"nms_top_k": nms_top_k,
"keep_top_k": keep_top_k,
"background_class": background_class,
"nms_eta": nms_eta,
"normalized": normalized
}
return _get_node_factory_opset9().create("MulticlassNms", inputs, attributes)
@@ -94,7 +94,7 @@ from openvino.runtime.opset1.ops import maximum
from openvino.runtime.opset1.ops import minimum
from openvino.runtime.opset4.ops import mish
from openvino.runtime.opset1.ops import mod
from openvino.runtime.opset8.ops import multiclass_nms
from openvino.runtime.opset9.ops import multiclass_nms
from openvino.runtime.opset1.ops import multiply
from openvino.runtime.opset6.ops import mvn
from openvino.runtime.opset1.ops import negative
@@ -1,7 +1,7 @@
# Copyright (C) 2018-2022 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Factory functions for all ngraph ops."""
"""Factory functions for all openvino ops."""
from functools import partial
from typing import Optional
@@ -190,3 +190,65 @@ def irdft(
inputs = as_nodes(data, axes, signal_size)
return _get_node_factory_opset9().create("IRDFT", inputs)
@nameable_op
def multiclass_nms(
boxes: NodeInput,
scores: NodeInput,
roisnum: Optional[NodeInput] = None,
sort_result_type: Optional[str] = "none",
sort_result_across_batch: Optional[bool] = False,
output_type: Optional[str] = "i64",
iou_threshold: Optional[float] = 0.0,
score_threshold: Optional[float] = 0.0,
nms_top_k: Optional[int] = -1,
keep_top_k: Optional[int] = -1,
background_class: Optional[int] = -1,
nms_eta: Optional[float] = 1.0,
normalized: Optional[bool] = True
) -> Node:
"""Return a node which performs MulticlassNms.
:param boxes: Tensor with box coordinates.
:param scores: Tensor with box scores.
:param roisnum: Tensor with roisnum. Specifies the number of rois in each image. Required when
'scores' is a 2-dimensional tensor.
:param sort_result_type: Specifies order of output elements, possible values:
'class': sort selected boxes by class id (ascending)
'score': sort selected boxes by score (descending)
'none': do not guarantee the order.
:param sort_result_across_batch: Specifies whenever it is necessary to sort selected boxes
across batches or not
:param output_type: Specifies the output tensor type, possible values:
'i64', 'i32'
:param iou_threshold: Specifies intersection over union threshold
:param score_threshold: Specifies minimum score to consider box for the processing
:param nms_top_k: Specifies maximum number of boxes to be selected per class, -1 meaning
to keep all boxes
:param keep_top_k: Specifies maximum number of boxes to be selected per batch element, -1
meaning to keep all boxes
:param background_class: Specifies the background class id, -1 meaning to keep all classes
:param nms_eta: Specifies eta parameter for adpative NMS, in close range [0, 1.0]
:param normalized: Specifies whether boxes are normalized or not
:return: The new node which performs MuticlassNms
"""
if roisnum is None:
inputs = as_nodes(boxes, scores)
else:
inputs = as_nodes(boxes, scores, roisnum)
attributes = {
"sort_result_type": sort_result_type,
"sort_result_across_batch": sort_result_across_batch,
"output_type": output_type,
"iou_threshold": iou_threshold,
"score_threshold": score_threshold,
"nms_top_k": nms_top_k,
"keep_top_k": keep_top_k,
"background_class": background_class,
"nms_eta": nms_eta,
"normalized": normalized
}
return _get_node_factory_opset9().create("MulticlassNms", inputs, attributes)
@@ -12,7 +12,7 @@ from openvino.runtime import Node, Output
from openvino.runtime.exceptions import UserInputError
DEFAULT_OPSET = "opset8"
DEFAULT_OPSET = "opset9"
class NodeFactory(object):
@@ -3,13 +3,14 @@
import numpy as np
import pytest
from openvino.runtime import PartialShape, Dimension, Model
from openvino.runtime.exceptions import UserInputError
from openvino.runtime.utils.types import make_constant_node
import openvino.runtime.opset9 as ov
import openvino.runtime.opset1 as ov_opset1
import openvino.runtime.opset5 as ov_opset5
import openvino.runtime.opset9 as ov
from openvino.runtime import Type
np_types = [np.float32, np.int32]
@@ -1819,7 +1820,33 @@ def test_multiclass_nms():
scores_data = scores_data.reshape([1, 2, 6])
score = ov.constant(scores_data, dtype=np.float)
nms_node = ov.multiclass_nms(box, score, output_type="i32", nms_top_k=3,
nms_node = ov.multiclass_nms(box, score, None, output_type="i32", nms_top_k=3,
iou_threshold=0.5, score_threshold=0.0, sort_result_type="classid",
nms_eta=1.0)
assert nms_node.get_type_name() == "MulticlassNms"
assert nms_node.get_output_size() == 3
assert nms_node.outputs()[0].get_partial_shape() == PartialShape([Dimension(0, 6), Dimension(6)])
assert nms_node.outputs()[1].get_partial_shape() == PartialShape([Dimension(0, 6), Dimension(1)])
assert list(nms_node.outputs()[2].get_shape()) == [1, ]
assert nms_node.get_output_element_type(0) == Type.f32
assert nms_node.get_output_element_type(1) == Type.i32
assert nms_node.get_output_element_type(2) == Type.i32
boxes_data = np.array([[[7.55, 1.10, 18.28, 14.47],
[7.25, 0.47, 12.28, 17.77]],
[[4.06, 5.15, 16.11, 18.40],
[9.66, 3.36, 18.57, 13.26]],
[[6.50, 7.00, 13.33, 17.63],
[0.73, 5.34, 19.97, 19.97]]]).astype("float32")
box = ov.constant(boxes_data, dtype=np.float)
scores_data = np.array([[0.34, 0.66],
[0.45, 0.61],
[0.39, 0.59]]).astype("float32")
score = ov.constant(scores_data, dtype=np.float)
rois_num_data = np.array([3]).astype("int32")
roisnum = ov.constant(rois_num_data, dtype=np.int)
nms_node = ov.multiclass_nms(box, score, roisnum, output_type="i32", nms_top_k=3,
iou_threshold=0.5, score_threshold=0.0, sort_result_type="classid",
nms_eta=1.0)
@@ -2,7 +2,9 @@
# SPDX-License-Identifier: Apache-2.0
import numpy as np
import pytest
from _pyngraph import PartialShape, Dimension
import ngraph as ng
@@ -1885,7 +1887,33 @@ def test_multiclass_nms():
scores_data = scores_data.reshape([1, 2, 6])
score = ng.constant(scores_data, dtype=np.float)
nms_node = ng.multiclass_nms(box, score, output_type="i32", nms_top_k=3,
nms_node = ng.multiclass_nms(box, score, None, output_type="i32", nms_top_k=3,
iou_threshold=0.5, score_threshold=0.0, sort_result_type="classid",
nms_eta=1.0)
assert nms_node.get_type_name() == "MulticlassNms"
assert nms_node.get_output_size() == 3
assert nms_node.outputs()[0].get_partial_shape() == PartialShape([Dimension(0, 6), Dimension(6)])
assert nms_node.outputs()[1].get_partial_shape() == PartialShape([Dimension(0, 6), Dimension(1)])
assert list(nms_node.outputs()[2].get_shape()) == [1, ]
assert nms_node.get_output_element_type(0) == Type.f32
assert nms_node.get_output_element_type(1) == Type.i32
assert nms_node.get_output_element_type(2) == Type.i32
boxes_data = np.array([[[7.55, 1.10, 18.28, 14.47],
[7.25, 0.47, 12.28, 17.77]],
[[4.06, 5.15, 16.11, 18.40],
[9.66, 3.36, 18.57, 13.26]],
[[6.50, 7.00, 13.33, 17.63],
[0.73, 5.34, 19.97, 19.97]]]).astype("float32")
box = ng.constant(boxes_data, dtype=np.float)
scores_data = np.array([[0.34, 0.66],
[0.45, 0.61],
[0.39, 0.59]]).astype("float32")
score = ng.constant(scores_data, dtype=np.float)
rois_num_data = np.array([3]).astype("int32")
roisnum = ng.constant(rois_num_data, dtype=np.int)
nms_node = ng.multiclass_nms(box, score, roisnum, output_type="i32", nms_top_k=3,
iou_threshold=0.5, score_threshold=0.0, sort_result_type="classid",
nms_eta=1.0)
@@ -0,0 +1,38 @@
// Copyright (C) 2018-2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <transformations_visibility.hpp>
#include "ngraph/op/util/multiclass_nms_base.hpp"
#include "ngraph/opsets/opset9.hpp"
namespace ngraph {
namespace op {
namespace internal {
class TRANSFORMATIONS_API MulticlassNmsIEInternal : public opset9::MulticlassNms {
public:
OPENVINO_OP("MulticlassNmsIEInternal", "ie_internal_opset", opset9::MulticlassNms);
BWDCMP_RTTI_DECLARATION;
MulticlassNmsIEInternal() = default;
MulticlassNmsIEInternal(const Output<Node>& boxes,
const Output<Node>& scores,
const ngraph::op::util::MulticlassNmsBase::Attributes& attrs);
MulticlassNmsIEInternal(const Output<Node>& boxes,
const Output<Node>& scores,
const Output<Node>& roisnum,
const ngraph::op::util::MulticlassNmsBase::Attributes& attrs);
void validate_and_infer_types() override;
std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override;
};
} // namespace internal
} // namespace op
} // namespace ngraph
@@ -16,7 +16,6 @@ namespace ov {
namespace op {
namespace v8 {
class MulticlassNms;
class MatrixNms;
} // namespace v8
@@ -84,7 +83,7 @@ void NmsStaticShapeIE<BaseNmsOp>::validate_and_infer_types() {
max_output_boxes_per_class = num_boxes;
auto max_output_boxes_per_batch = max_output_boxes_per_class * num_classes;
if (this->m_keep_top_k >= 0)
if (this->m_attrs.keep_top_k >= 0)
max_output_boxes_per_batch =
std::min(max_output_boxes_per_batch, static_cast<int64_t>(this->m_attrs.keep_top_k));
@@ -136,7 +135,6 @@ const ::ngraph::Node::type_info_t NmsStaticShapeIE<BaseNmsOp>::type_info =
#endif
#ifdef __clang__
extern template class TRANSFORMATIONS_API op::internal::NmsStaticShapeIE<ov::op::v8::MulticlassNms>;
extern template class TRANSFORMATIONS_API op::internal::NmsStaticShapeIE<ov::op::v8::MatrixNms>;
#endif // __clang__
@@ -4,11 +4,8 @@
#pragma once
#include <memory>
#include <ngraph/pass/graph_rewrite.hpp>
#include <transformations_visibility.hpp>
#include <utility>
#include <vector>
namespace ngraph {
namespace pass {
@@ -0,0 +1,24 @@
// Copyright (C) 2018-2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <memory>
#include <ngraph/pass/graph_rewrite.hpp>
#include <transformations_visibility.hpp>
#include <utility>
namespace ngraph {
namespace pass {
class TRANSFORMATIONS_API ConvertMulticlassNms8ToMulticlassNms9;
} // namespace pass
} // namespace ngraph
class ngraph::pass::ConvertMulticlassNms8ToMulticlassNms9 : public ngraph::pass::MatcherPass {
public:
OPENVINO_RTTI("ConvertMulticlassNms8ToMulticlassNms9", "0");
ConvertMulticlassNms8ToMulticlassNms9();
};
@@ -0,0 +1,62 @@
// Copyright (C) 2018-2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "ngraph_ops/multiclass_nms_ie_internal.hpp"
#include "../../core/shape_inference/include/multiclass_nms_shape_inference.hpp"
#include "itt.hpp"
using namespace std;
using namespace ngraph;
BWDCMP_RTTI_DEFINITION(op::internal::MulticlassNmsIEInternal);
op::internal::MulticlassNmsIEInternal::MulticlassNmsIEInternal(const Output<Node>& boxes,
const Output<Node>& scores,
const op::util::MulticlassNmsBase::Attributes& attrs)
: opset9::MulticlassNms(boxes, scores, attrs) {
constructor_validate_and_infer_types();
}
op::internal::MulticlassNmsIEInternal::MulticlassNmsIEInternal(const Output<Node>& boxes,
const Output<Node>& scores,
const Output<Node>& roisnum,
const op::util::MulticlassNmsBase::Attributes& attrs)
: opset9::MulticlassNms(boxes, scores, roisnum, attrs) {
constructor_validate_and_infer_types();
}
std::shared_ptr<Node> op::internal::MulticlassNmsIEInternal::clone_with_new_inputs(const OutputVector& new_args) const {
INTERNAL_OP_SCOPE(internal_MulticlassNmsIEInternal_clone_with_new_inputs);
if (new_args.size() == 3) {
return std::make_shared<MulticlassNmsIEInternal>(new_args.at(0), new_args.at(1), new_args.at(2), m_attrs);
} else if (new_args.size() == 2) {
return std::make_shared<MulticlassNmsIEInternal>(new_args.at(0), new_args.at(1), m_attrs);
}
throw ngraph::ngraph_error("Unsupported number of inputs: " + std::to_string(new_args.size()));
}
void op::internal::MulticlassNmsIEInternal::validate_and_infer_types() {
INTERNAL_OP_SCOPE(internal_MulticlassNmsIEInternal_validate_and_infer_types);
const auto output_type = get_attrs().output_type;
validate();
const auto& boxes_ps = get_input_partial_shape(0);
const auto& scores_ps = get_input_partial_shape(1);
std::vector<PartialShape> input_shapes = {boxes_ps, scores_ps};
if (get_input_size() == 3) {
const auto& roisnum_ps = get_input_partial_shape(2);
input_shapes.push_back(roisnum_ps);
}
std::vector<PartialShape> output_shapes = {{Dimension::dynamic(), 6},
{Dimension::dynamic(), 1},
{Dimension::dynamic()}};
shape_infer(this, input_shapes, output_shapes, true, true);
set_output_type(0, get_input_element_type(0), output_shapes[0]);
set_output_type(1, output_type, output_shapes[1]);
set_output_type(2, output_type, output_shapes[2]);
}
@@ -13,7 +13,6 @@ namespace ngraph {
namespace op {
namespace internal {
template class TRANSFORMATIONS_API op::internal::NmsStaticShapeIE<op::v8::MulticlassNms>;
template class TRANSFORMATIONS_API op::internal::NmsStaticShapeIE<op::v8::MatrixNms>;
} // namespace internal
@@ -81,6 +81,7 @@
#include "transformations/op_conversions/convert_maxpool_upgrade.hpp"
#include "transformations/op_conversions/convert_minimum_to_power_and_max.hpp"
#include "transformations/op_conversions/convert_mod.hpp"
#include "transformations/op_conversions/convert_multiclass_nms_upgrade.hpp"
#include "transformations/op_conversions/convert_pad_to_group_conv.hpp"
#include "transformations/op_conversions/convert_prior_box_v8_to_v0.hpp"
#include "transformations/op_conversions/convert_reduce_to_pooling.hpp"
@@ -201,6 +202,7 @@ bool ngraph::pass::CommonOptimizations::run_on_model(const std::shared_ptr<ngrap
manager.register_pass<ngraph::pass::ConvertDetectionOutput8ToDetectionOutput1>();
manager.register_pass<ngraph::pass::ConvertROIAlign3To9, false>();
manager.register_pass<ngraph::pass::ConvertROIAlign9To3>();
manager.register_pass<ngraph::pass::ConvertMulticlassNms8ToMulticlassNms9>();
auto fq_fusions = manager.register_pass<ngraph::pass::GraphRewrite>();
fq_fusions->add_matcher<ngraph::pass::FakeQuantizeMulFusion>();
@@ -262,6 +262,7 @@ bool ngraph::pass::ConvertPrecision::run_on_model(const std::shared_ptr<ngraph::
{opset9::NonMaxSuppression::get_type_info_static(), fuse_type_to_nms9},
{opset8::MatrixNms::get_type_info_static(), fuse_type_to_matrix_nms},
{opset8::MulticlassNms::get_type_info_static(), fuse_type_to_multiclass_nms},
{opset9::MulticlassNms::get_type_info_static(), fuse_type_to_multiclass_nms},
{opset9::GenerateProposals::get_type_info_static(), fuse_type_to_generate_proposals},
{opset6::CTCGreedyDecoderSeqLen::get_type_info_static(), fuse_type_to_ctc_greedy_decoder_seq_len},
{opset4::TopK::get_type_info_static(), fuse_type_to_topk},
@@ -448,7 +449,12 @@ bool fuse_type_to_matrix_nms(const std::shared_ptr<ngraph::Node>& node, ngraph::
}
bool fuse_type_to_multiclass_nms(const std::shared_ptr<ngraph::Node>& node, ngraph::element::Type to, size_t idx) {
auto nms = ov::as_type_ptr<opset8::MulticlassNms>(node);
std::shared_ptr<ov::op::util::MulticlassNmsBase> nms;
if (ov::is_type<ov::op::v8::MulticlassNms>(node)) {
nms = ov::as_type_ptr<opset8::MulticlassNms>(node);
} else {
nms = ov::as_type_ptr<opset9::MulticlassNms>(node);
}
if (!nms) {
return false;
}
@@ -34,7 +34,7 @@ ngraph::pass::ConvertMatrixNmsToMatrixNmsIE::ConvertMatrixNmsToMatrixNmsIE(bool
// vector of new nGraph operations
NodeVector new_ops;
auto attrs = nms->get_attrs();
attrs.output_type = force_i32_output_type ? element::i32 : nms->get_output_type();
attrs.output_type = force_i32_output_type ? element::i32 : attrs.output_type;
auto nms_new = std::make_shared<op::internal::NmsStaticShapeIE<ngraph::opset8::MatrixNms>>(new_args.at(0),
new_args.at(1),
attrs);
@@ -6,39 +6,52 @@
#include <memory>
#include <ngraph/opsets/opset1.hpp>
#include <ngraph/opsets/opset5.hpp>
#include <ngraph/opsets/opset8.hpp>
#include <ngraph/opsets/opset9.hpp>
#include <ngraph/pattern/op/wrap_type.hpp>
#include <ngraph/rt_info.hpp>
#include <vector>
#include "itt.hpp"
#include "ngraph_ops/nms_static_shape_ie.hpp"
#include "ngraph_ops/multiclass_nms_ie_internal.hpp"
ngraph::pass::ConvertMulticlassNmsToMulticlassNmsIE::ConvertMulticlassNmsToMulticlassNmsIE(bool force_i32_output_type) {
using namespace ngraph;
pass::ConvertMulticlassNmsToMulticlassNmsIE::ConvertMulticlassNmsToMulticlassNmsIE(bool force_i32_output_type) {
MATCHER_SCOPE(ConvertMulticlassNmsToMulticlassNmsIE);
auto nms = ngraph::pattern::wrap_type<ngraph::opset8::MulticlassNms>();
auto nms = pattern::wrap_type<opset9::MulticlassNms>();
ngraph::matcher_pass_callback callback = [=](pattern::Matcher& m) {
auto nms = std::dynamic_pointer_cast<ngraph::opset8::MulticlassNms>(m.get_match_root());
matcher_pass_callback callback = [=](pattern::Matcher& m) {
auto nms = std::dynamic_pointer_cast<opset9::MulticlassNms>(m.get_match_root());
if (!nms || transformation_callback(nms)) {
return false;
}
const auto new_args = nms->input_values();
// if input shape is dynamic force the output shape must be dynamic too
if (nms->get_input_partial_shape(0).is_dynamic() || nms->get_input_partial_shape(1).is_dynamic()) {
return false;
}
if (new_args.size() > 2) {
if (nms->get_input_partial_shape(2).is_dynamic()) {
return false;
}
}
const auto new_args = nms->input_values();
// vector of new nGraph operations
NodeVector new_ops;
auto attrs = nms->get_attrs();
attrs.output_type = force_i32_output_type ? element::i32 : nms->get_output_type();
attrs.output_type = force_i32_output_type ? element::i32 : attrs.output_type;
auto nms_new = std::make_shared<op::internal::NmsStaticShapeIE<ngraph::opset8::MulticlassNms>>(new_args.at(0),
new_args.at(1),
attrs);
std::shared_ptr<op::internal::MulticlassNmsIEInternal> nms_new;
if (new_args.size() > 2) {
nms_new = std::make_shared<op::internal::MulticlassNmsIEInternal>(new_args.at(0),
new_args.at(1),
new_args.at(2),
attrs);
} else {
nms_new = std::make_shared<op::internal::MulticlassNmsIEInternal>(new_args.at(0), new_args.at(1), attrs);
}
new_ops.emplace_back(nms_new);
Output<Node> output_0 = nms_new->output(0);
@@ -58,11 +71,11 @@ ngraph::pass::ConvertMulticlassNmsToMulticlassNmsIE::ConvertMulticlassNmsToMulti
}
nms_new->set_friendly_name(nms->get_friendly_name());
ngraph::copy_runtime_info(nms, new_ops);
ngraph::replace_node(nms, {output_0, output_1, output_2});
copy_runtime_info(nms, new_ops);
replace_node(nms, {output_0, output_1, output_2});
return true;
};
auto m = std::make_shared<ngraph::pattern::Matcher>(nms, matcher_name);
auto m = std::make_shared<pattern::Matcher>(nms, matcher_name);
this->register_matcher(m, callback);
}
@@ -0,0 +1,38 @@
// Copyright (C) 2018-2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "transformations/op_conversions/convert_multiclass_nms_upgrade.hpp"
#include <ngraph/opsets/opset8.hpp>
#include <ngraph/opsets/opset9.hpp>
#include <ngraph/pattern/op/wrap_type.hpp>
#include <ngraph/rt_info.hpp>
#include "itt.hpp"
ngraph::pass::ConvertMulticlassNms8ToMulticlassNms9::ConvertMulticlassNms8ToMulticlassNms9() {
MATCHER_SCOPE(ConvertMulticlassNms8ToMulticlassNms9);
auto nms_v8_pattern = pattern::wrap_type<opset8::MulticlassNms>();
matcher_pass_callback callback = [=](pattern::Matcher& m) {
auto nms_v8_node = std::dynamic_pointer_cast<opset8::MulticlassNms>(m.get_match_root());
if (!nms_v8_node)
return false;
const auto new_args = nms_v8_node->input_values();
// vector of new nGraph operations
NodeVector new_ops;
auto attrs = nms_v8_node->get_attrs();
auto nms_v9_node = std::make_shared<opset9::MulticlassNms>(new_args.at(0), new_args.at(1), attrs);
nms_v9_node->set_friendly_name(nms_v8_node->get_friendly_name());
copy_runtime_info(nms_v8_node, nms_v9_node);
replace_node(nms_v8_node, nms_v9_node);
return true;
};
auto m = std::make_shared<pattern::Matcher>(nms_v8_pattern, matcher_name);
register_matcher(m, callback);
}
+2 -1
View File
@@ -4,7 +4,8 @@
#pragma once
#include "ngraph/op/util/nms_base.hpp"
#include "ngraph/node.hpp"
#include "ngraph/op/op.hpp"
#include "openvino/op/matrix_nms.hpp"
namespace ngraph {
@@ -4,7 +4,7 @@
#pragma once
#include "ngraph/op/util/nms_base.hpp"
#include "ngraph/op/util/multiclass_nms_base.hpp"
#include "openvino/op/multiclass_nms.hpp"
namespace ngraph {
@@ -12,5 +12,8 @@ namespace op {
namespace v8 {
using ov::op::v8::MulticlassNms;
} // namespace v8
namespace v9 {
using ov::op::v9::MulticlassNms;
} // namespace v9
} // namespace op
} // namespace ngraph
@@ -4,14 +4,15 @@
#pragma once
#include "ngraph/coordinate_diff.hpp"
#include "ngraph/op/op.hpp"
#include "openvino/op/util/nms_base.hpp"
#include "ngraph/op/util/attr_types.hpp"
#include "openvino/op/util/multiclass_nms_base.hpp"
namespace ngraph {
namespace op {
namespace util {
using ov::op::util::NmsBase;
using ov::op::util::MulticlassNmsBase;
} // namespace util
} // namespace op
using ov::operator<<;
} // namespace ngraph
+33 -5
View File
@@ -4,7 +4,7 @@
#pragma once
#include "openvino/op/util/nms_base.hpp"
#include "openvino/op/op.hpp"
namespace ov {
namespace op {
@@ -12,13 +12,19 @@ namespace v8 {
/// \brief MatrixNms operation
///
/// \ingroup ov_ops_cpp_api
class OPENVINO_API MatrixNms : public util::NmsBase {
class OPENVINO_API MatrixNms : public Op {
public:
OPENVINO_OP("MatrixNms", "opset8", op::util::NmsBase);
OPENVINO_OP("MatrixNms", "opset8");
BWDCMP_RTTI_DECLARATION;
enum class DecayFunction { GAUSSIAN, LINEAR };
enum class SortResultType {
CLASSID, // sort selected boxes by class id (ascending) in each batch element
SCORE, // sort selected boxes by score (descending) in each batch element
NONE // do not guarantee the order in each batch element
};
/// \brief Structure that specifies attributes of the operation
struct Attributes {
// specifies order of output elements
@@ -74,7 +80,8 @@ public:
normalized(normalized) {}
};
MatrixNms();
/// \brief Constructs a conversion operation.
MatrixNms() = default;
/// \brief Constructs a MatrixNms operation
///
@@ -87,15 +94,22 @@ public:
std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override;
void validate_and_infer_types() override;
/// \brief Returns attributes of the operation MatrixNms
const Attributes& get_attrs() const {
return m_attrs;
}
void set_output_type(const element::Type& output_type) {
m_attrs.output_type = output_type;
}
using Node::set_output_type;
protected:
Attributes m_attrs;
void validate() override;
void validate(); // helper
};
} // namespace v8
} // namespace op
@@ -113,4 +127,18 @@ public:
BWDCMP_RTTI_DECLARATION;
};
OPENVINO_API
std::ostream& operator<<(std::ostream& s, const op::v8::MatrixNms::SortResultType& type);
template <>
class OPENVINO_API AttributeAdapter<op::v8::MatrixNms::SortResultType>
: public EnumAttributeAdapterBase<op::v8::MatrixNms::SortResultType> {
public:
AttributeAdapter(op::v8::MatrixNms::SortResultType& value)
: EnumAttributeAdapterBase<op::v8::MatrixNms::SortResultType>(value) {}
OPENVINO_RTTI("AttributeAdapter<ov::op::v8::MatrixNms::SortResultType>");
BWDCMP_RTTI_DECLARATION;
};
} // namespace ov
+41 -42
View File
@@ -4,47 +4,20 @@
#pragma once
#include "openvino/op/util/nms_base.hpp"
#include "openvino/op/util/multiclass_nms_base.hpp"
namespace ov {
namespace op {
namespace v8 {
/// \brief MulticlassNms operation
///
/// \ingroup ov_ops_cpp_api
class OPENVINO_API MulticlassNms : public util::NmsBase {
class OPENVINO_API MulticlassNms : public util::MulticlassNmsBase {
public:
OPENVINO_OP("MulticlassNms", "opset8", op::util::NmsBase);
OPENVINO_OP("MulticlassNms", "opset8", op::util::MulticlassNmsBase);
BWDCMP_RTTI_DECLARATION;
/// \brief Structure that specifies attributes of the operation
struct Attributes {
// specifies order of output elements
SortResultType sort_result_type = SortResultType::NONE;
// specifies whenever it is necessary to sort selected boxes across batches or
// not
bool sort_result_across_batch = false;
// specifies the output tensor type
ov::element::Type output_type = ov::element::i64;
// specifies intersection over union threshold
float iou_threshold = 0.0f;
// specifies minimum score to consider box for the processing
float score_threshold = 0.0f;
// specifies maximum number of boxes to be selected per class, -1 meaning to
// keep all boxes
int nms_top_k = -1;
// specifies maximum number of boxes to be selected per batch element, -1
// meaning to keep all boxes
int keep_top_k = -1;
// specifies the background class id, -1 meaning to keep all classes
int background_class = -1;
// specifies eta parameter for adpative NMS, in close range [0, 1.0]
float nms_eta = 1.0f;
// specifies whether boxes are normalized or not
bool normalized = true;
};
MulticlassNms();
/// \brief Constructs a conversion operation.
MulticlassNms() = default;
/// \brief Constructs a MulticlassNms operation
///
@@ -53,19 +26,45 @@ public:
/// \param attrs Attributes of the operation
MulticlassNms(const Output<Node>& boxes, const Output<Node>& scores, const Attributes& attrs);
bool visit_attributes(AttributeVisitor& visitor) override;
void validate_and_infer_types() override;
std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override;
/// \brief Returns attributes of the operation MulticlassNms
const Attributes& get_attrs() const {
return m_attrs;
}
protected:
Attributes m_attrs;
void validate() override;
};
} // namespace v8
namespace v9 {
/// \brief MulticlassNms operation
///
class OPENVINO_API MulticlassNms : public util::MulticlassNmsBase {
public:
OPENVINO_OP("MulticlassNms", "opset9", op::util::MulticlassNmsBase);
BWDCMP_RTTI_DECLARATION;
/// \brief Constructs a conversion operation.
MulticlassNms() = default;
/// \brief Constructs a MulticlassNms operation
///
/// \param boxes Node producing the box coordinates
/// \param scores Node producing the box scores
/// \param attrs Attributes of the operation
MulticlassNms(const Output<Node>& boxes, const Output<Node>& scores, const Attributes& attrs);
/// \brief Constructs a MulticlassNms operation
///
/// \param boxes Node producing the box coordinates
/// \param scores Node producing the box scores
/// \param roisnum Node producing the number of rois
/// \param attrs Attributes of the operation
MulticlassNms(const Output<Node>& boxes,
const Output<Node>& scores,
const Output<Node>& roisnum,
const Attributes& attrs);
void validate_and_infer_types() override;
std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override;
};
} // namespace v9
} // namespace op
} // namespace ov
@@ -0,0 +1,93 @@
// Copyright (C) 2018-2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include "openvino/op/op.hpp"
namespace ov {
namespace op {
namespace util {
/// \brief Base class for operations MulticlassNMS v8 and MulticlassNMS
/// v9.
class OPENVINO_API MulticlassNmsBase : public Op {
public:
OPENVINO_OP("MulticlassNmsBase", "util");
BWDCMP_RTTI_DECLARATION;
enum class SortResultType {
CLASSID, // sort selected boxes by class id (ascending) in each batch element
SCORE, // sort selected boxes by score (descending) in each batch element
NONE // do not guarantee the order in each batch element
};
/// \brief Structure that specifies attributes of the operation
struct Attributes {
// specifies order of output elements
SortResultType sort_result_type = SortResultType::NONE;
// specifies whenever it is necessary to sort selected boxes across batches or
// not
bool sort_result_across_batch = false;
// specifies the output tensor type
ov::element::Type output_type = ov::element::i64;
// specifies intersection over union threshold
float iou_threshold = 0.0f;
// specifies minimum score to consider box for the processing
float score_threshold = 0.0f;
// specifies maximum number of boxes to be selected per class, -1 meaning to
// keep all boxes
int nms_top_k = -1;
// specifies maximum number of boxes to be selected per batch element, -1
// meaning to keep all boxes
int keep_top_k = -1;
// specifies the background class id, -1 meaning to keep all classes
int background_class = -1;
// specifies eta parameter for adpative NMS, in close range [0, 1.0]
float nms_eta = 1.0f;
// specifies whether boxes are normalized or not
bool normalized = true;
};
/// \brief Constructs a conversion operation.
MulticlassNmsBase() = default;
/// \brief Constructs a MulticlassNmsBase operation
///
/// \param arguments Node list producing the box coordinates, scores, etc.
/// \param attrs Attributes of the operation
MulticlassNmsBase(const OutputVector& arguments, const Attributes& attrs);
bool visit_attributes(AttributeVisitor& visitor) override;
/// \brief Returns attributes of the operation MulticlassNmsBase
const Attributes& get_attrs() const {
return m_attrs;
}
void set_output_type(const element::Type& output_type) {
m_attrs.output_type = output_type;
}
using Node::set_output_type;
protected:
Attributes m_attrs;
void validate(); // helper
};
} // namespace util
} // namespace op
OPENVINO_API
std::ostream& operator<<(std::ostream& s, const op::util::MulticlassNmsBase::SortResultType& type);
template <>
class OPENVINO_API AttributeAdapter<op::util::MulticlassNmsBase::SortResultType>
: public EnumAttributeAdapterBase<op::util::MulticlassNmsBase::SortResultType> {
public:
AttributeAdapter(op::util::MulticlassNmsBase::SortResultType& value)
: EnumAttributeAdapterBase<op::util::MulticlassNmsBase::SortResultType>(value) {}
OPENVINO_RTTI("AttributeAdapter<ov::op::util::MulticlassNmsBase::SortResultType>");
BWDCMP_RTTI_DECLARATION;
};
} // namespace ov
@@ -1,90 +0,0 @@
// Copyright (C) 2018-2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include "openvino/op/op.hpp"
namespace ov {
namespace op {
namespace util {
/// \brief Base class for operations NmsBase and MatrixNms
///
class OPENVINO_API NmsBase : public Op {
public:
OPENVINO_OP("NmsBase", "util");
enum class SortResultType {
CLASSID, // sort selected boxes by class id (ascending) in each batch element
SCORE, // sort selected boxes by score (descending) in each batch element
NONE // do not guarantee the order in each batch element
};
NmsBase() = delete;
/// \brief Constructs a NmsBase operation
///
/// \param output_type Specifies the output tensor type
/// \param nms_top_k Specifies maximum number of boxes to be selected per
/// class, -1 meaning to keep all boxes
/// \param keep_top_k Specifies maximum number of boxes to be selected per
/// batch element, -1 meaning to keep all boxes
NmsBase(element::Type& output_type, int& nms_top_k, int& keep_top_k);
/// \brief Constructs a NmsBase operation
///
/// \param boxes Node producing the box coordinates
/// \param scores Node producing the box scores
/// \param output_type Specifies the output tensor type
/// \param nms_top_k Specifies maximum number of boxes to be selected per
/// class, -1 meaning to keep all boxes
/// \param keep_top_k Specifies maximum number of boxes to be selected per
/// batch element, -1 meaning to keep all boxes
NmsBase(const Output<Node>& boxes,
const Output<Node>& scores,
element::Type& output_type,
int& nms_top_k,
int& keep_top_k);
void validate_and_infer_types() override;
const element::Type& get_output_type() const {
return m_output_type;
}
void set_output_type(const element::Type& output_type) {
m_output_type = output_type;
}
using Node::set_output_type;
int get_nms_top_k() const {
return m_nms_top_k;
}
int get_keep_top_k() const {
return m_keep_top_k;
}
protected:
element::Type& m_output_type;
int& m_nms_top_k;
int& m_keep_top_k;
virtual void validate();
};
} // namespace util
} // namespace op
OPENVINO_API
std::ostream& operator<<(std::ostream& s, const op::util::NmsBase::SortResultType& type);
template <>
class OPENVINO_API AttributeAdapter<op::util::NmsBase::SortResultType>
: public EnumAttributeAdapterBase<op::util::NmsBase::SortResultType> {
public:
AttributeAdapter(op::util::NmsBase::SortResultType& value)
: EnumAttributeAdapterBase<op::util::NmsBase::SortResultType>(value) {}
OPENVINO_RTTI("AttributeAdapter<ov::op::util::NmsBase::SortResultType>");
BWDCMP_RTTI_DECLARATION;
};
} // namespace ov
@@ -178,7 +178,6 @@ _OPENVINO_OP_REG(I420toBGR, ov::op::v8)
_OPENVINO_OP_REG(I420toRGB, ov::op::v8)
_OPENVINO_OP_REG(MatrixNms, ov::op::v8)
_OPENVINO_OP_REG(MaxPool, ov::op::v8)
_OPENVINO_OP_REG(MulticlassNms, ov::op::v8)
_OPENVINO_OP_REG(NV12toBGR, ov::op::v8)
_OPENVINO_OP_REG(NV12toRGB, ov::op::v8)
_OPENVINO_OP_REG(RandomUniform, ov::op::v8)
@@ -195,3 +194,4 @@ _OPENVINO_OP_REG(NonMaxSuppression, ov::op::v9)
_OPENVINO_OP_REG(ROIAlign, ov::op::v9)
_OPENVINO_OP_REG(SoftSign, ov::op::v9)
_OPENVINO_OP_REG(GenerateProposals, ov::op::v9)
_OPENVINO_OP_REG(MulticlassNms, ov::op::v9)
@@ -15,18 +15,40 @@
#include <vector>
#include "ngraph/node.hpp"
#include "ngraph/op/util/nms_base.hpp"
#include "ngraph/op/util/multiclass_nms_base.hpp"
#include "ngraph/op/util/op_types.hpp"
#include "ngraph/shape_util.hpp"
namespace ngraph {
namespace runtime {
namespace reference {
namespace multiclass_nms_impl {
struct InfoForNMS {
Shape selected_outputs_shape;
Shape selected_indices_shape;
Shape selected_numrois_shape;
Shape boxes_shape;
Shape scores_shape;
Shape roisnum_shape;
std::vector<float> boxes_data;
std::vector<float> scores_data;
std::vector<int64_t> roisnum_data;
size_t selected_outputs_shape_size;
size_t selected_indices_shape_size;
size_t selected_numrois_shape_size;
};
InfoForNMS get_info_for_nms_eval(const std::shared_ptr<op::util::MulticlassNmsBase>& nms,
const std::vector<std::shared_ptr<HostTensor>>& inputs);
} // namespace multiclass_nms_impl
void multiclass_nms(const float* boxes_data,
const Shape& boxes_data_shape,
const float* scores_data,
const Shape& scores_data_shape,
const op::v8::MulticlassNms::Attributes& attrs,
const int64_t* roisnum_data,
const Shape& roisnum_data_shape,
const op::util::MulticlassNmsBase::Attributes& attrs,
float* selected_outputs,
const Shape& selected_outputs_shape,
int64_t* selected_indices,
@@ -10,17 +10,172 @@
#include <queue>
#include <vector>
#include "../shape_inference/include/multiclass_nms_shape_inference.hpp"
#include "ngraph/runtime/reference/multiclass_nms.hpp"
#include "ngraph/runtime/reference/utils/nms_common.hpp"
#include "ngraph/shape.hpp"
using namespace ngraph;
using namespace ngraph::runtime::reference;
namespace ngraph {
namespace runtime {
namespace reference {
namespace multiclass_nms_v8 {
namespace multiclass_nms_impl {
namespace {
std::vector<float> get_floats(const std::shared_ptr<HostTensor>& input, const Shape& shape) {
size_t input_size = shape_size(shape);
std::vector<float> result(input_size);
switch (input->get_element_type()) {
case element::Type_t::bf16: {
bfloat16* p = input->get_data_ptr<bfloat16>();
for (size_t i = 0; i < input_size; ++i) {
result[i] = float(p[i]);
}
} break;
case element::Type_t::f16: {
float16* p = input->get_data_ptr<float16>();
for (size_t i = 0; i < input_size; ++i) {
result[i] = float(p[i]);
}
} break;
case element::Type_t::f32: {
float* p = input->get_data_ptr<float>();
memcpy(result.data(), p, input_size * sizeof(float));
} break;
default:
throw std::runtime_error("Unsupported data type.");
break;
}
return result;
}
std::vector<int64_t> get_integers(const std::shared_ptr<HostTensor>& input, const Shape& shape) {
size_t input_size = shape_size(shape);
std::vector<int64_t> result(input_size);
switch (input->get_element_type()) {
case element::Type_t::i8: {
auto p = input->get_data_ptr<int8_t>();
for (size_t i = 0; i < input_size; ++i) {
result[i] = int64_t(p[i]);
}
} break;
case element::Type_t::i16: {
auto p = input->get_data_ptr<int16_t>();
for (size_t i = 0; i < input_size; ++i) {
result[i] = int64_t(p[i]);
}
} break;
case element::Type_t::i32: {
auto p = input->get_data_ptr<int32_t>();
for (size_t i = 0; i < input_size; ++i) {
result[i] = int64_t(p[i]);
}
} break;
case element::Type_t::i64: {
auto p = input->get_data_ptr<int64_t>();
for (size_t i = 0; i < input_size; ++i) {
result[i] = int64_t(p[i]);
}
} break;
case element::Type_t::u8: {
auto p = input->get_data_ptr<uint8_t>();
for (size_t i = 0; i < input_size; ++i) {
result[i] = int64_t(p[i]);
}
} break;
case element::Type_t::u16: {
auto p = input->get_data_ptr<uint16_t>();
for (size_t i = 0; i < input_size; ++i) {
result[i] = int64_t(p[i]);
}
} break;
case element::Type_t::u32: {
auto p = input->get_data_ptr<uint32_t>();
for (size_t i = 0; i < input_size; ++i) {
result[i] = int64_t(p[i]);
}
} break;
case element::Type_t::u64: {
auto p = input->get_data_ptr<uint64_t>();
for (size_t i = 0; i < input_size; ++i) {
result[i] = int64_t(p[i]);
}
} break;
default:
throw std::runtime_error("Unsupported data type");
break;
}
return result;
}
static std::vector<float> prepare_boxes_data(const std::shared_ptr<HostTensor>& boxes, const Shape& boxes_shape) {
auto result = get_floats(boxes, boxes_shape);
return result;
}
static std::vector<float> prepare_scores_data(const std::shared_ptr<HostTensor>& scores, const Shape& scores_shape) {
auto result = get_floats(scores, scores_shape);
return result;
}
static std::vector<int64_t> prepare_roisnum_data(const std::shared_ptr<HostTensor>& roisnum,
const Shape& roisnum_shape) {
auto result = get_integers(roisnum, roisnum_shape);
return result;
}
} // namespace
constexpr size_t boxes_port = 0;
constexpr size_t scores_port = 1;
constexpr size_t roisnum_port = 2;
InfoForNMS get_info_for_nms_eval(const std::shared_ptr<op::util::MulticlassNmsBase>& nms,
const std::vector<std::shared_ptr<HostTensor>>& inputs) {
InfoForNMS result;
const auto boxes_ps = inputs[boxes_port]->get_partial_shape();
const auto scores_ps = inputs[scores_port]->get_partial_shape();
std::vector<PartialShape> input_shapes = {boxes_ps, scores_ps};
if (nms->get_input_size() == 3) {
const auto roisnum_ps = inputs[roisnum_port]->get_partial_shape();
input_shapes.push_back(roisnum_ps);
}
std::vector<PartialShape> output_shapes = {{Dimension::dynamic(), 6},
{Dimension::dynamic(), 1},
{Dimension::dynamic()}};
ov::op::util::shape_infer(nms.get(),
input_shapes,
output_shapes,
true,
false); // here just for upper boundary estimation.
result.selected_outputs_shape = output_shapes[0].to_shape();
result.selected_indices_shape = output_shapes[1].to_shape();
result.selected_numrois_shape = output_shapes[2].to_shape();
result.boxes_shape = inputs[boxes_port]->get_shape();
result.scores_shape = inputs[scores_port]->get_shape();
result.boxes_data = prepare_boxes_data(inputs[boxes_port], result.boxes_shape);
result.scores_data = prepare_scores_data(inputs[scores_port], result.scores_shape);
if (inputs.size() == 3) {
result.roisnum_shape = inputs[roisnum_port]->get_shape();
result.roisnum_data = prepare_roisnum_data(inputs[roisnum_port], result.roisnum_shape);
}
result.selected_outputs_shape_size = shape_size(result.selected_outputs_shape);
result.selected_indices_shape_size = shape_size(result.selected_indices_shape);
result.selected_numrois_shape_size = shape_size(result.selected_numrois_shape);
return result;
}
using Rectangle = runtime::reference::nms_common::Rectangle;
using BoxInfo = runtime::reference::nms_common::BoxInfo;
static float intersectionOverUnion(const Rectangle& boxI, const Rectangle& boxJ, const bool normalized) {
@@ -44,6 +199,192 @@ static float intersectionOverUnion(const Rectangle& boxI, const Rectangle& boxJ,
return intersection_area / (areaI + areaJ - intersection_area);
}
// slice an image
// for the case when boxes are not shared among classes.
// boxes: [in] C, M, 4 -> [out] C, M', 4
// scores: [in] C, M -> [out] C, M'
// start: start index along axis "M"
template <class T>
std::vector<T> slice_image(const T* data, const Shape& data_shape, const int64_t start, const int64_t item_num) {
std::vector<T> slice_data;
const auto class_num = data_shape[0];
const auto item_size = (data_shape.size() == 3) ? data_shape[2] : 1;
// start and end should within [0, M)
OPENVINO_ASSERT(start >= 0 && (start + item_num) <= data_shape[1],
"Invaid inputs as it is trying to slice data out of range.");
const auto row_num = item_num * item_size;
slice_data.reserve(class_num * row_num);
T* item_data = slice_data.data();
T* src = const_cast<T*>(data + start * item_size);
for (size_t i = 0; i < class_num; i++) {
std::memcpy(item_data + i * row_num, src, sizeof(T) * row_num);
src += data_shape[1] * item_size;
}
return slice_data;
}
// nms over a class
// boxes: num_priors, 4
// scores: num_priors, 1
static const std::vector<BoxInfo> nms(const float* boxes_data,
const float* scoresPtr,
const int64_t num_priors,
const op::util::MulticlassNmsBase::Attributes& attrs,
const size_t image_idx,
const size_t class_idx) {
auto func = [](float iou, float adaptive_threshold) {
return iou <= adaptive_threshold ? 1.0f : 0.0f;
};
const Rectangle* bboxesPtr = reinterpret_cast<const Rectangle*>(const_cast<float*>(boxes_data));
std::vector<BoxInfo> selected; // container for a class
auto adaptive_threshold = attrs.iou_threshold;
std::vector<BoxInfo> candidate_boxes;
for (int64_t box_idx = 0; box_idx < num_priors; box_idx++) {
if (scoresPtr[box_idx] >= attrs.score_threshold) { /* NOTE: ">=" instead of ">" used in PDPD */
candidate_boxes.emplace_back(bboxesPtr[box_idx], box_idx, scoresPtr[box_idx], 0, image_idx, class_idx);
}
}
auto candiate_size = candidate_boxes.size();
// threshold nms_top_k for each class
// NOTE: "nms_top_k" in PDPD not exactly equal to
// "max_output_boxes_per_class" in ONNX.
if (attrs.nms_top_k > -1 && attrs.nms_top_k < candiate_size) {
candiate_size = attrs.nms_top_k;
}
if (candiate_size <= 0) { // early drop
return selected; // empty
}
// sort by score in current class
std::partial_sort(candidate_boxes.begin(),
candidate_boxes.begin() + candiate_size,
candidate_boxes.end(),
std::greater<BoxInfo>());
std::priority_queue<BoxInfo> sorted_boxes(candidate_boxes.begin(),
candidate_boxes.begin() + candiate_size,
std::less<BoxInfo>());
// Get the next box with top score, filter by iou_threshold
BoxInfo next_candidate;
float original_score;
while (!sorted_boxes.empty()) {
next_candidate = sorted_boxes.top();
original_score = next_candidate.score;
sorted_boxes.pop();
bool should_hard_suppress = false;
for (int64_t j = static_cast<int64_t>(selected.size()) - 1; j >= next_candidate.suppress_begin_index; --j) {
float iou = intersectionOverUnion(next_candidate.box, selected[j].box, attrs.normalized);
next_candidate.score *= func(iou, adaptive_threshold);
if (iou >= adaptive_threshold) {
should_hard_suppress = true;
break;
}
if (next_candidate.score <= attrs.score_threshold) {
break;
}
}
next_candidate.suppress_begin_index = selected.size();
if (!should_hard_suppress) {
if (attrs.nms_eta < 1 && adaptive_threshold > 0.5) {
adaptive_threshold *= attrs.nms_eta;
}
if (next_candidate.score == original_score) {
selected.push_back(next_candidate);
continue;
}
if (next_candidate.score > attrs.score_threshold) {
sorted_boxes.push(next_candidate);
}
}
}
return selected;
}
// nms over an image
// shared Y N
// boxes: 1, M, 4 C, M', 4
// scores: 1, C, M C, M'
static const std::vector<BoxInfo> multiclass_nms(const float* boxes_data,
const Shape& boxes_data_shape,
const float* scores_data,
const Shape& scores_data_shape,
const op::util::MulticlassNmsBase::Attributes& attrs,
const size_t image_idx,
const bool shared) {
int64_t num_dets = 0;
std::vector<BoxInfo> selected_boxes; // container for a batch element
(void)boxes_data_shape;
const auto num_classes = shared ? scores_data_shape[1] : scores_data_shape[0];
const auto num_boxes = shared ? scores_data_shape[2] : scores_data_shape[1];
for (size_t class_idx = 0; class_idx < num_classes; class_idx++) {
if (class_idx == attrs.background_class)
continue;
std::vector<BoxInfo> selected;
if (shared) {
const float* scoresPtr = scores_data + class_idx * num_boxes;
selected = nms(boxes_data, scoresPtr, num_boxes, attrs, image_idx, class_idx);
} else {
const float* scoresPtr = scores_data + class_idx * num_boxes;
const float* boxesPtr = boxes_data + class_idx * num_boxes * 4;
selected = nms(boxesPtr, scoresPtr, num_boxes, attrs, image_idx, class_idx);
}
for (const auto& box_info : selected) {
selected_boxes.push_back(box_info);
}
num_dets += selected.size();
} // for each class
// sort inside batch element before go through keep_top_k
std::sort(selected_boxes.begin(), selected_boxes.end(), [](const BoxInfo& l, const BoxInfo& r) {
return ((l.batch_index == r.batch_index) &&
((l.score > r.score) || ((std::fabs(l.score - r.score) < 1e-6) && l.class_index < r.class_index) ||
((std::fabs(l.score - r.score) < 1e-6) && l.class_index == r.class_index && l.index < r.index)));
});
// threshold keep_top_k for each batch element
if (attrs.keep_top_k > -1 && attrs.keep_top_k < num_dets) {
num_dets = attrs.keep_top_k;
selected_boxes.resize(num_dets);
}
// sort
if (!attrs.sort_result_across_batch) {
if (attrs.sort_result_type == op::util::MulticlassNmsBase::SortResultType::CLASSID) {
std::sort(selected_boxes.begin(), selected_boxes.end(), [](const BoxInfo& l, const BoxInfo& r) {
return (
(l.batch_index == r.batch_index) &&
((l.class_index < r.class_index) || ((l.class_index == r.class_index) && l.score > r.score) ||
((std::fabs(l.score - r.score) <= 1e-6) && l.class_index == r.class_index && l.index < r.index)));
});
}
// in case of "SCORE", pass through, as,
// it has already gurranteed.
}
return selected_boxes;
}
struct SelectedIndex {
SelectedIndex(int64_t batch_idx, int64_t box_idx, int64_t num_box)
: flattened_index(batch_idx * num_box + box_idx) {}
@@ -68,179 +409,88 @@ struct SelectedOutput {
float box_score = 0.0f;
float xmin, ymin, xmax, ymax;
};
} // namespace multiclass_nms_v8
} // namespace multiclass_nms_impl
// compute nms over each image and each class
// shared Y N
// boxes: N, M, 4 C, sum(M'), 4
// scores: N, C, M C, sum(M')
void multiclass_nms(const float* boxes_data,
const Shape& boxes_data_shape,
const float* scores_data,
const Shape& scores_data_shape,
const op::v8::MulticlassNms::Attributes& attrs,
const int64_t* roisnum_data,
const Shape& roisnum_data_shape,
const op::util::MulticlassNmsBase::Attributes& attrs,
float* selected_outputs,
const Shape& selected_outputs_shape,
int64_t* selected_indices,
const Shape& selected_indices_shape,
int64_t* valid_outputs) {
using SelectedIndex = multiclass_nms_v8::SelectedIndex;
using SelectedOutput = multiclass_nms_v8::SelectedOutput;
using BoxInfo = multiclass_nms_v8::BoxInfo;
using Rectangle = multiclass_nms_v8::Rectangle;
using namespace multiclass_nms_impl;
auto func = [](float iou, float adaptive_threshold) {
return iou <= adaptive_threshold ? 1.0f : 0.0f;
};
// boxes shape: {num_batches, num_boxes, 4}
// scores shape: {num_batches, num_classes, num_boxes}
int64_t num_batches = static_cast<int64_t>(scores_data_shape[0]);
int64_t num_classes = static_cast<int64_t>(scores_data_shape[1]);
int64_t num_boxes = static_cast<int64_t>(boxes_data_shape[1]);
SelectedIndex* selected_indices_ptr = reinterpret_cast<SelectedIndex*>(selected_indices);
SelectedOutput* selected_scores_ptr = reinterpret_cast<SelectedOutput*>(selected_outputs);
const auto shared = scores_data_shape.size() == 3; // bboxes shared among classes
const bool has_roinum = roisnum_data;
std::vector<BoxInfo> filteredBoxes; // container for the whole batch
for (int64_t batch = 0; batch < num_batches; batch++) {
const float* boxesPtr = boxes_data + batch * num_boxes * 4;
Rectangle* r = reinterpret_cast<Rectangle*>(const_cast<float*>(boxesPtr));
int64_t num_images = 0;
if (has_roinum) {
num_images = static_cast<int64_t>(shared ? scores_data_shape[0] : roisnum_data_shape[0]);
} else {
OPENVINO_ASSERT(shared, "Expect the input 'scores' is a 3D tensor when there is no 'roisnum' input.");
num_images = static_cast<int64_t>(scores_data_shape[0]);
}
int64_t num_dets = 0;
std::vector<BoxInfo> selected_boxes; // container for a batch element
int64_t head = 0;
for (int64_t i = 0; i < num_images; i++) {
std::vector<BoxInfo> selected_boxes;
if (shared) {
const auto num_boxes = boxes_data_shape[1];
const auto num_classes = scores_data_shape[1];
for (int64_t class_idx = 0; class_idx < num_classes; class_idx++) {
if (class_idx == attrs.background_class)
continue;
const float* boxesPtr = boxes_data + i * num_boxes * 4;
const float* scoresPtr = scores_data + i * num_classes * num_boxes;
auto adaptive_threshold = attrs.iou_threshold;
const Shape boxes_sp = {1, num_boxes, 4};
const Shape scores_sp = {1, num_classes, num_boxes};
const float* scoresPtr = scores_data + batch * (num_classes * num_boxes) + class_idx * num_boxes;
std::vector<BoxInfo> candidate_boxes;
for (int64_t box_idx = 0; box_idx < num_boxes; box_idx++) {
if (scoresPtr[box_idx] >= attrs.score_threshold) /* NOTE: ">=" instead of ">" used in PDPD */
{
candidate_boxes.emplace_back(r[box_idx], box_idx, scoresPtr[box_idx], 0, batch, class_idx);
}
}
int candiate_size = candidate_boxes.size();
// threshold nms_top_k for each class
// NOTE: "nms_top_k" in PDPD not exactly equal to
// "max_output_boxes_per_class" in ONNX.
if (attrs.nms_top_k > -1 && attrs.nms_top_k < candiate_size) {
candiate_size = attrs.nms_top_k;
}
if (candiate_size <= 0) // early drop
{
selected_boxes = multiclass_nms(boxesPtr, boxes_sp, scoresPtr, scores_sp, attrs, i, shared);
} else {
if (roisnum_data[i] <= 0) {
*valid_outputs++ = 0;
continue;
}
// sort by score in current class
std::partial_sort(candidate_boxes.begin(),
candidate_boxes.begin() + candiate_size,
candidate_boxes.end(),
std::greater<BoxInfo>());
const auto num_classes = boxes_data_shape[0];
std::priority_queue<BoxInfo> sorted_boxes(candidate_boxes.begin(),
candidate_boxes.begin() + candiate_size,
std::less<BoxInfo>());
const auto boxes = slice_image(boxes_data, boxes_data_shape, head, roisnum_data[i]);
const auto scores = slice_image(scores_data, scores_data_shape, head, roisnum_data[i]);
std::vector<BoxInfo> selected; // container for a class
const Shape boxes_sp = {num_classes, static_cast<size_t>(roisnum_data[i]), 4};
const Shape scores_sp = {num_classes, static_cast<size_t>(roisnum_data[i])};
// Get the next box with top score, filter by iou_threshold
BoxInfo next_candidate;
float original_score;
selected_boxes = multiclass_nms(boxes.data(), boxes_sp, scores.data(), scores_sp, attrs, i, shared);
while (!sorted_boxes.empty()) {
next_candidate = sorted_boxes.top();
original_score = next_candidate.score;
sorted_boxes.pop();
bool should_hard_suppress = false;
for (int64_t j = static_cast<int64_t>(selected.size()) - 1; j >= next_candidate.suppress_begin_index;
--j) {
float iou =
multiclass_nms_v8::intersectionOverUnion(next_candidate.box, selected[j].box, attrs.normalized);
next_candidate.score *= func(iou, adaptive_threshold);
if (iou >= adaptive_threshold) {
should_hard_suppress = true;
break;
}
if (next_candidate.score <= attrs.score_threshold) {
break;
}
}
next_candidate.suppress_begin_index = selected.size();
if (!should_hard_suppress) {
if (attrs.nms_eta < 1 && adaptive_threshold > 0.5) {
adaptive_threshold *= attrs.nms_eta;
}
if (next_candidate.score == original_score) {
selected.push_back(next_candidate);
continue;
}
if (next_candidate.score > attrs.score_threshold) {
sorted_boxes.push(next_candidate);
}
}
}
for (const auto& box_info : selected) {
selected_boxes.push_back(box_info);
}
num_dets += selected.size();
} // for each class
// sort inside batch element before go through keep_top_k
std::sort(selected_boxes.begin(), selected_boxes.end(), [](const BoxInfo& l, const BoxInfo& r) {
return ((l.batch_index == r.batch_index) &&
((l.score > r.score) || ((std::fabs(l.score - r.score) < 1e-6) && l.class_index < r.class_index) ||
((std::fabs(l.score - r.score) < 1e-6) && l.class_index == r.class_index && l.index < r.index)));
});
// threshold keep_top_k for each batch element
if (attrs.keep_top_k > -1 && attrs.keep_top_k < num_dets) {
num_dets = attrs.keep_top_k;
selected_boxes.resize(num_dets);
head += roisnum_data[i];
}
// sort
if (!attrs.sort_result_across_batch) {
if (attrs.sort_result_type == op::v8::MulticlassNms::SortResultType::CLASSID) {
std::sort(selected_boxes.begin(), selected_boxes.end(), [](const BoxInfo& l, const BoxInfo& r) {
return ((l.batch_index == r.batch_index) &&
((l.class_index < r.class_index) ||
((l.class_index == r.class_index) && l.score > r.score) ||
((std::fabs(l.score - r.score) <= 1e-6) && l.class_index == r.class_index &&
l.index < r.index)));
});
}
// in case of "SCORE", pass through, as,
// it has already gurranteed.
}
*valid_outputs++ = static_cast<int64_t>(selected_boxes.size());
*valid_outputs++ = num_dets;
for (auto& v : selected_boxes) {
filteredBoxes.push_back(v);
}
} // for each batch element
if (attrs.sort_result_across_batch) { /* sort across batch */
if (attrs.sort_result_type == op::v8::MulticlassNms::SortResultType::SCORE) {
if (attrs.sort_result_type == op::util::MulticlassNmsBase::SortResultType::SCORE) {
std::sort(filteredBoxes.begin(), filteredBoxes.end(), [](const BoxInfo& l, const BoxInfo& r) {
return (l.score > r.score) || (l.score == r.score && l.batch_index < r.batch_index) ||
(l.score == r.score && l.batch_index == r.batch_index && l.class_index < r.class_index) ||
(l.score == r.score && l.batch_index == r.batch_index && l.class_index == r.class_index &&
l.index < r.index);
});
} else if (attrs.sort_result_type == op::v8::MulticlassNms::SortResultType::CLASSID) {
} else if (attrs.sort_result_type == op::util::MulticlassNmsBase::SortResultType::CLASSID) {
std::sort(filteredBoxes.begin(), filteredBoxes.end(), [](const BoxInfo& l, const BoxInfo& r) {
return (l.class_index < r.class_index) ||
(l.class_index == r.class_index && l.batch_index < r.batch_index) ||
@@ -252,6 +502,8 @@ void multiclass_nms(const float* boxes_data,
}
/* output */
SelectedIndex* selected_indices_ptr = reinterpret_cast<SelectedIndex*>(selected_indices);
SelectedOutput* selected_scores_ptr = reinterpret_cast<SelectedOutput*>(selected_outputs);
size_t max_num_of_selected_indices = selected_indices_shape[0];
size_t output_size = std::min(filteredBoxes.size(), max_num_of_selected_indices);
@@ -259,7 +511,18 @@ void multiclass_nms(const float* boxes_data,
size_t idx;
for (idx = 0; idx < output_size; idx++) {
const auto& box_info = filteredBoxes[idx];
SelectedIndex selected_index{box_info.batch_index, box_info.index, num_boxes};
SelectedIndex selected_index;
if (shared) {
const auto num_boxes = static_cast<int64_t>(boxes_data_shape[1]);
selected_index = {box_info.batch_index, box_info.index, num_boxes};
} else {
const auto num_classes = static_cast<int64_t>(boxes_data_shape[0]);
int64_t offset = 0;
for (int64_t i = 0; i < box_info.batch_index; i++) {
offset += roisnum_data[i];
}
selected_index = {(offset + box_info.index), box_info.class_index, num_classes};
}
SelectedOutput selected_score{static_cast<float>(box_info.class_index),
box_info.score,
box_info.box.x1,
@@ -0,0 +1,203 @@
// Copyright (C) 2018-2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <vector>
#include <openvino/op/multiclass_nms.hpp>
#include <openvino/op/util/multiclass_nms_base.hpp>
namespace ov {
namespace op {
namespace util {
template <class T>
void shape_infer(const ov::op::util::MulticlassNmsBase* op,
const std::vector<T>& input_shapes,
std::vector<T>& output_shapes,
bool static_output = false,
bool ignore_bg_class = false) {
NODE_VALIDATION_CHECK(op, (input_shapes.size() == 2 || input_shapes.size() == 3)
&& output_shapes.size() == 3);
const auto& boxes_ps = input_shapes[0];
const auto& scores_ps = input_shapes[1];
const auto& nms_attrs = op->get_attrs();
const auto nms_top_k = nms_attrs.nms_top_k;
const auto keep_top_k = nms_attrs.keep_top_k;
// validate rank of each input
if (boxes_ps.rank().is_dynamic() || scores_ps.rank().is_dynamic()) {
return;
}
if (op->get_input_size() == 3) {
NODE_VALIDATION_CHECK(op, input_shapes.size() == 3);
const auto& roisnum_ps = input_shapes[2];
if (roisnum_ps.rank().is_dynamic()) {
return;
}
}
// validate shape of each input
NODE_VALIDATION_CHECK(op,
boxes_ps.rank().is_static() && boxes_ps.rank().get_length() == 3,
"Expected a 3D tensor for the 'boxes' input. Got: ",
boxes_ps);
NODE_VALIDATION_CHECK(op,
boxes_ps[2].is_static() && boxes_ps[2].get_length() == 4,
"The third dimension of the 'boxes' must be 4. Got: ",
boxes_ps[2]);
if (ov::is_type<ov::op::v8::MulticlassNms>(op)) {
NODE_VALIDATION_CHECK(
op,
scores_ps.rank().is_static() && scores_ps.rank().get_length() == 3,
"Expected a 3D tensor for the 'scores' input. Got: ",
scores_ps);
} else {
NODE_VALIDATION_CHECK(
op,
scores_ps.rank().is_static() && (scores_ps.rank().get_length() == 3 || scores_ps.rank().get_length() == 2),
"Expected a 2D or 3D tensor for the 'scores' input. Got: ",
scores_ps);
}
if (op->get_input_size() == 3) {
const auto& roisnum_ps = input_shapes[2];
NODE_VALIDATION_CHECK(op,
roisnum_ps.rank().is_static() && roisnum_ps.rank().get_length() == 1,
"Expected a 1D tensor for the 'roisnum' input. Got: ",
roisnum_ps);
}
// validate compatibility of input shapes
if (scores_ps.rank().is_static() && scores_ps.rank().get_length() == 3) { // if scores shape (N, C, M)
const auto num_batches_boxes = boxes_ps[0];
const auto num_batches_scores = scores_ps[0];
NODE_VALIDATION_CHECK(op,
num_batches_boxes.same_scheme(num_batches_scores),
"The first dimension of both 'boxes' and 'scores' must match. Boxes: ",
num_batches_boxes,
"; Scores: ",
num_batches_scores);
const auto num_boxes_boxes = boxes_ps[1];
const auto num_boxes_scores = scores_ps[2];
NODE_VALIDATION_CHECK(op,
num_boxes_boxes.same_scheme(num_boxes_scores),
"'boxes' and 'scores' input shapes must match at the second and third "
"dimension respectively. Boxes: ",
num_boxes_boxes,
"; Scores: ",
num_boxes_scores);
}
if (scores_ps.rank().is_static() && scores_ps.rank().get_length() == 2) { // if scores shape (C, M)
NODE_VALIDATION_CHECK(op,
op->get_input_size() == 3,
"Expected the 'roisnum' input when the input 'scores' is a 2D tensor.");
const auto num_classes_boxes = boxes_ps[0];
const auto num_classes_scores = scores_ps[0];
NODE_VALIDATION_CHECK(op,
num_classes_boxes.same_scheme(num_classes_scores),
"'boxes' and 'scores' input shapes must match. Boxes: ",
num_classes_boxes,
"; Scores: ",
num_classes_scores);
const auto num_boxes_boxes = boxes_ps[1];
const auto num_boxes_scores = scores_ps[1];
NODE_VALIDATION_CHECK(op,
num_boxes_boxes.same_scheme(num_boxes_scores),
"'boxes' and 'scores' input shapes must match. Boxes: ",
num_boxes_boxes,
"; Scores: ",
num_boxes_scores);
}
/* rank of inputs have been static since here. */
auto _ready_infer = [&]() {
if (boxes_ps.rank().is_dynamic() || scores_ps.rank().is_dynamic()) {
return false;
}
const bool shared = (scores_ps.rank().get_length() == 3);
if (shared) {
return boxes_ps[1].is_static() && scores_ps[1].is_static() && scores_ps[0].is_static();
} else {
const auto& roisnum_ps = input_shapes[2];
if (roisnum_ps.rank().is_dynamic()) {
return false;
}
return boxes_ps[1].is_static() && boxes_ps[0].is_static() && roisnum_ps[0].is_static();
}
};
// Here output 0 and output 1 is not the real dimension of output.
// It will be rewritten in the computing runtime.
// But we still need it here for static shape only backends.
auto first_dim_shape = Dimension::dynamic();
if (_ready_infer()) {
const bool shared = (scores_ps.rank().get_length() == 3);
ov::PartialShape roisnum_ps;
if (!shared) {
roisnum_ps = input_shapes[2];
}
const auto num_boxes = shared ? boxes_ps[1].get_length() : boxes_ps[1].get_length();
auto num_classes = shared ? scores_ps[1].get_length() : boxes_ps[0].get_length();
auto num_images = shared ? scores_ps[0].get_length() : roisnum_ps[0].get_length();
if (ignore_bg_class) {
if (nms_attrs.background_class >= 0 && nms_attrs.background_class < num_classes) {
num_classes = std::max(int64_t{1}, num_classes - 1);
}
}
int64_t max_output_boxes_per_class = 0;
if (nms_top_k >= 0)
max_output_boxes_per_class = std::min(num_boxes, (int64_t)nms_top_k);
else
max_output_boxes_per_class = num_boxes;
auto max_output_boxes_per_batch = max_output_boxes_per_class * num_classes;
if (keep_top_k >= 0)
max_output_boxes_per_batch = std::min(max_output_boxes_per_batch, (int64_t)keep_top_k);
first_dim_shape = static_output ? max_output_boxes_per_batch * num_images
: Dimension(0, max_output_boxes_per_batch * num_images);
}
// 'selected_outputs' have the following format:
// [number of selected boxes, [class_id, box_score, xmin, ymin, xmax, ymax]]
output_shapes[0] = {first_dim_shape, 6};
// 'selected_indices' have the following format:
// [number of selected boxes, ]
output_shapes[1] = {first_dim_shape, 1};
// 'selected_num' have the following format:
// [num_batches, ]
if (op->get_input_size() == 3) {
const auto& roisnum_ps = input_shapes[2];
if (roisnum_ps.rank().is_static() && roisnum_ps.rank().get_length() > 0) {
output_shapes[2] = {roisnum_ps[0]};
} else {
output_shapes[2] = {Dimension::dynamic()};
}
} else { // shared
if (boxes_ps.rank().is_static() && boxes_ps.rank().get_length() > 0) {
output_shapes[2] = {boxes_ps[0]};
} else {
output_shapes[2] = {Dimension::dynamic()};
}
}
}
} // namespace util
} // namespace op
} // namespace ov
+101 -6
View File
@@ -17,12 +17,10 @@
#include "ngraph/util.hpp"
using namespace ngraph;
BWDCMP_RTTI_DEFINITION(ov::op::v8::MatrixNms);
op::v8::MatrixNms::MatrixNms() : NmsBase(m_attrs.output_type, m_attrs.nms_top_k, m_attrs.keep_top_k) {}
BWDCMP_RTTI_DEFINITION(op::v8::MatrixNms);
op::v8::MatrixNms::MatrixNms(const Output<Node>& boxes, const Output<Node>& scores, const Attributes& attrs)
: NmsBase(boxes, scores, m_attrs.output_type, m_attrs.nms_top_k, m_attrs.keep_top_k),
: Op({boxes, scores}),
m_attrs{attrs} {
constructor_validate_and_infer_types();
}
@@ -37,7 +35,37 @@ std::shared_ptr<Node> op::v8::MatrixNms::clone_with_new_inputs(const OutputVecto
void op::v8::MatrixNms::validate() {
NGRAPH_OP_SCOPE(v8_MatrixNms_validate);
NmsBase::validate();
const auto& nms_attrs = this->get_attrs();
const auto output_type = nms_attrs.output_type;
const auto nms_top_k = nms_attrs.nms_top_k;
const auto keep_top_k = nms_attrs.keep_top_k;
auto is_float_type_admissible = [](const element::Type& t) {
return t == element::f32 || t == element::f16 || t == element::bf16;
};
// validate dtype of each input
NODE_VALIDATION_CHECK(this,
output_type == element::i64 || output_type == element::i32,
"Output type must be i32 or i64");
NODE_VALIDATION_CHECK(this,
is_float_type_admissible(this->get_input_element_type(0)),
"Expected bf16, fp16 or fp32 as element type for the 'boxes' input.");
NODE_VALIDATION_CHECK(this,
is_float_type_admissible(this->get_input_element_type(1)),
"Expected bf16, fp16 or fp32 as element type for the 'scores' input.");
NODE_VALIDATION_CHECK(this,
this->get_input_element_type(0).compatible(this->get_input_element_type(1)),
"Expected 'boxes', 'scores' type is same.");
// validate attributes
NODE_VALIDATION_CHECK(this, nms_top_k >= -1, "The 'nms_top_k' must be great or equal -1. Got:", nms_top_k);
NODE_VALIDATION_CHECK(this, keep_top_k >= -1, "The 'keep_top_k' must be great or equal -1. Got:", keep_top_k);
NODE_VALIDATION_CHECK(this,
m_attrs.background_class >= -1,
@@ -45,7 +73,55 @@ void op::v8::MatrixNms::validate() {
m_attrs.background_class);
}
bool ngraph::op::v8::MatrixNms::visit_attributes(AttributeVisitor& visitor) {
void op::v8::MatrixNms::validate_and_infer_types() {
NGRAPH_OP_SCOPE(v8_MatrixNms_validate_and_infer_types);
const auto boxes_ps = get_input_partial_shape(0);
const auto scores_ps = get_input_partial_shape(1);
auto first_dim_shape = Dimension::dynamic();
validate();
const auto& nms_attrs = this->get_attrs();
const auto output_type = nms_attrs.output_type;
const auto nms_top_k = nms_attrs.nms_top_k;
const auto keep_top_k = nms_attrs.keep_top_k;
if (boxes_ps.rank().is_static() && scores_ps.rank().is_static()) {
const auto num_boxes_boxes = boxes_ps[1];
if (num_boxes_boxes.is_static() && scores_ps[0].is_static() && scores_ps[1].is_static()) {
const auto num_boxes = num_boxes_boxes.get_length();
const auto num_classes = scores_ps[1].get_length();
int64_t max_output_boxes_per_class = 0;
if (nms_top_k >= 0)
max_output_boxes_per_class = std::min(num_boxes, (int64_t)nms_top_k);
else
max_output_boxes_per_class = num_boxes;
auto max_output_boxes_per_batch = max_output_boxes_per_class * num_classes;
if (keep_top_k >= 0)
max_output_boxes_per_batch = std::min(max_output_boxes_per_batch, (int64_t)keep_top_k);
first_dim_shape = Dimension(0, max_output_boxes_per_batch * scores_ps[0].get_length());
}
}
// 'selected_outputs' have the following format:
// [number of selected boxes, [class_id, box_score, xmin, ymin, xmax, ymax]]
set_output_type(0, get_input_element_type(0), {first_dim_shape, 6});
// 'selected_indices' have the following format:
// [number of selected boxes, ]
set_output_type(1, output_type, {first_dim_shape, 1});
// 'selected_num' have the following format:
// [num_batches, ]
if (boxes_ps.rank().is_static() && boxes_ps.rank().get_length() > 0) {
set_output_type(2, output_type, {boxes_ps[0]});
} else {
set_output_type(2, output_type, {Dimension::dynamic()});
}
}
bool op::v8::MatrixNms::visit_attributes(AttributeVisitor& visitor) {
NGRAPH_OP_SCOPE(v8_MatrixNms_visit_attributes);
visitor.on_attribute("sort_result_type", m_attrs.sort_result_type);
@@ -81,3 +157,22 @@ EnumNames<ngraph::op::v8::MatrixNms::DecayFunction>::get() {
BWDCMP_RTTI_DEFINITION(AttributeAdapter<op::v8::MatrixNms::DecayFunction>);
} // namespace ov
std::ostream& ov::operator<<(std::ostream& s, const op::v8::MatrixNms::SortResultType& type) {
return s << as_string(type);
}
namespace ov {
template <>
NGRAPH_API EnumNames<op::v8::MatrixNms::SortResultType>& EnumNames<op::v8::MatrixNms::SortResultType>::get() {
static auto enum_names =
EnumNames<op::v8::MatrixNms::SortResultType>("op::v8::MatrixNms::SortResultType",
{{"classid", op::v8::MatrixNms::SortResultType::CLASSID},
{"score", op::v8::MatrixNms::SortResultType::SCORE},
{"none", op::v8::MatrixNms::SortResultType::NONE}});
return enum_names;
}
BWDCMP_RTTI_DEFINITION(AttributeAdapter<op::v8::MatrixNms::SortResultType>);
} // namespace ov
+71 -42
View File
@@ -4,66 +4,95 @@
#include "ngraph/op/multiclass_nms.hpp"
#include <cstring>
#include <ngraph/validation_util.hpp>
#include "itt.hpp"
#include "ngraph/attribute_visitor.hpp"
#include "ngraph/op/constant.hpp"
#include "ngraph/op/util/op_types.hpp"
#include "ngraph/runtime/reference/multiclass_nms.hpp"
#include "ngraph/type/bfloat16.hpp"
#include "ngraph/type/float16.hpp"
#include "ngraph/util.hpp"
#include "multiclass_nms_shape_inference.hpp"
using namespace ngraph;
using namespace op::util;
BWDCMP_RTTI_DEFINITION(ov::op::v8::MulticlassNms);
BWDCMP_RTTI_DEFINITION(op::v8::MulticlassNms);
BWDCMP_RTTI_DEFINITION(op::v9::MulticlassNms);
op::v8::MulticlassNms::MulticlassNms() : NmsBase(m_attrs.output_type, m_attrs.nms_top_k, m_attrs.keep_top_k) {}
// ------------------------------ V8 ------------------------------
op::v8::MulticlassNms::MulticlassNms(const Output<Node>& boxes, const Output<Node>& scores, const Attributes& attrs)
: NmsBase(boxes, scores, m_attrs.output_type, m_attrs.nms_top_k, m_attrs.keep_top_k),
m_attrs{attrs} {
: MulticlassNmsBase({boxes, scores}, attrs) {
constructor_validate_and_infer_types();
}
std::shared_ptr<Node> op::v8::MulticlassNms::clone_with_new_inputs(const OutputVector& new_args) const {
NGRAPH_OP_SCOPE(v8_MulticlassNms_clone_with_new_inputs);
NGRAPH_OP_SCOPE(MulticlassNms_v8_clone_with_new_inputs);
check_new_args_count(this, new_args);
NODE_VALIDATION_CHECK(this, new_args.size() == 2, "Number of inputs must be 2");
NODE_VALIDATION_CHECK(this, new_args.size() >= 2, "Number of inputs must be 2 at least");
return std::make_shared<op::v8::MulticlassNms>(new_args.at(0), new_args.at(1), m_attrs);
return std::make_shared<MulticlassNms>(new_args.at(0), new_args.at(1), m_attrs);
}
void op::v8::MulticlassNms::validate() {
NGRAPH_OP_SCOPE(v8_MulticlassNms_validate);
NmsBase::validate();
void op::v8::MulticlassNms::validate_and_infer_types() {
NGRAPH_OP_SCOPE(MulticlassNms_v9_validate_and_infer_types);
const auto output_type = get_attrs().output_type;
NODE_VALIDATION_CHECK(this,
m_attrs.background_class >= -1,
"The 'background_class' must be great or equal -1. Got:",
m_attrs.background_class);
validate();
NODE_VALIDATION_CHECK(this,
m_attrs.nms_eta >= 0.0f && m_attrs.nms_eta <= 1.0f,
"The 'nms_eta' must be in close range [0, 1.0]. Got:",
m_attrs.nms_eta);
const auto& boxes_ps = get_input_partial_shape(0);
const auto& scores_ps = get_input_partial_shape(1);
std::vector<PartialShape> input_shapes = {boxes_ps, scores_ps};
std::vector<PartialShape> output_shapes = {{Dimension::dynamic(), 6},
{Dimension::dynamic(), 1},
{Dimension::dynamic()}};
shape_infer(this, input_shapes, output_shapes, false, false);
set_output_type(0, get_input_element_type(0), output_shapes[0]);
set_output_type(1, output_type, output_shapes[1]);
set_output_type(2, output_type, output_shapes[2]);
}
bool ngraph::op::v8::MulticlassNms::visit_attributes(AttributeVisitor& visitor) {
NGRAPH_OP_SCOPE(v8_MulticlassNms_visit_attributes);
// ------------------------------ V9 ------------------------------
visitor.on_attribute("sort_result_type", m_attrs.sort_result_type);
visitor.on_attribute("output_type", m_attrs.output_type);
visitor.on_attribute("nms_top_k", m_attrs.nms_top_k);
visitor.on_attribute("keep_top_k", m_attrs.keep_top_k);
visitor.on_attribute("sort_result_across_batch", m_attrs.sort_result_across_batch);
visitor.on_attribute("iou_threshold", m_attrs.iou_threshold);
visitor.on_attribute("score_threshold", m_attrs.score_threshold);
visitor.on_attribute("background_class", m_attrs.background_class);
visitor.on_attribute("nms_eta", m_attrs.nms_eta);
visitor.on_attribute("normalized", m_attrs.normalized);
return true;
op::v9::MulticlassNms::MulticlassNms(const Output<Node>& boxes, const Output<Node>& scores, const Attributes& attrs)
: MulticlassNmsBase({boxes, scores}, attrs) {
constructor_validate_and_infer_types();
}
op::v9::MulticlassNms::MulticlassNms(const Output<Node>& boxes,
const Output<Node>& scores,
const Output<Node>& roisnum,
const Attributes& attrs)
: MulticlassNmsBase({boxes, scores, roisnum}, attrs) {
constructor_validate_and_infer_types();
}
std::shared_ptr<Node> op::v9::MulticlassNms::clone_with_new_inputs(const OutputVector& new_args) const {
NGRAPH_OP_SCOPE(MulticlassNms_v9_clone_with_new_inputs);
check_new_args_count(this, new_args);
NODE_VALIDATION_CHECK(this, new_args.size() == 2 || new_args.size() == 3, "Number of inputs must be 2 or 3");
switch (new_args.size()) {
case 3:
return std::make_shared<MulticlassNms>(new_args.at(0), new_args.at(1), new_args.at(2), m_attrs);
default:
return std::make_shared<MulticlassNms>(new_args.at(0), new_args.at(1), m_attrs);
}
}
void op::v9::MulticlassNms::validate_and_infer_types() {
NGRAPH_OP_SCOPE(MulticlassNms_v9_validate_and_infer_types);
const auto output_type = get_attrs().output_type;
validate();
const auto& boxes_ps = get_input_partial_shape(0);
const auto& scores_ps = get_input_partial_shape(1);
std::vector<PartialShape> input_shapes = {boxes_ps, scores_ps};
if (get_input_size() == 3) {
const auto& roisnum_ps = get_input_partial_shape(2);
input_shapes.push_back(roisnum_ps);
}
std::vector<PartialShape> output_shapes = {{Dimension::dynamic(), 6},
{Dimension::dynamic(), 1},
{Dimension::dynamic()}};
shape_infer(this, input_shapes, output_shapes, false, false);
set_output_type(0, get_input_element_type(0), output_shapes[0]);
set_output_type(1, output_type, output_shapes[1]);
set_output_type(2, output_type, output_shapes[2]);
}
@@ -0,0 +1,103 @@
// Copyright (C) 2018-2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "openvino/op/util/multiclass_nms_base.hpp"
#include "itt.hpp"
using namespace ov;
BWDCMP_RTTI_DEFINITION(ov::op::util::MulticlassNmsBase);
op::util::MulticlassNmsBase::MulticlassNmsBase(const OutputVector& arguments, const Attributes& attrs)
: Op(arguments),
m_attrs{attrs} {}
void op::util::MulticlassNmsBase::validate() {
NGRAPH_OP_SCOPE(util_MulticlassNmsBase_validate);
const auto& nms_attrs = this->get_attrs();
const auto output_type = nms_attrs.output_type;
const auto nms_top_k = nms_attrs.nms_top_k;
const auto keep_top_k = nms_attrs.keep_top_k;
auto is_float_type_admissible = [](const element::Type& t) {
return t == element::f32 || t == element::f16 || t == element::bf16;
};
// validate dtype of each input
NODE_VALIDATION_CHECK(this,
output_type == element::i64 || output_type == element::i32,
"Output type must be i32 or i64");
NODE_VALIDATION_CHECK(this,
is_float_type_admissible(this->get_input_element_type(0)),
"Expected bf16, fp16 or fp32 as element type for the 'boxes' input.");
NODE_VALIDATION_CHECK(this,
is_float_type_admissible(this->get_input_element_type(1)),
"Expected bf16, fp16 or fp32 as element type for the 'scores' input.");
NODE_VALIDATION_CHECK(this,
this->get_input_element_type(0).compatible(this->get_input_element_type(1)),
"Expected 'boxes', 'scores' type is same.");
if (this->get_input_size() == 3) {
NODE_VALIDATION_CHECK(
this,
this->get_input_element_type(2) == element::i64 || this->get_input_element_type(2) == element::i32,
"Expected i64 or i32 as element type for the 'roisnum' input.");
}
// validate attributes
NODE_VALIDATION_CHECK(this, nms_top_k >= -1, "The 'nms_top_k' must be great or equal -1. Got:", nms_top_k);
NODE_VALIDATION_CHECK(this, keep_top_k >= -1, "The 'keep_top_k' must be great or equal -1. Got:", keep_top_k);
NODE_VALIDATION_CHECK(this,
m_attrs.background_class >= -1,
"The 'background_class' must be great or equal -1. Got:",
m_attrs.background_class);
NODE_VALIDATION_CHECK(this,
m_attrs.nms_eta >= 0.0f && m_attrs.nms_eta <= 1.0f,
"The 'nms_eta' must be in close range [0, 1.0]. Got:",
m_attrs.nms_eta);
}
bool op::util::MulticlassNmsBase::visit_attributes(AttributeVisitor& visitor) {
NGRAPH_OP_SCOPE(util_MulticlassNmsBase_visit_attributes);
visitor.on_attribute("sort_result_type", m_attrs.sort_result_type);
visitor.on_attribute("output_type", m_attrs.output_type);
visitor.on_attribute("nms_top_k", m_attrs.nms_top_k);
visitor.on_attribute("keep_top_k", m_attrs.keep_top_k);
visitor.on_attribute("sort_result_across_batch", m_attrs.sort_result_across_batch);
visitor.on_attribute("iou_threshold", m_attrs.iou_threshold);
visitor.on_attribute("score_threshold", m_attrs.score_threshold);
visitor.on_attribute("background_class", m_attrs.background_class);
visitor.on_attribute("nms_eta", m_attrs.nms_eta);
visitor.on_attribute("normalized", m_attrs.normalized);
return true;
}
std::ostream& ov::operator<<(std::ostream& s, const op::util::MulticlassNmsBase::SortResultType& type) {
return s << as_string(type);
}
namespace ov {
template <>
NGRAPH_API EnumNames<op::util::MulticlassNmsBase::SortResultType>&
EnumNames<op::util::MulticlassNmsBase::SortResultType>::get() {
static auto enum_names = EnumNames<op::util::MulticlassNmsBase::SortResultType>(
"op::util::MulticlassNmsBase::SortResultType",
{{"classid", op::util::MulticlassNmsBase::SortResultType::CLASSID},
{"score", op::util::MulticlassNmsBase::SortResultType::SCORE},
{"none", op::util::MulticlassNmsBase::SortResultType::NONE}});
return enum_names;
}
BWDCMP_RTTI_DEFINITION(AttributeAdapter<op::util::MulticlassNmsBase::SortResultType>);
} // namespace ov
-164
View File
@@ -1,164 +0,0 @@
// Copyright (C) 2018-2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "ngraph/op/util/nms_base.hpp"
#include <cstring>
#include <ngraph/validation_util.hpp>
#include "itt.hpp"
#include "ngraph/attribute_visitor.hpp"
#include "ngraph/op/constant.hpp"
#include "ngraph/op/util/op_types.hpp"
#include "ngraph/type/bfloat16.hpp"
#include "ngraph/type/float16.hpp"
#include "ngraph/util.hpp"
ov::op::util::NmsBase::NmsBase(ngraph::element::Type& output_type, int& nms_top_k, int& keep_top_k)
: m_output_type(output_type),
m_nms_top_k(nms_top_k),
m_keep_top_k(keep_top_k) {}
ov::op::util::NmsBase::NmsBase(const Output<Node>& boxes,
const Output<Node>& scores,
ngraph::element::Type& output_type,
int& nms_top_k,
int& keep_top_k)
: Op({boxes, scores}),
m_output_type(output_type),
m_nms_top_k(nms_top_k),
m_keep_top_k(keep_top_k) {}
namespace {
inline bool is_float_type_admissible(const ov::element::Type& t) {
return t == ov::element::f32 || t == ov::element::f16 || t == ov::element::bf16;
}
} // namespace
void ov::op::util::NmsBase::validate() {
NGRAPH_OP_SCOPE(util_NmsBase_validate);
const auto boxes_ps = get_input_partial_shape(0);
const auto scores_ps = get_input_partial_shape(1);
NODE_VALIDATION_CHECK(this,
m_output_type == element::i64 || m_output_type == element::i32,
"Output type must be i32 or i64");
if (boxes_ps.is_dynamic() || scores_ps.is_dynamic()) {
return;
}
NODE_VALIDATION_CHECK(this,
is_float_type_admissible(get_input_element_type(0)),
"Expected bf16, fp16 or fp32 as element type for the 'boxes' input.");
NODE_VALIDATION_CHECK(this,
is_float_type_admissible(get_input_element_type(1)),
"Expected bf16, fp16 or fp32 as element type for the 'scores' input.");
NODE_VALIDATION_CHECK(this,
get_input_element_type(0).compatible(get_input_element_type(1)),
"Expected 'boxes', 'scores' type is same.");
NODE_VALIDATION_CHECK(this,
boxes_ps.rank().is_static() && boxes_ps.rank().get_length() == 3,
"Expected a 3D tensor for the 'boxes' input. Got: ",
boxes_ps);
NODE_VALIDATION_CHECK(this,
boxes_ps[2].is_static() && boxes_ps[2].get_length() == 4,
"The third dimension of the 'boxes' must be 4. Got: ",
boxes_ps[2]);
NODE_VALIDATION_CHECK(this,
scores_ps.rank().is_static() && scores_ps.rank().get_length() == 3,
"Expected a 3D tensor for the 'scores' input. Got: ",
scores_ps);
NODE_VALIDATION_CHECK(this, m_nms_top_k >= -1, "The 'nms_top_k' must be great or equal -1. Got:", m_nms_top_k);
NODE_VALIDATION_CHECK(this, m_keep_top_k >= -1, "The 'keep_top_k' must be great or equal -1. Got:", m_keep_top_k);
const auto num_batches_boxes = boxes_ps[0];
const auto num_batches_scores = scores_ps[0];
NODE_VALIDATION_CHECK(this,
num_batches_boxes.same_scheme(num_batches_scores),
"The first dimension of both 'boxes' and 'scores' must match. Boxes: ",
num_batches_boxes,
"; Scores: ",
num_batches_scores);
const auto num_boxes_boxes = boxes_ps[1];
const auto num_boxes_scores = scores_ps[2];
NODE_VALIDATION_CHECK(this,
num_boxes_boxes.same_scheme(num_boxes_scores),
"'boxes' and 'scores' input shapes must match at the second and third "
"dimension respectively. Boxes: ",
num_boxes_boxes,
"; Scores: ",
num_boxes_scores);
}
void ov::op::util::NmsBase::validate_and_infer_types() {
NGRAPH_OP_SCOPE(util_NmsBase_validate_and_infer_types);
const auto boxes_ps = get_input_partial_shape(0);
const auto scores_ps = get_input_partial_shape(1);
auto first_dim_shape = Dimension::dynamic();
validate();
if (boxes_ps.rank().is_static() && scores_ps.rank().is_static()) {
const auto num_boxes_boxes = boxes_ps[1];
if (num_boxes_boxes.is_static() && scores_ps[0].is_static() && scores_ps[1].is_static()) {
const auto num_boxes = num_boxes_boxes.get_length();
const auto num_classes = scores_ps[1].get_length();
int64_t max_output_boxes_per_class = 0;
if (m_nms_top_k >= 0)
max_output_boxes_per_class = std::min(num_boxes, (int64_t)m_nms_top_k);
else
max_output_boxes_per_class = num_boxes;
auto max_output_boxes_per_batch = max_output_boxes_per_class * num_classes;
if (m_keep_top_k >= 0)
max_output_boxes_per_batch = std::min(max_output_boxes_per_batch, (int64_t)m_keep_top_k);
first_dim_shape = Dimension(0, max_output_boxes_per_batch * scores_ps[0].get_length());
}
}
// 'selected_outputs' have the following format:
// [number of selected boxes, [class_id, box_score, xmin, ymin, xmax, ymax]]
set_output_type(0, get_input_element_type(0), {first_dim_shape, 6});
// 'selected_indices' have the following format:
// [number of selected boxes, ]
set_output_type(1, m_output_type, {first_dim_shape, 1});
// 'selected_num' have the following format:
// [num_batches, ]
if (boxes_ps.rank().is_static() && boxes_ps.rank().get_length() > 0) {
set_output_type(2, m_output_type, {boxes_ps[0]});
} else {
set_output_type(2, m_output_type, {Dimension::dynamic()});
}
}
std::ostream& ov::operator<<(std::ostream& s, const op::util::NmsBase::SortResultType& type) {
return s << as_string(type);
}
namespace ov {
template <>
NGRAPH_API EnumNames<op::util::NmsBase::SortResultType>& EnumNames<op::util::NmsBase::SortResultType>::get() {
static auto enum_names =
EnumNames<op::util::NmsBase::SortResultType>("op::util::NmsBase::SortResultType",
{{"classid", op::util::NmsBase::SortResultType::CLASSID},
{"score", op::util::NmsBase::SortResultType::SCORE},
{"none", op::util::NmsBase::SortResultType::NONE}});
return enum_names;
}
BWDCMP_RTTI_DEFINITION(AttributeAdapter<op::util::NmsBase::SortResultType>);
} // namespace ov
+1
View File
@@ -425,6 +425,7 @@ set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/threading.cpp
if(SUGGEST_OVERRIDE_SUPPORTED)
set_source_files_properties(ov_tensor_test.cpp
type_prop/multiclass_nms.cpp
PROPERTIES COMPILE_OPTIONS -Wno-suggest-override)
endif()
+371 -314
View File
@@ -20,320 +20,377 @@ using namespace ov::frontend;
using PaddleFuzzyOpTest = FrontEndFuzzyOpTest;
static const std::vector<std::string> models{std::string("argmax"),
std::string("argmax1"),
std::string("assign_none/assign_none.pdmodel"),
std::string("assign_output/assign_output.pdmodel"),
std::string("assign_value_boolean"),
std::string("assign_value_fp32"),
std::string("assign_value_int32"),
std::string("assign_value_int64"),
std::string("avgAdaptivePool2D_test1"),
std::string("avgPool_test1"),
std::string("avgPool_test10"),
std::string("avgPool_test11"),
std::string("avgPool_test2"),
std::string("avgPool_test3"),
std::string("avgPool_test4"),
std::string("avgPool_test5"),
// avgPool_test6<nchw support is disabled now>,
std::string("avgPool_test7"),
std::string("avgPool_test8"),
std::string("avgPool_test9"),
std::string("batch_norm_nchw"),
std::string("batch_norm_nhwc"),
std::string("bicubic_downsample_false_0"),
std::string("bicubic_downsample_false_1"),
std::string("bicubic_downsample_true_0"),
std::string("bicubic_upsample_false_0"),
std::string("bicubic_upsample_false_1"),
std::string("bicubic_upsample_scales"),
std::string("bicubic_upsample_scales2"),
std::string("bicubic_upsample_true_0"),
std::string("bilinear_downsample_false_0"),
std::string("bilinear_downsample_false_1"),
std::string("bilinear_downsample_true_0"),
std::string("bilinear_upsample_false_0"),
std::string("bilinear_upsample_false_1"),
std::string("bilinear_upsample_scales"),
std::string("bilinear_upsample_scales2"),
std::string("bilinear_upsample_true_0"),
std::string("bmm"),
std::string("clip"),
std::string("conv2d_dilation_assymetric_pads_strides"),
std::string("conv2d_SAME_padding"),
std::string("conv2d_strides_assymetric_padding"),
std::string("conv2d_strides_no_padding"),
std::string("conv2d_strides_padding"),
std::string("conv2d_transpose_dilation_assymetric_pads_strides"),
// conv2d_transpose_SAME_padding(Paddle outputs wrong results),
std::string("conv2d_transpose_strides_assymetric_padding"),
std::string("conv2d_transpose_strides_no_padding"),
std::string("conv2d_transpose_strides_padding"),
std::string("conv2d_transpose_VALID_padding"),
std::string("conv2d_VALID_padding"),
std::string("cumsum"),
std::string("cumsum_i32"),
std::string("cumsum_i64"),
std::string("cumsum_f32"),
std::string("cumsum_f64"),
std::string("depthwise_conv2d_convolution"),
std::string("depthwise_conv2d_transpose_convolution"),
std::string("dropout"),
std::string("dropout_upscale_in_train"),
std::string("elementwise_add1"),
std::string("elementwise_div1"),
std::string("elementwise_max1"),
std::string("elementwise_min1"),
std::string("elementwise_mul1"),
std::string("elementwise_pow1"),
std::string("elementwise_sub1"),
std::string("elementwise_add2"),
std::string("elementwise_div2"),
std::string("elementwise_max2"),
std::string("elementwise_min2"),
std::string("elementwise_mul2"),
std::string("elementwise_pow2"),
std::string("elementwise_sub2"),
std::string("elementwise_add3"),
std::string("elementwise_div3"),
std::string("elementwise_max3"),
std::string("elementwise_min3"),
std::string("elementwise_mul3"),
std::string("elementwise_pow3"),
std::string("elementwise_sub3"),
std::string("elementwise_add4"),
std::string("elementwise_div4"),
std::string("elementwise_max4"),
std::string("elementwise_min4"),
std::string("elementwise_mul4"),
std::string("elementwise_pow4"),
std::string("elementwise_sub4"),
std::string("embedding_0"),
std::string("embedding_sparse"),
std::string("embedding_none_weight"),
std::string("embedding_paddings"),
std::string("embedding_paddings_neg1"),
std::string("embedding_tensorIds"),
std::string("embedding_tensorIds_paddings"),
std::string("equal"),
std::string("expand_v2"),
std::string("expand_v2_tensor"),
std::string("expand_v2_tensor_list"),
std::string("expand_v2_tensor_list2"),
std::string("exp_test_float32"),
std::string("fill_any_like"),
std::string("fill_any_like_f16"),
std::string("fill_any_like_f32"),
std::string("fill_any_like_f64"),
std::string("fill_any_like_i32"),
std::string("fill_any_like_i64"),
std::string("fill_constant"),
std::string("fill_constant_batch_size_like"),
std::string("fill_constant_int32"),
std::string("fill_constant_int64"),
std::string("fill_constant_tensor"),
std::string("fill_constant_shape_tensor"),
std::string("fill_constant_shape_tensor_list"),
std::string("flatten_contiguous_range_test1"),
std::string("floor_float32"),
std::string("gather_multi_dimension"),
std::string("gather_one_dimension"),
std::string("gather_one_dimension2"),
// gather_axis_input
// (CVS-82724: not support Axis as input),
std::string("gelu_erf"),
std::string("gelu_tanh"),
std::string("generate_proposals_v2_0"),
std::string("generate_proposals_v2_1"),
std::string("generate_proposals_v2_2"),
std::string("generate_proposals_v2_3"),
std::string("generate_proposals_v2_4"),
std::string("generate_proposals_v2_5"),
std::string("generate_proposals_v2_6"),
// greater_equal_big_int64(failure due to CPU inference),
std::string("greater_equal_big_int64"),
std::string("greater_equal_float32"),
std::string("greater_equal_int32"),
std::string("greater_equal_int64"),
std::string("greater_than_float32"),
std::string("greater_than_int32"),
std::string("greater_than_int64"),
std::string("hard_sigmoid"),
std::string("hard_swish"),
std::string("layer_norm"),
std::string("layer_norm_noall"),
std::string("layer_norm_noscale"),
std::string("layer_norm_noshift"),
std::string("leaky_relu"),
std::string("less_than_float32"),
std::string("less_than_int32"),
std::string("less_than_int64"),
std::string("linear_downsample_false_0"),
std::string("linear_downsample_false_1"),
std::string("linear_downsample_true_0"),
std::string("linear_upsample_false_0"),
std::string("linear_upsample_false_1"),
std::string("linear_upsample_scales"),
std::string("linear_upsample_scales2"),
std::string("linear_upsample_true_0"),
std::string("log"),
std::string("logical_and"),
std::string("logical_not"),
std::string("logical_or"),
std::string("logical_xor"),
std::string("matmul_xt"),
std::string("matmul_xt_yt"),
std::string("matmul_yt"),
std::string("matmul_v2_1dx1d"),
std::string("matmul_v2_1dx2d"),
std::string("matmul_v2_2dx1d"),
std::string("matmul_v2_ndxmd"),
std::string("matmul_v2_xt"),
std::string("matmul_v2_xt_yt"),
std::string("matmul_v2_yt"),
std::string("maxAdaptivePool2D_test1"),
std::string("maxPool_test1"),
std::string("maxPool_test10"),
std::string("maxPool_test11"),
std::string("maxPool_test2"),
std::string("maxPool_test3"),
std::string("maxPool_test4"),
std::string("maxPool_test5"),
// maxPool_test6(nchw support is disabled now),
std::string("maxPool_test7"),
std::string("maxPool_test8"),
std::string("maxPool_test9"),
std::string("meshgrid/meshgrid.pdmodel"),
std::string("nearest_downsample_false_0"),
std::string("nearest_downsample_false_1"),
std::string("nearest_upsample_false_0"),
std::string("nearest_upsample_false_1"),
std::string("pad3d_test1"),
std::string("pad3d_test2"),
std::string("pad3d_test3"),
// pad3d_test4,
std::string("pow_float32"),
std::string("pow_int32"),
std::string("pow_int64"),
// pow_int64_out_of_range(out of range of OV int64),
std::string("pow_y_tensor"),
std::string("prior_box_attrs_mmar_order_true"),
std::string("prior_box_default"),
std::string("prior_box_flip_clip_false"),
std::string("prior_box_max_sizes_none"),
std::string("range0"),
std::string("range1"),
std::string("range2"),
std::string("reduce_max_test_0"),
std::string("reduce_max_test_1"),
std::string("reduce_max_test_2"),
std::string("reduce_max_test_3"),
std::string("reduce_max_test_4"),
std::string("reduce_max_test_5"),
std::string("reduce_mean_test_0"),
std::string("reduce_mean_test_1"),
std::string("reduce_mean_test_2"),
std::string("reduce_mean_test_3"),
std::string("reduce_mean_test_4"),
std::string("reduce_mean_test_5"),
std::string("reduce_min_test_0"),
std::string("reduce_min_test_1"),
std::string("reduce_min_test_2"),
std::string("reduce_min_test_3"),
std::string("reduce_min_test_4"),
std::string("reduce_min_test_5"),
std::string("reduce_prod_test_0"),
std::string("reduce_prod_test_1"),
std::string("reduce_prod_test_2"),
std::string("reduce_prod_test_3"),
std::string("reduce_prod_test_4"),
std::string("reduce_prod_test_5"),
std::string("reduce_sum_test_0"),
std::string("reduce_sum_test_1"),
std::string("reduce_sum_test_2"),
std::string("reduce_sum_test_3"),
std::string("reduce_sum_test_4"),
std::string("reduce_sum_test_5"),
std::string("relu"),
std::string("relu6"),
std::string("relu6_1"),
std::string("reshape"),
std::string("reshape_tensor"),
std::string("reshape_tensor_list"),
std::string("rnn_lstm_layer_1_bidirectional"),
std::string("rnn_lstm_layer_1_forward"),
std::string("rnn_lstm_layer_2_bidirectional"),
std::string("rnn_lstm_layer_2_forward"),
std::string("rnn_lstm_layer_1_forward_seq_len_4"),
std::string("rnn_lstm_layer_2_bidirectional_seq_len_4"),
std::string("roi_align_test"),
std::string("roi_align_test2"),
std::string("scale_bias_after_float32"),
std::string("scale_bias_after_int32"),
std::string("scale_bias_after_int64"),
std::string("scale_bias_before_float32"),
std::string("scale_bias_before_int32"),
std::string("scale_bias_before_int64"),
std::string("scale_tensor_bias_after"),
std::string("scale_tensor_bias_before"),
std::string("shape"),
std::string("sigmoid"),
std::string("slice"),
std::string("slice_1d"),
std::string("slice_decrease_axis/slice_decrease_axis.pdmodel"),
std::string("slice_decrease_axis_all/slice_decrease_axis_all.pdmodel"),
std::string("slice_reshape/slice_reshape.pdmodel"),
std::string("softmax"),
std::string("softmax_minus"),
std::string("softplus_default_params"),
std::string("split_test1"),
std::string("split_test2"),
std::string("split_test3"),
std::string("split_test4"),
std::string("split_test5"),
std::string("split_test6"),
std::string("split_test_dim_int32"),
std::string("split_test_dim_int64"),
std::string("split_test_list"),
std::string("split_test_list_tensor"),
std::string("sqrt_float32"),
std::string("squeeze"),
std::string("squeeze_null_axes"),
std::string("stack_test_float32"),
std::string("stack_test_int32"),
std::string("stack_test_neg_axis"),
std::string("stack_test_none_axis"),
std::string("strided_slice_input1_1"),
std::string("strided_slice_input1_2"),
std::string("strided_slice_input1_3"),
std::string("strided_slice_input1_4"),
std::string("strided_slice_input2_1"),
std::string("strided_slice_input2_2"),
std::string("strided_slice_input2_3"),
std::string("strided_slice_input3_1"),
std::string("strided_slice_input3_2"),
std::string("swish_default_params"),
std::string("swish_beta"),
std::string("tanh"),
std::string("trilinear_downsample_false_0"),
std::string("trilinear_downsample_false_1"),
std::string("trilinear_downsample_true_0"),
std::string("trilinear_upsample_false_0"),
std::string("trilinear_upsample_false_1"),
std::string("trilinear_upsample_scales"),
std::string("trilinear_upsample_scales2"),
std::string("trilinear_upsample_true_0"),
std::string("unsqueeze"),
std::string("where_1"),
std::string("where_2"),
std::string("where_3"),
// Temporily disable them until root caused to secure CI stable.
// CVS-66703 to track this.
// std::string("yolo_box_clip_box"),
// std::string("yolo_box_default"),
// std::string("yolo_box_scale_xy"),
std::string("yolo_box_uneven_wh")};
static const std::vector<std::string> models{
std::string("argmax"),
std::string("argmax1"),
std::string("assign_none/assign_none.pdmodel"),
std::string("assign_output/assign_output.pdmodel"),
std::string("assign_value_boolean"),
std::string("assign_value_fp32"),
std::string("assign_value_int32"),
std::string("assign_value_int64"),
std::string("avgAdaptivePool2D_test1"),
std::string("avgPool_test1"),
std::string("avgPool_test10"),
std::string("avgPool_test11"),
std::string("avgPool_test2"),
std::string("avgPool_test3"),
std::string("avgPool_test4"),
std::string("avgPool_test5"),
// avgPool_test6<nchw support is disabled now>,
std::string("avgPool_test7"),
std::string("avgPool_test8"),
std::string("avgPool_test9"),
std::string("batch_norm_nchw"),
std::string("batch_norm_nhwc"),
std::string("bicubic_downsample_false_0"),
std::string("bicubic_downsample_false_1"),
std::string("bicubic_downsample_true_0"),
std::string("bicubic_upsample_false_0"),
std::string("bicubic_upsample_false_1"),
std::string("bicubic_upsample_scales"),
std::string("bicubic_upsample_scales2"),
std::string("bicubic_upsample_true_0"),
std::string("bilinear_downsample_false_0"),
std::string("bilinear_downsample_false_1"),
std::string("bilinear_downsample_true_0"),
std::string("bilinear_upsample_false_0"),
std::string("bilinear_upsample_false_1"),
std::string("bilinear_upsample_scales"),
std::string("bilinear_upsample_scales2"),
std::string("bilinear_upsample_true_0"),
std::string("bmm"),
std::string("clip"),
std::string("conv2d_dilation_assymetric_pads_strides"),
std::string("conv2d_SAME_padding"),
std::string("conv2d_strides_assymetric_padding"),
std::string("conv2d_strides_no_padding"),
std::string("conv2d_strides_padding"),
std::string("conv2d_transpose_dilation_assymetric_pads_strides"),
// conv2d_transpose_SAME_padding(Paddle outputs wrong results),
std::string("conv2d_transpose_strides_assymetric_padding"),
std::string("conv2d_transpose_strides_no_padding"),
std::string("conv2d_transpose_strides_padding"),
std::string("conv2d_transpose_VALID_padding"),
std::string("conv2d_VALID_padding"),
std::string("cumsum"),
std::string("cumsum_i32"),
std::string("cumsum_i64"),
std::string("cumsum_f32"),
std::string("cumsum_f64"),
std::string("depthwise_conv2d_convolution"),
std::string("depthwise_conv2d_transpose_convolution"),
std::string("dropout"),
std::string("dropout_upscale_in_train"),
std::string("elementwise_add1"),
std::string("elementwise_div1"),
std::string("elementwise_max1"),
std::string("elementwise_min1"),
std::string("elementwise_mul1"),
std::string("elementwise_pow1"),
std::string("elementwise_sub1"),
std::string("elementwise_add2"),
std::string("elementwise_div2"),
std::string("elementwise_max2"),
std::string("elementwise_min2"),
std::string("elementwise_mul2"),
std::string("elementwise_pow2"),
std::string("elementwise_sub2"),
std::string("elementwise_add3"),
std::string("elementwise_div3"),
std::string("elementwise_max3"),
std::string("elementwise_min3"),
std::string("elementwise_mul3"),
std::string("elementwise_pow3"),
std::string("elementwise_sub3"),
std::string("elementwise_add4"),
std::string("elementwise_div4"),
std::string("elementwise_max4"),
std::string("elementwise_min4"),
std::string("elementwise_mul4"),
std::string("elementwise_pow4"),
std::string("elementwise_sub4"),
std::string("embedding_0"),
std::string("embedding_sparse"),
std::string("embedding_none_weight"),
std::string("embedding_paddings"),
std::string("embedding_paddings_neg1"),
std::string("embedding_tensorIds"),
std::string("embedding_tensorIds_paddings"),
std::string("equal"),
std::string("expand_v2"),
std::string("expand_v2_tensor"),
std::string("expand_v2_tensor_list"),
std::string("expand_v2_tensor_list2"),
std::string("exp_test_float32"),
std::string("fill_any_like"),
std::string("fill_any_like_f16"),
std::string("fill_any_like_f32"),
std::string("fill_any_like_f64"),
std::string("fill_any_like_i32"),
std::string("fill_any_like_i64"),
std::string("fill_constant"),
std::string("fill_constant_batch_size_like"),
std::string("fill_constant_int32"),
std::string("fill_constant_int64"),
std::string("fill_constant_tensor"),
std::string("fill_constant_shape_tensor"),
std::string("fill_constant_shape_tensor_list"),
std::string("flatten_contiguous_range_test1"),
std::string("floor_float32"),
std::string("gather_multi_dimension"),
std::string("gather_one_dimension"),
std::string("gather_one_dimension2"),
// gather_axis_input
// (CVS-82724: not support Axis as input),
std::string("gelu_erf"),
std::string("gelu_tanh"),
std::string("generate_proposals_v2_0"),
std::string("generate_proposals_v2_1"),
std::string("generate_proposals_v2_2"),
std::string("generate_proposals_v2_3"),
std::string("generate_proposals_v2_4"),
std::string("generate_proposals_v2_5"),
std::string("generate_proposals_v2_6"),
// greater_equal_big_int64(failure due to CPU inference),
std::string("greater_equal_big_int64"),
std::string("greater_equal_float32"),
std::string("greater_equal_int32"),
std::string("greater_equal_int64"),
std::string("greater_than_float32"),
std::string("greater_than_int32"),
std::string("greater_than_int64"),
std::string("hard_sigmoid"),
std::string("hard_swish"),
std::string("layer_norm"),
std::string("layer_norm_noall"),
std::string("layer_norm_noscale"),
std::string("layer_norm_noshift"),
std::string("leaky_relu"),
std::string("less_than_float32"),
std::string("less_than_int32"),
std::string("less_than_int64"),
std::string("linear_downsample_false_0"),
std::string("linear_downsample_false_1"),
std::string("linear_downsample_true_0"),
std::string("linear_upsample_false_0"),
std::string("linear_upsample_false_1"),
std::string("linear_upsample_scales"),
std::string("linear_upsample_scales2"),
std::string("linear_upsample_true_0"),
std::string("log"),
std::string("logical_and"),
std::string("logical_not"),
std::string("logical_or"),
std::string("logical_xor"),
std::string("matmul_xt"),
std::string("matmul_xt_yt"),
std::string("matmul_yt"),
std::string("matmul_v2_1dx1d"),
std::string("matmul_v2_1dx2d"),
std::string("matmul_v2_2dx1d"),
std::string("matmul_v2_ndxmd"),
std::string("matmul_v2_xt"),
std::string("matmul_v2_xt_yt"),
std::string("matmul_v2_yt"),
std::string("matrix_nms_by_background"),
std::string("matrix_nms_by_keep_top_k"),
std::string("matrix_nms_by_nms_top_k"),
std::string("matrix_nms_by_post_threshold"),
std::string("matrix_nms_flipped_coordinates"),
std::string("matrix_nms_gaussian"),
std::string("matrix_nms_gaussian_sigma"),
std::string("matrix_nms_identical_boxes"),
std::string("matrix_nms_not_normalized"),
std::string("matrix_nms_not_return_indexed"),
std::string("matrix_nms_not_return_rois_num"),
std::string("matrix_nms_not_return_rois_num_neither_index"),
std::string("matrix_nms_one_batch"),
std::string("matrix_nms_single_box"),
std::string("matrix_nms_two_batches_two_classes"),
std::string("matrix_nms_normalized_random"),
std::string("matrix_nms_not_normalized_random"),
std::string("maxAdaptivePool2D_test1"),
std::string("maxPool_test1"),
std::string("maxPool_test10"),
std::string("maxPool_test11"),
std::string("maxPool_test2"),
std::string("maxPool_test3"),
std::string("maxPool_test4"),
std::string("maxPool_test5"),
// maxPool_test6(nchw support is disabled now),
std::string("maxPool_test7"),
std::string("maxPool_test8"),
std::string("maxPool_test9"),
std::string("meshgrid/meshgrid.pdmodel"),
std::string("multiclass_nms_by_background"),
std::string("multiclass_nms_by_class_id"),
std::string("multiclass_nms_by_IOU"),
std::string("multiclass_nms_by_IOU_and_scores"),
std::string("multiclass_nms_by_keep_top_k"),
std::string("multiclass_nms_by_nms_eta"),
std::string("multiclass_nms_by_nms_top_k"),
std::string("multiclass_nms_flipped_coordinates"),
std::string("multiclass_nms_identical_boxes"),
// default
std::string("multiclass_nms_lod_roisnum_multiple_images_default"),
std::string("multiclass_nms_lod_roisnum_multiple_images_0_default"),
std::string("multiclass_nms_lod_roisnum_single_image_default"),
// background
std::string("multiclass_nms_lod_roisnum_multiple_images_background"),
std::string("multiclass_nms_lod_roisnum_multiple_images_0_background"),
std::string("multiclass_nms_lod_roisnum_single_image_background"),
// score_threshold
std::string("multiclass_nms_lod_roisnum_multiple_images_score_threshold"),
std::string("multiclass_nms_lod_roisnum_multiple_images_0_score_threshold"),
std::string("multiclass_nms_lod_roisnum_single_image_score_threshold"),
// nms_top_k
std::string("multiclass_nms_lod_roisnum_multiple_images_nms_top_k"),
std::string("multiclass_nms_lod_roisnum_multiple_images_0_nms_top_k"),
std::string("multiclass_nms_lod_roisnum_single_image_nms_top_k"),
// keep_top_k
std::string("multiclass_nms_lod_roisnum_multiple_images_keep_top_k"),
std::string("multiclass_nms_lod_roisnum_multiple_images_0_keep_top_k"),
std::string("multiclass_nms_lod_roisnum_single_image_keep_top_k"),
// normalized
std::string("multiclass_nms_lod_roisnum_multiple_images_normalized"),
std::string("multiclass_nms_lod_roisnum_multiple_images_0_normalized"),
std::string("multiclass_nms_lod_roisnum_single_image_normalized"),
std::string("multiclass_nms_not_normalized"),
std::string("multiclass_nms_not_return_indexed"),
std::string("multiclass_nms_single_box"),
std::string("multiclass_nms_two_batches_two_classes_by_class_id"),
std::string("multiclass_nms_normalized_random"),
std::string("multiclass_nms_not_normalized_random"),
std::string("nearest_downsample_false_0"),
std::string("nearest_downsample_false_1"),
std::string("nearest_upsample_false_0"),
std::string("nearest_upsample_false_1"),
std::string("pad3d_test1"),
std::string("pad3d_test2"),
std::string("pad3d_test3"),
// pad3d_test4,
std::string("pow_float32"),
std::string("pow_int32"),
std::string("pow_int64"),
// pow_int64_out_of_range(out of range of OV int64),
std::string("pow_y_tensor"),
std::string("prior_box_attrs_mmar_order_true"),
std::string("prior_box_default"),
std::string("prior_box_flip_clip_false"),
std::string("prior_box_max_sizes_none"),
std::string("range0"),
std::string("range1"),
std::string("range2"),
std::string("reduce_max_test_0"),
std::string("reduce_max_test_1"),
std::string("reduce_max_test_2"),
std::string("reduce_max_test_3"),
std::string("reduce_max_test_4"),
std::string("reduce_max_test_5"),
std::string("reduce_mean_test_0"),
std::string("reduce_mean_test_1"),
std::string("reduce_mean_test_2"),
std::string("reduce_mean_test_3"),
std::string("reduce_mean_test_4"),
std::string("reduce_mean_test_5"),
std::string("reduce_min_test_0"),
std::string("reduce_min_test_1"),
std::string("reduce_min_test_2"),
std::string("reduce_min_test_3"),
std::string("reduce_min_test_4"),
std::string("reduce_min_test_5"),
std::string("reduce_prod_test_0"),
std::string("reduce_prod_test_1"),
std::string("reduce_prod_test_2"),
std::string("reduce_prod_test_3"),
std::string("reduce_prod_test_4"),
std::string("reduce_prod_test_5"),
std::string("reduce_sum_test_0"),
std::string("reduce_sum_test_1"),
std::string("reduce_sum_test_2"),
std::string("reduce_sum_test_3"),
std::string("reduce_sum_test_4"),
std::string("reduce_sum_test_5"),
std::string("relu"),
std::string("relu6"),
std::string("relu6_1"),
std::string("reshape"),
std::string("reshape_tensor"),
std::string("reshape_tensor_list"),
std::string("rnn_lstm_layer_1_bidirectional"),
std::string("rnn_lstm_layer_1_forward"),
std::string("rnn_lstm_layer_2_bidirectional"),
std::string("rnn_lstm_layer_2_forward"),
std::string("rnn_lstm_layer_1_forward_seq_len_4"),
std::string("rnn_lstm_layer_2_bidirectional_seq_len_4"),
std::string("roi_align_test"),
std::string("roi_align_test2"),
std::string("scale_bias_after_float32"),
std::string("scale_bias_after_int32"),
std::string("scale_bias_after_int64"),
std::string("scale_bias_before_float32"),
std::string("scale_bias_before_int32"),
std::string("scale_bias_before_int64"),
std::string("scale_tensor_bias_after"),
std::string("scale_tensor_bias_before"),
std::string("shape"),
std::string("sigmoid"),
std::string("slice"),
std::string("slice_1d"),
std::string("slice_decrease_axis/slice_decrease_axis.pdmodel"),
std::string("slice_decrease_axis_all/slice_decrease_axis_all.pdmodel"),
std::string("slice_reshape/slice_reshape.pdmodel"),
std::string("softmax"),
std::string("softmax_minus"),
std::string("softplus_default_params"),
std::string("split_test1"),
std::string("split_test2"),
std::string("split_test3"),
std::string("split_test4"),
std::string("split_test5"),
std::string("split_test6"),
std::string("split_test_dim_int32"),
std::string("split_test_dim_int64"),
std::string("split_test_list"),
std::string("split_test_list_tensor"),
std::string("sqrt_float32"),
std::string("squeeze"),
std::string("squeeze_null_axes"),
std::string("stack_test_float32"),
std::string("stack_test_int32"),
std::string("stack_test_neg_axis"),
std::string("stack_test_none_axis"),
std::string("strided_slice_input1_1"),
std::string("strided_slice_input1_2"),
std::string("strided_slice_input1_3"),
std::string("strided_slice_input1_4"),
std::string("strided_slice_input2_1"),
std::string("strided_slice_input2_2"),
std::string("strided_slice_input2_3"),
std::string("strided_slice_input3_1"),
std::string("strided_slice_input3_2"),
std::string("swish_default_params"),
std::string("swish_beta"),
std::string("tanh"),
std::string("trilinear_downsample_false_0"),
std::string("trilinear_downsample_false_1"),
std::string("trilinear_downsample_true_0"),
std::string("trilinear_upsample_false_0"),
std::string("trilinear_upsample_false_1"),
std::string("trilinear_upsample_scales"),
std::string("trilinear_upsample_scales2"),
std::string("trilinear_upsample_true_0"),
std::string("unsqueeze"),
std::string("where_1"),
std::string("where_2"),
std::string("where_3"),
// Temporily disable them until root caused to secure CI stable.
// CVS-66703 to track this.
// std::string("yolo_box_clip_box"),
// std::string("yolo_box_default"),
// std::string("yolo_box_scale_xy"),
std::string("yolo_box_uneven_wh")};
INSTANTIATE_TEST_SUITE_P(PaddleFuzzyOpTest,
FrontEndFuzzyOpTest,
@@ -0,0 +1,407 @@
# Copyright (C) 2018-2022 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
#
# matrix_nms paddle model generator
#
import os
import numpy as np
import copy # deepcopy
import sys
from nms import NMS
def main(): # matrix_nms
test_case = [None] * 20
# case matrix_nms_one_batch
test_case[0] = { # N 1, C 2, M 6
'name':
'matrix_nms_one_batch',
'boxes':
np.array([[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0,
101.0]]]).astype(np.float32),
'scores':
np.array([[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3],
[0.95, 0.75, 0.6, 0.80, 0.5, 0.3]]]).astype(np.float32),
'pdpd_attrs': {
'nms_type': 'matrix_nms', # PDPD Op type
'score_threshold': 0.0,
'post_threshold': 0.0,
'nms_top_k': 3,
'keep_top_k': -1,
'use_gaussian': False,
'gaussian_sigma': 2.,
'background_label': -1,
'normalized': True,
'return_index': True,
'return_rois_num': True
}
}
# case matrix_nms_two_batches_two_classes
test_case[1] = { # N 2, C 2, M 3
'name':
'matrix_nms_two_batches_two_classes',
'boxes':
np.array([[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0, 101.0]],
[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0,
101.0]]]).astype('float32'),
'scores':
np.array([[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3],
[0.95, 0.75, 0.6, 0.80, 0.5, 0.3]],
[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3],
[0.95, 0.75, 0.6, 0.80, 0.5, 0.3]]]).astype('float32'),
'pdpd_attrs': {
'nms_type': 'matrix_nms', # PDPD Op type
'score_threshold': 0.0,
'post_threshold': 0.0,
'nms_top_k': 3,
'keep_top_k': -1,
'use_gaussian': False,
'gaussian_sigma': 2.,
'background_label': -1,
'normalized': True,
'return_index': True,
'return_rois_num': True
}
}
# case matrix_nms_identical_boxes
test_case[2] = { # N 1, C 1, M 10
'name':
'matrix_nms_identical_boxes',
'boxes':
np.array([[[0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 1.0, 1.0],
[0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 1.0, 1.0],
[0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 1.0, 1.0],
[0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 1.0, 1.0],
[0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 1.0,
1.0]]]).astype(np.float32),
'scores':
np.array([[[0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9,
0.9]]]).astype(np.float32),
'pdpd_attrs': {
'nms_type': 'matrix_nms', # PDPD Op type
'score_threshold': 0.0,
'post_threshold': 0.8,
'nms_top_k': 3,
'keep_top_k': -1,
'use_gaussian': False,
'gaussian_sigma': 2.,
'background_label': -1,
'normalized': True,
'return_index': True,
'return_rois_num': True
}
}
# case matrix_nms_flipped_coordinates
test_case[3] = { # N 1, C 1, M 6
'name':
'matrix_nms_flipped_coordinates',
'boxes':
np.array([[[1.0, 1.0, 0.0, 0.0], [0.0, 0.1, 1.0, 1.1],
[0.0, 0.9, 1.0, -0.1], [0.0, 10.0, 1.0, 11.0],
[1.0, 10.1, 0.0, 11.1], [1.0, 101.0, 0.0,
100.0]]]).astype(np.float32),
'scores':
np.array([[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3]]]).astype(np.float32),
'pdpd_attrs': {
'nms_type': 'matrix_nms', # PDPD Op type
'score_threshold': 0.0,
'post_threshold': 0.0,
'nms_top_k': 3,
'keep_top_k': -1,
'use_gaussian': False,
'gaussian_sigma': 2.,
'background_label': -1,
'normalized': True,
'return_index': True,
'return_rois_num': True
}
}
# case matrix_nms_by_nms_top_k
test_case[4] = { # N 1, C 1, M 6
'name':
'matrix_nms_by_nms_top_k',
'boxes':
np.array([[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0,
101.0]]]).astype(np.float32),
'scores':
np.array([[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3]]]).astype(np.float32),
'pdpd_attrs': {
'nms_type': 'matrix_nms', # PDPD Op type
'score_threshold': 0.0,
'post_threshold': 0.0,
'nms_top_k': 2,
'keep_top_k': -1,
'use_gaussian': False,
'gaussian_sigma': 2.,
'background_label': -1,
'normalized': True,
'return_index': True,
'return_rois_num': True
}
}
# case matrix_nms_single_box
test_case[5] = { # N 1, C 1, M 1
'name': 'matrix_nms_single_box',
'boxes': np.array([[[0.0, 0.0, 1.0, 1.0]]]).astype(np.float32),
'scores': np.array([[[0.9]]]).astype(np.float32),
'pdpd_attrs': {
'nms_type': 'matrix_nms', # PDPD Op type
'score_threshold': 0.0,
'post_threshold': 0.0,
'nms_top_k': 3,
'keep_top_k': -1,
'use_gaussian': False,
'gaussian_sigma': 2.,
'background_label': -1,
'normalized': True,
'return_index': True,
'return_rois_num': True
}
}
# case matrix_nms_gaussian
test_case[6] = { # N 1, C 1, M 6
'name':
'matrix_nms_gaussian',
'boxes':
np.array([[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0,
101.0]]]).astype(np.float32),
'scores':
np.array([[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3],
[0.95, 0.75, 0.6, 0.80, 0.5, 0.3]]]).astype(np.float32),
'pdpd_attrs': {
'nms_type': 'matrix_nms', # PDPD Op type
'score_threshold': 0.0,
'post_threshold': 0.0,
'nms_top_k': 3,
'keep_top_k': -1,
'use_gaussian': True,
'gaussian_sigma': 2.,
'background_label': -1,
'normalized': True,
'return_index': True,
'return_rois_num': True
}
}
# case matrix_nms_gaussian_sigma
test_case[7] = { # N 1, C 1, M 6
'name':
'matrix_nms_gaussian_sigma',
'boxes':
np.array([[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0,
101.0]]]).astype(np.float32),
'scores':
np.array([[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3],
[0.95, 0.75, 0.6, 0.80, 0.5, 0.3]]]).astype(np.float32),
'pdpd_attrs': {
'nms_type': 'matrix_nms', # PDPD Op type
'score_threshold': 0.0,
'post_threshold': 0.0,
'nms_top_k': 3,
'keep_top_k': -1,
'use_gaussian': True,
'gaussian_sigma': 4.,
'background_label': -1,
'normalized': True,
'return_index': True,
'return_rois_num': True
}
}
# case matrix_nms_by_background
test_case[8] = { # N 2, C 2, M 3
'name':
'matrix_nms_by_background',
'boxes':
np.array([[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0, 101.0]],
[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0,
101.0]]]).astype('float32'),
'scores':
np.array([[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3],
[0.95, 0.75, 0.6, 0.80, 0.5, 0.3]],
[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3],
[0.95, 0.75, 0.6, 0.80, 0.5, 0.3]]]).astype('float32'),
'pdpd_attrs': {
'nms_type': 'matrix_nms', # PDPD Op type
'score_threshold': 0.0,
'post_threshold': 0.0,
'nms_top_k': 3,
'keep_top_k': -1,
'use_gaussian': True,
'gaussian_sigma': 4.,
'background_label': 0,
'normalized': True,
'return_index': True,
'return_rois_num': True
}
}
# case matrix_nms_by_keep_top_k
test_case[9] = { # N 2, C 2, M 3
'name':
'matrix_nms_by_keep_top_k',
'boxes':
np.array([[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0, 101.0]],
[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0,
101.0]]]).astype('float32'),
'scores':
np.array([[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3],
[0.95, 0.75, 0.6, 0.80, 0.5, 0.3]],
[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3],
[0.95, 0.75, 0.6, 0.80, 0.5, 0.3]]]).astype('float32'),
'pdpd_attrs': {
'nms_type': 'matrix_nms', # PDPD Op type
'score_threshold': 0.0,
'post_threshold': 0.0,
'nms_top_k': 3,
'keep_top_k': 3,
'use_gaussian': True,
'gaussian_sigma': 4.,
'background_label': -1,
'normalized': True,
'return_index': True,
'return_rois_num': True
}
}
# case matrix_nms_by_post_threshold
test_case[10] = { # N 1, C 2, M 3
'name':
'matrix_nms_by_post_threshold',
'boxes':
np.array([[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0, 101.0]]]).astype('float32'),
'scores':
np.array([[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3],
[0.96, 0.77, 0.6, 0.80, 0.5, 0.3]]]).astype('float32'),
'pdpd_attrs': {
'nms_type': 'matrix_nms', # PDPD Op type
'score_threshold': 0.0,
'post_threshold': 0.8,
'nms_top_k': 3,
'keep_top_k': -1,
'use_gaussian': True,
'gaussian_sigma': 4.,
'background_label': -1,
'normalized': True,
'return_index': True,
'return_rois_num': True
}
}
# case matrix_nms_not_normalized
test_case[11] = copy.deepcopy(test_case[0])
test_case[11]['name'] = 'matrix_nms_not_normalized'
test_case[11]['pdpd_attrs']['normalized'] = False
# case matrix_nms_not_return_indexed
test_case[12] = copy.deepcopy(test_case[1])
test_case[12]['name'] = 'matrix_nms_not_return_indexed'
test_case[12]['pdpd_attrs']['return_index'] = False
# case matrix_nms_not_return_rois_num
test_case[13] = copy.deepcopy(test_case[1])
test_case[13]['name'] = 'matrix_nms_not_return_rois_num'
test_case[13]['pdpd_attrs']['return_rois_num'] = False
# case matrix_nms_not_return_rois_num_neither_index
test_case[14] = copy.deepcopy(test_case[1])
test_case[14]['name'] = 'matrix_nms_not_return_rois_num_neither_index'
test_case[14]['pdpd_attrs']['return_rois_num'] = False
test_case[14]['pdpd_attrs']['return_index'] = False
# bboxes shape (N, M, 4)
# scores shape (N, C, M)
for i, t in enumerate(test_case):
if t is not None:
print('\033[95m' +
'\n\Generating matrix_nms test case: {} {} ......'.format(i, t['name']) +
'\033[0m')
data_bboxes = t['boxes']
data_scores = t['scores']
pdpd_attrs = t['pdpd_attrs']
NMS(t['name'], data_bboxes, data_scores, pdpd_attrs)
def TEST1(N=7, M=1200, C=21):
def softmax(x):
# clip to shiftx, otherwise, when calc loss with
# log(exp(shiftx)), may get log(0)=INF
shiftx = (x - np.max(x)).clip(-64.)
exps = np.exp(shiftx)
return exps / np.sum(exps)
BOX_SIZE = 4
background = 0
post_threshold = 0.01
nms_top_k = 400
keep_top_k = 200
score_threshold = 0.01
scores = np.random.random((N * M, C)).astype('float32')
scores = np.apply_along_axis(softmax, 1, scores)
scores = np.reshape(scores, (N, M, C))
# There looks a bug in cnpy, which is used by pdpd fuzzy_tet,
# that Fortran Contiguous is required.
# https://github.com/OpenChemistry/tomviz/issues/1809
scores = np.ascontiguousarray(np.transpose(scores, (0, 2, 1)))
boxes = np.random.random((N, M, BOX_SIZE)).astype('float32')
boxes[:, :, 0] = boxes[:, :, 0] * 10
boxes[:, :, 1] = boxes[:, :, 1] * 10
boxes[:, :, 2] = boxes[:, :, 2] * 10 + 10
boxes[:, :, 3] = boxes[:, :, 3] * 10 + 10
pdpd_attrs = {
'nms_type': 'matrix_nms', # PDPD Op type
'score_threshold': score_threshold,
'post_threshold': post_threshold,
'nms_top_k': nms_top_k,
'keep_top_k': keep_top_k,
'use_gaussian': False,
'gaussian_sigma': 2.,
'background_label': background,
'normalized': True,
'return_index': True,
'return_rois_num': True
}
NMS("matrix_nms_normalized_random", boxes, scores, pdpd_attrs)
pdpd_attrs['normalized'] = False
NMS("matrix_nms_not_normalized_random", boxes, scores, pdpd_attrs)
if __name__ == "__main__":
main()
TEST1()
@@ -0,0 +1,421 @@
# Copyright (C) 2018-2022 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
#
# multiclass_nms paddle model generator
#
import os
import numpy as np
import copy # deepcopy
import sys
from nms import NMS
def main(): # multiclass_nms
test_case = [None] * 20
# case multiclass_nms_by_class_id
test_case[0] = { # N 1, C 2, M 6
'name':
'multiclass_nms_by_class_id',
'boxes':
np.array([[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0,
101.0]]]).astype(np.float32),
'scores':
np.array([[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3],
[0.95, 0.75, 0.6, 0.80, 0.5, 0.3]]]).astype(np.float32),
'pdpd_attrs': {
'nms_type': 'multiclass_nms3', # PDPD Op type
'background_label': -1,
'score_threshold': 0.0,
'nms_top_k': 3,
'nms_threshold': 0.5,
'keep_top_k': -1,
'normalized': True,
'nms_eta': 1.0,
'return_index': True
}
}
# case multiclass_nms_two_batches_two_classes_by_class_id
test_case[1] = { # N 2, C 2, M 3
'name':
'multiclass_nms_two_batches_two_classes_by_class_id',
'boxes':
np.array([[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0, 101.0]],
[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0,
101.0]]]).astype('float32'),
'scores':
np.array([[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3],
[0.95, 0.75, 0.6, 0.80, 0.5, 0.3]],
[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3],
[0.95, 0.75, 0.6, 0.80, 0.5, 0.3]]]).astype('float32'),
'pdpd_attrs': {
'nms_type': 'multiclass_nms3', # PDPD Op type
'background_label': -1,
'score_threshold': 0.0, # the less, the more bbox kept.
'nms_top_k': 3, # max_output_box_per_class
'nms_threshold': 0.5, # the bigger, the more bbox kept.
'keep_top_k': -1, # -1, keep all
'normalized': True,
'nms_eta': 1.0,
'return_index': True
}
}
# case multiclass_nms_identical_boxes
test_case[2] = { # N 1, C 1, M 10
'name':
'multiclass_nms_identical_boxes',
'boxes':
np.array([[[0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 1.0, 1.0],
[0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 1.0, 1.0],
[0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 1.0, 1.0],
[0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 1.0, 1.0],
[0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 1.0,
1.0]]]).astype(np.float32),
'scores':
np.array([[[0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9,
0.9]]]).astype(np.float32),
'pdpd_attrs': {
'nms_type': 'multiclass_nms3', # PDPD Op type
'background_label': -1,
'score_threshold': 0.0,
'nms_top_k': 3,
'nms_threshold': 0.5,
'keep_top_k': -1,
'normalized': True,
'nms_eta': 1.0,
'return_index': True
}
}
# case multiclass_nms_flipped_coordinates
test_case[3] = { # N 1, C 1, M 6
'name':
'multiclass_nms_flipped_coordinates',
'boxes':
np.array([[[1.0, 1.0, 0.0, 0.0], [0.0, 0.1, 1.0, 1.1],
[0.0, 0.9, 1.0, -0.1], [0.0, 10.0, 1.0, 11.0],
[1.0, 10.1, 0.0, 11.1], [1.0, 101.0, 0.0,
100.0]]]).astype(np.float32),
'scores':
np.array([[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3]]]).astype(np.float32),
'pdpd_attrs': {
'nms_type': 'multiclass_nms3', # PDPD Op type
'background_label': -1,
'score_threshold': 0.0,
'nms_top_k': 3,
'nms_threshold': 0.5,
'keep_top_k': -1,
'normalized': True,
'nms_eta': 1.0,
'return_index': True
}
}
# case multiclass_nms_by_nms_top_k
test_case[4] = { # N 1, C 1, M 6
'name':
'multiclass_nms_by_nms_top_k',
'boxes':
np.array([[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0,
101.0]]]).astype(np.float32),
'scores':
np.array([[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3]]]).astype(np.float32),
'pdpd_attrs': {
'nms_type': 'multiclass_nms3', # PDPD Op type
'background_label': -1,
'score_threshold': 0.0,
'nms_top_k': 2,
'nms_threshold': 0.5,
'keep_top_k': -1,
'normalized': True,
'nms_eta': 1.0,
'return_index': True
}
}
# case multiclass_nms_single_box
test_case[5] = { # N 1, C 1, M 1
'name': 'multiclass_nms_single_box',
'boxes': np.array([[[0.0, 0.0, 1.0, 1.0]]]).astype(np.float32),
'scores': np.array([[[0.9]]]).astype(np.float32),
'pdpd_attrs': {
'nms_type': 'multiclass_nms3', # PDPD Op type
'background_label': -1,
'score_threshold': 0.0,
'nms_top_k': 3,
'nms_threshold': 0.5,
'keep_top_k': -1,
'normalized': True,
'nms_eta': 1.0,
'return_index': True
}
}
# case multiclass_nms_by_IOU
test_case[6] = { # N 1, C 1, M 6
'name':
'multiclass_nms_by_IOU',
'boxes':
np.array([[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0,
101.0]]]).astype(np.float32),
'scores':
np.array([[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3]]]).astype(np.float32),
'pdpd_attrs': {
'nms_type': 'multiclass_nms3', # PDPD Op type
'background_label': -1,
'score_threshold': 0.0,
'nms_top_k': 3,
'nms_threshold': 0.5,
'keep_top_k': -1,
'normalized': True,
'nms_eta': 1.0,
'return_index': True
}
}
# case multiclass_nms_by_IOU_and_scores
test_case[7] = { # N 1, C 1, M 6
'name':
'multiclass_nms_by_IOU_and_scores',
'boxes':
np.array([[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0,
101.0]]]).astype(np.float32),
'scores':
np.array([[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3]]]).astype(np.float32),
'pdpd_attrs': {
'nms_type': 'multiclass_nms3', # PDPD Op type
'background_label': -1,
'score_threshold': 0.93,
'nms_top_k': 3,
'nms_threshold': 0.5,
'keep_top_k': -1,
'normalized': True,
'nms_eta': 1.0,
'return_index': True
}
}
# case multiclass_nms_by_background
test_case[8] = { # N 2, C 2, M 3
'name':
'multiclass_nms_by_background',
'boxes':
np.array([[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0, 101.0]],
[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0,
101.0]]]).astype('float32'),
'scores':
np.array([[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3],
[0.95, 0.75, 0.6, 0.80, 0.5, 0.3]],
[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3],
[0.95, 0.75, 0.6, 0.80, 0.5, 0.3]]]).astype('float32'),
'pdpd_attrs': {
'nms_type': 'multiclass_nms3', # PDPD Op type
'background_label': 0,
'score_threshold': 0.0, # the less, the more bbox kept.
'nms_top_k': 3, # max_output_box_per_class
'nms_threshold': 0.5, # the bigger, the more bbox kept.
'keep_top_k': -1, # -1, keep all
'normalized': True,
'nms_eta': 1.0,
'return_index': True
}
}
# case multiclass_nms_by_keep_top_k
test_case[9] = { # N 2, C 2, M 3
'name':
'multiclass_nms_by_keep_top_k',
'boxes':
np.array([[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0, 101.0]],
[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0,
101.0]]]).astype('float32'),
'scores':
np.array([[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3],
[0.95, 0.75, 0.6, 0.80, 0.5, 0.3]],
[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3],
[0.95, 0.75, 0.6, 0.80, 0.5, 0.3]]]).astype('float32'),
'pdpd_attrs': {
'nms_type': 'multiclass_nms3', # PDPD Op type
'background_label': -1,
'score_threshold': 0.0, # the less, the more bbox kept.
'nms_top_k': 3, # max_output_box_per_class
'nms_threshold': 0.5, # the bigger, the more bbox kept.
'keep_top_k': 3, # -1, keep all
'normalized': True,
'nms_eta': 1.0,
'return_index': True
}
}
# case multiclass_nms_by_nms_eta
test_case[10] = { # N 2, C 2, M 3
'name':
'multiclass_nms_by_nms_eta',
'boxes':
np.array([[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0, 101.0]],
[[0.0, 0.0, 1.0, 1.0], [0.0, 0.1, 1.0, 1.1],
[0.0, -0.1, 1.0, 0.9], [0.0, 10.0, 1.0, 11.0],
[0.0, 10.1, 1.0, 11.1], [0.0, 100.0, 1.0,
101.0]]]).astype('float32'),
'scores':
np.array([[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3],
[0.95, 0.75, 0.6, 0.80, 0.5, 0.3]],
[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3],
[0.95, 0.75, 0.6, 0.80, 0.5, 0.3]]]).astype('float32'),
'pdpd_attrs': {
'nms_type': 'multiclass_nms3', # PDPD Op type
'background_label': -1,
'score_threshold': 0.0, # the less, the more bbox kept.
'nms_top_k': -1, # max_output_box_per_class
'nms_threshold': 1.0, # the bigger, the more bbox kept.
'keep_top_k': -1, # -1, keep all
'normalized': True,
'nms_eta': 0.1,
'return_index': True
}
}
# case multiclass_nms_not_normalized
test_case[11] = copy.deepcopy(test_case[0])
test_case[11]['name'] = 'multiclass_nms_not_normalized'
test_case[11]['pdpd_attrs']['normalized'] = False
# case multiclass_nms_not_return_indexed
test_case[12] = copy.deepcopy(test_case[1])
test_case[12]['name'] = 'multiclass_nms_not_return_indexed'
test_case[12]['pdpd_attrs']['return_index'] = False
# bboxes shape (N, M, 4)
# scores shape (N, C, M)
for i, t in enumerate(test_case):
if t is not None:
print('\033[95m' +
'\n\Generating multiclass_nms test case: {} {} ......'.format(i, t['name']) +
'\033[0m')
data_bboxes = t['boxes']
data_scores = t['scores']
pdpd_attrs = t['pdpd_attrs']
NMS(t['name'], data_bboxes, data_scores, pdpd_attrs)
def TEST1(N=7, M=1200, C=21):
def softmax(x):
# clip to shiftx, otherwise, when calc loss with
# log(exp(shiftx)), may get log(0)=INF
shiftx = (x - np.max(x)).clip(-64.)
exps = np.exp(shiftx)
return exps / np.sum(exps)
BOX_SIZE = 4
background = 0
nms_threshold = 0.3
nms_top_k = 10
keep_top_k = 5
score_threshold = 0.01
scores = np.random.random((N * M, C)).astype('float32')
scores = np.apply_along_axis(softmax, 1, scores)
scores = np.reshape(scores, (N, M, C))
# There looks a bug in cnpy, which is used by pdpd fuzzy_tet,
# that Fortran Contiguous is required.
# https://github.com/OpenChemistry/tomviz/issues/1809
scores = np.ascontiguousarray(np.transpose(scores, (0, 2, 1)))
boxes = np.random.random((N, M, BOX_SIZE)).astype('float32')
boxes[:, :, 0:2] = boxes[:, :, 0:2] * 0.5
boxes[:, :, 2:4] = boxes[:, :, 2:4] * 0.5 + 0.5
pdpd_attrs = {
'nms_type': 'multiclass_nms3', # PDPD Op type
'background_label': background,
'score_threshold': score_threshold, # the less, the more bbox kept.
'nms_top_k': nms_top_k, # max_output_box_per_class
'nms_threshold': nms_threshold, # the bigger, the more bbox kept.
'keep_top_k': keep_top_k, # -1, keep all
'normalized': True,
'nms_eta': 1.0,
'return_index': True
}
NMS("multiclass_nms_normalized_random", boxes, scores, pdpd_attrs)
pdpd_attrs['normalized'] = False
NMS("multiclass_nms_not_normalized_random", boxes, scores, pdpd_attrs)
def multiclass_nms_lod(appendix : str = '_default', background = -1, score_threshold = 0.01, nms_threshold = 0.3, nms_top_k = 400, keep_top_k = 200, normalized = False):
BOX_SIZE = 4
M = 3
C = 2
scores = np.array([[0.34, 0.66 ],
[0.45, 0.61 ],
[0.39, 0.59 ]]).astype('float32')
boxes = np.array([[[7.55, 1.10, 18.28, 14.47 ],
[7.25, 0.47, 12.28, 17.77 ]],
[[4.06, 5.15, 16.11, 18.40 ],
[9.66, 3.36, 18.57, 13.26 ]],
[[6.50, 7.00, 13.33, 17.63 ],
[0.73, 5.34, 19.97, 19.97 ]]]).astype('float32')
box_lod = [3]
rois_num = np.array(box_lod).astype('int32')
pdpd_attrs = {
'nms_type': 'multiclass_nms3', # PDPD Op type
'background_label': background,
'score_threshold': score_threshold, # the less, the more bbox kept.
'nms_top_k': nms_top_k, # max_output_box_per_class
'nms_threshold': nms_threshold, # the bigger, the more bbox kept.
'keep_top_k': keep_top_k, # -1, keep all
'normalized': normalized,
'nms_eta': 1.0,
'return_index': True
}
NMS("multiclass_nms_lod_roisnum_single_image" + appendix, boxes, scores, pdpd_attrs, rois_num)
box_lod = [1, 2]
rois_num = np.array(box_lod).astype('int32')
NMS("multiclass_nms_lod_roisnum_multiple_images" + appendix, boxes, scores, pdpd_attrs, rois_num)
box_lod = [0, 3]
rois_num = np.array(box_lod).astype('int32')
NMS("multiclass_nms_lod_roisnum_multiple_images_0" + appendix, boxes, scores, pdpd_attrs, rois_num)
if __name__ == "__main__":
main()
TEST1()
multiclass_nms_lod() # default
multiclass_nms_lod('_background', background = -1)
multiclass_nms_lod('_score_threshold', score_threshold = 0.5)
multiclass_nms_lod('_nms_threshold', nms_threshold = 0.0)
multiclass_nms_lod('_nms_top_k', nms_top_k = 2)
multiclass_nms_lod('_keep_top_k', keep_top_k = 1)
multiclass_nms_lod('_normalized', normalized = True)
@@ -0,0 +1,124 @@
# Copyright (C) 2018-2022 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
#
# helper for multiclass/matrix_nms paddle model generator
#
import os
import numpy as np
import copy # deepcopy
import sys
from save_model import saveModel, exportModel, print_alike
# bboxes shape (N, M, 4) if shared else (M, C, 4)
# scores shape (N, C, M) if shared else (M, C)
def NMS(name: str, bboxes, scores, attrs: dict, rois_num=None, verbose=False):
import paddle as pdpd
from ops import multiclass_nms as multiclass_nms
from ops import matrix_nms as matrix_nms
pdpd.enable_static()
with pdpd.static.program_guard(pdpd.static.Program(),
pdpd.static.Program()):
# make model with inputs of dynamic shape
node_boxes = pdpd.static.data(name='bboxes',
shape=[-1, -1, 4],
dtype=bboxes.dtype,
lod_level=1)
node_scores = pdpd.static.data(name='scores',
shape=[-1] * len(scores.shape),
dtype=scores.dtype,
lod_level=1)
node_rois_num = None
if rois_num is not None:
node_rois_num = pdpd.static.data(name='rois_num',
shape=rois_num.shape,
dtype=rois_num.dtype,
lod_level=1)
if attrs['nms_type'] is 'multiclass_nms3':
nms_outputs = multiclass_nms(bboxes=node_boxes,
scores=node_scores,
background_label=attrs['background_label'],
score_threshold=attrs['score_threshold'],
nms_top_k=attrs['nms_top_k'],
nms_threshold=attrs['nms_threshold'],
keep_top_k=attrs['keep_top_k'],
normalized=attrs['normalized'],
nms_eta=attrs['nms_eta'],
return_index=attrs['return_index'],
return_rois_num=True,
rois_num=node_rois_num)
else:
nms_outputs = matrix_nms(bboxes=node_boxes,
scores=node_scores,
score_threshold=attrs['score_threshold'],
post_threshold=attrs['post_threshold'],
nms_top_k=attrs['nms_top_k'],
keep_top_k=attrs['keep_top_k'],
use_gaussian=attrs['use_gaussian'],
gaussian_sigma=attrs['gaussian_sigma'],
background_label=attrs['background_label'],
normalized=attrs['normalized'],
return_index=attrs['return_index'],
return_rois_num=attrs['return_rois_num'])
# output of NMS is mix of int and float. To make it easy for op_fuzzy unittest, cast int output to float.
output = []
for x in nms_outputs:
if x is not None:
if x.dtype==pdpd.int32 or x.dtype==pdpd.int64:
x = pdpd.cast(x, "float32")
output.append(x)
cpu = pdpd.static.cpu_places(1)
exe = pdpd.static.Executor(cpu[0])
# startup program will call initializer to initialize the parameters.
exe.run(pdpd.static.default_startup_program())
fetch_vars = [x for x in output if x is not None]
feed_dict = {'bboxes': bboxes, 'scores': scores}
if rois_num is not None:
feed_dict['rois_num'] = rois_num
output_lod = exe.run(feed=feed_dict,
fetch_list=fetch_vars,
return_numpy=False)
# There is a bug in paddledet that dtype of model var mismatch its output LodTensor.
# Specifically, it is 'Index' is 'int64', while its LodTensor of 'int32'.
# This will lead to a failure in ngraph frontend op fuzzy test.
# So here is an workaround to align the dtypes.
out = np.array(output_lod.pop(0))
nms_rois_num = np.array(
output_lod.pop(0)) if output[1] is not None else None
index = np.array(output_lod.pop(0)).astype(pdpd.fluid.data_feeder.convert_dtype(
output[2].dtype)) if output[2] is not None else None
# Save inputs in order of ngraph function, to facilite Fuzzy test,
# which accepts inputs and outputs in this order as well.
output_np = [out, nms_rois_num, index]
saveModel(name,
exe,
feedkeys=list(feed_dict.keys()),
fetchlist=fetch_vars,
inputs=list(feed_dict.values()),
outputs=[x for x in output_np if x is not None],
target_dir=sys.argv[1])
if verbose:
# input
print('\033[94m' + 'bboxes: {}'.format(bboxes.shape) + '\033[0m')
print_alike(bboxes, seperator_begin='', seperator_end='', verbose=True)
print('\033[94m' + 'scores: {}'.format(scores.shape) + '\033[0m')
print_alike(scores, seperator_begin='', seperator_end='', verbose=True)
# output
print('\033[91m' + 'out_np: {}'.format(out.shape) + '\033[0m')
print_alike(out, seperator_begin='', seperator_end='', verbose=True)
print('\033[91m' + 'nms_rois_num_np: {}'.format(nms_rois_num.shape) +
'\033[0m')
print_alike(nms_rois_num, seperator_begin='', seperator_end='', verbose=True)
if index is not None:
print('\033[91m' + 'index_np: {}'.format(index.shape) + '\033[0m')
print_alike(index, seperator_begin='', seperator_end='', verbose=True)
@@ -7,33 +7,39 @@ import numpy as np
import paddle
#print numpy array like C structure
def print_alike(arr):
#print numpy array like C structure
def print_alike(arr, seperator_begin='{', seperator_end='}', verbose=False):
shape = arr.shape
rank = len(shape)
#print("shape: ", shape, "rank: %d" %(rank))
#for idx, value in np.ndenumerate(arr):
# for idx, value in np.ndenumerate(arr):
# print(idx, value)
def print_array(arr, end=' '):
shape = arr.shape
rank = len(arr.shape)
if rank > 1:
line = "{"
line = seperator_begin
for i in range(arr.shape[0]):
line += print_array(arr[i,:], end="},\n" if i < arr.shape[0]-1 else "}")
line += print_array(
arr[i, :],
end=seperator_end +
",\n" if i < arr.shape[0] - 1 else seperator_end)
line += end
return line
else:
line = "{"
for i in range(arr.shape[0]):
line += "{:.2f}".format(arr[i]) #str(arr[i])
line += ", " if i < shape[0]-1 else ' '
line = seperator_begin
for i in range(arr.shape[0]):
line += "{:.2f}".format(arr[i]) # str(arr[i])
line += ", " if i < shape[0] - 1 else ' '
line += end
#print(line)
# print(line)
return line
# print(print_array(arr, "}"))
if verbose:
print(print_array(arr, seperator_end))
def saveModel(name, exe, feedkeys:list, fetchlist:list, inputs:list, outputs:list, target_dir:str):
@@ -63,17 +69,22 @@ def saveModel(name, exe, feedkeys:list, fetchlist:list, inputs:list, outputs:lis
export dyn model, along with input and output for reference.
input_data: list of all inputs
'''
def exportModel(name, dyn_func, input_data:list, target_dir:str):
def exportModel(name, dyn_func, input_data:list, target_dir:str, dyn_shapes:list=[]):
model_dir = os.path.join(target_dir, name)
if not os.path.exists(model_dir):
os.makedirs(model_dir)
save_path = '{}/{}'.format(model_dir, name)
if len(dyn_shapes)>0:
assert(len(dyn_shapes) == len(input_data))
input_specs = []
for idx, data in enumerate(input_data):
input_name = 'input{}'.format(idx)
input_shape = dyn_shapes[idx] if len(dyn_shapes)>0 and dyn_shapes[idx] is not None else data.shape
input_specs.append(
paddle.static.InputSpec(shape=data.shape, dtype=data.dtype, name=input_name)
paddle.static.InputSpec(shape=input_shape, dtype=data.dtype, name=input_name)
)
# dump input
@@ -93,6 +104,8 @@ def exportModel(name, dyn_func, input_data:list, target_dir:str):
np.save(os.path.join(model_dir, "output{}".format(idx)), out.numpy())
else:
np.save(os.path.join(model_dir, "output{}".format(0)), result.numpy())
return result
if __name__ == "__main__":
@@ -115,4 +128,4 @@ if __name__ == "__main__":
[
[1, 2, 3],
[4, 5, 6]
]]]).astype(np.float32)
]]]).astype(np.float32)
+182 -45
View File
@@ -9,45 +9,105 @@
using namespace std;
using namespace ngraph;
TEST(type_prop, multiclass_nms_incorrect_boxes_rank) {
template <typename T>
class type_prop : public testing::Test {};
typedef testing::Types<op::v8::MulticlassNms, op::v9::MulticlassNms> test_prop_types;
TYPED_TEST_SUITE(type_prop, test_prop_types);
TYPED_TEST(type_prop, multiclass_nms_incorrect_boxes_rank) {
try {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{1, 2, 3, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{1, 2, 3});
const auto unused = make_shared<op::v8::MulticlassNms>(boxes, scores, op::v8::MulticlassNms::Attributes());
const auto unused = make_shared<TypeParam>(boxes, scores, ov::op::util::MulticlassNmsBase::Attributes());
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), "Expected a 3D tensor for the 'boxes' input");
}
}
TEST(type_prop, multiclass_nms_incorrect_scores_rank) {
TEST(type_prop2, multiclass_nms_incorrect_boxes_rank) {
try {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{1, 2, 3, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{1, 2, 3});
const auto roisnum = make_shared<op::Parameter>(element::i32, Shape{1});
const auto unused =
make_shared<op::v9::MulticlassNms>(boxes, scores, roisnum, ov::op::util::MulticlassNmsBase::Attributes());
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), "Expected a 3D tensor for the 'boxes' input");
}
}
TYPED_TEST(type_prop, multiclass_nms_incorrect_scores_rank) {
try {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{1, 2, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{1});
const auto unused = make_shared<TypeParam>(boxes, scores, ov::op::util::MulticlassNmsBase::Attributes());
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(),
TypeParam::get_type_info_static().get_version() == "opset8"
? "Expected a 3D tensor for the 'scores' input"
: "Expected a 2D or 3D tensor for the 'scores' input");
}
}
TEST(type_prop2, multiclass_nms_incorrect_scores_rank2) {
try {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{1, 2, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{1, 2});
const auto unused = make_shared<op::v8::MulticlassNms>(boxes, scores, op::v8::MulticlassNms::Attributes());
const auto unused =
make_shared<op::v9::MulticlassNms>(boxes, scores, ov::op::util::MulticlassNmsBase::Attributes());
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), "Expected a 3D tensor for the 'scores' input");
EXPECT_HAS_SUBSTRING(error.what(), "Expected the 'roisnum' input when the input 'scores' is a 2D tensor.");
}
}
TEST(type_prop, multiclass_nms_incorrect_scheme_num_batches) {
TEST(type_prop2, multiclass_nms_incorrect_roisnum_rank) {
try {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{2, 3, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{2, 3});
const auto roisnum = make_shared<op::Parameter>(element::i32, Shape{1, 2});
const auto unused =
make_shared<op::v9::MulticlassNms>(boxes, scores, roisnum, ov::op::util::MulticlassNmsBase::Attributes());
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), "Expected a 1D tensor for the 'roisnum' input");
}
}
TYPED_TEST(type_prop, multiclass_nms_incorrect_scheme_num_batches) {
try {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{1, 2, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{2, 2, 3});
const auto unused = make_shared<op::v8::MulticlassNms>(boxes, scores, op::v8::MulticlassNms::Attributes());
const auto unused = make_shared<TypeParam>(boxes, scores, ov::op::util::MulticlassNmsBase::Attributes());
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), "The first dimension of both 'boxes' and 'scores' must match");
}
}
TEST(type_prop, multiclass_nms_incorrect_scheme_num_boxes) {
TEST(type_prop2, multiclass_nms_incorrect_scheme_num_classes) {
try {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{2, 3, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{1, 3});
const auto roisnum = make_shared<op::Parameter>(element::i32, Shape{1});
const auto unused =
make_shared<op::v9::MulticlassNms>(boxes, scores, roisnum, ov::op::util::MulticlassNmsBase::Attributes());
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), "'boxes' and 'scores' input shapes must match");
}
}
TYPED_TEST(type_prop, multiclass_nms_incorrect_scheme_num_boxes) {
try {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{1, 2, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{1, 2, 3});
const auto unused = make_shared<op::v8::MulticlassNms>(boxes, scores, op::v8::MulticlassNms::Attributes());
const auto unused = make_shared<TypeParam>(boxes, scores, ov::op::util::MulticlassNmsBase::Attributes());
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(),
"'boxes' and 'scores' input shapes must match at the second and third "
@@ -55,98 +115,124 @@ TEST(type_prop, multiclass_nms_incorrect_scheme_num_boxes) {
}
}
TEST(type_prop, multiclass_nms_incorrect_boxes_rank2) {
TEST(type_prop2, multiclass_nms_incorrect_scheme_num_boxes) {
try {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{1, 2, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{1, 3});
const auto roisnum = make_shared<op::Parameter>(element::i32, Shape{1});
const auto unused =
make_shared<op::v9::MulticlassNms>(boxes, scores, roisnum, ov::op::util::MulticlassNmsBase::Attributes());
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), "'boxes' and 'scores' input shapes must match.");
}
}
TEST(type_prop2, multiclass_nms_incorrect_scheme_num_boxes2) {
try {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{1, 2, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{3, 2});
const auto roisnum = make_shared<op::Parameter>(element::i32, Shape{1});
const auto unused =
make_shared<op::v9::MulticlassNms>(boxes, scores, roisnum, ov::op::util::MulticlassNmsBase::Attributes());
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), "'boxes' and 'scores' input shapes must match.");
}
}
TYPED_TEST(type_prop, multiclass_nms_incorrect_boxes_rank2) {
try {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{1, 2, 3});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{2, 2, 2});
const auto unused = make_shared<op::v8::MulticlassNms>(boxes, scores, op::v8::MulticlassNms::Attributes());
const auto unused = make_shared<TypeParam>(boxes, scores, ov::op::util::MulticlassNmsBase::Attributes());
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), "The third dimension of the 'boxes' must be 4");
}
}
TEST(type_prop, multiclass_nms_incorrect_output_type) {
TYPED_TEST(type_prop, multiclass_nms_incorrect_output_type) {
try {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{1, 2, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{1, 2, 2});
op::v8::MulticlassNms::Attributes attrs;
ov::op::util::MulticlassNmsBase::Attributes attrs;
attrs.output_type = ngraph::element::f32;
const auto unused = make_shared<op::v8::MulticlassNms>(boxes, scores, attrs);
const auto unused = make_shared<TypeParam>(boxes, scores, attrs);
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), "Output type must be i32 or i64");
}
}
TEST(type_prop, multiclass_nms_incorrect_nms_topk) {
TYPED_TEST(type_prop, multiclass_nms_incorrect_nms_topk) {
try {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{1, 2, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{1, 2, 2});
op::v8::MulticlassNms::Attributes attrs;
ov::op::util::MulticlassNmsBase::Attributes attrs;
attrs.nms_top_k = -2;
const auto unused = make_shared<op::v8::MulticlassNms>(boxes, scores, attrs);
const auto unused = make_shared<TypeParam>(boxes, scores, attrs);
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), "The 'nms_top_k' must be great or equal -1");
}
}
TEST(type_prop, multiclass_nms_incorrect_keep_topk) {
TYPED_TEST(type_prop, multiclass_nms_incorrect_keep_topk) {
try {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{1, 2, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{1, 2, 2});
op::v8::MulticlassNms::Attributes attrs;
ov::op::util::MulticlassNmsBase::Attributes attrs;
attrs.keep_top_k = -2;
const auto unused = make_shared<op::v8::MulticlassNms>(boxes, scores, attrs);
const auto unused = make_shared<TypeParam>(boxes, scores, attrs);
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), "The 'keep_top_k' must be great or equal -1");
}
}
TEST(type_prop, multiclass_nms_incorrect_background_class) {
TYPED_TEST(type_prop, multiclass_nms_incorrect_background_class) {
try {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{1, 2, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{1, 2, 2});
op::v8::MulticlassNms::Attributes attrs;
ov::op::util::MulticlassNmsBase::Attributes attrs;
attrs.background_class = -2;
const auto unused = make_shared<op::v8::MulticlassNms>(boxes, scores, attrs);
const auto unused = make_shared<TypeParam>(boxes, scores, attrs);
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), "The 'background_class' must be great or equal -1");
}
}
TEST(type_prop, multiclass_nms_incorrect_eta) {
TYPED_TEST(type_prop, multiclass_nms_incorrect_eta) {
try {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{1, 2, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{1, 2, 2});
op::v8::MulticlassNms::Attributes attrs;
ov::op::util::MulticlassNmsBase::Attributes attrs;
attrs.nms_eta = 2.0f;
const auto unused = make_shared<op::v8::MulticlassNms>(boxes, scores, attrs);
const auto unused = make_shared<TypeParam>(boxes, scores, attrs);
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), "The 'nms_eta' must be in close range [0, 1.0]");
}
}
TEST(type_prop, multiclass_nms_incorrect_input_type) {
TYPED_TEST(type_prop, multiclass_nms_incorrect_input_type) {
try {
const auto boxes = make_shared<op::Parameter>(element::f16, Shape{1, 2, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{1, 2, 2});
const auto unused = make_shared<op::v8::MulticlassNms>(boxes, scores, op::v8::MulticlassNms::Attributes());
const auto unused = make_shared<TypeParam>(boxes, scores, ov::op::util::MulticlassNmsBase::Attributes());
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), "Expected 'boxes', 'scores' type is same.");
}
}
TEST(type_prop, multiclass_nms_output_shape_1dim_dynamic) {
TYPED_TEST(type_prop, multiclass_nms_output_shape_1dim_dynamic) {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{5, 2, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{5, 3, 2});
const auto nms = make_shared<op::v8::MulticlassNms>(boxes, scores, op::v8::MulticlassNms::Attributes());
const auto nms = make_shared<TypeParam>(boxes, scores, ov::op::util::MulticlassNmsBase::Attributes());
ASSERT_TRUE(nms->get_output_partial_shape(0).same_scheme(PartialShape{Dimension::dynamic(), 6}));
ASSERT_TRUE(nms->get_output_partial_shape(1).same_scheme(PartialShape{Dimension::dynamic(), 1}));
@@ -154,11 +240,11 @@ TEST(type_prop, multiclass_nms_output_shape_1dim_dynamic) {
EXPECT_EQ(nms->get_output_shape(2), (Shape{5}));
}
TEST(type_prop, multiclass_nms_output_shape_1dim_max_out) {
TYPED_TEST(type_prop, multiclass_nms_output_shape_1dim_max_out) {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{2, 7, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{2, 5, 7});
const auto nms = make_shared<op::v8::MulticlassNms>(boxes, scores, op::v8::MulticlassNms::Attributes());
const auto nms = make_shared<TypeParam>(boxes, scores, ov::op::util::MulticlassNmsBase::Attributes());
ASSERT_EQ(nms->get_output_element_type(0), element::f32);
ASSERT_EQ(nms->get_output_element_type(1), element::i64);
@@ -170,13 +256,13 @@ TEST(type_prop, multiclass_nms_output_shape_1dim_max_out) {
EXPECT_EQ(nms->get_output_shape(2), (Shape{2}));
}
TEST(type_prop, multiclass_nms_output_shape_1dim_nms_topk) {
TYPED_TEST(type_prop, multiclass_nms_output_shape_1dim_nms_topk) {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{2, 7, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{2, 5, 7});
op::v8::MulticlassNms::Attributes attrs;
ov::op::util::MulticlassNmsBase::Attributes attrs;
attrs.nms_top_k = 3;
const auto nms = make_shared<op::v8::MulticlassNms>(boxes, scores, attrs);
const auto nms = make_shared<TypeParam>(boxes, scores, attrs);
ASSERT_EQ(nms->get_output_element_type(0), element::f32);
ASSERT_EQ(nms->get_output_element_type(1), element::i64);
@@ -187,14 +273,14 @@ TEST(type_prop, multiclass_nms_output_shape_1dim_nms_topk) {
EXPECT_EQ(nms->get_output_shape(2), (Shape{2}));
}
TEST(type_prop, multiclass_nms_output_shape_1dim_keep_topk) {
TYPED_TEST(type_prop, multiclass_nms_output_shape_1dim_keep_topk) {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{2, 7, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{2, 5, 7});
op::v8::MulticlassNms::Attributes attrs;
ov::op::util::MulticlassNmsBase::Attributes attrs;
attrs.nms_top_k = 3;
attrs.keep_top_k = 8;
const auto nms = make_shared<op::v8::MulticlassNms>(boxes, scores, attrs);
const auto nms = make_shared<TypeParam>(boxes, scores, attrs);
ASSERT_EQ(nms->get_output_element_type(0), element::f32);
ASSERT_EQ(nms->get_output_element_type(1), element::i64);
@@ -205,11 +291,11 @@ TEST(type_prop, multiclass_nms_output_shape_1dim_keep_topk) {
EXPECT_EQ(nms->get_output_shape(2), (Shape{2}));
}
TEST(type_prop, multiclass_nms_input_f16) {
TYPED_TEST(type_prop, multiclass_nms_input_f16) {
const auto boxes = make_shared<op::Parameter>(element::f16, Shape{2, 7, 4});
const auto scores = make_shared<op::Parameter>(element::f16, Shape{2, 5, 7});
const auto nms = make_shared<op::v8::MulticlassNms>(boxes, scores, op::v8::MulticlassNms::Attributes());
const auto nms = make_shared<TypeParam>(boxes, scores, ov::op::util::MulticlassNmsBase::Attributes());
ASSERT_EQ(nms->get_output_element_type(0), element::f16);
ASSERT_EQ(nms->get_output_element_type(1), element::i64);
@@ -220,13 +306,13 @@ TEST(type_prop, multiclass_nms_input_f16) {
EXPECT_EQ(nms->get_output_shape(2), (Shape{2}));
}
TEST(type_prop, multiclass_nms_output_shape_i32) {
TYPED_TEST(type_prop, multiclass_nms_output_shape_i32) {
const auto boxes = make_shared<op::Parameter>(element::f32, Shape{2, 7, 4});
const auto scores = make_shared<op::Parameter>(element::f32, Shape{2, 5, 7});
op::v8::MulticlassNms::Attributes attrs;
ov::op::util::MulticlassNmsBase::Attributes attrs;
attrs.output_type = ngraph::element::i32;
const auto nms = make_shared<op::v8::MulticlassNms>(boxes, scores, attrs);
const auto nms = make_shared<TypeParam>(boxes, scores, attrs);
ASSERT_EQ(nms->get_output_element_type(0), element::f32);
ASSERT_EQ(nms->get_output_element_type(1), element::i32);
@@ -237,11 +323,62 @@ TEST(type_prop, multiclass_nms_output_shape_i32) {
EXPECT_EQ(nms->get_output_shape(2), (Shape{2}));
}
TEST(type_prop, multiclass_nms_dynamic_boxes_and_scores) {
TYPED_TEST(type_prop, multiclass_nms_dynamic_boxes_and_scores) {
const auto boxes = make_shared<op::Parameter>(element::f32, PartialShape::dynamic());
const auto scores = make_shared<op::Parameter>(element::f32, PartialShape::dynamic());
const auto nms = make_shared<op::v8::MulticlassNms>(boxes, scores, op::v8::MulticlassNms::Attributes());
const auto nms = make_shared<TypeParam>(boxes, scores, ov::op::util::MulticlassNmsBase::Attributes());
ASSERT_EQ(nms->get_output_element_type(0), element::f32);
ASSERT_EQ(nms->get_output_element_type(1), element::i64);
ASSERT_EQ(nms->get_output_element_type(2), element::i64);
EXPECT_EQ(nms->get_output_partial_shape(0), PartialShape({Dimension::dynamic(), 6}));
EXPECT_EQ(nms->get_output_partial_shape(1), PartialShape({Dimension::dynamic(), 1}));
EXPECT_EQ(nms->get_output_partial_shape(2), PartialShape({Dimension::dynamic()}));
}
TEST(type_prop2, multiclass_nms_dynamic_boxes_and_scores) {
const auto boxes = make_shared<op::Parameter>(element::f32, PartialShape::dynamic());
const auto scores = make_shared<op::Parameter>(element::f32, PartialShape::dynamic());
const auto roisnum = make_shared<op::Parameter>(element::i32, PartialShape::dynamic());
const auto nms =
make_shared<op::v9::MulticlassNms>(boxes, scores, roisnum, ov::op::util::MulticlassNmsBase::Attributes());
ASSERT_EQ(nms->get_output_element_type(0), element::f32);
ASSERT_EQ(nms->get_output_element_type(1), element::i64);
ASSERT_EQ(nms->get_output_element_type(2), element::i64);
EXPECT_EQ(nms->get_output_partial_shape(0), PartialShape({Dimension::dynamic(), 6}));
EXPECT_EQ(nms->get_output_partial_shape(1), PartialShape({Dimension::dynamic(), 1}));
EXPECT_EQ(nms->get_output_partial_shape(2), PartialShape({Dimension::dynamic()}));
}
TYPED_TEST(type_prop, multiclass_nms_dynamic_boxes_and_scores2) {
const auto boxes =
make_shared<op::Parameter>(element::f32, PartialShape({Dimension::dynamic(), Dimension::dynamic(), 4}));
const auto scores =
make_shared<op::Parameter>(element::f32,
PartialShape({Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()}));
const auto nms = make_shared<TypeParam>(boxes, scores, ov::op::util::MulticlassNmsBase::Attributes());
ASSERT_EQ(nms->get_output_element_type(0), element::f32);
ASSERT_EQ(nms->get_output_element_type(1), element::i64);
ASSERT_EQ(nms->get_output_element_type(2), element::i64);
EXPECT_EQ(nms->get_output_partial_shape(0), PartialShape({Dimension::dynamic(), 6}));
EXPECT_EQ(nms->get_output_partial_shape(1), PartialShape({Dimension::dynamic(), 1}));
EXPECT_EQ(nms->get_output_partial_shape(2), PartialShape({Dimension::dynamic()}));
}
TEST(type_prop2, multiclass_nms_dynamic_boxes_and_scores2) {
const auto boxes =
make_shared<op::Parameter>(element::f32, PartialShape({Dimension::dynamic(), Dimension::dynamic(), 4}));
const auto scores =
make_shared<op::Parameter>(element::f32, PartialShape({Dimension::dynamic(), Dimension::dynamic()}));
const auto roisnum = make_shared<op::Parameter>(element::i32, PartialShape({Dimension::dynamic()}));
const auto nms =
make_shared<op::v9::MulticlassNms>(boxes, scores, roisnum, ov::op::util::MulticlassNmsBase::Attributes());
ASSERT_EQ(nms->get_output_element_type(0), element::f32);
ASSERT_EQ(nms->get_output_element_type(1), element::i64);
+78 -3
View File
@@ -6,10 +6,8 @@
#include "ngraph/ngraph.hpp"
#include "ngraph/op/util/attr_types.hpp"
#include "ngraph/opsets/opset1.hpp"
#include "ngraph/opsets/opset3.hpp"
#include "ngraph/opsets/opset4.hpp"
#include "ngraph/opsets/opset5.hpp"
#include "ngraph/opsets/opset8.hpp"
#include "ngraph/opsets/opset9.hpp"
#include "util/visitor.hpp"
using namespace std;
@@ -91,3 +89,80 @@ TEST(attributes, multiclass_nms_v8_op_default_attributes) {
EXPECT_EQ(g_nms_attrs.nms_eta, nms_attrs.nms_eta);
EXPECT_EQ(g_nms_attrs.normalized, nms_attrs.normalized);
}
TEST(attributes, multiclass_nms_v9_op_custom_attributes) {
NodeBuilder::get_ops().register_factory<opset9::MulticlassNms>();
auto boxes = make_shared<op::Parameter>(element::f32, Shape{3, 2, 4});
auto scores = make_shared<op::Parameter>(element::f32, Shape{3, 2});
auto roisnum = make_shared<op::Parameter>(element::i32, Shape{2});
opset9::MulticlassNms::Attributes attrs;
attrs.sort_result_type = opset9::MulticlassNms::SortResultType::SCORE;
attrs.sort_result_across_batch = true;
attrs.output_type = ngraph::element::i32;
attrs.nms_top_k = 100;
attrs.keep_top_k = 10;
attrs.iou_threshold = 0.1f;
attrs.score_threshold = 0.2f;
attrs.background_class = 2;
attrs.nms_eta = 0.3f;
attrs.normalized = false;
auto nms = make_shared<opset9::MulticlassNms>(boxes, scores, roisnum, attrs);
NodeBuilder builder(nms);
auto g_nms = ov::as_type_ptr<opset9::MulticlassNms>(builder.create());
const auto expected_attr_count = 10;
EXPECT_EQ(builder.get_value_map_size(), expected_attr_count);
auto& g_nms_attrs = g_nms->get_attrs();
auto& nms_attrs = nms->get_attrs();
EXPECT_EQ(g_nms_attrs.sort_result_type, nms_attrs.sort_result_type);
EXPECT_EQ(g_nms_attrs.sort_result_across_batch, nms_attrs.sort_result_across_batch);
EXPECT_EQ(g_nms_attrs.output_type, nms_attrs.output_type);
EXPECT_EQ(g_nms_attrs.nms_top_k, nms_attrs.nms_top_k);
EXPECT_EQ(g_nms_attrs.keep_top_k, nms_attrs.keep_top_k);
EXPECT_EQ(g_nms_attrs.iou_threshold, nms_attrs.iou_threshold);
EXPECT_EQ(g_nms_attrs.score_threshold, nms_attrs.score_threshold);
EXPECT_EQ(g_nms_attrs.background_class, nms_attrs.background_class);
EXPECT_EQ(g_nms_attrs.nms_eta, nms_attrs.nms_eta);
EXPECT_EQ(g_nms_attrs.normalized, nms_attrs.normalized);
EXPECT_EQ(attrs.sort_result_type, nms_attrs.sort_result_type);
EXPECT_EQ(attrs.sort_result_across_batch, nms_attrs.sort_result_across_batch);
EXPECT_EQ(attrs.output_type, nms_attrs.output_type);
EXPECT_EQ(attrs.nms_top_k, nms_attrs.nms_top_k);
EXPECT_EQ(attrs.keep_top_k, nms_attrs.keep_top_k);
EXPECT_EQ(attrs.iou_threshold, nms_attrs.iou_threshold);
EXPECT_EQ(attrs.score_threshold, nms_attrs.score_threshold);
EXPECT_EQ(attrs.background_class, nms_attrs.background_class);
EXPECT_EQ(attrs.nms_eta, nms_attrs.nms_eta);
EXPECT_EQ(attrs.normalized, nms_attrs.normalized);
}
TEST(attributes, multiclass_nms_v9_op_default_attributes) {
NodeBuilder::get_ops().register_factory<opset9::MulticlassNms>();
auto boxes = make_shared<op::Parameter>(element::f32, Shape{3, 2, 4});
auto scores = make_shared<op::Parameter>(element::f32, Shape{3, 2});
auto roisnum = make_shared<op::Parameter>(element::i32, Shape{2});
auto nms = make_shared<opset9::MulticlassNms>(boxes, scores, roisnum, opset9::MulticlassNms::Attributes());
NodeBuilder builder(nms);
auto g_nms = ov::as_type_ptr<opset9::MulticlassNms>(builder.create());
const auto expected_attr_count = 10;
EXPECT_EQ(builder.get_value_map_size(), expected_attr_count);
auto& g_nms_attrs = g_nms->get_attrs();
auto& nms_attrs = nms->get_attrs();
EXPECT_EQ(g_nms_attrs.sort_result_type, nms_attrs.sort_result_type);
EXPECT_EQ(g_nms_attrs.sort_result_across_batch, nms_attrs.sort_result_across_batch);
EXPECT_EQ(g_nms_attrs.output_type, nms_attrs.output_type);
EXPECT_EQ(g_nms_attrs.nms_top_k, nms_attrs.nms_top_k);
EXPECT_EQ(g_nms_attrs.keep_top_k, nms_attrs.keep_top_k);
EXPECT_EQ(g_nms_attrs.iou_threshold, nms_attrs.iou_threshold);
EXPECT_EQ(g_nms_attrs.score_threshold, nms_attrs.score_threshold);
EXPECT_EQ(g_nms_attrs.background_class, nms_attrs.background_class);
EXPECT_EQ(g_nms_attrs.nms_eta, nms_attrs.nms_eta);
EXPECT_EQ(g_nms_attrs.normalized, nms_attrs.normalized);
}
+16 -3
View File
@@ -3,14 +3,14 @@
//
#include "openvino/frontend/paddle/node_context.hpp"
#include "openvino/frontend/paddle/visibility.hpp"
#include "openvino/opsets/opset8.hpp"
#include "openvino/opsets/opset9.hpp"
namespace ov {
namespace frontend {
namespace paddle {
namespace op {
NamedOutputs multiclass_nms(const NodeContext& node) {
using namespace opset8;
using namespace opset9;
using namespace element;
auto bboxes = node.get_input("BBoxes");
@@ -48,7 +48,20 @@ NamedOutputs multiclass_nms(const NodeContext& node) {
attrs.output_type = type_index;
attrs.sort_result_across_batch = false;
nms_outputs = std::make_shared<MulticlassNms>(bboxes, scores, attrs)->outputs();
if (node.has_input("RoisNum")) {
const auto roisnum = node.get_input("RoisNum");
// transpose scores and boxes first
auto input_order_scores = Constant::create(element::i64, {2}, {1, 0});
auto transposed_scores = std::make_shared<Transpose>(scores, input_order_scores);
auto input_order_boxes = Constant::create(element::i64, {3}, {1, 0, 2});
auto transposed_boxes = std::make_shared<Transpose>(bboxes, input_order_boxes);
nms_outputs = std::make_shared<MulticlassNms>(transposed_boxes, transposed_scores, roisnum, attrs)->outputs();
} else {
nms_outputs = std::make_shared<MulticlassNms>(bboxes, scores, attrs)->outputs();
}
named_outputs["Out"] = {nms_outputs[0]};
named_outputs["Index"] = {nms_outputs[1]};
@@ -43,7 +43,7 @@ inline void addInputOutput(cnpy::NpyArray& npy_array, test::TestCase& test_case,
T* npy_begin = npy_array.data<T>();
std::vector<T> data(npy_begin, npy_begin + npy_array.num_vals);
if (is_input)
test_case.add_input(data);
test_case.add_input(npy_array.shape, data);
else
test_case.add_expected_output(npy_array.shape, data);
}
@@ -453,7 +453,7 @@ void CNNNetworkNGraphImpl::reshape(const std::map<std::string, ngraph::PartialSh
::ngraph::pass::Manager manager;
// resolves dynamism by replacing dynamic operation with static version
manager.register_pass<::ngraph::pass::ConvertNMS5ToLegacyMatcher>(false);
manager.register_pass<::ngraph::pass::ConvertMulticlassNmsToMulticlassNmsIE>(false);
manager.register_pass<ngraph::pass::ConvertMulticlassNmsToMulticlassNmsIE>(false);
manager.register_pass<::ngraph::pass::ConvertMatrixNmsToMatrixNmsIE>(false);
manager.register_pass<::ngraph::pass::ConvertNMS9ToNMSIEInternal>();
manager.register_pass<::ngraph::pass::DisableConvertConstantFoldingOnConstPath>();
+1
View File
@@ -189,6 +189,7 @@ const InferenceEngine::details::caseless_unordered_map<std::string, Type> type_t
{ "NonMaxSuppressionIEInternal", Type::NonMaxSuppression},
{ "MatrixNms", Type::MatrixNms},
{ "MulticlassNms", Type::MulticlassNms},
{ "MulticlassNmsIEInternal", Type::MulticlassNms},
{ "Reference", Type::Reference},
{ "Subgraph", Type::Subgraph},
{ "PriorBox", Type::PriorBox},
+2 -1
View File
@@ -12,6 +12,7 @@
#include <ngraph_ops/type_relaxed.hpp>
#include <ngraph_ops/nms_ie_internal.hpp>
#include <ngraph_ops/nms_static_shape_ie.hpp>
#include <ngraph_ops/multiclass_nms_ie_internal.hpp>
#include <mutex>
@@ -103,7 +104,7 @@ std::map<std::string, ngraph::OpSet> Extension::getOpSets() {
#define NGRAPH_OP(NAME, NAMESPACE) opset.insert<NAMESPACE::NAME>();
NGRAPH_OP(NonMaxSuppressionIEInternal, ngraph::op::internal)
NGRAPH_OP(NmsStaticShapeIE<ov::op::v8::MulticlassNms>, ngraph::op::internal)
NGRAPH_OP(MulticlassNmsIEInternal, ngraph::op::internal)
NGRAPH_OP(NmsStaticShapeIE<ov::op::v8::MatrixNms>, ngraph::op::internal)
#undef NGRAPH_OP
@@ -20,7 +20,7 @@ namespace ov {
namespace intel_cpu {
namespace node {
using ngNmsSortResultType = ngraph::op::util::NmsBase::SortResultType;
using ngNmsSortResultType = ngraph::op::v8::MatrixNms::SortResultType;
using ngNmseDcayFunction = ngraph::op::v8::MatrixNms::DecayFunction;
bool MatrixNms::isSupportedOperation(const std::shared_ptr<const ngraph::Node>& op, std::string& errorMessage) noexcept {
@@ -65,11 +65,11 @@ MatrixNms::MatrixNms(const std::shared_ptr<ngraph::Node>& op, const dnnl::engine
const auto matrix_nms = std::dynamic_pointer_cast<const ngraph::op::v8::MatrixNms>(op);
auto& attrs = matrix_nms->get_attrs();
if (attrs.sort_result_type == ngraph::op::util::NmsBase::SortResultType::CLASSID)
if (attrs.sort_result_type == ngraph::op::v8::MatrixNms::SortResultType::CLASSID)
m_sortResultType = MatrixNmsSortResultType::CLASSID;
else if (attrs.sort_result_type == ngraph::op::util::NmsBase::SortResultType::SCORE)
else if (attrs.sort_result_type == ngraph::op::v8::MatrixNms::SortResultType::SCORE)
m_sortResultType = MatrixNmsSortResultType::SCORE;
else if (attrs.sort_result_type == ngraph::op::util::NmsBase::SortResultType::NONE)
else if (attrs.sort_result_type == ngraph::op::v8::MatrixNms::SortResultType::NONE)
m_sortResultType = MatrixNmsSortResultType::NONE;
if (attrs.decay_function == ngraph::op::v8::MatrixNms::DecayFunction::GAUSSIAN)
@@ -3,6 +3,7 @@
//
#include "multiclass_nms.hpp"
#include "ngraph_ops/multiclass_nms_ie_internal.hpp"
#include <algorithm>
#include <cassert>
@@ -23,19 +24,15 @@ namespace ov {
namespace intel_cpu {
namespace node {
using ngNmsSortResultType = ngraph::op::util::NmsBase::SortResultType;
using ngNmsSortResultType = ov::op::util::MulticlassNmsBase::SortResultType;
bool MultiClassNms::isSupportedOperation(const std::shared_ptr<const ngraph::Node>& op, std::string& errorMessage) noexcept {
bool MultiClassNms::isSupportedOperation(const std::shared_ptr<const ov::Node>& op, std::string& errorMessage) noexcept {
try {
const auto nms = std::dynamic_pointer_cast<const ngraph::op::v8::MulticlassNms>(op);
if (!nms) {
errorMessage = "Only MulticlassNms operation is supported";
return false;
}
const auto& atrri = nms->get_attrs();
const auto& sortType = atrri.sort_result_type;
if (!one_of(sortType, ngNmsSortResultType::NONE, ngNmsSortResultType::SCORE, ngNmsSortResultType::CLASSID)) {
errorMessage = "Does not support SortResultType mode: " + ngraph::as_string(sortType);
if (!one_of(op->get_type_info(),
ov::op::v9::MulticlassNms::get_type_info_static(),
ov::op::v8::MulticlassNms::get_type_info_static(),
ngraph::op::internal::MulticlassNmsIEInternal::get_type_info_static())) {
errorMessage = "Node is not an instance of MulticlassNms from opset v8 or v9.";
return false;
}
} catch (...) {
@@ -44,7 +41,7 @@ bool MultiClassNms::isSupportedOperation(const std::shared_ptr<const ngraph::Nod
return true;
}
MultiClassNms::MultiClassNms(const std::shared_ptr<ngraph::Node>& op, const dnnl::engine& eng, WeightsSharing::Ptr& cache)
MultiClassNms::MultiClassNms(const std::shared_ptr<ov::Node>& op, const dnnl::engine& eng, WeightsSharing::Ptr& cache)
: Node(op, eng, cache) {
std::string errorMessage;
if (!isSupportedOperation(op, errorMessage)) {
@@ -52,15 +49,16 @@ MultiClassNms::MultiClassNms(const std::shared_ptr<ngraph::Node>& op, const dnnl
}
m_errorPrefix = "MultiClassNms layer with name '" + getName() + "' ";
if (getOriginalInputsNumber() != 2)
if (getOriginalInputsNumber() != 2 && getOriginalInputsNumber() != 3)
IE_THROW() << m_errorPrefix << "has incorrect number of input edges: " << getOriginalInputsNumber();
if (getOriginalOutputsNumber() != 3)
IE_THROW() << m_errorPrefix << "has incorrect number of output edges: " << getOriginalOutputsNumber();
const auto nms = std::dynamic_pointer_cast<const ngraph::op::v8::MulticlassNms>(op);
auto& atrri = nms->get_attrs();
auto nmsBase = std::dynamic_pointer_cast<ov::op::util::MulticlassNmsBase>(op);
if (nmsBase == nullptr)
IE_THROW() << m_errorPrefix << " is not an instance of MulticlassNmsBase.";
auto& atrri = nmsBase->get_attrs();
m_sortResultAcrossBatch = atrri.sort_result_across_batch;
m_nmsTopK = atrri.nms_top_k;
m_iouThreshold = atrri.iou_threshold;
@@ -76,14 +74,27 @@ MultiClassNms::MultiClassNms(const std::shared_ptr<ngraph::Node>& op, const dnnl
m_nmsEta = atrri.nms_eta;
m_normalized = atrri.normalized;
// boxes [N, M, 4], scores [N, C, M] opset8/9
// boxes [C, M, 4], scores [C, M], roisnum [N] opset9
const auto& boxes_dims = getInputShapeAtPort(NMS_BOXES).getDims();
const auto& scores_dims = getInputShapeAtPort(NMS_SCORES).getDims();
if (boxes_dims.size() != 3)
IE_THROW() << m_errorPrefix << "has unsupported 'boxes' input rank: " << boxes_dims.size();
if (boxes_dims[2] != 4)
IE_THROW() << m_errorPrefix << "has unsupported 'boxes' input 3rd dimension size: " << boxes_dims[2];
const auto& scores_dims = getInputShapeAtPort(NMS_SCORES).getDims();
if (scores_dims.size() != 3)
if (scores_dims.size() == 3) {
if (boxes_dims[0] != scores_dims[0] || boxes_dims[1] != scores_dims[2])
IE_THROW() << m_errorPrefix << "has incompatible 'boxes' and 'scores' shape " << PartialShape(boxes_dims) << " v.s. " << PartialShape(scores_dims);
} else if (scores_dims.size() == 2) {
if (op->get_type_info() == ov::op::v8::MulticlassNms::get_type_info_static())
IE_THROW() << m_errorPrefix << "has unsupported 'scores' input rank: " << scores_dims.size();
if (boxes_dims[0] != scores_dims[0] || boxes_dims[1] != scores_dims[1])
IE_THROW() << m_errorPrefix << "has incompatible 'boxes' and 'scores' shape " << PartialShape(boxes_dims) << " v.s. " << PartialShape(scores_dims);
if (getOriginalInputsNumber() != 3)
IE_THROW() << m_errorPrefix << "has incorrect number of input edges: " << getOriginalInputsNumber() << " when input 'scores' is 2D.";
} else {
IE_THROW() << m_errorPrefix << "has unsupported 'scores' input rank: " << scores_dims.size();
}
}
void MultiClassNms::initSupportedPrimitiveDescriptors() {
@@ -100,25 +111,57 @@ void MultiClassNms::initSupportedPrimitiveDescriptors() {
checkPrecision(getOriginalOutputPrecisionAtPort(NMS_SELECTEDOUTPUTS), supportedFloatPrecision, "selected_outputs", m_outType);
checkPrecision(getOriginalOutputPrecisionAtPort(NMS_SELECTEDNUM), supportedIntOutputPrecision, "selected_num", m_outType);
addSupportedPrimDesc({{LayoutType::ncsp, Precision::FP32},
{LayoutType::ncsp, Precision::FP32}},
{{LayoutType::ncsp, Precision::FP32},
{LayoutType::ncsp, Precision::I32},
{LayoutType::ncsp, Precision::I32}},
impl_desc_type::ref_any);
if (getOriginalInputsNumber() == 3) {
checkPrecision(getOriginalInputPrecisionAtPort(NMS_ROISNUM), supportedIntOutputPrecision, "roisnum", m_inType);
addSupportedPrimDesc({{LayoutType::ncsp, Precision::FP32},
{LayoutType::ncsp, Precision::FP32},
{LayoutType::ncsp, Precision::I32}},
{{LayoutType::ncsp, Precision::FP32},
{LayoutType::ncsp, Precision::I32},
{LayoutType::ncsp, Precision::I32}},
impl_desc_type::ref_any);
} else {
addSupportedPrimDesc({{LayoutType::ncsp, Precision::FP32},
{LayoutType::ncsp, Precision::FP32}},
{{LayoutType::ncsp, Precision::FP32},
{LayoutType::ncsp, Precision::I32},
{LayoutType::ncsp, Precision::I32}},
impl_desc_type::ref_any);
}
}
// shared Y N
// boxes: N, M, 4 C, sum(M'), 4
// scores: N, C, M C, sum(M')
void MultiClassNms::prepareParams() {
const auto& boxes_dims = getParentEdgeAt(NMS_BOXES)->getMemory().getStaticDims();
const auto& scores_dims = getParentEdgeAt(NMS_SCORES)->getMemory().getStaticDims();
if (!(boxes_dims[0] == scores_dims[0] && boxes_dims[1] == scores_dims[2])) {
IE_THROW() << m_errorPrefix << "has incompatible 'boxes' and 'scores' input dmensions";
const bool has_roinum = getOriginalInputsNumber() == 3;
const auto shared = scores_dims.size() == 3; // bboxes shared among classes
if (shared) {
if (boxes_dims[0] != scores_dims[0] || boxes_dims[1] != scores_dims[2])
IE_THROW() << m_errorPrefix << "has incompatible 'boxes' and 'scores' shape " << PartialShape(boxes_dims) << " v.s. " << PartialShape(scores_dims);
} else if (scores_dims.size() == 2) {
if (boxes_dims[0] != scores_dims[0] || boxes_dims[1] != scores_dims[1])
IE_THROW() << m_errorPrefix << "has incompatible 'boxes' and 'scores' shape " << PartialShape(boxes_dims) << " v.s. " << PartialShape(scores_dims);
if (!has_roinum)
IE_THROW() << m_errorPrefix << "has incorrect number of input edges: " << getOriginalInputsNumber() << " when input 'scores' is 2D.";
} else {
IE_THROW() << m_errorPrefix << "has unsupported 'scores' input rank: " << scores_dims.size();
}
m_numBatches = boxes_dims[0];
m_numBoxes = boxes_dims[1];
m_numClasses = scores_dims[1];
if (has_roinum) {
const auto& roisnum_dims = getParentEdgeAt(NMS_ROISNUM)->getMemory().getStaticDims();
if (roisnum_dims.size() != 1)
IE_THROW() << m_errorPrefix << "has unsupported 'roisnum' input rank: " << roisnum_dims.size();
m_numBatches = shared ? boxes_dims[0] : roisnum_dims[0];
} else {
m_numBatches = boxes_dims[0];
}
m_numBoxes = shared ? boxes_dims[1] : boxes_dims[1];
m_numClasses = shared ? scores_dims[1] : scores_dims[0];
int max_output_boxes_per_class = 0;
size_t real_num_classes = m_backgroundClass == -1 ? m_numClasses :
@@ -134,7 +177,7 @@ void MultiClassNms::prepareParams() {
if (m_keepTopK >= 0)
m_maxBoxesPerBatch = std::min(m_maxBoxesPerBatch, static_cast<size_t>(m_keepTopK));
m_numFiltBox.resize(m_numBatches);
m_numFiltBox.resize(m_numBatches); // number of rois after nms for each class in each image
for (auto &numPerBatch : m_numFiltBox) {
numPerBatch.resize(m_numClasses, 0);
}
@@ -158,10 +201,14 @@ void MultiClassNms::execute(dnnl::stream strm) {
const float* scores = reinterpret_cast<const float*>(getParentEdgeAt(NMS_SCORES)->getMemoryPtr()->GetPtr());
auto dims_boxes = getParentEdgeAt(NMS_BOXES)->getMemory().getStaticDims();
auto dims_scores = getParentEdgeAt(NMS_SCORES)->getMemory().getStaticDims();
if (m_nmsRealTopk == 0)
return;
const bool has_roinum = getOriginalInputsNumber() == 3;
const auto shared = dims_scores.size() == 3; // bboxes shared among classes
auto selectedOutputsMemPtr = getChildEdgesAtPort(NMS_SELECTEDOUTPUTS)[0]->getMemoryPtr();
auto selectedIndicesMemPtr = getChildEdgesAtPort(NMS_SELECTEDINDICES)[0]->getMemoryPtr();
auto validOutputsMemPtr = getChildEdgesAtPort(NMS_SELECTEDNUM)[0]->getMemoryPtr();
@@ -169,10 +216,17 @@ void MultiClassNms::execute(dnnl::stream strm) {
auto boxesStrides = getParentEdgeAt(NMS_BOXES)->getMemory().GetDescWithType<BlockedMemoryDesc>()->getStrides();
auto scoresStrides = getParentEdgeAt(NMS_SCORES)->getMemory().GetDescWithType<BlockedMemoryDesc>()->getStrides();
int* roisnum = nullptr;
VectorDims roisnumStrides;
if (has_roinum) {
roisnum = reinterpret_cast<int*>(getParentEdgeAt(NMS_ROISNUM)->getMemoryPtr()->GetPtr());
roisnumStrides = getParentEdgeAt(NMS_ROISNUM)->getMemory().GetDescWithType<BlockedMemoryDesc>()->getStrides();
}
if ((m_nmsEta >= 0) && (m_nmsEta < 1)) {
nmsWithEta(boxes, scores, boxesStrides, scoresStrides);
nmsWithEta(boxes, scores, roisnum, boxesStrides, scoresStrides, roisnumStrides, shared);
} else {
nmsWithoutEta(boxes, scores, boxesStrides, scoresStrides);
nmsWithoutEta(boxes, scores, roisnum, boxesStrides, scoresStrides, roisnumStrides, shared);
}
size_t startOffset = m_numFiltBox[0][0];
@@ -229,7 +283,7 @@ void MultiClassNms::execute(dnnl::stream strm) {
}
}
if (m_sortResultAcrossBatch) {
if (m_sortResultAcrossBatch) { /* sort across batch */
if (m_sortResultType == MulticlassNmsSortResultType::SCORE) {
parallel_sort(m_filtBoxes.begin(), m_filtBoxes.begin() + startOffset, [](const filteredBoxes& l, const filteredBoxes& r) {
return (l.score > r.score) || (l.score == r.score && l.batch_index < r.batch_index) ||
@@ -252,10 +306,11 @@ void MultiClassNms::execute(dnnl::stream strm) {
});
}
const size_t validOutputs = std::min(startOffset, m_maxBoxesPerBatch * dims_boxes[0]);
/* output */
const size_t validOutputs = std::min(startOffset, m_maxBoxesPerBatch * m_numBatches);
std::vector<size_t> m_selected_num;
m_selected_num.resize(dims_boxes[0]);
m_selected_num.resize(m_numBatches);
const size_t selectedBoxesNum_perBatch = m_maxBoxesPerBatch;
@@ -272,22 +327,46 @@ void MultiClassNms::execute(dnnl::stream strm) {
float* selected_outputs = reinterpret_cast<float*>(selectedOutputsMemPtr->GetPtr());
int* selected_num = reinterpret_cast<int*>(validOutputsMemPtr->GetPtr());
auto _flattened_index = [](int batch_idx, int box_idx, int num_box) {
return batch_idx * num_box + box_idx;
};
int64_t output_offset = 0;
int64_t original_offset = 0;
for (size_t i = 0; i < dims_boxes[0]; i++) {
for (size_t i = 0; i < m_numBatches; i++) {
auto real_boxes = m_selected_num[i];
selected_num[i] = static_cast<int>(real_boxes);
for (size_t j = 0; j < real_boxes; j++) {
auto original_index = original_offset + j;
selected_indices[j + output_offset] = m_filtBoxes[original_index].batch_index * dims_boxes[1] + m_filtBoxes[original_index].box_index;
const auto &box_info = m_filtBoxes[original_index];
auto selected_base = selected_outputs + (output_offset + j) * 6;
selected_base[0] = m_filtBoxes[original_index].class_index;
selected_base[1] = m_filtBoxes[original_index].score;
selected_base[2] = boxes[selected_indices[j + output_offset] * 4];
selected_base[3] = boxes[selected_indices[j + output_offset] * 4 + 1];
selected_base[4] = boxes[selected_indices[j + output_offset] * 4 + 2];
selected_base[5] = boxes[selected_indices[j + output_offset] * 4 + 3];
selected_base[0] = box_info.class_index;
selected_base[1] = box_info.score;
auto &selected_index = selected_indices[j + output_offset];
if (shared) {
selected_index = _flattened_index(box_info.batch_index, box_info.box_index, m_numBoxes);
selected_base[2] = boxes[selected_index * 4];
selected_base[3] = boxes[selected_index * 4 + 1];
selected_base[4] = boxes[selected_index * 4 + 2];
selected_base[5] = boxes[selected_index * 4 + 3];
} else {
int64_t offset = 0;
for (int64_t i = 0; i < box_info.batch_index; i++) {
offset += roisnum[i];
}
// selected index from (M, C, 4)
selected_index = _flattened_index((offset + box_info.box_index),
box_info.class_index, m_numClasses);
int idx = box_info.class_index * boxesStrides[0] + offset * boxesStrides[1];
const float* curboxes = boxes + idx; // a slice of boxes of current class current image
selected_base[2] = curboxes[4 * box_info.box_index];
selected_base[3] = curboxes[4 * box_info.box_index + 1];
selected_base[4] = curboxes[4 * box_info.box_index + 2];
selected_base[5] = curboxes[4 * box_info.box_index + 3];
}
}
// TODO [DS NMS]: remove when nodes from models where nms is not last node in model supports DS
if (!isDynamicNode()) {
@@ -330,7 +409,13 @@ float MultiClassNms::intersectionOverUnion(const float* boxesI, const float* box
return intersection_area / (areaI + areaJ - intersection_area);
}
void MultiClassNms::nmsWithEta(const float* boxes, const float* scores, const SizeVector& boxesStrides, const SizeVector& scoresStrides) {
void MultiClassNms::nmsWithEta(const float* boxes,
const float* scores,
const int* roisnum,
const SizeVector& boxesStrides,
const SizeVector& scoresStrides,
const SizeVector& roisnumStrides,
const bool shared) {
auto less = [](const boxInfo& l, const boxInfo& r) {
return l.score < r.score || ((l.score == r.score) && (l.idx > r.idx));
};
@@ -340,13 +425,20 @@ void MultiClassNms::nmsWithEta(const float* boxes, const float* scores, const Si
};
parallel_for2d(m_numBatches, m_numClasses, [&](int batch_idx, int class_idx) {
if (!shared) {
if (roisnum[batch_idx] <= 0) {
m_numFiltBox[batch_idx][class_idx] = 0;
return;
}
}
if (class_idx != m_backgroundClass) {
std::vector<filteredBoxes> fb;
const float* boxesPtr = boxes + batch_idx * boxesStrides[0];
const float* scoresPtr = scores + batch_idx * scoresStrides[0] + class_idx * scoresStrides[1];
const float* boxesPtr = slice_class(batch_idx, class_idx, boxes, boxesStrides, true, roisnum, roisnumStrides, shared);
const float* scoresPtr = slice_class(batch_idx, class_idx, scores, scoresStrides, false, roisnum, roisnumStrides, shared);
std::priority_queue<boxInfo, std::vector<boxInfo>, decltype(less)> sorted_boxes(less);
for (int box_idx = 0; box_idx < m_numBoxes; box_idx++) {
int cur_numBoxes = shared ? m_numBoxes : roisnum[batch_idx];
for (int box_idx = 0; box_idx < cur_numBoxes; box_idx++) {
if (scoresPtr[box_idx] >= m_scoreThreshold) // algin with ref
sorted_boxes.emplace(boxInfo({scoresPtr[box_idx], box_idx, 0}));
}
@@ -396,15 +488,65 @@ void MultiClassNms::nmsWithEta(const float* boxes, const float* scores, const Si
});
}
void MultiClassNms::nmsWithoutEta(const float* boxes, const float* scores, const SizeVector& boxesStrides, const SizeVector& scoresStrides) {
/* get boxes/scores for current class and image
// shared not-shared
// boxes: [in] N, M, 4 C, M, 4 -> [out] num_priors, 4
// scores: [in] N, C, M C, M -> [out] num_priors,
*/
const float* MultiClassNms::slice_class(const int batch_idx,
const int class_idx,
const float* dataPtr,
const SizeVector& dataStrides,
const bool is_boxes,
const int* roisnum,
const SizeVector& roisnumStrides,
const bool shared) {
if (shared) {
if (is_boxes)
return dataPtr + batch_idx * dataStrides[0];
else
return dataPtr + batch_idx * dataStrides[0] + class_idx * dataStrides[1];
}
// get M boxes of current class_idx : 1, M, 4
const float* boxesPtr_cls = dataPtr + class_idx * dataStrides[0];
// then get Mi boxes of current batch_idx and current class_idx : M', 4
auto boxes_idx = 0;
for (auto i = 0; i < batch_idx; i++) {
boxes_idx += roisnum[i];
}
// auto boxes_num = roisnum[batch_idx];
return boxesPtr_cls + boxes_idx * dataStrides[1];
}
void MultiClassNms::nmsWithoutEta(const float* boxes,
const float* scores,
const int* roisnum,
const SizeVector& boxesStrides,
const SizeVector& scoresStrides,
const SizeVector& roisnumStrides,
const bool shared) {
parallel_for2d(m_numBatches, m_numClasses, [&](int batch_idx, int class_idx) {
/*
// nms over a class over an image
// boxes: num_priors, 4
// scores: num_priors, 1
*/
if (!shared) {
if (roisnum[batch_idx] <= 0) {
m_numFiltBox[batch_idx][class_idx] = 0;
return;
}
}
if (class_idx != m_backgroundClass) {
const float* boxesPtr = boxes + batch_idx * boxesStrides[0];
const float* scoresPtr = scores + batch_idx * scoresStrides[0] + class_idx * scoresStrides[1];
const float* boxesPtr = slice_class(batch_idx, class_idx, boxes, boxesStrides, true, roisnum, roisnumStrides, shared);
const float* scoresPtr = slice_class(batch_idx, class_idx, scores, scoresStrides, false, roisnum, roisnumStrides, shared);
std::vector<std::pair<float, int>> sorted_boxes;
for (int box_idx = 0; box_idx < m_numBoxes; box_idx++) {
if (scoresPtr[box_idx] >= m_scoreThreshold) // algin with ref
int cur_numBoxes = shared ? m_numBoxes : roisnum[batch_idx];
for (int box_idx = 0; box_idx < cur_numBoxes; box_idx++) {
if (scoresPtr[box_idx] >= m_scoreThreshold) // align with ref
sorted_boxes.emplace_back(std::make_pair(scoresPtr[box_idx], box_idx));
}
@@ -40,6 +40,7 @@ private:
// input (port Num)
const size_t NMS_BOXES = 0;
const size_t NMS_SCORES = 1;
const size_t NMS_ROISNUM = 2;
// output (port Num)
const size_t NMS_SELECTEDOUTPUTS = 0;
@@ -66,7 +67,7 @@ private:
std::string m_errorPrefix;
std::vector<std::vector<size_t>> m_numFiltBox;
std::vector<std::vector<size_t>> m_numFiltBox; // number of rois after nms for each class in each image
std::vector<size_t> m_numBoxOffset;
const std::string m_inType = "input", m_outType = "output";
@@ -86,17 +87,27 @@ private:
int suppress_begin_index;
};
std::vector<filteredBoxes> m_filtBoxes;
std::vector<filteredBoxes> m_filtBoxes; // rois after nms for each class in each image
void checkPrecision(const InferenceEngine::Precision prec, const std::vector<InferenceEngine::Precision> precList, const std::string name,
const std::string type);
float intersectionOverUnion(const float* boxesI, const float* boxesJ, const bool normalized);
void nmsWithEta(const float* boxes, const float* scores, const InferenceEngine::SizeVector& boxesStrides, const InferenceEngine::SizeVector& scoresStrides);
void nmsWithEta(const float* boxes, const float* scores, const int* roisnum, const InferenceEngine::SizeVector& boxesStrides,
const InferenceEngine::SizeVector& scoresStrides, const InferenceEngine::SizeVector& roisnumStrides, const bool shared);
void nmsWithoutEta(const float* boxes, const float* scores, const InferenceEngine::SizeVector& boxesStrides,
const InferenceEngine::SizeVector& scoresStrides);
void nmsWithoutEta(const float* boxes, const float* scores, const int* roisnum, const InferenceEngine::SizeVector& boxesStrides,
const InferenceEngine::SizeVector& scoresStrides, const InferenceEngine::SizeVector& roisnumStrides, const bool shared);
const float* slice_class(const int batch_idx,
const int class_idx,
const float* dataPtr,
const InferenceEngine::SizeVector& dataStrides,
const bool is_boxes,
const int* roisnum,
const InferenceEngine::SizeVector& roisnumStrides,
const bool shared);
};
} // namespace node
@@ -14,7 +14,8 @@ TEST_P(MulticlassNmsLayerTest, Serialize) {
serialize();
}
const std::vector<std::vector<ov::test::InputShape>> shapeParams = {
/* input format #1 with 2 inputs: bboxes N, M, 4, scores N, C, M */
const std::vector<std::vector<ov::test::InputShape>> shapeParams1 = {
// num_batches, num_boxes, 4
{{{ngraph::Dimension::dynamic(), ngraph::Dimension::dynamic(), 4},
{{1, 10, 4}, {2, 100, 4}}},
@@ -27,6 +28,34 @@ const std::vector<std::vector<ov::test::InputShape>> shapeParams = {
{{1, 3, 10}, {2, 5, 100}}}}
};
/* input format #2 with 3 inputs: bboxes C, M, 4, scores C, M, roisnum N */
const std::vector<std::vector<ov::test::InputShape>> shapeParams2 = {
/*0*/
// bboxes
{{{ngraph::Dimension::dynamic(), ngraph::Dimension::dynamic(), 4},
{{1, 10, 4}, {2, 100, 4}}},
// scores
{{ngraph::Dimension::dynamic(), ngraph::Dimension::dynamic()},
{{1, 10}, {2, 100}}},
// roisnum
{{ngraph::Dimension::dynamic()},
{{1}, {10}}}},
/*1*/
{{{ngraph::Dimension(1, 10), ngraph::Dimension(1, 100), 4},
{{1, 10, 4}, {2, 100, 4}}},
{{{ngraph::Dimension(1, 10), ngraph::Dimension(1, 100)}},
{{1, 10}, {2, 100}}},
{{ngraph::Dimension::dynamic()},
{{1}, {10}}}},
/*2*/
{{{ngraph::Dimension(3), ngraph::Dimension(2), 4},
{{3, 2, 4}}},
{{{ngraph::Dimension(3), ngraph::Dimension(2)}},
{{3, 2}}},
{{ngraph::Dimension::dynamic()},
{{1}, {2}}}}
};
const std::vector<int32_t> nmsTopK = {-1, 20};
const std::vector<float> iouThreshold = {0.7f};
const std::vector<float> scoreThreshold = {0.7f};
@@ -34,7 +63,7 @@ const std::vector<int32_t> backgroundClass = {-1, 0};
const std::vector<int32_t> keepTopK = {-1, 30};
const std::vector<element::Type> outType = {element::i32, element::i64};
const std::vector<op::v8::MulticlassNms::SortResultType> sortResultType = {
const std::vector<ov::op::util::MulticlassNmsBase::SortResultType> sortResultType = {
op::v8::MulticlassNms::SortResultType::SCORE,
op::v8::MulticlassNms::SortResultType::CLASSID,
op::v8::MulticlassNms::SortResultType::NONE};
@@ -42,9 +71,10 @@ const std::vector<bool> sortResDesc = {true, false};
const std::vector<float> nmsEta = {0.6f, 1.0f};
const std::vector<bool> normalized = {true, false};
const auto nmsParams = ::testing::Combine(
::testing::ValuesIn(shapeParams),
const auto nmsParams1_smoke = ::testing::Combine(
::testing::ValuesIn(shapeParams1),
::testing::Combine(::testing::Values(ov::element::f32),
::testing::Values(ov::element::i32),
::testing::Values(ov::element::i32),
::testing::Values(ov::element::f32)),
::testing::ValuesIn(nmsTopK),
@@ -59,8 +89,32 @@ const auto nmsParams = ::testing::Combine(
::testing::ValuesIn(normalized)),
::testing::Values(CommonTestUtils::DEVICE_CPU));
INSTANTIATE_TEST_SUITE_P(smoke_MulticlassNmsLayerTest,
INSTANTIATE_TEST_SUITE_P(smoke_MulticlassNmsLayerTest1,
MulticlassNmsLayerTest,
nmsParams,
nmsParams1_smoke,
MulticlassNmsLayerTest::getTestCaseName);
const auto nmsParams2_smoke = ::testing::Combine(
::testing::ValuesIn(shapeParams2),
::testing::Combine(::testing::Values(ov::element::f32),
::testing::Values(ov::element::i32),
::testing::Values(ov::element::i32),
::testing::Values(ov::element::f32)),
::testing::ValuesIn(nmsTopK),
::testing::Combine(::testing::ValuesIn(iouThreshold),
::testing::ValuesIn(scoreThreshold),
::testing::ValuesIn(nmsEta)),
::testing::ValuesIn(backgroundClass),
::testing::ValuesIn(keepTopK),
::testing::ValuesIn(outType),
::testing::ValuesIn(sortResultType),
::testing::Combine(::testing::ValuesIn(sortResDesc),
::testing::ValuesIn(normalized)),
::testing::Values(CommonTestUtils::DEVICE_CPU));
INSTANTIATE_TEST_SUITE_P(smoke_MulticlassNmsLayerTest2,
MulticlassNmsLayerTest,
nmsParams2_smoke,
MulticlassNmsLayerTest::getTestCaseName);
} // namespace
@@ -10,13 +10,11 @@
#include <ngraph/function.hpp>
#include <ngraph/opsets/opset1.hpp>
#include <ngraph/opsets/opset3.hpp>
#include <ngraph/opsets/opset5.hpp>
#include <ngraph/opsets/opset8.hpp>
#include <ngraph/opsets/opset9.hpp>
#include <transformations/op_conversions/convert_multiclass_nms_to_multiclass_nms_ie.hpp>
#include <transformations/init_node_info.hpp>
#include <transformations/utils/utils.hpp>
#include <ngraph_ops/nms_static_shape_ie.hpp>
#include <ngraph_ops/multiclass_nms_ie_internal.hpp>
#include <ngraph/pass/constant_folding.hpp>
#include <ngraph/pass/manager.hpp>
@@ -30,18 +28,18 @@ TEST_F(TransformationTestsF, ConvertMulticlassNmsToMulticlassNmsIE) {
auto boxes = std::make_shared<opset1::Parameter>(element::f32, Shape{1, 1000, 4});
auto scores = std::make_shared<opset1::Parameter>(element::f32, Shape{1, 1, 1000});
auto nms = std::make_shared<opset8::MulticlassNms>(boxes, scores, opset8::MulticlassNms::Attributes());
auto nms = std::make_shared<opset9::MulticlassNms>(boxes, scores, opset9::MulticlassNms::Attributes());
function = std::make_shared<Function>(NodeVector{nms}, ParameterVector{boxes, scores});
manager.register_pass<ngraph::pass::ConvertMulticlassNmsToMulticlassNmsIE>();
manager.register_pass<ngraph::pass::ConstantFolding>();
manager.register_pass<pass::ConvertMulticlassNmsToMulticlassNmsIE>();
manager.register_pass<pass::ConstantFolding>();
}
{
auto boxes = std::make_shared<opset1::Parameter>(element::f32, Shape{1, 1000, 4});
auto scores = std::make_shared<opset1::Parameter>(element::f32, Shape{1, 1, 1000});
auto nms = std::make_shared<op::internal::NmsStaticShapeIE<ngraph::opset8::MulticlassNms>>(boxes, scores, opset8::MulticlassNms::Attributes());
auto nms = std::make_shared<op::internal::MulticlassNmsIEInternal>(boxes, scores, opset9::MulticlassNms::Attributes());
function_ref = std::make_shared<Function>(NodeVector{nms}, ParameterVector{boxes, scores});
}
@@ -0,0 +1,84 @@
// Copyright (C) 2018-2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <gtest/gtest.h>
#include <string>
#include <memory>
#include <ngraph/function.hpp>
#include <ngraph/opsets/opset1.hpp>
#include <ngraph/opsets/opset8.hpp>
#include <ngraph/opsets/opset9.hpp>
#include <ngraph/pass/manager.hpp>
#include <transformations/op_conversions/convert_multiclass_nms_upgrade.hpp>
#include <transformations/init_node_info.hpp>
#include "common_test_utils/ngraph_test_utils.hpp"
using namespace testing;
using namespace ngraph;
TEST_F(TransformationTestsF, ConvertMulticlassNms8ToMulticlassNms9) {
{
auto boxes = std::make_shared<opset1::Parameter>(element::f32, Shape{1, 1000, 4});
auto scores = std::make_shared<opset1::Parameter>(element::f32, Shape{1, 1, 1000});
auto nms = std::make_shared<opset8::MulticlassNms>(boxes, scores, opset8::MulticlassNms::Attributes());
function = std::make_shared<Function>(NodeVector{nms}, ParameterVector{boxes, scores});
manager.register_pass<ngraph::pass::ConvertMulticlassNms8ToMulticlassNms9>();
}
{
auto boxes = std::make_shared<opset1::Parameter>(element::f32, Shape{1, 1000, 4});
auto scores = std::make_shared<opset1::Parameter>(element::f32, Shape{1, 1, 1000});
auto nms = std::make_shared<opset9::MulticlassNms>(boxes, scores, opset9::MulticlassNms::Attributes());
function_ref = std::make_shared<Function>(NodeVector{nms}, ParameterVector{boxes, scores});
}
}
TEST_F(TransformationTestsF, ConvertMulticlassNms8ToMulticlassNms9_dynamic_rank) {
{
auto boxes = std::make_shared<opset1::Parameter>(element::f32, PartialShape::dynamic());
auto scores = std::make_shared<opset1::Parameter>(element::f32, PartialShape::dynamic());
auto nms = std::make_shared<opset8::MulticlassNms>(boxes, scores, opset8::MulticlassNms::Attributes());
function = std::make_shared<Function>(NodeVector{nms}, ParameterVector{boxes, scores});
manager.register_pass<ngraph::pass::ConvertMulticlassNms8ToMulticlassNms9>();
}
{
auto boxes = std::make_shared<opset1::Parameter>(element::f32, PartialShape::dynamic());
auto scores = std::make_shared<opset1::Parameter>(element::f32, PartialShape::dynamic());
auto nms = std::make_shared<opset9::MulticlassNms>(boxes, scores, opset9::MulticlassNms::Attributes());
function_ref = std::make_shared<Function>(NodeVector{nms}, ParameterVector{boxes, scores});
}
}
TEST_F(TransformationTestsF, ConvertMulticlassNms8ToMulticlassNms9_dynamic_dims) {
{
auto boxes = std::make_shared<opset1::Parameter>(element::f32, PartialShape({Dimension::dynamic(), Dimension::dynamic(), 4}));
auto scores = std::make_shared<opset1::Parameter>(element::f32, PartialShape({Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()}));
auto nms = std::make_shared<opset8::MulticlassNms>(boxes, scores, opset8::MulticlassNms::Attributes());
function = std::make_shared<Function>(NodeVector{nms}, ParameterVector{boxes, scores});
manager.register_pass<ngraph::pass::ConvertMulticlassNms8ToMulticlassNms9>();
}
{
auto boxes = std::make_shared<opset1::Parameter>(element::f32, PartialShape({Dimension::dynamic(), Dimension::dynamic(), 4}));
auto scores = std::make_shared<opset1::Parameter>(element::f32, PartialShape({Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()}));
auto nms = std::make_shared<opset9::MulticlassNms>(boxes, scores, opset9::MulticlassNms::Attributes());
function_ref = std::make_shared<Function>(NodeVector{nms}, ParameterVector{boxes, scores});
}
}
@@ -5,6 +5,7 @@
#include "behavior/ov_plugin/caching_tests.hpp"
#include <ngraph_ops/nms_ie_internal.hpp>
#include <ngraph_ops/nms_static_shape_ie.hpp>
#include <ngraph_ops/multiclass_nms_ie_internal.hpp>
using namespace ov::test::behavior;
using namespace ngraph;
@@ -61,9 +62,9 @@ namespace {
static std::shared_ptr<ngraph::Function> simple_function_multiclass_nms_internal(ngraph::element::Type, size_t) {
auto boxes = std::make_shared<ov::op::v0::Parameter>(element::f32, Shape{1, 1000, 4});
auto scores = std::make_shared<ov::op::v0::Parameter>(element::f32, Shape{1, 1, 1000});
ov::op::v8::MulticlassNms::Attributes attr;
ov::op::util::MulticlassNmsBase::Attributes attr;
attr.output_type = element::i32;
auto nms = std::make_shared<op::internal::NmsStaticShapeIE<ov::op::v8::MulticlassNms>>(boxes, scores, attr);
auto nms = std::make_shared<ngraph::op::internal::MulticlassNmsIEInternal>(boxes, scores, attr);
auto res = std::make_shared<ov::op::v0::Result>(nms);
auto func = std::make_shared<Function>(NodeVector{nms}, ParameterVector{boxes, scores});
return func;
@@ -73,7 +74,7 @@ namespace {
std::vector<ovModelWithName> funcs = {
ovModelWithName { simple_function_non_max_supression_internal, "NonMaxSuppressionIEInternal"},
ovModelWithName { simple_function_matrix_nms_internal, "NmsStaticShapeIE_MatrixNms"},
ovModelWithName { simple_function_multiclass_nms_internal, "NmsStaticShapeIE_MulticlassNms"},
ovModelWithName { simple_function_multiclass_nms_internal, "MulticlassNmsIEInternal"},
};
return funcs;
}
@@ -5,6 +5,7 @@
#include "behavior/plugin/caching_tests.hpp"
#include <ngraph_ops/nms_ie_internal.hpp>
#include <ngraph_ops/nms_static_shape_ie.hpp>
#include <ngraph_ops/multiclass_nms_ie_internal.hpp>
using namespace LayerTestsDefinitions;
using namespace ngraph;
@@ -61,9 +62,9 @@ namespace {
static std::shared_ptr<ngraph::Function> simple_function_multiclass_nms_internal(ngraph::element::Type, size_t) {
auto boxes = std::make_shared<opset1::Parameter>(element::f32, Shape{1, 1000, 4});
auto scores = std::make_shared<opset1::Parameter>(element::f32, Shape{1, 1, 1000});
ov::op::v8::MulticlassNms::Attributes attr;
op::util::MulticlassNmsBase::Attributes attr;
attr.output_type = element::i32;
auto nms = std::make_shared<op::internal::NmsStaticShapeIE<ov::op::v8::MulticlassNms>>(boxes, scores, attr);
auto nms = std::make_shared<op::internal::MulticlassNmsIEInternal>(boxes, scores, attr);
auto res = std::make_shared<ngraph::opset6::Result>(nms);
auto func = std::make_shared<Function>(NodeVector{nms}, ParameterVector{boxes, scores});
return func;
@@ -73,7 +74,7 @@ namespace {
std::vector<nGraphFunctionWithName> funcs = {
nGraphFunctionWithName { simple_function_non_max_supression_internal, "NonMaxSuppressionIEInternal"},
nGraphFunctionWithName { simple_function_matrix_nms_internal, "NmsStaticShapeIE_MatrixNms"},
nGraphFunctionWithName { simple_function_multiclass_nms_internal, "NmsStaticShapeIE_MulticlassNms"},
nGraphFunctionWithName { simple_function_multiclass_nms_internal, "MulticlassNmsIEInternal"},
};
return funcs;
}
@@ -12,12 +12,13 @@ using namespace ov::test::subgraph;
using namespace InferenceEngine;
using namespace ngraph;
const std::vector<std::vector<ov::Shape>> inStaticShapeParams = {
/* input format #1 with 2 inputs: bboxes N, M, 4, scores N, C, M */
const std::vector<std::vector<ov::Shape>> inStaticShapeParams1 = {
{{3, 100, 4}, {3, 1, 100}},
{{1, 10, 4}, {1, 100, 10 }}
};
const std::vector<std::vector<ov::test::InputShape>> inDynamicShapeParams = {
const std::vector<std::vector<ov::test::InputShape>> inDynamicShapeParams1 = {
// num_batches, num_boxes, 4
{{{ngraph::Dimension::dynamic(), ngraph::Dimension::dynamic(), 4},
{{1, 10, 4}, {2, 100, 4}}},
@@ -30,6 +31,48 @@ const std::vector<std::vector<ov::test::InputShape>> inDynamicShapeParams = {
{{1, 3, 10}, {2, 5, 100}}}}
};
/* input format #2 with 3 inputs: bboxes C, M, 4, scores C, M, roisnum N */
const std::vector<std::vector<ov::Shape>> inStaticShapeParams2 = {
{{1, 10, 4}, {1, 10}, {1}},
{{1, 10, 4}, {1, 10}, {10}},
{{2, 100, 4}, {2, 100}, {1}},
{{2, 100, 4}, {2, 100}, {10}}
};
const std::vector<std::vector<ov::test::InputShape>> inDynamicShapeParams2 = {
/*0*/
// bboxes
{{{ngraph::Dimension::dynamic(), ngraph::Dimension::dynamic(), 4},
{{1, 10, 4}, {2, 100, 4}}},
// scores
{{ngraph::Dimension::dynamic(), ngraph::Dimension::dynamic()},
{{1, 10}, {2, 100}}},
// roisnum
{{ngraph::Dimension::dynamic()},
{{1}, {10}}}},
/*1*/
{{{ngraph::Dimension(1, 10), ngraph::Dimension(1, 100), 4},
{{1, 10, 4}, {2, 100, 4}}},
{{{ngraph::Dimension(1, 10), ngraph::Dimension(1, 100)}},
{{1, 10}, {2, 100}}},
{{ngraph::Dimension::dynamic()},
{{1}, {10}}}},
/*2*/
{{{ngraph::Dimension(2), ngraph::Dimension(100), 4},
{{2, 100, 4}}},
{{{ngraph::Dimension(2), ngraph::Dimension(100)}},
{{2, 100}}},
{{ngraph::Dimension::dynamic()},
{{1}, {10}}}},
/*3*/
{{{ngraph::Dimension(3), ngraph::Dimension(2), 4},
{{3, 2, 4}}},
{{{ngraph::Dimension(3), ngraph::Dimension(2)}},
{{3, 2}}},
{{ngraph::Dimension::dynamic()},
{{1}, {10}}}} // more images than num_boxes
};
const std::vector<int32_t> nmsTopK = {-1, 20};
const std::vector<float> iouThreshold = {0.7f};
const std::vector<float> scoreThreshold = {0.7f};
@@ -37,15 +80,20 @@ const std::vector<int32_t> backgroundClass = {-1, 1};
const std::vector<int32_t> keepTopK = {-1, 30};
const std::vector<element::Type> outType = {element::i32, element::i64};
const std::vector<op::v8::MulticlassNms::SortResultType> sortResultType = {
op::v8::MulticlassNms::SortResultType::SCORE, op::v8::MulticlassNms::SortResultType::CLASSID, op::v8::MulticlassNms::SortResultType::NONE};
const std::vector<ov::op::util::MulticlassNmsBase::SortResultType> sortResultType = {
ov::op::util::MulticlassNmsBase::SortResultType::SCORE,
ov::op::util::MulticlassNmsBase::SortResultType::CLASSID,
ov::op::util::MulticlassNmsBase::SortResultType::NONE};
const std::vector<bool> sortResDesc = {true, false};
const std::vector<float> nmsEta = {0.6f, 1.0f};
const std::vector<bool> normalized = {true, false};
const auto nmsParamsStatic = ::testing::Combine(
::testing::ValuesIn(ov::test::static_shapes_to_test_representation(inStaticShapeParams)),
::testing::Combine(::testing::Values(ov::element::f32), ::testing::Values(ov::element::i32), ::testing::Values(ov::element::f32)),
const auto nmsParamsStatic_smoke1 = ::testing::Combine(
::testing::ValuesIn(ov::test::static_shapes_to_test_representation(inStaticShapeParams1)),
::testing::Combine(::testing::Values(ov::element::f32),
::testing::Values(ov::element::i32),
::testing::Values(ov::element::i32),
::testing::Values(ov::element::f32)),
::testing::ValuesIn(nmsTopK),
::testing::Combine(::testing::ValuesIn(iouThreshold), ::testing::ValuesIn(scoreThreshold), ::testing::ValuesIn(nmsEta)),
::testing::ValuesIn(backgroundClass),
@@ -55,9 +103,12 @@ const auto nmsParamsStatic = ::testing::Combine(
::testing::Combine(::testing::ValuesIn(sortResDesc), ::testing::ValuesIn(normalized)),
::testing::Values(CommonTestUtils::DEVICE_CPU));
const auto nmsParamsDynamic = ::testing::Combine(
::testing::ValuesIn(inDynamicShapeParams),
::testing::Combine(::testing::Values(ov::element::f32), ::testing::Values(ov::element::i32), ::testing::Values(ov::element::f32)),
const auto nmsParamsDynamic_smoke1 = ::testing::Combine(
::testing::ValuesIn(inDynamicShapeParams1),
::testing::Combine(::testing::Values(ov::element::f32),
::testing::Values(ov::element::i32),
::testing::Values(ov::element::i32),
::testing::Values(ov::element::f32)),
::testing::ValuesIn(nmsTopK),
::testing::Combine(::testing::ValuesIn(iouThreshold), ::testing::ValuesIn(scoreThreshold), ::testing::ValuesIn(nmsEta)),
::testing::ValuesIn(backgroundClass),
@@ -67,5 +118,38 @@ const auto nmsParamsDynamic = ::testing::Combine(
::testing::Combine(::testing::ValuesIn(sortResDesc), ::testing::ValuesIn(normalized)),
::testing::Values(CommonTestUtils::DEVICE_CPU));
INSTANTIATE_TEST_SUITE_P(smoke_MulticlassNmsLayerTest_static, MulticlassNmsLayerTest, nmsParamsStatic, MulticlassNmsLayerTest::getTestCaseName);
INSTANTIATE_TEST_SUITE_P(smoke_MulticlassNmsLayerTest_dynamic, MulticlassNmsLayerTest, nmsParamsDynamic, MulticlassNmsLayerTest::getTestCaseName);
INSTANTIATE_TEST_SUITE_P(smoke_MulticlassNmsLayerTest_static1, MulticlassNmsLayerTest, nmsParamsStatic_smoke1, MulticlassNmsLayerTest::getTestCaseName);
INSTANTIATE_TEST_SUITE_P(smoke_MulticlassNmsLayerTest_dynamic1, MulticlassNmsLayerTest, nmsParamsDynamic_smoke1, MulticlassNmsLayerTest::getTestCaseName);
const auto nmsParamsStatic_smoke2 = ::testing::Combine(
::testing::ValuesIn(ov::test::static_shapes_to_test_representation(inStaticShapeParams2)),
::testing::Combine(::testing::Values(ov::element::f32),
::testing::Values(ov::element::i32),
::testing::Values(ov::element::i32),
::testing::Values(ov::element::f32)),
::testing::ValuesIn(nmsTopK),
::testing::Combine(::testing::ValuesIn(iouThreshold), ::testing::ValuesIn(scoreThreshold), ::testing::ValuesIn(nmsEta)),
::testing::ValuesIn(backgroundClass),
::testing::ValuesIn(keepTopK),
::testing::ValuesIn(outType),
::testing::ValuesIn(sortResultType),
::testing::Combine(::testing::ValuesIn(sortResDesc), ::testing::ValuesIn(normalized)),
::testing::Values(CommonTestUtils::DEVICE_CPU));
const auto nmsParamsDynamic_smoke2 = ::testing::Combine(
::testing::ValuesIn(inDynamicShapeParams2),
::testing::Combine(::testing::Values(ov::element::f32),
::testing::Values(ov::element::i32),
::testing::Values(ov::element::i32),
::testing::Values(ov::element::f32)),
::testing::ValuesIn(nmsTopK),
::testing::Combine(::testing::ValuesIn(iouThreshold), ::testing::ValuesIn(scoreThreshold), ::testing::ValuesIn(nmsEta)),
::testing::ValuesIn(backgroundClass),
::testing::ValuesIn(keepTopK),
::testing::ValuesIn(outType),
::testing::ValuesIn(sortResultType),
::testing::Combine(::testing::ValuesIn(sortResDesc), ::testing::ValuesIn(normalized)),
::testing::Values(CommonTestUtils::DEVICE_CPU));
INSTANTIATE_TEST_SUITE_P(smoke_MulticlassNmsLayerTest_static2, MulticlassNmsLayerTest, nmsParamsStatic_smoke2, MulticlassNmsLayerTest::getTestCaseName);
INSTANTIATE_TEST_SUITE_P(smoke_MulticlassNmsLayerTest_dynamic2, MulticlassNmsLayerTest, nmsParamsDynamic_smoke2, MulticlassNmsLayerTest::getTestCaseName);
@@ -25,7 +25,8 @@ static const std::vector<std::pair<ov::DiscreteTypeInfo, std::shared_ptr<ov::Mod
}
for (const auto& type_info : opsInfo) {
res.push_back({type_info, opGenerator.find(type_info)->second()});
if (opGenerator.find(type_info) != opGenerator.end())
res.push_back({type_info, opGenerator.find(type_info)->second()});
}
return res;
}
@@ -1454,19 +1454,28 @@ std::shared_ptr<ov::Model> generateMultiSubGraph(const std::shared_ptr<ov::op::O
}
}
std::shared_ptr<ov::Model> generateNmsBase(const std::shared_ptr<ov::op::Op> &node) {
std::shared_ptr<ov::Model> generate(const std::shared_ptr<ov::op::v8::MatrixNms> &node) {
const auto params = ngraph::builder::makeDynamicParams(ov::element::f16, {{1, 2, 4}, {1, 2, 2}});
const auto outputs =
ngraph::helpers::convert2OutputVector(ngraph::helpers::castOps2Nodes<ov::op::v0::Parameter>(params));
if (ov::is_type<ov::op::v8::MatrixNms>(node)) {
const auto nms =
std::make_shared<ov::op::v8::MatrixNms>(outputs[0], outputs[1], ov::op::v8::MatrixNms::Attributes());
ov::ResultVector results{std::make_shared<ov::op::v0::Result>(nms)};
return std::make_shared<ov::Model>(results, params, "MatrixNms");
} else if (ov::is_type<ov::op::v8::MulticlassNms>(node)) {
const auto nms =
std::make_shared<ov::op::v8::MatrixNms>(outputs[0], outputs[1], ov::op::v8::MatrixNms::Attributes());
ov::ResultVector results{std::make_shared<ov::op::v0::Result>(nms)};
return std::make_shared<ov::Model>(results, params, "MatrixNms");
}
std::shared_ptr<ov::Model> generateMulticlassNmsBase(const std::shared_ptr<ov::op::Op> &node) {
const auto params = ngraph::builder::makeDynamicParams(ov::element::f16, {{1, 2, 4}, {1, 2, 2}});
const auto outputs =
ngraph::helpers::convert2OutputVector(ngraph::helpers::castOps2Nodes<ov::op::v0::Parameter>(params));
if (ov::is_type<ov::op::v8::MulticlassNms>(node)) {
const auto nms = std::make_shared<ov::op::v8::MulticlassNms>(outputs[0], outputs[1], ov::op::v8::MulticlassNms::Attributes());
ov::ResultVector results{std::make_shared<ov::op::v0::Result>(nms)};
return std::make_shared<ov::Model>(results, params, "MulticlassNms");
} else if (ov::is_type<ov::op::v9::MulticlassNms>(node)) {
const auto nms = std::make_shared<ov::op::v9::MulticlassNms>(outputs[0], outputs[1], ov::op::v9::MulticlassNms::Attributes());
ov::ResultVector results{std::make_shared<ov::op::v0::Result>(nms)};
return std::make_shared<ov::Model>(results, params, "MulticlassNms");
} else {
return nullptr;
}
@@ -1774,8 +1783,8 @@ std::shared_ptr<ov::Model> generateGraph() {
} else if (ov::is_type<ov::op::util::ConvertColorNV12Base>(node) ||
ov::is_type<ov::op::util::ConvertColorI420Base>(node)) {
return generateConvertColor(node);
} else if (ov::is_type<ov::op::util::NmsBase>(node)) {
return generateNmsBase(node);
} else if (ov::is_type<ov::op::util::MulticlassNmsBase>(node)) {
return generateMulticlassNmsBase(node);
} else if (ov::is_type<ov::op::util::ReadValueBase>(node)) {
return generateReadValueBase(node);
} else if (ov::is_type<ov::op::util::DeformableConvolutionBase>(node)) {
@@ -15,7 +15,8 @@ namespace ov {
namespace test {
namespace subgraph {
using InputPrecisions = std::tuple<ElementType, // boxes and scores precisions
using InputPrecisions = std::tuple<ElementType, // input 'boxes' and 'scores' precisions
ElementType, // input 'roisnum' precision
ElementType, // max_output_boxes_per_class
// precision
ElementType>; // iou_threshold, score_threshold,
@@ -28,14 +29,14 @@ using InputfloatVar = std::tuple<float, // iouThreshold
using InputboolVar = std::tuple<bool, // nmsEta
bool>; // normalized
using MulticlassNmsParams = std::tuple<std::vector<InputShape>, // Params using to create 1st and 2nd inputs
using MulticlassNmsParams = std::tuple<std::vector<InputShape>, // Params using to create inputs
InputPrecisions, // Input precisions
int32_t, // Max output boxes per class
InputfloatVar, // iouThreshold, scoreThreshold, nmsEta
int32_t, // background_class
int32_t, // keep_top_k
ngraph::element::Type, // Output type
ngraph::op::util::NmsBase::SortResultType, // SortResultType
ngraph::op::util::MulticlassNmsBase::SortResultType, // SortResultType
InputboolVar, // Sort result across batch, normalized
std::string>;
@@ -51,7 +52,7 @@ protected:
private:
void GetOutputParams(size_t& numBatches, size_t& maxOutputBoxesPerBatch);
ngraph::op::v8::MulticlassNms::Attributes m_attrs;
ov::op::util::MulticlassNmsBase::Attributes m_attrs;
bool m_outStaticShape;
};
} // namespace subgraph
@@ -23,7 +23,7 @@ std::string MulticlassNmsLayerTest::getTestCaseName(const testing::TestParamInfo
int32_t nmsTopK, backgroundClass, keepTopK;
element::Type outType;
op::util::NmsBase::SortResultType sortResultType;
op::util::MulticlassNmsBase::SortResultType sortResultType;
InputfloatVar inFloatVar;
InputboolVar inboolVar;
@@ -32,8 +32,8 @@ std::string MulticlassNmsLayerTest::getTestCaseName(const testing::TestParamInfo
std::tie(shapes, inPrecisions, nmsTopK, inFloatVar, backgroundClass, keepTopK, outType, sortResultType, inboolVar, targetDevice) = obj.param;
ElementType paramsPrec, maxBoxPrec, thrPrec;
std::tie(paramsPrec, maxBoxPrec, thrPrec) = inPrecisions;
ElementType paramsPrec, roisnumPrec, maxBoxPrec, thrPrec;
std::tie(paramsPrec, roisnumPrec, maxBoxPrec, thrPrec) = inPrecisions;
float iouThr, scoreThr, nmsEta;
std::tie(iouThr, scoreThr, nmsEta) = inFloatVar;
@@ -53,7 +53,7 @@ std::string MulticlassNmsLayerTest::getTestCaseName(const testing::TestParamInfo
}
}
result << ")_paramsPrec=" << paramsPrec << "_maxBoxPrec=" << maxBoxPrec << "_thrPrec=" << thrPrec << "_";
result << ")_paramsPrec=" << paramsPrec << "_roisnumPrec=" << roisnumPrec << "_maxBoxPrec=" << maxBoxPrec << "_thrPrec=" << thrPrec << "_";
result << "nmsTopK=" << nmsTopK << "_";
result << "iouThr=" << iouThr << "_scoreThr=" << scoreThr << "_backgroundClass=" << backgroundClass << "_";
result << "keepTopK=" << keepTopK << "_outType=" << outType << "_";
@@ -66,11 +66,12 @@ void MulticlassNmsLayerTest::generate_inputs(const std::vector<ngraph::Shape>& t
inputs.clear();
const auto& funcInputs = function->inputs();
ASSERT_TRUE(funcInputs.size() == 2 || funcInputs.size() == 3) << "Expected 3 inputs or 2 inputs.";
for (int i = 0; i < funcInputs.size(); ++i) {
const auto& funcInput = funcInputs[i];
ov::Tensor tensor;
if (i == 1) {
if (i == 1) { // scores
tensor = ov::Tensor(funcInput.get_element_type(), targetInputStaticShapes[i]);
const size_t range = 1;
@@ -85,8 +86,45 @@ void MulticlassNmsLayerTest::generate_inputs(const std::vector<ngraph::Shape>& t
auto value = static_cast<float>(distribution(random));
dataPtr[i] = value / static_cast<float>(k);
}
} else {
} else if (i == 0) { // bboxes
tensor = ov::test::utils::create_and_fill_tensor(funcInput.get_element_type(), targetInputStaticShapes[i]);
} else { // roisnum
/* sum of rois is no larger than num_bboxes. */
ASSERT_TRUE(targetInputStaticShapes[i].size() == 1) << "Expected shape size 1 for input roisnum, got: " << targetInputStaticShapes[i];
// returns num random values whose sum is max_num.
auto _generate_roisnum = [](int num, int max_num) {
std::vector<int> array;
std::vector<int> results(num);
array.push_back(0);
for (auto i = 0; i < num-1; i++) {
array.push_back(std::rand() % max_num);
}
array.push_back(max_num);
std::sort(array.begin(), array.end());
for (auto i = 0; i < num; i++) {
results[i] = array[i+1] - array[i];
}
return results;
};
auto roisnum = _generate_roisnum(targetInputStaticShapes[i][0], targetInputStaticShapes[0][1]/*num_bboxes*/);
tensor = ov::Tensor(funcInput.get_element_type(), targetInputStaticShapes[i]);
if (tensor.get_element_type() == ov::element::i32) {
auto dataPtr = tensor.data<int32_t>();
for (size_t i = 0; i < roisnum.size(); i++) {
dataPtr[i] = static_cast<int32_t>(roisnum[i]);
}
} else {
auto dataPtr = tensor.data<int64_t>();
for (size_t i = 0; i < roisnum.size(); i++) {
dataPtr[i] = static_cast<int64_t>(roisnum[i]);
}
}
}
inputs.insert({funcInput.get_node_shared_ptr(), tensor});
@@ -94,21 +132,19 @@ void MulticlassNmsLayerTest::generate_inputs(const std::vector<ngraph::Shape>& t
}
void MulticlassNmsLayerTest::GetOutputParams(size_t& numBatches, size_t& maxOutputBoxesPerBatch) {
size_t it = 0;
size_t numBoxes = 0, numClasses = 0;
const auto& funcInputs = function->inputs();
for (int i = 0; i < funcInputs.size(); ++i) {
const auto& funcInput = funcInputs[i];
const auto& dims = inputs[funcInput.get_node_shared_ptr()].get_shape();
const auto& boxes_dims = inputs[funcInputs[0].get_node_shared_ptr()].get_shape();
const auto& scores_dims = inputs[funcInputs[1].get_node_shared_ptr()].get_shape();
if (it == 1) {
numClasses = dims[1];
} else {
numBatches = dims[0];
numBoxes = dims[1];
}
it++;
}
const auto shared = (scores_dims.size() == 3);
if (!shared)
ASSERT_TRUE(funcInputs.size() > 2) << "Expected 3 inputs when input 'score' is 2D.";
const auto& roisnum_dims = funcInputs.size() >2 ? inputs[funcInputs[2].get_node_shared_ptr()].get_shape() : Shape();
const auto numBoxes = shared ? boxes_dims[1] : boxes_dims[1];
auto numClasses = shared ? scores_dims[1] : boxes_dims[0];
numBatches = shared ? scores_dims[0] : roisnum_dims[0];
ASSERT_TRUE(numBatches > 0 && numBoxes > 0 && numClasses > 0)
<< "Expected numBatches, numBoxes, numClasses > 0, got:" << numBatches << ", " << numBoxes << ", " << numClasses;
@@ -132,14 +168,18 @@ void MulticlassNmsLayerTest::GetOutputParams(size_t& numBatches, size_t& maxOutp
void MulticlassNmsLayerTest::compare(const std::vector<ov::Tensor> &expectedOutputs,
const std::vector<ov::Tensor> &actualOutputs) {
auto batchIndex = -1;
auto batchIndex = -1; // output index for output 'selected_num'
size_t numBatches(0), maxOutputBoxesPerBatch(0);
GetOutputParams(numBatches, maxOutputBoxesPerBatch);
std::vector<int32_t> numPerBatch(numBatches);
std::vector<size_t> numPerBatch(numBatches);
ASSERT_TRUE(expectedOutputs.size() == 3) << "Expect 3 outputs, got: " << expectedOutputs.size();
for (int outputIndex = static_cast<int>(expectedOutputs.size()) - 1; outputIndex >= 0; outputIndex--) {
const auto& actual = actualOutputs[outputIndex];
const auto _dims = actual.get_shape();
if (_dims.size() == 1 && _dims[0] == numBatches) {
if (_dims.size() == 1) { // 'selected_num'
ASSERT_TRUE(_dims[0] == numBatches) << "Expect output 'selected_num' has shape of " << numBatches << ", got: " << _dims[0];
batchIndex = outputIndex;
if (actual.get_element_type() == ov::element::i32) {
auto buffer = actual.data<int32_t>();
@@ -148,21 +188,28 @@ void MulticlassNmsLayerTest::compare(const std::vector<ov::Tensor> &expectedOutp
auto buffer = actual.data<int64_t>();
std::copy_n(buffer, numBatches, numPerBatch.begin());
}
break;
}
}
ASSERT_TRUE(batchIndex > -1) << "Expect to get output index for 'selected_num'";
// reserve order could make sure output 'selected_num' get checked first.
for (int outputIndex = static_cast<int>(expectedOutputs.size()) - 1; outputIndex >= 0; outputIndex--) {
const auto& expected = expectedOutputs[outputIndex];
const auto& actual = actualOutputs[outputIndex];
const auto actualBuffer = static_cast<uint8_t*>(actual.data());
const auto expectedBuffer = static_cast<uint8_t*>(expected.data());
const auto expected_shape = expected.get_shape();
const auto actual_shape = actual.get_shape();
// Compare Selected Outputs & Selected Indices
if (outputIndex != batchIndex) {
if (outputIndex == 2) {
if (expected.get_size() != actual.get_size())
throw std::runtime_error("Expected and actual size 3rd output have different "
"size");
if (m_outStaticShape) {
ASSERT_TRUE(expected_shape[0] <= actual_shape[0]) << "Expected the compatible shape, got: " << expected_shape << " and " << actual_shape;
} else {
ASSERT_TRUE(expected_shape == actual_shape) << "Expected the same shape, got: " << expected_shape << " and " << actual_shape;
}
const auto& precision = actual.get_element_type();
@@ -248,11 +295,7 @@ void MulticlassNmsLayerTest::compare(const std::vector<ov::Tensor> &expectedOutp
}
}
} else {
if (outputIndex == 2) {
if (expected.get_size() != actual.get_size())
throw std::runtime_error("Expected and actual size 3rd output have different "
"size");
}
ASSERT_TRUE(expected_shape == actual_shape) << "Expected the same shape, got: " << expected_shape << " and " << actual_shape;
const auto& precision = actual.get_element_type();
size_t size = expected.get_size();
@@ -300,7 +343,7 @@ void MulticlassNmsLayerTest::SetUp() {
size_t maxOutBoxesPerClass, backgroundClass, keepTopK;
element::Type outType;
op::util::NmsBase::SortResultType sortResultType;
op::util::MulticlassNmsBase::SortResultType sortResultType;
InputfloatVar inFloatVar;
InputboolVar inboolVar;
@@ -317,8 +360,8 @@ void MulticlassNmsLayerTest::SetUp() {
return shape.rank() == 0;
});
ElementType paramsPrec, maxBoxPrec, thrPrec;
std::tie(paramsPrec, maxBoxPrec, thrPrec) = inPrecisions;
ElementType paramsPrec, roisnumPrec, maxBoxPrec, thrPrec;
std::tie(paramsPrec, roisnumPrec, maxBoxPrec, thrPrec) = inPrecisions;
float iouThr, scoreThr, nmsEta;
std::tie(iouThr, scoreThr, nmsEta) = inFloatVar;
@@ -326,7 +369,12 @@ void MulticlassNmsLayerTest::SetUp() {
bool sortResCB, normalized;
std::tie(sortResCB, normalized) = inboolVar;
const auto params = ngraph::builder::makeDynamicParams(paramsPrec, inputDynamicShapes);
ParameterVector params;
if (inputDynamicShapes.size() > 2) {
params = ngraph::builder::makeDynamicParams({paramsPrec, paramsPrec, roisnumPrec}, inputDynamicShapes);
} else {
params = ngraph::builder::makeDynamicParams(paramsPrec, inputDynamicShapes);
}
const auto paramOuts =
ngraph::helpers::convert2OutputVector(ngraph::helpers::castOps2Nodes<ngraph::op::Parameter>(params));
@@ -341,11 +389,20 @@ void MulticlassNmsLayerTest::SetUp() {
m_attrs.background_class = backgroundClass;
m_attrs.normalized = normalized;
auto nms = std::make_shared<opset8::MulticlassNms>(paramOuts[0], paramOuts[1], m_attrs);
std::shared_ptr<opset9::MulticlassNms> nms;
if (paramOuts.size() > 2) {
nms = std::make_shared<opset9::MulticlassNms>(paramOuts[0], paramOuts[1], paramOuts[2], m_attrs);
} else {
nms = std::make_shared<opset9::MulticlassNms>(paramOuts[0], paramOuts[1], m_attrs);
}
if (!m_outStaticShape) {
auto result = std::make_shared<opset5::Result>(nms);
function = std::make_shared<Function>(result, params, "MulticlassNMS");
OutputVector results = {
std::make_shared<opset5::Result>(nms->output(0)),
std::make_shared<opset5::Result>(nms->output(1)),
std::make_shared<opset5::Result>(nms->output(2))
};
function = std::make_shared<Function>(results, params, "MulticlassNMS");
} else {
auto nms_0_identity = std::make_shared<opset5::Multiply>(nms->output(0), opset5::Constant::create(paramsPrec, Shape {1}, {1}));
auto nms_1_identity = std::make_shared<opset5::Multiply>(nms->output(1), opset5::Constant::create(outType, Shape {1}, {1}));
@@ -319,7 +319,9 @@ std::ostream& operator<<(std::ostream & os, SequenceTestsMode type);
std::ostream& operator<<(std::ostream & os, MemoryTransformation type);
std::ostream& operator<<(std::ostream & os, op::util::NmsBase::SortResultType type);
std::ostream& operator<<(std::ostream & os, op::util::MulticlassNmsBase::SortResultType type);
std::ostream& operator<<(std::ostream & os, op::v8::MatrixNms::SortResultType type);
std::ostream& operator<<(std::ostream & os, op::v8::MatrixNms::DecayFunction type);
@@ -906,15 +906,32 @@ std::ostream& operator<<(std::ostream & os, MemoryTransformation type) {
return os;
}
std::ostream& operator<<(std::ostream & os, ngraph::op::util::NmsBase::SortResultType type) {
std::ostream& operator<<(std::ostream & os, op::v8::MatrixNms::SortResultType type) {
switch (type) {
case op::util::NmsBase::SortResultType::CLASSID:
case op::v8::MatrixNms::SortResultType::CLASSID:
os << "CLASSID";
break;
case op::util::NmsBase::SortResultType::SCORE:
case op::v8::MatrixNms::SortResultType::SCORE:
os << "SCORE";
break;
case op::util::NmsBase::SortResultType::NONE:
case op::v8::MatrixNms::SortResultType::NONE:
os << "NONE";
break;
default:
throw std::runtime_error("NOT_SUPPORTED_TYPE");
}
return os;
}
std::ostream& operator<<(std::ostream & os, ngraph::op::util::MulticlassNmsBase::SortResultType type) {
switch (type) {
case op::util::MulticlassNmsBase::SortResultType::CLASSID:
os << "CLASSID";
break;
case op::util::MulticlassNmsBase::SortResultType::SCORE:
os << "SCORE";
break;
case op::util::MulticlassNmsBase::SortResultType::NONE:
os << "NONE";
break;
default: