Ejemplo n.º 1
0
def save_restored_graph(graph: Graph, path: str, meta_data, name=None):
    """
    Function to apply all necessary transforms from back stage to prepare and save restored graph and metadata.
    :param graph: Graph to save
    :param path: Path to saved IR
    :param meta_data: Namespace with converting parameters restored from IR
    :param name: Name for saved IR
    :return:
    """

    if name is None:
        name = graph.name

    precision = data_type_str_to_precision(graph.graph['cmd_params'].data_type)
    assert precision in ['FP16', 'FP32'], 'Cannot define precision for restored model!'

    # List items order matters, do not change it.
    transformation_list = [
        ConvolutionWithGroupsResolver,
        StridedSliceMasksNormalizer,
        PackBinaryWeights,
        BlobNormalizer,
        ConvolutionNormalizer,
        KaldiRemoveMemoryOutputBackReplacementPattern,
    ]

    # We need to run some specific passes from MO back stage.
    apply_replacements_list(graph, transformation_list)

    # Transformations with enabled=False should be run manually.
    for_graph_and_each_sub_graph_recursively(graph, RemoveConstOps().find_and_replace_pattern)
    for_graph_and_each_sub_graph_recursively(graph, CreateConstNodesReplacement().find_and_replace_pattern)

    prepare_emit_ir(graph, precision, path, name, meta_info=meta_data)
Ejemplo n.º 2
0
def emit_ir(graph: Graph, argv: argparse.Namespace):
    NormalizeTI().find_and_replace_pattern(graph)
    for_graph_and_each_sub_graph_recursively(
        graph,
        RemoveConstOps().find_and_replace_pattern)
    for_graph_and_each_sub_graph_recursively(
        graph,
        CreateConstNodesReplacement().find_and_replace_pattern)

    prepare_emit_ir(
        graph=graph,
        data_type=graph.graph['cmd_params'].data_type,
        output_dir=argv.output_dir,
        output_model_name=argv.model_name,
        mean_data=graph.graph['mf'] if 'mf' in graph.graph else None,
        input_names=graph.graph['input_names']
        if 'input_names' in graph.graph else [],
        meta_info=get_meta_info(argv))

    if not (argv.framework == 'tf'
            and argv.tensorflow_custom_operations_config_update):
        output_dir = argv.output_dir if argv.output_dir != '.' else os.getcwd()
        print('\n[ SUCCESS ] Generated IR version {} model.'.format(
            get_ir_version(argv)))
        print('[ SUCCESS ] XML file: {}.xml'.format(
            os.path.join(output_dir, argv.model_name)))
        print('[ SUCCESS ] BIN file: {}.bin'.format(
            os.path.join(output_dir, argv.model_name)))

    return 0
Ejemplo n.º 3
0
def save_restored_graph(graph: Graph, path: str, meta_data, name=None):
    """
    Function to apply all necessary transforms from back stage to prepare and save restored graph and metadata.
    :param graph: Graph to save
    :param path: Path to saved IR
    :param meta_data: Namespace with converting parameters restored from IR
    :param name: Name for saved IR
    :return:
    """

    if name is None:
        name = graph.name

    if 'data_type' not in meta_data:
        log.debug(
            'Provided `meta_data` does not contain `data_type` parameter. Set `data_type`'
            ' parameter value to `FP32`.')
        # Set data_type to FP32. All restored constants will be saved in provided data type.
        data_type = 'FP32'

        # We need to specify this attribute to pass graph transformations. This information will not be saved into IR.
        # All constants and placeholders will be saved with same types as restored from IR
        graph.graph['cmd_params'].data_type = data_type
    else:
        data_type = data_type_str_to_precision(
            graph.graph['cmd_params'].data_type)

    assert data_type in ['FP16', 'FP32'], '`data_type` value {} is not supported by MO,' \
                                          ' cannot save graph'.format(data_type)

    # List items order matters, do not change it.
    transformation_list = [
        ConvolutionWithGroupsResolver,
        StridedSliceMasksNormalizer,
        PackBinaryWeights,
        BlobNormalizer,
        ConvolutionNormalizer,
        MarkNodesWithShapeValues,
    ]

    # We need to run some specific passes from MO back stage.
    apply_replacements_list(graph, transformation_list)

    # Transformations with enabled=False should be run manually.
    for_graph_and_each_sub_graph_recursively(
        graph,
        RemoveConstOps().find_and_replace_pattern)
    for_graph_and_each_sub_graph_recursively(
        graph,
        CreateConstNodesReplacement().find_and_replace_pattern)

    prepare_emit_ir(graph,
                    data_type,
                    path,
                    name,
                    meta_info=meta_data,
                    used_by_ir_reader=True)
Ejemplo n.º 4
0
    def find_and_replace_pattern(self, graph: Graph):
        for_graph_and_each_sub_graph_recursively(graph, lambda G: G.clean_up())

        EltwiseChecker().find_and_replace_pattern(graph)

        for_graph_and_each_sub_graph_recursively(graph, convert_muladd_to_scaleshift)
        for_graph_and_each_sub_graph_recursively(graph, lambda G: G.clean_up())

        for_graph_and_each_sub_graph_recursively(graph, convert_add_or_mul_to_scaleshift)
        for_graph_and_each_sub_graph_recursively(graph, lambda G: G.clean_up())
