code-loader 1.0.214.dev1__tar.gz → 1.0.215.dev1__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.
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/PKG-INFO +1 -1
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/contract/datasetclasses.py +35 -11
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/inner_leap_binder/leapbinder.py +58 -2
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/inner_leap_binder/leapbinder_decorators.py +54 -5
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/leaploader.py +40 -3
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/leaploaderbase.py +4 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/utils.py +3 -3
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/pyproject.toml +5 -1
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/LICENSE +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/README.md +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/__init__.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/contract/__init__.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/contract/enums.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/contract/exceptions.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/contract/mapping.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/contract/responsedataclasses.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/contract/sim_config.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/contract/visualizer_classes.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/default_losses.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/default_metrics.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/experiment_api/__init__.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/experiment_api/api.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/experiment_api/cli_config_utils.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/experiment_api/client.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/experiment_api/epoch.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/experiment_api/experiment.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/experiment_api/experiment_context.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/experiment_api/types.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/experiment_api/utils.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/experiment_api/workingspace_config_utils.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/inner_leap_binder/__init__.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/mixpanel_tracker.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/plot_functions/__init__.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/plot_functions/plot_functions.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/plot_functions/visualize.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/visualizers/__init__.py +0 -0
- {code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/visualizers/default_visualizers.py +0 -0
{code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/contract/datasetclasses.py
RENAMED
|
@@ -25,6 +25,17 @@ _simulation_context: Dict[str, bool] = {"active": False}
|
|
|
25
25
|
|
|
26
26
|
SampleId = Union[int, str]
|
|
27
27
|
|
|
28
|
+
SUPPORTED_SAMPLE_IDS_CONTAINERS = (list, tuple, range)
|
|
29
|
+
SUPPORTED_SAMPLE_IDS = ("a list of str, a list of int (with sample_id_type=int), "
|
|
30
|
+
"or a list of non-empty lists of str or int for grouped samples "
|
|
31
|
+
"(a tuple or range can be used instead of the outer list)")
|
|
32
|
+
|
|
33
|
+
_SAMPLE_ID_TYPES: Dict[type, Tuple[type, ...]] = {str: (str, np.str_), int: (int,)}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def is_sample_id_of_type(sample_id: Any, sample_id_type: type) -> bool:
|
|
37
|
+
return type(sample_id) in _SAMPLE_ID_TYPES.get(sample_id_type, ())
|
|
38
|
+
|
|
28
39
|
|
|
29
40
|
@dataclass
|
|
30
41
|
class PreprocessResponse:
|
|
@@ -69,19 +80,24 @@ class PreprocessResponse:
|
|
|
69
80
|
self._grouped = False
|
|
70
81
|
elif self.sample_ids is not None:
|
|
71
82
|
given_length = self.length
|
|
83
|
+
assert type(self.sample_ids) in SUPPORTED_SAMPLE_IDS_CONTAINERS, \
|
|
84
|
+
(f"PreprocessResponse.sample_ids should be a list. Got: {type(self.sample_ids).__name__}. "
|
|
85
|
+
f"Supported: {SUPPORTED_SAMPLE_IDS}. Convert it with .tolist() or list(...), "
|
|
86
|
+
f"e.g. sample_ids=df.index.tolist().")
|
|
72
87
|
self._grouped = len(self.sample_ids) > 0 and isinstance(self.sample_ids[0], list)
|
|
73
88
|
if self._grouped:
|
|
74
89
|
groups = cast(List[List[SampleId]], self.sample_ids)
|
|
75
90
|
assert len(groups) >= 1, "Grouped PreprocessResponse must have at least one group."
|
|
76
91
|
for group in groups:
|
|
77
|
-
assert
|
|
78
|
-
"Each group in a grouped PreprocessResponse must be a non-empty list."
|
|
79
|
-
|
|
80
|
-
assert
|
|
81
|
-
f"Sample id should be of type str or int. Got: {
|
|
92
|
+
assert type(group) is list and len(group) > 0, \
|
|
93
|
+
f"Each group in a grouped PreprocessResponse must be a non-empty list. Got: {type(group).__name__}"
|
|
94
|
+
first_type = type(groups[0][0])
|
|
95
|
+
assert first_type in (str, np.str_, int), \
|
|
96
|
+
f"Sample id should be of type str or int. Got: {first_type.__name__}"
|
|
97
|
+
self.sample_id_type = int if first_type is int else str
|
|
82
98
|
for group in groups:
|
|
83
99
|
for sample_id in group:
|
|
84
|
-
assert
|
|
100
|
+
assert is_sample_id_of_type(sample_id, self.sample_id_type), \
|
|
85
101
|
f"Sample id should be of type {self.sample_id_type.__name__}. Got: {type(sample_id)}"
|
|
86
102
|
self.length = sum(len(group) for group in groups)
|
|
87
103
|
else:
|
|
@@ -89,9 +105,13 @@ class PreprocessResponse:
|
|
|
89
105
|
self.length = len(flat_ids)
|
|
90
106
|
if self.sample_id_type is None:
|
|
91
107
|
self.sample_id_type = str
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
108
|
+
assert self.sample_id_type in (str, int), \
|
|
109
|
+
f"PreprocessResponse.sample_id_type should be str or int. Got: {self.sample_id_type}"
|
|
110
|
+
for sample_id in flat_ids:
|
|
111
|
+
assert is_sample_id_of_type(sample_id, self.sample_id_type), \
|
|
112
|
+
(f"Sample id should be of type {self.sample_id_type.__name__}. Got: {type(sample_id)}. "
|
|
113
|
+
f"Supported: {SUPPORTED_SAMPLE_IDS}. Convert NumPy values with .tolist(), "
|
|
114
|
+
f"or pass sample_id_type=int for int ids.")
|
|
95
115
|
# dataclasses.replace() re-invokes __init__ with both fields already populated
|
|
96
116
|
# (length previously derived from sample_ids); only reject a genuine mismatch.
|
|
97
117
|
if given_length is not None:
|
|
@@ -155,6 +175,9 @@ class ElementInstance:
|
|
|
155
175
|
# masks funnel (utils.to_numpy_return_masks_wrapper) so the engine copies flags rather than
|
|
156
176
|
# deriving them, exactly as it does for sample-level metadata.
|
|
157
177
|
instance_metadata_is_none: Optional[Dict[str, bool]] = None
|
|
178
|
+
# Per-instance metric values keyed by the registered name of a tensorleap_custom_instances_metric.
|
|
179
|
+
# Only meaningful on false-positive instances (they have no ground-truth row for the metric to run on).
|
|
180
|
+
instance_metrics: Optional[Dict[str, float]] = None
|
|
158
181
|
|
|
159
182
|
SectionCallableInterface = Callable[[Union[int, str], PreprocessResponse], npt.NDArray[np.float32]]
|
|
160
183
|
InstanceCallableInterface = Callable[[Union[int, str], PreprocessResponse, int], Optional[ElementInstance]]
|
|
@@ -310,7 +333,7 @@ class ElementInstanceMasksHandler:
|
|
|
310
333
|
@dataclass
|
|
311
334
|
class FalsePositiveInstancesHandler:
|
|
312
335
|
name: str
|
|
313
|
-
function: Callable
|
|
336
|
+
function: Callable[..., Any]
|
|
314
337
|
|
|
315
338
|
@dataclass
|
|
316
339
|
class GroundTruthHandler(DatasetBaseHandler):
|
|
@@ -411,7 +434,8 @@ class DatasetIntegrationSetup:
|
|
|
411
434
|
inputs: List[InputHandler] = field(default_factory=list)
|
|
412
435
|
instance_masks: List[ElementInstanceMasksHandler] = field(default_factory=list)
|
|
413
436
|
false_positive_instances: Optional[FalsePositiveInstancesHandler] = None
|
|
414
|
-
false_positive_empty_gt: Dict[str, Callable] = field(default_factory=dict)
|
|
437
|
+
false_positive_empty_gt: Dict[str, Callable[..., Any]] = field(default_factory=dict)
|
|
438
|
+
false_positive_custom_latent_spaces: Dict[str, Callable[..., Any]] = field(default_factory=dict)
|
|
415
439
|
ground_truths: List[GroundTruthHandler] = field(default_factory=list)
|
|
416
440
|
metadata: List[MetadataHandler] = field(default_factory=list)
|
|
417
441
|
prediction_types: List[PredictionTypeHandler] = field(default_factory=list)
|
{code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/inner_leap_binder/leapbinder.py
RENAMED
|
@@ -341,7 +341,7 @@ class LeapBinder:
|
|
|
341
341
|
self.setup_container.instance_masks.append(ElementInstanceMasksHandler(name, function))
|
|
342
342
|
|
|
343
343
|
|
|
344
|
-
def set_false_positive_instances(self, function: Callable, name: str) -> None:
|
|
344
|
+
def set_false_positive_instances(self, function: Callable[..., Any], name: str) -> None:
|
|
345
345
|
"""
|
|
346
346
|
Set the false-positive instances handler. It receives (sample_id, preprocess, predictions)
|
|
347
347
|
and returns a list of ElementInstance, one per false-positive prediction.
|
|
@@ -351,7 +351,7 @@ class LeapBinder:
|
|
|
351
351
|
function = to_numpy_return_fp_masks_wrapper(function)
|
|
352
352
|
self.setup_container.false_positive_instances = FalsePositiveInstancesHandler(name, function)
|
|
353
353
|
|
|
354
|
-
def set_false_positive_empty_gt(self, function: Callable, gt_name: str) -> None:
|
|
354
|
+
def set_false_positive_empty_gt(self, function: Callable[..., Any], gt_name: str) -> None:
|
|
355
355
|
"""
|
|
356
356
|
Set the empty ground truth for false-positive instance rows of the given GT encoder.
|
|
357
357
|
It receives (sample_id, preprocess) and returns an array shaped like the GT encoder's output.
|
|
@@ -392,6 +392,61 @@ class LeapBinder:
|
|
|
392
392
|
f"tensorleap_false_positive_empty_gt for '{name}' returned dtype {empty.dtype}, "
|
|
393
393
|
f"which cannot be cast to float32.")
|
|
394
394
|
|
|
395
|
+
def set_false_positive_custom_latent_space(self, function: Callable[..., Any], name: str) -> None:
|
|
396
|
+
"""
|
|
397
|
+
Set the custom latent space hook for false-positive instance rows. It receives
|
|
398
|
+
(sample_id, preprocess, fp_instance) and returns a 1-D vector for the instance-aware
|
|
399
|
+
custom latent space registered under `name`.
|
|
400
|
+
"""
|
|
401
|
+
if name in self.setup_container.false_positive_custom_latent_spaces:
|
|
402
|
+
raise Exception(f"tensorleap_false_positive_custom_latent_space for '{name}' is already defined")
|
|
403
|
+
self.setup_container.false_positive_custom_latent_spaces[name] = function
|
|
404
|
+
|
|
405
|
+
def check_false_positive_custom_latent_spaces(
|
|
406
|
+
self, preprocess_result: Optional[Dict[DataStateEnum, PreprocessResponse]] = None) -> None:
|
|
407
|
+
"""Every FP latent-space hook must name an instance-aware custom latent space and, when a
|
|
408
|
+
preprocess result is given, return the same shape as it (no-op without an FP encoder)."""
|
|
409
|
+
if self.setup_container.false_positive_instances is None:
|
|
410
|
+
return
|
|
411
|
+
for name in self.setup_container.false_positive_custom_latent_spaces:
|
|
412
|
+
handler = self.setup_container.custom_latent_spaces.get(name)
|
|
413
|
+
if handler is None or not handler.instance_aware:
|
|
414
|
+
raise Exception(
|
|
415
|
+
f"tensorleap_false_positive_custom_latent_space validation failed: '{name}' is not an "
|
|
416
|
+
f"instance custom latent space (tensorleap_instance_custom_latent_space)")
|
|
417
|
+
if preprocess_result is not None:
|
|
418
|
+
self._check_false_positive_custom_latent_space_shapes(preprocess_result)
|
|
419
|
+
|
|
420
|
+
def _check_false_positive_custom_latent_space_shapes(
|
|
421
|
+
self, preprocess_result: Dict[DataStateEnum, PreprocessResponse]) -> None:
|
|
422
|
+
"""Call each FP latent-space hook with a real GT ElementInstance and compare its shape with
|
|
423
|
+
the instance custom latent space's. FP and GT rows of one latent space are usually stored in
|
|
424
|
+
different bulks, so a width mismatch would otherwise be dropped silently at load time.
|
|
425
|
+
Skipped when there is no GT instance to probe with (no mask encoder, or no training sample
|
|
426
|
+
with an instance)."""
|
|
427
|
+
fp_hooks = self.setup_container.false_positive_custom_latent_spaces
|
|
428
|
+
if not fp_hooks or not self.setup_container.instance_masks:
|
|
429
|
+
return
|
|
430
|
+
training = preprocess_result.get(DataStateEnum.training)
|
|
431
|
+
if training is None or not training.sample_ids_to_instance_mappings:
|
|
432
|
+
return
|
|
433
|
+
sample_id = next((sid for sid, instance_ids in training.sample_ids_to_instance_mappings.items()
|
|
434
|
+
if instance_ids), None)
|
|
435
|
+
if sample_id is None:
|
|
436
|
+
return
|
|
437
|
+
gt_instance = self.setup_container.instance_masks[0].function(sample_id, training, 0)
|
|
438
|
+
if gt_instance is None:
|
|
439
|
+
return
|
|
440
|
+
for name, fp_hook in fp_hooks.items():
|
|
441
|
+
instance_ls = cast(InstanceSectionCallableInterface,
|
|
442
|
+
self.setup_container.custom_latent_spaces[name].function)
|
|
443
|
+
gt_shape = np.asarray(instance_ls(sample_id, training, 0)).shape
|
|
444
|
+
fp_shape = np.asarray(fp_hook(sample_id, training, gt_instance)).shape
|
|
445
|
+
if fp_shape != gt_shape:
|
|
446
|
+
raise Exception(
|
|
447
|
+
f"tensorleap_false_positive_custom_latent_space validation failed: '{name}' returns shape "
|
|
448
|
+
f"{fp_shape} but the instance custom latent space returns {gt_shape}")
|
|
449
|
+
|
|
395
450
|
def add_custom_loss(self, function: CustomCallableInterface, name: str) -> None:
|
|
396
451
|
"""
|
|
397
452
|
Add a custom loss function to the setup.
|
|
@@ -1075,6 +1130,7 @@ class LeapBinder:
|
|
|
1075
1130
|
self.check_preprocess(preprocess_result)
|
|
1076
1131
|
self.check_handlers(preprocess_result)
|
|
1077
1132
|
self.check_false_positive_empty_gt(preprocess_result)
|
|
1133
|
+
self.check_false_positive_custom_latent_spaces(preprocess_result)
|
|
1078
1134
|
self.check_simulations()
|
|
1079
1135
|
self.validate_ignore_latent_spaces()
|
|
1080
1136
|
print("Successful!")
|
|
@@ -27,6 +27,7 @@ from code_loader.contract.datasetclasses import CustomCallableInterfaceMultiArgs
|
|
|
27
27
|
CustomMultipleReturnCallableInterfaceMultiArgs, ConfusionMatrixCallableInterfaceMultiArgs, CustomCallableInterface, \
|
|
28
28
|
VisualizerCallableInterface, MetadataSectionCallableInterface, PreprocessResponse, SectionCallableInterface, \
|
|
29
29
|
ConfusionMatrixElement, SamplePreprocessResponse, PredictionTypeHandler, InstanceCallableInterface, ElementInstance, \
|
|
30
|
+
is_sample_id_of_type, \
|
|
30
31
|
InstanceLengthCallableInterface, InstanceSectionCallableInterface, AutoregressiveStepCallableInterface, \
|
|
31
32
|
MAX_CUSTOM_LATENT_SPACE_DIM, CUSTOM_LATENT_SPACE_WARN_DIM
|
|
32
33
|
from code_loader.contract.enums import MetricDirection, LeapDataType, DatasetMetadataType, DataStateType, \
|
|
@@ -236,7 +237,7 @@ def _validate_id_or_group(sample_id, preprocess_response, func_name):
|
|
|
236
237
|
f'is grouped. Pass a group (list of sample ids) for a grouped dataset.')
|
|
237
238
|
ids = sample_id if is_group else [sample_id]
|
|
238
239
|
for sid in ids:
|
|
239
|
-
assert
|
|
240
|
+
assert is_sample_id_of_type(sid, preprocess_response.sample_id_type), \
|
|
240
241
|
(f'{func_name}() validation failed: '
|
|
241
242
|
f'Argument sample_id should be as the same type as defined in the preprocess response '
|
|
242
243
|
f'{preprocess_response.sample_id_type}. Got {type(sid)}.')
|
|
@@ -2491,7 +2492,7 @@ def tensorleap_autoregressive_step(latent_space_aggregation: str = 'last_step'):
|
|
|
2491
2492
|
(f'{user_function.__name__}() validation failed: '
|
|
2492
2493
|
f'the first call (prev_inputs=None, prev_outputs=None) must pass state=None. '
|
|
2493
2494
|
f'Got state of type {type(state).__name__}.')
|
|
2494
|
-
assert
|
|
2495
|
+
assert is_sample_id_of_type(sample_id, preprocess_response.sample_id_type), \
|
|
2495
2496
|
(f'{user_function.__name__}() validation failed: '
|
|
2496
2497
|
f'Argument sample_id should be as the same type as defined in the preprocess response '
|
|
2497
2498
|
f'{preprocess_response.sample_id_type}. Got {type(sample_id)}.')
|
|
@@ -3360,7 +3361,7 @@ def tensorleap_element_instance_preprocess(
|
|
|
3360
3361
|
"Remove the instance encoders or don't group this dataset.")
|
|
3361
3362
|
sample_ids_to_instance_mappings = {}
|
|
3362
3363
|
instance_to_sample_ids_mappings = {}
|
|
3363
|
-
all_sample_ids = preprocess_response.sample_ids
|
|
3364
|
+
all_sample_ids = list(preprocess_response.sample_ids)
|
|
3364
3365
|
for sample_id in preprocess_response.sample_ids:
|
|
3365
3366
|
instances_length = instance_length_encoder(sample_id, preprocess_response)
|
|
3366
3367
|
instances_ids = [f'{sample_id}_{instance_id}' for instance_id in range(instances_length)]
|
|
@@ -3458,7 +3459,7 @@ def tensorleap_instances_masks_encoder(name: str):
|
|
|
3458
3459
|
assert isinstance(preprocess_response, PreprocessResponse), \
|
|
3459
3460
|
(f'tensorleap_instances_masks_encoder validation failed: '
|
|
3460
3461
|
f'Argument preprocess_response should be a PreprocessResponse. Got {type(preprocess_response)}.')
|
|
3461
|
-
assert
|
|
3462
|
+
assert is_sample_id_of_type(sample_id, preprocess_response.sample_id_type), \
|
|
3462
3463
|
(f'tensorleap_instances_masks_encoder validation failed: '
|
|
3463
3464
|
f'Argument sample_id should be as the same type as defined in the preprocess response '
|
|
3464
3465
|
f'{preprocess_response.sample_id_type}. Got {type(sample_id)}.')
|
|
@@ -3603,6 +3604,54 @@ def tensorleap_false_positive_empty_gt(gt_name: str):
|
|
|
3603
3604
|
return decorating_function
|
|
3604
3605
|
|
|
3605
3606
|
|
|
3607
|
+
def tensorleap_false_positive_custom_latent_space(name: str):
|
|
3608
|
+
"""Compute the instance custom latent space `name` (a tensorleap_instance_custom_latent_space)
|
|
3609
|
+
for a false-positive instance. Signature: fn(sample_id, preprocess, fp_instance) -> 1-D np.ndarray."""
|
|
3610
|
+
def decorating_function(user_function: Callable):
|
|
3611
|
+
def _validate_input_args(sample_id, preprocess_response, fp_instance):
|
|
3612
|
+
assert isinstance(sample_id, (str, int)), \
|
|
3613
|
+
(f'tensorleap_false_positive_custom_latent_space validation failed: '
|
|
3614
|
+
f'Argument sample_id should be str or int. Got {type(sample_id)}.')
|
|
3615
|
+
assert isinstance(preprocess_response, PreprocessResponse), \
|
|
3616
|
+
(f'tensorleap_false_positive_custom_latent_space validation failed: '
|
|
3617
|
+
f'Argument preprocess_response should be a PreprocessResponse. Got {type(preprocess_response)}.')
|
|
3618
|
+
assert isinstance(fp_instance, ElementInstance), \
|
|
3619
|
+
(f'tensorleap_false_positive_custom_latent_space validation failed: '
|
|
3620
|
+
f'Argument fp_instance should be an ElementInstance. Got {type(fp_instance)}.')
|
|
3621
|
+
|
|
3622
|
+
def _validate_result(result):
|
|
3623
|
+
assert isinstance(result, np.ndarray), \
|
|
3624
|
+
(f'tensorleap_false_positive_custom_latent_space validation failed: '
|
|
3625
|
+
f'The return type should be a numpy array. Got {type(result)}.')
|
|
3626
|
+
assert result.ndim == 1, \
|
|
3627
|
+
(f'tensorleap_false_positive_custom_latent_space validation failed: '
|
|
3628
|
+
f'The returned array should be 1-D. Got shape {result.shape}.')
|
|
3629
|
+
|
|
3630
|
+
def inner_without_validate(sample_id, preprocess_response, fp_instance):
|
|
3631
|
+
global _called_from_inside_tl_decorator
|
|
3632
|
+
_called_from_inside_tl_decorator += 1
|
|
3633
|
+
try:
|
|
3634
|
+
result = user_function(sample_id, preprocess_response, fp_instance)
|
|
3635
|
+
finally:
|
|
3636
|
+
_called_from_inside_tl_decorator -= 1
|
|
3637
|
+
return result
|
|
3638
|
+
|
|
3639
|
+
leap_binder.set_false_positive_custom_latent_space(inner_without_validate, name)
|
|
3640
|
+
|
|
3641
|
+
def inner(sample_id, preprocess_response, fp_instance):
|
|
3642
|
+
if os.environ.get(mapping_runtime_mode_env_var_mame):
|
|
3643
|
+
return np.zeros(0, dtype=np.float32)
|
|
3644
|
+
|
|
3645
|
+
_validate_input_args(sample_id, preprocess_response, fp_instance)
|
|
3646
|
+
result = inner_without_validate(sample_id, preprocess_response, fp_instance)
|
|
3647
|
+
_validate_result(result)
|
|
3648
|
+
return result
|
|
3649
|
+
|
|
3650
|
+
return inner
|
|
3651
|
+
|
|
3652
|
+
return decorating_function
|
|
3653
|
+
|
|
3654
|
+
|
|
3606
3655
|
def tensorleap_instances_length_encoder(name: str):
|
|
3607
3656
|
def decorating_function(user_function: InstanceLengthCallableInterface):
|
|
3608
3657
|
def _validate_input_args(sample_id: str, preprocess_response: PreprocessResponse):
|
|
@@ -3612,7 +3661,7 @@ def tensorleap_instances_length_encoder(name: str):
|
|
|
3612
3661
|
assert isinstance(preprocess_response, PreprocessResponse), \
|
|
3613
3662
|
(f'tensorleap_instances_length_encoder validation failed: '
|
|
3614
3663
|
f'Argument preprocess_response should be a PreprocessResponse. Got {type(preprocess_response)}.')
|
|
3615
|
-
assert
|
|
3664
|
+
assert is_sample_id_of_type(sample_id, preprocess_response.sample_id_type), \
|
|
3616
3665
|
(f'tensorleap_instances_length_encoder validation failed: '
|
|
3617
3666
|
f'Argument sample_id should be as the same type as defined in the preprocess response '
|
|
3618
3667
|
f'{preprocess_response.sample_id_type}. Got {type(sample_id)}.')
|
|
@@ -653,7 +653,9 @@ class LeapLoader(LeapLoaderBase):
|
|
|
653
653
|
return None
|
|
654
654
|
test_result = DatasetTestResultPayload(handler.name)
|
|
655
655
|
try:
|
|
656
|
-
|
|
656
|
+
preprocess_result = self._preprocess_result()
|
|
657
|
+
global_leap_binder.check_false_positive_empty_gt(preprocess_result)
|
|
658
|
+
global_leap_binder.check_false_positive_custom_latent_spaces(preprocess_result)
|
|
657
659
|
except Exception as e:
|
|
658
660
|
line_number, file_name, stacktrace = get_root_exception_file_and_line_number()
|
|
659
661
|
error_string = f"{repr(e)} in file {file_name}, line_number: {line_number}\nStacktrace:\n{stacktrace}"
|
|
@@ -1825,7 +1827,7 @@ class LeapLoader(LeapLoaderBase):
|
|
|
1825
1827
|
row = {name: array[i] for name, array in predictions.items()}
|
|
1826
1828
|
try:
|
|
1827
1829
|
instances = handler.function(self._native_sample_id(sample_id), preprocess_response, row)
|
|
1828
|
-
self._validate_false_positive_instances(instances)
|
|
1830
|
+
self._validate_false_positive_instances(instances, set(self._instance_metric_handler_by_name()))
|
|
1829
1831
|
except Exception as e:
|
|
1830
1832
|
print(f"tensorleap_false_positive_instances_encoder failed for sample {sample_id!r} "
|
|
1831
1833
|
f"(state {state.name}): {e!r}")
|
|
@@ -1835,7 +1837,7 @@ class LeapLoader(LeapLoaderBase):
|
|
|
1835
1837
|
return results
|
|
1836
1838
|
|
|
1837
1839
|
@staticmethod
|
|
1838
|
-
def _validate_false_positive_instances(instances: Any) -> None:
|
|
1840
|
+
def _validate_false_positive_instances(instances: Any, registered_instance_metrics: Set[str]) -> None:
|
|
1839
1841
|
prefix = "tensorleap_false_positive_instances_encoder validation failed: "
|
|
1840
1842
|
if not isinstance(instances, list):
|
|
1841
1843
|
raise Exception(f"{prefix}The return type should be a list of ElementInstance. "
|
|
@@ -1844,6 +1846,21 @@ class LeapLoader(LeapLoaderBase):
|
|
|
1844
1846
|
if not isinstance(instance, ElementInstance):
|
|
1845
1847
|
raise Exception(f"{prefix}Element {j} of the returned list should be an ElementInstance. "
|
|
1846
1848
|
f"Got {type(instance)}.")
|
|
1849
|
+
if instance.instance_metrics is None:
|
|
1850
|
+
continue
|
|
1851
|
+
if not isinstance(instance.instance_metrics, dict):
|
|
1852
|
+
raise Exception(f"{prefix}instance_metrics of element {j} should be a dict. "
|
|
1853
|
+
f"Got {type(instance.instance_metrics)}.")
|
|
1854
|
+
for key, value in instance.instance_metrics.items():
|
|
1855
|
+
if key not in registered_instance_metrics:
|
|
1856
|
+
raise Exception(f"{prefix}instance_metrics key {key!r} of element {j} is not the name of a "
|
|
1857
|
+
f"registered tensorleap_custom_instances_metric. "
|
|
1858
|
+
f"Registered: {sorted(registered_instance_metrics)}.")
|
|
1859
|
+
try:
|
|
1860
|
+
instance.instance_metrics[key] = float(value)
|
|
1861
|
+
except (TypeError, ValueError):
|
|
1862
|
+
raise Exception(f"{prefix}instance_metrics[{key!r}] of element {j} should be castable to "
|
|
1863
|
+
f"float. Got {type(value)}.")
|
|
1847
1864
|
|
|
1848
1865
|
def get_false_positive_empty_gt(self, state: DataStateEnum,
|
|
1849
1866
|
sample_id: Union[str, int]) -> Dict[str, npt.NDArray[np.float32]]:
|
|
@@ -1859,6 +1876,26 @@ class LeapLoader(LeapLoaderBase):
|
|
|
1859
1876
|
empty_gt[gt_name] = value.astype(np.float32, copy=False)
|
|
1860
1877
|
return empty_gt
|
|
1861
1878
|
|
|
1879
|
+
def get_false_positive_custom_latent_spaces(self, state: DataStateEnum, sample_id: Union[str, int],
|
|
1880
|
+
fp_instance: ElementInstance) -> Dict[str, npt.NDArray[np.float32]]:
|
|
1881
|
+
self.exec_script()
|
|
1882
|
+
hooks = global_leap_binder.setup_container.false_positive_custom_latent_spaces
|
|
1883
|
+
if not hooks:
|
|
1884
|
+
return {}
|
|
1885
|
+
preprocess_response = self._preprocess_result()[state]
|
|
1886
|
+
sample_id = self._native_sample_id(sample_id)
|
|
1887
|
+
vectors: Dict[str, npt.NDArray[np.float32]] = {}
|
|
1888
|
+
for name, function in hooks.items():
|
|
1889
|
+
value = function(sample_id, preprocess_response, fp_instance)
|
|
1890
|
+
if not isinstance(value, np.ndarray):
|
|
1891
|
+
raise Exception(f"tensorleap_false_positive_custom_latent_space validation failed: "
|
|
1892
|
+
f"The return type for '{name}' should be a numpy array. Got {type(value)}.")
|
|
1893
|
+
if value.ndim != 1:
|
|
1894
|
+
raise Exception(f"tensorleap_false_positive_custom_latent_space validation failed: "
|
|
1895
|
+
f"The return value for '{name}' should be a 1-D array. Got shape {value.shape}.")
|
|
1896
|
+
vectors[name] = value.astype(np.float32, copy=False)
|
|
1897
|
+
return vectors
|
|
1898
|
+
|
|
1862
1899
|
def get_instances_data(self, state: DataStateEnum) -> Tuple[Dict[str, List[str]], Dict[str, str]]:
|
|
1863
1900
|
preprocess_result = self._preprocess_result()
|
|
1864
1901
|
preprocess_state = preprocess_result.get(state)
|
|
@@ -87,6 +87,10 @@ class LeapLoaderBase:
|
|
|
87
87
|
sample_id: Union[str, int]) -> Dict[str, npt.NDArray[np.float32]]:
|
|
88
88
|
raise NotImplementedError("get_false_positive_empty_gt is not implemented by this loader")
|
|
89
89
|
|
|
90
|
+
def get_false_positive_custom_latent_spaces(self, state: DataStateEnum, sample_id: Union[str, int],
|
|
91
|
+
fp_instance: ElementInstance) -> Dict[str, npt.NDArray[np.float32]]:
|
|
92
|
+
return {}
|
|
93
|
+
|
|
90
94
|
def get_metadata_multiple_samples(self, state: DataStateEnum, sample_ids: Union[List[int], List[str]],
|
|
91
95
|
requested_metadata_names: Optional[List[str]] = None
|
|
92
96
|
) -> Tuple[Dict[str, Union[List[str], List[int], List[bool],
|
|
@@ -6,7 +6,7 @@ import pickle
|
|
|
6
6
|
import sys
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from types import TracebackType
|
|
9
|
-
from typing import List, Union, Tuple, Any, Callable, Dict, Optional
|
|
9
|
+
from typing import List, Union, Tuple, Any, Callable, Dict, Optional, cast
|
|
10
10
|
import traceback
|
|
11
11
|
import numpy as np
|
|
12
12
|
import numpy.typing as npt
|
|
@@ -53,11 +53,11 @@ def to_numpy_return_masks_wrapper(encoder_function: InstanceCallableInterface) -
|
|
|
53
53
|
return numpy_encoder_function
|
|
54
54
|
|
|
55
55
|
|
|
56
|
-
def to_numpy_return_fp_masks_wrapper(encoder_function: Callable) -> Callable:
|
|
56
|
+
def to_numpy_return_fp_masks_wrapper(encoder_function: Callable[..., Any]) -> Callable[..., List[ElementInstance]]:
|
|
57
57
|
def numpy_encoder_function(idx: Union[int, str], samples: PreprocessResponse, predictions: Dict[str, Any]) -> List[ElementInstance]:
|
|
58
58
|
result = encoder_function(idx, samples, predictions)
|
|
59
59
|
if not isinstance(result, list):
|
|
60
|
-
return result # malformed: the loader reports it with a clear message
|
|
60
|
+
return cast(List[ElementInstance], result) # malformed: the loader reports it with a clear message
|
|
61
61
|
for instance in result:
|
|
62
62
|
if not isinstance(instance, ElementInstance):
|
|
63
63
|
continue
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "code-loader"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.215.dev1"
|
|
4
4
|
description = ""
|
|
5
5
|
authors = ["dorhar <doron.harnoy@tensorleap.ai>"]
|
|
6
6
|
license = "MIT"
|
|
@@ -30,6 +30,10 @@ pytest-watch = "^4.2.0"
|
|
|
30
30
|
mypy = "1.3.0"
|
|
31
31
|
onnxruntime = {version = ">=1.0.0", python = ">=3.10"}
|
|
32
32
|
onnx = {version = ">=1.0.0", python = ">=3.10"}
|
|
33
|
+
pandas = [
|
|
34
|
+
{ version = "^2.0.3", python = ">=3.8,<3.11" },
|
|
35
|
+
{ version = "^2.2.3", python = ">=3.11,<3.13" }
|
|
36
|
+
]
|
|
33
37
|
|
|
34
38
|
[build-system]
|
|
35
39
|
requires = ["poetry-core>=1.0.0"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/contract/responsedataclasses.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/contract/visualizer_classes.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/experiment_api/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/experiment_api/cli_config_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/experiment_api/experiment.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/inner_leap_binder/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/plot_functions/__init__.py
RENAMED
|
File without changes
|
{code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/plot_functions/plot_functions.py
RENAMED
|
File without changes
|
{code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/plot_functions/visualize.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_loader-1.0.214.dev1 → code_loader-1.0.215.dev1}/code_loader/visualizers/default_visualizers.py
RENAMED
|
File without changes
|