[MO] disabling inserting redundant Converts for int in legacy IR serialization (#17572)
* disabling inserting redundant Converts for integer types for legacy IR serialization
* Revert "disabling inserting redundant Converts for integer types for legacy IR serialization"
This reverts commit ddd96e2034
.
* more selective skip; added unit-tests
* corrected unit-tests
* fix unit-tests: replace dynamic Parameter input with Const
* fix unit-tests: implemented reading with IR frontend
* sort imports
* final revision of unit-tests
---------
Co-authored-by: Evgenya Stepyreva <evgenya.stepyreva@intel.com>
This commit is contained in:
parent
a1a753bb03
commit
84f6deb757
@ -169,16 +169,23 @@ def convert_inputs_of_specific_ops(graph: Graph):
|
|||||||
''.format(port_id, node.soft_get('name', node.id), precision))
|
''.format(port_id, node.soft_get('name', node.id), precision))
|
||||||
in_port = node.in_port(port_id)
|
in_port = node.in_port(port_id)
|
||||||
np_type = data_type_str_to_np(precision)
|
np_type = data_type_str_to_np(precision)
|
||||||
if in_port.get_source().node.type == 'Const':
|
in_node = node.in_port(port_id).get_source().node
|
||||||
const_node = node.in_port(port_id).get_source().node
|
in_type = in_node.out_port(0).get_data_type()
|
||||||
const_type = const_node.out_port(0).get_data_type()
|
|
||||||
if np.issubdtype(const_type, np.integer) and np.issubdtype(np_type, np.integer):
|
if in_node.type == 'Const':
|
||||||
|
if np.issubdtype(in_type, np.integer) and np.issubdtype(np_type, np.integer):
|
||||||
# do not convert Constant value if both source and destination types are of integer types
|
# do not convert Constant value if both source and destination types are of integer types
|
||||||
# otherwise, it affects compatibility of MO IR Engine and TF FE
|
# otherwise, it affects compatibility of MO IR Engine and TF FE
|
||||||
# TF FE intents to use original model type for layers if it is possible
|
# TF FE intents to use original model type for layers if it is possible
|
||||||
continue
|
continue
|
||||||
convert_const_node_value_type(const_node, np_type)
|
convert_const_node_value_type(in_node, np_type)
|
||||||
else:
|
else:
|
||||||
|
allowed_int_types = [np.int32, np.int64, np.uint32, np.uint64]
|
||||||
|
if in_type in allowed_int_types and np_type in allowed_int_types:
|
||||||
|
# do not convert if both source and destination types are within the set of
|
||||||
|
# int32/int64/uint32/uint64. It prevents from getting different IRs from the original
|
||||||
|
# cpp serializer and from the legacy serialized when restored with ir_reader_utils
|
||||||
|
continue
|
||||||
in_port.get_connection().insert_node(Cast(graph, {'dst_type': np_type}).create_node())
|
in_port.get_connection().insert_node(Cast(graph, {'dst_type': np_type}).create_node())
|
||||||
|
|
||||||
|
|
||||||
|
@ -90,8 +90,8 @@ def _update(cls, registered_list: list, registered_dict: dict, key: str, enabled
|
|||||||
if hasattr(c, key) and getattr(c, key) is not None:
|
if hasattr(c, key) and getattr(c, key) is not None:
|
||||||
k = getattr(c, key)
|
k = getattr(c, key)
|
||||||
if k.lower() in new_keys_lower:
|
if k.lower() in new_keys_lower:
|
||||||
log.warning('Attempt to register of custom name {} for the second time as class {}. '
|
# log.warning('Attempt to register of custom name {} for the second time as class {}. '
|
||||||
'Note that custom names are case-insensitive. ' + refer_to_faq_msg(55), k, c)
|
# 'Note that custom names are case-insensitive. ' + refer_to_faq_msg(55), k, c)
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
new_keys_lower[k.lower()] = k
|
new_keys_lower[k.lower()] = k
|
||||||
|
@ -4,8 +4,17 @@
|
|||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
from defusedxml.common import EntitiesForbidden
|
from defusedxml.common import EntitiesForbidden
|
||||||
from openvino.tools.mo.utils.ir_reader.restore_graph import restore_graph_from_ir
|
|
||||||
|
import openvino.tools.mo.utils.ir_reader.extenders.convert_extender
|
||||||
|
from openvino.tools.mo.middle.passes.convert_data_type import destination_type_to_np_data_type
|
||||||
|
from openvino.tools.mo.middle.passes.infer import type_infer
|
||||||
|
from openvino.tools.mo.utils.graph import Node
|
||||||
|
from openvino.tools.mo.utils.ir_engine.compare_graphs import compare_graphs
|
||||||
|
from openvino.tools.mo.utils.ir_reader.extender import Extender
|
||||||
|
from openvino.tools.mo.utils.ir_reader.restore_graph import restore_graph_from_ir, save_restored_graph
|
||||||
|
|
||||||
|
|
||||||
class TestIRReader(unittest.TestCase):
|
class TestIRReader(unittest.TestCase):
|
||||||
@ -127,3 +136,320 @@ class TestIRReader(unittest.TestCase):
|
|||||||
malformed_ir_file.close()
|
malformed_ir_file.close()
|
||||||
self.assertRaises(ValueError, restore_graph_from_ir, malformed_ir_file.name)
|
self.assertRaises(ValueError, restore_graph_from_ir, malformed_ir_file.name)
|
||||||
os.remove(malformed_ir_file.name)
|
os.remove(malformed_ir_file.name)
|
||||||
|
|
||||||
|
|
||||||
|
class PatchedConvert_extender(Extender):
|
||||||
|
"""
|
||||||
|
Original ConvertExtender contains setting 'stop_value_propagation', and because axis value goes to the Gather
|
||||||
|
through Convert during shape_infer axis turns out to be None and shape_infer fails.
|
||||||
|
For purposes of this unit-test we patch extender so that it will not add 'stop_value_propagation' attr.
|
||||||
|
Outside the unit-test Convert_extender is left unchanged because inserting 'stop_value_propagation'
|
||||||
|
is needed in other cases for CompressQuantizeWeights.
|
||||||
|
See description of openvino/tools/mo/utils/ir_reader/extenders/convert_extender.py
|
||||||
|
"""
|
||||||
|
op = 'Convert'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def extend(op: Node):
|
||||||
|
op['dst_type'] = destination_type_to_np_data_type(op.destination_type)
|
||||||
|
|
||||||
|
|
||||||
|
class TestIRSerializeAndRestore(unittest.TestCase):
|
||||||
|
test_ir_xml = """<?xml version="1.0"?>
|
||||||
|
<net name="test_ir" version="11">
|
||||||
|
<layers>
|
||||||
|
<layer id="0" name="input_1" type="Parameter" version="opset1">
|
||||||
|
<data shape="1,128" element_type="f32" />
|
||||||
|
<output>
|
||||||
|
<port id="0" precision="FP32" names="input_1">
|
||||||
|
<dim>1</dim>
|
||||||
|
<dim>128</dim>
|
||||||
|
</port>
|
||||||
|
</output>
|
||||||
|
</layer>
|
||||||
|
<layer id="1" name="input_2" type="Parameter" version="opset1">
|
||||||
|
<data shape="10" element_type="i32" />
|
||||||
|
<output>
|
||||||
|
<port id="0" precision="I32" names="input_2">
|
||||||
|
<dim>4</dim>
|
||||||
|
</port>
|
||||||
|
</output>
|
||||||
|
</layer>
|
||||||
|
<layer id="3" name="gather_axis" type="Const" version="opset1">
|
||||||
|
<data element_type="i32" shape="1" offset="0" size="4" />
|
||||||
|
<output>
|
||||||
|
<port id="0" precision="I32">
|
||||||
|
<dim>1</dim>
|
||||||
|
</port>
|
||||||
|
</output>
|
||||||
|
</layer>
|
||||||
|
<layer id="501" name="gather" type="Gather" version="opset8">
|
||||||
|
<data batch_dims="0" />
|
||||||
|
<input>
|
||||||
|
<port id="0" precision="FP32">
|
||||||
|
<dim>1</dim>
|
||||||
|
<dim>128</dim>
|
||||||
|
</port>
|
||||||
|
<port id="1" precision="I32">
|
||||||
|
<dim>10</dim>
|
||||||
|
</port>
|
||||||
|
<port id="2" precision="I32">
|
||||||
|
<dim>1</dim>
|
||||||
|
</port>
|
||||||
|
</input>
|
||||||
|
<output>
|
||||||
|
<port id="3" precision="FP32" names="gather">
|
||||||
|
<dim>1</dim>
|
||||||
|
<dim>10</dim>
|
||||||
|
</port>
|
||||||
|
</output>
|
||||||
|
</layer>
|
||||||
|
<layer id="590" name="result" type="Result" version="opset1">
|
||||||
|
<input>
|
||||||
|
<port id="0" precision="FP32">
|
||||||
|
<dim>1</dim>
|
||||||
|
<dim>10</dim>
|
||||||
|
</port>
|
||||||
|
</input>
|
||||||
|
</layer>
|
||||||
|
</layers>
|
||||||
|
|
||||||
|
<edges>
|
||||||
|
<edge from-layer="0" from-port="0" to-layer="501" to-port="0" />
|
||||||
|
<edge from-layer="1" from-port="0" to-layer="501" to-port="1" />
|
||||||
|
<edge from-layer="3" from-port="0" to-layer="501" to-port="2" />
|
||||||
|
<edge from-layer="501" from-port="3" to-layer="590" to-port="0" />
|
||||||
|
</edges>
|
||||||
|
</net>
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_save_and_restore(self):
|
||||||
|
original_xml_file = tempfile.NamedTemporaryFile(delete=False)
|
||||||
|
original_xml_file.write(bytes(self.test_ir_xml, 'utf-8'))
|
||||||
|
original_xml_file.close()
|
||||||
|
|
||||||
|
axis_const_blob = np.array([1], dtype=np.int32)
|
||||||
|
original_bin_file = tempfile.NamedTemporaryFile(mode='wb', delete=False)
|
||||||
|
axis_const_blob.tofile(original_bin_file)
|
||||||
|
original_bin_file.close()
|
||||||
|
|
||||||
|
graph_orig, _ = restore_graph_from_ir(original_xml_file.name, original_bin_file.name)
|
||||||
|
type_infer(graph_orig)
|
||||||
|
os.remove(original_xml_file.name)
|
||||||
|
os.remove(original_bin_file.name)
|
||||||
|
|
||||||
|
restored_ir_dir = tempfile.TemporaryDirectory()
|
||||||
|
|
||||||
|
save_restored_graph(graph_orig.copy(), restored_ir_dir.name, {})
|
||||||
|
restored_xml_name = restored_ir_dir.name + '/test_ir.xml'
|
||||||
|
restored_bin_name = restored_ir_dir.name + '/test_ir.bin'
|
||||||
|
|
||||||
|
# Gather is listed in convert_inputs_of_specific_ops as 'Gather': {2: 'int64'}, but
|
||||||
|
# no additional converts will be inserted, because input is int32
|
||||||
|
graph_restored, _ = restore_graph_from_ir(restored_xml_name, restored_bin_name)
|
||||||
|
os.remove(restored_xml_name)
|
||||||
|
os.remove(restored_bin_name)
|
||||||
|
os.remove(restored_xml_name.replace('xml', 'mapping'))
|
||||||
|
os.removedirs(restored_ir_dir.name)
|
||||||
|
|
||||||
|
flag, msg = compare_graphs(graph_orig, graph_restored, 'result', 'gather/sink_port_0')
|
||||||
|
self.assertTrue(flag, msg)
|
||||||
|
|
||||||
|
test_ir_xml_with_i8 = """<?xml version="1.0"?>
|
||||||
|
<net name="test_ir" version="11">
|
||||||
|
<layers>
|
||||||
|
<layer id="0" name="input_1" type="Parameter" version="opset1">
|
||||||
|
<data shape="1,128" element_type="f32" />
|
||||||
|
<output>
|
||||||
|
<port id="0" precision="FP32" names="input_1">
|
||||||
|
<dim>1</dim>
|
||||||
|
<dim>128</dim>
|
||||||
|
</port>
|
||||||
|
</output>
|
||||||
|
</layer>
|
||||||
|
<layer id="1" name="input_2" type="Parameter" version="opset1">
|
||||||
|
<data shape="10" element_type="i32" />
|
||||||
|
<output>
|
||||||
|
<port id="0" precision="I32" names="input_2">
|
||||||
|
<dim>10</dim>
|
||||||
|
</port>
|
||||||
|
</output>
|
||||||
|
</layer>
|
||||||
|
<layer id="3" name="gather_axis" type="Const" version="opset1">
|
||||||
|
<data element_type="i8" shape="1" offset="0" size="1" />
|
||||||
|
<output>
|
||||||
|
<port id="0" precision="I8">
|
||||||
|
<dim>1</dim>
|
||||||
|
</port>
|
||||||
|
</output>
|
||||||
|
</layer>
|
||||||
|
<layer id="501" name="gather" type="Gather" version="opset8">
|
||||||
|
<data batch_dims="0" />
|
||||||
|
<input>
|
||||||
|
<port id="0" precision="FP32">
|
||||||
|
<dim>1</dim>
|
||||||
|
<dim>128</dim>
|
||||||
|
</port>
|
||||||
|
<port id="1" precision="I32">
|
||||||
|
<dim>10</dim>
|
||||||
|
</port>
|
||||||
|
<port id="2" precision="I32">
|
||||||
|
<dim>1</dim>
|
||||||
|
</port>
|
||||||
|
</input>
|
||||||
|
<output>
|
||||||
|
<port id="3" precision="FP32" names="gather">
|
||||||
|
<dim>1</dim>
|
||||||
|
<dim>10</dim>
|
||||||
|
</port>
|
||||||
|
</output>
|
||||||
|
</layer>
|
||||||
|
<layer id="590" name="result" type="Result" version="opset1">
|
||||||
|
<input>
|
||||||
|
<port id="0" precision="FP32">
|
||||||
|
<dim>1</dim>
|
||||||
|
<dim>10</dim>
|
||||||
|
</port>
|
||||||
|
</input>
|
||||||
|
</layer>
|
||||||
|
</layers>
|
||||||
|
|
||||||
|
<edges>
|
||||||
|
<edge from-layer="0" from-port="0" to-layer="501" to-port="0" />
|
||||||
|
<edge from-layer="1" from-port="0" to-layer="501" to-port="1" />
|
||||||
|
<edge from-layer="3" from-port="0" to-layer="501" to-port="2" />
|
||||||
|
<edge from-layer="501" from-port="3" to-layer="590" to-port="0" />
|
||||||
|
</edges>
|
||||||
|
</net>
|
||||||
|
"""
|
||||||
|
|
||||||
|
test_ir_xml_with_convert = """<?xml version="1.0"?>
|
||||||
|
<net name="test_ir" version="11">
|
||||||
|
<layers>
|
||||||
|
<layer id="0" name="input_1" type="Parameter" version="opset1">
|
||||||
|
<data shape="1,128" element_type="f32" />
|
||||||
|
<output>
|
||||||
|
<port id="0" precision="FP32" names="input_1">
|
||||||
|
<dim>1</dim>
|
||||||
|
<dim>128</dim>
|
||||||
|
</port>
|
||||||
|
</output>
|
||||||
|
</layer>
|
||||||
|
<layer id="1" name="input_2" type="Parameter" version="opset1">
|
||||||
|
<data shape="10" element_type="i32" />
|
||||||
|
<output>
|
||||||
|
<port id="0" precision="I32" names="input_2">
|
||||||
|
<dim>10</dim>
|
||||||
|
</port>
|
||||||
|
</output>
|
||||||
|
</layer>
|
||||||
|
<layer id="3" name="gather_axis" type="Const" version="opset1">
|
||||||
|
<data element_type="i8" shape="1" offset="0" size="1" />
|
||||||
|
<output>
|
||||||
|
<port id="0" precision="I8">
|
||||||
|
<dim>1</dim>
|
||||||
|
</port>
|
||||||
|
</output>
|
||||||
|
</layer>
|
||||||
|
<layer id="583" name="convert" type="Convert" version="opset1">
|
||||||
|
<data destination_type="i64" />
|
||||||
|
<input>
|
||||||
|
<port id="0" precision="I8">
|
||||||
|
<dim>1</dim>
|
||||||
|
</port>
|
||||||
|
</input>
|
||||||
|
<output>
|
||||||
|
<port id="1" precision="I64">
|
||||||
|
<dim>1</dim>
|
||||||
|
</port>
|
||||||
|
</output>
|
||||||
|
</layer>
|
||||||
|
<layer id="501" name="gather" type="Gather" version="opset8">
|
||||||
|
<data batch_dims="0" />
|
||||||
|
<input>
|
||||||
|
<port id="0" precision="FP32">
|
||||||
|
<dim>1</dim>
|
||||||
|
<dim>128</dim>
|
||||||
|
</port>
|
||||||
|
<port id="1" precision="I32">
|
||||||
|
<dim>10</dim>
|
||||||
|
</port>
|
||||||
|
<port id="2" precision="I32">
|
||||||
|
<dim>1</dim>
|
||||||
|
</port>
|
||||||
|
</input>
|
||||||
|
<output>
|
||||||
|
<port id="3" precision="FP32" names="gather">
|
||||||
|
<dim>1</dim>
|
||||||
|
<dim>10</dim>
|
||||||
|
</port>
|
||||||
|
</output>
|
||||||
|
</layer>
|
||||||
|
<layer id="590" name="result" type="Result" version="opset1">
|
||||||
|
<input>
|
||||||
|
<port id="0" precision="FP32">
|
||||||
|
<dim>1</dim>
|
||||||
|
<dim>10</dim>
|
||||||
|
</port>
|
||||||
|
</input>
|
||||||
|
</layer>
|
||||||
|
</layers>
|
||||||
|
|
||||||
|
<edges>
|
||||||
|
<edge from-layer="0" from-port="0" to-layer="501" to-port="0" />
|
||||||
|
<edge from-layer="1" from-port="0" to-layer="501" to-port="1" />
|
||||||
|
<edge from-layer="3" from-port="0" to-layer="583" to-port="0" />
|
||||||
|
<edge from-layer="583" from-port="1" to-layer="501" to-port="2" />
|
||||||
|
<edge from-layer="501" from-port="3" to-layer="590" to-port="0" />
|
||||||
|
</edges>
|
||||||
|
</net>
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_save_and_restore_with_converts(self):
|
||||||
|
original_xml_file = tempfile.NamedTemporaryFile(delete=False)
|
||||||
|
original_xml_file.write(bytes(self.test_ir_xml_with_i8, 'utf-8'))
|
||||||
|
original_xml_file.close()
|
||||||
|
|
||||||
|
gather_axis_blob = np.array([1], dtype=np.int8)
|
||||||
|
original_bin_file = tempfile.NamedTemporaryFile(mode='wb', delete=False)
|
||||||
|
gather_axis_blob.tofile(original_bin_file)
|
||||||
|
original_bin_file.close()
|
||||||
|
|
||||||
|
graph_orig, _ = restore_graph_from_ir(original_xml_file.name, original_bin_file.name)
|
||||||
|
type_infer(graph_orig)
|
||||||
|
os.remove(original_xml_file.name)
|
||||||
|
|
||||||
|
restored_ir_dir = tempfile.TemporaryDirectory()
|
||||||
|
save_restored_graph(graph_orig.copy(), restored_ir_dir.name, {})
|
||||||
|
|
||||||
|
ir_file_with_convert = tempfile.NamedTemporaryFile(delete=False)
|
||||||
|
ir_file_with_convert.write(bytes(self.test_ir_xml_with_convert, 'utf-8'))
|
||||||
|
ir_file_with_convert.close()
|
||||||
|
|
||||||
|
from openvino.tools.mo.utils.ir_reader.extender import Extender
|
||||||
|
|
||||||
|
if 'Convert' in Extender.registered_ops:
|
||||||
|
Extender.registered_ops['Convert'] = PatchedConvert_extender
|
||||||
|
|
||||||
|
graph_with_convert, _ = restore_graph_from_ir(ir_file_with_convert.name, original_bin_file.name)
|
||||||
|
type_infer(graph_with_convert)
|
||||||
|
os.remove(ir_file_with_convert.name)
|
||||||
|
|
||||||
|
if 'Convert' in Extender.registered_ops:
|
||||||
|
Extender.registered_ops['Convert'] = openvino.tools.mo.utils.ir_reader.extenders.convert_extender.Convert_extender
|
||||||
|
|
||||||
|
restored_xml_file = restored_ir_dir.name + '/test_ir.xml'
|
||||||
|
restored_bin_file = restored_ir_dir.name + '/test_ir.bin'
|
||||||
|
|
||||||
|
# Gather is listed in convert_inputs_of_specific_ops as 'Gather': {2: 'int64'},
|
||||||
|
# converts from int8 to int64 will be inserted
|
||||||
|
graph_restored, _ = restore_graph_from_ir(restored_xml_file, restored_bin_file)
|
||||||
|
|
||||||
|
os.remove(original_bin_file.name)
|
||||||
|
os.remove(restored_xml_file)
|
||||||
|
os.remove(restored_bin_file)
|
||||||
|
os.remove(restored_xml_file.replace('xml', 'mapping'))
|
||||||
|
os.removedirs(restored_ir_dir.name)
|
||||||
|
|
||||||
|
flag, msg = compare_graphs(graph_orig, graph_restored, 'result', 'gather/sink_port_0')
|
||||||
|
self.assertTrue(flag, msg)
|
||||||
|
Loading…
Reference in New Issue
Block a user