Ejemplo n.º 5
0
    def find_and_replace_pattern(self, graph: Graph):
        for_graph_and_each_sub_graph_recursively(graph, lambda G: G.clean_up())

        EltwiseChecker().find_and_replace_pattern(graph)

        # turn off run of transformation for body of TI due to error on TF_Multicell topology
        convert_muladd_to_scaleshift(graph)
        graph.clean_up()

        # turn off run of transformation for body of TI due to error on TF_Multicell topology
        convert_add_or_mul_to_scaleshift(graph)
        graph.clean_up()
Ejemplo n.º 6
0
def get_all_operation_nodes(graph: Graph, recursively: bool = False):
    """ Returns sequence of all nodes in graph
    :param graph: NetworkX model to take nodes
    :param recursively: whether return all nodes from the graph
    and each subgraph or only from the external graph
    :return list of all nodes
    """
    if recursively:
        get_all_op_nodes_func = FunctionResultsAccumulator(lambda graph: graph.get_op_nodes())
        for_graph_and_each_sub_graph_recursively(graph, get_all_op_nodes_func)
        return get_all_op_nodes_func.results

    return graph.get_op_nodes()
Ejemplo n.º 7
0
def emit_ir(graph: Graph, argv: argparse.Namespace):
    NormalizeTI().find_and_replace_pattern(graph)
    for_graph_and_each_sub_graph_recursively(
        graph,
        RemoveConstOps().find_and_replace_pattern)
    for_graph_and_each_sub_graph_recursively(
        graph,
        CreateConstNodesReplacement().find_and_replace_pattern)

    prepare_emit_ir(
        graph=graph,
        data_type=graph.graph['cmd_params'].data_type,
        output_dir=argv.output_dir,
        output_model_name=argv.model_name,
        mean_data=graph.graph['mf'] if 'mf' in graph.graph else None,
        input_names=graph.graph['input_names']
        if 'input_names' in graph.graph else [],
        meta_info=get_meta_info(argv))

    if not (argv.framework == 'tf'
            and argv.tensorflow_custom_operations_config_update):
        output_dir = argv.output_dir if argv.output_dir != '.' else os.getcwd()
        orig_model_name = os.path.normpath(
            os.path.join(output_dir, argv.model_name))

        # This try-except is additional reinsurance that the IE
        # dependency search does not break the MO pipeline
        try:
            if find_ie_version(silent=True):
                path_to_offline_transformations = os.path.join(
                    os.path.realpath(os.path.dirname(__file__)), 'back',
                    'offline_transformations.py')
                status = subprocess.run([
                    sys.executable, path_to_offline_transformations,
                    orig_model_name
                ],
                                        env=os.environ,
                                        timeout=100)
                if status.returncode != 0 and not argv.silent:
                    print("[ WARNING ] offline_transformations return code {}".
                          format(status.returncode))
        except Exception as e:
            # TODO: send error message
            pass

        print('[ SUCCESS ] Generated IR version {} model.'.format(
            get_ir_version(argv)))
        print('[ SUCCESS ] XML file: {}.xml'.format(orig_model_name))
        print('[ SUCCESS ] BIN file: {}.bin'.format(orig_model_name))

    return 0
Ejemplo n.º 8
0
def prepare_emit_ir(graph: Graph, data_type: str, output_dir: str, output_model_name: str,
                    mean_data: [list, None] = None, input_names: list = None, meta_info: dict = None):
    if input_names is None:
        input_names = []
    if meta_info is None:
        meta_info = {}
    graph.strict_mode = False

    # convert Parameter data types
    convert_data_type.convert_parameters_data_type(graph, data_type)
    # convert blobs (usually weights and biases)
    for sub_graph in [graph] + collect_sub_graphs(graph):
        convert_data_type.convert_blobs(sub_graph, data_type)

    # restore data type for specific inputs/outputs of specific ops to the data types required by nGraph
    if not graph.graph['cmd_params'].generate_deprecated_IR_V7:
        for_graph_and_each_sub_graph_recursively(graph, convert_inputs_of_specific_ops)

    if graph.graph['cmd_params'].generate_experimental_IR_V10:
        for_graph_and_each_sub_graph_recursively(graph, OpVersioning().find_and_replace_pattern)

    # do not run the type inference in sub-graphs. It will be called automatically as part of the type inference of
    # the TensorIterator nodes
    type_infer(graph)
    RemoveUselessConvert().find_and_replace_pattern(graph)

    for sub_graph in [graph] + collect_sub_graphs(graph):
        op_order, data_order = determined_sort(get_sorted_outputs(sub_graph))
        mapping = {v: u for u, v in enumerate(op_order)}
        mapping.update({v: u for u, v in enumerate(data_order, start=len(sub_graph))})
        relabel_nodes_inplace_safe(sub_graph, mapping)
        port_renumber(sub_graph)

    tensor_names.propagate_op_name_to_tensor(graph)

    bin_file = os.path.join(output_dir, '{}.bin'.format(output_model_name))
    serialize_constants(graph, bin_file)

    mean_offset = None
    mean_size = None
    if mean_data:
        mean_offset, mean_size = serialize_mean_image(bin_file, mean_data=mean_data)

    generate_ie_ir(graph=graph,
                   file_name=os.path.join(output_dir, '{}.xml'.format(output_model_name)),
                   input_names=input_names,
                   mean_offset=mean_offset,
                   mean_size=mean_size,
                   meta_info=meta_info)
    tensor_names.output_tensor_names_map(graph, os.path.join(output_dir, '{}.mapping'.format(output_model_name)))
