[TF FE] Move GRUBlockCell conversion to loaders stage (#24332)
**Details:** It should improve conversion time and make conversion more robust to source changes. **Ticket:** TBD --------- Signed-off-by: Kazantsev, Roman <roman.kazantsev@intel.com>
This commit is contained in:
parent
7e6f6876cb
commit
853a48a5af
|
|
@ -12,7 +12,6 @@
|
|||
#include "helper_transforms/block_lstm_replacer.hpp"
|
||||
#include "helper_transforms/const_to_result_remover.hpp"
|
||||
#include "helper_transforms/embedding_segments_feature_fusing.hpp"
|
||||
#include "helper_transforms/gru_block_cell_replacer.hpp"
|
||||
#include "helper_transforms/saved_model_unused_remover.hpp"
|
||||
#include "helper_transforms/tensor_array_v3_replacer.hpp"
|
||||
#include "input_model.hpp"
|
||||
|
|
@ -567,7 +566,6 @@ void FrontEnd::normalize(const std::shared_ptr<ov::Model>& model) const {
|
|||
manager.register_pass<pass::UninitializedVariableResolver>();
|
||||
manager.register_pass<pass::EmbeddingSegmentSingleFeatureFusion>();
|
||||
manager.register_pass<pass::BlockLSTMReplacer>();
|
||||
manager.register_pass<pass::GRUBlockCellReplacer>();
|
||||
manager.register_pass<pass::TensorArrayV3Replacer>();
|
||||
manager.register_pass<pass::ConstToResultRemover>();
|
||||
manager.register_pass<pass::SwitchMergeResolver>();
|
||||
|
|
|
|||
|
|
@ -6,9 +6,17 @@
|
|||
|
||||
#include "common_op_table.hpp"
|
||||
#include "openvino/frontend/tensorflow/node_context.hpp"
|
||||
#include "openvino/op/concat.hpp"
|
||||
#include "openvino/op/constant.hpp"
|
||||
#include "openvino/op/gru_cell.hpp"
|
||||
#include "openvino/op/shape_of.hpp"
|
||||
#include "openvino/op/slice.hpp"
|
||||
#include "openvino/op/split.hpp"
|
||||
#include "openvino/op/variadic_split.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace ov;
|
||||
using namespace ov::op;
|
||||
using namespace ov::frontend::tensorflow;
|
||||
|
||||
namespace ov {
|
||||
|
|
@ -32,6 +40,7 @@ OutputVector translate_gru_block_cell_op(const ov::frontend::tensorflow::NodeCon
|
|||
// 2) c: Output of the cell connection gate
|
||||
// 3) h: Current state of the GRU cell
|
||||
default_op_checks(node, 6, {"GRUBlockCell"});
|
||||
auto node_name = node.get_name();
|
||||
auto x = node.get_input(0);
|
||||
auto h_prev = node.get_input(1);
|
||||
auto w_ru = node.get_input(2);
|
||||
|
|
@ -39,9 +48,94 @@ OutputVector translate_gru_block_cell_op(const ov::frontend::tensorflow::NodeCon
|
|||
auto b_ru = node.get_input(4);
|
||||
auto b_c = node.get_input(5);
|
||||
|
||||
// try to deduce hidden_size
|
||||
// 1. use h_prev_shape
|
||||
auto hidden_size = ov::Dimension::dynamic();
|
||||
auto h_prev_shape = h_prev.get_partial_shape();
|
||||
auto h_prev_rank = h_prev_shape.rank();
|
||||
if (h_prev_rank.is_static()) {
|
||||
hidden_size = h_prev_shape[1].is_static() ? h_prev_shape[1].get_length() : hidden_size;
|
||||
}
|
||||
auto w_ru_shape = w_ru.get_partial_shape();
|
||||
auto w_ru_rank = w_ru_shape.rank();
|
||||
if (w_ru_rank.is_static()) {
|
||||
hidden_size = w_ru_shape[1].is_static() ? w_ru_shape[1].get_length() / 2 : hidden_size;
|
||||
}
|
||||
// 3. use w_c shape
|
||||
auto w_c_shape = w_c.get_partial_shape();
|
||||
auto w_c_rank = w_c_shape.rank();
|
||||
if (w_c_rank.is_static()) {
|
||||
hidden_size = w_c_shape[1].is_static() ? w_c_shape[1].get_length() : hidden_size;
|
||||
}
|
||||
// 3. use b_ru shape
|
||||
auto b_ru_shape = b_ru.get_partial_shape();
|
||||
auto b_ru_rank = b_ru_shape.rank();
|
||||
if (b_ru_rank.is_static()) {
|
||||
hidden_size = b_ru_shape[0].is_static() ? b_ru_shape[0].get_length() / 2 : hidden_size;
|
||||
}
|
||||
// 4. use b_c shape
|
||||
auto b_c_shape = b_c.get_partial_shape();
|
||||
auto b_c_rank = b_c_shape.rank();
|
||||
if (b_c_rank.is_static()) {
|
||||
hidden_size = b_c_shape[0].is_static() ? b_c_shape[0].get_length() : hidden_size;
|
||||
}
|
||||
|
||||
TENSORFLOW_OP_VALIDATION(
|
||||
node,
|
||||
hidden_size.is_static(),
|
||||
"[TensorFlow Frontend] internal error: GRUBlockCell is supported only for static hidden size");
|
||||
|
||||
// retrive input_size and hidden_size
|
||||
auto x_shape = std::make_shared<v3::ShapeOf>(x, element::i64);
|
||||
auto ss_start = std::make_shared<v0::Constant>(element::i64, Shape{1}, 1);
|
||||
auto ss_end = std::make_shared<v0::Constant>(element::i64, Shape{1}, 2);
|
||||
auto ss_step = std::make_shared<v0::Constant>(element::i64, Shape{1}, 1);
|
||||
auto input_size = std::make_shared<v8::Slice>(x_shape, ss_start, ss_end, ss_step);
|
||||
auto h_prev_shape_graph = std::make_shared<v3::ShapeOf>(h_prev, element::i64);
|
||||
auto hidden_size_graph = std::make_shared<v8::Slice>(h_prev_shape_graph, ss_start, ss_end, ss_step);
|
||||
|
||||
// prepare weights input
|
||||
// TensorFlow provides weights in a format w_ru and w_c, where
|
||||
// z or u - update, r - reset, c or h - hidden (connection)
|
||||
// OpenVINO GRUCell accepts weights in a format w_zrh (or w_urс)
|
||||
// 1. split w_ru into w_r and w_u
|
||||
auto split_w_ru = std::make_shared<v1::Split>(w_ru, std::make_shared<v0::Constant>(element::i64, Shape{}, 1), 2);
|
||||
// 2. concatenate different parts of weights into w_zrh (or w_urс)
|
||||
auto w_urc = std::make_shared<v0::Concat>(OutputVector{split_w_ru->output(1), split_w_ru->output(0), w_c}, 1);
|
||||
|
||||
// prepare bias in the same way
|
||||
auto split_b_ru = std::make_shared<v1::Split>(b_ru, std::make_shared<v0::Constant>(element::i64, Shape{}, 0), 2);
|
||||
auto b_urc = std::make_shared<v0::Concat>(OutputVector{split_b_ru->output(1), split_b_ru->output(0), b_c}, 0);
|
||||
|
||||
// transpose weights
|
||||
// the current shape - [input_size + hidden_size, 3 * hidden_size]
|
||||
// we need the shape [3 * hidden_size, input_size + hidden_size]
|
||||
// in order to split WR into W and R
|
||||
auto transpose_order = std::make_shared<v0::Constant>(element::i64, Shape{2}, std::vector<int64_t>{1, 0});
|
||||
auto w_urc_transpose = std::make_shared<v1::Transpose>(w_urc, transpose_order);
|
||||
|
||||
// split combined weights WR into W and R
|
||||
auto split_axis = std::make_shared<v0::Constant>(element::i64, Shape{}, 1);
|
||||
auto split_nums = std::make_shared<v0::Concat>(OutputVector{input_size, hidden_size_graph}, 0);
|
||||
auto split_WR = std::make_shared<v1::VariadicSplit>(w_urc_transpose, split_axis, split_nums);
|
||||
|
||||
auto gru_cell = std::make_shared<v3::GRUCell>(x,
|
||||
h_prev,
|
||||
split_WR->output(0),
|
||||
split_WR->output(1),
|
||||
b_urc,
|
||||
hidden_size.get_length());
|
||||
// preserve names of the node and the output tensor
|
||||
gru_cell->output(0).set_names({node_name + ":3"});
|
||||
|
||||
auto gru_block_cell_node = make_shared<GRUBlockCell>(x, h_prev, w_ru, w_c, b_ru, b_c, node.get_decoder());
|
||||
set_node_name(node.get_name(), gru_block_cell_node);
|
||||
return gru_block_cell_node->outputs();
|
||||
gru_block_cell_node->output(0).set_names({node_name + ":0"});
|
||||
gru_block_cell_node->output(1).set_names({node_name + ":1"});
|
||||
gru_block_cell_node->output(2).set_names({node_name + ":2"});
|
||||
ov::OutputVector results = gru_block_cell_node->outputs();
|
||||
results[3] = gru_cell->output(0);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
} // namespace op
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
// Copyright (C) 2018-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "openvino/pass/graph_rewrite.hpp"
|
||||
#include "openvino/pass/pass.hpp"
|
||||
|
||||
namespace ov {
|
||||
namespace frontend {
|
||||
namespace tensorflow {
|
||||
namespace pass {
|
||||
|
||||
// This transformation handles GRUBlockCell with just one output - hidden state
|
||||
class GRUBlockCellReplacer : public ov::pass::MatcherPass {
|
||||
public:
|
||||
OPENVINO_RTTI("ov::frontend::tensorflow::pass::GRUBlockCellReplacer");
|
||||
GRUBlockCellReplacer();
|
||||
};
|
||||
|
||||
} // namespace pass
|
||||
} // namespace tensorflow
|
||||
} // namespace frontend
|
||||
} // namespace ov
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
// Copyright (C) 2018-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "helper_transforms/gru_block_cell_replacer.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "helper_ops/gru_block_cell.hpp"
|
||||
#include "openvino/op/concat.hpp"
|
||||
#include "openvino/op/constant.hpp"
|
||||
#include "openvino/op/gru_cell.hpp"
|
||||
#include "openvino/op/shape_of.hpp"
|
||||
#include "openvino/op/slice.hpp"
|
||||
#include "openvino/op/split.hpp"
|
||||
#include "openvino/op/transpose.hpp"
|
||||
#include "openvino/op/variadic_split.hpp"
|
||||
#include "openvino/pass/pattern/matcher.hpp"
|
||||
#include "openvino/pass/pattern/op/or.hpp"
|
||||
#include "openvino/pass/pattern/op/wrap_type.hpp"
|
||||
#include "transformations/utils/utils.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace ov::pass;
|
||||
using namespace ov::op;
|
||||
using namespace ov::frontend::tensorflow;
|
||||
|
||||
pass::GRUBlockCellReplacer::GRUBlockCellReplacer() {
|
||||
auto gru_block_cell = pattern::wrap_type<GRUBlockCell>();
|
||||
|
||||
matcher_pass_callback callback = [=](pattern::Matcher& m) {
|
||||
NodeRegistry rg;
|
||||
|
||||
auto gru_block_cell_node = std::dynamic_pointer_cast<GRUBlockCell>(m.get_match_root());
|
||||
if (!gru_block_cell_node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// this transformation expects only one output (the forth output) - hidden state
|
||||
// that is only output supported by OpenVINO GRUCell
|
||||
std::vector<int> restricted_output_indices = {0, 1, 2};
|
||||
for (size_t output_ind : restricted_output_indices) {
|
||||
if (gru_block_cell_node->output(output_ind).get_target_inputs().size() > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// currently, OpenVINO support only static hidden_size
|
||||
auto m_hidden_size = gru_block_cell_node->get_hidden_size();
|
||||
if (m_hidden_size.is_dynamic()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto x = gru_block_cell_node->input_value(0);
|
||||
auto h_prev = gru_block_cell_node->input_value(1);
|
||||
auto w_ru = gru_block_cell_node->input_value(2);
|
||||
auto w_c = gru_block_cell_node->input_value(3);
|
||||
auto b_ru = gru_block_cell_node->input_value(4);
|
||||
auto b_c = gru_block_cell_node->input_value(5);
|
||||
|
||||
// retrive input_size and hidden_size
|
||||
auto x_shape = rg.make<v3::ShapeOf>(x, element::i64);
|
||||
auto ss_start = rg.make<v0::Constant>(element::i64, Shape{1}, 1);
|
||||
auto ss_end = rg.make<v0::Constant>(element::i64, Shape{1}, 2);
|
||||
auto ss_step = rg.make<v0::Constant>(element::i64, Shape{1}, 1);
|
||||
auto input_size = rg.make<v8::Slice>(x_shape, ss_start, ss_end, ss_step);
|
||||
auto h_prev_shape = rg.make<v3::ShapeOf>(h_prev, element::i64);
|
||||
auto hidden_size = rg.make<v8::Slice>(h_prev_shape, ss_start, ss_end, ss_step);
|
||||
|
||||
// prepare weights input
|
||||
// TensorFlow provides weights in a format w_ru and w_c, where
|
||||
// z or u - update, r - reset, c or h - hidden (connection)
|
||||
// OpenVINO GRUCell accepts weights in a format w_zrh (or w_urс)
|
||||
// 1. split w_ru into w_r and w_u
|
||||
auto split_w_ru = rg.make<v1::Split>(w_ru, rg.make<v0::Constant>(element::i64, Shape{}, 1), 2);
|
||||
// 2. concatenate different parts of weights into w_zrh (or w_urс)
|
||||
auto w_urc = rg.make<v0::Concat>(OutputVector{split_w_ru->output(1), split_w_ru->output(0), w_c}, 1);
|
||||
|
||||
// prepare bias in the same way
|
||||
auto split_b_ru = rg.make<v1::Split>(b_ru, rg.make<v0::Constant>(element::i64, Shape{}, 0), 2);
|
||||
auto b_urc = rg.make<v0::Concat>(OutputVector{split_b_ru->output(1), split_b_ru->output(0), b_c}, 0);
|
||||
|
||||
// transpose weights
|
||||
// the current shape - [input_size + hidden_size, 3 * hidden_size]
|
||||
// we need the shape [3 * hidden_size, input_size + hidden_size]
|
||||
// in order to split WR into W and R
|
||||
auto transpose_order = rg.make<v0::Constant>(element::i64, Shape{2}, std::vector<int64_t>{1, 0});
|
||||
auto w_urc_transpose = rg.make<v1::Transpose>(w_urc, transpose_order);
|
||||
|
||||
// split combined weights WR into W and R
|
||||
auto split_axis = rg.make<v0::Constant>(element::i64, Shape{}, 1);
|
||||
auto split_nums = rg.make<v0::Concat>(OutputVector{input_size, hidden_size}, 0);
|
||||
auto split_WR = rg.make<v1::VariadicSplit>(w_urc_transpose, split_axis, split_nums);
|
||||
|
||||
auto gru_cell = rg.make<v3::GRUCell>(x,
|
||||
h_prev,
|
||||
split_WR->output(0),
|
||||
split_WR->output(1),
|
||||
b_urc,
|
||||
m_hidden_size.get_length());
|
||||
|
||||
// preserve names of the node and the output tensor
|
||||
gru_cell->set_friendly_name(m.get_match_root()->get_friendly_name() + ":3");
|
||||
copy_runtime_info(gru_block_cell_node, rg.get());
|
||||
|
||||
// replace GRUBlockCell with GRUCell manually instead of calling
|
||||
// ov::replace_node(m.get_match_root(), gru_cell);
|
||||
// because GRUBlockCell has 4 outputs and GRUCell has just one
|
||||
m.get_match_root()->output(3).replace(gru_cell->output(0));
|
||||
return true;
|
||||
};
|
||||
|
||||
auto m = std::make_shared<pattern::Matcher>(gru_block_cell, "ov::frontend::tensorflow::pass::GRUBlockCellReplacer");
|
||||
register_matcher(m, callback);
|
||||
}
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
// Copyright (C) 2018-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "helper_transforms/gru_block_cell_replacer.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "conversion_with_reference.hpp"
|
||||
#include "helper_ops/gru_block_cell.hpp"
|
||||
#include "openvino/frontend/manager.hpp"
|
||||
#include "openvino/op/concat.hpp"
|
||||
#include "openvino/op/constant.hpp"
|
||||
#include "openvino/op/gru_cell.hpp"
|
||||
#include "openvino/op/parameter.hpp"
|
||||
#include "openvino/op/shape_of.hpp"
|
||||
#include "openvino/op/slice.hpp"
|
||||
#include "openvino/op/split.hpp"
|
||||
#include "openvino/op/transpose.hpp"
|
||||
#include "openvino/op/variadic_split.hpp"
|
||||
#include "openvino/pass/manager.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace ov;
|
||||
using namespace ov::op;
|
||||
using namespace element;
|
||||
using namespace frontend::tensorflow;
|
||||
using namespace frontend::tensorflow::pass;
|
||||
|
||||
namespace {
|
||||
shared_ptr<Model> gen_model(Dimension batch_size, int64_t hidden_size, Dimension input_size) {
|
||||
auto x = make_shared<v0::Parameter>(f32, PartialShape{batch_size, input_size});
|
||||
auto h_prev = make_shared<v0::Parameter>(f32, PartialShape{batch_size, hidden_size});
|
||||
auto w_ru = make_shared<v0::Parameter>(f32, PartialShape::dynamic());
|
||||
auto w_c = make_shared<v0::Parameter>(f32, PartialShape::dynamic());
|
||||
auto b_ru = make_shared<v0::Parameter>(f32, PartialShape::dynamic());
|
||||
auto b_c = make_shared<v0::Parameter>(f32, PartialShape::dynamic());
|
||||
|
||||
auto gru_block_cell = make_shared<GRUBlockCell>(x, h_prev, w_ru, w_c, b_ru, b_c);
|
||||
|
||||
return make_shared<Model>(OutputVector{gru_block_cell->output(3)},
|
||||
ParameterVector{x, h_prev, w_ru, w_c, b_ru, b_c});
|
||||
}
|
||||
|
||||
shared_ptr<Model> gen_model_with_two_outputs(Dimension batch_size, int64_t hidden_size, Dimension input_size) {
|
||||
auto x = make_shared<v0::Parameter>(f32, PartialShape{batch_size, input_size});
|
||||
auto h_prev = make_shared<v0::Parameter>(f32, PartialShape{batch_size, hidden_size});
|
||||
auto w_ru = make_shared<v0::Parameter>(f32, PartialShape::dynamic());
|
||||
auto w_c = make_shared<v0::Parameter>(f32, PartialShape::dynamic());
|
||||
auto b_ru = make_shared<v0::Parameter>(f32, PartialShape::dynamic());
|
||||
auto b_c = make_shared<v0::Parameter>(f32, PartialShape::dynamic());
|
||||
|
||||
auto gru_block_cell = make_shared<GRUBlockCell>(x, h_prev, w_ru, w_c, b_ru, b_c);
|
||||
|
||||
return make_shared<Model>(OutputVector{gru_block_cell->output(0), gru_block_cell->output(3)},
|
||||
ParameterVector{x, h_prev, w_ru, w_c, b_ru, b_c});
|
||||
}
|
||||
|
||||
shared_ptr<Model> gen_model_ref(Dimension m_batch_size, int64_t m_hidden_size, Dimension m_input_size) {
|
||||
auto x = make_shared<v0::Parameter>(f32, PartialShape{m_batch_size, m_input_size});
|
||||
auto h_prev = make_shared<v0::Parameter>(f32, PartialShape{m_batch_size, m_hidden_size});
|
||||
auto w_ru = make_shared<v0::Parameter>(f32, PartialShape::dynamic());
|
||||
auto w_c = make_shared<v0::Parameter>(f32, PartialShape::dynamic());
|
||||
auto b_ru = make_shared<v0::Parameter>(f32, PartialShape::dynamic());
|
||||
auto b_c = make_shared<v0::Parameter>(f32, PartialShape::dynamic());
|
||||
|
||||
// retrive input_size and hidden_size
|
||||
auto x_shape = make_shared<v3::ShapeOf>(x, element::i64);
|
||||
auto ss_start = make_shared<v0::Constant>(element::i64, Shape{1}, 1);
|
||||
auto ss_end = make_shared<v0::Constant>(element::i64, Shape{1}, 2);
|
||||
auto ss_step = make_shared<v0::Constant>(element::i64, Shape{1}, 1);
|
||||
auto input_size = make_shared<v8::Slice>(x_shape, ss_start, ss_end, ss_step);
|
||||
auto h_prev_shape = make_shared<v3::ShapeOf>(h_prev, element::i64);
|
||||
auto hidden_size = make_shared<v8::Slice>(h_prev_shape, ss_start, ss_end, ss_step);
|
||||
|
||||
// prepare weights input
|
||||
// TensorFlow provides weights in a format w_ru and w_c, where
|
||||
// z or u - update, r - reset, c or h - hidden (connection)
|
||||
// OpenVINO GRUCell accepts weights in a format w_zrh (or w_urс)
|
||||
// 1. split w_ru into w_r and w_u
|
||||
auto split_w_ru = make_shared<v1::Split>(w_ru, make_shared<v0::Constant>(element::i64, Shape{}, 1), 2);
|
||||
// 2. concatenate different parts of weights into w_zrh (or w_urс)
|
||||
auto w_urc = make_shared<v0::Concat>(OutputVector{split_w_ru->output(1), split_w_ru->output(0), w_c}, 1);
|
||||
|
||||
// prepare bias in the same way
|
||||
auto split_b_ru = make_shared<v1::Split>(b_ru, make_shared<v0::Constant>(element::i64, Shape{}, 0), 2);
|
||||
auto b_urc = make_shared<v0::Concat>(OutputVector{split_b_ru->output(1), split_b_ru->output(0), b_c}, 0);
|
||||
|
||||
// transpose weights
|
||||
// the current shape - [input_size + hidden_size, 3 * hidden_size]
|
||||
// we need the shape [3 * hidden_size, input_size + hidden_size]
|
||||
// in order to split WR into W and R
|
||||
auto transpose_order = make_shared<v0::Constant>(element::i64, Shape{2}, std::vector<int64_t>{1, 0});
|
||||
auto w_urc_transpose = make_shared<v1::Transpose>(w_urc, transpose_order);
|
||||
|
||||
// split combined weights WR into W and R
|
||||
auto split_axis = make_shared<v0::Constant>(element::i64, Shape{}, 1);
|
||||
auto split_nums = make_shared<v0::Concat>(OutputVector{input_size, hidden_size}, 0);
|
||||
auto split_WR = make_shared<v1::VariadicSplit>(w_urc_transpose, split_axis, split_nums);
|
||||
|
||||
auto gru_cell = make_shared<v3::GRUCell>(x, h_prev, split_WR->output(0), split_WR->output(1), b_urc, m_hidden_size);
|
||||
|
||||
return make_shared<Model>(OutputVector{gru_cell->output(0)}, ParameterVector{x, h_prev, w_ru, w_c, b_ru, b_c});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_F(FrontEndConversionWithReferenceTestsF, GRUBlockCellReplacerOneOutput) {
|
||||
{
|
||||
model = gen_model(2, 10, 120);
|
||||
manager.register_pass<GRUBlockCellReplacer>();
|
||||
}
|
||||
{ model_ref = gen_model_ref(2, 10, 120); }
|
||||
}
|
||||
|
||||
TEST_F(FrontEndConversionWithReferenceTestsF, GRUBlockCellReplacerTwoOutputs) {
|
||||
{
|
||||
model = gen_model_with_two_outputs(2, 10, 120);
|
||||
manager.register_pass<GRUBlockCellReplacer>();
|
||||
}
|
||||
{
|
||||
// transformation is not applied due to presence of the first output
|
||||
model_ref = gen_model_with_two_outputs(2, 10, 120);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,44 +3,43 @@
|
|||
|
||||
import numpy as np
|
||||
import pytest
|
||||
import tensorflow as tf
|
||||
from common.tf_layer_test_class import CommonTFLayerTest
|
||||
|
||||
rng = np.random.default_rng(2024)
|
||||
|
||||
class TestTFGRUBlockCell(CommonTFLayerTest):
|
||||
def _prepare_input(self, inputs_dict):
|
||||
for input in inputs_dict.keys():
|
||||
inputs_dict[input] = np.zeros(inputs_dict[input]).astype(np.float32)
|
||||
return inputs_dict
|
||||
|
||||
def create_tf_gru_block_cell(self, batch_size, input_size, hidden_size):
|
||||
import tensorflow as tf
|
||||
class TestGRUBlockCell(CommonTFLayerTest):
|
||||
def _prepare_input(self, inputs_info):
|
||||
assert 'x:0' in inputs_info, "Test error: inputs_info must contain `x`"
|
||||
x_shape = inputs_info['x:0']
|
||||
inputs_data = {}
|
||||
inputs_data['x:0'] = rng.uniform(0, 1, x_shape).astype(np.float32)
|
||||
return inputs_data
|
||||
|
||||
def create_gru_block_cell(self, batch_size, input_size, hidden_size):
|
||||
tf.compat.v1.reset_default_graph()
|
||||
|
||||
# Create the graph and model
|
||||
with tf.compat.v1.Session() as sess:
|
||||
tf_x_shape = [batch_size, input_size]
|
||||
tf_h_prev_shape = [batch_size, hidden_size]
|
||||
tf_w_ru_shape = [input_size + hidden_size, hidden_size * 2]
|
||||
tr_w_c_shape = [input_size + hidden_size, hidden_size]
|
||||
tf_b_ru_shape = [hidden_size * 2]
|
||||
tf_b_c_shape = [hidden_size]
|
||||
x_shape = [batch_size, input_size]
|
||||
h_prev_shape = [batch_size, hidden_size]
|
||||
w_ru_shape = [input_size + hidden_size, hidden_size * 2]
|
||||
w_c_shape = [input_size + hidden_size, hidden_size]
|
||||
b_ru_shape = [hidden_size * 2]
|
||||
b_c_shape = [hidden_size]
|
||||
|
||||
random_generator = np.random.default_rng(2022)
|
||||
x = tf.compat.v1.placeholder(np.float32, x_shape, 'x')
|
||||
|
||||
x = random_generator.uniform(0, 1, tf_x_shape).astype(np.float32)
|
||||
h_prev = random_generator.uniform(0, 1, tf_h_prev_shape).astype(np.float32)
|
||||
# generate weights
|
||||
h_prev = rng.uniform(0, 1, h_prev_shape).astype(np.float32)
|
||||
w_ru = rng.uniform(0, 1, w_ru_shape).astype(np.float32)
|
||||
w_c = rng.uniform(0, 1, w_c_shape).astype(np.float32)
|
||||
b_ru = rng.uniform(0, 1, b_ru_shape).astype(np.float32)
|
||||
b_c = rng.uniform(0, 1, b_c_shape).astype(np.float32)
|
||||
|
||||
w_ru = random_generator.uniform(0, 1, tf_w_ru_shape).astype(np.float32)
|
||||
w_c = random_generator.uniform(0, 1, tr_w_c_shape).astype(np.float32)
|
||||
|
||||
b_ru = random_generator.uniform(0, 1, tf_b_ru_shape).astype(np.float32)
|
||||
b_c = random_generator.uniform(0, 1, tf_b_c_shape).astype(np.float32)
|
||||
|
||||
r, u, c, h = tf.raw_ops.GRUBlockCell(x=x, h_prev=h_prev, w_ru=w_ru, w_c=w_c, b_ru=b_ru, b_c=b_c, name="TFGRUBlockCell")
|
||||
|
||||
# Dummy Add layer to prevent from Const network, and compare only "h" output
|
||||
input_zero = tf.compat.v1.placeholder(tf.as_dtype(np.float32), tf_h_prev_shape, 'Input')
|
||||
add = tf.add(h, input_zero)
|
||||
_, _, _, h = tf.raw_ops.GRUBlockCell(x=x, h_prev=h_prev, w_ru=w_ru, w_c=w_c, b_ru=b_ru, b_c=b_c)
|
||||
tf.identity(h, name='gru_block_cell')
|
||||
|
||||
tf.compat.v1.global_variables_initializer()
|
||||
tf_net = sess.graph_def
|
||||
|
|
@ -48,22 +47,16 @@ class TestTFGRUBlockCell(CommonTFLayerTest):
|
|||
ref_net = None
|
||||
return tf_net, ref_net
|
||||
|
||||
test_data = [
|
||||
dict(batch_size=1, input_size=6, hidden_size=6),
|
||||
dict(batch_size=1, input_size=10, hidden_size=15),
|
||||
dict(batch_size=1, input_size=15, hidden_size=10),
|
||||
dict(batch_size=2, input_size=6, hidden_size=6),
|
||||
dict(batch_size=2, input_size=12, hidden_size=6),
|
||||
pytest.param(dict(batch_size=2, input_size=6, hidden_size=12), marks=pytest.mark.precommit),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("params", test_data)
|
||||
@pytest.mark.parametrize('batch_size', [1, 2])
|
||||
@pytest.mark.parametrize('input_size', [1, 5, 6, 12])
|
||||
@pytest.mark.parametrize('hidden_size', [1, 6, 10, 12])
|
||||
@pytest.mark.nightly
|
||||
@pytest.mark.precommit
|
||||
def test_tf_gru_block_cell(self, params, ie_device, precision, ir_version, temp_dir,
|
||||
use_legacy_frontend):
|
||||
def test_gru_block_cell(self, batch_size, input_size, hidden_size,
|
||||
ie_device, precision, ir_version, temp_dir,
|
||||
use_legacy_frontend):
|
||||
if ie_device == 'GPU':
|
||||
pytest.skip("Skip TF GRUBlockCell test on GPU")
|
||||
self._test(*self.create_tf_gru_block_cell(**params),
|
||||
self._test(*self.create_gru_block_cell(batch_size, input_size, hidden_size),
|
||||
ie_device, precision, temp_dir=temp_dir, ir_version=ir_version,
|
||||
use_legacy_frontend=use_legacy_frontend, custom_eps=1e-3, **params)
|
||||
use_legacy_frontend=use_legacy_frontend, custom_eps=1e-3)
|
||||
|
|
|
|||
Loading…
Reference in New Issue