Пример #1
0
 def extract(cls, node):
     attrs = {
         'shape': node.shape,
         'data_type': np.float32,  # TODO: other types?
     }
     Parameter.update_node_stat(node, {})
     return cls.enabled
Пример #2
0
 def extract(node):
     attrs = {
         'data_type': tf_dtype_extractor(node.pb.attr["dtype"].type),
         'shape': tf_tensor_shape(node.pb.attr["shape"].shape),
         'permute_attrs': PermuteAttrs().update_attrs(attrs=[('shape', 'output:0')])
     }
     Parameter.update_node_stat(node, attrs)
     return __class__.enabled
Пример #3
0
 def extract(node):
     attrs = {
         'shape':
         np.array([d.dim_value for d in node.pb.type.tensor_type.shape.dim],
                  dtype=np.int64),
     }
     Parameter.update_node_stat(node, attrs)
     return __class__.enabled
Пример #4
0
def insert_do(graph: Graph, replacement_descriptions: dict):
    do_outputs = replacement_descriptions['do_outputs']
    prior_boxes_node = Node(graph, 'ROIFeatureExtractor_2')
    num_classes = 81
    box_regressions_input_node = Node(
        graph, replacement_descriptions['box_regressions_input_node'])
    box_regressions_node = create_op_node_with_second_input(
        graph, Reshape, int64_array([-1, 4 * num_classes]),
        dict(name='box_regressions'), box_regressions_input_node)

    class_predicitons_node = Node(
        graph, replacement_descriptions['class_predicitons_node'])
    im_info_node = Parameter(graph, {
        "name": 'im_info',
        'shape': int64_array([1, 3])
    }).create_node()

    do_node = ExperimentalDetectronDetectionOutput(
        graph, {
            'name':
            'DetectionOutput',
            'class_agnostic_box_regression':
            0,
            'deltas_weights':
            np.array([10.0, 10.0, 5.0, 5.0]),
            'max_delta_log_wh':
            replacement_descriptions['max_delta_log_wh'],
            'nms_threshold':
            replacement_descriptions['nms_threshold'],
            'score_threshold':
            replacement_descriptions['score_threshold'],
            'num_classes':
            num_classes,
            'max_detections_per_image':
            replacement_descriptions['max_detections_per_image'],
            'post_nms_count':
            replacement_descriptions['post_nms_count']
        }).create_node()
    prior_boxes_node.out_port(1).connect(do_node.in_port(0))
    box_regressions_node.out_port(0).connect(do_node.in_port(1))
    class_predicitons_node.out_port(0).connect(do_node.in_port(2))
    im_info_node.out_port(0).connect(do_node.in_port(3))

    do_output_ports = [
        do_node.out_port(0),
        do_node.out_port(1),
        do_node.out_port(2)
    ]
    old_do_output_nodes = [Node(graph, node_id) for node_id in do_outputs]
    for old_node, new_port in zip(old_do_output_nodes, do_output_ports):
        old_node.out_port(0).get_connection().set_source(new_port)
    # the consumer of the second output port of the ExperimentalDetectronDetectionOutput is the Mul node which second
    # input is of type int64 so it is necessary to insert Cast to have data types match
    do_node.out_port(1).get_connection().insert_node(
        Cast(graph, {
            'dst_type': np.int64
        }).create_node())
Пример #5
0
def create_parameter_with_empty_attrs(graph, param_name):
    graph.add_node(param_name, kind='op', op='Parameter', name=param_name, pb=None, shape=None)
    parameter_node = Node(graph, param_name)
    # need to manually update necessary attrs for the node because extractor will not be called
    # for it because the node does not have .pb attribute
    Parameter.update_node_stat(parameter_node, {})
    parameter_node['internal_layer_id'] = len(graph.nodes)

    return parameter_node
Пример #6
0
 def extract(cls, node):
     t_type = node.pb.type.tensor_type
     attrs = {
         'shape':
         np.array([d.dim_value for d in t_type.shape.dim], dtype=np.int64),
         'data_type':
         TENSOR_TYPE_TO_NP_TYPE[t_type.elem_type]
     }
     Parameter.update_node_stat(node, attrs)
     return cls.enabled