Ejemplo n.º 9
0
def need_to_repeat_conversion(graph: nx.MultiDiGraph):
    """ Detects if another round of conversion is required for the entire graph.

        It traverses a given `graph` and all sub-graphs recursively and searches for
        'repeat_conversion' graph attribute. If at least one is found and its value is True,
        this function returns True.
    """
    result = False

    def check_for_repeat(graph: nx.MultiDiGraph):
        if 'repeat_conversion' in graph.graph and graph.graph['repeat_conversion']:
            nonlocal result
            result = True

    for_graph_and_each_sub_graph_recursively(graph, check_for_repeat)

    return result
Ejemplo n.º 10
0
def apply_transform(graph: Graph, replacer_cls, **kwargs):
    """
    Safely executes transform if it should be and validates graph after transform execution
    """
    replacer = replacer_cls()
    replacement_id = 'REPLACEMENT_ID'
    if hasattr(replacer, 'replacement_id'):
        replacement_id = replacer.replacement_id

    if hasattr(replacer, 'enabled') and not replacer.enabled:
        log.info("Skip replacer {} (enabled = False)".format(replacer_cls))
        return

    if hasattr(replacer, 'graph_condition') and \
            not all([condition(graph) for condition in replacer.graph_condition]):
        log.info("Skip replacer {} (graph_condition not satisfied)".format(
            replacer_cls))
        return

    log.debug("Run replacer {}".format(replacer_cls))

    try:
        if hasattr(replacer, 'run_not_recursively'):
            replacer.find_and_replace_pattern(graph)
        else:
            for_graph_and_each_sub_graph_recursively(
                graph, replacer.find_and_replace_pattern)

        if hasattr(replacer, 'force_clean_up') and replacer.force_clean_up:
            for_graph_and_each_sub_graph_recursively(graph,
                                                     lambda G: G.clean_up())

        if hasattr(replacer,
                   'force_shape_inference') and replacer.force_shape_inference:
            shape_inference(graph)

        for_graph_and_each_sub_graph_recursively(
            graph, lambda _: graph.check_empty_graph(replacer_cls))
        for_graph_and_each_sub_graph_recursively(
            graph, lambda _: graph.check_shapes_consistency())

    except Error as err:
        raise Error(
            'Exception occurred during running replacer "{}" ({}): {}'.format(
                replacement_id,
                replacer_cls,
                str(err).replace('[REPLACEMENT_ID]', replacement_id),
            )) from err
    except Exception as err:
        raise Exception(
            'Exception occurred during running replacer "{} ({})": {}'.format(
                replacement_id,
                replacer_cls,
                str(err).replace('[REPLACEMENT_ID]', replacement_id),
            )) from err
Ejemplo n.º 11
0
def send_op_names_info(framework: str, graph: Graph):
    """
    This function sends information about operations in model.
    :param framework: framework name.
    :param graph: model graph.
    """
    op_counter = Counter()

    def gather_op_statistics(g: Graph, op_c: Counter = op_counter):
        if hasattr(g, 'op_names_statistic'):
            op_c += g.op_names_statistic

    for_graph_and_each_sub_graph_recursively(graph, gather_op_statistics)

    t = tm.Telemetry()
    for op_name in op_counter:
        t.send_event('mo', 'op_count', "{}_{}".format(framework, op_name),
                     op_counter[op_name])
Ejemplo n.º 12
0
def get_nodes_by_type(graph: Graph, types: list, recursively: bool = False) -> list:
    """ Returns all nodes with type from types collection
     :param graph: NetworkX model to collect nodes
     :param types: list of required types
     :param recursively: whether return all nodes from the graph
     and each subgraph or only from the main graph
     :return list of nodes filtered by 'types' collection
      """
    def get_nodes_by_type_from_main_graph(graph, types):
        return [node for t in types for node in graph.get_op_nodes(type=t)]

    if recursively:
        partial_get_nodes_by_type = partial(get_nodes_by_type_from_main_graph, types=types)
        get_nodes_by_type_recursively = FunctionResultsAccumulator(partial_get_nodes_by_type)
        for_graph_and_each_sub_graph_recursively(graph, get_nodes_by_type_recursively)
        nodes = [node for node in get_nodes_by_type_recursively.results if node]
    else:
        nodes = get_nodes_by_type_from_main_graph(graph, types)
    return nodes
Ejemplo n.º 13
0
def get_node_by_name(graph: Graph, name: str, recursively: bool = False) -> Node:
    """ Returns node by name
    :param graph: NetworkX model to take node
    :param name: name of the node
    :param recursively: whether return all nodes from the graph
    and each subgraph or only from the external graph
    :return node from NetworkX model (of type Node or None if there's no such node)
    """
    if recursively:
        def get_node_by_fullname(graph: Graph, name: str) -> Node:
            nodes = graph.get_nodes_with_attributes(**dict(kind='op', fullname=name))
            return [Node(graph, nodes[0])] if nodes else None

        partial_get_node_by_fullname = partial(get_node_by_fullname, name=name)
        get_node_by_fullname_func = FunctionResultsAccumulator(partial_get_node_by_fullname)
        for_graph_and_each_sub_graph_recursively(graph, get_node_by_fullname_func)
        node = get_node_by_fullname_func.results
    else:
        node = graph.get_op_nodes(name=name)

    return node[0] if node else None
