valor-lite 0.33.10__py3-none-any.whl → 0.33.12__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.
@@ -182,9 +182,9 @@ def compute_metrics(
182
182
  out=precision,
183
183
  )
184
184
 
185
- accuracy = np.zeros_like(recall)
185
+ accuracy = np.zeros(n_scores, dtype=np.float64)
186
186
  np.divide(
187
- (counts[:, :, 0] + counts[:, :, 3]),
187
+ counts[:, :, 0].sum(axis=1),
188
188
  float(n_datums),
189
189
  out=accuracy,
190
190
  )
@@ -367,6 +367,14 @@ class Evaluator:
367
367
  )
368
368
  ]
369
369
 
370
+ metrics[MetricType.Accuracy] = [
371
+ Accuracy(
372
+ value=accuracy.astype(float).tolist(),
373
+ score_thresholds=score_thresholds,
374
+ hardmax=hardmax,
375
+ )
376
+ ]
377
+
370
378
  for label_idx, label in self.index_to_label.items():
371
379
 
372
380
  kwargs = {
@@ -401,12 +409,6 @@ class Evaluator:
401
409
  **kwargs,
402
410
  )
403
411
  )
404
- metrics[MetricType.Accuracy].append(
405
- Accuracy(
406
- value=accuracy[:, label_idx].astype(float).tolist(),
407
- **kwargs,
408
- )
409
- )
410
412
  metrics[MetricType.F1].append(
411
413
  F1(
412
414
  value=f1_score[:, label_idx].astype(float).tolist(),
@@ -158,24 +158,23 @@ class Recall(_ThresholdValue):
158
158
  pass
159
159
 
160
160
 
161
- class Accuracy(_ThresholdValue):
161
+ class F1(_ThresholdValue):
162
162
  """
163
- Accuracy metric for a specific class label.
163
+ F1 score for a specific class label.
164
164
 
165
- This class calculates the accuracy at various score thresholds for a binary
166
- classification task. Accuracy is defined as the ratio of the sum of true positives and
167
- true negatives over all predictions.
165
+ This class calculates the F1 score at various score thresholds for a binary
166
+ classification task.
168
167
 
169
168
  Attributes
170
169
  ----------
171
170
  value : list[float]
172
- Accuracy values computed at each score threshold.
171
+ F1 scores computed at each score threshold.
173
172
  score_thresholds : list[float]
174
- Score thresholds at which the accuracy values are computed.
173
+ Score thresholds at which the F1 scores are computed.
175
174
  hardmax : bool
176
175
  Indicates whether hardmax thresholding was used.
177
176
  label : str
178
- The class label for which the accuracy is computed.
177
+ The class label for which the F1 score is computed.
179
178
 
180
179
  Methods
181
180
  -------
@@ -188,23 +187,21 @@ class Accuracy(_ThresholdValue):
188
187
  pass
189
188
 
190
189
 
191
- class F1(_ThresholdValue):
190
+ @dataclass
191
+ class Accuracy:
192
192
  """
193
- F1 score for a specific class label.
193
+ Multiclass accuracy metric.
194
194
 
195
- This class calculates the F1 score at various score thresholds for a binary
196
- classification task.
195
+ This class calculates the accuracy at various score thresholds.
197
196
 
198
197
  Attributes
199
198
  ----------
200
199
  value : list[float]
201
- F1 scores computed at each score threshold.
200
+ Accuracy values computed at each score threshold.
202
201
  score_thresholds : list[float]
203
- Score thresholds at which the F1 scores are computed.
202
+ Score thresholds at which the accuracy values are computed.
204
203
  hardmax : bool
205
204
  Indicates whether hardmax thresholding was used.
206
- label : str
207
- The class label for which the F1 score is computed.
208
205
 
209
206
  Methods
210
207
  -------
@@ -214,7 +211,22 @@ class F1(_ThresholdValue):
214
211
  Converts the instance to a dictionary representation.
215
212
  """
216
213
 
217
- pass
214
+ value: list[float]
215
+ score_thresholds: list[float]
216
+ hardmax: bool
217
+
218
+ def to_metric(self) -> Metric:
219
+ return Metric(
220
+ type=type(self).__name__,
221
+ value=self.value,
222
+ parameters={
223
+ "score_thresholds": self.score_thresholds,
224
+ "hardmax": self.hardmax,
225
+ },
226
+ )
227
+
228
+ def to_dict(self) -> dict:
229
+ return self.to_metric().to_dict()
218
230
 
219
231
 
220
232
  @dataclass
@@ -184,7 +184,7 @@ def _compute_ranked_pairs_for_datum(
184
184
 
185
185
  # find best fits for prediction
186
186
  mask_label_match = data[:, 4] == data[:, 5]
187
- matched_predicitons = np.unique(data[mask_label_match, 2].astype(int))
187
+ matched_predicitons = np.unique(data[mask_label_match, 2].astype(np.int32))
188
188
  mask_unmatched_predictions = ~np.isin(data[:, 2], matched_predicitons)
189
189
  data = data[mask_label_match | mask_unmatched_predictions]
190
190
 
@@ -333,7 +333,7 @@ def compute_metrics(
333
333
  average_recall = np.zeros((n_scores, n_labels))
334
334
  counts = np.zeros((n_ious, n_scores, n_labels, 7))
335
335
 
336
- pd_labels = data[:, 5].astype(int)
336
+ pd_labels = data[:, 5].astype(np.int32)
337
337
  scores = data[:, 6]
338
338
  unique_pd_labels, unique_pd_indices = np.unique(
339
339
  pd_labels, return_index=True
@@ -383,17 +383,19 @@ def compute_metrics(
383
383
  true_positives_mask[mask_tp_inner] = mask_gt_unique
384
384
 
385
385
  # calculate intermediates
386
- pd_count = np.bincount(pd_labels, minlength=n_labels).astype(float)
386
+ pd_count = np.bincount(pd_labels, minlength=n_labels).astype(
387
+ np.float64
388
+ )
387
389
  tp_count = np.bincount(
388
390
  pd_labels,
389
391
  weights=true_positives_mask,
390
392
  minlength=n_labels,
391
- ).astype(float)
393
+ ).astype(np.float64)
392
394
 
393
395
  fp_count = np.bincount(
394
396
  pd_labels[mask_fp_inner],
395
397
  minlength=n_labels,
396
- ).astype(float)
398
+ ).astype(np.float64)
397
399
 
398
400
  fn_count = np.bincount(
399
401
  pd_labels[mask_fn_inner],
@@ -476,7 +478,7 @@ def compute_metrics(
476
478
  where=running_gt_count > 1e-9,
477
479
  out=recall,
478
480
  )
479
- recall_index = np.floor(recall * 100.0).astype(int)
481
+ recall_index = np.floor(recall * 100.0).astype(np.int32)
480
482
 
481
483
  # bin precision-recall curve
482
484
  pr_curve = np.zeros((n_ious, n_labels, 101, 2))
@@ -582,7 +584,7 @@ def _count_with_examples(
582
584
  Counts for each unique label index.
583
585
  """
584
586
  unique_rows, indices = np.unique(
585
- data.astype(int)[:, unique_idx],
587
+ data.astype(np.int32)[:, unique_idx],
586
588
  return_index=True,
587
589
  axis=0,
588
590
  )
@@ -593,6 +595,35 @@ def _count_with_examples(
593
595
  return examples, labels, counts
594
596
 
595
597
 
598
+ def _isin(
599
+ data: NDArray[np.int32],
600
+ subset: NDArray[np.int32],
601
+ ) -> NDArray[np.bool_]:
602
+ """
603
+ Creates a mask of rows that exist within the subset.
604
+
605
+ Parameters
606
+ ----------
607
+ data : NDArray[np.int32]
608
+ An array with shape (N, 2).
609
+ subset : NDArray[np.int32]
610
+ An array with shape (M, 2) where N >= M.
611
+
612
+ Returns
613
+ -------
614
+ NDArray[np.bool_]
615
+ Returns a bool mask with shape (N,).
616
+ """
617
+ combined_data = (data[:, 0].astype(np.int64) << 32) | data[:, 1].astype(
618
+ np.uint32
619
+ )
620
+ combined_subset = (subset[:, 0].astype(np.int64) << 32) | subset[
621
+ :, 1
622
+ ].astype(np.uint32)
623
+ mask = np.isin(combined_data, combined_subset, assume_unique=False)
624
+ return mask
625
+
626
+
596
627
  def compute_confusion_matrix(
597
628
  data: NDArray[np.float64],
598
629
  label_metadata: NDArray[np.int32],
@@ -666,20 +697,16 @@ def compute_confusion_matrix(
666
697
  mask_gt_pd_match = mask_gt_pd_exists & mask_label_match
667
698
  mask_gt_pd_mismatch = mask_gt_pd_exists & ~mask_label_match
668
699
 
669
- groundtruths = data[:, [0, 1]].astype(int)
670
- predictions = data[:, [0, 2]].astype(int)
700
+ groundtruths = data[:, [0, 1]].astype(np.int32)
701
+ predictions = data[:, [0, 2]].astype(np.int32)
671
702
  for iou_idx in range(n_ious):
672
703
  mask_iou_threshold = data[:, 3] >= iou_thresholds[iou_idx]
673
704
  mask_iou = mask_iou_nonzero & mask_iou_threshold
674
705
 
675
706
  groundtruths_passing_ious = np.unique(groundtruths[mask_iou], axis=0)
676
- mask_groundtruths_with_passing_ious = (
677
- (
678
- groundtruths.reshape(-1, 1, 2)
679
- == groundtruths_passing_ious.reshape(1, -1, 2)
680
- )
681
- .all(axis=2)
682
- .any(axis=1)
707
+ mask_groundtruths_with_passing_ious = _isin(
708
+ data=groundtruths,
709
+ subset=groundtruths_passing_ious,
683
710
  )
684
711
  mask_groundtruths_without_passing_ious = (
685
712
  ~mask_groundtruths_with_passing_ious & mask_gt_exists
@@ -688,13 +715,9 @@ def compute_confusion_matrix(
688
715
  predictions_with_passing_ious = np.unique(
689
716
  predictions[mask_iou], axis=0
690
717
  )
691
- mask_predictions_with_passing_ious = (
692
- (
693
- predictions.reshape(-1, 1, 2)
694
- == predictions_with_passing_ious.reshape(1, -1, 2)
695
- )
696
- .all(axis=2)
697
- .any(axis=1)
718
+ mask_predictions_with_passing_ious = _isin(
719
+ data=predictions,
720
+ subset=predictions_with_passing_ious,
698
721
  )
699
722
  mask_predictions_without_passing_ious = (
700
723
  ~mask_predictions_with_passing_ious & mask_pd_exists
@@ -707,13 +730,9 @@ def compute_confusion_matrix(
707
730
  groundtruths_with_passing_score = np.unique(
708
731
  groundtruths[mask_iou & mask_score], axis=0
709
732
  )
710
- mask_groundtruths_with_passing_score = (
711
- (
712
- groundtruths.reshape(-1, 1, 2)
713
- == groundtruths_with_passing_score.reshape(1, -1, 2)
714
- )
715
- .all(axis=2)
716
- .any(axis=1)
733
+ mask_groundtruths_with_passing_score = _isin(
734
+ data=groundtruths,
735
+ subset=groundtruths_with_passing_score,
717
736
  )
718
737
  mask_groundtruths_without_passing_score = (
719
738
  ~mask_groundtruths_with_passing_score & mask_gt_exists
@@ -736,21 +755,13 @@ def compute_confusion_matrix(
736
755
  )
737
756
 
738
757
  # filter out true-positives from misclf and misprd
739
- mask_gts_with_tp_override = (
740
- (
741
- data[mask_misclf][:, [0, 1]].reshape(-1, 1, 2)
742
- == data[mask_tp][:, [0, 1]].reshape(1, -1, 2)
743
- )
744
- .all(axis=2)
745
- .any(axis=1)
758
+ mask_gts_with_tp_override = _isin(
759
+ data=groundtruths[mask_misclf],
760
+ subset=groundtruths[mask_tp],
746
761
  )
747
- mask_pds_with_tp_override = (
748
- (
749
- data[mask_misclf][:, [0, 2]].reshape(-1, 1, 2)
750
- == data[mask_tp][:, [0, 2]].reshape(1, -1, 2)
751
- )
752
- .all(axis=2)
753
- .any(axis=1)
762
+ mask_pds_with_tp_override = _isin(
763
+ data=predictions[mask_misclf],
764
+ subset=predictions[mask_tp],
754
765
  )
755
766
  mask_misprd[mask_misclf] |= (
756
767
  ~mask_gts_with_tp_override & mask_pds_with_tp_override
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: valor-lite
3
- Version: 0.33.10
3
+ Version: 0.33.12
4
4
  Summary: Compute valor metrics locally.
5
5
  License: MIT License
6
6
 
@@ -3,12 +3,12 @@ valor_lite/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  valor_lite/schemas.py,sha256=r4cC10w1xYsA785KmGE4ePeOX3wzEs846vT7QAiVg_I,293
4
4
  valor_lite/classification/__init__.py,sha256=2wmmziIzUATm7MbmAcPNLXrEX5l4oeD7XBwPd9bWM3Q,506
5
5
  valor_lite/classification/annotation.py,sha256=0aUOvcwBAZgiNOJuyh-pXyNTG7vP7r8CUfnU3OmpUwQ,1113
6
- valor_lite/classification/computation.py,sha256=qd9K7CcSGmMm_7shfX47_ZIuB-uE2LLiLMZSS_3NJTk,12093
7
- valor_lite/classification/manager.py,sha256=7NKk4syQHH5hBEUDWTD0zIFkJSNdOMzJn8a8GzfBnDc,23205
8
- valor_lite/classification/metric.py,sha256=m9_zD82YGl0QhuMql943YNKg67NZ6bsrR8ggs6_JZms,11728
6
+ valor_lite/classification/computation.py,sha256=pMePRFKCikYiGDgR-ZB8TmrzAts5ZIz4EywCT-XL42g,12100
7
+ valor_lite/classification/manager.py,sha256=fwb5z84SzgJ-ud1kTY3oYbUJLbA7R0cdWqqcaAIUcWs,23222
8
+ valor_lite/classification/metric.py,sha256=JjY9x6Sq1Hr_2agGnyT9EhVI5wXKQcMmEwxIK32yhGw,11903
9
9
  valor_lite/object_detection/__init__.py,sha256=PiKfemo8FkZRzBhPSjhil8ahGURLy0Vk_iV25CB4UBU,1139
10
10
  valor_lite/object_detection/annotation.py,sha256=o6VfiRobiB0ljqsNBLAYMXgi32RSIR7uTA-dgxq6zBI,8248
11
- valor_lite/object_detection/computation.py,sha256=Z9jhiimYm7j3tYAqYN4yZd6Hm5eQYrHmXBsemAltS5M,27530
11
+ valor_lite/object_detection/computation.py,sha256=ZW83XT-aemRg-5ZdISmrj0bRD9wWmYCU3gkSlfXlNZc,27747
12
12
  valor_lite/object_detection/manager.py,sha256=vb4JpynNF0JcnFwNmReFjls9UGAquigN2hpEbG89J04,38991
13
13
  valor_lite/object_detection/metric.py,sha256=tHRVnpBqw_w1VwnNkTCmu1yv7Max9FRlf5uh0wYew4s,24046
14
14
  valor_lite/semantic_segmentation/__init__.py,sha256=IdarTHKUuUMDvMBmInQu12Mm_NMCbql6Hf0nL5b56Ak,424
@@ -17,8 +17,8 @@ valor_lite/semantic_segmentation/computation.py,sha256=iJkEmTNmw9HwQCxSnpJkQsAdV
17
17
  valor_lite/semantic_segmentation/manager.py,sha256=aJk6edWZWKqrzl6hVmEUSZVYhHLuyihxWgAIXsCXkZ0,17361
18
18
  valor_lite/semantic_segmentation/metric.py,sha256=Y8M3z92SaABEe9TwBUN37TFsh9DR5WoIxO-TfXVwz8I,6289
19
19
  valor_lite/text_generation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- valor_lite-0.33.10.dist-info/LICENSE,sha256=M0L53VuwfEEqezhHb7NPeYcO_glw7-k4DMLZQ3eRN64,1068
21
- valor_lite-0.33.10.dist-info/METADATA,sha256=U_O0KL08ks1p4k7yZnX5Z7ItdcCnDxZZ5xgnu7Skhpw,5632
22
- valor_lite-0.33.10.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
23
- valor_lite-0.33.10.dist-info/top_level.txt,sha256=9ujykxSwpl2Hu0_R95UQTR_l07k9UUTSdrpiqmq6zc4,11
24
- valor_lite-0.33.10.dist-info/RECORD,,
20
+ valor_lite-0.33.12.dist-info/LICENSE,sha256=M0L53VuwfEEqezhHb7NPeYcO_glw7-k4DMLZQ3eRN64,1068
21
+ valor_lite-0.33.12.dist-info/METADATA,sha256=Sak_wCIniTYTNYjNrF8sy-ITbFdG_j_zFUq-jz1PYLk,5632
22
+ valor_lite-0.33.12.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
23
+ valor_lite-0.33.12.dist-info/top_level.txt,sha256=9ujykxSwpl2Hu0_R95UQTR_l07k9UUTSdrpiqmq6zc4,11
24
+ valor_lite-0.33.12.dist-info/RECORD,,