Example #1
0
    def test_fake_results(self):
        then_graph_nodes = {**valued_const_with_data('fake_const', int64_array(0)),
                            **regular_op_with_empty_data('shapeof',
                                         {'kind': 'op', 'type': 'ShapeOf', 'op': 'ShapeOf', 'infer': Shape.infer,
                                          'output_type': np.int64}),
                            **regular_op_with_empty_data('res_1', {'kind': 'op', 'type': 'Result', 'op': 'Result',
                                                                   'infer': lambda x: 0, 'output_id': 0})}
        then_graph_edges = [*connect('fake_const', 'shapeof'),
                            *connect('shapeof', 'res_1'),
                            ]

        else_graph_nodes = {**regular_op_with_empty_data('param_1', {'type': 'Parameter', 'kind': 'op', 'input_id': 1,
                                                                     'shape': None, 'infer': Parameter.infer}),
                            **regular_op_with_empty_data('res_1', {'kind': 'op', 'type': 'Result', 'op': 'Result',
                                                                   'infer': lambda x: 0, 'output_id': 0})}
        else_graph_edges = [*connect('param_1', 'res_1')]
        then_graph = build_graph_with_edge_attrs(then_graph_nodes, then_graph_edges)
        else_graph = build_graph_with_edge_attrs(else_graph_nodes, else_graph_edges)
        external_graph_nodes = {
            **valued_const_with_data('cond', np.array([True], dtype=np.bool)),
            **valued_const_with_data('input_1', int64_array([[1, 2, 3], [3, 2, 3]])),
            **regular_op_with_empty_data('if', {'kind': 'op', 'op': 'If', 'then_graph': then_graph,
                                                'else_graph': else_graph, 'infer': If.infer}),
            **result('res_1')}
        external_graph_edges = [*connect('cond', '0:if'),
                                *connect('input_1', '1:if'),
                                *connect('if', 'res_1')]

        graph = build_graph(external_graph_nodes, external_graph_edges)
        graph.stage = 'middle'
        partial_infer(graph)
        res_1 = Node(graph, 'res_1')
        npt.assert_array_equal(res_1.in_port(0).data.get_shape(), int64_array([2,3]))
Example #2
0
    def build_and_test_shape_inference(data_shape, indices_shape, axis,
                                       batch_dims, ref_shape):
        nodes = {
            **shaped_parameter('data', int64_array(data_shape)),
            **shaped_parameter('indices', int64_array(indices_shape)),
            **valued_const_with_data('axis', int64_array(axis)),
            **regular_op_with_empty_data('gather', {
                'op': 'Gather',
                'batch_dims': batch_dims,
                'infer': Gather.infer
            }),
            **result('res'),
        }

        edges = [
            *connect('data', '0:gather'), *connect('indices', '1:gather'),
            *connect('axis', '2:gather'), *connect('gather', 'res')
        ]

        graph = build_graph(nodes, edges)
        graph.stage = 'middle'
        partial_infer(graph)

        node = Node(graph, 'gather')
        res = node.out_port(0).data.get_shape()
        npt.assert_array_equal(res, ref_shape)
Example #3
0
 def test_for_is_cyclic1(self):
     # Test for case of cyclic graph without is_cyclic attrs
     graph = build_graph(nodes_attributes,
                         [('node_1', 'node_1_data'),
                          ('node_1_data', 'node_3'),
                          ('node_3', 'node_3_data'),
                          ('node_3_data', 'node_1')],
                         nodes_with_edges_only=True)
     with self.assertRaisesRegex(Error, 'Graph contains a cycle. Can not proceed.*'):
         partial_infer(graph)
Example #4
0
    def test_partial_infer(self):
        graph = build_graph(nodes_attributes, [('node_1', 'concat'),
                                               ('node_2', 'concat'),
                                               ('concat', 'node_3'),
                                               ('node_3', 'op_output')],
                            {
                                'node_3': {
                                    'kind': 'data',
                                    'shape': None,
                                    'infer': None
                                },
                                'node_1': {
                                    'kind': 'data',
                                    'shape': np.array([1, 3, 227, 227]),
                                    'infer': None
                                },
                                'node_2': {
                                    'kind': 'data',
                                    'shape': np.array([1, 3, 227, 227]),
                                    'infer': None
                                },
                                'concat': {
                                    'kind': 'op',
                                    'axis': 2,
                                    'infer': concat_infer
                                }
                            },
                            nodes_with_edges_only=True)

        start_node = 'concat'
        partial_infer(graph, start_node)
        node = Node(graph, start_node)
        self.assertTrue(node.is_partial_inferred)
        self.assertTrue(node.out_node().is_partial_inferred)

        # check if previous nodes are not inferred
        node = Node(graph, start_node)
        while True:
            # collect nodes in a list
            if isinstance(node.in_nodes(), list):
                in_nodes = node.in_nodes()
            else:
                in_nodes = [y for x, y in node.in_nodes().items()]

            # check parents and find next parent
            for n in in_nodes:
                if 'embedded_input_' not in n.id:
                    node = n
                self.assertFalse(n.has('is_partial_inferred'))

            if not len(in_nodes):
                break
Example #5
0
    def test_custom_value_propagation(self, value, expected, custom_dtype):
        graph = build_graph(nodes(value, custom_dtype), [
            *connect('value', 'convert'), *connect('convert', 'output'),
        ])
        partial_infer(graph)

        graph_ref = build_graph(nodes(value, custom_dtype), [
            *connect('value', 'convert'), *connect('convert', 'output')],
                                {'convert_d': {'force_type': custom_dtype, 'force_shape': np.array(value).shape,
                                               'value': expected}})

        (flag, resp) = compare_graphs(graph, graph_ref, 'output', check_op_attrs=True)
        self.assertTrue(flag, resp)
Example #6
0
 def find_and_replace_pattern(self, graph: Graph):
     dynamic_inputs = {}
     for parameter in graph.get_op_nodes(op='Parameter'):
         param_shape = parameter.soft_get('shape', shape_array(dynamic_dimension_value))
         if not is_fully_defined(param_shape):
             parameter_name = parameter.soft_get('name', parameter.id)
             dynamic_inputs[parameter_name] = param_shape
     if dynamic_inputs:
         log.error('The model contains input(s) with partially defined shapes: {}. '
                   'Starting from the 2022.1 release the Model Optimizer can generate an IR with partially defined '
                   'input shapes ("-1" dimension in the TensorFlow model or dimension with string value in the ONNX '
                   'model). Some of the OpenVINO plugins require model input shapes to be static, so you should '
                   'call "reshape" method in the Inference Engine and specify static input shapes. For optimal '
                   'performance, it is still recommended to update input shapes with fixed ones using "--input" or '
                   '"--input_shape" command-line parameters.'
                   .format(','.join('name="{}" shape="{}"'.format(name, unmask_shape(shape))
                                    for name, shape in dynamic_inputs.items())),
                   extra={'is_warning': True})
     partial_infer(graph)
Example #7
0
    def test_is_not_fully_inferred_param(self):
        # Node that have is_not_fully_inferred=True
        graph = build_graph(nodes_attributes, [('node_1', 'concat'),
                                               ('node_2', 'concat'),
                                               ('concat', 'node_3'),
                                               ('node_3', 'op_output')],
                            {
                                'node_3': {
                                    'kind': 'data',
                                    'shape': None,
                                    'infer': None
                                },
                                'node_1': {
                                    'kind': 'data',
                                    'shape': np.array([1, 3, 227, 227]),
                                    'infer': None
                                },
                                'node_2': {
                                    'kind': 'data',
                                    'shape': np.array([1, 3, 227, 227]),
                                    'infer': None
                                },
                                'concat': {
                                    'kind': 'op',
                                    'axis': 2,
                                    'infer': concat_infer,
                                    'is_not_fully_inferred': True
                                }
                            },
                            nodes_with_edges_only=True)

        start_node = 'concat'
        try:
            partial_infer(graph, start_node)
        except Error:
            self.fail("Unexpected Error raised")
        node = Node(graph, start_node)
        self.assertTrue(node.is_partial_inferred)
        self.assertTrue(node.out_node().is_partial_inferred)
