Skip to content

Commit 04e5fb8

Browse files
committed
Merge branch 'develop' into vsaltykovx/add_mmdetection_input_parameters_validation
2 parents 1d5e06c + abafaa3 commit 04e5fb8

File tree

142 files changed

+18574
-68
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

142 files changed

+18574
-68
lines changed

.gitmodules

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
path = external/mmdetection
33
url = ../../openvinotoolkit/mmdetection
44
[submodule "external/deep-object-reid"]
5-
path = external/deep-object-reid
5+
path = external/deep-object-reid/submodule
66
url = ../../openvinotoolkit/deep-object-reid
77
[submodule "external/mmsegmentation"]
8-
path = external/mmsegmentation
8+
path = external/mmsegmentation/submodule
99
url = ../../openvinotoolkit/mmsegmentation

.pre-commit-config.yaml

+7-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ repos:
1414
alias: isort_rest
1515
name: "isort (ote_cli|external)"
1616
args: ["--settings", ".isort.cfg"]
17-
files: '^(ote_cli|external)/.*\.py'
17+
files: '^(ote_cli|external/anomaly)/.*\.py'
18+
exclude: "tests/"
1819

1920
- repo: https://github.com/psf/black
2021
rev: 21.7b0
@@ -26,14 +27,14 @@ repos:
2627
- id: black
2728
name: "black (rest)"
2829
args: [--line-length, "120"]
29-
files: '^external/.*\.py'
30+
files: '^external/anomaly/.*\.py'
3031

3132
- repo: https://github.com/PyCQA/flake8
3233
rev: "3.9.2"
3334
hooks:
3435
- id: flake8
3536
name: "flake8"
36-
files: '^(ote_sdk|ote_cli|external)/.*\.py'
37+
files: '^(ote_sdk|ote_cli|external/anomaly)/.*\.py'
3738
args: ["--config", ".flake8", "--max-complexity", "20"]
3839
exclude: ".*/protobuf"
3940

@@ -43,6 +44,7 @@ repos:
4344
hooks:
4445
- id: prettier
4546
types: [yaml]
47+
exclude: "external/deep-object-reid"
4648

4749
- repo: https://github.com/pre-commit/mirrors-mypy
4850
rev: "v0.812"
@@ -71,14 +73,14 @@ repos:
7173
- id: mypy
7274
alias: mypy_rest
7375
name: "mypy (external)"
74-
files: '^external/.*\.py'
76+
files: '^external/anomaly/.*\.py'
7577
args: ["--config-file=ote_sdk/.mypy.ini"]
7678

7779
- repo: local
7880
hooks:
7981
- id: pylint
8082
name: "pylint"
81-
files: '^(ote_sdk|ote_cli|external)/.*\.py'
83+
files: '^(ote_sdk|ote_cli|external/anomaly)/.*\.py'
8284
entry: pylint
8385
language: system
8486
types: [python]

.pylintrc

+1-1
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ ignored-classes=optparse.Values,thread._local,_thread._local
267267
# (useful for modules/projects where namespaces are manipulated during runtime
268268
# and thus existing member attributes cannot be deduced by static analysis). It
269269
# supports qualified module names, as well as Unix pattern matching.
270-
ignored-modules=ote_sdk,mmseg,mmdet,torchreid,cv2,anomalib,pytorch_lightning,torch,addict,compression,openvino,pandas
270+
ignored-modules=ote_sdk,mmseg,segmentation_tasks,mmdet,torchreid,torchreid_tasks,cv2,anomalib,pytorch_lightning,torch,addict,compression,openvino,pandas
271271

272272
# Show a hint with possible names when a member name was not found. The aspect
273273
# of finding the hint is based on edit distance.

