[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:
parent
ab2192d51d
commit
41195a4b2a
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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'}},
|
||||
|
|
|
|||
|
|
@ -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"}
|
||||
|
|
|
|||
Loading…
Reference in New Issue