Ejemplo n.º 14
0
def apply_replacements(graph: Graph, replacements_type):
    """
    Apply all patterns that do not have 'op' first, then apply patterns from registered_ops.
    If two or more classes replaces the same op (both have op class attribute and values match), such
    pattern is not applied (while registration it will warn user that we have a conflict).
    """
    dependency_graph = Graph()
    for class_type, classes_set in _registered_classes_dict.items():
        if class_type == replacements_type:
            for cls in classes_set:
                replacers = [c for c in cls.registered_cls if not hasattr(c, 'op')] + \
                            [c for op, c in cls.registered_ops.items() if c]
                for replacer_cls in replacers:
                    if replacer_cls in cls.excluded_replacers:
                        # skip infrastructure classes
                        continue

                    dependency_graph.add_node(replacer_cls)
                    for cls_after in replacer_cls().run_before():
                        log.debug("Replacer {} will be run before {}".format(
                            replacer_cls, cls_after))
                        dependency_graph.add_edge(replacer_cls, cls_after)
                    for cls_before in replacer_cls().run_after():
                        log.debug("Replacer {} will be run after {}".format(
                            replacer_cls, cls_before))
                        dependency_graph.add_edge(cls_before, replacer_cls)

    try:
        replacers_order = list(nx.topological_sort(dependency_graph))
    except nx.NetworkXUnfeasible as exception:
        cycles = nx.simple_cycles(dependency_graph)
        raise Error(
            'There is(are) cyclic dependency(ies) between replacers. One of the cycles is the following: {}',
            ' -> '.join([str(node)
                         for node in list(cycles)[0]])) from exception

    for replacer_cls in replacers_order:
        replacer = replacer_cls()

        replacement_id = 'REPLACEMENT_ID'
        if hasattr(replacer, 'replacement_id'):
            replacement_id = replacer.replacement_id

        if hasattr(replacer, 'enabled') and not replacer.enabled:
            log.info("Skip replacer {} (enabled = False)".format(replacer_cls))
            continue

        if hasattr(replacer, 'graph_condition') and \
                not all([condition(graph) for condition in replacer.graph_condition]):
            log.info("Skip replacer {} (graph_condition not satisfied)".format(
                replacer_cls))
            continue

        log.debug("Run replacer {}".format(replacer_cls))

        try:
            replacer.find_and_replace_pattern(graph)

            if hasattr(replacer, 'force_clean_up') and replacer.force_clean_up:
                for_graph_and_each_sub_graph_recursively(
                    graph, graph_clean_up_tf
                    if graph.graph['fw'] == 'tf' else graph_clean_up_onnx
                    if graph.graph['fw'] == 'onnx' else graph_clean_up)

            for_graph_and_each_sub_graph_recursively(
                graph, lambda _: graph.check_empty_graph(replacer_cls))
            for_graph_and_each_sub_graph_recursively(
                graph, lambda _: graph.check_shapes_consistency())

        except Error as err:
            raise Error(
                'Exception occurred during running replacer "{}" ({}): {}'.
                format(
                    replacement_id,
                    replacer_cls,
                    str(err).replace('[REPLACEMENT_ID]', replacement_id),
                )) from err
        except Exception as err:
            raise Exception(
                'Exception occurred during running replacer "{} ({})": {}'.
                format(
                    replacement_id,
                    replacer_cls,
                    str(err).replace('[REPLACEMENT_ID]', replacement_id),
                )) from err
