[shape_infer]Implement shape inference of Roll, ROIAlign,Proposal (#8610)

* Implement the proposal and experimental_detecron_generate_proposals

* Implement the proposal shape infer

* Add ROI_Align OP shape infer implement.

* Fix building issue

* Fix bug.

* Update test cases.

* Add test cases for the OPs

* Apply the CI coding style check.

* Move the shape_infer API to the new folder.

* Update some fix.

* Applied review comments

* Move the shape infer tests into new folder.

* Apply review comments.

* Fix missing header when mering with master
This commit is contained in:
Luwei Zhou 2021-12-23 11:02:15 +08:00 committed by GitHub
parent 8f908db61e
commit 3d244a41ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 582 additions and 234 deletions

View File

@ -52,6 +52,10 @@
#include "variadic_split_shape_inference.hpp"
#include "einsum_shape_inference.hpp"
#include "strided_slice_shape_inference.hpp"
#include "experimental_detectron_generate_proposals_shape_inference.hpp"
#include "roi_align_shape_inference.hpp"
#include "roll_shape_inference.hpp"
#include "proposal_shape_inference.hpp"
#include "static_shape.hpp"
#include "tile_shape_inference.hpp"
#include "utils.hpp"
@ -204,6 +208,16 @@ void shape_inference(ov::Node* op,
shape_infer(node, input_shapes, output_shapes);
} else if (auto node = ov::as_type<ov::opset1::ReverseSequence>(op)) {
shape_infer(node, input_shapes, output_shapes);
} else if (auto node = ov::as_type<ov::opset7::Roll>(op)) {
shape_infer(node, input_shapes, output_shapes, constant_data);
} else if (auto node = ov::as_type<ov::opset6::ExperimentalDetectronGenerateProposalsSingleImage>(op)) {
shape_infer(node, input_shapes, output_shapes);
} else if (auto node = ov::as_type<ov::opset4::Proposal>(op)) {
shape_infer(node, input_shapes, output_shapes);
} else if (auto node = ov::as_type<ov::opset1::Proposal>(op)) {
shape_infer(node, input_shapes, output_shapes);
} else if (auto node = ov::as_type<ov::opset3::ROIAlign>(op)) {
shape_infer(node, input_shapes, output_shapes);
} else {
ngraph::OutputVector new_inputs;
for (size_t i = 0; i < op->get_input_size(); ++i) {

View File

@ -66,6 +66,7 @@ public:
protected:
Attributes m_attrs;
void validate_element_types();
};
} // namespace v0

View File

@ -0,0 +1,86 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <openvino/op/experimental_detectron_generate_proposals.hpp>
namespace ov {
namespace op {
namespace v6 {
template <class T>
void shape_infer(const ExperimentalDetectronGenerateProposalsSingleImage* op,
const std::vector<T>& input_shapes,
std::vector<T>& output_shapes) {
NODE_VALIDATION_CHECK(op, input_shapes.size() == 4 && output_shapes.size() == 2);
auto post_nms_count = static_cast<size_t>(op->get_attrs().post_nms_count);
const auto& im_info_shape = input_shapes[0];
const auto& anchors_shape = input_shapes[1];
const auto& deltas_shape = input_shapes[2];
const auto& scores_shape = input_shapes[3];
const auto im_info_shape_rank = im_info_shape.rank();
NODE_VALIDATION_CHECK(op,
im_info_shape_rank.compatible(1),
"The 'input_im_info' input is expected to be a 1D. Got: ",
im_info_shape);
if (im_info_shape_rank.is_static()) {
NODE_VALIDATION_CHECK(op,
im_info_shape[0].compatible(3),
"The 'input_im_info' shape is expected to be a compatible with [3]. Got: ",
im_info_shape);
}
const auto anchors_shape_rank = anchors_shape.rank();
NODE_VALIDATION_CHECK(op,
anchors_shape_rank.compatible(2),
"The 'input_anchors' input is expected to be a 2D. Got: ",
anchors_shape);
if (anchors_shape_rank.is_static()) {
NODE_VALIDATION_CHECK(op,
anchors_shape[1].compatible(4),
"The second dimension of 'input_anchors' should be compatible with 4. Got: ",
anchors_shape[1]);
}
const auto deltas_shape_rank = deltas_shape.rank();
const auto scores_shape_rank = scores_shape.rank();
NODE_VALIDATION_CHECK(op,
deltas_shape_rank.compatible(3),
"The 'input_deltas' input is expected to be a 3D. Got: ",
deltas_shape);
NODE_VALIDATION_CHECK(op,
scores_shape_rank.compatible(3),
"The 'input_scores' input is expected to be a 3D. Got: ",
scores_shape);
if (deltas_shape_rank.is_static() && scores_shape_rank.is_static()) {
NODE_VALIDATION_CHECK(op,
deltas_shape[1].compatible(scores_shape[1]),
"Heights for inputs 'input_deltas' and 'input_scores' should be "
"equal. Got: ",
deltas_shape[1],
scores_shape[1]);
NODE_VALIDATION_CHECK(op,
deltas_shape[2].compatible(scores_shape[2]),
"Width for inputs 'input_deltas' and 'input_scores' should be "
"equal. Got: ",
deltas_shape[2],
scores_shape[2]);
}
auto& rois_shape = output_shapes[0];
auto& rois_scores_shape = output_shapes[1];
rois_shape.resize(2);
rois_scores_shape.resize(1);
rois_shape[0] = post_nms_count;
rois_shape[1] = 4;
rois_scores_shape[0] = post_nms_count;
}
} // namespace v6
} // namespace op
} // namespace ov

View File

@ -0,0 +1,109 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <openvino/op/proposal.hpp>
namespace ov {
namespace op {
namespace v0 {
template <class OpType, class ShapeType>
void infer_prop_shape(const OpType* op,
const std::vector<ShapeType>& input_shapes,
std::vector<ShapeType>& output_shapes) {
using DimType = typename std::iterator_traits<typename ShapeType::iterator>::value_type;
const auto& class_probs_ps = input_shapes[0];
const auto& bbox_deltas_ps = input_shapes[1];
const auto& image_shape_ps = input_shapes[2];
NODE_VALIDATION_CHECK(op,
class_probs_ps.rank().compatible(4),
"Proposal layer shape class_probs should be rank 4 compatible (",
class_probs_ps,
").");
NODE_VALIDATION_CHECK(op,
bbox_deltas_ps.rank().compatible(4),
"Proposal layer shape bbox_deltas should be rank 4 compatible (",
bbox_deltas_ps,
").");
NODE_VALIDATION_CHECK(op,
image_shape_ps.rank().compatible(1),
"Proposal layer shape image_shape should be rank 1 compatible (",
image_shape_ps,
").");
if (bbox_deltas_ps.rank().is_static() && class_probs_ps.rank().is_static()) {
// check anchor count and batch number consistency
NODE_VALIDATION_CHECK(op,
bbox_deltas_ps[1].compatible(class_probs_ps[1] * 2),
"Anchor number inconsistent between class_probs (",
class_probs_ps[1] * 2,
"), and bbox_deltas (",
bbox_deltas_ps[1],
").");
NODE_VALIDATION_CHECK(op,
class_probs_ps[0].compatible(bbox_deltas_ps[0]),
"Batch size inconsistent between class_probs (",
class_probs_ps[0],
") and bbox deltas (",
bbox_deltas_ps[0],
").");
}
if (image_shape_ps.is_static()) {
const auto image_shape_elem = image_shape_ps[0].get_length();
NODE_VALIDATION_CHECK(op,
image_shape_elem >= 3 && image_shape_elem <= 4,
"Image_shape 1D tensor must have => 3 and <= 4 elements (image_shape_shape[0]",
image_shape_ps[0],
").");
}
auto out_dim = DimType{};
if (class_probs_ps.rank().is_static() && bbox_deltas_ps.rank().is_static()) {
DimType::merge(out_dim, class_probs_ps[0], bbox_deltas_ps[0]);
} else if (class_probs_ps.rank().is_static()) {
out_dim = class_probs_ps[0];
} else if (bbox_deltas_ps.rank().is_static()) {
out_dim = bbox_deltas_ps[0];
} else {
out_dim = Dimension::dynamic();
}
auto& proposed_boxes_shape = output_shapes[0];
proposed_boxes_shape.resize(2);
proposed_boxes_shape[0] = out_dim * op->get_attrs().post_nms_topn;
proposed_boxes_shape[1] = 5;
}
template <class T>
void shape_infer(const ov::op::v0::Proposal* op, const std::vector<T>& input_shapes, std::vector<T>& output_shapes) {
NODE_VALIDATION_CHECK(op, input_shapes.size() == 3 && output_shapes.size() == 1);
ov::op::v0::infer_prop_shape(op, input_shapes, output_shapes);
}
} // namespace v0
} // namespace op
} // namespace ov
namespace ov {
namespace op {
namespace v4 {
template <class T>
void shape_infer(const ov::op::v4::Proposal* op, const std::vector<T>& input_shapes, std::vector<T>& output_shapes) {
NODE_VALIDATION_CHECK(op, input_shapes.size() == 3 && output_shapes.size() == 2);
ov::op::v0::infer_prop_shape(op, input_shapes, output_shapes);
const auto& proposals_ps = output_shapes[0];
auto& out_ps = output_shapes[1];
out_ps = T{proposals_ps[0]};
}
} // namespace v4
} // namespace op
} // namespace ov

View File

@ -0,0 +1,77 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <openvino/op/roi_align.hpp>
#include "utils.hpp"
namespace ov {
namespace op {
namespace v3 {
template <class T>
void shape_infer(const ov::op::v3::ROIAlign* op, const std::vector<T>& input_shapes, std::vector<T>& output_shapes) {
using DimType = typename std::iterator_traits<typename T::iterator>::value_type;
NODE_VALIDATION_CHECK(op, input_shapes.size() == 3 && output_shapes.size() == 1);
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();
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);
if (batch_indices_ps_rank.is_static()) {
NODE_VALIDATION_CHECK(op,
rois_ps[0].compatible(batch_indices_ps[0]),
"The first dimension of ROIs input must be equal to the first dimension ",
"of the batch indices input. Got: ",
rois_ps[0],
" and: ",
batch_indices_ps[0]);
}
}
auto& output_shape = output_shapes[0];
output_shape.resize(4);
output_shape[1] = input_ps_rank.is_static() ? input_ps[1] : -1;
output_shape[2] = op->get_pooled_h();
output_shape[3] = op->get_pooled_w();
// if either of those 2 dimensions is static its value will be used
// for the first dimension of the output shape - 'NUM_ROIS'
if (rois_ps_rank.is_static() && batch_indices_ps_rank.is_static()) {
DimType::merge(output_shape[0], batch_indices_ps[0], rois_ps[0]);
} else if (rois_ps_rank.is_static()) {
output_shape[0] = rois_ps[0];
} else if (batch_indices_ps_rank.is_static()) {
output_shape[0] = batch_indices_ps[0];
} else {
output_shape[0] = Dimension::dynamic();
}
}
} // namespace v3
} // namespace op
} // namespace ov

