diff --git a/model-optimizer/extensions/back/ChangeOutputTypeAttributes.py b/model-optimizer/extensions/back/ChangeOutputTypeAttributes.py index 5e525d48791b7e..9695f112e42103 100644 --- a/model-optimizer/extensions/back/ChangeOutputTypeAttributes.py +++ b/model-optimizer/extensions/back/ChangeOutputTypeAttributes.py @@ -8,12 +8,12 @@ from mo.back.replacement import BackReplacementPattern from mo.graph.graph import Graph from mo.graph.graph import Node -from mo.middle.passes.convert_data_type import data_type_str_to_np +from mo.middle.passes.convert_data_type import data_type_str_to_np, convert_blob from mo.utils.error import Error operations_with_data_type_attributes = { - 'Cast': {'attr_name': 'dst_type', 'in_ports_to_check': (0,)}, - 'Range': {'attr_name': 'output_type', 'in_ports_to_check': (0, 1, 2)}, + 'Cast': {'attr_name': 'dst_type', 'in_ports_to_check': (0,), 'check_out_shape': False}, + 'Range': {'attr_name': 'output_type', 'in_ports_to_check': (0, 1, 2), 'check_out_shape': True}, } @@ -27,7 +27,6 @@ class ChangeOutputTypeAttributes(BackReplacementPattern): avoid floating point overflow. """ enabled = True - force_shape_inference = True def run_after(self): from extensions.back.MarkNodesWithShapeValues import MarkNodesWithShapeValues @@ -73,17 +72,31 @@ def assert_that_is_castable_to_fp16(node: Node): val = node.in_port(i).data.get_value() if val is None: return - - if np.any(val > np.finfo(np.float16).max) or np.any(val < np.finfo(np.float16).min): - raise Error("Try to convert with --data_type=FP32 argument. " - "This model can not be converted to FP16 precision, since " - "'{}' node value {} exceeds FP16 allowed limits: [{}, {}]" - .format(node_name, val, np.finfo(np.float16).min, np.finfo(np.float16).max)) - # further this input values will be rewritten since force_shape_inference=True + # is needed for Range node.in_port(i).data.set_value(val.astype(np.float16)) + node.in_node(i)['correct_data_type'] = True original_output = node.out_port(0).data.get_value() - node.infer(node) + converted_blob, infinite_match_count, zero_match_count = convert_blob(original_output, np.float16) + + if infinite_match_count: + # some models have -Inf values but nevertheless are correctly inferred in FP16 + # we should not raise an Error here but instead show a warning + log.error("{} of {} elements of '{}' were clipped to infinity while converting into FP16. " + "This may lead to incorrect results during inference or may not be a problem, " + "depending on the model.".format(infinite_match_count, original_output.size, node_name, + extra={'is_warning': True})) + if zero_match_count: + # some values are clipped into zero but nevertheless are correctly inferred + log.error("{} of {} elements of '{}' were clipped to zero while converting into FP16. " + "This may lead to incorrect results during inference or may not be a problem, " + "depending on the model.".format(zero_match_count, original_output.size, node_name, + extra={'is_warning': True})) + + if not operations_with_data_type_attributes[op_name]['check_out_shape']: + return + + node.infer(node) # is needed for Range casted_output = node.out_port(0).data.get_value() original_output_len = len(original_output) if hasattr(original_output, '__len__') else None casted_output_len = len(casted_output) if hasattr(casted_output, '__len__') else None diff --git a/model-optimizer/extensions/ops/range.py b/model-optimizer/extensions/ops/range.py index ae0ed22433a604..689f9af76c4c8c 100644 --- a/model-optimizer/extensions/ops/range.py +++ b/model-optimizer/extensions/ops/range.py @@ -70,6 +70,9 @@ def infer(node: Node): start = node.in_port(0).data.get_value() limit = node.in_port(1).data.get_value() delta = node.in_port(2).data.get_value() + if any(np.isinf((start, limit, delta))): + raise Error("Range node's '{}' input values must be finite, but instead " + "it contain infinities: start={}, stop={}, step={}".format(name, start, limit, delta)) for input in (start, limit, delta): if input is not None and not node.has_valid('output_type'): diff --git a/model-optimizer/mo/middle/passes/convert_data_type.py b/model-optimizer/mo/middle/passes/convert_data_type.py index c4133df2ecbfbb..bdd74427a64403 100644 --- a/model-optimizer/mo/middle/passes/convert_data_type.py +++ b/model-optimizer/mo/middle/passes/convert_data_type.py @@ -126,11 +126,13 @@ def convert_node_blobs(graph: Graph, node: Node, data_type: type): if finite_match_count: log.error( ("{} elements of {} were clipped to infinity while converting a blob for node [{}] to {}. " + - refer_to_faq_msg(76)).format(finite_match_count, blob.size, consumers, data_type)) + refer_to_faq_msg(76)).format(finite_match_count, blob.size, consumers, data_type), + extra={'is_warning': True}) if zero_match_count: - log.warning( + log.error( ("{} elements of {} were clipped to zero while converting a blob for node [{}] to {}. " + - refer_to_faq_msg(77)).format(zero_match_count, blob.size, consumers, data_type)) + refer_to_faq_msg(77)).format(zero_match_count, blob.size, consumers, data_type), + extra={'is_warning': True}) node.value = new_blob # for the constant node need to propagate the converted value to the node output because there is a fake diff --git a/model-optimizer/unit_tests/extensions/back/ChangeOutputTypeAttributes_test.py b/model-optimizer/unit_tests/extensions/back/ChangeOutputTypeAttributes_test.py index 2f607113dc8be6..4033182aa7df99 100644 --- a/model-optimizer/unit_tests/extensions/back/ChangeOutputTypeAttributes_test.py +++ b/model-optimizer/unit_tests/extensions/back/ChangeOutputTypeAttributes_test.py @@ -57,12 +57,16 @@ def test_cast_correct_case(self): def test_cast_out_of_fp16_max(self): input_data = np.array([0, 100000, 4, 9, 0]) graph, graph_ref = build_cast_test_graphs(input_data, dst_type_str='FP16') - self.assertRaises(Error, ChangeOutputTypeAttributes().find_and_replace_pattern, graph) + with self.assertLogs() as captured: + ChangeOutputTypeAttributes().find_and_replace_pattern(graph) + self.assertRegex(str(captured[1]), 'were clipped to infinity') def test_cast_out_of_fp16_min(self): input_data = np.array([0, -100000, 4, 9, 0]) graph, graph_ref = build_cast_test_graphs(input_data, dst_type_str='FP16') - self.assertRaises(Error, ChangeOutputTypeAttributes().find_and_replace_pattern, graph) + with self.assertLogs() as captured: + ChangeOutputTypeAttributes().find_and_replace_pattern(graph) + self.assertRegex(str(captured[1]), 'were clipped to infinity') def build_range_test_graphs(start=0, limit=10, delta=1, dst_type_str='FP16',