Ejemplo n.º 15
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'] = 5
    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)
    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_scale_shift_to_mul_add(graph)
    graph_clean_up_onnx(graph)

    fuse_mul_add_sequence(graph)
    graph_clean_up_onnx(graph)

    fuse_linear_ops(graph)
    graph_clean_up_onnx(graph)

    grouped_convolutions_fusing(graph)
    graph_clean_up_onnx(graph)

    fuse_linear_ops(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
Ejemplo n.º 16
0
def emit_ir(graph: Graph, argv: argparse.Namespace):
    NormalizeTI().find_and_replace_pattern(graph)
    for_graph_and_each_sub_graph_recursively(
        graph,
        RemoveConstOps().find_and_replace_pattern)
    for_graph_and_each_sub_graph_recursively(
        graph,
        CreateConstNodesReplacement().find_and_replace_pattern)

    mean_data = deepcopy(graph.graph['mf']) if 'mf' in graph.graph else None
    input_names = deepcopy(
        graph.graph['input_names']) if 'input_names' in graph.graph else []

    # Remove temporary ie_is_available key from argv no to have it in IR
    ie_is_available = argv.ie_is_available
    del argv.ie_is_available

    prepare_emit_ir(graph=graph,
                    data_type=graph.graph['cmd_params'].data_type,
                    output_dir=argv.output_dir,
                    output_model_name=argv.model_name,
                    mean_data=mean_data,
                    input_names=input_names,
                    meta_info=get_meta_info(argv),
                    use_temporary_path=True)

    # This graph cleanup is required to avoid double memory consumption
    graph.clear()

    if not (argv.framework == 'tf'
            and argv.tensorflow_custom_operations_config_update):
        output_dir = argv.output_dir if argv.output_dir != '.' else os.getcwd()
        orig_model_name = os.path.normpath(
            os.path.join(output_dir, argv.model_name))

        return_code = "not executed"
        # This try-except is additional reinsurance that the IE
        # dependency search does not break the MO pipeline
        try:
            if not argv.legacy_ir_generation and ie_is_available:
                path_to_offline_transformations = os.path.join(
                    os.path.realpath(os.path.dirname(__file__)), 'back',
                    'offline_transformations.py')
                status = subprocess.run([
                    sys.executable, path_to_offline_transformations,
                    "--input_model", orig_model_name, "--framework",
                    argv.framework, "--transform", argv.transform
                ],
                                        env=os.environ)
                return_code = status.returncode
        except Exception as e:
            return_code = "failed"
            log.error(e, extra={'is_warning': True})

        message = str(
            dict({
                "platform": platform.system(),
                "mo_version": get_simplified_mo_version(),
                "ie_version": get_simplified_ie_version(env=os.environ),
                "python_version": sys.version,
                "return_code": return_code
            }))
        t = tm.Telemetry()
        t.send_event('mo', 'offline_transformations_status', message)

        # if IR wasn't produced by offline_transformations step we need to fallback to IR
        # produced by prepare_ir. This IR needs to be renamed from XXX_tmp.xml to XXX.xml
        suffixes = [".xml", ".bin", ".mapping"]
        if return_code != 0:
            if len(argv.transform) != 0:
                # Remove temporary IR before throwing exception
                for suf in suffixes:
                    path_to_file = orig_model_name + "_tmp" + suf
                    if os.path.exists(path_to_file):
                        os.remove(path_to_file)
                raise Error("Failed to apply transformations: {}".format(
                    argv.transform))

            log.error("Using fallback to produce IR.",
                      extra={'is_warning': True})
            for suf in suffixes:
                # remove existing files
                path_to_file = orig_model_name + suf
                if os.path.exists(path_to_file):
                    os.remove(path_to_file)

                # rename tmp IR to original name
                os.rename(orig_model_name + "_tmp" + suf,
                          orig_model_name + suf)
        else:
            for suf in suffixes:
                # remove existing files
                path_to_file = orig_model_name + "_tmp" + suf
                if os.path.exists(path_to_file):
                    os.remove(path_to_file)

            # add meta information to IR
            append_ir_info(file=orig_model_name,
                           meta_info=get_meta_info(argv),
                           mean_data=mean_data,
                           input_names=input_names)

        print('[ SUCCESS ] Generated IR version {} model.'.format(
            get_ir_version(argv)))
        print('[ SUCCESS ] XML file: {}.xml'.format(orig_model_name))
        print('[ SUCCESS ] BIN file: {}.bin'.format(orig_model_name))

    return 0
Ejemplo n.º 17
0
    def find_and_replace_pattern(self, graph: Graph):
        fw = graph.graph['fw']
        argv = graph.graph['cmd_params']
        layout = graph.graph['layout']

        for_graph_and_each_sub_graph_recursively(graph, fuse_pad)
        for_graph_and_each_sub_graph_recursively(graph, lambda G: G.clean_up())

        # 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 batchNormInference with 4 inputs, so we have to split it to two ScaleShift
        for_graph_and_each_sub_graph_recursively(graph, convert_batch_norm)

        if fw == 'caffe':
            # 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, Div().find_and_replace_pattern)
        for_graph_and_each_sub_graph_recursively(graph, Sub().find_and_replace_pattern)
        for_graph_and_each_sub_graph_recursively(graph, lambda G: G.clean_up())

        if not argv.disable_fusing:
            if fw != 'caffe':
                # 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, lambda G: G.clean_up())

            # 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, lambda G: G.clean_up())

            normalize_eltwise_inputs(graph)
            for_graph_and_each_sub_graph_recursively(graph, lambda G: G.clean_up())

            # Fusing linear operation to Convolution
            for_graph_and_each_sub_graph_recursively(graph, fuse_linear_ops)
            for_graph_and_each_sub_graph_recursively(graph, lambda G: G.clean_up())

        if not argv.disable_gfusing:
            for_graph_and_each_sub_graph_recursively(graph, grouped_convolutions_fusing)
            for_graph_and_each_sub_graph_recursively(graph, lambda G: G.clean_up())
            if not argv.disable_fusing:
                for_graph_and_each_sub_graph_recursively(graph, fuse_linear_ops)
                for_graph_and_each_sub_graph_recursively(graph, lambda G: G.clean_up())

        for_graph_and_each_sub_graph_recursively(graph, normalize_eltwise_inputs)
        for_graph_and_each_sub_graph_recursively(graph, lambda G: G.clean_up())

        MarkNodesToFuseUpToFakeQuantize().find_and_replace_pattern(graph)
        FakeQuantizeFuse().find_and_replace_pattern(graph)
        AddFakeQuantizeFuse().find_and_replace_pattern(graph)
        MulFakeQuantizeFuse().find_and_replace_pattern(graph)
        for_graph_and_each_sub_graph_recursively(graph, lambda G: G.clean_up())

        for_graph_and_each_sub_graph_recursively(graph, fuse_pad)
        for_graph_and_each_sub_graph_recursively(graph, lambda G: G.clean_up())

        if layout != 'NHWC' and not argv.disable_resnet_optimization:
            stride_optimization(graph)
Ejemplo n.º 18
0
def driver(argv: argparse.Namespace, model_file_name: str, output_model_name: str, output_dir: str):
    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 5
    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)
    class_registration.apply_replacements(graph, class_registration.ClassType.MIDDLE_REPLACER)

    fuse_pad(graph)
    graph_clean_up_onnx(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_onnx(graph)

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

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

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

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

    AddQuantizeFuse().find_and_replace_pattern(graph)
    MulQuantizeFuse().find_and_replace_pattern(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)

    if argv.reverse_input_channels:
        reverse_input_channels(graph)

    if argv.move_to_preprocess:
        move_scaleshift_to_preprocess(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)

    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
Ejemplo n.º 19
0
def driver(onnx_modelproto_bytes, precision: str, output_model_name: str,
           output_dir: str):
    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['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,
            blobs_as_inputs=False,
            keep_quantize_ops_in_IR=False,
            generate_experimental_IR_V10=False)
        graph.graph['ir_version'] = 6

    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)
    class_registration.apply_replacements(
        graph, class_registration.ClassType.MIDDLE_REPLACER)

    fuse_pad(graph)
    graph_clean_up_onnx(graph)

    for_graph_and_each_sub_graph_recursively(
        graph, convert_matmul_to_fully_connected)

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

    # 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_onnx(graph)

    # Converting ScaleShift layer to Mul->Add
    convert_scale_shift_to_mul_add(graph)
    graph_clean_up_onnx(graph)

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

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

    grouped_convolutions_fusing(graph)
    graph_clean_up_onnx(graph)

    fuse_linear_ops(graph)
    graph_clean_up_onnx(graph)

    MarkNodesToFuseUpToFakeQuantize().find_and_replace_pattern(graph)
    FakeQuantizeFuse().find_and_replace_pattern(graph)

    AddFakeQuantizeFuse().find_and_replace_pattern(graph)
    MulFakeQuantizeFuse().find_and_replace_pattern(graph)

    convert_muladd_to_scaleshift(graph)
    graph_clean_up_onnx(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)

    FuseReshapesSequence().find_and_replace_pattern(graph)
    RemoveRedundantReshapes().find_and_replace_pattern(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)

    graph_clean_up_onnx(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
Ejemplo n.º 20
0
    def load(self, graph: Graph):
        argv = graph.graph['cmd_params']
        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_v1.load_op_library(library)

        graph_def, variables_values, framework = load_tf_graph_def(graph_file_name=argv.input_model,
                                                                   is_binary=not argv.input_model_is_text,
                                                                   checkpoint=argv.input_checkpoint,
                                                                   user_output_node_names_list=argv.output,
                                                                   model_dir=argv.saved_model_dir,
                                                                   meta_graph_file=argv.input_meta_graph,
                                                                   saved_model_tags=argv.saved_model_tags)
        send_framework_info(framework)

        try:
            tf_v1.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_util.dump_for_tensorboard(graph_def, argv.tensorboard_logdir)

        update_extractors_with_extensions(tf_op_extractors)

        try:
            protobuf2nx(graph, graph_def)
        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),
                argv.model_name,
                str(e)
            ) from e

        graph.__setattr__('name', argv.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['fw'] = 'tf'

        graph.graph['variables_values'] = variables_values
        del variables_values

        used_tensors = restore_edges(graph, get_tf_edges)

        # Tensor names information corresponding to a node is stored on outgoing edges.
        # As output nodes do not have outgoing edges, fake outputs are required. In the following code
        # for each output Identity node is added, and tensor name for the output is kept
        # on (output, fake output) edge. After Result nodes adding transformation fake outputs
        # are deleted from graph.
        add_outputs_identity(graph, graph.nodes - used_tensors, lambda g, output, fake_node_name: g.add_edges_from([
            create_tf_edge(output, fake_node_name, 0)]))

        remove_control_dependency_inputs(graph)

        graph.check_empty_graph('protobuf2nx. It may happen due to problems with loaded model')
        extract_node_attrs(graph, lambda node: tf_op_extractor(node, check_for_duplicates(tf_op_extractors)))

        # try to detect layout from the nodes of the graph. If there are no convolution nodes in N(D)HWC layout then we
        # consider that the graph is in NCHW layout and no layout conversion should be performed
        if not argv.disable_nhwc_to_nchw and not graph_or_sub_graph_has_nhwc_ops(graph):
            if not argv.silent:
                log.debug('disable_nhwc_to_nchw" was automatically enabled.')
            for_graph_and_each_sub_graph_recursively(graph, update_cmd_params_and_layout)

        send_op_names_info(framework, graph)
        send_shapes_info(framework, graph)
Ejemplo n.º 21
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
def save_restored_graph(graph: Graph, path: str, meta_data, name=None):
    """
    Function to apply all necessary transforms from back stage to prepare and save restored graph and metadata.
    :param graph: Graph to save
    :param path: Path to saved IR
    :param meta_data: Namespace with converting parameters restored from IR
    :param name: Name for saved IR
    :return:
    """

    if name is None:
        name = graph.name

    precisions = set()

    for op in graph.get_op_nodes():
        if op.type in ('Convolution', 'MatMul'):
            if op.in_port(1).get_source().node.type == 'FakeQuantize':
                data_type = op.in_port(1).get_source().node.in_port(
                    0).get_source().node.soft_get('data_type', None)
            else:
                data_type = op.in_port(1).get_source().node.soft_get(
                    'data_type', None)

            if data_type is not None:
                precisions.add(np_data_type_to_precision(data_type))
            else:
                log.warning(
                    'Cannot check data type for node {} with type {}, skip it.'
                    .format(op.name, op.type))

    precision = 'FP16' if 'FP16' in precisions else 'FP32'

    # We need to run some specific passes from MO back stage.
    # After some of them we need to clean up graph!
    for_graph_and_each_sub_graph_recursively(
        graph,
        ConvolutionWithGroupsResolver().find_and_replace_pattern)
    for_graph_and_each_sub_graph_recursively(
        graph,
        TopKNormalizer().find_and_replace_pattern)
    graph.clean_up()

    for_graph_and_each_sub_graph_recursively(
        graph,
        StridedSliceMasksNormalizer().find_and_replace_pattern)

    for_graph_and_each_sub_graph_recursively(
        graph,
        BlobNormalizer().find_and_replace_pattern)
    for_graph_and_each_sub_graph_recursively(
        graph,
        ConvolutionNormalizer().find_and_replace_pattern)
    for_graph_and_each_sub_graph_recursively(
        graph,
        RemoveConstOps().find_and_replace_pattern)
    for_graph_and_each_sub_graph_recursively(
        graph,
        CreateConstNodesReplacement().find_and_replace_pattern)

    prepare_emit_ir(graph, precision, path, name, meta_info=meta_data)
Ejemplo n.º 23
0
def driver(argv: argparse.Namespace, input_model: str, output_model_name: str,
           output_dir: str):
    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)
    graph.check_empty_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 5
    extract_node_attrs(graph, mxnet_op_extractor)

    # --------------------------------- LOAD END ------------------------------------------------------
    class_registration.apply_replacements(
        graph, class_registration.ClassType.FRONT_REPLACER)
    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)
    graph_clean_up(graph)
    convert_add_or_mul_to_scaleshift(graph)  # scale = 1
    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)

    pattern = EltwiseInputNormalize()
    pattern.find_and_replace_pattern(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)

    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
