valor-lite 0.33.7__py3-none-any.whl → 0.33.8__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.
- valor_lite/classification/annotation.py +6 -2
- valor_lite/classification/computation.py +31 -52
- valor_lite/classification/manager.py +66 -131
- valor_lite/classification/metric.py +7 -23
- valor_lite/detection/annotation.py +64 -29
- valor_lite/detection/computation.py +130 -92
- valor_lite/detection/manager.py +202 -462
- valor_lite/detection/metric.py +20 -48
- valor_lite/segmentation/__init__.py +27 -0
- valor_lite/segmentation/annotation.py +49 -0
- valor_lite/segmentation/computation.py +186 -0
- valor_lite/segmentation/manager.py +532 -0
- valor_lite/segmentation/metric.py +119 -0
- {valor_lite-0.33.7.dist-info → valor_lite-0.33.8.dist-info}/METADATA +1 -1
- valor_lite-0.33.8.dist-info/RECORD +22 -0
- valor_lite-0.33.7.dist-info/RECORD +0 -17
- {valor_lite-0.33.7.dist-info → valor_lite-0.33.8.dist-info}/LICENSE +0 -0
- {valor_lite-0.33.7.dist-info → valor_lite-0.33.8.dist-info}/WHEEL +0 -0
- {valor_lite-0.33.7.dist-info → valor_lite-0.33.8.dist-info}/top_level.txt +0 -0
|
@@ -35,7 +35,7 @@ class Counts:
|
|
|
35
35
|
tn: list[int]
|
|
36
36
|
score_thresholds: list[float]
|
|
37
37
|
hardmax: bool
|
|
38
|
-
label:
|
|
38
|
+
label: str
|
|
39
39
|
|
|
40
40
|
@property
|
|
41
41
|
def metric(self) -> Metric:
|
|
@@ -50,10 +50,7 @@ class Counts:
|
|
|
50
50
|
parameters={
|
|
51
51
|
"score_thresholds": self.score_thresholds,
|
|
52
52
|
"hardmax": self.hardmax,
|
|
53
|
-
"label":
|
|
54
|
-
"key": self.label[0],
|
|
55
|
-
"value": self.label[1],
|
|
56
|
-
},
|
|
53
|
+
"label": self.label,
|
|
57
54
|
},
|
|
58
55
|
)
|
|
59
56
|
|
|
@@ -66,7 +63,7 @@ class _ThresholdValue:
|
|
|
66
63
|
value: list[float]
|
|
67
64
|
score_thresholds: list[float]
|
|
68
65
|
hardmax: bool
|
|
69
|
-
label:
|
|
66
|
+
label: str
|
|
70
67
|
|
|
71
68
|
@property
|
|
72
69
|
def metric(self) -> Metric:
|
|
@@ -76,10 +73,7 @@ class _ThresholdValue:
|
|
|
76
73
|
parameters={
|
|
77
74
|
"score_thresholds": self.score_thresholds,
|
|
78
75
|
"hardmax": self.hardmax,
|
|
79
|
-
"label":
|
|
80
|
-
"key": self.label[0],
|
|
81
|
-
"value": self.label[1],
|
|
82
|
-
},
|
|
76
|
+
"label": self.label,
|
|
83
77
|
},
|
|
84
78
|
)
|
|
85
79
|
|
|
@@ -106,19 +100,14 @@ class F1(_ThresholdValue):
|
|
|
106
100
|
@dataclass
|
|
107
101
|
class ROCAUC:
|
|
108
102
|
value: float
|
|
109
|
-
label:
|
|
103
|
+
label: str
|
|
110
104
|
|
|
111
105
|
@property
|
|
112
106
|
def metric(self) -> Metric:
|
|
113
107
|
return Metric(
|
|
114
108
|
type=type(self).__name__,
|
|
115
109
|
value=self.value,
|
|
116
|
-
parameters={
|
|
117
|
-
"label": {
|
|
118
|
-
"key": self.label[0],
|
|
119
|
-
"value": self.label[1],
|
|
120
|
-
},
|
|
121
|
-
},
|
|
110
|
+
parameters={"label": self.label},
|
|
122
111
|
)
|
|
123
112
|
|
|
124
113
|
def to_dict(self) -> dict:
|
|
@@ -128,16 +117,13 @@ class ROCAUC:
|
|
|
128
117
|
@dataclass
|
|
129
118
|
class mROCAUC:
|
|
130
119
|
value: float
|
|
131
|
-
label_key: str
|
|
132
120
|
|
|
133
121
|
@property
|
|
134
122
|
def metric(self) -> Metric:
|
|
135
123
|
return Metric(
|
|
136
124
|
type=type(self).__name__,
|
|
137
125
|
value=self.value,
|
|
138
|
-
parameters={
|
|
139
|
-
"label_key": self.label_key,
|
|
140
|
-
},
|
|
126
|
+
parameters={},
|
|
141
127
|
)
|
|
142
128
|
|
|
143
129
|
def to_dict(self) -> dict:
|
|
@@ -170,7 +156,6 @@ class ConfusionMatrix:
|
|
|
170
156
|
],
|
|
171
157
|
]
|
|
172
158
|
score_threshold: float
|
|
173
|
-
label_key: str
|
|
174
159
|
number_of_examples: int
|
|
175
160
|
|
|
176
161
|
@property
|
|
@@ -183,7 +168,6 @@ class ConfusionMatrix:
|
|
|
183
168
|
},
|
|
184
169
|
parameters={
|
|
185
170
|
"score_threshold": self.score_threshold,
|
|
186
|
-
"label_key": self.label_key,
|
|
187
171
|
},
|
|
188
172
|
)
|
|
189
173
|
|
|
@@ -11,10 +11,14 @@ class BoundingBox:
|
|
|
11
11
|
xmax: float
|
|
12
12
|
ymin: float
|
|
13
13
|
ymax: float
|
|
14
|
-
labels: list[
|
|
14
|
+
labels: list[str]
|
|
15
15
|
scores: list[float] = field(default_factory=list)
|
|
16
16
|
|
|
17
17
|
def __post_init__(self):
|
|
18
|
+
if len(self.scores) == 0 and len(self.labels) != 1:
|
|
19
|
+
raise ValueError(
|
|
20
|
+
"Ground truths must be defined with no scores and a single label. If you meant to define a prediction, then please include one score for every label provided."
|
|
21
|
+
)
|
|
18
22
|
if len(self.scores) > 0 and len(self.labels) != len(self.scores):
|
|
19
23
|
raise ValueError(
|
|
20
24
|
"If scores are defined, there must be a 1:1 pairing with labels."
|
|
@@ -22,66 +26,97 @@ class BoundingBox:
|
|
|
22
26
|
|
|
23
27
|
@property
|
|
24
28
|
def extrema(self) -> tuple[float, float, float, float]:
|
|
29
|
+
"""
|
|
30
|
+
Returns annotation extrema in the form (xmin, xmax, ymin, ymax).
|
|
31
|
+
"""
|
|
25
32
|
return (self.xmin, self.xmax, self.ymin, self.ymax)
|
|
26
33
|
|
|
34
|
+
@property
|
|
35
|
+
def annotation(self) -> tuple[float, float, float, float]:
|
|
36
|
+
"""
|
|
37
|
+
Returns the annotation's data representation.
|
|
38
|
+
"""
|
|
39
|
+
return self.extrema
|
|
40
|
+
|
|
27
41
|
|
|
28
42
|
@dataclass
|
|
29
43
|
class Polygon:
|
|
30
44
|
shape: ShapelyPolygon
|
|
31
|
-
labels: list[
|
|
45
|
+
labels: list[str]
|
|
32
46
|
scores: list[float] = field(default_factory=list)
|
|
33
47
|
|
|
34
48
|
def __post_init__(self):
|
|
35
49
|
if not isinstance(self.shape, ShapelyPolygon):
|
|
36
50
|
raise TypeError("shape must be of type shapely.geometry.Polygon.")
|
|
51
|
+
if self.shape.is_empty:
|
|
52
|
+
raise ValueError("Polygon is empty.")
|
|
53
|
+
|
|
54
|
+
if len(self.scores) == 0 and len(self.labels) != 1:
|
|
55
|
+
raise ValueError(
|
|
56
|
+
"Ground truths must be defined with no scores and a single label. If you meant to define a prediction, then please include one score for every label provided."
|
|
57
|
+
)
|
|
37
58
|
if len(self.scores) > 0 and len(self.labels) != len(self.scores):
|
|
38
59
|
raise ValueError(
|
|
39
60
|
"If scores are defined, there must be a 1:1 pairing with labels."
|
|
40
61
|
)
|
|
41
62
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
63
|
+
@property
|
|
64
|
+
def extrema(self) -> tuple[float, float, float, float]:
|
|
65
|
+
"""
|
|
66
|
+
Returns annotation extrema in the form (xmin, xmax, ymin, ymax).
|
|
67
|
+
"""
|
|
47
68
|
xmin, ymin, xmax, ymax = self.shape.bounds
|
|
69
|
+
return (xmin, xmax, ymin, ymax)
|
|
48
70
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
scores=self.scores,
|
|
56
|
-
)
|
|
71
|
+
@property
|
|
72
|
+
def annotation(self) -> ShapelyPolygon:
|
|
73
|
+
"""
|
|
74
|
+
Returns the annotation's data representation.
|
|
75
|
+
"""
|
|
76
|
+
return self.shape
|
|
57
77
|
|
|
58
78
|
|
|
59
79
|
@dataclass
|
|
60
80
|
class Bitmask:
|
|
61
81
|
mask: NDArray[np.bool_]
|
|
62
|
-
labels: list[
|
|
82
|
+
labels: list[str]
|
|
63
83
|
scores: list[float] = field(default_factory=list)
|
|
64
84
|
|
|
65
85
|
def __post_init__(self):
|
|
86
|
+
|
|
87
|
+
if (
|
|
88
|
+
not isinstance(self.mask, np.ndarray)
|
|
89
|
+
or self.mask.dtype != np.bool_
|
|
90
|
+
):
|
|
91
|
+
raise ValueError(
|
|
92
|
+
"Expected mask to be of type `NDArray[np.bool_]`."
|
|
93
|
+
)
|
|
94
|
+
elif not self.mask.any():
|
|
95
|
+
raise ValueError("Mask does not define any object instances.")
|
|
96
|
+
|
|
97
|
+
if len(self.scores) == 0 and len(self.labels) != 1:
|
|
98
|
+
raise ValueError(
|
|
99
|
+
"Ground truths must be defined with no scores and a single label. If you meant to define a prediction, then please include one score for every label provided."
|
|
100
|
+
)
|
|
66
101
|
if len(self.scores) > 0 and len(self.labels) != len(self.scores):
|
|
67
102
|
raise ValueError(
|
|
68
103
|
"If scores are defined, there must be a 1:1 pairing with labels."
|
|
69
104
|
)
|
|
70
105
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
106
|
+
@property
|
|
107
|
+
def extrema(self) -> tuple[float, float, float, float]:
|
|
108
|
+
"""
|
|
109
|
+
Returns annotation extrema in the form (xmin, xmax, ymin, ymax).
|
|
110
|
+
"""
|
|
76
111
|
rows, cols = np.nonzero(self.mask)
|
|
77
|
-
return
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
112
|
+
return (cols.min(), cols.max(), rows.min(), rows.max())
|
|
113
|
+
|
|
114
|
+
@property
|
|
115
|
+
def annotation(self) -> NDArray[np.bool_]:
|
|
116
|
+
"""
|
|
117
|
+
Returns the annotation's data representation.
|
|
118
|
+
"""
|
|
119
|
+
return self.mask
|
|
85
120
|
|
|
86
121
|
|
|
87
122
|
@dataclass
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import numpy as np
|
|
2
|
+
import shapely
|
|
2
3
|
from numpy.typing import NDArray
|
|
3
4
|
|
|
4
5
|
|
|
5
|
-
def compute_bbox_iou(data: NDArray[np.
|
|
6
|
+
def compute_bbox_iou(data: NDArray[np.float64]) -> NDArray[np.float64]:
|
|
6
7
|
"""
|
|
7
8
|
Computes intersection-over-union (IoU) for axis-aligned bounding boxes.
|
|
8
9
|
|
|
@@ -23,26 +24,30 @@ def compute_bbox_iou(data: NDArray[np.floating]) -> NDArray[np.floating]:
|
|
|
23
24
|
|
|
24
25
|
Parameters
|
|
25
26
|
----------
|
|
26
|
-
data : NDArray[np.
|
|
27
|
+
data : NDArray[np.float64]
|
|
27
28
|
A sorted array of bounding box pairs.
|
|
28
29
|
|
|
29
30
|
Returns
|
|
30
31
|
-------
|
|
31
|
-
NDArray[np.
|
|
32
|
+
NDArray[np.float64]
|
|
32
33
|
Computed IoU's.
|
|
33
34
|
"""
|
|
35
|
+
if data.size == 0:
|
|
36
|
+
return np.array([], dtype=np.float64)
|
|
37
|
+
|
|
38
|
+
n_pairs = data.shape[0]
|
|
34
39
|
|
|
35
40
|
xmin1, xmax1, ymin1, ymax1 = (
|
|
36
|
-
data[:, 0],
|
|
37
|
-
data[:, 1],
|
|
38
|
-
data[:, 2],
|
|
39
|
-
data[:, 3],
|
|
41
|
+
data[:, 0, 0],
|
|
42
|
+
data[:, 0, 1],
|
|
43
|
+
data[:, 0, 2],
|
|
44
|
+
data[:, 0, 3],
|
|
40
45
|
)
|
|
41
46
|
xmin2, xmax2, ymin2, ymax2 = (
|
|
42
|
-
data[:,
|
|
43
|
-
data[:,
|
|
44
|
-
data[:,
|
|
45
|
-
data[:,
|
|
47
|
+
data[:, 1, 0],
|
|
48
|
+
data[:, 1, 1],
|
|
49
|
+
data[:, 1, 2],
|
|
50
|
+
data[:, 1, 3],
|
|
46
51
|
)
|
|
47
52
|
|
|
48
53
|
xmin = np.maximum(xmin1, xmin2)
|
|
@@ -59,15 +64,17 @@ def compute_bbox_iou(data: NDArray[np.floating]) -> NDArray[np.floating]:
|
|
|
59
64
|
|
|
60
65
|
union_area = area1 + area2 - intersection_area
|
|
61
66
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
ious = np.zeros(n_pairs, dtype=np.float64)
|
|
68
|
+
np.divide(
|
|
69
|
+
intersection_area,
|
|
70
|
+
union_area,
|
|
71
|
+
where=union_area >= 1e-9,
|
|
72
|
+
out=ious,
|
|
66
73
|
)
|
|
67
|
-
return
|
|
74
|
+
return ious
|
|
68
75
|
|
|
69
76
|
|
|
70
|
-
def compute_bitmask_iou(data: NDArray[np.
|
|
77
|
+
def compute_bitmask_iou(data: NDArray[np.bool_]) -> NDArray[np.float64]:
|
|
71
78
|
"""
|
|
72
79
|
Computes intersection-over-union (IoU) for bitmasks.
|
|
73
80
|
|
|
@@ -82,23 +89,41 @@ def compute_bitmask_iou(data: NDArray[np.floating]) -> NDArray[np.floating]:
|
|
|
82
89
|
|
|
83
90
|
Parameters
|
|
84
91
|
----------
|
|
85
|
-
data : NDArray[np.
|
|
92
|
+
data : NDArray[np.float64]
|
|
86
93
|
A sorted array of bitmask pairs.
|
|
87
94
|
|
|
88
95
|
Returns
|
|
89
96
|
-------
|
|
90
|
-
NDArray[np.
|
|
97
|
+
NDArray[np.float64]
|
|
91
98
|
Computed IoU's.
|
|
92
99
|
"""
|
|
93
|
-
intersection_ = np.array([np.logical_and(x, y).sum() for x, y in data])
|
|
94
|
-
union_ = np.array([np.logical_or(x, y).sum() for x, y in data])
|
|
95
100
|
|
|
96
|
-
|
|
101
|
+
if data.size == 0:
|
|
102
|
+
return np.array([], dtype=np.float64)
|
|
103
|
+
|
|
104
|
+
n_pairs = data.shape[0]
|
|
105
|
+
lhs = data[:, 0, :, :].reshape(n_pairs, -1)
|
|
106
|
+
rhs = data[:, 1, :, :].reshape(n_pairs, -1)
|
|
107
|
+
|
|
108
|
+
lhs_sum = lhs.sum(axis=1)
|
|
109
|
+
rhs_sum = rhs.sum(axis=1)
|
|
110
|
+
|
|
111
|
+
intersection_ = np.logical_and(lhs, rhs).sum(axis=1)
|
|
112
|
+
union_ = lhs_sum + rhs_sum - intersection_
|
|
113
|
+
|
|
114
|
+
ious = np.zeros(n_pairs, dtype=np.float64)
|
|
115
|
+
np.divide(
|
|
116
|
+
intersection_,
|
|
117
|
+
union_,
|
|
118
|
+
where=union_ >= 1e-9,
|
|
119
|
+
out=ious,
|
|
120
|
+
)
|
|
121
|
+
return ious
|
|
97
122
|
|
|
98
123
|
|
|
99
124
|
def compute_polygon_iou(
|
|
100
|
-
data: NDArray[np.
|
|
101
|
-
) -> NDArray[np.
|
|
125
|
+
data: NDArray[np.float64],
|
|
126
|
+
) -> NDArray[np.float64]:
|
|
102
127
|
"""
|
|
103
128
|
Computes intersection-over-union (IoU) for shapely polygons.
|
|
104
129
|
|
|
@@ -113,31 +138,43 @@ def compute_polygon_iou(
|
|
|
113
138
|
|
|
114
139
|
Parameters
|
|
115
140
|
----------
|
|
116
|
-
data : NDArray[np.
|
|
141
|
+
data : NDArray[np.float64]
|
|
117
142
|
A sorted array of polygon pairs.
|
|
118
143
|
|
|
119
144
|
Returns
|
|
120
145
|
-------
|
|
121
|
-
NDArray[np.
|
|
146
|
+
NDArray[np.float64]
|
|
122
147
|
Computed IoU's.
|
|
123
148
|
"""
|
|
124
|
-
intersection_ = np.array(
|
|
125
|
-
[poly1.intersection(poly2).area for poly1, poly2 in data]
|
|
126
|
-
)
|
|
127
|
-
union_ = np.array(
|
|
128
|
-
[
|
|
129
|
-
poly1.area + poly2.area - intersection_[i]
|
|
130
|
-
for i, (poly1, poly2) in enumerate(data)
|
|
131
|
-
]
|
|
132
|
-
)
|
|
133
149
|
|
|
134
|
-
|
|
150
|
+
if data.size == 0:
|
|
151
|
+
return np.array([], dtype=np.float64)
|
|
152
|
+
|
|
153
|
+
n_pairs = data.shape[0]
|
|
154
|
+
|
|
155
|
+
lhs = data[:, 0]
|
|
156
|
+
rhs = data[:, 1]
|
|
157
|
+
|
|
158
|
+
intersections = shapely.intersection(lhs, rhs)
|
|
159
|
+
intersection_areas = shapely.area(intersections)
|
|
160
|
+
|
|
161
|
+
unions = shapely.union(lhs, rhs)
|
|
162
|
+
union_areas = shapely.area(unions)
|
|
163
|
+
|
|
164
|
+
ious = np.zeros(n_pairs, dtype=np.float64)
|
|
165
|
+
np.divide(
|
|
166
|
+
intersection_areas,
|
|
167
|
+
union_areas,
|
|
168
|
+
where=union_areas >= 1e-9,
|
|
169
|
+
out=ious,
|
|
170
|
+
)
|
|
171
|
+
return ious
|
|
135
172
|
|
|
136
173
|
|
|
137
174
|
def _compute_ranked_pairs_for_datum(
|
|
138
|
-
data: NDArray[np.
|
|
175
|
+
data: NDArray[np.float64],
|
|
139
176
|
label_metadata: NDArray[np.int32],
|
|
140
|
-
) -> NDArray[np.
|
|
177
|
+
) -> NDArray[np.float64]:
|
|
141
178
|
"""
|
|
142
179
|
Computes ranked pairs for a datum.
|
|
143
180
|
"""
|
|
@@ -177,9 +214,9 @@ def _compute_ranked_pairs_for_datum(
|
|
|
177
214
|
|
|
178
215
|
|
|
179
216
|
def compute_ranked_pairs(
|
|
180
|
-
data: list[NDArray[np.
|
|
217
|
+
data: list[NDArray[np.float64]],
|
|
181
218
|
label_metadata: NDArray[np.int32],
|
|
182
|
-
) -> NDArray[np.
|
|
219
|
+
) -> NDArray[np.float64]:
|
|
183
220
|
"""
|
|
184
221
|
Performs pair ranking on input data.
|
|
185
222
|
|
|
@@ -197,14 +234,14 @@ def compute_ranked_pairs(
|
|
|
197
234
|
|
|
198
235
|
Parameters
|
|
199
236
|
----------
|
|
200
|
-
data : NDArray[np.
|
|
237
|
+
data : NDArray[np.float64]
|
|
201
238
|
A sorted array summarizing the IOU calculations of one or more pairs.
|
|
202
239
|
label_metadata : NDArray[np.int32]
|
|
203
240
|
An array containing metadata related to labels.
|
|
204
241
|
|
|
205
242
|
Returns
|
|
206
243
|
-------
|
|
207
|
-
NDArray[np.
|
|
244
|
+
NDArray[np.float64]
|
|
208
245
|
A filtered array containing only ranked pairs.
|
|
209
246
|
"""
|
|
210
247
|
|
|
@@ -226,25 +263,25 @@ def compute_ranked_pairs(
|
|
|
226
263
|
|
|
227
264
|
|
|
228
265
|
def compute_metrics(
|
|
229
|
-
data: NDArray[np.
|
|
266
|
+
data: NDArray[np.float64],
|
|
230
267
|
label_metadata: NDArray[np.int32],
|
|
231
|
-
iou_thresholds: NDArray[np.
|
|
232
|
-
score_thresholds: NDArray[np.
|
|
268
|
+
iou_thresholds: NDArray[np.float64],
|
|
269
|
+
score_thresholds: NDArray[np.float64],
|
|
233
270
|
) -> tuple[
|
|
234
271
|
tuple[
|
|
235
|
-
NDArray[np.
|
|
236
|
-
NDArray[np.
|
|
237
|
-
NDArray[np.
|
|
238
|
-
|
|
272
|
+
NDArray[np.float64],
|
|
273
|
+
NDArray[np.float64],
|
|
274
|
+
NDArray[np.float64],
|
|
275
|
+
float,
|
|
239
276
|
],
|
|
240
277
|
tuple[
|
|
241
|
-
NDArray[np.
|
|
242
|
-
NDArray[np.
|
|
243
|
-
NDArray[np.
|
|
244
|
-
|
|
278
|
+
NDArray[np.float64],
|
|
279
|
+
NDArray[np.float64],
|
|
280
|
+
NDArray[np.float64],
|
|
281
|
+
float,
|
|
245
282
|
],
|
|
246
|
-
NDArray[np.
|
|
247
|
-
NDArray[np.
|
|
283
|
+
NDArray[np.float64],
|
|
284
|
+
NDArray[np.float64],
|
|
248
285
|
]:
|
|
249
286
|
"""
|
|
250
287
|
Computes Object Detection metrics.
|
|
@@ -261,20 +298,20 @@ def compute_metrics(
|
|
|
261
298
|
|
|
262
299
|
Parameters
|
|
263
300
|
----------
|
|
264
|
-
data : NDArray[np.
|
|
301
|
+
data : NDArray[np.float64]
|
|
265
302
|
A sorted array summarizing the IOU calculations of one or more pairs.
|
|
266
303
|
label_metadata : NDArray[np.int32]
|
|
267
304
|
An array containing metadata related to labels.
|
|
268
|
-
iou_thresholds : NDArray[np.
|
|
305
|
+
iou_thresholds : NDArray[np.float64]
|
|
269
306
|
A 1-D array containing IoU thresholds.
|
|
270
|
-
score_thresholds : NDArray[np.
|
|
307
|
+
score_thresholds : NDArray[np.float64]
|
|
271
308
|
A 1-D array containing score thresholds.
|
|
272
309
|
|
|
273
310
|
Returns
|
|
274
311
|
-------
|
|
275
|
-
tuple[NDArray, NDArray, NDArray
|
|
312
|
+
tuple[NDArray, NDArray, NDArray, float]
|
|
276
313
|
Average Precision results.
|
|
277
|
-
tuple[NDArray, NDArray, NDArray
|
|
314
|
+
tuple[NDArray, NDArray, NDArray, float]
|
|
278
315
|
Average Recall results.
|
|
279
316
|
np.ndarray
|
|
280
317
|
Precision, Recall, TP, FP, FN, F1 Score, Accuracy.
|
|
@@ -287,6 +324,11 @@ def compute_metrics(
|
|
|
287
324
|
n_ious = iou_thresholds.shape[0]
|
|
288
325
|
n_scores = score_thresholds.shape[0]
|
|
289
326
|
|
|
327
|
+
if n_ious == 0:
|
|
328
|
+
raise ValueError("At least one IoU threshold must be passed.")
|
|
329
|
+
elif n_scores == 0:
|
|
330
|
+
raise ValueError("At least one score threshold must be passed.")
|
|
331
|
+
|
|
290
332
|
average_precision = np.zeros((n_ious, n_labels))
|
|
291
333
|
average_recall = np.zeros((n_scores, n_labels))
|
|
292
334
|
counts = np.zeros((n_ious, n_scores, n_labels, 7))
|
|
@@ -450,26 +492,23 @@ def compute_metrics(
|
|
|
450
492
|
average_precision = average_precision / 101.0
|
|
451
493
|
|
|
452
494
|
# calculate average recall
|
|
453
|
-
average_recall
|
|
495
|
+
average_recall = average_recall / n_ious
|
|
454
496
|
|
|
455
497
|
# calculate mAP and mAR
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
mAR[:, key_idx] = average_recall[:, labels].mean(axis=1)
|
|
465
|
-
|
|
466
|
-
# calculate AP and mAP averaged over iou thresholds
|
|
498
|
+
if unique_pd_labels.size > 0:
|
|
499
|
+
mAP = average_precision[:, unique_pd_labels].mean(axis=1)
|
|
500
|
+
mAR = average_recall[:, unique_pd_labels].mean(axis=1)
|
|
501
|
+
else:
|
|
502
|
+
mAP = np.zeros(n_ious, dtype=np.float64)
|
|
503
|
+
mAR = np.zeros(n_scores, dtype=np.float64)
|
|
504
|
+
|
|
505
|
+
# calculate AR and AR averaged over thresholds
|
|
467
506
|
APAveragedOverIoUs = average_precision.mean(axis=0)
|
|
468
|
-
|
|
507
|
+
ARAveragedOverScores = average_recall.mean(axis=0)
|
|
469
508
|
|
|
470
|
-
# calculate
|
|
471
|
-
|
|
472
|
-
|
|
509
|
+
# calculate mAP and mAR averaged over thresholds
|
|
510
|
+
mAPAveragedOverIoUs = mAP.mean(axis=0)
|
|
511
|
+
mARAveragedOverScores = mAR.mean(axis=0)
|
|
473
512
|
|
|
474
513
|
ap_results = (
|
|
475
514
|
average_precision,
|
|
@@ -480,8 +519,8 @@ def compute_metrics(
|
|
|
480
519
|
ar_results = (
|
|
481
520
|
average_recall,
|
|
482
521
|
mAR,
|
|
483
|
-
|
|
484
|
-
|
|
522
|
+
ARAveragedOverScores,
|
|
523
|
+
mARAveragedOverScores,
|
|
485
524
|
)
|
|
486
525
|
|
|
487
526
|
return (
|
|
@@ -493,16 +532,16 @@ def compute_metrics(
|
|
|
493
532
|
|
|
494
533
|
|
|
495
534
|
def _count_with_examples(
|
|
496
|
-
data: NDArray[np.
|
|
535
|
+
data: NDArray[np.float64],
|
|
497
536
|
unique_idx: int | list[int],
|
|
498
537
|
label_idx: int | list[int],
|
|
499
|
-
) -> tuple[NDArray[np.
|
|
538
|
+
) -> tuple[NDArray[np.float64], NDArray[np.int32], NDArray[np.int32]]:
|
|
500
539
|
"""
|
|
501
540
|
Helper function for counting occurences of unique detailed pairs.
|
|
502
541
|
|
|
503
542
|
Parameters
|
|
504
543
|
----------
|
|
505
|
-
data : NDArray[np.
|
|
544
|
+
data : NDArray[np.float64]
|
|
506
545
|
A masked portion of a detailed pairs array.
|
|
507
546
|
unique_idx : int | list[int]
|
|
508
547
|
The index or indices upon which uniqueness is constrained.
|
|
@@ -511,7 +550,7 @@ def _count_with_examples(
|
|
|
511
550
|
|
|
512
551
|
Returns
|
|
513
552
|
-------
|
|
514
|
-
NDArray[np.
|
|
553
|
+
NDArray[np.float64]
|
|
515
554
|
Examples drawn from the data input.
|
|
516
555
|
NDArray[np.int32]
|
|
517
556
|
Unique label indices.
|
|
@@ -531,13 +570,12 @@ def _count_with_examples(
|
|
|
531
570
|
|
|
532
571
|
|
|
533
572
|
def compute_confusion_matrix(
|
|
534
|
-
data: NDArray[np.
|
|
573
|
+
data: NDArray[np.float64],
|
|
535
574
|
label_metadata: NDArray[np.int32],
|
|
536
|
-
iou_thresholds: NDArray[np.
|
|
537
|
-
score_thresholds: NDArray[np.
|
|
575
|
+
iou_thresholds: NDArray[np.float64],
|
|
576
|
+
score_thresholds: NDArray[np.float64],
|
|
538
577
|
n_examples: int,
|
|
539
|
-
) -> tuple[NDArray[np.
|
|
540
|
-
|
|
578
|
+
) -> tuple[NDArray[np.float64], NDArray[np.float64], NDArray[np.int32]]:
|
|
541
579
|
"""
|
|
542
580
|
Compute detailed counts.
|
|
543
581
|
|
|
@@ -553,22 +591,22 @@ def compute_confusion_matrix(
|
|
|
553
591
|
|
|
554
592
|
Parameters
|
|
555
593
|
----------
|
|
556
|
-
data : NDArray[np.
|
|
594
|
+
data : NDArray[np.float64]
|
|
557
595
|
A sorted array summarizing the IOU calculations of one or more pairs.
|
|
558
596
|
label_metadata : NDArray[np.int32]
|
|
559
597
|
An array containing metadata related to labels.
|
|
560
|
-
iou_thresholds : NDArray[np.
|
|
598
|
+
iou_thresholds : NDArray[np.float64]
|
|
561
599
|
A 1-D array containing IoU thresholds.
|
|
562
|
-
score_thresholds : NDArray[np.
|
|
600
|
+
score_thresholds : NDArray[np.float64]
|
|
563
601
|
A 1-D array containing score thresholds.
|
|
564
602
|
n_examples : int
|
|
565
603
|
The maximum number of examples to return per count.
|
|
566
604
|
|
|
567
605
|
Returns
|
|
568
606
|
-------
|
|
569
|
-
NDArray[np.
|
|
607
|
+
NDArray[np.float64]
|
|
570
608
|
Confusion matrix.
|
|
571
|
-
NDArray[np.
|
|
609
|
+
NDArray[np.float64]
|
|
572
610
|
Hallucinations.
|
|
573
611
|
NDArray[np.int32]
|
|
574
612
|
Missing Predictions.
|