From c1b208b2a5e594a92d87e8ee502647955e477190 Mon Sep 17 00:00:00 2001 From: Pawel Raasz Date: Fri, 27 Jan 2023 07:44:03 +0100 Subject: [PATCH] Review ReverseSequence class for shape inference aspects (#15128) * Review reverse sequence for: - partial shapes and labels propagation - template implementation of shape infer - refactor shape_infer to use it when op created with default ctor * Remove friend shape_infer from reverse sequence op --- .../include/openvino/op/reverse_sequence.hpp | 18 +- .../reverse_sequence_shape_inference.hpp | 30 +- src/core/src/op/reverse_sequence.cpp | 39 +- src/core/tests/type_prop/reverse_sequence.cpp | 345 ++++++++++-------- .../reverse_sequence_shape_inference.cpp | 24 -- .../reverse_sequence_shape_inference_test.cpp | 76 ++++ 6 files changed, 296 insertions(+), 236 deletions(-) delete mode 100644 src/plugins/intel_cpu/tests/unit/shape_inference_test/reverse_sequence_shape_inference.cpp create mode 100644 src/plugins/intel_cpu/tests/unit/shape_inference_test/reverse_sequence_shape_inference_test.cpp diff --git a/src/core/include/openvino/op/reverse_sequence.hpp b/src/core/include/openvino/op/reverse_sequence.hpp index 15d512e9949..716c5e94df3 100644 --- a/src/core/include/openvino/op/reverse_sequence.hpp +++ b/src/core/include/openvino/op/reverse_sequence.hpp @@ -34,13 +34,12 @@ public: std::shared_ptr clone_with_new_inputs(const OutputVector& new_args) const override; - size_t get_batch_axis() const { - return m_normalized_batch_axis; - } + size_t get_batch_axis() const; int64_t get_origin_batch_axis() const { return m_batch_axis; } void set_batch_axis(int64_t batch_axis); + size_t get_sequence_axis() const { return m_normalized_seq_axis; } @@ -50,16 +49,9 @@ public: void set_sequence_axis(int64_t sequence_axis); private: - int64_t m_batch_axis; - int64_t m_seq_axis = 1; - size_t m_normalized_batch_axis; - size_t m_normalized_seq_axis; - template - friend void shape_infer(const ReverseSequence* op, - const std::vector& input_shapes, - std::vector& output_shapes); - - void normalize_axes(ReverseSequence* op); + int64_t m_batch_axis{}; + int64_t m_seq_axis{1}; + size_t m_normalized_seq_axis{}; }; } // namespace v0 } // namespace op diff --git a/src/core/shape_inference/include/reverse_sequence_shape_inference.hpp b/src/core/shape_inference/include/reverse_sequence_shape_inference.hpp index 14a545d03a3..f51b3265208 100644 --- a/src/core/shape_inference/include/reverse_sequence_shape_inference.hpp +++ b/src/core/shape_inference/include/reverse_sequence_shape_inference.hpp @@ -9,14 +9,16 @@ namespace ov { namespace op { namespace v0 { -template -void shape_infer(const ReverseSequence* op, const std::vector& input_shapes, std::vector& output_shapes) { - NODE_VALIDATION_CHECK(op, input_shapes.size() == 2 && output_shapes.size() == 1); +template +std::vector shape_infer(const ReverseSequence* op, const std::vector& input_shapes) { + NODE_VALIDATION_CHECK(op, input_shapes.size() == 2); + using DimType = typename TShape::value_type; + const auto& data_pshape = input_shapes[0]; const auto& data_rank = data_pshape.rank(); - using DimType = typename std::iterator_traits::value_type; const auto& seq_lengths_pshape = input_shapes[1]; const auto& seq_lengths_rank = seq_lengths_pshape.rank(); + NODE_VALIDATION_CHECK(op, data_rank.is_dynamic() || data_rank.get_length() >= 2, "Data input rank should be equal or greater than 2. Got: ", @@ -26,25 +28,33 @@ void shape_infer(const ReverseSequence* op, const std::vector& input_shapes, seq_lengths_rank.compatible(1), "Sequence lengths rank must be equal to 1. Got: ", seq_lengths_pshape); - auto& output_pshape = output_shapes[0]; - - output_pshape = data_pshape; + auto output_pshape = data_pshape; if (data_rank.is_static() && seq_lengths_rank.is_static()) { + const auto normalized_batch_axis = ov::normalize_axis(op, op->get_origin_batch_axis(), data_rank); DimType merged_sequence_length; NODE_VALIDATION_CHECK( op, - DimType::merge(merged_sequence_length, data_pshape[op->m_normalized_batch_axis], seq_lengths_pshape[0]), + DimType::merge(merged_sequence_length, data_pshape[normalized_batch_axis], seq_lengths_pshape[0]), "Sequence lengths input size (", seq_lengths_pshape[0], ") is not equal to batch axis dimension of data input (", - data_pshape[op->m_normalized_batch_axis], + data_pshape[normalized_batch_axis], ") (argument shape: ", data_pshape, ", sequence indices shape: ", seq_lengths_pshape, ")."); - output_pshape[op->m_normalized_batch_axis] = merged_sequence_length; + output_pshape[normalized_batch_axis] = merged_sequence_length; } + + return {output_pshape}; +} + +template +void shape_infer(const ReverseSequence* op, + const std::vector& input_shapes, + std::vector& output_shapes) { + output_shapes = shape_infer(op, input_shapes); } } // namespace v0 } // namespace op diff --git a/src/core/src/op/reverse_sequence.cpp b/src/core/src/op/reverse_sequence.cpp index de666057260..dc476232a27 100644 --- a/src/core/src/op/reverse_sequence.cpp +++ b/src/core/src/op/reverse_sequence.cpp @@ -22,9 +22,7 @@ op::ReverseSequence::ReverseSequence(const Output& arg, int64_t seq_axis) : Op({arg, seq_indices}), m_batch_axis(batch_axis), - m_seq_axis(seq_axis), - m_normalized_batch_axis{0}, - m_normalized_seq_axis{0} { + m_seq_axis(seq_axis) { constructor_validate_and_infer_types(); } @@ -37,18 +35,16 @@ bool ngraph::op::v0::ReverseSequence::visit_attributes(AttributeVisitor& visitor void op::ReverseSequence::validate_and_infer_types() { OV_OP_SCOPE(v0_ReverseSequence_validate_and_infer_types); - const auto& data_pshape = get_input_partial_shape(0); const auto& seq_lengths_et = get_input_element_type(1); - const auto& seq_lengths_pshape = get_input_partial_shape(1); - normalize_axes(this); - std::vector output_shapes = {ov::PartialShape{}}; - std::vector input_shapes = {data_pshape, seq_lengths_pshape}; - shape_infer(this, input_shapes, output_shapes); NODE_VALIDATION_CHECK(this, seq_lengths_et.is_real() || seq_lengths_et.is_integral_number(), "Sequence lengths element type must be numeric type. Got: ", seq_lengths_et); - set_output_type(0, get_input_element_type(0), output_shapes[0]); + + const auto output_shape = shape_infer(this, get_node_input_partial_shapes(*this)).front(); + set_output_type(0, get_input_element_type(0), output_shape); + + m_normalized_seq_axis = ov::normalize_axis(this, m_seq_axis, get_input_partial_shape(0).rank()); } shared_ptr op::ReverseSequence::clone_with_new_inputs(const OutputVector& new_args) const { @@ -59,25 +55,14 @@ shared_ptr op::ReverseSequence::clone_with_new_inputs(const OutputVector& void op::ReverseSequence::set_batch_axis(int64_t batch_axis) { m_batch_axis = batch_axis; - const auto& data_pshape = get_input_partial_shape(0); - const auto& data_rank = data_pshape.rank(); - m_normalized_batch_axis = ov::normalize_axis(this, m_batch_axis, data_rank); +} + +size_t op::ReverseSequence::get_batch_axis() const { + const auto& data_rank = get_input_partial_shape(0).rank(); + return static_cast(ov::normalize_axis(this, m_batch_axis, data_rank)); } void op::ReverseSequence::set_sequence_axis(int64_t sequence_axis) { m_seq_axis = sequence_axis; - const auto& data_pshape = get_input_partial_shape(0); - const auto& data_rank = data_pshape.rank(); - m_normalized_seq_axis = ov::normalize_axis(this, m_seq_axis, data_rank); -} - -void op::ReverseSequence::normalize_axes(ReverseSequence* op) { - const auto& data_pshape = op->get_input_partial_shape(0); - const auto& data_rank = data_pshape.rank(); - NODE_VALIDATION_CHECK(op, - data_rank.is_dynamic() || data_rank.get_length() >= 2, - "Data input rank should be equal or greater than 2. Got: ", - data_pshape); - op->m_normalized_batch_axis = ov::normalize_axis(op, op->m_batch_axis, data_rank); - op->m_normalized_seq_axis = ov::normalize_axis(op, op->m_seq_axis, data_rank); + m_normalized_seq_axis = ov::normalize_axis(this, m_seq_axis, get_input_partial_shape(0).rank()); } diff --git a/src/core/tests/type_prop/reverse_sequence.cpp b/src/core/tests/type_prop/reverse_sequence.cpp index 83fa1a2397a..03f7ac16a61 100644 --- a/src/core/tests/type_prop/reverse_sequence.cpp +++ b/src/core/tests/type_prop/reverse_sequence.cpp @@ -2,17 +2,19 @@ // SPDX-License-Identifier: Apache-2.0 // -#include "gtest/gtest.h" -#include "ngraph/ngraph.hpp" +#include "common_test_utils/test_assertions.hpp" +#include "openvino/opsets/opset10.hpp" +#include "reverse_sequence_shape_inference.hpp" #include "util/type_prop.hpp" -using namespace std; -using namespace ngraph; +using namespace ov; +using namespace ov::opset10; +using namespace testing; TEST(type_prop, reverse_sequence_default_attributes) { - auto data = make_shared(element::f32, PartialShape{4, 3, 2}); - auto seq_lengths = make_shared(element::i32, PartialShape{4}); - auto reverse_seq = make_shared(data, seq_lengths); + auto data = std::make_shared(element::f32, PartialShape{4, 3, 2}); + auto seq_lengths = std::make_shared(element::i32, PartialShape{4}); + auto reverse_seq = std::make_shared(data, seq_lengths); EXPECT_EQ(reverse_seq->get_batch_axis(), 0); EXPECT_EQ(reverse_seq->get_sequence_axis(), 1); @@ -25,9 +27,9 @@ TEST(type_prop, reverse_sequence_default_attributes) { TEST(type_prop, reverse_sequence_negative_attribute_axes) { int64_t batch_axis = -3; int64_t seq_axis = -2; - auto data = make_shared(element::f32, PartialShape{1, 2, 3, 4, 5}); - auto seq_lengths = make_shared(element::i32, PartialShape{3}); - auto reverse_seq = make_shared(data, seq_lengths, batch_axis, seq_axis); + auto data = std::make_shared(element::f32, PartialShape{1, 2, 3, 4, 5}); + auto seq_lengths = std::make_shared(element::i32, PartialShape{3}); + auto reverse_seq = std::make_shared(data, seq_lengths, batch_axis, seq_axis); EXPECT_EQ(reverse_seq->get_batch_axis(), 2); EXPECT_EQ(reverse_seq->get_sequence_axis(), 3); @@ -51,10 +53,10 @@ TEST(type_prop, reverse_sequence_data_et) { element::boolean}; for (auto& et : element_types) { try { - auto data = std::make_shared(et, PartialShape{4, 4}); - auto seq_lengths = std::make_shared(element::i32, PartialShape{4}); + auto data = std::make_shared(et, PartialShape{4, 4}); + auto seq_lengths = std::make_shared(element::i32, PartialShape{4}); - EXPECT_NO_THROW(const auto unused = std::make_shared(data, seq_lengths)); + EXPECT_NO_THROW(const auto unused = std::make_shared(data, seq_lengths)); } catch (...) { FAIL() << "Data input element type validation check failed for unexpected reason"; } @@ -65,255 +67,274 @@ TEST(type_prop, reverse_sequence_invalid_seq_lengths_et) { int64_t batch_axis = 0; int64_t seq_axis = 1; std::vector invalid_et{element::bf16, element::f16, element::f32, element::boolean}; - auto data = make_shared(element::f32, PartialShape{4, 3, 2}); - auto seq_lengths = make_shared(element::boolean, PartialShape{4}); - try { - auto reverse_seq = make_shared(data, seq_lengths, batch_axis, seq_axis); - FAIL() << "Invalid element type of seq_lengths input not detected"; - } catch (const NodeValidationFailure& error) { - EXPECT_HAS_SUBSTRING(error.what(), std::string("Sequence lengths element type must be numeric type.")); - } catch (...) { - FAIL() << "Element type validation check of seq_lengths input failed for unexpected reason"; - } + auto data = std::make_shared(element::f32, PartialShape{4, 3, 2}); + auto seq_lengths = std::make_shared(element::boolean, PartialShape{4}); + OV_EXPECT_THROW( + auto reverse_seq = std::make_shared(data, seq_lengths, batch_axis, seq_axis), + NodeValidationFailure, + HasSubstr("Sequence lengths element type must be numeric type.")); } TEST(type_prop, reverse_sequence_invalid_data_rank) { - std::vector invalid_pshapes = {{}, {4}}; - for (auto& pshape : invalid_pshapes) { - try { - auto data = make_shared(element::f32, pshape); - auto seq_lengths = make_shared(element::i32, PartialShape{1}); - auto reverse_seq = make_shared(data, seq_lengths); - FAIL() << "Invalid rank of data input not detected"; - } catch (const NodeValidationFailure& error) { - EXPECT_HAS_SUBSTRING(error.what(), std::string("Data input rank should be equal or greater than 2.")); - } catch (...) { - FAIL() << "Rank check of data input failed for unexpected reason"; - } + auto seq_lengths = std::make_shared(element::i32, PartialShape{1}); + + for (auto& invalid_shape : PartialShapes{{}, {4}}) { + auto data = std::make_shared(element::f32, invalid_shape); + + OV_EXPECT_THROW(auto reverse_seq = std::make_shared(data, seq_lengths), + NodeValidationFailure, + HasSubstr("Data input rank should be equal or greater than 2.")); } } TEST(type_prop, reverse_sequence_invalid_seq_lengths_rank) { - std::vector invalid_pshapes = {{}, {4, 1}, {1, 1, 4}}; - int64_t batch_axis = 0; - int64_t seq_axis = 1; - auto data = make_shared(element::f32, PartialShape{4, 3, 2}); - for (auto& pshape : invalid_pshapes) { - try { - auto seq_lengths = make_shared(element::i32, pshape); - auto reverse_seq = make_shared(data, seq_lengths, batch_axis, seq_axis); - FAIL() << "Invalid rank of seq_lengths input not detected"; - } catch (const NodeValidationFailure& error) { - EXPECT_HAS_SUBSTRING(error.what(), std::string("Sequence lengths rank must be equal to 1.")); - } catch (...) { - FAIL() << "Rank check of seq_lengths input failed for unexpected reason"; - } + constexpr int64_t batch_axis = 0, seq_axis = 1; + auto data = std::make_shared(element::f32, PartialShape{4, 3, 2}); + + for (auto& invalid_shape : PartialShapes{{}, {4, 1}, {1, 1, 4}}) { + auto seq_lengths = std::make_shared(element::i32, invalid_shape); + + OV_EXPECT_THROW( + auto reverse_seq = std::make_shared(data, seq_lengths, batch_axis, seq_axis), + NodeValidationFailure, + HasSubstr("Sequence lengths rank must be equal to 1.")); } } TEST(type_prop, reverse_sequence_invalid_batch_axis_value) { int64_t batch_axis = 3; int64_t seq_axis = 1; - auto data = make_shared(element::f32, PartialShape{4, 3, 2}); - auto seq_lengths = make_shared(element::i32, PartialShape{3}); - try { - auto reverse_seq = make_shared(data, seq_lengths, batch_axis, seq_axis); - FAIL() << "Invalid value of batch_axis attribute not detected"; - } catch (const ngraph_error& error) { - EXPECT_HAS_SUBSTRING(error.what(), std::string("Parameter axis 3 out of the tensor rank")); - } catch (...) { - FAIL() << "Out of bounds check of batch_axis attribute failed for unexpected reason"; - } + auto data = std::make_shared(element::f32, PartialShape{4, 3, 2}); + auto seq_lengths = std::make_shared(element::i32, PartialShape{3}); + + OV_EXPECT_THROW( + auto reverse_seq = std::make_shared(data, seq_lengths, batch_axis, seq_axis), + AssertFailure, + HasSubstr("Parameter axis 3 out of the tensor rank")); } TEST(type_prop, reverse_sequence_invalid_seq_axis_value) { int64_t batch_axis = 1; int64_t seq_axis = 3; - auto data = make_shared(element::f32, PartialShape{4, 3, 2}); - auto seq_lengths = make_shared(element::i32, PartialShape{3}); - try { - auto reverse_seq = make_shared(data, seq_lengths, batch_axis, seq_axis); - FAIL() << "Invalid value of seq_axis attribute not detected"; - } catch (const ngraph_error& error) { - EXPECT_HAS_SUBSTRING(error.what(), std::string("Parameter axis 3 out of the tensor rank")); - } catch (...) { - FAIL() << "Out of bounds check of seq_axis attribute failed for unexpected reason"; - } + auto data = std::make_shared(element::f32, PartialShape{4, 3, 2}); + auto seq_lengths = std::make_shared(element::i32, PartialShape{3}); + + OV_EXPECT_THROW( + auto reverse_seq = std::make_shared(data, seq_lengths, batch_axis, seq_axis), + AssertFailure, + HasSubstr("Parameter axis 3 out of the tensor rank")); } TEST(type_prop, reverse_sequence_incompatible_seq_len_size_with_batch_dim) { - auto data = make_shared(element::f32, PartialShape{4, 3, 2}); - auto seq_lengths = make_shared(element::i32, PartialShape{3}); - try { - auto reverse_seq = make_shared(data, seq_lengths); - FAIL() << "Incompatible number of elements between seq_lengths and batch dimension of data input not detected"; - } catch (const NodeValidationFailure& error) { - EXPECT_HAS_SUBSTRING( - error.what(), - std::string("Sequence lengths input size (3) is not equal to batch axis dimension of data input (4)")); - } catch (...) { - FAIL() << "Number of elements of input seq_lengths check with respect batch dimension of input failed for " - "unexpected reason"; - } + auto data = std::make_shared(element::f32, PartialShape{4, 3, 2}); + auto seq_lengths = std::make_shared(element::i32, PartialShape{3}); + + OV_EXPECT_THROW( + auto reverse_seq = std::make_shared(data, seq_lengths), + NodeValidationFailure, + HasSubstr("Sequence lengths input size (3) is not equal to batch axis dimension of data input (4)")); } TEST(type_prop, reverse_sequence_dynamic_inputs_with_dynamic_rank) { - auto data = make_shared(element::f32, PartialShape::dynamic()); - auto seq_lengths = make_shared(element::i32, PartialShape::dynamic()); + auto data = std::make_shared(element::f32, PartialShape::dynamic()); + auto seq_lengths = std::make_shared(element::i32, PartialShape::dynamic()); // Unrealistic values, but they don't matter here. int64_t batch_axis = 202; int64_t seq_axis = 909; - auto reverse_seq = make_shared(data, seq_lengths, batch_axis, seq_axis); + auto reverse_seq = std::make_shared(data, seq_lengths, batch_axis, seq_axis); EXPECT_EQ(reverse_seq->get_output_partial_shape(0), (PartialShape::dynamic())); EXPECT_EQ(reverse_seq->get_output_element_type(0), element::f32); } TEST(type_prop, reverse_sequence_dynamic_data_input_dynamic_rank) { - auto data = make_shared(element::f32, PartialShape::dynamic()); - auto seq_lengths = make_shared(element::i32, PartialShape{3}); + auto data = std::make_shared(element::f32, PartialShape::dynamic()); + auto seq_lengths = std::make_shared(element::i32, PartialShape{3}); // Unrealistic values, but they don't matter here. int64_t batch_axis = 202; int64_t seq_axis = 909; - auto reverse_seq = make_shared(data, seq_lengths, batch_axis, seq_axis); + auto reverse_seq = std::make_shared(data, seq_lengths, batch_axis, seq_axis); EXPECT_EQ(reverse_seq->get_output_partial_shape(0), (PartialShape::dynamic())); EXPECT_EQ(reverse_seq->get_output_element_type(0), element::f32); } TEST(type_prop, reverse_sequence_dynamic_seq_lenghts_input_dynamic_rank) { - auto data = make_shared(element::f32, PartialShape{2, 4, 6, 8}); - auto seq_lengths = make_shared(element::i32, PartialShape::dynamic()); + auto data = std::make_shared(element::f32, PartialShape{2, 4, 6, 8}); + auto seq_lengths = std::make_shared(element::i32, PartialShape::dynamic()); int64_t batch_axis = 0; int64_t seq_axis = 1; - auto reverse_seq = make_shared(data, seq_lengths, batch_axis, seq_axis); + auto reverse_seq = std::make_shared(data, seq_lengths, batch_axis, seq_axis); - EXPECT_TRUE(reverse_seq->get_output_partial_shape(0).same_scheme(PartialShape{2, 4, 6, 8})); + EXPECT_EQ(reverse_seq->get_output_partial_shape(0), PartialShape({2, 4, 6, 8})); EXPECT_EQ(reverse_seq->get_output_element_type(0), element::f32); } TEST(type_prop, reverse_sequence_dynamic_data_input_static_rank_and_seq_lengths_dynamic_rank) { - auto data = make_shared( + auto data = std::make_shared( element::f32, PartialShape{Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()}); - auto seq_lengths = make_shared(element::i32, PartialShape::dynamic()); + auto seq_lengths = std::make_shared(element::i32, PartialShape::dynamic()); int64_t batch_axis = 0; int64_t seq_axis = 1; - auto reverse_seq = make_shared(data, seq_lengths, batch_axis, seq_axis); + auto reverse_seq = std::make_shared(data, seq_lengths, batch_axis, seq_axis); - EXPECT_TRUE(reverse_seq->get_output_partial_shape(0).same_scheme( - PartialShape{Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()})); + EXPECT_EQ(reverse_seq->get_output_partial_shape(0), PartialShape::dynamic(4)); EXPECT_EQ(reverse_seq->get_output_element_type(0), element::f32); } TEST(type_prop, reverse_sequence_dynamic_invalid_batch_axis) { - auto data = make_shared( + auto data = std::make_shared( element::f32, PartialShape{Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()}); - auto seq_lengths = make_shared(element::i32, PartialShape{Dimension::dynamic()}); + auto seq_lengths = std::make_shared(element::i32, PartialShape{Dimension::dynamic()}); int64_t batch_axis = 4; int64_t seq_axis = 1; - try { - auto reverse_seq = make_shared(data, seq_lengths, batch_axis, seq_axis); - FAIL() << "Invalid batch_axis attribute value not detected (rank-static dynamic shape)"; - } catch (const ngraph_error& error) { - EXPECT_HAS_SUBSTRING(error.what(), std::string("Parameter axis 4 out of the tensor rank")); - } catch (...) { - FAIL() << "Out of bounds check of batch_axis attribute failed for unexpected reason"; - } + + OV_EXPECT_THROW( + auto reverse_seq = std::make_shared(data, seq_lengths, batch_axis, seq_axis), + AssertFailure, + HasSubstr("Parameter axis 4 out of the tensor rank")); } TEST(type_prop, reverse_sequence_dynamic_invalid_seq_axis) { - auto data = make_shared( + auto data = std::make_shared( element::f32, PartialShape{Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()}); - auto seq_lengths = make_shared(element::i32, PartialShape{Dimension::dynamic()}); + auto seq_lengths = std::make_shared(element::i32, PartialShape{Dimension::dynamic()}); int64_t batch_axis = 1; int64_t seq_axis = 4; - try { - auto reverse_seq = make_shared(data, seq_lengths, batch_axis, seq_axis); - FAIL() << "Invalid seq_axis attribute value not detected (rank-static dynamic shape)"; - } catch (const ngraph_error& error) { - EXPECT_HAS_SUBSTRING(error.what(), std::string("Parameter axis 4 out of the tensor rank")); - } catch (...) { - FAIL() << "Out of bounds check of seq_axis attribute failed for unexpected reason"; - } + + OV_EXPECT_THROW( + auto reverse_seq = std::make_shared(data, seq_lengths, batch_axis, seq_axis), + AssertFailure, + HasSubstr("Parameter axis 4 out of the tensor rank")); } TEST(type_prop, reverse_sequence_dynamic_data_input_static_rank) { - auto data = make_shared( - element::f32, - PartialShape{Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()}); - auto seq_lengths = make_shared(element::i32, PartialShape{3}); + auto data_shape = PartialShape::dynamic(4); + set_shape_labels(data_shape, 10); + auto data = std::make_shared(element::f32, data_shape); + auto seq_lengths = std::make_shared(element::i32, PartialShape{3}); int64_t batch_axis = 2; int64_t seq_axis = 1; - auto reverse_seq = make_shared(data, seq_lengths, batch_axis, seq_axis); + auto reverse_seq = std::make_shared(data, seq_lengths, batch_axis, seq_axis); - EXPECT_TRUE(reverse_seq->get_output_partial_shape(0).same_scheme( - PartialShape{Dimension::dynamic(), Dimension::dynamic(), 3, Dimension::dynamic()})); + EXPECT_EQ(reverse_seq->get_output_partial_shape(0), PartialShape({-1, -1, 3, -1})); EXPECT_EQ(reverse_seq->get_output_element_type(0), element::f32); + EXPECT_THAT(get_shape_labels(reverse_seq->get_output_partial_shape(0)), ElementsAre(10, 11, 12, 13)); } TEST(type_prop, reverse_sequence_dynamic_data_input_static_rank_seq_lengths_input_dynamic_rank) { auto data = - make_shared(element::f32, - PartialShape{Dimension::dynamic(), Dimension::dynamic(), 3, Dimension::dynamic()}); - auto seq_lengths = make_shared(element::i32, PartialShape{Dimension::dynamic()}); + std::make_shared(element::f32, + PartialShape{Dimension::dynamic(), Dimension::dynamic(), 3, Dimension::dynamic()}); + auto seq_lengths = std::make_shared(element::i32, PartialShape{Dimension::dynamic()}); int64_t batch_axis = 2; int64_t seq_axis = 1; - auto reverse_seq = make_shared(data, seq_lengths, batch_axis, seq_axis); + auto reverse_seq = std::make_shared(data, seq_lengths, batch_axis, seq_axis); - EXPECT_TRUE(reverse_seq->get_output_partial_shape(0).same_scheme( - PartialShape{Dimension::dynamic(), Dimension::dynamic(), 3, Dimension::dynamic()})); + EXPECT_EQ(reverse_seq->get_output_partial_shape(0), PartialShape({-1, -1, 3, -1})); EXPECT_EQ(reverse_seq->get_output_element_type(0), element::f32); } TEST(type_prop, reverse_sequence_dynamic_data_input_static_rank_with_static_batch_dim) { auto data = - make_shared(element::f32, - PartialShape{Dimension::dynamic(), Dimension::dynamic(), 3, Dimension::dynamic()}); - auto seq_lengths = make_shared(element::i32, PartialShape{3}); + std::make_shared(element::f32, + PartialShape{Dimension::dynamic(), Dimension::dynamic(), 3, Dimension::dynamic()}); + auto seq_lengths = std::make_shared(element::i32, PartialShape{3}); int64_t batch_axis = 2; int64_t seq_axis = 1; - auto reverse_seq = make_shared(data, seq_lengths, batch_axis, seq_axis); + auto reverse_seq = std::make_shared(data, seq_lengths, batch_axis, seq_axis); - EXPECT_TRUE(reverse_seq->get_output_partial_shape(0).same_scheme( - PartialShape{Dimension::dynamic(), Dimension::dynamic(), 3, Dimension::dynamic()})); + EXPECT_EQ(reverse_seq->get_output_partial_shape(0), PartialShape({-1, -1, 3, -1})); EXPECT_EQ(reverse_seq->get_output_element_type(0), element::f32); } TEST(type_prop, reverse_sequence_dynamic_incompatible_data_input_static_rank_with_static_batch_dim) { auto data = - make_shared(element::f32, - PartialShape{Dimension::dynamic(), Dimension::dynamic(), 3, Dimension::dynamic()}); - auto seq_lengths = make_shared(element::i32, PartialShape{4}); + std::make_shared(element::f32, + PartialShape{Dimension::dynamic(), Dimension::dynamic(), 3, Dimension::dynamic()}); + auto seq_lengths = std::make_shared(element::i32, PartialShape{4}); int64_t batch_axis = 2; int64_t seq_axis = 1; - try { - auto reverse_seq = make_shared(data, seq_lengths, batch_axis, seq_axis); - FAIL() << "Incompatible number of elements between seq_lengths and batch dimension of data input not detected " - "(rank-static dynamic shape)"; - } catch (const NodeValidationFailure& error) { - EXPECT_HAS_SUBSTRING( - error.what(), - std::string("Sequence lengths input size (4) is not equal to batch axis dimension of data input (3)")); - } catch (...) { - FAIL() << "Number of elements of input seq_lengths check with respect batch dimension of input failed for " - "unexpected reason"; - } + + OV_EXPECT_THROW( + auto reverse_seq = std::make_shared(data, seq_lengths, batch_axis, seq_axis), + NodeValidationFailure, + HasSubstr("Sequence lengths input size (4) is not equal to batch axis dimension of data input (3)")); } -TEST(type_prop, reverse_sequence_dynamic_invalid_negative_axis_and_data_input_dynamic_rank) { - auto data = make_shared(element::f32, PartialShape::dynamic()); - auto seq_lengths = make_shared(element::i32, PartialShape{1}); +class TypePropReverseSequenceV0Test : public TypePropOpTest {}; + +TEST_F(TypePropReverseSequenceV0Test, dynamic_invalid_negative_axis_and_data_input_dynamic_rank) { + auto data = std::make_shared(element::f32, PartialShape::dynamic()); + auto seq_lengths = std::make_shared(element::i32, PartialShape{1}); int64_t batch_axis = 1; int64_t seq_axis = -2; - try { - auto reverse_seq = make_shared(data, seq_lengths, batch_axis, seq_axis); - FAIL() << "Dynamic rank of data input for negative axis not detected"; - } catch (const CheckFailure& error) { - EXPECT_HAS_SUBSTRING(error.what(), std::string("Rank must be static in order to normalize negative axis=-2")); - } catch (...) { - FAIL() << "Static rank of data input for negative axis validation check failed for unexpected reason"; - } + + OV_EXPECT_THROW(auto reverse_seq = make_op(data, seq_lengths, batch_axis, seq_axis), + AssertFailure, + HasSubstr("Rank must be static in order to normalize negative axis=-2")); +} + +TEST_F(TypePropReverseSequenceV0Test, default_ctor) { + auto data = std::make_shared(element::f32, PartialShape{4, 3, 2}); + auto seq_lengths = std::make_shared(element::i32, PartialShape{3}); + auto op = make_op(); + + op->set_arguments(OutputVector{data, seq_lengths}); + op->set_batch_axis(1); + op->set_sequence_axis(0); + op->validate_and_infer_types(); + + EXPECT_EQ(op->get_batch_axis(), 1); + EXPECT_EQ(op->get_sequence_axis(), 0); + EXPECT_EQ(op->get_input_size(), 2); + EXPECT_EQ(op->get_output_size(), 1); + EXPECT_EQ(op->get_output_element_type(0), element::f32); + EXPECT_EQ(op->get_output_partial_shape(0), (PartialShape{4, 3, 2})); +} + +TEST_F(TypePropReverseSequenceV0Test, default_ctor_no_arguments) { + auto op = make_op(); + op->set_batch_axis(1); + + const auto output_shapes = shape_infer(op.get(), PartialShapes{{{4, 5}, 3, 2}, {3}}); + + EXPECT_EQ(output_shapes.size(), 1); + EXPECT_EQ(output_shapes.front(), PartialShape({{4, 5}, 3, 2})); + + EXPECT_EQ(op->get_input_size(), 0); + EXPECT_EQ(op->get_output_size(), 0); +} + +TEST_F(TypePropReverseSequenceV0Test, data_shape_interval_and_sequence_static_dim_with_labels) { + auto data_shape = PartialShape{{2, 5}, 4, {1, 3}}; + auto seq_shape = PartialShape{3}; + set_shape_labels(data_shape, 10); + set_shape_labels(seq_shape, 20); + + auto data = std::make_shared(element::f32, data_shape); + auto seq_lengths = std::make_shared(element::i32, seq_shape); + auto op = make_op(data, seq_lengths, 0, 1); + + EXPECT_EQ(op->get_output_element_type(0), element::f32); + EXPECT_EQ(op->get_output_partial_shape(0), PartialShape({3, 4, {1, 3}})); + EXPECT_THAT(get_shape_labels(op->get_output_partial_shape(0)), ElementsAre(20, 11, 12)); +} + +TEST_F(TypePropReverseSequenceV0Test, data_shape_and_sequence_interval_dim_with_labels) { + auto data_shape = PartialShape{{2, 5}, 4, {1, 3}}; + auto seq_shape = PartialShape{{3, 6}}; + set_shape_labels(data_shape, 10); + set_shape_labels(seq_shape, 20); + + auto data = std::make_shared(element::f32, data_shape); + auto seq_lengths = std::make_shared(element::i32, seq_shape); + auto op = make_op(data, seq_lengths, -3, -1); + + EXPECT_EQ(op->get_output_element_type(0), element::f32); + EXPECT_EQ(op->get_output_partial_shape(0), PartialShape({{3, 5}, 4, {1, 3}})); + EXPECT_THAT(get_shape_labels(op->get_output_partial_shape(0)), ElementsAre(20, 11, 12)); } diff --git a/src/plugins/intel_cpu/tests/unit/shape_inference_test/reverse_sequence_shape_inference.cpp b/src/plugins/intel_cpu/tests/unit/shape_inference_test/reverse_sequence_shape_inference.cpp deleted file mode 100644 index 44f6537d05f..00000000000 --- a/src/plugins/intel_cpu/tests/unit/shape_inference_test/reverse_sequence_shape_inference.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) 2018-2023 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 -// - -#include - -#include -#include -#include -#include - -using namespace ov; -using namespace ov::intel_cpu; - -TEST(StaticShapeInferenceTest, ReverseSequenceTest) { - auto data = std::make_shared(element::f32, PartialShape{-1, -1, -1}); - auto seq_lengths = std::make_shared(element::i32, PartialShape{4}); - auto reverse_seq = std::make_shared(data, seq_lengths); - // Test StaticShape - std::vector static_input_shapes = {StaticShape{4, 3, 2}, StaticShape{4}}, - static_output_shapes = {StaticShape{}}; - shape_inference(reverse_seq.get(), static_input_shapes, static_output_shapes); - ASSERT_EQ(static_output_shapes[0], (StaticShape{4, 3, 2})); -} diff --git a/src/plugins/intel_cpu/tests/unit/shape_inference_test/reverse_sequence_shape_inference_test.cpp b/src/plugins/intel_cpu/tests/unit/shape_inference_test/reverse_sequence_shape_inference_test.cpp new file mode 100644 index 00000000000..ca367910fe7 --- /dev/null +++ b/src/plugins/intel_cpu/tests/unit/shape_inference_test/reverse_sequence_shape_inference_test.cpp @@ -0,0 +1,76 @@ +// Copyright (C) 2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "common_test_utils/test_assertions.hpp" +#include "openvino/opsets/opset10.hpp" +#include "utils.hpp" + +using namespace ov; +using namespace ov::intel_cpu; +using namespace ov::opset10; +using namespace testing; + +class ReverseSequenceV0StaticShapeInferenceTest : public OpStaticShapeInferenceTest { +protected: + void SetUp() override { + output_shapes.resize(1); + + data = std::make_shared(element::f32, PartialShape::dynamic()); + seq_lengths = std::make_shared(element::i32, PartialShape::dynamic()); + } + + std::shared_ptr data, seq_lengths; +}; + +TEST_F(ReverseSequenceV0StaticShapeInferenceTest, default_batch_seq_axes) { + auto op = make_op(data, seq_lengths); + + input_shapes = ShapeVector{{4, 3, 2}, {4}}; + shape_inference(op.get(), input_shapes, output_shapes); + + EXPECT_EQ(output_shapes[0], StaticShape({4, 3, 2})); +} + +TEST_F(ReverseSequenceV0StaticShapeInferenceTest, set_batch_seq_axes) { + auto op = make_op(data, seq_lengths, -1, 1); + + input_shapes = ShapeVector{{4, 3, 2}, {2}}; + shape_inference(op.get(), input_shapes, output_shapes); + + EXPECT_EQ(output_shapes[0], StaticShape({4, 3, 2})); +} + +TEST_F(ReverseSequenceV0StaticShapeInferenceTest, invalid_input_shapes_count) { + auto op = make_op(data, seq_lengths); + + input_shapes = ShapeVector{{1, 2, 4}}; + EXPECT_THROW(shape_inference(op.get(), input_shapes, output_shapes), NodeValidationFailure); +} + +TEST_F(ReverseSequenceV0StaticShapeInferenceTest, invalid_data_shape_rank) { + auto op = make_op(data, seq_lengths); + + input_shapes = ShapeVector{{4}, {4}}; + OV_EXPECT_THROW(shape_inference(op.get(), input_shapes, output_shapes), + NodeValidationFailure, + HasSubstr("Data input rank should be equal or greater than 2. Got: ")); +} + +TEST_F(ReverseSequenceV0StaticShapeInferenceTest, invalid_sequence_shape_rank) { + auto op = make_op(data, seq_lengths); + + input_shapes = ShapeVector{{4, 5, 6}, {2, 2}}; + OV_EXPECT_THROW(shape_inference(op.get(), input_shapes, output_shapes), + NodeValidationFailure, + HasSubstr("Sequence lengths rank must be equal to 1. Got: ")); +} + +TEST_F(ReverseSequenceV0StaticShapeInferenceTest, default_ctor) { + auto op = make_op(); + + input_shapes = ShapeVector{{11, 2, 3}, {11}}; + shape_inference(op.get(), input_shapes, output_shapes); + + EXPECT_EQ(output_shapes[0], StaticShape({11, 2, 3})); +}