diff --git a/src/core/include/openvino/op/shuffle_channels.hpp b/src/core/include/openvino/op/shuffle_channels.hpp index 3a231a9c266..f6c9c8e4f07 100644 --- a/src/core/include/openvino/op/shuffle_channels.hpp +++ b/src/core/include/openvino/op/shuffle_channels.hpp @@ -35,10 +35,10 @@ public: std::shared_ptr clone_with_new_inputs(const OutputVector& new_args) const override; - int64_t get_axis() const { + const int64_t& get_axis() const { return m_axis; } - int64_t get_group() const { + const int64_t& get_group() const { return m_group; } OPENVINO_SUPPRESS_DEPRECATED_START @@ -48,7 +48,6 @@ public: private: bool evaluate_shuffle_channels(const HostTensorVector& outputs, const HostTensorVector& inputs) const; - int64_t m_axis{1}; int64_t m_group{1}; }; diff --git a/src/core/include/openvino/op/util/detection_output_base.hpp b/src/core/include/openvino/op/util/detection_output_base.hpp index 4a8030ae891..28ac6c7b5a2 100644 --- a/src/core/include/openvino/op/util/detection_output_base.hpp +++ b/src/core/include/openvino/op/util/detection_output_base.hpp @@ -34,10 +34,9 @@ public: DetectionOutputBase() = default; DetectionOutputBase(const OutputVector& args); - void validate_and_infer_types_base(const AttributesBase& attrs, Dimension num_classes); + void validate_base(const AttributesBase& attrs); bool visit_attributes_base(AttributeVisitor& visitor, AttributesBase& attrs); - Dimension compute_num_classes(const AttributesBase& attrs); }; } // namespace util diff --git a/src/core/shape_inference/include/detection_output_shape_inference.hpp b/src/core/shape_inference/include/detection_output_shape_inference.hpp new file mode 100644 index 00000000000..df7e1e4a62e --- /dev/null +++ b/src/core/shape_inference/include/detection_output_shape_inference.hpp @@ -0,0 +1,343 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include + +namespace ov { +namespace op { +namespace util { + +template ::value_type::value_type> +void compute_num_classes(const DetectionOutputBase* op, + const DetectionOutputBase::AttributesBase& attrs, + const std::vector& input_shapes, + V& num_classes, + V& num_prior_boxes) { + const T& box_logits_pshape = input_shapes[0]; + const T& class_preds_pshape = input_shapes[1]; + const T& proposals_pshape = input_shapes[2]; + T ad_class_preds_shape{}; + T ad_box_preds_shape{}; + bool have_five_inputs = false; + + NODE_VALIDATION_CHECK(op, + box_logits_pshape.rank().compatible(2), + "Box logits rank must be 2. Got ", + box_logits_pshape.rank().get_length()); + + NODE_VALIDATION_CHECK(op, + class_preds_pshape.rank().compatible(2), + "Class predictions rank must be 2. Got ", + class_preds_pshape.rank().get_length()); + NODE_VALIDATION_CHECK(op, + proposals_pshape.rank().compatible(3), + "Proposals rank must be 3. Got ", + proposals_pshape.rank().get_length()); + if (input_shapes.size() == 5) { + ad_class_preds_shape = input_shapes[3]; + NODE_VALIDATION_CHECK(op, + ad_class_preds_shape.rank().compatible(2), + "Additional class predictions rank must be 2. Got ", + ad_class_preds_shape.rank().get_length()); + ad_box_preds_shape = input_shapes[4]; + NODE_VALIDATION_CHECK(op, + ad_box_preds_shape.rank().compatible(2), + "Additional box predictions rank must be 2. Got ", + ad_box_preds_shape.rank().get_length()); + have_five_inputs = true; + } + + int64_t prior_box_size = attrs.normalized ? 4 : 5; + + // try to deduce a number of prior boxes + if (num_prior_boxes == 0 && proposals_pshape.rank().is_static() && proposals_pshape[2].is_static()) { + NODE_VALIDATION_CHECK(op, + (proposals_pshape[2].get_length()) % prior_box_size == 0, + "Proposals' third dimension must be a multiply of prior_box_size (", + prior_box_size, + "). Current value is: ", + proposals_pshape[2].get_length(), + "."); + num_prior_boxes = (proposals_pshape[2].get_length()) / prior_box_size; + NODE_VALIDATION_CHECK(op, + num_prior_boxes > 0, + "A number of prior boxes must be greater zero. Got: ", + num_prior_boxes); + } + if (num_prior_boxes == 0 && have_five_inputs && ad_class_preds_shape.rank().is_static() && + ad_class_preds_shape[1].is_static()) { + NODE_VALIDATION_CHECK( + op, + (ad_class_preds_shape[1].get_length()) % 2 == 0, + "Additional class predictions second dimension must be a multiply of 2. Current value is: ", + ad_class_preds_shape[1].get_length(), + "."); + num_prior_boxes = (ad_class_preds_shape[1].get_length()) / 2; + NODE_VALIDATION_CHECK(op, + num_prior_boxes > 0, + "A number of prior boxes must be greater zero. Got: ", + num_prior_boxes); + } + + // try to deduce a number of classes + if (num_classes == 0 && num_prior_boxes > 0 && class_preds_pshape.rank().is_static() && + class_preds_pshape[1].is_static()) { + NODE_VALIDATION_CHECK(op, + (class_preds_pshape[1].get_length()) % num_prior_boxes == 0, + "Class predictions second dimension must be a multiply of num_prior_boxes (", + num_prior_boxes, + "). Current value is: ", + class_preds_pshape[1].get_length(), + "."); + num_classes = (class_preds_pshape[1].get_length()) / num_prior_boxes; + } + if (num_classes == 0 && num_prior_boxes > 0 && box_logits_pshape.rank().is_static() && + box_logits_pshape[1].is_static() && !attrs.share_location) { + NODE_VALIDATION_CHECK(op, + (box_logits_pshape[1].get_length()) % (num_prior_boxes * 4) == 0, + "Box logits second dimension must be a multiply of num_prior_boxes * 4 (", + num_prior_boxes * 4, + "). Current value is: ", + box_logits_pshape[1].get_length(), + "."); + num_classes = (box_logits_pshape[1].get_length()) / (num_prior_boxes * 4); + } + if (num_classes == 0 && num_prior_boxes > 0 && have_five_inputs && ad_box_preds_shape.rank().is_static() && + ad_box_preds_shape[1].is_static() && !attrs.share_location) { + NODE_VALIDATION_CHECK(op, + (ad_box_preds_shape[1].get_length()) % (num_prior_boxes * 4) == 0, + "Additional box predictions second dimension must be a multiply of num_prior_boxes * 4 (", + num_prior_boxes * 4, + "). Current value is: ", + ad_box_preds_shape[1].get_length(), + "."); + num_classes = ad_box_preds_shape[1].get_length() / (num_prior_boxes * 4); + } +} + +template +void shape_infer_base(const DetectionOutputBase* op, + const DetectionOutputBase::AttributesBase& attrs, + const std::vector& input_shapes, + std::vector& output_shapes, + int64_t attribute_num_classes) { + using dim_t = typename std::iterator_traits::value_type; + using val_type = typename dim_t::value_type; + + NODE_VALIDATION_CHECK(op, (input_shapes.size() == 3 || input_shapes.size() == 5) && output_shapes.size() == 1); + + auto& ret_output_shape = output_shapes[0]; + ret_output_shape.resize(4); + + const auto& box_logits_pshape = input_shapes[0]; + const auto& class_preds_pshape = input_shapes[1]; + const auto& proposals_pshape = input_shapes[2]; + + val_type num_classes = 0; + val_type num_prior_boxes = 0; + dim_t dim_num_images{}; + bool dim_num_images_updated = false; + + if (attribute_num_classes == -1) { + ov::op::util::compute_num_classes(op, attrs, input_shapes, num_classes, num_prior_boxes); + } else { + num_classes = static_cast(attribute_num_classes); + } + + const val_type num_loc_classes = attrs.share_location ? 1 : num_classes; + const val_type prior_box_size = attrs.normalized ? 4 : 5; + + if (box_logits_pshape.rank().is_static()) { + NODE_VALIDATION_CHECK(op, + box_logits_pshape.size() == 2, + "Box logits rank must be 2. Got ", + box_logits_pshape.size()); + dim_num_images = box_logits_pshape[0]; + dim_num_images_updated = true; + if (!num_prior_boxes && box_logits_pshape[1].is_static()) { + auto box_logits_pshape_2nd_dim = box_logits_pshape[1].get_length(); + NODE_VALIDATION_CHECK(op, + (box_logits_pshape_2nd_dim % (num_loc_classes * 4)) == 0, + "Box logits' second dimension must be a multiply of num_loc_classes * 4 (", + num_loc_classes * 4, + "). Current value is: ", + box_logits_pshape_2nd_dim, + "."); + num_prior_boxes = box_logits_pshape_2nd_dim / (num_loc_classes * 4); + } + } + if (class_preds_pshape.rank().is_static()) { + NODE_VALIDATION_CHECK(op, + class_preds_pshape.size() == 2, + "Class predictions rank must be 2. Got ", + class_preds_pshape.size()); + if ((!dim_num_images_updated || dim_num_images.is_dynamic()) && class_preds_pshape[0].is_static()) { + dim_num_images = class_preds_pshape[0]; + dim_num_images_updated = true; + } else { + NODE_VALIDATION_CHECK( + op, + class_preds_pshape[0].compatible(dim_num_images), + "Class predictions' first dimension is not compatible with batch size. Current value is: ", + class_preds_pshape[0], + ", expected: ", + dim_num_images, + "."); + } + if (class_preds_pshape[1].is_static() && num_classes) { + auto class_preds_pshape_2nd_dim = class_preds_pshape[1].get_length(); + if (!num_prior_boxes) { + NODE_VALIDATION_CHECK(op, + class_preds_pshape_2nd_dim % num_classes == 0, + "Class predictions' second dimension must be a multiply of num_classes (", + num_classes, + "). Current value is: ", + class_preds_pshape_2nd_dim, + "."); + num_prior_boxes = class_preds_pshape_2nd_dim / num_classes; + } else { + NODE_VALIDATION_CHECK(op, + class_preds_pshape_2nd_dim == num_prior_boxes * num_classes, + "Class predictions' second dimension must be equal to num_prior_boxes * " + "num_classes (", + num_prior_boxes * num_classes, + "). Current value is: ", + class_preds_pshape_2nd_dim, + "."); + } + } + } + if (proposals_pshape.rank().is_static()) { + NODE_VALIDATION_CHECK(op, + proposals_pshape.size() == 3, + "Proposals rank must be 3. Got ", + proposals_pshape.size()); + NODE_VALIDATION_CHECK(op, + proposals_pshape[0].compatible(1) || proposals_pshape[0].compatible(dim_num_images), + "Proposals' first dimension is must be equal to either batch size (", + dim_num_images, + ") or 1. Got: ", + proposals_pshape[0], + "."); + + size_t proposals_expected_2nd_dim = attrs.variance_encoded_in_target ? 1 : 2; + NODE_VALIDATION_CHECK(op, + proposals_pshape[1].compatible(proposals_expected_2nd_dim), + "Proposals' second dimension is mismatched. Current value is: ", + proposals_pshape[1], + ", expected: ", + proposals_expected_2nd_dim, + "."); + + if (proposals_pshape[2].is_static()) { + auto proposals_pshape_3rd_dim = proposals_pshape[2].get_length(); + if (!num_prior_boxes) { + NODE_VALIDATION_CHECK(op, + proposals_pshape_3rd_dim % prior_box_size == 0, + "Proposals' third dimension must be a multiply of prior_box_size (", + prior_box_size, + "). Current value is: ", + proposals_pshape_3rd_dim, + "."); + num_prior_boxes = proposals_pshape_3rd_dim / prior_box_size; + } else { + NODE_VALIDATION_CHECK(op, + proposals_pshape_3rd_dim == num_prior_boxes * prior_box_size, + "Proposals' third dimension must be equal to num_prior_boxes " + "* prior_box_size (", + num_prior_boxes * prior_box_size, + "). Current value is: ", + proposals_pshape_3rd_dim, + "."); + } + } + } + + if (input_shapes.size() == 5) { + const auto& aux_class_preds_pshape = input_shapes[3]; + const auto& aux_box_preds_pshape = input_shapes[4]; + if (aux_class_preds_pshape.rank().is_static()) { + NODE_VALIDATION_CHECK(op, + aux_class_preds_pshape.size() == 2, + "additional class predictions rank must be 2. Got ", + aux_class_preds_pshape.size()); + NODE_VALIDATION_CHECK(op, + aux_class_preds_pshape[0].compatible(dim_num_images), + "Additional class predictions' first dimension must be " + "compatible with batch size. Current value is: ", + aux_class_preds_pshape[0], + ", expected: ", + dim_num_images, + "."); + if (num_prior_boxes) { + NODE_VALIDATION_CHECK(op, + aux_class_preds_pshape[1].compatible(num_prior_boxes * 2), + "Additional class predictions' second dimension must be compatible with " + "num_prior_boxes * 2. Current value is: ", + aux_class_preds_pshape[1], + ", expected: ", + num_prior_boxes * 2, + "."); + } + + if (aux_class_preds_pshape[1].is_static()) + num_prior_boxes = aux_class_preds_pshape[1].get_length() / 2; + } + NODE_VALIDATION_CHECK( + op, + aux_box_preds_pshape.compatible(box_logits_pshape), + "Additional box predictions' shape must be compatible with box logits shape. Current value is: ", + aux_box_preds_pshape, + ", expected: ", + box_logits_pshape, + "."); + } + + ret_output_shape[0] = 1; + ret_output_shape[1] = 1; + ret_output_shape[3] = 7; + + const dim_t dim_num_prior_boxes = num_prior_boxes ? dim_t{num_prior_boxes} : Dimension(); + const dim_t dim_num_classes = num_classes ? dim_t{num_classes} : Dimension(); + + if (attrs.keep_top_k[0] > 0) { + ret_output_shape[2] = dim_num_images * attrs.keep_top_k[0]; + } else if (attrs.keep_top_k[0] == -1 && attrs.top_k > 0) { + ret_output_shape[2] = dim_num_images * attrs.top_k * dim_num_classes; + } else { + ret_output_shape[2] = dim_num_images * dim_num_prior_boxes * dim_num_classes; + } +} + +} // namespace util +} // namespace op +} // namespace ov + +namespace ov { +namespace op { +namespace v0 { +template +void shape_infer(const DetectionOutput* op, const std::vector& input_shapes, std::vector& output_shapes) { + const auto& attrs = op->get_attrs(); + ov::op::util::shape_infer_base(op, attrs, input_shapes, output_shapes, attrs.num_classes); +} + +} // namespace v0 +} // namespace op +} // namespace ov + +namespace ov { +namespace op { +namespace v8 { + +template +void shape_infer(const DetectionOutput* op, const std::vector& input_shapes, std::vector& output_shapes) { + ov::op::util::shape_infer_base(op, op->get_attrs(), input_shapes, output_shapes, -1); +} + +} // namespace v8 +} // namespace op +} // namespace ov \ No newline at end of file diff --git a/src/core/shape_inference/include/select_shape_inference.hpp b/src/core/shape_inference/include/select_shape_inference.hpp new file mode 100644 index 00000000000..afc8ee37dce --- /dev/null +++ b/src/core/shape_inference/include/select_shape_inference.hpp @@ -0,0 +1,48 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include + +namespace ov { +namespace op { +namespace v1 { + +template +void shape_infer(const Select* op, const std::vector& input_shapes, std::vector& output_shapes) { + NODE_VALIDATION_CHECK(op, input_shapes.size() == 3 && output_shapes.size() == 1); + + const auto& broadcast_spec = op->get_auto_broadcast(); + auto& result_shape = output_shapes[0]; + if (broadcast_spec.m_type == op::AutoBroadcastType::PDPD) { + result_shape = input_shapes[1]; // 'then' tensor + // in PDPD type, Broacast-merging 'else' into 'then' one way not each other. + NODE_VALIDATION_CHECK(op, + T::broadcast_merge_into(result_shape, input_shapes[2], broadcast_spec), + "'Else' tensor shape is not broadcastable."); + NODE_VALIDATION_CHECK(op, + T::broadcast_merge_into(result_shape, input_shapes[0], broadcast_spec), + "'Cond' tensor shape is not broadcastable."); + } else { + result_shape = input_shapes[2]; + for (int input_port = 1; input_port >= 0; input_port--) { + if (broadcast_spec.m_type == op::AutoBroadcastType::NONE) { + NODE_VALIDATION_CHECK(op, + T::merge_into(result_shape, input_shapes[input_port]), + "Argument shapes are inconsistent."); + } else if (broadcast_spec.m_type == op::AutoBroadcastType::NUMPY) { + NODE_VALIDATION_CHECK(op, + T::broadcast_merge_into(result_shape, input_shapes[input_port], broadcast_spec), + "Argument shapes are inconsistent."); + } else { + NODE_VALIDATION_CHECK(op, false, "Unsupported auto broadcast specification"); + } + } + } +} + +} // namespace v1 +} // namespace op +} // namespace ov \ No newline at end of file diff --git a/src/core/shape_inference/include/shuffle_channels_shape_inference.hpp b/src/core/shape_inference/include/shuffle_channels_shape_inference.hpp new file mode 100644 index 00000000000..587f8e8d7eb --- /dev/null +++ b/src/core/shape_inference/include/shuffle_channels_shape_inference.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include + +namespace ov { +namespace op { +namespace v0 { + +template +void shape_infer(const ShuffleChannels* op, const std::vector& input_shapes, std::vector& output_shapes) { + NODE_VALIDATION_CHECK(op, input_shapes.size() == 1 && output_shapes.size() == 1); + + const auto& group = op->get_group(); + NODE_VALIDATION_CHECK(op, group >= 1, "The 'group' parameter must be greater or equal to 1."); + + const auto& input_shape = input_shapes[0]; + const auto input_shape_rank = input_shape.rank(); + + if (input_shape_rank.is_static()) { + const int64_t input_rank_value = static_cast(input_shape.size()); + NODE_VALIDATION_CHECK(op, input_rank_value >= 1, "The input tensor's shape is expected to be at least 1D."); + + const auto& axis = op->get_axis(); + NODE_VALIDATION_CHECK(op, + axis < input_rank_value && axis >= (0 - input_rank_value), + "The 'axis' parameter for ShuffleChannels has to point to one of the " + "input tensor's shape dimensions."); + size_t axis_zb = static_cast(axis >= 0 ? axis : (axis + input_rank_value)); + + if (input_shape[axis_zb].is_static()) { + const auto channel_dim_size = input_shape[axis_zb].get_length(); + NODE_VALIDATION_CHECK(op, + channel_dim_size % group == 0, + "The channel dimension size has to be a multiple of the groups parameter value."); + } + } + output_shapes[0] = input_shape; +} + +} // namespace v0 +} // namespace op +} // namespace ov \ No newline at end of file diff --git a/src/core/src/op/detection_output.cpp b/src/core/src/op/detection_output.cpp index cac74673f34..92071e01ca6 100644 --- a/src/core/src/op/detection_output.cpp +++ b/src/core/src/op/detection_output.cpp @@ -4,6 +4,8 @@ #include "ngraph/op/detection_output.hpp" +#include + #include "itt.hpp" using namespace std; @@ -33,7 +35,16 @@ ov::op::v0::DetectionOutput::DetectionOutput(const Output& box_logits, void ov::op::v0::DetectionOutput::validate_and_infer_types() { NGRAPH_OP_SCOPE(v0_DetectionOutput_validate_and_infer_types); NODE_VALIDATION_CHECK(this, m_attrs.num_classes > 0, "Number of classes must be greater than zero"); - validate_and_infer_types_base(m_attrs, m_attrs.num_classes); + validate_base(m_attrs); + std::vector input_shapes; + for (auto input_idx = 0; input_idx < get_input_size(); input_idx++) + input_shapes.push_back(get_input_partial_shape(input_idx)); + std::vector output_shapes = {ov::PartialShape{}}; + + shape_infer(this, input_shapes, output_shapes); + + set_output_size(1); + set_output_type(0, get_input_element_type(0), output_shapes[0]); } shared_ptr ov::op::v0::DetectionOutput::clone_with_new_inputs(const OutputVector& new_args) const { @@ -86,8 +97,17 @@ ov::op::v8::DetectionOutput::DetectionOutput(const Output& box_logits, } void ov::op::v8::DetectionOutput::validate_and_infer_types() { - NGRAPH_OP_SCOPE(v0_DetectionOutput_validate_and_infer_types); - validate_and_infer_types_base(m_attrs, Dimension::dynamic()); + NGRAPH_OP_SCOPE(v8_DetectionOutput_validate_and_infer_types); + validate_base(m_attrs); + std::vector input_shapes; + for (auto input_idx = 0; input_idx < get_input_size(); input_idx++) + input_shapes.push_back(get_input_partial_shape(input_idx)); + std::vector output_shapes = {ov::PartialShape{}}; + + shape_infer(this, input_shapes, output_shapes); + + set_output_size(1); + set_output_type(0, get_input_element_type(0), output_shapes[0]); } shared_ptr ov::op::v8::DetectionOutput::clone_with_new_inputs(const OutputVector& new_args) const { @@ -114,4 +134,4 @@ bool ov::op::v8::DetectionOutput::visit_attributes(AttributeVisitor& visitor) { NGRAPH_OP_SCOPE(v0_DetectionOutput_visit_attributes); visit_attributes_base(visitor, m_attrs); return true; -} +} \ No newline at end of file diff --git a/src/core/src/op/select.cpp b/src/core/src/op/select.cpp index 15f6af798e8..ea098d43a66 100644 --- a/src/core/src/op/select.cpp +++ b/src/core/src/op/select.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "itt.hpp" #include "ngraph/attribute_visitor.hpp" @@ -42,36 +43,12 @@ void op::v1::Select::validate_and_infer_types() { element::Type::merge(result_et, get_input_element_type(1), get_input_element_type(2)), "Argument 1 and 2 element types must match."); - ov::PartialShape result_shape; - if (get_auto_broadcast().m_type == op::AutoBroadcastType::PDPD) { - result_shape = get_input_partial_shape(1); // 'then' tensor - NODE_VALIDATION_CHECK( - this, - ov::PartialShape::broadcast_merge_into(result_shape, get_input_partial_shape(2), get_auto_broadcast()), - "'Else' tensor shape is not broadcastable."); - NODE_VALIDATION_CHECK( - this, - ov::PartialShape::broadcast_merge_into(result_shape, get_input_partial_shape(0), get_auto_broadcast()), - "'Cond' tensor shape is not broadcastable."); - } else { - result_shape = get_input_partial_shape(2); - for (int i = 1; i >= 0; i--) { - if (get_auto_broadcast().m_type == op::AutoBroadcastType::NONE) { - NODE_VALIDATION_CHECK(this, - ov::PartialShape::merge_into(result_shape, get_input_partial_shape(i)), - "Argument shapes are inconsistent."); - } else if (get_auto_broadcast().m_type == op::AutoBroadcastType::NUMPY) { - NODE_VALIDATION_CHECK(this, - ov::PartialShape::broadcast_merge_into(result_shape, - get_input_partial_shape(i), - get_auto_broadcast()), - "Argument shapes are inconsistent."); - } else { - NODE_VALIDATION_CHECK(this, false, "Unsupported auto broadcast specification"); - } - } - } - set_output_type(0, result_et, result_shape); + std::vector output_shapes = {ov::PartialShape{}}; + const std::vector 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, result_et, output_shapes[0]); } shared_ptr op::v1::Select::clone_with_new_inputs(const OutputVector& new_args) const { diff --git a/src/core/src/op/shuffle_channels.cpp b/src/core/src/op/shuffle_channels.cpp index 6a44f846c0a..6866eba13e8 100644 --- a/src/core/src/op/shuffle_channels.cpp +++ b/src/core/src/op/shuffle_channels.cpp @@ -5,6 +5,7 @@ #include "ngraph/op/shuffle_channels.hpp" #include +#include #include "itt.hpp" #include "ngraph/attribute_visitor.hpp" @@ -48,25 +49,12 @@ size_t op::ShuffleChannels::get_zero_based_axis() const { void op::ShuffleChannels::validate_and_infer_types() { NGRAPH_OP_SCOPE(v0_ShuffleChannels_validate_and_infer_types); + const auto& data_type = get_input_element_type(0); - if (get_input_partial_shape(0).is_static()) { - const auto shape = get_input_shape(0); - NODE_VALIDATION_CHECK(this, shape.size() >= 1, "The input tensor's shape is expected to be at least 1D."); - - size_t axis_zb = get_zero_based_axis(); - NODE_VALIDATION_CHECK(this, - axis_zb < shape.size(), - "The 'axis' parameter for ShuffleChannels has to point to one of the " - "input tensor's shape dimensions."); - - NODE_VALIDATION_CHECK(this, m_group >= 1, "The 'group' parameter must be greater or equal to 1."); - - const auto channel_dim_size = shape.at(axis_zb); - NODE_VALIDATION_CHECK(this, - channel_dim_size % m_group == 0, - "The channel dimension size has to be a multiple of the groups parameter value."); - } - set_output_type(0, data_type, get_input_partial_shape(0)); + std::vector output_shapes = {ov::PartialShape{}}; + const std::vector input_shapes = {get_input_partial_shape(0)}; + shape_infer(this, input_shapes, output_shapes); + set_output_type(0, data_type, output_shapes[0]); } shared_ptr op::ShuffleChannels::clone_with_new_inputs(const OutputVector& new_args) const { diff --git a/src/core/src/op/util/detection_output_base.cpp b/src/core/src/op/util/detection_output_base.cpp index c8e2462c012..b16de435600 100644 --- a/src/core/src/op/util/detection_output_base.cpp +++ b/src/core/src/op/util/detection_output_base.cpp @@ -4,6 +4,7 @@ #include "ngraph/op/util/detection_output_base.hpp" +#include #include #include "ngraph/op/concat.hpp" @@ -17,128 +18,7 @@ using namespace ov::op::util; DetectionOutputBase::DetectionOutputBase(const ov::OutputVector& args) : Op(args) {} -ov::Dimension DetectionOutputBase::compute_num_classes(const AttributesBase& attrs) { - Dimension num_classes = Dimension::dynamic(); - - NODE_VALIDATION_CHECK(this, - 3 <= get_input_size() && get_input_size() <= 5, - "A number of arguments must be greater than or equal to 3 and less than or equal to 5. Got " + - std::to_string(get_input_size())); - - const ov::PartialShape& box_logits_pshape = get_input_partial_shape(0); - const ov::PartialShape& class_preds_pshape = get_input_partial_shape(1); - const ov::PartialShape& proposals_pshape = get_input_partial_shape(2); - ov::PartialShape ad_class_preds_shape = ov::PartialShape::dynamic(); - ov::PartialShape ad_box_preds_shape = ov::PartialShape::dynamic(); - - if (box_logits_pshape.rank().is_static()) { - NODE_VALIDATION_CHECK( - this, - box_logits_pshape.rank().get_length() == 2, - "Box logits rank must be 2. Got " + std::to_string(box_logits_pshape.rank().get_length())); - } - if (class_preds_pshape.rank().is_static()) { - NODE_VALIDATION_CHECK( - this, - class_preds_pshape.rank().get_length() == 2, - "Class predictions rank must be 2. Got " + std::to_string(class_preds_pshape.rank().get_length())); - } - if (proposals_pshape.rank().is_static()) { - NODE_VALIDATION_CHECK(this, - proposals_pshape.rank().get_length() == 3, - "Proposals rank must be 3. Got " + std::to_string(proposals_pshape.rank().get_length())); - } - if (get_input_size() >= 4) { - ad_class_preds_shape = get_input_partial_shape(3); - if (ad_class_preds_shape.rank().is_static()) { - NODE_VALIDATION_CHECK(this, - ad_class_preds_shape.rank().get_length() == 2, - "Additional class predictions rank must be 2. Got " + - std::to_string(ad_class_preds_shape.rank().get_length())); - } - } - if (get_input_size() == 5) { - ad_box_preds_shape = get_input_partial_shape(4); - if (ad_box_preds_shape.rank().is_static()) { - NODE_VALIDATION_CHECK(this, - ad_box_preds_shape.rank().get_length() == 2, - "Additional box predictions rank must be 2. Got " + - std::to_string(ad_box_preds_shape.rank().get_length())); - } - } - - int prior_box_size = attrs.normalized ? 4 : 5; - Dimension num_prior_boxes = Dimension::dynamic(); - - // try to deduce a number of prior boxes - if (num_prior_boxes.is_dynamic() && proposals_pshape.rank().is_static() && proposals_pshape[2].is_static()) { - NODE_VALIDATION_CHECK(this, - proposals_pshape[2].get_length() % prior_box_size == 0, - "Proposals' third dimension must be a multiply of prior_box_size (" + - std::to_string(prior_box_size) + "). Current value is: ", - proposals_pshape[2].get_length(), - "."); - num_prior_boxes = proposals_pshape[2].get_length() / prior_box_size; - NODE_VALIDATION_CHECK( - this, - num_prior_boxes.get_length() > 0, - "A number of prior boxes must be greater zero. Got: " + std::to_string(num_prior_boxes.get_length())); - } - if (num_prior_boxes.is_dynamic() && ad_class_preds_shape.rank().is_static() && - ad_class_preds_shape[1].is_static()) { - NODE_VALIDATION_CHECK( - this, - ad_class_preds_shape[1].get_length() % 2 == 0, - "Additional class predictions second dimension must be a multiply of 2. Current value is: ", - ad_class_preds_shape[1].get_length(), - "."); - num_prior_boxes = ad_class_preds_shape[1].get_length() / 2; - NODE_VALIDATION_CHECK( - this, - num_prior_boxes.get_length() > 0, - "A number of prior boxes must be greater zero. Got: " + std::to_string(num_prior_boxes.get_length())); - } - - // try to deduce a number of classes - if (num_classes.is_dynamic() && num_prior_boxes.is_static() && class_preds_pshape.rank().is_static() && - class_preds_pshape[1].is_static()) { - NODE_VALIDATION_CHECK(this, - class_preds_pshape[1].get_length() % num_prior_boxes.get_length() == 0, - "Class predictions second dimension must be a multiply of num_prior_boxes (" + - std::to_string(num_prior_boxes.get_length()) + "). Current value is: ", - class_preds_pshape[1].get_length(), - "."); - num_classes = class_preds_pshape[1].get_length() / num_prior_boxes.get_length(); - } - if (num_classes.is_dynamic() && num_prior_boxes.is_static() && box_logits_pshape.rank().is_static() && - box_logits_pshape[1].is_static() && !attrs.share_location) { - NODE_VALIDATION_CHECK(this, - box_logits_pshape[1].get_length() % (num_prior_boxes.get_length() * 4) == 0, - "Box logits second dimension must be a multiply of num_prior_boxes * 4 (" + - std::to_string(num_prior_boxes.get_length() * 4) + "). Current value is: ", - box_logits_pshape[1].get_length(), - "."); - num_classes = box_logits_pshape[1].get_length() / (num_prior_boxes.get_length() * 4); - } - if (num_classes.is_dynamic() && num_prior_boxes.is_static() && ad_box_preds_shape.is_static() && - ad_box_preds_shape[1].is_static() && !attrs.share_location) { - NODE_VALIDATION_CHECK( - this, - ad_box_preds_shape[1].get_length() % (num_prior_boxes.get_length() * 4) == 0, - "Additional box predictions second dimension must be a multiply of num_prior_boxes * 4 (" + - std::to_string(num_prior_boxes.get_length() * 4) + "). Current value is: ", - ad_box_preds_shape[1].get_length(), - "."); - num_classes = ad_box_preds_shape[1].get_length() / (num_prior_boxes.get_length() * 4); - } - - return num_classes; -} - -void DetectionOutputBase::validate_and_infer_types_base(const DetectionOutputBase::AttributesBase& attrs, - ov::Dimension num_classes) { - NODE_VALIDATION_CHECK(this, attrs.keep_top_k.size() > 0, "keep_top_k attribute must be provided"); - +void DetectionOutputBase::validate_base(const DetectionOutputBase::AttributesBase& attrs) { NODE_VALIDATION_CHECK( this, attrs.code_type == "caffe.PriorBoxParameter.CORNER" || attrs.code_type == "caffe.PriorBoxParameter.CENTER_SIZE", @@ -159,117 +39,7 @@ void DetectionOutputBase::validate_and_infer_types_base(const DetectionOutputBas proposals_et.is_real(), "Proposals' data type must be floating point. Got " + proposals_et.get_type_name()); - const ov::PartialShape& box_logits_pshape = get_input_partial_shape(0); - const ov::PartialShape& class_preds_pshape = get_input_partial_shape(1); - const ov::PartialShape& proposals_pshape = get_input_partial_shape(2); - - // deduce a number of classes for DetectionOutput-8 - if (num_classes.is_dynamic()) { - num_classes = compute_num_classes(attrs); - } - - Dimension num_loc_classes = attrs.share_location ? 1 : num_classes; - int prior_box_size = attrs.normalized ? 4 : 5; - - Dimension num_images = Dimension::dynamic(); - Dimension num_prior_boxes = Dimension::dynamic(); - if (box_logits_pshape.rank().is_static()) { - NODE_VALIDATION_CHECK( - this, - box_logits_pshape.rank().get_length() == 2, - "Box logits rank must be 2. Got " + std::to_string(box_logits_pshape.rank().get_length())); - num_images = box_logits_pshape[0]; - if (box_logits_pshape[1].is_static() && num_loc_classes.is_static()) { - NODE_VALIDATION_CHECK(this, - (box_logits_pshape[1].get_length() % (num_loc_classes.get_length() * 4)) == 0, - "Box logits' second dimension must be a multiply of num_loc_classes * 4 (" + - std::to_string(num_loc_classes.get_length() * 4) + "). Current value is: ", - box_logits_pshape[1].get_length(), - "."); - num_prior_boxes = box_logits_pshape[1].get_length() / (num_loc_classes.get_length() * 4); - } - } - if (class_preds_pshape.rank().is_static()) { - NODE_VALIDATION_CHECK( - this, - class_preds_pshape.rank().get_length() == 2, - "Class predictions rank must be 2. Got " + std::to_string(class_preds_pshape.rank().get_length())); - if (num_images.is_dynamic() && class_preds_pshape[0].is_static()) { - num_images = class_preds_pshape[0]; - } else { - NODE_VALIDATION_CHECK(this, - class_preds_pshape[0].compatible(num_images), - "Class predictions' first dimension is not compatible with batch size."); - } - if (class_preds_pshape[1].is_static()) { - if (num_prior_boxes.is_dynamic() && num_classes.is_static()) { - NODE_VALIDATION_CHECK(this, - class_preds_pshape[1].get_length() % num_classes.get_length() == 0, - "Class predictions' second dimension must be a multiply of num_classes (" + - std::to_string(num_classes.get_length()) + "). Current value is: ", - class_preds_pshape[1].get_length(), - "."); - num_prior_boxes = class_preds_pshape[1].get_length() / num_classes.get_length(); - } else if (num_classes.is_static()) { - int num_prior_boxes_val = num_prior_boxes.get_length(); - NODE_VALIDATION_CHECK( - this, - class_preds_pshape[1].get_length() == num_prior_boxes_val * num_classes.get_length(), - "Class predictions' second dimension must be equal to num_prior_boxes * " - "num_classes (" + - std::to_string(num_prior_boxes_val * num_classes.get_length()) + "). Current value is: ", - class_preds_pshape[1].get_length(), - "."); - } - } - } - if (proposals_pshape.rank().is_static()) { - NODE_VALIDATION_CHECK(this, - proposals_pshape.rank().get_length() == 3, - "Proposals rank must be 3. Got " + std::to_string(proposals_pshape.rank().get_length())); - if (num_images.is_static() && proposals_pshape[0].is_static()) { - int64_t proposals_1st_dim = proposals_pshape[0].get_length(); - int64_t num_images_val = num_images.get_length(); - NODE_VALIDATION_CHECK(this, - proposals_1st_dim == 1 || proposals_1st_dim == num_images_val, - "Proposals' first dimension is must be equal to either batch size (" + - std::to_string(num_images_val) + - ") or 1. Got: " + std::to_string(proposals_1st_dim) + "."); - } - if (proposals_pshape[1].is_static()) { - size_t proposals_expected_2nd_dim = attrs.variance_encoded_in_target ? 1 : 2; - NODE_VALIDATION_CHECK(this, - proposals_pshape[1].compatible(proposals_expected_2nd_dim), - "Proposals' second dimension is mismatched. Current value is: ", - proposals_pshape[1].get_length(), - ", expected: ", - proposals_expected_2nd_dim, - "."); - } - if (proposals_pshape[2].is_static()) { - if (num_prior_boxes.is_dynamic()) { - NODE_VALIDATION_CHECK(this, - proposals_pshape[2].get_length() % prior_box_size == 0, - "Proposals' third dimension must be a multiply of prior_box_size (" + - std::to_string(prior_box_size) + "). Current value is: ", - proposals_pshape[2].get_length(), - "."); - num_prior_boxes = proposals_pshape[2].get_length() / prior_box_size; - } else { - int num_prior_boxes_val = num_prior_boxes.get_length(); - NODE_VALIDATION_CHECK(this, - proposals_pshape[2].get_length() == num_prior_boxes_val * prior_box_size, - "Proposals' third dimension must be equal to num_prior_boxes " - "* prior_box_size (" + - std::to_string(num_prior_boxes_val * prior_box_size) + - "). Current value is: ", - proposals_pshape[2].get_length(), - "."); - } - } - } - - if (get_input_size() > 3) { + if (get_input_size() == 5) { auto aux_class_preds_et = get_input_element_type(3); NODE_VALIDATION_CHECK(this, aux_class_preds_et == class_preds_et, @@ -281,42 +51,7 @@ void DetectionOutputBase::validate_and_infer_types_base(const DetectionOutputBas aux_box_preds_et == box_logits_et, "Additional box predictions' data type must be the same as box logits data type (" + box_logits_et.get_type_name() + "). Got " + aux_box_preds_et.get_type_name()); - - const ov::PartialShape& aux_class_preds_pshape = get_input_partial_shape(3); - const ov::PartialShape& aux_box_preds_pshape = get_input_partial_shape(4); - if (aux_class_preds_pshape.rank().is_static()) { - NODE_VALIDATION_CHECK(this, - aux_class_preds_pshape[0].compatible(num_images), - "Additional class predictions' first dimension must be " - "compatible with batch size."); - if (num_prior_boxes.is_static()) { - int num_prior_boxes_val = num_prior_boxes.get_length(); - NODE_VALIDATION_CHECK(this, - aux_class_preds_pshape[1].get_length() == num_prior_boxes_val * 2, - "Additional class predictions' second dimension must be equal to " - "num_prior_boxes * 2 (" + - std::to_string(num_prior_boxes_val * 2) + "). Got " + - std::to_string(aux_class_preds_pshape[1].get_length()) + "."); - } - } - NODE_VALIDATION_CHECK(this, - aux_box_preds_pshape.compatible(box_logits_pshape), - "Additional box predictions' shape must be compatible with box logits shape."); } - - std::vector output_shape{1, 1}; - if (attrs.keep_top_k[0] > 0) { - output_shape.push_back(num_images * attrs.keep_top_k[0]); - } else if (attrs.top_k > 0 && num_classes.is_static()) { - output_shape.push_back(num_images * attrs.top_k * num_classes); - } else if (num_classes.is_static()) { - output_shape.push_back(num_images * num_prior_boxes * num_classes); - } else { - output_shape.push_back(Dimension::dynamic()); - } - output_shape.emplace_back(7); - - set_output_type(0, box_logits_et, output_shape); } bool ov::op::util::DetectionOutputBase::visit_attributes_base(AttributeVisitor& visitor, @@ -338,3 +73,23 @@ bool ov::op::util::DetectionOutputBase::visit_attributes_base(AttributeVisitor& visitor.on_attribute("objectness_score", attrs.objectness_score); return true; } + +ov::Dimension DetectionOutputBase::compute_num_classes(const AttributesBase& attrs) { + NODE_VALIDATION_CHECK(this, + 3 == get_input_size() || get_input_size() == 5, + "A number of arguments must be equal to 3 or equal to 5. Got ", + get_input_size()); + + std::vector input_shapes; + for (auto input_idx = 0; input_idx < get_input_size(); input_idx++) + input_shapes.push_back(get_input_partial_shape(input_idx)); + std::vector output_shapes = {ov::PartialShape{}}; + + int64_t num_classes = 0; + int64_t num_prior_boxes_calculated = 0; + ov::op::util::compute_num_classes(this, attrs, input_shapes, num_classes, num_prior_boxes_calculated); + if (num_classes > 0) + return ov::Dimension{num_classes}; + else + return ov::Dimension::dynamic(); +} \ No newline at end of file diff --git a/src/core/src/partial_shape.cpp b/src/core/src/partial_shape.cpp index 78f266bc122..00b3d71960d 100644 --- a/src/core/src/partial_shape.cpp +++ b/src/core/src/partial_shape.cpp @@ -298,6 +298,9 @@ bool ov::PartialShape::broadcast_merge_into(PartialShape& dst, // Ranks are both static. auto dst_rank = dst.rank().get_length(); auto src_rank = src.rank().get_length(); + // source rank can't be bigger than destination rank according to PDPD broadcast rule. + if (src_rank > dst_rank) + return false; if (dst_rank == src_rank && dst.compatible(src)) return true; diff --git a/src/core/tests/type_prop/detection_output.cpp b/src/core/tests/type_prop/detection_output.cpp index ed7b83ae859..eb8e2db1a1f 100644 --- a/src/core/tests/type_prop/detection_output.cpp +++ b/src/core/tests/type_prop/detection_output.cpp @@ -135,6 +135,25 @@ TEST(type_prop_layers, detection_output_no_share_location) { ASSERT_EQ(op->get_element_type(), element::f32); } +TEST(type_prop_layers, detection_output_calculated_num_prior_boxes) { + op::DetectionOutputAttrs attrs; + attrs.keep_top_k = {-1}; + attrs.top_k = -1; + attrs.normalized = true; + attrs.num_classes = 2; + attrs.share_location = false; + auto op = create_detection_output(PartialShape{4, -1}, + PartialShape::dynamic(), + PartialShape::dynamic(), + PartialShape{-1, 20}, + PartialShape::dynamic(), + attrs, + element::f32, + element::f32); + ASSERT_EQ(op->get_shape(), (Shape{1, 1, 80, 7})); + ASSERT_EQ(op->get_element_type(), element::f32); +} + TEST(type_prop_layers, detection_output_top_k) { op::DetectionOutputAttrs attrs; attrs.keep_top_k = {-1}; @@ -594,9 +613,10 @@ TEST(type_prop_layers, detection_output_invalid_aux_class_preds) { element::f32); FAIL() << "Exception expected"; } catch (const NodeValidationFailure& error) { - EXPECT_HAS_SUBSTRING(error.what(), - std::string("Additional class predictions' second dimension must " - "be equal to num_prior_boxes * 2 (6). Got 7.")); + EXPECT_HAS_SUBSTRING( + error.what(), + std::string("Additional class predictions' second dimension must " + "be compatible with num_prior_boxes * 2. Current value is: 7, expected: 6.")); } catch (...) { FAIL() << "Unknown exception was thrown"; } diff --git a/src/core/tests/type_prop/select.cpp b/src/core/tests/type_prop/select.cpp index ac8aa7cd4e4..041926e026a 100644 --- a/src/core/tests/type_prop/select.cpp +++ b/src/core/tests/type_prop/select.cpp @@ -243,9 +243,16 @@ INSTANTIATE_TEST_SUITE_P( // TODO: Whats the right behavior here? // SelectParams({{2}, {2, 4}, {2}, {2, 4}}, {element::boolean, element::f32, // element::dynamic, element::f32}, {op::AutoBroadcastType::PDPD, 0}), + SelectParams({{4}, {2, 4}, {2, 4}, {2, 4}}, + {element::boolean, element::f32, element::f32, element::f32}, + {op::AutoBroadcastType::PDPD, 1}), SelectParams({{4}, {2, 4}, {4}, {2, 4}}, {element::boolean, element::f32, element::dynamic, element::f32}, - {op::AutoBroadcastType::PDPD, 1})), + {op::AutoBroadcastType::PDPD, 1}), + SelectParams({{4}, {4, 2, 3, 8}, {4, 2, 3, 1}, {4, 2, 3, 8}}, + {element::boolean, element::f32, element::f32, element::f32}, + {op::AutoBroadcastType::PDPD, 0})), + PrintToDummyParamName()); TEST(type_prop, select_v1_partial_shape) { diff --git a/src/core/tests/type_prop/shuffle_channels.cpp b/src/core/tests/type_prop/shuffle_channels.cpp index ea08f51d445..9f556144b23 100644 --- a/src/core/tests/type_prop/shuffle_channels.cpp +++ b/src/core/tests/type_prop/shuffle_channels.cpp @@ -128,6 +128,32 @@ TEST(type_prop, shuffle_channels_negative_axis_calculation) { EXPECT_EQ(shuffle_channels->get_zero_based_axis(), 1); } +TEST(type_prop, shuffle_channels_infer_shape_with_negative_axis_calculation) { + // Only when the length of `axis` dimension is even, the shuffle_channels OP can work correctly. + const auto group = 2; + { + const auto data_input_shape = Shape{1, 3, 5, 8}; + const auto data = make_shared(element::f64, data_input_shape); + + const auto shuffle_channels = make_shared(data, -1, group); + EXPECT_EQ(shuffle_channels->get_output_partial_shape(0), data_input_shape); + } + { + const auto data_input_shape = Shape{1, 3, 8, 5}; + const auto data = make_shared(element::f64, data_input_shape); + + const auto shuffle_channels = make_shared(data, -2, group); + EXPECT_EQ(shuffle_channels->get_output_partial_shape(0), data_input_shape); + } + { + const auto data_input_shape = Shape{8, 3, 5, 7}; + const auto data = make_shared(element::f64, data_input_shape); + + const auto shuffle_channels = make_shared(data, -4, group); + EXPECT_EQ(shuffle_channels->get_output_partial_shape(0), data_input_shape); + } +} + TEST(type_prop, shuffle_channels_invalid_input_shape) { try { const auto data = make_shared(element::f64, Shape{}); diff --git a/src/plugins/intel_cpu/src/utils/shape_inference/shape_inference.cpp b/src/plugins/intel_cpu/src/utils/shape_inference/shape_inference.cpp index 3e1a3b083d3..273b8265e3e 100644 --- a/src/plugins/intel_cpu/src/utils/shape_inference/shape_inference.cpp +++ b/src/plugins/intel_cpu/src/utils/shape_inference/shape_inference.cpp @@ -56,6 +56,9 @@ #include "roi_align_shape_inference.hpp" #include "roll_shape_inference.hpp" #include "proposal_shape_inference.hpp" +#include "detection_output_shape_inference.hpp" +#include "select_shape_inference.hpp" +#include "shuffle_channels_shape_inference.hpp" #include "static_shape.hpp" #include "tile_shape_inference.hpp" #include "utils.hpp" @@ -218,6 +221,14 @@ void shape_inference(ov::Node* op, shape_infer(node, input_shapes, output_shapes); } else if (auto node = ov::as_type(op)) { shape_infer(node, input_shapes, output_shapes); + } else if (auto node = ov::as_type(op)) { + shape_infer(node, input_shapes, output_shapes); + } else if (auto node = ov::as_type(op)) { + shape_infer(node, input_shapes, output_shapes); + } else if (auto node = ov::as_type(op)) { + shape_infer(node, input_shapes, output_shapes); + } else if (auto node = ov::as_type(op)) { + shape_infer(node, input_shapes, output_shapes); } else { ngraph::OutputVector new_inputs; for (size_t i = 0; i < op->get_input_size(); ++i) { diff --git a/src/plugins/intel_cpu/src/utils/shape_inference/static_shape.cpp b/src/plugins/intel_cpu/src/utils/shape_inference/static_shape.cpp index 1a684d663ab..197c2196987 100644 --- a/src/plugins/intel_cpu/src/utils/shape_inference/static_shape.cpp +++ b/src/plugins/intel_cpu/src/utils/shape_inference/static_shape.cpp @@ -124,6 +124,10 @@ bool ov::StaticShape::broadcast_merge_into(StaticShape& dst, // Ranks are both static. auto dst_rank = dst.rank().get_length(); auto src_rank = src.rank().get_length(); + // source rank can't be bigger than destination rank according to + // PDPD broadcast rule. + if (src_rank > dst_rank) + return false; if (dst_rank == src_rank && dst.compatible(src)) return true; diff --git a/src/tests/unit/cpu/shape_inference_test/detection_output_shape_inference.cpp b/src/tests/unit/cpu/shape_inference_test/detection_output_shape_inference.cpp new file mode 100644 index 00000000000..adaa19b58e1 --- /dev/null +++ b/src/tests/unit/cpu/shape_inference_test/detection_output_shape_inference.cpp @@ -0,0 +1,177 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include +#include +#include + +#include "utils/shape_inference/static_shape.hpp" + +using namespace ov; + +template +std::shared_ptr create_detection_output(const PartialShape& box_logits_shape, + const PartialShape& class_preds_shape, + const PartialShape& proposals_shape, + const PartialShape& aux_class_preds_shape, + const PartialShape& aux_box_preds_shape, + T2& attrs, + element::Type input_type, + element::Type proposals_type) { + auto box_logits = std::make_shared(input_type, box_logits_shape); + auto class_preds = std::make_shared(input_type, class_preds_shape); + auto proposals = std::make_shared(proposals_type, proposals_shape); + auto aux_class_preds = std::make_shared(input_type, aux_class_preds_shape); + auto aux_box_preds = std::make_shared(input_type, aux_box_preds_shape); + return std::make_shared(box_logits, class_preds, proposals, aux_class_preds, aux_box_preds, attrs); +} + +TEST(StaticShapeInferenceTest, detection_output_top_k) { + op::v0::DetectionOutput::Attributes attrs; + attrs.keep_top_k = {-1}; + attrs.top_k = 7; + attrs.normalized = true; + attrs.num_classes = 2; + auto op = create_detection_output(PartialShape{4, 20}, + PartialShape{4, 10}, + PartialShape{4, 2, 20}, + PartialShape{4, 10}, + PartialShape{4, 20}, + attrs, + element::f32, + element::f32); + + const std::vector input_shapes = {StaticShape{4, 20}, + StaticShape{4, 10}, + StaticShape{4, 2, 20}, + StaticShape{4, 10}, + StaticShape{4, 20}}; + std::vector output_shapes = {StaticShape{}}; + shape_inference(op.get(), input_shapes, output_shapes); + ASSERT_EQ(output_shapes[0], StaticShape({1, 1, 56, 7})); +} + +TEST(StaticShapeInferenceTest, detection_output_no_share_location) { + op::v0::DetectionOutput::Attributes attrs; + attrs.keep_top_k = {-1}; + attrs.top_k = -1; + attrs.normalized = true; + attrs.num_classes = 2; + attrs.share_location = false; + auto op = create_detection_output(PartialShape{4, 40}, + PartialShape{4, 10}, + PartialShape{4, 2, 20}, + PartialShape{4, 10}, + PartialShape{4, 40}, + attrs, + element::f32, + element::f32); + + const std::vector input_shapes = {StaticShape{4, 40}, + StaticShape{4, 10}, + StaticShape{4, 2, 20}, + StaticShape{4, 10}, + StaticShape{4, 40}}; + std::vector output_shapes = {StaticShape{}}; + shape_inference(op.get(), input_shapes, output_shapes); + ASSERT_EQ(output_shapes[0], StaticShape({1, 1, 40, 7})); +} + +TEST(StaticShapeInferenceTest, detection_output) { + op::v0::DetectionOutput::Attributes attrs; + attrs.keep_top_k = {200}; + attrs.num_classes = 2; + attrs.normalized = true; + auto op = create_detection_output(PartialShape{4, 20}, + PartialShape{4, 10}, + PartialShape{4, 2, 20}, + PartialShape{4, 10}, + PartialShape{4, 20}, + attrs, + element::f32, + element::f32); + + const std::vector input_shapes = {StaticShape{4, 20}, + StaticShape{4, 10}, + StaticShape{4, 2, 20}, + StaticShape{4, 10}, + StaticShape{4, 20}}; + std::vector output_shapes = {StaticShape{}}; + shape_inference(op.get(), input_shapes, output_shapes); + ASSERT_EQ(output_shapes[0], (StaticShape{1, 1, 800, 7})); +} + +TEST(StaticShapeInferenceTest, detection_outputv8_top_k) { + op::v8::DetectionOutput::Attributes attrs; + attrs.keep_top_k = {-1}; + attrs.top_k = 7; + attrs.normalized = true; + auto op = create_detection_output(PartialShape{4, 20}, + PartialShape{4, 10}, + PartialShape{4, 2, 20}, + PartialShape{4, 10}, + PartialShape{4, 20}, + attrs, + element::f32, + element::f32); + + const std::vector input_shapes = {StaticShape{4, 20}, + StaticShape{4, 10}, + StaticShape{4, 2, 20}, + StaticShape{4, 10}, + StaticShape{4, 20}}; + std::vector output_shapes = {StaticShape{}}; + shape_inference(op.get(), input_shapes, output_shapes); + ASSERT_EQ(output_shapes[0], StaticShape({1, 1, 56, 7})); +} + +TEST(StaticShapeInferenceTest, detection_outputv8_no_share_location) { + op::v8::DetectionOutput::Attributes attrs; + attrs.keep_top_k = {-1}; + attrs.top_k = -1; + attrs.normalized = true; + attrs.share_location = false; + auto op = create_detection_output(PartialShape{4, 40}, + PartialShape{4, 10}, + PartialShape{4, 2, 20}, + PartialShape{4, 10}, + PartialShape{4, 40}, + attrs, + element::f32, + element::f32); + + const std::vector input_shapes = {StaticShape{4, 40}, + StaticShape{4, 10}, + StaticShape{4, 2, 20}, + StaticShape{4, 10}, + StaticShape{4, 40}}; + std::vector output_shapes = {StaticShape{}}; + shape_inference(op.get(), input_shapes, output_shapes); + ASSERT_EQ(output_shapes[0], StaticShape({1, 1, 40, 7})); +} + +TEST(StaticShapeInferenceTest, detection_output_v8) { + op::v8::DetectionOutput::Attributes attrs; + attrs.keep_top_k = {200}; + attrs.normalized = true; + auto op = create_detection_output(PartialShape{4, 20}, + PartialShape{4, 10}, + PartialShape{4, 2, 20}, + PartialShape{4, 10}, + PartialShape{4, 20}, + attrs, + element::f32, + element::f32); + + const std::vector input_shapes = {StaticShape{4, 20}, + StaticShape{4, 10}, + StaticShape{4, 2, 20}, + StaticShape{4, 10}, + StaticShape{4, 20}}; + std::vector output_shapes = {StaticShape{}}; + shape_inference(op.get(), input_shapes, output_shapes); + ASSERT_EQ(output_shapes[0], (StaticShape{1, 1, 800, 7})); +} \ No newline at end of file diff --git a/src/tests/unit/cpu/shape_inference_test/select_shape_inference.cpp b/src/tests/unit/cpu/shape_inference_test/select_shape_inference.cpp new file mode 100644 index 00000000000..8821127ea69 --- /dev/null +++ b/src/tests/unit/cpu/shape_inference_test/select_shape_inference.cpp @@ -0,0 +1,63 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include +#include +#include + +#include "utils/shape_inference/static_shape.hpp" + +using namespace ov; + +TEST(StaticShapeInferenceTest, SelectTestBCastModeNUMPY) { + auto cond = std::make_shared(element::boolean, PartialShape{}); + auto ptrue = std::make_shared(element::f32, PartialShape{}); + auto pfalse = std::make_shared(element::f32, PartialShape{}); + auto select = std::make_shared(cond, ptrue, pfalse, op::AutoBroadcastType::NUMPY); + { + std::vector static_input_shapes = {StaticShape{}, StaticShape{4}, StaticShape{2, 4}}, + static_output_shapes = {StaticShape{}}; + shape_inference(select.get(), static_input_shapes, static_output_shapes); + ASSERT_EQ(static_output_shapes[0], StaticShape({2, 4})); + } + + { + std::vector static_input_shapes = {StaticShape{}, StaticShape{2, 4}, StaticShape{2, 4}}, + static_output_shapes = {StaticShape{}}; + shape_inference(select.get(), static_input_shapes, static_output_shapes); + ASSERT_EQ(static_output_shapes[0], StaticShape({2, 4})); + } + + { + std::vector static_input_shapes = {StaticShape{4}, StaticShape{2, 4}, StaticShape{4}}, + static_output_shapes = {StaticShape{}}; + shape_inference(select.get(), static_input_shapes, static_output_shapes); + ASSERT_EQ(static_output_shapes[0], StaticShape({2, 4})); + } +} +TEST(StaticShapeInferenceTest, SelectTestBCastModePDPD) { + auto cond = std::make_shared(element::boolean, PartialShape{}); + auto ptrue = std::make_shared(element::f32, PartialShape{}); + auto pfalse = std::make_shared(element::f32, PartialShape{}); + auto select = + std::make_shared(cond, ptrue, pfalse, op::AutoBroadcastSpec{op::AutoBroadcastType::PDPD, 1}); + std::vector static_input_shapes = {StaticShape{4}, StaticShape{2, 4}, StaticShape{4}}, + static_output_shapes = {StaticShape{}}; + shape_inference(select.get(), static_input_shapes, static_output_shapes); + ASSERT_EQ(static_output_shapes[0], StaticShape({2, 4})); +} + +TEST(StaticShapeInferenceTest, SelectTestBCastModeNone) { + auto cond = std::make_shared(element::boolean, PartialShape{}); + auto ptrue = std::make_shared(element::f32, PartialShape{}); + auto pfalse = std::make_shared(element::f32, PartialShape{}); + auto select = std::make_shared(cond, ptrue, pfalse, op::AutoBroadcastType::NONE); + + std::vector static_input_shapes = {StaticShape{6, 4}, StaticShape{6, 4}, StaticShape{6, 4}}, + static_output_shapes = {StaticShape{}}; + shape_inference(select.get(), static_input_shapes, static_output_shapes); + ASSERT_EQ(static_output_shapes[0], StaticShape({6, 4})); +} diff --git a/src/tests/unit/cpu/shape_inference_test/shuffle_channels_shape_inference.cpp b/src/tests/unit/cpu/shape_inference_test/shuffle_channels_shape_inference.cpp new file mode 100644 index 00000000000..42089ddebe8 --- /dev/null +++ b/src/tests/unit/cpu/shape_inference_test/shuffle_channels_shape_inference.cpp @@ -0,0 +1,26 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include +#include +#include + +#include "utils/shape_inference/static_shape.hpp" + +using namespace ov; + +TEST(StaticShapeInferenceTest, ShuffleChannelsTest) { + const auto data = std::make_shared(element::f32, PartialShape{-1, -1, -1}); + const auto axis = -1; + const auto group = 3; + const auto shuffle_channels = std::make_shared(data, axis, group); + + std::vector static_input_shapes = {StaticShape{5, 4, 9}}; + std::vector static_output_shapes = {StaticShape{}}; + shape_inference(shuffle_channels.get(), static_input_shapes, static_output_shapes); + + ASSERT_EQ(static_output_shapes[0], static_input_shapes[0]); +} \ No newline at end of file