Пример #7
0
    def replace_sub_graph(graph: Graph, match: dict, **kwargs):
        inputs_dict = {}
        for u, v, edge_attrs in graph.out_edges(match['queue_deque'].id, data=True):
            out_port = edge_attrs['out']
            shape = match['fifo_queue'].shapes[out_port]
            if out_port not in inputs_dict:
                input_op = Parameter(graph, {'shape': shape.copy()})
                inputs_dict[out_port] = input_op.create_node([])
            graph.create_edge(inputs_dict[out_port], Node(graph, v), edge_attrs['out'], edge_attrs['in'], edge_attrs)

        graph.remove_node(match['queue_deque'].id)
        graph.remove_node(match['fifo_queue'].id)
Пример #8
0
 def create_offsets_for_weighted_sum(self, graph, weighted_sum_nodes, merge_offsets, index_shape):
     new_offsets = None
     for i, (node, ind_shape) in enumerate(weighted_sum_nodes):
         if merge_offsets and len(weighted_sum_nodes) > 1:
             # generate single offsets input if possible
             if new_offsets is None:
                 shape = int64_array([len(weighted_sum_nodes), index_shape, 2])
                 new_offsets = Parameter(graph, {'name': 'Emb_Bag/offsets',
                                                 'shape': shape,
                                                 'data_type': np.int32}).create_node()
                 log.error(
                     'Pre-process of offsets is needed for generated input "Emb_Bag/offsets" of shape: {}. '
                     'Refer to the documentation on how to convert the ONNX* DLRM model'.format(shape),
                     extra={'is_warning': True})
             gather = create_op_with_const_inputs(graph, Gather, {1: int64_array(i), 2: int64_array(0)},
                                                  {'name': node.name + '/Gather_'})
             new_offsets.out_port(0).connect(gather.in_port(0))
             gather.out_port(0).connect(node.in_port(0))
         else:
             shape = int64_array([ind_shape, 2])
             new_offsets = Parameter(graph, {'name': 'Emb_Bag/offsets{}'.format(i),
                                             'shape': shape,
                                             'data_type': np.int32}).create_node()
             new_offsets.out_port(0).connect(node.in_port(0))
             log.error(
                 'Pre-process of offsets is needed for generated input "Emb_Bag/offsets{}" of shape: {}. '
                 'Refer to the documentation on how to convert the ONNX* DLRM model'.format(i, shape),
                 extra={'is_warning': True})
Пример #9
0
 def extract(cls, node):
     t_type = node.pb.type.tensor_type
     attrs = {
         'shape':
         shape_array([
             d.dim_value if
             (not hasattr(d, 'dim_param') or d.dim_param == '')
             and d.dim_value != 0 else dynamic_dimension_value
             for d in t_type.shape.dim
         ]),
         'data_type':
         TENSOR_TYPE_TO_NP_TYPE[t_type.elem_type]
     }
     Parameter.update_node_stat(node, attrs)
     return cls.enabled
Пример #10
0
def insert_do(graph: Graph, replacement_descriptions):
    do_outputs = ['6530', '6532', '6534']
    prior_boxes_node = Node(graph, 'ROIFeatureExtractor_2')
    num_classes = 81
    box_regressions_node = create_op_node_with_second_input(
        graph, Reshape, int64_array([-1, 4 * num_classes]),
        dict(name='box_regressions'), Node(graph, '2773'))

    class_predicitons_node = Node(graph, '2774')
    im_info_node = Parameter(graph, {
        "name": 'im_info',
        'shape': int64_array([1, 3])
    }).create_node()

    do_node = ExperimentalDetectronDetectionOutput(
        graph, {
            'name':
            'DetectionOutput',
            'class_agnostic_box_regression':
            0,
            'deltas_weights':
            np.array([10.0, 10.0, 5.0, 5.0]),
            'max_delta_log_wh':
            replacement_descriptions['max_delta_log_wh'],
            'nms_threshold':
            replacement_descriptions['nms_threshold'],
            'score_threshold':
            replacement_descriptions['score_threshold'],
            'num_classes':
            num_classes,
            'max_detections_per_image':
            replacement_descriptions['max_detections_per_image'],
            'post_nms_count':
            replacement_descriptions['post_nms_count']
        }).create_node()
    prior_boxes_node.out_port(1).connect(do_node.in_port(0))
    box_regressions_node.out_port(0).connect(do_node.in_port(1))
    class_predicitons_node.out_port(0).connect(do_node.in_port(2))
    im_info_node.out_port(0).connect(do_node.in_port(3))

    do_output_ports = [
        do_node.out_port(0),
        do_node.out_port(1),
        do_node.out_port(2)
    ]
    old_do_output_nodes = [Node(graph, node_id) for node_id in do_outputs]
    for old_node, new_port in zip(old_do_output_nodes, do_output_ports):
        old_node.out_port(0).get_connection().set_source(new_port)
