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
This commit is contained in:
1 parent
ea48786bc6
commit
c1b208b2a5
6 files changed
+296
-236
No files matched your search
@@ -34,13 +34,12 @@ public:
|
||||
|
||||
std::shared_ptr<Node> 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 <class T>
|
||||
friend void shape_infer(const ReverseSequence* op,
|
||||
const std::vector<T>& input_shapes,
|
||||
std::vector<T>& 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
|
||||
|
||||
@@ -9,14 +9,16 @@
|
||||
namespace ov {
|
||||
namespace op {
|
||||
namespace v0 {
|
||||
template <class T>
|
||||
void shape_infer(const ReverseSequence* op, const std::vector<T>& input_shapes, std::vector<T>& output_shapes) {
|
||||
NODE_VALIDATION_CHECK(op, input_shapes.size() == 2 && output_shapes.size() == 1);
|
||||
template <class TShape>
|
||||
std::vector<TShape> shape_infer(const ReverseSequence* op, const std::vector<TShape>& 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<typename T::iterator>::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<T>& 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 <class TShape>
|
||||
void shape_infer(const ReverseSequence* op,
|
||||
const std::vector<TShape>& input_shapes,
|
||||
std::vector<TShape>& output_shapes) {
|
||||
output_shapes = shape_infer(op, input_shapes);
|
||||
}
|
||||
} // namespace v0
|
||||
} // namespace op
|
||||
|
||||
@@ -22,9 +22,7 @@ op::ReverseSequence::ReverseSequence(const Output<Node>& 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<ov::PartialShape> output_shapes = {ov::PartialShape{}};
|
||||
std::vector<ov::PartialShape> 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<Node> op::ReverseSequence::clone_with_new_inputs(const OutputVector& new_args) const {
|
||||
@@ -59,25 +55,14 @@ shared_ptr<Node> 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<size_t>(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());
|
||||
}
|
||||
@@ -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<op::Parameter>(element::f32, PartialShape{4, 3, 2});
|
||||
auto seq_lengths = make_shared<op::Parameter>(element::i32, PartialShape{4});
|
||||
auto reverse_seq = make_shared<op::ReverseSequence>(data, seq_lengths);
|
||||
auto data = std::make_shared<Parameter>(element::f32, PartialShape{4, 3, 2});
|
||||
auto seq_lengths = std::make_shared<Parameter>(element::i32, PartialShape{4});
|
||||
auto reverse_seq = std::make_shared<op::v0::ReverseSequence>(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<op::Parameter>(element::f32, PartialShape{1, 2, 3, 4, 5});
|
||||
auto seq_lengths = make_shared<op::Parameter>(element::i32, PartialShape{3});
|
||||
auto reverse_seq = make_shared<op::ReverseSequence>(data, seq_lengths, batch_axis, seq_axis);
|
||||
auto data = std::make_shared<Parameter>(element::f32, PartialShape{1, 2, 3, 4, 5});
|
||||
auto seq_lengths = std::make_shared<Parameter>(element::i32, PartialShape{3});
|
||||
auto reverse_seq = std::make_shared<op::v0::ReverseSequence>(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<op::Parameter>(et, PartialShape{4, 4});
|
||||
auto seq_lengths = std::make_shared<op::Parameter>(element::i32, PartialShape{4});
|
||||
auto data = std::make_shared<Parameter>(et, PartialShape{4, 4});
|
||||
auto seq_lengths = std::make_shared<Parameter>(element::i32, PartialShape{4});
|
||||
|
||||
EXPECT_NO_THROW(const auto unused = std::make_shared<op::ReverseSequence>(data, seq_lengths));
|
||||
EXPECT_NO_THROW(const auto unused = std::make_shared<op::v0::ReverseSequence>(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<element::Type> invalid_et{element::bf16, element::f16, element::f32, element::boolean};
|
||||
auto data = make_shared<op::Parameter>(element::f32, PartialShape{4, 3, 2});
|
||||
auto seq_lengths = make_shared<op::Parameter>(element::boolean, PartialShape{4});
|
||||
try {
|
||||
auto reverse_seq = make_shared<op::ReverseSequence>(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<Parameter>(element::f32, PartialShape{4, 3, 2});
|
||||
auto seq_lengths = std::make_shared<Parameter>(element::boolean, PartialShape{4});
|
||||
OV_EXPECT_THROW(
|
||||
auto reverse_seq = std::make_shared<op::v0::ReverseSequence>(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<PartialShape> invalid_pshapes = {{}, {4}};
|
||||
for (auto& pshape : invalid_pshapes) {
|
||||
try {
|
||||
auto data = make_shared<op::Parameter>(element::f32, pshape);
|
||||
auto seq_lengths = make_shared<op::Parameter>(element::i32, PartialShape{1});
|
||||
auto reverse_seq = make_shared<op::ReverseSequence>(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<Parameter>(element::i32, PartialShape{1});
|
||||
|
||||
for (auto& invalid_shape : PartialShapes{{}, {4}}) {
|
||||
auto data = std::make_shared<Parameter>(element::f32, invalid_shape);
|
||||
|
||||
OV_EXPECT_THROW(auto reverse_seq = std::make_shared<op::v0::ReverseSequence>(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<PartialShape> invalid_pshapes = {{}, {4, 1}, {1, 1, 4}};
|
||||
int64_t batch_axis = 0;
|
||||
int64_t seq_axis = 1;
|
||||
auto data = make_shared<op::Parameter>(element::f32, PartialShape{4, 3, 2});
|
||||
for (auto& pshape : invalid_pshapes) {
|
||||
try {
|
||||
auto seq_lengths = make_shared<op::Parameter>(element::i32, pshape);
|
||||
auto reverse_seq = make_shared<op::ReverseSequence>(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<Parameter>(element::f32, PartialShape{4, 3, 2});
|
||||
|
||||
for (auto& invalid_shape : PartialShapes{{}, {4, 1}, {1, 1, 4}}) {
|
||||
auto seq_lengths = std::make_shared<Parameter>(element::i32, invalid_shape);
|
||||
|
||||
OV_EXPECT_THROW(
|
||||
auto reverse_seq = std::make_shared<op::v0::ReverseSequence>(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<op::Parameter>(element::f32, PartialShape{4, 3, 2});
|
||||
auto seq_lengths = make_shared<op::Parameter>(element::i32, PartialShape{3});
|
||||
try {
|
||||
auto reverse_seq = make_shared<op::ReverseSequence>(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<Parameter>(element::f32, PartialShape{4, 3, 2});
|
||||
auto seq_lengths = std::make_shared<Parameter>(element::i32, PartialShape{3});
|
||||
|
||||
OV_EXPECT_THROW(
|
||||
auto reverse_seq = std::make_shared<op::v0::ReverseSequence>(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<op::Parameter>(element::f32, PartialShape{4, 3, 2});
|
||||
auto seq_lengths = make_shared<op::Parameter>(element::i32, PartialShape{3});
|
||||
try {
|
||||
auto reverse_seq = make_shared<op::ReverseSequence>(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<Parameter>(element::f32, PartialShape{4, 3, 2});
|
||||
auto seq_lengths = std::make_shared<Parameter>(element::i32, PartialShape{3});
|
||||
|
||||
OV_EXPECT_THROW(
|
||||
auto reverse_seq = std::make_shared<op::v0::ReverseSequence>(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<op::Parameter>(element::f32, PartialShape{4, 3, 2});
|
||||
auto seq_lengths = make_shared<op::Parameter>(element::i32, PartialShape{3});
|
||||
try {
|
||||
auto reverse_seq = make_shared<op::ReverseSequence>(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<Parameter>(element::f32, PartialShape{4, 3, 2});
|
||||
auto seq_lengths = std::make_shared<Parameter>(element::i32, PartialShape{3});
|
||||
|
||||
OV_EXPECT_THROW(
|
||||
auto reverse_seq = std::make_shared<op::v0::ReverseSequence>(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<op::Parameter>(element::f32, PartialShape::dynamic());
|
||||
auto seq_lengths = make_shared<op::Parameter>(element::i32, PartialShape::dynamic());
|
||||
auto data = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
|
||||
auto seq_lengths = std::make_shared<Parameter>(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<op::ReverseSequence>(data, seq_lengths, batch_axis, seq_axis);
|
||||
auto reverse_seq = std::make_shared<op::v0::ReverseSequence>(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<op::Parameter>(element::f32, PartialShape::dynamic());
|
||||
auto seq_lengths = make_shared<op::Parameter>(element::i32, PartialShape{3});
|
||||
auto data = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
|
||||
auto seq_lengths = std::make_shared<Parameter>(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<op::ReverseSequence>(data, seq_lengths, batch_axis, seq_axis);
|
||||
auto reverse_seq = std::make_shared<op::v0::ReverseSequence>(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<op::Parameter>(element::f32, PartialShape{2, 4, 6, 8});
|
||||
auto seq_lengths = make_shared<op::Parameter>(element::i32, PartialShape::dynamic());
|
||||
auto data = std::make_shared<Parameter>(element::f32, PartialShape{2, 4, 6, 8});
|
||||
auto seq_lengths = std::make_shared<Parameter>(element::i32, PartialShape::dynamic());
|
||||
int64_t batch_axis = 0;
|
||||
int64_t seq_axis = 1;
|
||||
auto reverse_seq = make_shared<op::ReverseSequence>(data, seq_lengths, batch_axis, seq_axis);
|
||||
auto reverse_seq = std::make_shared<op::v0::ReverseSequence>(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<op::Parameter>(
|
||||
auto data = std::make_shared<Parameter>(
|
||||
element::f32,
|
||||
PartialShape{Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()});
|
||||
auto seq_lengths = make_shared<op::Parameter>(element::i32, PartialShape::dynamic());
|
||||
auto seq_lengths = std::make_shared<Parameter>(element::i32, PartialShape::dynamic());
|
||||
int64_t batch_axis = 0;
|
||||
int64_t seq_axis = 1;
|
||||
auto reverse_seq = make_shared<op::ReverseSequence>(data, seq_lengths, batch_axis, seq_axis);
|
||||
auto reverse_seq = std::make_shared<op::v0::ReverseSequence>(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<op::Parameter>(
|
||||
auto data = std::make_shared<Parameter>(
|
||||
element::f32,
|
||||
PartialShape{Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()});
|
||||
auto seq_lengths = make_shared<op::Parameter>(element::i32, PartialShape{Dimension::dynamic()});
|
||||
auto seq_lengths = std::make_shared<Parameter>(element::i32, PartialShape{Dimension::dynamic()});
|
||||
int64_t batch_axis = 4;
|
||||
int64_t seq_axis = 1;
|
||||
try {
|
||||
auto reverse_seq = make_shared<op::ReverseSequence>(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<op::v0::ReverseSequence>(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<op::Parameter>(
|
||||
auto data = std::make_shared<Parameter>(
|
||||
element::f32,
|
||||
PartialShape{Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()});
|
||||
auto seq_lengths = make_shared<op::Parameter>(element::i32, PartialShape{Dimension::dynamic()});
|
||||
auto seq_lengths = std::make_shared<Parameter>(element::i32, PartialShape{Dimension::dynamic()});
|
||||
int64_t batch_axis = 1;
|
||||
int64_t seq_axis = 4;
|
||||
try {
|
||||
auto reverse_seq = make_shared<op::ReverseSequence>(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<op::v0::ReverseSequence>(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<op::Parameter>(
|
||||
element::f32,
|
||||
PartialShape{Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()});
|
||||
auto seq_lengths = make_shared<op::Parameter>(element::i32, PartialShape{3});
|
||||
auto data_shape = PartialShape::dynamic(4);
|
||||
set_shape_labels(data_shape, 10);
|
||||
auto data = std::make_shared<Parameter>(element::f32, data_shape);
|
||||
auto seq_lengths = std::make_shared<Parameter>(element::i32, PartialShape{3});
|
||||
int64_t batch_axis = 2;
|
||||
int64_t seq_axis = 1;
|
||||
auto reverse_seq = make_shared<op::ReverseSequence>(data, seq_lengths, batch_axis, seq_axis);
|
||||
auto reverse_seq = std::make_shared<op::v0::ReverseSequence>(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<op::Parameter>(element::f32,
|
||||
PartialShape{Dimension::dynamic(), Dimension::dynamic(), 3, Dimension::dynamic()});
|
||||
auto seq_lengths = make_shared<op::Parameter>(element::i32, PartialShape{Dimension::dynamic()});
|
||||
std::make_shared<Parameter>(element::f32,
|
||||
PartialShape{Dimension::dynamic(), Dimension::dynamic(), 3, Dimension::dynamic()});
|
||||
auto seq_lengths = std::make_shared<Parameter>(element::i32, PartialShape{Dimension::dynamic()});
|
||||
int64_t batch_axis = 2;
|
||||
int64_t seq_axis = 1;
|
||||
auto reverse_seq = make_shared<op::ReverseSequence>(data, seq_lengths, batch_axis, seq_axis);
|
||||
auto reverse_seq = std::make_shared<op::v0::ReverseSequence>(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<op::Parameter>(element::f32,
|
||||
PartialShape{Dimension::dynamic(), Dimension::dynamic(), 3, Dimension::dynamic()});
|
||||
auto seq_lengths = make_shared<op::Parameter>(element::i32, PartialShape{3});
|
||||
std::make_shared<Parameter>(element::f32,
|
||||
PartialShape{Dimension::dynamic(), Dimension::dynamic(), 3, Dimension::dynamic()});
|
||||
auto seq_lengths = std::make_shared<Parameter>(element::i32, PartialShape{3});
|
||||
int64_t batch_axis = 2;
|
||||
int64_t seq_axis = 1;
|
||||
auto reverse_seq = make_shared<op::ReverseSequence>(data, seq_lengths, batch_axis, seq_axis);
|
||||
auto reverse_seq = std::make_shared<op::v0::ReverseSequence>(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<op::Parameter>(element::f32,
|
||||
PartialShape{Dimension::dynamic(), Dimension::dynamic(), 3, Dimension::dynamic()});
|
||||
auto seq_lengths = make_shared<op::Parameter>(element::i32, PartialShape{4});
|
||||
std::make_shared<Parameter>(element::f32,
|
||||
PartialShape{Dimension::dynamic(), Dimension::dynamic(), 3, Dimension::dynamic()});
|
||||
auto seq_lengths = std::make_shared<Parameter>(element::i32, PartialShape{4});
|
||||
int64_t batch_axis = 2;
|
||||
int64_t seq_axis = 1;
|
||||
try {
|
||||
auto reverse_seq = make_shared<op::ReverseSequence>(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<op::v0::ReverseSequence>(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<op::Parameter>(element::f32, PartialShape::dynamic());
|
||||
auto seq_lengths = make_shared<op::Parameter>(element::i32, PartialShape{1});
|
||||
class TypePropReverseSequenceV0Test : public TypePropOpTest<op::v0::ReverseSequence> {};
|
||||
|
||||
TEST_F(TypePropReverseSequenceV0Test, dynamic_invalid_negative_axis_and_data_input_dynamic_rank) {
|
||||
auto data = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
|
||||
auto seq_lengths = std::make_shared<Parameter>(element::i32, PartialShape{1});
|
||||
int64_t batch_axis = 1;
|
||||
int64_t seq_axis = -2;
|
||||
try {
|
||||
auto reverse_seq = make_shared<op::ReverseSequence>(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<Parameter>(element::f32, PartialShape{4, 3, 2});
|
||||
auto seq_lengths = std::make_shared<Parameter>(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<Parameter>(element::f32, data_shape);
|
||||
auto seq_lengths = std::make_shared<Parameter>(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<Parameter>(element::f32, data_shape);
|
||||
auto seq_lengths = std::make_shared<Parameter>(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));
|
||||
}
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
// Copyright (C) 2018-2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <openvino/op/parameter.hpp>
|
||||
#include <reverse_sequence_shape_inference.hpp>
|
||||
#include <utils/shape_inference/shape_inference.hpp>
|
||||
#include <utils/shape_inference/static_shape.hpp>
|
||||
|
||||
using namespace ov;
|
||||
using namespace ov::intel_cpu;
|
||||
|
||||
TEST(StaticShapeInferenceTest, ReverseSequenceTest) {
|
||||
auto data = std::make_shared<op::v0::Parameter>(element::f32, PartialShape{-1, -1, -1});
|
||||
auto seq_lengths = std::make_shared<op::v0::Parameter>(element::i32, PartialShape{4});
|
||||
auto reverse_seq = std::make_shared<op::v0::ReverseSequence>(data, seq_lengths);
|
||||
// Test StaticShape
|
||||
std::vector<StaticShape> 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}));
|
||||
}
|
||||
+76
@@ -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<op::v0::ReverseSequence> {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
output_shapes.resize(1);
|
||||
|
||||
data = std::make_shared<Parameter>(element::f32, PartialShape::dynamic());
|
||||
seq_lengths = std::make_shared<Parameter>(element::i32, PartialShape::dynamic());
|
||||
}
|
||||
|
||||
std::shared_ptr<Parameter> 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}));
|
||||
}
|
||||
Reference in new issue
Block a user