From c9ea173202c054f1ce7ae3c47fd310f08095adbc Mon Sep 17 00:00:00 2001 From: Roman Kazantsev Date: Wed, 8 May 2024 12:15:17 +0400 Subject: [PATCH] [MO][TF FE] Handle constant with undefined value (#17311) (#24382) **Details:** Since TF 2.10 the native model freezing can produce constants with undefined value, i.e. tensor shape can be any and value is []. In this case the tensor just fills up with the default value (0 - for numerics, "" - for strings) **Ticket:** 140458 Porting of https://github.com/openvinotoolkit/openvino/pull/17311 Signed-off-by: Kazantsev, Roman --- .../tools/mo/front/tf/extractors/utils.py | 19 +++++- .../model_add_with_undefined_constant.pbtxt | 58 +++++++++++++++++++ .../model_add_with_undefined_constant.py | 13 +++++ .../model_mul_with_undefined_constant.pbtxt | 52 +++++++++++++++++ .../model_mul_with_undefined_constant.py | 13 +++++ 5 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 tools/mo/unit_tests/moc_tf_fe/test_models/model_add_with_undefined_constant.pbtxt create mode 100644 tools/mo/unit_tests/moc_tf_fe/test_models/model_add_with_undefined_constant.py create mode 100644 tools/mo/unit_tests/moc_tf_fe/test_models/model_mul_with_undefined_constant.pbtxt create mode 100644 tools/mo/unit_tests/moc_tf_fe/test_models/model_mul_with_undefined_constant.py diff --git a/tools/mo/openvino/tools/mo/front/tf/extractors/utils.py b/tools/mo/openvino/tools/mo/front/tf/extractors/utils.py index e97b43e4d3e..0e9dc18cc18 100644 --- a/tools/mo/openvino/tools/mo/front/tf/extractors/utils.py +++ b/tools/mo/openvino/tools/mo/front/tf/extractors/utils.py @@ -82,7 +82,7 @@ def tf_tensor_content(tf_dtype, shape, pb_tensor): value_length = len(value) except TypeError: # case, when value is a scalar - value_length = 0 + return value if value_length == 1: # return scalar if shape is [] otherwise broadcast according to shape try: @@ -91,18 +91,33 @@ def tf_tensor_content(tf_dtype, shape, pb_tensor): log.error(decode_err_msg, extra={'is_warning': True}) return mo_array(value[0]) else: + if len(shape) == 0 and value_length == 0: + # Since TF 2.10 the model freezing can produce constants with non-empty tensor + # but with undefined value [] + # in this case, the tensor is filled with the default value + # that is 0 for numeric types and "" for string + default_value = 0 if type_helper[0] != str else "" + value = mo_array(default_value, dtype=type_helper[0]) # no shape, return value as is return value if len(value) != shape.prod(): log.warning("Shape and content size of tensor don't match, shape: {} content size: {}". format(shape, len(value))) + + if len(value) == 0: + # Since TF 2.10 the model freezing can produce constants with non-empty tensor but with undefined value [] + # In this case, the tensor is filled with the default value that is 0 for numeric types and "" for string + default_value = 0 if type_helper[0] != str else "" + value_flatten = mo_array([default_value], dtype=type_helper[0]) + else: + value_flatten = value.flatten() + # broadcast semantics according to TensorFlow v1.5 documentation: # The argument value can be a constant value, or a list of values of type dtype. If value is a list, # then the length of the list must be less than or equal to the number of elements implied by the shape # argument (if specified). In the case where the list length is less than the number of elements specified # by shape, the last element in the list will be used to fill the remaining entries. - value_flatten = value.flatten() add_value = value_flatten[-1] add_length = shape.prod() - len(value_flatten) value = np.concatenate([value_flatten, np.full([add_length], add_value)]) diff --git a/tools/mo/unit_tests/moc_tf_fe/test_models/model_add_with_undefined_constant.pbtxt b/tools/mo/unit_tests/moc_tf_fe/test_models/model_add_with_undefined_constant.pbtxt new file mode 100644 index 00000000000..37dd135ccfd --- /dev/null +++ b/tools/mo/unit_tests/moc_tf_fe/test_models/model_add_with_undefined_constant.pbtxt @@ -0,0 +1,58 @@ +node { + name: "x" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_FLOAT + } + } + attr { + key: "shape" + value { + shape { + dim { + size: 2 + } + dim { + size: 3 + } + } + } + } +} +node { + name: "Const" + op: "Const" + attr { + key: "dtype" + value { + type: DT_FLOAT + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_FLOAT + tensor_shape { + dim { + size: 3 + } + } + } + } + } +} +node { + name: "add" + op: "AddV2" + input: "x" + input: "Const" + attr { + key: "T" + value { + type: DT_FLOAT + } + } +} diff --git a/tools/mo/unit_tests/moc_tf_fe/test_models/model_add_with_undefined_constant.py b/tools/mo/unit_tests/moc_tf_fe/test_models/model_add_with_undefined_constant.py new file mode 100644 index 00000000000..04de808dbff --- /dev/null +++ b/tools/mo/unit_tests/moc_tf_fe/test_models/model_add_with_undefined_constant.py @@ -0,0 +1,13 @@ +# Copyright (C) 2018-2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +import tensorflow.compat.v1 as tf + +tf.reset_default_graph() +# Create the graph and model +with tf.Session() as sess: + x = tf.placeholder(tf.float32, [2, 3], 'x') + const = tf.constant(value=[], dtype=tf.float32, shape=[3], name='Const') + tf.add(x, const, name="add") + tf.global_variables_initializer() + tf.io.write_graph(sess.graph, './', 'model_add_with_undefined_constant.pbtxt', as_text=True) diff --git a/tools/mo/unit_tests/moc_tf_fe/test_models/model_mul_with_undefined_constant.pbtxt b/tools/mo/unit_tests/moc_tf_fe/test_models/model_mul_with_undefined_constant.pbtxt new file mode 100644 index 00000000000..e4a6470f3d2 --- /dev/null +++ b/tools/mo/unit_tests/moc_tf_fe/test_models/model_mul_with_undefined_constant.pbtxt @@ -0,0 +1,52 @@ +node { + name: "x" + op: "Placeholder" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "shape" + value { + shape { + dim { + size: 2 + } + } + } + } +} +node { + name: "Const" + op: "Const" + attr { + key: "dtype" + value { + type: DT_INT32 + } + } + attr { + key: "value" + value { + tensor { + dtype: DT_INT32 + tensor_shape { + } + } + } + } +} +node { + name: "mul" + op: "Mul" + input: "x" + input: "Const" + attr { + key: "T" + value { + type: DT_INT32 + } + } +} diff --git a/tools/mo/unit_tests/moc_tf_fe/test_models/model_mul_with_undefined_constant.py b/tools/mo/unit_tests/moc_tf_fe/test_models/model_mul_with_undefined_constant.py new file mode 100644 index 00000000000..8c0c6dd814d --- /dev/null +++ b/tools/mo/unit_tests/moc_tf_fe/test_models/model_mul_with_undefined_constant.py @@ -0,0 +1,13 @@ +# Copyright (C) 2018-2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +import tensorflow.compat.v1 as tf + +tf.reset_default_graph() +# Create the graph and model +with tf.Session() as sess: + x = tf.placeholder(tf.int32, [2], 'x') + const = tf.constant(value=[], dtype=tf.int32, shape=[], name='Const') + tf.multiply(x, const, name="mul") + tf.global_variables_initializer() + tf.io.write_graph(sess.graph, './', 'model_mul_with_undefined_constant.pbtxt', as_text=True)