View File

@ -0,0 +1,73 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <openvino/op/roll.hpp>
#include "utils.hpp"
namespace ov {
namespace op {
namespace v7 {
template <class T>
void shape_infer(const ov::op::v7::Roll* op,
const std::vector<T>& input_shapes,
std::vector<T>& output_shapes,
const std::map<size_t, std::shared_ptr<ngraph::runtime::HostTensor>>& constant_data = {}) {
NODE_VALIDATION_CHECK(op, input_shapes.size() == 3 && output_shapes.size() == 1);
const auto& data_pshape = input_shapes[0];
const auto& shift_pshape = input_shapes[1];
const auto& axes_pshape = input_shapes[2];
if (shift_pshape.rank().is_static()) {
const auto& shift_rank = shift_pshape.size();
NODE_VALIDATION_CHECK(op, shift_rank <= 1, "Shift must be a scalar or 1D tensor.");
// If shift is a scalar, than axes can be arbitrary 1d tensor and we don't need
// to check shift shape consistency with axes, otherwise the check is needed.
if (shift_rank == 1) {
NODE_VALIDATION_CHECK(op,
shift_pshape.compatible(axes_pshape),
"If shift is a 1D vector, axes must be a 1D tensor of the same size.");
}
}
if (axes_pshape.rank().is_static()) {
const auto& axes_rank = axes_pshape.size();
NODE_VALIDATION_CHECK(op, axes_rank <= 1, "Axes must be a scalar or 1D tensor.");
}
std::vector<int64_t> axes{};
if (get_data_as_int64<T>(2, op, axes, constant_data)) {
if (data_pshape.rank().is_static()) {
const auto& data_rank = data_pshape.size();
for (int64_t& axis : axes) {
NODE_VALIDATION_CHECK(op,
axis < static_cast<int64_t>(data_rank),
"Axes must be less than data tensor rank. Got "
"data tensor rank: ",
data_rank,
", axis: ",
axis);
if (axis < 0) {
axis += static_cast<int64_t>(data_rank);
}
NODE_VALIDATION_CHECK(op,
axis >= 0,
"Axes must be positive or equal to zero. Got "
"axis: ",
axis);
}
}
}
output_shapes[0] = input_shapes[0];
}
} // namespace v7
} // namespace op
} // namespace ov

