Review PSROIPooling class for shape inference aspects (#16447)

* Review ROIPooling class
- check interval shape and label propagation
- add template shape_infer
- add shape infer into cpu plugin
- add test with StaticShape

* Use get_output_roi instead of get_output_size

* Add missing includes

* Review PSROIPooling operator
- review interval and label propagation
- add template shape_infer implementation
- add shape_infer to cpu plugin
This commit is contained in:
Pawel Raasz 2023-03-28 13:02:16 +02:00 committed by GitHub
parent d9d1df2fe3
commit 49d150b3b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 532 additions and 270 deletions

View File

@ -43,21 +43,56 @@ public:
std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override;
/**
* @brief Set the output channel dimension size.
* @param output_dim Channel dimension size.
*/
void set_output_dim(size_t output_dim);
size_t get_output_dim() const {
return m_output_dim;
}
/**
* @brief Set the output groups number.
* @param group_size Number of groups.
*/
void set_group_size(size_t group_size);
size_t get_group_size() const {
return m_group_size;
}
/**
* @brief Set the spatial scale.
* @param scale Spatial scale value.
*/
void set_spatial_scale(float scale);
float get_spatial_scale() const {
return m_spatial_scale;
}
/**
* @brief Set the number of bins over image width.
* @param x Number of bins over width (x) axis.
*/
void set_spatial_bins_x(int x);
int get_spatial_bins_x() const {
return m_spatial_bins_x;
}
/**
* @brief Set the number of bins over image height.
* @param y Number of bins over height (y) axis.
*/
void set_spatial_bins_y(int y);
int get_spatial_bins_y() const {
return m_spatial_bins_y;
}
/**
* @brief Set the pooling mode.
* @param mode Pooling mode name.
*/
void set_mode(std::string mode);
const std::string& get_mode() const {
return m_mode;
}

View File

@ -0,0 +1,99 @@
// Copyright (C) 2018-2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <cmath>
#include "compare.hpp"
#include "dimension_util.hpp"
#include "openvino/op/roi_pooling.hpp"
#include "roi_pooling_shape_inference.hpp"
namespace ov {
namespace op {
namespace psroi_pooling {
namespace validate {
template <class TROIPooling, class TShape>
void feat_input_shape(const TROIPooling* op, const TShape feat_shape) {
using namespace ov::util;
roi_pooling::validate::feat_intput_shape(op, feat_shape);
if (feat_shape.rank().is_static()) {
const auto& mode = op->get_mode();
const auto& num_channels = feat_shape[1];
if (mode == "average") {
const auto group_area = op->get_group_size() * op->get_group_size();
NODE_VALIDATION_CHECK(
op,
num_channels.compatible(group_area * op->get_output_dim()),
"Number of input's channels must be a multiply of output_dim * group_size * group_size");
} else if (mode == "bilinear") {
const auto bins_area = op->get_spatial_bins_x() * op->get_spatial_bins_y();
NODE_VALIDATION_CHECK(
op,
num_channels.compatible(bins_area * op->get_output_dim()),
"Number of input's channels must be a multiply of output_dim * spatial_bins_x * spatial_bins_y");
}
}
}
template <class TROIPooling>
void output_group_attr(const TROIPooling* op) {
NODE_VALIDATION_CHECK(op, op->get_group_size() > 0, "group_size has to be greater than 0");
}
template <class TROIPooling>
void bins_attr(const TROIPooling* op) {
if (op->get_mode() == "bilinear") {
NODE_VALIDATION_CHECK(op, op->get_spatial_bins_x() > 0, "spatial_bins_x has to be greater than 0");
NODE_VALIDATION_CHECK(op, op->get_spatial_bins_y() > 0, "spatial_bins_y has to be greater than 0");
}
}
template <class TROIPooling>
void mode_attr(const TROIPooling* op) {
const auto& mode = op->get_mode();
NODE_VALIDATION_CHECK(op,
mode == "average" || mode == "bilinear",
"Expected 'average' or 'bilinear' mode. Got " + mode);
}
} // namespace validate
} // namespace psroi_pooling
namespace v0 {
template <class TShape>
std::vector<TShape> shape_infer(const PSROIPooling* op, const std::vector<TShape>& input_shapes) {
NODE_VALIDATION_CHECK(op, input_shapes.size() == 2);
using namespace ov::util;
const auto& feat_shape = input_shapes[0];
const auto& rois_shape = input_shapes[1];
psroi_pooling::validate::mode_attr(op);
psroi_pooling::validate::output_group_attr(op);
psroi_pooling::validate::bins_attr(op);
roi_pooling::validate::scale_attr(op);
psroi_pooling::validate::feat_input_shape(op, feat_shape);
roi_pooling::validate::rois_input_shape(op, rois_shape);
TShape out_shape;
out_shape.reserve(4);
out_shape.emplace_back(rois_shape.rank().is_static() ? rois_shape[0] : dim::inf_bound);
out_shape.emplace_back(op->get_output_dim());
out_shape.insert(out_shape.end(), 2, op->get_group_size());
return {out_shape};
}
template <class TShape>
void shape_infer(const PSROIPooling* op, const std::vector<TShape>& input_shapes, std::vector<TShape>& output_shapes) {
output_shapes = shape_infer(op, input_shapes);
}
} // namespace v0
} // namespace op
} // namespace ov

View File

@ -12,8 +12,16 @@
namespace ov {
namespace op {
namespace pooling {
namespace roi_pooling {
namespace validate {
template <class TROIPooling, class TShape>
void feat_intput_shape(const TROIPooling* op, const TShape& feat_shape) {
NODE_VALIDATION_CHECK(op,
feat_shape.rank().compatible(4),
"Expected a 4D tensor for the feature maps input. Got: ",
feat_shape);
}
template <class TROIPooling, class TShape>
void rois_input_shape(const TROIPooling* op, const TShape rois_shape) {
if (rois_shape.rank().is_static()) {
@ -66,7 +74,7 @@ void method_attr(const TROIPooling* op) {
method);
}
} // namespace validate
} // namespace pooling
} // namespace roi_pooling
namespace v0 {
template <class TShape>
@ -78,15 +86,11 @@ std::vector<TShape> shape_infer(const ROIPooling* op, const std::vector<TShape>&
const auto& rois_shape = input_shapes[1];
const auto& feat_rank = feat_shape.rank();
NODE_VALIDATION_CHECK(op,
feat_rank.compatible(4),
"Expected a 4D tensor for the feature maps input. Got: ",
feat_shape);
pooling::validate::rois_input_shape(op, rois_shape);
pooling::validate::output_roi_attr(op);
pooling::validate::scale_attr(op);
pooling::validate::method_attr(op);
roi_pooling::validate::feat_intput_shape(op, feat_shape);
roi_pooling::validate::rois_input_shape(op, rois_shape);
roi_pooling::validate::output_roi_attr(op);
roi_pooling::validate::scale_attr(op);
roi_pooling::validate::method_attr(op);
TShape out_shape;
out_shape.reserve(4);

View File

@ -2,15 +2,20 @@
// SPDX-License-Identifier: Apache-2.0
//
#include "ngraph/op/psroi_pooling.hpp"
#include "openvino/op/psroi_pooling.hpp"
#include "itt.hpp"
#include "ngraph/attribute_visitor.hpp"
#include "openvino/core/attribute_visitor.hpp"
#include "openvino/core/validation_util.hpp"
#include "psroi_pooling_shape_inference.hpp"
using namespace std;
using namespace ngraph;
ov::op::v0::PSROIPooling::PSROIPooling(const Output<Node>& input,
namespace ov {
namespace op {
namespace v0 {
PSROIPooling::PSROIPooling(const Output<Node>& input,
const Output<Node>& coords,
const size_t output_dim,
const size_t group_size,
@ -28,7 +33,7 @@ ov::op::v0::PSROIPooling::PSROIPooling(const Output<Node>& input,
constructor_validate_and_infer_types();
}
bool ngraph::op::v0::PSROIPooling::visit_attributes(AttributeVisitor& visitor) {
bool PSROIPooling::visit_attributes(AttributeVisitor& visitor) {
OV_OP_SCOPE(v0_PSROIPooling_visit_attributes);
visitor.on_attribute("output_dim", m_output_dim);
visitor.on_attribute("group_size", m_group_size);
@ -39,70 +44,22 @@ bool ngraph::op::v0::PSROIPooling::visit_attributes(AttributeVisitor& visitor) {
return true;
}
void ov::op::v0::PSROIPooling::validate_and_infer_types() {
void PSROIPooling::validate_and_infer_types() {
OV_OP_SCOPE(v0_PSROIPooling_validate_and_infer_types);
auto feat_maps_et = get_input_element_type(0);
auto coords_et = get_input_element_type(1);
const auto& feat_maps_et = get_input_element_type(0);
const auto& coords_et = get_input_element_type(1);
NODE_VALIDATION_CHECK(this,
feat_maps_et.is_real(),
"Feature maps' data type must be floating point. Got " + feat_maps_et.get_type_name());
NODE_VALIDATION_CHECK(this,
coords_et.is_real(),
"Coords' data type must be floating point. Got " + coords_et.get_type_name());
NODE_VALIDATION_CHECK(this,
m_mode == "average" || m_mode == "bilinear",
"Expected 'average' or 'bilinear' mode. Got " + m_mode);
NODE_VALIDATION_CHECK(this, m_group_size > 0, "group_size has to be greater than 0");
if (m_mode == "bilinear") {
NODE_VALIDATION_CHECK(this, m_spatial_bins_x > 0, "spatial_bins_x has to be greater than 0");
NODE_VALIDATION_CHECK(this, m_spatial_bins_y > 0, "spatial_bins_y has to be greater than 0");
const auto output_shapes = shape_infer(this, get_node_input_partial_shapes(*this));
set_output_type(0, feat_maps_et, output_shapes[0]);
}
const ov::PartialShape& feat_map_pshape = get_input_partial_shape(0);
const ov::PartialShape& coords_pshape = get_input_partial_shape(1);
if (feat_map_pshape.rank().is_dynamic() || coords_pshape.rank().is_dynamic()) {
set_output_type(0, feat_maps_et, ov::PartialShape::dynamic());
} else {
NODE_VALIDATION_CHECK(this,
feat_map_pshape.rank().get_length() == 4,
"PSROIPooling expects 4 dimensions for input. Got ",
feat_map_pshape.rank().get_length());
NODE_VALIDATION_CHECK(this,
coords_pshape.rank().get_length() == 2,
"PSROIPooling expects 2 dimensions for box coordinates. Got ",
coords_pshape.rank().get_length());
if (feat_map_pshape[1].is_static()) {
auto num_input_channels = feat_map_pshape[1].get_interval().get_min_val();
if (m_mode == "average") {
NODE_VALIDATION_CHECK(this,
num_input_channels % (m_group_size * m_group_size) == 0,
"Number of input's channels must be a multiply of group_size * group_size");
NODE_VALIDATION_CHECK(this,
m_output_dim == num_input_channels / (m_group_size * m_group_size),
"output_dim must be equal to input channels divided by "
"group_size * group_size");
} else if (m_mode == "bilinear") {
NODE_VALIDATION_CHECK(this,
num_input_channels % (m_spatial_bins_x * m_spatial_bins_y) == 0,
"Number of input's channels must be a multiply of "
"spatial_bins_x * spatial_bins_y");
NODE_VALIDATION_CHECK(
this,
m_output_dim == static_cast<size_t>(num_input_channels / (m_spatial_bins_x * m_spatial_bins_y)),
"output_dim must be equal to input channels divided by "
"spatial_bins_x * spatial_bins_y");
}
}
std::vector<Dimension> output_shape{coords_pshape[0], static_cast<Dimension::value_type>(m_output_dim)};
for (int64_t i = 2; i < feat_map_pshape.rank().get_length(); i++) {
output_shape.emplace_back(m_group_size);
}
set_output_type(0, feat_maps_et, output_shape);
}
}
shared_ptr<Node> ov::op::v0::PSROIPooling::clone_with_new_inputs(const OutputVector& new_args) const {
shared_ptr<Node> PSROIPooling::clone_with_new_inputs(const OutputVector& new_args) const {
OV_OP_SCOPE(v0_PSROIPooling_clone_with_new_inputs);
check_new_args_count(this, new_args);
return make_shared<PSROIPooling>(new_args.at(0),
@ -114,3 +71,30 @@ shared_ptr<Node> ov::op::v0::PSROIPooling::clone_with_new_inputs(const OutputVec
m_spatial_bins_y,
m_mode);
}
void PSROIPooling::set_output_dim(size_t output_dim) {
m_output_dim = output_dim;
}
void PSROIPooling::set_group_size(size_t group_size) {
m_group_size = group_size;
}
void PSROIPooling::set_spatial_scale(float scale) {
m_spatial_scale = scale;
}
void PSROIPooling::set_spatial_bins_x(int x) {
m_spatial_bins_x = x;
}
void PSROIPooling::set_spatial_bins_y(int y) {
m_spatial_bins_y = y;
}
void PSROIPooling::set_mode(std::string mode) {
m_mode = std::move(mode);
}
} // namespace v0
} // namespace op
} // namespace ov

View File

@ -2,224 +2,265 @@
// SPDX-License-Identifier: Apache-2.0
//
#include "ngraph/op/psroi_pooling.hpp"
#include "common_test_utils/test_assertions.hpp"
#include "gtest/gtest.h"
#include "ngraph/ngraph.hpp"
#include "util/type_prop.hpp"
#include "openvino/opsets/opset11.hpp"
#include "type_prop.hpp"
using namespace ngraph;
using namespace ov;
using namespace ov::opset11;
using namespace testing;
TEST(type_prop, psroi_pooling_average) {
auto inputs = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{1, 72, 4, 5});
auto coords = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{150, 5});
auto op = std::make_shared<op::PSROIPooling>(inputs, coords, 2, 6, 0.0625f, 0, 0, "average");
ASSERT_EQ(op->get_shape(), (Shape{150, 2, 6, 6}));
ASSERT_EQ(op->get_element_type(), element::Type_t::f32);
class TypePropPSROIPoolingV0 : public TypePropOpTest<op::v0::PSROIPooling> {
protected:
float spatial_scale = 0.625f;
int bin_not_used = 0;
Shape pooling_roi_2x2{2, 2};
};
TEST_F(TypePropPSROIPoolingV0, basic_average) {
const auto inputs = std::make_shared<Parameter>(element::f32, Shape{1, 72, 4, 5});
const auto coords = std::make_shared<Parameter>(element::f32, Shape{150, 5});
const auto op = make_op(inputs, coords, 2, 6, spatial_scale, bin_not_used, bin_not_used, "average");
EXPECT_EQ(op->get_shape(), (Shape{150, 2, 6, 6}));
EXPECT_EQ(op->get_element_type(), element::f32);
}
TEST(type_prop, psroi_pooling_bilinear) {
auto inputs = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{1, 72, 4, 5});
auto coords = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{150, 5});
auto op = std::make_shared<op::PSROIPooling>(inputs, coords, 18, 6, 1.0f, 2, 2, "bilinear");
ASSERT_EQ(op->get_shape(), (Shape{150, 18, 6, 6}));
ASSERT_EQ(op->get_element_type(), element::Type_t::f32);
TEST_F(TypePropPSROIPoolingV0, basic_bilinear) {
const auto inputs = std::make_shared<Parameter>(element::f32, Shape{1, 72, 4, 5});
const auto coords = std::make_shared<Parameter>(element::f32, Shape{150, 5});
auto op = make_op(inputs, coords, 18, 6, 1.0f, 2, 2, "bilinear");
EXPECT_EQ(op->get_shape(), (Shape{150, 18, 6, 6}));
EXPECT_EQ(op->get_element_type(), element::f32);
}
TEST(type_prop, psroi_pooling_invalid_type) {
try {
auto inputs = std::make_shared<op::Parameter>(element::Type_t::i32, Shape{1, 72, 4, 5});
auto coords = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{150, 5});
auto op = std::make_shared<op::PSROIPooling>(inputs, coords, 2, 6, 0.0625f, 0, 0, "average");
FAIL() << "Exception expected";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), std::string("Feature maps' data type must be floating point"));
} catch (...) {
FAIL() << "Unknown exception was thrown";
TEST_F(TypePropPSROIPoolingV0, invalid_features_element_type) {
const auto inputs = std::make_shared<Parameter>(element::i32, Shape{1, 72, 4, 5});
const auto coords = std::make_shared<Parameter>(element::f32, Shape{150, 5});
OV_EXPECT_THROW(auto op = make_op(inputs, coords, 2, 6, spatial_scale, bin_not_used, bin_not_used, "average"),
NodeValidationFailure,
HasSubstr("Feature maps' data type must be floating point"));
}
try {
auto inputs = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{1, 72, 4, 5});
auto coords = std::make_shared<op::Parameter>(element::Type_t::i32, Shape{150, 5});
auto op = std::make_shared<op::PSROIPooling>(inputs, coords, 2, 6, 0.0625f, 0, 0, "average");
FAIL() << "Exception expected";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), std::string("Coords' data type must be floating point"));
} catch (...) {
FAIL() << "Unknown exception was thrown";
}
TEST_F(TypePropPSROIPoolingV0, invalid_rois_element_type) {
const auto inputs = std::make_shared<Parameter>(element::f32, Shape{1, 72, 4, 5});
const auto coords = std::make_shared<Parameter>(element::u16, Shape{150, 5});
OV_EXPECT_THROW(auto op = make_op(inputs, coords, 2, 6, spatial_scale, bin_not_used, bin_not_used, "average"),
NodeValidationFailure,
HasSubstr("Coords' data type must be floating point"));
}
TEST(type_prop, psroi_pooling_invalid_mode) {
try {
auto inputs = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{1, 72, 4, 5});
auto coords = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{150, 5});
auto op = std::make_shared<op::PSROIPooling>(inputs, coords, 2, 6, 0.0625f, 0, 0, "invalid_mode");
FAIL() << "Exception expected";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), std::string("Expected 'average' or 'bilinear' mode"));
} catch (...) {
FAIL() << "Unknown exception was thrown";
}
TEST_F(TypePropPSROIPoolingV0, invalid_pooling_mode) {
const auto inputs = std::make_shared<Parameter>(element::f32, Shape{1, 72, 4, 5});
const auto coords = std::make_shared<Parameter>(element::f32, Shape{150, 5});
OV_EXPECT_THROW(auto op = make_op(inputs, coords, 2, 6, spatial_scale, bin_not_used, bin_not_used, "invalid"),
NodeValidationFailure,
HasSubstr("Expected 'average' or 'bilinear' mode"));
}
TEST(type_prop, psroi_pooling_invalid_shapes) {
try {
auto inputs = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{1, 72, 5});
auto coords = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{150, 5});
auto op = std::make_shared<op::PSROIPooling>(inputs, coords, 2, 6, 0.0625f, 0, 0, "average");
FAIL() << "Exception expected";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), std::string("PSROIPooling expects 4 dimensions for input"));
} catch (...) {
FAIL() << "Unknown exception was thrown";
TEST_F(TypePropPSROIPoolingV0, invalid_features_rank) {
const auto inputs = std::make_shared<Parameter>(element::f32, Shape{1, 72, 4});
const auto coords = std::make_shared<Parameter>(element::f32, Shape{150, 5});
OV_EXPECT_THROW(auto op = make_op(inputs, coords, 2, 6, spatial_scale, bin_not_used, bin_not_used, "average"),
NodeValidationFailure,
HasSubstr("Expected a 4D tensor for the feature maps input"));
}
try {
auto inputs = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{1, 1, 72, 5});
auto coords = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{150});
auto op = std::make_shared<op::PSROIPooling>(inputs, coords, 2, 6, 0.0625f, 0, 0, "average");
FAIL() << "Exception expected";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), std::string("PSROIPooling expects 2 dimensions for box coordinates"));
} catch (...) {
FAIL() << "Unknown exception was thrown";
}
TEST_F(TypePropPSROIPoolingV0, invalid_rois_rank) {
const auto inputs = std::make_shared<Parameter>(element::f32, Shape{1, 72, 4, 2});
const auto coords = std::make_shared<Parameter>(element::f32, Shape{150});
OV_EXPECT_THROW(auto op = make_op(inputs, coords, 2, 6, spatial_scale, bin_not_used, bin_not_used, "average"),
NodeValidationFailure,
HasSubstr("Expected a 2D tensor for the ROIs input with box coordinates"));
}
TEST(type_prop, psroi_pooling_invalid_group_size) {
try {
auto inputs = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{1, 72, 5, 5});
auto coords = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{150, 5});
auto op = std::make_shared<op::PSROIPooling>(inputs, coords, 2, 0, 1.0f, 0, 0, "average");
FAIL() << "Exception expected";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), std::string("group_size has to be greater than 0"));
} catch (...) {
FAIL() << "Unknown exception was thrown";
TEST_F(TypePropPSROIPoolingV0, invalid_group_size) {
const auto inputs = std::make_shared<Parameter>(element::f32, Shape{1, 72, 4, 2});
const auto coords = std::make_shared<Parameter>(element::f32, Shape{150, 5});
OV_EXPECT_THROW(auto op = make_op(inputs, coords, 2, 0, spatial_scale, bin_not_used, bin_not_used, "average"),
NodeValidationFailure,
HasSubstr("group_size has to be greater than 0"));
}
try {
auto inputs = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{1, 72, 5, 5});
auto coords = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{150, 5});
auto op = std::make_shared<op::PSROIPooling>(inputs, coords, 2, 5, 1.0f, 0, 0, "average");
FAIL() << "Exception expected";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(),
std::string("Number of input's channels must be a multiply of group_size * group_size"));
} catch (...) {
FAIL() << "Unknown exception was thrown";
}
TEST_F(TypePropPSROIPoolingV0, invalid_number_of_channels_and_group_size_in_avg_mode) {
const auto inputs = std::make_shared<Parameter>(element::f32, Shape{1, 72, 4, 2});
const auto coords = std::make_shared<Parameter>(element::f32, Shape{150, 5});
OV_EXPECT_THROW(auto op = make_op(inputs, coords, 2, 5, spatial_scale, bin_not_used, bin_not_used, "average"),
NodeValidationFailure,
HasSubstr("Number of input's channels must be a multiply of output_dim * group_size * group_size"));
}
TEST(type_prop, psroi_pooling_invalid_output_dim) {
try {
auto inputs = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{1, 72, 5, 5});
auto coords = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{150, 5});
auto op = std::make_shared<op::PSROIPooling>(inputs, coords, 17, 2, 1.0f, 0, 0, "average");
FAIL() << "Exception expected";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(
error.what(),
std::string("output_dim must be equal to input channels divided by group_size * group_size"));
} catch (...) {
FAIL() << "Unknown exception was thrown";
}
TEST_F(TypePropPSROIPoolingV0, invalid_output_dim_in_avg_mode) {
const auto inputs = std::make_shared<Parameter>(element::f32, Shape{1, 72, 4, 2});
const auto coords = std::make_shared<Parameter>(element::f32, Shape{150, 5});
OV_EXPECT_THROW(auto op = make_op(inputs, coords, 17, 2, spatial_scale, bin_not_used, bin_not_used, "average"),
NodeValidationFailure,
HasSubstr("Number of input's channels must be a multiply of output_dim * group_size * group_size"));
}
TEST(type_prop, psroi_pooling_invalid_spatial_bins) {
try {
auto inputs = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{1, 72, 5, 5});
auto coords = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{150, 5});
auto op = std::make_shared<op::PSROIPooling>(inputs, coords, 17, 2, 1.0f, 0, 0, "bilinear");
FAIL() << "Exception expected";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), std::string("spatial_bins_x has to be greater than 0"));
} catch (...) {
FAIL() << "Unknown exception was thrown";
TEST_F(TypePropPSROIPoolingV0, invalid_spatial_bins_x) {
const auto inputs = std::make_shared<Parameter>(element::f32, Shape{1, 72, 5, 5});
const auto coords = std::make_shared<Parameter>(element::f32, Shape{150, 5});
OV_EXPECT_THROW(auto op = make_op(inputs, coords, 17, 2, spatial_scale, 0, 1, "bilinear"),
NodeValidationFailure,
HasSubstr("spatial_bins_x has to be greater than 0"));
}
try {
auto inputs = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{1, 72, 5, 5});
auto coords = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{150, 5});
auto op = std::make_shared<op::PSROIPooling>(inputs, coords, 17, 2, 1.0f, 1, 0, "bilinear");
FAIL() << "Exception expected";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), std::string("spatial_bins_y has to be greater than 0"));
} catch (...) {
FAIL() << "Unknown exception was thrown";
TEST_F(TypePropPSROIPoolingV0, invalid_spatial_bins_y) {
const auto inputs = std::make_shared<Parameter>(element::f32, Shape{1, 72, 5, 5});
const auto coords = std::make_shared<Parameter>(element::f32, Shape{150, 5});
OV_EXPECT_THROW(auto op = make_op(inputs, coords, 17, 2, spatial_scale, 1, 0, "bilinear"),
NodeValidationFailure,
HasSubstr("spatial_bins_y has to be greater than 0"));
}
try {
auto inputs = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{1, 72, 5, 5});
auto coords = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{150, 5});
auto op = std::make_shared<op::PSROIPooling>(inputs, coords, 17, 2, 1.0f, 2, 5, "bilinear");
FAIL() << "Exception expected";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(),
std::string("Number of input's channels must be a multiply of "
"spatial_bins_x * spatial_bins_y"));
} catch (...) {
FAIL() << "Unknown exception was thrown";
TEST_F(TypePropPSROIPoolingV0, invalid_number_of_channels_and_spatial_bins_in_bilinear_mode) {
const auto inputs = std::make_shared<Parameter>(element::f32, Shape{1, 72, 5, 5});
const auto coords = std::make_shared<Parameter>(element::f32, Shape{150, 5});
OV_EXPECT_THROW(
auto op = make_op(inputs, coords, 17, 2, spatial_scale, 2, 5, "bilinear"),
NodeValidationFailure,
HasSubstr("Number of input's channels must be a multiply of output_dim * spatial_bins_x * spatial_bins_y"));
}
try {
auto inputs = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{1, 72, 5, 5});
auto coords = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{150, 5});
auto op = std::make_shared<op::PSROIPooling>(inputs, coords, 10, 2, 1.0f, 2, 4, "bilinear");
FAIL() << "Exception expected";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(),
std::string("output_dim must be equal to input channels divided by "
"spatial_bins_x * spatial_bins_y"));
} catch (...) {
FAIL() << "Unknown exception was thrown";
}
TEST_F(TypePropPSROIPoolingV0, invalid_output_dim_in_bilinear_mode) {
const auto inputs = std::make_shared<Parameter>(element::f32, Shape{1, 72, 5, 5});
const auto coords = std::make_shared<Parameter>(element::f32, Shape{150, 5});
OV_EXPECT_THROW(
auto op = make_op(inputs, coords, 10, 2, spatial_scale, 2, 4, "bilinear"),
NodeValidationFailure,
HasSubstr("Number of input's channels must be a multiply of output_dim * spatial_bins_x * spatial_bins_y"));
}
TEST(type_prop, psroi_pooling_dynamic_ranks) {
{
auto inputs = std::make_shared<op::Parameter>(element::Type_t::f32, PartialShape::dynamic());
auto coords = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{150, 5});
auto op = std::make_shared<op::PSROIPooling>(inputs, coords, 2, 6, 0.0625f, 0, 0, "average");
ASSERT_EQ(op->get_output_partial_shape(0), PartialShape::dynamic());
ASSERT_EQ(op->get_element_type(), element::Type_t::f32);
}
{
auto inputs = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{1, 72, 4, 5});
auto coords = std::make_shared<op::Parameter>(element::Type_t::f32, PartialShape::dynamic());
auto op = std::make_shared<op::PSROIPooling>(inputs, coords, 2, 6, 0.0625f, 0, 0, "average");
ASSERT_EQ(op->get_output_partial_shape(0), PartialShape::dynamic());
ASSERT_EQ(op->get_element_type(), element::Type_t::f32);
}
TEST_F(TypePropPSROIPoolingV0, features_dynamic_rank) {
auto coords_shape = PartialShape{150, 5};
set_shape_labels(coords_shape, 20);
const auto inputs = std::make_shared<Parameter>(element::f16, PartialShape::dynamic());
const auto coords = std::make_shared<Parameter>(element::f16, coords_shape);
const auto op = make_op(inputs, coords, 2, 6, spatial_scale, 0, 0, "average");
EXPECT_EQ(op->get_element_type(), element::f16);
EXPECT_EQ(op->get_output_partial_shape(0), PartialShape({150, 2, 6, 6})); // 4d
EXPECT_THAT(get_shape_labels(op->get_output_partial_shape(0)),
ElementsAre(20, ov::no_label, ov::no_label, ov::no_label));
}
TEST(type_prop, psroi_pooling_dynamic_num_boxes) {
auto inputs = std::make_shared<op::Parameter>(element::Type_t::f32, Shape{1, 72, 4, 5});
auto coords = std::make_shared<op::Parameter>(element::Type_t::f32, PartialShape{{Dimension::dynamic(), 5}});
auto op = std::make_shared<op::PSROIPooling>(inputs, coords, 2, 6, 0.0625f, 0, 0, "average");
ASSERT_EQ(op->get_output_partial_shape(0), (PartialShape{{Dimension::dynamic(), 2, 6, 6}}));
ASSERT_EQ(op->get_element_type(), element::Type_t::f32);
TEST_F(TypePropPSROIPoolingV0, rois_dynamic_rank) {
auto feat_shape = PartialShape{1, 72, 4, 5};
set_shape_labels(feat_shape, 10);
const auto inputs = std::make_shared<Parameter>(element::f16, feat_shape);
const auto coords = std::make_shared<Parameter>(element::f16, PartialShape::dynamic());
const auto op = make_op(inputs, coords, 2, 6, spatial_scale, 0, 0, "average");
EXPECT_EQ(op->get_element_type(), element::f16);
EXPECT_EQ(op->get_output_partial_shape(0), PartialShape({-1, 2, 6, 6}));
EXPECT_THAT(get_shape_labels(op->get_output_partial_shape(0)), Each(ov::no_label));
}
TEST(type_prop, psroi_pooling_static_rank_dynamic_shape) {
{
auto inputs = std::make_shared<op::Parameter>(
element::Type_t::f32,
PartialShape{{Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()}});
auto coords = std::make_shared<op::Parameter>(element::Type_t::f32,
PartialShape{{Dimension::dynamic(), Dimension::dynamic()}});
auto op = std::make_shared<op::PSROIPooling>(inputs, coords, 2, 6, 0.0625f, 0, 0, "average");
ASSERT_EQ(op->get_output_partial_shape(0), (PartialShape{{Dimension::dynamic(), 2, 6, 6}}));
ASSERT_EQ(op->get_element_type(), element::Type_t::f32);
TEST_F(TypePropPSROIPoolingV0, dynamic_num_boxes) {
auto coords_shape = PartialShape{{Dimension::dynamic(), 5}};
set_shape_labels(coords_shape, 20);
const auto inputs = std::make_shared<Parameter>(element::f16, PartialShape::dynamic());
const auto coords = std::make_shared<Parameter>(element::f16, coords_shape);
const auto op = make_op(inputs, coords, 2, 6, spatial_scale, 0, 0, "average");
EXPECT_EQ(op->get_element_type(), element::f16);
EXPECT_EQ(op->get_output_partial_shape(0), PartialShape({-1, 2, 6, 6}));
EXPECT_THAT(get_shape_labels(op->get_output_partial_shape(0)),
ElementsAre(20, ov::no_label, ov::no_label, ov::no_label));
}
{
auto inputs = std::make_shared<op::Parameter>(
element::Type_t::f32,
PartialShape{{Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()}});
auto coords = std::make_shared<op::Parameter>(element::Type_t::f32, PartialShape{{200, Dimension::dynamic()}});
auto op = std::make_shared<op::PSROIPooling>(inputs, coords, 2, 6, 0.0625f, 0, 0, "average");
ASSERT_EQ(op->get_shape(), (Shape{200, 2, 6, 6}));
ASSERT_EQ(op->get_element_type(), element::Type_t::f32);
TEST_F(TypePropPSROIPoolingV0, feat_static_rank_dynamic_shape) {
auto feat_shape = PartialShape::dynamic(4);
auto coords_shape = PartialShape{{Dimension::dynamic(), 5}};
set_shape_labels(feat_shape, 10);
set_shape_labels(coords_shape, 20);
const auto inputs = std::make_shared<Parameter>(element::f16, feat_shape);
const auto coords = std::make_shared<Parameter>(element::f16, coords_shape);
const auto op = make_op(inputs, coords, 2, 6, spatial_scale, 0, 0, "average");
EXPECT_EQ(op->get_element_type(), element::f16);
EXPECT_EQ(op->get_output_partial_shape(0), PartialShape({-1, 2, 6, 6})); // 4d
EXPECT_THAT(get_shape_labels(op->get_output_partial_shape(0)),
ElementsAre(20, ov::no_label, ov::no_label, ov::no_label));
}
TEST_F(TypePropPSROIPoolingV0, feat_and_rois_static_rank_dynamic_shape) {
auto feat_shape = PartialShape::dynamic(4);
auto coords_shape = PartialShape::dynamic(2);
set_shape_labels(feat_shape, 10);
set_shape_labels(coords_shape, 20);
const auto inputs = std::make_shared<Parameter>(element::f16, feat_shape);
const auto coords = std::make_shared<Parameter>(element::f16, coords_shape);
const auto op = make_op(inputs, coords, 2, 6, spatial_scale, 0, 0, "average");
EXPECT_EQ(op->get_element_type(), element::f16);
EXPECT_EQ(op->get_output_partial_shape(0), PartialShape({-1, 2, 6, 6})); // 4d
EXPECT_THAT(get_shape_labels(op->get_output_partial_shape(0)),
ElementsAre(20, ov::no_label, ov::no_label, ov::no_label));
}
TEST_F(TypePropPSROIPoolingV0, feat_and_rois_interval_shapes) {
auto feat_shape = PartialShape{{1, 2}, {10, 100}, {10, 20}, {30, 90}};
auto coords_shape = PartialShape{{3, 10}, {1, 5}};
set_shape_labels(feat_shape, 10);
set_shape_labels(coords_shape, 20);
const auto inputs = std::make_shared<Parameter>(element::f16, feat_shape);
const auto coords = std::make_shared<Parameter>(element::f16, coords_shape);
const auto op = make_op(inputs, coords, 2, 6, spatial_scale, 0, 0, "average");
EXPECT_EQ(op->get_element_type(), element::f16);
EXPECT_EQ(op->get_output_partial_shape(0), PartialShape({{3, 10}, 2, 6, 6})); // 4d
EXPECT_THAT(get_shape_labels(op->get_output_partial_shape(0)),
ElementsAre(20, ov::no_label, ov::no_label, ov::no_label));
}
TEST_F(TypePropPSROIPoolingV0, default_ctor) {
auto feat_shape = PartialShape{2, {10, 100}, 10, 10};
auto coords_shape = PartialShape{{3, 10}, {1, 5}};
set_shape_labels(feat_shape, 10);
set_shape_labels(coords_shape, 20);
const auto inputs = std::make_shared<Parameter>(element::f16, feat_shape);
const auto coords = std::make_shared<Parameter>(element::f16, coords_shape);
const auto op = make_op();
op->set_arguments(OutputVector{inputs, coords});
op->set_output_dim(2);
op->set_group_size(6);
op->set_spatial_scale(spatial_scale);
op->set_mode("average");
op->validate_and_infer_types();
EXPECT_FLOAT_EQ(op->get_spatial_scale(), spatial_scale);
EXPECT_EQ(op->get_mode(), "average");
EXPECT_EQ(op->get_group_size(), 6);
EXPECT_EQ(op->get_input_size(), 2);
EXPECT_EQ(op->get_output_size(), 1);
EXPECT_EQ(op->get_element_type(), element::f16);
EXPECT_EQ(op->get_output_partial_shape(0), PartialShape({{3, 10}, 2, 6, 6})); // 4d
EXPECT_THAT(get_shape_labels(op->get_output_partial_shape(0)),
ElementsAre(20, ov::no_label, ov::no_label, ov::no_label));
}

View File

@ -53,6 +53,7 @@
#include "one_hot_shape_inference.hpp"
#include "pad_shape_inference.hpp"
#include "proposal_shape_inference.hpp"
#include "psroi_pooling_shape_inference.hpp"
#include "range_shape_inference.hpp"
#include "rdft_shape_inference.hpp"
#include "read_value_shape_inference.hpp"
@ -589,6 +590,7 @@ const IShapeInferCommonFactory::TRegistry IShapeInferCommonFactory::registry{
_OV_OP_SHAPE_INFER_REG(ov::op::internal::AUGRUSequence, entryIO),
_OV_OP_SHAPE_INFER_REG(Pad, entryIOC),
_OV_OP_SHAPE_INFER_REG(Proposal, entryIO),
_OV_OP_SHAPE_INFER_REG(PSROIPooling, entryIO),
_OV_OP_SHAPE_INFER_REG(Range, entryIOC),
_OV_OP_SHAPE_INFER_REG(RDFT, entryIOC),
_OV_OP_SHAPE_INFER_REG(ReadValue, entryIO),

View File

@ -0,0 +1,97 @@
// Copyright (C) 2018-2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <gmock/gmock.h>
#include "common_test_utils/test_assertions.hpp"
#include "openvino/opsets/opset11.hpp"
#include "utils.hpp"
using namespace ov;
using namespace ov::intel_cpu;
using namespace testing;
class PSROIPoolingV0StaticShapeInferenceTest : public OpStaticShapeInferenceTest<op::v0::PSROIPooling> {
protected:
void SetUp() override {
output_shapes.resize(1);
}
float scale = 0.45f;
size_t group = 3;
int bins_x = 4;
int bins_y = 3;
};
TEST_F(PSROIPoolingV0StaticShapeInferenceTest, default_ctor_avg_mode) {
op = make_op();
op->set_output_dim(5);
op->set_group_size(3);
op->set_spatial_scale(scale);
op->set_mode("average");
input_shapes = ShapeVector{{1, 45, 10, 10}, {3, 5}};
auto shape_infer = make_shape_inference(op);
shape_inference(op.get(), input_shapes, output_shapes);
EXPECT_EQ(output_shapes.size(), 1);
EXPECT_EQ(output_shapes.front(), StaticShape({3, 5, 3, 3}));
}
TEST_F(PSROIPoolingV0StaticShapeInferenceTest, default_ctor_bilinear_mode) {
op = make_op();
op->set_output_dim(5);
op->set_group_size(8);
op->set_spatial_bins_x(5);
op->set_spatial_bins_y(3);
op->set_spatial_scale(scale);
op->set_mode("bilinear");
input_shapes = ShapeVector{{1, 75, 10, 10}, {2, 5}};
auto shape_infer = make_shape_inference(op);
shape_inference(op.get(), input_shapes, output_shapes);
EXPECT_EQ(output_shapes.size(), 1);
EXPECT_EQ(output_shapes.front(), StaticShape({2, 5, 8, 8}));
}
TEST_F(PSROIPoolingV0StaticShapeInferenceTest, inputs_dynamic_rank) {
const auto feat = std::make_shared<op::v0::Parameter>(element::f64, PartialShape::dynamic());
const auto rois = std::make_shared<op::v0::Parameter>(element::f64, PartialShape::dynamic());
op = make_op(feat, rois, 4, group, scale, 0, 0, "average");
input_shapes = ShapeVector{{2, 36, 100, 100}, {10, 5}};
shape_inference(op.get(), input_shapes, output_shapes);
EXPECT_EQ(output_shapes.size(), 1);
EXPECT_EQ(output_shapes.front(), StaticShape({10, 4, 3, 3}));
}
TEST_F(PSROIPoolingV0StaticShapeInferenceTest, inputs_static_rank) {
const auto feat = std::make_shared<op::v0::Parameter>(element::f64, PartialShape::dynamic(4));
const auto rois = std::make_shared<op::v0::Parameter>(element::f64, PartialShape::dynamic(2));
op = make_op(feat, rois, 2, 1, scale, bins_x, bins_y, "bilinear");
input_shapes = ShapeVector{{2, 24, 20, 100}, {1, 5}};
shape_inference(op.get(), input_shapes, output_shapes);
EXPECT_EQ(output_shapes.size(), 1);
EXPECT_EQ(output_shapes.front(), StaticShape({1, 2, 1, 1}));
}
TEST_F(PSROIPoolingV0StaticShapeInferenceTest, invalid_rois_batch_size) {
const auto feat = std::make_shared<op::v0::Parameter>(element::f64, PartialShape::dynamic(4));
const auto rois = std::make_shared<op::v0::Parameter>(element::f64, PartialShape::dynamic());
op = make_op(feat, rois, 2, 1, scale, bins_x, bins_y, "bilinear");
input_shapes = ShapeVector{{2, 24, 20, 100}, {1, 6}};
OV_EXPECT_THROW(shape_inference(op.get(), input_shapes, output_shapes),
NodeValidationFailure,
HasSubstr("The second dimension of ROIs input should contain batch id and box coordinates. This "
"dimension is expected to be equal to 5"));
}