def test_mul_add_to_power_1(self): graph = self._create_graph_with_mul_add(np.array([3]), np.array([2])) graph_ref = build_graph(nodes_attributes, [ ('placeholder_1', 'placeholder_1_data'), ('placeholder_1_data', 'power_1'), ('power_1', 'power_1_data'), ('power_1_data', 'op_output'), ], { 'power_1': { 'scale': 3, 'shift': 2, 'power': 1 }, 'power_1_data': {} }) convert_muladd_to_scaleshift_or_power(graph) graph_clean_up(graph) (flag, resp) = compare_graphs(graph, graph_ref, 'add_1_data', 'power_1_data', check_op_attrs=True) self.assertTrue(flag, resp)
def test_mean_to_avg_1(self): graph = self._create_graph_with_mean(axis=np.array([1, 2])) graph_ref = build_graph( nodes_attributes, [ ('placeholder_1', 'placeholder_1_data'), ('placeholder_1_data', 'pool_1'), ('pool_1', 'pool_1_data'), ('pool_1_data', 'op_output'), ], { 'pool_1': { 'pool_method': 'avg', 'rounding_type': 'ceil', 'exclude_pad': 'true', 'op': 'AvgPool', 'shape': np.array([1, 227, 227, 3]) }, 'pool_1_data': { 'shape': np.array([1, 227, 227, 3]) } }) MeanToAvgPool().find_and_replace_pattern(graph) graph_clean_up(graph) (flag, resp) = compare_graphs(graph, graph_ref, 'mean_1_data', 'pool_1_data', check_op_attrs=True) self.assertTrue(flag, resp)
def grouped_convolutions_fusing(graph: Graph): while True: is_fused = False graph_clean_up(graph, ['TFCustomSubgraphCall', 'ShapeOf', 'Shape']) for node in graph.pseudo_topological_sort(): if node.kind == 'op' and len(node.out_nodes()) > 1: if node.soft_get('can_be_fused') == False: continue is_valid_convolutions = True last_layer = None next_nodes = get_next_operation(node) # Check that all operation after this one are Convolutions # and all convolutions has same output if len(next_nodes) > 1 and all(_node.soft_get('type') in ['Convolution', 'Deconvolution'] for _node in next_nodes): for conv in next_nodes: conv_outputs = get_next_operation(conv) if conv.soft_get('can_be_fused') == False: is_valid_convolutions = False if len(conv_outputs) != 1: is_valid_convolutions = False if last_layer is None: last_layer = conv_outputs[0].id elif conv_outputs[0].id != last_layer: is_valid_convolutions = False if is_valid_convolutions: is_fused = concat_convolutions(graph, node, Node(graph, last_layer)) if is_fused: break if not is_fused: break
def test_mul_add_neg_5(self): graph = self._create_graph_with_mul_add(np.array([3]), np.array([3, 2, 1])) graph_ref = build_graph( nodes_attributes, [ ('placeholder_1', 'placeholder_1_data'), ('placeholder_1_data', 'scaleshift_1'), ('scaleshift_1_w', 'scaleshift_1'), ('scaleshift_1_b', 'scaleshift_1'), ('scaleshift_1', 'add_1_data'), ], { 'scaleshift_1_w': { 'shape': np.array([3]), 'value': np.array([3, 3, 3]) }, 'scaleshift_1_b': { 'shape': np.array([3]), 'value': np.array([3, 2, 1]) }, 'add_1_data': { 'is_output': True } }) convert_muladd_to_scaleshift_or_power(graph) graph_clean_up(graph) (flag, resp) = compare_graphs(graph, graph_ref, 'add_1_data', 'add_1_data', check_op_attrs=True) self.assertTrue(flag, resp)
def test_variadic_split_non_zero(self): graph = build_graph(nodes_attributes, [('placeholder_1', 'placeholder_data'), ('placeholder_data', 'variadic_split'), ('variadic_split', 'variadic_split_data_1'), ('variadic_split_data_1', 'last'), ('last', 'last_data'), ('last_data', 'res'), ('axis_const', 'axis_const_data'), ('split_dim_const', 'split_dim_const_data'), ('axis_const_data', 'variadic_split', {'in': 1}), ('split_dim_const_data', 'variadic_split', {'in': 2}), ], nodes_with_edges_only=True) node = Node(graph, 'variadic_split') # extractor should do it node['out_ports_count'] = 3 for p in range(len(node.out_edges()), node.out_ports_count): node.add_output_port(p) replacer = AddFakeOutputsToVariadicSplit() replacer.find_and_replace_pattern(graph) for n in graph.get_op_nodes(): n['need_shape_inference'] = False graph_clean_up(graph) self.assertTrue(len(node.out_edges()) == 3)
def test_scaleshift2_axis1_to_mul(self): graph = build_graph( nodes_attributes, [ ('placeholder_1', 'placeholder_1_data'), ('placeholder_2', 'placeholder_2_data'), ('placeholder_1_data', 'scaleshift_1'), ('placeholder_2_data', 'scaleshift_1'), ('scaleshift_1', 'scaleshift_1_data'), ], { 'placeholder_1_data': { 'shape': np.array([1, 227, 227, 3]) }, 'placeholder_2_data': { 'shape': np.array([227]) }, 'scaleshift_1': { 'axis': 1 }, 'scaleshift_1_data': { 'is_output': True } }) graph_ref = build_graph( nodes_attributes, [ ('placeholder_1', 'placeholder_1_data'), ('placeholder_2', 'placeholder_2_data'), ('placeholder_2_data', 'placeholder_2/Reshape_'), ('placeholder_2/Reshape_', 'placeholder_2/Reshape_data'), ('placeholder_1_data', 'mul_1'), ('placeholder_2/Reshape_data', 'mul_1'), ('mul_1', 'scaleshift_1_data'), ], { 'placeholder_1_data': { 'shape': np.array([1, 227, 227, 3]) }, 'placeholder_2_data': { 'shape': np.array([227]) }, 'placeholder_2/Reshape_': { 'dim': np.array([1, 227, 1, 1]) }, 'placeholder_2/Reshape_data': { 'shape': np.array([1, 227, 1, 1]) }, 'mul_1': { 'can_be_fused': True }, 'scaleshift_1_data': { 'is_output': True } }) graph.graph['layout'] = 'NHWC' convert_scale_shift_to_mul_add(graph) graph_clean_up(graph) (flag, resp) = compare_graphs(graph, graph_ref, 'scaleshift_1_data') self.assertTrue(flag, resp)
def test_scaleshift_to_mul_2(self): graph = build_graph( nodes_attributes, [('placeholder_1', 'placeholder_1_data'), ('placeholder_1_data', 'scaleshift_1'), ('const_scaleshift_1_w', 'scaleshift_1_w'), ('const_scaleshift_1_b', 'scaleshift_1_b'), ('scaleshift_1_w', 'scaleshift_1'), ('scaleshift_1_b', 'scaleshift_1'), ('scaleshift_1', 'scaleshift_1_data'), ('scaleshift_1_data', 'op_output')], { 'placeholder_1_data': { 'shape': np.array([1, 227, 227, 3]) }, 'scaleshift_1_w': { 'shape': np.array([3]), 'value': np.array([1, 2, 3]) }, 'scaleshift_1_b': { 'shape': np.array([3]), 'value': np.array([0, 0, 0]) }, 'scaleshift_1_data': {} }) graph_ref = build_graph( nodes_attributes, [('placeholder_1', 'placeholder_1_data'), ('placeholder_1_data', 'mul_1'), ('const_mul_1_w', 'mul_1_w'), ('mul_1_w', 'mul_1'), ('mul_1', 'scaleshift_1_data'), ('scaleshift_1_data', 'op_output')], { 'placeholder_1_data': { 'shape': np.array([1, 227, 227, 3]) }, 'const_mul_1_w': { 'shape': np.array([3]), 'value': np.array([1, 2, 3]) }, 'mul_1_w': { 'shape': np.array([3]), 'value': np.array([1, 2, 3]) }, 'mul_1': { 'can_be_fused': True }, 'scaleshift_1_data': {} }) graph.graph['layout'] = 'NHWC' convert_scale_shift_to_mul_add(graph) graph_clean_up(graph) (flag, resp) = compare_graphs(graph, graph_ref, 'placeholder_1') self.assertTrue(flag, resp)
def test_mul_to_scaleshift_1(self): graph = AddToScaleShift._create_graph_with_mul( np.array([1, 2, 3], dtype=np.float32)) graph.stage = 'middle' graph_ref = build_graph(nodes_attributes, [('placeholder_1', 'placeholder_1_data'), ('placeholder_1_data', 'scaleshift_1'), ('const_scaleshift_1_w', 'scaleshift_1_w'), ('const_scaleshift_1_b', 'scaleshift_1_b'), ('scaleshift_1_w', 'scaleshift_1'), ('scaleshift_1_b', 'scaleshift_1'), ('scaleshift_1', 'scaleshift_1_data'), ('scaleshift_1_data', 'op_output')], { 'placeholder_1_data': { 'shape': np.array([1, 227, 227, 3]) }, 'scaleshift_1_data': { 'shape': np.array([1, 227, 227, 3]) }, 'const_scaleshift_1_w': { 'shape': np.array([3]), 'value': np.array([1, 2, 3]) }, 'scaleshift_1_w': { 'shape': np.array([3]), 'value': np.array([1, 2, 3]) }, 'const_scaleshift_1_b': { 'shape': np.array([3]), 'value': np.array([0, 0, 0]) }, 'scaleshift_1_b': { 'shape': np.array([3]), 'value': np.array([0, 0, 0]) }, }, nodes_with_edges_only=True) convert_add_or_mul_to_scaleshift(graph) graph_clean_up(graph) (flag, resp) = compare_graphs(graph, graph_ref, 'op_output') self.assertTrue(flag, resp) scsh_node = Node(graph, 'op_output').in_port(0).get_source().node self.assertTrue( graph.get_edge_data(scsh_node.in_node(1).id, scsh_node.id)[0] ['bin'] == 'weights') self.assertTrue( graph.get_edge_data(scsh_node.in_node(2).id, scsh_node.id)[0] ['bin'] == 'biases')
def test_mul_add_neg_3(self): graph = self._create_graph_with_mul_add(None, None) graph_ref = self._create_graph_with_mul_add(None, None) convert_muladd_to_scaleshift_or_power(graph) graph_clean_up(graph) (flag, resp) = compare_graphs(graph, graph_ref, 'add_1_data', 'add_1_data', check_op_attrs=True) self.assertTrue(flag, resp)
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 test_mark_ops_producing_constant_values(self): """ Checks case when operation produces only constant tensors so it could be removed. If the node produces several tensors and at least one of them is not constant then we should not mark this node. The graph contains data nodes. "data_node_2" and "data_node_5" are output. "node_3" produces constant tensor "data_node_3" and non-constant tensor "data_node_3_2". "node_6" produces constant tensor "data_node_6". "node_4" could be eliminated since it gets constant input. node_6->data_node_6-> \ placeholder_1->placeholder_1_data_node->node_1->data_node_1->node_2->data_node_2 / node_3->data_node_3->node_4->data_node_4-> \ ->data_node_3_2->node_5->data_node_5 :return: None """ graph = build_graph(nodes_attributes, [('placeholder_1', 'placeholder_1_data_node'), ('placeholder_1_data_node', 'node_1'), ('node_1', 'data_node_1'), ('data_node_1', 'node_2'), ('node_2', 'data_node_2'), ('node_3', 'data_node_3'), ('node_3', 'data_node_3_2'), ('node_6', 'data_node_6'), ('data_node_6', 'node_1'), ('data_node_3_2', 'node_5'), ('node_5', 'data_node_5'), ('data_node_3', 'node_4'), ('data_node_4', 'node_1'), ('data_node_2', 'op_output'), ('data_node_5', 'op_output_1') ], {'data_node_2': {}, 'data_node_5': {}, 'data_node_3': {'value': np.array(1)}, 'data_node_6': {'value': np.array(1)}}, nodes_with_edges_only=True) mark_const_producer_nodes(graph) self.assertTrue((graph.node['node_6']['is_const_producer'])) self.assertListEqual(sorted(['node_1', 'node_2', 'node_3', 'node_5', 'placeholder_1']), sorted(graph.get_nodes_with_attributes(is_const_producer=False, kind='op'))) graph_clean_up(graph) self.assertTrue('node_3' in graph.nodes()) self.assertTrue('node_4' not in graph.nodes()) self.assertTrue('node_6' not in graph.nodes())
def test_mul_add_neg_4(self): graph = self._create_graph_with_mul_add(np.array([1, 2, 3]), np.array([3])) graph_ref = self._create_graph_with_mul_add(np.array([1, 2, 3]), np.array(3)) convert_muladd_to_scaleshift_or_power(graph) graph_clean_up(graph) (flag, resp) = compare_graphs(graph, graph_ref, 'add_1_data', 'add_1_data', check_op_attrs=True) self.assertTrue(flag, resp)
def test_output_port_cut(self, output): nodes = {'A': {'op': 'Placeholder', 'kind': 'op'}, 'B': {'op': 'Placeholder', 'kind': 'op'}, 'C': {'type': 'Identity', 'kind': 'op'}, 'D': {'type': 'Identity', 'kind': 'op'}, 'E': {'type': 'Identity', 'kind': 'op'}, } edges = [ ('A', 'C', {'in': 0, 'out': 0}), ('B', 'C', {'in': 1, 'out': 0}), ('C', 'D', {'in': 0, 'out': 0}), ('C', 'E', {'in': 0, 'out': 1}) ] graph = build_graph_with_edge_attrs(nodes, edges) sinks = add_output_ops(graph, output) eliminate.graph_clean_up(graph) self.assertEqual(len(graph.nodes()), 2)
def test_duplicate_shared_weights_1(self): graph = build_graph(nodes_attributes, [ ('const', 'mul_1_w'), ('mul_1_w', 'mul_1'), ('mul_1', 'mul_1_data'), ('mul_1_w', 'mul_2'), ('mul_2', 'mul_2_data'), ('mul_1_w', 'mul_3'), ('mul_3', 'mul_3_data'), ('mul_1_data', 'concat_1'), ('mul_2_data', 'concat_1'), ('mul_3_data', 'concat_1'), ('concat_1', 'concat_1_data'), ('concat_1_data', 'op_output') ], {'mul_1_w': { 'shape': np.array([3]), 'value': np.array([1, 2, 3]) }}, nodes_with_edges_only=True) graph_ref = build_graph(nodes_attributes, [('mul_1_w', 'mul_1'), ('mul_1', 'mul_1_data'), ('mul_2_w', 'mul_2'), ('mul_2', 'mul_2_data'), ('mul_3_w', 'mul_3'), ('mul_3', 'mul_3_data'), ('mul_1_data', 'concat_1'), ('mul_2_data', 'concat_1'), ('mul_3_data', 'concat_1'), ('concat_1', 'concat_1_data'), ('concat_1_data', 'op_output')], { 'mul_1_w': { 'shape': np.array([3]), 'value': np.array([1, 2, 3]) }, 'mul_2_w': { 'shape': np.array([3]), 'value': np.array([1, 2, 3]) }, 'mul_3_w': { 'shape': np.array([3]), 'value': np.array([1, 2, 3]) }, }, nodes_with_edges_only=True) SharedWeightsDuplication().find_and_replace_pattern(graph) graph_clean_up(graph) graph_clean_up(graph_ref) (flag, resp) = compare_graphs(graph, graph_ref, 'concat_1_data') self.assertTrue(flag, resp)
def test_mean_to_avg_2(self): graph = self._create_graph_with_mean(axis=np.array([0]), keep_dims=False, mean_out_shape=np.array([227, 227, 3])) graph_ref = build_graph(nodes_attributes, [('placeholder_1', 'placeholder_1_data'), ('placeholder_1_data', 'pool_1'), ('pool_1', 'pool_1_data'), ('pool_1_data', 'reshape_1'), ('reshape_1', 'reshape_1_data') ], {'pool_1': {'pool_method': 'avg', 'rounding_type': 'ceil', 'exclude_pad': 'true', 'op': 'AvgPool', 'shape': np.array([1, 227, 227, 3])}, 'pool_1_data': {'shape': np.array([1, 227, 227, 3])}, 'reshape_1_data': {'is_output': True, 'shape': np.array([227, 227, 3])}, }) mean_to_avgpool(graph) graph_clean_up(graph) (flag, resp) = compare_graphs(graph, graph_ref, 'mean_1_data', 'reshape_1_data', check_op_attrs=True) self.assertTrue(flag, resp)
def test_scaleshift_to_nothing(self): graph = build_graph(nodes_attributes, [('placeholder_1', 'placeholder_1_data'), ('placeholder_1_data', 'scaleshift_1'), ('const_scaleshift_1_w', 'scaleshift_1_w'), ('const_scaleshift_1_b', 'scaleshift_1_b'), ('scaleshift_1_w', 'scaleshift_1'), ('scaleshift_1_b', 'scaleshift_1'), ('scaleshift_1', 'scaleshift_1_data'), ('scaleshift_1_data', 'op_output')], { 'placeholder_1_data': { 'shape': np.array([1, 227, 227, 3]) }, 'scaleshift_1_w': { 'shape': np.array([3]), 'value': np.array([1, 1, 1]) }, 'scaleshift_1_b': { 'shape': np.array([3]), 'value': np.array([0, 0, 0]) }, 'scaleshift_1_data': { 'shape': np.array([1, 227, 227, 3]) } }, nodes_with_edges_only=True) graph_ref = build_graph( nodes_attributes, [('placeholder_1', 'placeholder_1_data'), ('placeholder_1_data', 'op_output')], {'placeholder_1_data': { 'shape': np.array([1, 227, 227, 3]) }}, nodes_with_edges_only=True) graph.graph['layout'] = 'NHWC' convert_scale_shift_to_mul_add(graph) graph_clean_up(graph) (flag, resp) = compare_graphs(graph, graph_ref, 'placeholder_1') self.assertTrue(flag, resp)
def driver(argv: argparse.Namespace, proto_file_name: str, model_file_name: str, output_model_name: str, output_dir: str, caffe_proto_path: str, mean_file: str = "", mean_file_offsets: tuple = None, custom_layers_mapping_path: str = None): log_step(argv.steps, 'LOAD') meta_info = get_meta_info(argv) caffe_pb2 = loader.import_caffe_pb2(caffe_proto_path) proto, model = loader.load_caffe_proto_model(caffe_pb2, 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") graph.print_graph_stat() graph.check_empty_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' 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 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))) # --------------------------------- LOAD END ------------------------------------------------------ log_step(argv.steps, 'FRONT') class_registration.apply_replacements( graph, class_registration.ClassType.FRONT_REPLACER) log_step(argv.steps, 'MIDDLE') class_registration.apply_replacements( graph, class_registration.ClassType.MIDDLE_REPLACER) # 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(graph) convert_matmul_to_fully_connected(graph) batch_norm_fuse(graph) convert_add_or_mul_to_scaleshift(graph) # scale = 1 graph_clean_up(graph) log.debug("After graph_cleanup") graph.print_graph_stat() if argv.reverse_input_channels: reverse_input_channels(graph) if argv.move_to_preprocess: move_scaleshift_to_preprocess(graph) graph_clean_up(graph) FuseReshapesSequence().find_and_replace_pattern(graph) RemoveRedundantReshapes().find_and_replace_pattern(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, caffe_pb2) 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 merge_nodes_permutations(graph) permute_data_nodes_attrs(graph) permute_op_nodes_attrs(graph) graph_clean_up(graph) log_step(argv.steps, 'BACK') class_registration.apply_replacements( graph, class_registration.ClassType.BACK_REPLACER) remove_const_ops(graph) CreateConstNodesReplacement().find_and_replace_pattern(graph) remove_output_ops(graph) log_step(argv.steps, 'EMIT') 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
def test_bn_decomposition_1(self): graph = build_graph( nodes_attributes, [('placeholder_1', 'placeholder_1_data'), ('placeholder_1_data', 'bn_op'), ('bn_const', 'bn_op'), ('bn_beta', 'bn_op'), ('bn_mean', 'bn_op'), ('bn_var', 'bn_op'), ('bn_op', 'bn_data'), ('concat', 'concat_data'), ('bn_data', 'concat')], { 'placeholder_1_data': { 'shape': np.array([1, 227, 227, 3]) }, 'bn_op': { 'eps': 1.2 }, 'bn_const': { 'shape': np.array([3]), 'value': np.array([1, 2, 3]) }, 'bn_beta': { 'shape': np.array([3]), 'value': np.array([1, 2, 3]) }, 'bn_mean': { 'shape': np.array([3]), 'value': np.array([1, 2, 3]) }, 'bn_var': { 'shape': np.array([3]), 'value': np.array([1, 2, 3]) }, 'bn_data': { 'shape': np.array([1, 227, 227, 3]) }, 'concat_data': { 'is_output': True } }) graph_ref = build_graph( nodes_attributes, [('placeholder_1', 'placeholder_1_data'), ('placeholder_1_data', 'mul_1'), ('mul_1_w', 'mul_1'), ('mul_1', 'mul_1_data'), ('mul_1_data', 'add_1'), ('add_1_w', 'add_1'), ('add_1', 'add_1_data'), ('add_1_data', 'mul_2'), ('mul_2_w', 'mul_2'), ('mul_2', 'mul_2_data'), ('mul_2_data', 'add_2'), ('add_2_w', 'add_2'), ('add_2', 'add_2_data'), ('concat', 'concat_data'), ('add_2_data', 'concat')], { 'placeholder_1_data': { 'shape': np.array([1, 227, 227, 3]) }, 'mul_1_w': { 'shape': np.array([3]), 'value': np.array([0.67419986, 0.55901699, 0.48795004]) }, 'mul_2_w': { 'shape': np.array([3]), 'value': np.array([1, 2, 3]) }, 'add_1_w': { 'shape': np.array([3]), 'value': np.array([-0.67419986, -1.11803399, -1.46385011]) }, 'add_2_w': { 'shape': np.array([3]), 'value': np.array([1, 2, 3]) }, 'add_2_data': { 'shape': np.array([1, 227, 227, 3]) }, 'mul_1': { 'can_be_fused': True }, 'mul_2': { 'can_be_fused': True }, 'add_1': { 'can_be_fused': True }, 'add_2': { 'can_be_fused': True }, 'concat_data': { 'is_output': True } }) graph.graph['layout'] = 'NHWC' convert_batch_norm(graph) graph_clean_up(graph) (flag, resp) = compare_graphs(graph, graph_ref, 'concat_data') self.assertTrue(flag, resp)
def test_caffe_bn_decomposition_2(self): graph = build_graph( nodes_attributes, [('placeholder_1', 'placeholder_1_data'), ('placeholder_1_data', 'bn_op'), ('bn_mean', 'bn_op'), ('bn_var', 'bn_op'), ('bn_op', 'bn_data'), ('concat', 'concat_data'), ('bn_data', 'concat')], { 'placeholder_1_data': { 'shape': np.array([1, 227, 227, 3]) }, 'bn_op': { 'epsilon': 1.2, 'op': 'BatchNormalization', 'can_be_fused': False }, 'bn_mean': { 'shape': np.array([3]), 'value': np.array([1, 2, 3]) }, 'bn_var': { 'shape': np.array([3]), 'value': np.array([1, 2, 3]) }, 'bn_data': { 'shape': np.array([1, 227, 227, 3]) }, 'concat_data': { 'is_output': True } }) del graph['placeholder_1']['placeholder_1_data'][0]['in'] del graph['bn_op']['bn_data'][0]['in'] graph_ref = build_graph( nodes_attributes, [('placeholder_1', 'placeholder_1_data'), ('placeholder_1_data', 'mul_1'), ('mul_1_w', 'mul_1'), ('mul_1', 'mul_1_data'), ('mul_1_data', 'add_1'), ('add_1_w', 'add_1'), ('add_1', 'add_1_data'), ('concat', 'concat_data'), ('add_1_data', 'concat')], { 'placeholder_1_data': { 'shape': np.array([1, 227, 227, 3]) }, 'mul_1_w': { 'shape': np.array([3]), 'value': np.array([0.67419986, 0.55901699, 0.48795004]) }, 'add_1_w': { 'shape': np.array([3]), 'value': np.array([-0.67419986, -1.11803399, -1.46385011]) }, 'add_1_data': { 'shape': np.array([1, 227, 227, 3]) }, 'mul_1': { 'can_be_fused': False }, 'add_1': { 'can_be_fused': False }, 'concat_data': { 'is_output': True } }) graph.graph['layout'] = 'NHWC' convert_bn_to_mul_add(graph) graph_clean_up(graph) (flag, resp) = compare_graphs(graph, graph_ref, 'concat_data') self.assertTrue(flag, resp)
def test_scaleshift_can_be_fused(self): graph = build_graph( nodes_attributes, [ ('placeholder_1', 'placeholder_1_data'), ('placeholder_1_data', 'scaleshift_1'), ('scaleshift_1_w', 'scaleshift_1'), ('scaleshift_1_b', 'scaleshift_1'), ('scaleshift_1', 'scaleshift_1_data'), ], { 'placeholder_1_data': { 'shape': np.array([1, 227, 227, 3]) }, 'scaleshift_1_w': { 'shape': np.array([3]), 'value': np.array([1, 1, 1]) }, 'scaleshift_1_b': { 'shape': np.array([3]), 'value': np.array([0, 0, 0]) }, 'scaleshift_1': { 'can_be_fused': False }, 'scaleshift_1_data': { 'shape': np.array([1, 227, 227, 3]), 'is_output': True } }) graph_ref = build_graph( nodes_attributes, [ ('placeholder_1', 'placeholder_1_data'), ('placeholder_1_data', 'scaleshift_1'), ('scaleshift_1_w', 'scaleshift_1'), ('scaleshift_1_b', 'scaleshift_1'), ('scaleshift_1', 'scaleshift_1_data'), ], { 'placeholder_1_data': { 'shape': np.array([1, 227, 227, 3]) }, 'scaleshift_1_w': { 'shape': np.array([3]), 'value': np.array([1, 1, 1]) }, 'scaleshift_1_b': { 'shape': np.array([3]), 'value': np.array([0, 0, 0]) }, 'scaleshift_1': { 'can_be_fused': False }, 'scaleshift_1_data': { 'shape': np.array([1, 227, 227, 3]), 'is_output': True } }) convert_scale_shift_to_mul_add(graph) graph_clean_up(graph) (flag, resp) = compare_graphs(graph, graph_ref, 'scaleshift_1_data') self.assertTrue(flag, resp)
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
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
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
def graph_clean_up_onnx(graph: Graph): graph_clean_up(graph, ['Shape'])
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 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
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
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