[TF FE] Set single output tensor name for TF1 formats. (#21075)

* Set single output tensor name for TF1 and TF2 formats.

* Removed debug output.

* Added param for defining if tensor names need indices.

* Clang format.

* Comment corrected.

* Fixed TF1 layer tests.

* Minor correction.

* Fixed errors.

* Error fixed.

* Bug fixes.

* Bug fix.

* Code style, minor corrections.

* Added comments.

* Update src/frontends/tensorflow/src/frontend.cpp

Co-authored-by: Roman Kazantsev <roman.kazantsev@intel.com>

* Added tests.

* Optimize imports.

* Code correction.

* Removed WA

* Small correction.

* Moved names alignment logic to adjust_saved_model_names().

* Removed changes in utils.

* Fixed errors, applied comments.

* Test fixed.

* Removed changes from utils.

* Removed commented code.

* Added note.

* Minor corrections.

* Code style.

* Changed set_node_name, removed not needed changes.

* Clang format.

* Fixed names for output places in input model.

* Fixed tensor names of identity.

* Added ticket number.

* Added ticket numbers.

* Added ticket numbers.

* Code style.

* Corrected tests.

* Update tests/layer_tests/ovc_python_api_tests/test_tf.py

Co-authored-by: Roman Kazantsev <roman.kazantsev@intel.com>

---------

Co-authored-by: Roman Kazantsev <roman.kazantsev@intel.com>
This commit is contained in:
Anastasiia Pnevskaia 2024-01-15 18:53:43 +01:00 committed by GitHub
parent ab2192d51d
commit 41195a4b2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 158 additions and 18 deletions

View File

@ -295,8 +295,9 @@ void InputModel::InputModelTFImpl::load_places() {
auto output_place = std::make_shared<TensorPlace>(m_input_model,
ov::PartialShape({}),
ov::element::dynamic,
std::vector<std::string>{output_name});
m_tensor_places[output_name] = output_place;
std::vector<std::string>{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;

View File

@ -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<ov::opset8::Result>(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<ov::opset8::Result>(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<OpPlace> operation_place = nullptr;

View File

@ -178,7 +178,7 @@ TEST_F(FrontEndConversionWithReferenceTestsF, SavedModelWithNumericalNames) {
auto z = make_shared<Parameter>(element::f32, Shape{1});
z->output(0).set_names({"2"});
auto add = make_shared<Add>(x, y);
add->output(0).set_names({"3", "3:0"});
add->output(0).set_names({"3:0"});
auto sub = make_shared<Subtract>(add, z);
sub->output(0).set_names({"4"});
auto result = make_shared<Result>(sub);

View File

@ -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};
}

View File

@ -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>& 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<v0::Parameter>(node)) {
set_out_name(node_name, outputs[0]);
}
for (size_t idx = 0; idx < outputs.size(); ++idx) {

View File

@ -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):

View File

@ -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'}},

View File

@ -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)
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"}