[Op]: Added definition of ROIAlignRotated. (#23462)

### Details:
 - Added ROIAlignRotated definition to core
- Refactored tests of ROIAlign shape inference info - to use the same
tests for ROIAlignRotated

### Tickets:
 - *CVS-115297*

---------

Co-authored-by: Pawel Raasz <pawel.raasz@intel.com>
Co-authored-by: Michal Lukaszewski <michal.lukaszewski@intel.com>
This commit is contained in:
Piotr Kowalczyk 2024-04-24 10:25:28 +02:00 committed by GitHub
parent 08c3b7ff6e
commit bb2de2f3d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 496 additions and 293 deletions

View File

@ -157,6 +157,7 @@
#include "openvino/op/rnn_cell.hpp"
#include "openvino/op/rnn_sequence.hpp"
#include "openvino/op/roi_align.hpp"
#include "openvino/op/roi_align_rotated.hpp"
#include "openvino/op/roi_pooling.hpp"
#include "openvino/op/roll.hpp"
#include "openvino/op/round.hpp"

View File

@ -4,7 +4,7 @@
#pragma once
#include "openvino/op/op.hpp"
#include "openvino/op/util/roi_align_base.hpp"
namespace ov {
namespace op {
@ -12,23 +12,15 @@ namespace v3 {
/// \brief ROIAlign operation.
///
/// \ingroup ov_ops_cpp_api
class OPENVINO_API ROIAlign : public Op {
class OPENVINO_API ROIAlign : public util::ROIAlignBase {
public:
OPENVINO_OP("ROIAlign", "opset3", op::Op);
OPENVINO_OP("ROIAlign", "opset3", util::ROIAlignBase);
enum class PoolingMode { AVG, MAX };
ROIAlign() = default;
/// \brief Constructs a ROIAlign node matching the ONNX ROIAlign specification
/// Check util::ROIAlignBase for description of common params.
///
/// \param input Input feature map {N, C, H, W}
/// \param rois Regions of interest to pool over
/// \param batch_indices Indices of images in the batch matching
/// the number or ROIs
/// \param pooled_h Height of the ROI output features
/// \param pooled_w Width of the ROI output features
/// \param sampling_ratio Number of sampling points used to compute
/// an output element
/// \param spatial_scale Spatial scale factor used to translate ROI coordinates
/// \param mode Method of pooling - 'avg' or 'max'
ROIAlign(const Output<Node>& input,
const Output<Node>& rois,
@ -52,35 +44,8 @@ public:
bool visit_attributes(AttributeVisitor& visitor) override;
std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override;
int get_pooled_h() const {
return m_pooled_h;
}
void set_pooled_h(const int h) {
m_pooled_h = h;
}
int get_pooled_w() const {
return m_pooled_w;
}
void set_pooled_w(const int w) {
m_pooled_w = w;
}
int get_sampling_ratio() const {
return m_sampling_ratio;
}
void set_sampling_ratio(const int ratio) {
m_sampling_ratio = ratio;
}
float get_spatial_scale() const {
return m_spatial_scale;
}
void set_spatial_scale(const float scale) {
m_spatial_scale = scale;
int get_rois_input_second_dim_size() const override {
return 4;
}
PoolingMode get_mode() const {
@ -98,24 +63,19 @@ private:
PoolingMode mode_from_string(const std::string& mode) const;
private:
int m_pooled_h;
int m_pooled_w;
int m_sampling_ratio;
float m_spatial_scale;
PoolingMode m_mode;
};
} // namespace v3
namespace v9 {
class OPENVINO_API ROIAlign : public Op {
class OPENVINO_API ROIAlign : public util::ROIAlignBase {
public:
OPENVINO_OP("ROIAlign", "opset9");
OPENVINO_OP("ROIAlign", "opset9", util::ROIAlignBase);
enum class PoolingMode { AVG, MAX };
enum class AlignedMode { ASYMMETRIC, HALF_PIXEL_FOR_NN, HALF_PIXEL };
ROIAlign() = default;
/// \brief Constructs a ROIAlign operation.
///
/// \param input Input feature map {N, C, H, W}
/// \param rois Regions of interest to pool over
/// \param batch_indices Indices of images in the batch matching
@ -125,6 +85,7 @@ public:
/// \param sampling_ratio Number of sampling points used to compute
/// an output element
/// \param spatial_scale Spatial scale factor used to translate ROI coordinates
///
/// \param mode Method of pooling - 'avg' or 'max'
/// \param aligned_mode Method of coordinates alignment - 'asymmetric', 'half_pixel_for_nn' or 'half_pixel'
ROIAlign(const Output<Node>& input,
@ -141,35 +102,8 @@ public:
bool visit_attributes(AttributeVisitor& visitor) override;
std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override;
int get_pooled_h() const {
return m_pooled_h;
}
void set_pooled_h(const int h) {
m_pooled_h = h;
}
int get_pooled_w() const {
return m_pooled_w;
}
void set_pooled_w(const int w) {
m_pooled_w = w;
}
int get_sampling_ratio() const {
return m_sampling_ratio;
}
void set_sampling_ratio(const int ratio) {
m_sampling_ratio = ratio;
}
float get_spatial_scale() const {
return m_spatial_scale;
}
void set_spatial_scale(const float scale) {
m_spatial_scale = scale;
int get_rois_input_second_dim_size() const override {
return 4;
}
PoolingMode get_mode() const {
@ -190,10 +124,6 @@ public:
private:
PoolingMode mode_from_string(const std::string& mode) const;
int m_pooled_h;
int m_pooled_w;
int m_sampling_ratio;
float m_spatial_scale;
PoolingMode m_mode;
AlignedMode m_aligned_mode;
};

View File

@ -0,0 +1,62 @@
// Copyright (C) 2018-2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include "openvino/op/util/roi_align_base.hpp"
namespace ov {
namespace op {
namespace v14 {
/// \brief ROIAlignRotated operation.
///
/// \ingroup ov_ops_cpp_api
class OPENVINO_API ROIAlignRotated : public util::ROIAlignBase {
public:
OPENVINO_OP("ROIAlignRotated", "opset14", util::ROIAlignBase);
ROIAlignRotated() = default;
/// \brief Constructs a ROIAlignRotated operation.
/// \param input Input feature map {N, C, H, W}
/// \param rois Regions of interest to pool over
/// \param batch_indices Indices of images in the batch matching
/// the number or ROIs
/// \param pooled_h Height of the ROI output features
/// \param pooled_w Width of the ROI output features
/// \param sampling_ratio Number of sampling points used to compute
/// an output element
/// \param spatial_scale Spatial scale factor used to translate ROI coordinates
///
/// \param clockwise_mode If true, rotation angle is interpreted as clockwise, otherwise as counterclockwise
ROIAlignRotated(const Output<Node>& input,
const Output<Node>& rois,
const Output<Node>& batch_indices,
const int pooled_h,
const int pooled_w,
const int sampling_ratio,
const float spatial_scale,
const bool clockwise_mode);
void validate_and_infer_types() override;
bool visit_attributes(AttributeVisitor& visitor) override;
std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override;
int get_rois_input_second_dim_size() const override {
return 5;
}
bool get_clockwise_mode() const {
return m_clockwise_mode;
}
void set_clockwise_mode(const bool clockwise_mode) {
m_clockwise_mode = clockwise_mode;
}
private:
bool m_clockwise_mode;
};
} // namespace v14
} // namespace op
} // namespace ov

View File

@ -0,0 +1,90 @@
// Copyright (C) 2018-2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include "openvino/op/op.hpp"
namespace ov {
namespace op {
namespace util {
///
/// \brief Base class for ROIAlignXXX operators.
///
class OPENVINO_API ROIAlignBase : public Op {
public:
OPENVINO_OP("ROIAlignBase", "util");
protected:
ROIAlignBase() = default;
/// \brief Constructs a ROIAlignBase operation.
///
/// \param input Input feature map {N, C, H, W}
/// \param rois Regions of interest to pool over
/// \param batch_indices Indices of images in the batch matching
/// the number or ROIs
/// \param pooled_h Height of the ROI output features
/// \param pooled_w Width of the ROI output features
/// \param sampling_ratio Number of sampling points used to compute
/// an output element
/// \param spatial_scale Spatial scale factor used to translate ROI coordinates
ROIAlignBase(const Output<Node>& input,
const Output<Node>& rois,
const Output<Node>& batch_indices,
const int pooled_h,
const int pooled_w,
const int sampling_ratio,
const float spatial_scale);
public:
// Return size of second dimension of the ROI input.
// Needed for validation check.
virtual int get_rois_input_second_dim_size() const = 0;
void validate_and_infer_types() override;
bool visit_attributes(AttributeVisitor& visitor) override;
int get_pooled_h() const {
return m_pooled_h;
}
void set_pooled_h(const int h) {
m_pooled_h = h;
}
int get_pooled_w() const {
return m_pooled_w;
}
void set_pooled_w(const int w) {
m_pooled_w = w;
}
int get_sampling_ratio() const {
return m_sampling_ratio;
}
void set_sampling_ratio(const int ratio) {
m_sampling_ratio = ratio;
}
float get_spatial_scale() const {
return m_spatial_scale;
}
void set_spatial_scale(const float scale) {
m_spatial_scale = scale;
}
private:
int m_pooled_h;
int m_pooled_w;
int m_sampling_ratio;
float m_spatial_scale;
};
} // namespace util
} // namespace op
} // namespace ov

View File

@ -0,0 +1,19 @@
// Copyright (C) 2018-2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include "roi_align_shape_utils.hpp"
namespace ov {
namespace op {
namespace v14 {
class ROIAlignRotated;
template <class TShape, class TRShape = result_shape_t<TShape>>
std::vector<TRShape> shape_infer(const ROIAlignRotated* op, const std::vector<TShape>& input_shapes) {
return roi_align::shape_infer<TShape, TRShape>(op, input_shapes);
}
} // namespace v14
} // namespace op
} // namespace ov

View File

@ -4,115 +4,23 @@
#pragma once
#include <openvino/op/roi_align.hpp>
#include "utils.hpp"
#include "openvino/op/roi_align.hpp"
#include "roi_align_shape_utils.hpp"
namespace ov {
namespace op {
namespace roi_align {
namespace validate {
/**
* @brief Validates ROIs align input data and ROIs element type.
*
* @param op Pointer to ROIs align node.
* @return Valid ROIs align output element type.
*/
inline element::Type data_and_roi_et(const Node* const op) {
auto out_et = element::dynamic;
const auto& input_et = op->get_input_element_type(0);
const auto& rois_et = op->get_input_element_type(1);
NODE_VALIDATION_CHECK(op,
element::Type::merge(out_et, input_et, rois_et) && out_et.is_real(),
"The data type for input and ROIs is expected to be a same floating point type. Got: ",
input_et,
" and: ",
rois_et);
return out_et;
}
/**
* @brief Check ROIs align batch indicies input element type.
*
* @param op Pointer to ROIs align node.
*/
inline void batch_indicies_et(const Node* const op) {
const auto& indicies_et = op->get_input_element_type(2);
NODE_VALIDATION_CHECK(op,
indicies_et.is_integral_number(),
"The data type for batch indices is expected to be an integer. Got: ",
indicies_et);
}
} // namespace validate
template <class OpType, class TShape, class TRShape = result_shape_t<TShape>>
std::vector<TRShape> shape_infer(const OpType* op, const std::vector<TShape>& input_shapes) {
NODE_VALIDATION_CHECK(op, input_shapes.size() == 3);
using TDim = typename TShape::value_type;
const auto& input_ps = input_shapes[0];
const auto& rois_ps = input_shapes[1];
const auto& batch_indices_ps = input_shapes[2];
const auto rois_ps_rank = rois_ps.rank();
const auto input_ps_rank = input_ps.rank();
const auto batch_indices_ps_rank = batch_indices_ps.rank();
auto output_shapes = std::vector<TRShape>(1);
auto& out_shape = output_shapes.front();
out_shape.reserve(4);
NODE_VALIDATION_CHECK(op, input_ps_rank.compatible(4), "Expected a 4D tensor for the input data. Got: ", input_ps);
NODE_VALIDATION_CHECK(op, rois_ps_rank.compatible(2), "Expected a 2D tensor for the ROIs input. Got: ", rois_ps);
NODE_VALIDATION_CHECK(op,
batch_indices_ps_rank.compatible(1),
"Expected a 1D tensor for the batch indices input. Got: ",
batch_indices_ps);
if (rois_ps_rank.is_static()) {
const auto& rois_second_dim = rois_ps[1];
NODE_VALIDATION_CHECK(op,
rois_second_dim.compatible(4),
"The second dimension of ROIs input should contain box coordinates. ",
"op dimension is expected to be equal to 4. Got: ",
rois_second_dim);
out_shape.push_back(rois_ps[0]);
} else {
out_shape.push_back(Dimension::dynamic());
}
NODE_VALIDATION_CHECK(
op,
batch_indices_ps_rank.is_dynamic() || TDim::merge(out_shape[0], batch_indices_ps[0], out_shape[0]),
"The first dimension of ROIs input must be equal to the first dimension of the batch indices input. Got: ",
out_shape[0],
" and: ",
batch_indices_ps[0]);
out_shape.push_back(input_ps_rank.is_static() ? input_ps[1] : Dimension::dynamic());
out_shape.emplace_back(static_cast<typename TDim::value_type>(op->get_pooled_h()));
out_shape.emplace_back(static_cast<typename TDim::value_type>(op->get_pooled_w()));
return output_shapes;
}
} // namespace roi_align
namespace v3 {
template <class TShape, class TRShape = result_shape_t<TShape>>
std::vector<TRShape> shape_infer(const ROIAlign* op, const std::vector<TShape>& input_shapes) {
return roi_align::shape_infer(op, input_shapes);
return roi_align::shape_infer<TShape, TRShape>(op, input_shapes);
}
} // namespace v3
namespace v9 {
template <class TShape, class TRShape = result_shape_t<TShape>>
std::vector<TRShape> shape_infer(const ROIAlign* op, const std::vector<TShape>& input_shapes) {
return roi_align::shape_infer(op, input_shapes);
return roi_align::shape_infer<TShape, TRShape>(op, input_shapes);
}
} // namespace v9
} // namespace op

View File

@ -0,0 +1,106 @@
// Copyright (C) 2018-2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <openvino/op/util/roi_align_base.hpp>
#include "utils.hpp"
namespace ov {
namespace op {
namespace roi_align {
namespace validate {
/**
* @brief Validates ROIs align input data and ROIs element type.
*
* @param op Pointer to ROIs align node.
* @return Valid ROIs align output element type.
*/
inline element::Type data_and_roi_et(const Node* const op) {
auto out_et = element::dynamic;
const auto& input_et = op->get_input_element_type(0);
const auto& rois_et = op->get_input_element_type(1);
NODE_VALIDATION_CHECK(op,
element::Type::merge(out_et, input_et, rois_et) && out_et.is_real(),
"The data type for input and ROIs is expected to be a same floating point type. Got: ",
input_et,
" and: ",
rois_et);
return out_et;
}
/**
* @brief Check ROIs align batch indicies input element type.
*
* @param op Pointer to ROIs align node.
*/
inline void batch_indicies_et(const Node* const op) {
const auto& indicies_et = op->get_input_element_type(2);
NODE_VALIDATION_CHECK(op,
indicies_et.is_integral_number(),
"The data type for batch indices is expected to be an integer. Got: ",
indicies_et);
}
} // namespace validate
template <class TShape, class TRShape = result_shape_t<TShape>>
std::vector<TRShape> shape_infer(const util::ROIAlignBase* op, const std::vector<TShape>& input_shapes) {
NODE_VALIDATION_CHECK(op, input_shapes.size() == 3);
using TDim = typename TShape::value_type;
const auto& input_ps = input_shapes[0];
const auto& rois_ps = input_shapes[1];
const auto& batch_indices_ps = input_shapes[2];
const auto rois_ps_rank = rois_ps.rank();
const auto input_ps_rank = input_ps.rank();
const auto batch_indices_ps_rank = batch_indices_ps.rank();
auto output_shapes = std::vector<TRShape>(1);
auto& out_shape = output_shapes.front();
out_shape.reserve(4);
NODE_VALIDATION_CHECK(op, input_ps_rank.compatible(4), "Expected a 4D tensor for the input data. Got: ", input_ps);
NODE_VALIDATION_CHECK(op, rois_ps_rank.compatible(2), "Expected a 2D tensor for the ROIs input. Got: ", rois_ps);
NODE_VALIDATION_CHECK(op,
batch_indices_ps_rank.compatible(1),
"Expected a 1D tensor for the batch indices input. Got: ",
batch_indices_ps);
if (rois_ps_rank.is_static()) {
const auto& rois_second_dim = rois_ps[1];
NODE_VALIDATION_CHECK(op,
rois_second_dim.compatible(op->get_rois_input_second_dim_size()),
"The second dimension of ROIs input should contain box coordinates. "
"op dimension is expected to be equal to ",
op->get_rois_input_second_dim_size(),
". Got: ",
rois_second_dim);
out_shape.push_back(rois_ps[0]);
} else {
out_shape.push_back(Dimension::dynamic());
}
NODE_VALIDATION_CHECK(
op,
batch_indices_ps_rank.is_dynamic() || TDim::merge(out_shape[0], batch_indices_ps[0], out_shape[0]),
"The first dimension of ROIs input must be equal to the first dimension of the batch indices input. Got: ",
out_shape[0],
" and: ",
batch_indices_ps[0]);
out_shape.push_back(input_ps_rank.is_static() ? input_ps[1] : Dimension::dynamic());
out_shape.emplace_back(static_cast<typename TDim::value_type>(op->get_pooled_h()));
out_shape.emplace_back(static_cast<typename TDim::value_type>(op->get_pooled_w()));
return output_shapes;
}
} // namespace roi_align
} // namespace op
} // namespace ov

View File

@ -19,12 +19,10 @@ op::v3::ROIAlign::ROIAlign(const Output<Node>& input,
const int sampling_ratio,
const float spatial_scale,
const string& mode)
: Op{{input, rois, batch_indices}},
m_pooled_h{pooled_h},
m_pooled_w{pooled_w},
m_sampling_ratio{sampling_ratio},
m_spatial_scale{spatial_scale},
: ROIAlignBase{input, rois, batch_indices, pooled_h, pooled_w, sampling_ratio, spatial_scale},
m_mode{EnumNames<ROIAlign::PoolingMode>::as_enum(mode)} {
// NOTE: Cannot be called in base class, since then ROIAlignRotated
// is not fully constructed.
constructor_validate_and_infer_types();
}
@ -36,47 +34,21 @@ op::v3::ROIAlign::ROIAlign(const Output<Node>& input,
const int sampling_ratio,
const float spatial_scale,
const PoolingMode mode)
: Op{{input, rois, batch_indices}},
m_pooled_h{pooled_h},
m_pooled_w{pooled_w},
m_sampling_ratio{sampling_ratio},
m_spatial_scale{spatial_scale},
: ROIAlignBase{input, rois, batch_indices, pooled_h, pooled_w, sampling_ratio, spatial_scale},
m_mode{mode} {
// NOTE: Cannot be called in base class, since then ROIAlignRotated
// is not fully constructed.
constructor_validate_and_infer_types();
}
void op::v3::ROIAlign::validate_and_infer_types() {
OV_OP_SCOPE(v3_ROIAlign_validate_and_infer_types);
const auto out_et = roi_align::validate::data_and_roi_et(this);
roi_align::validate::batch_indicies_et(this);
const auto input_shapes = ov::util::get_node_input_partial_shapes(*this);
auto output_shape = shape_infer(this, input_shapes).front();
set_output_type(0, out_et, output_shape);
const auto& input_ps = input_shapes.front();
// if the channels dimension is not known
// the first input should be used during the function specialization
if (input_ps.rank().is_static() && input_ps[1].is_dynamic()) {
set_input_is_relevant_to_shape(0);
}
// if the 'NUM_ROIS' value is not known
// the last 2 inputs should be used during the function specialization
if (output_shape[0].is_dynamic()) {
set_input_is_relevant_to_shape(1);
set_input_is_relevant_to_shape(2);
}
ROIAlignBase::validate_and_infer_types();
}
bool op::v3::ROIAlign::visit_attributes(AttributeVisitor& visitor) {
OV_OP_SCOPE(v3_ROIAlign_visit_attributes);
visitor.on_attribute("pooled_h", m_pooled_h);
visitor.on_attribute("pooled_w", m_pooled_w);
visitor.on_attribute("sampling_ratio", m_sampling_ratio);
visitor.on_attribute("spatial_scale", m_spatial_scale);
ROIAlignBase::visit_attributes(visitor);
visitor.on_attribute("mode", m_mode);
return true;
@ -88,11 +60,11 @@ shared_ptr<Node> op::v3::ROIAlign::clone_with_new_inputs(const OutputVector& new
return make_shared<ROIAlign>(new_args.at(0),
new_args.at(1),
new_args.at(2),
m_pooled_h,
m_pooled_w,
m_sampling_ratio,
m_spatial_scale,
m_mode);
get_pooled_h(),
get_pooled_w(),
get_sampling_ratio(),
get_spatial_scale(),
get_mode());
}
// ------------------------------ V9 ------------------------------
@ -106,11 +78,7 @@ op::v9::ROIAlign::ROIAlign(const Output<Node>& input,
const float spatial_scale,
const PoolingMode mode,
const AlignedMode aligned_mode)
: Op{{input, rois, batch_indices}},
m_pooled_h{pooled_h},
m_pooled_w{pooled_w},
m_sampling_ratio{sampling_ratio},
m_spatial_scale{spatial_scale},
: ROIAlignBase{input, rois, batch_indices, pooled_h, pooled_w, sampling_ratio, spatial_scale},
m_mode{mode},
m_aligned_mode{aligned_mode} {
constructor_validate_and_infer_types();
@ -118,36 +86,12 @@ op::v9::ROIAlign::ROIAlign(const Output<Node>& input,
void op::v9::ROIAlign::validate_and_infer_types() {
OV_OP_SCOPE(v9_ROIAlign_validate_and_infer_types);
const auto out_et = roi_align::validate::data_and_roi_et(this);
roi_align::validate::batch_indicies_et(this);
const auto input_shapes = ov::util::get_node_input_partial_shapes(*this);
auto output_shape = shape_infer(this, input_shapes).front();
set_output_type(0, out_et, output_shape);
const auto& input_ps = input_shapes.front();
// if the channels dimension is not known
// the first input should be used during the function specialization
if (input_ps.rank().is_static() && input_ps[1].is_dynamic()) {
set_input_is_relevant_to_shape(0);
}
// if the 'NUM_ROIS' value is not known
// the last 2 inputs should be used during the function specialization
if (output_shape[0].is_dynamic()) {
set_input_is_relevant_to_shape(1);
set_input_is_relevant_to_shape(2);
}
ROIAlignBase::validate_and_infer_types();
}
bool op::v9::ROIAlign::visit_attributes(AttributeVisitor& visitor) {
OV_OP_SCOPE(v9_ROIAlign_visit_attributes);
visitor.on_attribute("pooled_h", m_pooled_h);
visitor.on_attribute("pooled_w", m_pooled_w);
visitor.on_attribute("sampling_ratio", m_sampling_ratio);
visitor.on_attribute("spatial_scale", m_spatial_scale);
ROIAlignBase::visit_attributes(visitor);
visitor.on_attribute("mode", m_mode);
visitor.on_attribute("aligned_mode", m_aligned_mode);
@ -160,12 +104,12 @@ shared_ptr<Node> op::v9::ROIAlign::clone_with_new_inputs(const OutputVector& new
return make_shared<ROIAlign>(new_args.at(0),
new_args.at(1),
new_args.at(2),
m_pooled_h,
m_pooled_w,
m_sampling_ratio,
m_spatial_scale,
m_mode,
m_aligned_mode);
get_pooled_h(),
get_pooled_w(),
get_sampling_ratio(),
get_spatial_scale(),
get_mode(),
get_aligned_mode());
}
template <>
@ -306,7 +250,13 @@ bool evaluate(const TensorVector& args,
bool v3::ROIAlign::evaluate(TensorVector& outputs, const TensorVector& inputs) const {
OV_OP_SCOPE(v3_ROIAlign_evaluate);
return roi_align::evaluate(inputs, outputs[0], m_pooled_h, m_pooled_w, m_sampling_ratio, m_spatial_scale, m_mode);
return roi_align::evaluate(inputs,
outputs[0],
get_pooled_h(),
get_pooled_w(),
get_sampling_ratio(),
get_spatial_scale(),
get_mode());
}
bool v3::ROIAlign::has_evaluate() const {

View File

@ -0,0 +1,54 @@
// Copyright (C) 2018-2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "openvino/op/roi_align_rotated.hpp"
#include "itt.hpp"
namespace ov {
namespace op {
namespace v14 {
ROIAlignRotated::ROIAlignRotated(const Output<Node>& input,
const Output<Node>& rois,
const Output<Node>& batch_indices,
const int pooled_h,
const int pooled_w,
const int sampling_ratio,
const float spatial_scale,
const bool clockwise_mode)
: ROIAlignBase{input, rois, batch_indices, pooled_h, pooled_w, sampling_ratio, spatial_scale},
m_clockwise_mode{clockwise_mode} {
// NOTE: Cannot be called in base class, since then ROIAlignRotated
// is not fully constructed.
constructor_validate_and_infer_types();
}
void ROIAlignRotated::validate_and_infer_types() {
OV_OP_SCOPE(v14_ROIAlignRotated_validate_and_infer_types);
ROIAlignBase::validate_and_infer_types();
}
bool ROIAlignRotated::visit_attributes(AttributeVisitor& visitor) {
OV_OP_SCOPE(v14_ROIAlignRotated_visit_attributes);
ROIAlignBase::visit_attributes(visitor);
visitor.on_attribute("clockwise_mode", m_clockwise_mode);
return true;
}
std::shared_ptr<Node> ROIAlignRotated::clone_with_new_inputs(const OutputVector& new_args) const {
OV_OP_SCOPE(v14_ROIAlignRotated_clone_with_new_inputs);
check_new_args_count(this, new_args);
return std::make_shared<ROIAlignRotated>(new_args.at(0),
new_args.at(1),
new_args.at(2),
get_pooled_h(),
get_pooled_w(),
get_sampling_ratio(),
get_spatial_scale(),
get_clockwise_mode());
}
} // namespace v14
} // namespace op
} // namespace ov

View File

@ -0,0 +1,65 @@
// Copyright (C) 2018-2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "openvino/op/util/roi_align_base.hpp"
#include "itt.hpp"
#include "roi_align_shape_utils.hpp"
namespace ov {
namespace op {
namespace util {
ROIAlignBase::ROIAlignBase(const Output<Node>& input,
const Output<Node>& rois,
const Output<Node>& batch_indices,
const int pooled_h,
const int pooled_w,
const int sampling_ratio,
const float spatial_scale)
: Op{{input, rois, batch_indices}},
m_pooled_h{pooled_h},
m_pooled_w{pooled_w},
m_sampling_ratio{sampling_ratio},
m_spatial_scale{spatial_scale} {}
void ROIAlignBase::validate_and_infer_types() {
OV_OP_SCOPE(util_RoiAlignBase_validate_and_infer_types);
const auto out_et = roi_align::validate::data_and_roi_et(this);
roi_align::validate::batch_indicies_et(this);
const auto input_shapes = ov::util::get_node_input_partial_shapes(*this);
auto output_shape = roi_align::shape_infer(this, input_shapes).front();
set_output_type(0, out_et, output_shape);
const auto& input_ps = input_shapes.front();
// if the channels dimension is not known
// the first input should be used during the function specialization
if (input_ps.rank().is_static() && input_ps[1].is_dynamic()) {
set_input_is_relevant_to_shape(0);
}
// if the 'NUM_ROIS' value is not known
// the last 2 inputs should be used during the function specialization
if (output_shape[0].is_dynamic()) {
set_input_is_relevant_to_shape(1);
set_input_is_relevant_to_shape(2);
}
}
bool ROIAlignBase::visit_attributes(AttributeVisitor& visitor) {
OV_OP_SCOPE(util_RoiAlignBase_visit_attributes);
visitor.on_attribute("pooled_h", m_pooled_h);
visitor.on_attribute("pooled_w", m_pooled_w);
visitor.on_attribute("sampling_ratio", m_sampling_ratio);
visitor.on_attribute("spatial_scale", m_spatial_scale);
return true;
}
} // namespace util
} // namespace op
} // namespace ov

View File

@ -5,30 +5,48 @@
#include "common_test_utils/test_assertions.hpp"
#include "common_test_utils/type_prop.hpp"
#include "openvino/opsets/opset11.hpp"
#include "openvino/opsets/opset14.hpp"
using namespace std;
using namespace ov;
using namespace ov::opset11;
using namespace testing;
template <typename T>
class ROIAlignTest : public TypePropOpTest<T> {};
template <typename TOp>
class ROIAlignTest : public testing::Test {
protected:
std::shared_ptr<TOp> make_roi_op(const Output<Node>& input,
const Output<Node>& rois,
const Output<Node>& batch_indices,
const int pooled_h,
const int pooled_w) {
auto ret = std::make_shared<TOp>();
ret->set_arguments(OutputVector{input, rois, batch_indices});
ret->set_pooled_h(pooled_h);
ret->set_pooled_w(pooled_w);
ret->validate_and_infer_types();
return ret;
}
ov::Dimension::value_type GetROISecondDimSizeForOp() const {
// Those magic numbers comes from definition of ROIAlign ops.
if (std::is_same<TOp, op::v14::ROIAlignRotated>::value)
return 5;
return 4;
}
};
TYPED_TEST_SUITE_P(ROIAlignTest);
TYPED_TEST_P(ROIAlignTest, default_ctor) {
const size_t second_roi_dim = static_cast<size_t>(this->GetROISecondDimSizeForOp());
const auto data = make_shared<Parameter>(element::f32, PartialShape{2, 3, 5, 5});
const auto rois = make_shared<Parameter>(element::f32, Shape{7, 4});
const auto rois = make_shared<Parameter>(element::f32, Shape{7, second_roi_dim});
const auto batch_indices = make_shared<Parameter>(element::i32, Shape{7});
const auto op = this->make_op();
op->set_arguments(OutputVector{data, rois, batch_indices});
op->set_pooled_h(2);
op->set_pooled_w(2);
op->set_sampling_ratio(1);
op->set_spatial_scale(1.0f);
op->set_mode(TypeParam::PoolingMode::AVG);
op->validate_and_infer_types();
const auto op = this->make_roi_op(data, rois, batch_indices, 2, 2);
EXPECT_EQ(op->get_input_size(), 3);
EXPECT_EQ(op->get_output_size(), 1);
@ -37,7 +55,7 @@ TYPED_TEST_P(ROIAlignTest, default_ctor) {
TYPED_TEST_P(ROIAlignTest, simple_shape_inference) {
auto data_shape = PartialShape{2, 3, 5, 5};
auto rois_shape = PartialShape{7, 4};
auto rois_shape = PartialShape{7, this->GetROISecondDimSizeForOp()};
auto batch_shape = PartialShape{7};
auto data_symbols = set_shape_symbols(data_shape);
@ -48,7 +66,7 @@ TYPED_TEST_P(ROIAlignTest, simple_shape_inference) {
const auto rois = make_shared<Parameter>(element::f16, rois_shape);
const auto batch_indices = make_shared<Parameter>(element::i16, batch_shape);
const auto op = this->make_op(data, rois, batch_indices, 2, 2, 1, 1.0f, TypeParam::PoolingMode::AVG);
const auto op = this->make_roi_op(data, rois, batch_indices, 2, 2);
EXPECT_EQ(op->get_element_type(), element::f16);
EXPECT_EQ(op->get_output_partial_shape(0), PartialShape({7, 3, 2, 2}));
@ -58,7 +76,7 @@ TYPED_TEST_P(ROIAlignTest, simple_shape_inference) {
TYPED_TEST_P(ROIAlignTest, dynamic_channels_dim) {
auto data_shape = PartialShape{10, -1, 5, 5};
auto rois_shape = PartialShape{7, 4};
auto rois_shape = PartialShape{7, this->GetROISecondDimSizeForOp()};
auto batch_shape = PartialShape{7};
auto data_symbols = set_shape_symbols(data_shape);
@ -68,7 +86,7 @@ TYPED_TEST_P(ROIAlignTest, dynamic_channels_dim) {
const auto rois = make_shared<Parameter>(element::f64, rois_shape);
const auto batch_indices = make_shared<Parameter>(element::i64, batch_shape);
const auto op = this->make_op(data, rois, batch_indices, 3, 4, 1, 1.0f, TypeParam::PoolingMode::AVG);
const auto op = this->make_roi_op(data, rois, batch_indices, 3, 4);
EXPECT_EQ(op->get_element_type(), element::f64);
EXPECT_EQ(op->get_output_partial_shape(0), PartialShape({7, -1, 3, 4}));
@ -81,7 +99,7 @@ TYPED_TEST_P(ROIAlignTest, num_rois_from_batch_indices) {
const auto rois = make_shared<Parameter>(element::f32, PartialShape::dynamic(2));
const auto batch_indices = make_shared<Parameter>(element::i32, PartialShape{9});
const auto op = this->make_op(data, rois, batch_indices, 4, 2, 1, 1.0f, TypeParam::PoolingMode::MAX);
const auto op = this->make_roi_op(data, rois, batch_indices, 4, 2);
EXPECT_EQ(op->get_element_type(), element::f32);
EXPECT_EQ(op->get_output_partial_shape(0), PartialShape({9, 3, 4, 2}));
@ -93,7 +111,7 @@ TYPED_TEST_P(ROIAlignTest, all_inputs_dynamic_rank) {
const auto rois = make_shared<Parameter>(element::bf16, PartialShape::dynamic());
const auto batch_indices = make_shared<Parameter>(element::i8, PartialShape::dynamic());
const auto op = this->make_op(data, rois, batch_indices, 40, 12, 3, 2.2f, TypeParam::PoolingMode::AVG);
const auto op = this->make_roi_op(data, rois, batch_indices, 40, 12);
EXPECT_EQ(op->get_element_type(), element::bf16);
EXPECT_EQ(op->get_output_partial_shape(0), PartialShape({-1, -1, 40, 12}));
@ -113,7 +131,7 @@ TYPED_TEST_P(ROIAlignTest, all_inputs_static_rank_dynamic_dims) {
const auto rois = make_shared<Parameter>(element::f16, rois_shape);
const auto batch_indices = make_shared<Parameter>(element::u16, batch_shape);
const auto op = this->make_op(data, rois, batch_indices, 8, 8, 3, 2.2f, TypeParam::PoolingMode::AVG);
const auto op = this->make_roi_op(data, rois, batch_indices, 8, 8);
EXPECT_EQ(op->get_element_type(), element::f16);
EXPECT_EQ(op->get_output_partial_shape(0), PartialShape({-1, -1, 8, 8}));
@ -134,7 +152,7 @@ TYPED_TEST_P(ROIAlignTest, interval_shapes) {
const auto rois = make_shared<Parameter>(element::f32, rois_shape);
const auto batch_indices = make_shared<Parameter>(element::u64, batch_shape);
const auto op = this->make_op(data, rois, batch_indices, 8, 18, -3, -42.2f, TypeParam::PoolingMode::AVG);
const auto op = this->make_roi_op(data, rois, batch_indices, 8, 18);
EXPECT_EQ(op->get_element_type(), element::f32);
EXPECT_EQ(op->get_output_partial_shape(0), PartialShape({{3, 6}, {2, 4}, 8, 18}));
@ -148,7 +166,7 @@ TYPED_TEST_P(ROIAlignTest, incompatible_num_rois) {
const auto batch_indices = make_shared<Parameter>(element::i32, PartialShape{9});
OV_EXPECT_THROW(
std::ignore = this->make_op(data, rois, batch_indices, 8, 8, 1, 1.0f, TypeParam::PoolingMode::AVG),
std::ignore = this->make_roi_op(data, rois, batch_indices, 8, 8),
NodeValidationFailure,
HasSubstr("The first dimension of ROIs input must be equal to the first dimension of the batch indices input"));
}
@ -158,7 +176,7 @@ TYPED_TEST_P(ROIAlignTest, incompatible_input_rank) {
const auto rois = make_shared<Parameter>(element::f32, PartialShape{1, -1});
const auto batch_indices = make_shared<Parameter>(element::i32, PartialShape{9});
OV_EXPECT_THROW(std::ignore = this->make_op(data, rois, batch_indices, 8, 8, 1, 1.0f, TypeParam::PoolingMode::AVG),
OV_EXPECT_THROW(std::ignore = this->make_roi_op(data, rois, batch_indices, 8, 8),
NodeValidationFailure,
HasSubstr("Expected a 4D tensor for the input data"));
}
@ -168,38 +186,38 @@ TYPED_TEST_P(ROIAlignTest, incompatible_rois_rank) {
const auto rois = make_shared<Parameter>(element::f32, PartialShape{2});
const auto batch_indices = make_shared<Parameter>(element::i32, PartialShape{9});
OV_EXPECT_THROW(std::ignore = this->make_op(data, rois, batch_indices, 8, 8, 1, 1.0f, TypeParam::PoolingMode::AVG),
OV_EXPECT_THROW(std::ignore = this->make_roi_op(data, rois, batch_indices, 8, 8),
NodeValidationFailure,
HasSubstr("Expected a 2D tensor for the ROIs input"));
}
TYPED_TEST_P(ROIAlignTest, incompatible_batch_indicies_rank) {
const auto data = make_shared<Parameter>(element::f32, PartialShape{10, 3, 5, 5});
const auto rois = make_shared<Parameter>(element::f32, PartialShape{2, 4});
const auto rois = make_shared<Parameter>(element::f32, PartialShape{2, this->GetROISecondDimSizeForOp()});
const auto batch_indices = make_shared<Parameter>(element::i32, PartialShape{2, 1});
OV_EXPECT_THROW(std::ignore = this->make_op(data, rois, batch_indices, 8, 8, 1, 1.0f, TypeParam::PoolingMode::AVG),
OV_EXPECT_THROW(std::ignore = this->make_roi_op(data, rois, batch_indices, 8, 8),
NodeValidationFailure,
HasSubstr("Expected a 1D tensor for the batch indices input."));
}
TYPED_TEST_P(ROIAlignTest, incompatible_rois_2nd_dim) {
const auto data = make_shared<Parameter>(element::f32, PartialShape{10, 3, 5, 5});
const auto rois = make_shared<Parameter>(element::f32, PartialShape{2, {5, -1}});
const auto rois = make_shared<Parameter>(element::f32, PartialShape{2, {7, -1}});
const auto batch_indices = make_shared<Parameter>(element::i32, PartialShape{2});
OV_EXPECT_THROW(std::ignore = this->make_op(data, rois, batch_indices, 8, 8, 1, 1.0f, TypeParam::PoolingMode::AVG),
OV_EXPECT_THROW(std::ignore = this->make_roi_op(data, rois, batch_indices, 8, 8),
NodeValidationFailure,
HasSubstr("op dimension is expected to be equal to 4"));
HasSubstr("op dimension is expected to be equal to"));
}
TYPED_TEST_P(ROIAlignTest, incompatible_1st_dim_of_rois_and_batch) {
const auto data = make_shared<Parameter>(element::f32, PartialShape{10, 3, 5, 5});
const auto rois = make_shared<Parameter>(element::f32, PartialShape{{11, -1}, 4});
const auto rois = make_shared<Parameter>(element::f32, PartialShape{{11, -1}, this->GetROISecondDimSizeForOp()});
const auto batch_indices = make_shared<Parameter>(element::i32, PartialShape{{0, 10}});
OV_EXPECT_THROW(
std::ignore = this->make_op(data, rois, batch_indices, 8, 8, 1, 1.0f, TypeParam::PoolingMode::AVG),
std::ignore = this->make_roi_op(data, rois, batch_indices, 8, 8),
NodeValidationFailure,
HasSubstr("The first dimension of ROIs input must be equal to the first dimension of the batch indices input"));
}
@ -209,37 +227,37 @@ TYPED_TEST_P(ROIAlignTest, data_not_floating_point) {
const auto rois = make_shared<Parameter>(element::f32, PartialShape{8, 4});
const auto batch_indices = make_shared<Parameter>(element::i32, PartialShape{8});
OV_EXPECT_THROW(std::ignore = this->make_op(data, rois, batch_indices, 8, 8, 1, 1.0f, TypeParam::PoolingMode::AVG),
OV_EXPECT_THROW(std::ignore = this->make_roi_op(data, rois, batch_indices, 8, 8),
NodeValidationFailure,
HasSubstr("The data type for input and ROIs is expected to be a same floating point type"));
}
TYPED_TEST_P(ROIAlignTest, rois_not_floating_point) {
const auto data = make_shared<Parameter>(element::f32, PartialShape{10, 3, 5, 5});
const auto rois = make_shared<Parameter>(element::i32, PartialShape{8, 4});
const auto rois = make_shared<Parameter>(element::i32, PartialShape{8, this->GetROISecondDimSizeForOp()});
const auto batch_indices = make_shared<Parameter>(element::i32, PartialShape{8});
OV_EXPECT_THROW(std::ignore = this->make_op(data, rois, batch_indices, 8, 8, 1, 1.0f, TypeParam::PoolingMode::AVG),
OV_EXPECT_THROW(std::ignore = this->make_roi_op(data, rois, batch_indices, 8, 8),
NodeValidationFailure,
HasSubstr("The data type for input and ROIs is expected to be a same floating point type"));
}
TYPED_TEST_P(ROIAlignTest, data_and_rois_not_same_type) {
const auto data = make_shared<Parameter>(element::f32, PartialShape{10, 3, 5, 5});
const auto rois = make_shared<Parameter>(element::f16, PartialShape{8, 4});
const auto rois = make_shared<Parameter>(element::f16, PartialShape{8, this->GetROISecondDimSizeForOp()});
const auto batch_indices = make_shared<Parameter>(element::i32, PartialShape{8});
OV_EXPECT_THROW(std::ignore = this->make_op(data, rois, batch_indices, 8, 8, 1, 1.0f, TypeParam::PoolingMode::AVG),
OV_EXPECT_THROW(std::ignore = this->make_roi_op(data, rois, batch_indices, 8, 8),
NodeValidationFailure,
HasSubstr("The data type for input and ROIs is expected to be a same floating point type"));
}
TYPED_TEST_P(ROIAlignTest, batch_indicies_not_integer) {
const auto data = make_shared<Parameter>(element::f32, PartialShape{10, 3, 5, 5});
const auto rois = make_shared<Parameter>(element::f32, PartialShape{8, 4});
const auto rois = make_shared<Parameter>(element::f32, PartialShape{8, this->GetROISecondDimSizeForOp()});
const auto batch_indices = make_shared<Parameter>(element::f32, PartialShape{8});
OV_EXPECT_THROW(std::ignore = this->make_op(data, rois, batch_indices, 8, 8, 1, 1.0f, TypeParam::PoolingMode::AVG),
OV_EXPECT_THROW(std::ignore = this->make_roi_op(data, rois, batch_indices, 8, 8),
NodeValidationFailure,
HasSubstr("The data type for batch indices is expected to be an integer"));
}
@ -263,5 +281,5 @@ REGISTER_TYPED_TEST_SUITE_P(ROIAlignTest,
data_and_rois_not_same_type,
batch_indicies_not_integer);
typedef Types<op::v3::ROIAlign, op::v9::ROIAlign> ROIAlignTypes;
typedef Types<op::v3::ROIAlign, op::v9::ROIAlign, op::v14::ROIAlignRotated> ROIAlignTypes;
INSTANTIATE_TYPED_TEST_SUITE_P(type_prop, ROIAlignTest, ROIAlignTypes);