Beispiel #1
0
def get_all_node_op_addresses_in_block(
        compressed_model: NNCFNetwork,
        block: BuildingBlock) -> Set[OperationAddress]:
    """
    Returns set of operation addresses of all layers included in the block.

    :param compressed_model: Target model.
    :param block: Building blocks.
    :return: Set of operation addresses for building block.
    """
    graph = compressed_model.get_original_graph()
    nx_graph = graph.get_nx_graph_copy()
    start_node, end_node = block
    start_node_key, end_node_key = None, None
    #pylint: disable=protected-access
    for node in nx_graph._node.values():
        if start_node == str(node['node_name']):
            start_node_key = node['key']
        if end_node == str(node['node_name']):
            end_node_key = node['key']
    simple_paths = nx.all_simple_paths(nx_graph, start_node_key, end_node_key)
    op_adresses = set()
    for node_keys_in_path in simple_paths:
        for node_key in node_keys_in_path:
            op_adresses.add(
                OperationAddress.from_str(
                    nx_graph._node[node_key]['node_name']))
    start_op_address = OperationAddress.from_str(
        nx_graph._node[start_node_key]['node_name'])
    op_adresses.remove(start_op_address)
    return op_adresses
def get_mock_nncf_node_attrs(op_name=None, scope_str=None):
    op_name_to_set = op_name if op_name is not None else MOCK_OPERATOR_NAME
    scope_to_set = Scope() if scope_str is None else Scope.from_str(scope_str)
    return {
        NNCFGraph.NODE_NAME_ATTR: str(OperationAddress(op_name_to_set, scope_to_set, 0)),
        NNCFGraph.NODE_TYPE_ATTR: op_name_to_set
    }
    def test_single_insertions(self, setup, target_point: PTTargetPoint):
        insertion_point = PTInsertionPoint(target_point.target_type,
                                           OperationAddress.from_str(target_point.target_node_name),
                                           target_point.input_port_id)
        if insertion_point.insertion_type in [PTInsertionType.OPERATOR_PRE_HOOK, PTInsertionType.OPERATOR_POST_HOOK]:
            hook = lambda x: x
        else:
            hook = BaseOp(lambda x: x)

        self.compressed_model.insert_at_point(insertion_point, [hook])

        # pylint:disable=protected-access
        if insertion_point.insertion_type == PTInsertionType.OPERATOR_PRE_HOOK:
            ctx = self.compressed_model.get_tracing_context()
            pre_hook_id = PreHookId(insertion_point.op_address, input_port_id=insertion_point.input_port_id)
            assert ctx._pre_hooks[pre_hook_id][0] is hook
        if insertion_point.insertion_type == PTInsertionType.OPERATOR_POST_HOOK:
            ctx = self.compressed_model.get_tracing_context()
            assert ctx._post_hooks[insertion_point.op_address][0] is hook
        if insertion_point.insertion_type == PTInsertionType.NNCF_MODULE_PRE_OP:
            module = self.compressed_model.get_module_by_scope(insertion_point.module_scope)
            assert module.pre_ops["0"] is hook

        if insertion_point.insertion_type == PTInsertionType.NNCF_MODULE_POST_OP:
            module = self.compressed_model.get_module_by_scope(insertion_point.module_scope)
            assert module.post_ops["0"] is hook
