supervisely 6.73.268__py3-none-any.whl → 6.73.270__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 supervisely might be problematic. Click here for more details.
- supervisely/api/file_api.py +1 -1
- supervisely/nn/benchmark/utils/semantic_segmentation/evaluator.py +13 -103
- supervisely/nn/inference/inference.py +411 -64
- supervisely/nn/training/gui/gui.py +13 -5
- supervisely/nn/training/gui/training_artifacts.py +121 -51
- supervisely/nn/training/train_app.py +79 -23
- {supervisely-6.73.268.dist-info → supervisely-6.73.270.dist-info}/METADATA +1 -1
- {supervisely-6.73.268.dist-info → supervisely-6.73.270.dist-info}/RECORD +12 -12
- {supervisely-6.73.268.dist-info → supervisely-6.73.270.dist-info}/LICENSE +0 -0
- {supervisely-6.73.268.dist-info → supervisely-6.73.270.dist-info}/WHEEL +0 -0
- {supervisely-6.73.268.dist-info → supervisely-6.73.270.dist-info}/entry_points.txt +0 -0
- {supervisely-6.73.268.dist-info → supervisely-6.73.270.dist-info}/top_level.txt +0 -0
supervisely/api/file_api.py
CHANGED
|
@@ -1620,7 +1620,7 @@ class FileApi(ModuleApiBase):
|
|
|
1620
1620
|
downloaded_file_hash = await get_file_hash_async(local_save_path)
|
|
1621
1621
|
if hash_to_check != downloaded_file_hash:
|
|
1622
1622
|
raise RuntimeError(
|
|
1623
|
-
f"Downloaded hash of
|
|
1623
|
+
f"Downloaded hash of file path: '{remote_path}' does not match the expected hash: {downloaded_file_hash} != {hash_to_check}"
|
|
1624
1624
|
)
|
|
1625
1625
|
if progress_cb is not None and progress_cb_type == "number":
|
|
1626
1626
|
progress_cb(1)
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import os
|
|
2
1
|
from collections import defaultdict
|
|
3
|
-
from
|
|
2
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
3
|
+
from typing import Iterable, List, Optional, Union
|
|
4
4
|
|
|
5
|
-
import cv2
|
|
6
5
|
import numpy as np
|
|
7
6
|
import pandas as pd
|
|
8
7
|
|
|
@@ -12,10 +11,7 @@ from supervisely.nn.benchmark.utils.semantic_segmentation.utils import (
|
|
|
12
11
|
get_exterior_boundary,
|
|
13
12
|
get_interior_boundary,
|
|
14
13
|
get_single_contiguous_segment,
|
|
15
|
-
one_hot,
|
|
16
|
-
single_one_hot,
|
|
17
14
|
)
|
|
18
|
-
from supervisely.sly_logger import logger
|
|
19
15
|
from supervisely.task.progress import tqdm_sly
|
|
20
16
|
|
|
21
17
|
ERROR_CODES = {
|
|
@@ -63,11 +59,6 @@ class Evaluator:
|
|
|
63
59
|
:param boundary_implementation: Choose "exact" for the euclidean pixel distance.
|
|
64
60
|
The Boundary IoU paper uses the L1 distance ("fast").
|
|
65
61
|
"""
|
|
66
|
-
global torch, np, GPU, numpy
|
|
67
|
-
import torch # pylint: disable=import-error
|
|
68
|
-
|
|
69
|
-
numpy = np
|
|
70
|
-
GPU = False
|
|
71
62
|
|
|
72
63
|
self.progress = progress or tqdm_sly
|
|
73
64
|
self.class_names = class_names
|
|
@@ -109,8 +100,6 @@ class Evaluator:
|
|
|
109
100
|
self.per_image_metrics = pd.DataFrame()
|
|
110
101
|
|
|
111
102
|
def extract_masks(self, seg, cl, n_cl):
|
|
112
|
-
if GPU:
|
|
113
|
-
seg = np.asarray(seg)
|
|
114
103
|
h, w = seg.shape
|
|
115
104
|
masks = np.zeros((n_cl, h, w))
|
|
116
105
|
|
|
@@ -120,8 +109,6 @@ class Evaluator:
|
|
|
120
109
|
return masks
|
|
121
110
|
|
|
122
111
|
def extract_masks_gen(self, seg, cl):
|
|
123
|
-
if GPU:
|
|
124
|
-
seg = np.asarray(seg)
|
|
125
112
|
h, w = seg.shape
|
|
126
113
|
for c in cl:
|
|
127
114
|
mask = np.zeros((h, w))
|
|
@@ -164,21 +151,18 @@ class Evaluator:
|
|
|
164
151
|
self.boundary_iou_union_counts = np.zeros(self.num_classes, dtype=np.int64)
|
|
165
152
|
|
|
166
153
|
with self.progress(message="Calculating metrics...", total=len(loader)) as pbar:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
self.
|
|
154
|
+
def _func(loader_data):
|
|
155
|
+
pred, gt, img = loader_data
|
|
156
|
+
sample_results = self.evaluate_sample(pred, gt, img)
|
|
157
|
+
self.update_results(sample_results, img)
|
|
170
158
|
self.confusion_matrix = self.calc_confusion_matrix(
|
|
171
|
-
pred,
|
|
172
|
-
gt,
|
|
173
|
-
self.confusion_matrix,
|
|
174
|
-
img_name,
|
|
159
|
+
pred, gt, self.confusion_matrix, img
|
|
175
160
|
)
|
|
176
161
|
pbar.update(1)
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
self.boundary_iou_union_counts = self.boundary_iou_union_counts.get()
|
|
162
|
+
|
|
163
|
+
with ThreadPoolExecutor(max_workers=4) as executor:
|
|
164
|
+
for _ in executor.map(_func, loader):
|
|
165
|
+
pass
|
|
182
166
|
|
|
183
167
|
result = self.calculate_error_metrics()
|
|
184
168
|
normalized_confusion_matrix = self.confusion_matrix / self.confusion_matrix.sum(
|
|
@@ -319,14 +303,14 @@ class Evaluator:
|
|
|
319
303
|
e_extent_ou_renormed = e_extent / (tp + e_boundary + e_extent)
|
|
320
304
|
e_segment_ou_renormed = e_segment_ou
|
|
321
305
|
|
|
322
|
-
with
|
|
306
|
+
with np.errstate(invalid="ignore"):
|
|
323
307
|
boundary_iou = (
|
|
324
308
|
image_stats["boundary_iou_intersection_counts"]
|
|
325
309
|
/ image_stats["boundary_iou_union_counts"]
|
|
326
310
|
)
|
|
327
311
|
|
|
328
312
|
def postprocess_values(values):
|
|
329
|
-
values = values[~
|
|
313
|
+
values = values[~np.isnan(values)]
|
|
330
314
|
value = round(float(np.mean(values)), 2)
|
|
331
315
|
return value
|
|
332
316
|
|
|
@@ -352,10 +336,6 @@ class Evaluator:
|
|
|
352
336
|
H, W = tp_mask.shape[-2:]
|
|
353
337
|
if self.use_relative_boundary_width:
|
|
354
338
|
img_diag = np.sqrt(H**2 + W**2)
|
|
355
|
-
if GPU:
|
|
356
|
-
img_diag = img_diag.get()
|
|
357
|
-
tp_mask = tp_mask.get()
|
|
358
|
-
tn_mask = tn_mask.get()
|
|
359
339
|
|
|
360
340
|
boundary_width = int(round(self.boundary_width * img_diag))
|
|
361
341
|
else:
|
|
@@ -368,21 +348,10 @@ class Evaluator:
|
|
|
368
348
|
tn_mask, width=boundary_width, implementation=self.boundary_implementation
|
|
369
349
|
)
|
|
370
350
|
|
|
371
|
-
if GPU:
|
|
372
|
-
tp_ext_boundary, tn_ext_boundary = np.asarray(tp_ext_boundary), np.asarray(
|
|
373
|
-
tn_ext_boundary
|
|
374
|
-
)
|
|
375
|
-
|
|
376
351
|
boundary_intersection = np.logical_and(tp_ext_boundary, tn_ext_boundary)
|
|
377
352
|
fp_boundary_mask_naive = np.logical_and(fp_mask, boundary_intersection)
|
|
378
353
|
fn_boundary_mask_naive = np.logical_and(fn_mask, boundary_intersection)
|
|
379
354
|
|
|
380
|
-
if GPU:
|
|
381
|
-
fp_boundary_mask_naive, fn_boundary_mask_naive = (
|
|
382
|
-
fp_boundary_mask_naive.get(),
|
|
383
|
-
fn_boundary_mask_naive.get(),
|
|
384
|
-
)
|
|
385
|
-
|
|
386
355
|
dilated_fp_boundary_mask = dilate_mask(
|
|
387
356
|
mask=fp_boundary_mask_naive,
|
|
388
357
|
width=boundary_width,
|
|
@@ -394,17 +363,9 @@ class Evaluator:
|
|
|
394
363
|
implementation=self.boundary_implementation,
|
|
395
364
|
)
|
|
396
365
|
|
|
397
|
-
if GPU:
|
|
398
|
-
dilated_fp_boundary_mask = np.asarray(dilated_fp_boundary_mask)
|
|
399
|
-
dilated_fn_boundary_mask = np.asarray(dilated_fn_boundary_mask)
|
|
400
|
-
|
|
401
366
|
fp_boundary_mask = np.logical_and(dilated_fp_boundary_mask, fp_mask)
|
|
402
367
|
fn_boundary_mask = np.logical_and(dilated_fn_boundary_mask, fn_mask)
|
|
403
368
|
|
|
404
|
-
if GPU:
|
|
405
|
-
fp_boundary_mask = fp_boundary_mask.get()
|
|
406
|
-
fn_boundary_mask = fn_boundary_mask.get()
|
|
407
|
-
|
|
408
369
|
# check if every segment of boundary errors has a TP and a TN as direct neighbor
|
|
409
370
|
fp_boundary_segments = get_contiguous_segments(fp_boundary_mask)
|
|
410
371
|
fn_boundary_segments = get_contiguous_segments(fn_boundary_mask)
|
|
@@ -440,10 +401,6 @@ class Evaluator:
|
|
|
440
401
|
H, W = tp_mask.shape[-2:]
|
|
441
402
|
if self.use_relative_boundary_width:
|
|
442
403
|
img_diag = np.sqrt(H**2 + W**2)
|
|
443
|
-
if GPU:
|
|
444
|
-
img_diag = img_diag.get()
|
|
445
|
-
tp_mask = tp_mask.get()
|
|
446
|
-
tn_mask = tn_mask.get()
|
|
447
404
|
|
|
448
405
|
boundary_width = int(round(self.boundary_width * img_diag))
|
|
449
406
|
else:
|
|
@@ -456,21 +413,10 @@ class Evaluator:
|
|
|
456
413
|
tn_mask, width=boundary_width, implementation=self.boundary_implementation
|
|
457
414
|
)
|
|
458
415
|
|
|
459
|
-
if GPU:
|
|
460
|
-
tp_ext_boundary, tn_ext_boundary = np.asarray(tp_ext_boundary), np.asarray(
|
|
461
|
-
tn_ext_boundary
|
|
462
|
-
)
|
|
463
|
-
|
|
464
416
|
boundary_intersection = np.logical_and(tp_ext_boundary, tn_ext_boundary)
|
|
465
417
|
fp_boundary_mask_naive = np.logical_and(fp_mask, boundary_intersection)
|
|
466
418
|
fn_boundary_mask_naive = np.logical_and(fn_mask, boundary_intersection)
|
|
467
419
|
|
|
468
|
-
if GPU:
|
|
469
|
-
fp_boundary_mask_naive, fn_boundary_mask_naive = (
|
|
470
|
-
fp_boundary_mask_naive.get(),
|
|
471
|
-
fn_boundary_mask_naive.get(),
|
|
472
|
-
)
|
|
473
|
-
|
|
474
420
|
dilated_fp_boundary_mask = dilate_mask(
|
|
475
421
|
mask=fp_boundary_mask_naive,
|
|
476
422
|
width=boundary_width,
|
|
@@ -482,17 +428,9 @@ class Evaluator:
|
|
|
482
428
|
implementation=self.boundary_implementation,
|
|
483
429
|
)
|
|
484
430
|
|
|
485
|
-
if GPU:
|
|
486
|
-
dilated_fp_boundary_mask = np.asarray(dilated_fp_boundary_mask)
|
|
487
|
-
dilated_fn_boundary_mask = np.asarray(dilated_fn_boundary_mask)
|
|
488
|
-
|
|
489
431
|
fp_boundary_mask = np.logical_and(dilated_fp_boundary_mask, fp_mask)
|
|
490
432
|
fn_boundary_mask = np.logical_and(dilated_fn_boundary_mask, fn_mask)
|
|
491
433
|
|
|
492
|
-
if GPU:
|
|
493
|
-
fp_boundary_mask = fp_boundary_mask.get()
|
|
494
|
-
fn_boundary_mask = fn_boundary_mask.get()
|
|
495
|
-
|
|
496
434
|
# check if every segment of boundary errors has a TP and a TN as direct neighbor
|
|
497
435
|
fp_boundary_segments = get_single_contiguous_segment(fp_boundary_mask)
|
|
498
436
|
fn_boundary_segments = get_single_contiguous_segment(fn_boundary_mask)
|
|
@@ -528,9 +466,6 @@ class Evaluator:
|
|
|
528
466
|
pred_one_hot,
|
|
529
467
|
gt_one_hot,
|
|
530
468
|
):
|
|
531
|
-
if GPU:
|
|
532
|
-
pred_one_hot = pred_one_hot.get()
|
|
533
|
-
gt_one_hot = gt_one_hot.get()
|
|
534
469
|
|
|
535
470
|
pred_segments = get_contiguous_segments(pred_one_hot)
|
|
536
471
|
gt_segments = get_contiguous_segments(gt_one_hot)
|
|
@@ -570,8 +505,6 @@ class Evaluator:
|
|
|
570
505
|
else: # only FP segment errors for this class
|
|
571
506
|
# positive prediction must be a superset of unassigned
|
|
572
507
|
# every prediction can only be unassigned or ignore
|
|
573
|
-
if GPU:
|
|
574
|
-
pred_c = np.asarray(pred_c)
|
|
575
508
|
assert pred_c[results[c] == ERROR_CODES["unassigned"]].all()
|
|
576
509
|
results[c][results[c] == ERROR_CODES["unassigned"]] = ERROR_CODES["FP_segment"]
|
|
577
510
|
else:
|
|
@@ -588,9 +521,6 @@ class Evaluator:
|
|
|
588
521
|
pred_mask,
|
|
589
522
|
gt_mask,
|
|
590
523
|
):
|
|
591
|
-
if GPU:
|
|
592
|
-
pred_mask = pred_mask.get()
|
|
593
|
-
gt_mask = gt_mask.get()
|
|
594
524
|
|
|
595
525
|
pred_segments = get_single_contiguous_segment(pred_mask)
|
|
596
526
|
gt_segments = get_single_contiguous_segment(gt_mask)
|
|
@@ -629,8 +559,6 @@ class Evaluator:
|
|
|
629
559
|
else: # only FP segment errors for this class
|
|
630
560
|
# positive prediction must be a superset of unassigned
|
|
631
561
|
# every prediction can only be unassigned or ignore
|
|
632
|
-
if GPU:
|
|
633
|
-
pred_mask = np.asarray(pred_mask)
|
|
634
562
|
assert pred_mask[class_results == ERROR_CODES["unassigned"]].all()
|
|
635
563
|
class_results[class_results == ERROR_CODES["unassigned"]] = ERROR_CODES[
|
|
636
564
|
"FP_segment"
|
|
@@ -651,11 +579,6 @@ class Evaluator:
|
|
|
651
579
|
H, W = sample_results.shape[-2:]
|
|
652
580
|
img_diag = np.sqrt(H**2 + W**2)
|
|
653
581
|
|
|
654
|
-
if GPU:
|
|
655
|
-
img_diag = img_diag.get()
|
|
656
|
-
pred_one_hot = pred_one_hot.get()
|
|
657
|
-
gt_one_hot = gt_one_hot.get()
|
|
658
|
-
|
|
659
582
|
boundary_width = max(int(round(self.boundary_iou_d * img_diag)), 1)
|
|
660
583
|
|
|
661
584
|
# BoundaryIoU uses "fast" boundary implementation, see https://github.com/bowenc0221/boundary-iou-api/blob/37d25586a677b043ed585f10e5c42d4e80176ea9/boundary_iou/utils/boundary_utils.py#L12
|
|
@@ -669,10 +592,6 @@ class Evaluator:
|
|
|
669
592
|
gt_one_hot, width=boundary_width, implementation="fast"
|
|
670
593
|
) # G_d - G
|
|
671
594
|
|
|
672
|
-
if GPU:
|
|
673
|
-
pred_one_hot_int_boundary = np.asarray(pred_one_hot_int_boundary)
|
|
674
|
-
gt_one_hot_int_boundary = np.asarray(gt_one_hot_int_boundary)
|
|
675
|
-
|
|
676
595
|
boundary_intersection = np.logical_and(pred_one_hot_int_boundary, gt_one_hot_int_boundary)
|
|
677
596
|
boundary_union = np.logical_or(pred_one_hot_int_boundary, gt_one_hot_int_boundary)
|
|
678
597
|
|
|
@@ -690,11 +609,6 @@ class Evaluator:
|
|
|
690
609
|
H, W = class_results.shape[-2:]
|
|
691
610
|
img_diag = np.sqrt(H**2 + W**2)
|
|
692
611
|
|
|
693
|
-
if GPU:
|
|
694
|
-
img_diag = img_diag.get()
|
|
695
|
-
pred_mask = pred_mask.get()
|
|
696
|
-
gt_mask = gt_mask.get()
|
|
697
|
-
|
|
698
612
|
boundary_width = max(int(round(self.boundary_iou_d * img_diag)), 1)
|
|
699
613
|
|
|
700
614
|
# BoundaryIoU uses "fast" boundary implementation, see https://github.com/bowenc0221/boundary-iou-api/blob/37d25586a677b043ed585f10e5c42d4e80176ea9/boundary_iou/utils/boundary_utils.py#L12
|
|
@@ -708,10 +622,6 @@ class Evaluator:
|
|
|
708
622
|
gt_mask, width=boundary_width, implementation="fast"
|
|
709
623
|
) # G_d - G
|
|
710
624
|
|
|
711
|
-
if GPU:
|
|
712
|
-
pred_mask_int_boundary = np.asarray(pred_mask_int_boundary)
|
|
713
|
-
gt_mask_int_boundary = np.asarray(gt_mask_int_boundary)
|
|
714
|
-
|
|
715
625
|
boundary_intersection = np.logical_and(pred_mask_int_boundary, gt_mask_int_boundary)
|
|
716
626
|
boundary_union = np.logical_or(pred_mask_int_boundary, gt_mask_int_boundary)
|
|
717
627
|
|