Пример #11
0
    def cover_body_input_data_nodes_with_parameter_ops(ti: Node):
        body = ti.body

        op_port_map = []
        for record in ti.input_port_map:
            operation_node = get_internal_node_by_layer_id(
                ti, record['internal_layer_id'])
            real_in_port = TensorIterator.special_port_to_real_port(
                operation_node, copy(record['internal_port_id']))
            op_port_map.append((operation_node, real_in_port))

        for operation_node, in_port in op_port_map:
            data_node = operation_node.in_node(in_port)

            attrs = deepcopy(
                body.get_edge_data(data_node.id, operation_node.id)[0])
            body.remove_edge(data_node.id, operation_node.id)

            assert data_node.has_valid('shape'), \
                'Data node should have `shape` attribute set, but it`s not for node {}'.format(data_node.id)
            shape = data_node['shape'].copy()
            parameter_data_node = Parameter(body, {
                'shape': shape
            }).create_node_with_data()

            body.create_edge(src_node=parameter_data_node,
                             dst_node=operation_node,
                             out_port=0,
                             in_port=in_port,
                             edge_attrs=attrs)
            del body.get_edge_data(parameter_data_node.id,
                                   operation_node.id)[0]['out']
Пример #12
0
    def replace_pattern(graph: Graph, match: dict):
        node = match['op']
        node_id = node['variable_id']

        i = 0
        node.in_port(0).disconnect()
        for dest in node.out_port(0).get_destinations():
            new_in = Parameter(
                graph, {
                    'name': "Parameter_" + str(i) + "_for_" + node_id,
                    'shape': dest.data.get_shape()
                }).create_node()
            i += 1
            dest.disconnect()
            new_in.out_port(0).connect(dest)
            log.error("Add input/output mapped {} -> {} ".format(
                new_in.name, "Result_for_" + node_id),
                      extra={'is_warning': True})
Пример #13
0
    def replace_pattern(graph: Graph, match: dict):
        node = match['op']
        node_id = node['id']

        if node.in_port(0).disconnected():
            i = 0
            for dest in node.out_port(0).get_destinations():
                new_in = Parameter(graph, {'name': "Parameter_"+str(i)+"_for_"+node_id,
                                           'shape': dest.data.get_shape()}).create_node()
                i += 1
                dest.disconnect()
                new_in.out_port(0).connect(dest)
                log.error("Add input/output mapped {} -> {} ".format(new_in.name, "Result_for_"+node_id),
                          extra={'is_warning': True})
        else:
            out_node_port = node.out_port(0).get_destination()
            in_node_port = node.in_port(0).get_source()
            node.in_port(0).disconnect()
            node.out_port(0).disconnect()
            crop = Crop(graph, {'name': 'Result_for_'+node_id, 'dim': np.array([1]), 'offset': np.array([0]), 'axis': np.array([0])}).create_node()
            in_node_port.connect(crop.in_port(0))
            crop.out_port(0).connect(out_node_port)
Пример #14
0
def convert_graph_inputs_to_parameters(internal_graph, internal_graph_proto):
    # create Parameter nodes for the body graph
    body_parameters = []
    body_parameter_names = []
    for idx, pb_node in enumerate(internal_graph_proto['input_arg']):
        param_id = internal_graph.unique_id(pb_node.name)
        internal_graph.add_node(param_id,
                                name=param_id,
                                kind='op',
                                op='Parameter',
                                pb=None,
                                shape=None)
        parameter_node = Node(internal_graph, pb_node.name)
        Parameter.update_node_stat(
            parameter_node, {
                'data_type':
                tf_dtype_extractor(pb_node.type),
                'permute_attrs':
                PermuteAttrs().update_attrs(attrs=[('shape', 'output:0')])
            })
        body_parameters.append(parameter_node)
        body_parameter_names.append(param_id)
    return body_parameters, body_parameter_names