Example #8
0
def driver(argv, input_model, output_model_name, output_dir):
    meta_info = get_meta_info(argv)

    EltwiseChecker.enabled = False

    try:
        graph, input_shapes = load_kaldi_model(input_model)
    except Exception as e:
        raise Error('Model Optimizer is not able to read Kaldi model {}. '.format(input_model) +
                    refer_to_faq_msg(91)) from e
    graph.check_empty_graph('load_kaldi_nnet_model')
    graph.graph['cmd_params'] = argv
    graph.graph['fw'] = 'kaldi'
    graph.graph['ir_version'] = 2 if argv.generate_deprecated_IR_V2 else 5
    update_extractors_with_extensions(kaldi_type_extractors)
    extract_node_attrs(graph, lambda node: kaldi_extractor(node))

    # --------------------------------- LOAD END ------------------------------------------------------
    class_registration.apply_replacements(graph, class_registration.ClassType.FRONT_REPLACER)

    graph = partial_infer(graph)

    # The order is intentional, firstly eliminate repeated, then remove redundant
    FuseRepeatedReshapes().find_and_replace_pattern(graph)
    EliminateRedundantReshape().find_and_replace_pattern(graph)
    graph.check_empty_graph('partial_infer')
    if argv.counts:
        try:
            counts = read_counts_file(argv.counts)
        except Exception as e:
            raise Error('Model Optimizer is not able to read counts file {}'.format(argv.counts) +
                        refer_to_faq_msg(92)) from e

        apply_biases_to_last_layer(graph, counts)

    if argv.remove_output_softmax:
        RemoveLastSoftMaxPattern().find_and_replace_pattern(graph)
        graph_clean_up(graph)
        log.debug("After removing softmax")
        graph.print_graph_stat()

    # Intentionally after all transformations
    KaldiRemoveMemoryOutputBackReplacementPattern().find_and_replace_pattern(graph)

    remove_const_ops(graph)
    CreateConstNodesReplacement().find_and_replace_pattern(graph)

    remove_output_ops(graph)

    prepare_emit_ir(graph, argv.data_type, output_dir, output_model_name, meta_info=meta_info)
    return 0
def build_range_test_graphs(start=0,
                            limit=10,
                            delta=1,
                            dst_type_str='FP16',
                            src_type_str='FP32',
                            returns_shape_value=None):
    nodes = {
        **valued_const_with_data('start', float32_array(start)),
        **valued_const_with_data('limit', float32_array(limit)),
        **valued_const_with_data('delta', float32_array(delta)),
        **regular_op_with_empty_data(
            'range', {
                'type': 'Range',
                'op': 'Range',
                'returns_shape_value': returns_shape_value,
                'output_type': data_type_str_to_np(src_type_str),
                'infer': Range.infer
            }),
        **result('res'),
    }

    nodes_ref = deepcopy(nodes)
    nodes_ref.update({
        **regular_op_with_empty_data(
            'range', {
                'type': 'Range',
                'op': 'Range',
                'returns_shape_value': returns_shape_value,
                'output_type': data_type_str_to_np(dst_type_str),
                'infer': Range.infer
            }),
    })

    edges = [
        *connect('start', '0:range'),
        *connect('limit', '1:range'),
        *connect('delta', '2:range'),
        *connect('range', 'res'),
    ]
    graph = build_graph(nodes, edges)
    graph_ref = build_graph(nodes_ref, edges)

    graph = partial_infer(graph)

    graph.graph['cmd_params'].data_type = dst_type_str
    convert_blobs(graph, dst_type_str)
    return graph, graph_ref
def build_cast_test_graphs(input_data, dst_type_str='FP16'):
    nodes = {
        **valued_const_with_data('input', float32_array(input_data)),
        **regular_op_with_empty_data(
            'cast', {
                'type': 'Convert',
                'op': 'Cast',
                'dst_type': np.float32,
                'infer': Cast.infer
            }),
        **result('res'),
    }

    nodes_ref = deepcopy(nodes)
    nodes_ref.update({
        **regular_op_with_empty_data(
            'cast', {
                'type': 'Convert',
                'op': 'Cast',
                'dst_type': data_type_str_to_np(dst_type_str),
                'infer': Cast.infer
            }),
    })

    edges = [
        *connect('input', 'cast'),
        *connect('cast', 'res'),
    ]
    graph = build_graph(nodes, edges)
    graph_ref = build_graph(nodes_ref, edges)

    graph = partial_infer(graph)

    graph.graph['cmd_params'].data_type = dst_type_str
    convert_blobs(graph, dst_type_str)
    return graph, graph_ref
Example #11
0
def driver_R5(onnx_modelproto_bytes,
              precision: str,
              output_model_name: str,
              outputs: list,
              output_dir: str,
              scale: float,
              user_shapes: [None, list, np.array] = None,
              mean_scale_values: [dict, list] = ()):

    try:
        model_proto = onnx.load_from_string(bytes(onnx_modelproto_bytes))
    except Exception as e:
        print("[python] onnx exception: ", str(e))

    model_graph = model_proto.graph  # pylint: disable=no-member
    log.debug("Number of nodes in graph_def: {}".format(len(model_graph.node)))
    log.debug(
        "Number of all input ports (not true inputs) in graph_def: {}".format(
            len(model_graph.input)))
    log.debug("Number of initializers in graph_def: {}".format(
        len(model_graph.initializer)))
    log.debug("Number of real inputs in graph_def: {}".format(
        len(model_graph.input) - len(model_graph.initializer)))
    update_extractors_with_extensions(onnx_op_extractors)

    try:
        graph = protobuf2nx(model_proto)
        log.debug("Number of nodes in NX graph: {}".format(
            graph.number_of_nodes()))
        graph.__setattr__(
            'name',
            output_model_name if output_model_name else model_proto.graph.name)  # pylint: disable=no-member
        graph.graph['layout'] = 'NCHW'
        graph.graph['fw'] = 'onnx'
        graph.graph[
            'feature_dim'] = 1 if graph.graph['layout'] == 'NCHW' else 3
        graph.graph['ir_version'] = 4
        extract_node_attrs(graph, lambda node:
                           (True, common_onnx_fields(node)))
    except Exception as e:
        raise Error(
            'Cannot pre-process ONNX graph after reading from model file "{}". '
            'File is corrupt or has unsupported format. Details: {}. ' +
            refer_to_faq_msg(44), model_file_name, str(e)) from e
    check_empty_graph(
        graph, 'protobuf2nx. It may happen due to problems with loaded model')
    packed_user_shapes, packed_outputs, _ = user_data_repack(
        graph, user_shapes, outputs, None)

    output_op_nodes = add_output_ops(graph, packed_outputs)
    input_op_nodes = add_input_ops(graph, packed_user_shapes, True)

    graph_clean_up(graph)
    check_empty_graph(graph, 'add_output_ops and add_input_ops')
    extract_node_attrs(
        graph, lambda node: onnx_op_extractor(
            node, check_for_duplicates(onnx_op_extractors)))

    class_registration.apply_replacements(
        graph, class_registration.ClassType.FRONT_REPLACER)

    create_tensor_nodes(graph)
    graph_clean_up(graph)

    override_placeholder_shapes(graph, packed_user_shapes)

    graph_clean_up(graph)
    remove_op_nodes(graph, {'op': 'Identity'})

    graph_clean_up(graph)

    remove_output_ops(graph)

    partial_infer(graph)
    graph_clean_up(graph)
    check_empty_graph(graph, 'partial_infer')

    input_op_nodes = add_input_ops(graph, packed_user_shapes, False)
    graph_clean_up(graph)
    check_empty_graph(graph, 'add_input_ops')

    scale_input(graph, scale)
    add_mean_scale_values(graph, mean_scale_values)

    convert_dilated_convolution(graph)
    graph_clean_up(graph)

    graph_clean_up(graph)

    remove_op_nodes(graph, {'op': 'Identity'})
    remove_useless_split(graph)

    class_registration.apply_replacements(
        graph, class_registration.ClassType.MIDDLE_REPLACER)

    convert_gemm_to_fully_connected(graph)
    NormalizeFullyConnected().find_and_replace_pattern(graph)

    fuse_pad(graph)
    graph_clean_up(graph)

    convert_batch_norm(graph)
    graph_clean_up(graph)

    convert_scale_shift_to_mul_add(graph)
    graph_clean_up(graph)

    fuse_mul_add_sequence(graph)
    graph_clean_up(graph)

    fuse_linear_ops(graph)
    graph_clean_up(graph)

    grouped_convolutions_fusing(graph)
    graph_clean_up(graph)

    fuse_linear_ops(graph)
    graph_clean_up(graph)

    convert_muladd_to_scaleshift_or_power(graph)
    graph_clean_up(graph)

    convert_mul_add_to_power(graph)
    graph_clean_up(graph)

    convert_reshape(graph)
    convert_add_to_scaleshift(graph)  # scale = 1
    convert_mul_to_scaleshift(graph)  # biases = 0

    fuse_pad(graph)
    graph_clean_up(graph)

    fuse_sequence_of_reshapes(graph)
    graph_clean_up(graph)

    pattern = EltwiseInputNormalize()
    pattern.find_and_replace_pattern(graph)

    merge_nodes_permutations(graph)
    permute_data_nodes_attrs(graph)
    permute_op_nodes_attrs(graph)

    class_registration.apply_replacements(
        graph, class_registration.ClassType.BACK_REPLACER)

    weights, xml_string = prepare_emit_ir(graph=graph,
                                          data_type=precision,
                                          output_dir=output_dir,
                                          output_model_name=output_model_name,
                                          meta_info={'unset': []})

    return weights, xml_string
