Spaces:
Running
Running
Commit
·
9cf5bb9
1
Parent(s):
802ca0e
update det-metrics for class-specific computation
Browse files- README.md +7 -2
- det-metrics.py +60 -4
README.md
CHANGED
@@ -61,10 +61,11 @@ results = module.compute()
|
|
61 |
print(results)
|
62 |
```
|
63 |
|
64 |
-
This will output the following dictionary containing metrics for the detection model. The key of the dictionary will be the model name or "custom" if no model names are available like in this case.
|
65 |
|
66 |
```json
|
67 |
{
|
|
|
68 |
"custom": {
|
69 |
"metrics": ...,
|
70 |
"eval": ...,
|
@@ -137,6 +138,7 @@ Customize your evaluation by specifying various parameters when loading SEA-AI/d
|
|
137 |
- **bbox_format**: Set the bounding box format (e.g., `"xywh"`).
|
138 |
- **iou_threshold**: Choose the IOU threshold for determining correct detections.
|
139 |
- **class_agnostic**: Specify whether to calculate metrics disregarding class labels.
|
|
|
140 |
|
141 |
```python
|
142 |
area_ranges_tuples = [
|
@@ -191,6 +193,8 @@ SEA-AI/det-metrics metrics dictionary provides a detailed breakdown of performan
|
|
191 |
- **fpi**: Number of images with predictions but no ground truths.
|
192 |
- **nImgs**: Total number of images evaluated.
|
193 |
|
|
|
|
|
194 |
### Eval
|
195 |
|
196 |
The SEA-AI/det-metrics evaluation dictionary provides details about evaluation metrics and results. Below is a description of each field:
|
@@ -244,7 +248,8 @@ The params return value of the COCO evaluation parameters in PyCOCO represents a
|
|
244 |
- **areaRng**: Object area ranges for evaluation. This parameter defines the sizes of objects to evaluate. It is specified as a list of tuples, where each tuple represents a range of area in square pixels.
|
245 |
- **maxDets**: List of thresholds on maximum detections per image for evaluation. By default, it evaluates with thresholds of 1, 10, and 100 detections per image.
|
246 |
- **iouType**: Type of IoU calculation used for evaluation. It can be ‘segm’ (segmentation), ‘bbox’ (bounding box), or ‘keypoints’.
|
247 |
-
- **
|
|
|
248 |
|
249 |
> Note:
|
250 |
> If useCats=0 category labels are ignored as in proposal scoring.
|
|
|
61 |
print(results)
|
62 |
```
|
63 |
|
64 |
+
This will output the following dictionary containing metrics for the detection model. The key of the dictionary will be the model name or "custom" if no model names are available like in this case. Additionally, there is a single key "classes" which maps the labels to the respective indices of the results. If the results are class agnostic, the value of "classes" is None.
|
65 |
|
66 |
```json
|
67 |
{
|
68 |
+
"classes": ...
|
69 |
"custom": {
|
70 |
"metrics": ...,
|
71 |
"eval": ...,
|
|
|
138 |
- **bbox_format**: Set the bounding box format (e.g., `"xywh"`).
|
139 |
- **iou_threshold**: Choose the IOU threshold for determining correct detections.
|
140 |
- **class_agnostic**: Specify whether to calculate metrics disregarding class labels.
|
141 |
+
- **label_mapping**: Provide an optional mapping of string labels to numeric labels in the form of a dictionary (e.g., `{"SHIP": 0, "BOAT": 1}`). Defaults to a label mapping defined by the SEA.AI label merging map.
|
142 |
|
143 |
```python
|
144 |
area_ranges_tuples = [
|
|
|
193 |
- **fpi**: Number of images with predictions but no ground truths.
|
194 |
- **nImgs**: Total number of images evaluated.
|
195 |
|
196 |
+
If the det-metrics is computed with `class_agnostic=False`, all counts (`tp/fp/fn/duplicates/support/fpi`) and scores (`precision/recall/f1`) are arrays instead of single numbers. For a label mapping of `{"SHIP": 0, "BOAT": 1}`, a exemplary array could be `tp=np.array([10, 4])`, which means there are 10 true positive ships and 4 true positive boats.
|
197 |
+
|
198 |
### Eval
|
199 |
|
200 |
The SEA-AI/det-metrics evaluation dictionary provides details about evaluation metrics and results. Below is a description of each field:
|
|
|
248 |
- **areaRng**: Object area ranges for evaluation. This parameter defines the sizes of objects to evaluate. It is specified as a list of tuples, where each tuple represents a range of area in square pixels.
|
249 |
- **maxDets**: List of thresholds on maximum detections per image for evaluation. By default, it evaluates with thresholds of 1, 10, and 100 detections per image.
|
250 |
- **iouType**: Type of IoU calculation used for evaluation. It can be ‘segm’ (segmentation), ‘bbox’ (bounding box), or ‘keypoints’.
|
251 |
+
- **class_agnostic**: Boolean flag indicating whether to use category labels for evaluation (default is 1, meaning true).
|
252 |
+
- **label_mapping**: Dict of str: int pairs, mapping string labels to numeric labels, so that the payload labels can be mapped to numeric labels (default is a label mapping defined by the class merging structure). Should be provided only if `class_agnostic=False`.
|
253 |
|
254 |
> Note:
|
255 |
> If useCats=0 category labels are ignored as in proposal scoring.
|
det-metrics.py
CHANGED
@@ -13,7 +13,7 @@
|
|
13 |
# limitations under the License.
|
14 |
"""TODO: Add a description here."""
|
15 |
|
16 |
-
from typing import List, Literal, Tuple
|
17 |
|
18 |
import datasets
|
19 |
import evaluate
|
@@ -23,6 +23,43 @@ from seametrics.detection import PrecisionRecallF1Support
|
|
23 |
from seametrics.detection.utils import payload_to_det_metric
|
24 |
from seametrics.payload import Payload
|
25 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
_CITATION = """\
|
27 |
@InProceedings{coco:2020,
|
28 |
title = {Microsoft {COCO:} Common Objects in Context},
|
@@ -124,6 +161,7 @@ class DetectionMetric(evaluate.Metric):
|
|
124 |
bbox_format: str = "xywh",
|
125 |
iou_type: Literal["bbox", "segm"] = "bbox",
|
126 |
payload: Payload = None,
|
|
|
127 |
**kwargs,
|
128 |
):
|
129 |
super().__init__(**kwargs)
|
@@ -136,6 +174,12 @@ class DetectionMetric(evaluate.Metric):
|
|
136 |
self.class_agnostic = class_agnostic
|
137 |
self.iou_type = iou_type
|
138 |
self.bbox_format = bbox_format
|
|
|
|
|
|
|
|
|
|
|
|
|
139 |
|
140 |
# postprocess parameters
|
141 |
self.iou_thresholds = (
|
@@ -143,7 +187,7 @@ class DetectionMetric(evaluate.Metric):
|
|
143 |
)
|
144 |
self.area_ranges = [v for _, v in area_ranges_tuples]
|
145 |
self.area_ranges_labels = [k for k, _ in area_ranges_tuples]
|
146 |
-
|
147 |
# initialize coco_metrics
|
148 |
self.coco_metric = PrecisionRecallF1Support(
|
149 |
iou_thresholds=self.iou_thresholds,
|
@@ -152,6 +196,7 @@ class DetectionMetric(evaluate.Metric):
|
|
152 |
class_agnostic=self.class_agnostic,
|
153 |
iou_type=self.iou_type,
|
154 |
box_format=self.bbox_format,
|
|
|
155 |
)
|
156 |
|
157 |
# initialize evaluation metric
|
@@ -237,6 +282,7 @@ class DetectionMetric(evaluate.Metric):
|
|
237 |
"""Called within the evaluate.Metric.compute() method"""
|
238 |
|
239 |
results = {}
|
|
|
240 |
for model_name in self.model_names:
|
241 |
print(f"\n##### {model_name} #####")
|
242 |
# add payload if available (otherwise predictions and references must be added with add function)
|
@@ -260,7 +306,7 @@ class DetectionMetric(evaluate.Metric):
|
|
260 |
"""Converts the payload to the format expected by the metric"""
|
261 |
# import only if needed since fiftyone is not a direct dependency
|
262 |
|
263 |
-
predictions, references = payload_to_det_metric(payload, model_name)
|
264 |
self.add(prediction=predictions, reference=references)
|
265 |
|
266 |
return self
|
@@ -312,6 +358,11 @@ class DetectionMetric(evaluate.Metric):
|
|
312 |
import plotly.graph_objects as go
|
313 |
from seametrics.detection.utils import get_confidence_metric_vals
|
314 |
|
|
|
|
|
|
|
|
|
|
|
315 |
# Create traces
|
316 |
fig = go.Figure()
|
317 |
metrics = ["precision", "recall", "f1"]
|
@@ -377,6 +428,11 @@ class DetectionMetric(evaluate.Metric):
|
|
377 |
wandb: To interact with the Weights and Biases platform.
|
378 |
datetime: To generate a timestamp for run names.
|
379 |
"""
|
|
|
|
|
|
|
|
|
|
|
380 |
import os
|
381 |
import wandb
|
382 |
import datetime
|
@@ -448,7 +504,7 @@ class DetectionMetric(evaluate.Metric):
|
|
448 |
Note:
|
449 |
- If the metric does not support area ranges, the metric should store the results under the `all` key.
|
450 |
- If a range area is provided it will be displayed in the output. if area_ranges_tuples is None, then all the area ranges will be displayed
|
451 |
-
"""
|
452 |
results = {}
|
453 |
|
454 |
for model_name in payload.models:
|
|
|
13 |
# limitations under the License.
|
14 |
"""TODO: Add a description here."""
|
15 |
|
16 |
+
from typing import List, Literal, Tuple, Dict
|
17 |
|
18 |
import datasets
|
19 |
import evaluate
|
|
|
23 |
from seametrics.detection.utils import payload_to_det_metric
|
24 |
from seametrics.payload import Payload
|
25 |
|
26 |
+
LABEL_MAPPING = {
|
27 |
+
'SHIP': 0,
|
28 |
+
'BATTLE_SHIP': 0,
|
29 |
+
'FISHING_SHIP': 0,
|
30 |
+
'CONTAINER_SHIP': 0,
|
31 |
+
'CRUISE_SHIP': 0,
|
32 |
+
'BOAT_WITHOUT_SAILS': 1,
|
33 |
+
'MOTORBOAT': 1,
|
34 |
+
'MARITIME_VEHICLE': 1,
|
35 |
+
'BOAT': 1,
|
36 |
+
'SAILING_BOAT': 2,
|
37 |
+
'SAILING_BOAT_WITH_CLOSED_SAILS': 2,
|
38 |
+
'SAILING_BOAT_WITH_OPEN_SAILS': 2,
|
39 |
+
'LEISURE_VEHICLE': 3,
|
40 |
+
'WATER_SKI': 3,
|
41 |
+
'BUOY': 4,
|
42 |
+
'CONSTRUCTION': 4,
|
43 |
+
'FISHING_BUOY': 4,
|
44 |
+
'HARBOUR_BUOY': 4,
|
45 |
+
'FLOTSAM': 5,
|
46 |
+
'CONTAINER': 5,
|
47 |
+
'SEA_MINE': 5,
|
48 |
+
'WOODEN_LOG': 5,
|
49 |
+
'UNKNOWN': 5,
|
50 |
+
'HUMAN_IN_WATER': 5,
|
51 |
+
'FAR_AWAY_OBJECT': 6,
|
52 |
+
'MARITIME_ANIMAL': 7,
|
53 |
+
'ANIMAL': 7,
|
54 |
+
'FISH': 7,
|
55 |
+
'DOLPHIN': 7,
|
56 |
+
'MAMMAL': 7,
|
57 |
+
'WHALE': 7,
|
58 |
+
'AERIAL_ANIMAL': 8,
|
59 |
+
'SEAGULL': 8,
|
60 |
+
'BIRD': 8,
|
61 |
+
}
|
62 |
+
|
63 |
_CITATION = """\
|
64 |
@InProceedings{coco:2020,
|
65 |
title = {Microsoft {COCO:} Common Objects in Context},
|
|
|
161 |
bbox_format: str = "xywh",
|
162 |
iou_type: Literal["bbox", "segm"] = "bbox",
|
163 |
payload: Payload = None,
|
164 |
+
label_mapping: Dict[str, int] = None,
|
165 |
**kwargs,
|
166 |
):
|
167 |
super().__init__(**kwargs)
|
|
|
174 |
self.class_agnostic = class_agnostic
|
175 |
self.iou_type = iou_type
|
176 |
self.bbox_format = bbox_format
|
177 |
+
self.label_mapping = LABEL_MAPPING if not self.class_agnostic else None
|
178 |
+
if not class_agnostic:
|
179 |
+
if label_mapping:
|
180 |
+
print("WARNING: overwritting the default label mapping with the \
|
181 |
+
custom label mapping provided via `label_mapping`.")
|
182 |
+
self.label_mapping = label_mapping
|
183 |
|
184 |
# postprocess parameters
|
185 |
self.iou_thresholds = (
|
|
|
187 |
)
|
188 |
self.area_ranges = [v for _, v in area_ranges_tuples]
|
189 |
self.area_ranges_labels = [k for k, _ in area_ranges_tuples]
|
190 |
+
|
191 |
# initialize coco_metrics
|
192 |
self.coco_metric = PrecisionRecallF1Support(
|
193 |
iou_thresholds=self.iou_thresholds,
|
|
|
196 |
class_agnostic=self.class_agnostic,
|
197 |
iou_type=self.iou_type,
|
198 |
box_format=self.bbox_format,
|
199 |
+
labels=sorted(list(set(list(self.label_mapping.values())))) if self.label_mapping else None,
|
200 |
)
|
201 |
|
202 |
# initialize evaluation metric
|
|
|
282 |
"""Called within the evaluate.Metric.compute() method"""
|
283 |
|
284 |
results = {}
|
285 |
+
results["classes"] = self.label_mapping
|
286 |
for model_name in self.model_names:
|
287 |
print(f"\n##### {model_name} #####")
|
288 |
# add payload if available (otherwise predictions and references must be added with add function)
|
|
|
306 |
"""Converts the payload to the format expected by the metric"""
|
307 |
# import only if needed since fiftyone is not a direct dependency
|
308 |
|
309 |
+
predictions, references = payload_to_det_metric(payload, model_name, class_agnostic=self.class_agnostic, label_mapping=self.label_mapping)
|
310 |
self.add(prediction=predictions, reference=references)
|
311 |
|
312 |
return self
|
|
|
358 |
import plotly.graph_objects as go
|
359 |
from seametrics.detection.utils import get_confidence_metric_vals
|
360 |
|
361 |
+
if not self.class_agnostic:
|
362 |
+
raise ValueError(
|
363 |
+
"This method is not yet implemented for `self.class_agnostic=False`."
|
364 |
+
)
|
365 |
+
|
366 |
# Create traces
|
367 |
fig = go.Figure()
|
368 |
metrics = ["precision", "recall", "f1"]
|
|
|
428 |
wandb: To interact with the Weights and Biases platform.
|
429 |
datetime: To generate a timestamp for run names.
|
430 |
"""
|
431 |
+
if not self.class_agnostic:
|
432 |
+
raise ValueError(
|
433 |
+
"This method is not yet implemented for `self.class_agnostic=False`."
|
434 |
+
)
|
435 |
+
|
436 |
import os
|
437 |
import wandb
|
438 |
import datetime
|
|
|
504 |
Note:
|
505 |
- If the metric does not support area ranges, the metric should store the results under the `all` key.
|
506 |
- If a range area is provided it will be displayed in the output. if area_ranges_tuples is None, then all the area ranges will be displayed
|
507 |
+
"""
|
508 |
results = {}
|
509 |
|
510 |
for model_name in payload.models:
|