Пример #15
0
    def replace_sub_graph(graph: Graph, match: dict, **kwargs):
        """
        Usually graph looks like:

          main_graph
            ...             Result
             |                 |
        image_batch      label_batch
                \        /
                batch_join
                /        \
        placeholder      fifo_queue

        Replacer works for both cases (that's why we have loop - 68 line):
            label_batch was marked as output
            there is no label_batch node
        """
        true_placeholder_shape = match['placeholder'].shape
        placeholder_shape = match['fifo_queue'].shapes[0]
        placeholder_data_type = match['fifo_queue'].types[0]
        assert true_placeholder_shape.ndim <= 1
        if true_placeholder_shape.ndim == 1 and len(
                true_placeholder_shape) > 1:
            log.warning(
                'Placeholder \'{}\' got non 0-dimensional shape {} in FIFOQueue pattern. Placeholder will have the '
                'same shape after folding the pattern instead of {} shape which is original for the network.'
                ''.format(match['placeholder'].id, true_placeholder_shape,
                          placeholder_shape))
            placeholder_shape = true_placeholder_shape
        placeholder_name = match['fifo_queue'].name
        graph.erase_node(match['fifo_queue'])
        graph.erase_node(match['placeholder'])
        for _, out in match['batch_join'].out_nodes().items():
            if out.id != match['image_batch'].id:
                if out.out_node().op == 'Result':
                    graph.remove_node(out.out_node().id)
                graph.remove_node(out.id)
        graph.remove_node(match['batch_join'].id)
        placeholder = Parameter(
            graph, {
                'name': placeholder_name,
                'shape': placeholder_shape,
                'data_type': placeholder_data_type
            }).create_node()
        graph.create_edge(placeholder, match['image_batch'])
        log.info(
            "FIFOQueueV2 pattern was detected. New shape of placeholder {} is {}. Use -b to set batch size if "
            "needed".format(placeholder.id, placeholder['shape']))
Пример #16
0
 def extract(node):
     Parameter.update_node_stat(node)
     return __class__.enabled
Пример #17
0
 def extract(cls, node):
     if 'value' in node.symbol_dict:
         Const.update_node_stat(node, {'value': node.symbol_dict['value']})
     else:
         Parameter.update_node_stat(node, {})
     return cls.enabled