def get_nncf_graph_from_mock_nx_graph(nx_graph: nx.DiGraph) -> PTNNCFGraph:
    # pylint:disable=too-many-branches
    mock_graph = PTNNCFGraph()
    key_vs_id = {}
    edge_vs_output_idx_and_creator_id = {}  # type: Dict[Tuple[str, str], Tuple[int, int]]
    from networkx.algorithms.dag import lexicographical_topological_sort
    for idx, curr_node_key in enumerate(lexicographical_topological_sort(nx_graph)):
        node = nx_graph.nodes[curr_node_key]
        if NNCFGraph.NODE_NAME_ATTR in node:
            node_name = node[NNCFGraph.NODE_NAME_ATTR]
        else:
            node_name = str(OperationAddress(curr_node_key, Scope(), 0))

        if NNCFGraph.NODE_TYPE_ATTR in node:
            node_type = node[NNCFGraph.NODE_TYPE_ATTR]
        else:
            node_type = curr_node_key

        layer_attributes = node.get(NNCFGraph.LAYER_ATTRIBUTES)

        if NNCFGraph.METATYPE_ATTR in node:
            metatype = node[NNCFGraph.METATYPE_ATTR]
        else:
            metatype = PT_OPERATOR_METATYPES.get_operator_metatype_by_op_name(node_type)
            if metatype is not UnknownMetatype:
                if metatype.subtypes:
                    subtype = metatype.determine_subtype(layer_attributes=layer_attributes)
                    if subtype is not None:
                        metatype = subtype

        node_id = idx
        node = mock_graph.add_nncf_node(
            node_name=node_name,
            node_type=node_type,
            node_metatype=metatype,
            layer_attributes=layer_attributes,
            node_id_override=idx)
        key_vs_id[curr_node_key] = node_id

        preds = list(nx_graph.predecessors(curr_node_key))
        for pred_idx, pred in enumerate(preds):
            in_edge = (pred, curr_node_key)
            out_idx, creator_id = edge_vs_output_idx_and_creator_id[in_edge]
            edge_data = nx_graph.edges[in_edge]
            if NNCFGraph.DTYPE_EDGE_ATTR in edge_data:
                dtype = edge_data[NNCFGraph.DTYPE_EDGE_ATTR]
            else:
                dtype = Dtype.FLOAT
            mock_graph.add_edge_between_nncf_nodes(creator_id, node_id,
                                                   [1, 1, 1, 1], input_port_id=pred_idx,
                                                   output_port_id=out_idx,
                                                   dtype=dtype)

        for out_idx, out_edge in enumerate(nx_graph.out_edges(curr_node_key)):
            edge_vs_output_idx_and_creator_id[out_edge] = (out_idx, node.node_id)
    return mock_graph
Beispiel #5
0
 def __init__(self,
              operator_name: str,
              scope_in_model: Scope,
              call_order: int,
              tensor_metas: List[TensorMeta],
              tm_comparators: List[TensorMetaComparator] = None,
              input_matcher: InputsMatcher = None):
     self.op_address = OperationAddress(operator_name, scope_in_model,
                                        call_order)
     # This should be a list with a length equal to the number of inputs.
     # "None" values in this list correspond to non-tensor input nodes.
     self.tensor_metas = tensor_metas
     self.tm_comparators = tm_comparators if tm_comparators else [
         DefaultTensorMetaComparator()
     ]
     self.input_matcher = input_matcher if input_matcher else DefaultInputsMatcher(
     )
Beispiel #6
0
    def get_caller_context(self, operator_name: str) -> OperationAddress:
        """
        Designed to work in the following way - for each scope the context will track the number of the calls to the
        operators with the name operator_name (call_order). The counter values are preserved until reset by a
        corresponding member function of the context, which must be called after each model iteration - this is
        usually handled inside NNCF. This mechanism allows to discern between multiple function calls inside the same
        module that would each require their own instance of compression layers - for instance, multiple `relu`
        function calls (either on their own or inside a `for` cycle), and at the same moment allow the checkpoints to
        be loaded if the model had changed in the meantime in a way that does not impact the major function call
        order (e.g. if comments were added to the .py file with the model)
        """

        call_order = self.get_operator_call_count_in_scope(
            operator_name, self.scope)

        op_address = OperationAddress(operator_name, self.scope, call_order)
        return op_address
