valor-lite 0.33.2__tar.gz → 0.33.4__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.

Potentially problematic release.


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

Files changed (39) hide show
  1. {valor_lite-0.33.2 → valor_lite-0.33.4}/PKG-INFO +2 -1
  2. {valor_lite-0.33.2 → valor_lite-0.33.4}/benchmarks/benchmark_objdet.py +39 -15
  3. {valor_lite-0.33.2 → valor_lite-0.33.4}/pyproject.toml +1 -0
  4. {valor_lite-0.33.2 → valor_lite-0.33.4}/tests/detection/conftest.py +214 -13
  5. {valor_lite-0.33.2 → valor_lite-0.33.4}/tests/detection/test_average_precision.py +302 -280
  6. {valor_lite-0.33.2 → valor_lite-0.33.4}/tests/detection/test_average_recall.py +212 -190
  7. {valor_lite-0.33.2 → valor_lite-0.33.4}/tests/detection/test_counts.py +220 -200
  8. valor_lite-0.33.4/tests/detection/test_dataloader.py +171 -0
  9. {valor_lite-0.33.2 → valor_lite-0.33.4}/tests/detection/test_detailed_counts.py +494 -639
  10. {valor_lite-0.33.2 → valor_lite-0.33.4}/tests/detection/test_evaluator.py +25 -3
  11. {valor_lite-0.33.2 → valor_lite-0.33.4}/tests/detection/test_filtering.py +115 -4
  12. valor_lite-0.33.4/tests/detection/test_iou.py +522 -0
  13. {valor_lite-0.33.2 → valor_lite-0.33.4}/tests/detection/test_pr_curve.py +1 -1
  14. {valor_lite-0.33.2 → valor_lite-0.33.4}/tests/detection/test_precision.py +102 -96
  15. {valor_lite-0.33.2 → valor_lite-0.33.4}/tests/detection/test_recall.py +102 -96
  16. {valor_lite-0.33.2 → valor_lite-0.33.4}/tests/detection/test_schemas.py +60 -4
  17. {valor_lite-0.33.2 → valor_lite-0.33.4}/tests/detection/test_stability.py +2 -2
  18. {valor_lite-0.33.2 → valor_lite-0.33.4}/valor_lite/detection/__init__.py +3 -3
  19. valor_lite-0.33.4/valor_lite/detection/annotation.py +98 -0
  20. {valor_lite-0.33.2 → valor_lite-0.33.4}/valor_lite/detection/computation.py +165 -76
  21. {valor_lite-0.33.2 → valor_lite-0.33.4}/valor_lite/detection/manager.py +610 -286
  22. {valor_lite-0.33.2 → valor_lite-0.33.4}/valor_lite/detection/metric.py +32 -7
  23. {valor_lite-0.33.2 → valor_lite-0.33.4}/valor_lite.egg-info/PKG-INFO +2 -1
  24. {valor_lite-0.33.2 → valor_lite-0.33.4}/valor_lite.egg-info/requires.txt +1 -0
  25. valor_lite-0.33.2/tests/detection/test_dataloader.py +0 -34
  26. valor_lite-0.33.2/tests/detection/test_iou.py +0 -30
  27. valor_lite-0.33.2/valor_lite/detection/annotation.py +0 -54
  28. {valor_lite-0.33.2 → valor_lite-0.33.4}/LICENSE +0 -0
  29. {valor_lite-0.33.2 → valor_lite-0.33.4}/README.md +0 -0
  30. {valor_lite-0.33.2 → valor_lite-0.33.4}/benchmarks/.gitignore +0 -0
  31. {valor_lite-0.33.2 → valor_lite-0.33.4}/examples/.gitignore +0 -0
  32. {valor_lite-0.33.2 → valor_lite-0.33.4}/examples/coco-yolo.ipynb +0 -0
  33. {valor_lite-0.33.2 → valor_lite-0.33.4}/setup.cfg +0 -0
  34. {valor_lite-0.33.2 → valor_lite-0.33.4}/tests/detection/__init__.py +0 -0
  35. {valor_lite-0.33.2 → valor_lite-0.33.4}/valor_lite/__init__.py +0 -0
  36. {valor_lite-0.33.2 → valor_lite-0.33.4}/valor_lite/schemas.py +0 -0
  37. {valor_lite-0.33.2 → valor_lite-0.33.4}/valor_lite.egg-info/SOURCES.txt +0 -0
  38. {valor_lite-0.33.2 → valor_lite-0.33.4}/valor_lite.egg-info/dependency_links.txt +0 -0
  39. {valor_lite-0.33.2 → valor_lite-0.33.4}/valor_lite.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: valor-lite
