From db81e50a0291c2095c500935506b74c582ade443 Mon Sep 17 00:00:00 2001 From: Roman Kazantsev Date: Fri, 25 Nov 2022 09:22:42 +0300 Subject: [PATCH] [TF FE] Support unknown and dynamic rank Placeholder shape (#14211) * [TF FE] Support unknown and undefined Placeholder shape Signed-off-by: Kazantsev, Roman * Fix mistake in the test Signed-off-by: Kazantsev, Roman --- .../tensorflow/src/decoder_proto.cpp | 5 +- src/frontends/tensorflow/src/input_model.cpp | 15 +++- .../tests/convert_tricky_models.cpp | 40 ++++++++++ .../models_pbtxt/undefined_input_shape.pbtxt | 75 +++++++++++++++++++ .../models_pbtxt/undefined_input_shape.py | 17 +++++ 5 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 src/frontends/tensorflow/tests/convert_tricky_models.cpp create mode 100644 src/frontends/tensorflow/tests/test_models/models_pbtxt/undefined_input_shape.pbtxt create mode 100644 src/frontends/tensorflow/tests/test_models/models_pbtxt/undefined_input_shape.py diff --git a/src/frontends/tensorflow/src/decoder_proto.cpp b/src/frontends/tensorflow/src/decoder_proto.cpp index e23f9fde722..e08110ad2ef 100644 --- a/src/frontends/tensorflow/src/decoder_proto.cpp +++ b/src/frontends/tensorflow/src/decoder_proto.cpp @@ -101,8 +101,11 @@ ov::Any DecoderProto::get_attribute(const std::string& name) const { case ::tensorflow::AttrValue::ValueCase::kI: return attrs[0].i(); case ::tensorflow::AttrValue::ValueCase::kShape: { - std::vector dims; const auto& tf_shape = attrs[0].shape(); + if (tf_shape.unknown_rank()) { + return ov::PartialShape::dynamic(); + } + std::vector dims; for (int i = 0; i < tf_shape.dim_size(); i++) { dims.emplace_back(tf_shape.dim(i).size()); } diff --git a/src/frontends/tensorflow/src/input_model.cpp b/src/frontends/tensorflow/src/input_model.cpp index 5b05a97b065..5471e37363a 100644 --- a/src/frontends/tensorflow/src/input_model.cpp +++ b/src/frontends/tensorflow/src/input_model.cpp @@ -115,8 +115,19 @@ void InputModel::InputModelTFImpl::loadPlaces() { m_op_places.push_back(op_place); m_op_places_map[op_name] = op_place; if (op_type == "Placeholder") { - auto pshape = node_decoder->get_attribute("shape").as(); - auto type = node_decoder->get_attribute("dtype").as(); + auto pshape = ov::PartialShape::dynamic(); + auto shape_any = node_decoder->get_attribute("shape"); + if (shape_any.is()) { + // sometimes shape attribute can be absent in the graph + // so we need to check if Any object is initialized first + pshape = shape_any.as(); + } + auto dtype_any = node_decoder->get_attribute("dtype"); + auto placeholder_name = node_decoder->get_op_name(); + FRONT_END_GENERAL_CHECK( + dtype_any.is(), + "Incorrect input model: Placeholder node " + placeholder_name + " has unspecified type."); + auto type = dtype_any.as(); std::vector names = {op_name}; auto tensor_place = std::make_shared(m_input_model, pshape, type, names); m_tensor_places[op_name] = tensor_place; diff --git a/src/frontends/tensorflow/tests/convert_tricky_models.cpp b/src/frontends/tensorflow/tests/convert_tricky_models.cpp new file mode 100644 index 00000000000..03e7ed89d32 --- /dev/null +++ b/src/frontends/tensorflow/tests/convert_tricky_models.cpp @@ -0,0 +1,40 @@ +// Copyright (C) 2018-2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include +#include + +#include "common_test_utils/ngraph_test_utils.hpp" +#include "tf_utils.hpp" +#include "utils.hpp" + +using namespace std; +using namespace ngraph; +using namespace ov::frontend; + +TEST(FrontEndConvertModelTest, test_undefined_input_shape) { + FrontEndManager fem; + FrontEnd::Ptr frontEnd; + InputModel::Ptr inputModel; + ASSERT_NO_THROW(frontEnd = fem.load_by_framework(TF_FE)); + ASSERT_NE(frontEnd, nullptr); + auto model_filename = FrontEndTestUtils::make_model_path(string(TEST_TENSORFLOW_MODELS_DIRNAME) + + string("undefined_input_shape/undefined_input_shape.pb")); + ASSERT_NO_THROW(inputModel = frontEnd->load(model_filename)); + ASSERT_NE(inputModel, nullptr); + shared_ptr function; + ASSERT_NO_THROW(function = frontEnd->convert(inputModel)); + ASSERT_NE(function, nullptr); + + for (auto& node : function->get_ordered_ops()) { + if (node->get_friendly_name() == "x") { + ASSERT_TRUE(node->get_output_partial_shape(0).same_scheme(ov::PartialShape::dynamic())); + } else if (node->get_friendly_name() == "y") { + ASSERT_TRUE(node->get_output_partial_shape(0).same_scheme(ov::PartialShape{2, 3})); + } else if (node->get_friendly_name() == "z") { + ASSERT_TRUE(node->get_output_partial_shape(0).same_scheme(ov::PartialShape::dynamic())); + } + } +} diff --git a/src/frontends/tensorflow/tests/test_models/models_pbtxt/undefined_input_shape.pbtxt b/src/frontends/tensorflow/tests/test_models/models_pbtxt/undefined_input_shape.pbtxt new file mode 100644 index 00000000000..5e968b13d92 --- /dev/null +++ b/src/frontends/tensorflow/tests/test_models/models_pbtxt/undefined_input_shape.pbtxt @@ -0,0 +1,75 @@ +node { + name: "x" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_FLOAT + } + } + attr { + key: "shape" + value { + shape { + unknown_rank: true + } + } + } +} +node { + name: "y" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_FLOAT + } + } + attr { + key: "shape" + value { + shape { + dim { + size: 2 + } + dim { + size: 3 + } + } + } + } +} +node { + name: "z" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_FLOAT + } + } +} +node { + name: "add" + op: "AddV2" + input: "x" + input: "y" + attr { + key: "T" + value { + type: DT_FLOAT + } + } +} +node { + name: "Mul" + op: "Mul" + input: "add" + input: "z" + attr { + key: "T" + value { + type: DT_FLOAT + } + } +} diff --git a/src/frontends/tensorflow/tests/test_models/models_pbtxt/undefined_input_shape.py b/src/frontends/tensorflow/tests/test_models/models_pbtxt/undefined_input_shape.py new file mode 100644 index 00000000000..8b0d3896f50 --- /dev/null +++ b/src/frontends/tensorflow/tests/test_models/models_pbtxt/undefined_input_shape.py @@ -0,0 +1,17 @@ +# Copyright (C) 2018-2022 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + + +import tensorflow.compat.v1 as tf + +tf.reset_default_graph() + +with tf.Session() as sess: + x = tf.placeholder(dtype=tf.float32, shape=None, name='x') + y = tf.placeholder(dtype=tf.float32, shape=[2, 3], name='y') + z = tf.placeholder(dtype=tf.float32, shape=None, name='z') + add = tf.add(x, y, name="add") + tf.multiply(add, z) + + tf.global_variables_initializer() + tf.io.write_graph(sess.graph, '.', 'undefined_input_shape.pbtxt', as_text=True)