Example #1
0
    def get_configs_constrained_by_traces_order(self, traces_order: TracesOrder) -> \
            Tuple[List[ConfigurationForHAWQToEvaluate], List[CoveringConfigurationForQuantNoiseCalculation]]:
        configuration_space_in_trace_order = [
        ]  # type: List[List[QuantizerConfig]]
        trace_order_indices_of_defaulted_configs = set()  # type: Set[int]
        quantizer_ids_in_exec_order = list(
            self._weight_quantizations_by_execution_order.keys())
        assert len(quantizer_ids_in_exec_order) == len(traces_order)
        for trace_idx in range(len(traces_order)):
            exec_idx = traces_order.get_execution_index_by_traces_index(
                trace_idx)
            qid = quantizer_ids_in_exec_order[exec_idx]
            default_qconfig = self._weight_quantizations_by_execution_order[
                qid].get_current_config()
            qconfig_constraints = []
            if self._hw_precision_constraints:
                qconfig_constraints = self._hw_precision_constraints.get(qid)
            if qconfig_constraints:
                configuration_space_in_trace_order.append(qconfig_constraints)
            else:
                configuration_space_in_trace_order.append([default_qconfig])
                trace_order_indices_of_defaulted_configs.add(trace_idx)

        matcher = TraceOrderBitwidthMatcher(self._bits, traces_order)
        return matcher.get_qconfig_sequences_constrained_by_trace_order(
            configuration_space_in_trace_order,
            trace_order_indices_of_defaulted_configs)
Example #2
0
def test_hawq_behaviour__if_method_returns_none(mocker, method_name,
                                                expected_behavior):
    config = HAWQConfigBuilder().with_sample_size([1, 1, 4, 4]).build()
    config['compression']['initializer']['range']['num_init_samples'] = 0
    config['quantizer_setup_type'] = 'pattern_based'
    model = BasicConvTestModel()
    mock_train_loader = mocker.stub()
    mock_train_loader.batch_size = 1
    config.register_extra_structs([
        QuantizationPrecisionInitArgs(criterion_fn=mocker.stub(),
                                      criterion=mocker.stub(),
                                      data_loader=mock_train_loader,
                                      device='cuda')
    ])
    mocker.patch(
        'nncf.quantization.algo.QuantizationController.run_batchnorm_adaptation'
    )
    mocked_calc_traces = mocker.patch(
        'nncf.quantization.precision_init.hawq_init.HAWQPrecisionInitializer._calc_traces'
    )
    stub = mocker.stub()
    stub.traces_order = TracesOrder([0])
    mocked_calc_traces.return_value = stub

    mocked_method = mocker.patch(
        'nncf.quantization.precision_init.hawq_init.HAWQPrecisionInitializer.'
        + method_name)
    mocked_method.return_value = None

    with expected_behavior:
        create_compressed_model_and_algo_for_test(model, config)
Example #3
0
def test_get_configs_constrained_by_precision(precision_constraints):
    bits_configurations, constraints, survived_configurations_id, order = precision_constraints
    traces_order = TracesOrder(order)
    ref_configurations = [bits_configurations[config_id] for config_id in survived_configurations_id]
    ordered_weight_keys = [get_mock_quantizer_id(str(i)) for i in range(len(constraints))]
    hw_precision_constraints = get_mock_precision_constraints(constraints, ordered_weight_keys)

    # pylint:disable=protected-access
    actual_configs = HAWQPrecisionInitializer._filter_configs_by_precision_constraints(
        bits_configurations, hw_precision_constraints, ordered_weight_keys, traces_order)

    assert ref_configurations == actual_configs
Example #4
0
 def _get_weight_qp_ids_in_trace_order(
         self, traces_order: TracesOrder) -> List[Set[QuantizationPointId]]:
     quant_module_ids = list(
         self._weight_quantizations_by_execution_order.keys())
     qp_ids_in_trace_order = []
     for trace_idx in range(len(traces_order)):
         exec_idx = traces_order.get_execution_index_by_traces_index(
             trace_idx)
         quant_module_id = quant_module_ids[exec_idx]
         qp_ids_in_trace_order.append(
             self._algo.module_id_to_qp_id_translation_dict[quant_module_id]
         )
     return qp_ids_in_trace_order
Example #5
0
 def get_flops_bits_per_config(self, configurations_in_trace_order: List[
     List[QuantizerConfig]], traces_order: TracesOrder) -> List[float]:
     skipped = self._quantizers_handler.get_skipped_weight_quantizers_per_id(
     )
     flops_bits_per_config = []
     for configuration in configurations_in_trace_order:
         execution_order_config = traces_order.get_execution_order_config(
             configuration)
         bit_sequence = [qc.bits for qc in execution_order_config]
         flops_bits_per_config.append(
             self.flops_counter.ratio_for_bits_configuration(
                 bit_sequence, skipped))
     return flops_bits_per_config
