From ca344aea541da2df0d3358a52a6a1b35e667a7cb Mon Sep 17 00:00:00 2001 From: Vitaliy Urusovskij Date: Tue, 19 Sep 2023 15:46:13 +0400 Subject: [PATCH] `TensorIteratorTest` to API2.0 (#19869) * `TensorIteratorTest` to API2.0 * Port `TensorIteratorBody` to ov::test::utils --- .../single_layer_tests/tensor_iterator.cpp | 94 ++++--- .../single_op_tests/tensor_iterator.hpp | 15 ++ .../single_op/tensor_iterator.hpp | 39 +++ .../src/single_op/tensor_iterator.cpp | 238 ++++++++++++++++++ .../ngraph_functions/utils/ngraph_helpers.hpp | 12 +- .../src/utils/ngraph_helpers.cpp | 17 -- .../include/common_test_utils/test_enums.hpp | 9 + .../common_test_utils/src/test_enums.cpp | 17 ++ 8 files changed, 365 insertions(+), 76 deletions(-) create mode 100644 src/tests/functional/plugin/shared/include/single_op_tests/tensor_iterator.hpp create mode 100644 src/tests/functional/shared_test_classes/include/shared_test_classes/single_op/tensor_iterator.hpp create mode 100644 src/tests/functional/shared_test_classes/src/single_op/tensor_iterator.cpp diff --git a/src/plugins/intel_cpu/tests/functional/shared_tests_instances/single_layer_tests/tensor_iterator.cpp b/src/plugins/intel_cpu/tests/functional/shared_tests_instances/single_layer_tests/tensor_iterator.cpp index 75e8cfe9422..d0c0f7594c7 100644 --- a/src/plugins/intel_cpu/tests/functional/shared_tests_instances/single_layer_tests/tensor_iterator.cpp +++ b/src/plugins/intel_cpu/tests/functional/shared_tests_instances/single_layer_tests/tensor_iterator.cpp @@ -3,59 +3,57 @@ // #include -#include -#include "single_layer_tests/tensor_iterator.hpp" +#include "single_op_tests/tensor_iterator.hpp" #include "common_test_utils/test_constants.hpp" -using namespace LayerTestsDefinitions; +using ov::test::TensorIteratorTest; namespace { - std::vector should_decompose = {true, false}; - // output values increase rapidly without clip, so use only seq_lengths = 2 - std::vector seq_lengths_zero_clip{2}; - std::vector seq_lengths_clip_non_zero{20}; - std::vector batch{1, 10}; - std::vector hidden_size{1, 10}; - // std::vector input_size{10}; - std::vector sequence_axis{0, 1}; - std::vector body_type - = {ngraph::helpers::TensorIteratorBody::LSTM, ngraph::helpers::TensorIteratorBody::RNN, - ngraph::helpers::TensorIteratorBody::GRU}; - std::vector clip{0.f}; - std::vector clip_non_zeros{0.7f}; - std::vector direction = {ngraph::op::RecurrentSequenceDirection::FORWARD, - ngraph::op::RecurrentSequenceDirection::REVERSE}; - std::vector netPrecisions = {InferenceEngine::Precision::FP32, - InferenceEngine::Precision::FP16}; +std::vector should_decompose = {true, false}; +// output values increase rapidly without clip, so use only seq_lengths = 2 +std::vector seq_lengths_zero_clip{2}; +std::vector seq_lengths_clip_non_zero{20}; +std::vector batch{1, 10}; +std::vector hidden_size{1, 10}; +// std::vector input_size{10}; +std::vector sequence_axis{0, 1}; +std::vector body_type += {ov::test::utils::TensorIteratorBody::LSTM, ov::test::utils::TensorIteratorBody::RNN, + ov::test::utils::TensorIteratorBody::GRU}; +std::vector clip{0.f}; +std::vector clip_non_zeros{0.7f}; +std::vector direction = {ov::op::RecurrentSequenceDirection::FORWARD, + ov::op::RecurrentSequenceDirection::REVERSE}; +std::vector model_types = {ov::element::f32, ov::element::f16}; - INSTANTIATE_TEST_SUITE_P(smoke_TensorIteratorCommon, TensorIteratorTest, - ::testing::Combine( - ::testing::ValuesIn(should_decompose), - ::testing::ValuesIn(seq_lengths_zero_clip), - ::testing::ValuesIn(batch), - ::testing::ValuesIn(hidden_size), - //::testing::ValuesIn(input_size), // hardcoded to 10 due to Combine supports up to 10 args - ::testing::ValuesIn(sequence_axis), - ::testing::ValuesIn(clip), - ::testing::ValuesIn(body_type), - ::testing::ValuesIn(direction), - ::testing::ValuesIn(netPrecisions), - ::testing::Values(ov::test::utils::DEVICE_CPU)), - TensorIteratorTest::getTestCaseName); +INSTANTIATE_TEST_SUITE_P(smoke_TensorIteratorCommon, TensorIteratorTest, + ::testing::Combine( + ::testing::ValuesIn(should_decompose), + ::testing::ValuesIn(seq_lengths_zero_clip), + ::testing::ValuesIn(batch), + ::testing::ValuesIn(hidden_size), + //::testing::ValuesIn(input_size), // hardcoded to 10 due to Combine supports up to 10 args + ::testing::ValuesIn(sequence_axis), + ::testing::ValuesIn(clip), + ::testing::ValuesIn(body_type), + ::testing::ValuesIn(direction), + ::testing::ValuesIn(model_types), + ::testing::Values(ov::test::utils::DEVICE_CPU)), + TensorIteratorTest::getTestCaseName); - INSTANTIATE_TEST_SUITE_P(smoke_TensorIteratorCommonClip, TensorIteratorTest, - ::testing::Combine( - ::testing::ValuesIn(should_decompose), - ::testing::ValuesIn(seq_lengths_clip_non_zero), - ::testing::ValuesIn(batch), - ::testing::ValuesIn(hidden_size), - //::testing::ValuesIn(input_size), // hardcoded to 10 due to Combine supports up to 10 args - ::testing::ValuesIn(sequence_axis), - ::testing::ValuesIn(clip_non_zeros), - ::testing::ValuesIn(body_type), - ::testing::ValuesIn(direction), - ::testing::ValuesIn(netPrecisions), - ::testing::Values(ov::test::utils::DEVICE_CPU)), - TensorIteratorTest::getTestCaseName); +INSTANTIATE_TEST_SUITE_P(smoke_TensorIteratorCommonClip, TensorIteratorTest, + ::testing::Combine( + ::testing::ValuesIn(should_decompose), + ::testing::ValuesIn(seq_lengths_clip_non_zero), + ::testing::ValuesIn(batch), + ::testing::ValuesIn(hidden_size), + //::testing::ValuesIn(input_size), // hardcoded to 10 due to Combine supports up to 10 args + ::testing::ValuesIn(sequence_axis), + ::testing::ValuesIn(clip_non_zeros), + ::testing::ValuesIn(body_type), + ::testing::ValuesIn(direction), + ::testing::ValuesIn(model_types), + ::testing::Values(ov::test::utils::DEVICE_CPU)), + TensorIteratorTest::getTestCaseName); } // namespace diff --git a/src/tests/functional/plugin/shared/include/single_op_tests/tensor_iterator.hpp b/src/tests/functional/plugin/shared/include/single_op_tests/tensor_iterator.hpp new file mode 100644 index 00000000000..f2409efa0cd --- /dev/null +++ b/src/tests/functional/plugin/shared/include/single_op_tests/tensor_iterator.hpp @@ -0,0 +1,15 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include "shared_test_classes/single_op/tensor_iterator.hpp" + +namespace ov { +namespace test { +TEST_P(TensorIteratorTest, Inference) { + run(); +}; +} // namespace test +} // namespace ov diff --git a/src/tests/functional/shared_test_classes/include/shared_test_classes/single_op/tensor_iterator.hpp b/src/tests/functional/shared_test_classes/include/shared_test_classes/single_op/tensor_iterator.hpp new file mode 100644 index 00000000000..27e8a4e420d --- /dev/null +++ b/src/tests/functional/shared_test_classes/include/shared_test_classes/single_op/tensor_iterator.hpp @@ -0,0 +1,39 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include +#include +#include +#include "shared_test_classes/base/ov_subgraph.hpp" +#include "common_test_utils/test_enums.hpp" + +namespace ov { +namespace test { +using TensorIteratorParams = typename std::tuple< + bool, // using unroll tensor iterator transformation + size_t, // seq_lengths + size_t, // batch + size_t, // hidden size + // todo: fix. input size hardcoded to 10 due to limitation (10 args) of gtests Combine() func. + //size_t, // input size + size_t, // sequence axis + float, // clip + ov::test::utils::TensorIteratorBody, // body type + ov::op::RecurrentSequenceDirection, // direction + ov::element::Type, // Model type + ov::test::TargetDevice>; // Device name + +class TensorIteratorTest : public testing::WithParamInterface, + virtual public ov::test::SubgraphBaseTest { +public: + static std::string getTestCaseName(const testing::TestParamInfo &obj); + +protected: + void SetUp() override; +}; +} // namespace test +} // namespace ov diff --git a/src/tests/functional/shared_test_classes/src/single_op/tensor_iterator.cpp b/src/tests/functional/shared_test_classes/src/single_op/tensor_iterator.cpp new file mode 100644 index 00000000000..7cf3bd44972 --- /dev/null +++ b/src/tests/functional/shared_test_classes/src/single_op/tensor_iterator.cpp @@ -0,0 +1,238 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "transformations/control_flow/unroll_tensor_iterator.hpp" +#include "shared_test_classes/single_op/tensor_iterator.hpp" +#include "openvino/pass/manager.hpp" +#include "ngraph_functions/builders.hpp" + +namespace ov { +namespace test { +std::string TensorIteratorTest::getTestCaseName(const testing::TestParamInfo &obj) { + bool should_decompose; + size_t seq_lengths; + size_t batch; + size_t hidden_size; + size_t input_size = 10; + size_t sequence_axis; + ov::test::utils::TensorIteratorBody ti_body; + float clip; + ov::op::RecurrentSequenceDirection direction; + ov::element::Type model_type; + std::string target_device; + std::tie(should_decompose, seq_lengths, batch, hidden_size, sequence_axis, clip, ti_body, direction, model_type, + target_device) = obj.param; + std::vector input_shapes = {}; + + switch (ti_body) { + case ov::test::utils::TensorIteratorBody::LSTM: + input_shapes = { + {{batch, input_size}, {batch, hidden_size}, {batch, hidden_size}, {4 * hidden_size, input_size}, + {4 * hidden_size, hidden_size}, {4 * hidden_size}}, + }; + break; + case ov::test::utils::TensorIteratorBody::GRU: + input_shapes = { + {{batch, input_size}, {batch, hidden_size}, {3 * hidden_size, input_size}, + {3 * hidden_size, hidden_size}, {3 * hidden_size}}, + }; + break; + case ov::test::utils::TensorIteratorBody::RNN: + input_shapes = {{batch, input_size}, {batch, hidden_size}, + {hidden_size, input_size}, {hidden_size, hidden_size}, {hidden_size}}; + break; + } + + std::ostringstream result; + result << "unrolling=" << should_decompose << "_"; + result << "seq_len=" << seq_lengths << "_"; + result << "seq_len_axis=" << sequence_axis << "_"; + result << "batch=" << batch << "_"; + result << "hidden_size=" << hidden_size << "_"; + result << "input_size=" << input_size << "_"; + result << "IS=" << ov::test::utils::vec2str(input_shapes) << "_"; + result << "TensorIteratorBody=" << ti_body << "_"; + result << "direction=" << direction << "_"; + result << "clip=" << clip << "_"; + result << "modelType=" << model_type.to_string() << "_"; + result << "targetDevice=" << target_device << "_"; + return result.str(); +} + +void TensorIteratorTest::SetUp() { + size_t seq_lengths; + bool should_decompose; + size_t batch; + size_t hidden_size; + size_t input_size = 10; + size_t sequence_axis; + ov::test::utils::TensorIteratorBody ti_body; + float clip; + ov::op::RecurrentSequenceDirection direction; + ov::element::Type model_type; + std::tie(should_decompose, seq_lengths, batch, hidden_size, sequence_axis, clip, ti_body, direction, model_type, + targetDevice) = this->GetParam(); + std::vector input_shapes; + auto tensor_iterator = std::make_shared(); + + // Each case consist of 3 steps: + // 1. Create TensorIterator body. + // 2. Set PortMap + // 3. Create outer function + auto axis = std::make_shared(ov::element::i64, ov::Shape{1}, + std::vector{static_cast(sequence_axis)}); + switch (ti_body) { + case ov::test::utils::TensorIteratorBody::LSTM: { + input_shapes = { + {{batch, seq_lengths, input_size}, {batch, hidden_size}, {batch, hidden_size}, {4 * hidden_size, input_size}, + {4 * hidden_size, hidden_size}, {4 * hidden_size}}, + }; + if (sequence_axis == 0) { + // swap batch and seq_lengths + std::swap(input_shapes[0][0], input_shapes[0][1]); + } + init_input_shapes(static_shapes_to_test_representation(input_shapes)); + ov::ParameterVector outer_params{std::make_shared(model_type, inputDynamicShapes[0]), + std::make_shared(model_type, inputDynamicShapes[1]), + std::make_shared(model_type, inputDynamicShapes[2])}; + + // 1. Create TensorIterator body. + inputDynamicShapes[0][sequence_axis] = 1; // sliced dimension + ov::ParameterVector body_params{std::make_shared(model_type, inputDynamicShapes[0]), + std::make_shared(model_type, inputDynamicShapes[1]), + std::make_shared(model_type, inputDynamicShapes[2])}; + + auto squeeze = std::make_shared(body_params[0], axis); + std::vector WRB = {input_shapes[3], input_shapes[4], input_shapes[5]}; + ov::OutputVector out_vector = {squeeze, body_params[1], body_params[2]}; + auto lstm_cell = ngraph::builder::makeLSTM(out_vector, WRB, hidden_size, {"sigmoid", "tanh", "tanh"}, {}, {}, clip); + auto unsqueeze = std::make_shared(lstm_cell->output(0), axis); + ov::ResultVector results{std::make_shared(unsqueeze), + std::make_shared(lstm_cell->output(0)), + std::make_shared(lstm_cell->output(1))}; + auto body = std::make_shared(results, body_params, "lstm_cell"); + tensor_iterator->set_function(body); + + // 2. Set PortMap + if (direction == ov::op::RecurrentSequenceDirection::FORWARD) { + tensor_iterator->set_sliced_input(body_params[0], outer_params[0], 0, 1, 1, -1, sequence_axis); + tensor_iterator->get_concatenated_slices(results[0], 0, 1, 1, -1, sequence_axis); + } else if (direction == ov::op::RecurrentSequenceDirection::REVERSE) { + tensor_iterator->set_sliced_input(body_params[0], outer_params[0], -1, -1, 1, 0, sequence_axis); + tensor_iterator->get_concatenated_slices(results[0], -1, -1, 1, 0, sequence_axis); + } else { + OPENVINO_THROW("Bidirectional case is not supported."); + } + + tensor_iterator->set_merged_input(body_params[1], outer_params[1], results[1]); + tensor_iterator->set_merged_input(body_params[2], outer_params[2], results[2]); + tensor_iterator->get_iter_value(results[1]); + tensor_iterator->get_iter_value(results[2]); + + // 3. Outer model + function = std::make_shared(tensor_iterator->outputs(), outer_params); + break; + } + case ov::test::utils::TensorIteratorBody::GRU: { + input_shapes = { + {{batch, seq_lengths, input_size}, {batch, hidden_size}, {3 * hidden_size, input_size}, + {3 * hidden_size, hidden_size}, {3 * hidden_size}}, + }; + if (sequence_axis == 0) { + // swap batch and seq_lengths + std::swap(input_shapes[0][0], input_shapes[0][1]); + } + init_input_shapes(static_shapes_to_test_representation(input_shapes)); + ov::ParameterVector outer_params{std::make_shared(model_type, inputDynamicShapes[0]), + std::make_shared(model_type, inputDynamicShapes[1])}; + + // 1. Create TensorIterator body. + inputDynamicShapes[0][sequence_axis] = 1; // sliced dimension + ov::ParameterVector body_params{std::make_shared(model_type, inputDynamicShapes[0]), + std::make_shared(model_type, inputDynamicShapes[1])}; + + std::vector WRB = {input_shapes[2], input_shapes[3], input_shapes[4]}; + auto squeeze = std::make_shared(body_params[0], axis); + ov::OutputVector out_vector = {squeeze, body_params[1]}; + auto gru_cell = ngraph::builder::makeGRU(out_vector, WRB, hidden_size, {"sigmoid", "tanh"}, + {}, {}, clip, false); + auto unsqueeze = std::make_shared(gru_cell->output(0), axis); + ov::ResultVector results{std::make_shared(gru_cell->output(0)), + std::make_shared(unsqueeze)}; + auto body = std::make_shared(results, body_params, "gru_cell"); + tensor_iterator->set_function(body); + + // 2. Set PortMap + if (direction == ov::op::RecurrentSequenceDirection::FORWARD) { + tensor_iterator->set_sliced_input(body_params[0], outer_params[0], 0, 1, 1, -1, sequence_axis); + tensor_iterator->get_concatenated_slices(results[1], 0, 1, 1, -1, sequence_axis); + } else if (direction == ov::op::RecurrentSequenceDirection::REVERSE) { + tensor_iterator->set_sliced_input(body_params[0], outer_params[0], -1, -1, 1, 0, sequence_axis); + tensor_iterator->get_concatenated_slices(results[1], -1, -1, 1, 0, sequence_axis); + } else { + OPENVINO_THROW("Bidirectional case is not supported."); + } + + tensor_iterator->set_merged_input(body_params[1], outer_params[1], results[0]); + tensor_iterator->get_iter_value(results[0]); + + // 3. Outer function + function = std::make_shared(ov::OutputVector{tensor_iterator->output(0), tensor_iterator->output(1)}, outer_params); + break; + } + case ov::test::utils::TensorIteratorBody::RNN: { + input_shapes = {{batch, seq_lengths, input_size}, + {batch, hidden_size}, + {hidden_size, input_size}, + {hidden_size, hidden_size}, + {hidden_size}}; + if (sequence_axis == 0) { + // swap batch and seq_lengths + std::swap(input_shapes[0][0], input_shapes[0][1]); + } + init_input_shapes(static_shapes_to_test_representation(input_shapes)); + ov::ParameterVector outer_params{std::make_shared(model_type, inputDynamicShapes[0]), + std::make_shared(model_type, inputDynamicShapes[1])}; + + // 1. Create TensorIterator body. + inputDynamicShapes[0][sequence_axis] = 1; // sliced dimension + ov::ParameterVector body_params{std::make_shared(model_type, inputDynamicShapes[0]), + std::make_shared(model_type, inputDynamicShapes[1])}; + std::vector WRB = {input_shapes[2], input_shapes[3], input_shapes[4]}; + auto squeeze = std::make_shared(body_params[0], axis); + ov::OutputVector out_vector = {squeeze, body_params[1]}; + auto rnn_cell = ngraph::builder::makeRNN(out_vector, WRB, hidden_size, {"tanh"}, {}, {}, clip); + auto unsqueeze = std::make_shared(rnn_cell->output(0), axis); + ov::ResultVector results{std::make_shared(rnn_cell), + std::make_shared(unsqueeze)}; + auto body = std::make_shared(results, body_params, "rnn_cell"); + tensor_iterator->set_function(body); + + // 2. Set PortMap + if (direction == ov::op::RecurrentSequenceDirection::FORWARD) { + tensor_iterator->set_sliced_input(body_params[0], outer_params[0], 0, 1, 1, -1, sequence_axis); + tensor_iterator->get_concatenated_slices(results[1], 0, 1, 1, -1, sequence_axis); + } else if (direction == ov::op::RecurrentSequenceDirection::REVERSE) { + tensor_iterator->set_sliced_input(body_params[0], outer_params[0], -1, -1, 1, 0, sequence_axis); + tensor_iterator->get_concatenated_slices(results[1], -1, -1, 1, 0, sequence_axis); + } else { + OPENVINO_THROW("Bidirectional case is not supported."); + } + + tensor_iterator->set_merged_input(body_params[1], outer_params[1], results[0]); + tensor_iterator->get_iter_value(results[0]); + + // 3. Outer function + function = std::make_shared(ov::OutputVector{tensor_iterator->output(0), tensor_iterator->output(1)}, outer_params); + break; + } + } + if (should_decompose) { + ov::pass::Manager m; + m.register_pass(); + m.run_passes(function); + } +} +} // namespace test +} // namespace ov diff --git a/src/tests/ngraph_helpers/ngraph_functions/include/ngraph_functions/utils/ngraph_helpers.hpp b/src/tests/ngraph_helpers/ngraph_functions/include/ngraph_functions/utils/ngraph_helpers.hpp index e8d16e0cfb7..5d0f3cd4ac7 100644 --- a/src/tests/ngraph_helpers/ngraph_functions/include/ngraph_functions/utils/ngraph_helpers.hpp +++ b/src/tests/ngraph_helpers/ngraph_functions/include/ngraph_functions/utils/ngraph_helpers.hpp @@ -85,19 +85,11 @@ enum QuantizationGranularity { Perchannel }; +using ov::test::utils::TensorIteratorBody; using ov::test::utils::ReductionType; using ov::test::utils::DFTOpType; using ov::test::utils::InputLayerType; using ov::test::utils::PadMode; - - -enum class TensorIteratorBody { - RNN, - GRU, - LSTM, - // CNN todo: implement -}; - using ov::test::utils::SequenceTestsMode; enum class MemoryTransformation { @@ -169,8 +161,6 @@ std::vector convertOutputPrecision(const std::vector const element::Type_t& toPrecision, const size_t elementsCount); -std::ostream& operator<<(std::ostream& os, TensorIteratorBody type); - std::ostream& operator<<(std::ostream& os, MemoryTransformation type); void resize_function(std::shared_ptr function, const std::vector& targetInputStaticShapes); diff --git a/src/tests/ngraph_helpers/ngraph_functions/src/utils/ngraph_helpers.cpp b/src/tests/ngraph_helpers/ngraph_functions/src/utils/ngraph_helpers.cpp index ff28247546f..6237536c943 100644 --- a/src/tests/ngraph_helpers/ngraph_functions/src/utils/ngraph_helpers.cpp +++ b/src/tests/ngraph_helpers/ngraph_functions/src/utils/ngraph_helpers.cpp @@ -650,23 +650,6 @@ std::vector convertOutputPrecision(const std::vector } } -std::ostream& operator<<(std::ostream& os, TensorIteratorBody type) { - switch (type) { - case TensorIteratorBody::LSTM: - os << "LSTM"; - break; - case TensorIteratorBody::RNN: - os << "RNN"; - break; - case TensorIteratorBody::GRU: - os << "GRU"; - break; - default: - throw std::runtime_error("NOT_SUPPORTED_OP_TYPE"); - } - return os; -} - std::ostream& operator<<(std::ostream& os, MemoryTransformation type) { switch (type) { case MemoryTransformation::NONE: diff --git a/src/tests/test_utils/common_test_utils/include/common_test_utils/test_enums.hpp b/src/tests/test_utils/common_test_utils/include/common_test_utils/test_enums.hpp index 4311535df95..6e73dd07a5a 100644 --- a/src/tests/test_utils/common_test_utils/include/common_test_utils/test_enums.hpp +++ b/src/tests/test_utils/common_test_utils/include/common_test_utils/test_enums.hpp @@ -152,6 +152,13 @@ enum class DFTOpType { INVERSE }; +enum class TensorIteratorBody { + RNN, + GRU, + LSTM, + // CNN todo: implement +}; + // clang-format on std::ostream& operator<<(std::ostream& os, const ReductionType& m); @@ -182,6 +189,8 @@ std::ostream& operator<<(std::ostream& os, ov::op::v8::MatrixNms::SortResultType std::ostream& operator<<(std::ostream& os, ov::op::v8::MatrixNms::DecayFunction type); +std::ostream& operator<<(std::ostream& os, TensorIteratorBody type); + } // namespace utils } // namespace test } // namespace ov diff --git a/src/tests/test_utils/common_test_utils/src/test_enums.cpp b/src/tests/test_utils/common_test_utils/src/test_enums.cpp index 446aae2cda7..8bb1cff3ce7 100644 --- a/src/tests/test_utils/common_test_utils/src/test_enums.cpp +++ b/src/tests/test_utils/common_test_utils/src/test_enums.cpp @@ -322,6 +322,23 @@ std::ostream& operator<<(std::ostream& os, op::v8::MatrixNms::DecayFunction type return os; } +std::ostream& operator<<(std::ostream& os, TensorIteratorBody type) { + switch (type) { + case TensorIteratorBody::LSTM: + os << "LSTM"; + break; + case TensorIteratorBody::RNN: + os << "RNN"; + break; + case TensorIteratorBody::GRU: + os << "GRU"; + break; + default: + throw std::runtime_error("NOT_SUPPORTED_OP_TYPE"); + } + return os; +} + } // namespace utils } // namespace test } // namespace ov