Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MinMax] Move get_statistic_collector from backend to common #3132

Merged
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions nncf/experimental/common/tensor_statistics/collectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from nncf.experimental.common.tensor_statistics.statistics import MedianMADTensorStatistic
from nncf.experimental.common.tensor_statistics.statistics import TensorStatistic
from nncf.quantization.advanced_parameters import AggregatorType
from nncf.quantization.range_estimator import StatisticsType
from nncf.tensor import Tensor

InplaceInsertionFNType = TypeVar("InplaceInsertionFNType")
Expand Down Expand Up @@ -835,6 +836,15 @@ def _move_axes_flatten_cat(
return fns.concatenate(reshaped_tensors, axis=0), shape_after_aggregation


REDUCERS_MAP = {
StatisticsType.MIN: MinReducer,
StatisticsType.MAX: MaxReducer,
StatisticsType.ABS_MAX: AbsMaxReducer,
StatisticsType.MEAN: MeanReducer,
StatisticsType.QUANTILE: QuantileReducer,
StatisticsType.ABS_QUANTILE: AbsQuantileReducer,
}

AGGREGATORS_MAP = {
AggregatorType.MIN: MinAggregator,
AggregatorType.MAX: MaxAggregator,
Expand Down
17 changes: 0 additions & 17 deletions nncf/onnx/statistics/collectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,15 @@

from typing import Optional

from nncf.experimental.common.tensor_statistics.collectors import AbsMaxReducer
from nncf.experimental.common.tensor_statistics.collectors import AbsQuantileReducer
from nncf.experimental.common.tensor_statistics.collectors import BatchMeanReducer
from nncf.experimental.common.tensor_statistics.collectors import MaxReducer
from nncf.experimental.common.tensor_statistics.collectors import MeanAggregator
from nncf.experimental.common.tensor_statistics.collectors import MeanPerChReducer
from nncf.experimental.common.tensor_statistics.collectors import MeanReducer
from nncf.experimental.common.tensor_statistics.collectors import MinReducer
from nncf.experimental.common.tensor_statistics.collectors import NoopAggregator
from nncf.experimental.common.tensor_statistics.collectors import QuantileReducer
from nncf.experimental.common.tensor_statistics.collectors import RawReducer
from nncf.experimental.common.tensor_statistics.collectors import ShapeAggregator
from nncf.experimental.common.tensor_statistics.collectors import TensorCollector
from nncf.experimental.common.tensor_statistics.statistics import MeanTensorStatistic
from nncf.experimental.common.tensor_statistics.statistics import RawTensorStatistic
from nncf.quantization.advanced_parameters import StatisticsType


def get_mean_statistic_collector(
Expand Down Expand Up @@ -76,13 +69,3 @@ def get_raw_stat_collector(num_samples: int) -> TensorCollector:
collector = TensorCollector(RawTensorStatistic)
collector.register_statistic_branch(RawTensorStatistic.VALUES_STATS, reducer, aggregator)
return collector


ONNX_REDUCERS_MAP = {
StatisticsType.MIN: MinReducer,
StatisticsType.MAX: MaxReducer,
StatisticsType.ABS_MAX: AbsMaxReducer,
StatisticsType.MEAN: MeanReducer,
StatisticsType.QUANTILE: QuantileReducer,
StatisticsType.ABS_QUANTILE: AbsQuantileReducer,
}
2 changes: 1 addition & 1 deletion nncf/quantization/advanced_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ class AdvancedQuantizationParameters:
# General parameters
overflow_fix: OverflowFix = None
quantize_outputs: bool = False
inplace_statistics: bool = True
inplace_statistics: bool = False
rk119 marked this conversation as resolved.
Show resolved Hide resolved
disable_channel_alignment: bool = True
disable_bias_correction: bool = False
batchwise_statistics: Optional[bool] = None
Expand Down
70 changes: 66 additions & 4 deletions nncf/quantization/algorithms/min_max/algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,12 @@
from nncf.common.quantization.structs import QuantizationScheme
from nncf.common.quantization.structs import QuantizerConfig
from nncf.common.quantization.structs import QuantizerGroup
from nncf.common.tensor_statistics.collectors import TensorStatisticCollectorBase
from nncf.common.tensor_statistics.statistic_point import StatisticPoint
from nncf.common.tensor_statistics.statistic_point import StatisticPointsContainer
from nncf.common.utils.backend import BackendType
from nncf.common.utils.backend import get_backend
from nncf.experimental.common.tensor_statistics.collectors import AGGREGATORS_MAP
from nncf.experimental.common.tensor_statistics.collectors import TensorCollector
from nncf.experimental.common.tensor_statistics.statistics import MinMaxTensorStatistic
from nncf.parameters import ModelType
from nncf.parameters import QuantizationMode
Expand All @@ -63,8 +64,10 @@
from nncf.quantization.fake_quantize import calculate_quantizer_parameters
from nncf.quantization.fake_quantize import get_quantizer_narrow_range
from nncf.quantization.passes import transform_to_inference_graph
from nncf.quantization.range_estimator import AggregatorType
from nncf.quantization.range_estimator import RangeEstimatorParameters
from nncf.quantization.range_estimator import RangeEstimatorParametersSet
from nncf.quantization.range_estimator import StatisticsType
from nncf.scopes import IgnoredScope
from nncf.scopes import get_ignored_node_names_from_ignored_scope

Expand Down Expand Up @@ -437,7 +440,7 @@ def _get_stat_collector(
target_point: TargetPoint,
qconfig: QuantizerConfig,
batchwise_statistics: bool,
) -> TensorStatisticCollectorBase:
) -> TensorCollector:
"""
Creates and returns a statistic collector based on the quantizer's configuration.

Expand Down Expand Up @@ -474,15 +477,74 @@ def _get_stat_collector(
shape, channel_axes, batchwise_statistics
)

return self._backend_entity.get_statistic_collector(
return self._get_statistic_collector(
range_estimator_params,
collector_params.use_abs_max,
reduction_axes,
aggregation_axes,
self._inplace_statistics,
num_samples=num_samples,
num_samples,
)

def _get_statistic_collector(
self,
range_estimator_params: RangeEstimatorParameters,
use_abs_max: bool,
reduction_axes: Optional[Tuple[int, ...]],
aggregation_axes: Optional[Tuple[int, ...]],
inplace: bool,
num_samples: Optional[int] = None,
) -> TensorCollector:
"""
Returns statistic collector.

:param range_estimator_params: Parameters that specify estimators types.
:param use_abs_max: Wheather reduce absolute values of input tensors or not.
:param reduction_axes: Axes for reducer.
:param aggregation_axes: Axes for aggregator.
:param inplace: Whether to calculate statistic inplace or not.
:param num_samples: Maximum number of samples to collect.
:return: TensorCollector for the statistics calculation.
"""
collector = TensorCollector(MinMaxTensorStatistic)
rk119 marked this conversation as resolved.
Show resolved Hide resolved
for params, container_key in zip(
[range_estimator_params.min, range_estimator_params.max],
[MinMaxTensorStatistic.MIN_STAT, MinMaxTensorStatistic.MAX_STAT],
):
if params.statistics_type not in self._backend_entity.reducer_map:
raise nncf.InternalError(f"Statistic type: {params.statistics_type} is not yet supported.")

if params.aggregator_type not in AGGREGATORS_MAP:
raise nncf.InternalError(f"Aggregator type: {params.aggregator_type} is not yet supported.")

statistic_type = params.statistics_type
if statistic_type in [StatisticsType.QUANTILE, StatisticsType.ABS_QUANTILE]:
# TODO(dlyakhov): merge two quantile aggregators in one
if container_key == MinMaxTensorStatistic.MIN_STAT:
quantile = params.quantile_outlier_prob
else:
quantile = 1 - params.quantile_outlier_prob
reducer = self._backend_entity.reducer_map[statistic_type](
reduction_axes=reduction_axes, inplace=inplace, quantile=[quantile]
)
else:
if use_abs_max and statistic_type == StatisticsType.MAX:
statistic_type = StatisticsType.ABS_MAX
reducer = self._backend_entity.reducer_map[statistic_type](
reduction_axes=reduction_axes, inplace=inplace
)

kwargs = {
"num_samples": num_samples,
"aggregation_axes": aggregation_axes,
}
if params.aggregator_type in [AggregatorType.MEAN_NO_OUTLIERS, AggregatorType.MEDIAN_NO_OUTLIERS]:
kwargs.update({"quantile": params.quantile_outlier_prob})
aggregator = AGGREGATORS_MAP[params.aggregator_type](**kwargs)

collector.register_statistic_branch(container_key, reducer, aggregator)
return collector

def _get_default_qconfig(self, constraints: QuantizationConstraints = None) -> QuantizerConfig:
"""
Returns default quantizer configuration, based on the provided constraints.
Expand Down
33 changes: 9 additions & 24 deletions nncf/quantization/algorithms/min_max/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
from nncf.common.graph.transformations.commands import TransformationCommand
from nncf.common.hardware.config import HWConfig
from nncf.common.quantization.structs import QuantizerConfig
from nncf.common.tensor_statistics.collectors import TensorStatisticCollectorBase
from nncf.experimental.common.tensor_statistics.collectors import TensorReducerBase
from nncf.parameters import ModelType
from nncf.parameters import TargetDevice
from nncf.quantization.fake_quantize import FakeConvertParameters
from nncf.quantization.fake_quantize import FakeQuantizeParameters
from nncf.quantization.range_estimator import RangeEstimatorParameters
from nncf.quantization.range_estimator import StatisticsType

TModel = TypeVar("TModel")

Expand Down Expand Up @@ -131,6 +131,13 @@ def quant_trait_op_dict(self) -> Dict[int, OperatorMetatype]:
Property for the backend-specific dictionary that contains QuantizationTrait-specific metatypes.
"""

@property
@abstractmethod
def reducer_map(self) -> Dict[StatisticsType, TensorReducerBase]:
"""
Property for the backend-specific dictionary that conatins StatisticsType-specific tensor reducers.
"""
rk119 marked this conversation as resolved.
Show resolved Hide resolved

@staticmethod
@abstractmethod
def target_point(target_type: TargetType, target_node_name: str, port_id: int) -> TargetPoint:
Expand Down Expand Up @@ -229,28 +236,6 @@ def get_weight_quantization_axes(node: NNCFNode, target_point: TargetPoint, ndim
:return: Axes for per-channel quantization of weights.
"""

@staticmethod
@abstractmethod
def get_statistic_collector(
range_estimator_params: RangeEstimatorParameters,
use_abs_max: bool,
reduction_axes: Optional[Tuple[int, ...]],
aggregation_axes: Optional[Tuple[int, ...]],
inplace: bool,
num_samples: Optional[int] = None,
) -> TensorStatisticCollectorBase:
"""
Returns backend-specific statistic collector.

:param range_estimator_params: Parameters that specify estimators types.
:param use_abs_max: Wheather reduce absolute values of input tensors or not.
:param reduction_axes: Axes for reducer.
:param aggregation_axes: Axes for aggregator.
:param inplace: Whether to calculate statistic inplace or not.
:param num_samples: Maximum number of samples to collect.
:return: Backend-specific TensorStatisticCollectorBase for the statistics calculation.
"""

@staticmethod
@abstractmethod
def get_weight_tensor_port_ids(node: NNCFNode, graph: NNCFGraph) -> List[Optional[int]]:
Expand Down
61 changes: 8 additions & 53 deletions nncf/quantization/algorithms/min_max/onnx_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@
from nncf.common.graph.transformations.commands import TransformationCommand
from nncf.common.hardware.config import HWConfig
from nncf.common.quantization.structs import QuantizerConfig
from nncf.experimental.common.tensor_statistics.collectors import AGGREGATORS_MAP
from nncf.experimental.common.tensor_statistics.collectors import TensorCollector
from nncf.experimental.common.tensor_statistics.statistics import MinMaxTensorStatistic
from nncf.experimental.common.tensor_statistics.collectors import REDUCERS_MAP
from nncf.experimental.common.tensor_statistics.collectors import TensorReducerBase
from nncf.onnx.graph.metatypes import onnx_metatypes as om
from nncf.onnx.graph.metatypes.groups import ELEMENTWISE_OPERATIONS
from nncf.onnx.graph.metatypes.groups import MATMUL_METATYPES
Expand All @@ -35,18 +34,16 @@
from nncf.onnx.hardware.config import ONNXHWConfig
from nncf.onnx.quantization.default_quantization import DEFAULT_ONNX_QUANT_TRAIT_TO_OP_DICT
from nncf.onnx.quantization.quantizer_parameters import convert_fq_params_to_onnx_params
from nncf.onnx.statistics.collectors import ONNX_REDUCERS_MAP
from nncf.parameters import ModelType
from nncf.parameters import TargetDevice
from nncf.quantization.advanced_parameters import StatisticsType
from nncf.quantization.algorithms.min_max.backend import MinMaxAlgoBackend
from nncf.quantization.fake_quantize import FakeConvertParameters
from nncf.quantization.fake_quantize import FakeQuantizeParameters
from nncf.quantization.range_estimator import AggregatorType
from nncf.quantization.range_estimator import RangeEstimatorParameters
from nncf.quantization.range_estimator import StatisticsType


class ONNXMinMaxAlgoBackend(MinMaxAlgoBackend):

@property
def preserved_metatypes(self) -> List[OperatorMetatype]:
return []
Expand Down Expand Up @@ -111,6 +108,10 @@ def hw_config(self) -> HWConfig:
def quant_trait_op_dict(self) -> Dict[int, OperatorMetatype]:
return DEFAULT_ONNX_QUANT_TRAIT_TO_OP_DICT

@property
def reducer_map(self) -> Dict[StatisticsType, TensorReducerBase]:
return REDUCERS_MAP

daniil-lyakhov marked this conversation as resolved.
Show resolved Hide resolved
@staticmethod
def get_start_nodes_for_activation_path_tracing(
nncf_graph: NNCFGraph,
Expand Down Expand Up @@ -173,52 +174,6 @@ def get_target_point_shape(nncf_graph: NNCFGraph, node: NNCFNode, target_point:
def get_weight_quantization_axes(node: NNCFNode, target_point: ONNXTargetPoint, ndims: int) -> Tuple[int]:
return (get_weight_quantization_axis(node, target_point.port_id),)

@staticmethod
def get_statistic_collector(
range_estimator_params: RangeEstimatorParameters,
use_abs_max: bool,
reduction_axes: Optional[Tuple[int, ...]],
aggregation_axes: Optional[Tuple[int, ...]],
inplace: bool,
num_samples: Optional[int] = None,
) -> TensorCollector:
collector = TensorCollector(MinMaxTensorStatistic)
for params, container_key in zip(
[range_estimator_params.min, range_estimator_params.max],
[MinMaxTensorStatistic.MIN_STAT, MinMaxTensorStatistic.MAX_STAT],
):
if params.statistics_type not in ONNX_REDUCERS_MAP:
raise nncf.InternalError(
f"Statistic type: {params.statistics_type} is not supported for ONNX PTQ backend yet."
)
if params.aggregator_type not in AGGREGATORS_MAP:
raise nncf.InternalError(
f"Aggregator type: {params.aggregator_type} is not supported for ONNX PTQ backend yet."
)
kwargs = {"reduction_axes": reduction_axes, "inplace": False}
if params.statistics_type in [StatisticsType.QUANTILE, StatisticsType.ABS_QUANTILE]:
if container_key == MinMaxTensorStatistic.MIN_STAT:
quantile = params.quantile_outlier_prob
else:
quantile = 1 - params.quantile_outlier_prob
kwargs.update({"quantile": [quantile]})
# TODO(dlyakhov): merge two quantile aggregators in one
statistic_type = params.statistics_type
if use_abs_max and statistic_type == StatisticsType.MAX:
statistic_type = StatisticsType.ABS_MAX
reducer = ONNX_REDUCERS_MAP[statistic_type](**kwargs)

kwargs = {
"num_samples": num_samples,
"aggregation_axes": aggregation_axes,
}
if params.aggregator_type in [AggregatorType.MEAN_NO_OUTLIERS, AggregatorType.MEDIAN_NO_OUTLIERS]:
kwargs.update({"quantile": params.quantile_outlier_prob})
aggregator = AGGREGATORS_MAP[params.aggregator_type](**kwargs)

collector.register_statistic_branch(container_key, reducer, aggregator)
return collector

@staticmethod
def get_weight_tensor_port_ids(node: NNCFNode, graph: NNCFGraph) -> List[Optional[int]]:
return list(node.layer_attributes.weight_attrs.keys())
Expand Down
Loading