[IE][VPU][GT][DTS]: Update MyriadPlugin to work with dynamic NMS-5 (#2698)

* [VPU][GT][NGraph] Get rid of DynamicNMS and transformation
* [VPU][NGraph] Update DTS for NMS
* [VPU][NGraph] Update StaticShapeNMS to be inherrited from NMS-5
* [VPU][GT] Update StaticShapeNMS stage to work with updated NGraph op
* [VPU][Tests] Update tests
* [VPU][GT] Fix StaticShapeNMS to be inherited from NonMaxSuppressionIE3
* [VPU][GT] Remove unused NonMaxSuppression
This commit is contained in:
Andrew Bakalin 2020-10-23 17:04:36 +03:00 committed by GitHub
parent c4e0b74fb1
commit cab7a77cba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 253 additions and 1098 deletions

View File

@ -1,61 +0,0 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include "ngraph/op/non_max_suppression.hpp"
namespace ngraph { namespace vpu { namespace op {
class DynamicNonMaxSuppression : public ngraph::op::v4::NonMaxSuppression {
public:
static constexpr NodeTypeInfo type_info{"DynamicNonMaxSuppression", 0};
const NodeTypeInfo& get_type_info() const override { return type_info; }
DynamicNonMaxSuppression() = default;
/// \brief Constructs a DynamicNonMaxSuppression operation.
///
/// \param boxes Node producing the box coordinates
/// \param scores Node producing the box scores
/// \param max_output_boxes_per_class Node producing maximum number of boxes to be
/// selected per class
/// \param iou_threshold Node producing intersection over union threshold
/// \param score_threshold Node producing minimum score threshold
/// \param box_encoding Specifies the format of boxes data encoding
/// \param sort_result_descending Specifies whether it is necessary to sort selected
/// boxes across batches
/// \param output_type Specifies the output tensor type
DynamicNonMaxSuppression(const Output<Node>& boxes,
const Output<Node>& scores,
const Output<Node>& max_output_boxes_per_class,
const Output<Node>& iou_threshold,
const Output<Node>& score_threshold,
const BoxEncodingType box_encoding = BoxEncodingType::CORNER,
const bool sort_result_descending = true,
const ngraph::element::Type& output_type = ngraph::element::i64);
/// \brief Constructs a DynamicNonMaxSuppression operation with default values for the last
/// 3 inputs
///
/// \param boxes Node producing the box coordinates
/// \param scores Node producing the box coordinates
/// \param box_encoding Specifies the format of boxes data encoding
/// \param sort_result_descending Specifies whether it is necessary to sort selected
/// boxes across batches
/// \param output_type Specifies the output tensor type
DynamicNonMaxSuppression(const Output<Node>& boxes,
const Output<Node>& scores,
const BoxEncodingType box_encoding = BoxEncodingType::CORNER,
const bool sort_result_descending = true,
const ngraph::element::Type& output_type = ngraph::element::i64);
void validate_and_infer_types() override;
std::shared_ptr<Node>
clone_with_new_inputs(const OutputVector& new_args) const override;
};
} // namespace op
} // namespace vpu
} // namespace ngraph

View File

@ -5,33 +5,27 @@
#pragma once #pragma once
#include <ngraph/node.hpp> #include <ngraph/node.hpp>
#include <ngraph/op/op.hpp> #include <legacy/ngraph_ops/nms_ie.hpp>
#include <memory> #include <memory>
#include <vector> #include <vector>
namespace ngraph { namespace vpu { namespace op { namespace ngraph { namespace vpu { namespace op {
class StaticShapeNonMaxSuppression : public ngraph::op::v4::NonMaxSuppression { class StaticShapeNonMaxSuppression : public ngraph::op::NonMaxSuppressionIE3 {
public: public:
static constexpr NodeTypeInfo type_info{"StaticShapeNonMaxSuppression", 0}; static constexpr NodeTypeInfo type_info{"StaticShapeNonMaxSuppression", 0};
const NodeTypeInfo& get_type_info() const override { return type_info; } const NodeTypeInfo& get_type_info() const override { return type_info; }
StaticShapeNonMaxSuppression() = default;
StaticShapeNonMaxSuppression(const Output<Node>& boxes, StaticShapeNonMaxSuppression(const Output<Node>& boxes,
const Output<Node>& scores, const Output<Node>& scores,
const Output<Node>& max_output_boxes_per_class, const Output<Node>& maxOutputBoxesPerClass,
const Output<Node>& iou_threshold, const Output<Node>& iouThreshold,
const Output<Node>& score_threshold, const Output<Node>& scoreThreshold,
const BoxEncodingType box_encoding = BoxEncodingType::CORNER, const Output<Node>& softNmsSigma,
const bool sort_result_descending = true, int centerPointBox = 0,
const ngraph::element::Type& output_type = ngraph::element::i64); bool sortResultDescending = true,
const ngraph::element::Type& outputType = ngraph::element::i64);
StaticShapeNonMaxSuppression(const Output<Node>& boxes,
const Output<Node>& scores,
const BoxEncodingType box_encoding = BoxEncodingType::CORNER,
const bool sort_result_descending = true,
const ngraph::element::Type& output_type = ngraph::element::i64);
void validate_and_infer_types() override; void validate_and_infer_types() override;
std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override; std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override;

View File

@ -1,21 +0,0 @@
// Copyright (C) 2018-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <ngraph/pass/graph_rewrite.hpp>
namespace vpu {
class UpgradeNMS4ToNMSDynamic : public ngraph::pass::GraphRewrite {
public:
UpgradeNMS4ToNMSDynamic() : GraphRewrite() {
upgrade_nms4_to_nms_dynamic();
}
private:
void upgrade_nms4_to_nms_dynamic();
};
} // namespace vpu

View File

@ -1,89 +0,0 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "vpu/ngraph/operations/dynamic_non_max_suppression.hpp"
#include "vpu/utils/error.hpp"
#include "ngraph/opsets/opset3.hpp"
#include "ngraph/evaluator.hpp"
namespace ngraph { namespace vpu { namespace op {
constexpr NodeTypeInfo DynamicNonMaxSuppression::type_info;
DynamicNonMaxSuppression::DynamicNonMaxSuppression(
const Output<Node>& boxes,
const Output<Node>& scores,
const Output<Node>& max_output_boxes_per_class,
const Output<Node>& iou_threshold,
const Output<Node>& score_threshold,
const BoxEncodingType box_encoding,
const bool sort_result_descending,
const element::Type& output_type)
: ngraph::op::v4::NonMaxSuppression(boxes,
scores,
max_output_boxes_per_class,
iou_threshold,
score_threshold,
box_encoding,
sort_result_descending,
output_type) {
constructor_validate_and_infer_types();
}
DynamicNonMaxSuppression::DynamicNonMaxSuppression(
const Output<Node>& boxes,
const Output<Node>& scores,
const BoxEncodingType box_encoding,
const bool sort_result_descending,
const element::Type& output_type)
: ngraph::op::v4::NonMaxSuppression(boxes,
scores,
ngraph::op::Constant::create(element::i64, Shape{}, {0}),
ngraph::op::Constant::create(element::f32, Shape{}, {.0f}),
ngraph::op::Constant::create(element::f32, Shape{}, {.0f}),
box_encoding,
sort_result_descending,
output_type) {
constructor_validate_and_infer_types();
}
std::shared_ptr<Node> DynamicNonMaxSuppression::clone_with_new_inputs(const OutputVector& new_args) const {
check_new_args_count(this, new_args);
NODE_VALIDATION_CHECK(this,
new_args.size() >= 2 && new_args.size() <= 5,
"Number of inputs must be 2, 3, 4 or 5");
const auto& arg2 = new_args.size() > 2
? new_args.at(2)
: ngraph::op::Constant::create(element::i32, Shape{}, {0});
const auto& arg3 = new_args.size() > 3
? new_args.at(3)
: ngraph::op::Constant::create(element::f32, Shape{}, {.0f});
const auto& arg4 = new_args.size() > 4
? new_args.at(4)
: ngraph::op::Constant::create(element::f32, Shape{}, {.0f});
return std::make_shared<DynamicNonMaxSuppression>(new_args.at(0),
new_args.at(1),
arg2,
arg3,
arg4,
m_box_encoding,
m_sort_result_descending,
m_output_type);
}
void DynamicNonMaxSuppression::validate_and_infer_types() {
ngraph::op::v4::NonMaxSuppression::validate_and_infer_types();
// NonMaxSuppression produces triplets
// that have the following format: [batch_index, class_index, box_index]
set_output_type(0, m_output_type, PartialShape{Dimension::dynamic(), 3});
}
} // namespace op
} // namespace vpu
} // namespace ngraph

View File

@ -3,6 +3,7 @@
// //
#include <ngraph/opsets/opset3.hpp> #include <ngraph/opsets/opset3.hpp>
#include <ngraph/opsets/opset5.hpp>
#include "vpu/ngraph/operations/static_shape_non_maximum_suppression.hpp" #include "vpu/ngraph/operations/static_shape_non_maximum_suppression.hpp"
#include "ngraph/runtime/host_tensor.hpp" #include "ngraph/runtime/host_tensor.hpp"
@ -14,65 +15,40 @@ constexpr NodeTypeInfo StaticShapeNonMaxSuppression::type_info;
StaticShapeNonMaxSuppression::StaticShapeNonMaxSuppression( StaticShapeNonMaxSuppression::StaticShapeNonMaxSuppression(
const Output<Node>& boxes, const Output<Node>& boxes,
const Output<Node>& scores, const Output<Node>& scores,
const Output<Node>& max_output_boxes_per_class, const Output<Node>& maxOutputBoxesPerClass,
const Output<Node>& iou_threshold, const Output<Node>& iouThreshold,
const Output<Node>& score_threshold, const Output<Node>& scoreThreshold,
const StaticShapeNonMaxSuppression::BoxEncodingType box_encoding, const Output<Node>& softNmsSigma,
const bool sort_result_descending, int centerPointBox,
const element::Type& output_type) const bool sortResultDescending,
: ngraph::op::v4::NonMaxSuppression( const element::Type& outputType)
boxes, scores, max_output_boxes_per_class, iou_threshold, score_threshold, : ngraph::op::NonMaxSuppressionIE3(
box_encoding, sort_result_descending, output_type) { boxes, scores, maxOutputBoxesPerClass, iouThreshold, scoreThreshold,
constructor_validate_and_infer_types(); softNmsSigma, centerPointBox, sortResultDescending, outputType) {
}
StaticShapeNonMaxSuppression::StaticShapeNonMaxSuppression(
const Output<Node>& boxes,
const Output<Node>& scores,
const StaticShapeNonMaxSuppression::BoxEncodingType box_encoding,
const bool sort_result_descending,
const element::Type& output_type)
: ngraph::op::v4::NonMaxSuppression(boxes,
scores,
ngraph::opset3::Constant::create(element::i64, Shape{}, {0}),
ngraph::opset3::Constant::create(element::f32, Shape{}, {.0f}),
ngraph::opset3::Constant::create(element::f32, Shape{}, {.0f}),
box_encoding, sort_result_descending, output_type) {
constructor_validate_and_infer_types(); constructor_validate_and_infer_types();
} }
std::shared_ptr<Node> std::shared_ptr<Node>
StaticShapeNonMaxSuppression::clone_with_new_inputs(const OutputVector& new_args) const { StaticShapeNonMaxSuppression::clone_with_new_inputs(const OutputVector& new_args) const {
check_new_args_count(this, new_args); check_new_args_count(this, new_args);
NODE_VALIDATION_CHECK(this, return std::make_shared<StaticShapeNonMaxSuppression>(new_args.at(0), new_args.at(1), new_args.at(2), new_args.at(3),
new_args.size() >= 2 && new_args.size() <= 5, new_args.at(4), new_args.at(5), m_center_point_box, m_sort_result_descending,
"Number of inputs must be 2, 3, 4 or 5");
const auto& arg2 = new_args.size() > 2 ? new_args.at(2) : ngraph::opset3::Constant::create(element::i32, Shape{}, {0});
const auto& arg3 = new_args.size() > 3 ? new_args.at(3) : ngraph::opset3::Constant::create(element::f32, Shape{}, {.0f});
const auto& arg4 = new_args.size() > 4 ? new_args.at(4) : ngraph::opset3::Constant::create(element::f32, Shape{}, {.0f});
return std::make_shared<StaticShapeNonMaxSuppression>(
new_args.at(0),
new_args.at(1),
arg2,
arg3,
arg4,
m_box_encoding,
m_sort_result_descending,
m_output_type); m_output_type);
} }
void StaticShapeNonMaxSuppression::validate_and_infer_types() { void StaticShapeNonMaxSuppression::validate_and_infer_types() {
ngraph::op::v4::NonMaxSuppression::validate_and_infer_types(); ngraph::op::NonMaxSuppressionIE3::validate_and_infer_types();
const auto out_shape = this->get_output_partial_shape(0); auto outIndicesShape = get_output_partial_shape(0);
NODE_VALIDATION_CHECK(this, out_shape.is_static(), auto outScoresShape = get_output_partial_shape(1);
"StaticShapeNonMaxSuppression output shape is not fully defined: ", out_shape);
set_output_size(2); NODE_VALIDATION_CHECK(this, outIndicesShape.is_static(),
set_output_type(0, m_output_type, out_shape); "StaticShapeNonMaxSuppression output shape is not fully defined: ", outIndicesShape);
set_output_type(1, m_output_type, Shape{2}); NODE_VALIDATION_CHECK(this, outScoresShape.is_static(),
"StaticShapeNonMaxSuppression output shape is not fully defined: ", outScoresShape);
// Replace valid outputs with the shape of selected_indices and selected_scores outputs
set_output_type(2, m_output_type, Shape{2});
} }
} // namespace op } // namespace op

View File

@ -1,55 +0,0 @@
// Copyright (C) 2018-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "vpu/ngraph/transformations/convert_nms_4_to_nms_dynamic.hpp"
#include <vpu/ngraph/operations/dynamic_non_max_suppression.hpp>
#include <ngraph/graph_util.hpp>
#include <ngraph/opsets/opset4.hpp>
#include <ngraph/rt_info.hpp>
#include <transformations/utils/utils.hpp>
#include <memory>
#include <vector>
void vpu::UpgradeNMS4ToNMSDynamic::upgrade_nms4_to_nms_dynamic() {
auto boxes = std::make_shared<ngraph::pattern::op::Label>(ngraph::element::f32, ngraph::Shape{1, 1000, 4});
auto scores = std::make_shared<ngraph::pattern::op::Label>(ngraph::element::f32, ngraph::Shape{1, 1, 1000});
auto max_output_boxes_per_class = ngraph::opset4::Constant::create(ngraph::element::i64, ngraph::Shape{}, {10});
auto iou_threshold = ngraph::opset4::Constant::create(ngraph::element::f32, ngraph::Shape{}, {0.75});
auto score_threshold = ngraph::opset4::Constant::create(ngraph::element::f32, ngraph::Shape{}, {0.7});
auto nms = std::make_shared<ngraph::opset4::NonMaxSuppression>(boxes, scores, max_output_boxes_per_class,
iou_threshold, score_threshold);
ngraph::graph_rewrite_callback callback = [](ngraph::pattern::Matcher &m) {
auto nms_4 = std::dynamic_pointer_cast<ngraph::opset4::NonMaxSuppression>(m.get_match_root());
if (!nms_4) {
return false;
}
const auto box_encoding = nms_4->get_box_encoding();
const auto new_args = nms_4->input_values();
const auto& arg2 = new_args.size() > 2 ? new_args.at(2) : ngraph::opset4::Constant::create(ngraph::element::i32, ngraph::Shape{}, {0});
const auto& arg3 = new_args.size() > 3 ? new_args.at(3) : ngraph::opset4::Constant::create(ngraph::element::f32, ngraph::Shape{}, {.0f});
const auto& arg4 = new_args.size() > 4 ? new_args.at(4) : ngraph::opset4::Constant::create(ngraph::element::f32, ngraph::Shape{}, {.0f});
const auto nms_dynamic = std::make_shared<ngraph::vpu::op::DynamicNonMaxSuppression>(
new_args.at(0),
new_args.at(1),
arg2,
arg3,
arg4,
box_encoding,
nms_4->get_sort_result_descending(),
nms_4->get_output_type());
nms_dynamic->set_friendly_name(nms_4->get_friendly_name());
ngraph::copy_runtime_info(nms_4, nms_dynamic);
ngraph::replace_node(nms_4, nms_dynamic);
return true;
};
auto m = std::make_shared<ngraph::pattern::Matcher>(nms, "UpgradeNMS4ToDynamic");
this->add_matcher(m, callback, ngraph::pass::PassProperty::CHANGE_DYNAMIC_STATE);
}

View File

@ -28,7 +28,6 @@
#include "ngraph/opsets/opset3.hpp" #include "ngraph/opsets/opset3.hpp"
#include "ngraph/opsets/opset5.hpp" #include "ngraph/opsets/opset5.hpp"
#include "vpu/ngraph/operations/dynamic_non_max_suppression.hpp"
namespace vpu { namespace vpu {
@ -82,7 +81,7 @@ const Transformations& getDefaultTransformations() {
{ngraph::opset3::Maximum::type_info, dynamicToStaticShapeBinaryEltwise}, {ngraph::opset3::Maximum::type_info, dynamicToStaticShapeBinaryEltwise},
{ngraph::opset3::Minimum::type_info, dynamicToStaticShapeBinaryEltwise}, {ngraph::opset3::Minimum::type_info, dynamicToStaticShapeBinaryEltwise},
{ngraph::opset3::Less::type_info, dynamicToStaticShapeBinaryEltwise}, {ngraph::opset3::Less::type_info, dynamicToStaticShapeBinaryEltwise},
{ngraph::vpu::op::DynamicNonMaxSuppression::type_info, dynamicToStaticNonMaxSuppression}, {ngraph::opset5::NonMaxSuppression::type_info, dynamicToStaticNonMaxSuppression},
{ngraph::opset3::NonZero::type_info, dynamicToStaticShapeNonZero}, {ngraph::opset3::NonZero::type_info, dynamicToStaticShapeNonZero},
{ngraph::opset3::TopK::type_info, dynamicToStaticShapeTopK}, {ngraph::opset3::TopK::type_info, dynamicToStaticShapeTopK},
{ngraph::opset3::Transpose::type_info, dynamicToStaticShapeTranspose}, {ngraph::opset3::Transpose::type_info, dynamicToStaticShapeTranspose},

View File

@ -4,39 +4,50 @@
#include "vpu/ngraph/transformations/dynamic_to_static_shape_non_max_suppression.hpp" #include "vpu/ngraph/transformations/dynamic_to_static_shape_non_max_suppression.hpp"
#include <vpu/ngraph/operations/static_shape_non_maximum_suppression.hpp>
#include "vpu/ngraph/operations/dynamic_shape_resolver.hpp" #include "vpu/ngraph/operations/dynamic_shape_resolver.hpp"
#include "vpu/ngraph/operations/dynamic_non_max_suppression.hpp"
#include "vpu/ngraph/utilities.hpp" #include "vpu/ngraph/utilities.hpp"
#include <vpu/utils/error.hpp>
#include <vpu/utils/error.hpp>
#include "ngraph/graph_util.hpp" #include "ngraph/graph_util.hpp"
#include "ngraph/opsets/opset3.hpp" #include "ngraph/opsets/opset5.hpp"
#include <memory> #include <memory>
#include <vpu/ngraph/operations/static_shape_non_maximum_suppression.hpp>
namespace vpu { namespace vpu {
void dynamicToStaticNonMaxSuppression(std::shared_ptr<ngraph::Node> node) { void dynamicToStaticNonMaxSuppression(std::shared_ptr<ngraph::Node> node) {
auto nms_dynamic = std::dynamic_pointer_cast<ngraph::vpu::op::DynamicNonMaxSuppression>(node); auto nms = std::dynamic_pointer_cast<ngraph::opset5::NonMaxSuppression>(node);
VPU_THROW_UNLESS(nms_dynamic, "dynamicToStaticNonMaxSuppression transformation for {} of type {} expects {} as node for replacement", VPU_THROW_UNLESS(nms, "dynamicToStaticNonMaxSuppression transformation for {} of type {} expects {} as node for replacement",
node->get_friendly_name(), node->get_type_info(), ngraph::vpu::op::DynamicNonMaxSuppression::type_info); node->get_friendly_name(), node->get_type_info(), ngraph::opset5::NonMaxSuppression::type_info);
auto staticShapeNMS = std::make_shared<ngraph::vpu::op::StaticShapeNonMaxSuppression>( auto staticShapeNMS = std::make_shared<ngraph::vpu::op::StaticShapeNonMaxSuppression>(
nms_dynamic->input_value(0), nms->input_value(0),
nms_dynamic->input_value(1), nms->input_value(1),
nms_dynamic->input_value(2), nms->input_value(2),
nms_dynamic->input_value(3), nms->input_value(3),
nms_dynamic->input_value(4), nms->input_value(4),
nms_dynamic->get_box_encoding(), nms->input_value(5),
nms_dynamic->get_sort_result_descending(), nms->get_box_encoding() == ngraph::opset5::NonMaxSuppression::BoxEncodingType::CENTER ? 1 : 0,
nms_dynamic->get_output_type()); nms->get_sort_result_descending(),
nms->get_output_type());
auto dynamicShapeResolver = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>( auto dsrIndices = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(
staticShapeNMS->output(0), staticShapeNMS->output(1)); staticShapeNMS->output(0), staticShapeNMS->output(2));
dynamicShapeResolver->set_friendly_name(nms_dynamic->get_friendly_name()); auto dsrScores = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(
staticShapeNMS->output(1), staticShapeNMS->output(2));
dsrIndices->set_friendly_name(nms->output(0).get_node_shared_ptr()->get_friendly_name());
dsrScores->set_friendly_name(nms->output(1).get_node_shared_ptr()->get_friendly_name());
ngraph::replace_node(std::move(nms_dynamic), std::move(dynamicShapeResolver)); const auto gatherValidOutputs = std::make_shared<ngraph::opset5::Gather>(
staticShapeNMS->output(2),
ngraph::opset5::Constant::create(staticShapeNMS->output(2).get_element_type(), ngraph::Shape{1}, {0}),
ngraph::opset5::Constant::create(staticShapeNMS->output(2).get_element_type(), ngraph::Shape{1}, {0}));
gatherValidOutputs->set_friendly_name(nms->output(2).get_node_shared_ptr()->get_friendly_name());
nms->output(0).replace(dsrIndices);
nms->output(1).replace(dsrScores);
nms->output(2).replace(gatherValidOutputs);
} }
} // namespace vpu } // namespace vpu

View File

@ -136,7 +136,6 @@ public:
void parseTopK(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const; void parseTopK(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const;
void parseSelect(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const; void parseSelect(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const;
void parseExpDetectionOutput(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const; void parseExpDetectionOutput(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const;
void parseNonMaxSuppression(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const;
void parseROIFeatureExtractor(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const; void parseROIFeatureExtractor(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const;
void parseConvert(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const; void parseConvert(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const;
void parseErf(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const; void parseErf(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const;

View File

@ -144,7 +144,6 @@ VPU_DECLARE_ENUM(StageType,
ScatterUpdate = 103, ScatterUpdate = 103,
ReduceMin = 105, ReduceMin = 105,
ExpDetectionOutput = 106, // ExperimentalDetectronDetectionOutput ExpDetectionOutput = 106, // ExperimentalDetectronDetectionOutput
NonMaxSuppression = 107,
ROIFeatureExtractor = 108, ROIFeatureExtractor = 108,
SCRelu = 109, SCRelu = 109,
Erf = 110, Erf = 110,

View File

@ -1,34 +0,0 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <vpu/model/stage.hpp>
namespace vpu {
class NonMaxSuppression : public StageNode {
protected:
StagePtr cloneImpl() const override;
void propagateDataOrderImpl(StageDataInfo<DimsOrder>& orderInfo) override;
void getDataStridesRequirementsImpl(StageDataInfo<StridesRequirement>& stridesInfo) override;
void finalizeDataLayoutImpl() override;
void getBatchSupportInfoImpl(StageDataInfo<BatchSupport>& batchInfo) override;
StageSHAVEsRequirements getSHAVEsRequirementsImpl() const override;
void initialCheckImpl() const override;
void finalCheckImpl() const override;
void serializeParamsImpl(BlobSerializer& serializer) const override;
void serializeDataImpl(BlobSerializer& serializer) const override;
};
} // namespace vpu

View File

@ -32,7 +32,6 @@
#include <transformations/common_optimizations/common_optimizations.hpp> #include <transformations/common_optimizations/common_optimizations.hpp>
#include <transformations/init_node_info.hpp> #include <transformations/init_node_info.hpp>
#include <vpu/ngraph/transformations/merge_subsequent_dsr_operations.hpp> #include <vpu/ngraph/transformations/merge_subsequent_dsr_operations.hpp>
#include <vpu/ngraph/transformations/convert_nms_4_to_nms_dynamic.hpp>
#include "vpu/ngraph/transformations/dynamic_to_static_shape.hpp" #include "vpu/ngraph/transformations/dynamic_to_static_shape.hpp"
#include "vpu/ngraph/transformations/eliminate_shapeof_after_dsr.hpp" #include "vpu/ngraph/transformations/eliminate_shapeof_after_dsr.hpp"
#include <vpu/ngraph/operations/dynamic_shape_resolver.hpp> #include <vpu/ngraph/operations/dynamic_shape_resolver.hpp>
@ -105,7 +104,6 @@ FrontEnd::FrontEnd(StageBuilder::Ptr stageBuilder, const ie::ICore* core)
{"Select", LAYER_PARSER(parseSelect)}, {"Select", LAYER_PARSER(parseSelect)},
{"Erf", LAYER_PARSER(parseErf)}, {"Erf", LAYER_PARSER(parseErf)},
{"ExperimentalDetectronDetectionOutput", LAYER_PARSER(parseExpDetectionOutput)}, {"ExperimentalDetectronDetectionOutput", LAYER_PARSER(parseExpDetectionOutput)},
{"NonMaxSuppression", LAYER_PARSER(parseNonMaxSuppression)},
{"ExperimentalDetectronROIFeatureExtractor", LAYER_PARSER(parseROIFeatureExtractor)}, {"ExperimentalDetectronROIFeatureExtractor", LAYER_PARSER(parseROIFeatureExtractor)},
{"Convert", LAYER_PARSER(parseConvert)}, {"Convert", LAYER_PARSER(parseConvert)},
{"ReduceMax", LAYER_PARSER(parseReduce)}, {"ReduceMax", LAYER_PARSER(parseReduce)},
@ -173,7 +171,6 @@ ie::ICNNNetwork::Ptr FrontEnd::convertNetwork(ie::ICNNNetwork& network) {
manager.register_pass<::ngraph::pass::InitNodeInfo>(); manager.register_pass<::ngraph::pass::InitNodeInfo>();
// WA: ConvertPriorBox must be executed before the 1st ConstantFolding pass // WA: ConvertPriorBox must be executed before the 1st ConstantFolding pass
manager.register_pass<::ngraph::pass::ConvertPriorBox>(); manager.register_pass<::ngraph::pass::ConvertPriorBox>();
manager.register_pass<vpu::UpgradeNMS4ToNMSDynamic>();
manager.register_pass<ngraph::pass::CommonOptimizations>(); manager.register_pass<ngraph::pass::CommonOptimizations>();
manager.register_pass<vpu::DynamicToStaticShape>(); manager.register_pass<vpu::DynamicToStaticShape>();
manager.register_pass<vpu::EliminateShapeOfAfterDSR>(); manager.register_pass<vpu::EliminateShapeOfAfterDSR>();

View File

@ -1,97 +0,0 @@
// Copyright (C) 2018-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <vpu/stages/nms.hpp>
#include <vpu/frontend/frontend.hpp>
#include <memory>
#include <set>
namespace vpu {
StagePtr NonMaxSuppression::cloneImpl() const {
return std::make_shared<NonMaxSuppression>(*this);
}
void NonMaxSuppression::propagateDataOrderImpl(StageDataInfo<DimsOrder>& orderInfo) {
}
void NonMaxSuppression::getDataStridesRequirementsImpl(StageDataInfo<StridesRequirement>& stridesInfo) {
}
void NonMaxSuppression::finalizeDataLayoutImpl() {
}
void NonMaxSuppression::getBatchSupportInfoImpl(StageDataInfo<BatchSupport>& batchInfo) {
}
StageSHAVEsRequirements NonMaxSuppression::getSHAVEsRequirementsImpl() const {
// Current NMS implementation doesn't allow calculation of `> boxesThreshold` boxes using one SHAVE
constexpr int boxesThreshold = 3650;
const auto& inDesc = input(0)->desc();
const auto& maxBoxesNum = inDesc.dim(Dim::H);
if (maxBoxesNum > boxesThreshold) {
return StageSHAVEsRequirements::NeedMax;
} else {
return StageSHAVEsRequirements::OnlyOne;
}
}
void NonMaxSuppression::initialCheckImpl() const {
assertInputsOutputsTypes(this,
{{DataType::FP16},
{DataType::FP16},
{DataType::S32},
{DataType::FP16},
{DataType::FP16}},
{{DataType::S32}});
}
void NonMaxSuppression::finalCheckImpl() const {
}
void NonMaxSuppression::serializeParamsImpl(BlobSerializer& serializer) const {
bool center_point_box = attrs().get<bool>("center_point_box");
serializer.append(static_cast<int32_t>(center_point_box));
}
void NonMaxSuppression::serializeDataImpl(BlobSerializer& serializer) const {
IE_ASSERT(inputEdges().size() >= 2 && inputEdges().size() <= 5);
IE_ASSERT(outputEdges().size() == 1);
auto input1 = inputEdges()[0]->input();
auto input2 = inputEdges()[1]->input();
auto input3 = inputEdges()[2]->input();
auto input4 = inputEdges()[3]->input();
auto input5 = inputEdges()[4]->input();
auto output = outputEdges()[0]->output();
input1->serializeBuffer(serializer);
input2->serializeBuffer(serializer);
output->serializeBuffer(serializer);
input3->serializeBuffer(serializer);
input4->serializeBuffer(serializer);
input5->serializeBuffer(serializer);
}
void FrontEnd::parseNonMaxSuppression(const Model& model, const ie::CNNLayerPtr& _layer, const DataVector& inputs, const DataVector& outputs) const {
auto layer = std::dynamic_pointer_cast<ie::NonMaxSuppressionLayer>(_layer);
IE_ASSERT(layer != nullptr);
IE_ASSERT(inputs.size() >= 2 && inputs.size() <= 5);
IE_ASSERT(outputs.size() == 1);
DataVector tempInputs = inputs;
for (size_t fake = inputs.size(); fake < 5; fake++) {
tempInputs.push_back(model->addFakeData());
}
auto stage = model->addNewStage<NonMaxSuppression>(layer->name, StageType::NonMaxSuppression, layer, tempInputs, outputs);
stage->attrs().set<bool>("center_point_box", layer->center_point_box);
}
} // namespace vpu

View File

@ -2,10 +2,9 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
#include <vpu/stages/nms.hpp>
#include <vpu/frontend/frontend.hpp> #include <vpu/frontend/frontend.hpp>
#include <ngraph/op/non_max_suppression.hpp> #include <precision_utils.h>
#include <memory> #include <memory>
#include <set> #include <set>
@ -14,12 +13,34 @@ namespace vpu {
namespace { namespace {
class StaticShapeNMS final : public NonMaxSuppression { class StaticShapeNMS final : public StageNode {
private: private:
StagePtr cloneImpl() const override { StagePtr cloneImpl() const override {
return std::make_shared<StaticShapeNMS>(*this); return std::make_shared<StaticShapeNMS>(*this);
} }
void propagateDataOrderImpl(StageDataInfo<DimsOrder>& orderInfo) override {
}
void getDataStridesRequirementsImpl(StageDataInfo<StridesRequirement>& stridesInfo) override {
}
void finalizeDataLayoutImpl() override {
}
void getBatchSupportInfoImpl(StageDataInfo<BatchSupport>& batchInfo) override {
}
StageSHAVEsRequirements getSHAVEsRequirementsImpl() const override {
// Current NMS implementation doesn't allow calculation of `> boxesThreshold` boxes using one SHAVE
constexpr int boxesThreshold = 3650;
const auto& inDesc = input(0)->desc();
const auto& maxBoxesNum = inDesc.dim(Dim::H);
return maxBoxesNum <= boxesThreshold ? StageSHAVEsRequirements::OnlyOne : StageSHAVEsRequirements::NeedMax;
}
void initialCheckImpl() const override { void initialCheckImpl() const override {
assertInputsOutputsTypes(this, assertInputsOutputsTypes(this,
{{DataType::FP16}, {{DataType::FP16},
@ -31,6 +52,12 @@ private:
{DataType::S32}}); {DataType::S32}});
} }
void serializeParamsImpl(BlobSerializer& serializer) const override {
const auto center_point_box = attrs().get<bool>("center_point_box");
serializer.append(static_cast<int32_t>(center_point_box));
}
void serializeDataImpl(BlobSerializer& serializer) const override { void serializeDataImpl(BlobSerializer& serializer) const override {
auto input1 = inputEdges()[0]->input(); auto input1 = inputEdges()[0]->input();
auto input2 = inputEdges()[1]->input(); auto input2 = inputEdges()[1]->input();
@ -53,29 +80,45 @@ private:
} // namespace } // namespace
void FrontEnd::parseStaticShapeNMS(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const { void FrontEnd::parseStaticShapeNMS(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const {
VPU_THROW_UNLESS(inputs.size() >= 2 && inputs.size() <= 5, VPU_THROW_UNLESS(inputs.size() == 6,
"StaticShapeNMS parsing failed, expected number of input is in range [2, 5], but {} provided", "StaticShapeNMS with name {} parsing failed, expected number of inputs: 6, but {} provided",
inputs.size()); layer->name, inputs.size());
VPU_THROW_UNLESS(outputs.size() == 2, VPU_THROW_UNLESS(outputs.size() == 3,
"StaticShapeNMS parsing failed, expected number of outputs: 2, but {} provided", "StaticShapeNMS with name {} parsing failed, expected number of outputs: 4, but {} provided",
outputs.size()); layer->name, outputs.size());
const auto softNMSSigmaData = inputs[5];
VPU_THROW_UNLESS(softNMSSigmaData->usage() == DataUsage::Const,
"StaticShapeNMS with name {} parsing failed: softNMSSigma should have usage {} while it actually has {}",
layer->type, DataUsage::Const, softNMSSigmaData->usage());
VPU_THROW_UNLESS(softNMSSigmaData->desc().totalDimSize() == 1,
"StaticShapeNMS with name {} parsing failed: softNMSSigma input should contain 1 value, while it has {} values",
layer->type, softNMSSigmaData->desc().totalDimSize());
const auto softNMSSigma = InferenceEngine::PrecisionUtils::f16tof32(softNMSSigmaData->content()->get<InferenceEngine::ie_fp16>()[0]);
VPU_THROW_UNLESS(softNMSSigma == 0,
"StaticShapeNMS with name {} parsing failed: the only supported value for softNMSSigma is 0, while it actually equal to {}",
layer->name, softNMSSigma);
auto usedInputs = inputs;
// Erase unused softNMSSigma input
usedInputs.pop_back();
const auto& outIndices = outputs[0];
const auto& outScores = outputs[1];
const auto& outShape = outputs[2];
VPU_THROW_UNLESS(outScores == nullptr,
"StaticShapeNMS with name {} parsing failed: selected_scores output is not supported {}",
layer->name);
const auto sortResultDescending = layer->GetParamAsBool("sort_result_descending"); const auto sortResultDescending = layer->GetParamAsBool("sort_result_descending");
const auto boxEncoding = layer->GetParamAsString("box_encoding"); const auto centerPointBox = layer->GetParamAsBool("center_point_box");
VPU_THROW_UNLESS(sortResultDescending == false, VPU_THROW_UNLESS(sortResultDescending == false,
"StaticShapeNMS: parameter sortResultDescending=true is not supported on VPU"); "StaticShapeNMS with name {}: parameter sortResultDescending=true is not supported on VPU", layer->name);
VPU_THROW_UNLESS(boxEncoding == "corner" || boxEncoding == "center",
"StaticShapeNMS: boxEncoding currently supports only two values: \"corner\" and \"center\" "
"while {} was provided", boxEncoding);
DataVector tempInputs = inputs; auto stage = model->addNewStage<StaticShapeNMS>(layer->name, StageType::StaticShapeNMS, layer, usedInputs, DataVector{outIndices, outShape});
for (auto fake = inputs.size(); fake < 5; fake++) { stage->attrs().set<bool>("center_point_box", centerPointBox);
tempInputs.push_back(model->addFakeData());
}
auto stage = model->addNewStage<StaticShapeNMS>(layer->name, StageType::StaticShapeNMS, layer, tempInputs, outputs);
stage->attrs().set<bool>("center_point_box", boxEncoding == "center");
} }
} // namespace vpu } // namespace vpu

View File

@ -5,13 +5,16 @@
#include <common_test_utils/test_common.hpp> #include <common_test_utils/test_common.hpp>
#include <ngraph_functions/utils/ngraph_helpers.hpp> #include <ngraph_functions/utils/ngraph_helpers.hpp>
#include <ngraph/opsets/opset3.hpp> #include <ngraph/opsets/opset3.hpp>
#include <ngraph/opsets/opset5.hpp>
#include <ngraph/op/non_max_suppression.hpp>
#include <ngraph/output_vector.hpp>
#include <vpu/ngraph/operations/dynamic_shape_resolver.hpp> #include <vpu/ngraph/operations/dynamic_shape_resolver.hpp>
#include <vpu/ngraph/operations/dynamic_non_max_suppression.hpp>
#include <vpu/ngraph/transformations/dynamic_to_static_shape.hpp> #include <vpu/ngraph/transformations/dynamic_to_static_shape.hpp>
#include <vpu/ngraph/transformations/dynamic_to_static_shape_non_max_suppression.hpp> #include <vpu/ngraph/transformations/dynamic_to_static_shape_non_max_suppression.hpp>
#include <vpu/ngraph/operations/static_shape_non_maximum_suppression.hpp> #include <vpu/ngraph/operations/static_shape_non_maximum_suppression.hpp>
#include <vpu/utils/error.hpp> #include <vpu/utils/error.hpp>
#include <numeric> #include <numeric>
#include <queue> #include <queue>
#include <random> #include <random>
@ -22,50 +25,48 @@ using DataType = ngraph::element::Type_t;
using DataDims = ngraph::Shape; using DataDims = ngraph::Shape;
struct NonMaxSuppressionTestCase { struct NonMaxSuppressionTestCase {
int64_t num_batches, num_boxes, num_classes, max_output_boxes_per_class; int64_t numBatches, numBoxes, numClasses, maxOutputBoxesPerClass;
float iou_threshold, score_threshold; float iouThreshold, scoreThreshold, softNMSSigma;
}; };
class DynamicToStaticShapeNonMaxSuppression : public CommonTestUtils::TestsCommon, class DynamicToStaticShapeNonMaxSuppression : public CommonTestUtils::TestsCommon,
public testing::WithParamInterface<std::tuple<DataType, DataType, NonMaxSuppressionTestCase>> { public testing::WithParamInterface<std::tuple<DataType, DataType, NonMaxSuppressionTestCase>> {
public: public:
void SetUp() override { void SetUp() override {
const auto& parameters = GetParam(); const auto& parameters = GetParam();
const auto& float_type = std::get<0>(parameters); const auto& floatType = std::get<0>(parameters);
const auto& integer_type = std::get<1>(parameters); const auto& integerType = std::get<1>(parameters);
const auto& nms_setup = std::get<2>(parameters); const auto& nmsSetup = std::get<2>(parameters);
ngraph::helpers::CompareFunctions(*transform(float_type, integer_type, nms_setup), ngraph::helpers::CompareFunctions(*transform(floatType, integerType, nmsSetup),
*reference(float_type, integer_type, nms_setup)); *reference(floatType, integerType, nmsSetup));
} }
protected: protected:
std::shared_ptr<const ngraph::Function> transform( std::shared_ptr<const ngraph::Function> transform(
const ngraph::element::Type_t& float_type, const ngraph::element::Type_t& floatType,
const ngraph::element::Type_t& integer_type, const ngraph::element::Type_t& integerType,
const NonMaxSuppressionTestCase& nms_setup) const { const NonMaxSuppressionTestCase& nmsSetup) const {
const auto boxes = std::make_shared<ngraph::opset3::Parameter>( const auto boxes = std::make_shared<ngraph::opset3::Parameter>(
float_type, ngraph::PartialShape{nms_setup.num_batches, nms_setup.num_boxes, 4}); floatType, ngraph::PartialShape{nmsSetup.numBatches, nmsSetup.numBoxes, 4});
const auto scores = std::make_shared<ngraph::opset3::Parameter>( const auto scores = std::make_shared<ngraph::opset3::Parameter>(
float_type, ngraph::PartialShape{nms_setup.num_batches, nms_setup.num_classes, nms_setup.num_boxes}); floatType, ngraph::PartialShape{nmsSetup.numBatches, nmsSetup.numClasses, nmsSetup.numBoxes});
const auto max_output_boxes_per_class = ngraph::opset3::Constant::create(integer_type, {}, std::vector<int64_t>{nms_setup.max_output_boxes_per_class});
const auto iou_threshold = ngraph::opset3::Constant::create(float_type, ngraph::Shape{}, std::vector<float>{nms_setup.iou_threshold});
const auto score_threshold = ngraph::opset3::Constant::create(float_type, ngraph::Shape{}, std::vector<float>{nms_setup.score_threshold});
const auto maxOutputBoxesPerClass = ngraph::opset3::Constant::create(integerType, {}, std::vector<int64_t>{nmsSetup.maxOutputBoxesPerClass});
const auto iouThreshold = ngraph::opset3::Constant::create(floatType, ngraph::Shape{}, std::vector<float>{nmsSetup.iouThreshold});
const auto scoreThreshold = ngraph::opset3::Constant::create(floatType, ngraph::Shape{}, std::vector<float>{nmsSetup.scoreThreshold});
const auto softNMSSigma = ngraph::opset3::Constant::create(floatType, ngraph::Shape{}, std::vector<float>{nmsSetup.softNMSSigma});
const auto dims = std::make_shared<ngraph::opset3::Parameter>(ngraph::element::i64, ngraph::Shape{3}); const auto dims = std::make_shared<ngraph::opset3::Parameter>(ngraph::element::i64, ngraph::Shape{3});
const auto dsr = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(scores, dims); const auto dsr = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(scores, dims);
const auto node = std::make_shared<ngraph::vpu::op::DynamicNonMaxSuppression>( const auto node = std::make_shared<ngraph::op::v5::NonMaxSuppression>(
boxes, dsr, max_output_boxes_per_class, iou_threshold, score_threshold); boxes, dsr, maxOutputBoxesPerClass, iouThreshold, scoreThreshold, softNMSSigma);
auto outputShape = node->get_output_partial_shape(0);
const auto function = std::make_shared<ngraph::Function>( const auto function = std::make_shared<ngraph::Function>(
ngraph::NodeVector{node}, ngraph::OutputVector{node->outputs()},
ngraph::ParameterVector{boxes, scores, dims}, ngraph::ParameterVector{boxes, scores, dims},
"Actual"); "Actual");
node->set_output_type(0, dsr->get_input_element_type(0), ngraph::PartialShape::dynamic(outputShape.rank()));
const auto transformations = vpu::Transformations{{node->type_info, vpu::dynamicToStaticNonMaxSuppression}}; const auto transformations = vpu::Transformations{{node->type_info, vpu::dynamicToStaticNonMaxSuppression}};
vpu::DynamicToStaticShape(transformations).run_on_function(function); vpu::DynamicToStaticShape(transformations).run_on_function(function);
@ -73,27 +74,35 @@ protected:
} }
std::shared_ptr<const ngraph::Function> reference( std::shared_ptr<const ngraph::Function> reference(
const ngraph::element::Type_t& float_type, const ngraph::element::Type_t& floatType,
const ngraph::element::Type_t& integer_type, const ngraph::element::Type_t& integerType,
const NonMaxSuppressionTestCase& nms_setup) const { const NonMaxSuppressionTestCase& nmsSetup) const {
const auto boxes = std::make_shared<ngraph::opset3::Parameter>( const auto boxes = std::make_shared<ngraph::opset3::Parameter>(
float_type, ngraph::PartialShape{nms_setup.num_batches, nms_setup.num_boxes, 4}); floatType, ngraph::PartialShape{nmsSetup.numBatches, nmsSetup.numBoxes, 4});
const auto scores = std::make_shared<ngraph::opset3::Parameter>( const auto scores = std::make_shared<ngraph::opset3::Parameter>(
float_type, ngraph::PartialShape{nms_setup.num_batches, nms_setup.num_classes, nms_setup.num_boxes}); floatType, ngraph::PartialShape{nmsSetup.numBatches, nmsSetup.numClasses, nmsSetup.numBoxes});
const auto max_output_boxes_per_class = ngraph::opset3::Constant::create(integer_type, {}, std::vector<int64_t>{nms_setup.max_output_boxes_per_class});
const auto iou_threshold = ngraph::opset3::Constant::create(float_type, {}, std::vector<float>{nms_setup.iou_threshold});
const auto score_threshold = ngraph::opset3::Constant::create(float_type, {}, std::vector<float>{nms_setup.score_threshold});
const auto maxOutputBoxesPerClass = ngraph::opset3::Constant::create(integerType, {}, std::vector<int64_t>{nmsSetup.maxOutputBoxesPerClass});
const auto iouThreshold = ngraph::opset3::Constant::create(floatType, {}, std::vector<float>{nmsSetup.iouThreshold});
const auto scoreThreshold = ngraph::opset3::Constant::create(floatType, {}, std::vector<float>{nmsSetup.scoreThreshold});
const auto softNMSSigma = ngraph::opset3::Constant::create(floatType, ngraph::Shape{}, std::vector<float>{nmsSetup.softNMSSigma});
const auto dims = std::make_shared<ngraph::opset3::Parameter>(ngraph::element::i64, ngraph::Shape{3}); const auto dims = std::make_shared<ngraph::opset3::Parameter>(ngraph::element::i64, ngraph::Shape{3});
const auto dsr = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(scores, dims); const auto dsrInput = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(scores, dims);
const auto node = std::make_shared<ngraph::vpu::op::StaticShapeNonMaxSuppression>( const auto node = std::make_shared<ngraph::vpu::op::StaticShapeNonMaxSuppression>(
boxes, dsr, max_output_boxes_per_class, iou_threshold, score_threshold); boxes, dsrInput, maxOutputBoxesPerClass, iouThreshold, scoreThreshold, softNMSSigma);
const auto validOutputs = std::make_shared<ngraph::opset5::Gather>(
node->output(2),
ngraph::opset5::Constant::create(dims->get_element_type(), ngraph::Shape{1}, {0}),
ngraph::opset5::Constant::create(dims->get_element_type(), ngraph::Shape{1}, {0}));
const auto dsrIndices = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(node->output(0), node->output(2));
const auto dsrScores = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(node->output(1), node->output(2));
const auto dsr1 = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(node->output(0), node->output(1));
return std::make_shared<ngraph::Function>( return std::make_shared<ngraph::Function>(
ngraph::NodeVector{dsr1}, ngraph::NodeVector{dsrIndices, dsrScores, validOutputs},
ngraph::ParameterVector{boxes, scores, dims}, ngraph::ParameterVector{boxes, scores, dims},
"Expected"); "Expected");
} }
@ -111,10 +120,10 @@ INSTANTIATE_TEST_CASE_P(smoke_NGraph, DynamicToStaticShapeNonMaxSuppression, tes
ngraph::element::i64, ngraph::element::i64,
ngraph::element::u8), ngraph::element::u8),
testing::Values( testing::Values(
// num_batches, num_boxes, num_classes, max_output_boxes_per_class, iou_threshold, score_threshold // numBatches, numBoxes, numClasses, maxOutputBoxesPerClass, iouThreshold, scoreThreshold, softNMSSigma
NonMaxSuppressionTestCase{1, 10, 5, 10, 0., 0.}, NonMaxSuppressionTestCase{1, 10, 5, 10, 0., 0., 0.},
NonMaxSuppressionTestCase{2, 100, 5, 10, 0., 0.}, NonMaxSuppressionTestCase{2, 100, 5, 10, 0., 0., 0.},
NonMaxSuppressionTestCase{3, 10, 5, 2, 0.5, 0.}, NonMaxSuppressionTestCase{3, 10, 5, 2, 0.5, 0., 0.},
NonMaxSuppressionTestCase{1, 1000, 1, 2000, 0.5, 0.}))); NonMaxSuppressionTestCase{1, 1000, 1, 2000, 0.5, 0., 0.})));
} // namespace } // namespace

View File

@ -54,11 +54,12 @@ protected:
std::shared_ptr<const ngraph::Function> reference( std::shared_ptr<const ngraph::Function> reference(
const TensorType& dataType, const TensorType& dataType,
const TensorShape& dataShape) const { const TensorShape& dataShape) const {
const auto data = std::make_shared<ngraph::opset3::Parameter>(dataType, dataShape);
const auto shape = std::make_shared<ngraph::opset3::Parameter>(ngraph::element::i64, ngraph::Shape{dataShape.size()}); const auto shape = std::make_shared<ngraph::opset3::Parameter>(ngraph::element::i64, ngraph::Shape{dataShape.size()});
return std::make_shared<ngraph::Function>( return std::make_shared<ngraph::Function>(
ngraph::NodeVector{shape}, ngraph::NodeVector{shape},
ngraph::ParameterVector{shape}, ngraph::ParameterVector{data, shape},
"Expected"); "Expected");
} }
}; };
@ -115,13 +116,14 @@ protected:
std::shared_ptr<const ngraph::Function> reference( std::shared_ptr<const ngraph::Function> reference(
const TensorType& dataType, const TensorType& dataType,
const TensorShape& dataShape) const { const TensorShape& dataShape) const {
const auto data = std::make_shared<ngraph::opset3::Parameter>(dataType, dataShape);
const auto shape = std::make_shared<ngraph::opset3::Parameter>(ngraph::element::i64, ngraph::Shape{dataShape.size()}); const auto shape = std::make_shared<ngraph::opset3::Parameter>(ngraph::element::i64, ngraph::Shape{dataShape.size()});
const auto shapeRelu = std::make_shared<ngraph::opset3::Relu>(shape); const auto shapeRelu = std::make_shared<ngraph::opset3::Relu>(shape);
return std::make_shared<ngraph::Function>( return std::make_shared<ngraph::Function>(
ngraph::NodeVector{shapeRelu}, ngraph::NodeVector{shapeRelu},
ngraph::ParameterVector{shape}, ngraph::ParameterVector{data, shape},
"Expected"); "Expected");
} }
}; };

View File

@ -6,6 +6,7 @@
#include <functional_test_utils/blob_utils.hpp> #include <functional_test_utils/blob_utils.hpp>
#include <ngraph/opsets/opset3.hpp> #include <ngraph/opsets/opset3.hpp>
#include <ngraph/op/non_max_suppression.hpp>
#include "vpu/ngraph/operations/static_shape_non_maximum_suppression.hpp" #include "vpu/ngraph/operations/static_shape_non_maximum_suppression.hpp"
using TensorShape = InferenceEngine::SizeVector; using TensorShape = InferenceEngine::SizeVector;
@ -16,7 +17,8 @@ using StaticShapeNMSParam = std::tuple<
int64_t, // Number of classes int64_t, // Number of classes
int64_t, // Maximum output boxes per class int64_t, // Maximum output boxes per class
float, // IOU threshold float, // IOU threshold
float>; // Score threshold float, // Score threshold
float>; // Soft NMS sigma
using StaticShapeNMSTestParam = std::tuple< using StaticShapeNMSTestParam = std::tuple<
StaticShapeNMSParam, // NMS params StaticShapeNMSParam, // NMS params
@ -66,6 +68,7 @@ protected:
const auto maxOutputBoxesPerClass = std::get<3>(NMSParams); const auto maxOutputBoxesPerClass = std::get<3>(NMSParams);
const auto iouThreshold = std::get<4>(NMSParams); const auto iouThreshold = std::get<4>(NMSParams);
const auto scoreThreshold = std::get<5>(NMSParams); const auto scoreThreshold = std::get<5>(NMSParams);
const auto softNMSSigma = std::get<6>(NMSParams);
auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(inPrc); auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(inPrc);
@ -79,10 +82,12 @@ protected:
ngraph::element::f32, ngraph::Shape{}, iouThreshold); ngraph::element::f32, ngraph::Shape{}, iouThreshold);
const auto scoreThresholdConst = std::make_shared<ngraph::opset3::Constant>( const auto scoreThresholdConst = std::make_shared<ngraph::opset3::Constant>(
ngraph::element::f32, ngraph::Shape{}, scoreThreshold); ngraph::element::f32, ngraph::Shape{}, scoreThreshold);
const auto softNMSSigmaConst = std::make_shared<ngraph::opset3::Constant>(
ngraph::element::f32, ngraph::Shape{1}, softNMSSigma);
const auto staticShapeNMS = std::make_shared<ngraph::vpu::op::StaticShapeNonMaxSuppression>( const auto staticShapeNMS = std::make_shared<ngraph::vpu::op::StaticShapeNonMaxSuppression>(
inputBoxes, inputScores, maxOutputBoxesPerClassConst, iouThresholdConst, scoreThresholdConst, inputBoxes, inputScores, maxOutputBoxesPerClassConst, iouThresholdConst, scoreThresholdConst, softNMSSigmaConst,
ngraph::opset3::NonMaxSuppression::BoxEncodingType::CORNER, false, ngraph::element::i32); 0, false, ngraph::element::i32);
ngraph::ResultVector results{std::make_shared<ngraph::opset3::Result>(staticShapeNMS->output(0)), ngraph::ResultVector results{std::make_shared<ngraph::opset3::Result>(staticShapeNMS->output(0)),
std::make_shared<ngraph::opset3::Result>(staticShapeNMS->output(1))}; std::make_shared<ngraph::opset3::Result>(staticShapeNMS->output(1))};
@ -95,11 +100,11 @@ TEST_P(StaticShapeNMSLayerTest, accuracy) {
} }
std::vector<StaticShapeNMSParam> NMSParams = { std::vector<StaticShapeNMSParam> NMSParams = {
std::make_tuple(1, 10, 5, 10, 0., 0.), std::make_tuple(1, 10, 5, 10, 0., 0., 0.),
std::make_tuple(2, 100, 5, 10, 0., 0.), std::make_tuple(2, 100, 5, 10, 0., 0., 0.),
std::make_tuple(3, 10, 5, 2, 0.5, 0.), std::make_tuple(3, 10, 5, 2, 0.5, 0., 0.),
std::make_tuple(1, 1000, 1, 2000, 0.5, 0.), std::make_tuple(1, 1000, 1, 2000, 0.5, 0., 0.),
std::make_tuple(1, 8200, 1, 8200, 0.5, 0.), std::make_tuple(1, 8200, 1, 8200, 0.5, 0., 0.),
}; };
std::vector<InferenceEngine::Precision> NMSPrecisions = { std::vector<InferenceEngine::Precision> NMSPrecisions = {

View File

@ -5,7 +5,7 @@
#include <functional_test_utils/layer_test_utils.hpp> #include <functional_test_utils/layer_test_utils.hpp>
#include <ngraph_functions/builders.hpp> #include <ngraph_functions/builders.hpp>
#include <vpu/ngraph/operations/dynamic_shape_resolver.hpp> #include <vpu/ngraph/operations/dynamic_shape_resolver.hpp>
#include <vpu/ngraph/operations/dynamic_non_max_suppression.hpp> #include <ngraph/op/non_max_suppression.hpp>
namespace { namespace {
@ -49,7 +49,7 @@ protected:
const auto dims = std::make_shared<ngraph::opset3::Parameter>(ngraph::element::i64, ngraph::Shape{3}); const auto dims = std::make_shared<ngraph::opset3::Parameter>(ngraph::element::i64, ngraph::Shape{3});
const auto dsr = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(scores, dims); const auto dsr = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(scores, dims);
const auto node = std::make_shared<ngraph::vpu::op::DynamicNonMaxSuppression>( const auto node = std::make_shared<ngraph::op::v5::NonMaxSuppression>(
boxes, dsr, max_output_boxes_per_class, iou_threshold, score_threshold); boxes, dsr, max_output_boxes_per_class, iou_threshold, score_threshold);
const auto result = std::make_shared<ngraph::opset3::Result>(node); const auto result = std::make_shared<ngraph::opset3::Result>(node);

View File

@ -177,8 +177,6 @@ std::vector<std::vector<std::uint8_t>> getConstData(const std::shared_ptr<Functi
namespace { namespace {
using ComparingNodesPair = std::pair<std::shared_ptr<ngraph::Node>, std::shared_ptr<ngraph::Node>>;
std::string toString(const NodeTypeInfo& typeInfo) { std::string toString(const NodeTypeInfo& typeInfo) {
return std::string(typeInfo.name) + " ver. " + std::to_string(typeInfo.version); return std::string(typeInfo.name) + " ver. " + std::to_string(typeInfo.version);
} }
@ -195,34 +193,38 @@ void CompareNodes(const Node& actual, const Node& expected) {
const auto& numActualInputs = actual.inputs().size(); const auto& numActualInputs = actual.inputs().size();
const auto& numExpectedInputs = expected.inputs().size(); const auto& numExpectedInputs = expected.inputs().size();
NGRAPH_CHECK(numActualInputs == numExpectedInputs, "Functions compare: numbers of inputs are different: ", numActualInputs, " and ", numExpectedInputs); NGRAPH_CHECK(numActualInputs == numExpectedInputs, "Functions compare: numbers of inputs are different: ", numActualInputs, " and ", numExpectedInputs);
const auto& numActualOutputs = actual.outputs().size();
const auto& numExpectedOutputs = expected.outputs().size();
NGRAPH_CHECK(numActualOutputs == numExpectedOutputs, "Functions compare: numbers of outputs are different: ",
numActualOutputs, " and ", numExpectedOutputs);
} }
} // namespace } // namespace
void CompareFunctions(const Function& actual, const Function& expected) { void CompareFunctions(const Function& actual, const Function& expected) {
const auto& actualResults = actual.get_results(); const auto& actualOrderedOps = actual.get_ordered_ops();
NGRAPH_CHECK(actualResults.size() == 1, "Got ", actualResults.size(), " outputs for function, but only single output functions are supported"); const auto& expectedOrderedOps = expected.get_ordered_ops();
const auto& actualResult = actualResults.front();
const auto& expectedResults = expected.get_results(); NGRAPH_CHECK(expectedOrderedOps.size() == actualOrderedOps.size(),
NGRAPH_CHECK(expectedResults.size() == 1, "Got ", expectedResults.size(), " outputs for function, but only single output functions are supported"); "Functions compare: expected and actual ops number should be equal "
const auto& expectedResult = expectedResults.front(); "but got ", expectedOrderedOps.size(), " and ", actualOrderedOps.size(), " respectively");
std::queue<ComparingNodesPair> nodes; for (std::size_t i = 0; i < expectedOrderedOps.size(); i++) {
nodes.emplace(actualResult, expectedResult); const auto& expectedOp = expectedOrderedOps[i];
while (!nodes.empty()) { const auto& actualOp = actualOrderedOps[i];
const auto actualNode = nodes.front().first;
const auto expectedNode = nodes.front().second;
nodes.pop();
CompareNodes(*actualNode, *expectedNode); CompareNodes(*actualOp, *expectedOp);
for (std::size_t i = 0; i < actualOp->inputs().size(); ++i) {
for (std::size_t i = 0; i < actualNode->inputs().size(); ++i) { const auto& actualShape = actualOp->input(i).get_partial_shape();
const auto& actualShape = actualNode->input(i).get_partial_shape(); const auto& expectedShape = expectedOp->input(i).get_partial_shape();
const auto& expectedShape = expectedNode->input(i).get_partial_shape();
CompareShapes(actualShape, expectedShape); CompareShapes(actualShape, expectedShape);
}
nodes.emplace(actualNode->input_value(i).get_node_shared_ptr(), expectedNode->input_value(i).get_node_shared_ptr()); for (std::size_t i = 0; i < actualOp->outputs().size(); ++i) {
const auto& actualShape = actualOp->output(i).get_partial_shape();
const auto& expectedShape = expectedOp->output(i).get_partial_shape();
CompareShapes(actualShape, expectedShape);
} }
} }
} }

View File

@ -1,260 +0,0 @@
// Copyright (C) 2018-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "myriad_layers_nms_test.hpp"
INSTANTIATE_TEST_CASE_P(accuracy, myriadLayersTestsNonMaxSuppression_smoke,
::testing::Values(
MAKE_STRUCT(NMS_testParams,
{6, 1, 1}, // {spatial_dimension, num_classes, num_batches}
1,
{3},
{0.5f},
{0.f},
{ // batches
{ // spatial_dimension
{0.5f, 0.5f, 1.0f, 1.0f}, // center_point_box=0 {y1, x1, y2, x2} center_point_box=1 {y0, x0, w, h}
{0.5f, 0.6f, 1.0f, 1.0f},
{0.5f, 0.4f, 1.0f, 1.0f},
{0.5f, 10.5f, 1.0f, 1.0f},
{0.5f, 10.6f, 1.0f, 1.0f},
{0.5f, 100.5f, 1.0f, 1.0f},
},
},
{ // batches
{ // classes
{0.9f, 0.75f, 0.6f, 0.95f, 0.5f, 0.3f}, // spatial_dimension
},
},
{ // num_selected_indices
{0, 0, 3}, // {batch_index, class_index, box_index}
{0, 0, 0},
{0, 0, 5},
}
),
MAKE_STRUCT(NMS_testParams,
{6, 1, 1},
0,
{3},
{0.5f},
{0.f},
{
{
{1.0f, 1.0f, 0.0f, 0.0f},
{0.0f, 0.1f, 1.0f, 1.1f},
{0.0f, 0.9f, 1.0f, -0.1f},
{0.0f, 10.0f, 1.0f, 11.0f},
{1.0f, 10.1f, 0.0f, 11.1f},
{1.0f, 101.0f, 0.0f, 100.0f}
}
},
{
{
{0.9f, 0.75f, 0.6f, 0.95f, 0.5f, 0.3f}
}
},
{
{0, 0, 3},
{0, 0, 0},
{0, 0, 5},
}
),
MAKE_STRUCT(NMS_testParams,
{10, 1, 1},
0,
{3},
{0.5f},
{0.f},
{
{
{0.0f, 0.0f, 1.0f, 1.0f},
{0.0f, 0.0f, 1.0f, 1.0f},
{0.0f, 0.0f, 1.0f, 1.0f},
{0.0f, 0.0f, 1.0f, 1.0f},
{0.0f, 0.0f, 1.0f, 1.0f},
{0.0f, 0.0f, 1.0f, 1.0f},
{0.0f, 0.0f, 1.0f, 1.0f},
{0.0f, 0.0f, 1.0f, 1.0f},
{0.0f, 0.0f, 1.0f, 1.0f},
{0.0f, 0.0f, 1.0f, 1.0f},
}
},
{
{
{0.9f, 0.9f, 0.9f, 0.9f, 0.9f, 0.9f, 0.9f, 0.9f, 0.9f, 0.9f}
}
},
{
{0, 0, 0},
}
),
MAKE_STRUCT(NMS_testParams,
{6, 1, 1},
0,
{2},
{0.5f},
{0.f},
{
{
{0.0f, 0.0f, 1.0f, 1.0f},
{0.0f, 0.1f, 1.0f, 1.1f},
{0.0f, -0.1f, 1.0f, 0.9f},
{0.0f, 10.0f, 1.0f, 11.0f},
{0.0f, 10.1f, 1.0f, 11.1f},
{0.0f, 100.0f, 1.0f, 101.0f},
}
},
{
{
{0.9f, 0.75f, 0.6f, 0.95f, 0.5f, 0.3f}
}
},
{
{0, 0, 3},
{0, 0, 0},
}
),
MAKE_STRUCT(NMS_testParams,
{1, 1, 1},
0,
{3},
{0.5f},
{0.f},
{
{
{0.0f, 0.0f, 1.0f, 1.0f},
}
},
{
{
{0.9f}
}
},
{
{0, 0, 0},
}
),
MAKE_STRUCT(NMS_testParams,
{6, 1, 1},
0,
{3},
{0.5f},
{0.f},
{
{
{0.0f, 0.0f, 1.0f, 1.0f},
{0.0f, 0.1f, 1.0f, 1.1f},
{0.0f, -0.1f, 1.0f, 0.9f},
{0.0f, 10.0f, 1.0f, 11.0f},
{0.0f, 10.1f, 1.0f, 11.1f},
{0.0f, 100.0f, 1.0f, 101.0f},
}
},
{
{
{0.9f, 0.75f, 0.6f, 0.95f, 0.5f, 0.3f}
}
},
{
{0, 0, 3},
{0, 0, 0},
{0, 0, 5},
}
),
MAKE_STRUCT(NMS_testParams,
{6, 1, 1},
0,
{3},
{0.5f},
{0.4f},
{
{
{0.0f, 0.0f, 1.0f, 1.0f},
{0.0f, 0.1f, 1.0f, 1.1f},
{0.0f, -0.1f, 1.0f, 0.9f},
{0.0f, 10.0f, 1.0f, 11.0f},
{0.0f, 10.1f, 1.0f, 11.1f},
{0.0f, 100.0f, 1.0f, 101.0f},
}
},
{
{
{0.9f, 0.75f, 0.6f, 0.95f, 0.5f, 0.3f}
}
},
{
{0, 0, 3},
{0, 0, 0},
}
),
MAKE_STRUCT(NMS_testParams,
{6, 1, 2},
0,
{2},
{0.5f},
{0.0f},
{
{
{0.0f, 0.0f, 1.0f, 1.0f},
{0.0f, 0.1f, 1.0f, 1.1f},
{0.0f, -0.1f, 1.0f, 0.9f},
{0.0f, 10.0f, 1.0f, 11.0f},
{0.0f, 10.1f, 1.0f, 11.1f},
{0.0f, 100.0f, 1.0f, 101.0f},
},
{
{0.0f, 0.0f, 1.0f, 1.0f},
{0.0f, 0.1f, 1.0f, 1.1f},
{0.0f, -0.1f, 1.0f, 0.9f},
{0.0f, 10.0f, 1.0f, 11.0f},
{0.0f, 10.1f, 1.0f, 11.1f},
{0.0f, 100.0f, 1.0f, 101.0f},
}
},
{
{
{0.9f, 0.75f, 0.6f, 0.95f, 0.5f, 0.3f}
},
{
{0.9f, 0.75f, 0.6f, 0.95f, 0.5f, 0.3f}
}
},
{
{0, 0, 3},
{0, 0, 0},
{1, 0, 3},
{1, 0, 0},
}
),
MAKE_STRUCT(NMS_testParams,
{6, 2, 1},
0,
{2},
{0.5f},
{0.0f},
{
{
{0.0f, 0.0f, 1.0f, 1.0f},
{0.0f, 0.1f, 1.0f, 1.1f},
{0.0f, -0.1f, 1.0f, 0.9f},
{0.0f, 10.0f, 1.0f, 11.0f},
{0.0f, 10.1f, 1.0f, 11.1f},
{0.0f, 100.0f, 1.0f, 101.0f},
}
},
{
{
{0.9f, 0.75f, 0.6f, 0.95f, 0.5f, 0.3f},
{0.9f, 0.75f, 0.6f, 0.95f, 0.5f, 0.3f}
}
},
{
{0, 0, 3},
{0, 0, 0},
{0, 1, 3},
{0, 1, 0},
}
)
)
);

View File

@ -1,264 +0,0 @@
// Copyright (C) 2018-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "myriad_layers_tests.hpp"
#include "tests_vpu_common.hpp"
using namespace InferenceEngine;
typedef std::vector<int> NMS_Dims;
typedef std::vector<std::vector<std::vector<float>>> init3DFloat;
typedef std::vector<int> initIntScalar;
typedef std::vector<float> initFPScalar;
typedef std::vector<std::vector<int>> refType;
struct NMS_testParams {
int dims[3]; // {spat_dim, num_classes, num_batches}
int centerPointBox;
initIntScalar MaxOutBoxesPerClass; // scalar
initFPScalar IoUThreshold; // scalar
initFPScalar ScoreThreshold; // scalar
init3DFloat boxes;
init3DFloat scores;
refType referenceOutput;
};
static std::string getModel(const int numOfInputs, const NMS_Dims &dims, const int center_point_box) {
std::string model = R"V0G0N(
<net name="testNMS" version="7">
<layers>
<layer id="0" name="boxes" precision="FP16" type="Input">
<output>
<port id="0">
<dim>__BATCHES__</dim>
<dim>__SPAT_DIM__</dim>
<dim>4</dim>
</port>
</output>
</layer>
<layer id="1" name="scores" precision="FP16" type="Input">
<output>
<port id="0">
<dim>__BATCHES__</dim>
<dim>__CLASSES__</dim>
<dim>__SPAT_DIM__</dim>
</port>
</output>
</layer>)V0G0N";
if (numOfInputs > 2)
model += R"V0G0N(
<layer id="2" name="MaxOutputBoxesPerClass" precision="I32" type="Input">
<output>
<port id="0">
<dim>1</dim>
</port>
</output>
</layer>)V0G0N";
if (numOfInputs > 3)
model += R"V0G0N(
<layer id="3" name="IoUThreshold" precision="FP16" type="Input">
<output>
<port id="0">
<dim>1</dim>
</port>
</output>
</layer>)V0G0N";
if (numOfInputs > 4)
model += R"V0G0N(
<layer id="4" name="ScoreThreshold" precision="FP16" type="Input">
<output>
<port id="0">
<dim>1</dim>
</port>
</output>
</layer>)V0G0N";
model += R"V0G0N(
<layer id="5" name="NMS" precision="I32" type="NonMaxSuppression">
<data center_point_box="__CPB__"/>
<input>
<port id="0">
<dim>__BATCHES__</dim>
<dim>__SPAT_DIM__</dim>
<dim>4</dim>
</port>
<port id="1">
<dim>__BATCHES__</dim>
<dim>__CLASSES__</dim>
<dim>__SPAT_DIM__</dim>
</port>)V0G0N";
if (numOfInputs > 2)
model += R"V0G0N(
<port id="2">
<dim>1</dim>
</port>)V0G0N";
if (numOfInputs > 3)
model += R"V0G0N(
<port id="3">
<dim>1</dim>
</port>)V0G0N";
if (numOfInputs > 4)
model += R"V0G0N(
<port id="4">
<dim>1</dim>
</port>)V0G0N";
model += R"V0G0N(
</input>
<output>
<port id="4">
<dim>__SPAT_DIM__</dim>
<dim>3</dim>
</port>
</output>
</layer>
</layers>
<edges>
<edge from-layer="0" from-port="0" to-layer="5" to-port="0"/>
<edge from-layer="1" from-port="0" to-layer="5" to-port="1"/>)V0G0N";
if (numOfInputs > 2)
model += R"V0G0N(
<edge from-layer="2" from-port="0" to-layer="5" to-port="2"/>)V0G0N";
if (numOfInputs > 3)
model += R"V0G0N(
<edge from-layer="3" from-port="0" to-layer="5" to-port="3"/>)V0G0N";
if (numOfInputs > 4)
model += R"V0G0N(
<edge from-layer="4" from-port="0" to-layer="5" to-port="4"/>)V0G0N";
model += R"V0G0N(
</edges>
</net>
)V0G0N";
REPLACE_WITH_STR(model, "__SPAT_DIM__", std::to_string(dims[0]));
REPLACE_WITH_STR(model, "__CLASSES__", std::to_string(dims[1]));
REPLACE_WITH_STR(model, "__BATCHES__", std::to_string(dims[2]));
REPLACE_WITH_STR(model, "__CPB__", std::to_string(center_point_box));
return model;
}
static void copyScalarToBlob(const Blob::Ptr& blob, const initIntScalar& scalar) {
auto *data = blob->buffer().as<int32_t *>();
data[0] = scalar[0];
}
static void copyScalarToBlob(const Blob::Ptr& blob, const initFPScalar& scalar) {
auto *data = blob->buffer().as<ie_fp16 *>();
data[0] = PrecisionUtils::f32tof16(scalar[0]);
}
static void copy3DToBlob(const Blob::Ptr& blob, const init3DFloat& src) {
auto *data = blob->buffer().as<ie_fp16 *>();
const auto dims = blob->getTensorDesc().getDims();
for (int i = 0; i < dims[0]; i++) {
for (int j = 0; j < dims[1]; j++) {
for (int k = 0; k < dims[2]; k++) {
data[i * dims[1] * dims[2] + j * dims[2] + k] = PrecisionUtils::f32tof16(src[i][j][k]);
}
}
}
}
static void copyReference(const Blob::Ptr& blob, const refType src) {
int32_t *data = blob->buffer().as<int32_t *>();
const auto dims = blob->getTensorDesc().getDims();
int boxNum = 0;
for (; boxNum < src.size(); boxNum++) {
data[boxNum * 3 + 0] = src[boxNum][0];
data[boxNum * 3 + 1] = src[boxNum][1];
data[boxNum * 3 + 2] = src[boxNum][2];
}
for (; boxNum < dims[0]; boxNum++) {
data[boxNum * 3 + 0] = -1;
data[boxNum * 3 + 1] = -1;
data[boxNum * 3 + 2] = -1;
}
}
typedef myriadLayerTestBaseWithParam<NMS_testParams> myriadLayersTestsNonMaxSuppression_smoke;
TEST_P(myriadLayersTestsNonMaxSuppression_smoke, NonMaxSuppression) {
const auto params = GetParam();
const int spatDim = params.dims[0];
const int numClasses = params.dims[1];
const int numBatches = params.dims[2];
const int center_point_box = params.centerPointBox;
int numOfInputs = 2;
if (!params.ScoreThreshold.empty())
numOfInputs = 5;
else if (!params.IoUThreshold.empty())
numOfInputs = 4;
else if (!params.MaxOutBoxesPerClass.empty())
numOfInputs = 3;
const auto model = getModel(numOfInputs, {spatDim, numClasses, numBatches}, center_point_box);
ASSERT_NO_THROW(readNetwork(model));
const auto& network = _cnnNetwork;
_inputsInfo = network.getInputsInfo();
_inputsInfo["boxes"]->setPrecision(Precision::FP16);
_inputsInfo["scores"]->setPrecision(Precision::FP16);
if (numOfInputs > 2)
_inputsInfo["MaxOutputBoxesPerClass"]->setPrecision(Precision::I32);
if (numOfInputs > 3)
_inputsInfo["IoUThreshold"]->setPrecision(Precision::FP16);
if (numOfInputs > 4)
_inputsInfo["ScoreThreshold"]->setPrecision(Precision::FP16);
_outputsInfo = network.getOutputsInfo();
_outputsInfo["NMS"]->setPrecision(Precision::I32);
StatusCode st = OK;
ASSERT_NO_THROW(st = _vpuPluginPtr->LoadNetwork(_exeNetwork, network, _config, &_resp));
ASSERT_EQ(StatusCode::OK, st) << _resp.msg;
ASSERT_NE(_exeNetwork, nullptr) << _resp.msg;
ASSERT_NO_THROW(st = _exeNetwork->CreateInferRequest(_inferRequest, &_resp));
ASSERT_EQ(StatusCode::OK, st) << _resp.msg;
Blob::Ptr boxesBlob;
ASSERT_NO_THROW(st = _inferRequest->GetBlob("boxes", boxesBlob, &_resp));
ASSERT_EQ(StatusCode::OK, st) << _resp.msg;
std::cout << CheckMyriadX() << std::endl;
copy3DToBlob(boxesBlob, params.boxes);
Blob::Ptr scoresBlob;
ASSERT_NO_THROW(st = _inferRequest->GetBlob("scores", scoresBlob, &_resp));
ASSERT_EQ(StatusCode::OK, st) << _resp.msg;
copy3DToBlob(scoresBlob, params.scores);
if (numOfInputs > 2) {
Blob::Ptr MaxOutputBoxesBlob;
ASSERT_NO_THROW(st = _inferRequest->GetBlob("MaxOutputBoxesPerClass", MaxOutputBoxesBlob, &_resp));
ASSERT_EQ(StatusCode::OK, st) << _resp.msg;
copyScalarToBlob(MaxOutputBoxesBlob, params.MaxOutBoxesPerClass);
}
if (numOfInputs > 3) {
Blob::Ptr IoUThresholdBlob;
ASSERT_NO_THROW(st = _inferRequest->GetBlob("IoUThreshold", IoUThresholdBlob, &_resp));
ASSERT_EQ(StatusCode::OK, st) << _resp.msg;
copyScalarToBlob(IoUThresholdBlob, params.IoUThreshold);
}
if (numOfInputs > 4) {
Blob::Ptr ScoreThresholdBlob;
ASSERT_NO_THROW(st = _inferRequest->GetBlob("ScoreThreshold", ScoreThresholdBlob, &_resp));
ASSERT_EQ(StatusCode::OK, st) << _resp.msg;
copyScalarToBlob(ScoreThresholdBlob, params.ScoreThreshold);
}
ASSERT_NO_THROW(st = _inferRequest->Infer(&_resp));
ASSERT_EQ(StatusCode::OK, st) << _resp.msg;
Blob::Ptr outputBlob;
ASSERT_NO_THROW(st = _inferRequest->GetBlob("NMS", outputBlob, &_resp));
ASSERT_EQ(StatusCode::OK, st) << _resp.msg;
Blob::Ptr refBlob = make_shared_blob<int32_t>(outputBlob->getTensorDesc());
refBlob->allocate();
copyReference(refBlob, params.referenceOutput);
if (memcmp(refBlob->cbuffer(), outputBlob->cbuffer(), outputBlob->byteSize()))
FAIL() << "Wrong result with compare ONNX reference!";
}