Example #12
0
    def test_simple_shape_inf(self):
        then_graph_nodes = {**regular_op_with_empty_data('param_1', {'type': 'Parameter', 'kind': 'op', 'input_id': 1,
                                                                     'shape': None, 'infer': Parameter.infer}),
                            **regular_op_with_empty_data('param_2', {'type': 'Parameter', 'kind': 'op', 'input_id': 2,
                                                                     'shape': None, 'infer': Parameter.infer}),
                            **regular_op_with_empty_data('add', {'type': 'Add', 'kind': 'op', 'op': 'Add',
                                                                 'infer': lambda node: eltwise_infer(node,
                                                                                                     Add.operation)}),
                            **regular_op_with_empty_data('mul', {'type': 'Mul', 'kind': 'op', 'op': 'Mul',
                                                                 'infer': lambda node: eltwise_infer(node,
                                                                                                     Mul.operation)}),
                            **regular_op_with_empty_data('res1', {'kind': 'op', 'type': 'Result', 'op': 'Result',
                                                                  'infer': lambda x: 0, 'output_id': 0}),
                            **regular_op_with_empty_data('res2', {'kind': 'op', 'type': 'Result', 'op': 'Result',
                                                                  'infer': lambda x: 0, 'output_id': 1})}
        then_graph_edges = [*connect('param_1', '0:add'),
                            *connect('param_2', '1:add'),
                            *connect('param_1', '1:mul'),
                            *connect('param_2', '0:mul'),
                            *connect('add', 'res1'),
                            *connect('mul', 'res2'),
                            ]

        else_graph_nodes = {**regular_op_with_empty_data('param_1', {'type': 'Parameter', 'kind': 'op', 'input_id': 1,
                                                                     'shape': None, 'infer': Parameter.infer}),
                            **regular_op_with_empty_data('param_2', {'type': 'Parameter', 'kind': 'op', 'input_id': 3,
                                                                     'shape': None, 'infer': Parameter.infer}),
                            **regular_op_with_empty_data('identity',
                                                         {'kind': 'op', 'op': 'Identity', 'infer': Identity.infer}),
                            **regular_op_with_empty_data('identity_1',
                                                         {'kind': 'op', 'op': 'Identity', 'infer': Identity.infer}),
                            **regular_op_with_empty_data('res1', {'kind': 'op', 'type': 'Result', 'op': 'Result',
                                                                  'infer': lambda x: 0, 'output_id': 0}),
                            **regular_op_with_empty_data('res2', {'kind': 'op', 'type': 'Result', 'op': 'Result',
                                                                  'infer': lambda x: 0, 'output_id': 1})}
        else_graph_edges = [*connect('param_1', 'identity'),
                            *connect('param_2', 'identity_1'),
                            *connect('identity_1', 'res2'),
                            *connect('identity', 'res1'), ]
        then_graph = build_graph_with_edge_attrs(then_graph_nodes, then_graph_edges)
        else_graph = build_graph_with_edge_attrs(else_graph_nodes, else_graph_edges)
        external_graph_nodes = {
            **valued_const_with_data('cond', np.array([True], dtype=np.bool)),
            **valued_const_with_data('input_2', int64_array([3, 2, 1])),
            **valued_const_with_data('input_1', int64_array([1, 2, 3])),
            **valued_const_with_data('input_3', int64_array([8, 4])),
            **regular_op('if', {'kind': 'op', 'op': 'If', 'then_graph': then_graph,
                                'else_graph': else_graph, 'infer': If.infer}),
            **empty_data('if_d_1'),
            **empty_data('if_d_2'),
            **result('res_1'),
            **result('res_2')}
        external_graph_edges = [*connect('cond', '0:if'),
                                *connect('input_1', '1:if'),
                                *connect('input_2', '2:if'),
                                *connect('input_3', '3:if'),
                                ('if', 'if_d_1', {'out': 0}),
                                ('if', 'if_d_2', {'out': 1}),
                                ('if_d_1', 'res_1'),
                                ('if_d_2', 'res_2')]

        graph = build_graph(external_graph_nodes, external_graph_edges)
        graph.stage = 'middle'
        partial_infer(graph)
        res_1 = Node(graph, 'res_1')
        res_2 = Node(graph, 'res_2')
        npt.assert_array_equal(res_1.in_port(0).data.get_shape(), int64_array([3]))
        npt.assert_array_equal(res_2.in_port(0).data.get_shape(), int64_array([3]))
Example #13
0
 def infer(if_node: Node):
     If.update_body_parameters_shape(if_node, True)
     If.update_body_parameters_shape(if_node, False)
     partial_infer(if_node.then_graph)
     partial_infer(if_node.else_graph)
     If.update_if_output_ports_shape(if_node)
Example #14
0
def driver(argv, input_model, output_model_name, output_dir):
    log_step(argv.steps, 'LOAD')
    meta_info = get_meta_info(argv)

    EltwiseChecker.enabled = False

    try:
        graph = load_kaldi_model(input_model)
    except Exception as e:
        raise Error('Model Optimizer is not able to parse Kaldi model {}. '.format(input_model) +
                    refer_to_faq_msg(91)) from e
    graph.check_empty_graph('load_kaldi_nnet_model')
    graph.graph['cmd_params'] = argv
    graph.graph['fw'] = 'kaldi'

    if graph.graph['cmd_params'].generate_experimental_IR_V10:
        version = 10
    else:
        version = 6
    graph.graph['ir_version'] = 2 if argv.generate_deprecated_IR_V2 else version

    update_extractors_with_extensions(kaldi_type_extractors)
    extract_node_attrs(graph, lambda node: kaldi_extractor(node))

    # --------------------------------- LOAD END ------------------------------------------------------
    log_step(argv.steps, 'FRONT')
    ReplaceLSTMNodePattern().find_and_replace_pattern(graph)
    class_registration.apply_replacements(graph, class_registration.ClassType.FRONT_REPLACER)
    log_step(argv.steps, 'MIDDLE')
    graph = partial_infer(graph)

    ReplacePNormNodePattern().find_and_replace_pattern(graph)
    ReplaceMemoryOffsetNodePattern().find_and_replace_pattern(graph)
    ReplaceMemoryOffsetWithMemoryNodePattern().find_and_replace_pattern(graph)
    RemoveMemoryDuplicationPattern().find_and_replace_pattern(graph)
    MergeNeighborSplicePattern().find_and_replace_pattern(graph)
    RemoveUselessCropsPattern().find_and_replace_pattern(graph)
    RemoveIdentity().find_and_replace_pattern(graph)
    graph_clean_up(graph)

    AddSelectBeforeMemoryNodePattern().find_and_replace_pattern(graph)

    ReplaceSpliceNodePattern().find_and_replace_pattern(graph)
    graph_clean_up(graph)

    # The order is intentional, firstly eliminate repeated, then remove redundant
    FuseRepeatedReshapes().find_and_replace_pattern(graph)
    EliminateRedundantReshape().find_and_replace_pattern(graph)
    graph_clean_up(graph)
    graph.check_empty_graph('partial_infer')
    if argv.counts:
        try:
            counts = read_counts_file(argv.counts)
        except Exception as e:
            raise Error('Model Optimizer is not able to read counts file {}'.format(argv.counts) +
                        refer_to_faq_msg(92)) from e

        apply_biases_to_last_layer(graph, counts)

    if argv.remove_output_softmax:
        RemoveLastSoftMaxPattern().find_and_replace_pattern(graph)
        graph_clean_up(graph)
        log.debug("After removing softmax")
        graph.print_graph_stat()

    log_step(argv.steps, 'BACK')
    LeakyReluToReluWithNegativeSlope().find_and_replace_pattern(graph)
    TransposeToPermute().find_and_replace_pattern(graph)
    DivideToEltwises().find_and_replace_pattern(graph)
    SubtractToEltwises().find_and_replace_pattern(graph)
    SimpleEltwiseToEltwiseOp().find_and_replace_pattern(graph)
    for_graph_and_each_sub_graph_recursively(graph, convert_matmul_to_fully_connected)

    # Intentionally after all transformations
    if argv.remove_memory:
        CutMemory().find_and_replace_pattern(graph)
        graph_clean_up(graph)
    ParameterToInput().find_and_replace_pattern(graph)

    KaldiRemoveMemoryOutputBackReplacementPattern().find_and_replace_pattern(graph)
    ForceStrictPrecision().find_and_replace_pattern(graph)
    remove_const_ops(graph)
    CreateConstNodesReplacement().find_and_replace_pattern(graph)

    remove_output_ops(graph)
    log_step(argv.steps, 'EMIT')
    prepare_emit_ir(graph, argv.data_type, output_dir, output_model_name, meta_info=meta_info)
    return 0
