From ea52dd2642c2ca393ba45de7686e21b663f3d664 Mon Sep 17 00:00:00 2001 From: Ivan Tikhonov Date: Tue, 17 Nov 2020 12:38:22 +0300 Subject: [PATCH] TI and Sequences related transformations: transition from cnn to ngraph versions (#2927) * sequences to ti transformations, support for seq_lengths input, update reference implemetations, add new tests * fix python api, update sequences to ti transformation * transition from cnn to ngraph transformations for cpu, gpu, vpu plugins * fix convert_ti_to_sequence transformation * fix naming issue in unroll transformation * test pure TensorIterator in vpu plugin * fix sequences to ti transformation * Update sequences to TI transformation: fix reverse sequence support * update single layer tests, fix TI reference impl, fix Sequences to TI transformations * ngraph code style * fix build * fix ngraph python api * resolver review comments, refactoring * revert vpu changes * disable/fix tests * refactoring * Resolve review remarks * optimization of LSTMSeq -> LSTMSeq IE: remove unnecessary Transpose ops * Refactoring of transformation pipeline in cpu and gpu plugins, align GRU/RNN -> GRU/RNN IE with LSTM -> LSTM IE * update TensorIterator tests, refactoring * fix typo * Fix unit tests, delete unnecessary callbacks * Refactoring: delete commented code * Add FullyConnected to skipConstInfer list for legacy ConstFolding * disable legacy cnn unit tests * delete xfail * fix for backward compatibility with opset1::LSTMCell * delete xfail * fix build, remove Reshape layer from skipConstInfer list --- .../src/cldnn_engine/cldnn_engine.cpp | 50 +++++++++ .../src/cldnn_engine/cldnn_program.cpp | 18 ---- .../legacy/ngraph_ops/gru_sequence_ie.hpp | 4 +- .../legacy/ngraph_ops/lstm_sequence_ie.hpp | 4 +- .../legacy/ngraph_ops/rnn_sequence_ie.hpp | 4 +- .../src/convert_function_to_cnn_network.cpp | 6 +- .../src/legacy_api/src/graph_transformer.cpp | 2 + .../src/ngraph_ops/gru_sequence_ie.cpp | 18 ++-- .../src/ngraph_ops/lstm_sequence_ie.cpp | 18 ++-- .../src/ngraph_ops/rnn_sequence_ie.cpp | 18 ++-- .../convert_sequences_to_sequences_ie.cpp | 97 +++++++++++++++-- .../src/mkldnn_plugin/mkldnn_exec_network.cpp | 3 - .../src/mkldnn_plugin/mkldnn_plugin.cpp | 64 +++++++++-- .../nodes/mkldnn_tensoriterator_node.cpp | 1 - .../control_flow/unroll_tensor_iterator.cpp | 77 +++++-------- .../convert_ti_to_sequences.cpp | 101 ++++++++++-------- .../op_conversions/gru_cell_decomposition.cpp | 4 +- .../lstm_cell_decomposition.cpp | 14 ++- .../op_conversions/rnn_cell_decomposition.cpp | 4 +- .../convert_ti_to_sequences_test.cpp | 27 +++-- .../single_layer_tests/tensor_iterator.cpp | 11 +- .../single_layer_tests/tensor_iterator.hpp | 4 +- .../single_layer_tests/tensor_iterator.cpp | 60 +++++++---- .../shared_tests/lstm/rnn_seq_test.hpp | 4 +- .../single_layer_tests/ti_tests.hpp | 6 +- .../tests/test_ngraph/test_ops_fused.py | 2 - .../runtime/interpreter/int_executable.hpp | 1 + .../runtime/interpreter/opset_int_tbl.hpp | 1 + 28 files changed, 413 insertions(+), 210 deletions(-) diff --git a/inference-engine/src/cldnn_engine/cldnn_engine.cpp b/inference-engine/src/cldnn_engine/cldnn_engine.cpp index 0c9d6574431..91f0249d092 100644 --- a/inference-engine/src/cldnn_engine/cldnn_engine.cpp +++ b/inference-engine/src/cldnn_engine/cldnn_engine.cpp @@ -32,6 +32,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -146,6 +150,8 @@ InferenceEngine::ICNNNetwork::Ptr clDNNEngine::CloneAndTransformNetwork(const In { // Note: instead of running all Conversion Transformations you can make up your own transformation pipeline ngraph::pass::Manager manager; + using const_node_ptr = const std::shared_ptr; + const auto& pass_config = manager.get_pass_config(); manager.register_pass(); // WA: ConvertPriorBox must be executed before the 1st ConstantFolding pass manager.register_pass(); @@ -155,8 +161,51 @@ InferenceEngine::ICNNNetwork::Ptr clDNNEngine::CloneAndTransformNetwork(const In manager.register_pass(); manager.register_pass(); manager.register_pass(); + manager.register_pass(); + manager.register_pass(); + manager.register_pass(); + manager.register_pass(); + manager.register_pass(); + manager.register_pass(); manager.set_callback(transformations_callback); + + auto isCellPrimitiveSupported = [](const_node_ptr &node) -> bool { + if (const auto &rnn_cell = std::dynamic_pointer_cast(node)) { + return false; + } else if (const auto &gru_cell = std::dynamic_pointer_cast( + node)) { + return false; + } else if (const auto &lstm_cell = std::dynamic_pointer_cast( + node)) { + return lstm_cell->get_clip() == 0.0f && + lstm_cell->get_activations() == std::vector{"sigmoid", "tanh", "tanh"}; + } else if (const auto &lstm_cell_v1 = std::dynamic_pointer_cast( + node)) { + return lstm_cell_v1->get_clip() == 0.0f && + lstm_cell_v1->get_activations() == std::vector{"sigmoid", "tanh", "tanh"}; + } + return false; + }; + + pass_config->set_callback( + [isCellPrimitiveSupported](const_node_ptr &node) -> bool { + return isCellPrimitiveSupported(node); + }); + + pass_config->set_callback( + [isCellPrimitiveSupported](const_node_ptr &node) -> bool { + if (const auto& ti_op = std::dynamic_pointer_cast(node)) { + size_t count_rnn = 0; + for (const auto &op : ti_op->get_body()->get_ops()) + count_rnn += isCellPrimitiveSupported(op); + return count_rnn != 1; + } + return true; + }); manager.run_passes(nGraphFunc); enableInt8 = config.enableInt8 && ngraph::pass::low_precision::LowPrecisionTransformer::isFunctionQuantized(nGraphFunc); @@ -193,6 +242,7 @@ InferenceEngine::ICNNNetwork::Ptr clDNNEngine::CloneAndTransformNetwork(const In { ngraph::pass::Manager manager = ngraph::pass::Manager(); manager.register_pass(); + manager.register_pass(); manager.set_callback(transformations_callback); manager.run_passes(nGraphFunc); } diff --git a/inference-engine/src/cldnn_engine/cldnn_program.cpp b/inference-engine/src/cldnn_engine/cldnn_program.cpp index fb314c55e8b..a68b40cd7d3 100644 --- a/inference-engine/src/cldnn_engine/cldnn_program.cpp +++ b/inference-engine/src/cldnn_engine/cldnn_program.cpp @@ -475,24 +475,6 @@ Program::Program(InferenceEngine::ICNNNetwork& network, std::shared_ptr bool { - if (rnn.clip != 0.0f) - return true; - if (rnn.type == "GRUCell" || - rnn.type == "GRUSequence" || - rnn.type == "RNNCell" || - rnn.type == "RNNSequence") - return true; - if (!(rnn.type == "LSTMCell" || rnn.type == "LSTMSequence") || - rnn.activations == std::vector{"sigmoid", "tanh", "tanh"}) - return false; - return true; - }); - } - if (m_config.max_dynamic_batch > 1) { // check topology for applicability if (!CanProcessDynBatch(network)) { diff --git a/inference-engine/src/legacy_api/include/legacy/ngraph_ops/gru_sequence_ie.hpp b/inference-engine/src/legacy_api/include/legacy/ngraph_ops/gru_sequence_ie.hpp index 4ce569ae828..05a6d074500 100644 --- a/inference-engine/src/legacy_api/include/legacy/ngraph_ops/gru_sequence_ie.hpp +++ b/inference-engine/src/legacy_api/include/legacy/ngraph_ops/gru_sequence_ie.hpp @@ -32,7 +32,8 @@ public: const std::vector &activations_alpha, const std::vector &activations_beta, float clip, - bool linear_before_reset); + bool linear_before_reset, + int64_t seq_axis = 1); GRUSequenceIE() = delete; @@ -53,6 +54,7 @@ public: bool visit_attributes(AttributeVisitor& visitor) override; protected: + int64_t m_seq_axis; op::RecurrentSequenceDirection m_direction; bool m_linear_before_reset; }; diff --git a/inference-engine/src/legacy_api/include/legacy/ngraph_ops/lstm_sequence_ie.hpp b/inference-engine/src/legacy_api/include/legacy/ngraph_ops/lstm_sequence_ie.hpp index debe93b98f6..75e8cb6ec3f 100644 --- a/inference-engine/src/legacy_api/include/legacy/ngraph_ops/lstm_sequence_ie.hpp +++ b/inference-engine/src/legacy_api/include/legacy/ngraph_ops/lstm_sequence_ie.hpp @@ -32,7 +32,8 @@ public: const std::vector &activations, const std::vector &activations_alpha, const std::vector &activations_beta, - float clip); + float clip, + int64_t seq_len = 1); std::shared_ptr clone_with_new_inputs(const OutputVector &new_args) const override; @@ -43,6 +44,7 @@ public: bool visit_attributes(AttributeVisitor& visitor) override; protected: + int64_t m_seq_axis; ngraph::op::RecurrentSequenceDirection m_direction; }; } // namespace op diff --git a/inference-engine/src/legacy_api/include/legacy/ngraph_ops/rnn_sequence_ie.hpp b/inference-engine/src/legacy_api/include/legacy/ngraph_ops/rnn_sequence_ie.hpp index 26378ca9b88..33c83cda388 100644 --- a/inference-engine/src/legacy_api/include/legacy/ngraph_ops/rnn_sequence_ie.hpp +++ b/inference-engine/src/legacy_api/include/legacy/ngraph_ops/rnn_sequence_ie.hpp @@ -29,7 +29,8 @@ public: const std::vector &activations, const std::vector &activations_alpha, const std::vector &activations_beta, - float clip); + float clip, + int64_t seq_axis = 1); RNNSequenceIE() = delete; @@ -50,6 +51,7 @@ public: bool visit_attributes(AttributeVisitor& visitor) override; protected: + int64_t m_seq_axis; op::RecurrentSequenceDirection m_direction; }; } // namespace op diff --git a/inference-engine/src/legacy_api/src/convert_function_to_cnn_network.cpp b/inference-engine/src/legacy_api/src/convert_function_to_cnn_network.cpp index 3e8a8130ed5..5084b537815 100644 --- a/inference-engine/src/legacy_api/src/convert_function_to_cnn_network.cpp +++ b/inference-engine/src/legacy_api/src/convert_function_to_cnn_network.cpp @@ -745,7 +745,7 @@ InferenceEngine::details::CNNLayerCreator::CNNLayerCreator(const std::shared_ptr details::convertPrecision(node->get_output_element_type(0))}; auto res = std::make_shared(attrs); res->params = params; - + res->axis = std::stoi(res->params["axis"]); if (res->params["direction"] == "reverse") res->params["direction"] = "Backward"; else if (res->params["direction"] == "forward") @@ -784,7 +784,7 @@ InferenceEngine::details::CNNLayerCreator::CNNLayerCreator(const std::shared_ptr res->params = params; res->cellType = RNNSequenceLayer::CellType::RNN; - + res->axis = std::stoi(res->params["axis"]); if (res->params["direction"] == "reverse") res->params["direction"] = "Backward"; else if (res->params["direction"] == "forward") @@ -818,7 +818,7 @@ InferenceEngine::details::CNNLayerCreator::CNNLayerCreator(const std::shared_ptr res->params = params; res->cellType = RNNSequenceLayer::CellType::LSTM; - + res->axis = std::stoi(res->params["axis"]); if (res->params["direction"] == "reverse") res->params["direction"] = "Backward"; else if (res->params["direction"] == "forward") diff --git a/inference-engine/src/legacy_api/src/graph_transformer.cpp b/inference-engine/src/legacy_api/src/graph_transformer.cpp index ff7c98b561e..f2b50cdf3e3 100644 --- a/inference-engine/src/legacy_api/src/graph_transformer.cpp +++ b/inference-engine/src/legacy_api/src/graph_transformer.cpp @@ -218,6 +218,8 @@ static std::vector skipConstInfer = { "CumSum", // Const inference function for CumSum is not implemented "Convolution", // Const inference function for Convolution is not implemented "Eltwise", // Const inference function for Eltwise is not implemented + "FullyConnected", + "Squeeze" }; const std::map ConstTransformer::getConstLayers(const std::vector& sortedLayers) { diff --git a/inference-engine/src/legacy_api/src/ngraph_ops/gru_sequence_ie.cpp b/inference-engine/src/legacy_api/src/ngraph_ops/gru_sequence_ie.cpp index 532f63f850b..df615cb0122 100644 --- a/inference-engine/src/legacy_api/src/ngraph_ops/gru_sequence_ie.cpp +++ b/inference-engine/src/legacy_api/src/ngraph_ops/gru_sequence_ie.cpp @@ -25,10 +25,12 @@ op::GRUSequenceIE::GRUSequenceIE(const Output& X, const std::vector& activations_alpha, const std::vector& activations_beta, float clip, - bool linear_before_reset) + bool linear_before_reset, + int64_t seq_axis) : RNNCellBase({X, H_t, seq_lenghts, WR, B}, hidden_size, clip, activations, activations_alpha, activations_beta), m_direction(direction), - m_linear_before_reset(linear_before_reset) { + m_linear_before_reset(linear_before_reset), + m_seq_axis(seq_axis) { constructor_validate_and_infer_types(); } @@ -62,9 +64,12 @@ void op::GRUSequenceIE::validate_and_infer_types() { PartialShape output_shape_0{PartialShape::dynamic(3)}; PartialShape output_shape_1{PartialShape::dynamic(2)}; if (get_input_partial_shape(0).is_static()) { - size_t batch_size = get_input_partial_shape(0).get_shape()[0]; - size_t seq_length = get_input_partial_shape(0).get_shape()[1]; - output_shape_0 = Shape{batch_size, seq_length, m_hidden_size}; + size_t batch_size = get_input_partial_shape(0).get_shape()[1 - m_seq_axis]; + size_t seq_length = get_input_partial_shape(0).get_shape()[m_seq_axis]; + if (m_seq_axis == 1) + output_shape_0 = Shape{batch_size, seq_length, m_hidden_size}; + else + output_shape_0 = Shape{seq_length, batch_size, m_hidden_size}; output_shape_1 = Shape{batch_size, m_hidden_size}; } set_output_type(0, arg_type, output_shape_0); @@ -74,6 +79,7 @@ void op::GRUSequenceIE::validate_and_infer_types() { bool op::GRUSequenceIE::visit_attributes(AttributeVisitor& visitor) { visitor.on_attribute("direction", m_direction); visitor.on_attribute("linear_before_reset", m_linear_before_reset); + visitor.on_attribute("axis", m_seq_axis); return op::util::RNNCellBase::visit_attributes(visitor); } @@ -81,5 +87,5 @@ shared_ptr op::GRUSequenceIE::clone_with_new_inputs(const OutputVector& ne check_new_args_count(this, new_args); return std::make_shared(new_args.at(0), new_args.at(1), new_args.at(2), new_args.at(3), new_args.at(4), m_hidden_size, m_direction, m_activations, m_activations_alpha, m_activations_beta, m_clip, - m_linear_before_reset); + m_linear_before_reset, m_seq_axis); } diff --git a/inference-engine/src/legacy_api/src/ngraph_ops/lstm_sequence_ie.cpp b/inference-engine/src/legacy_api/src/ngraph_ops/lstm_sequence_ie.cpp index dd0e31b1867..fa7b6f45ae6 100644 --- a/inference-engine/src/legacy_api/src/ngraph_ops/lstm_sequence_ie.cpp +++ b/inference-engine/src/legacy_api/src/ngraph_ops/lstm_sequence_ie.cpp @@ -25,9 +25,11 @@ op::LSTMSequenceIE::LSTMSequenceIE(const Output &X, const std::vector &activations, const std::vector &activations_alpha, const std::vector &activations_beta, - float clip) + float clip, + int64_t seq_axis) : RNNCellBase({X, H_t, C_t, seq_lenghts, WR, B}, hidden_size, clip, activations, activations_alpha, activations_beta), - m_direction(direction) { + m_direction(direction), + m_seq_axis(seq_axis) { constructor_validate_and_infer_types(); } @@ -64,9 +66,12 @@ void op::LSTMSequenceIE::validate_and_infer_types() { PartialShape output_shape_0{PartialShape::dynamic(3)}; PartialShape output_shape_1{PartialShape::dynamic(2)}; if (get_input_partial_shape(0).is_static()) { - size_t batch_size = get_input_partial_shape(0).get_shape()[0]; - size_t seq_length = get_input_partial_shape(0).get_shape()[1]; - output_shape_0 = Shape{batch_size, seq_length, m_hidden_size}; + size_t batch_size = get_input_partial_shape(0).get_shape()[1 - m_seq_axis]; + size_t seq_length = get_input_partial_shape(0).get_shape()[m_seq_axis]; + if (m_seq_axis == 1) + output_shape_0 = Shape{batch_size, seq_length, m_hidden_size}; + else + output_shape_0 = Shape{seq_length, batch_size, m_hidden_size}; output_shape_1 = Shape{batch_size, m_hidden_size}; } set_output_type(0, arg_type, output_shape_0); @@ -76,6 +81,7 @@ void op::LSTMSequenceIE::validate_and_infer_types() { bool ngraph::op::LSTMSequenceIE::visit_attributes(AttributeVisitor& visitor) { visitor.on_attribute("direction", m_direction); + visitor.on_attribute("axis", m_seq_axis); return op::util::RNNCellBase::visit_attributes(visitor); } @@ -83,5 +89,5 @@ shared_ptr op::LSTMSequenceIE::clone_with_new_inputs(const OutputVector &n check_new_args_count(this, new_args); return make_shared(new_args.at(0), new_args.at(1), new_args.at(2), new_args.at(3), new_args.at(4), new_args.at(5), m_hidden_size, m_direction, m_activations, m_activations_alpha, m_activations_beta, - m_clip); + m_clip, m_seq_axis); } diff --git a/inference-engine/src/legacy_api/src/ngraph_ops/rnn_sequence_ie.cpp b/inference-engine/src/legacy_api/src/ngraph_ops/rnn_sequence_ie.cpp index 632ba2e6453..0c519694364 100644 --- a/inference-engine/src/legacy_api/src/ngraph_ops/rnn_sequence_ie.cpp +++ b/inference-engine/src/legacy_api/src/ngraph_ops/rnn_sequence_ie.cpp @@ -24,9 +24,11 @@ op::RNNSequenceIE::RNNSequenceIE(const Output& X, const std::vector& activations, const std::vector& activations_alpha, const std::vector& activations_beta, - float clip) + float clip, + int64_t seq_axis) : RNNCellBase({X, H_t, seq_lengths, WR, B}, hidden_size, clip, activations, activations_alpha, activations_beta), - m_direction(direction) { + m_direction(direction), + m_seq_axis(seq_axis) { constructor_validate_and_infer_types(); } @@ -60,9 +62,12 @@ void op::RNNSequenceIE::validate_and_infer_types() { PartialShape output_shape_0{PartialShape::dynamic(3)}; PartialShape output_shape_1{PartialShape::dynamic(2)}; if (get_input_partial_shape(0).is_static()) { - size_t batch_size = get_input_partial_shape(0).get_shape()[0]; - size_t seq_length = get_input_partial_shape(0).get_shape()[1]; - output_shape_0 = Shape{batch_size, seq_length, m_hidden_size}; + size_t batch_size = get_input_partial_shape(0).get_shape()[1 - m_seq_axis]; + size_t seq_length = get_input_partial_shape(0).get_shape()[m_seq_axis]; + if (m_seq_axis == 1) + output_shape_0 = Shape{batch_size, seq_length, m_hidden_size}; + else + output_shape_0 = Shape{seq_length, batch_size, m_hidden_size}; output_shape_1 = Shape{batch_size, m_hidden_size}; } set_output_type(0, arg_type, output_shape_0); @@ -71,11 +76,12 @@ void op::RNNSequenceIE::validate_and_infer_types() { bool op::RNNSequenceIE::visit_attributes(AttributeVisitor& visitor) { visitor.on_attribute("direction", m_direction); + visitor.on_attribute("axis", m_seq_axis); return op::util::RNNCellBase::visit_attributes(visitor); } shared_ptr op::RNNSequenceIE::clone_with_new_inputs(const ngraph::OutputVector &new_args) const { check_new_args_count(this, new_args); return make_shared(new_args.at(0), new_args.at(1), new_args.at(2), new_args.at(3), - new_args.at(4), m_hidden_size, m_direction, m_activations, m_activations_alpha, m_activations_beta, m_clip); + new_args.at(4), m_hidden_size, m_direction, m_activations, m_activations_alpha, m_activations_beta, m_clip, m_seq_axis); } diff --git a/inference-engine/src/legacy_api/src/transformations/convert_opset1_to_legacy/convert_sequences_to_sequences_ie.cpp b/inference-engine/src/legacy_api/src/transformations/convert_opset1_to_legacy/convert_sequences_to_sequences_ie.cpp index 4ac964ad92d..4255aba7ed9 100644 --- a/inference-engine/src/legacy_api/src/transformations/convert_opset1_to_legacy/convert_sequences_to_sequences_ie.cpp +++ b/inference-engine/src/legacy_api/src/transformations/convert_opset1_to_legacy/convert_sequences_to_sequences_ie.cpp @@ -18,6 +18,41 @@ NGRAPH_RTTI_DEFINITION(ngraph::pass::ConvertLSTMSequenceMatcher, "ConvertLSTMSeq NGRAPH_RTTI_DEFINITION(ngraph::pass::ConvertGRUSequenceMatcher, "ConvertGRUSequenceMatcher", 0); NGRAPH_RTTI_DEFINITION(ngraph::pass::ConvertRNNSequenceMatcher, "ConvertRNNSequenceMatcher", 0); +namespace { + int64_t get_seq_axis(const std::shared_ptr& sequence_node) { + // Optimization. + // Plug-ins support seq_axis attribute (value 1 or 0) for Seq ops, but according to the spec we don't + // support this attribute and should insert Transpose layer before and after Seq op in TI to Sequences + // transformation. Additional Transpose layers affect the performance, so we try to detect pattern + // Transpose(axis_order={1,0,2}) -> Seq -> Transpose(axis_order={2,1,0,3} + // and replace unnecessary Transpose ops with SeqIE (seq_axis = 0) to transfer value + // of the attribute to plug-ins. + // todo: specify seq_axis attribute for Sequence ops. + int64_t seq_axis = 1; // default + const auto& target_inputs = sequence_node->output(0).get_target_inputs(); + if (target_inputs.size() == 1) { + const auto& transpose_before = std::dynamic_pointer_cast(sequence_node->input_value(0).get_node_shared_ptr()); + const auto& transpose_after = std::dynamic_pointer_cast(target_inputs.begin()->get_node()->shared_from_this()); + if (transpose_after != nullptr && transpose_before != nullptr) { + auto order_before = std::dynamic_pointer_cast( + transpose_before->input_value(1).get_node_shared_ptr()); + auto order_after = std::dynamic_pointer_cast( + transpose_after->input_value(1).get_node_shared_ptr()); + if (order_before != nullptr && order_after != nullptr) { + auto order_before_values = order_before->cast_vector(); + auto order_after_values = order_after->cast_vector(); + std::vector order_ref_before = {1, 0, 2}; + std::vector order_ref_after = {2, 1, 0, 3}; + if (order_before_values == order_ref_before && order_after_values == order_ref_after) { + seq_axis = 0; + } + } + } + } + return seq_axis; + } +} // namespace + ngraph::pass::ConvertLSTMSequenceMatcher::ConvertLSTMSequenceMatcher() { auto lstm_sequence_ngraph = ngraph::pattern::wrap_type(); @@ -34,6 +69,13 @@ ngraph::pass::ConvertLSTMSequenceMatcher::ConvertLSTMSequenceMatcher() { if (lstm_sequence->get_direction() == ngraph::op::RecurrentSequenceDirection::BIDIRECTIONAL) return false; + // Detect pattern: Transpose_before -> Seq -> Transpose_after + auto seq_axis = get_seq_axis(lstm_sequence); + ngraph::Output in_0 = lstm_sequence->input(0).get_source_output(); + if (seq_axis == 0) { + // input(0) to Transpose_before + in_0 = lstm_sequence->get_input_source_output(0).get_node_shared_ptr()->get_input_source_output(0); + } // for forward/reverse cases we can squeeze num_direction dimension auto axis_1 = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); auto in_1 = std::make_shared(lstm_sequence->input_value(1), axis_1); @@ -43,7 +85,7 @@ ngraph::pass::ConvertLSTMSequenceMatcher::ConvertLSTMSequenceMatcher() { auto in_3 = std::make_shared(concat->output(0), axis_2); auto in_4 = std::make_shared(lstm_sequence->input_value(6), axis_2); auto lstm_sequence_ie = std::make_shared( - lstm_sequence->input(0).get_source_output(), // X + in_0, // X in_1, // initial_hidden_state in_2, // initial_cell_state lstm_sequence->input_value(3), @@ -54,7 +96,8 @@ ngraph::pass::ConvertLSTMSequenceMatcher::ConvertLSTMSequenceMatcher() { lstm_sequence->get_activations(), lstm_sequence->get_activations_alpha(), lstm_sequence->get_activations_beta(), - lstm_sequence->get_clip()); + lstm_sequence->get_clip(), + seq_axis); auto unsqueeze_axis = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); auto unsqueeze_1 = std::make_shared(lstm_sequence_ie->output(0), unsqueeze_axis); @@ -66,7 +109,13 @@ ngraph::pass::ConvertLSTMSequenceMatcher::ConvertLSTMSequenceMatcher() { unsqueeze_1->set_friendly_name(lstm_sequence->get_friendly_name()+".0"); unsqueeze_2->set_friendly_name(lstm_sequence->get_friendly_name()+".1"); unsqueeze_3->set_friendly_name(lstm_sequence->get_friendly_name()+".2"); - ngraph::replace_node(lstm_sequence, {unsqueeze_1->output(0), unsqueeze_2->output(0), unsqueeze_3->output(0)}); + if (seq_axis == 1) { + ngraph::replace_node(lstm_sequence, {unsqueeze_1->output(0), unsqueeze_2->output(0), unsqueeze_3->output(0)}); + } else { + auto transpose_after = lstm_sequence->output(0).get_target_inputs().begin()->get_node()->shared_from_this(); + ngraph::replace_node(transpose_after, unsqueeze_1); + ngraph::replace_node(lstm_sequence, {lstm_sequence_ie->output(0), unsqueeze_2->output(0), unsqueeze_3->output(0)}); + } return true; }; @@ -90,6 +139,13 @@ ngraph::pass::ConvertGRUSequenceMatcher::ConvertGRUSequenceMatcher() { if (gru_sequence->get_direction() == ngraph::op::RecurrentSequenceDirection::BIDIRECTIONAL) return false; + // Detect pattern: Transpose_before -> Seq -> Transpose_after + auto seq_axis = get_seq_axis(gru_sequence); + ngraph::Output in_0 = gru_sequence->input(0).get_source_output(); + if (seq_axis == 0) { + // input(0) to Transpose_before + in_0 = gru_sequence->get_input_source_output(0).get_node_shared_ptr()->get_input_source_output(0); + } // for forward/reverse cases we can squeeze num_direction dimension auto axis_1 = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); auto in_1 = std::make_shared(gru_sequence->input_value(1), axis_1); @@ -99,7 +155,7 @@ ngraph::pass::ConvertGRUSequenceMatcher::ConvertGRUSequenceMatcher() { auto in_4 = std::make_shared(gru_sequence->input_value(5), axis_2); auto gru_sequence_ie = std::make_shared( - gru_sequence->input_value(0), // X + in_0, // X in_1, // initial_hidden_state gru_sequence->input_value(2), in_3, // WR @@ -110,7 +166,8 @@ ngraph::pass::ConvertGRUSequenceMatcher::ConvertGRUSequenceMatcher() { gru_sequence->get_activations_alpha(), gru_sequence->get_activations_beta(), gru_sequence->get_clip(), - gru_sequence->get_linear_before_reset()); + gru_sequence->get_linear_before_reset(), + seq_axis); auto unsqueeze_axis = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); auto unsqueeze_1 = std::make_shared(gru_sequence_ie->output(0), unsqueeze_axis); @@ -119,7 +176,13 @@ ngraph::pass::ConvertGRUSequenceMatcher::ConvertGRUSequenceMatcher() { ngraph::copy_runtime_info(gru_sequence, {concat, gru_sequence_ie, unsqueeze_1, unsqueeze_2, in_1, in_3, in_4}); unsqueeze_1->set_friendly_name(gru_sequence->get_friendly_name()+".0"); unsqueeze_2->set_friendly_name(gru_sequence->get_friendly_name()+".1"); - ngraph::replace_node(gru_sequence, {unsqueeze_1, unsqueeze_2}); + if (seq_axis == 1) { + ngraph::replace_node(gru_sequence, {unsqueeze_1->output(0), unsqueeze_2->output(0)}); + } else { + auto transpose_after = gru_sequence->output(0).get_target_inputs().begin()->get_node()->shared_from_this(); + ngraph::replace_node(transpose_after, unsqueeze_1); + ngraph::replace_node(gru_sequence, {gru_sequence_ie->output(0), unsqueeze_2->output(0)}); + } return true; }; @@ -140,6 +203,14 @@ ngraph::pass::ConvertRNNSequenceMatcher::ConvertRNNSequenceMatcher() { if (rnn_sequence->get_direction() == ngraph::op::RecurrentSequenceDirection::BIDIRECTIONAL) return false; + // Detect pattern: Transpose_before -> Seq -> Transpose_after + auto seq_axis = get_seq_axis(rnn_sequence); + ngraph::Output in_0 = rnn_sequence->input(0).get_source_output(); + if (seq_axis == 0) { + // input(0) to Transpose_before + in_0 = rnn_sequence->get_input_source_output(0).get_node_shared_ptr()->get_input_source_output(0); + } + auto W = rnn_sequence->input_value(3); auto R = rnn_sequence->input_value(4); @@ -151,7 +222,7 @@ ngraph::pass::ConvertRNNSequenceMatcher::ConvertRNNSequenceMatcher() { auto in_3 = std::make_shared(concat->output(0), axis_2); auto in_4 = std::make_shared(rnn_sequence->input_value(5), axis_2); auto rnn_sequence_ie = std::make_shared( - rnn_sequence->input_value(0), // X + in_0, // X in_1, // initial_hidden_state rnn_sequence->input_value(2), in_3, // WR @@ -161,7 +232,8 @@ ngraph::pass::ConvertRNNSequenceMatcher::ConvertRNNSequenceMatcher() { rnn_sequence->get_activations(), rnn_sequence->get_activations_alpha(), rnn_sequence->get_activations_beta(), - rnn_sequence->get_clip()); + rnn_sequence->get_clip(), + seq_axis); auto unsqueeze_axis = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); auto unsqueeze_1 = std::make_shared(rnn_sequence_ie->output(0), unsqueeze_axis); @@ -171,7 +243,14 @@ ngraph::pass::ConvertRNNSequenceMatcher::ConvertRNNSequenceMatcher() { unsqueeze_2}); unsqueeze_1->set_friendly_name(rnn_sequence->get_friendly_name()+".0"); unsqueeze_2->set_friendly_name(rnn_sequence->get_friendly_name()+".1"); - ngraph::replace_node(rnn_sequence, {unsqueeze_1->output(0), unsqueeze_2->output(0)}); + + if (seq_axis == 1) { + ngraph::replace_node(rnn_sequence, {unsqueeze_1->output(0), unsqueeze_2->output(0)}); + } else { + auto transpose_after = rnn_sequence->output(0).get_target_inputs().begin()->get_node()->shared_from_this(); + ngraph::replace_node(transpose_after, unsqueeze_1); + ngraph::replace_node(rnn_sequence, {rnn_sequence_ie->output(0), unsqueeze_2->output(0)}); + } return true; }; diff --git a/inference-engine/src/mkldnn_plugin/mkldnn_exec_network.cpp b/inference-engine/src/mkldnn_plugin/mkldnn_exec_network.cpp index 676a8d06b7f..e19708a52b0 100644 --- a/inference-engine/src/mkldnn_plugin/mkldnn_exec_network.cpp +++ b/inference-engine/src/mkldnn_plugin/mkldnn_exec_network.cpp @@ -78,9 +78,6 @@ MKLDNNExecNetwork::MKLDNNExecNetwork(const InferenceEngine::ICNNNetwork &network } } - OV_ITT_TASK_NEXT(taskChain, "UnrollPasses"); - MKLDNNGraph::ApplyUnrollPasses(static_cast(*_clonedNetwork)); - OV_ITT_TASK_NEXT(taskChain, "createConstInputs"); auto createConstInputTo = [&](CNNLayerPtr layer, Blob::Ptr blob, std::string name) { LayerParams attrs = {layer.get()->name + "_const_" + name, "Const", blob->getTensorDesc().getPrecision()}; diff --git a/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp b/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp index 21fc23cb1b8..c7225373b3b 100644 --- a/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp +++ b/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp @@ -46,6 +46,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -102,17 +106,23 @@ static void Transformation(ICNNNetwork::Ptr& clonedNetwork, const Config& conf) manager.register_pass(); manager.register_pass(); manager.register_pass(); + manager.register_pass(); + manager.register_pass(); + manager.register_pass(); + manager.register_pass(); + manager.register_pass(); + manager.register_pass(); - std::vector> convert_precision_list { - {ngraph::element::i64, ngraph::element::i32}, - {ngraph::element::u64, ngraph::element::i32}, - {ngraph::element::u16, ngraph::element::i32}, - {ngraph::element::u32, ngraph::element::i32}, - {ngraph::element::f16, ngraph::element::f32}, + std::vector> convert_precision_list{ + {ngraph::element::i64, ngraph::element::i32}, + {ngraph::element::u64, ngraph::element::i32}, + {ngraph::element::u16, ngraph::element::i32}, + {ngraph::element::u32, ngraph::element::i32}, + {ngraph::element::f16, ngraph::element::f32}, {ngraph::element::boolean, ngraph::element::u8}, }; - for (auto & precision : convert_precision_list) { + for (auto &precision : convert_precision_list) { manager.register_pass(precision.first, precision.second); } @@ -122,7 +132,7 @@ static void Transformation(ICNNNetwork::Ptr& clonedNetwork, const Config& conf) // SpaceToDepth/ DepthToSpace node implementation supports only equal input/output tensors with rank <= 5 pass_config->set_callback( + ngraph::pass::ConvertDepthToSpace>( [](const_node_ptr &node) -> bool { return node->input_value(0).get_shape().size() <= 5lu && node->input_value(0).get_shape().size() == node->get_output_shape(0).size(); @@ -141,6 +151,44 @@ static void Transformation(ICNNNetwork::Ptr& clonedNetwork, const Config& conf) return rank == 4lu || rank == 5lu; }); + auto isCellPrimitiveSupported = [](const_node_ptr &node) -> bool { + if (const auto &rnn_cell = std::dynamic_pointer_cast(node)) { + return rnn_cell->get_clip() == 0.0f; + } else if (const auto &gru_cell = std::dynamic_pointer_cast( + node)) { + return gru_cell->get_clip() == 0.0f + && gru_cell->get_activations() == std::vector{"sigmoid", "tanh"}; + } else if (const auto &lstm_cell = std::dynamic_pointer_cast( + node)) { + return lstm_cell->get_clip() == 0.0f && + lstm_cell->get_activations() == std::vector{"sigmoid", "tanh", "tanh"}; + } else if (const auto &lstm_cell_v1 = std::dynamic_pointer_cast( + node)) { + return lstm_cell_v1->get_clip() == 0.0f && + lstm_cell_v1->get_activations() == std::vector{"sigmoid", "tanh", "tanh"}; + } + return false; + }; + + pass_config->set_callback( + [isCellPrimitiveSupported](const_node_ptr &node) -> bool { + return isCellPrimitiveSupported(node); + }); + + pass_config->set_callback( + [isCellPrimitiveSupported](const_node_ptr &node) -> bool { + if (const auto& ti_op = std::dynamic_pointer_cast(node)) { + size_t count_rnn = 0; + for (const auto &op : ti_op->get_body()->get_ops()) + count_rnn += isCellPrimitiveSupported(op); + return count_rnn != 1; + } + return true; + }); + // List of enabled/disabled transformations pass_config->disable(); pass_config->disable(); diff --git a/inference-engine/src/mkldnn_plugin/nodes/mkldnn_tensoriterator_node.cpp b/inference-engine/src/mkldnn_plugin/nodes/mkldnn_tensoriterator_node.cpp index b299e14733f..a155a865e23 100644 --- a/inference-engine/src/mkldnn_plugin/nodes/mkldnn_tensoriterator_node.cpp +++ b/inference-engine/src/mkldnn_plugin/nodes/mkldnn_tensoriterator_node.cpp @@ -193,7 +193,6 @@ void MKLDNNTensorIteratorNode::getSupportedDescriptors() { THROW_IE_EXCEPTION << "Cannot convert to TensorIterator layer."; n_iter = getNumIteration(*ti); - MKLDNNGraph::ApplyUnrollPasses(ti->body); sub_graph.CreateGraph(ti->body, ext_mng, weightCache); // Try to detect inputs and outputs by indexes diff --git a/inference-engine/src/transformations/src/transformations/control_flow/unroll_tensor_iterator.cpp b/inference-engine/src/transformations/src/transformations/control_flow/unroll_tensor_iterator.cpp index d374e281a5e..96a7a634cc6 100644 --- a/inference-engine/src/transformations/src/transformations/control_flow/unroll_tensor_iterator.cpp +++ b/inference-engine/src/transformations/src/transformations/control_flow/unroll_tensor_iterator.cpp @@ -22,8 +22,8 @@ bool ngraph::pass::UnrollTensorIterator::run_on_function(std::shared_ptrget_body(); - auto num_iter = ti->get_num_iterations(); + const auto& function = ti->get_body(); + const auto num_iter = ti->get_num_iterations(); // negative value means inconsistent TI if (num_iter <= -1) { @@ -44,13 +44,7 @@ bool ngraph::pass::UnrollTensorIterator::run_on_function(std::shared_ptrget_input_descriptions()) { const std::string& type_name = desc->get_type_info().name; - - if (type_name == "SliceInputDescription") { - auto input_desc = std::dynamic_pointer_cast(desc); - if (!input_desc) { - return false; - } - + if (const auto& input_desc = std::dynamic_pointer_cast(desc)) { // Connect the sliced input (layer before the input) to the Split layer and connect // the corresponding Split output to the corresponding copy of the body. // If the number of iterations is 1, then the Split is not needed. @@ -65,50 +59,39 @@ bool ngraph::pass::UnrollTensorIterator::run_on_function(std::shared_ptr 0 ? j : num_iter - j - 1; - auto param = body_functions[j]->get_parameters()[input_desc->m_body_parameter_index]; + const auto& param = body_functions[j]->get_parameters()[input_desc->m_body_parameter_index]; for (auto &output : param->outputs()) { output.replace(split->output(idx)); } } } else { // connect to the body - auto param = body_functions[0]->get_parameters()[input_desc->m_body_parameter_index]; + const auto& param = body_functions[0]->get_parameters()[input_desc->m_body_parameter_index]; for (auto &output : param->outputs()) { output.replace(in_data); } } - } else if (type_name == "MergedInputDescription") { - auto input_desc = std::dynamic_pointer_cast(desc); - if (!input_desc) { - return false; - } - + } else if (const auto& merged_desc = std::dynamic_pointer_cast(desc)) { // Connect the input to the corresponding copy of the body. - auto in_data = ti->input_values()[input_desc->m_input_index].get_node_shared_ptr(); - auto param = body_functions[0]->get_parameters()[input_desc->m_body_parameter_index]; + auto in_data = ti->input_values()[merged_desc->m_input_index]; + const auto& param = body_functions[0]->get_parameters()[merged_desc->m_body_parameter_index]; for (auto &output : param->outputs()) { output.replace(in_data); } // Back-edge processing. Connect the copies of the body to each other. for (int64_t j = 1; j < num_iter; j++) { - auto cur_param = body_functions[j]->get_parameters()[input_desc->m_body_parameter_index]; - auto prev_val = body_functions[j - 1]->get_results()[input_desc->m_body_value_index]; + const auto& cur_param = body_functions[j]->get_parameters()[merged_desc->m_body_parameter_index]; + const auto& prev_val = body_functions[j - 1]->get_results()[merged_desc->m_body_value_index]; for (auto &output : cur_param->outputs()) { output.replace(prev_val->get_input_source_output(0)); } } - } else if (type_name == "InvariantInputDescription") { - auto input_desc = std::dynamic_pointer_cast( - desc); - if (!input_desc) { - return false; - } - + } else if (const auto& invariant_desc = std::dynamic_pointer_cast(desc)) { // Connect the input to the corresponding copy of the body. - auto in_data = ti->input_values()[input_desc->m_input_index].get_node_shared_ptr(); + auto in_data = ti->input_values()[invariant_desc->m_input_index]; for (int64_t j = 0; j < num_iter; j++) { - auto param = body_functions[j]->get_parameters()[input_desc->m_body_parameter_index]; + auto param = body_functions[j]->get_parameters()[invariant_desc->m_body_parameter_index]; for (auto &output : param->outputs()) { output.replace(in_data); } @@ -122,9 +105,8 @@ bool ngraph::pass::UnrollTensorIterator::run_on_function(std::shared_ptrget_output_descriptions()) { std::string type_name = desc->get_type_info().name; - if (type_name == "ConcatOutputDescription") { - auto output_desc = std::dynamic_pointer_cast(desc); - if (!output_desc) { + if (const auto& concat_desc = std::dynamic_pointer_cast(desc)) { + if (!concat_desc) { return false; } @@ -134,44 +116,43 @@ bool ngraph::pass::UnrollTensorIterator::run_on_function(std::shared_ptr 1) { ngraph::OutputVector to_concat(num_iter); - auto stride = output_desc->m_stride; + auto stride = concat_desc->m_stride; // Connect outputs of the bodies to the Concat layer for (int64_t j = 0; j < num_iter; j++) { auto idx = stride > 0 ? j : num_iter - j - 1; - std::shared_ptr result = body_functions[idx]->get_results()[output_desc->m_body_value_index]; + std::shared_ptr result = body_functions[idx]->get_results()[concat_desc->m_body_value_index]; auto input_to_res = result->get_input_source_output(0); to_concat[j] = input_to_res; } - auto concat = std::make_shared(to_concat, output_desc->m_axis); + auto concat = std::make_shared(to_concat, concat_desc->m_axis); copy_runtime_info(ti, concat); - // connect the Concat layer to the corresponding TI outputs + // set output name to Tensor to store it for ngraph to cnn conversion concat->output(0).get_tensor().set_name( - op::util::create_ie_output_name(ti->output(output_desc->m_output_index))); - for (auto &input : ti->output(output_desc->m_output_index).get_target_inputs()) { + op::util::create_ie_output_name(ti->output(concat_desc->m_output_index))); + // connect the Concat layer to the corresponding TI outputs + for (auto &input : ti->output(concat_desc->m_output_index).get_target_inputs()) { input.replace_source_output(concat); } } else { // Connect outputs of the bodies to the corresponding TI outputs - std::shared_ptr result = body_functions[0]->get_results()[output_desc->m_body_value_index]; - auto input_to_res = result->get_input_source_output(0); - for (auto &input : ti->output(output_desc->m_output_index).get_target_inputs()) { + std::shared_ptr result = body_functions[0]->get_results().at(concat_desc->m_body_value_index); + const auto& input_to_res = result->get_input_source_output(0); + // set output name to Tensor to store it for ngraph to cnn conversion + input_to_res.get_tensor().set_name(op::util::create_ie_output_name(ti->output(concat_desc->m_output_index))); + for (auto &input : ti->output(concat_desc->m_output_index).get_target_inputs()) { input.replace_source_output(input_to_res); } } - } else if (type_name == "BodyOutputDescription") { - auto output_desc = std::dynamic_pointer_cast(desc); - if (!output_desc) { - return false; - } - + } else if (const auto& output_desc = std::dynamic_pointer_cast(desc)) { // Connect outputs of the bodies to the corresponding TI outputs auto iter = output_desc->m_iteration; iter = iter >= 0? iter: num_iter - 1; std::shared_ptr result = body_functions[iter]->get_results()[output_desc->m_body_value_index]; const auto& in_value = result->input_value(0); + // set output name to Tensor to store it for ngraph to cnn conversion in_value.get_tensor().set_name(op::util::create_ie_output_name(ti->output(output_desc->m_output_index))); for (const auto &input : ti->output(output_desc->m_output_index).get_target_inputs()) { input.replace_source_output(result->get_input_source_output(0)); diff --git a/inference-engine/src/transformations/src/transformations/op_conversions/convert_ti_to_sequences.cpp b/inference-engine/src/transformations/src/transformations/op_conversions/convert_ti_to_sequences.cpp index 5570d2380d5..e439f278660 100644 --- a/inference-engine/src/transformations/src/transformations/op_conversions/convert_ti_to_sequences.cpp +++ b/inference-engine/src/transformations/src/transformations/op_conversions/convert_ti_to_sequences.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -25,25 +26,23 @@ ngraph::pass::ConvertTensorIteratorToLSTMSequence::ConvertTensorIteratorToLSTMSe ngraph::Shape{}, ngraph::pattern::has_class()); ngraph::matcher_pass_callback callback = [this](pattern::Matcher &m) { auto ti = std::dynamic_pointer_cast(m.get_match_root()); - if (!ti || !m_transformation_callback(ti)) + if (!ti || m_transformation_callback(ti)) return false; // create pattern auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{1, 1, 1}); - auto axis_squeeze = std::make_shared(ngraph::element::i64, ngraph::Shape{1}, 1); - - auto input_data = std::make_shared(data, axis_squeeze); + auto pattern_1 = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {1, 1}); + auto squeeze = std::make_shared(data, pattern_1, false); auto input_H_state = std::make_shared(ngraph::element::f32, ngraph::Shape{1, 1}); auto input_C_state = std::make_shared(ngraph::element::f32, ngraph::Shape{1, 1}); auto input_W = std::make_shared(ngraph::element::f32, ngraph::Shape{4, 1}); auto input_R = std::make_shared(ngraph::element::f32, ngraph::Shape{4, 1}); auto input_B = std::make_shared(ngraph::element::f32, ngraph::Shape{4}); - auto cell = std::make_shared(input_data, input_H_state, input_C_state, + auto cell = std::make_shared(squeeze, input_H_state, input_C_state, input_W, input_R, input_B, 1); - - auto axis_unsqueeze = std::make_shared(ngraph::element::i64, ngraph::Shape{1}, 1); - auto unsqueeze = std::make_shared(cell, axis_unsqueeze); + auto pattern_2 = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{3}, {1, 1, 1}); + auto unsqueeze = std::make_shared(cell, pattern_2, false); ngraph::pattern::Matcher matcher(unsqueeze); bool match = false; @@ -54,11 +53,28 @@ ngraph::pass::ConvertTensorIteratorToLSTMSequence::ConvertTensorIteratorToLSTMSe break; } + // support for opset1::LSTMCell + auto cell_v1 = std::make_shared(squeeze, input_H_state, input_C_state, + input_W, input_R, input_B, 1); + if (!match) { + unsqueeze = std::make_shared(cell_v1, pattern_2, false); + matcher.clear_state(); + matcher.m_pattern_node = unsqueeze; + for (const auto& res : func->get_results()) { + match = matcher.match((res->get_input_source_output(0))); + if (match) + break; + } + } + // All nodes are in the TI body should be matched in pattern if (!match || (matcher.get_matched_nodes().size() + func->get_results().size()) != func->get_ops().size()) return false; auto pattern_map = matcher.get_pattern_map(); + std::shared_ptr& found_cell = pattern_map[cell]; + if (!found_cell) + found_cell = pattern_map[cell_v1]; auto params = func->get_parameters(); std::vector> ordered_in_descs(3); @@ -105,9 +121,9 @@ ngraph::pass::ConvertTensorIteratorToLSTMSequence::ConvertTensorIteratorToLSTMSe stride = concat_output->m_stride; ordered_out_descs[0] = output_desc; - } else if (res->get_input_source_output(0) == pattern_map[cell]->output(0)) { + } else if (res->get_input_source_output(0) == found_cell->output(0)) { ordered_out_descs[1] = output_desc; - } else if (res->get_input_source_output(0) == pattern_map[cell]->output(1)) { + } else if (res->get_input_source_output(0) == found_cell->output(1)) { ordered_out_descs[2] = output_desc; } else { return false; @@ -115,7 +131,7 @@ ngraph::pass::ConvertTensorIteratorToLSTMSequence::ConvertTensorIteratorToLSTMSe } auto seq_lengths = ngraph::opset5::Constant::create(element::i32, Shape{batch_size}, {ti->get_num_iterations()}); - const auto& lstm_cell = std::dynamic_pointer_cast(pattern_map[cell]); + const auto& lstm_cell = std::dynamic_pointer_cast(found_cell); auto in_0 = ti->input_values()[ordered_in_descs[0]->m_input_index]; if (slice_axis == 0) { auto order = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{3}, {1, 0, 2}); @@ -145,17 +161,16 @@ ngraph::pass::ConvertTensorIteratorToLSTMSequence::ConvertTensorIteratorToLSTMSe lstm_cell->get_clip()); auto axis_out = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); - auto out_0 = std::make_shared(sequence->output(0), axis_out); + Output out = sequence->output(0); + if (slice_axis == 0) { + auto order = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {2, 1, 0, 3}); + out = std::make_shared(out, order); + } + auto out_0 = std::make_shared(out, axis_out); auto out_1 = std::make_shared(sequence->output(1), axis_out); auto out_2 = std::make_shared(sequence->output(2), axis_out); - std::shared_ptr out = out_0; - if (slice_axis == 0) { - auto order = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{3}, {1, 0, 2}); - out = std::make_shared(out_0, order); - } - - ngraph::NodeVector outputs = {out, out_1, out_2}; + ngraph::NodeVector outputs = {out_0, out_1, out_2}; for (size_t i = 0; i < ordered_out_descs.size(); ++i) { if (ordered_out_descs[i]) { for (const auto &input : ti->output(ordered_out_descs[i]->m_output_index).get_target_inputs()) { @@ -165,12 +180,12 @@ ngraph::pass::ConvertTensorIteratorToLSTMSequence::ConvertTensorIteratorToLSTMSe } } - ngraph::NodeVector new_nodes = {in_1, in_2, in_4, in_5, in_6, sequence, out_0, out_1, out_2}; + ngraph::OutputVector new_nodes = {in_1, in_2, in_4, in_5, in_6, sequence->output(0), out_0, out_1, out_2}; if (slice_axis == 0) { new_nodes.push_back(out); new_nodes.push_back(in_0.get_node_shared_ptr()); } - copy_runtime_info(ti, new_nodes); + copy_runtime_info(ti, as_node_vector(new_nodes)); return true; }; @@ -183,23 +198,23 @@ ngraph::pass::ConvertTensorIteratorToRNNSequence::ConvertTensorIteratorToRNNSequ ngraph::Shape{}, ngraph::pattern::has_class()); ngraph::matcher_pass_callback callback = [this](pattern::Matcher &m) { auto ti = std::dynamic_pointer_cast(m.get_match_root()); - if (!ti || !m_transformation_callback(ti)) + if (!ti || m_transformation_callback(ti)) return false; // create pattern auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{1, 1, 1}); - auto axis_squeeze = std::make_shared(ngraph::element::i64, ngraph::Shape{1}, 0); - auto input_data = std::make_shared(data, axis_squeeze); + auto pattern_1 = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {1, 1}); + auto squeeze = std::make_shared(data, pattern_1, false); auto input_H_state = std::make_shared(ngraph::element::f32, ngraph::Shape{1, 1}); auto input_W = std::make_shared(ngraph::element::f32, ngraph::Shape{1, 1}); auto input_R = std::make_shared(ngraph::element::f32, ngraph::Shape{1, 1}); auto input_B = std::make_shared(ngraph::element::f32, ngraph::Shape{1}); - auto cell = std::make_shared(input_data, input_H_state, input_W, input_R, input_B, 1); + auto cell = std::make_shared(squeeze, input_H_state, input_W, input_R, input_B, 1); - auto axis_unsqueeze = std::make_shared(ngraph::element::i64, ngraph::Shape{1}, 0); - auto unsqueeze = std::make_shared(cell, axis_unsqueeze); + auto pattern_2 = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{3}, {1, 1, 1}); + auto unsqueeze = std::make_shared(cell, pattern_2, false); ngraph::pattern::Matcher matcher(unsqueeze); bool match = false; @@ -297,16 +312,16 @@ ngraph::pass::ConvertTensorIteratorToRNNSequence::ConvertTensorIteratorToRNNSequ rnn_cell->get_clip()); auto axis_out = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); - auto out_0 = std::make_shared(sequence->output(0), axis_out); auto out_1 = std::make_shared(sequence->output(1), axis_out); - std::shared_ptr out = out_0; + Output out = sequence->output(0); if (slice_axis == 0) { - auto order = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{3}, {1, 0, 2}); - out = std::make_shared(out_0, order); + auto order = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {2, 1, 0, 3}); + out = std::make_shared(out, order); } + auto out_0 = std::make_shared(out, axis_out); - ngraph::NodeVector outputs = {out, out_1}; + ngraph::NodeVector outputs = {out_0, out_1}; for (size_t i = 0; i < ordered_out_descs.size(); ++i) { if (ordered_out_descs[i]) { for (const auto &input : ti->output(ordered_out_descs[i]->m_output_index).get_target_inputs()) { @@ -334,23 +349,23 @@ ngraph::pass::ConvertTensorIteratorToGRUSequence::ConvertTensorIteratorToGRUSequ ngraph::Shape{}, ngraph::pattern::has_class()); ngraph::matcher_pass_callback callback = [this](pattern::Matcher &m) { auto ti = std::dynamic_pointer_cast(m.get_match_root()); - if (!ti || !m_transformation_callback(ti)) + if (!ti || m_transformation_callback(ti)) return false; // create pattern auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{1, 1, 1}); - auto axis_squeeze = std::make_shared(ngraph::element::i64, ngraph::Shape{1}, 0); - auto input_data = std::make_shared(data, axis_squeeze); + auto pattern_1 = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {1, 1}); + auto squeeze = std::make_shared(data, pattern_1, false); auto input_H_state = std::make_shared(ngraph::element::f32, ngraph::Shape{1, 1}); auto input_W = std::make_shared(ngraph::element::f32, ngraph::Shape{3, 1}); auto input_R = std::make_shared(ngraph::element::f32, ngraph::Shape{3, 1}); auto input_B = std::make_shared(ngraph::element::f32, ngraph::Shape{3}); - auto cell = std::make_shared(input_data, input_H_state, input_W, input_R, input_B, 1); + auto cell = std::make_shared(squeeze, input_H_state, input_W, input_R, input_B, 1); - auto axis_unsqueeze = std::make_shared(ngraph::element::i64, ngraph::Shape{1}, 0); - auto unsqueeze = std::make_shared(cell, axis_unsqueeze); + auto pattern_2 = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{3}, {1, 1, 1}); + auto unsqueeze = std::make_shared(cell, pattern_2, false); ngraph::pattern::Matcher matcher(unsqueeze); bool match = false; @@ -449,16 +464,16 @@ ngraph::pass::ConvertTensorIteratorToGRUSequence::ConvertTensorIteratorToGRUSequ rnn_cell->get_linear_before_reset()); auto axis_out = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); - auto out_0 = std::make_shared(sequence->output(0), axis_out); auto out_1 = std::make_shared(sequence->output(1), axis_out); - std::shared_ptr out = out_0; + Output out = sequence->output(0); if (slice_axis == 0) { - auto order = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{3}, {1, 0, 2}); - out = std::make_shared(out_0, order); + auto order = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {2, 1, 0, 3}); + out = std::make_shared(out, order); } + auto out_0 = std::make_shared(out, axis_out); - ngraph::NodeVector outputs = {out, out_1}; + ngraph::NodeVector outputs = {out_0, out_1}; for (size_t i = 0; i < ordered_out_descs.size(); ++i) { if (ordered_out_descs[i]) { for (const auto &input : ti->output(ordered_out_descs[i]->m_output_index).get_target_inputs()) { diff --git a/inference-engine/src/transformations/src/transformations/op_conversions/gru_cell_decomposition.cpp b/inference-engine/src/transformations/src/transformations/op_conversions/gru_cell_decomposition.cpp index 88fa5f22782..a96b198c180 100644 --- a/inference-engine/src/transformations/src/transformations/op_conversions/gru_cell_decomposition.cpp +++ b/inference-engine/src/transformations/src/transformations/op_conversions/gru_cell_decomposition.cpp @@ -16,9 +16,9 @@ NGRAPH_RTTI_DEFINITION(ngraph::pass::GRUCellDecomposition, "GRUCellDecomposition ngraph::pass::GRUCellDecomposition::GRUCellDecomposition() { auto gru_cell = ngraph::pattern::wrap_type(); - ngraph::matcher_pass_callback callback = [](ngraph::pattern::Matcher& m) { + ngraph::matcher_pass_callback callback = [this](ngraph::pattern::Matcher& m) { auto gru_cell = std::dynamic_pointer_cast (m.get_match_root()); - if (!gru_cell) { + if (!gru_cell || m_transformation_callback(gru_cell)) { return false; } diff --git a/inference-engine/src/transformations/src/transformations/op_conversions/lstm_cell_decomposition.cpp b/inference-engine/src/transformations/src/transformations/op_conversions/lstm_cell_decomposition.cpp index a93d3fa3dea..80cb67df6de 100644 --- a/inference-engine/src/transformations/src/transformations/op_conversions/lstm_cell_decomposition.cpp +++ b/inference-engine/src/transformations/src/transformations/op_conversions/lstm_cell_decomposition.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -15,10 +16,13 @@ NGRAPH_RTTI_DEFINITION(ngraph::pass::LSTMCellDecomposition, "LSTMCellDecomposition", 0); ngraph::pass::LSTMCellDecomposition::LSTMCellDecomposition() { - auto lstm_cell = ngraph::pattern::wrap_type(); - ngraph::matcher_pass_callback callback = [](ngraph::pattern::Matcher& m) { - auto lstm_cell = std::dynamic_pointer_cast (m.get_match_root()); - if (!lstm_cell) { + auto is_supported_lstm_cell = [](const std::shared_ptr& n) { + return pattern::has_class()(n) || pattern::has_class()(n); + }; + auto any_lstm = std::make_shared(element::f32, Shape{}, is_supported_lstm_cell); + ngraph::matcher_pass_callback callback = [this](ngraph::pattern::Matcher& m) { + auto lstm_cell = std::dynamic_pointer_cast(m.get_match_root()); + if (!lstm_cell || m_transformation_callback(lstm_cell)) { return false; } const Output& X = lstm_cell->input_value(0); @@ -82,6 +86,6 @@ ngraph::pass::LSTMCellDecomposition::LSTMCellDecomposition() { return true; }; - auto m = std::make_shared(lstm_cell, "LSTMCellDecomposition"); + auto m = std::make_shared(any_lstm, "LSTMCellDecomposition"); register_matcher(m, callback); } diff --git a/inference-engine/src/transformations/src/transformations/op_conversions/rnn_cell_decomposition.cpp b/inference-engine/src/transformations/src/transformations/op_conversions/rnn_cell_decomposition.cpp index 2e4fd9aa05f..cdbe412e16d 100644 --- a/inference-engine/src/transformations/src/transformations/op_conversions/rnn_cell_decomposition.cpp +++ b/inference-engine/src/transformations/src/transformations/op_conversions/rnn_cell_decomposition.cpp @@ -16,9 +16,9 @@ NGRAPH_RTTI_DEFINITION(ngraph::pass::RNNCellDecomposition, "RNNCellDecomposition ngraph::pass::RNNCellDecomposition::RNNCellDecomposition() { auto rnn_cell = ngraph::pattern::wrap_type(); - ngraph::matcher_pass_callback callback = [](ngraph::pattern::Matcher& m) { + ngraph::matcher_pass_callback callback = [this](ngraph::pattern::Matcher& m) { auto rnn_cell = std::dynamic_pointer_cast (m.get_match_root()); - if (!rnn_cell) { + if (!rnn_cell || m_transformation_callback(rnn_cell)) { return false; } const Output& X = rnn_cell->input_value(0); diff --git a/inference-engine/tests/functional/inference_engine/transformations/convert_ti_to_sequences_test.cpp b/inference-engine/tests/functional/inference_engine/transformations/convert_ti_to_sequences_test.cpp index 608e7f9c980..a60a6b975af 100644 --- a/inference-engine/tests/functional/inference_engine/transformations/convert_ti_to_sequences_test.cpp +++ b/inference-engine/tests/functional/inference_engine/transformations/convert_ti_to_sequences_test.cpp @@ -34,8 +34,8 @@ TEST(TransformationTests, ConvertTensorIteratorToLSTMSequence) { auto Zi = std::make_shared(element::f32, Shape{1, 128}); // Body - auto axis = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); - auto squeeze = std::make_shared(Xi, axis); + auto reshape_pattern = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {1, 16}); + auto squeeze = std::make_shared(Xi, reshape_pattern, false); auto w_val = std::vector(512 * 16, 0); auto r_val = std::vector(512 * 128, 0); @@ -46,8 +46,8 @@ TEST(TransformationTests, ConvertTensorIteratorToLSTMSequence) { auto lstm_cell = std::make_shared(squeeze, Yi, Zi, W, R, B, 128); auto res_1 = std::make_shared(lstm_cell); - auto axis_unsqueeze = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); - auto unsqueeze = std::make_shared(lstm_cell, axis_unsqueeze); + auto reshape_pattern_2 = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{3}, {1, 1, 128}); + auto unsqueeze = std::make_shared(lstm_cell, reshape_pattern_2, false); auto res_2 = std::make_shared(unsqueeze); auto body = std::make_shared(OutputVector{res_1, res_2}, ParameterVector{Xi, Yi, Zi}); @@ -70,7 +70,6 @@ TEST(TransformationTests, ConvertTensorIteratorToLSTMSequence) { ngraph::pass::Manager m; m.register_pass(); m.register_pass(); - m.set_callback([](const std::shared_ptr&) -> bool { return true; }); m.run_passes(f); ASSERT_NO_THROW(check_rt_info(f)); } @@ -121,8 +120,8 @@ TEST(TransformationTests, ConvertTensorIteratorToRNNSequence) { auto Yi = std::make_shared(element::f32, Shape{1, 128}); // Body - auto axis = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); - auto squeeze = std::make_shared(Xi, axis); + auto reshape_pattern = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {1, 16}); + auto squeeze = std::make_shared(Xi, reshape_pattern, false); auto w_val = std::vector(128 * 16, 0); auto r_val = std::vector(128 * 128, 0); @@ -133,8 +132,8 @@ TEST(TransformationTests, ConvertTensorIteratorToRNNSequence) { auto rnn_cell = std::make_shared(squeeze, Yi, W, R, B, 128); auto res_1 = std::make_shared(rnn_cell); - auto axis_unsqueeze = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); - auto unsqueeze = std::make_shared(rnn_cell, axis_unsqueeze); + auto reshape_pattern_2 = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{3}, {1, 1, 128}); + auto unsqueeze = std::make_shared(rnn_cell, reshape_pattern_2, false); auto res_2 = std::make_shared(unsqueeze); auto body = std::make_shared(OutputVector{res_1, res_2}, ParameterVector{Xi, Yi}); @@ -156,7 +155,6 @@ TEST(TransformationTests, ConvertTensorIteratorToRNNSequence) { ngraph::pass::Manager m; m.register_pass(); m.register_pass(); - m.set_callback([](const std::shared_ptr&) -> bool { return true; }); m.run_passes(f); ASSERT_NO_THROW(check_rt_info(f)); } @@ -204,8 +202,8 @@ TEST(TransformationTests, ConvertTensorIteratorToGRUSequence) { auto Yi = std::make_shared(element::f32, Shape{1, 128}); // Body - auto axis = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); - auto squeeze = std::make_shared(Xi, axis); + auto reshape_pattern = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {1, 16}); + auto squeeze = std::make_shared(Xi, reshape_pattern, false); auto w_val = std::vector(384 * 16, 0); auto r_val = std::vector(384 * 128, 0); @@ -216,8 +214,8 @@ TEST(TransformationTests, ConvertTensorIteratorToGRUSequence) { auto gru_cell = std::make_shared(squeeze, Yi, W, R, B, 128); auto res_1 = std::make_shared(gru_cell); - auto axis_unsqueeze = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); - auto unsqueeze = std::make_shared(gru_cell, axis_unsqueeze); + auto reshape_pattern_2 = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{3}, {1, 1, 128}); + auto unsqueeze = std::make_shared(gru_cell, reshape_pattern_2, false); auto res_2 = std::make_shared(unsqueeze); auto body = std::make_shared(OutputVector{res_1, res_2}, ParameterVector{Xi, Yi}); @@ -239,7 +237,6 @@ TEST(TransformationTests, ConvertTensorIteratorToGRUSequence) { ngraph::pass::Manager m; m.register_pass(); m.register_pass(); - m.set_callback([](const std::shared_ptr&) -> bool { return true; }); m.run_passes(f); ASSERT_NO_THROW(check_rt_info(f)); } diff --git a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/tensor_iterator.cpp b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/tensor_iterator.cpp index d66a972491b..7a6f19b3329 100644 --- a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/tensor_iterator.cpp +++ b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/tensor_iterator.cpp @@ -10,13 +10,14 @@ using namespace LayerTestsDefinitions; namespace { - // output values increase rapidly without clip, so use only seq_lenghts = 2 std::vector should_decompose = {true, false}; + // output values increase rapidly without clip, so use only seq_lenghts = 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 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}; @@ -33,7 +34,8 @@ namespace { ::testing::ValuesIn(seq_lengths_zero_clip), ::testing::ValuesIn(batch), ::testing::ValuesIn(hidden_size), - ::testing::ValuesIn(input_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), @@ -47,7 +49,8 @@ namespace { ::testing::ValuesIn(seq_lengths_clip_non_zero), ::testing::ValuesIn(batch), ::testing::ValuesIn(hidden_size), - ::testing::ValuesIn(input_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), diff --git a/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/tensor_iterator.hpp b/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/tensor_iterator.hpp index cb346784442..4184f87d5e9 100644 --- a/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/tensor_iterator.hpp +++ b/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/tensor_iterator.hpp @@ -20,7 +20,9 @@ using TensorIteratorParams = typename std::tuple< size_t, // seq_lengths size_t, // batch size_t, // hidden size - size_t, // input 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 ngraph::helpers::TensorIteratorBody, // body type ngraph::op::RecurrentSequenceDirection, // direction diff --git a/inference-engine/tests/functional/plugin/shared/src/single_layer_tests/tensor_iterator.cpp b/inference-engine/tests/functional/plugin/shared/src/single_layer_tests/tensor_iterator.cpp index e0844434816..4b166d12909 100644 --- a/inference-engine/tests/functional/plugin/shared/src/single_layer_tests/tensor_iterator.cpp +++ b/inference-engine/tests/functional/plugin/shared/src/single_layer_tests/tensor_iterator.cpp @@ -26,13 +26,14 @@ namespace LayerTestsDefinitions { size_t seq_lenghts; size_t batch; size_t hidden_size; - size_t input_size; + size_t input_size = 10; + size_t sequence_axis; ngraph::helpers::TensorIteratorBody ti_body; float clip; ngraph::op::RecurrentSequenceDirection direction; InferenceEngine::Precision netPrecision; std::string targetDevice; - std::tie(should_decompose, seq_lenghts, batch, hidden_size, input_size, clip, ti_body, direction, netPrecision, + std::tie(should_decompose, seq_lenghts, batch, hidden_size, sequence_axis, clip, ti_body, direction, netPrecision, targetDevice) = obj.param; std::vector> inputShapes = {}; @@ -57,7 +58,8 @@ namespace LayerTestsDefinitions { std::ostringstream result; result << "unrolling=" << should_decompose << "_"; - result << "seq_lenghts=" << seq_lenghts << "_"; + result << "seq_len=" << seq_lenghts << "_"; + result << "seq_len_axis=" << sequence_axis << "_"; result << "batch=" << batch << "_"; result << "hidden_size=" << hidden_size << "_"; result << "input_size=" << input_size << "_"; @@ -75,12 +77,13 @@ namespace LayerTestsDefinitions { bool should_decompose; size_t batch; size_t hidden_size; - size_t input_size; + size_t input_size = 10; + size_t sequence_axis; ngraph::helpers::TensorIteratorBody ti_body; float clip; ngraph::op::RecurrentSequenceDirection direction; InferenceEngine::Precision netPrecision; - std::tie(should_decompose, seq_lenghts, batch, hidden_size, input_size, clip, ti_body, direction, netPrecision, + std::tie(should_decompose, seq_lenghts, batch, hidden_size, sequence_axis, clip, ti_body, direction, netPrecision, targetDevice) = this->GetParam(); std::vector> inputShapes; auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision); @@ -90,17 +93,22 @@ namespace LayerTestsDefinitions { // 1. Create TensorIterator body. // 2. Set PortMap // 3. Create outer function - auto axis = std::make_shared(ngraph::element::i64, ngraph::Shape{1}, std::vector{1}); + auto axis = std::make_shared(ngraph::element::i64, ngraph::Shape{1}, + std::vector{static_cast(sequence_axis)}); switch (ti_body) { case ngraph::helpers::TensorIteratorBody::LSTM: { inputShapes = { {{batch, seq_lenghts, 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(inputShapes[0][0], inputShapes[0][1]); + } auto outer_params = ngraph::builder::makeParams(ngPrc, {inputShapes[0], inputShapes[1], inputShapes[2]}); // 1. Create TensorIterator body. - inputShapes[0][1] = 1; // sliced dimension + inputShapes[0][sequence_axis] = 1; // sliced dimension auto body_params = ngraph::builder::makeParams(ngPrc, {inputShapes[0], inputShapes[1], inputShapes[2]}); auto squeeze = std::make_shared(body_params[0], axis); std::vector WRB = {inputShapes[3], inputShapes[4], inputShapes[5]}; @@ -115,17 +123,17 @@ namespace LayerTestsDefinitions { // 2. Set PortMap if (direction == ngraph::op::RecurrentSequenceDirection::FORWARD) { - tensor_iterator->set_sliced_input(body_params[0], outer_params[0], 0, 1, 1, -1, 1); - tensor_iterator->get_concatenated_slices(results[0], 0, 1, 1, -1, 1); + 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 == ngraph::op::RecurrentSequenceDirection::REVERSE) { - tensor_iterator->set_sliced_input(body_params[0], outer_params[0], -1, -1, 1, 0, 1); - tensor_iterator->get_concatenated_slices(results[0], -1, -1, 1, 0, 1); + 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 { NGRAPH_CHECK(false, "Bidirectional case is not supported."); } tensor_iterator->set_merged_input(body_params[1], outer_params[1], results[1]); - tensor_iterator->set_invariant_input(body_params[2], outer_params[2]); + 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]); @@ -139,10 +147,14 @@ namespace LayerTestsDefinitions { {{batch, seq_lenghts, 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(inputShapes[0][0], inputShapes[0][1]); + } auto outer_params = ngraph::builder::makeParams(ngPrc, {inputShapes[0], inputShapes[1]}); // 1. Create TensorIterator body. - inputShapes[0][1] = 1; // sliced dimension + inputShapes[0][sequence_axis] = 1; // sliced dimension auto body_params = ngraph::builder::makeParams(ngPrc, {inputShapes[0], inputShapes[1]}); std::vector WRB = {inputShapes[2], inputShapes[3], inputShapes[4]}; auto squeeze = std::make_shared(body_params[0], axis); @@ -157,11 +169,11 @@ namespace LayerTestsDefinitions { // 2. Set PortMap if (direction == ngraph::op::RecurrentSequenceDirection::FORWARD) { - tensor_iterator->set_sliced_input(body_params[0], outer_params[0], 0, 1, 1, -1, 1); - tensor_iterator->get_concatenated_slices(results[1], 0, 1, 1, -1, 1); + 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 == ngraph::op::RecurrentSequenceDirection::REVERSE) { - tensor_iterator->set_sliced_input(body_params[0], outer_params[0], -1, -1, 1, 0, 1); - tensor_iterator->get_concatenated_slices(results[1], -1, -1, 1, 0, 1); + 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 { NGRAPH_CHECK(false, "Bidirectional case is not supported."); } @@ -179,10 +191,14 @@ namespace LayerTestsDefinitions { {hidden_size, input_size}, {hidden_size, hidden_size}, {hidden_size}}; + if (sequence_axis == 0) { + // swap batch and seq_lengths + std::swap(inputShapes[0][0], inputShapes[0][1]); + } auto outer_params = ngraph::builder::makeParams(ngPrc, {inputShapes[0], inputShapes[1]}); // 1. Create TensorIterator body. - inputShapes[0][1] = 1; // sliced dimension + inputShapes[0][sequence_axis] = 1; // sliced dimension auto body_params = ngraph::builder::makeParams(ngPrc, {inputShapes[0], inputShapes[1]}); std::vector WRB = {inputShapes[2], inputShapes[3], inputShapes[4]}; auto squeeze = std::make_shared(body_params[0], axis); @@ -196,11 +212,11 @@ namespace LayerTestsDefinitions { // 2. Set PortMap if (direction == ngraph::op::RecurrentSequenceDirection::FORWARD) { - tensor_iterator->set_sliced_input(body_params[0], outer_params[0], 0, 1, 1, -1, 1); - tensor_iterator->get_concatenated_slices(results[1], 0, 1, 1, -1, 1); + 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 == ngraph::op::RecurrentSequenceDirection::REVERSE) { - tensor_iterator->set_sliced_input(body_params[0], outer_params[0], -1, -1, 1, 0, 1); - tensor_iterator->get_concatenated_slices(results[1], -1, -1, 1, 0, 1); + 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 { NGRAPH_CHECK(false, "Bidirectional case is not supported."); } diff --git a/inference-engine/tests_deprecated/functional/shared_tests/lstm/rnn_seq_test.hpp b/inference-engine/tests_deprecated/functional/shared_tests/lstm/rnn_seq_test.hpp index 92464f12c93..287d41b130f 100644 --- a/inference-engine/tests_deprecated/functional/shared_tests/lstm/rnn_seq_test.hpp +++ b/inference-engine/tests_deprecated/functional/shared_tests/lstm/rnn_seq_test.hpp @@ -60,7 +60,9 @@ const Named test_name( [] (const rnn_param &p) { using RNNSeqTest = PlgTest; -TEST_P(RNNSeqTest, SingleRNN) { +// disabled due to transition to ngraph transformation +// DO NOT DELETE, part of the functionality is still needed +TEST_P(RNNSeqTest, DISABLED_SingleRNN) { auto p = param(); auto cell = std::get<0>(p); diff --git a/inference-engine/tests_deprecated/functional/shared_tests/single_layer_tests/ti_tests.hpp b/inference-engine/tests_deprecated/functional/shared_tests/single_layer_tests/ti_tests.hpp index f7ee40f39cf..2498281bd78 100644 --- a/inference-engine/tests_deprecated/functional/shared_tests/single_layer_tests/ti_tests.hpp +++ b/inference-engine/tests_deprecated/functional/shared_tests/single_layer_tests/ti_tests.hpp @@ -177,7 +177,8 @@ protected: using TITest = TITestBase; -TEST_P(TITest, TestsWitUnusedOut) { RunTITest(); } +// disabled due to transition to ngraph transformations +TEST_P(TITest, DISABLED_TestsWitUnusedOut) { RunTITest(); } /* TI body contains const data placeholder @@ -328,4 +329,5 @@ protected: using TITest2 = TITest2Base; -TEST_P(TITest2, TestsWitCopy) { RunTITest(); } +// disabled due to transition to ngraph transformations +TEST_P(TITest2, DISABLED_TestsWitCopy) { RunTITest(); } diff --git a/ngraph/python/tests/test_ngraph/test_ops_fused.py b/ngraph/python/tests/test_ngraph/test_ops_fused.py index 59b38d42f09..49412d3a54d 100644 --- a/ngraph/python/tests/test_ngraph/test_ops_fused.py +++ b/ngraph/python/tests/test_ngraph/test_ops_fused.py @@ -23,7 +23,6 @@ from tests import (xfail_issue_40957, xfail_issue_34327, xfail_issue_36485, xfail_issue_36486, - xfail_issue_34314, xfail_issue_36487) @@ -536,7 +535,6 @@ def test_mvn_operator(): assert np.allclose(result, expected) -@xfail_issue_34314 def test_space_to_depth_operator(): runtime = get_runtime() diff --git a/ngraph/test/runtime/interpreter/int_executable.hpp b/ngraph/test/runtime/interpreter/int_executable.hpp index cd5f8495393..c581008915d 100644 --- a/ngraph/test/runtime/interpreter/int_executable.hpp +++ b/ngraph/test/runtime/interpreter/int_executable.hpp @@ -725,6 +725,7 @@ protected: gru_cell->get_linear_before_reset()); break; } + case OP_TYPEID::LSTMCell_v0: case OP_TYPEID::LSTMCell_v4: { const op::v4::LSTMCell* lstm_cell = static_cast(&node); diff --git a/ngraph/test/runtime/interpreter/opset_int_tbl.hpp b/ngraph/test/runtime/interpreter/opset_int_tbl.hpp index 491fe950ad4..8cebe8d3ade 100644 --- a/ngraph/test/runtime/interpreter/opset_int_tbl.hpp +++ b/ngraph/test/runtime/interpreter/opset_int_tbl.hpp @@ -21,6 +21,7 @@ #define ID_SUFFIX(NAME) NAME##_v0 NGRAPH_OP(CTCGreedyDecoder, ngraph::op::v0) NGRAPH_OP(DetectionOutput, op::v0) +NGRAPH_OP(LSTMCell, op::v0) NGRAPH_OP(RegionYolo, op::v0) NGRAPH_OP(ReorgYolo, op::v0) NGRAPH_OP(RNNCell, op::v0)