external/README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,6 @@ Custom_Rotated_Detection_via_Instance_Segmentation_MaskRCNN_ResNet50 | MaskRCNN-
4444
## Semantic Segmentaion
4545
ID | Name | Complexity (GFlops) | Model size (MB) | Path
4646
------- | ------- | ------- | ------- | -------
47-
Custom_Semantic_Segmentation_Lite-HRNet-18_OCR | Lite-HRNet-18 OCR | 3.45 | 4.5 | mmsegmentation/configs/ote/custom-sematic-segmentation/ocr-lite-hrnet-18/template.yaml
48-
Custom_Semantic_Segmentation_Lite-HRNet-18-mod2_OCR | Lite-HRNet-18-mod2 OCR | 3.63 | 4.8 | mmsegmentation/configs/ote/custom-sematic-segmentation/ocr-lite-hrnet-18-mod2/template.yaml
49-
Custom_Semantic_Segmentation_Lite-HRNet-x-mod3_OCR | Lite-HRNet-x-mod3 OCR | 13.97 | 6.4 | mmsegmentation/configs/ote/custom-sematic-segmentation/ocr-lite-hrnet-x-mod3/template.yaml
47+
Custom_Semantic_Segmentation_Lite-HRNet-18_OCR | Lite-HRNet-18 OCR | 3.45 | 4.5 | mmsegmentation/configs/custom-sematic-segmentation/ocr-lite-hrnet-18/template.yaml
48+
Custom_Semantic_Segmentation_Lite-HRNet-18-mod2_OCR | Lite-HRNet-18-mod2 OCR | 3.63 | 4.8 | mmsegmentation/configs/custom-sematic-segmentation/ocr-lite-hrnet-18-mod2/template.yaml
49+
Custom_Semantic_Segmentation_Lite-HRNet-x-mod3_OCR | Lite-HRNet-x-mod3 OCR | 13.97 | 6.4 | mmsegmentation/configs/custom-sematic-segmentation/ocr-lite-hrnet-x-mod3/template.yaml

external/anomaly/constraints.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ opencv-python==4.5.3.56
1313
openvino-dev==2022.1.0.dev20220302
1414
pillow==9.0.0
1515
pytorch-lightning==1.5.9
16-
requests==2.25.1
16+
requests==2.26.0
1717
scikit-image==0.17.2
1818
scikit-learn==0.24.2

external/anomaly/ote_anomalib/callbacks/inference.py

+3-6
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,13 @@ def on_predict_epoch_end(self, _trainer: pl.Trainer, pl_module: AnomalyModule, o
5858
self.ote_dataset, pred_scores, pred_labels, anomaly_maps, pred_masks
5959
):
6060
label = self.anomalous_label if pred_label else self.normal_label
61-
if self.task_type == TaskType.ANOMALY_CLASSIFICATION:
62-
probability = (1 - pred_score) if pred_score < 0.5 else pred_score
63-
dataset_item.append_labels([ScoredLabel(label=label, probability=float(probability))])
64-
elif self.task_type == TaskType.ANOMALY_SEGMENTATION:
61+
probability = (1 - pred_score) if pred_score < 0.5 else pred_score
62+
dataset_item.append_labels([ScoredLabel(label=label, probability=float(probability))])
63+
if self.task_type == TaskType.ANOMALY_SEGMENTATION:
6564
mask = pred_mask.squeeze().astype(np.uint8)
6665
dataset_item.append_annotations(
6766
create_annotation_from_segmentation_map(mask, anomaly_map.squeeze(), self.label_map)
6867
)
69-
else:
70-
raise ValueError(f"Unknown task type: {self.task_type}")
7168

