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
This commit is contained in:
Ivan Tikhonov 2020-11-17 12:38:22 +03:00 committed by GitHub
parent cfe143fd33
commit ea52dd2642
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 413 additions and 210 deletions

View File

@ -32,6 +32,10 @@
#include <transformations/opset_conversions/convert_opset2_to_opset1.hpp>
#include <transformations/opset_conversions/convert_opset3_to_opset2.hpp>
#include <transformations/op_conversions/convert_sequences_to_tensor_iterator.hpp>
#include <transformations/op_conversions/convert_ti_to_sequences.hpp>
#include <transformations/op_conversions/gru_cell_decomposition.hpp>
#include <transformations/op_conversions/lstm_cell_decomposition.hpp>
#include <transformations/op_conversions/rnn_cell_decomposition.hpp>
#include <transformations/init_node_info.hpp>
#include <transformations/convert_precision.hpp>
#include <transformations/rt_info/fused_names_attribute.hpp>
@ -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 ngraph::Node>;
const auto& pass_config = manager.get_pass_config();
manager.register_pass<ngraph::pass::InitNodeInfo>();
// WA: ConvertPriorBox must be executed before the 1st ConstantFolding pass
manager.register_pass<ngraph::pass::ConvertPriorBox>();
@ -155,8 +161,51 @@ InferenceEngine::ICNNNetwork::Ptr clDNNEngine::CloneAndTransformNetwork(const In
manager.register_pass<ngraph::pass::ConvertLSTMSequenceToTensorIterator>();
manager.register_pass<ngraph::pass::ConvertOpSet3ToOpSet2>();
manager.register_pass<ngraph::pass::ConvertOpSet2ToOpSet1>();
manager.register_pass<ngraph::pass::ConvertTensorIteratorToGRUSequence>();
manager.register_pass<ngraph::pass::ConvertTensorIteratorToLSTMSequence>();
manager.register_pass<ngraph::pass::ConvertTensorIteratorToRNNSequence>();
manager.register_pass<ngraph::pass::LSTMCellDecomposition>();
manager.register_pass<ngraph::pass::GRUCellDecomposition>();
manager.register_pass<ngraph::pass::RNNCellDecomposition>();
manager.set_callback(transformations_callback);
auto isCellPrimitiveSupported = [](const_node_ptr &node) -> bool {
if (const auto &rnn_cell = std::dynamic_pointer_cast<const ngraph::opset4::RNNCell>(node)) {
return false;
} else if (const auto &gru_cell = std::dynamic_pointer_cast<const ngraph::opset4::GRUCell>(
node)) {
return false;
} else if (const auto &lstm_cell = std::dynamic_pointer_cast<const ngraph::opset4::LSTMCell>(
node)) {
return lstm_cell->get_clip() == 0.0f &&
lstm_cell->get_activations() == std::vector<std::string>{"sigmoid", "tanh", "tanh"};
} else if (const auto &lstm_cell_v1 = std::dynamic_pointer_cast<const ngraph::opset1::LSTMCell>(
node)) {
return lstm_cell_v1->get_clip() == 0.0f &&
lstm_cell_v1->get_activations() == std::vector<std::string>{"sigmoid", "tanh", "tanh"};
}
return false;
};
pass_config->set_callback<ngraph::pass::RNNCellDecomposition, ngraph::pass::GRUCellDecomposition,
ngraph::pass::LSTMCellDecomposition>(
[isCellPrimitiveSupported](const_node_ptr &node) -> bool {
return isCellPrimitiveSupported(node);
});
pass_config->set_callback<ngraph::pass::ConvertTensorIteratorToRNNSequence,
ngraph::pass::ConvertTensorIteratorToLSTMSequence,
ngraph::pass::ConvertTensorIteratorToGRUSequence>(
[isCellPrimitiveSupported](const_node_ptr &node) -> bool {
if (const auto& ti_op = std::dynamic_pointer_cast<const ngraph::op::TensorIterator>(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<ngraph::pass::ConvertOpSet1ToLegacy>();
manager.register_pass<ngraph::pass::UnrollTensorIterator>();
manager.set_callback(transformations_callback);
manager.run_passes(nGraphFunc);
}

View File

@ -475,24 +475,6 @@ Program::Program(InferenceEngine::ICNNNetwork& network, std::shared_ptr<const cl
}
}
NetPass::CombineRNNSeq(network);
for (int i = 0; i < 2; i++) {
NetPass::UnrollTI(network);
NetPass::UnrollRNN_if(network, [](const RNNCellBase &rnn) -> 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<std::string>{"sigmoid", "tanh", "tanh"})
return false;
return true;
});
}
if (m_config.max_dynamic_batch > 1) {
// check topology for applicability
if (!CanProcessDynBatch(network)) {

View File

@ -32,7 +32,8 @@ public:
const std::vector<float> &activations_alpha,
const std::vector<float> &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;
};

View File

@ -32,7 +32,8 @@ public:
const std::vector<std::string> &activations,
const std::vector<float> &activations_alpha,
const std::vector<float> &activations_beta,
float clip);
float clip,
int64_t seq_len = 1);
std::shared_ptr<Node> 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