Example #15
0
    def test_simple_shape_inf(self, cond, output_port_0_shape,
                              output_port_1_shape):
        then_graph_nodes = {
            **regular_op_with_empty_data(
                'param_1', {
                    'type': 'Parameter',
                    'kind': 'op',
                    'input_id': 1,
                    'shape': None,
                    'infer': Parameter.infer
                }),
            **regular_op_with_empty_data(
                'param_2', {
                    'type': 'Parameter',
                    'kind': 'op',
                    'input_id': 2,
                    'shape': None,
                    'infer': Parameter.infer
                }),
            **regular_op_with_empty_data(
                'add', {
                    'type': 'Add',
                    'kind': 'op',
                    'op': 'Add',
                    'infer': lambda node: eltwise_infer(node, Add.operation)
                }),
            **regular_op_with_empty_data(
                'mul', {
                    'type': 'Mul',
                    'kind': 'op',
                    'op': 'Mul',
                    'infer': lambda node: eltwise_infer(node, Mul.operation)
                }),
            **regular_op_with_empty_data(
                'res1', {
                    'kind': 'op',
                    'type': 'Result',
                    'op': 'Result',
                    'infer': lambda x: 0,
                    'output_id': 0
                }),
            **regular_op_with_empty_data(
                'res2', {
                    'kind': 'op',
                    'type': 'Result',
                    'op': 'Result',
                    'infer': lambda x: 0,
                    'output_id': 1
                })
        }
        then_graph_edges = [
            *connect('param_1', '0:add'),
            *connect('param_2', '1:add'),
            *connect('param_1', '1:mul'),
            *connect('param_2', '0:mul'),
            *connect('add', 'res1'),
            *connect('mul', 'res2'),
        ]

        else_graph_nodes = {
            **regular_op_with_empty_data(
                'param_1', {
                    'type': 'Parameter',
                    'kind': 'op',
                    'input_id': 1,
                    'shape': None,
                    'infer': Parameter.infer
                }),
            **regular_op_with_empty_data(
                'param_2', {
                    'type': 'Parameter',
                    'kind': 'op',
                    'input_id': 3,
                    'shape': None,
                    'infer': Parameter.infer
                }),
            **regular_op_with_empty_data('identity', {
                'kind': 'op',
                'op': 'Identity',
                'infer': Identity.infer
            }),
            **regular_op_with_empty_data('identity_1', {
                'kind': 'op',
                'op': 'Identity',
                'infer': Identity.infer
            }),
            **regular_op_with_empty_data(
                'res1', {
                    'kind': 'op',
                    'type': 'Result',
                    'op': 'Result',
                    'infer': lambda x: 0,
                    'output_id': 0
                }),
            **regular_op_with_empty_data(
                'res2', {
                    'kind': 'op',
                    'type': 'Result',
                    'op': 'Result',
                    'infer': lambda x: 0,
                    'output_id': 1
                })
        }
        else_graph_edges = [
            *connect('param_1', 'identity'),
            *connect('param_2', 'identity_1'),
            *connect('identity_1', 'res2'),
            *connect('identity', 'res1'),
        ]
        then_graph = build_graph_with_edge_attrs(then_graph_nodes,
                                                 then_graph_edges)
        else_graph = build_graph_with_edge_attrs(else_graph_nodes,
                                                 else_graph_edges)
        external_graph_nodes = {
            **valued_const_with_data('cond', cond),
            **valued_const_with_data('input_2', int64_array([3, 2, 1])),
            **valued_const_with_data('input_1', int64_array([1, 2, 3])),
            **valued_const_with_data('input_3', int64_array([8, 4])),
            **regular_op(
                'if', {
                    'kind': 'op',
                    'op': 'If',
                    'then_graph': then_graph,
                    'else_graph': else_graph,
                    'infer': If.infer
                }),
            **empty_data('if_d_1'),
            **empty_data('if_d_2'),
            **result('res_1'),
            **result('res_2')
        }
        external_graph_edges = [
            *connect('cond', '0:if'), *connect('input_1', '1:if'),
            *connect('input_2', '2:if'), *connect('input_3', '3:if'),
            ('if', 'if_d_1', {
                'out': 0
            }), ('if', 'if_d_2', {
                'out': 1
            }), ('if_d_1', 'res_1'), ('if_d_2', 'res_2')
        ]

        graph = build_graph(external_graph_nodes, external_graph_edges)
        graph.stage = 'middle'
        partial_infer(graph)
        if_node = Node(graph, 'if')
        self.assertTrue(
            strict_compare_tensors(
                if_node.out_port(0).data.get_shape(), output_port_0_shape))
        # shape of the "then" branch is [3] and shape of the "else" branch is [2], so the output shape is "[dynamic]"
        self.assertTrue(
            strict_compare_tensors(
                if_node.out_port(1).data.get_shape(), output_port_1_shape))
Example #16
0
def driver_R1(onnx_modelproto_bytes, precision: str, output_model_name: str, outputs: list, output_dir: str,
              scale: float,
              user_shapes: [None, list, np.array] = None,
              mean_scale_values: [dict, list] = ()):

    try:
        model_proto = onnx.load_from_string(bytes(onnx_modelproto_bytes))
    except Exception as e:
        print("[python] onnx exception: ", str(e))

    model_graph = model_proto.graph  # pylint: disable=no-member

    update_extractors_with_extensions(onnx_op_extractors)

    try:
        graph = protobuf2nx(model_proto)
        log.debug("Number of nodes in NX graph: {}".format(
            graph.number_of_nodes()))
        graph.__setattr__(
            'name', output_model_name if output_model_name else model_proto.graph.name)  # pylint: disable=no-member
        graph.graph['layout'] = 'NCHW'
        graph.graph['cmd_params'] = argparse.Namespace(batch=None, data_type='float', disable_fusing=False, disable_gfusing=False, disable_resnet_optimization=False, enable_concat_optimization=False, extensions=mo_extensions, finegrain_fusing=None, framework='onnx', freeze_placeholder_with_value=None, generate_deprecated_IR_V2=False,
                                                       input=None, input_model=None, input_shape=None, keep_shape_ops=False, log_level='ERROR', mean_scale_values={}, mean_values=(), model_name=None, move_to_preprocess=False, output=None, output_dir='.', placeholder_shapes=None, reverse_input_channels=False, scale=None, scale_values=(), silent=False, version=False)
        graph.graph['fw'] = 'onnx'
        graph.graph['feature_dim'] = 1 if graph.graph['layout'] == 'NCHW' else 3
        graph.graph['ir_version'] = 4
        extract_node_attrs(graph, lambda node: (
            True, common_onnx_fields(node)))
    except Exception as e:
        raise Error(
            'Cannot pre-process ONNX graph after reading from model file "{}". '
            'File is corrupt or has unsupported format. Details: {}. ' +
            refer_to_faq_msg(44),
            model_file_name,
            str(e)
        ) from e
    graph.check_empty_graph(
        'protobuf2nx. It may happen due to problems with loaded model')
    extract_node_attrs(graph, lambda node: onnx_op_extractor(
        node, check_for_duplicates(onnx_op_extractors)))

    # --------------------------------- LOAD END ------------------------------------------------------
    class_registration.apply_replacements(
        graph, class_registration.ClassType.FRONT_REPLACER)
    partial_infer(graph)
    graph.check_empty_graph('partial_infer')
    class_registration.apply_replacements(
        graph, class_registration.ClassType.MIDDLE_REPLACER)

    fuse_pad(graph)
    graph_clean_up_onnx(graph)

    mark_unfused_nodes(graph, 'False')
    convert_batch_norm(graph)
    graph_clean_up_onnx(graph)

    convert_muladd_to_scaleshift_or_power(graph)
    graph_clean_up_onnx(graph)

    convert_mul_add_to_power(graph)
    graph_clean_up_onnx(graph)

    convert_reshape(graph)
    graph_clean_up_onnx(graph)
    convert_add_or_mul_to_scaleshift(graph)  # scale = 1
    graph_clean_up_onnx(graph)

    fuse_pad(graph)
    graph_clean_up_onnx(graph)

    fuse_sequence_of_reshapes(graph)
    graph_clean_up_onnx(graph)

    pattern = EltwiseInputNormalize()
    pattern.find_and_replace_pattern(graph)

    merge_nodes_permutations(graph)
    permute_data_nodes_attrs(graph)
    permute_op_nodes_attrs(graph)

    class_registration.apply_replacements(
        graph, class_registration.ClassType.BACK_REPLACER)

    for_graph_and_each_sub_graph_recursively(graph, remove_const_ops)

    CreateConstNodesReplacement().find_and_replace_pattern(graph)

    for_graph_and_each_sub_graph_recursively(graph, remove_output_ops)

    weights, xml_string = prepare_emit_ir(graph=graph, data_type=precision, output_dir=output_dir, output_model_name=output_model_name,
                                          meta_info={'unset': []})

    return weights, xml_string
Example #17
0
 def find_and_replace_pattern(self, graph: Graph):
     partial_infer(graph)
