valor-lite 0.36.6__py3-none-any.whl → 0.37.5__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.
Files changed (38) hide show
  1. valor_lite/cache/__init__.py +11 -0
  2. valor_lite/cache/compute.py +211 -0
  3. valor_lite/cache/ephemeral.py +302 -0
  4. valor_lite/cache/persistent.py +536 -0
  5. valor_lite/classification/__init__.py +5 -10
  6. valor_lite/classification/annotation.py +4 -0
  7. valor_lite/classification/computation.py +233 -251
  8. valor_lite/classification/evaluator.py +882 -0
  9. valor_lite/classification/loader.py +97 -0
  10. valor_lite/classification/metric.py +141 -4
  11. valor_lite/classification/shared.py +184 -0
  12. valor_lite/classification/utilities.py +221 -118
  13. valor_lite/exceptions.py +5 -0
  14. valor_lite/object_detection/__init__.py +5 -4
  15. valor_lite/object_detection/annotation.py +13 -1
  16. valor_lite/object_detection/computation.py +368 -299
  17. valor_lite/object_detection/evaluator.py +804 -0
  18. valor_lite/object_detection/loader.py +292 -0
  19. valor_lite/object_detection/metric.py +152 -3
  20. valor_lite/object_detection/shared.py +206 -0
  21. valor_lite/object_detection/utilities.py +182 -100
  22. valor_lite/semantic_segmentation/__init__.py +5 -4
  23. valor_lite/semantic_segmentation/annotation.py +7 -0
  24. valor_lite/semantic_segmentation/computation.py +20 -110
  25. valor_lite/semantic_segmentation/evaluator.py +414 -0
  26. valor_lite/semantic_segmentation/loader.py +205 -0
  27. valor_lite/semantic_segmentation/shared.py +149 -0
  28. valor_lite/semantic_segmentation/utilities.py +6 -23
  29. {valor_lite-0.36.6.dist-info → valor_lite-0.37.5.dist-info}/METADATA +3 -1
  30. valor_lite-0.37.5.dist-info/RECORD +49 -0
  31. {valor_lite-0.36.6.dist-info → valor_lite-0.37.5.dist-info}/WHEEL +1 -1
  32. valor_lite/classification/manager.py +0 -545
  33. valor_lite/object_detection/manager.py +0 -864
  34. valor_lite/profiling.py +0 -374
  35. valor_lite/semantic_segmentation/benchmark.py +0 -237
  36. valor_lite/semantic_segmentation/manager.py +0 -446
  37. valor_lite-0.36.6.dist-info/RECORD +0 -41
  38. {valor_lite-0.36.6.dist-info → valor_lite-0.37.5.dist-info}/top_level.txt +0 -0
