Skip to content

Commit 6ff1420

Browse files
authored
[TF FE] Support TF 2.17 and stick exact TF version for validation (openvinotoolkit#26014)
**Details:** Stick exact version for TF FE validation. This approach is more transparent about what TF version is exactly tested against. We will select the highest available version for each platform. **Ticket:** 150601 --------- Signed-off-by: Kazantsev, Roman <roman.kazantsev@intel.com>
1 parent d74a392 commit 6ff1420

31 files changed

+305
-491
lines changed

.github/workflows/job_python_unit_tests.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,9 @@ jobs:
270270
TEST_PRECISION: FP16
271271

272272
- name: TensorFlow 2 Layer Tests - Legacy FE
273-
if: fromJSON(inputs.affected-components).TF_FE.test
273+
# no longer workable since TF 2.17
274+
# will be removed in 2024.5
275+
if: ${{ 'false' }}
274276
run: python3 -m pytest ${{ env.LAYER_TESTS_INSTALL_DIR }}/tensorflow2_keras_tests/test_tf2_keras_activation.py --use_legacy_frontend --ir_version=11 -k "sigmoid" --junitxml=${{ env.INSTALL_TEST_DIR }}/TEST-tf2_Activation.xml
275277
env:
276278
TEST_DEVICE: CPU

src/bindings/python/src/openvino/frontend/tensorflow/utils.py

+31-10
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@
66

77

88
import logging as log
9+
import numpy as np
910
import sys
11+
from openvino.runtime import PartialShape, Dimension, Type
1012
from packaging.version import parse, Version
1113
from typing import List, Dict, Union
1214

13-
import numpy as np
14-
from openvino.runtime import PartialShape, Dimension, Type
15-
1615

1716
# TODO: reuse this method in ovc and remove duplication
1817
def get_static_shape(shape: [PartialShape, list, tuple], dynamic_value=None):
@@ -106,13 +105,32 @@ def trace_tf_model_if_needed(input_model, placeholder_shapes, placeholder_data_t
106105
return trace_tf_model(input_model, placeholder_shapes, placeholder_data_types, example_input)
107106

108107

109-
def get_input_spec_from_model(model):
108+
def partial_shape_to_list(partial_shape: PartialShape):
109+
if partial_shape.rank.is_dynamic:
110+
return None
111+
res_list = []
112+
for dim in partial_shape:
113+
if dim.is_static:
114+
res_list.append(dim.get_length())
115+
else:
116+
res_list.append(None)
117+
return res_list
118+
119+
120+
def get_input_spec_from_model(model, input_shapes=None):
110121
import tensorflow as tf
111122
if hasattr(model, "_build_input_shape") and model._build_input_shape is not None:
112123
if isinstance(model._build_input_shape, list):
113124
input_spec = [[tf.TensorSpec(shape) for shape in model._build_input_shape]]
114125
else:
115126
input_spec = [tf.TensorSpec(model._build_input_shape)]
127+
elif input_shapes and isinstance(input_shapes, list) and len(input_shapes) > 0:
128+
input_spec = []
129+
for input_shape in input_shapes:
130+
if isinstance(input_shape, PartialShape):
131+
input_spec.append(tf.TensorSpec(partial_shape_to_list(input_shape)))
132+
else:
133+
input_spec.append(tf.TensorSpec(None))
116134
else:
117135
input_spec = [tf.TensorSpec(None)]
118136
return input_spec
@@ -199,10 +217,13 @@ def create_generic_function_from_keras_model(keras_model):
199217
if tf_input_signature is not None:
200218
@tf.function(input_signature=tf_input_signature)
201219
def wrapper_function_dict(*args):
202-
input_dict = {}
203-
for ind, tensor_spec in enumerate(tf_input_signature):
204-
input_dict[tensor_spec.name] = args[ind]
205-
outputs = keras_model(input_dict)
220+
if isinstance(keras_input_signature, list):
221+
outputs = keras_model(args)
222+
else:
223+
input_dict = {}
224+
for ind, tensor_spec in enumerate(tf_input_signature):
225+
input_dict[tensor_spec.name] = args[ind]
226+
outputs = keras_model(input_dict)
206227
# need to wrap the output into dictionary
207228
# it helps to preserve original keras tensor names
208229
post_outputs = {}
@@ -276,7 +297,7 @@ def are_shapes_defined(shape: Union[List, Dict]):
276297
"Could not trace the TF model with the following error: {}",
277298
use_example_input=False)
278299
else:
279-
input_spec = get_input_spec_from_model(model)
300+
input_spec = get_input_spec_from_model(model, input_shapes)
280301
concrete_func = get_concrete_func(tf_function, input_spec, input_needs_packing,
281302
"Could not trace the TF model with the following error: {}.\n"
282303
"Please provide 'example_input'.")
@@ -457,4 +478,4 @@ def tf_type_to_ov_type(val):
457478
}
458479
if val not in tf_to_ov_type:
459480
raise Exception("The provided data type is not supported by OpenVino {}.".format(val))
460-
return tf_to_ov_type[val]
481+
return tf_to_ov_type[val]

