quadra 2.5.0__py3-none-any.whl → 2.6.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- quadra/__init__.py +1 -1
- quadra/configs/experiment/base/classification/classification.yaml +0 -1
- quadra/configs/scheduler/default.yaml +0 -1
- quadra/configs/scheduler/rop.yaml +0 -1
- quadra/tasks/anomaly.py +29 -3
- quadra/utils/anomaly.py +35 -0
- {quadra-2.5.0.dist-info → quadra-2.6.0.dist-info}/METADATA +6 -6
- {quadra-2.5.0.dist-info → quadra-2.6.0.dist-info}/RECORD +11 -11
- {quadra-2.5.0.dist-info → quadra-2.6.0.dist-info}/WHEEL +1 -1
- {quadra-2.5.0.dist-info → quadra-2.6.0.dist-info}/entry_points.txt +0 -0
- {quadra-2.5.0.dist-info → quadra-2.6.0.dist-info}/licenses/LICENSE +0 -0
quadra/__init__.py
CHANGED
quadra/tasks/anomaly.py
CHANGED
|
@@ -244,7 +244,7 @@ class AnomalibDetection(Generic[AnomalyDataModuleT], LightningTask[AnomalyDataMo
|
|
|
244
244
|
):
|
|
245
245
|
threshold = torch.tensor(100.0)
|
|
246
246
|
else:
|
|
247
|
-
threshold = self.module.image_metrics.F1Score.threshold
|
|
247
|
+
threshold = self.module.image_metrics.F1Score.threshold # type: ignore[union-attr,assignment]
|
|
248
248
|
|
|
249
249
|
# The output of the prediction is a normalized score so the cumulative histogram is displayed with the
|
|
250
250
|
# normalized scores
|
|
@@ -328,6 +328,22 @@ class AnomalibDetection(Generic[AnomalyDataModuleT], LightningTask[AnomalyDataMo
|
|
|
328
328
|
else:
|
|
329
329
|
utils.upload_file_tensorboard(a, tensorboard_logger)
|
|
330
330
|
|
|
331
|
+
def execute(self):
|
|
332
|
+
"""Execute the experiment and all the steps."""
|
|
333
|
+
self.prepare()
|
|
334
|
+
self.train()
|
|
335
|
+
# When training in fp16 mixed precision, export function casts model weights from fp32 to fp16,
|
|
336
|
+
# for this reason, predictions logits could slightly change and predictions could be inconsistent between
|
|
337
|
+
# test and generated report.
|
|
338
|
+
# Performing export before test allows to have consistent results in test metrics and generated report.
|
|
339
|
+
if self.config.export is not None and len(self.config.export.types) > 0:
|
|
340
|
+
self.export()
|
|
341
|
+
if self.run_test:
|
|
342
|
+
self.test()
|
|
343
|
+
if self.report:
|
|
344
|
+
self.generate_report()
|
|
345
|
+
self.finalize()
|
|
346
|
+
|
|
331
347
|
|
|
332
348
|
class AnomalibEvaluation(Evaluation[AnomalyDataModule]):
|
|
333
349
|
"""Evaluation task for Anomalib.
|
|
@@ -445,12 +461,22 @@ class AnomalibEvaluation(Evaluation[AnomalyDataModule]):
|
|
|
445
461
|
training_threshold = self.model_data[f"{self.training_threshold_type}_threshold"]
|
|
446
462
|
optimal_threshold = self.metadata["threshold"]
|
|
447
463
|
|
|
448
|
-
normalized_optimal_threshold = cast(float, normalize_anomaly_score(optimal_threshold, training_threshold))
|
|
449
|
-
|
|
450
464
|
os.makedirs(os.path.join(self.report_path, "predictions"), exist_ok=True)
|
|
451
465
|
os.makedirs(os.path.join(self.report_path, "heatmaps"), exist_ok=True)
|
|
452
466
|
|
|
453
467
|
anomaly_scores = self.metadata["anomaly_scores"].cpu().numpy()
|
|
468
|
+
|
|
469
|
+
# The reason I have to expand dims and cast the optimal threshold to anomaly_scores dtype is because
|
|
470
|
+
# of internal roundings performed differently by numpy and python
|
|
471
|
+
# Particularly the normalized_optimal_threshold computed directly using float values might be higher than the
|
|
472
|
+
# actual value obtained by the anomaly_scores
|
|
473
|
+
normalized_optimal_threshold = cast(
|
|
474
|
+
np.ndarray,
|
|
475
|
+
normalize_anomaly_score(
|
|
476
|
+
np.expand_dims(np.array(optimal_threshold, dtype=anomaly_scores.dtype), -1), training_threshold
|
|
477
|
+
),
|
|
478
|
+
).item()
|
|
479
|
+
|
|
454
480
|
anomaly_scores = normalize_anomaly_score(anomaly_scores, training_threshold)
|
|
455
481
|
|
|
456
482
|
if not isinstance(anomaly_scores, np.ndarray):
|
quadra/utils/anomaly.py
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
|
+
from typing import cast
|
|
9
|
+
|
|
8
10
|
try:
|
|
9
11
|
from typing import Any, TypeAlias
|
|
10
12
|
except ImportError:
|
|
@@ -43,6 +45,39 @@ def normalize_anomaly_score(raw_score: MapOrValue, threshold: float) -> MapOrVal
|
|
|
43
45
|
else:
|
|
44
46
|
normalized_score = 200.0 - ((raw_score / threshold) * 100.0)
|
|
45
47
|
|
|
48
|
+
# Ensures that the normalized scores are consistent with the raw scores
|
|
49
|
+
# For all the items whose prediction changes after normalization, force the normalized score to be
|
|
50
|
+
# consistent with the prediction made on the raw score by clipping the score:
|
|
51
|
+
# - to 100.0 if the prediction was "anomaly" on the raw score and "good" on the normalized score
|
|
52
|
+
# - to 99.99 if the prediction was "good" on the raw score and "anomaly" on the normalized score
|
|
53
|
+
score = raw_score
|
|
54
|
+
if isinstance(score, torch.Tensor):
|
|
55
|
+
score = score.cpu().numpy()
|
|
56
|
+
# Anomalib classify as anomaly if anomaly_score gte threshold
|
|
57
|
+
is_anomaly_mask = score >= threshold
|
|
58
|
+
is_not_anomaly_mask = np.bitwise_not(is_anomaly_mask)
|
|
59
|
+
if isinstance(normalized_score, torch.Tensor):
|
|
60
|
+
if normalized_score.dim() == 0:
|
|
61
|
+
normalized_score = (
|
|
62
|
+
normalized_score.clamp(min=100.0) if is_anomaly_mask else normalized_score.clamp(max=99.99)
|
|
63
|
+
)
|
|
64
|
+
else:
|
|
65
|
+
normalized_score[is_anomaly_mask] = normalized_score[is_anomaly_mask].clamp(min=100.0)
|
|
66
|
+
normalized_score[is_not_anomaly_mask] = normalized_score[is_not_anomaly_mask].clamp(max=99.99)
|
|
67
|
+
elif isinstance(normalized_score, np.ndarray) or np.isscalar(normalized_score):
|
|
68
|
+
if np.isscalar(normalized_score) or normalized_score.ndim == 0: # type: ignore[union-attr]
|
|
69
|
+
normalized_score = (
|
|
70
|
+
np.clip(normalized_score, a_min=100.0, a_max=None)
|
|
71
|
+
if is_anomaly_mask
|
|
72
|
+
else np.clip(normalized_score, a_min=None, a_max=99.99)
|
|
73
|
+
)
|
|
74
|
+
else:
|
|
75
|
+
normalized_score = cast(np.ndarray, normalized_score)
|
|
76
|
+
normalized_score[is_anomaly_mask] = np.clip(normalized_score[is_anomaly_mask], a_min=100.0, a_max=None)
|
|
77
|
+
normalized_score[is_not_anomaly_mask] = np.clip(
|
|
78
|
+
normalized_score[is_not_anomaly_mask], a_min=None, a_max=99.99
|
|
79
|
+
)
|
|
80
|
+
|
|
46
81
|
if isinstance(normalized_score, torch.Tensor):
|
|
47
82
|
return torch.clamp(normalized_score, 0.0, 1000.0)
|
|
48
83
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quadra
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.6.0
|
|
4
4
|
Summary: Deep Learning experiment orchestration library
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -22,7 +22,7 @@ Provides-Extra: onnx
|
|
|
22
22
|
Requires-Dist: albumentations (>=1.3,<1.4)
|
|
23
23
|
Requires-Dist: anomalib-orobix (==0.7.0.dev150)
|
|
24
24
|
Requires-Dist: boto3 (>=1.26,<1.27)
|
|
25
|
-
Requires-Dist: grad-cam-orobix (==1.5.3.
|
|
25
|
+
Requires-Dist: grad-cam-orobix (==1.5.3.dev1)
|
|
26
26
|
Requires-Dist: h5py (>=3.8,<3.9)
|
|
27
27
|
Requires-Dist: hydra_colorlog (>=1.2,<1.3)
|
|
28
28
|
Requires-Dist: hydra_core (>=1.3,<1.4)
|
|
@@ -35,7 +35,7 @@ Requires-Dist: numpy (<2)
|
|
|
35
35
|
Requires-Dist: nvitop (>=0.11,<0.12)
|
|
36
36
|
Requires-Dist: onnx (==1.15.0) ; extra == "onnx"
|
|
37
37
|
Requires-Dist: onnxconverter-common (>=1.14.0,<2.0.0) ; extra == "onnx"
|
|
38
|
-
Requires-Dist: onnxruntime_gpu (==1.
|
|
38
|
+
Requires-Dist: onnxruntime_gpu (==1.23.2) ; extra == "onnx"
|
|
39
39
|
Requires-Dist: onnxsim (==0.4.28) ; extra == "onnx"
|
|
40
40
|
Requires-Dist: opencv_python_headless (>=4.7.0,<4.8.0)
|
|
41
41
|
Requires-Dist: pandas (<2.0)
|
|
@@ -44,17 +44,17 @@ Requires-Dist: pydantic (>=1.10.10)
|
|
|
44
44
|
Requires-Dist: python_dotenv (>=0.21,<0.22)
|
|
45
45
|
Requires-Dist: pytorch_lightning (>=2.4,<2.5)
|
|
46
46
|
Requires-Dist: rich (>=13.2,<13.3)
|
|
47
|
-
Requires-Dist: scikit_learn (>=1.
|
|
47
|
+
Requires-Dist: scikit_learn (>=1.6,<1.7)
|
|
48
48
|
Requires-Dist: scikit_multilearn (>=0.2,<0.3)
|
|
49
49
|
Requires-Dist: seaborn (>=0.12,<0.13)
|
|
50
50
|
Requires-Dist: segmentation_models_pytorch-orobix (==0.3.3.dev1)
|
|
51
51
|
Requires-Dist: tensorboard (>=2.11,<2.12)
|
|
52
52
|
Requires-Dist: timm (==0.9.12)
|
|
53
|
-
Requires-Dist: torch (==2.
|
|
53
|
+
Requires-Dist: torch (==2.8.0)
|
|
54
54
|
Requires-Dist: torchinfo (>=1.8,<1.9)
|
|
55
55
|
Requires-Dist: torchmetrics (>=0.10,<0.11)
|
|
56
56
|
Requires-Dist: torchsummary (>=1.5,<1.6)
|
|
57
|
-
Requires-Dist: torchvision (
|
|
57
|
+
Requires-Dist: torchvision (==0.23)
|
|
58
58
|
Requires-Dist: tripy (>=1.0,<1.1)
|
|
59
59
|
Requires-Dist: typing_extensions (==4.11.0) ; python_version < "3.10"
|
|
60
60
|
Requires-Dist: xxhash (>=3.2,<3.3)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
quadra/__init__.py,sha256=
|
|
1
|
+
quadra/__init__.py,sha256=ylxTD-7xItBBl8y254g9lUc-ehYh4LCjfEoDhXhBfUw,112
|
|
2
2
|
quadra/callbacks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
quadra/callbacks/anomalib.py,sha256=WLBEGhZA9HoP4Yh9UbbC2GzDOKYTkvU9EY1lkZcV7Fs,11971
|
|
4
4
|
quadra/callbacks/lightning.py,sha256=qvtzDiv8ZUV7K11gKHKWCyo-a9XR_Jm_M-IEicTM1Yo,20242
|
|
@@ -59,7 +59,7 @@ quadra/configs/experiment/base/anomaly/fastflow.yaml,sha256=jN3TeJXPGT7_GOhu2Eac
|
|
|
59
59
|
quadra/configs/experiment/base/anomaly/inference.yaml,sha256=aLS3U0yC0Yb17BD1NSl-nhjJ9fcV6jDmxVQrrwZoMYI,446
|
|
60
60
|
quadra/configs/experiment/base/anomaly/padim.yaml,sha256=5trGY5kL7gKzRTQuWT-LHYVPf4-q9J2I_-196noIZd4,829
|
|
61
61
|
quadra/configs/experiment/base/anomaly/patchcore.yaml,sha256=a795iOcdH6kSoeA7ufChjBGWYdBn0ztRVtLBk1vpI3Q,841
|
|
62
|
-
quadra/configs/experiment/base/classification/classification.yaml,sha256=
|
|
62
|
+
quadra/configs/experiment/base/classification/classification.yaml,sha256=MNWrzDPpTIBc5gfIyeZmEiLqeI-FPjXJt2APD4gY0gU,1290
|
|
63
63
|
quadra/configs/experiment/base/classification/classification_evaluation.yaml,sha256=r_pWUr9MbZYXlJlKIZIRb3GQfuGkuFOMjSOiZrt5fdU,463
|
|
64
64
|
quadra/configs/experiment/base/classification/multilabel_classification.yaml,sha256=I8g8TUMW1q6uoa_pT_V9swwsVzS4ouZxUN3Dz424bJQ,774
|
|
65
65
|
quadra/configs/experiment/base/classification/sklearn_classification.yaml,sha256=Mun6mabSBtFoOo1zE96syfoVNBmonmSmw7HAfEx3D5s,519
|
|
@@ -148,8 +148,8 @@ quadra/configs/optimizer/adamw.yaml,sha256=bofKJKqkjhtCf07KrARdUxMpQO6ux8UKGG2c0
|
|
|
148
148
|
quadra/configs/optimizer/default.yaml,sha256=_JNfHj0JnkggcHKorPNJ_dSAJdkifNapve8VlHRcIVg,69
|
|
149
149
|
quadra/configs/optimizer/lars.yaml,sha256=NwBKZNLQ5lbPAiWNPgmX2W4ap0PW3h-LpWKF6Qz35Vs,138
|
|
150
150
|
quadra/configs/optimizer/sgd.yaml,sha256=_JNfHj0JnkggcHKorPNJ_dSAJdkifNapve8VlHRcIVg,69
|
|
151
|
-
quadra/configs/scheduler/default.yaml,sha256=
|
|
152
|
-
quadra/configs/scheduler/rop.yaml,sha256=
|
|
151
|
+
quadra/configs/scheduler/default.yaml,sha256=vmLBhrgBLs9DDXC69CRIbTkcKiGT11vfrq-hJNrYWy4,94
|
|
152
|
+
quadra/configs/scheduler/rop.yaml,sha256=Z--NTA5X60asZ3nm85dNucJL7h1J4cICtryA9Bc-KbI,96
|
|
153
153
|
quadra/configs/scheduler/step.yaml,sha256=0pj1rENjeeke8XQUhdrWrKD7eaoQ2a9-H25Deww9w3o,67
|
|
154
154
|
quadra/configs/scheduler/warmrestart.yaml,sha256=cD7pPYFwBgCqLTCnYkrOW24Fd-8CiLgs88rsF0NHoyw,90
|
|
155
155
|
quadra/configs/scheduler/warmup.yaml,sha256=2vv928tgNOE7yelnBSL2DVslqS3vqGz39LVXnZCJkPU,198
|
|
@@ -248,7 +248,7 @@ quadra/schedulers/__init__.py,sha256=mQivr18c0j36hpV3Lm8nlyBVKFevWp8TtLuTfvI9kQc
|
|
|
248
248
|
quadra/schedulers/base.py,sha256=T1EdrLOJ0i9MzWoLCkrNA0uypm7hJ-L6NFhjIXFB6NE,1462
|
|
249
249
|
quadra/schedulers/warmup.py,sha256=chzzrK7OqqlicBCxiF4CqMYNrWu6nflIbRE-C86Jrw0,4962
|
|
250
250
|
quadra/tasks/__init__.py,sha256=tmAfMoH0k3UC7r2pNrgbBa1Pfc3tpLl3IObFF6Z0eRE,820
|
|
251
|
-
quadra/tasks/anomaly.py,sha256=
|
|
251
|
+
quadra/tasks/anomaly.py,sha256=40ciWnkle45Hl6SjY_4OHWdT2Mb1Qfoog60alZG-uQ0,25899
|
|
252
252
|
quadra/tasks/base.py,sha256=piYlTFtvqH-4s4oEq4GczdAs_gL29UHAJGsOC5Sd3Bc,14187
|
|
253
253
|
quadra/tasks/classification.py,sha256=_GQOPMGuOZ_uLA9jFhLEaJkW_Sid_WKHNn9ALXnGNmo,53407
|
|
254
254
|
quadra/tasks/patch.py,sha256=nzo8o-ei7iF1Iarvd8-c08s0Rs_lPvVPDLAbkFMx-Qw,20251
|
|
@@ -258,7 +258,7 @@ quadra/trainers/README.md,sha256=XtpbUOxwvPpOUL7E5s2JHjRgwT-CRKTxsBeUSXrg9BU,248
|
|
|
258
258
|
quadra/trainers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
259
259
|
quadra/trainers/classification.py,sha256=YeJ0z7Vk0-dsMTcoKBxSdSA0rxtilEcQTp-Zq9Xi1hw,7042
|
|
260
260
|
quadra/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
261
|
-
quadra/utils/anomaly.py,sha256=
|
|
261
|
+
quadra/utils/anomaly.py,sha256=uyzrFTz5QFTyIEbOT81A6OxXbHceGeiGP-JP3qr65D8,6044
|
|
262
262
|
quadra/utils/classification.py,sha256=dKFuv4RywWhvhstOnEOnaf-6qcViUK0dTgah9m9mw2Q,24917
|
|
263
263
|
quadra/utils/deprecation.py,sha256=zF_S-yqenaZxRBOudhXts0mX763WjEUWCnHd09TZnwY,852
|
|
264
264
|
quadra/utils/evaluation.py,sha256=oooRJPu1AaHhOwvB1Y6SFjQ645OkgrDzKtUvwWq8oq4,19005
|
|
@@ -293,8 +293,8 @@ quadra/utils/validator.py,sha256=wmVXycB90VNyAbKBUVncFCxK4nsYiOWJIY3ISXwxYCY,463
|
|
|
293
293
|
quadra/utils/visualization.py,sha256=yYm7lPziUOlybxigZ2qTycNewb67Q80H4hjQGWUh788,16094
|
|
294
294
|
quadra/utils/vit_explainability.py,sha256=Gh6BHaDEzWxOjJp1aqvCxLt9Rb8TXd5uKXOAx7-acUk,13351
|
|
295
295
|
hydra_plugins/quadra_searchpath_plugin.py,sha256=AAn4TzR87zUK7nwSsK-KoqALiPtfQ8FvX3fgZPTGIJ0,1189
|
|
296
|
-
quadra-2.
|
|
297
|
-
quadra-2.
|
|
298
|
-
quadra-2.
|
|
299
|
-
quadra-2.
|
|
300
|
-
quadra-2.
|
|
296
|
+
quadra-2.6.0.dist-info/METADATA,sha256=eAbmWIkIwEc5poNJHwM_9gEu4gH6uXmGlDv2HOfO7iA,17624
|
|
297
|
+
quadra-2.6.0.dist-info/WHEEL,sha256=3ny-bZhpXrU6vSQ1UPG34FoxZBp3lVcvK0LkgUz6VLk,88
|
|
298
|
+
quadra-2.6.0.dist-info/entry_points.txt,sha256=sRYonBZyx-sAJeWcQNQoVQIU5lm02cnCQt6b15k0WHU,43
|
|
299
|
+
quadra-2.6.0.dist-info/licenses/LICENSE,sha256=8cTbQtcWa02YJoSpMeV_gxj3jpMTkxvl-w3WJ5gV_QE,11342
|
|
300
|
+
quadra-2.6.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|