View File

@ -4,6 +4,8 @@
#include "ngraph/op/experimental_detectron_generate_proposals.hpp"
#include <experimental_detectron_generate_proposals_shape_inference.hpp>
#include "itt.hpp"
#include "ngraph/attribute_visitor.hpp"
#include "ngraph/op/util/op_types.hpp"
@ -47,69 +49,15 @@ bool op::v6::ExperimentalDetectronGenerateProposalsSingleImage::visit_attributes
void op::v6::ExperimentalDetectronGenerateProposalsSingleImage::validate_and_infer_types() {
NGRAPH_OP_SCOPE(v6_ExperimentalDetectronGenerateProposalsSingleImage_validate_and_infer_types);
auto post_nms_count = static_cast<size_t>(m_attrs.post_nms_count);
auto input_et = get_input_element_type(0);
set_output_size(2);
set_output_type(0, input_et, ov::Shape{post_nms_count, 4});
set_output_type(1, input_et, ov::Shape{post_nms_count});
std::vector<ov::PartialShape> output_shapes = {ov::PartialShape{}, ov::PartialShape{}};
std::vector<ov::PartialShape> input_shapes = {get_input_partial_shape(0),
get_input_partial_shape(1),
get_input_partial_shape(2),
get_input_partial_shape(3)};
shape_infer(this, input_shapes, output_shapes);
auto im_info_shape = get_input_partial_shape(0);
auto anchors_shape = get_input_partial_shape(1);
auto deltas_shape = get_input_partial_shape(2);
auto scores_shape = get_input_partial_shape(3);
if (im_info_shape.rank().is_static()) {
NODE_VALIDATION_CHECK(this,
im_info_shape.rank().get_length() == 1,
"The 'input_im_info' input is expected to be a 1D. Got: ",
im_info_shape);
NODE_VALIDATION_CHECK(this,
im_info_shape[0].is_dynamic() || im_info_shape[0] == 3,
"The 'input_im_info' shape is expected to be a [3]. Got: ",
im_info_shape);
}
if (anchors_shape.rank().is_static()) {
NODE_VALIDATION_CHECK(this,
anchors_shape.rank().get_length() == 2,
"The 'input_anchors' input is expected to be a 2D. Got: ",
anchors_shape);
NODE_VALIDATION_CHECK(this,
anchors_shape[1].is_dynamic() || anchors_shape[1] == 4,
"The second dimension of 'input_anchors' should be 4. Got: ",
anchors_shape[1]);
}
if (deltas_shape.rank().is_static()) {
NODE_VALIDATION_CHECK(this,
deltas_shape.rank().get_length() == 3,
"The 'input_deltas' input is expected to be a 3D. Got: ",
deltas_shape);
}
if (scores_shape.rank().is_static()) {
NODE_VALIDATION_CHECK(this,
scores_shape.rank().get_length() == 3,
"The 'input_scores' input is expected to be a 3D. Got: ",
scores_shape);
}
if (deltas_shape.rank().is_static() && scores_shape.rank().is_static()) {
NODE_VALIDATION_CHECK(
this,
deltas_shape[1].is_dynamic() || scores_shape[1].is_dynamic() || deltas_shape[1] == scores_shape[1],
"Heights for inputs 'input_deltas' and 'input_scores' should be "
"equal. Got: ",
deltas_shape[1],
scores_shape[1]);
NODE_VALIDATION_CHECK(
this,
deltas_shape[2].is_dynamic() || scores_shape[2].is_dynamic() || deltas_shape[2] == scores_shape[2],
"Width for inputs 'input_deltas' and 'input_scores' should be "
"equal. Got: ",
deltas_shape[2],
scores_shape[2]);
}
const auto& input_et = get_input_element_type(0);
set_output_type(0, input_et, output_shapes[0]);
set_output_type(1, input_et, output_shapes[1]);
}

