Skip to content

Commit ceb2ca1

Browse files
Update check_nncf_graph.
Add reference graphs for anomaly models.
1 parent 11c933f commit ceb2ca1

File tree

11 files changed

+1413
-20
lines changed

11 files changed

+1413
-20
lines changed

external/anomaly/tasks/inference.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,13 @@ def save_model(self, output_model: ModelEntity) -> None:
300300
def _set_metadata(self, output_model: ModelEntity):
301301
output_model.set_data("image_threshold", self.model.image_threshold.value.cpu().numpy().tobytes())
302302
output_model.set_data("pixel_threshold", self.model.pixel_threshold.value.cpu().numpy().tobytes())
303-
output_model.set_data("min", self.model.normalization_metrics.state_dict()["min"].cpu().numpy().tobytes())
304-
output_model.set_data("max", self.model.normalization_metrics.state_dict()["max"].cpu().numpy().tobytes())
303+
if hasattr(self.model, "normalization_metrics"):
304+
output_model.set_data("min", self.model.normalization_metrics.state_dict()["min"].cpu().numpy().tobytes())
305+
output_model.set_data("max", self.model.normalization_metrics.state_dict()["max"].cpu().numpy().tobytes())
306+
else:
307+
logger.warning(
308+
"The model was not trained before saving. This will lead to incorrect normalization of the heatmaps."
309+
)
305310

306311
@staticmethod
307312
def _is_docker() -> bool:

external/anomaly/tests/anomaly_common.py

+20
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
from collections import namedtuple
1919
from copy import deepcopy
2020
from typing import List, Type
21+
from typing import TYPE_CHECKING
22+
23+
if TYPE_CHECKING:
24+
from nncf.torch.nncf_network import NNCFNetwork
2125

2226
from adapters.anomalib.data.mvtec import OteMvtecDataset
2327
from ote_sdk.entities.datasets import DatasetEntity
@@ -38,6 +42,7 @@
3842
OTETestTrainingEvaluationAction,
3943
)
4044
from ote_sdk.test_suite.training_tests_common import ROOT_PATH_KEY, make_paths_be_abs
45+
from tasks import NNCFTask
4146

4247
logger = logging.getLogger(__name__)
4348

@@ -107,3 +112,18 @@ def get_anomaly_domain_test_action_classes(
107112
OTETestNNCFExportEvaluationAction,
108113
OTETestNNCFGraphAction,
109114
]
115+
116+
117+
def get_dummy_compressed_model(task: NNCFTask) -> "NNCFNetwork":
118+
"""
119+
Return compressed model without initialization
120+
"""
121+
from anomalib.utils.callbacks.nncf.utils import wrap_nncf_model
122+
123+
# Disable quantaizers initialization
124+
for compression in task.optimization_config["nncf_config"]["compression"]:
125+
if compression["algorithm"] == "quantization":
126+
compression["initializer"] = {"batchnorm_adaptation": {"num_bn_adaptation_samples": 0}}
127+
128+
_, compressed_model = wrap_nncf_model(task.model, task.optimization_config["nncf_config"])
129+
return compressed_model

external/anomaly/tests/reference/ote_anomaly_classification_padim/nncf/nncf_quantization.dot

+240
Large diffs are not rendered by default.

external/anomaly/tests/reference/ote_anomaly_classification_stfpm/nncf/nncf_quantization.dot

+430
Large diffs are not rendered by default.

external/anomaly/tests/reference/ote_anomaly_segmentation_padim/nncf/nncf_quantization.dot

+240
Large diffs are not rendered by default.

external/anomaly/tests/reference/ote_anomaly_segmentation_stfpm/nncf/nncf_quantization.dot

+430
Large diffs are not rendered by default.

external/anomaly/tests/test_configurable_parameters.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121

2222
import pytest
2323
from adapters.anomalib.config import get_anomalib_config
24-
from configs.anomaly_classification.padim import PadimAnomalyClassificationConfig
25-
from configs.anomaly_classification.stfpm import STFPMAnomalyClassificationConfig
24+
from configs.classification.padim import PadimAnomalyClassificationConfig
25+
from configs.classification.stfpm import STFPMAnomalyClassificationConfig
2626
from ote_sdk.configuration.helper import convert, create
2727

2828
from tests.helpers.config import get_config_and_task_name

external/anomaly/tests/test_ote_anomaly_classification_training.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
_create_anomaly_dataset_and_labels_schema,
5252
_get_dataset_params_from_dataset_definitions,
5353
get_anomaly_domain_test_action_classes,
54+
get_dummy_compressed_model,
5455
)
5556

5657
logger = get_logger(__name__)
@@ -287,7 +288,7 @@ def _nncf_graph_params_factory() -> Dict:
287288
"labels_schema": labels_schema,
288289
"template_path": template_path,
289290
"reference_dir": ote_current_reference_dir_fx,
290-
"fn_get_compressed_model": None, # NNCF not yet implemented in Anomaly
291+
"fn_get_compressed_model": get_dummy_compressed_model,
291292
}
292293

293294
params_factories_for_test_actions = {

external/anomaly/tests/test_ote_anomaly_segmentation_training.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
_create_anomaly_dataset_and_labels_schema,
5454
_get_dataset_params_from_dataset_definitions,
5555
get_anomaly_domain_test_action_classes,
56+
get_dummy_compressed_model,
5657
)
5758