View File

@ -29,7 +29,8 @@ public:
const std::vector<std::string> &activations,
const std::vector<float> &activations_alpha,
const std::vector<float> &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

View File

@ -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<RNNSequenceLayer>(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")

View File

@ -218,6 +218,8 @@ static std::vector<std::string> 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<std::string, bool> ConstTransformer::getConstLayers(const std::vector<CNNLayerPtr>& sortedLayers) {

View File

@ -25,10 +25,12 @@ op::GRUSequenceIE::GRUSequenceIE(const Output<Node>& X,
const std::vector<float>& activations_alpha,
const std::vector<float>& 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<Node> op::GRUSequenceIE::clone_with_new_inputs(const OutputVector& ne
check_new_args_count(this, new_args);
return std::make_shared<op::GRUSequenceIE>(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);
}

View File

@ -25,9 +25,11 @@ op::LSTMSequenceIE::LSTMSequenceIE(const Output<Node> &X,
const std::vector<std::string> &activations,
const std::vector<float> &activations_alpha,
const std::vector<float> &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<Node> op::LSTMSequenceIE::clone_with_new_inputs(const OutputVector &n
check_new_args_count(this, new_args);
return make_shared<op::LSTMSequenceIE>(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);
}

View File

@ -24,9 +24,11 @@ op::RNNSequenceIE::RNNSequenceIE(const Output<Node>& X,
const std::vector<std::string>& activations,
const std::vector<float>& activations_alpha,
const std::vector<float>& 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<Node> op::RNNSequenceIE::clone_with_new_inputs(const ngraph::OutputVector &new_args) const {
check_new_args_count(this, new_args);
return make_shared<op::RNNSequenceIE>(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);
}

View File

@ -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<ngraph::Node>& 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<ngraph::opset5::Transpose>(sequence_node->input_value(0).get_node_shared_ptr());
const auto& transpose_after = std::dynamic_pointer_cast<ngraph::opset5::Transpose>(target_inputs.begin()->get_node()->shared_from_this());
if (transpose_after != nullptr && transpose_before != nullptr) {
auto order_before = std::dynamic_pointer_cast<ngraph::opset5::Constant>(
transpose_before->input_value(1).get_node_shared_ptr());
auto order_after = std::dynamic_pointer_cast<ngraph::opset5::Constant>(
transpose_after->input_value(1).get_node_shared_ptr());
if (order_before != nullptr && order_after != nullptr) {
auto order_before_values = order_before->cast_vector<int64_t>();
auto order_after_values = order_after->cast_vector<int64_t>();
std::vector<int64_t> order_ref_before = {1, 0, 2};
std::vector<int64_t> 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<ngraph::opset5::LSTMSequence>();
@ -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<ngraph::Node> 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<ngraph::opset5::Squeeze>(lstm_sequence->input_value(1), axis_1);
@ -43,7 +85,7 @@ ngraph::pass::ConvertLSTMSequenceMatcher::ConvertLSTMSequenceMatcher() {
auto in_3 = std::make_shared<ngraph::opset5::Squeeze>(concat->output(0), axis_2);
auto in_4 = std::make_shared<ngraph::opset5::Squeeze>(lstm_sequence->input_value(6), axis_2);
auto lstm_sequence_ie = std::make_shared<ngraph::op::LSTMSequenceIE>(
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<ngraph::opset5::Unsqueeze>(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<ngraph::Node> 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<ngraph::opset5::Squeeze>(gru_sequence->input_value(1), axis_1);
@ -99,7 +155,7 @@ ngraph::pass::ConvertGRUSequenceMatcher::ConvertGRUSequenceMatcher() {
auto in_4 = std::make_shared<ngraph::opset5::Squeeze>(gru_sequence->input_value(5), axis_2);
auto gru_sequence_ie = std::make_shared<ngraph::op::GRUSequenceIE>(
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<ngraph::opset5::Unsqueeze>(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<ngraph::Node> 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<ngraph::opset5::Squeeze>(concat->output(0), axis_2);
auto in_4 = std::make_shared<ngraph::opset5::Squeeze>(rnn_sequence->input_value(5), axis_2);
auto rnn_sequence_ie = std::make_shared<ngraph::op::RNNSequenceIE>(
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<ngraph::opset5::Unsqueeze>(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;
};

View File

@ -78,9 +78,6 @@ MKLDNNExecNetwork::MKLDNNExecNetwork(const InferenceEngine::ICNNNetwork &network
}
}
OV_ITT_TASK_NEXT(taskChain, "UnrollPasses");
MKLDNNGraph::ApplyUnrollPasses(static_cast<ICNNNetwork&>(*_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()};

View File

@ -46,6 +46,10 @@
#include <transformations/op_conversions/convert_sequences_to_tensor_iterator.hpp>
#include <transformations/control_flow/unroll_tensor_iterator.hpp>
#include <transformations/op_conversions/convert_mod.hpp>
#include <transformations/op_conversions/convert_ti_to_sequences.hpp>
#include <transformations/op_conversions/lstm_cell_decomposition.hpp>
#include <transformations/op_conversions/rnn_cell_decomposition.hpp>
#include <transformations/op_conversions/gru_cell_decomposition.hpp>
#include <transformations/op_conversions/log_softmax_decomposition.hpp>
#include <transformations/convert_precision.hpp>
#include <transformations/init_node_info.hpp>
@ -102,17 +106,23 @@ static void Transformation(ICNNNetwork::Ptr& clonedNetwork, const Config& conf)
manager.register_pass<ngraph::pass::ConvertLSTMSequenceToTensorIterator>();
manager.register_pass<ngraph::pass::ConvertOpSet3ToOpSet2>();
manager.register_pass<ngraph::pass::ConvertOpSet2ToOpSet1>();
manager.register_pass<ngraph::pass::ConvertTensorIteratorToGRUSequence>();
manager.register_pass<ngraph::pass::ConvertTensorIteratorToLSTMSequence>();
manager.register_pass<ngraph::pass::ConvertTensorIteratorToRNNSequence>();
manager.register_pass<ngraph::pass::LSTMCellDecomposition>();
manager.register_pass<ngraph::pass::GRUCellDecomposition>();
manager.register_pass<ngraph::pass::RNNCellDecomposition>();
std::vector<std::pair<ngraph::element::Type, ngraph::element::Type>> 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<std::pair<ngraph::element::Type, ngraph::element::Type>> 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<ngraph::pass::ConvertPrecision>(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::ConvertSpaceToDepth,
ngraph::pass::ConvertDepthToSpace>(
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<const ngraph::opset4::RNNCell>(node)) {
return rnn_cell->get_clip() == 0.0f;
} else if (const auto &gru_cell = std::dynamic_pointer_cast<const ngraph::opset4::GRUCell>(
node)) {
return gru_cell->get_clip() == 0.0f
&& gru_cell->get_activations() == std::vector<std::string>{"sigmoid", "tanh"};
} else if (const auto &lstm_cell = std::dynamic_pointer_cast<const ngraph::opset4::LSTMCell>(
node)) {
return lstm_cell->get_clip() == 0.0f &&
lstm_cell->get_activations() == std::vector<std::string>{"sigmoid", "tanh", "tanh"};
} else if (const auto &lstm_cell_v1 = std::dynamic_pointer_cast<const ngraph::opset1::LSTMCell>(
node)) {
return lstm_cell_v1->get_clip() == 0.0f &&
lstm_cell_v1->get_activations() == std::vector<std::string>{"sigmoid", "tanh", "tanh"};
}
return false;
};
pass_config->set_callback<ngraph::pass::RNNCellDecomposition, ngraph::pass::GRUCellDecomposition,
ngraph::pass::LSTMCellDecomposition>(
[isCellPrimitiveSupported](const_node_ptr &node) -> bool {
return isCellPrimitiveSupported(node);
});
pass_config->set_callback<ngraph::pass::ConvertTensorIteratorToRNNSequence,
ngraph::pass::ConvertTensorIteratorToLSTMSequence,
ngraph::pass::ConvertTensorIteratorToGRUSequence>(
[isCellPrimitiveSupported](const_node_ptr &node) -> bool {
if (const auto& ti_op = std::dynamic_pointer_cast<const ngraph::op::TensorIterator>(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<ngraph::pass::ConvertGELU>();
pass_config->disable<ngraph::pass::HSwishDecomposition>();

View File

@ -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

View File

@ -22,8 +22,8 @@ bool ngraph::pass::UnrollTensorIterator::run_on_function(std::shared_ptr<ngraph:
continue;
}
const auto function = ti->get_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_ptr<ngraph:
// Port map : inputs and back edges
for (const auto& desc : ti->get_input_descriptions()) {
const std::string& type_name = desc->get_type_info().name;
if (type_name == "SliceInputDescription") {
auto input_desc = std::dynamic_pointer_cast<ngraph::opset4::TensorIterator::SliceInputDescription>(desc);
if (!input_desc) {
return false;
}
if (const auto& input_desc = std::dynamic_pointer_cast<ngraph::opset4::TensorIterator::SliceInputDescription>(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<ngraph:
// connect to the body
for (int64_t j = 0; j < num_iter; j++) {
auto idx = stride > 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<ngraph::opset4::TensorIterator::MergedInputDescription>(desc);
if (!input_desc) {
return false;
}
} else if (const auto& merged_desc = std::dynamic_pointer_cast<ngraph::opset4::TensorIterator::MergedInputDescription>(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<ngraph::opset4::TensorIterator::InvariantInputDescription>(
desc);
if (!input_desc) {
return false;
}
} else if (const auto& invariant_desc = std::dynamic_pointer_cast<ngraph::opset4::TensorIterator::InvariantInputDescription>(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_ptr<ngraph:
// Port map: outputs
for (const auto& desc : ti->get_output_descriptions()) {
std::string type_name = desc->get_type_info().name;
if (type_name == "ConcatOutputDescription") {
auto output_desc = std::dynamic_pointer_cast<ngraph::opset4::TensorIterator::ConcatOutputDescription>(desc);
if (!output_desc) {
if (const auto& concat_desc = std::dynamic_pointer_cast<ngraph::opset4::TensorIterator::ConcatOutputDescription>(desc)) {
if (!concat_desc) {
return false;
}
@ -134,44 +116,43 @@ bool ngraph::pass::UnrollTensorIterator::run_on_function(std::shared_ptr<ngraph:
if (num_iter > 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<opset4::Result> result = body_functions[idx]->get_results()[output_desc->m_body_value_index];
std::shared_ptr<opset4::Result> 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<ngraph::opset4::Concat>(to_concat, output_desc->m_axis);
auto concat = std::make_shared<ngraph::opset4::Concat>(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<opset4::Result> 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<opset4::Result> 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<ngraph::opset4::TensorIterator::BodyOutputDescription>(desc);
if (!output_desc) {
return false;
}
} else if (const auto& output_desc = std::dynamic_pointer_cast<ngraph::opset4::TensorIterator::BodyOutputDescription>(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<opset4::Result> 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));

View File

@ -11,6 +11,7 @@
#include <ngraph/node.hpp>
#include <ngraph/pass/manager.hpp>
#include <ngraph/opsets/opset5.hpp>
#include <ngraph/opsets/opset1.hpp>
#include <ngraph/rt_info.hpp>
#include <ngraph/graph_util.hpp>
#include <ngraph/specialize_function.hpp>
@ -25,25 +26,23 @@ ngraph::pass::ConvertTensorIteratorToLSTMSequence::ConvertTensorIteratorToLSTMSe
ngraph::Shape{}, ngraph::pattern::has_class<ngraph::opset5::TensorIterator>());
ngraph::matcher_pass_callback callback = [this](pattern::Matcher &m) {
auto ti = std::dynamic_pointer_cast<ngraph::opset5::TensorIterator>(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::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 1, 1});
auto axis_squeeze = std::make_shared<ngraph::opset5::Constant>(ngraph::element::i64, ngraph::Shape{1}, 1);
auto input_data = std::make_shared<ngraph::opset5::Squeeze>(data, axis_squeeze);
auto pattern_1 = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {1, 1});
auto squeeze = std::make_shared<ngraph::opset5::Reshape>(data, pattern_1, false);
auto input_H_state = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 1});
auto input_C_state = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 1});
auto input_W = std::make_shared<ngraph::opset5::Constant>(ngraph::element::f32, ngraph::Shape{4, 1});
auto input_R = std::make_shared<ngraph::opset5::Constant>(ngraph::element::f32, ngraph::Shape{4, 1});
auto input_B = std::make_shared<ngraph::opset5::Constant>(ngraph::element::f32, ngraph::Shape{4});
auto cell = std::make_shared<ngraph::opset5::LSTMCell>(input_data, input_H_state, input_C_state,
auto cell = std::make_shared<ngraph::opset5::LSTMCell>(squeeze, input_H_state, input_C_state,
input_W, input_R, input_B, 1);
auto axis_unsqueeze = std::make_shared<ngraph::opset5::Constant>(ngraph::element::i64, ngraph::Shape{1}, 1);
auto unsqueeze = std::make_shared<ngraph::opset5::Unsqueeze>(cell, axis_unsqueeze);
auto pattern_2 = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{3}, {1, 1, 1});
auto unsqueeze = std::make_shared<ngraph::opset5::Reshape>(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<ngraph::opset1::LSTMCell>(squeeze, input_H_state, input_C_state,
input_W, input_R, input_B, 1);
if (!match) {
unsqueeze = std::make_shared<ngraph::opset5::Reshape>(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<Node>& found_cell = pattern_map[cell];
if (!found_cell)
found_cell = pattern_map[cell_v1];
auto params = func->get_parameters();
std::vector<std::shared_ptr<ngraph::opset5::TensorIterator::InputDescription>> 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<ngraph::opset5::LSTMCell>(pattern_map[cell]);
const auto& lstm_cell = std::dynamic_pointer_cast<ngraph::op::util::RNNCellBase>(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<ngraph::opset5::Squeeze>(sequence->output(0), axis_out);
Output<Node> 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<ngraph::opset5::Transpose>(out, order);
}
auto out_0 = std::make_shared<ngraph::opset5::Squeeze>(out, axis_out);
auto out_1 = std::make_shared<ngraph::opset5::Squeeze>(sequence->output(1), axis_out);
auto out_2 = std::make_shared<ngraph::opset5::Squeeze>(sequence->output(2), axis_out);
std::shared_ptr<Node> 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<ngraph::opset5::Transpose>(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::opset5::TensorIterator>());
ngraph::matcher_pass_callback callback = [this](pattern::Matcher &m) {
auto ti = std::dynamic_pointer_cast<ngraph::opset5::TensorIterator>(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::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 1, 1});
auto axis_squeeze = std::make_shared<ngraph::opset5::Constant>(ngraph::element::i64, ngraph::Shape{1}, 0);
auto input_data = std::make_shared<ngraph::opset5::Squeeze>(data, axis_squeeze);
auto pattern_1 = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {1, 1});
auto squeeze = std::make_shared<ngraph::opset5::Reshape>(data, pattern_1, false);
auto input_H_state = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 1});
auto input_W = std::make_shared<ngraph::opset5::Constant>(ngraph::element::f32, ngraph::Shape{1, 1});
auto input_R = std::make_shared<ngraph::opset5::Constant>(ngraph::element::f32, ngraph::Shape{1, 1});
auto input_B = std::make_shared<ngraph::opset5::Constant>(ngraph::element::f32, ngraph::Shape{1});
auto cell = std::make_shared<ngraph::opset5::RNNCell>(input_data, input_H_state, input_W, input_R, input_B, 1);
auto cell = std::make_shared<ngraph::opset5::RNNCell>(squeeze, input_H_state, input_W, input_R, input_B, 1);
auto axis_unsqueeze = std::make_shared<ngraph::opset5::Constant>(ngraph::element::i64, ngraph::Shape{1}, 0);
auto unsqueeze = std::make_shared<ngraph::opset5::Unsqueeze>(cell, axis_unsqueeze);
auto pattern_2 = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{3}, {1, 1, 1});
auto unsqueeze = std::make_shared<ngraph::opset5::Reshape>(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<ngraph::opset5::Squeeze>(sequence->output(0), axis_out);
auto out_1 = std::make_shared<ngraph::opset5::Squeeze>(sequence->output(1), axis_out);
std::shared_ptr<Node> out = out_0;
Output<Node> 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<ngraph::opset5::Transpose>(out_0, order);
auto order = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {2, 1, 0, 3});
out = std::make_shared<ngraph::opset5::Transpose>(out, order);
}
auto out_0 = std::make_shared<ngraph::opset5::Squeeze>(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::opset5::TensorIterator>());
ngraph::matcher_pass_callback callback = [this](pattern::Matcher &m) {
auto ti = std::dynamic_pointer_cast<ngraph::opset5::TensorIterator>(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::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 1, 1});
auto axis_squeeze = std::make_shared<ngraph::opset5::Constant>(ngraph::element::i64, ngraph::Shape{1}, 0);
auto input_data = std::make_shared<ngraph::opset5::Squeeze>(data, axis_squeeze);
auto pattern_1 = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {1, 1});
auto squeeze = std::make_shared<ngraph::opset5::Reshape>(data, pattern_1, false);
auto input_H_state = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 1});
auto input_W = std::make_shared<ngraph::opset5::Constant>(ngraph::element::f32, ngraph::Shape{3, 1});
auto input_R = std::make_shared<ngraph::opset5::Constant>(ngraph::element::f32, ngraph::Shape{3, 1});
auto input_B = std::make_shared<ngraph::opset5::Constant>(ngraph::element::f32, ngraph::Shape{3});
auto cell = std::make_shared<ngraph::opset5::GRUCell>(input_data, input_H_state, input_W, input_R, input_B, 1);
auto cell = std::make_shared<ngraph::opset5::GRUCell>(squeeze, input_H_state, input_W, input_R, input_B, 1);
auto axis_unsqueeze = std::make_shared<ngraph::opset5::Constant>(ngraph::element::i64, ngraph::Shape{1}, 0);
auto unsqueeze = std::make_shared<ngraph::opset5::Unsqueeze>(cell, axis_unsqueeze);
auto pattern_2 = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{3}, {1, 1, 1});
auto unsqueeze = std::make_shared<ngraph::opset5::Reshape>(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<ngraph::opset5::Squeeze>(sequence->output(0), axis_out);
auto out_1 = std::make_shared<ngraph::opset5::Squeeze>(sequence->output(1), axis_out);
std::shared_ptr<Node> out = out_0;
Output<Node> 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<ngraph::opset5::Transpose>(out_0, order);
auto order = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {2, 1, 0, 3});
out = std::make_shared<ngraph::opset5::Transpose>(out, order);
}
auto out_0 = std::make_shared<ngraph::opset5::Squeeze>(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()) {

View File

@ -16,9 +16,9 @@ NGRAPH_RTTI_DEFINITION(ngraph::pass::GRUCellDecomposition, "GRUCellDecomposition
ngraph::pass::GRUCellDecomposition::GRUCellDecomposition() {
auto gru_cell = ngraph::pattern::wrap_type<opset4::GRUCell>();
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<ngraph::opset4::GRUCell> (m.get_match_root());
if (!gru_cell) {
if (!gru_cell || m_transformation_callback(gru_cell)) {
return false;
}

View File

@ -8,6 +8,7 @@
#include <vector>
#include <ngraph/opsets/opset4.hpp>
#include <ngraph/opsets/opset1.hpp>
#include <ngraph/rt_info.hpp>
#include <ngraph/pattern/op/wrap_type.hpp>
#include <transformations/utils/utils.hpp>
@ -15,10 +16,13 @@
NGRAPH_RTTI_DEFINITION(ngraph::pass::LSTMCellDecomposition, "LSTMCellDecomposition", 0);
ngraph::pass::LSTMCellDecomposition::LSTMCellDecomposition() {
auto lstm_cell = ngraph::pattern::wrap_type<opset4::LSTMCell>();
ngraph::matcher_pass_callback callback = [](ngraph::pattern::Matcher& m) {
auto lstm_cell = std::dynamic_pointer_cast<ngraph::opset4::LSTMCell> (m.get_match_root());
if (!lstm_cell) {
auto is_supported_lstm_cell = [](const std::shared_ptr<Node>& n) {
return pattern::has_class<ngraph::opset1::LSTMCell>()(n) || pattern::has_class<ngraph::opset4::LSTMCell>()(n);
};
auto any_lstm = std::make_shared<pattern::op::Label>(element::f32, Shape{}, is_supported_lstm_cell);
ngraph::matcher_pass_callback callback = [this](ngraph::pattern::Matcher& m) {
auto lstm_cell = std::dynamic_pointer_cast<ngraph::op::util::RNNCellBase>(m.get_match_root());
if (!lstm_cell || m_transformation_callback(lstm_cell)) {
return false;
}
const Output<Node>& X = lstm_cell->input_value(0);
@ -82,6 +86,6 @@ ngraph::pass::LSTMCellDecomposition::LSTMCellDecomposition() {
return true;
};
auto m = std::make_shared<ngraph::pattern::Matcher>(lstm_cell, "LSTMCellDecomposition");
auto m = std::make_shared<ngraph::pattern::Matcher>(any_lstm, "LSTMCellDecomposition");
register_matcher(m, callback);
}

View File

@ -16,9 +16,9 @@ NGRAPH_RTTI_DEFINITION(ngraph::pass::RNNCellDecomposition, "RNNCellDecomposition
ngraph::pass::RNNCellDecomposition::RNNCellDecomposition() {
auto rnn_cell = ngraph::pattern::wrap_type<opset4::RNNCell>();
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<ngraph::opset4::RNNCell> (m.get_match_root());
if (!rnn_cell) {
if (!rnn_cell || m_transformation_callback(rnn_cell)) {
return false;
}
const Output<Node>& X = rnn_cell->input_value(0);

View File

@ -34,8 +34,8 @@ TEST(TransformationTests, ConvertTensorIteratorToLSTMSequence) {
auto Zi = std::make_shared<opset5::Parameter>(element::f32, Shape{1, 128});
// Body
auto axis = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1});
auto squeeze = std::make_shared<opset5::Squeeze>(Xi, axis);
auto reshape_pattern = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {1, 16});
auto squeeze = std::make_shared<opset5::Reshape>(Xi, reshape_pattern, false);
auto w_val = std::vector<float>(512 * 16, 0);
auto r_val = std::vector<float>(512 * 128, 0);
@ -46,8 +46,8 @@ TEST(TransformationTests, ConvertTensorIteratorToLSTMSequence) {
auto lstm_cell = std::make_shared<opset5::LSTMCell>(squeeze, Yi, Zi, W, R, B, 128);
auto res_1 = std::make_shared<opset5::Result>(lstm_cell);
auto axis_unsqueeze = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1});
auto unsqueeze = std::make_shared<opset5::Unsqueeze>(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<opset5::Reshape>(lstm_cell, reshape_pattern_2, false);
auto res_2 = std::make_shared<opset5::Result>(unsqueeze);
auto body = std::make_shared<Function>(OutputVector{res_1, res_2},
ParameterVector{Xi, Yi, Zi});
@ -70,7 +70,6 @@ TEST(TransformationTests, ConvertTensorIteratorToLSTMSequence) {
ngraph::pass::Manager m;
m.register_pass<ngraph::pass::InitNodeInfo>();
m.register_pass<ngraph::pass::ConvertTensorIteratorToLSTMSequence>();
m.set_callback([](const std::shared_ptr<const Node>&) -> 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<opset5::Parameter>(element::f32, Shape{1, 128});
// Body
auto axis = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1});
auto squeeze = std::make_shared<opset5::Squeeze>(Xi, axis);
auto reshape_pattern = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {1, 16});
auto squeeze = std::make_shared<opset5::Reshape>(Xi, reshape_pattern, false);
auto w_val = std::vector<float>(128 * 16, 0);
auto r_val = std::vector<float>(128 * 128, 0);
@ -133,8 +132,8 @@ TEST(TransformationTests, ConvertTensorIteratorToRNNSequence) {
auto rnn_cell = std::make_shared<opset5::RNNCell>(squeeze, Yi, W, R, B, 128);
auto res_1 = std::make_shared<opset5::Result>(rnn_cell);
auto axis_unsqueeze = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1});
auto unsqueeze = std::make_shared<opset5::Unsqueeze>(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<opset5::Reshape>(rnn_cell, reshape_pattern_2, false);
auto res_2 = std::make_shared<opset5::Result>(unsqueeze);
auto body = std::make_shared<Function>(OutputVector{res_1, res_2},
ParameterVector{Xi, Yi});
@ -156,7 +155,6 @@ TEST(TransformationTests, ConvertTensorIteratorToRNNSequence) {
ngraph::pass::Manager m;
m.register_pass<ngraph::pass::InitNodeInfo>();
m.register_pass<ngraph::pass::ConvertTensorIteratorToRNNSequence>();
m.set_callback([](const std::shared_ptr<const Node>&) -> 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<opset5::Parameter>(element::f32, Shape{1, 128});
// Body
auto axis = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1});
auto squeeze = std::make_shared<opset5::Squeeze>(Xi, axis);
auto reshape_pattern = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {1, 16});
auto squeeze = std::make_shared<opset5::Reshape>(Xi, reshape_pattern, false);
auto w_val = std::vector<float>(384 * 16, 0);
auto r_val = std::vector<float>(384 * 128, 0);
@ -216,8 +214,8 @@ TEST(TransformationTests, ConvertTensorIteratorToGRUSequence) {
auto gru_cell = std::make_shared<opset5::GRUCell>(squeeze, Yi, W, R, B, 128);
auto res_1 = std::make_shared<opset5::Result>(gru_cell);
auto axis_unsqueeze = ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1});
auto unsqueeze = std::make_shared<opset5::Unsqueeze>(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<opset5::Reshape>(gru_cell, reshape_pattern_2, false);
auto res_2 = std::make_shared<opset5::Result>(unsqueeze);
auto body = std::make_shared<Function>(OutputVector{res_1, res_2},
ParameterVector{Xi, Yi});
@ -239,7 +237,6 @@ TEST(TransformationTests, ConvertTensorIteratorToGRUSequence) {
ngraph::pass::Manager m;
m.register_pass<ngraph::pass::InitNodeInfo>();
m.register_pass<ngraph::pass::ConvertTensorIteratorToGRUSequence>();
m.set_callback([](const std::shared_ptr<const Node>&) -> bool { return true; });
m.run_passes(f);
ASSERT_NO_THROW(check_rt_info(f));
}

View File

@ -10,13 +10,14 @@
using namespace LayerTestsDefinitions;
namespace {
// output values increase rapidly without clip, so use only seq_lenghts = 2
std::vector<bool> should_decompose = {true, false};
// output values increase rapidly without clip, so use only seq_lenghts = 2
std::vector<size_t> seq_lengths_zero_clip{2};
std::vector<size_t> seq_lengths_clip_non_zero{20};
std::vector<size_t> batch{1, 10};
std::vector<size_t> hidden_size{1, 10};
std::vector<size_t> input_size{10};
// std::vector<size_t> input_size{10};
std::vector<size_t> sequence_axis{0, 1};
std::vector<ngraph::helpers::TensorIteratorBody> 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),

View File

@ -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

View File

@ -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<std::vector<size_t>> 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<std::vector<size_t>> 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::opset5::Constant>(ngraph::element::i64, ngraph::Shape{1}, std::vector<int64_t>{1});
auto axis = std::make_shared<ngraph::opset5::Constant>(ngraph::element::i64, ngraph::Shape{1},
std::vector<int64_t>{static_cast<int64_t>(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<ngraph::opset5::Squeeze>(body_params[0], axis);
std::vector<ngraph::Shape> 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<ngraph::Shape> WRB = {inputShapes[2], inputShapes[3], inputShapes[4]};
auto squeeze = std::make_shared<ngraph::opset5::Squeeze>(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<ngraph::Shape> WRB = {inputShapes[2], inputShapes[3], inputShapes[4]};
auto squeeze = std::make_shared<ngraph::opset5::Squeeze>(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.");
}

View File

@ -60,7 +60,9 @@ const Named<rnn_param> test_name( [] (const rnn_param &p) {
using RNNSeqTest = PlgTest<rnn_param>;
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);

View File

@ -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(); }

View File

@ -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()

View File

@ -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<const op::v4::LSTMCell*>(&node);

View File

@ -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)