valor-lite 0.37.1__tar.gz → 0.37.2__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.
- {valor_lite-0.37.1 → valor_lite-0.37.2}/PKG-INFO +1 -1
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/object_detection/computation.py +116 -97
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/object_detection/evaluator.py +9 -10
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/object_detection/shared.py +25 -4
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite.egg-info/PKG-INFO +1 -1
- {valor_lite-0.37.1 → valor_lite-0.37.2}/README.md +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/pyproject.toml +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/setup.cfg +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/LICENSE +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/__init__.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/cache/__init__.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/cache/compute.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/cache/ephemeral.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/cache/persistent.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/classification/__init__.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/classification/annotation.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/classification/computation.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/classification/evaluator.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/classification/loader.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/classification/metric.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/classification/numpy_compatibility.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/classification/shared.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/classification/utilities.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/exceptions.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/object_detection/__init__.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/object_detection/annotation.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/object_detection/loader.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/object_detection/metric.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/object_detection/utilities.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/schemas.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/semantic_segmentation/__init__.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/semantic_segmentation/annotation.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/semantic_segmentation/computation.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/semantic_segmentation/evaluator.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/semantic_segmentation/loader.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/semantic_segmentation/metric.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/semantic_segmentation/shared.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/semantic_segmentation/utilities.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/text_generation/__init__.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/text_generation/annotation.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/text_generation/computation.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/text_generation/llm/__init__.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/text_generation/llm/exceptions.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/text_generation/llm/generation.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/text_generation/llm/instructions.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/text_generation/llm/integrations.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/text_generation/llm/utilities.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/text_generation/llm/validators.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/text_generation/manager.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite/text_generation/metric.py +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite.egg-info/SOURCES.txt +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite.egg-info/dependency_links.txt +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite.egg-info/requires.txt +0 -0
- {valor_lite-0.37.1 → valor_lite-0.37.2}/valor_lite.egg-info/top_level.txt +0 -0
|
@@ -176,11 +176,32 @@ def compute_polygon_iou(
|
|
|
176
176
|
return ious
|
|
177
177
|
|
|
178
178
|
|
|
179
|
-
def rank_pairs(
|
|
179
|
+
def rank_pairs(
|
|
180
|
+
sorted_pairs: NDArray[np.float64],
|
|
181
|
+
) -> tuple[NDArray[np.float64], NDArray[np.intp]]:
|
|
180
182
|
"""
|
|
181
183
|
Prunes and ranks prediction pairs.
|
|
182
184
|
|
|
183
185
|
Should result in a single pair per prediction annotation.
|
|
186
|
+
|
|
187
|
+
Parameters
|
|
188
|
+
----------
|
|
189
|
+
sorted_pairs : NDArray[np.float64]
|
|
190
|
+
Ranked annotation pairs.
|
|
191
|
+
Index 0 - Datum Index
|
|
192
|
+
Index 1 - GroundTruth Index
|
|
193
|
+
Index 2 - Prediction Index
|
|
194
|
+
Index 3 - GroundTruth Label Index
|
|
195
|
+
Index 4 - Prediction Label Index
|
|
196
|
+
Index 5 - IOU
|
|
197
|
+
Index 6 - Score
|
|
198
|
+
|
|
199
|
+
Returns
|
|
200
|
+
-------
|
|
201
|
+
NDArray[float64]
|
|
202
|
+
Ranked prediction pairs.
|
|
203
|
+
NDArray[intp]
|
|
204
|
+
Indices of ranked prediction pairs.
|
|
184
205
|
"""
|
|
185
206
|
|
|
186
207
|
# remove unmatched ground truths
|
|
@@ -197,8 +218,10 @@ def rank_pairs(sorted_pairs: NDArray[np.float64]):
|
|
|
197
218
|
pairs = pairs[mask_label_match | mask_unmatched_predictions]
|
|
198
219
|
indices = indices[mask_label_match | mask_unmatched_predictions]
|
|
199
220
|
|
|
200
|
-
# only keep the highest ranked
|
|
201
|
-
_, unique_indices = np.unique(
|
|
221
|
+
# only keep the highest ranked prediction (datum_id, prediction_id, predicted_label_id)
|
|
222
|
+
_, unique_indices = np.unique(
|
|
223
|
+
pairs[:, [0, 2, 4]], axis=0, return_index=True
|
|
224
|
+
)
|
|
202
225
|
pairs = pairs[unique_indices]
|
|
203
226
|
indices = indices[unique_indices]
|
|
204
227
|
|
|
@@ -216,55 +239,57 @@ def rank_pairs(sorted_pairs: NDArray[np.float64]):
|
|
|
216
239
|
|
|
217
240
|
|
|
218
241
|
def calculate_ranking_boundaries(
|
|
219
|
-
ranked_pairs: NDArray[np.float64],
|
|
220
|
-
):
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
ious = ranked_pairs[:, 5]
|
|
242
|
+
ranked_pairs: NDArray[np.float64],
|
|
243
|
+
) -> NDArray[np.float64]:
|
|
244
|
+
"""
|
|
245
|
+
Determine IOU boundaries for computing AP across chunks.
|
|
224
246
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
247
|
+
Parameters
|
|
248
|
+
----------
|
|
249
|
+
ranked_pairs : NDArray[np.float64]
|
|
250
|
+
Ranked annotation pairs.
|
|
251
|
+
Index 0 - Datum Index
|
|
252
|
+
Index 1 - GroundTruth Index
|
|
253
|
+
Index 2 - Prediction Index
|
|
254
|
+
Index 3 - GroundTruth Label Index
|
|
255
|
+
Index 4 - Prediction Label Index
|
|
256
|
+
Index 5 - IOU
|
|
257
|
+
Index 6 - Score
|
|
258
|
+
|
|
259
|
+
Returns
|
|
260
|
+
-------
|
|
261
|
+
NDArray[np.float64]
|
|
262
|
+
A 1-D array containing the lower IOU boundary for classifying pairs as true-positive across chunks.
|
|
263
|
+
"""
|
|
264
|
+
# groundtruths defined as (datum_id, groundtruth_id, groundtruth_label_id)
|
|
265
|
+
gts = ranked_pairs[:, (0, 1, 3)].astype(np.int64)
|
|
266
|
+
ious = ranked_pairs[:, 5]
|
|
232
267
|
|
|
233
|
-
|
|
234
|
-
winning_predictions[gt_ids < 0] = False # null gts cannot be won
|
|
235
|
-
iou_boundary = np.zeros_like(ious)
|
|
268
|
+
iou_boundary = np.ones_like(ious) * 2 # impossible bound
|
|
236
269
|
|
|
270
|
+
mask_valid_gts = gts[:, 1] >= 0
|
|
271
|
+
unique_gts = np.unique(gts[mask_valid_gts], axis=0)
|
|
237
272
|
for gt in unique_gts:
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
mask_plabel = (ranked_pairs[:, 4] == label) & mask_gts
|
|
243
|
-
if mask_plabel.sum() <= 1:
|
|
244
|
-
continue
|
|
273
|
+
mask_gt = (gts == gt).all(axis=1)
|
|
274
|
+
if mask_gt.sum() <= 1:
|
|
275
|
+
iou_boundary[mask_gt] = 0.0
|
|
276
|
+
continue
|
|
245
277
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
idx_dec = np.where(~mask_increasing_iou)[0]
|
|
251
|
-
if idx_dec.size == 1:
|
|
252
|
-
mask_increasing_iou[idx_dec[0] :] = False
|
|
278
|
+
running_max = np.maximum.accumulate(ious[mask_gt])
|
|
279
|
+
mask_rmax = np.isclose(running_max, ious[mask_gt])
|
|
280
|
+
mask_rmax[1:] &= running_max[1:] > running_max[:-1]
|
|
281
|
+
mask_gt[mask_gt] &= mask_rmax
|
|
253
282
|
|
|
254
|
-
|
|
255
|
-
iou_boundary[mask_plabel][1:] = labeled_ious[:-1]
|
|
256
|
-
iou_boundary[mask_plabel][
|
|
257
|
-
~mask_increasing_iou
|
|
258
|
-
] = 2.0 # arbitrary >1.0 value
|
|
283
|
+
indices = np.where(mask_gt)[0]
|
|
259
284
|
|
|
260
|
-
|
|
261
|
-
indices =
|
|
262
|
-
winning_predictions[indices] = False
|
|
285
|
+
iou_boundary[indices[0]] = 0.0
|
|
286
|
+
iou_boundary[indices[1:]] = ious[indices[:-1]]
|
|
263
287
|
|
|
264
|
-
return iou_boundary
|
|
288
|
+
return iou_boundary
|
|
265
289
|
|
|
266
290
|
|
|
267
|
-
def rank_table(tbl: pa.Table
|
|
291
|
+
def rank_table(tbl: pa.Table) -> pa.Table:
|
|
292
|
+
"""Rank table for AP computation."""
|
|
268
293
|
numeric_columns = [
|
|
269
294
|
"datum_id",
|
|
270
295
|
"gt_id",
|
|
@@ -278,24 +303,24 @@ def rank_table(tbl: pa.Table, number_of_labels: int) -> pa.Table:
|
|
|
278
303
|
("pd_score", "descending"),
|
|
279
304
|
("iou", "descending"),
|
|
280
305
|
]
|
|
306
|
+
|
|
307
|
+
# initial sort
|
|
281
308
|
sorted_tbl = tbl.sort_by(sorting_args)
|
|
282
309
|
pairs = np.column_stack(
|
|
283
310
|
[sorted_tbl[col].to_numpy() for col in numeric_columns]
|
|
284
311
|
)
|
|
285
|
-
|
|
312
|
+
|
|
313
|
+
# rank pairs
|
|
314
|
+
ranked_pairs, indices = rank_pairs(pairs)
|
|
286
315
|
ranked_tbl = sorted_tbl.take(indices)
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
)
|
|
290
|
-
ranked_tbl = ranked_tbl.append_column(
|
|
291
|
-
pa.field("high_score", pa.bool_()),
|
|
292
|
-
pa.array(winning_predictions, type=pa.bool_()),
|
|
293
|
-
)
|
|
316
|
+
|
|
317
|
+
# find boundaries
|
|
318
|
+
lower_iou_bound = calculate_ranking_boundaries(ranked_pairs)
|
|
294
319
|
ranked_tbl = ranked_tbl.append_column(
|
|
295
320
|
pa.field("iou_prev", pa.float64()),
|
|
296
321
|
pa.array(lower_iou_bound, type=pa.float64()),
|
|
297
322
|
)
|
|
298
|
-
|
|
323
|
+
|
|
299
324
|
return ranked_tbl
|
|
300
325
|
|
|
301
326
|
|
|
@@ -306,41 +331,42 @@ def compute_counts(
|
|
|
306
331
|
number_of_groundtruths_per_label: NDArray[np.uint64],
|
|
307
332
|
number_of_labels: int,
|
|
308
333
|
running_counts: NDArray[np.uint64],
|
|
309
|
-
|
|
334
|
+
pr_curve: NDArray[np.float64],
|
|
335
|
+
) -> NDArray[np.uint64]:
|
|
310
336
|
"""
|
|
311
337
|
Computes Object Detection metrics.
|
|
312
338
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
Index 0 - Datum Index
|
|
316
|
-
Index 1 - GroundTruth Index
|
|
317
|
-
Index 2 - Prediction Index
|
|
318
|
-
Index 3 - GroundTruth Label Index
|
|
319
|
-
Index 4 - Prediction Label Index
|
|
320
|
-
Index 5 - IOU
|
|
321
|
-
Index 6 - Score
|
|
322
|
-
Index 7 - IOU Lower Boundary
|
|
323
|
-
Index 8 - Winning Prediction
|
|
339
|
+
Precision-recall curve and running counts are updated in-place.
|
|
324
340
|
|
|
325
341
|
Parameters
|
|
326
342
|
----------
|
|
327
343
|
ranked_pairs : NDArray[np.float64]
|
|
328
344
|
A ranked array summarizing the IOU calculations of one or more pairs.
|
|
345
|
+
Index 0 - Datum Index
|
|
346
|
+
Index 1 - GroundTruth Index
|
|
347
|
+
Index 2 - Prediction Index
|
|
348
|
+
Index 3 - GroundTruth Label Index
|
|
349
|
+
Index 4 - Prediction Label Index
|
|
350
|
+
Index 5 - IOU
|
|
351
|
+
Index 6 - Score
|
|
352
|
+
Index 7 - IOU Lower Boundary
|
|
329
353
|
iou_thresholds : NDArray[np.float64]
|
|
330
354
|
A 1-D array containing IOU thresholds.
|
|
331
355
|
score_thresholds : NDArray[np.float64]
|
|
332
356
|
A 1-D array containing score thresholds.
|
|
357
|
+
number_of_groundtruths_per_label : NDArray[np.uint64]
|
|
358
|
+
A 1-D array containing total number of ground truths per label.
|
|
359
|
+
number_of_labels : int
|
|
360
|
+
Total number of unique labels.
|
|
361
|
+
running_counts : NDArray[np.uint64]
|
|
362
|
+
A 2-D array containing running counts of total predictions and true-positive. This array is mutated.
|
|
363
|
+
pr_curve : NDArray[np.float64]
|
|
364
|
+
A 2-D array containing 101-point binning of precision and score over a fixed recall interval. This array is mutated.
|
|
333
365
|
|
|
334
366
|
Returns
|
|
335
367
|
-------
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
tuple[NDArray[np.float64], NDArray[np.float64]]
|
|
339
|
-
Average Recall results (AR, mAR).
|
|
340
|
-
NDArray[np.float64]
|
|
341
|
-
Precision, Recall, TP, FP, FN, F1 Score.
|
|
342
|
-
NDArray[np.float64]
|
|
343
|
-
Interpolated Precision-Recall Curves.
|
|
368
|
+
NDArray[uint64]
|
|
369
|
+
Batched counts of TP, FP, FN.
|
|
344
370
|
"""
|
|
345
371
|
n_rows = ranked_pairs.shape[0]
|
|
346
372
|
n_labels = number_of_labels
|
|
@@ -349,7 +375,6 @@ def compute_counts(
|
|
|
349
375
|
|
|
350
376
|
# initialize result arrays
|
|
351
377
|
counts = np.zeros((n_ious, n_scores, 3, n_labels), dtype=np.uint64)
|
|
352
|
-
pr_curve = np.zeros((n_ious, n_labels, 101, 2))
|
|
353
378
|
|
|
354
379
|
# start computation
|
|
355
380
|
ids = ranked_pairs[:, :5].astype(np.int64)
|
|
@@ -359,7 +384,6 @@ def compute_counts(
|
|
|
359
384
|
ious = ranked_pairs[:, 5]
|
|
360
385
|
scores = ranked_pairs[:, 6]
|
|
361
386
|
prev_ious = ranked_pairs[:, 7]
|
|
362
|
-
winners = ranked_pairs[:, 8].astype(np.bool_)
|
|
363
387
|
|
|
364
388
|
unique_pd_labels, _ = np.unique(pd_labels, return_index=True)
|
|
365
389
|
|
|
@@ -384,9 +408,9 @@ def compute_counts(
|
|
|
384
408
|
mask_iou_prev = prev_ious < iou_thresholds[iou_idx]
|
|
385
409
|
mask_iou = mask_iou_curr & mask_iou_prev
|
|
386
410
|
|
|
387
|
-
mask_tp_outer = mask_tp & mask_iou
|
|
411
|
+
mask_tp_outer = mask_tp & mask_iou
|
|
388
412
|
mask_fp_outer = mask_fp & (
|
|
389
|
-
(~mask_gt_exists_labels_match & mask_iou) | ~mask_iou
|
|
413
|
+
(~mask_gt_exists_labels_match & mask_iou) | ~mask_iou
|
|
390
414
|
)
|
|
391
415
|
|
|
392
416
|
for score_idx in range(n_scores):
|
|
@@ -421,33 +445,29 @@ def compute_counts(
|
|
|
421
445
|
)
|
|
422
446
|
|
|
423
447
|
# create true-positive mask score threshold
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
tp_candidates[:, [0, 1, 3]], axis=0, return_index=True
|
|
427
|
-
)
|
|
428
|
-
mask_gt_unique = np.zeros(tp_candidates.shape[0], dtype=np.bool_)
|
|
429
|
-
mask_gt_unique[indices_gt_unique] = True
|
|
430
|
-
true_positives_mask = np.zeros(n_rows, dtype=np.bool_)
|
|
431
|
-
true_positives_mask[mask_tp_outer] = mask_gt_unique
|
|
448
|
+
mask_tps = mask_tp_outer
|
|
449
|
+
true_positives_mask = mask_tps & mask_iou_prev
|
|
432
450
|
|
|
433
451
|
# count running tp and total for AP
|
|
434
452
|
for pd_label in unique_pd_labels:
|
|
435
453
|
mask_pd_label = pd_labels == pd_label
|
|
454
|
+
total_count = mask_pd_label.sum()
|
|
455
|
+
if total_count == 0:
|
|
456
|
+
continue
|
|
436
457
|
|
|
437
458
|
# running total prediction count
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
running_counts[iou_idx, pd_label, 0],
|
|
441
|
-
running_counts[iou_idx, pd_label, 0] + total_count,
|
|
459
|
+
running_total_count[iou_idx, mask_pd_label] = np.arange(
|
|
460
|
+
running_counts[iou_idx, pd_label, 0] + 1,
|
|
461
|
+
running_counts[iou_idx, pd_label, 0] + total_count + 1,
|
|
442
462
|
)
|
|
443
463
|
running_counts[iou_idx, pd_label, 0] += total_count
|
|
444
464
|
|
|
445
465
|
# running true-positive count
|
|
446
466
|
mask_tp_for_counting = mask_pd_label & true_positives_mask
|
|
447
467
|
tp_count = mask_tp_for_counting.sum()
|
|
448
|
-
running_tp_count[iou_idx
|
|
449
|
-
running_counts[iou_idx, pd_label, 1],
|
|
450
|
-
running_counts[iou_idx, pd_label, 1] + tp_count,
|
|
468
|
+
running_tp_count[iou_idx, mask_tp_for_counting] = np.arange(
|
|
469
|
+
running_counts[iou_idx, pd_label, 1] + 1,
|
|
470
|
+
running_counts[iou_idx, pd_label, 1] + tp_count + 1,
|
|
451
471
|
)
|
|
452
472
|
running_counts[iou_idx, pd_label, 1] += tp_count
|
|
453
473
|
|
|
@@ -474,15 +494,14 @@ def compute_counts(
|
|
|
474
494
|
pr_curve[iou_idx, pd_labels, recall_index[iou_idx], 0],
|
|
475
495
|
precision[iou_idx],
|
|
476
496
|
)
|
|
477
|
-
pr_curve[
|
|
478
|
-
|
|
479
|
-
|
|
497
|
+
pr_curve[
|
|
498
|
+
iou_idx, pd_labels[::-1], recall_index[iou_idx][::-1], 1
|
|
499
|
+
] = np.maximum(
|
|
500
|
+
pr_curve[iou_idx, pd_labels[::-1], recall_index[iou_idx][::-1], 1],
|
|
501
|
+
scores[::-1],
|
|
480
502
|
)
|
|
481
503
|
|
|
482
|
-
return
|
|
483
|
-
counts,
|
|
484
|
-
pr_curve,
|
|
485
|
-
)
|
|
504
|
+
return counts
|
|
486
505
|
|
|
487
506
|
|
|
488
507
|
def compute_precision_recall_f1(
|
|
@@ -79,7 +79,7 @@ class Builder:
|
|
|
79
79
|
batch_size=batch_size,
|
|
80
80
|
)
|
|
81
81
|
ranked_writer = MemoryCacheWriter.create(
|
|
82
|
-
schema=generate_ranked_schema(),
|
|
82
|
+
schema=generate_ranked_schema(metadata_fields),
|
|
83
83
|
batch_size=batch_size,
|
|
84
84
|
)
|
|
85
85
|
|
|
@@ -126,7 +126,7 @@ class Builder:
|
|
|
126
126
|
)
|
|
127
127
|
ranked_writer = FileCacheWriter.create(
|
|
128
128
|
path=generate_ranked_cache_path(path),
|
|
129
|
-
schema=generate_ranked_schema(),
|
|
129
|
+
schema=generate_ranked_schema(metadata_fields),
|
|
130
130
|
batch_size=batch_size,
|
|
131
131
|
rows_per_file=rows_per_file,
|
|
132
132
|
compression=compression,
|
|
@@ -163,11 +163,9 @@ class Builder:
|
|
|
163
163
|
columns=[
|
|
164
164
|
field.name
|
|
165
165
|
for field in self._ranked_writer.schema
|
|
166
|
-
if field.name
|
|
166
|
+
if field.name != "iou_prev"
|
|
167
167
|
],
|
|
168
|
-
table_sort_override=
|
|
169
|
-
tbl, number_of_labels=n_labels
|
|
170
|
-
),
|
|
168
|
+
table_sort_override=rank_table,
|
|
171
169
|
)
|
|
172
170
|
self._ranked_writer.flush()
|
|
173
171
|
|
|
@@ -454,7 +452,8 @@ class Evaluator:
|
|
|
454
452
|
|
|
455
453
|
counts = np.zeros((n_ious, n_scores, 3, n_labels), dtype=np.uint64)
|
|
456
454
|
pr_curve = np.zeros((n_ious, n_labels, 101, 2), dtype=np.float64)
|
|
457
|
-
running_counts = np.
|
|
455
|
+
running_counts = np.zeros((n_ious, n_labels, 2), dtype=np.uint64)
|
|
456
|
+
|
|
458
457
|
for pairs in self._ranked_reader.iterate_arrays(
|
|
459
458
|
numeric_columns=[
|
|
460
459
|
"datum_id",
|
|
@@ -465,23 +464,22 @@ class Evaluator:
|
|
|
465
464
|
"iou",
|
|
466
465
|
"pd_score",
|
|
467
466
|
"iou_prev",
|
|
468
|
-
"high_score",
|
|
469
467
|
],
|
|
470
468
|
filter=datums,
|
|
471
469
|
):
|
|
472
470
|
if pairs.size == 0:
|
|
473
471
|
continue
|
|
474
472
|
|
|
475
|
-
|
|
473
|
+
batch_counts = compute_counts(
|
|
476
474
|
ranked_pairs=pairs,
|
|
477
475
|
iou_thresholds=np.array(iou_thresholds),
|
|
478
476
|
score_thresholds=np.array(score_thresholds),
|
|
479
477
|
number_of_groundtruths_per_label=n_gts_per_lbl,
|
|
480
478
|
number_of_labels=len(self._index_to_label),
|
|
481
479
|
running_counts=running_counts,
|
|
480
|
+
pr_curve=pr_curve,
|
|
482
481
|
)
|
|
483
482
|
counts += batch_counts
|
|
484
|
-
pr_curve = np.maximum(batch_pr_curve, pr_curve)
|
|
485
483
|
|
|
486
484
|
# fn count
|
|
487
485
|
counts[:, :, 2, :] = n_gts_per_lbl - counts[:, :, 0, :]
|
|
@@ -551,6 +549,7 @@ class Evaluator:
|
|
|
551
549
|
(n_ious, n_scores, n_labels), dtype=np.uint64
|
|
552
550
|
)
|
|
553
551
|
unmatched_predictions = np.zeros_like(unmatched_groundtruths)
|
|
552
|
+
|
|
554
553
|
for pairs in self._detailed_reader.iterate_arrays(
|
|
555
554
|
numeric_columns=[
|
|
556
555
|
"datum_id",
|
|
@@ -68,8 +68,10 @@ def generate_detailed_schema(
|
|
|
68
68
|
return pa.schema(reserved_fields + metadata_fields)
|
|
69
69
|
|
|
70
70
|
|
|
71
|
-
def generate_ranked_schema(
|
|
72
|
-
|
|
71
|
+
def generate_ranked_schema(
|
|
72
|
+
metadata_fields: list[tuple[str, str | pa.DataType]] | None
|
|
73
|
+
) -> pa.Schema:
|
|
74
|
+
reserved_detailed_fields = [
|
|
73
75
|
("datum_uid", pa.string()),
|
|
74
76
|
("datum_id", pa.int64()),
|
|
75
77
|
# groundtruth
|
|
@@ -81,10 +83,29 @@ def generate_ranked_schema() -> pa.Schema:
|
|
|
81
83
|
("pd_score", pa.float64()),
|
|
82
84
|
# pair
|
|
83
85
|
("iou", pa.float64()),
|
|
84
|
-
|
|
86
|
+
]
|
|
87
|
+
reserved_ranking_fields = [
|
|
85
88
|
("iou_prev", pa.float64()),
|
|
86
89
|
]
|
|
87
|
-
|
|
90
|
+
metadata_fields = metadata_fields if metadata_fields else []
|
|
91
|
+
|
|
92
|
+
# validate
|
|
93
|
+
reserved_field_names = {
|
|
94
|
+
f[0] for f in reserved_detailed_fields + reserved_ranking_fields
|
|
95
|
+
}
|
|
96
|
+
metadata_field_names = {f[0] for f in metadata_fields}
|
|
97
|
+
if conflicting := reserved_field_names & metadata_field_names:
|
|
98
|
+
raise ValueError(
|
|
99
|
+
f"metadata fields {conflicting} conflict with reserved fields"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
return pa.schema(
|
|
103
|
+
[
|
|
104
|
+
*reserved_detailed_fields,
|
|
105
|
+
*metadata_fields,
|
|
106
|
+
*reserved_ranking_fields,
|
|
107
|
+
]
|
|
108
|
+
)
|
|
88
109
|
|
|
89
110
|
|
|
90
111
|
def encode_metadata_fields(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|