[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:
parent
8f908db61e
commit
3d244a41ab
@ -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) {
|
||||
|
@ -66,6 +66,7 @@ public:
|
||||
|
||||
protected:
|
||||
Attributes m_attrs;
|
||||
void validate_element_types();
|
||||
};
|
||||
} // namespace v0
|
||||
|
||||
|
@ -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
|
109
src/core/shape_inference/include/proposal_shape_inference.hpp
Normal file
109
src/core/shape_inference/include/proposal_shape_inference.hpp
Normal 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
|
@ -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
|
73
src/core/shape_inference/include/roll_shape_inference.hpp
Normal file
73
src/core/shape_inference/include/roll_shape_inference.hpp
Normal 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
|
@ -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]);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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}));
|
||||
}
|
53
src/tests/unit/cpu/shape_inference_test/proposal.cpp
Normal file
53
src/tests/unit/cpu/shape_inference_test/proposal.cpp
Normal 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}));
|
||||
}
|
@ -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}));
|
||||
}
|
@ -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]);
|
||||
}
|
Loading…
Reference in New Issue
Block a user