コード例 #1
0
    def _is_module_prunable(self, graph: NNCFGraph,
                            node: NNCFNode) -> PruningAnalysisDecision:
        """
        Check whether we should prune module corresponding to provided node
        according to algorithm parameters.

        :param graph: Graph to work with.
        :param node: Node to check.
        :return: Pruning analysis decision.
        """
        stop_propagation_ops = self._stop_propagation_op_metatype.get_all_op_aliases(
        )
        types_to_track = self._prune_operations_types + stop_propagation_ops
        input_non_pruned_nodes = get_first_nodes_of_type(graph, types_to_track)
        node_name = node.node_name

        if not should_consider_scope(node_name, self._ignored_scopes,
                                     self._target_scopes):
            return PruningAnalysisDecision(False,
                                           PruningAnalysisReason.IGNORED_SCOPE)

        if not self._prune_first and node in input_non_pruned_nodes:
            return PruningAnalysisDecision(False,
                                           PruningAnalysisReason.FIRST_CONV)

        if is_grouped_conv(node) and not is_prunable_depthwise_conv(node):
            return PruningAnalysisDecision(False,
                                           PruningAnalysisReason.GROUP_CONV)

        if not self._prune_downsample_convs and is_conv_with_downsampling(
                node):
            return PruningAnalysisDecision(
                False, PruningAnalysisReason.DOWNSAMPLE_CONV)

        return PruningAnalysisDecision(True)
コード例 #2
0
    def mask_propagation(cls, node: NNCFNode, graph: NNCFGraph):
        input_masks = get_input_masks(node, graph)
        output_mask = node.data.get('output_mask', None)

        if is_grouped_conv(node):
            output_mask = None
            if is_depthwise_conv(node):
                output_mask = input_masks[0]

        node.data['output_mask'] = output_mask
コード例 #3
0
    def mask_propagation(cls, node: NNCFNode, graph: NNCFGraph):
        input_masks = get_input_masks(node, graph)
        output_mask = node.data.get('output_mask', None)

        # In case of group convs we can't prune by output filters
        if is_grouped_conv(node):
            output_mask = None
            if is_depthwise_conv(node):
                output_mask = input_masks[0]

        node.data['output_mask'] = output_mask
コード例 #4
0
ファイル: operations.py プロジェクト: openvinotoolkit/nncf
    def mask_propagation(
            cls, node: NNCFNode, graph: NNCFGraph,
            tensor_processor: Type[NNCFPruningBaseTensorProcessor]) -> None:
        input_masks = get_input_masks(node, graph)
        output_mask = node.data.get('output_mask', None)

        if is_grouped_conv(node):
            output_mask = None
            if is_prunable_depthwise_conv(node):
                output_mask = input_masks[0]

        node.data['output_mask'] = output_mask
コード例 #5
0
 def accept_pruned_input(cls, node: NNCFNode):
     accept_pruned_input = True
     if is_grouped_conv(node):
         if not is_depthwise_conv(node):
             accept_pruned_input = False
     return accept_pruned_input
コード例 #6
0
    def symbolic_mask_propagation(self, prunable_layers_types: List[str],
                                  can_prune_after_analysis: Dict[int, PruningAnalysisDecision]) \
            -> Dict[int, PruningAnalysisDecision]:
        """
        Check all nodes that were marked as prunable after the model analysis and compatibility check vs.
        pruning algo have a correct correspondent closing node on each path from self to outputs;
        the check entails verifying that every convolution prunable by the output channel dimension
        has a corresponding convolution that is prunable by its input channel dimension (output channel
        dimension equal to closing convolution input channel dimension) in every path from self to outputs.
        If the check fails, the entire groups containing such nodes will be marked as unprunable.
        If convolution symbolic mask mixes with other symbolic masks (by elementwise operation, for example)
        and mixing masks can't be mixed, all mask producers participated in this mixing will be marked as unprunable.
        If convolution output channel dimension reducing directly affect an output of the model -
        it will be marked as unprunable as well.


        :param prunable_layers_types: Types of operations with prunable filters.
        :param can_prune_after_analysis: Dict of node indices vs the decision made by previous steps;
            the decision is true only for the nodes that do not conflict with mask propagation and
            are supported by the NNCF pruning algorithm.
        :return: Dict of node indices vs the decision made by symbolic mask propagation algorithm.
        """

        can_be_closing_convs = {
            node.node_id
            for node in self._graph.get_all_nodes()
            if node.node_type in prunable_layers_types
            and not is_grouped_conv(node)
        }
        can_prune_by_dim = {k: None for k in can_be_closing_convs}
        for node in self._graph.topological_sort():
            if node.node_id in can_be_closing_convs and can_prune_after_analysis[
                    node.node_id]:
                # Set output mask
                node.data['output_mask'] = SymbolicMask(
                    node.layer_attributes.out_channels, [node.node_id])
            # Propagate masks
            cls = self.get_meta_operation_by_type_name(node.node_type)
            cls.mask_propagation(node, self._graph, SymbolicMaskProcessor)
            if node.node_id in can_be_closing_convs:
                # Check input mask producers out channel dimension
                input_masks = get_input_masks(node, self._graph)
                if any(input_masks):
                    assert len(input_masks) == 1
                    input_mask = input_masks[0]

                    for producer in input_mask.mask_producers:
                        previously_dims_equal = True if can_prune_by_dim[producer] is None \
                            else can_prune_by_dim[producer]

                        is_dims_equal = node.layer_attributes.in_channels == input_mask.shape[
                            0]
                        decision = previously_dims_equal and is_dims_equal
                        can_prune_by_dim[producer] = PruningAnalysisDecision(
                            decision, PruningAnalysisReason.DIMENSION_MISMATCH)
        # Remove all convolutions with masks
        # that were propagated to output node
        for out_node in self._graph.get_output_nodes():
            for input_mask in get_input_masks(out_node, self._graph):
                if input_mask:
                    for producer in input_mask.mask_producers:
                        can_prune_by_dim[producer] = PruningAnalysisDecision(
                            False, PruningAnalysisReason.LAST_CONV)
        # Update decision for nodes which
        # have no closing convolution
        convs_without_closing_conv = {}
        for k, v in can_prune_by_dim.items():
            if v is None:
                convs_without_closing_conv[k] = \
                    PruningAnalysisDecision(False, PruningAnalysisReason.CLOSING_CONV_MISSING)
        can_prune_by_dim.update(convs_without_closing_conv)

        # Clean nodes masks
        for node in self._graph.get_all_nodes():
            node.data['output_mask'] = None

        return can_prune_by_dim
コード例 #7
0
ファイル: operations.py プロジェクト: openvinotoolkit/nncf
 def accept_pruned_input(cls, node: NNCFNode) -> bool:
     if is_grouped_conv(node) and not is_prunable_depthwise_conv(node):
         return False
     return True