Example #18
0
def tf2nx(argv: argparse.Namespace, model_file_name: str, output_model_name: str, outputs: list, output_dir: str,
          scale: float, is_binary: bool,
          user_shapes: [None, list, np.array] = None,
          mean_scale_values: [dict, list] = ()):
    """
    Convert TF GraphDef object to NetworkX representation.
    The resulting graph is still TF-specific and needs normalization passes to be applied.
    The specific TF structure assumes each GraphDef node is converted to a single
    NetworkX node, node id is an original TF node name, and edges go directly from one op   to another op.
    """
    meta_info = get_meta_info(argv)

    if argv.tensorflow_custom_layer_libraries:
        libraries = argv.tensorflow_custom_layer_libraries.split(',')
        for library in libraries:
            log.info('Loading library "{}" with custom operations'.format(library))
            tf.load_op_library(library)

    graph_def, variables_values = load_tf_graph_def(graph_file_name=model_file_name, is_binary=is_binary,
                                                    checkpoint=argv.input_checkpoint,
                                                    user_output_node_names_list=outputs,
                                                    model_dir=argv.saved_model_dir,
                                                    meta_graph_file=argv.input_meta_graph,
                                                    saved_model_tags=argv.saved_model_tags)

    try:
        tf.import_graph_def(graph_def, name='')
    except:
        log.warning("TensorFlow post-processing of loaded model was unsuccessful. "
                    "This is an optional step that Model Optimizer performs for any input model but it is not usually "
                    "required for all models."
                    "It likely means that the original model is ill-formed. "
                    "Model Optimizer will continue converting this model.")

    log.debug("Number of nodes in graph_def: {}".format(len(graph_def.node)))  # pylint: disable=no-member

    if argv.tensorboard_logdir:
        tensorboard.dump_for_tensorboard(graph_def, argv.tensorboard_logdir)

    update_extractors_with_extensions(tf_op_extractors)

    try:
        graph = protobuf2nx(graph_def)
        graph.__setattr__('name', output_model_name)
        # 'layout' parameter change may cause an issue in EltwiseInputReshape replacer
        # and convert_nhwc_to_nchw(graph)
        graph.graph['layout'] = 'NCHW' if argv.disable_nhwc_to_nchw else 'NHWC'
        graph.graph['cmd_params'] = argv
        graph.graph['fw'] = 'tf'
        graph.graph['ir_version'] = 2 if argv.generate_deprecated_IR_V2 else 4

        if graph.graph['ir_version'] == 2:
            # When the deprecated IR version was requested,
            # we configure only those phases that can lead to
            # functional regressions in the version 2.
            # BasicLSTMCell is one such transformation; when it is turned off,
            # the body of TF basic_lstm_cell is converted as-is in a decomposed form,
            # and should work in version 2.
            BasicLSTMCell.enabled = False

        # placeholder for request from a transformation pass to repeat the entire conversion
        graph.graph['repeat_conversion'] = False

        graph = restore_edges(graph, get_tf_edges)
        graph = remove_control_dependency_inputs(graph)
        # extract basic attributes earlier to enable some passes that relies on them before full attribute
        # extractor is called
        extract_node_attrs(graph, lambda node: (True, common_tf_fields(node)))
    except Exception as e:
        raise Error(
            'Cannot pre-process TensorFlow graph after reading from model file "{}". ' \
            'File is corrupt or has unsupported format. Details: {}. ' +
            refer_to_faq_msg(44),
            model_file_name,
            str(e)
        ) from e

    check_empty_graph(graph, 'protobuf2nx. It may happen due to problems with loaded model')

    packed_user_shapes, packed_outputs, freeze_placeholder = user_data_repack(graph, user_shapes, outputs,
                                                                              argv.freeze_placeholder_with_value)
    if freeze_placeholder is not None:
        FreezePlaceholderValue.enabled = True
        FreezePlaceholderValue.replacement_dict = freeze_placeholder
        update_registration()

    GemmResolver.enabled = False

    inputs = list(packed_user_shapes.keys()) if packed_user_shapes is not None and isinstance(packed_user_shapes,
                                                                                              dict) else None
    graph.graph['inputs'] = inputs  # save user defined inputs for other extensions

    output_op_nodes = add_output_ops(graph, packed_outputs, inputs=packed_user_shapes)
    input_op_nodes = add_input_ops(graph, packed_user_shapes, True)

    # this call of 'graph_clean_up' removes child nodes of outputs which is useful when custom output is specified
    graph_clean_up_tf(graph)

    check_empty_graph(graph, 'add_output_ops and add_input_ops. It may happen due to absence of \'Placeholder\' layer '
                             'in the model')

    variables_to_constants(graph, variables_values)
    del variables_values
    graph_clean_up_tf(graph)

    if argv.tensorflow_custom_operations_config_update:
        if update_custom_replacement_config_file(graph, argv.tensorflow_custom_operations_config_update):
            return 0
        else:
            return 1

    unsupported_ops_to_offload_to_tf = list()

    MAX_ITERATIONS = 5
    cur_iteration = 0
    while cur_iteration < MAX_ITERATIONS:
        graph_copy = copy.deepcopy(graph)  # create a copy of graph for the case when some ops are unsupported

        if argv.tensorflow_subgraph_patterns is not None:
            csc.replace_subgraph_calls(graph, argv.tensorflow_subgraph_patterns)

        if argv.tensorflow_operation_patterns is not None:
            csc.offload_operations_to_tf(graph, argv.tensorflow_operation_patterns)

        if argv.offload_unsupported_operations_to_tf and len(unsupported_ops_to_offload_to_tf):
            csc.offload_unsupported_operations_to_tf(graph, unsupported_ops_to_offload_to_tf)

        extract_node_attrs(graph, lambda node: tf_op_extractor(node, check_for_duplicates(tf_op_extractors)))

        if argv.tensorflow_use_custom_operations_config is not None:
            registry = CustomReplacementRegistry()
            registry.add_custom_replacement_description_from_config(argv.tensorflow_use_custom_operations_config)

            # automatically generate sub-classes for custom replacements that replace sub-graph with a single node
            for replacement_desc in registry.get_all_replacements_descriptions():
                if replacement_desc.has('op'):
                    type('FrontReplacementFromConfigFileOp' + replacement_desc.op, (FrontReplacementFromConfigFileOp,),
                         {'replacement_id': replacement_desc.id})
            update_registration()

        override_placeholder_shapes(graph, packed_user_shapes)

        # the user shapes are used to convert TensorFlow Object Detection API models
        graph.graph['user_shapes'] = packed_user_shapes
        class_registration.apply_replacements(graph, class_registration.ClassType.FRONT_REPLACER)

        override_batch(graph, argv.batch)

        create_tensor_nodes(graph)
        graph_clean_up_tf(graph)

        remove_output_ops(graph)
        partial_infer(graph)
        delete_control_flow_edges(graph)

        replacer = AddIsCyclicAttribute()
        replacer.find_and_replace_pattern(graph)

        # TENSOR ITERATOR CREATING BEGINS
        if graph.graph['is_cyclic']:
            replacer = DeleteSelect()
            replacer.find_and_replace_pattern(graph)

            replacer = SmartInputMatcher()
            replacer.find_and_replace_pattern(graph)

            replacer = SmartOutputMatcher()
            replacer.find_and_replace_pattern(graph)

            replacer = LoopConditionMatcher()
            replacer.find_and_replace_pattern(graph)

            replacer = SimpleConditionMather()
            replacer.find_and_replace_pattern(graph)

            replacer = BackEdgesMatching()
            replacer.find_and_replace_pattern(graph)

            replacer = ConditionChecks()
            replacer.find_and_replace_pattern(graph)

        delete_not_executable(graph)
        graph_clean_up_tf(graph)
        if graph.graph['is_cyclic']:
            replacer = SimpleInputMatcher()
            replacer.find_and_replace_pattern(graph)

            replacer = BackEdgeSimpleInputMatcher()
            replacer.find_and_replace_pattern(graph)

            # Here will be optimizing path (ops after Enter and before body take out of body)

            replacer = TensorIteratorMerge()
            replacer.find_and_replace_pattern(graph)
        # TENSOR ITERATOR CREATING ENDS

        check_for_cycle(graph)

        for_graph_and_each_sub_graph_recursively(graph, graph_clean_up_tf)
        check_empty_graph(graph, 'partial_infer')

        csc.prepare_tf_call_nodes(graph)
        graph_clean_up_tf(graph)

        duplicate_shared_weights(graph)

        input_op_nodes = add_input_ops(graph, packed_user_shapes, False)
        graph_clean_up_tf(graph)
        check_empty_graph(graph, 'add_input_ops')

        change_placeholders_types_to_FP32(graph)

        scale_input(graph, scale)
        add_mean_scale_values(graph, mean_scale_values)

        convert_dilated_convolution(graph)
        for_graph_and_each_sub_graph_recursively(graph, graph_clean_up_tf)

        l2_norm_to_norm(graph)
        graph_clean_up_tf(graph)

        remove_op_nodes(graph, {'identity': True})
        remove_useless_split(graph)

        class_registration.apply_replacements(graph, class_registration.ClassType.MIDDLE_REPLACER)

        mean_to_avgpool(graph)
        convert_nasnet(graph)

        fuse_pad(graph)
        graph_clean_up_tf(graph)

        convert_matmul_to_fully_connected(graph)

        # Mark nodes with attr 'can_be_fused': False to disable fusing for specified nodes
        for_graph_and_each_sub_graph_recursively(graph, lambda graph: mark_unfused_nodes(graph, argv.finegrain_fusing))

        # Converting FusedBatchNorm layer to Mul->Add->Mul->Add sequence
        # IE doesn't support BN with 4 inputs, so we have to split it to two ScaleShift
        convert_batch_norm(graph)
        graph_clean_up_tf(graph)

        if not argv.disable_fusing:
            # Converting ScaleShift layer to Mul->Add
            for_graph_and_each_sub_graph_recursively(graph, convert_scale_shift_to_mul_add)
            for_graph_and_each_sub_graph_recursively(graph, graph_clean_up_tf)

            # Fusing the sequences of Mul/Add operations
            for_graph_and_each_sub_graph_recursively(graph, fuse_mul_add_sequence)
            for_graph_and_each_sub_graph_recursively(graph, graph_clean_up_tf)

            # Fusing linear operation to Convolution
            for_graph_and_each_sub_graph_recursively(graph, fuse_linear_ops)
            for_graph_and_each_sub_graph_recursively(graph, graph_clean_up_tf)

        if not argv.disable_gfusing:
            grouped_convolutions_fusing(graph)
            graph_clean_up_tf(graph)
            if not argv.disable_fusing:
                fuse_linear_ops(graph)
                graph_clean_up_tf(graph)

        # Converting Mul->Add to ScaleShift node
        for_graph_and_each_sub_graph_recursively(graph, convert_muladd_to_scaleshift_or_power)
        for_graph_and_each_sub_graph_recursively(graph, graph_clean_up_tf)

        for_graph_and_each_sub_graph_recursively(graph, convert_mul_add_to_power)

        # Need to eliminate dead nodes before doing update_fully_connected_shapes
        # because update_fully_connected_shapes does partial inference and dead
        # nodes will lead to sporadic failures.
        for_graph_and_each_sub_graph_recursively(graph, graph_clean_up_tf)
        for_graph_and_each_sub_graph_recursively(graph, update_fully_connected_shapes)

        for_graph_and_each_sub_graph_recursively(graph, convert_mul_eltwise_to_leaky_relu)
        graph_clean_up_tf(graph)
        for_graph_and_each_sub_graph_recursively(graph, graph_clean_up_tf)

        for_graph_and_each_sub_graph_recursively(graph, fuse_pad)
        for_graph_and_each_sub_graph_recursively(graph, graph_clean_up_tf)

        for_graph_and_each_sub_graph_recursively(graph, convert_reshape)
        for_graph_and_each_sub_graph_recursively(graph, convert_squeeze)

        for_graph_and_each_sub_graph_recursively(graph, convert_add_to_scaleshift)  # scale = 1
        for_graph_and_each_sub_graph_recursively(graph, convert_mul_to_scaleshift)  # biases = 0

        if argv.reverse_input_channels:
            reverse_input_channels(graph)

        if argv.move_to_preprocess:
            move_scaleshift_to_preprocess(graph)
            graph_clean_up_tf(graph)

        for_graph_and_each_sub_graph_recursively(graph, fuse_sequence_of_reshapes)

        pattern = EltwiseInputNormalize()
        pattern.find_and_replace_pattern(graph)

        conv_flatten_concat(graph)

        for_graph_and_each_sub_graph_recursively(graph, apply_nhwc_to_nchw_permutation)
        for_graph_and_each_sub_graph_recursively(graph, merge_nodes_permutations)
        for_graph_and_each_sub_graph_recursively(graph, permute_data_nodes_attrs)
        for_graph_and_each_sub_graph_recursively(graph, permute_op_nodes_attrs)

        for_graph_and_each_sub_graph_recursively(graph, repack_fully_connected_weights_nhwc_to_nchw)
        for_graph_and_each_sub_graph_recursively(graph, transpose_fully_connected_weights)

        for_graph_and_each_sub_graph_recursively(graph, graph_clean_up_tf)

        if argv.offload_unsupported_operations_to_tf:
            unsupported_ops_to_offload_to_tf = find_unsupported_ops(graph)
            if len(unsupported_ops_to_offload_to_tf) == 0:
                log.info('All operations are supported! Exit from the loop.')
                if not need_to_repeat_conversion(graph):
                    break
            else:
                print('After {} iteration there are {} unsupported ops'.format(cur_iteration + 1,
                                                                               len(unsupported_ops_to_offload_to_tf)))
        else:
            if not need_to_repeat_conversion(graph):
                break

        graph = graph_copy
        cur_iteration += 1

    class_registration.apply_replacements(graph, class_registration.ClassType.BACK_REPLACER)

    prepare_emit_ir(graph=graph, data_type=argv.data_type, output_dir=output_dir, output_model_name=output_model_name,
                    meta_info=meta_info)

    return 0