class TestInsertionCommands:
    @pytest.fixture()
    def setup(self):
        self.compressed_model = NNCFNetwork(InsertionPointTestModel(),
                                            [ModelInputInfo([1, 1, 10, 10])])  # type: NNCFNetwork

    conv1_node_name = 'InsertionPointTestModel/NNCFConv2d[conv1]/conv2d_0'
    point_for_conv1_weights = PTTargetPoint(target_type=TargetType.OPERATION_WITH_WEIGHTS,
                                            target_node_name=conv1_node_name)
    point_for_conv1_inputs = PTTargetPoint(target_type=TargetType.OPERATOR_PRE_HOOK,
                                           target_node_name=conv1_node_name)
    point_for_conv1_activations = PTTargetPoint(target_type=TargetType.POST_LAYER_OPERATION,
                                                target_node_name=conv1_node_name)

    conv2_node_name = 'InsertionPointTestModel/NNCFConv2d[conv2]/conv2d_0'
    point_for_conv2_weights = PTTargetPoint(target_type=TargetType.OPERATION_WITH_WEIGHTS,
                                            target_node_name=conv2_node_name)
    point_for_conv2_inputs = PTTargetPoint(target_type=TargetType.OPERATOR_PRE_HOOK,
                                           target_node_name=conv2_node_name)
    point_for_conv2_activations = PTTargetPoint(target_type=TargetType.POST_LAYER_OPERATION,
                                                target_node_name=conv2_node_name)

    linear_node_name = 'InsertionPointTestModel/linear_0'
    point_for_linear_weight_input = PTTargetPoint(target_type=TargetType.OPERATOR_PRE_HOOK,
                                                  target_node_name=linear_node_name, input_port_id=0)
    point_for_linear_activation = PTTargetPoint(target_type=TargetType.OPERATOR_POST_HOOK,
                                                target_node_name=linear_node_name)

    relu_node_name = 'InsertionPointTestModel/ReLU[relu]/relu_0'
    point_for_relu_inputs = PTTargetPoint(target_type=TargetType.OPERATOR_PRE_HOOK,
                                          target_node_name=relu_node_name, input_port_id=0)
    point_for_relu_activations = PTTargetPoint(target_type=TargetType.OPERATOR_POST_HOOK,
                                               target_node_name=relu_node_name)

    available_points = [point_for_conv1_weights,
                        point_for_conv2_weights,
                        point_for_conv1_inputs,
                        point_for_conv2_inputs,
                        point_for_conv1_activations,
                        point_for_conv2_activations,
                        point_for_linear_activation,
                        point_for_linear_weight_input,
                        point_for_relu_activations,
                        point_for_relu_inputs]

    @pytest.mark.parametrize("target_point", available_points)
    def test_single_insertions(self, setup, target_point: PTTargetPoint):
        insertion_point = PTInsertionPoint(target_point.target_type,
                                           OperationAddress.from_str(target_point.target_node_name),
                                           target_point.input_port_id)
        if insertion_point.insertion_type in [PTInsertionType.OPERATOR_PRE_HOOK, PTInsertionType.OPERATOR_POST_HOOK]:
            hook = lambda x: x
        else:
            hook = BaseOp(lambda x: x)

        self.compressed_model.insert_at_point(insertion_point, [hook])

        # pylint:disable=protected-access
        if insertion_point.insertion_type == PTInsertionType.OPERATOR_PRE_HOOK:
            ctx = self.compressed_model.get_tracing_context()
            pre_hook_id = PreHookId(insertion_point.op_address, input_port_id=insertion_point.input_port_id)
            assert ctx._pre_hooks[pre_hook_id][0] is hook
        if insertion_point.insertion_type == PTInsertionType.OPERATOR_POST_HOOK:
            ctx = self.compressed_model.get_tracing_context()
            assert ctx._post_hooks[insertion_point.op_address][0] is hook
        if insertion_point.insertion_type == PTInsertionType.NNCF_MODULE_PRE_OP:
            module = self.compressed_model.get_module_by_scope(insertion_point.module_scope)
            assert module.pre_ops["0"] is hook

        if insertion_point.insertion_type == PTInsertionType.NNCF_MODULE_POST_OP:
            module = self.compressed_model.get_module_by_scope(insertion_point.module_scope)
            assert module.post_ops["0"] is hook

    priority_types = ["same", "different"]
    insertion_types = TargetType
    priority_test_cases = list(itertools.product(priority_types, insertion_types))

    @staticmethod
    def check_order(iterable1: List, iterable2: List, ordering: List):
        for idx, order in enumerate(ordering):
            assert iterable1[idx] is iterable2[order]

    # pylint:disable=undefined-variable
    @pytest.mark.parametrize("case", priority_test_cases, ids=[x[1].name + '-' + x[0] for x in priority_test_cases])
    def test_priority(self, case, setup):
        # pylint:disable=too-many-branches
        priority_type = case[0]
        insertion_type = case[1]
        if insertion_type in [TargetType.OPERATION_WITH_WEIGHTS, TargetType.POST_LAYER_OPERATION]:
            hook1 = BaseOp(lambda x: x)
            hook2 = BaseOp(lambda x: 2 * x)
            hook3 = BaseOp(lambda x: 3 * x)
        else:
            hook1 = lambda x: x
            hook2 = lambda x: 2 * x
            hook3 = lambda x: 3 * x

        if insertion_type == TargetType.OPERATION_WITH_WEIGHTS:
            point = self.point_for_conv2_weights
        elif insertion_type == TargetType.POST_LAYER_OPERATION:
            point = self.point_for_conv1_activations
        elif insertion_type == TargetType.OPERATOR_PRE_HOOK:
            point = self.point_for_linear_weight_input
        elif insertion_type == TargetType.OPERATOR_POST_HOOK:
            point = self.point_for_relu_activations
        else:
            pytest.skip("Insertion type {} currently unsupported in PT".format(insertion_type))

        if priority_type == "same":
            # Same-priority commands will be executed in registration order
            command1 = PTInsertionCommand(point, hook1, TransformationPriority.DEFAULT_PRIORITY)
            command2 = PTInsertionCommand(point, hook2, TransformationPriority.DEFAULT_PRIORITY)
            command3 = PTInsertionCommand(point, hook3, TransformationPriority.DEFAULT_PRIORITY)
        else:
            # Prioritized commands will be executed in ascending priority order
            command1 = PTInsertionCommand(point, hook1, TransformationPriority.SPARSIFICATION_PRIORITY)
            command2 = PTInsertionCommand(point, hook2, TransformationPriority.QUANTIZATION_PRIORITY)
            command3 = PTInsertionCommand(point, hook3, TransformationPriority.DEFAULT_PRIORITY)

        layout = PTTransformationLayout()
        layout.register(command1)
        layout.register(command2)
        layout.register(command3)
        self.compressed_model = PTModelTransformer(self.compressed_model).transform(layout)

        hook_list = [hook1, hook2, hook3]

        if priority_type == "same":
            order = [0, 1, 2]
        elif priority_type == "different":
            order = [2, 0, 1]

        # pylint:disable=protected-access
        if insertion_type == TargetType.OPERATOR_PRE_HOOK:
            ctx = self.compressed_model.get_tracing_context()
            pre_hook_id = PreHookId(OperationAddress.from_str(point.target_node_name),
                                    input_port_id=point.input_port_id)
            self.check_order(ctx._pre_hooks[pre_hook_id], hook_list, order)
        if insertion_type == TargetType.OPERATOR_POST_HOOK:
            ctx = self.compressed_model.get_tracing_context()
            self.check_order(ctx._post_hooks[OperationAddress.from_str(point.target_node_name)],
                             hook_list, order)

        if insertion_type == TargetType.OPERATION_WITH_WEIGHTS:
            module = self.compressed_model.get_containing_module(point.target_node_name)
            # Works because Pytorch ModuleDict is ordered
            self.check_order([x.operand for x in module.pre_ops.values()], hook_list, order)

        if insertion_type == TargetType.POST_LAYER_OPERATION:
            module = self.compressed_model.get_containing_module(point.target_node_name)
            # Works because Pytorch ModuleDict is ordered
            self.check_order(list(module.post_ops.values()), hook_list, order)
Beispiel #8
0
def make_op_address_for_coalescing_test(scope_str: str) -> OperationAddress:
    op_address = OperationAddress.from_str(scope_str)
    return op_address