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:
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__
|
||||
|
||||
|
||||
-3
@@ -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 {
|
||||
|
||||
+24
@@ -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
|
||||
|
||||
+2
@@ -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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+28
-15
@@ -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);
|
||||
}
|
||||
+38
@@ -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);
|
||||
}
|
||||
@@ -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
-3
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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>();
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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
|
||||
|
||||
+60
-6
@@ -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
|
||||
+6
-8
@@ -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});
|
||||
}
|
||||
|
||||
+84
@@ -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});
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -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;
|
||||
}
|
||||
|
||||
+4
-3
@@ -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;
|
||||
}
|
||||
|
||||
+96
-12
@@ -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);
|
||||
+2
-1
@@ -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;
|
||||
}
|
||||
|
||||
+18
-9
@@ -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)) {
|
||||
|
||||
+5
-4
@@ -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}));
|
||||
|
||||
+3
-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:
|
||||
|
||||
Reference in new issue
Block a user