Example #19
0
def driver(argv,
           input_model,
           output_model_name,
           outputs,
           output_dir,
           scale,
           placeholder_shapes=None,
           mean_scale_values=()):
    meta_info = get_meta_info(argv)

    EltwiseChecker.enabled = False

    try:
        graph, input_shapes = load_kaldi_model(input_model)
    except Exception as e:
        raise Error('Model Optimizer is not able to read Kaldi model {}. '.
                    format(input_model) + refer_to_faq_msg(91)) from e
    check_empty_graph(graph, 'load_kaldi_nnet_model')
    graph.graph['cmd_params'] = argv
    graph.graph['fw'] = 'kaldi'
    graph.graph['ir_version'] = 2 if argv.generate_deprecated_IR_V2 else 4

    update_extractors_with_extensions(kaldi_type_extractors)

    extract_node_attrs(graph, lambda node: kaldi_extractor(node))

    class_registration.apply_replacements(
        graph, class_registration.ClassType.FRONT_REPLACER)

    output_op_nodes = add_output_ops(
        graph, outputs)  # TODO pass real outputs instead of None
    log.debug("After adding specific nodes for outputs")
    print_graph_stat(graph)

    check_empty_graph(graph, 'add_output_ops')
    create_tensor_nodes(graph)

    graph_clean_up(graph)
    log.debug("After removing specific nodes for output")
    print_graph_stat(graph)

    override_placeholder_shapes(graph, placeholder_shapes)
    override_batch(graph, argv.batch)

    graph_clean_up(graph)
    log.debug("After setting input shapes")
    print_graph_stat(graph)
    graph_clean_up(graph)
    remove_output_ops(graph)
    log.debug("After removing specific nodes for output")
    print_graph_stat(graph)

    # You need to pass required network outputs here
    # but we don't have a way yet, so just passing all discovered sinks
    mark_outputs(graph)
    graph_clean_up(graph)
    log.debug("After graph_cleanup")
    print_graph_stat(graph)
    graph = partial_infer(graph)

    # The order is intentional, firstly eliminate repeated, then remove redundant
    FuseRepeatedReshapes().find_and_replace_pattern(graph)
    EliminateRedundantReshape().find_and_replace_pattern(graph)
    check_empty_graph(graph, 'partial_infer')
    if argv.counts:
        try:
            counts = read_counts_file(argv.counts)
        except Exception as e:
            raise Error('Model Optimizer is not able to read counts file {}'.
                        format(argv.counts) + refer_to_faq_msg(92)) from e

        apply_biases_to_last_layer(graph, counts)

    if argv.remove_output_softmax:
        RemoveLastSoftMaxPattern().find_and_replace_pattern(graph)
        graph_clean_up(graph)
        log.debug("After removing softmax")
        print_graph_stat(graph)

    # Intentionally after all transformations
    KaldiRemoveMemoryOutputBackReplacementPattern().find_and_replace_pattern(
        graph)
    prepare_emit_ir(graph,
                    argv.data_type,
                    output_dir,
                    output_model_name,
                    meta_info=meta_info)
    return 0
