From f26d4a68e0968c74b2ecf4913bb2efdfd8c94bc4 Mon Sep 17 00:00:00 2001 From: Riffat Khan <83776178+rk119@users.noreply.github.com> Date: Tue, 30 Jul 2024 20:51:25 +0400 Subject: [PATCH 1/4] Add test for statistics aggregator --- tests/torch/fx/test_statistics_aggregator.py | 117 +++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 tests/torch/fx/test_statistics_aggregator.py diff --git a/tests/torch/fx/test_statistics_aggregator.py b/tests/torch/fx/test_statistics_aggregator.py new file mode 100644 index 00000000000..0737b55b877 --- /dev/null +++ b/tests/torch/fx/test_statistics_aggregator.py @@ -0,0 +1,117 @@ +# Copyright (c) 2024 Intel Corporation +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Callable, List, Type + +import numpy as np +import pytest +import torch +from torch import nn +from nncf import Dataset +from nncf.common.graph.transformations.commands import TargetType +from nncf.experimental.common.tensor_statistics.collectors import TensorReducerBase +from nncf.quantization.algorithms.fast_bias_correction.torch_fx_backend import FXFastBiasCorrectionAlgoBackend +from nncf.quantization.algorithms.min_max.torch_fx_backend import FXMinMaxAlgoBackend +from nncf.torch.graph.graph import PTTargetPoint +from nncf.experimental.torch.fx.statistics.aggregator import FXStatisticsAggregator +from tests.common.test_statistics_aggregator import TemplateTestStatisticsAggregator +from torch._export import capture_pre_autograd_graph +from nncf.torch.dynamic_graph.patch_pytorch import disable_patching + +IDENTITY_NODE_NAME = "add" +CONV_NODE_NAME = "conv2d" +INPUT_SHAPE = [1, 3, 3, 3] + + +class IdentityConv(nn.Module): + def __init__(self, kernel) -> None: + super().__init__() + self.conv = nn.Conv2d( + in_channels=3, out_channels=3, kernel_size=3, + ) + self.conv.weight.data = torch.tensor(kernel, dtype=torch.float32) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.conv(x + 0.0) + + +class TestStatisticsAggregator(TemplateTestStatisticsAggregator): + @staticmethod + def get_min_max_algo_backend_cls() -> Type[FXMinMaxAlgoBackend]: + return FXMinMaxAlgoBackend + + def get_bias_correction_algo_backend_cls(self) -> None: + pytest.skip("FXBiasCorrectionAlgoBackend is not implemented") + + def get_fast_bias_correction_algo_backend_cls(self) -> Type[FXFastBiasCorrectionAlgoBackend]: + return FXFastBiasCorrectionAlgoBackend + + def get_backend_model(self, dataset_samples): + sample = dataset_samples[0].reshape(INPUT_SHAPE[1:]) + conv_w = self.dataset_samples_to_conv_w(np.array(sample)) + with disable_patching(): + model = capture_pre_autograd_graph(IdentityConv(conv_w), args=(torch.randn(1, 3, 3, 3),)) + return model + + def get_statistics_aggregator(self, dataset): + return FXStatisticsAggregator(dataset) + + def get_dataset(self, samples): + def transform_fn(data_item): + return data_item + + return Dataset(samples, transform_fn) + + @staticmethod + def get_target_point(target_type: TargetType): + target_node_name = IDENTITY_NODE_NAME + port_id = 0 + if target_type == TargetType.OPERATION_WITH_WEIGHTS: + target_node_name = CONV_NODE_NAME + port_id = 1 + return FXMinMaxAlgoBackend.target_point(target_type, target_node_name, port_id) + + def get_target_point_cls(self): + return PTTargetPoint + + @pytest.fixture(scope="session") + def test_params(self): + return + + @pytest.fixture + def dataset_samples(self, dataset_values): + input_shape = INPUT_SHAPE + dataset_samples = [np.zeros(input_shape), np.ones(input_shape)] + + for i, value in enumerate(dataset_values): + dataset_samples[0][0, i, 0, 0] = value["max"] + dataset_samples[0][0, i, 0, 1] = value["min"] + + return torch.tensor(dataset_samples, dtype=torch.float32) + + @pytest.fixture(params=[False], ids=["out_of_palce"]) + def inplace_statistics(self, request) -> bool: + return request.param + + @pytest.fixture + def is_backend_support_custom_estimators(self) -> bool: + return True + + def reducers_map(self) -> List[TensorReducerBase]: + return None + + @pytest.mark.skip("Merging is not implemented yet") + def test_statistic_merging(self, dataset_samples, inplace_statistics): + pass + + @pytest.mark.skip("Merging is not implemented yet") + def test_same_collectors_different_attrs_dont_merge(self, statistics_type, test_params, dataset_samples): + pass \ No newline at end of file From 1a706e38c8819070177212d5105773f25e94728b Mon Sep 17 00:00:00 2001 From: Riffat Khan <83776178+rk119@users.noreply.github.com> Date: Tue, 30 Jul 2024 21:21:57 +0400 Subject: [PATCH 2/4] Import fix --- tests/torch/fx/test_statistics_aggregator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/torch/fx/test_statistics_aggregator.py b/tests/torch/fx/test_statistics_aggregator.py index 0737b55b877..960c556bdd4 100644 --- a/tests/torch/fx/test_statistics_aggregator.py +++ b/tests/torch/fx/test_statistics_aggregator.py @@ -9,7 +9,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Callable, List, Type +from typing import List, Type import numpy as np import pytest From 54614b4318debd9afd62a1558c9984463f8bfda4 Mon Sep 17 00:00:00 2001 From: Riffat Khan <83776178+rk119@users.noreply.github.com> Date: Tue, 30 Jul 2024 22:16:47 +0400 Subject: [PATCH 3/4] pre-commit fix --- tests/torch/fx/test_statistics_aggregator.py | 27 +++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/tests/torch/fx/test_statistics_aggregator.py b/tests/torch/fx/test_statistics_aggregator.py index 960c556bdd4..82989dc629c 100644 --- a/tests/torch/fx/test_statistics_aggregator.py +++ b/tests/torch/fx/test_statistics_aggregator.py @@ -15,16 +15,17 @@ import pytest import torch from torch import nn +from torch._export import capture_pre_autograd_graph + from nncf import Dataset from nncf.common.graph.transformations.commands import TargetType from nncf.experimental.common.tensor_statistics.collectors import TensorReducerBase +from nncf.experimental.torch.fx.statistics.aggregator import FXStatisticsAggregator from nncf.quantization.algorithms.fast_bias_correction.torch_fx_backend import FXFastBiasCorrectionAlgoBackend from nncf.quantization.algorithms.min_max.torch_fx_backend import FXMinMaxAlgoBackend +from nncf.torch.dynamic_graph.patch_pytorch import disable_patching from nncf.torch.graph.graph import PTTargetPoint -from nncf.experimental.torch.fx.statistics.aggregator import FXStatisticsAggregator from tests.common.test_statistics_aggregator import TemplateTestStatisticsAggregator -from torch._export import capture_pre_autograd_graph -from nncf.torch.dynamic_graph.patch_pytorch import disable_patching IDENTITY_NODE_NAME = "add" CONV_NODE_NAME = "conv2d" @@ -35,7 +36,9 @@ class IdentityConv(nn.Module): def __init__(self, kernel) -> None: super().__init__() self.conv = nn.Conv2d( - in_channels=3, out_channels=3, kernel_size=3, + in_channels=3, + out_channels=3, + kernel_size=3, ) self.conv.weight.data = torch.tensor(kernel, dtype=torch.float32) @@ -60,16 +63,16 @@ def get_backend_model(self, dataset_samples): with disable_patching(): model = capture_pre_autograd_graph(IdentityConv(conv_w), args=(torch.randn(1, 3, 3, 3),)) return model - + def get_statistics_aggregator(self, dataset): return FXStatisticsAggregator(dataset) - + def get_dataset(self, samples): def transform_fn(data_item): return data_item return Dataset(samples, transform_fn) - + @staticmethod def get_target_point(target_type: TargetType): target_node_name = IDENTITY_NODE_NAME @@ -78,14 +81,14 @@ def get_target_point(target_type: TargetType): target_node_name = CONV_NODE_NAME port_id = 1 return FXMinMaxAlgoBackend.target_point(target_type, target_node_name, port_id) - + def get_target_point_cls(self): return PTTargetPoint - + @pytest.fixture(scope="session") def test_params(self): return - + @pytest.fixture def dataset_samples(self, dataset_values): input_shape = INPUT_SHAPE @@ -96,7 +99,7 @@ def dataset_samples(self, dataset_values): dataset_samples[0][0, i, 0, 1] = value["min"] return torch.tensor(dataset_samples, dtype=torch.float32) - + @pytest.fixture(params=[False], ids=["out_of_palce"]) def inplace_statistics(self, request) -> bool: return request.param @@ -114,4 +117,4 @@ def test_statistic_merging(self, dataset_samples, inplace_statistics): @pytest.mark.skip("Merging is not implemented yet") def test_same_collectors_different_attrs_dont_merge(self, statistics_type, test_params, dataset_samples): - pass \ No newline at end of file + pass From 3ff9cd67dda35bd51a8f6653ddca4a9d198cc9e4 Mon Sep 17 00:00:00 2001 From: Riffat Khan <83776178+rk119@users.noreply.github.com> Date: Wed, 31 Jul 2024 11:54:56 +0400 Subject: [PATCH 4/4] Use INPUT_SHAPE for example input --- tests/torch/fx/test_statistics_aggregator.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/torch/fx/test_statistics_aggregator.py b/tests/torch/fx/test_statistics_aggregator.py index 82989dc629c..d9e16b509e3 100644 --- a/tests/torch/fx/test_statistics_aggregator.py +++ b/tests/torch/fx/test_statistics_aggregator.py @@ -61,7 +61,7 @@ def get_backend_model(self, dataset_samples): sample = dataset_samples[0].reshape(INPUT_SHAPE[1:]) conv_w = self.dataset_samples_to_conv_w(np.array(sample)) with disable_patching(): - model = capture_pre_autograd_graph(IdentityConv(conv_w), args=(torch.randn(1, 3, 3, 3),)) + model = capture_pre_autograd_graph(IdentityConv(conv_w), args=(torch.ones(INPUT_SHAPE),)) return model def get_statistics_aggregator(self, dataset): @@ -91,8 +91,7 @@ def test_params(self): @pytest.fixture def dataset_samples(self, dataset_values): - input_shape = INPUT_SHAPE - dataset_samples = [np.zeros(input_shape), np.ones(input_shape)] + dataset_samples = [np.zeros(INPUT_SHAPE), np.ones(INPUT_SHAPE)] for i, value in enumerate(dataset_values): dataset_samples[0][0, i, 0, 0] = value["max"]