Fix preprocessing in MO to use friendly names as well as tensor names (#9206)
* Fix preprocessing in MO to use friendly names as well as tensor names * Apply review comments * Revert not necessary changes * Apply review feedback
This commit is contained in:
parent
ad10edbd2e
commit
36a6774067
@ -38,52 +38,6 @@ def compress_model(func: object):
|
||||
compress_model_transformation(func)
|
||||
|
||||
|
||||
def add_layouts(ov_function, argv: argparse.Namespace):
|
||||
from openvino.preprocess import PrePostProcessor # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.runtime import Layout # pylint: disable=import-error,no-name-in-module
|
||||
|
||||
prep = PrePostProcessor(ov_function)
|
||||
layout_values = argv.layout_values
|
||||
if '' in layout_values:
|
||||
if len(ov_function.inputs) == 1:
|
||||
layout_values = {
|
||||
list(ov_function.input().get_tensor().get_names())[0]: {
|
||||
'source_layout': layout_values[''].get('source_layout'),
|
||||
'target_layout': layout_values[''].get('target_layout')
|
||||
}
|
||||
}
|
||||
else:
|
||||
input_names = [list(ov_input.get_tensor().get_names())[0] for ov_input in ov_function.inputs]
|
||||
raise Error('Layout without name can be specified for models with only one input, '
|
||||
'but provided model has {} inputs: \'{}\'. '
|
||||
'Please specify explicitly input/output name for --layout option'
|
||||
.format(len(input_names), input_names))
|
||||
|
||||
set_layout_names = set(layout_values.keys())
|
||||
for idx, ov_input in enumerate(ov_function.inputs):
|
||||
found = set.intersection(set(ov_input.get_tensor().get_names()), set_layout_names)
|
||||
assert len(found) <= 1, 'More then one name point to the same node'
|
||||
if len(found) == 1:
|
||||
node_name = list(found)[0]
|
||||
found_layout = layout_values[node_name]
|
||||
if found_layout['source_layout']:
|
||||
prep.input(node_name).model().set_layout(Layout(found_layout['source_layout']))
|
||||
if found_layout['target_layout']:
|
||||
prep.input(node_name).tensor().set_layout(Layout(found_layout['target_layout']))
|
||||
|
||||
for idx, ov_output in enumerate(ov_function.outputs):
|
||||
found = set.intersection(set(ov_output.get_tensor().get_names()), set_layout_names)
|
||||
assert len(found) <= 1, 'More then one name point to the same node'
|
||||
if len(found) == 1:
|
||||
node_name = list(found)[0]
|
||||
found_layout = layout_values[node_name]
|
||||
if found_layout['source_layout']:
|
||||
prep.output(node_name).model().set_layout(Layout(found_layout['source_layout']))
|
||||
if found_layout['target_layout']:
|
||||
prep.output(node_name).tensor().set_layout(Layout(found_layout['target_layout']))
|
||||
prep.build()
|
||||
|
||||
|
||||
def apply_offline_transformations(input_model: str, argv: argparse.Namespace):
|
||||
# This variable is only needed by GenerateMappingFile transformation
|
||||
# to produce correct mapping
|
||||
@ -91,6 +45,7 @@ def apply_offline_transformations(input_model: str, argv: argparse.Namespace):
|
||||
|
||||
from openvino.offline_transformations_pybind import generate_mapping_file, serialize # pylint: disable=import-error,no-name-in-module
|
||||
from openvino.frontend import FrontEndManager, FrontEnd # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.tools.mo.back.preprocessing import apply_preprocessing # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
fem = FrontEndManager()
|
||||
|
||||
@ -104,7 +59,29 @@ def apply_offline_transformations(input_model: str, argv: argparse.Namespace):
|
||||
|
||||
func = read_model(input_model + "_tmp.xml")
|
||||
|
||||
add_layouts(func, argv) # TODO: replace with preprocessing
|
||||
# TODO: use ngraph preprocessing (Mean/Scale/ReverseInputChannels) for legacy frontends
|
||||
reverse_input_channels = False
|
||||
if 'reverse_input_channels' in argv:
|
||||
reverse_input_channels = argv.reverse_input_channels
|
||||
argv.reverse_input_channels = False
|
||||
mean_scale_values = {}
|
||||
if 'mean_scale_values' in argv:
|
||||
mean_scale_values = argv.mean_scale_values
|
||||
argv.mean_scale_values = {}
|
||||
scale = None
|
||||
if 'scale' in argv:
|
||||
scale = argv.scale
|
||||
argv.scale = None
|
||||
|
||||
# Apply preprocessing for layouts only
|
||||
apply_preprocessing(ov_function=func, argv=argv)
|
||||
|
||||
if 'reverse_input_channels' in argv:
|
||||
argv.reverse_input_channels = reverse_input_channels
|
||||
if 'mean_scale_values' in argv:
|
||||
argv.mean_scale_values = mean_scale_values
|
||||
if 'scale' in argv:
|
||||
argv.scale = scale
|
||||
|
||||
apply_user_transformations(func, parse_transform(argv.transform))
|
||||
apply_moc_transformations(func)
|
||||
|
@ -59,7 +59,7 @@ def update_mean_scale_to_dict(input_nodes: list, mean_scale_val, scale):
|
||||
return mean_scale_val
|
||||
|
||||
|
||||
def check_keys_valid(ov_function: Model, keys: list, search_outputs: bool):
|
||||
def check_keys_valid(ov_function: Model, dict_to_validate: dict, search_outputs: bool):
|
||||
"""
|
||||
Internal function: checks if keys from cmd line arguments correspond to ov_function's inputs/outputs
|
||||
Throws if some key is not found
|
||||
@ -70,7 +70,28 @@ def check_keys_valid(ov_function: Model, keys: list, search_outputs: bool):
|
||||
if search_outputs:
|
||||
nodes += ov_function.outputs
|
||||
|
||||
for name in keys:
|
||||
# We need to replace all node names from dict to tensor names
|
||||
rename_dict = {}
|
||||
# Find names for replacing
|
||||
for name in dict_to_validate.keys():
|
||||
for ov_node in nodes:
|
||||
if name in ov_node.get_tensor().get_names():
|
||||
break
|
||||
elif name == ov_node.get_node().get_friendly_name():
|
||||
assert len(ov_node.get_tensor().get_names()) > 0, 'Node must have at least one tensor name'
|
||||
new_name = list(ov_node.get_tensor().get_names())[0]
|
||||
rename_dict[name] = new_name
|
||||
break
|
||||
|
||||
# Replace found node names with tensor names
|
||||
for name, new_name in rename_dict.items():
|
||||
assert name in dict_to_validate, 'Key {} is not in initial dict'.format(name)
|
||||
assert new_name not in dict_to_validate, 'Key {} is already in initial dict'.format(new_name)
|
||||
dict_to_validate[new_name] = dict_to_validate[name]
|
||||
del dict_to_validate[name]
|
||||
|
||||
# validate the dict
|
||||
for name in dict_to_validate.keys():
|
||||
node_found = False
|
||||
for ov_node in nodes:
|
||||
if name in ov_node.get_tensor().get_names():
|
||||
@ -349,8 +370,8 @@ def apply_preprocessing(ov_function: Model, argv: argparse.Namespace):
|
||||
'target_layout': layout_values[''].get('target_layout')
|
||||
}
|
||||
}
|
||||
check_keys_valid(ov_function=ov_function, keys=mean_scale_values.keys(), search_outputs=False)
|
||||
check_keys_valid(ov_function=ov_function, keys=layout_values.keys(), search_outputs=True)
|
||||
check_keys_valid(ov_function=ov_function, dict_to_validate=mean_scale_values, search_outputs=False)
|
||||
check_keys_valid(ov_function=ov_function, dict_to_validate=layout_values, search_outputs=True)
|
||||
|
||||
layout_values = update_layout_is_input_flag(ov_function, layout_values)
|
||||
layout_values = guess_source_layouts_by_mean_scale(ov_function, layout_values, mean_scale_values)
|
||||
|
@ -40,7 +40,7 @@ def create_function2(shape1=[2, 2], shape2=[2, 2], dtype1=np.float32, dtype2=np.
|
||||
|
||||
def create_function1(shape1=[2, 2]):
|
||||
input1 = ops.parameter(shape1, dtype=np.float32, name="input1")
|
||||
input1.get_output_tensor(0).set_names({'input1', 'input1a'})
|
||||
input1.get_output_tensor(0).set_names({'input1a', 'input1b'})
|
||||
relu1 = ops.relu(input1)
|
||||
res1 = ops.result(relu1, "res1")
|
||||
res1.get_output_tensor(0).set_names({'res1', 'res1a'})
|
||||
@ -651,3 +651,17 @@ class TestPreprocessingMOC(unittest.TestCase):
|
||||
|
||||
# Verify that guessed layout (?C??) is not appeared in input2
|
||||
self.assertEqual(function.get_parameters()[1].layout, Layout())
|
||||
|
||||
def test_friendly_name(self):
|
||||
argv = Namespace(mean_scale_values={'input1': {'mean': np.array([2., 4., 8.]), 'scale': None}},
|
||||
layout_values={'input1': {'source_layout': 'nchw'}},
|
||||
scale=None)
|
||||
function = create_function1(shape1=[1, 3, 224, 224])
|
||||
process_function(ov_function=function, argv=argv)
|
||||
op_node = list(function.get_parameters()[0].output(0).get_target_inputs())[0].get_node()
|
||||
self.assertTrue(op_node.get_type_name() == 'Subtract' or op_node.get_type_name() == 'Add')
|
||||
self.check_mean_constant(op_node, expected=[2., 4., 8.], shape=[1, 3, 1, 1])
|
||||
|
||||
# Verify that layout (nchw) is appeared in input1
|
||||
self.assertEqual(function.get_parameters()[0].layout, Layout('nchw'))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user