[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))
|
||||
in_port = node.in_port(port_id)
|
||||
np_type = data_type_str_to_np(precision)
|
||||
if in_port.get_source().node.type == 'Const':
|
||||
const_node = node.in_port(port_id).get_source().node
|
||||
const_type = const_node.out_port(0).get_data_type()
|
||||
if np.issubdtype(const_type, np.integer) and np.issubdtype(np_type, np.integer):
|
||||
in_node = node.in_port(port_id).get_source().node
|
||||
in_type = in_node.out_port(0).get_data_type()
|
||||
|
||||
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
|
||||
# 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
|
||||
continue
|
||||
convert_const_node_value_type(const_node, np_type)
|
||||
convert_const_node_value_type(in_node, np_type)
|
||||
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())
|
||||
|
||||
|
||||
|
@ -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:
|
||||
k = getattr(c, key)
|
||||
if k.lower() in new_keys_lower:
|
||||
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)
|
||||
# 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)
|
||||
continue
|
||||
else:
|
||||
new_keys_lower[k.lower()] = k
|
||||
|
@ -4,8 +4,17 @@
|
||||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
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):
|
||||
@ -127,3 +136,320 @@ class TestIRReader(unittest.TestCase):
|
||||
malformed_ir_file.close()
|
||||
self.assertRaises(ValueError, restore_graph_from_ir, 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