def replace_op(self, graph: Graph, node: Node): ss_node = Split(graph, attrs={ 'name': 'Split_eltwise_' + node.name, 'num_split': node['num_inputs'] }).create_node() inp = node.get_inputs() in_node = inp[0][0] edge_attrs = inp[0][1] graph.add_edge(in_node, ss_node.id, **edge_attrs) if ss_node.num_split == 2: eltwise_node = Eltwise(graph, attrs={ 'name': 'Eltwise_' + node.name, 'operation': node['operation'] }).create_node() elif ss_node.num_split > 2: eltwise_node = EltwiseN(graph, attrs={ 'name': 'Eltwise_' + node.name, 'operation': node['operation'] }).create_node() else: raise Error('Error on replacing Kaldi eltwise') for i in range(ss_node.num_split): ss_node.add_output_port(i) ss_node.out_port(i).get_connection().set_destination( eltwise_node.in_port(i)) return [eltwise_node.id]
def _create_sub(graph: Graph, input_1: Node, port_1: int, input_2: Node, port_2: int): negate = Power(graph, dict(scale=-1, name=input_2.name + '/negate_')) add = Eltwise(graph, dict(operation='sum', name=input_1.name + '/add_')) out_node = add.create_node([(input_1, port_1), negate.create_node([(input_2, port_2)])]) return out_node
def replace_op(self, graph: nx.MultiDiGraph, node: Node): negate = Power(graph, dict(scale=-1, name=node.name + '/negate_')) add = Eltwise(graph, dict(operation='sum', name=node.name + '/add_')) out_node = add.create_node([ (node.in_node(0), node.in_edge(0)['out']), negate.create_node([(node.in_node(1), node.in_edge(1)['out'])]) ]) # Replace edge from out port 0 of the matched node with a edge from node out_node.id with port 0. # The "explicit" version of the return value is: [(out_node.id, 0)]) return [out_node.id]
def replace_op(self, graph: Graph, node: Node): out_node = node.in_node(0) operation = node.operation for ind in range(1, len(node.in_nodes())): eltwise_op = Eltwise( graph, dict(operation=operation, name=node.name + '/' + operation + '_' + str(ind))) out_node = eltwise_op.create_node([out_node, node.in_node(ind)]) return [out_node.id]
def replace_op(self, graph: Graph, node: Node): reciprocal = Power(graph, {'scale': 1, 'power': np.float64(-1), 'shift': 0, 'name': node.name + '/reciprocal_'}).create_node() mul = Eltwise(graph, {'operation': 'mul', 'name': node.name + '/mul_'}).create_node() # Connect nodes node.in_port(1).get_connection().set_destination(reciprocal.in_port(0)) node.in_port(0).get_connection().set_destination(mul.in_port(1)) reciprocal.out_port(0).connect(mul.in_port(0)) # The "explicit" version of the return value is: [(out_node.id, 0)]) return [mul.id]
def replace_op(self, graph: nx.MultiDiGraph, node: Node): reciprocal = Power( graph, dict(scale=1, power=np.float64(-1), shift=0, name=node.name + '/reciprocal_')) mul = Eltwise(graph, dict(operation='mul', name=node.name + '/mul_')) out_node = mul.create_node([ (node.in_node(0), node.in_edge(0)['out']), reciprocal.create_node([(node.in_node(1), node.in_edge(1)['out'])]) ]) # Replace edge from out port 0 of the matched node with a edge from node out_node.id with port 0. # The "explicit" version of the return value is: [(out_node.id, 0)]) return [out_node.id]
def replace_pattern(self, graph: Graph, match: dict): node = match['minimum'] # Constant propagation case if node.in_node(0).value is not None and node.in_node(1).value is not None: return negate_1 = Power(graph, dict(scale=-1, name=node.name + '/negate1_')) negate_2 = Power(graph, dict(scale=-1, name=node.name + '/negate2_')) maximum = Eltwise(graph, dict(operation='max', name=node.name + '/Max_')) negate_output = Power(graph, dict(scale=-1, name=node.name + '/negate_out_')) negate_output.create_node_with_data( inputs=[maximum.create_node_with_data([negate_1.create_node_with_data([node.in_node(0)]), negate_2.create_node_with_data([node.in_node(1)])])], data_nodes=node.out_node()) # Delete minimum vertex node.graph.remove_node(node.id)
def replace_sub_graph(self, graph: Graph, match: dict): fbn = match['fbn'] input = fbn.in_node(0) log.debug('Found potential MVN pattern after {} with name {}'.format( input.op, input.name)) if input.id != match['mean'].in_node( 0).id or input.id != match['sqdiff'].in_node(0).id: return log.debug('Confirmed MVN pattern after {} with name {}'.format( input.op, input.name)) MVN = Op.get_op_class_by_name('MVN') mvn = MVN( graph, dict(name=fbn.name + '/MVN_', eps=fbn.eps, required_reduction_indices=[1, 2] if fbn.data_format == b'NHWC' else [2, 3])) mvn.attrs['old_infer'] = mvn.attrs['infer'] mvn.attrs['infer'] = __class__.infer mul = Eltwise(graph, dict(operation='mul', name=fbn.name + '/Mul_')) add = Eltwise(graph, dict(operation='sum', name=fbn.name + '/Add_')) input_gamma = fbn.in_node(1) input_beta = fbn.in_node(2) mean_reduction = match['mean'].in_node(1) variance_reduction = match['variance'].in_node(1) new_subgraph = add.create_node([ mul.create_node([ mvn.create_node([input, mean_reduction, variance_reduction]), input_gamma ]), input_beta ]) fbn.replace_node(new_subgraph)
def replace_pattern(self, graph: Graph, match: dict): node = match['op'] if (node.data_format != b'NHWC' or len(node.in_nodes()) != 5 or node.in_node(0).value is not None or # input node.in_node(1).value is None or # scale node.in_node(2).value is None or # offset node.in_node(3).value is not None or # mean node.in_node(4).value is not None or # variance node.in_node(1).value.ndim != 1 or node.in_node(2).value.ndim != 1): return scale_mul = Eltwise( graph, dict(operation='mul', name=node.name + '/scale_mul_')) shift_add = Eltwise( graph, dict(operation='sum', name=node.name + '/shift_add_')) mean_add = Eltwise( graph, dict(operation='sum', name=node.name + '/mean_add_')) variance_mul = Eltwise( graph, dict(operation='mul', name=node.name + '/variance_mul_')) mean_negate = Power(graph, dict(scale=-1, name=node.name + '/mean_negate_')) mean_arg = mean_add.create_node_with_data([ node.in_node(0), mean_negate.create_node_with_data([node.in_node(3)]) ]) variance_square = Power( graph, dict(power=2, name=node.name + '/variance_square_')) variance_denom = Power( graph, dict(shift=node.eps, power=-0.5, name=node.name + '/variance_denom_')) variance_arg = variance_mul.create_node_with_data([ mean_arg, variance_denom.create_node_with_data([node.in_node(4)]) ]) shift_add.create_node_with_data([ scale_mul.create_node_with_data([variance_arg, node.in_node(1)]), node.in_node(2) ], data_nodes=node.out_node()) node.graph.remove_node(node.id)
def replace_op(self, graph: Graph, node: Node): # split input to (i_part, f_part, c_part, o_part, ct_1) split_node_axis = Const(graph, {'value': np.int64(1)}).create_node() split_node = Split(graph, { 'name': graph.unique_id(prefix='Split_lstm_input_'), 'num_splits': 5 }).create_node() node.in_port(0).get_connection().set_destination(split_node.in_port(0)) split_node.in_port(1).connect(split_node_axis.out_port(0)) # i_t = Sigmoid(i_part + w_ic*ct_1) i_scale_attrs = { 'name': graph.unique_id(prefix='i_scaleshift'), 'bias_term': False } i_scale = ScaleShiftOp(graph, i_scale_attrs).create_node() input_as_const(i_scale, i_scale_attrs, 1, 'weights', node.i_weights) split_node.out_port(4).connect(i_scale.in_port(0)) sum_i_c = Eltwise(graph, { 'name': graph.unique_id(prefix='sum_i_c_'), 'operation': 'sum' }).create_node() split_node.out_port(0).connect(sum_i_c.in_port(0)) i_scale.out_port(0).connect(sum_i_c.in_port(1)) i_sigmoid = Sigmoid(graph, {'name': 'i_sigmoid'}).create_node() sum_i_c.out_port(0).connect(i_sigmoid.in_port(0)) # f_t = Sigmoid(f_part + w_fc*ct_1) f_scale_attrs = { 'name': graph.unique_id(prefix='f_scaleshift'), 'bias_term': False } f_scale = ScaleShiftOp(graph, f_scale_attrs).create_node() input_as_const(f_scale, f_scale_attrs, 1, 'weights', node.f_weights) split_node.out_port(4).connect(f_scale.in_port(0)) sum_f_c = Eltwise(graph, { 'name': graph.unique_id(prefix='sum_f_c_'), 'operation': 'sum' }).create_node() split_node.out_port(1).connect(sum_f_c.in_port(0)) f_scale.out_port(0).connect(sum_f_c.in_port(1)) f_sigmoid = Sigmoid(graph, {'name': 'f_sigmoid'}).create_node() sum_f_c.out_port(0).connect(f_sigmoid.in_port(0)) # c_t = f_t*ct_1 + i_t * tanh(c_part) c_tanh = Tanh(graph, {'name': 'c_tanh'}).create_node() split_node.out_port(2).connect(c_tanh.in_port(0)) prod_i_c_tanh = Eltwise( graph, { 'name': graph.unique_id(prefix='prod_i_c_tanh_'), 'operation': 'mul' }).create_node() i_sigmoid.out_port(0).connect(prod_i_c_tanh.in_port(0)) c_tanh.out_port(0).connect(prod_i_c_tanh.in_port(1)) prod_f_ct_1 = Eltwise(graph, { 'name': graph.unique_id(prefix='prod_f_ct_1_'), 'operation': 'mul' }).create_node() f_sigmoid.out_port(0).connect(prod_f_ct_1.in_port(0)) split_node.out_port(4).connect(prod_f_ct_1.in_port(1)) sum_f_i = Eltwise(graph, { 'name': graph.unique_id(prefix='sum_f_i_'), 'operation': 'sum' }).create_node() prod_f_ct_1.out_port(0).connect(sum_f_i.in_port(0)) prod_i_c_tanh.out_port(0).connect(sum_f_i.in_port(1)) # o_t = Sigmoid(o_part + w_oc*c_t) o_scale_attrs = { 'name': graph.unique_id(prefix='o_scaleshift'), 'bias_term': False } o_scale = ScaleShiftOp(graph, o_scale_attrs).create_node() input_as_const(o_scale, o_scale_attrs, 1, 'weights', node.o_weights) sum_f_i.out_port(0).connect(o_scale.in_port(0)) sum_o_c = Eltwise(graph, { 'name': graph.unique_id(prefix='sum_o_c_'), 'operation': 'sum' }).create_node() split_node.out_port(3).connect(sum_o_c.in_port(0)) o_scale.out_port(0).connect(sum_o_c.in_port(1)) o_sigmoid = Sigmoid(graph, {'name': 'o_sigmoid'}).create_node() sum_o_c.out_port(0).connect(o_sigmoid.in_port(0)) # m_t = o_t * Tanh(c_t) c_t_tanh = Tanh(graph, {'name': 'c_t_tanh'}).create_node() sum_f_i.out_port(0).connect(c_t_tanh.in_port(0)) prod_o_c_t_tanh = Eltwise( graph, { 'name': graph.unique_id(prefix='prod_o_c_t_tanh_'), 'operation': 'mul' }).create_node() o_sigmoid.out_port(0).connect(prod_o_c_t_tanh.in_port(0)) c_t_tanh.out_port(0).connect(prod_o_c_t_tanh.in_port(1)) # add concat to create 1 output concat = Concat(graph, { 'name': graph.unique_id(prefix='Concat_c_m') }).create_node() concat.add_sequence_of_ports('in', range(2)) sum_f_i.out_port(0).connect(concat.in_port(0)) prod_o_c_t_tanh.out_port(0).connect(concat.in_port(1)) return [concat.id]
def replace_op(self, graph: Graph, node: Node): input_node = node.in_node() memory_pair_input = unique_id('id') memory_pair_output = unique_id('id') # Input -> FullyConnected fc_layer_after_input_attrs = { 'name': 'input_fullyconnected', 'num_output': node.gifo_x_weights_shape[0], 'bias_term': True } embed_input(fc_layer_after_input_attrs, 1, 'weights', node.gifo_x_weights) embed_input(fc_layer_after_input_attrs, 2, 'biases', node.gifo_biases) fc_layer_after_input = InnerProduct( graph, fc_layer_after_input_attrs).create_node([input_node]) prev_lstm_output = Memory( graph, { 'name': 'prev_memory_output', 'id': memory_pair_input, 'index': 1, 'size': 2, 'shape': np.array([node.gifo_r_weights_shape[1]], dtype=np.int64) }).create_node() # *Memory(output) -> FullyConnected fc_layer_from_prev_state_attrs = { 'name': 'prev_memory_output_fullyconnected', 'num_output': node.gifo_r_weights_shape[0], 'bias_term': False } embed_input(fc_layer_from_prev_state_attrs, 1, 'weights', node.gifo_r_weights) fc_layer_from_prev_state = InnerProduct( graph, fc_layer_from_prev_state_attrs).create_node([prev_lstm_output]) # Memory -> FullyConnected \ # *Eltwise(sum) # Input -> FullyConnected / join_input_prev_state_sum = Eltwise(graph, { 'name': 'join_input_eltwise', 'operation': 'sum' }).create_node([fc_layer_from_prev_state, fc_layer_after_input]) # *Eltwise(sum) -> Split # it is split into 4 nodes: Act, Eltw*3 # the following order is mandatory # ___Tanh # / # Split ---(2)Eltwise(sum) # |\ # | \__(3)Eltwise(sum) # |____(4)Eltwise(sum) split_joined_input = Split( graph, { 'name': 'join_input_split', 'axis': 1, 'num_split': 4, 'out_ports_count': 4, }).create_node([join_input_prev_state_sum]) prev_lstm_state = Memory( graph, { 'name': 'prev_memory_state', 'id': memory_pair_output, 'index': 1, 'size': 2, 'shape': np.array([node.input_gate_weights.shape[0]], dtype=np.int64) }).create_node() # *Memory(state) -> *ScaleShift(input) state_input_scaleshift_attrs = { 'name': 'input_scaleshift', 'bias_term': False } embed_input(state_input_scaleshift_attrs, 1, 'weights', node.input_gate_weights) state_input_scaleshift = ScaleShiftOp( graph, state_input_scaleshift_attrs).create_node([prev_lstm_state]) # *Memory(state) -> *ScaleShift(forget) state_forget_scaleshift_attrs = { 'name': 'forget_scaleshift', 'bias_term': False } embed_input(state_forget_scaleshift_attrs, 1, 'weights', node.forget_gate_weights) state_forget_scaleshift = ScaleShiftOp( graph, state_forget_scaleshift_attrs).create_node([prev_lstm_state]) # Split \ # (2)Eltwise(sum) # Memory(state) -> *ScaleShift(input) / join_prev_lstm_input_joined_input_sum = Eltwise( graph, { 'name': 'join_prev_lstm_input_joined_input_eltwise', 'operation': 'sum' }).create_node([(split_joined_input, 1), state_input_scaleshift]) # Split \ # (3)Eltwise(sum) # Memory(state) -> *ScaleShift(forget) / join_prev_lstm_input_joined_forget_sum = Eltwise( graph, { 'name': 'join_prev_lstm_input_joined_forget_sum', 'operation': 'sum' }).create_node([(split_joined_input, 2), state_forget_scaleshift]) # Split -> Tanh remember_tahn = Activation(graph, { 'name': 'remember_tahnv', 'operation': 'tanh' }).create_node([(split_joined_input, 0)]) # Split -> (2)Eltwise(sum) -> *Sigmoid remember_sigmoid = Activation(graph, { 'name': 'remember_sigmoid', 'operation': 'sigmoid' }).create_node([join_prev_lstm_input_joined_input_sum]) # Split -> (3)Eltwise(sum) -> **Sigmoid forget_sigmoid = Activation(graph, { 'name': 'forget_sigmoid', 'operation': 'sigmoid' }).create_node([join_prev_lstm_input_joined_forget_sum]) # *Memory(state) \ # (6)Eltwise(mul) # Split -> (3)Eltwise(sum) -> **Sigmoid / join_forget_prev_state_mul = Eltwise(graph, { 'name': 'join_forget_prev_state_mul', 'operation': 'mul' }).create_node([forget_sigmoid, prev_lstm_state]) # Split -> Tahn \ # (5)Eltwise(mul) # Split -> (2)Eltwise(sum) -> *Sigmoid / join_remember_candidates_mul = Eltwise(graph, { 'name': 'join_remember_candidates_mul', 'operation': 'mul' }).create_node([remember_tahn, remember_sigmoid]) # (5)Eltwise(mul) \ # (7)Eltwise(sum) # (6)Eltwise(mul) / join_forget_remember_sum = Eltwise(graph, { 'name': 'join_forget_remember_sum', 'operation': 'sum' }).create_node( [join_forget_prev_state_mul, join_remember_candidates_mul]) # (7)Eltwise(sum) -> Clamp join_forget_clamp = Clamp( graph, { 'name': 'join_forget_clamp', 'max': node.clip_value, 'min': -node.clip_value }).create_node([join_forget_remember_sum]) # # Clamp -> (2)Memory(state) Memory( graph, { 'name': 'next_lstm_state', 'id': memory_pair_output, 'index': 0, 'size': 2, 'shape': np.array([node.input_gate_weights.shape[0]], dtype=np.int64) }).create_node([join_forget_clamp]) # Clamp -> (2)Tahn state_filtered_tahn = Activation(graph, { 'name': 'state_filtered_tahn', 'operation': 'tanh' }).create_node([join_forget_clamp]) # Clamp -> (2)ScaleShift clamp_scaleshift_attrs = { 'name': 'clamp_scaleshift', 'bias_term': False } embed_input(clamp_scaleshift_attrs, 1, 'weights', node.output_gate_weights) clamp_scaleshift = ScaleShiftOp( graph, clamp_scaleshift_attrs).create_node([join_forget_clamp]) # Split \ # (4)Eltwise(sum) # Clamp -> (2)ScaleShift / join_next_lstm_input_joined_input_sum = Eltwise( graph, { 'name': 'join_next_lstm_input_joined_input_sum', 'operation': 'sum' }).create_node([(split_joined_input, 3), clamp_scaleshift]) # (4)Eltwise(sum) -> (3)Sigmoid output_sigmoid = Activation(graph, { 'name': 'output_sigmoid', 'operation': 'sigmoid' }).create_node([join_next_lstm_input_joined_input_sum]) # (4)Eltwise(sum) -> (3)Sigmoid \ # (5)Eltwise(mul) # Clamp -> (2)Tahn / joined_output_mul = Eltwise(graph, { 'name': 'joined_output_mul', 'operation': 'mul' }).create_node([state_filtered_tahn, output_sigmoid]) # (5)Eltwise(mul) -> (3)FullyConnected fc_output_attrs = { 'name': 'FullyConnected', 'num_output': node.projection_weights_shape[0], 'bias_term': False } embed_input(fc_output_attrs, 1, 'weights', node.projection_weights) fc_output = InnerProduct(graph, fc_output_attrs).create_node( [joined_output_mul]) # / (2)Memory(output) # (3)FullyConnected # \ Output (any next node) (edge created automatically after replacement) Memory( graph, { 'name': 'next_lstm_output', 'id': memory_pair_input, 'index': 0, 'size': 2, 'shape': np.array([node.gifo_r_weights_shape[1]], dtype=np.int64) }).create_node([fc_output]) return [fc_output.id]
def replace_pattern(graph: Graph, match: [str, Node]): Eltwise.update_node_stat( match['op'], {'operation': op_to_operation_map[match['op'].type]})
def generate_sub_graph(self, graph: Graph, match: SubgraphMatch): reshape_classes_op = Reshape(graph, {'dim': np.array([0, -1])}) reshape_classes_node = reshape_classes_op.create_node( [match.single_input_node(1)[0]], dict(name='do_reshape_classes')) priors_node = match.single_input_node(2)[0] placeholder = [ Node(graph, node_id) for node_id in graph.nodes() if Node(graph, node_id).op == 'Placeholder' ][0] im_height = placeholder.shape[1] im_width = placeholder.shape[2] # scale prior boxes to the [0, 1] interval priors_scale_const_node = Const( graph, { 'value': np.array( [1 / im_width, 1 / im_height, 1 / im_width, 1 / im_height]) }).create_node([]) priors_scale_node = Eltwise(graph, { 'name': 'scale_priors', 'operation': 'mul' }).create_node([priors_node, priors_scale_const_node]) # calculate prior boxes widths and heights split_node = SplitV(graph, { 'axis': 2, 'size_splits': [1, 1, 1, 1], 'out_ports_count': 4 }).create_node([priors_scale_node]) priors_width_node = __class__._create_sub(graph, split_node, 2, split_node, 0) priors_height_node = __class__._create_sub(graph, split_node, 3, split_node, 1) # concat weights and heights into a single tensor and multiple with the box coordinates regression values concat_width_height_node = Concat(graph, { 'name': 'concat_priors_width_height', 'axis': -1, 'in_ports_count': 4 }).create_node([ priors_width_node, priors_height_node, priors_width_node, priors_height_node ]) applied_width_height_regressions_node = Eltwise(graph, {'name': 'final_regressions', 'operation': 'mul'}). \ create_node([concat_width_height_node, match.single_input_node(0)[0]]) # reshape to 2D tensor as Inference Engine Detection Output layer expects reshape_regression_op = Reshape(graph, {'dim': np.array([0, -1])}) reshape_regression_node = reshape_regression_op.create_node( [applied_width_height_regressions_node], {'name': 'reshape_regression'}) detection_output_op = DetectionOutput( graph, match.custom_replacement_desc.custom_attributes) detection_output_op.attrs['old_infer'] = detection_output_op.attrs[ 'infer'] detection_output_op.attrs['infer'] = __class__.do_infer detection_output_node = detection_output_op.create_node( [reshape_regression_node, reshape_classes_node, priors_scale_node], dict(name=detection_output_op.attrs['type'], clip=1, normalized=1, variance_encoded_in_target=0)) return {'detection_output_node': detection_output_node}
def extract(node): Eltwise.update_node_stat(node, {'operation': 'max'}) return __class__.enabled
def extract(node): Eltwise.update_node_stat(node, { 'operation': 'floor_mod', 'force_precision': 'I32', }) return __class__.enabled