Example #20
0
def driver(argv: argparse.Namespace, input_model: str, output_model_name: str, outputs: list, output_dir: str,
           scale: float,
           placeholder_shapes: [None, list, np.array] = None,
           mean_scale_values: [dict, list] = ()):
    meta_info = get_meta_info(argv)

    try:
        model_nodes, model_params, model_name, iteration_number = load_symbol_def(input_model, argv.input_symbol,
                                                                                  argv.input,
                                                                                  argv.nd_prefix_name,
                                                                                  argv.pretrained_model_name,
                                                                                  argv.legacy_mxnet_model)
    except (ValueError, mxnet.base.MXNetError) as e:
        raise FrameworkError(
            'The following error happened while loading mxnet model {}: {}. ' +
            refer_to_faq_msg(53),
            input_model,
            str(e)
        ) from e

    if argv.nd_prefix_name and argv.pretrained_model_name and argv.save_params_from_nd:
        save_params_file(model_name, model_params._arg_params, model_params._aux_params, iteration_number)

    update_extractors_with_extensions(mxnet_op_extractors)
    graph = symbol2nx(model_nodes, model_params, argv.input)
    check_empty_graph(graph, 'symbol2nx. It may happen due to problems with loaded model')

    graph.__setattr__('name', output_model_name)
    graph.graph['layout'] = 'NCHW'
    graph.graph['cmd_params'] = argv
    graph.graph['fw'] = 'mxnet'
    graph.graph['feature_dim'] = 1 if graph.graph['layout'] == 'NCHW' else 3
    graph.graph['ir_version'] = 2 if argv.generate_deprecated_IR_V2 else 4
    graph = extract_node_attrs(graph, mxnet_op_extractor)
    check_softmax_node_inputs(graph)

    user_shapes, packed_outputs, _ = user_data_repack(graph, placeholder_shapes, outputs, None)
    output_op_nodes = add_output_ops(graph, packed_outputs)
    input_op_nodes = add_input_ops(graph, user_shapes, True)

    try:
        override_placeholder_shapes(graph, user_shapes, argv.batch)
    except ValueError as err:
        raise Error(
            'The following error happened while processing input shapes: {}. ' +
            refer_to_faq_msg(54),
            str(err)
        ) from err
    check_empty_graph(graph, 'add_output_ops and add_input_ops')

    class_registration.apply_replacements(graph, class_registration.ClassType.FRONT_REPLACER)
    add_input_data_to_prior_boxes(graph, argv.input)

    graph = create_tensor_nodes(graph)

    graph_clean_up(graph)
    remove_output_ops(graph)
    mark_outputs(graph)
    remove_output_ops(graph)

    graph_clean_up(graph)

    log.debug("After removing specific nodes for output")

    print_graph_stat(graph)

    graph = partial_infer(graph)
    graph_clean_up(graph)
    check_empty_graph(graph, 'partial_infer')

    duplicate_shared_weights(graph)

    scale_input(graph, scale)
    add_mean_scale_values(graph, mean_scale_values)

    remove_op_nodes(graph, {'identity': True})

    graph_clean_up(graph)

    class_registration.apply_replacements(graph, class_registration.ClassType.MIDDLE_REPLACER)
    fuse_pad(graph)

    # Mark nodes with attr 'can_be_fused': False to disable fusing for specified nodes
    mark_unfused_nodes(graph, argv.finegrain_fusing)

    # Converting FusedBatchNorm layer to Mul->Add->Mul->Add sequence
    convert_batch_norm(graph)
    graph_clean_up(graph)

    if not argv.disable_fusing:
        # Converting ScaleShift layer to Mul->Add
        convert_scale_shift_to_mul_add(graph)
        graph_clean_up(graph)

        # Fusing the sequences of Mul/Add operations
        fuse_mul_add_sequence(graph)
        graph_clean_up(graph)

        # Fusing linear operation to Convolution
        fuse_linear_ops(graph)
        graph_clean_up(graph)

    if not argv.disable_resnet_optimization:
        stride_optimization(graph)

    fuse_pad(graph)

    # Converting Mul->Add to ScaleShift node
    convert_muladd_to_scaleshift_or_power(graph)
    graph_clean_up(graph)

    convert_mul_add_to_power(graph)
    convert_add_to_scaleshift(graph)  # scale = 1
    convert_mul_to_scaleshift(graph)  # biases = 0

    if argv.reverse_input_channels:
        reverse_input_channels(graph)

    if argv.move_to_preprocess:
        move_scaleshift_to_preprocess(graph)
        graph_clean_up(graph)

    pattern = EltwiseInputNormalize()
    pattern.find_and_replace_pattern(graph)

    class_registration.apply_replacements(graph, class_registration.ClassType.BACK_REPLACER)

    prepare_emit_ir(graph=graph, data_type=argv.data_type, output_dir=output_dir, output_model_name=output_model_name,
                    meta_info=meta_info)
    return 0
Example #21
0
def driver(argv: argparse.Namespace,
           proto_file_name: str,
           model_file_name: str,
           output_model_name: str,
           outputs: list,
           output_dir: str,
           scale: float,
           user_shapes: [None, list, np.array] = None,
           mean_scale_values: [dict, list] = (),
           mean_file: str = "",
           mean_file_offsets: tuple = None,
           custom_layers_mapping_path: str = None):
    meta_info = get_meta_info(argv)

    FusePermutesSequence.enabled = False

    proto, model = loader.load_caffe_proto_model(proto_file_name,
                                                 model_file_name)

    update_extractors_with_extensions(
        caffe_type_extractors, argv.disable_omitting_optional if hasattr(
            argv, 'disable_omitting_optional') else False,
        argv.disable_flattening_optional_params if hasattr(
            argv, 'disable_flattening_optional_params') else False)

    try:
        graph, original_shapes = loader.caffe_pb_to_nx(proto, model)
    except ValueError as e:
        raise Error(
            'Invalid prototxt file: value error {}. ' + refer_to_faq_msg(11),
            str(e)) from e

    log.debug("After caffe_pb_to_nx")
    print_graph_stat(graph)
    check_empty_graph(graph, 'load_caffe_proto_model')

    graph.__setattr__('proto_path', proto_file_name)
    graph.__setattr__('caffemodel_path', model_file_name)
    graph.__setattr__('name',
                      getattr(proto, 'name', None) or output_model_name)
    graph.graph['layout'] = 'NCHW'
    graph.graph['cmd_params'] = argv
    graph.graph['fw'] = 'caffe'
    graph.graph['ir_version'] = 2 if argv.generate_deprecated_IR_V2 else 4

    extract_node_attrs(graph, lambda node: (True, common_caffe_fields(node)))

    log.debug("After adding specific nodes for outputs")
    print_graph_stat(graph)

    custom_layers_map = custom_layers_mapping.load_layers_xml(
        custom_layers_mapping_path)
    custom_layers_mapping.update_extractors(
        caffe_type_extractors,
        custom_layers_map, argv.disable_omitting_optional if hasattr(
            argv, 'disable_omitting_optional') else False,
        argv.enable_flattening_nested_params if hasattr(
            argv, 'enable_flattening_nested_params') else False)

    extract_node_attrs(
        graph, lambda node: caffe_extractor(
            node, check_for_duplicates(caffe_type_extractors)))

    log.debug("After extract_node_attr")
    print_graph_stat(graph)

    packed_user_shapes, packed_outputs, freeze_placeholder = user_data_repack(
        graph, user_shapes, outputs, argv.freeze_placeholder_with_value)
    if argv.freeze_placeholder_with_value is not None:
        FreezePlaceholderValue.enabled = True
        FreezePlaceholderValue.replacement_dict = freeze_placeholder
        class_registration.update_registration([FrontReplacementSubgraph])
    output_op_nodes = add_output_ops(graph, packed_outputs)
    input_op_nodes = add_input_ops(graph, packed_user_shapes, True)
    override_placeholder_shapes(graph, packed_user_shapes)
    override_batch(graph, argv.batch)
    graph_clean_up(graph)
    check_empty_graph(graph, 'add_output_ops and add_input_ops')
    class_registration.apply_replacements(
        graph, class_registration.ClassType.FRONT_REPLACER)

    graph = create_tensor_nodes(graph)

    log.debug("After create_tensor_nodes")
    print_graph_stat(graph)

    remove_op_nodes(graph, {'op': 'Identity'})
    remove_output_ops(graph)
    graph_clean_up(graph)

    log.debug("After removing specific nodes for output")
    print_graph_stat(graph)

    # you need to pass required network outputs here
    # but we don't have a way yet, so just passing all discovered sinks
    mark_outputs(graph)
    graph_clean_up(graph)
    log.debug("After graph_cleanup")
    print_graph_stat(graph)

    graph = partial_infer(graph)
    log.debug("After partial_infer")
    print_graph_stat(graph)
    check_empty_graph(graph, 'partial_infer')
    duplicate_shared_weights(graph)

    input_op_nodes = add_input_ops(graph, packed_user_shapes, False)
    graph_clean_up(graph)
    check_empty_graph(graph, 'add_input_ops')
    scale_input(graph, scale)

    add_mean_scale_values(graph, mean_scale_values)

    log.debug("Split multi input convolutions")
    convert_multi_input_conv(graph)

    graph_clean_up(graph)
    log.debug("After graph_cleanup")
    print_graph_stat(graph)

    remove_op_nodes(graph, {'op': 'Dropout'})
    remove_op_nodes(graph, {'phase': 0})
    graph_clean_up(graph)

    class_registration.apply_replacements(
        graph, class_registration.ClassType.MIDDLE_REPLACER)

    mean_to_avgpool(graph)

    # Mark nodes with attr 'can_be_fused': False to disable fusing for specified nodes
    mark_unfused_nodes(graph, argv.finegrain_fusing)

    #need this pass even without fusing to convert scale with 2 inputs
    convert_scale_shift_to_mul_add(graph)
    graph_clean_up(graph)

    if not argv.disable_fusing:
        convert_bn_to_mul_add(graph)
        graph_clean_up(graph)

        fuse_mul_add_sequence(graph)
        graph_clean_up(graph)

        fuse_linear_ops(graph)
        graph_clean_up(graph)

    if not argv.disable_resnet_optimization:
        stride_optimization(graph)

    convert_muladd_to_scaleshift_or_power(graph)
    convert_matmul_to_fully_connected(graph)
    batch_norm_fuse(graph)
    convert_mul_add_to_power(graph)
    convert_add_to_scaleshift(graph)  # scale = 1
    convert_mul_to_scaleshift(graph)  # biases = 0

    graph_clean_up(graph)
    log.debug("After graph_cleanup")
    print_graph_stat(graph)

    if argv.reverse_input_channels:
        reverse_input_channels(graph)

    if argv.move_to_preprocess:
        move_scaleshift_to_preprocess(graph)
        graph_clean_up(graph)

    fuse_sequence_of_reshapes(graph)

    input_names = find_inputs(graph)
    mf = []
    try:
        if mean_file and len(original_shapes) == 1:
            mf = loader.parse_mean(mean_file, original_shapes[input_names[0]],
                                   mean_file_offsets)
        elif mean_file:
            raise Error(
                'Mean file for topologies with multiple inputs is not supported. '
                + refer_to_faq_msg(9))
    except ValueError as e:
        raise Error(
            'Cannot load or process mean file: value error {}. ' +
            refer_to_faq_msg(10), str(e)) from e

    class_registration.apply_replacements(
        graph, class_registration.ClassType.BACK_REPLACER)

    prepare_emit_ir(graph=graph,
                    data_type=argv.data_type,
                    output_dir=output_dir,
                    output_model_name=output_model_name,
                    mean_data=mf,
                    input_names=input_names,
                    meta_info=meta_info)
    return 0
