valor-lite 0.33.12__py3-none-any.whl → 0.33.14__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.

Potentially problematic release.


This version of valor-lite might be problematic. Click here for more details.

@@ -16,27 +16,14 @@ from valor_lite.object_detection.computation import (
16
16
  compute_bbox_iou,
17
17
  compute_bitmask_iou,
18
18
  compute_confusion_matrix,
19
- compute_metrics,
20
19
  compute_polygon_iou,
20
+ compute_precion_recall,
21
21
  compute_ranked_pairs,
22
22
  )
23
- from valor_lite.object_detection.metric import (
24
- AP,
25
- AR,
26
- F1,
27
- Accuracy,
28
- APAveragedOverIOUs,
29
- ARAveragedOverScores,
30
- ConfusionMatrix,
31
- Counts,
32
- MetricType,
33
- Precision,
34
- PrecisionRecallCurve,
35
- Recall,
36
- mAP,
37
- mAPAveragedOverIOUs,
38
- mAR,
39
- mARAveragedOverScores,
23
+ from valor_lite.object_detection.metric import Metric, MetricType
24
+ from valor_lite.object_detection.utilities import (
25
+ unpack_confusion_matrix_into_metric_list,
26
+ unpack_precision_recall_into_metric_lists,
40
27
  )
41
28
 
42
29
  """
@@ -212,274 +199,23 @@ class Evaluator:
212
199
  label_metadata=label_metadata,
213
200
  )
214
201
 
215
- def _convert_example_to_dict(
216
- self, box: NDArray[np.float16]
217
- ) -> dict[str, float]:
218
- """
219
- Converts a cached bounding box example to dictionary format.
220
- """
221
- return {
222
- "xmin": float(box[0]),
223
- "xmax": float(box[1]),
224
- "ymin": float(box[2]),
225
- "ymax": float(box[3]),
226
- }
227
-
228
- def _unpack_confusion_matrix(
229
- self,
230
- confusion_matrix: NDArray[np.float64],
231
- number_of_labels: int,
232
- number_of_examples: int,
233
- ) -> dict[
234
- str,
235
- dict[
236
- str,
237
- dict[
238
- str,
239
- int
240
- | list[
241
- dict[
242
- str,
243
- str | dict[str, float] | float,
244
- ]
245
- ],
246
- ],
247
- ],
248
- ]:
249
- """
250
- Unpacks a numpy array of confusion matrix counts and examples.
251
- """
252
-
253
- datum_idx = lambda gt_label_idx, pd_label_idx, example_idx: int( # noqa: E731 - lambda fn
254
- confusion_matrix[
255
- gt_label_idx,
256
- pd_label_idx,
257
- example_idx * 4 + 1,
258
- ]
259
- )
260
-
261
- groundtruth_idx = lambda gt_label_idx, pd_label_idx, example_idx: int( # noqa: E731 - lambda fn
262
- confusion_matrix[
263
- gt_label_idx,
264
- pd_label_idx,
265
- example_idx * 4 + 2,
266
- ]
267
- )
268
-
269
- prediction_idx = lambda gt_label_idx, pd_label_idx, example_idx: int( # noqa: E731 - lambda fn
270
- confusion_matrix[
271
- gt_label_idx,
272
- pd_label_idx,
273
- example_idx * 4 + 3,
274
- ]
275
- )
276
-
277
- score_idx = lambda gt_label_idx, pd_label_idx, example_idx: float( # noqa: E731 - lambda fn
278
- confusion_matrix[
279
- gt_label_idx,
280
- pd_label_idx,
281
- example_idx * 4 + 4,
282
- ]
283
- )
284
-
285
- return {
286
- self.index_to_label[gt_label_idx]: {
287
- self.index_to_label[pd_label_idx]: {
288
- "count": max(
289
- int(confusion_matrix[gt_label_idx, pd_label_idx, 0]),
290
- 0,
291
- ),
292
- "examples": [
293
- {
294
- "datum": self.index_to_uid[
295
- datum_idx(
296
- gt_label_idx, pd_label_idx, example_idx
297
- )
298
- ],
299
- "groundtruth": self._convert_example_to_dict(
300
- self.groundtruth_examples[
301
- datum_idx(
302
- gt_label_idx,
303
- pd_label_idx,
304
- example_idx,
305
- )
306
- ][
307
- groundtruth_idx(
308
- gt_label_idx,
309
- pd_label_idx,
310
- example_idx,
311
- )
312
- ]
313
- ),
314
- "prediction": self._convert_example_to_dict(
315
- self.prediction_examples[
316
- datum_idx(
317
- gt_label_idx,
318
- pd_label_idx,
319
- example_idx,
320
- )
321
- ][
322
- prediction_idx(
323
- gt_label_idx,
324
- pd_label_idx,
325
- example_idx,
326
- )
327
- ]
328
- ),
329
- "score": score_idx(
330
- gt_label_idx, pd_label_idx, example_idx
331
- ),
332
- }
333
- for example_idx in range(number_of_examples)
334
- if datum_idx(gt_label_idx, pd_label_idx, example_idx)
335
- >= 0
336
- ],
337
- }
338
- for pd_label_idx in range(number_of_labels)
339
- }
340
- for gt_label_idx in range(number_of_labels)
341
- }
342
-
343
- def _unpack_hallucinations(
344
- self,
345
- hallucinations: NDArray[np.float64],
346
- number_of_labels: int,
347
- number_of_examples: int,
348
- ) -> dict[
349
- str,
350
- dict[
351
- str,
352
- int | list[dict[str, str | float | dict[str, float]]],
353
- ],
354
- ]:
355
- """
356
- Unpacks a numpy array of hallucination counts and examples.
357
- """
358
-
359
- datum_idx = (
360
- lambda pd_label_idx, example_idx: int( # noqa: E731 - lambda fn
361
- hallucinations[
362
- pd_label_idx,
363
- example_idx * 3 + 1,
364
- ]
365
- )
366
- )
367
-
368
- prediction_idx = (
369
- lambda pd_label_idx, example_idx: int( # noqa: E731 - lambda fn
370
- hallucinations[
371
- pd_label_idx,
372
- example_idx * 3 + 2,
373
- ]
374
- )
375
- )
376
-
377
- score_idx = (
378
- lambda pd_label_idx, example_idx: float( # noqa: E731 - lambda fn
379
- hallucinations[
380
- pd_label_idx,
381
- example_idx * 3 + 3,
382
- ]
383
- )
384
- )
385
-
386
- return {
387
- self.index_to_label[pd_label_idx]: {
388
- "count": max(
389
- int(hallucinations[pd_label_idx, 0]),
390
- 0,
391
- ),
392
- "examples": [
393
- {
394
- "datum": self.index_to_uid[
395
- datum_idx(pd_label_idx, example_idx)
396
- ],
397
- "prediction": self._convert_example_to_dict(
398
- self.prediction_examples[
399
- datum_idx(pd_label_idx, example_idx)
400
- ][prediction_idx(pd_label_idx, example_idx)]
401
- ),
402
- "score": score_idx(pd_label_idx, example_idx),
403
- }
404
- for example_idx in range(number_of_examples)
405
- if datum_idx(pd_label_idx, example_idx) >= 0
406
- ],
407
- }
408
- for pd_label_idx in range(number_of_labels)
409
- }
410
-
411
- def _unpack_missing_predictions(
412
- self,
413
- missing_predictions: NDArray[np.int32],
414
- number_of_labels: int,
415
- number_of_examples: int,
416
- ) -> dict[str, dict[str, int | list[dict[str, str | dict[str, float]]]]]:
417
- """
418
- Unpacks a numpy array of missing prediction counts and examples.
419
- """
420
-
421
- datum_idx = (
422
- lambda gt_label_idx, example_idx: int( # noqa: E731 - lambda fn
423
- missing_predictions[
424
- gt_label_idx,
425
- example_idx * 2 + 1,
426
- ]
427
- )
428
- )
429
-
430
- groundtruth_idx = (
431
- lambda gt_label_idx, example_idx: int( # noqa: E731 - lambda fn
432
- missing_predictions[
433
- gt_label_idx,
434
- example_idx * 2 + 2,
435
- ]
436
- )
437
- )
438
-
439
- return {
440
- self.index_to_label[gt_label_idx]: {
441
- "count": max(
442
- int(missing_predictions[gt_label_idx, 0]),
443
- 0,
444
- ),
445
- "examples": [
446
- {
447
- "datum": self.index_to_uid[
448
- datum_idx(gt_label_idx, example_idx)
449
- ],
450
- "groundtruth": self._convert_example_to_dict(
451
- self.groundtruth_examples[
452
- datum_idx(gt_label_idx, example_idx)
453
- ][groundtruth_idx(gt_label_idx, example_idx)]
454
- ),
455
- }
456
- for example_idx in range(number_of_examples)
457
- if datum_idx(gt_label_idx, example_idx) >= 0
458
- ],
459
- }
460
- for gt_label_idx in range(number_of_labels)
461
- }
462
-
463
202
  def compute_precision_recall(
464
203
  self,
465
204
  iou_thresholds: list[float] = [0.5, 0.75, 0.9],
466
205
  score_thresholds: list[float] = [0.5],
467
206
  filter_: Filter | None = None,
468
- as_dict: bool = False,
469
- ) -> dict[MetricType, list]:
207
+ ) -> dict[MetricType, list[Metric]]:
470
208
  """
471
209
  Computes all metrics except for ConfusionMatrix
472
210
 
473
211
  Parameters
474
212
  ----------
475
213
  iou_thresholds : list[float]
476
- A list of IoU thresholds to compute metrics over.
214
+ A list of IOU thresholds to compute metrics over.
477
215
  score_thresholds : list[float]
478
216
  A list of score thresholds to compute metrics over.
479
217
  filter_ : Filter, optional
480
218
  An optional filter object.
481
- as_dict : bool, default=False
482
- An option to return metrics as dictionaries.
483
219
 
484
220
  Returns
485
221
  -------
@@ -493,177 +229,20 @@ class Evaluator:
493
229
  ranked_pairs = ranked_pairs[filter_.ranked_indices]
494
230
  label_metadata = filter_.label_metadata
495
231
 
496
- (
497
- (
498
- average_precision,
499
- mean_average_precision,
500
- average_precision_average_over_ious,
501
- mean_average_precision_average_over_ious,
502
- ),
503
- (
504
- average_recall,
505
- mean_average_recall,
506
- average_recall_averaged_over_scores,
507
- mean_average_recall_averaged_over_scores,
508
- ),
509
- precision_recall,
510
- pr_curves,
511
- ) = compute_metrics(
232
+ results = compute_precion_recall(
512
233
  data=ranked_pairs,
513
234
  label_metadata=label_metadata,
514
235
  iou_thresholds=np.array(iou_thresholds),
515
236
  score_thresholds=np.array(score_thresholds),
516
237
  )
517
238
 
518
- metrics = defaultdict(list)
519
-
520
- metrics[MetricType.AP] = [
521
- AP(
522
- value=float(average_precision[iou_idx][label_idx]),
523
- iou_threshold=iou_thresholds[iou_idx],
524
- label=self.index_to_label[label_idx],
525
- )
526
- for iou_idx in range(average_precision.shape[0])
527
- for label_idx in range(average_precision.shape[1])
528
- if int(label_metadata[label_idx, 0]) > 0
529
- ]
530
-
531
- metrics[MetricType.mAP] = [
532
- mAP(
533
- value=float(mean_average_precision[iou_idx]),
534
- iou_threshold=iou_thresholds[iou_idx],
535
- )
536
- for iou_idx in range(mean_average_precision.shape[0])
537
- ]
538
-
539
- metrics[MetricType.APAveragedOverIOUs] = [
540
- APAveragedOverIOUs(
541
- value=float(average_precision_average_over_ious[label_idx]),
542
- iou_thresholds=iou_thresholds,
543
- label=self.index_to_label[label_idx],
544
- )
545
- for label_idx in range(self.n_labels)
546
- if int(label_metadata[label_idx, 0]) > 0
547
- ]
548
-
549
- metrics[MetricType.mAPAveragedOverIOUs] = [
550
- mAPAveragedOverIOUs(
551
- value=float(mean_average_precision_average_over_ious),
552
- iou_thresholds=iou_thresholds,
553
- )
554
- ]
555
-
556
- metrics[MetricType.AR] = [
557
- AR(
558
- value=float(average_recall[score_idx][label_idx]),
559
- iou_thresholds=iou_thresholds,
560
- score_threshold=score_thresholds[score_idx],
561
- label=self.index_to_label[label_idx],
562
- )
563
- for score_idx in range(average_recall.shape[0])
564
- for label_idx in range(average_recall.shape[1])
565
- if int(label_metadata[label_idx, 0]) > 0
566
- ]
567
-
568
- metrics[MetricType.mAR] = [
569
- mAR(
570
- value=float(mean_average_recall[score_idx]),
571
- iou_thresholds=iou_thresholds,
572
- score_threshold=score_thresholds[score_idx],
573
- )
574
- for score_idx in range(mean_average_recall.shape[0])
575
- ]
576
-
577
- metrics[MetricType.ARAveragedOverScores] = [
578
- ARAveragedOverScores(
579
- value=float(average_recall_averaged_over_scores[label_idx]),
580
- score_thresholds=score_thresholds,
581
- iou_thresholds=iou_thresholds,
582
- label=self.index_to_label[label_idx],
583
- )
584
- for label_idx in range(self.n_labels)
585
- if int(label_metadata[label_idx, 0]) > 0
586
- ]
587
-
588
- metrics[MetricType.mARAveragedOverScores] = [
589
- mARAveragedOverScores(
590
- value=float(mean_average_recall_averaged_over_scores),
591
- score_thresholds=score_thresholds,
592
- iou_thresholds=iou_thresholds,
593
- )
594
- ]
595
-
596
- metrics[MetricType.PrecisionRecallCurve] = [
597
- PrecisionRecallCurve(
598
- precisions=pr_curves[iou_idx, label_idx, :, 0]
599
- .astype(float)
600
- .tolist(),
601
- scores=pr_curves[iou_idx, label_idx, :, 1]
602
- .astype(float)
603
- .tolist(),
604
- iou_threshold=iou_threshold,
605
- label=label,
606
- )
607
- for iou_idx, iou_threshold in enumerate(iou_thresholds)
608
- for label_idx, label in self.index_to_label.items()
609
- if int(label_metadata[label_idx, 0]) > 0
610
- ]
611
-
612
- for label_idx, label in self.index_to_label.items():
613
-
614
- if label_metadata[label_idx, 0] == 0:
615
- continue
616
-
617
- for score_idx, score_threshold in enumerate(score_thresholds):
618
- for iou_idx, iou_threshold in enumerate(iou_thresholds):
619
-
620
- row = precision_recall[iou_idx][score_idx][label_idx]
621
- kwargs = {
622
- "label": label,
623
- "iou_threshold": iou_threshold,
624
- "score_threshold": score_threshold,
625
- }
626
- metrics[MetricType.Counts].append(
627
- Counts(
628
- tp=int(row[0]),
629
- fp=int(row[1]),
630
- fn=int(row[2]),
631
- **kwargs,
632
- )
633
- )
634
-
635
- metrics[MetricType.Precision].append(
636
- Precision(
637
- value=float(row[3]),
638
- **kwargs,
639
- )
640
- )
641
- metrics[MetricType.Recall].append(
642
- Recall(
643
- value=float(row[4]),
644
- **kwargs,
645
- )
646
- )
647
- metrics[MetricType.F1].append(
648
- F1(
649
- value=float(row[5]),
650
- **kwargs,
651
- )
652
- )
653
- metrics[MetricType.Accuracy].append(
654
- Accuracy(
655
- value=float(row[6]),
656
- **kwargs,
657
- )
658
- )
659
-
660
- if as_dict:
661
- return {
662
- mtype: [metric.to_dict() for metric in mvalues]
663
- for mtype, mvalues in metrics.items()
664
- }
665
-
666
- return metrics
239
+ return unpack_precision_recall_into_metric_lists(
240
+ results=results,
241
+ label_metadata=label_metadata,
242
+ iou_thresholds=iou_thresholds,
243
+ score_thresholds=score_thresholds,
244
+ index_to_label=self.index_to_label,
245
+ )
667
246
 
668
247
  def compute_confusion_matrix(
669
248
  self,
@@ -671,27 +250,24 @@ class Evaluator:
671
250
  score_thresholds: list[float] = [0.5],
672
251
  number_of_examples: int = 0,
673
252
  filter_: Filter | None = None,
674
- as_dict: bool = False,
675
- ) -> list:
253
+ ) -> list[Metric]:
676
254
  """
677
255
  Computes confusion matrices at various thresholds.
678
256
 
679
257
  Parameters
680
258
  ----------
681
259
  iou_thresholds : list[float]
682
- A list of IoU thresholds to compute metrics over.
260
+ A list of IOU thresholds to compute metrics over.
683
261
  score_thresholds : list[float]
684
262
  A list of score thresholds to compute metrics over.
685
263
  number_of_examples : int, default=0
686
264
  Maximum number of annotation examples to return in ConfusionMatrix.
687
265
  filter_ : Filter, optional
688
266
  An optional filter object.
689
- as_dict : bool, default=False
690
- An option to return metrics as dictionaries.
691
267
 
692
268
  Returns
693
269
  -------
694
- list[ConfusionMatrix] | list[dict]
270
+ list[Metric]
695
271
  List of confusion matrices per threshold pair.
696
272
  """
697
273
 
@@ -704,11 +280,7 @@ class Evaluator:
704
280
  if detailed_pairs.size == 0:
705
281
  return list()
706
282
 
707
- (
708
- confusion_matrix,
709
- hallucinations,
710
- missing_predictions,
711
- ) = compute_confusion_matrix(
283
+ results = compute_confusion_matrix(
712
284
  data=detailed_pairs,
713
285
  label_metadata=label_metadata,
714
286
  iou_thresholds=np.array(iou_thresholds),
@@ -716,39 +288,16 @@ class Evaluator:
716
288
  n_examples=number_of_examples,
717
289
  )
718
290
 
719
- n_ious, n_scores, n_labels, _, _ = confusion_matrix.shape
720
- matrices = [
721
- ConfusionMatrix(
722
- iou_threshold=iou_thresholds[iou_idx],
723
- score_threshold=score_thresholds[score_idx],
724
- number_of_examples=number_of_examples,
725
- confusion_matrix=self._unpack_confusion_matrix(
726
- confusion_matrix=confusion_matrix[
727
- iou_idx, score_idx, :, :, :
728
- ],
729
- number_of_labels=n_labels,
730
- number_of_examples=number_of_examples,
731
- ),
732
- hallucinations=self._unpack_hallucinations(
733
- hallucinations=hallucinations[iou_idx, score_idx, :, :],
734
- number_of_labels=n_labels,
735
- number_of_examples=number_of_examples,
736
- ),
737
- missing_predictions=self._unpack_missing_predictions(
738
- missing_predictions=missing_predictions[
739
- iou_idx, score_idx, :, :
740
- ],
741
- number_of_labels=n_labels,
742
- number_of_examples=number_of_examples,
743
- ),
744
- )
745
- for iou_idx in range(n_ious)
746
- for score_idx in range(n_scores)
747
- ]
748
-
749
- if as_dict:
750
- return [m.to_dict() for m in matrices]
751
- return matrices
291
+ return unpack_confusion_matrix_into_metric_list(
292
+ results=results,
293
+ iou_thresholds=iou_thresholds,
294
+ score_thresholds=score_thresholds,
295
+ number_of_examples=number_of_examples,
296
+ index_to_uid=self.index_to_uid,
297
+ index_to_label=self.index_to_label,
298
+ groundtruth_examples=self.groundtruth_examples,
299
+ prediction_examples=self.prediction_examples,
300
+ )
752
301
 
753
302
  def evaluate(
754
303
  self,
@@ -756,43 +305,40 @@ class Evaluator:
756
305
  score_thresholds: list[float] = [0.5],
757
306
  number_of_examples: int = 0,
758
307
  filter_: Filter | None = None,
759
- as_dict: bool = False,
760
- ) -> dict[MetricType, list]:
308
+ ) -> dict[MetricType, list[Metric]]:
761
309
  """
762
310
  Computes all avaiable metrics.
763
311
 
764
312
  Parameters
765
313
  ----------
766
314
  iou_thresholds : list[float]
767
- A list of IoU thresholds to compute metrics over.
315
+ A list of IOU thresholds to compute metrics over.
768
316
  score_thresholds : list[float]
769
317
  A list of score thresholds to compute metrics over.
770
318
  number_of_examples : int, default=0
771
319
  Maximum number of annotation examples to return in ConfusionMatrix.
772
320
  filter_ : Filter, optional
773
321
  An optional filter object.
774
- as_dict : bool, default=False
775
- An option to return metrics as dictionaries.
776
322
 
777
323
  Returns
778
324
  -------
779
- dict[MetricType, list]
780
- A dictionary mapping metric type to a list of metrics.
325
+ dict[MetricType, list[Metric]]
326
+ Lists of metrics organized by metric type.
781
327
  """
782
- results = self.compute_precision_recall(
328
+ metrics = self.compute_precision_recall(
783
329
  iou_thresholds=iou_thresholds,
784
330
  score_thresholds=score_thresholds,
785
331
  filter_=filter_,
786
- as_dict=as_dict,
787
332
  )
788
- results[MetricType.ConfusionMatrix] = self.compute_confusion_matrix(
333
+
334
+ metrics[MetricType.ConfusionMatrix] = self.compute_confusion_matrix(
789
335
  iou_thresholds=iou_thresholds,
790
336
  score_thresholds=score_thresholds,
791
337
  number_of_examples=number_of_examples,
792
338
  filter_=filter_,
793
- as_dict=as_dict,
794
339
  )
795
- return results
340
+
341
+ return metrics
796
342
 
797
343
 
798
344
  class DataLoader: