deepvisiontools 0.1.0__tar.gz → 0.2.0__tar.gz
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.
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/PKG-INFO +8 -7
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/README.md +4 -3
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/pyproject.toml +3 -2
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/__init__.py +1 -1
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/config/config.py +3 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/inference/predictor.py +7 -1
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/metrics/base_metric.py +102 -67
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/models/__init__.py +6 -4
- deepvisiontools-0.2.0/src/deepvisiontools/models/timmyolo/__init__.py +4 -0
- deepvisiontools-0.2.0/src/deepvisiontools/models/timmyolo/errors.py +5 -0
- deepvisiontools-0.2.0/src/deepvisiontools/models/timmyolo/timmyolo.py +392 -0
- deepvisiontools-0.2.0/src/deepvisiontools/models/timmyolo/utils.py +230 -0
- {deepvisiontools-0.1.0/src/deepvisiontools/models/yolov8 → deepvisiontools-0.2.0/src/deepvisiontools/models/yolo}/__init__.py +3 -3
- {deepvisiontools-0.1.0/src/deepvisiontools/models/yolov8 → deepvisiontools-0.2.0/src/deepvisiontools/models/yolo}/errors.py +1 -1
- deepvisiontools-0.1.0/src/deepvisiontools/models/yolov8/yolov8.py → deepvisiontools-0.2.0/src/deepvisiontools/models/yolo/yolo.py +19 -7
- deepvisiontools-0.2.0/src/deepvisiontools/models/yoloseg/__init__.py +4 -0
- {deepvisiontools-0.1.0/src/deepvisiontools/models/yolov8seg → deepvisiontools-0.2.0/src/deepvisiontools/models/yoloseg}/utils.py +1 -1
- deepvisiontools-0.1.0/src/deepvisiontools/models/yolov8seg/yolov8seg.py → deepvisiontools-0.2.0/src/deepvisiontools/models/yoloseg/yoloseg.py +32 -11
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/train/trainer.py +32 -12
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools.egg-info/PKG-INFO +8 -7
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools.egg-info/SOURCES.txt +12 -8
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools.egg-info/requires.txt +1 -1
- deepvisiontools-0.1.0/src/deepvisiontools/models/yolov8seg/__init__.py +0 -4
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/LICENSE.txt +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/setup.cfg +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/setup.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/config/__init__.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/config/errors.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/data/__init__.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/data/additional_augmentations.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/data/augmentation_class.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/data/batch_augmentations.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/data/data_reader/__init__.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/data/data_reader/readers.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/data/dataset.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/data/errors.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/formats/__init__.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/formats/base_data.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/formats/base_formats.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/formats/errors.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/formats/formats.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/formats/utils.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/inference/__init__.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/inference/evaluator.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/inference/patchifier.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/metrics/__init__.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/metrics/available_metrics.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/metrics/func.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/metrics/matcher.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/metrics/utils.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/models/basemodel.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/models/mask2former/__init__.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/models/mask2former/mask2former.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/models/smp/__init__.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/models/smp/errors.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/models/smp/smp.py +0 -0
- {deepvisiontools-0.1.0/src/deepvisiontools/models/yolov8 → deepvisiontools-0.2.0/src/deepvisiontools/models/yolo}/utils.py +0 -0
- {deepvisiontools-0.1.0/src/deepvisiontools/models/yolov8seg → deepvisiontools-0.2.0/src/deepvisiontools/models/yoloseg}/errors.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/preprocessing/__init__.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/preprocessing/image.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/preprocessing/preprocessing.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/train/__init__.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/utils/__init__.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/utils/errors.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools/utils/visualization.py +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools.egg-info/dependency_links.txt +0 -0
- {deepvisiontools-0.1.0 → deepvisiontools-0.2.0}/src/deepvisiontools.egg-info/top_level.txt +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepvisiontools
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Overlay of PyTorch to generalize trainning and inference processes for detection, instance segmentation and semantic segmentation tasks.
|
|
5
5
|
Author-email: Lucas Bernigaud Samatan <lucas.bernigaud-samatan@inrae.fr>, Jordan Bernigaud Samatan <jordan.bernigaud-samatan@inrae.fr>, Paul Faucher <paul.faucher@inrae.fr>
|
|
6
|
-
Maintainer-email: Jordan Bernigaud Samatan <jordan.bernigaud-samatan@inrae.fr>
|
|
6
|
+
Maintainer-email: Jordan Bernigaud Samatan <jordan.bernigaud-samatan@inrae.fr>, Lucas Bernigaud Samatan <lucas.bernigaud-samatan@inrae.fr>
|
|
7
7
|
License: GNU AFFERO GENERAL PUBLIC LICENSE
|
|
8
8
|
Version 3, 19 November 2007
|
|
9
9
|
|
|
@@ -673,7 +673,7 @@ Project-URL: Repository, https://forgemia.inra.fr/ue-apc/librairies/python/deepv
|
|
|
673
673
|
Classifier: Development Status :: 4 - Beta
|
|
674
674
|
Classifier: Programming Language :: Python :: 3.11
|
|
675
675
|
Classifier: Programming Language :: Python :: 3.12
|
|
676
|
-
Requires-Python: <=3.12.
|
|
676
|
+
Requires-Python: <=3.12.12,>=3.11.9
|
|
677
677
|
Description-Content-Type: text/markdown
|
|
678
678
|
License-File: LICENSE.txt
|
|
679
679
|
Requires-Dist: torch<=2.6.0,>=2.4.0
|
|
@@ -684,7 +684,7 @@ Requires-Dist: tensorboard<=2.19.0,>=2.18.0
|
|
|
684
684
|
Requires-Dist: ultralytics<=8.3.95,>=8.3.28
|
|
685
685
|
Requires-Dist: transformers<=4.50.0,>=4.44.2
|
|
686
686
|
Requires-Dist: colorcet==3.1.0
|
|
687
|
-
Requires-Dist: segmentation-models-pytorch<=0.
|
|
687
|
+
Requires-Dist: segmentation-models-pytorch<=0.5.0,>0.4.0
|
|
688
688
|
Requires-Dist: openpyxl==3.1.5
|
|
689
689
|
Dynamic: license-file
|
|
690
690
|
|
|
@@ -707,21 +707,22 @@ deepvisiontools is developped by INRAE (french National Research Institute for A
|
|
|
707
707
|
|
|
708
708
|
## Citations
|
|
709
709
|
|
|
710
|
-
deepvisiontools
|
|
710
|
+
deepvisiontools provides model wrappers that allow you to use differents models with all machinery available. It is the responsability of the user to cite properly the actual model developpers.
|
|
711
711
|
In particular, if using one of these models : Yolo, SMP please cite the actual models developpers (which are not deepvisiontools). For instance for Yolo, please cite ultralytics (https://www.ultralytics.com/) or for SMP cite https://github.com/qubvel-org/segmentation_models.pytorch
|
|
712
712
|
Similar stands for other models.
|
|
713
|
+
TimmYolo model is a new model that combines timm encoders with a Yolo detection head. The strategy is based on patchification for the backbone (to avoid loosing resolution in resizing) then merge the features before running a Yolo detection heads. If you use this wrapper please cite both timm library, ultralytics library as well as deepvisiontools as model developper.
|
|
713
714
|
|
|
714
715
|
## Documentation
|
|
715
716
|
|
|
716
717
|
All documentation about deepvisiontools, including tutorials, can be found at : https://deepvisiontools.readthedocs.io/en/latest/
|
|
717
718
|
|
|
718
719
|
## Installation
|
|
719
|
-
We have tested deepvisiontools for python versions between 3.11.9 and 3.12.
|
|
720
|
+
We have tested deepvisiontools for python versions between 3.11.9 and 3.12.11, we recommend to use python 3.12.11 to minimize the risk of bugs.
|
|
720
721
|
|
|
721
722
|
```shell
|
|
722
723
|
pip install deepvisiontools
|
|
723
724
|
```
|
|
724
|
-
|
|
725
|
+
If you wish to use TimmYolo model, you may encounter an error saying that feature_only is not available for a given encoder name. Please upgrade your timm version (1.0.15 should have most of them). You may need to reinstall deepvisiontools as you could create conflicts with segmentation-models-pytorch.
|
|
725
726
|
## License
|
|
726
727
|
|
|
727
728
|
GNU Affero General Public License v3 or later (AGPLv3+) (AGPL-3.0).
|
|
@@ -17,21 +17,22 @@ deepvisiontools is developped by INRAE (french National Research Institute for A
|
|
|
17
17
|
|
|
18
18
|
## Citations
|
|
19
19
|
|
|
20
|
-
deepvisiontools
|
|
20
|
+
deepvisiontools provides model wrappers that allow you to use differents models with all machinery available. It is the responsability of the user to cite properly the actual model developpers.
|
|
21
21
|
In particular, if using one of these models : Yolo, SMP please cite the actual models developpers (which are not deepvisiontools). For instance for Yolo, please cite ultralytics (https://www.ultralytics.com/) or for SMP cite https://github.com/qubvel-org/segmentation_models.pytorch
|
|
22
22
|
Similar stands for other models.
|
|
23
|
+
TimmYolo model is a new model that combines timm encoders with a Yolo detection head. The strategy is based on patchification for the backbone (to avoid loosing resolution in resizing) then merge the features before running a Yolo detection heads. If you use this wrapper please cite both timm library, ultralytics library as well as deepvisiontools as model developper.
|
|
23
24
|
|
|
24
25
|
## Documentation
|
|
25
26
|
|
|
26
27
|
All documentation about deepvisiontools, including tutorials, can be found at : https://deepvisiontools.readthedocs.io/en/latest/
|
|
27
28
|
|
|
28
29
|
## Installation
|
|
29
|
-
We have tested deepvisiontools for python versions between 3.11.9 and 3.12.
|
|
30
|
+
We have tested deepvisiontools for python versions between 3.11.9 and 3.12.11, we recommend to use python 3.12.11 to minimize the risk of bugs.
|
|
30
31
|
|
|
31
32
|
```shell
|
|
32
33
|
pip install deepvisiontools
|
|
33
34
|
```
|
|
34
|
-
|
|
35
|
+
If you wish to use TimmYolo model, you may encounter an error saying that feature_only is not available for a given encoder name. Please upgrade your timm version (1.0.15 should have most of them). You may need to reinstall deepvisiontools as you could create conflicts with segmentation-models-pytorch.
|
|
35
36
|
## License
|
|
36
37
|
|
|
37
38
|
GNU Affero General Public License v3 or later (AGPLv3+) (AGPL-3.0).
|
|
@@ -11,6 +11,7 @@ authors = [
|
|
|
11
11
|
]
|
|
12
12
|
maintainers = [
|
|
13
13
|
{ name = "Jordan Bernigaud Samatan", email = "jordan.bernigaud-samatan@inrae.fr" },
|
|
14
|
+
{ name = "Lucas Bernigaud Samatan", email = "lucas.bernigaud-samatan@inrae.fr" },
|
|
14
15
|
]
|
|
15
16
|
description = "Overlay of PyTorch to generalize trainning and inference processes for detection, instance segmentation and semantic segmentation tasks."
|
|
16
17
|
readme = "README.md"
|
|
@@ -20,7 +21,7 @@ classifiers = [
|
|
|
20
21
|
"Programming Language :: Python :: 3.12"
|
|
21
22
|
]
|
|
22
23
|
dynamic = ["version"]
|
|
23
|
-
requires-python = ">=3.11.9,<=3.12.
|
|
24
|
+
requires-python = ">=3.11.9,<=3.12.12"
|
|
24
25
|
dependencies = [
|
|
25
26
|
"torch>=2.4.0,<=2.6.0",
|
|
26
27
|
"torchvision>=0.19.0,<=0.21.0",
|
|
@@ -30,7 +31,7 @@ dependencies = [
|
|
|
30
31
|
"ultralytics>=8.3.28,<=8.3.95",
|
|
31
32
|
"transformers>=4.44.2,<=4.50.0",
|
|
32
33
|
"colorcet==3.1.0",
|
|
33
|
-
"segmentation-models-pytorch
|
|
34
|
+
"segmentation-models-pytorch>0.4.0,<=0.5.0",
|
|
34
35
|
"openpyxl==3.1.5"
|
|
35
36
|
]
|
|
36
37
|
|
|
@@ -105,6 +105,7 @@ class Configuration(metaclass=_SingletonConfig):
|
|
|
105
105
|
patchifier_mode: Literal["bbox", "instance_mask"] = "bbox",
|
|
106
106
|
seed: Union[False, int] = False,
|
|
107
107
|
deterministic: bool = False,
|
|
108
|
+
optimize=True,
|
|
108
109
|
):
|
|
109
110
|
|
|
110
111
|
# generic
|
|
@@ -127,6 +128,8 @@ class Configuration(metaclass=_SingletonConfig):
|
|
|
127
128
|
# reproducibility
|
|
128
129
|
self.seed = seed
|
|
129
130
|
self.deterministic = deterministic
|
|
131
|
+
# mixed precision (torch.amp + gradiant scaler)
|
|
132
|
+
self.optimize = optimize
|
|
130
133
|
|
|
131
134
|
@property
|
|
132
135
|
def device(self):
|
|
@@ -123,8 +123,14 @@ class Predictor:
|
|
|
123
123
|
else loader
|
|
124
124
|
)
|
|
125
125
|
predictions = BatchedFormat([])
|
|
126
|
+
|
|
126
127
|
for patch in loader:
|
|
127
|
-
|
|
128
|
+
with torch.autocast(
|
|
129
|
+
device_type=Configuration().device,
|
|
130
|
+
dtype=torch.float16,
|
|
131
|
+
enabled=Configuration().optimize,
|
|
132
|
+
):
|
|
133
|
+
predictions += self.model.get_predictions(patch)
|
|
128
134
|
return predictions
|
|
129
135
|
|
|
130
136
|
def predict(
|
|
@@ -38,7 +38,7 @@ class DetectMetric(Metric):
|
|
|
38
38
|
self.func = func
|
|
39
39
|
self.name = name
|
|
40
40
|
self.add_state("stats", default=[], dist_reduce_fx="cat")
|
|
41
|
-
self.nc = 1
|
|
41
|
+
self.nc = 1 # always one class
|
|
42
42
|
|
|
43
43
|
def update(
|
|
44
44
|
self,
|
|
@@ -71,67 +71,79 @@ class DetectMetric(Metric):
|
|
|
71
71
|
tp, fp, fn, _ = matcher.match_pred_target(pred, targ)
|
|
72
72
|
elif pred.nb_object != 0 and targ.nb_object == 0:
|
|
73
73
|
tp, fp, fn, _ = 0, pred.nb_object, 0, None
|
|
74
|
-
#elif prediction.size == 0 and target.size != 0:
|
|
74
|
+
# elif prediction.size == 0 and target.size != 0:
|
|
75
75
|
elif pred.nb_object == 0 and targ.nb_object != 0:
|
|
76
76
|
tp, fp, fn, _ = 0, 0, targ.nb_object, None
|
|
77
77
|
else:
|
|
78
78
|
tp, fp, fn, _ = torch.nan, torch.nan, torch.nan, None
|
|
79
79
|
|
|
80
80
|
# NaN because of no tn in detection
|
|
81
|
-
self.stats.append(
|
|
82
|
-
|
|
81
|
+
self.stats.append(
|
|
82
|
+
torch.tensor([[[tp, fp, torch.nan, fn, torch.nan]]])
|
|
83
|
+
) # fix tn and support to nan
|
|
84
|
+
|
|
83
85
|
def global_micro_compute(self) -> Tensor:
|
|
84
86
|
"""Compute metric with global/micro averagging."""
|
|
85
87
|
n_samples = len(self.stats)
|
|
86
88
|
samples_stack = torch.cat(self.stats).view(n_samples, self.nc, 5) # (N, NC, 5)
|
|
87
89
|
# sum stats accross samples
|
|
88
|
-
samples_stack = samples_stack.
|
|
90
|
+
samples_stack = samples_stack.nansum(dim=0) # (NC, 5)
|
|
89
91
|
# sum stats accross classes
|
|
90
|
-
micro_stack = torch.
|
|
92
|
+
micro_stack = torch.nansum(samples_stack, dim=0) # (5,)
|
|
91
93
|
# compute metric
|
|
92
94
|
tp, fp, tn, fn, _ = micro_stack.unbind(0)
|
|
93
95
|
return self.func(tp, fp, tn, fn)
|
|
94
|
-
|
|
96
|
+
|
|
95
97
|
def samplewise_micro(self) -> Tensor:
|
|
96
98
|
"""Compute metric with samplewise/micro averagging."""
|
|
97
99
|
n_samples = len(self.stats)
|
|
98
100
|
samples_stack = torch.cat(self.stats).view(n_samples, self.nc, 5) # (N, NC, 5))
|
|
99
101
|
# sum stat accross classes
|
|
100
|
-
samples_stack = samples_stack.
|
|
102
|
+
samples_stack = samples_stack.nansum(dim=1) # (NC, 5)
|
|
101
103
|
# compute metric/sample
|
|
102
104
|
tp, fp, tn, fn, _ = samples_stack.unbind(dim=1)
|
|
103
105
|
samples_metrics = self.func(tp, fp, tn, fn)
|
|
104
106
|
# mean accross samples
|
|
105
107
|
return torch.nanmean(samples_metrics)
|
|
106
|
-
|
|
108
|
+
|
|
107
109
|
def compute_last_sample(self):
|
|
108
110
|
"""Return metrics values of the last sample in self.stats.
|
|
109
111
|
Used in combination with self.update
|
|
110
|
-
|
|
112
|
+
|
|
111
113
|
Returns:
|
|
112
114
|
Dict[str, Float]: dictionnary with metric value for all classes combined and for each class
|
|
113
115
|
"""
|
|
114
116
|
|
|
115
117
|
if not self.stats:
|
|
116
|
-
return {
|
|
117
|
-
|
|
118
|
+
return {"all_cls": torch.tensor(torch.nan)}
|
|
119
|
+
|
|
118
120
|
metric_sample_dict = {}
|
|
119
121
|
|
|
120
|
-
matrix_stats_img = self.stats[-1].squeeze(
|
|
122
|
+
matrix_stats_img = self.stats[-1].squeeze(
|
|
123
|
+
0
|
|
124
|
+
) # matrix with stats (tp, fp, tn, fn) of one sample (one row for each class)
|
|
121
125
|
nb_class = matrix_stats_img.size(dim=0)
|
|
122
|
-
tp, fp, tn, fn, _ = matrix_stats_img.nansum(dim=0).unbind(
|
|
123
|
-
|
|
124
|
-
|
|
126
|
+
tp, fp, tn, fn, _ = matrix_stats_img.nansum(dim=0).unbind(
|
|
127
|
+
dim=0
|
|
128
|
+
) # sum over all classes
|
|
129
|
+
all_class_metric_value = round(
|
|
130
|
+
self.func(tp, fp, tn, fn).item(), 3
|
|
131
|
+
) # metric compute for all classes
|
|
132
|
+
metric_sample_dict["all_cls"] = all_class_metric_value
|
|
125
133
|
|
|
126
134
|
if nb_class > 1:
|
|
127
|
-
for index_class in range
|
|
128
|
-
matrix_stats_img_class = matrix_stats_img[index_class
|
|
129
|
-
tp, fp, tn, fn, _ = matrix_stats_img_class.unbind(
|
|
130
|
-
|
|
135
|
+
for index_class in range(nb_class): # metric compute for each class
|
|
136
|
+
matrix_stats_img_class = matrix_stats_img[index_class, :]
|
|
137
|
+
tp, fp, tn, fn, _ = matrix_stats_img_class.unbind(
|
|
138
|
+
dim=0
|
|
139
|
+
) # stats (tp, fp, tn, fn) of the given class
|
|
140
|
+
class_metric_value = round(
|
|
141
|
+
self.func(tp, fp, tn, fn).item(), 3
|
|
142
|
+
) # metric compute for the given class
|
|
131
143
|
metric_sample_dict["cls_{0}".format(index_class)] = class_metric_value
|
|
132
144
|
|
|
133
145
|
return metric_sample_dict
|
|
134
|
-
|
|
146
|
+
|
|
135
147
|
def compute(self) -> Dict[str, Tensor]:
|
|
136
148
|
"""Return metric computed with internal state.
|
|
137
149
|
|
|
@@ -140,7 +152,7 @@ class DetectMetric(Metric):
|
|
|
140
152
|
"""
|
|
141
153
|
if not self.stats:
|
|
142
154
|
return {self.name: torch.tensor(torch.nan)}
|
|
143
|
-
|
|
155
|
+
|
|
144
156
|
# global micro
|
|
145
157
|
global_value = self.global_micro_compute()
|
|
146
158
|
# samplewise micro
|
|
@@ -218,27 +230,31 @@ class ClassWiseDetectMetric(Metric):
|
|
|
218
230
|
if i == 0:
|
|
219
231
|
met.update(prediction, target)
|
|
220
232
|
else:
|
|
221
|
-
filtered_pred = self._filter_classes(
|
|
222
|
-
|
|
233
|
+
filtered_pred = self._filter_classes(
|
|
234
|
+
prediction, i - 1
|
|
235
|
+
) # -1 because classes start at 0
|
|
236
|
+
filtered_targ = self._filter_classes(target, i - 1)
|
|
223
237
|
met.update(filtered_pred, filtered_targ)
|
|
224
|
-
|
|
238
|
+
|
|
225
239
|
# retrieve and save in a list the stats for each sample in the batch for the given class
|
|
226
240
|
batch_size = prediction.size
|
|
227
|
-
for num_elem in range
|
|
241
|
+
for num_elem in range(batch_size, 0, -1):
|
|
228
242
|
met_samples_result.append(met.stats[-num_elem])
|
|
229
|
-
|
|
230
|
-
list_met_class.append(
|
|
231
|
-
|
|
243
|
+
|
|
244
|
+
list_met_class.append(
|
|
245
|
+
met_samples_result
|
|
246
|
+
) # save the list in the list containing the list of each class
|
|
247
|
+
|
|
232
248
|
# save the batch sample stats for each class in a matrix (N, NC, 5) and append in metric 'stats' attribute
|
|
233
249
|
for num_sample in range(batch_size):
|
|
234
250
|
sample_stats = []
|
|
235
|
-
for num_class in range(1,len(list_met_class)):
|
|
251
|
+
for num_class in range(1, len(list_met_class)):
|
|
236
252
|
sample_stats.append(list_met_class[num_class][num_sample])
|
|
237
|
-
|
|
238
|
-
class_stack = torch.cat(sample_stats).view(1, Configuration().num_classes, 5) # (N, NC, 5)
|
|
239
|
-
self.stats.append(class_stack)
|
|
240
|
-
|
|
241
253
|
|
|
254
|
+
class_stack = torch.cat(sample_stats).view(
|
|
255
|
+
1, Configuration().num_classes, 5
|
|
256
|
+
) # (N, NC, 5)
|
|
257
|
+
self.stats.append(class_stack)
|
|
242
258
|
|
|
243
259
|
# for sample_list_met_class in list_met_class:
|
|
244
260
|
# sample_list_met_class = sample_list_met_class[1:]
|
|
@@ -305,27 +321,37 @@ class ClassWiseDetectMetric(Metric):
|
|
|
305
321
|
def compute_last_sample(self):
|
|
306
322
|
"""Return metrics values of the last sample in self.stats.
|
|
307
323
|
Used in combination with self.update
|
|
308
|
-
|
|
324
|
+
|
|
309
325
|
Returns:
|
|
310
326
|
Dict[str, Float]: dictionnary with metric value for all classes combined and for each class
|
|
311
327
|
"""
|
|
312
328
|
|
|
313
329
|
if not self.stats:
|
|
314
|
-
return {
|
|
315
|
-
|
|
330
|
+
return {"all_cls": torch.tensor(torch.nan)}
|
|
331
|
+
|
|
316
332
|
metric_sample_dict = {}
|
|
317
333
|
|
|
318
|
-
matrix_stats_img = self.stats[-1].squeeze(
|
|
334
|
+
matrix_stats_img = self.stats[-1].squeeze(
|
|
335
|
+
0
|
|
336
|
+
) # matrix with stats (tp, fp, tn, fn) of one sample (one row for each class)
|
|
319
337
|
nb_class = matrix_stats_img.size(dim=0)
|
|
320
|
-
tp, fp, tn, fn, _ = matrix_stats_img.nansum(dim=0).unbind(
|
|
321
|
-
|
|
322
|
-
|
|
338
|
+
tp, fp, tn, fn, _ = matrix_stats_img.nansum(dim=0).unbind(
|
|
339
|
+
dim=0
|
|
340
|
+
) # sum over all classes
|
|
341
|
+
all_class_metric_value = round(
|
|
342
|
+
self.func(tp, fp, tn, fn).item(), 3
|
|
343
|
+
) # metric compute for all classes
|
|
344
|
+
metric_sample_dict["all_cls"] = all_class_metric_value
|
|
323
345
|
|
|
324
346
|
if nb_class > 1:
|
|
325
|
-
for index_class in range
|
|
326
|
-
matrix_stats_img_class = matrix_stats_img[index_class
|
|
327
|
-
tp, fp, tn, fn, _ = matrix_stats_img_class.unbind(
|
|
328
|
-
|
|
347
|
+
for index_class in range(nb_class): # metric compute for each class
|
|
348
|
+
matrix_stats_img_class = matrix_stats_img[index_class, :]
|
|
349
|
+
tp, fp, tn, fn, _ = matrix_stats_img_class.unbind(
|
|
350
|
+
dim=0
|
|
351
|
+
) # stats (tp, fp, tn, fn) of the given class
|
|
352
|
+
class_metric_value = round(
|
|
353
|
+
self.func(tp, fp, tn, fn).item(), 3
|
|
354
|
+
) # metric compute for the given class
|
|
329
355
|
metric_sample_dict["cls_{0}".format(index_class)] = class_metric_value
|
|
330
356
|
|
|
331
357
|
return metric_sample_dict
|
|
@@ -336,9 +362,9 @@ class ClassWiseDetectMetric(Metric):
|
|
|
336
362
|
Returns:
|
|
337
363
|
Dict[str, Tensor]: dictionnary with all "global" DetectMetric in self.classmetrics
|
|
338
364
|
"""
|
|
339
|
-
#classwisedict = {met.name: met.compute()["global"] for met in self.classmetrics}
|
|
340
|
-
#return classwisedict
|
|
341
|
-
|
|
365
|
+
# classwisedict = {met.name: met.compute()["global"] for met in self.classmetrics}
|
|
366
|
+
# return classwisedict
|
|
367
|
+
|
|
342
368
|
if not self.stats:
|
|
343
369
|
return {self.name: torch.tensor(torch.nan)}
|
|
344
370
|
|
|
@@ -349,8 +375,7 @@ class ClassWiseDetectMetric(Metric):
|
|
|
349
375
|
# global macro
|
|
350
376
|
global_macro, class_metrics = self.global_macro_compute()
|
|
351
377
|
classes_dict = {
|
|
352
|
-
f"/cls_{i}": class_metrics[i]
|
|
353
|
-
for i in range(class_metrics.nelement())
|
|
378
|
+
f"/cls_{i}": class_metrics[i] for i in range(class_metrics.nelement())
|
|
354
379
|
}
|
|
355
380
|
metric_dict.update({"_global_macro": global_macro})
|
|
356
381
|
metric_dict.update(classes_dict)
|
|
@@ -460,9 +485,9 @@ class ClassifMetric(Metric):
|
|
|
460
485
|
n_samples = len(self.stats)
|
|
461
486
|
samples_stack = torch.cat(self.stats).view(n_samples, self.nc, 5) # (N, NC, 5)
|
|
462
487
|
# sum stats accross samples
|
|
463
|
-
samples_stack = samples_stack.
|
|
488
|
+
samples_stack = samples_stack.nansum(dim=0) # (NC, 5)
|
|
464
489
|
# sum stats accross classes
|
|
465
|
-
micro_stack = torch.
|
|
490
|
+
micro_stack = torch.nansum(samples_stack, dim=0) # (5,)
|
|
466
491
|
# compute metric
|
|
467
492
|
tp, fp, tn, fn, _ = micro_stack.unbind(0)
|
|
468
493
|
return self.func(tp, fp, tn, fn)
|
|
@@ -473,7 +498,7 @@ class ClassifMetric(Metric):
|
|
|
473
498
|
n_samples = len(self.stats)
|
|
474
499
|
samples_stack = torch.cat(self.stats).view(n_samples, self.nc, 5) # (N, NC, 5)
|
|
475
500
|
# sum stats accross samples
|
|
476
|
-
samples_stack = samples_stack.
|
|
501
|
+
samples_stack = samples_stack.nansum(dim=0) # (NC, 5)
|
|
477
502
|
# compute metric/class
|
|
478
503
|
tp, fp, tn, fn, _ = samples_stack.unbind(1)
|
|
479
504
|
class_metrics = self.func(tp, fp, tn, fn) # (NC,)
|
|
@@ -484,7 +509,7 @@ class ClassifMetric(Metric):
|
|
|
484
509
|
n_samples = len(self.stats)
|
|
485
510
|
samples_stack = torch.cat(self.stats).view(n_samples, self.nc, 5) # (N, NC, 5))
|
|
486
511
|
# sum stat accross classes
|
|
487
|
-
samples_stack = samples_stack.
|
|
512
|
+
samples_stack = samples_stack.nansum(dim=1) # (NC, 5)
|
|
488
513
|
# compute metric/sample
|
|
489
514
|
tp, fp, tn, fn, _ = samples_stack.unbind(dim=1)
|
|
490
515
|
samples_metrics = self.func(tp, fp, tn, fn)
|
|
@@ -504,35 +529,45 @@ class ClassifMetric(Metric):
|
|
|
504
529
|
macro_samplewise = torch.nanmean(macro, dim=0)
|
|
505
530
|
|
|
506
531
|
return macro_samplewise
|
|
507
|
-
|
|
532
|
+
|
|
508
533
|
def compute_last_sample(self):
|
|
509
534
|
"""Return metrics values of the last sample in self.stats.
|
|
510
535
|
Used in combination with self.update
|
|
511
|
-
|
|
536
|
+
|
|
512
537
|
Returns:
|
|
513
538
|
Dict[str, Float]: dictionnary with metric value for all classes combined and for each class
|
|
514
539
|
"""
|
|
515
540
|
|
|
516
541
|
if not self.stats:
|
|
517
|
-
return {
|
|
518
|
-
|
|
542
|
+
return {"all_cls": torch.tensor(torch.nan)}
|
|
543
|
+
|
|
519
544
|
metric_sample_dict = {}
|
|
520
545
|
|
|
521
|
-
matrix_stats_img = self.stats[-1].squeeze(
|
|
546
|
+
matrix_stats_img = self.stats[-1].squeeze(
|
|
547
|
+
0
|
|
548
|
+
) # matrix with stats (tp, fp, tn, fn) of one sample (one row for each class)
|
|
522
549
|
nb_class = matrix_stats_img.size(dim=0)
|
|
523
|
-
tp, fp, tn, fn, _ = matrix_stats_img.nansum(dim=0).unbind(
|
|
524
|
-
|
|
525
|
-
|
|
550
|
+
tp, fp, tn, fn, _ = matrix_stats_img.nansum(dim=0).unbind(
|
|
551
|
+
dim=0
|
|
552
|
+
) # sum over all classes
|
|
553
|
+
all_class_metric_value = round(
|
|
554
|
+
self.func(tp, fp, tn, fn).item(), 3
|
|
555
|
+
) # metric compute for all classes
|
|
556
|
+
metric_sample_dict["all_cls"] = all_class_metric_value
|
|
526
557
|
|
|
527
558
|
if nb_class > 1:
|
|
528
|
-
for index_class in range
|
|
529
|
-
matrix_stats_img_class = matrix_stats_img[index_class
|
|
530
|
-
tp, fp, tn, fn, _ = matrix_stats_img_class.unbind(
|
|
531
|
-
|
|
559
|
+
for index_class in range(nb_class): # metric compute for each class
|
|
560
|
+
matrix_stats_img_class = matrix_stats_img[index_class, :]
|
|
561
|
+
tp, fp, tn, fn, _ = matrix_stats_img_class.unbind(
|
|
562
|
+
dim=0
|
|
563
|
+
) # stats (tp, fp, tn, fn) of the given class
|
|
564
|
+
class_metric_value = round(
|
|
565
|
+
self.func(tp, fp, tn, fn).item(), 3
|
|
566
|
+
) # metric compute for the given class
|
|
532
567
|
metric_sample_dict["cls_{0}".format(index_class)] = class_metric_value
|
|
533
568
|
|
|
534
569
|
return metric_sample_dict
|
|
535
|
-
|
|
570
|
+
|
|
536
571
|
def compute(self):
|
|
537
572
|
"""Comput metric with all averag strategy and return a dict with all values."""
|
|
538
573
|
if not self.stats:
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
from deepvisiontools.models.
|
|
2
|
-
from deepvisiontools.models.
|
|
1
|
+
from deepvisiontools.models.yolo.yolo import Yolo
|
|
2
|
+
from deepvisiontools.models.yoloseg.yoloseg import YoloSeg
|
|
3
3
|
from deepvisiontools.models.mask2former.mask2former import Mask2Former
|
|
4
|
+
from deepvisiontools.models.timmyolo.timmyolo import TimmYolo
|
|
4
5
|
from deepvisiontools.models.basemodel import BaseModel
|
|
5
6
|
from deepvisiontools.models.smp.smp import SMP, _ConcreteSegmentationModel
|
|
6
7
|
|
|
7
8
|
__all__ = (
|
|
8
9
|
"BaseModel",
|
|
9
|
-
"
|
|
10
|
-
"
|
|
10
|
+
"Yolo",
|
|
11
|
+
"YoloSeg",
|
|
12
|
+
"TimmYolo",
|
|
11
13
|
"Mask2Former",
|
|
12
14
|
"SMP",
|
|
13
15
|
"_ConcreteSegmentationModel",
|