5859
logger = logging.getLogger(__name__)
@@ -433,7 +434,7 @@ def _nncf_graph_params_factory() -> Dict[str, Callable[[], Dict]]:
433434
"labels_schema": labels_schema,
434435
"template_path": template_path,
435436
"reference_dir": ote_current_reference_dir_fx,
436-
"fn_get_compressed_model": None, # NNCF not yet implemented in Anomaly
437+
"fn_get_compressed_model": get_dummy_compressed_model,
437438
}
438439

439440
params_factories_for_test_actions = {

ote_sdk/ote_sdk/test_suite/fixtures.py

-2
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,6 @@ def ote_current_reference_dir_fx(ote_reference_root_dir_fx, current_test_paramet
6969
path = os.path.join(
7070
ote_reference_root_dir_fx, current_test_parameters_fx["model_name"]
7171
)
72-
if not os.path.isdir(path):
73-
return None
7472
return path
7573

7674

ote_sdk/ote_sdk/test_suite/training_tests_actions.py

+40-12
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
from abc import ABC, abstractmethod
1010
from collections import OrderedDict
1111
from copy import deepcopy
12-
from typing import List, Optional, Type
12+
from typing import TYPE_CHECKING, List, Optional, Type
13+
14+
if TYPE_CHECKING:
15+
from nncf.torch.nncf_network import NNCFNetwork
1316

1417
import pytest
1518

@@ -562,15 +565,28 @@ def __call__(self, data_collector: DataCollector, results_prev_stages: OrderedDi
562565

563566

564567
# TODO: think about move to special file
565-
def check_nncf_model_graph(model, path_to_dot):
568+
def check_nncf_model_graph(
569+
model: "NNCFNetwork", path_to_dot: str, force_regen_dot: bool = False
570+
):
571+
"""
572+
Compare gprah of compressed model with reference.
573+
"""
566574
import networkx as nx
567575

568-
logger.info(f"Reference graph: {path_to_dot}")
569-
load_graph = nx.drawing.nx_pydot.read_dot(path_to_dot)
570-
571576
graph = model.get_graph()
572577
nx_graph = graph.get_graph_for_structure_analysis()
573578

579+
if force_regen_dot:
580+
# Generate and rewrite reference graph
581+
dir_path = os.path.dirname(path_to_dot)
582+
if not os.path.exists(dir_path):
583+
os.makedirs(dir_path)
584+
nx.drawing.nx_pydot.write_dot(nx_graph, path_to_dot)
585+
logger.warning(f"Reference graph was generated: {path_to_dot}")
586+
587+
logger.info(f"Reference graph: {path_to_dot}")
588+
load_graph = nx.drawing.nx_pydot.read_dot(path_to_dot)
589+
574590
for _, node in nx_graph.nodes(data=True):
575591
if "scope" in node:
576592
node.pop("scope")
@@ -592,6 +608,7 @@ def check_nncf_model_graph(model, path_to_dot):
592608

593609
class OTETestNNCFGraphAction(BaseOTETestAction):
594610
_name = "nncf_graph"
611+
_VAR_REGEN_DOT = "NNCF_TEST_REGEN_DOT"
595612

596613
def __init__(
597614
self,
@@ -619,8 +636,13 @@ def _run_ote_nncf_graph(self, data_collector):
619636
if not is_nncf_enabled():
620637
pytest.skip("NNCF is not installed")
621638

622-
if not os.path.exists(self.reference_dir):
623-
pytest.skip("Reference directory does not exist")
639+
force_regen_dot = os.getenv(self._VAR_REGEN_DOT) is not None
640+
if not force_regen_dot:
641+
if self.reference_dir is None or not os.path.exists(self.reference_dir):
642+
pytest.skip(
643+
f"Reference directory does not exist: {self.reference_dir}.\n"
644+
f"To generate reference graph set the global variable {self._VAR_REGEN_DOT}."
645+
)
624646

625647
params = ote_sdk_configuration_helper_create(
626648
model_template.hyper_parameters.data
@@ -650,16 +672,22 @@ def _run_ote_nncf_graph(self, data_collector):
650672
nncf_task_cls = get_impl_class(nncf_task_class_impl_path)
651673
nncf_task = nncf_task_cls(task_environment=environment_for_nncf)
652674

653-
path_to_ref_dot = os.path.join(
654-
self.reference_dir, "nncf", f"{nncf_task._nncf_preset}.dot"
675+
nncf_preset = (
676+
nncf_task.nncf_preset
677+
if hasattr(nncf_task, "nncf_preset")
678+
else nncf_task._nncf_preset
655679
)
656-
if not os.path.exists(path_to_ref_dot):
657-
pytest.skip("Reference file does not exist: {}".format(path_to_ref_dot))
680+
path_to_ref_dot = os.path.join(self.reference_dir, "nncf", f"{nncf_preset}.dot")
681+
if not os.path.exists(path_to_ref_dot) and not force_regen_dot:
682+
pytest.skip(
683+
f"Reference file does not exist: {path_to_ref_dot}.\n"
684+
f"To generate reference graph set the global variable {self._VAR_REGEN_DOT}."
685+
)
658686

659687
compressed_model = self.fn_get_compressed_model(nncf_task)
660688

661689
assert check_nncf_model_graph(
662-
compressed_model, path_to_ref_dot
690+
compressed_model, path_to_ref_dot, force_regen_dot
663691
), "Compressed model differs from the reference"
664692

665693
def __call__(self, data_collector: DataCollector, results_prev_stages: OrderedDict):

0 commit comments

Comments
 (0)