View File

@ -4,6 +4,8 @@
#include "ngraph/op/proposal.hpp"
#include <proposal_shape_inference.hpp>
#include "itt.hpp"
#include "ngraph/op/constant.hpp"
@ -21,12 +23,7 @@ op::v0::Proposal::Proposal(const Output<Node>& class_probs,
constructor_validate_and_infer_types();
}
void op::v0::Proposal::validate_and_infer_types() {
NGRAPH_OP_SCOPE(v0_Proposal_validate_and_infer_types);
const auto& class_probs_ps = get_input_partial_shape(0);
const auto& bbox_deltas_ps = get_input_partial_shape(1);
const auto& image_shape_ps = get_input_partial_shape(2);
Dimension out_dim = Dimension::dynamic();
void op::v0::Proposal::validate_element_types() {
NODE_VALIDATION_CHECK(this,
get_input_element_type(0).is_real(),
"Proposal layer input class_probs should have floating point type (",
@ -44,63 +41,17 @@ void op::v0::Proposal::validate_and_infer_types() {
"Proposal layer input image_shape should have floating point type (",
get_input_element_type(2),
").");
}
NODE_VALIDATION_CHECK(this,
class_probs_ps.rank().compatible(4),
"Proposal layer shape class_probs should be rank 4 compatible (",
class_probs_ps,
").");
NODE_VALIDATION_CHECK(this,
bbox_deltas_ps.rank().compatible(4),
"Proposal layer shape bbox_deltas should be rank 4 compatible (",
bbox_deltas_ps,
").");
NODE_VALIDATION_CHECK(this,
image_shape_ps.rank().compatible(1),
"Proposal layer shape image_shape should be rank 1 compatible (",
image_shape_ps,
").");
if (bbox_deltas_ps.is_static() && class_probs_ps.is_static()) {
// class probs and bbox deltas shapes are static, check anchor count and batch number
// consistency
NODE_VALIDATION_CHECK(this,
class_probs_ps[1].get_length() * 2 == bbox_deltas_ps[1].get_length(),
"Anchor number inconsistent between class_probs (",
class_probs_ps[1].get_length() / 2,
"), and bbox_deltas (",
bbox_deltas_ps[1].get_length() / 4,
").");
NODE_VALIDATION_CHECK(this,
class_probs_ps[0] == bbox_deltas_ps[0],
"Batch size inconsistent between class_probs (",
class_probs_ps[0],
") and bbox deltas (",
bbox_deltas_ps[0],
").");
}
if (image_shape_ps.is_static()) {
NODE_VALIDATION_CHECK(this,
image_shape_ps[0].get_length() >= 3 && image_shape_ps[0].get_length() <= 4,
"Image_shape 1D tensor must have => 3 and <= 4 elements (image_shape_shape[0]",
image_shape_ps[0],
").");
}
if (class_probs_ps.rank().is_static() && bbox_deltas_ps.rank().is_static()) {
out_dim = (class_probs_ps[0] & bbox_deltas_ps[0]);
} else if (class_probs_ps.rank().is_static()) {
out_dim = class_probs_ps[0];
} else if (bbox_deltas_ps.rank().is_static()) {
out_dim = bbox_deltas_ps[0];
}
// intersect the batch size
set_output_type(0, get_input_element_type(0), ov::PartialShape{out_dim * m_attrs.post_nms_topn, 5});
void op::v0::Proposal::validate_and_infer_types() {
NGRAPH_OP_SCOPE(v0_Proposal_validate_and_infer_types);
validate_element_types();
std::vector<ov::PartialShape> output_shapes = {ov::PartialShape{}};
std::vector<ov::PartialShape> input_shapes = {get_input_partial_shape(0),
get_input_partial_shape(1),
get_input_partial_shape(2)};
shape_infer(this, input_shapes, output_shapes);
set_output_type(0, get_input_element_type(0), output_shapes[0]);
}
shared_ptr<Node> op::v0::Proposal::clone_with_new_inputs(const OutputVector& new_args) const {
@ -140,14 +91,17 @@ op::v4::Proposal::Proposal(const Output<Node>& class_probs,
void op::v4::Proposal::validate_and_infer_types() {
NGRAPH_OP_SCOPE(v4_Proposal_validate_and_infer_types);
v0::Proposal::validate_and_infer_types();
// Output shape was inferred in v0's validate_and_infer_types
const auto proposals_ps = get_output_partial_shape(0);
auto out_ps = ov::PartialShape{Dimension::dynamic()};
if (proposals_ps.rank().is_static() && proposals_ps.rank().compatible(2)) {
out_ps = ov::PartialShape{proposals_ps[0]};
}
set_output_type(1, get_input_element_type(0), out_ps);
v0::Proposal::validate_element_types();
std::vector<ov::PartialShape> output_shapes = {ov::PartialShape{}, ov::PartialShape{}};
std::vector<ov::PartialShape> input_shapes = {get_input_partial_shape(0),
get_input_partial_shape(1),
get_input_partial_shape(2)};
shape_infer(this, input_shapes, output_shapes);
const auto& input0_type = get_input_element_type(0);
set_output_type(0, input0_type, output_shapes[0]);
set_output_type(1, input0_type, output_shapes[1]);
}
std::shared_ptr<Node> op::v4::Proposal::clone_with_new_inputs(const OutputVector& new_args) const {

View File

@ -4,6 +4,8 @@
#include "ngraph/op/roi_align.hpp"
#include <roi_align_shape_inference.hpp>
#include "itt.hpp"
#include "ngraph/runtime/host_tensor.hpp"
#include "ngraph/runtime/reference/roi_align.hpp"
@ -69,69 +71,25 @@ void op::v3::ROIAlign::validate_and_infer_types() {
"The data type for batch indices is expected to be an integer. Got: ",
get_input_element_type(2));
const auto& input_ps = get_input_partial_shape(0);
NODE_VALIDATION_CHECK(this,
input_ps.rank().compatible(4),
"Expected a 4D tensor for the input data. Got: ",
input_ps);
const auto& rois_ps = get_input_partial_shape(1);
NODE_VALIDATION_CHECK(this,
rois_ps.rank().compatible(2),
"Expected a 2D tensor for the ROIs input. Got: ",
rois_ps);
const auto& batch_indices_ps = get_input_partial_shape(2);
NODE_VALIDATION_CHECK(this,
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(this,
rois_second_dim.compatible(4),
"The second dimension of ROIs input should contain box coordinates. ",
"This dimension is expected to be equal to 4. Got: ",
rois_second_dim);
if (batch_indices_ps.rank().is_static()) {
NODE_VALIDATION_CHECK(this,
rois_ps[0].compatible(batch_indices_ps[0]),
"The first dimension of ROIs input must be equal to the first dimension ",
"of the batch indices input. Got: ",
rois_ps[0],
" and: ",
batch_indices_ps[0]);
}
}
// the output shape should have the following format [NUM_ROIS, C, pooled_h, pooled_w]
auto output_shape = ov::PartialShape{{Dimension::dynamic(),
input_ps[1],
Dimension{static_cast<int64_t>(m_pooled_h)},
Dimension{static_cast<int64_t>(m_pooled_w)}}};
// if either of those 2 dimensions is static its value will be used
// for the first dimension of the output shape - 'NUM_ROIS'
if (rois_ps.rank().is_static() && rois_ps[0].is_static()) {
output_shape[0] = rois_ps[0];
} else if (batch_indices_ps.rank().is_static() && batch_indices_ps[0].is_static()) {
output_shape[0] = batch_indices_ps[0];
}
std::vector<ov::PartialShape> output_shapes = {ov::PartialShape{}};
const std::vector<ov::PartialShape> input_shapes = {get_input_partial_shape(0),
get_input_partial_shape(1),
get_input_partial_shape(2)};
shape_infer(this, input_shapes, output_shapes);
set_output_size(1);
set_output_type(0, get_input_element_type(0), output_shape);
set_output_type(0, get_input_element_type(0), output_shapes[0]);
const auto& input_ps = get_input_partial_shape(0);
// 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()) {
if ((output_shapes[0])[0].is_dynamic()) {
set_input_is_relevant_to_shape(1);
set_input_is_relevant_to_shape(2);
}

View File

@ -5,6 +5,7 @@
#include "ngraph/op/roll.hpp"
#include <ngraph/validation_util.hpp>
#include <roll_shape_inference.hpp>
#include "itt.hpp"
@ -31,54 +32,13 @@ void op::v7::Roll::validate_and_infer_types() {
axes_et.is_dynamic() || axes_et == element::i32 || axes_et == element::i64,
"Axes must have int32 or int64 element type.");
const auto& data_pshape = get_input_partial_shape(0);
const auto& shift_pshape = get_input_partial_shape(1);
const auto& axes_pshape = get_input_partial_shape(2);
std::vector<ov::PartialShape> output_shapes = {ov::PartialShape{}};
const std::vector<ov::PartialShape> input_shapes = {get_input_partial_shape(0),
get_input_partial_shape(1),
get_input_partial_shape(2)};
shape_infer(this, input_shapes, output_shapes);
if (shift_pshape.is_static()) {
const auto& shift_rank = shift_pshape.rank().get_length();
NODE_VALIDATION_CHECK(this, shift_rank <= 1, "Shift must be a scalar or 1D tensor.");
}
if (axes_pshape.is_static()) {
const auto& axes_rank = axes_pshape.rank().get_length();
NODE_VALIDATION_CHECK(this, axes_rank <= 1, "Axes must be a scalar or 1D tensor.");
}
// If shift is a scalar, than axes can be arbitrary 1d tensor and we don't need
// to check shift shape consistency with axes, otherwise the check is needed.
if (!(shift_pshape.is_static() && ngraph::is_scalar(shift_pshape.to_shape()))) {
NODE_VALIDATION_CHECK(this,
shift_pshape.compatible(axes_pshape),
"If shift is a 1D vector, axes must be a 1D tensor of the same size.");
}
if (const auto& const_axes = get_constant_from_source(input_value(2))) {
auto axes = const_axes->cast_vector<int64_t>();
if (data_pshape.is_static()) {
const auto& data_rank = data_pshape.rank().get_length();
for (int64_t& axis : axes) {
NODE_VALIDATION_CHECK(this,
axis < data_rank,
"Axes must be less than data tensor rank. Got "
"data tensor rank: ",
data_rank,
", axis: ",
axis);
if (axis < 0) {
axis += data_rank;
}
NODE_VALIDATION_CHECK(this,
axis >= 0,
"Axes must be positive or equal to zero. Got "
"axis: ",
axis);
}
}
}
set_output_type(0, get_input_element_type(0), get_input_partial_shape(0));
set_output_type(0, get_input_element_type(0), output_shapes[0]);
}
bool op::v7::Roll::visit_attributes(AttributeVisitor& visitor) {

View File

@ -0,0 +1,39 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <gtest/gtest.h>
#include <openvino/op/experimental_detectron_generate_proposals.hpp>
#include <openvino/op/parameter.hpp>
#include <utils/shape_inference/shape_inference.hpp>
#include <utils/shape_inference/static_shape.hpp>
using namespace ov;
using ExperimentalProposals = op::v6::ExperimentalDetectronGenerateProposalsSingleImage;
TEST(StaticShapeInferenceTest, ExperimentalProposalsTest) {
ExperimentalProposals::Attributes attrs;
attrs.min_size = 0.0f;
attrs.nms_threshold = 0.699999988079071f;
attrs.post_nms_count = 1000;
attrs.pre_nms_count = 1000;
size_t post_nms_count = 1000;
auto im_info = std::make_shared<op::v0::Parameter>(element::f32, PartialShape{-1});
auto anchors = std::make_shared<op::v0::Parameter>(element::f32, PartialShape{-1, -1});
auto deltas = std::make_shared<op::v0::Parameter>(element::f32, PartialShape{-1, -1, -1});
auto scores = std::make_shared<op::v0::Parameter>(element::f32, PartialShape{-1, -1, -1});
auto proposals = std::make_shared<ExperimentalProposals>(im_info, anchors, deltas, scores, attrs);
const std::vector<ov::StaticShape> input_shapes = {ov::StaticShape{3},
ov::StaticShape{201600, 4},
ov::StaticShape{12, 200, 336},
ov::StaticShape{3, 200, 336}};
std::vector<ov::StaticShape> output_shapes = {ov::StaticShape{}, ov::StaticShape{}};
shape_inference(proposals.get(), input_shapes, output_shapes);
ASSERT_EQ(output_shapes[0], (StaticShape{post_nms_count, 4}));
ASSERT_EQ(output_shapes[1], (StaticShape{post_nms_count}));
}

View File

@ -0,0 +1,53 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <gtest/gtest.h>
#include <openvino/op/parameter.hpp>
#include <openvino/op/proposal.hpp>
#include <utils/shape_inference/shape_inference.hpp>
#include <utils/shape_inference/static_shape.hpp>
using namespace ov;
TEST(StaticShapeInferenceTest, ProposalV0Test) {
op::v0::Proposal::Attributes attrs;
attrs.base_size = 1;
attrs.pre_nms_topn = 20;
attrs.post_nms_topn = 200;
const size_t batch_size = 7;
auto class_probs = std::make_shared<op::v0::Parameter>(element::f32, PartialShape{-1, -1, -1, -1});
auto class_bbox_deltas = std::make_shared<op::v0::Parameter>(element::f32, PartialShape{-1, -1, -1, -1});
auto image_shape = std::make_shared<op::v0::Parameter>(element::f32, PartialShape{-1});
auto op = std::make_shared<op::v0::Proposal>(class_probs, class_bbox_deltas, image_shape, attrs);
const std::vector<ov::StaticShape> input_shapes = {ov::StaticShape{batch_size, 12, 34, 62},
ov::StaticShape{batch_size, 24, 34, 62},
ov::StaticShape{3}};
std::vector<ov::StaticShape> output_shapes = {ov::StaticShape{}};
shape_inference(op.get(), input_shapes, output_shapes);
ASSERT_EQ(output_shapes[0], (StaticShape{batch_size * attrs.post_nms_topn, 5}));
}
TEST(StaticShapeInferenceTest, ProposalV4Test) {
op::v0::Proposal::Attributes attrs;
attrs.base_size = 1;
attrs.pre_nms_topn = 20;
attrs.post_nms_topn = 200;
const size_t batch_size = 7;
auto class_probs = std::make_shared<op::v0::Parameter>(element::f32, PartialShape{-1, -1, -1, -1});
auto class_bbox_deltas = std::make_shared<op::v0::Parameter>(element::f32, PartialShape{-1, -1, -1, -1});
auto image_shape = std::make_shared<op::v0::Parameter>(element::f32, PartialShape{-1});
auto op = std::make_shared<op::v4::Proposal>(class_probs, class_bbox_deltas, image_shape, attrs);
const std::vector<ov::StaticShape> input_shapes = {ov::StaticShape{batch_size, 12, 34, 62},
ov::StaticShape{batch_size, 24, 34, 62},
ov::StaticShape{3}};
std::vector<ov::StaticShape> output_shapes = {ov::StaticShape{}, ov::StaticShape{}};
shape_inference(op.get(), input_shapes, output_shapes);
ASSERT_EQ(output_shapes[0], (StaticShape{batch_size * attrs.post_nms_topn, 5}));
ASSERT_EQ(output_shapes[1], (StaticShape{batch_size * attrs.post_nms_topn}));
}

View File

@ -0,0 +1,26 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <gtest/gtest.h>
#include <openvino/op/parameter.hpp>
#include <openvino/op/roi_align.hpp>
#include <utils/shape_inference/shape_inference.hpp>
#include <utils/shape_inference/static_shape.hpp>
using namespace ov;
TEST(StaticShapeInferenceTest, ROIAlignTest) {
const auto data = std::make_shared<op::v0::Parameter>(element::f32, PartialShape{-1, -1, -1, -1});
const auto rois = std::make_shared<op::v0::Parameter>(element::f32, PartialShape{-1, -1});
const auto batch_indices = std::make_shared<op::v0::Parameter>(element::i32, PartialShape{-1});
const auto op = std::make_shared<op::v3::ROIAlign>(data, rois, batch_indices, 2, 2, 1, 1.0f, "avg");
const std::vector<ov::StaticShape> input_shapes = {ov::StaticShape{2, 3, 5, 5},
ov::StaticShape{7, 4},
ov::StaticShape{7}};
std::vector<ov::StaticShape> output_shapes = {ov::StaticShape{}};
shape_inference(op.get(), input_shapes, output_shapes);
ASSERT_EQ(output_shapes[0], (StaticShape{7, 3, 2, 2}));
}

View File

@ -0,0 +1,50 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <gtest/gtest.h>
#include <openvino/op/constant.hpp>
#include <openvino/op/parameter.hpp>
#include <openvino/op/roll.hpp>
#include <utils/shape_inference/shape_inference.hpp>
#include <utils/shape_inference/static_shape.hpp>
TEST(StaticShapeInferenceTest, RollTest) {
auto arg =
std::make_shared<ov::op::v0::Parameter>(ov::element::f32,
ov::PartialShape{ov::Dimension::dynamic(), ov::Dimension::dynamic()});
auto shift = std::make_shared<ov::op::v0::Parameter>(ov::element::i64, ov::PartialShape{ov::Dimension::dynamic()});
auto axes = std::make_shared<ov::op::v0::Parameter>(ov::element::i32, ov::PartialShape{ov::Dimension::dynamic()});
auto roll = std::make_shared<ov::op::v7::Roll>(arg, shift, axes);
int32_t axes_val[] = {0, 1, -1};
auto axes_tensor = std::make_shared<ngraph::runtime::HostTensor>(ov::element::i32, ov::Shape{3}, axes_val);
std::map<size_t, std::shared_ptr<ngraph::runtime::HostTensor>> constant_data;
constant_data[2] = axes_tensor;
const std::vector<ov::StaticShape> input_shapes = {ov::StaticShape{3, 3, 3},
ov::StaticShape{3},
ov::StaticShape{3}};
std::vector<ov::StaticShape> output_shapes = {ov::StaticShape{}};
shape_inference(roll.get(), input_shapes, output_shapes, constant_data);
ASSERT_EQ(output_shapes[0], input_shapes[0]);
}
TEST(StaticShapeInferenceTest, RollTestWithConstAxis) {
auto arg =
std::make_shared<ov::op::v0::Parameter>(ov::element::f32,
ov::PartialShape{ov::Dimension::dynamic(), ov::Dimension::dynamic()});
auto shift = std::make_shared<ov::op::v0::Parameter>(ov::element::i64, ov::PartialShape{ov::Dimension::dynamic()});
auto axes = std::make_shared<ov::op::v0::Constant>(ov::element::i32, ov::Shape{3}, std::vector<int32_t>{0, 1, -1});
auto roll = std::make_shared<ov::op::v7::Roll>(arg, shift, axes);
const std::vector<ov::StaticShape> input_shapes = {ov::StaticShape{3, 3, 3},
ov::StaticShape{3},
ov::StaticShape{3}};
std::vector<ov::StaticShape> output_shapes = {ov::StaticShape{}};
shape_inference(roll.get(), input_shapes, output_shapes);
ASSERT_EQ(output_shapes[0], input_shapes[0]);
}