src/frontends/tensorflow/src/input_model.cpp

+12-5
Original file line numberDiff line numberDiff line change
@@ -230,14 +230,21 @@ void InputModel::InputModelTFImpl::load_places() {
230230
if (dtype_any.is<ov::element::Type>()) {
231231
type = dtype_any.as<ov::element::Type>();
232232
}
233-
std::vector<std::string> names = {op_name + ":0"};
233+
std::string internal_tensor_name = op_name + ":0";
234+
std::vector<std::string> names{internal_tensor_name};
234235
auto tensor_place = std::make_shared<TensorPlace>(m_input_model, pshape, type, names, op_name);
235-
236-
m_default_places[op_name + ":0"] = tensor_place;
236+
m_default_places[internal_tensor_name] = tensor_place;
237237

238238
if (op_type == "Placeholder") {
239-
// by default, PlaceholderWithDefault is NOT used as input
240-
m_inputs.push_back(tensor_place);
239+
if (m_saved_model_input_names && (m_saved_model_input_names->size() > 0)) {
240+
// if input signature is defined,
241+
// found input must present in this signature
242+
if (m_saved_model_input_names->find(internal_tensor_name) != m_saved_model_input_names->end()) {
243+
m_inputs.push_back(tensor_place);
244+
}
245+
} else {
246+
m_inputs.push_back(tensor_place);
247+
}
241248
}
242249
} else if (op_type == "input_arg") {
243250
if (m_input_names.size() > 0 &&

tests/constraints.txt

+2-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ sympy>=1.10
1212
wheel>=0.38.1
1313
defusedxml>=0.7.1
1414
fastjsonschema~=2.17.1
15-
tensorflow>=2.5,<2.17.0
15+
tensorflow>=2.5,<2.18.0
1616
requests>=2.25.1
1717
opencv-python>=4.5
1818
paddlepaddle==2.6.1
@@ -26,8 +26,7 @@ jax<=0.4.14
2626
jaxlib<=0.4.14
2727
kornia==0.7.0
2828
networkx<=3.3
29-
keras>=2.0.0,<3.0.0
3029
timm==1.0.8
3130

3231
--extra-index-url https://download.pytorch.org/whl/cpu
33-
torch~=2.4.0
32+
torch~=2.4.0

tests/layer_tests/common/layer_test_class.py

+6-7
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
# Copyright (C) 2018-2024 Intel Corporation
22
# SPDX-License-Identifier: Apache-2.0
33

4+
import defusedxml.ElementTree as ET
45
import itertools
6+
import numpy as np
57
import os
68
import re
79
import warnings
8-
from pathlib import Path
9-
10-
import defusedxml.ElementTree as ET
11-
import numpy as np
1210
from common.constants import test_device, test_precision
1311
from common.layer_utils import InferAPI
1412
from common.utils.common_utils import generate_ir_python_api
13+
from pathlib import Path
1514

1615

1716
class CommonLayerTest:
@@ -177,9 +176,9 @@ def compare_ie_results_with_framework(self, infer_res, framework_res, framework_
177176
rtol=framework_eps):
178177
is_ok = False
179178
if ie_res.dtype != bool:
180-
print("Max diff is {}".format(
181-
np.array(
182-
abs(ie_res - framework_res[framework_out_name])).max()))
179+
fw_res = np.array(framework_res[framework_out_name])
180+
diff = np.array(abs(ie_res - fw_res)).max()
181+
print("Max diff is {}".format(diff))
183182
else:
184183
print("Boolean results are not equal")
185184
else:

tests/layer_tests/common/tf2_layer_test_class.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
def save_to_tf2_savedmodel(tf2_model, path_to_saved_tf2_model):
1111
import tensorflow as tf
1212
assert int(tf.__version__.split('.')[0]) >= 2, "TensorFlow 2 must be used for this suite validation"
13-
tf.keras.models.save_model(tf2_model, path_to_saved_tf2_model, save_format='tf')
13+
# Since TF 2.16 this is only way to serialize Keras objects into SavedModel format
14+
tf2_model.export(path_to_saved_tf2_model)
1415
assert os.path.isdir(path_to_saved_tf2_model), "the model haven't been saved " \
1516
"here: {}".format(path_to_saved_tf2_model)
1617
return path_to_saved_tf2_model

tests/layer_tests/mo_python_api_tests/test_mo_convert_extensions.py

+13-12
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
# Copyright (C) 2018-2024 Intel Corporation
22
# SPDX-License-Identifier: Apache-2.0
33

4-
import pytest
54
import numpy as np
6-
5+
import openvino.runtime as ov
6+
import pytest
77
from common.mo_convert_test_class import CommonMOConvertTest
88
from common.onnx_layer_test_class import save_to_onnx
9-
10-
import openvino.runtime as ov
119
from openvino.runtime import PartialShape, Model
1210

1311

@@ -199,14 +197,18 @@ def create_keras_model(self, temp_dir):
199197
tf.compat.v1.reset_default_graph()
200198

201199
input_name = "Input1"
202-
input_shape = [1, 2, 3]
200+
input_shape = [None, 1, 2, 3]
203201

204-
x = tf.keras.Input(shape=input_shape, name=input_name)
205-
y = tf.cos(x)
206-
keras_net = tf.keras.Model(inputs=[x], outputs=[y])
207-
tf.keras.backend.clear_session()
202+
tf.compat.v1.reset_default_graph()
203+
204+
with tf.compat.v1.Session() as sess:
205+
x = tf.compat.v1.placeholder(tf.float32, input_shape, input_name)
206+
tf.raw_ops.Cos(x=x, name='res')
207+
208+
tf.compat.v1.global_variables_initializer()
209+
tf_net = sess.graph_def
208210

209-
return keras_net
211+
return tf_net
210212

211213
def create_custom_extension_cos_to_sin():
212214
from openvino.frontend import ConversionExtension
@@ -228,9 +230,8 @@ def create_custom_op_extension_cos_to_sin():
228230
def create_ref_graph():
229231
shape = PartialShape([-1, 1, 2, 3])
230232
param = ov.opset14.parameter(shape, dtype=np.float32)
231-
param.get_output_tensor(0).set_names({"Input1"})
233+
param.get_output_tensor(0).set_names({"Input1:0"})
232234
y = ov.opset14.sin(param)
233-
y.get_output_tensor(0).set_names({"tf.math.cos/Cos:0"})
234235

235236
parameter_list = [param]
236237

0 commit comments

Comments
 (0)