3
- Version: 0.33.2
3
+ Version: 0.33.4
4
4
  Summary: Compute valor metrics directly in your client.
5
5
  License: MIT License
6
6
 
@@ -33,6 +33,7 @@ Requires-Dist: importlib_metadata; python_version < "3.8"
33
33
  Requires-Dist: tqdm
34
34
  Requires-Dist: requests
35
35
  Requires-Dist: numpy
36
+ Requires-Dist: shapely
36
37
  Provides-Extra: test
37
38
  Requires-Dist: pytest; extra == "test"
38
39
  Requires-Dist: coverage; extra == "test"
@@ -8,7 +8,7 @@ from time import time
8
8
 
9
9
  import requests
10
10
  from tqdm import tqdm
11
- from valor_lite.detection import DataLoader
11
+ from valor_lite.detection import DataLoader, MetricType
12
12
 
13
13
 
14
14
  class AnnotationType(str, Enum):
@@ -113,7 +113,7 @@ def ingest(
113
113
  elif len(groundtruths) < chunk_size or chunk_size == -1:
114
114
  continue
115
115
 
116
- timer, _ = time_it(manager.add_data_from_valor_dict)(
116
+ timer, _ = time_it(manager.add_bounding_boxes_from_valor_dict)(
117
117
  zip(groundtruths, predictions), True
118
118
  )
119
119
  accumulated_time += timer
@@ -121,7 +121,7 @@ def ingest(
121
121
  predictions = []
122
122
 
123
123
  if groundtruths:
124
- timer, _ = time_it(manager.add_data_from_valor_dict)(
124
+ timer, _ = time_it(manager.add_bounding_boxes_from_valor_dict)(
125
125
  zip(groundtruths, predictions), True
126
126
  )
127
127
  accumulated_time += timer
@@ -258,24 +258,48 @@ def run_benchmarking_analysis(
258
258
  f"Base precomputation timed out with limit of {limit}."
259
259
  )
260
260
 
261
- # test detailed counts with no samples
262
- detailed_counts_time_no_samples, _ = time_it(
263
- evaluator.compute_detailed_counts
264
- )()
265
-
266
- # test detailed counts with 3 samples
267
- detailed_counts_time_three_samples, _ = time_it(
268
- evaluator.compute_detailed_counts
269
- )(n_samples=3)
270
-
271
- # evaluate
261
+ # evaluate - base metrics only
272
262
  eval_time, metrics = time_it(evaluator.evaluate)()
273
- # print(metrics)
274
263
  if eval_time > evaluation_timeout and evaluation_timeout != -1:
275
264
  raise TimeoutError(
276
265
  f"Base evaluation timed out with {evaluator.n_datums} datums."
277
266
  )
278
267
 
268
+ # evaluate - base metrics + detailed counts with no samples
269
+ detailed_counts_time_no_samples, metrics = time_it(
270
+ evaluator.evaluate
271
+ )(
272
+ [
273
+ MetricType.DetailedCounts,
274
+ *MetricType.base_metrics(),
275
+ ]
276
+ )
277
+ if (
278
+ detailed_counts_time_no_samples > evaluation_timeout
279
+ and evaluation_timeout != -1
280
+ ):
281
+ raise TimeoutError(
282
+ f"Detailed evaluation w/ no samples timed out with {evaluator.n_datums} datums."
283
+ )
284
+
285
+ # evaluate - base metrics + detailed counts with 3 samples
286
+ detailed_counts_time_three_samples, metrics = time_it(
287
+ evaluator.evaluate
288
+ )(
289
+ [
290
+ MetricType.DetailedCounts,
291
+ *MetricType.base_metrics(),
292
+ ],
293
+ number_of_examples=3,
294
+ )
295
+ if (
296
+ detailed_counts_time_three_samples > evaluation_timeout
297
+ and evaluation_timeout != -1
298
+ ):
299
+ raise TimeoutError(
300
+ f"Detailed w/ 3 samples evaluation timed out with {evaluator.n_datums} datums."
301
+ )
302
+
279
303
  results.append(
280
304
  Benchmark(
281
305
  limit=limit,
@@ -11,6 +11,7 @@ dependencies = [
11
11
  "tqdm",
12
12
  "requests",
13
13
  "numpy",
14
+ "shapely",
14
15
  ]
15
16
 
16
17
  [project.urls]
@@ -1,5 +1,7 @@
1
+ import numpy as np
1
2
  import pytest
2
- from valor_lite.detection import BoundingBox, Detection
3
+ from shapely.geometry import Polygon as ShapelyPolygon
4
+ from valor_lite.detection import Bitmask, BoundingBox, Detection, Polygon
3
5
 
4
6
 
5
7
  @pytest.fixture
@@ -32,6 +34,42 @@ def rect5() -> tuple[float, float, float, float]:
32
34
  return (87, 158, 10, 400)
33
35
 
34
36
 
37
+ @pytest.fixture
38
+ def rect1_rotated_5_degrees_around_origin() -> list[tuple[float, float]]:
39
+ """Box with area = 1500."""
40
+ return [
41
+ (9.090389553440874, 10.833504408394036),
42
+ (58.90012445802815, 15.191291545776945),
43
+ (56.28545217559841, 45.07713248852931),
44
+ (6.475717271011129, 40.7193453511464),
45
+ (9.090389553440874, 10.833504408394036),
46
+ ]
47
+
48
+
49
+ @pytest.fixture
50
+ def rect2_rotated_5_degrees_around_origin() -> list[tuple[float, float]]:
51
+ """Box with area = 1100."""
52
+ return [
53
+ (14.942920471376183, 1.3073361412148725),
54
+ (69.7336288664222, 6.1009019923360714),
55
+ (67.99051401146903, 26.024795954170983),
56
+ (13.19980561642302, 21.231230103049782),
57
+ (14.942920471376183, 1.3073361412148725),
58
+ ]
59
+
60
+
61
+ @pytest.fixture
62
+ def rect3_rotated_5_degrees_around_origin() -> list[tuple[float, float]]:
63
+ """Box with area = 57,510."""
64
+ return [
65
+ (85.79738130650527, 17.544496599963715),
66
+ (156.52720487101922, 23.732554335047446),
67
+ (85.9310532454161, 830.6502597893614),
68
+ (15.20122968090216, 824.4622020542777),
69
+ (85.79738130650527, 17.544496599963715),
70
+ ]
71
+
72
+
35
73
  @pytest.fixture
36
74
  def basic_detections(
37
75
  rect1: tuple[float, float, float, float],
@@ -93,6 +131,62 @@ def basic_detections(
93
131
  ]
94
132
 
95
133
 
134
+ @pytest.fixture
135
+ def basic_rotated_detections(
136
+ rect1_rotated_5_degrees_around_origin: tuple[float, float, float, float],
137
+ rect2_rotated_5_degrees_around_origin: tuple[float, float, float, float],
138
+ rect3_rotated_5_degrees_around_origin: tuple[float, float, float, float],
139
+ ) -> list[Detection]:
140
+ return [
141
+ Detection(
142
+ uid="uid1",
143
+ groundtruths=[
144
+ Polygon(
145
+ shape=ShapelyPolygon(
146
+ rect1_rotated_5_degrees_around_origin
147
+ ),
148
+ labels=[("k1", "v1")],
149
+ ),
150
+ Polygon(
151
+ shape=ShapelyPolygon(
152
+ rect3_rotated_5_degrees_around_origin
153
+ ),
154
+ labels=[("k2", "v2")],
155
+ ),
156
+ ],
157
+ predictions=[
158
+ Polygon(
159
+ shape=ShapelyPolygon(
160
+ rect1_rotated_5_degrees_around_origin
161
+ ),
162
+ labels=[("k1", "v1")],
163
+ scores=[0.3],
164
+ ),
165
+ ],
166
+ ),
167
+ Detection(
168
+ uid="uid2",
169
+ groundtruths=[
170
+ Polygon(
171
+ shape=ShapelyPolygon(
172
+ rect2_rotated_5_degrees_around_origin
173
+ ),
174
+ labels=[("k1", "v1")],
175
+ ),
176
+ ],
177
+ predictions=[
178
+ Polygon(
179
+ shape=ShapelyPolygon(
180
+ rect2_rotated_5_degrees_around_origin
181
+ ),
182
+ labels=[("k2", "v2")],
183
+ scores=[0.98],
184
+ ),
185
+ ],
186
+ ),
187
+ ]
188
+
189
+
96
190
  @pytest.fixture
97
191
  def torchmetrics_detections() -> list[Detection]:
98
192
  """Creates a model called "test_model" with some predicted
@@ -309,9 +403,9 @@ def false_negatives_single_datum_detections() -> list[Detection]:
309
403
 
310
404
 
311
405
  @pytest.fixture
312
- def false_negatives_two_datums_one_empty_low_confidence_of_fp_detections() -> list[
313
- Detection
314
- ]:
406
+ def false_negatives_two_datums_one_empty_low_confidence_of_fp_detections() -> (
407
+ list[Detection]
408
+ ):
315
409
 
316
410
  return [
317
411
  Detection(
@@ -354,9 +448,9 @@ def false_negatives_two_datums_one_empty_low_confidence_of_fp_detections() -> li
354
448
 
355
449
 
356
450
  @pytest.fixture
357
- def false_negatives_two_datums_one_empty_high_confidence_of_fp_detections() -> list[
358
- Detection
359
- ]:
451
+ def false_negatives_two_datums_one_empty_high_confidence_of_fp_detections() -> (
452
+ list[Detection]
453
+ ):
360
454
 
361
455
  return [
362
456
  Detection(
@@ -399,9 +493,9 @@ def false_negatives_two_datums_one_empty_high_confidence_of_fp_detections() -> l
399
493
 
400
494
 
401
495
  @pytest.fixture
402
- def false_negatives_two_datums_one_only_with_different_class_low_confidence_of_fp_detections() -> list[
403
- Detection
404
- ]:
496
+ def false_negatives_two_datums_one_only_with_different_class_low_confidence_of_fp_detections() -> (
497
+ list[Detection]
498
+ ):
405
499
 
406
500
  return [
407
501
  Detection(
@@ -452,9 +546,9 @@ def false_negatives_two_datums_one_only_with_different_class_low_confidence_of_f
452
546
 
453
547
 
454
548
  @pytest.fixture
455
- def false_negatives_two_images_one_only_with_different_class_high_confidence_of_fp_detections() -> list[
456
- Detection
457
- ]:
549
+ def false_negatives_two_images_one_only_with_different_class_high_confidence_of_fp_detections() -> (
550
+ list[Detection]
551
+ ):
458
552
 
459
553
  return [
460
554
  Detection(
@@ -674,6 +768,113 @@ def detection_ranked_pair_ordering() -> Detection:
674
768
  )
675
769
 
676
770
 
771
+ @pytest.fixture
772
+ def detection_ranked_pair_ordering_with_bitmasks() -> Detection:
773
+
774
+ gts = {
775
+ "bitmasks": [
776
+ np.ones((80, 32), dtype=bool),
777
+ np.ones((80, 32), dtype=bool),
778
+ np.ones((80, 32), dtype=bool),
779
+ ],
780
+ "label_values": ["label1", "label2", "label3"],
781
+ }
782
+
783
+ # labels 1 and 2 have IOU==1, labels 3 and 4 have IOU==0
784
+ preds = {
785
+ "bitmasks": [
786
+ np.ones((80, 32), dtype=bool),
787
+ np.ones((80, 32), dtype=bool),
788
+ np.zeros((80, 32), dtype=bool),
789
+ np.zeros((80, 32), dtype=bool),
790
+ ],
791
+ "label_values": ["label1", "label2", "label3", "label4"],
792
+ "scores": [
793
+ 0.3,
794
+ 0.93,
795
+ 0.92,
796
+ 0.94,
797
+ ],
798
+ }
799
+ groundtruths = [
800
+ Bitmask(
801
+ mask=mask,
802
+ labels=[("class", label_value)],
803
+ )
804
+ for mask, label_value in zip(gts["bitmasks"], gts["label_values"])
805
+ ]
806
+
807
+ predictions = [
808
+ Bitmask(
809
+ mask=mask,
810
+ labels=[("class", label_value)],
811
+ scores=[score],
812
+ )
813
+ for mask, label_value, score in zip(
814
+ preds["bitmasks"], preds["label_values"], preds["scores"]
815
+ )
816
+ ]
817
+
818
+ return Detection(
819
+ uid="uid1", groundtruths=groundtruths, predictions=predictions
820
+ )
821
+
822
+
823
+ @pytest.fixture
824
+ def detection_ranked_pair_ordering_with_polygons(
825
+ rect1_rotated_5_degrees_around_origin: list[tuple[float, float]],
826
+ rect3_rotated_5_degrees_around_origin: list[tuple[float, float]],
827
+ ) -> Detection:
828
+ gts = {
829
+ "polygons": [
830
+ rect1_rotated_5_degrees_around_origin,
831
+ rect1_rotated_5_degrees_around_origin,
832
+ rect1_rotated_5_degrees_around_origin,
833
+ ],
834
+ "label_values": ["label1", "label2", "label3"],
835
+ }
836
+
837
+ # labels 1 and 2 have IOU==1, labels 3 and 4 have IOU==0
838
+ preds = {
839
+ "polygons": [
840
+ rect1_rotated_5_degrees_around_origin,
841
+ rect1_rotated_5_degrees_around_origin,
842
+ rect3_rotated_5_degrees_around_origin,
843
+ rect3_rotated_5_degrees_around_origin,
844
+ ],
845
+ "label_values": ["label1", "label2", "label3", "label4"],
846
+ "scores": [
847
+ 0.3,
848
+ 0.93,
849
+ 0.92,
850
+ 0.94,
851
+ ],
852
+ }
853
+
854
+ groundtruths = [
855
+ Polygon(
856
+ shape=ShapelyPolygon(polygon),
857
+ labels=[("class", label_value)],
858
+ )
859
+ for polygon, label_value in zip(gts["polygons"], gts["label_values"])
860
+ ]
861
+
862
+ predictions = [
863
+ Polygon(
864
+ shape=ShapelyPolygon(polygon),
865
+ labels=[("class", label_value)],
866
+ scores=[score],
867
+ )
868
+ for polygon, label_value, score in zip(
869
+ preds["polygons"], preds["label_values"], preds["scores"]
870
+ )
871
+ ]
872
+
873
+ return Detection(
874
+ uid="uid1", groundtruths=groundtruths, predictions=predictions
875
+ )
876
+
877
+
677
878
  @pytest.fixture
678
879
  def detections_no_groundtruths() -> list[Detection]:
679
880
  return [