Пример #18
0
    def replace_sub_graph(self, graph: Graph, match: dict):
        seq_len_tf = match['seq_len']
        transpose_tf = match['transpose']
        ctc_greedy_decoder_tf = match['ctc_greedy_decoder']
        cast_tf = match['cast']
        ctc_loss_tf = match['ctc_loss']
        sparse_to_dense_tf = match['sparse_to_dense']

        output_sparse_to_dense_name = sparse_to_dense_tf.soft_get(
            'name', sparse_to_dense_tf.id)
        output_ctc_loss_name = ctc_loss_tf.soft_get('name', ctc_loss_tf.id)
        ctc_greedy_decoder_tf_name = ctc_greedy_decoder_tf.soft_get(
            'name', ctc_greedy_decoder_tf.id)

        log.debug(
            'Found CTCLossFrontReplacer pattern after {} with name {}'.format(
                ctc_greedy_decoder_tf.op, ctc_greedy_decoder_tf.name))

        # create sequence mask node, sub-graph for transforming into sequence length and connect with consumers
        seq_len_tf_shape = seq_len_tf.soft_get('shape', None)
        if seq_len_tf_shape is None or len(seq_len_tf_shape) != 2:
            raise Error(
                'The sequence length that is the second input to the CTCGreedyDecoder node "{}"'
                ' must be specified in a mask format.'.format(
                    ctc_greedy_decoder_tf_name))
        log.error(
            'The format of input sequence length has been changed to a mask format',
            extra={'is_warning': True})
        seq_len_tf_type = seq_len_tf.soft_get('data_type', None)
        seq_len_tf_name = seq_len_tf.soft_get('name', seq_len_tf.id)
        seq_mask_placeholder = Parameter(
            graph, {
                'name': seq_len_tf_name,
                'shape': seq_len_tf_shape,
                'data_type': seq_len_tf_type
            }).create_node()
        reduce_to_seq_len_node = create_op_with_const_inputs(
            graph, ReduceSum, {1: np.array(1, dtype=np.int32)}, {
                'name': seq_len_tf_name + '/ReduceToSeqLen',
                'keep_dims': False
            })
        reduce_to_seq_len_node.in_port(0).connect(
            seq_mask_placeholder.out_port(0))
        seq_len_tf.out_port(0).get_connection().set_source(
            reduce_to_seq_len_node.out_port(0))

        cast_fp_type = data_type_str_to_np(graph.graph['cmd_params'].data_type)
        casted_seq_mask_node = Cast(graph, {
            'name': seq_len_tf_name + '/CastToFP32',
            'dst_type': cast_fp_type
        }).create_node()
        casted_seq_mask_node.in_port(0).connect(
            seq_mask_placeholder.out_port(0))
        permuted_casted_seq_mask = create_op_with_const_inputs(
            graph, Transpose, {1: int64_array([1, 0])},
            {'name': seq_len_tf_name + '/Permute'})
        permuted_casted_seq_mask.in_port(0).connect(
            casted_seq_mask_node.out_port(0))
        rename_nodes([(seq_len_tf, seq_len_tf_name + '/AbandonedName'),
                      (seq_mask_placeholder, seq_len_tf_name)])

        # create CTCGreedyDecoder node and set mask node
        ctc_merge_repeated_i = ctc_greedy_decoder_tf.soft_get(
            'ctc_merge_repeated', ctc_greedy_decoder_tf.id)
        ctc_greedy_decoder = CTCGreedyDecoderOp(
            graph, {
                'name': output_sparse_to_dense_name,
                'ctc_merge_repeated': ctc_merge_repeated_i
            }).create_node()
        ctc_greedy_decoder.in_port(1).connect(
            permuted_casted_seq_mask.out_port(0))
        rename_nodes([(sparse_to_dense_tf,
                       output_sparse_to_dense_name + '/AbandonedName'),
                      (ctc_greedy_decoder, output_sparse_to_dense_name)])

        # create CTCLoss node and set attributes
        assert ctc_loss_tf.has_valid('preprocess_collapse_repeated'), \
            'The CTCLoss node "{}" misses "preprocess_collapse_repeated" attribute'.format(output_ctc_loss_name)
        assert ctc_loss_tf.has_valid('ctc_merge_repeated'), \
            'The CTCLoss node "{}" misses "ctc_merge_repeated" attribute'.format(output_ctc_loss_name)
        assert ctc_loss_tf.has_valid('unique'), \
            'The CTCLoss node "{}" misses "unique" attribute'.format(output_ctc_loss_name)
        preprocess_collapse_repeated = ctc_loss_tf.preprocess_collapse_repeated
        ctc_merge_repeated = ctc_loss_tf.ctc_merge_repeated
        unique = ctc_loss_tf.unique
        ctc_loss = CTCLoss(
            graph, {
                'name': output_ctc_loss_name,
                'preprocess_collapse_repeated': preprocess_collapse_repeated,
                'ctc_merge_repeated': ctc_merge_repeated,
                'unique': unique
            }).create_node()
        rename_nodes([(ctc_loss_tf, output_ctc_loss_name + '/AbandonedName'),
                      (ctc_loss, output_ctc_loss_name)])

        # connect logits
        ctc_greedy_decoder_tf.in_port(0).get_connection().set_destination(
            ctc_greedy_decoder.in_port(0))
        ctc_loss.in_port(0).disconnect()
        transpose_tf.in_port(0).get_connection().add_destination(
            ctc_loss.in_port(0))

        # connect logit lengths
        ctc_greedy_decoder_tf.in_port(1).disconnect()
        ctc_loss.in_port(1).connect(reduce_to_seq_len_node.out_port(0))

        # connect labels to ctc_loss
        squeeze_op = create_op_with_const_inputs(graph, Squeeze,
                                                 {1: int64_array([2, 3])})
        cast_labels_op = Cast(
            graph, {
                'name': output_sparse_to_dense_name + '/CastLabels',
                'dst_type': np.int32
            }).create_node()
        squeeze_op.in_port(0).connect(ctc_greedy_decoder.out_port(0))
        cast_labels_op.in_port(0).connect(squeeze_op.out_port(0))
        ctc_loss.in_port(2).connect(cast_labels_op.out_port(0))

        # connect label lengths
        equal_op = create_op_with_const_inputs(
            graph, Equal, {1: np.array([-1], dtype=np.int32)},
            {'name': output_sparse_to_dense_name + '/Equal'})
        equal_op.in_port(0).connect(cast_labels_op.out_port(0))
        labels_shape_op = Shape(
            graph, {
                'name': output_sparse_to_dense_name + '/ShapeOf'
            }).create_node()
        labels_shape_op.in_port(0).connect(equal_op.out_port(0))
        broadcast_one = create_op_with_const_inputs(
            graph, Broadcast, {0: np.array([1], dtype=np.int32)}, {
                'mode': 'numpy',
                'name': output_sparse_to_dense_name + '/One'
            })
        broadcast_one.in_port(1).connect(labels_shape_op.out_port(0))
        broadcast_zero = create_op_with_const_inputs(
            graph, Broadcast, {0: np.array([0], dtype=np.int32)}, {
                'mode': 'numpy',
                'name': output_sparse_to_dense_name + '/Zero'
            })
        broadcast_zero.in_port(1).connect(labels_shape_op.out_port(0))

        select_node = Select(graph, {
            'name': output_sparse_to_dense_name + '/Select'
        }).create_node()
        select_node.in_port(0).connect(equal_op.out_port(0))
        select_node.in_port(1).connect(broadcast_zero.out_port(0))
        select_node.in_port(2).connect(broadcast_one.out_port(0))
        label_length_node = create_op_with_const_inputs(
            graph,
            ReduceSum, {1: int64_array([1])},
            op_attrs={
                'name': output_sparse_to_dense_name + '/LabelLength',
                'keep_dims': False
            })
        label_length_node.in_port(0).connect(select_node.out_port(0))
        ctc_loss.in_port(3).connect(label_length_node.out_port(0))

        # set source for output of new sub-graph and remove old nodes
        ctc_loss_tf.out_port(0).get_connection().set_source(
            ctc_loss.out_port(0))
        graph.remove_nodes_from([
            ctc_greedy_decoder_tf.id, ctc_loss_tf.id, cast_tf.id,
            sparse_to_dense_tf.id
        ])