Ejemplo n.º 24
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
Ejemplo n.º 25
0
def tf2nx(argv: argparse.Namespace, model_file_name: str, output_model_name: str, output_dir: str,
          is_binary: bool):
    """
    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=argv.output,
                                                    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 5

        graph.graph['variables_values'] = variables_values
        del variables_values

        graph = restore_edges(graph, get_tf_edges)
        graph = remove_control_dependency_inputs(graph)
    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

    graph.check_empty_graph('protobuf2nx. It may happen due to problems with loaded model')
    extract_node_attrs(graph, lambda node: tf_op_extractor(node, check_for_duplicates(tf_op_extractors)))

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

    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, graph_clean_up_tf)

    for_graph_and_each_sub_graph_recursively(graph, convert_add_or_mul_to_scaleshift)  # scale = 1
    for_graph_and_each_sub_graph_recursively(graph, graph_clean_up_tf)

    if argv.reverse_input_channels:
        reverse_input_channels(graph)

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

    fuse_sequence_of_reshapes(graph)

    pattern = EltwiseInputNormalize()
    pattern.find_and_replace_pattern(graph)

    conv_flatten_concat(graph)

    if argv.enable_concat_optimization:
        ConcatOptimization().find_and_replace_pattern(graph)

    LayoutChangeForConstantShapePaths().find_and_replace_pattern(graph)
    for_graph_and_each_sub_graph_recursively(graph, graph_clean_up_tf)

    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)

    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)

    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
Ejemplo n.º 26
0
def emit_ir(graph: Graph, argv: argparse.Namespace):
    NormalizeTI().find_and_replace_pattern(graph)
    for_graph_and_each_sub_graph_recursively(
        graph,
        RemoveConstOps().find_and_replace_pattern)
    for_graph_and_each_sub_graph_recursively(
        graph,
        CreateConstNodesReplacement().find_and_replace_pattern)

    if 'feManager' in argv:
        del argv.feManager

    mean_data = deepcopy(graph.graph['mf']) if 'mf' in graph.graph else None
    input_names = deepcopy(
        graph.graph['input_names']) if 'input_names' in graph.graph else []

    prepare_emit_ir(graph=graph,
                    data_type=graph.graph['cmd_params'].data_type,
                    output_dir=argv.output_dir,
                    output_model_name=argv.model_name,
                    mean_data=mean_data,
                    input_names=input_names,
                    meta_info=get_meta_info(argv),
                    use_temporary_path=True)

    # This graph cleanup is required to avoid double memory consumption
    graph.clear()

    if not (argv.framework == 'tf'
            and argv.tensorflow_custom_operations_config_update):
        output_dir = argv.output_dir if argv.output_dir != '.' else os.getcwd()
        orig_model_name = os.path.normpath(
            os.path.join(output_dir, argv.model_name))

        return_code = "not executed"
        # This try-except is additional reinsurance that the IE
        # dependency search does not break the MO pipeline
        try:
            if not argv.legacy_ir_generation:
                path_to_offline_transformations = os.path.join(
                    os.path.realpath(os.path.dirname(__file__)), 'back',
                    'offline_transformations.py')
                cmd = [
                    sys.executable, path_to_offline_transformations,
                    "--input_model", orig_model_name, "--framework",
                    argv.framework, "--transform", argv.transform
                ]
                if "compress_fp16" in argv and argv.compress_fp16:
                    cmd += ["--compress_fp16"]
                    # restore data_type cmd parameter
                    argv.data_type = 'FP16'
                status = subprocess.run(cmd, env=os.environ)
                return_code = status.returncode
        except Exception as e:
            return_code = "failed"
            log.error(e)

        message = str(
            dict({
                "platform": platform.system(),
                "mo_version": get_simplified_mo_version(),
                "ie_version": get_simplified_ie_version(env=os.environ),
                "python_version": sys.version,
                "return_code": return_code
            }))
        t = tm.Telemetry()
        t.send_event('mo', 'offline_transformations_status', message)

        if return_code != 0:
            raise Error("offline transformations step has failed.")

        for suf in [".xml", ".bin", ".mapping"]:
            # remove existing files
            path_to_file = orig_model_name + "_tmp" + suf
            if os.path.exists(path_to_file):
                os.remove(path_to_file)

        # add meta information to IR
        append_ir_info(file=orig_model_name,
                       meta_info=get_meta_info(argv),
                       mean_data=mean_data,
                       input_names=input_names)

        print('[ SUCCESS ] Generated IR version {} model.'.format(
            get_ir_version(argv)))
        print('[ SUCCESS ] XML file: {}.xml'.format(orig_model_name))
        print('[ SUCCESS ] BIN file: {}.bin'.format(orig_model_name))

    return 0
Ejemplo n.º 27
0
def apply_replacements(graph: Graph, replacements_type):
    """
    Apply all patterns that do not have 'op' first, then apply patterns from registered_ops.
    If two or more classes replaces the same op (both have op class attribute and values match), such
    pattern is not applied (while registration it will warn user that we have a conflict).
    """
    dependency_graph = DependencyGraph(name=ClassType(replacements_type).name)
    for class_type, classes_set in _registered_classes_dict.items():
        if class_type == replacements_type:
            replacers = []
            for cls in classes_set:
                cur_cls_replacers = [c for c in cls.registered_cls if not hasattr(c, 'op')] + \
                                    [c for op, c in cls.registered_ops.items() if c]
                replacers.extend([
                    replacer for replacer in cur_cls_replacers
                    if replacer not in cls.excluded_replacers
                ])

            for replacer_cls in replacers:
                dependency_graph.add_node(replacer_cls)

            for replacer_cls in replacers:
                for cls_after in replacer_cls().run_before():
                    log.debug("Replacer {} will be run before {}".format(
                        replacer_cls, cls_after))
                    dependency_graph.add_edge(replacer_cls, cls_after)
                for cls_before in replacer_cls().run_after():
                    log.debug("Replacer {} will be run after {}".format(
                        replacer_cls, cls_before))
                    dependency_graph.add_edge(cls_before, replacer_cls)

    replacers_order = dependency_graph.determined_sort()
    for replacer_cls in replacers_order:
        replacer = replacer_cls()

        replacement_id = 'REPLACEMENT_ID'
        if hasattr(replacer, 'replacement_id'):
            replacement_id = replacer.replacement_id

        if hasattr(replacer, 'enabled') and not replacer.enabled:
            log.info("Skip replacer {} (enabled = False)".format(replacer_cls))
            continue

        if hasattr(replacer, 'graph_condition') and \
                not all([condition(graph) for condition in replacer.graph_condition]):
            log.info("Skip replacer {} (graph_condition not satisfied)".format(
                replacer_cls))
            continue

        log.debug("Run replacer {}".format(replacer_cls))

        try:
            if hasattr(replacer, 'run_not_recursively'):
                replacer.find_and_replace_pattern(graph)
            else:
                for_graph_and_each_sub_graph_recursively(
                    graph, replacer.find_and_replace_pattern)

            if hasattr(replacer, 'force_clean_up') and replacer.force_clean_up:
                for_graph_and_each_sub_graph_recursively(
                    graph, graph_clean_up_tf
                    if graph.graph['fw'] == 'tf' else graph_clean_up_onnx
                    if graph.graph['fw'] == 'onnx' else graph_clean_up)

            if hasattr(replacer, 'force_shape_inference'
                       ) and replacer.force_shape_inference:
                shape_inference(graph)

            for_graph_and_each_sub_graph_recursively(
                graph, lambda _: graph.check_empty_graph(replacer_cls))
            for_graph_and_each_sub_graph_recursively(
                graph, lambda _: graph.check_shapes_consistency())

        except Error as err:
            raise Error(
                'Exception occurred during running replacer "{}" ({}): {}'.
                format(
                    replacement_id,
                    replacer_cls,
                    str(err).replace('[REPLACEMENT_ID]', replacement_id),
                )) from err
        except Exception as err:
            raise Exception(
                'Exception occurred during running replacer "{} ({})": {}'.
                format(
                    replacement_id,
                    replacer_cls,
                    str(err).replace('[REPLACEMENT_ID]', replacement_id),
                )) from err