Example #6
0
    def calc_quantization_noise(
        self, configurations_to_run: List[
            CoveringConfigurationForQuantNoiseCalculation],
        traces_order: TracesOrder
    ) -> Tuple[Perturbations, List[List[PerturbationObserver]]]:
        perturbations = Perturbations()
        qp_ids_in_trace_order = self._get_weight_qp_ids_in_trace_order(
            traces_order)
        ctrl = self._algo
        observers_for_all_configurations = [
        ]  # type: List[List[PerturbationObserver]]
        for configuration in configurations_to_run:
            quantizer_setup_to_run = self._apply_weight_configuration_to_quantizer_setup(
                configuration, qp_ids_in_trace_order,
                ctrl.get_quantizer_setup_for_current_state())
            ctrl, model = ctrl.apply_new_quantizer_setup(
                quantizer_setup_to_run
            )  # type: Tuple[ExperimentalQuantizationController, NNCFNetwork]

            hook_handles = []
            observers = []
            for qp_id_set in qp_ids_in_trace_order:
                for qp_id in qp_id_set:
                    wq_id = ctrl.setup_to_module_id_translation_dict[qp_id]
                    wq_module = ctrl.weight_quantizers[
                        wq_id].quantizer_module_ref
                    observer = PerturbationObserver(self._init_device)
                    hook_handles.append(
                        wq_module.register_forward_hook(
                            observer.calc_perturbation))
                    observers.append(observer)

            model.do_dummy_forward(force_eval=True)

            for i, observer in enumerate(observers):
                perturbations.add(
                    layer_id=traces_order.get_execution_index_by_traces_index(
                        i),
                    qconfig=configuration[i],
                    perturbation=observer.get_observation().to(
                        self._init_device))

            for handle in hook_handles:
                handle.remove()
            observers_for_all_configurations.append(observers)

        return perturbations, observers_for_all_configurations
Example #7
0
    def _filter_configs_by_grouped_weight_quantizers(
            trace_ordered_configurations: List[List[QuantizerConfig]],
            weight_quantization_ids_by_execution_order: List[QuantizerId],
            groups_of_adjacent_quantizers: GroupsOfAdjacentQuantizers,
            traces_order: TracesOrder) -> List[List[QuantizerConfig]]:
        """ removes configs where adjacent weight quantizers have different bitwidth. Adjacency is defined by common
        activation quantizers"""
        filtered_bits_configurations = []
        all_grouped_indexes = []
        for group_of_adjacent_quantizers in groups_of_adjacent_quantizers:
            wqs = group_of_adjacent_quantizers.weight_quantizers
            if len(wqs) > 1:
                indexes_of_grouped_wq = []
                for quantizer_id, _ in wqs:
                    if quantizer_id in weight_quantization_ids_by_execution_order:
                        index_by_execution_order = weight_quantization_ids_by_execution_order.index(
                            quantizer_id)
                        indexes_of_grouped_wq.append(index_by_execution_order)
                all_grouped_indexes.append(indexes_of_grouped_wq)

        if not all_grouped_indexes:
            return trace_ordered_configurations

        for qconf_configuration in trace_ordered_configurations:
            execution_ordered_configuration = traces_order.get_execution_order_config(
                qconf_configuration)
            bit_sequence = [qc.bits for qc in execution_ordered_configuration]
            keep_config = True
            for indexes_of_grouped_wq in all_grouped_indexes:
                grouped_bits = [
                    bit_sequence[index] for index in indexes_of_grouped_wq
                ]
                if grouped_bits[1:] != grouped_bits[:-1]:
                    keep_config = False
                    break
            if keep_config:
                filtered_bits_configurations.append(qconf_configuration)

        return filtered_bits_configurations
Example #8
0
    def _filter_configs_by_precision_constraints(
            bits_configurations: List[List[int]],
            hw_precision_constraints: HardwareQuantizationConstraints,
            ordered_weight_ids: List[QuantizerId],
            traces_order: TracesOrder) -> List[List[int]]:
        if not hw_precision_constraints:
            return bits_configurations

        filtered_bits_configurations = []
        for bits_configuration in bits_configurations:
            is_all_bitwidth_compatible = True
            ordered_config = traces_order.get_execution_order_config(
                bits_configuration)
            for i, bitwidth in enumerate(ordered_config):
                weight_id = ordered_weight_ids[i]
                bits_constraints = hw_precision_constraints.get(weight_id)
                if bitwidth not in bits_constraints:
                    is_all_bitwidth_compatible = False
                    break
            if is_all_bitwidth_compatible:
                filtered_bits_configurations.append(bits_configuration)
        return filtered_bits_configurations
Example #9
0
def test_get_non_decreasing_bit_sequences():
    bits = [4, 2, 8]
    L = 4
    m = len(bits)
    all_configs = list(itertools.product(bits, repeat=L))

    ref_configs = []
    for bit_config in all_configs:
        is_ok = True
        for i in range(L - 1):
            if bit_config[i + 1] < bit_config[i]:
                is_ok = False
                break
        if is_ok:
            ref_configs.append(list(bit_config))

    order = TracesOrder(list(range(L)))
    matcher = TraceOrderBitwidthMatcher(bits, order)
    actual_config = matcher.get_all_non_decreasing_bit_sequences()
    ref_num = get_size_of_search_space(m, L)
    assert len(ref_configs) == ref_num
    assert len(actual_config) == ref_num
    assert sorted(actual_config) == sorted(ref_configs)