Пример #19
0
    def extract(cls, loop_node):
        Loop.update_node_stat(loop_node, {})
        loop_name = loop_node.soft_get('name', loop_node.id)

        # check that required body and condition functions exist in the graph library
        main_graph = loop_node.graph
        body_graph_name = loop_node.pb.attr['body'].func.name
        cond_graph_name = loop_node.pb.attr['cond'].func.name
        assert 'library' in main_graph.graph, 'The graph does not contain a library that is required ' \
                                              'by node with name "{}".'.format(loop_name)
        library_graph = main_graph.graph['library']

        assert body_graph_name in library_graph, 'The library does not contain a function with name "{}" ' \
                                                 'that is required by node ' \
                                                 'with name "{}".'.format(body_graph_name, loop_name)
        body_graph_proto = library_graph[body_graph_name]

        assert cond_graph_name in library_graph, 'The library does not contain a function with name "{}" ' \
                                                 'that is required by node ' \
                                                 'with name "{}".'.format(cond_graph_name, loop_name)
        cond_graph_proto = library_graph[cond_graph_name]

        body_graph = Graph()
        # fill the body graph
        for attr_key in main_graph.graph.keys():
            if attr_key != 'library':
                body_graph.graph[attr_key] = copy.deepcopy(main_graph.graph[attr_key])
            else:
                # it is sufficient to have a link to the library
                body_graph.graph['library'] = main_graph.graph['library']
        loop_node['body'] = body_graph

        # create Parameter nodes for the body graph
        body_parameters = []
        body_parameter_names = []
        for idx, pb_node in enumerate(body_graph_proto['input_arg']):
            param_id = body_graph.unique_id(pb_node.name)
            body_graph.add_node(param_id, name=param_id, kind='op', op='Parameter', pb=None, shape=None)
            parameter_node = Node(body_graph, pb_node.name)
            Parameter.update_node_stat(parameter_node,
                                       {'data_type': tf_dtype_extractor(pb_node.type),
                                        'permute_attrs': PermuteAttrs().update_attrs(attrs=[('shape', 'output:0')])}
                                       )
            body_parameters.append(parameter_node)
            body_parameter_names.append(param_id)

        # update the loop body graph with the body function graph
        body_results = []
        update_body_graph(body_graph, body_graph_proto, body_parameter_names, body_results)

        # update the loop body graph with the condition function graph
        update_body_graph(body_graph, cond_graph_proto, body_parameter_names, body_results)

        # add 'internal_layer_id' attribute which is a must have attribute for the loop body node
        for idx, body_node in enumerate(body_graph.get_op_nodes()):
            body_node['internal_layer_id'] = idx

        body_graph.stage = 'front'

        # Currently,
        # Loop Inputs Order:
        #   0    - current iteration
        #   1    - trip count
        #   2..  - "loop carried" dependencies variables
        #
        # Body Inputs Order:
        #   0    - current iteration
        #   1    - trip count
        #   2..  - "loop carried" dependencies variables
        #
        # Body Outputs Order:
        #   0      - current iteration
        #   1      - trip count
        #   2..    - "loop carried" dependencies variables
        #
        # Loop Outputs Order:
        #   0    - current iteration
        #   1    - trip count
        #   2..  - "loop carried" dependencies variables
        #
        # so inputs must be reordered and execution condition must be created in the front transformation
        # to be aligned with the specification

        # connect external input ports with body parameter nodes except current iteration
        # since it must be disconnected from external port
        for idx in range(1, len(body_parameters)):
            Loop.connect_body_input(loop_node, idx, body_parameters[idx])

        # mark current iteration input Parameter node and execution condition Result node
        Loop.mark_current_iteration_parameter_node(loop_node, body_parameters[0])
        Loop.mark_execution_condition_result_node(loop_node, body_results[-1])

        # connect back edges in the body except current iteration
        for idx in range(1, len(body_parameters)):
            Loop.add_back_edge(loop_node, body_parameters[idx], body_results[idx])

        # connect body outputs with Loop operation output ports except the execution condition result
        for idx in range(len(body_results)-1):
            Loop.connect_body_output(loop_node, idx, body_results[idx])

        # run function to parse body nodes attributes similar to the main graph
        extract_node_attrs(body_graph, lambda node: tf_op_extractor(node, check_for_duplicates(tf_op_extractors)))
        return cls.enabled