@@ -1,446 +0,0 @@
1
- from dataclasses import asdict, dataclass
2
-
3
- import numpy as np
4
- from numpy.typing import NDArray
5
- from tqdm import tqdm
6
-
7
- from valor_lite.exceptions import EmptyEvaluatorError, EmptyFilterError
8
- from valor_lite.semantic_segmentation.annotation import Segmentation
9
- from valor_lite.semantic_segmentation.computation import (
10
- compute_intermediate_confusion_matrices,
11
- compute_label_metadata,
12
- compute_metrics,
13
- filter_cache,
14
- )
15
- from valor_lite.semantic_segmentation.metric import Metric, MetricType
16
- from valor_lite.semantic_segmentation.utilities import (
17
- unpack_precision_recall_iou_into_metric_lists,
18
- )
19
-
20
- """
21
- Usage
22
- -----
23
-
24
- manager = DataLoader()
25
- manager.add_data(
26
- groundtruths=groundtruths,
27
- predictions=predictions,
28
- )
29
- evaluator = manager.finalize()
30
-
31
- metrics = evaluator.evaluate()
32
-
33
- f1_metrics = metrics[MetricType.F1]
34
- accuracy_metrics = metrics[MetricType.Accuracy]
35
-
36
- filter_mask = evaluator.create_filter(datum_ids=["uid1", "uid2"])
37
- filtered_metrics = evaluator.evaluate(filter_mask=filter_mask)
38
- """
39
-
40
-
41
- @dataclass
42
- class Metadata:
43
- number_of_labels: int = 0
44
- number_of_pixels: int = 0
45
- number_of_datums: int = 0
46
- number_of_ground_truths: int = 0
47
- number_of_predictions: int = 0
48
-
49
- @classmethod
50
- def create(
51
- cls,
52
- confusion_matrices: NDArray[np.int64],
53
- ):
54
- if confusion_matrices.size == 0:
55
- return cls()
56
- return cls(
57
- number_of_labels=confusion_matrices.shape[1] - 1,
58
- number_of_pixels=confusion_matrices.sum(),
59
- number_of_datums=confusion_matrices.shape[0],
60
- number_of_ground_truths=confusion_matrices[:, 1:, :].sum(),
61
- number_of_predictions=confusion_matrices[:, :, 1:].sum(),
62
- )
63
-
64
- def to_dict(self) -> dict[str, int | bool]:
65
- return asdict(self)
66
-
67
-
68
- @dataclass
69
- class Filter:
70
- datum_mask: NDArray[np.bool_]
71
- label_mask: NDArray[np.bool_]
72
- metadata: Metadata
73
-
74
- def __post_init__(self):
75
- # validate datum mask
76
- if not self.datum_mask.any():
77
- raise EmptyFilterError("filter removes all datums")
78
-
79
- # validate label mask
80
- if self.label_mask.all():
81
- raise EmptyFilterError("filter removes all labels")
82
-
83
-
84
- class Evaluator:
85
- """
86
- Segmentation Evaluator
87
- """
88
-
89
- def __init__(self):
90
- """Initializes evaluator caches."""
91
- # external references
92
- self.datum_id_to_index: dict[str, int] = {}
93
- self.index_to_datum_id: list[str] = []
94
- self.label_to_index: dict[str, int] = {}
95
- self.index_to_label: list[str] = []
96
-
97
- # internal caches
98
- self._confusion_matrices = np.array([], dtype=np.int64)
99
- self._label_metadata = np.array([], dtype=np.int64)
100
- self._metadata = Metadata()
101
-
102
- @property
103
- def metadata(self) -> Metadata:
104
- return self._metadata
105
-
106
- @property
107
- def ignored_prediction_labels(self) -> list[str]:
108
- """
109
- Prediction labels that are not present in the ground truth set.
110
- """
111
- glabels = set(np.where(self._label_metadata[:, 0] > 0)[0])
112
- plabels = set(np.where(self._label_metadata[:, 1] > 0)[0])
113
- return [
114
- self.index_to_label[label_id] for label_id in (plabels - glabels)
115
- ]
116
-
117
- @property
118
- def missing_prediction_labels(self) -> list[str]:
119
- """
120
- Ground truth labels that are not present in the prediction set.
121
- """
122
- glabels = set(np.where(self._label_metadata[:, 0] > 0)[0])
123
- plabels = set(np.where(self._label_metadata[:, 1] > 0)[0])
124
- return [
125
- self.index_to_label[label_id] for label_id in (glabels - plabels)
126
- ]
127
-
128
- def create_filter(
129
- self,
130
- datums: list[str] | NDArray[np.int64] | None = None,
131
- labels: list[str] | NDArray[np.int64] | None = None,
132
- ) -> Filter:
133
- """
134
- Creates a filter for use with the evaluator.
135
-
136
- Parameters
137
- ----------
138
- datums : list[str] | NDArray[int64], optional
139
- An optional list of string ids or array of indices representing datums.
140
- labels : list[str] | NDArray[int64], optional
141
- An optional list of labels or array of indices.
142
-
143
- Returns
144
- -------
145
- Filter
146
- The filter object containing a mask and metadata.
147
- """
148
- datum_mask = np.ones(self._confusion_matrices.shape[0], dtype=np.bool_)
149
- label_mask = np.zeros(
150
- self.metadata.number_of_labels + 1, dtype=np.bool_
151
- )
152
-
153
- if datums is not None:
154
- # convert to indices
155
- if isinstance(datums, list):
156
- datums = np.array(
157
- [self.datum_id_to_index[uid] for uid in datums],
158
- dtype=np.int64,
159
- )
160
-
161
- # validate indices
162
- if datums.size == 0:
163
- raise EmptyFilterError(
164
- "filter removes all datums"
165
- ) # validate indices
166
- elif datums.min() < 0:
167
- raise ValueError(
168
- f"datum index cannot be negative '{datums.min()}'"
169
- )
170
- elif datums.max() >= len(self.index_to_datum_id):
171
- raise ValueError(
172
- f"datum index cannot exceed total number of datums '{datums.max()}'"
173
- )
174
-
175
- # apply to mask
176
- datums.sort()
177
- mask_valid_datums = (
178
- np.arange(self._confusion_matrices.shape[0]).reshape(-1, 1)
179
- == datums.reshape(1, -1)
180
- ).any(axis=1)
181
- datum_mask[~mask_valid_datums] = False
182
-
183
- if labels is not None:
184
- # convert to indices
185
- if isinstance(labels, list):
186
- labels = np.array(
187
- [self.label_to_index[label] for label in labels],
188
- dtype=np.int64,
189
- )
190
-
191
- # validate indices
192
- if labels.size == 0:
193
- raise EmptyFilterError("filter removes all labels")
194
- elif labels.min() < 0:
195
- raise ValueError(
196
- f"label index cannot be negative '{labels.min()}'"
197
- )
198
- elif labels.max() >= len(self.index_to_label):
199
- raise ValueError(
200
- f"label index cannot exceed total number of labels '{labels.max()}'"
201
- )
202
-
203
- # apply to mask
204
- labels = np.concatenate([labels, np.array([-1])])
205
- label_range = np.arange(self.metadata.number_of_labels + 1) - 1
206
- mask_valid_labels = (
207
- label_range.reshape(-1, 1) == labels.reshape(1, -1)
208
- ).any(axis=1)
209
- label_mask[~mask_valid_labels] = True
210
-
211
- filtered_confusion_matrices, _ = filter_cache(
212
- confusion_matrices=self._confusion_matrices.copy(),
213
- datum_mask=datum_mask,
214
- label_mask=label_mask,
215
- number_of_labels=self.metadata.number_of_labels,
216
- )
217
-
218
- return Filter(
219
- datum_mask=datum_mask,
220
- label_mask=label_mask,
221
- metadata=Metadata.create(
222
- confusion_matrices=filtered_confusion_matrices,
223
- ),
224
- )
225
-
226
- def filter(
227
- self, filter_: Filter
228
- ) -> tuple[NDArray[np.int64], NDArray[np.int64]]:
229
- """
230
- Performs the filter operation over the internal cache.
231
-
232
- Parameters
233
- ----------
234
- filter_ : Filter
235
- An object describing the filter operation.
236
-
237
- Returns
238
- -------
239
- NDArray[int64]
240
- Filtered confusion matrices.
241
- NDArray[int64]
242
- Filtered label metadata
243
- """
244
- return filter_cache(
245
- confusion_matrices=self._confusion_matrices.copy(),
246
- datum_mask=filter_.datum_mask,
247
- label_mask=filter_.label_mask,
248
- number_of_labels=self.metadata.number_of_labels,
249
- )
250
-
251
- def compute_precision_recall_iou(
252
- self, filter_: Filter | None = None
253
- ) -> dict[MetricType, list]:
254
- """
255
- Performs an evaluation and returns metrics.
256
-
257
- Returns
258
- -------
259
- dict[MetricType, list]
260
- A dictionary mapping MetricType enumerations to lists of computed metrics.
261
- """
262
- if filter_ is not None:
263
- confusion_matrices, label_metadata = self.filter(filter_)
264
- n_pixels = filter_.metadata.number_of_pixels
265
- else:
266
- confusion_matrices = self._confusion_matrices
267
- label_metadata = self._label_metadata
268
- n_pixels = self.metadata.number_of_pixels
269
-
270
- results = compute_metrics(
271
- confusion_matrices=confusion_matrices,
272
- label_metadata=label_metadata,
273
- n_pixels=n_pixels,
274
- )
275
- return unpack_precision_recall_iou_into_metric_lists(
276
- results=results,
277
- label_metadata=label_metadata,
278
- index_to_label=self.index_to_label,
279
- )
280
-
281
- def evaluate(
282
- self, filter_: Filter | None = None
283
- ) -> dict[MetricType, list[Metric]]:
284
- """
285
- Computes all available metrics.
286
-
287
- Returns
288
- -------
289
- dict[MetricType, list[Metric]]
290
- Lists of metrics organized by metric type.
291
- """
292
- return self.compute_precision_recall_iou(filter_=filter_)
293
-
294
-
295
- class DataLoader:
296
- """
297
- Segmentation DataLoader.
298
- """
299
-
300
- def __init__(self):
301
- self._evaluator = Evaluator()
302
- self.matrices = list()
303
-
304
- def _add_datum(self, uid: str) -> int:
305
- """
306
- Helper function for adding a datum to the cache.
307
-
308
- Parameters
309
- ----------
310
- uid : str
311
- The datum uid.
312
-
313
- Returns
314
- -------
315
- int
316
- The datum index.
317
- """
318
- if uid in self._evaluator.datum_id_to_index:
319
- raise ValueError(f"Datum with uid `{uid}` already exists.")
320
- index = len(self._evaluator.datum_id_to_index)
321
- self._evaluator.datum_id_to_index[uid] = index
322
- self._evaluator.index_to_datum_id.append(uid)
323
- return index
324
-
325
- def _add_label(self, label: str) -> int:
326
- """
327
- Helper function for adding a label to the cache.
328
-
329
- Parameters
330
- ----------
331
- label : str
332
- A string label.
333
-
334
- Returns
335
- -------
336
- int
337
- The label's index.
338
- """
339
- if label not in self._evaluator.label_to_index:
340
- label_id = len(self._evaluator.index_to_label)
341
- self._evaluator.label_to_index[label] = label_id
342
- self._evaluator.index_to_label.append(label)
343
- return self._evaluator.label_to_index[label]
344
-
345
- def add_data(
346
- self,
347
- segmentations: list[Segmentation],
348
- show_progress: bool = False,
349
- ):
350
- """
351
- Adds segmentations to the cache.
352
-
353
- Parameters
354
- ----------
355
- segmentations : list[Segmentation]
356
- A list of Segmentation objects.
357
- show_progress : bool, default=False
358
- Toggle for tqdm progress bar.
359
- """
360
-
361
- disable_tqdm = not show_progress
362
- for segmentation in tqdm(segmentations, disable=disable_tqdm):
363
- # update datum cache
364
- self._add_datum(segmentation.uid)
365
-
366
- groundtruth_labels = -1 * np.ones(
367
- len(segmentation.groundtruths), dtype=np.int64
368
- )
369
- for idx, groundtruth in enumerate(segmentation.groundtruths):
370
- label_idx = self._add_label(groundtruth.label)
371
- groundtruth_labels[idx] = label_idx
372
-
373
- prediction_labels = -1 * np.ones(
374
- len(segmentation.predictions), dtype=np.int64
375
- )
376
- for idx, prediction in enumerate(segmentation.predictions):
377
- label_idx = self._add_label(prediction.label)
378
- prediction_labels[idx] = label_idx
379
-
380
- if segmentation.groundtruths:
381
- combined_groundtruths = np.stack(
382
- [
383
- groundtruth.mask.flatten()
384
- for groundtruth in segmentation.groundtruths
385
- ],
386
- axis=0,
387
- )
388
- else:
389
- combined_groundtruths = np.zeros(
390
- (1, segmentation.shape[0] * segmentation.shape[1]),
391
- dtype=np.bool_,
392
- )
393
-
394
- if segmentation.predictions:
395
- combined_predictions = np.stack(
396
- [
397
- prediction.mask.flatten()
398
- for prediction in segmentation.predictions
399
- ],
400
- axis=0,
401
- )
402
- else:
403
- combined_predictions = np.zeros(
404
- (1, segmentation.shape[0] * segmentation.shape[1]),
405
- dtype=np.bool_,
406
- )
407
-
408
- self.matrices.append(
409
- compute_intermediate_confusion_matrices(
410
- groundtruths=combined_groundtruths,
411
- predictions=combined_predictions,
412
- groundtruth_labels=groundtruth_labels,
413
- prediction_labels=prediction_labels,
414
- n_labels=len(self._evaluator.index_to_label),
415
- )
416
- )
417
-
418
- def finalize(self) -> Evaluator:
419
- """
420
- Performs data finalization and some preprocessing steps.
421
-
422
- Returns
423
- -------
424
- Evaluator
425
- A ready-to-use evaluator object.
426
- """
427
-
428
- if len(self.matrices) == 0:
429
- raise EmptyEvaluatorError()
430
-
431
- n_labels = len(self._evaluator.index_to_label)
432
- n_datums = len(self._evaluator.index_to_datum_id)
433
- self._evaluator._confusion_matrices = np.zeros(
434
- (n_datums, n_labels + 1, n_labels + 1), dtype=np.int64
435
- )
436
- for idx, matrix in enumerate(self.matrices):
437
- h, w = matrix.shape
438
- self._evaluator._confusion_matrices[idx, :h, :w] = matrix
439
- self._evaluator._label_metadata = compute_label_metadata(
440
- confusion_matrices=self._evaluator._confusion_matrices,
441
- n_labels=n_labels,
442
- )
443
- self._evaluator._metadata = Metadata.create(
444
- confusion_matrices=self._evaluator._confusion_matrices,
445
- )
446
- return self._evaluator
@@ -1,41 +0,0 @@
1
- valor_lite/LICENSE,sha256=M0L53VuwfEEqezhHb7NPeYcO_glw7-k4DMLZQ3eRN64,1068
2
- valor_lite/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- valor_lite/exceptions.py,sha256=Q0PLMu0PnCPBx438iEPzpOQyMOcMOA3lOf5xQZP_yYU,385
4
- valor_lite/profiling.py,sha256=TLIROA1qccFw9NoEkMeQcrvvGGO75c4K5yTIWoCUix8,11746
5
- valor_lite/schemas.py,sha256=pB0MrPx5qFLbwBWDiOUUm-vmXdWvbJLFCBmKgbcbI5g,198
6
- valor_lite/classification/__init__.py,sha256=KXaVwyqAbeeeEq7bzNPyt4GTpbxhrABjV7lR58KR6Y4,440
7
- valor_lite/classification/annotation.py,sha256=0aUOvcwBAZgiNOJuyh-pXyNTG7vP7r8CUfnU3OmpUwQ,1113
8
- valor_lite/classification/computation.py,sha256=kB5n-RHzDsKG75Guvgg25xAOeLEQCq1TgjwHwfwbQ60,12010
9
- valor_lite/classification/manager.py,sha256=JZwA9sf-OG7p7uK5qIo-D711kSpBDDeTcXsPr1uuIBI,16884
10
- valor_lite/classification/metric.py,sha256=nSNWjoxQ1ou7gxTPOYxLNoUYf7avKQzJq3NHR9jzM48,11693
11
- valor_lite/classification/numpy_compatibility.py,sha256=roqtTetsm1_HxuaejrthQdydjsRIy-FpXpGb86cLh_E,365
12
- valor_lite/classification/utilities.py,sha256=jAcir7dW-o4I2gk_NEmlRr8j8Iniyyq9QT5j3PMxVHk,6435
13
- valor_lite/object_detection/__init__.py,sha256=eSrVAOpSykk1CfHXIKy1necplonUGxjyVKyDQ5UZoBQ,343
14
- valor_lite/object_detection/annotation.py,sha256=LVec-rIk408LuFxcOoIkPk0QZMWSSxbmsady4wapC1s,7007
15
- valor_lite/object_detection/computation.py,sha256=FPAOVOpvWlZemu9Lv4AAtrVQSMb_enbSxvupp22_2BY,24262
16
- valor_lite/object_detection/manager.py,sha256=y5QujUSXrI6FHmA6sg7JyQrvPgikxFW1q0Zudg841r0,30010
17
- valor_lite/object_detection/metric.py,sha256=sUYSZwXYfIyfmXG6_7Tje1_ZL_QwvecPq85jrGmwOWE,22739
18
- valor_lite/object_detection/utilities.py,sha256=jdY7ltjVcnjCB4S_tRyt3gthyGcPbVQKLK6ZZO6HW5s,10870
19
- valor_lite/semantic_segmentation/__init__.py,sha256=3YdItCThY_tW23IChCBm-R0zahnbZ06JDVjs-gQLVes,293
20
- valor_lite/semantic_segmentation/annotation.py,sha256=KrDqmSVzBsutxEdh0Kl8VqcEpTe4S68UdkVg-nyxcFg,4025
21
- valor_lite/semantic_segmentation/benchmark.py,sha256=uxd0SiDY3npsgU5pdeT4HvNP_au9GVRWzoqT6br9DtM,5961
22
- valor_lite/semantic_segmentation/computation.py,sha256=ZO0qAFmq8lN73UjCyiynSv18qQDtn35FNOmvuXY4rOw,7380
23
- valor_lite/semantic_segmentation/manager.py,sha256=h5w8Xl-O9gZxAzqT-ESofVE2th7d3cYahx4hHBic3pw,14256
24
- valor_lite/semantic_segmentation/metric.py,sha256=T9RfPJf4WgqGQTXYvSy08vJG5bjXXJnyYZeW0mlxMa8,7132
25
- valor_lite/semantic_segmentation/utilities.py,sha256=zgVmV8nyKWQK-T4Ov8cZFQzOmTKc5EL7errKFvc2H0g,2957
26
- valor_lite/text_generation/__init__.py,sha256=pGhpWCSZjLM0pPHCtPykAfos55B8ie3mi9EzbNxfj-U,356
27
- valor_lite/text_generation/annotation.py,sha256=O5aXiwCS4WjA-fqn4ly-O0MsTHoIOmqxqCaAp9IeI3M,1270
28
- valor_lite/text_generation/computation.py,sha256=hGDkPfzWY9SDTdozd-nArexJ3ZSNlCIWqHGoD8vO2Cc,18652
29
- valor_lite/text_generation/manager.py,sha256=C4QwvronGHXmYSkaRmUGy7TN0C0aeyDx9Hb-ClNYXK4,24810
30
- valor_lite/text_generation/metric.py,sha256=C9gbWejjOJ23JVLecuUhYW5rkx30NUCfRtgsM46uMds,10409
31
- valor_lite/text_generation/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
- valor_lite/text_generation/llm/exceptions.py,sha256=w4eYSJIJQ_jWuCmquCB6ETr_st_LzbDRlhnlPeqwmfo,349
33
- valor_lite/text_generation/llm/generation.py,sha256=XKPjCxPUZHiWInQSO7wLOb0YtMFLu50s8rHZe1Yz0s0,28954
34
- valor_lite/text_generation/llm/instructions.py,sha256=fz2onBZZWcl5W8iy7zEWkPGU9N07ez6O7SxZA5M2xe4,34056
35
- valor_lite/text_generation/llm/integrations.py,sha256=-rTfdAjq1zH-4ixwYuMQEOQ80pIFzMTe0BYfroVx3Pg,6974
36
- valor_lite/text_generation/llm/utilities.py,sha256=bjqatGgtVTcl1PrMwiDKTYPGJXKrBrx7PDtzIblGSys,1178
37
- valor_lite/text_generation/llm/validators.py,sha256=Wzr5RlfF58_2wOU-uTw7C8skan_fYdhy4Gfn0jSJ8HM,2700
38
- valor_lite-0.36.6.dist-info/METADATA,sha256=tqYUOtCt6-fgLB6xLFE0zs80nLZAzuP20nUG6ny9PW0,5071
39
- valor_lite-0.36.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
40
- valor_lite-0.36.6.dist-info/top_level.txt,sha256=9ujykxSwpl2Hu0_R95UQTR_l07k9UUTSdrpiqmq6zc4,11
41
- valor_lite-0.36.6.dist-info/RECORD,,