Example #22
0
 def infer(loop_node: Node):
     Loop.updated_body_parameters_shape(loop_node)
     partial_infer(loop_node.body)
     Loop.updated_loop_output_ports_shape_and_value(loop_node)
Example #23
0
def driver(argv: argparse.Namespace,
           model_file_name: str,
           output_model_name: str,
           outputs: list,
           output_dir: str,
           scale: float,
           user_shapes: [None, list, np.array] = None,
           mean_scale_values: [dict, list] = ()):

    meta_info = get_meta_info(argv)

    model_proto = load_onnx_model(model_file_name)
    model_graph = model_proto.graph  # pylint: disable=no-member
    #print(model_graph)
    #assert len(model_graph) == 1, "An ONNX model contains more than 1 graph: unsupported"
    log.debug("Number of nodes in graph_def: {}".format(len(model_graph.node)))
    log.debug(
        "Number of all input ports (not true inputs) in graph_def: {}".format(
            len(model_graph.input)))
    log.debug("Number of initializers in graph_def: {}".format(
        len(model_graph.initializer)))
    log.debug("Number of real inputs in graph_def: {}".format(
        len(model_graph.input) - len(model_graph.initializer)))
    update_extractors_with_extensions(onnx_op_extractors)

    try:
        graph = protobuf2nx(model_proto)
        log.debug("Number of nodes in NX graph: {}".format(
            graph.number_of_nodes()))
        graph.__setattr__(
            'name',
            output_model_name if output_model_name else model_proto.graph.name)  # pylint: disable=no-member
        graph.graph['layout'] = 'NCHW'
        graph.graph['cmd_params'] = argv
        graph.graph['fw'] = 'onnx'
        graph.graph[
            'feature_dim'] = 1 if graph.graph['layout'] == 'NCHW' else 3
        graph.graph['ir_version'] = 2 if argv.generate_deprecated_IR_V2 else 4
        # extract basic attributes earlier to enable some passes that relies on them before full attribute
        # extractor is called
        extract_node_attrs(graph, lambda node:
                           (True, common_onnx_fields(node)))
    except Exception as e:
        raise Error(
            'Cannot pre-process ONNX graph after reading from model file "{}". ' \
            'File is corrupt or has unsupported format. Details: {}. ' +
            refer_to_faq_msg(44),
            model_file_name,
            str(e)
        ) from e
    check_empty_graph(
        graph, 'protobuf2nx. It may happen due to problems with loaded model')
    packed_user_shapes, packed_outputs, _ = user_data_repack(
        graph, user_shapes, outputs, None)

    output_op_nodes = add_output_ops(graph, packed_outputs)
    input_op_nodes = add_input_ops(graph, packed_user_shapes, True)

    # this call of 'graph_clean_up' removes child nodes of outputs which is useful when custom output is specified
    graph_clean_up(graph)
    check_empty_graph(graph, 'add_output_ops and add_input_ops')
    extract_node_attrs(
        graph, lambda node: onnx_op_extractor(
            node, check_for_duplicates(onnx_op_extractors)))

    class_registration.apply_replacements(
        graph, class_registration.ClassType.FRONT_REPLACER)

    create_tensor_nodes(graph)
    graph_clean_up(graph)

    override_placeholder_shapes(graph, packed_user_shapes)
    override_batch(graph, argv.batch)

    graph_clean_up(graph)
    remove_op_nodes(graph, {'op': 'Identity'})

    graph_clean_up(graph)

    remove_output_ops(graph)

    partial_infer(graph)
    graph_clean_up(graph)
    check_empty_graph(graph, 'partial_infer')

    input_op_nodes = add_input_ops(graph, packed_user_shapes, False)
    graph_clean_up(graph)
    check_empty_graph(graph, 'add_input_ops')
    #change_placeholders_types_to_FP32(graph)

    scale_input(graph, scale)
    add_mean_scale_values(graph, mean_scale_values)

    convert_dilated_convolution(graph)
    graph_clean_up(graph)

    graph_clean_up(graph)

    remove_op_nodes(graph, {'op': 'Identity'})
    remove_useless_split(graph)

    class_registration.apply_replacements(
        graph, class_registration.ClassType.MIDDLE_REPLACER)

    convert_gemm_to_fully_connected(graph)
    NormalizeFullyConnected().find_and_replace_pattern(graph)

    fuse_pad(graph)
    graph_clean_up(graph)

    # Mark nodes with attr 'can_be_fused': False to disable fusing for specified nodes
    mark_unfused_nodes(graph, argv.finegrain_fusing)

    # Converting FusedBatchNorm layer to Mul->Add->Mul->Add sequence
    # IE doesn't support BN with 4 inputs, so we have to split it to two ScaleShift
    convert_batch_norm(graph)
    graph_clean_up(graph)

    if not argv.disable_fusing:
        # Converting ScaleShift layer to Mul->Add
        convert_scale_shift_to_mul_add(graph)
        graph_clean_up(graph)

        # Fusing the sequences of Mul/Add operations
        fuse_mul_add_sequence(graph)
        graph_clean_up(graph)

        # Fusing linear operation to Convolution
        fuse_linear_ops(graph)
        graph_clean_up(graph)

    if not argv.disable_gfusing:
        grouped_convolutions_fusing(graph)
        graph_clean_up(graph)
        if not argv.disable_fusing:
            fuse_linear_ops(graph)
            graph_clean_up(graph)

    convert_muladd_to_scaleshift_or_power(graph)
    graph_clean_up(graph)

    convert_mul_add_to_power(graph)
    graph_clean_up(graph)

    convert_reshape(graph)
    convert_add_to_scaleshift(graph)  # scale = 1
    convert_mul_to_scaleshift(graph)  # biases = 0

    fuse_pad(graph)
    graph_clean_up(graph)

    if argv.reverse_input_channels:
        reverse_input_channels(graph)

    if argv.move_to_preprocess:
        move_scaleshift_to_preprocess(graph)
        graph_clean_up(graph)

    fuse_sequence_of_reshapes(graph)
    graph_clean_up(graph)

    pattern = EltwiseInputNormalize()
    pattern.find_and_replace_pattern(graph)

    merge_nodes_permutations(graph)
    permute_data_nodes_attrs(graph)
    permute_op_nodes_attrs(graph)

    class_registration.apply_replacements(
        graph, class_registration.ClassType.BACK_REPLACER)

    prepare_emit_ir(graph=graph,
                    data_type=argv.data_type,
                    output_dir=output_dir,
                    output_model_name=output_model_name,
                    meta_info=meta_info)

    return 0