Пример #20
0
 def extract(cls, node):
     Parameter.update_node_stat(node)
     return cls.enabled
Пример #21
0
 def extract(node):
     Parameter.update_node_stat(
         node, {'shape': dim_to_shape(node.pb.input_param.shape[0].dim)})
     return __class__.enabled
Пример #22
0
    def extract(cls, loop_node):
        Loop.update_node_stat(loop_node, {})

        body_graph_proto = onnx_attr(loop_node, 'body', 'g', None)
        main_graph = loop_node.graph

        # create a Graph object for the body and take graph attributes from the main graph
        body_graph = Graph()
        main_graph_attrs_copy = copy.deepcopy(main_graph.graph)
        del main_graph_attrs_copy['tensor_mapping']
        body_graph.graph.update(main_graph_attrs_copy)
        loop_node['body'] = body_graph

        # maps a tensor name to a node produced it and the node port: str -> (node_id, node_port)
        data_nodes_map = {}
        body_graph.graph[
            'tensor_mapping'] = data_nodes_map  # save mapping for possible Loop inside the Loop

        body_parameters = add_initializers_and_inputs_to_graph(
            body_graph, body_graph_proto, data_nodes_map)

        external_edges = [
        ]  # (src_node, src_out_port), dest_body_parameter_node
        additional_params = {
        }  # (src_node, src_out_port) -> parameter_node (for manually added Parameters)
        # Go through all nodes in the original model order because data nodes are defined on-the-fly and order matters
        for pb_node in body_graph_proto.node:
            # create an NX node
            id = body_graph.unique_id(node_id(pb_node))
            body_graph.add_node(id, pb=pb_node, kind='op')

            # add incoming edges based on data_nodes_map
            for dst_port, inp in enumerate(pb_node.input):
                # should add edge inp --> id
                if inp not in data_nodes_map:
                    if inp == '':
                        # input is omitted; most likely it corresponds to an optional input for an operator
                        continue
                    elif inp in main_graph.graph['tensor_mapping']:
                        log.debug(
                            'The edge between outer and inner graphs detected: {} -> {}'
                            .format(inp, id))
                        if main_graph.graph['tensor_mapping'][
                                inp] not in additional_params:
                            # create new Parameter body node and connect the body node with the outer graph using it
                            param_id = str(inp)
                            body_graph.add_node(param_id,
                                                kind='op',
                                                op='Parameter',
                                                name=param_id,
                                                pb=None,
                                                shape=None)
                            parameter_node = Node(body_graph, param_id)
                            # need to manually update necessary attrs for the node because extractor will not be called
                            # for it because the node does not have .pb attribute
                            Parameter.update_node_stat(parameter_node, {})
                            external_edges.append(
                                (main_graph.graph['tensor_mapping'][inp],
                                 parameter_node))
                            src_id, src_port = param_id, 0
                            additional_params[main_graph.graph[
                                'tensor_mapping'][inp]] = parameter_node
                        else:
                            src_id, src_port = additional_params[
                                main_graph.graph['tensor_mapping'][inp]].id, 0
                    else:
                        raise Error(
                            'Reference to "{}" is not satisfied. A node refer not existing data tensor. ONNX '
                            'model is not consistent. Protobuf fragment: {}',
                            inp, pb_node)
                else:
                    src_id, src_port = data_nodes_map[inp]

                assert (body_graph.has_node(src_id))
                edge_attrs = {
                    'out': src_port,
                    'in': dst_port,
                    'name': inp,
                    'fw_tensor_debug_info': [(inp, inp)],
                    'in_attrs': ['in', 'name'],
                    'out_attrs': ['out', 'name'],
                    'data_attrs': ['fw_tensor_debug_info']
                }
                body_graph.add_edge(src_id, id, **edge_attrs)

            # add outgoing edges to data_nodes_map
            for src_port, out in enumerate(pb_node.output):
                if out in data_nodes_map:
                    log.debug("Detected reuse of blob {}.".format(out))
                data_nodes_map[out] = (id, src_port)

        body_results = []
        for output in body_graph_proto.output:
            tensor_name = str(output.name)
            node_name, output_port = data_nodes_map[tensor_name]
            assert body_graph.has_node(
                node_name
            ), 'The body graph does not contain output with name "{}"'.format(
                node_name)
            body_results.append(
                Node(body_graph,
                     add_opoutput(body_graph, node_name, output_port, False)))

        # add 'internal_layer_id' attribute which is a must have attribute for the loop body node
        for idx, body_node in enumerate(body_graph.get_op_nodes()):
            body_node['internal_layer_id'] = idx

        loop_carried_dependencies_count = len(body_graph_proto.input) - 2
        scan_outputs_count = len(
            body_graph_proto.output) - 1 - loop_carried_dependencies_count

        # Loop inputs:
        #   0 - trip count
        #   1 - execution condition
        #   2 .. - loop carried dependencies

        # Loop outputs:
        #   0 .. loop_carried_dependencies_count - 1 - loop carried dependencies
        #   loop_carried_dependencies_count .. - scan outputs

        # Body inputs:
        #   0 - iteration number
        #   1 - execution condition
        #   2 .. - loop carried dependencies

        # Body outputs:
        #   0 - execution condition
        #   1 .. loop_carried_dependencies_count - loop carried dependencies
        #   loop_carried_dependencies_count + 1 .. - scan outputs

        body_graph.stage = 'front'
        # some of the inputs/outputs may not be connected but the normalization transformation will take care of it
        # connection Loop body nodes with external input edges
        next_loop_input_port_idx = sorted(loop_node.in_edges().keys())[-1] + 1
        for (src_node, src_port), body_node in external_edges:
            main_graph.add_edge(
                src_node, loop_node.id, **{
                    'out': src_port,
                    'in': next_loop_input_port_idx,
                    'name': src_node,
                    'fw_tensor_debug_info': [(src_node, src_node)],
                    'in_attrs': ['in', 'name'],
                    'out_attrs': ['out', 'name'],
                    'data_attrs': ['fw_tensor_debug_info']
                })
            connect_body_input(loop_node, next_loop_input_port_idx, body_node)
            next_loop_input_port_idx += 1

        # mark current iteration input Parameter node
        Loop.mark_current_iteration_parameter_node(loop_node,
                                                   body_parameters[0])

        # connect initial value for "execution condition" input of the loop
        connect_body_input(loop_node, 1, body_parameters[1])
        # add back edge with "execution condition"
        Loop.add_back_edge(loop_node, body_parameters[1], body_results[0])
        # mark "execution condition" Result node
        Loop.mark_execution_condition_result_node(loop_node, body_results[0])

        # connect initial value for "loop carried" dependencies variables
        for idx in range(loop_carried_dependencies_count):
            connect_body_input(loop_node, idx + 2, body_parameters[idx + 2])
        # add back edge for "loop carried" dependencies variables
        for idx in range(loop_carried_dependencies_count):
            Loop.add_back_edge(loop_node, body_parameters[idx + 2],
                               body_results[idx + 1])
        # connect final value for "loop carried" dependencies variables
        for idx in range(loop_carried_dependencies_count):
            connect_body_output(loop_node, idx, body_results[idx + 1])

        # connect "scan outputs" and mark axis for concatenation
        for idx in range(loop_carried_dependencies_count,
                         loop_carried_dependencies_count + scan_outputs_count):
            connect_body_output(loop_node, idx, body_results[idx + 1], axis=0)

        # run function to parse body nodes attributes similar to the main graph
        extract_node_attrs(
            body_graph, lambda node: onnx_op_extractor(
                node, check_for_duplicates(onnx_op_extractors)))
        return cls.enabled