7269
dataset_item.append_metadata_item(
7370
ResultMediaEntity(

external/anomaly/ote_anomalib/data/data.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
import numpy as np
2323
from anomalib.pre_processing import PreProcessor
2424
from omegaconf import DictConfig, ListConfig
25+
from ote_anomalib.data.utils import (
26+
contains_anomalous_images,
27+
split_local_global_dataset,
28+
)
2529
from ote_anomalib.logging import get_logger
2630
from ote_sdk.entities.datasets import DatasetEntity
2731
from ote_sdk.entities.model_template import TaskType
@@ -182,7 +186,6 @@ def train_dataloader(
182186
"""
183187
Train Dataloader
184188
"""
185-
186189
dataset = OTEAnomalyDataset(self.config, self.train_ote_dataset, self.task_type)
187190
return DataLoader(
188191
dataset,
@@ -195,8 +198,15 @@ def val_dataloader(self) -> Union[DataLoader, List[DataLoader]]:
195198
"""
196199
Validation Dataloader
197200
"""
198-
199-
dataset = OTEAnomalyDataset(self.config, self.val_ote_dataset, self.task_type)
201+
global_dataset, local_dataset = split_local_global_dataset(self.val_ote_dataset)
202+
logger.info(f"Global annotations: {len(global_dataset)}")
203+
logger.info(f"Local annotations: {len(local_dataset)}")
204+
if contains_anomalous_images(local_dataset):
205+
logger.info("Dataset contains polygon annotations. Passing masks to anomalib.")
206+
dataset = OTEAnomalyDataset(self.config, local_dataset, TaskType.ANOMALY_SEGMENTATION)
207+
else:
208+
logger.info("Dataset does not contain polygon annotations. Not passing masks to anomalib.")
209+
dataset = OTEAnomalyDataset(self.config, global_dataset, TaskType.ANOMALY_CLASSIFICATION)
200210
return DataLoader(
201211
dataset,
202212
shuffle=False,
+169
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
"""
2+
Dataset utils for OTE Anomaly
3+
"""
4+
5+
# Copyright (C) 2021 Intel Corporation
6+
#
7+
# Licensed under the Apache License, Version 2.0 (the "License");
8+
# you may not use this file except in compliance with the License.
9+
# You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing,
14+
# software distributed under the License is distributed on an "AS IS" BASIS,
15+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
# See the License for the specific language governing permissions
17+
# and limitations under the License.
18+
19+
from typing import Tuple
20+
21+
from ote_sdk.entities.annotation import AnnotationSceneEntity, AnnotationSceneKind
22+
from ote_sdk.entities.dataset_item import DatasetItemEntity
23+
from ote_sdk.entities.datasets import DatasetEntity
24+
from ote_sdk.entities.resultset import ResultSetEntity
25+
from ote_sdk.entities.shapes.rectangle import Rectangle
26+
27+
28+
def split_local_global_dataset(dataset) -> Tuple[DatasetEntity, DatasetEntity]:
29+
"""Split a dataset into globally and locally annotated items."""
30+
globally_annotated = []
31+
locally_annotated = []
32+
for gt_item in dataset:
33+
34+
annotations = gt_item.get_annotations()
35+
global_annotations = [annotation for annotation in annotations if Rectangle.is_full_box(annotation.shape)]
36+
local_annotations = [annotation for annotation in annotations if not Rectangle.is_full_box(annotation.shape)]
37+
38+
if not any(label.is_anomalous for label in gt_item.get_shapes_labels()):
39+
# normal images get added to both datasets
40+
globally_annotated.append(gt_item)
41+
locally_annotated.append(gt_item)
42+
else: # image is abnormal
43+
globally_annotated.append(
44+
DatasetItemEntity(
45+
media=gt_item.media,
46+
annotation_scene=AnnotationSceneEntity(global_annotations, kind=AnnotationSceneKind.ANNOTATION),
47+
metadata=gt_item.metadata,
48+
subset=gt_item.subset,
49+
ignored_labels=gt_item.ignored_labels,
50+
)
51+
)
52+
# add locally annotated dataset items
53+
if len(local_annotations) > 0:
54+
locally_annotated.append(
55+
DatasetItemEntity(
56+
media=gt_item.media,
57+
annotation_scene=AnnotationSceneEntity(local_annotations, kind=AnnotationSceneKind.ANNOTATION),
58+
metadata=gt_item.metadata,
59+
subset=gt_item.subset,
60+
ignored_labels=gt_item.ignored_labels,
61+
)
62+
)
63+
global_gt_dataset = DatasetEntity(globally_annotated, purpose=dataset.purpose)
64+
local_gt_dataset = DatasetEntity(locally_annotated, purpose=dataset.purpose)
65+
return global_gt_dataset, local_gt_dataset
66+
67+
68+
def split_local_global_resultset(resultset) -> Tuple[ResultSetEntity, ResultSetEntity]:
69+
"""Split resultset based on the type of available annotations."""
70+
# splits the dataset
71+
globally_annotated = []
72+
locally_annotated = []
73+
globally_predicted = []
74+
locally_predicted = []
75+
for gt_item, pred_item in zip(resultset.ground_truth_dataset, resultset.prediction_dataset):
76+
77+
annotations = gt_item.get_annotations()
78+
global_annotations = [annotation for annotation in annotations if Rectangle.is_full_box(annotation.shape)]
79+
local_annotations = [annotation for annotation in annotations if not Rectangle.is_full_box(annotation.shape)]
80+
81+
predictions = gt_item.get_annotations()
82+
global_predictions = [predictions for predictions in predictions if Rectangle.is_full_box(predictions.shape)]
83+
local_predictions = [predictions for predictions in predictions if not Rectangle.is_full_box(predictions.shape)]
84+
85+
if not any(label.is_anomalous for label in gt_item.get_shapes_labels()):
86+
# normal images get added to both datasets
87+
globally_annotated.append(gt_item)
88+
locally_annotated.append(gt_item)
89+
globally_predicted.append(
90+
DatasetItemEntity(
91+
media=pred_item.media,
92+
annotation_scene=AnnotationSceneEntity(global_predictions, kind=AnnotationSceneKind.PREDICTION),
93+
metadata=pred_item.metadata,
94+
subset=pred_item.subset,
95+
ignored_labels=pred_item.ignored_labels,
96+
)
97+
)
98+
locally_predicted.append(
99+
DatasetItemEntity(
100+
media=pred_item.media,
101+
annotation_scene=AnnotationSceneEntity(local_predictions, kind=AnnotationSceneKind.PREDICTION),
102+
metadata=pred_item.metadata,
103+
subset=pred_item.subset,
104+
ignored_labels=pred_item.ignored_labels,
105+
)
106+
)
107+
else: # image is abnormal
108+
globally_annotated.append(
109+
DatasetItemEntity(
110+
media=gt_item.media,
111+
annotation_scene=AnnotationSceneEntity(global_annotations, kind=AnnotationSceneKind.ANNOTATION),
112+
metadata=gt_item.metadata,
113+
subset=gt_item.subset,
114+
ignored_labels=gt_item.ignored_labels,
115+
)
116+
)
117+
globally_predicted.append(
118+
DatasetItemEntity(
119+
media=pred_item.media,
120+
annotation_scene=AnnotationSceneEntity(global_predictions, kind=AnnotationSceneKind.PREDICTION),
121+
metadata=pred_item.metadata,
122+
subset=pred_item.subset,
123+
ignored_labels=pred_item.ignored_labels,
124+
)
125+
)
126+
# add locally annotated dataset items
127+
if len(local_annotations) > 0:
128+
locally_annotated.append(
129+
DatasetItemEntity(
130+
media=gt_item.media,
131+
annotation_scene=AnnotationSceneEntity(local_annotations, kind=AnnotationSceneKind.ANNOTATION),
132+
metadata=gt_item.metadata,
133+
subset=gt_item.subset,
134+
ignored_labels=gt_item.ignored_labels,
135+
)
136+
)
137+
locally_predicted.append(
138+
DatasetItemEntity(
139+
media=pred_item.media,
140+
annotation_scene=AnnotationSceneEntity(local_predictions, kind=AnnotationSceneKind.PREDICTION),
141+
metadata=pred_item.metadata,
142+
subset=pred_item.subset,
143+
ignored_labels=pred_item.ignored_labels,
144+
)
145+
)
146+
147+
global_resultset = ResultSetEntity(
148+
model=resultset.model,
149+
ground_truth_dataset=DatasetEntity(globally_annotated, purpose=resultset.ground_truth_dataset.purpose),
150+
prediction_dataset=DatasetEntity(globally_predicted, purpose=resultset.prediction_dataset.purpose),
151+
purpose=resultset.purpose,
152+
)
153+
local_resultset = ResultSetEntity(
154+
model=resultset.model,
155+
ground_truth_dataset=DatasetEntity(locally_annotated, purpose=resultset.ground_truth_dataset.purpose),
156+
prediction_dataset=DatasetEntity(locally_predicted, purpose=resultset.prediction_dataset.purpose),
157+
purpose=resultset.purpose,
158+
)
159+
160+
return global_resultset, local_resultset
161+
162+
163+
def contains_anomalous_images(dataset: DatasetEntity) -> bool:
164+
"""Find the number of local annotations in a resultset."""
165+
for item in dataset:
166+
labels = item.get_shapes_labels()
167+
if any(label.is_anomalous for label in labels):
168+
return True
169+
return False

external/anomaly/ote_anomalib/openvino.py

+15-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@
3737
from compression.pipeline.initializer import create_pipeline
3838
from omegaconf import OmegaConf
3939
from ote_anomalib.configs import get_anomalib_config
40+
from ote_anomalib.data.utils import (
41+
contains_anomalous_images,
42+
split_local_global_resultset,
43+
)
4044
from ote_anomalib.exportable_code import (
4145
AnomalyBase,
4246
AnomalyClassification,
@@ -215,7 +219,17 @@ def evaluate(self, output_resultset: ResultSetEntity, evaluation_metric: Optiona
215219
if self.task_type == TaskType.ANOMALY_CLASSIFICATION:
216220
metric = MetricsHelper.compute_f_measure(output_resultset)
217221
elif self.task_type == TaskType.ANOMALY_SEGMENTATION:
218-
metric = MetricsHelper.compute_dice_averaged_over_pixels(output_resultset, MetricAverageMethod.MICRO)
222+
global_resultset, local_resultset = split_local_global_resultset(output_resultset)
223+
logger.info(f"Global annotations: {len(global_resultset.ground_truth_dataset)}")
224+
logger.info(f"Local annotations: {len(local_resultset.ground_truth_dataset)}")
225+
logger.info(f"Global predictions: {len(global_resultset.prediction_dataset)}")
226+
logger.info(f"Local predictions: {len(local_resultset.prediction_dataset)}")
227+
if contains_anomalous_images(local_resultset.ground_truth_dataset):
228+
logger.info("Dataset contains polygon annotations. Using pixel-level evaluation metric.")
229+
metric = MetricsHelper.compute_dice_averaged_over_pixels(local_resultset, MetricAverageMethod.MICRO)
230+
else:
231+
logger.info("Dataset does not contain polygon annotations. Using image-level evaluation metric.")
232+
metric = MetricsHelper.compute_f_measure(global_resultset)
219233
else:
220234
raise ValueError(f"Unknown task type: {self.task_type}")
221235
output_resultset.performance = metric.get_performance()

external/anomaly/ote_anomalib/task.py

+16-8
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@
3030
from ote_anomalib.callbacks import AnomalyInferenceCallback, ProgressCallback
3131
from ote_anomalib.configs import get_anomalib_config
3232
from ote_anomalib.data import OTEAnomalyDataModule
33+
from ote_anomalib.data.utils import (
34+
contains_anomalous_images,
35+
split_local_global_resultset,
36+
)
3337
from ote_anomalib.logging import get_logger
3438
from ote_sdk.entities.datasets import DatasetEntity
3539
from ote_sdk.entities.inference_parameters import InferenceParameters
@@ -87,13 +91,7 @@ def get_config(self) -> Union[DictConfig, ListConfig]:
8791
config = get_anomalib_config(task_name=self.model_name, ote_config=hyper_parameters)
8892
config.project.path = self.project_path
8993

90-
# set task type
91-
if self.task_type == TaskType.ANOMALY_CLASSIFICATION:
92-
config.dataset.task = "classification"
93-
elif self.task_type == TaskType.ANOMALY_SEGMENTATION:
94-
config.dataset.task = "segmentation"
95-
else:
96-
raise ValueError(f"Unknown task type: {self.task_type}")
94+
config.dataset.task = "classification"
9795

9896
return config
9997

@@ -232,7 +230,17 @@ def evaluate(self, output_resultset: ResultSetEntity, evaluation_metric: Optiona
232230
if self.task_type == TaskType.ANOMALY_CLASSIFICATION:
233231
metric = MetricsHelper.compute_f_measure(output_resultset)
234232
elif self.task_type == TaskType.ANOMALY_SEGMENTATION:
235-
metric = MetricsHelper.compute_dice_averaged_over_pixels(output_resultset, MetricAverageMethod.MICRO)
233+
global_resultset, local_resultset = split_local_global_resultset(output_resultset)
234+
logger.info(f"Global annotations: {len(global_resultset.ground_truth_dataset)}")
235+
logger.info(f"Local annotations: {len(local_resultset.ground_truth_dataset)}")
236+
logger.info(f"Global predictions: {len(global_resultset.prediction_dataset)}")
237+
logger.info(f"Local predictions: {len(local_resultset.prediction_dataset)}")
238+
if contains_anomalous_images(local_resultset.ground_truth_dataset):
239+
logger.info("Dataset contains polygon annotations. Using pixel-level evaluation metric.")
240+
metric = MetricsHelper.compute_dice_averaged_over_pixels(local_resultset, MetricAverageMethod.MICRO)
241+
else:
242+
logger.info("Dataset does not contain polygon annotations. Using image-level evaluation metric.")
243+
metric = MetricsHelper.compute_f_measure(global_resultset)
236244
else:
237245
raise ValueError(f"Unknown task type: {self.task_type}")
238246
output_resultset.performance = metric.get_performance()

external/deep-object-reid

-1
This file was deleted.

0 commit comments

Comments
 (0)