diff --git a/src/frontends/tensorflow/src/input_model.cpp b/src/frontends/tensorflow/src/input_model.cpp index 459ce69b546..87ebc3e605b 100644 --- a/src/frontends/tensorflow/src/input_model.cpp +++ b/src/frontends/tensorflow/src/input_model.cpp @@ -295,8 +295,9 @@ void InputModel::InputModelTFImpl::load_places() { auto output_place = std::make_shared(m_input_model, ov::PartialShape({}), ov::element::dynamic, - std::vector{output_name}); - m_tensor_places[output_name] = output_place; + std::vector{output_name + ":0"}); + // TODO: Create tensor places for each ouput port, ticket-129464 + m_tensor_places[output_name + ":0"] = output_place; m_outputs.push_back(output_place); } return; diff --git a/src/frontends/tensorflow/src/translate_session.cpp b/src/frontends/tensorflow/src/translate_session.cpp index cc21022c61a..65f9372737e 100644 --- a/src/frontends/tensorflow/src/translate_session.cpp +++ b/src/frontends/tensorflow/src/translate_session.cpp @@ -639,12 +639,11 @@ void TranslateSession::translate_graph(const ov::frontend::InputModel::Ptr& inpu } } else if (port_type == "out") { const auto& node_outputs = indexed_from_named(ng_op_map[operation_name]); - FRONT_END_GENERAL_CHECK(node_outputs.size() > port_index, - "Output port with index " + std::to_string(port_index) + " of " + - operation_name + "node specified as custom output does not exist"); - auto result_node = std::make_shared(node_outputs[port_index]); - result_node->set_friendly_name(model_output_name); - results.push_back(result_node); + if (node_outputs.size() > port_index) { + auto result_node = std::make_shared(node_outputs[port_index]); + result_node->set_friendly_name(model_output_name); + results.push_back(result_node); + } } else if (port_type == "in") { // TODO: avoid this traversing by having a map for OpPlace objects, for example std::shared_ptr operation_place = nullptr; diff --git a/src/frontends/tensorflow/tests/convert_saved_model.cpp b/src/frontends/tensorflow/tests/convert_saved_model.cpp index 2c9a8a6362d..9a41c19167c 100644 --- a/src/frontends/tensorflow/tests/convert_saved_model.cpp +++ b/src/frontends/tensorflow/tests/convert_saved_model.cpp @@ -178,7 +178,7 @@ TEST_F(FrontEndConversionWithReferenceTestsF, SavedModelWithNumericalNames) { auto z = make_shared(element::f32, Shape{1}); z->output(0).set_names({"2"}); auto add = make_shared(x, y); - add->output(0).set_names({"3", "3:0"}); + add->output(0).set_names({"3:0"}); auto sub = make_shared(add, z); sub->output(0).set_names({"4"}); auto result = make_shared(sub); diff --git a/src/frontends/tensorflow_common/src/op/identity.cpp b/src/frontends/tensorflow_common/src/op/identity.cpp index cfffaafc4f1..3d66e5a5c02 100644 --- a/src/frontends/tensorflow_common/src/op/identity.cpp +++ b/src/frontends/tensorflow_common/src/op/identity.cpp @@ -29,7 +29,6 @@ OutputVector translate_identity_op(const NodeContext& node) { // set only tensor names // no need to change node name since Identity node is skipped - set_out_name(node.get_name(), input); set_out_name(node.get_name() + ":" + "0", input); return {input}; } diff --git a/src/frontends/tensorflow_common/src/utils.cpp b/src/frontends/tensorflow_common/src/utils.cpp index cd5fafa3291..56a7fbedda0 100644 --- a/src/frontends/tensorflow_common/src/utils.cpp +++ b/src/frontends/tensorflow_common/src/utils.cpp @@ -14,6 +14,7 @@ #include "openvino/op/divide.hpp" #include "openvino/op/maximum.hpp" #include "openvino/op/pad.hpp" +#include "openvino/op/parameter.hpp" #include "openvino/op/reshape.hpp" #include "openvino/op/shape_of.hpp" #include "openvino/op/slice.hpp" @@ -32,7 +33,8 @@ namespace tensorflow { void set_node_name(const string& node_name, const shared_ptr& node) { const auto& outputs = node->outputs(); node->set_friendly_name(node_name); - if (outputs.size() == 1) { + // TODO: Remove this and set single tensor names for model inputs, ticket - 129457 + if (outputs.size() == 1 && as_type_ptr(node)) { set_out_name(node_name, outputs[0]); } for (size_t idx = 0; idx < outputs.size(); ++idx) { diff --git a/tests/layer_tests/common/tf_layer_test_class.py b/tests/layer_tests/common/tf_layer_test_class.py index ab3289d8152..85e703dc95c 100644 --- a/tests/layer_tests/common/tf_layer_test_class.py +++ b/tests/layer_tests/common/tf_layer_test_class.py @@ -32,6 +32,9 @@ class CommonTFLayerTest(CommonLayerTest): graph_summary = summarize_graph(model_path=model_path) outputs_list = graph_summary["outputs"] + fw_outputs_list = [out + ":0" for out in outputs_list] + if self.use_new_frontend: + outputs_list = fw_outputs_list tf.compat.v1.reset_default_graph() @@ -42,7 +45,7 @@ class CommonTFLayerTest(CommonLayerTest): sess.graph.as_default() tf.compat.v1.import_graph_def(graph_def, name='') - tf_res = sess.run([out + ":0" for out in outputs_list], inputs_dict) + tf_res = sess.run(fw_outputs_list, inputs_dict) result = dict() for i, output in enumerate(outputs_list): diff --git a/tests/layer_tests/ovc_python_api_tests/test_complex_params.py b/tests/layer_tests/ovc_python_api_tests/test_complex_params.py index fab06da4d3a..ea1747b13c2 100644 --- a/tests/layer_tests/ovc_python_api_tests/test_complex_params.py +++ b/tests/layer_tests/ovc_python_api_tests/test_complex_params.py @@ -71,9 +71,9 @@ class TestComplexParams(CommonMOConvertTest): return save_to_pb(tf_net, tmp_dir) test_data = [ - {'params_test': {'output': ["Sigmoid_0", "Sigmoid_2"]}, + {'params_test': {'output': ["Sigmoid_0:0", "Sigmoid_2:0"]}, 'params_ref': {'output': "Sigmoid_0,Sigmoid_2"}}, - {'params_test': {'output': ["Sigmoid_0"]}, + {'params_test': {'output': ["Sigmoid_0:0"]}, 'params_ref': {'output': "Sigmoid_0"}}, {'params_test': {'input': [PartialShape([2, 3, 4]), [2, 3, 4], [Dimension(2), Dimension(3), Dimension(4)]]}, 'params_ref': {'input_shape': "[2,3,4],[2,3,4],[2,3,4]", 'input': 'Input1,Input2,Input3'}}, diff --git a/tests/layer_tests/ovc_python_api_tests/test_tf.py b/tests/layer_tests/ovc_python_api_tests/test_tf.py index 179de425284..5e3b0e5f5b2 100644 --- a/tests/layer_tests/ovc_python_api_tests/test_tf.py +++ b/tests/layer_tests/ovc_python_api_tests/test_tf.py @@ -1,16 +1,20 @@ # Copyright (C) 2018-2023 Intel Corporation # SPDX-License-Identifier: Apache-2.0 - +import os +import tempfile import unittest +from pathlib import Path import numpy as np import openvino.runtime as ov import pytest +import tensorflow as tf from openvino.runtime import PartialShape, Model, Dimension -from common.mo_convert_test_class import CommonMOConvertTest +from common import constants from common.layer_test_class import CommonLayerTest -import tensorflow as tf +from common.mo_convert_test_class import CommonMOConvertTest +from common.tf_layer_test_class import save_to_pb def create_tf_graph_def(tmp_dir): @@ -1068,4 +1072,136 @@ class TestTFConversionParams(CommonMOConvertTest): ref_model = params['ref_model'] test_params.update({'input_model': fw_model}) - self._test_by_ref_graph(temp_dir, test_params, ref_model, compare_tensor_names=False) \ No newline at end of file + self._test_by_ref_graph(temp_dir, test_params, ref_model, compare_tensor_names=False) + + +class TestOutputTensorName(unittest.TestCase): + @staticmethod + def create_keras_model_with_named_output(): + tf.keras.backend.clear_session() + tf.compat.v1.reset_default_graph() + + input_names = ["Input1", "Input2"] + input_shape = [1, 2, 3] + + x1 = tf.keras.Input(shape=input_shape, name=input_names[0]) + x2 = tf.keras.Input(shape=input_shape, name=input_names[1]) + y = tf.nn.sigmoid(tf.nn.relu(x1 + x2)) + keras_net = tf.keras.Model(inputs=[x1, x2], outputs=[{"output": y}]) + keras_net.output_names[0] = "output" + + return keras_net + + + @pytest.mark.nightly + @pytest.mark.precommit + def test_tf1_from_file_single_tensor_name(self): + tf.keras.backend.clear_session() + tf.compat.v1.reset_default_graph() + + Path(constants.out_path).mkdir(parents=True, exist_ok=True) + tmp_dir = tempfile.TemporaryDirectory(dir=constants.out_path).name + + from openvino import convert_model + + model, _, _ = create_tf_graph_def(None) + path = save_to_pb(model, tmp_dir) + + ov_model = convert_model(path) + out_tensors = ov_model.outputs[0].get_names() + + assert len(out_tensors) == 1 + assert list(out_tensors)[0] == "Sigmoid:0" + + out_tensor_name = list(out_tensors)[0] + + ov_model = convert_model(path, output=out_tensor_name) + out_tensors = ov_model.outputs[0].get_names() + + assert len(out_tensors) == 1 + assert list(out_tensors)[0] == "Sigmoid:0" + + @pytest.mark.nightly + @pytest.mark.precommit + def test_tf1_from_memory_single_tensor_name(self): + tf.keras.backend.clear_session() + tf.compat.v1.reset_default_graph() + from openvino.tools.ovc import convert_model + + model, _, _ = create_tf_graph_def(None) + + ov_model = convert_model(model) + out_tensors = ov_model.outputs[0].get_names() + + assert len(out_tensors) == 1 + assert list(out_tensors)[0] == "Sigmoid:0" + + out_tensor_name = list(out_tensors)[0] + + ov_model = convert_model(model, output=out_tensor_name) + out_tensors = ov_model.outputs[0].get_names() + + assert len(out_tensors) == 1 + assert list(out_tensors)[0] == "Sigmoid:0" + + + @pytest.mark.nightly + @pytest.mark.precommit + def test_tf2_from_file_single_tensor_name(self): + tf.keras.backend.clear_session() + tf.compat.v1.reset_default_graph() + Path(constants.out_path).mkdir(parents=True, exist_ok=True) + tmp_dir = tempfile.TemporaryDirectory(dir=constants.out_path).name + model_path = tmp_dir + os.sep + "model" + + from openvino import convert_model + + model = TestOutputTensorName.create_keras_model_with_named_output() + tf.saved_model.save(model, model_path) + + ov_model = convert_model(model_path) + for output in ov_model.outputs: + out_tensors = output.get_names() + + assert len(out_tensors) == 1 + out_tensor = list(out_tensors)[0] + assert out_tensor == "output" + + @pytest.mark.nightly + @pytest.mark.precommit + def test_tf2_from_memory_single_tensor_name(self): + tf.keras.backend.clear_session() + tf.compat.v1.reset_default_graph() + from openvino.tools.ovc import convert_model + + model = TestOutputTensorName.create_keras_model_with_named_output() + + ov_model = convert_model(model) + for output in ov_model.outputs: + out_tensors = output.get_names() + + assert len(out_tensors) == 1 + out_tensor = list(out_tensors)[0] + assert out_tensor == "output" + + @pytest.mark.nightly + @pytest.mark.precommit + def test_tf1_output_with_identity(self): + tf.keras.backend.clear_session() + tf.compat.v1.reset_default_graph() + from openvino.tools.ovc import convert_model + + with tf.compat.v1.Session() as sess: + x = tf.compat.v1.placeholder(tf.float32, [2], 'x') + y = tf.compat.v1.placeholder(tf.float32, [2], 'y') + add = tf.add(x, y, name="add") + result1 = tf.identity(add, name="result1") + result2 = tf.identity(add, name="result2") + + tf.compat.v1.global_variables_initializer() + model = sess.graph_def + + ov_model = convert_model(model) + + assert ov_model.outputs[0].get_names() == {"result1:0", "result2:0", "add:0"} + assert ov_model.outputs[1].get_names() == {"result1:0", "result2:0", "add:0"}