def replace_pattern(self, graph: nx.MultiDiGraph, match: dict): node = match['slice'] # Caffe case if not node.has_valid('start') or not node.has_valid('end'): return begin = node.start end = node.end input = node.in_node(0) output_data = node.out_node() # Check whether operation use only one axis or not dims = 0 axes = np.zeros(begin.size) for i in range(begin.size): if begin[i] != 0 or end[i] != input.shape[i]: dims += 1 axes[i] = 1 axes = np.array(axes, dtype=bool) if dims == 0: return elif dims == 1: # If Slice use only one axis, than # convert Slice to StridedSlice node['op'] = 'StridedSlice' node['type'] = 'StridedSlice' node['new_axis_mask'] = np.zeros(len(output_data.shape), dtype=np.bool) node['shrink_axis_mask'] = np.zeros(len(output_data.shape), dtype=np.bool) convert_negative_indices(begin, input.shape) convert_negative_indices(end, input.shape) else: # If Slice use more than one axis use Crop layer crop = Crop( graph, dict(axis=np.arange(begin.size)[axes], offset=begin[axes])) # creating node with data crop.create_node_with_data(inputs=[input], data_nodes=[output_data]) # Remove unnecessary edges from and to to Slice vertex graph.remove_edge(input.id, node.id) graph.remove_edge(node.id, output_data.id)
def replace_pattern(self, graph: Graph, match: dict): """ Converts specific for NasNet topology subgraph Pad->StridedSlice->AvgPool to Conv->Crop->AvgPool """ input = match['input'] pad_op = match['pad_op'] sslice = match['sslice'] sslice_out = match['sslice_out'] begin = [] end = [] stride = [] for s in sslice.slices: begin.append(s.start) end.append(s.stop) stride.append(s.step) if not np.array_equal(pad_op.pads, np.array([[0, 0], [0, 1], [0, 1], [0, 0]])): log.error(" Pad values doesn't match!") return if not np.array_equal(begin, np.array([0, 1, 1, 0])): log.error("StridedSlice has wrong begin") return if not np.array_equal(sslice.end_mask, np.array( [0, 0, 0, 0])) or not np.array_equal(sslice.begin_mask, np.array([0, 1, 1, 0])): log.error("StridedSlice has wrong masks") return # Cut Smth-x->Pad->StrudedSlice-x->AvgPool graph.remove_edge(input.id, pad_op.id) graph.remove_edge(sslice.id, sslice_out.id) # Pad -> Conv conv_node = graph.unique_id(pad_op.name + '/Conv_') conv_weights_node = graph.unique_id(pad_op.name + '/ConvW_') conv_weights = np.ones((input.shape[3], 1, 1, 1)) conv_output = graph.unique_id(pad_op.name + '/ConvOut_') output_shape = np.array([ input.shape[0], input.shape[1] + 1, input.shape[2] + 1, input.shape[3] ]) graph.add_node( conv_node, **add_attrs_props( dict(kind='op', type='Convolution', name=conv_node, op='Conv2D', stride=np.array([1, 1, 1, 1]), dilation=np.array([1, 1, 1, 1]), group=input.shape[3], bias_addable=True, bias_term=False, spatial_dims=np.array([1, 2]), kernel_spatial=np.array([1, 1]), pad=np.array([[0, 0], [0, 1], [0, 1], [0, 0]]), output_shape=output_shape, channel_dims=np.array([3]), output=input.shape[3], in_ports_count=3, out_ports_count=1))) graph.add_node( conv_weights_node, **add_attrs_props( dict(kind='data', name=conv_weights_node, value=np.array(conv_weights), shape=np.array(conv_weights.shape), data_type=input.data_type, infer=None, spatial_dims=np.array([0, 1]), input_channel_dim=2, output_channel_dim=3, dims_number=4, can_be_bias=True))) graph.add_node( conv_output, **add_attrs_props( dict(kind='data', name=conv_output, value=None, shape=output_shape, data_type=input.data_type))) # StridedSlice -> Crop crop = Crop( graph, dict(name=sslice.name + '/Crop_', axis=np.array([1, 2]), dim=np.array([output_shape[1] - 1, output_shape[2] - 1]), offset=np.array([1, 1]))) crop.create_node_with_data([Node(graph, conv_output)], data_nodes=sslice_out) # Connect : Conv->Crop->AvgPool graph.add_edges_from([ (input.id, conv_node, { 'in': 0 }), (conv_weights_node, conv_node, { 'in': 1, 'bin': 'weights' }), (conv_node, conv_output, { 'out': 0 }), ]) update_ie_fields(graph.node[conv_node], graph.graph['ir_version'])
def replace_pattern(self, graph: Graph, match: dict): node = match['slice'] # Caffe case if not node.has_valid('start') or not node.has_valid('end'): return begin = node.start end = node.end axis = node.axis if node.has_valid('axis') else range(begin.size) input = node.in_node(0) output_data = node.out_node() # Check whether operation use only one axis or not axes_begin = np.zeros(len(input.shape), dtype=np.int32) axes_end = np.zeros(len(input.shape), dtype=np.int32) begin_ext = np.zeros(len(input.shape), dtype=np.int32) end_ext = np.zeros(len(input.shape), dtype=np.int32) dims = 0 axes = np.zeros(begin.size) for i in range(len(axis)): if begin[i] != 0 or end[i] < input.shape[i]: dims += 1 axes[i] = 1 if begin[i] != 0: axes_begin[axis[i]] = 1 begin_ext[axis[i]] = begin[i] if end[i] < input.shape[i]: axes_end[axis[i]] = 1 end_ext[axis[i]] = end[i] axes = np.array(axes, dtype=bool) if dims == 1 or dims == 0: # If Slice use only one axis or no axis, than # convert Slice to StridedSlice ss = StridedSlice( graph, dict(new_axis_mask=np.zeros(len(output_data.shape), dtype=np.int32), shrink_axis_mask=np.zeros(len(output_data.shape), dtype=np.int32), ellipsis_mask=np.zeros(len(output_data.shape), dtype=np.int32), begin_mask=axes_begin, end_mask=axes_end)) convert_negative_indices(begin_ext, input.shape) convert_negative_indices(end_ext, input.shape) begin_node = Const(graph, { 'name': 'begin', 'value': begin_ext, 'force_precision': 'I32' }).create_node_with_data() end_node = Const(graph, { 'name': 'end', 'value': end_ext, 'force_precision': 'I32' }).create_node_with_data() ss.create_node_with_data(inputs=[input, begin_node, end_node], data_nodes=[output_data]) # Remove unnecessary edges from and to to Slice vertex graph.remove_edge(input.id, node.id) graph.remove_edge(node.id, output_data.id) else: # If Slice use more than one axis use Crop layer crop = Crop( graph, dict(axis=np.arange(begin.size)[axes], offset=begin[axes])) # creating node with data crop.create_node_with_data(inputs=[input], data_nodes=[output_data]) # Remove unnecessary edges from and to to Slice vertex graph.remove_edge(input.id, node.id) graph.remove_edge(node.id, output_data.id)