LowLatency v2 tests + resolving the review comments from PR 93758 (#14084)

* Enable SequenceFusion, TensorIteratorToSequence, GRUCellFusion transformation in MOC, the transformations have been deleted from plugin pipelines

* clean-up: delete augru transformation header

* Temporary disabled TensorIterator IR reader tests

* temporary disable tests, it's not TI issue, usqueeze doesn't have reference impl for fp64 and bf16

* Update ConvertTensorItearatorToSequence transformations: add Unsqueeze to pattern

* Codestyle

* Specify negative values for LSTM/GRU/RNN Sequence ops

* fix conflicts with master branch

* Insert ShapeOf subgraph in ConvertSequencesToTensorIterator transformation in case of dynamic input shape

* codestyle

* fix conflict with master branch

* fix onednn version

* Update low latency v2 to support GRU/RNN/LSTM Sequence ops, fix accuracy issue

* fix tensor names

* fix tensor name issue on gna

* fix transformation tests, fix copying rt_info in the transformation

* fix warning, enable bf16, f64 ti tests

* codestyle

* fix functional tests

* EliminateDuplicateTIInputs transformation, fix copy_with_new_inputs method of TI op

* move EliminateDuplicateTIInputs transformation

* codestyle

* add LLTv2 tests, resolve review comments

* resolve conflicts with master

Co-authored-by: Andrei Kochin <andrei.kochin@intel.com>
This commit is contained in:
Ivan TikhonovandAndrei Kochin authored and GitHub committed 2022-11-19 10:57:44 +03:00
1 parent ed643b3f74
commit 68e7f062c5
6 files changed
+192 -13

No files matched your search

@@ -69,9 +69,9 @@ ov::pass::EliminateDuplicateTIInputs::EliminateDuplicateTIInputs() {
const auto& body = ti->get_function();
// re-connect outputs of duplicate Parameters
auto parameters = body->get_parameters();
for (const auto& it : need_to_eliminate) {
for (const auto& redundant : it.second) {
auto parameters = body->get_parameters();
parameters[redundant->m_body_parameter_index]->output(0).replace(
parameters[it.first->m_body_parameter_index]);
}
+2
View File
@@ -119,6 +119,8 @@ bool op::v0::Unsqueeze::has_evaluate() const {
case ngraph::element::u64:
case ngraph::element::f16:
case ngraph::element::f32:
case ngraph::element::f64:
case ngraph::element::bf16:
return true;
default:
break;
+16 -6
View File
@@ -177,7 +177,6 @@ shared_ptr<ov::opset9::Assign> replace_with_memory(const ov::Input<ov::Node>& in
}
auto read_value = to.make<ReadValue>(read_value_in, variable);
input.replace_source_output(read_value->output(0));
read_value->set_friendly_name(variable_name);
auto assign = to.make<Assign>(output, variable);
// control dependency so that ReadValue is processed before Assign
assign->add_control_dependency(read_value);
@@ -189,10 +188,15 @@ std::vector<shared_ptr<ov::opset9::Assign>> replace_with_memory(const shared_ptr
bool use_const_initializer,
ov::pass::NodeRegistry& to) {
std::vector<shared_ptr<ov::opset9::Assign>> new_assigns;
size_t var_idx = 0;
for (const auto& idx : indexes) {
auto in = node->input(idx);
auto out = node->output(idx);
new_assigns.push_back(replace_with_memory(in, out, node->get_friendly_name(), use_const_initializer, to));
new_assigns.push_back(replace_with_memory(in,
out,
node->get_friendly_name() + "/variable_" + to_string(var_idx++),
use_const_initializer,
to));
}
return new_assigns;
}
@@ -211,7 +215,7 @@ ov::OutputVector prepare_inputs(const shared_ptr<ov::Node>& op, size_t seq_len_i
auto axis_0 = to.make<Constant>(ov::element::i32, ov::Shape{1}, 0);
auto axis_1 = to.make<Constant>(ov::element::i32, ov::Shape{1}, 1);
size_t num_lstm_inputs_without_peepholes = 7;
for (size_t i = 0; i < max(op->get_input_size(), num_lstm_inputs_without_peepholes); ++i) {
for (size_t i = 0; i < min(op->get_input_size(), num_lstm_inputs_without_peepholes); ++i) {
if (i < seq_len_idx) {
inputs.push_back(to.make<Squeeze>(op->get_input_source_output(i), axis_1));
} else if (i > seq_len_idx) {
@@ -305,13 +309,19 @@ std::vector<shared_ptr<ov::opset9::Assign>> process_sequence(const shared_ptr<ov
auto axis_1 = to.make<Constant>(ov::element::i32, ov::Shape{1}, 1);
ov::OutputVector outputs;
outputs.push_back(to.make<Unsqueeze>(cell->output(0), axis_1_2));
auto unsqueeze_Y = to.make<Unsqueeze>(cell->output(0), axis_1_2);
unsqueeze_Y->set_friendly_name(op->get_friendly_name() + ":0");
outputs.push_back(unsqueeze_Y);
size_t idx = 1;
for (const auto& out : cell->outputs()) {
outputs.push_back(to.make<Unsqueeze>(out, axis_1));
auto unsqueeze_state = to.make<Unsqueeze>(out, axis_1);
unsqueeze_state->set_friendly_name(op->get_friendly_name() + ":" + to_string(idx++));
outputs.push_back(unsqueeze_state);
}
replace_node(op, outputs);
copy_runtime_info(op, to.get());
}
copy_runtime_info(op, to.get());
return new_assigns;
}
} // namespace
@@ -323,12 +323,14 @@ void TransformationsPipeline::apply(std::shared_ptr<ov::Model> func) {
return isCellPrimitiveSupported(node);
});
pass_config->set_callback<ngraph::pass::ConvertRNNSequenceToTensorIterator,
ngraph::pass::ConvertGRUSequenceToTensorIterator,
ngraph::pass::ConvertLSTMSequenceToTensorIterator>(
[isSequencePrimitiveSupported](const_node_ptr &node) -> bool {
return isSequencePrimitiveSupported(node);
});
if (config.enable_loop_unrolling) {
pass_config->set_callback<ngraph::pass::ConvertRNNSequenceToTensorIterator,
ngraph::pass::ConvertGRUSequenceToTensorIterator,
ngraph::pass::ConvertLSTMSequenceToTensorIterator>(
[isSequencePrimitiveSupported](const_node_ptr &node) -> bool {
return isSequencePrimitiveSupported(node);
});
}
pass_config->set_callback<ngraph::pass::MVN6Decomposition>(
[](const_node_ptr &node) -> bool {
@@ -76,4 +76,5 @@ TEST(TransformationTests, EliminateDuplicateTIInputs) {
EXPECT_NE(ti_after_transformation, nullptr);
EXPECT_EQ(ti_after_transformation->get_body()->get_parameters().size(), 3);
EXPECT_EQ(ti_after_transformation->inputs().size(), 3);
EXPECT_EQ(ti_after_transformation->get_input_descriptions().size(), 3);
}
@@ -841,3 +841,167 @@ TEST(TransformationTests, LowLatencyLSTM_LLTv1_LLTv2) {
EXPECT_NO_THROW(manager.run_passes(f));
}
}
namespace {
using OutPtr = Output<Node>;
enum class RNNType : size_t {
RNN = 1,
GRU = 3,
LSTM = 4,
};
struct LLT2Params {
RNNType rnn_type;
size_t seq_len;
};
struct RNNAttributes {
size_t batch;
size_t num_dir;
size_t hidden_size;
size_t input_size;
size_t seq_len;
};
OutputVector create_sequence(RNNType rnn_type, RNNAttributes attrs, const OutPtr& X, const OutPtr& H, const OutPtr& C) {
auto gate = static_cast<size_t>(rnn_type);
auto shape_of = std::make_shared<ShapeOf>(X);
auto batch_dimension = std::make_shared<Gather>(
shape_of,
Constant::create(ngraph::element::i64, {1}, {0}),
Constant::create(ngraph::element::i64, {}, {0}));
auto seq_len_dim = std::make_shared<Gather>(
shape_of,
Constant::create(element::i64, {1}, {1}),
Constant::create(element::i64, {}, {0}));
auto seq_lengths = std::make_shared<Broadcast>(seq_len_dim, batch_dimension);
auto W = make_shared<Constant>(element::f32, Shape{attrs.num_dir, gate * attrs.hidden_size, attrs.input_size}, 0);
auto R = make_shared<Constant>(element::f32, Shape{attrs.num_dir, gate * attrs.hidden_size, attrs.hidden_size}, 0);
auto B = make_shared<Constant>(element::f32, Shape{attrs.num_dir, gate * attrs.hidden_size}, 0);
shared_ptr<Node> sequence;
if (rnn_type == RNNType::LSTM) {
sequence = make_shared<LSTMSequence>(X, H, C, seq_lengths, W, R, B, attrs.hidden_size, LSTMSequence::direction::FORWARD);
} else if (rnn_type == RNNType::RNN) {
sequence = make_shared<RNNSequence>(X, H, seq_lengths, W, R, B, attrs.hidden_size, op::RecurrentSequenceDirection::FORWARD);
} else if (rnn_type == RNNType::GRU) {
sequence = make_shared<GRUSequence>(X, H, seq_lengths, W, R, B, attrs.hidden_size, op::RecurrentSequenceDirection::FORWARD);
}
return sequence->outputs();
}
shared_ptr<ReadValue> create_read_value(const shared_ptr<Parameter>& param, const VariablePtr& variable) {
auto const_zero = make_shared<Constant>(param->get_element_type(), ov::Shape{1}, 0);
auto shape_of = make_shared<ShapeOf>(param);
auto broadcast = make_shared<Broadcast>(const_zero, shape_of);
auto read_value = make_shared<ReadValue>(broadcast, variable);
return read_value;
}
OutputVector create_cell_reference(RNNType rnn_type, RNNAttributes attrs, const OutPtr& X, const OutPtr& H, const OutPtr& C) {
auto gate = static_cast<size_t>(rnn_type);
auto axis_0 = Constant::create(element::i32, Shape{1}, {0});
auto axis_1 = Constant::create(element::i32, Shape{1}, {1});
shared_ptr<Node> squeeze_C;
if (rnn_type == RNNType::LSTM) {
squeeze_C = make_shared<Squeeze>(C, axis_1);
}
auto squeeze_X = make_shared<Squeeze>(X, axis_1);
auto squeeze_H = make_shared<Squeeze>(H, axis_1);
auto W = make_shared<Constant>(element::f32, Shape{attrs.num_dir, gate * attrs.hidden_size, attrs.input_size}, 0);
auto R = make_shared<Constant>(element::f32, Shape{attrs.num_dir, gate * attrs.hidden_size, attrs.hidden_size}, 0);
auto B = make_shared<Constant>(element::f32, Shape{attrs.num_dir, gate * attrs.hidden_size}, 0);
auto squeeze_W = std::make_shared<Squeeze>(W, axis_0);
auto squeeze_R = std::make_shared<Squeeze>(R, axis_0);
auto squeeze_B = std::make_shared<Squeeze>(B, axis_0);
shared_ptr<Node> cell;
if (rnn_type == RNNType::LSTM) {
cell = make_shared<LSTMCell>(squeeze_X, squeeze_H, squeeze_C, squeeze_W, squeeze_R, squeeze_B, attrs.hidden_size);
} else if (rnn_type == RNNType::RNN) {
cell = make_shared<RNNCell>(squeeze_X, squeeze_H, squeeze_W, squeeze_R, squeeze_B, attrs.hidden_size);
} else if (rnn_type == RNNType::GRU) {
cell = make_shared<GRUCell>(squeeze_X, squeeze_H, squeeze_W, squeeze_R, squeeze_B, attrs.hidden_size);
}
auto axis_12 = Constant::create(element::i32, Shape{2}, {1, 2});
auto unsqueeze_Y = make_shared<Unsqueeze>(cell->output(0), axis_12);
auto unsqueeze_H = make_shared<Unsqueeze>(cell->output(0), axis_1);
OutputVector outputs = {unsqueeze_Y, unsqueeze_H};
if (rnn_type == RNNType::LSTM) {
auto unsqueeze_C = make_shared<Unsqueeze>(cell->output(1), axis_1);
outputs.push_back(unsqueeze_C);
}
return outputs;
}
} // namespace
class LLT2Sequence
: public WithParamInterface<LLT2Params>,
public TransformationTestsF {
};
TEST_P(LLT2Sequence, RNNLowLatency_v2) {
const auto& p = GetParam();
RNNAttributes attrs = {1, 1, 10, 4, p.seq_len};
{
auto X = make_shared<Parameter>(element::f32, Shape{attrs.batch, attrs.seq_len, attrs.input_size});
auto H = make_shared<Parameter>(element::f32, Shape{attrs.batch, attrs.num_dir, attrs.hidden_size});
auto C = make_shared<Parameter>(element::f32, Shape{attrs.batch, attrs.num_dir, attrs.hidden_size});
auto outputs = create_sequence(p.rnn_type, attrs, X, H, C);
ParameterVector params{X, H};
if (p.rnn_type == RNNType::LSTM) {
params.push_back(C);
}
model = make_shared<ov::Model>(outputs, params);
manager.register_pass<pass::LowLatency2>();
}
{
auto X = make_shared<Parameter>(element::f32, Shape{attrs.batch, attrs.seq_len, attrs.input_size});
auto H = make_shared<Parameter>(element::f32, Shape{attrs.batch, attrs.num_dir, attrs.hidden_size});
auto C = make_shared<Parameter>(element::f32, Shape{attrs.batch, attrs.num_dir, attrs.hidden_size});
auto variable_h = make_shared<Variable>(VariableInfo{PartialShape::dynamic(), element::dynamic, "node_28/variable_0"});
auto variable_c = make_shared<Variable>(VariableInfo{PartialShape::dynamic(), element::dynamic, "node_28/variable_1"});
auto read_val_H = create_read_value(H, variable_h);
auto read_val_C = create_read_value(C, variable_c);
OutputVector outputs;
if (p.seq_len == 1) {
outputs = create_cell_reference(p.rnn_type, attrs, X, read_val_H, read_val_C);
} else {
outputs = create_sequence(p.rnn_type, attrs, X, read_val_H, read_val_C);
}
SinkVector sinks;
auto assign_h = make_shared<Assign>(outputs[1], variable_h);
sinks.push_back(assign_h);
assign_h->add_control_dependency(read_val_H);
ParameterVector params = {X, H};
if (p.rnn_type == RNNType::LSTM) {
params.push_back(C);
auto assign_c = make_shared<Assign>(outputs[2], variable_c);
assign_c->add_control_dependency(read_val_C);
sinks.push_back(assign_c);
}
model_ref = make_shared<ov::Model>(outputs, sinks, params);
}
comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES);
}
static const std::vector<LLT2Params> llt_v2_params = {
LLT2Params{RNNType::RNN, 1},
LLT2Params{RNNType::GRU, 1},
LLT2Params{RNNType::LSTM, 1},
LLT2Params{RNNType::RNN, 10},
LLT2Params{RNNType::GRU, 10},
LLT2Params{RNNType::LSTM, 10},
};
INSTANTIATE_TEST_SUITE_P(LLT2Sequence, LLT2Sequence, ValuesIn(llt_v2_params));