code-loader 1.0.212__tar.gz → 1.0.214.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.212 → code_loader-1.0.214.dev1}/PKG-INFO +1 -1
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/contract/datasetclasses.py +7 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/inner_leap_binder/leapbinder.py +60 -3
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/inner_leap_binder/leapbinder_decorators.py +153 -23
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/leaploader.py +91 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/leaploaderbase.py +16 -1
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/utils.py +16 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/pyproject.toml +1 -1
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/LICENSE +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/README.md +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/__init__.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/contract/__init__.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/contract/enums.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/contract/exceptions.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/contract/mapping.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/contract/responsedataclasses.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/contract/sim_config.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/contract/visualizer_classes.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/default_losses.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/default_metrics.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/experiment_api/__init__.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/experiment_api/api.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/experiment_api/cli_config_utils.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/experiment_api/client.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/experiment_api/epoch.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/experiment_api/experiment.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/experiment_api/experiment_context.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/experiment_api/types.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/experiment_api/utils.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/experiment_api/workingspace_config_utils.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/inner_leap_binder/__init__.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/mixpanel_tracker.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/plot_functions/__init__.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/plot_functions/plot_functions.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/plot_functions/visualize.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/visualizers/__init__.py +0 -0
- {code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/visualizers/default_visualizers.py +0 -0
|
@@ -307,6 +307,11 @@ class ElementInstanceMasksHandler:
|
|
|
307
307
|
name: str
|
|
308
308
|
function: InstanceCallableInterface
|
|
309
309
|
|
|
310
|
+
@dataclass
|
|
311
|
+
class FalsePositiveInstancesHandler:
|
|
312
|
+
name: str
|
|
313
|
+
function: Callable
|
|
314
|
+
|
|
310
315
|
@dataclass
|
|
311
316
|
class GroundTruthHandler(DatasetBaseHandler):
|
|
312
317
|
shape: Optional[List[int]] = None
|
|
@@ -405,6 +410,8 @@ class DatasetIntegrationSetup:
|
|
|
405
410
|
visualizers: List[VisualizerHandler] = field(default_factory=list)
|
|
406
411
|
inputs: List[InputHandler] = field(default_factory=list)
|
|
407
412
|
instance_masks: List[ElementInstanceMasksHandler] = field(default_factory=list)
|
|
413
|
+
false_positive_instances: Optional[FalsePositiveInstancesHandler] = None
|
|
414
|
+
false_positive_empty_gt: Dict[str, Callable] = field(default_factory=dict)
|
|
408
415
|
ground_truths: List[GroundTruthHandler] = field(default_factory=list)
|
|
409
416
|
metadata: List[MetadataHandler] = field(default_factory=list)
|
|
410
417
|
prediction_types: List[PredictionTypeHandler] = field(default_factory=list)
|
{code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/inner_leap_binder/leapbinder.py
RENAMED
|
@@ -16,7 +16,7 @@ from code_loader.contract.datasetclasses import SectionCallableInterface, InputH
|
|
|
16
16
|
CustomCallableInterfaceMultiArgs, ConfusionMatrixCallableInterfaceMultiArgs, LeapData, \
|
|
17
17
|
CustomMultipleReturnCallableInterfaceMultiArgs, DatasetBaseHandler, custom_latent_space_attribute, \
|
|
18
18
|
RawInputsForHeatmap, VisualizerHandlerData, MetricHandlerData, CustomLossHandlerData, SamplePreprocessResponse, \
|
|
19
|
-
ElementInstanceMasksHandler, InstanceCallableInterface, InstanceSectionCallableInterface, \
|
|
19
|
+
ElementInstanceMasksHandler, FalsePositiveInstancesHandler, InstanceCallableInterface, InstanceSectionCallableInterface, \
|
|
20
20
|
CustomLatentSpaceHandler, InstanceMetricHandler, MAX_CUSTOM_LATENT_SPACES, \
|
|
21
21
|
SimulationHandler, _simulation_context, AutoregressiveStepHandler, AutoregressiveStepCallableInterface, \
|
|
22
22
|
AUTOREGRESSIVE_LATENT_SPACE_AGGREGATIONS, AUTOREGRESSIVE_IMPLICIT_ARG_NAMES, \
|
|
@@ -28,7 +28,8 @@ from code_loader.contract.responsedataclasses import DatasetTestResultPayload, L
|
|
|
28
28
|
from code_loader.contract.visualizer_classes import map_leap_data_type_to_visualizer_class
|
|
29
29
|
from code_loader.default_losses import loss_name_to_function
|
|
30
30
|
from code_loader.default_metrics import metrics_names_to_functions_and_direction
|
|
31
|
-
from code_loader.utils import to_numpy_return_wrapper, get_shape, to_numpy_return_masks_wrapper
|
|
31
|
+
from code_loader.utils import to_numpy_return_wrapper, get_shape, to_numpy_return_masks_wrapper, \
|
|
32
|
+
to_numpy_return_fp_masks_wrapper
|
|
32
33
|
from code_loader.contract.sim_config import parse_sim_config, sample_sim_params
|
|
33
34
|
from code_loader.visualizers.default_visualizers import DefaultVisualizer, \
|
|
34
35
|
default_graph_visualizer, \
|
|
@@ -340,6 +341,57 @@ class LeapBinder:
|
|
|
340
341
|
self.setup_container.instance_masks.append(ElementInstanceMasksHandler(name, function))
|
|
341
342
|
|
|
342
343
|
|
|
344
|
+
def set_false_positive_instances(self, function: Callable, name: str) -> None:
|
|
345
|
+
"""
|
|
346
|
+
Set the false-positive instances handler. It receives (sample_id, preprocess, predictions)
|
|
347
|
+
and returns a list of ElementInstance, one per false-positive prediction.
|
|
348
|
+
"""
|
|
349
|
+
if self.setup_container.false_positive_instances is not None:
|
|
350
|
+
raise Exception("only one tensorleap_false_positive_instances_encoder can be defined")
|
|
351
|
+
function = to_numpy_return_fp_masks_wrapper(function)
|
|
352
|
+
self.setup_container.false_positive_instances = FalsePositiveInstancesHandler(name, function)
|
|
353
|
+
|
|
354
|
+
def set_false_positive_empty_gt(self, function: Callable, gt_name: str) -> None:
|
|
355
|
+
"""
|
|
356
|
+
Set the empty ground truth for false-positive instance rows of the given GT encoder.
|
|
357
|
+
It receives (sample_id, preprocess) and returns an array shaped like the GT encoder's output.
|
|
358
|
+
"""
|
|
359
|
+
if gt_name in self.setup_container.false_positive_empty_gt:
|
|
360
|
+
raise Exception(f"tensorleap_false_positive_empty_gt for '{gt_name}' is already defined")
|
|
361
|
+
self.setup_container.false_positive_empty_gt[gt_name] = function
|
|
362
|
+
|
|
363
|
+
def check_false_positive_empty_gt(self, preprocess_result: Dict[DataStateEnum, PreprocessResponse]) -> None:
|
|
364
|
+
"""Validate the empty-GT functions against the GT encoders (no-op without an FP encoder)."""
|
|
365
|
+
if self.setup_container.false_positive_instances is None:
|
|
366
|
+
return
|
|
367
|
+
gt_handlers = {handler.name: handler for handler in self.setup_container.ground_truths}
|
|
368
|
+
empty_gt = self.setup_container.false_positive_empty_gt
|
|
369
|
+
missing = [name for name in gt_handlers if name not in empty_gt]
|
|
370
|
+
if missing:
|
|
371
|
+
raise Exception(
|
|
372
|
+
f"tensorleap_false_positive_instances_encoder requires a tensorleap_false_positive_empty_gt "
|
|
373
|
+
f"for every ground truth encoder. Missing for: {missing}.")
|
|
374
|
+
unknown = [name for name in empty_gt if name not in gt_handlers]
|
|
375
|
+
if unknown:
|
|
376
|
+
raise Exception(
|
|
377
|
+
f"tensorleap_false_positive_empty_gt names {unknown} do not match any registered ground truth "
|
|
378
|
+
f"encoder. Registered ground truth encoders: {list(gt_handlers)}.")
|
|
379
|
+
training = preprocess_result.get(DataStateEnum.training)
|
|
380
|
+
if training is None or not training.sample_ids or training.is_grouped:
|
|
381
|
+
return
|
|
382
|
+
sample_id = cast(Union[int, str], training.sample_ids[0])
|
|
383
|
+
for name, handler in gt_handlers.items():
|
|
384
|
+
gt = np.asarray(handler.function(sample_id, training))
|
|
385
|
+
empty = np.asarray(empty_gt[name](sample_id, training))
|
|
386
|
+
if empty.shape != gt.shape:
|
|
387
|
+
raise Exception(
|
|
388
|
+
f"tensorleap_false_positive_empty_gt for '{name}' returned shape {empty.shape}, but the "
|
|
389
|
+
f"ground truth encoder returns shape {gt.shape}.")
|
|
390
|
+
if not np.can_cast(empty.dtype, np.float32, casting='same_kind'):
|
|
391
|
+
raise Exception(
|
|
392
|
+
f"tensorleap_false_positive_empty_gt for '{name}' returned dtype {empty.dtype}, "
|
|
393
|
+
f"which cannot be cast to float32.")
|
|
394
|
+
|
|
343
395
|
def add_custom_loss(self, function: CustomCallableInterface, name: str) -> None:
|
|
344
396
|
"""
|
|
345
397
|
Add a custom loss function to the setup.
|
|
@@ -798,6 +850,10 @@ class LeapBinder:
|
|
|
798
850
|
for state, preprocess_response in preprocess_result.items():
|
|
799
851
|
if preprocess_response.length is None or preprocess_response.length <= 0:
|
|
800
852
|
raise Exception('Invalid dataset length')
|
|
853
|
+
if preprocess_response.is_grouped and self.setup_container.false_positive_instances is not None:
|
|
854
|
+
raise Exception(
|
|
855
|
+
'tensorleap_false_positive_instances_encoder is not supported with a grouped '
|
|
856
|
+
f'preprocess response (grouped state: {state.name}). Use flat sample_ids.')
|
|
801
857
|
if unlabeled_preprocess_handler is not None and state == DataStateEnum.unlabeled:
|
|
802
858
|
unlabeled_preprocess_handler.data_length = preprocess_response.length
|
|
803
859
|
else:
|
|
@@ -1018,6 +1074,7 @@ class LeapBinder:
|
|
|
1018
1074
|
preprocess_result = self.get_preprocess_result()
|
|
1019
1075
|
self.check_preprocess(preprocess_result)
|
|
1020
1076
|
self.check_handlers(preprocess_result)
|
|
1077
|
+
self.check_false_positive_empty_gt(preprocess_result)
|
|
1021
1078
|
self.check_simulations()
|
|
1022
1079
|
self.validate_ignore_latent_spaces()
|
|
1023
1080
|
print("Successful!")
|
|
@@ -1058,7 +1115,7 @@ class LeapBinder:
|
|
|
1058
1115
|
"Simulations are not supported together with tensorleap_autoregressive_step yet: "
|
|
1059
1116
|
"the autoregressive entry points do not resolve synthetic sample ids. Remove the "
|
|
1060
1117
|
"simulation decorators or the autoregressive hook.")
|
|
1061
|
-
if self.setup_container.instance_masks:
|
|
1118
|
+
if self.setup_container.instance_masks or self.setup_container.false_positive_instances is not None:
|
|
1062
1119
|
raise Exception(
|
|
1063
1120
|
"Element instances are not supported together with tensorleap_autoregressive_step: "
|
|
1064
1121
|
"instance generation masks the sample's encoded inputs, which do not exist in an "
|
|
@@ -3254,29 +3254,59 @@ def tensorleap_simulation(name: str, sim_params: dict):
|
|
|
3254
3254
|
return decorating_function
|
|
3255
3255
|
|
|
3256
3256
|
|
|
3257
|
+
def _register_builtin_instance_metadata() -> None:
|
|
3258
|
+
"""Idempotently register the builtin instance metadata handler.
|
|
3259
|
+
|
|
3260
|
+
Shared by the element-instance preprocess and the false-positive encoder, since either alone
|
|
3261
|
+
makes the engine produce instance samples.
|
|
3262
|
+
"""
|
|
3263
|
+
if any(h.name == "builtin_instance_metadata" for h in leap_binder.setup_container.metadata):
|
|
3264
|
+
return
|
|
3265
|
+
|
|
3266
|
+
def builtin_instance_metadata(idx: str, preprocess: PreprocessResponse) -> Dict[str, str]:
|
|
3267
|
+
result = {'is_instance': '0', 'original_sample_id': idx, 'instance_name': 'none'}
|
|
3268
|
+
if leap_binder.setup_container.false_positive_instances is not None:
|
|
3269
|
+
result['is_false_positive'] = '0'
|
|
3270
|
+
return result
|
|
3271
|
+
|
|
3272
|
+
leap_binder.set_metadata(builtin_instance_metadata, "builtin_instance_metadata")
|
|
3273
|
+
|
|
3274
|
+
|
|
3275
|
+
def _register_builtin_instance_extra_metadata(metadata_types: Dict[str, DatasetMetadataType]) -> None:
|
|
3276
|
+
"""Register (or extend) the `builtin_instance_extra_metadata` column declaration.
|
|
3277
|
+
|
|
3278
|
+
Shared by the element-instance preprocess (keys probed from the GT mask encoder) and the
|
|
3279
|
+
false-positive encoder (keys declared with `instance_metadata_types`). Idempotent and merging:
|
|
3280
|
+
set_metadata appends without deduping, and the probe path runs inside preprocess, so a second
|
|
3281
|
+
call must never register a duplicate handler; a key already declared keeps its first type.
|
|
3282
|
+
"""
|
|
3283
|
+
if not metadata_types:
|
|
3284
|
+
return
|
|
3285
|
+
existing = next((handler for handler in leap_binder.setup_container.metadata
|
|
3286
|
+
if handler.name == "builtin_instance_extra_metadata"), None)
|
|
3287
|
+
if existing is not None:
|
|
3288
|
+
if isinstance(existing.metadata_type, dict):
|
|
3289
|
+
for name, metadata_type in metadata_types.items():
|
|
3290
|
+
existing.metadata_type.setdefault(name, metadata_type)
|
|
3291
|
+
return
|
|
3292
|
+
declared: Dict[str, DatasetMetadataType] = dict(metadata_types)
|
|
3293
|
+
|
|
3294
|
+
def builtin_instance_extra_metadata(idx: str, preprocess: PreprocessResponse) -> Dict[str, None]:
|
|
3295
|
+
# Sample rows declare the columns without claiming values; the engine injects the
|
|
3296
|
+
# real per-instance ones. A fresh dict, because nulling the probed
|
|
3297
|
+
# ElementInstance's own dict in place destroyed any encoder that returned a
|
|
3298
|
+
# reference into preprocess.data. Read at call time, so keys merged in later count.
|
|
3299
|
+
return {name: None for name in declared}
|
|
3300
|
+
|
|
3301
|
+
leap_binder.set_metadata(builtin_instance_extra_metadata,
|
|
3302
|
+
"builtin_instance_extra_metadata", declared)
|
|
3303
|
+
|
|
3304
|
+
|
|
3257
3305
|
def tensorleap_element_instance_preprocess(
|
|
3258
3306
|
instance_length_encoder: InstanceLengthCallableInterface,
|
|
3259
3307
|
instance_mask_encoder: InstanceCallableInterface,
|
|
3260
3308
|
instance_metadata_types: Optional[Dict[str, DatasetMetadataType]] = None):
|
|
3261
3309
|
def decorating_function(user_function: Callable[[], List[PreprocessResponse]]):
|
|
3262
|
-
def register_instance_extra_metadata(metadata_types: Dict[str, DatasetMetadataType]) -> None:
|
|
3263
|
-
# Idempotent: set_metadata appends without deduping, and the probe path runs inside
|
|
3264
|
-
# preprocess, so a second preprocess call would register a duplicate handler.
|
|
3265
|
-
if any(handler.name == "builtin_instance_extra_metadata"
|
|
3266
|
-
for handler in leap_binder.setup_container.metadata):
|
|
3267
|
-
return
|
|
3268
|
-
names = list(metadata_types)
|
|
3269
|
-
|
|
3270
|
-
def builtin_instance_extra_metadata(idx: str, preprocess: PreprocessResponse) -> Dict[str, None]:
|
|
3271
|
-
# Sample rows declare the columns without claiming values; the engine injects the
|
|
3272
|
-
# real per-instance ones. A fresh dict, because nulling the probed
|
|
3273
|
-
# ElementInstance's own dict in place destroyed any encoder that returned a
|
|
3274
|
-
# reference into preprocess.data.
|
|
3275
|
-
return {name: None for name in names}
|
|
3276
|
-
|
|
3277
|
-
leap_binder.set_metadata(builtin_instance_extra_metadata,
|
|
3278
|
-
"builtin_instance_extra_metadata", metadata_types)
|
|
3279
|
-
|
|
3280
3310
|
def resolve_instance_metadata_types(sample_id: Union[int, str], preprocess_response: PreprocessResponse,
|
|
3281
3311
|
idx: int) -> Optional[Dict[str, DatasetMetadataType]]:
|
|
3282
3312
|
# The probe enumerates the KEYS; the declaration, where given, supplies the TYPE.
|
|
@@ -3346,7 +3376,7 @@ def tensorleap_element_instance_preprocess(
|
|
|
3346
3376
|
resolved_types = resolve_instance_metadata_types(
|
|
3347
3377
|
sample_id, preprocess_response, idx)
|
|
3348
3378
|
if resolved_types:
|
|
3349
|
-
|
|
3379
|
+
_register_builtin_instance_extra_metadata(resolved_types)
|
|
3350
3380
|
found_instance_metadata = True
|
|
3351
3381
|
|
|
3352
3382
|
instance_to_sample_ids_mappings[instance_id] = sample_id
|
|
@@ -3357,11 +3387,8 @@ def tensorleap_element_instance_preprocess(
|
|
|
3357
3387
|
preprocess_response.sample_ids = all_sample_ids
|
|
3358
3388
|
return result
|
|
3359
3389
|
|
|
3360
|
-
def builtin_instance_metadata(idx: str, preprocess: PreprocessResponse) -> Dict[str, str]:
|
|
3361
|
-
return {'is_instance': '0', 'original_sample_id': idx, 'instance_name': 'none'}
|
|
3362
|
-
|
|
3363
3390
|
leap_binder.set_preprocess(user_function_instance)
|
|
3364
|
-
|
|
3391
|
+
_register_builtin_instance_metadata()
|
|
3365
3392
|
|
|
3366
3393
|
def _validate_input_args(*args, **kwargs):
|
|
3367
3394
|
assert len(args) == 0 and len(kwargs) == 0, \
|
|
@@ -3473,6 +3500,109 @@ def tensorleap_instances_masks_encoder(name: str):
|
|
|
3473
3500
|
return decorating_function
|
|
3474
3501
|
|
|
3475
3502
|
|
|
3503
|
+
def tensorleap_false_positive_instances_encoder(
|
|
3504
|
+
name: str, instance_metadata_types: Optional[Dict[str, DatasetMetadataType]] = None):
|
|
3505
|
+
"""Register the false-positive instances encoder.
|
|
3506
|
+
|
|
3507
|
+
`instance_metadata_types` declares the keys (and types) of the `instance_metadata` the returned
|
|
3508
|
+
ElementInstances may carry. They become `builtin_instance_extra_metadata_<key>` columns, merged
|
|
3509
|
+
with any keys the element-instance preprocess declares; a key not declared here (or by the
|
|
3510
|
+
GT instances) is dropped from false-positive rows by the engine.
|
|
3511
|
+
"""
|
|
3512
|
+
def decorating_function(user_function: Callable):
|
|
3513
|
+
def _validate_input_args(sample_id, preprocess_response, predictions):
|
|
3514
|
+
assert isinstance(sample_id, (str, int)), \
|
|
3515
|
+
(f'tensorleap_false_positive_instances_encoder validation failed: '
|
|
3516
|
+
f'Argument sample_id should be str or int. Got {type(sample_id)}.')
|
|
3517
|
+
assert isinstance(preprocess_response, PreprocessResponse), \
|
|
3518
|
+
(f'tensorleap_false_positive_instances_encoder validation failed: '
|
|
3519
|
+
f'Argument preprocess_response should be a PreprocessResponse. Got {type(preprocess_response)}.')
|
|
3520
|
+
assert isinstance(predictions, dict), \
|
|
3521
|
+
(f'tensorleap_false_positive_instances_encoder validation failed: '
|
|
3522
|
+
f'Argument predictions should be a dict. Got {type(predictions)}.')
|
|
3523
|
+
|
|
3524
|
+
def _validate_result(result):
|
|
3525
|
+
assert isinstance(result, list), \
|
|
3526
|
+
(f'tensorleap_false_positive_instances_encoder validation failed: '
|
|
3527
|
+
f'The return type should be a list of ElementInstance. Got {type(result)}.')
|
|
3528
|
+
for i, instance in enumerate(result):
|
|
3529
|
+
assert isinstance(instance, ElementInstance), \
|
|
3530
|
+
(f'tensorleap_false_positive_instances_encoder validation failed: '
|
|
3531
|
+
f'Element {i} of the returned list should be an ElementInstance. Got {type(instance)}.')
|
|
3532
|
+
|
|
3533
|
+
def inner_without_validate(sample_id, preprocess_response, predictions):
|
|
3534
|
+
global _called_from_inside_tl_decorator
|
|
3535
|
+
_called_from_inside_tl_decorator += 1
|
|
3536
|
+
|
|
3537
|
+
try:
|
|
3538
|
+
result = user_function(sample_id, preprocess_response, predictions)
|
|
3539
|
+
finally:
|
|
3540
|
+
_called_from_inside_tl_decorator -= 1
|
|
3541
|
+
|
|
3542
|
+
return result
|
|
3543
|
+
|
|
3544
|
+
leap_binder.set_false_positive_instances(inner_without_validate, name)
|
|
3545
|
+
_register_builtin_instance_metadata()
|
|
3546
|
+
if instance_metadata_types:
|
|
3547
|
+
_register_builtin_instance_extra_metadata(instance_metadata_types)
|
|
3548
|
+
|
|
3549
|
+
def inner(sample_id, preprocess_response, predictions):
|
|
3550
|
+
if os.environ.get(mapping_runtime_mode_env_var_mame):
|
|
3551
|
+
return []
|
|
3552
|
+
|
|
3553
|
+
_validate_input_args(sample_id, preprocess_response, predictions)
|
|
3554
|
+
|
|
3555
|
+
result = inner_without_validate(sample_id, preprocess_response, predictions)
|
|
3556
|
+
|
|
3557
|
+
_validate_result(result)
|
|
3558
|
+
return result
|
|
3559
|
+
|
|
3560
|
+
return inner
|
|
3561
|
+
|
|
3562
|
+
return decorating_function
|
|
3563
|
+
|
|
3564
|
+
|
|
3565
|
+
def tensorleap_false_positive_empty_gt(gt_name: str):
|
|
3566
|
+
"""Declare the empty ground truth used for false-positive instance rows of GT encoder `gt_name`."""
|
|
3567
|
+
def decorating_function(user_function: Callable):
|
|
3568
|
+
def _validate_input_args(sample_id, preprocess_response):
|
|
3569
|
+
assert isinstance(sample_id, (str, int)), \
|
|
3570
|
+
(f'tensorleap_false_positive_empty_gt validation failed: '
|
|
3571
|
+
f'Argument sample_id should be str or int. Got {type(sample_id)}.')
|
|
3572
|
+
assert isinstance(preprocess_response, PreprocessResponse), \
|
|
3573
|
+
(f'tensorleap_false_positive_empty_gt validation failed: '
|
|
3574
|
+
f'Argument preprocess_response should be a PreprocessResponse. Got {type(preprocess_response)}.')
|
|
3575
|
+
|
|
3576
|
+
def _validate_result(result):
|
|
3577
|
+
assert isinstance(result, np.ndarray), \
|
|
3578
|
+
(f'tensorleap_false_positive_empty_gt validation failed: '
|
|
3579
|
+
f'The return type should be a numpy array. Got {type(result)}.')
|
|
3580
|
+
|
|
3581
|
+
def inner_without_validate(sample_id, preprocess_response):
|
|
3582
|
+
global _called_from_inside_tl_decorator
|
|
3583
|
+
_called_from_inside_tl_decorator += 1
|
|
3584
|
+
try:
|
|
3585
|
+
result = user_function(sample_id, preprocess_response)
|
|
3586
|
+
finally:
|
|
3587
|
+
_called_from_inside_tl_decorator -= 1
|
|
3588
|
+
return result
|
|
3589
|
+
|
|
3590
|
+
leap_binder.set_false_positive_empty_gt(inner_without_validate, gt_name)
|
|
3591
|
+
|
|
3592
|
+
def inner(sample_id, preprocess_response):
|
|
3593
|
+
if os.environ.get(mapping_runtime_mode_env_var_mame):
|
|
3594
|
+
return np.zeros(0, dtype=np.float32)
|
|
3595
|
+
|
|
3596
|
+
_validate_input_args(sample_id, preprocess_response)
|
|
3597
|
+
result = inner_without_validate(sample_id, preprocess_response)
|
|
3598
|
+
_validate_result(result)
|
|
3599
|
+
return result
|
|
3600
|
+
|
|
3601
|
+
return inner
|
|
3602
|
+
|
|
3603
|
+
return decorating_function
|
|
3604
|
+
|
|
3605
|
+
|
|
3476
3606
|
def tensorleap_instances_length_encoder(name: str):
|
|
3477
3607
|
def decorating_function(user_function: InstanceLengthCallableInterface):
|
|
3478
3608
|
def _validate_input_args(sample_id: str, preprocess_response: PreprocessResponse):
|
|
@@ -434,6 +434,9 @@ class LeapLoader(LeapLoaderBase):
|
|
|
434
434
|
autoregressive_test_payload = self._check_autoregressive_step()
|
|
435
435
|
if autoregressive_test_payload is not None:
|
|
436
436
|
test_payloads.append(autoregressive_test_payload)
|
|
437
|
+
false_positive_test_payload = self._check_false_positive_empty_gt()
|
|
438
|
+
if false_positive_test_payload is not None:
|
|
439
|
+
test_payloads.append(false_positive_test_payload)
|
|
437
440
|
is_valid = all([payload.is_passed for payload in test_payloads])
|
|
438
441
|
setup_response = self.get_dataset_setup_response(handlers_test_payloads)
|
|
439
442
|
|
|
@@ -642,6 +645,22 @@ class LeapLoader(LeapLoaderBase):
|
|
|
642
645
|
result_payloads.append(test_result)
|
|
643
646
|
return result_payloads
|
|
644
647
|
|
|
648
|
+
def _check_false_positive_empty_gt(self) -> Optional[DatasetTestResultPayload]:
|
|
649
|
+
"""Push-time check that every GT encoder has a matching tensorleap_false_positive_empty_gt
|
|
650
|
+
of the right shape. None (no payload) without a false-positive encoder."""
|
|
651
|
+
handler = global_leap_binder.setup_container.false_positive_instances
|
|
652
|
+
if handler is None:
|
|
653
|
+
return None
|
|
654
|
+
test_result = DatasetTestResultPayload(handler.name)
|
|
655
|
+
try:
|
|
656
|
+
global_leap_binder.check_false_positive_empty_gt(self._preprocess_result())
|
|
657
|
+
except Exception as e:
|
|
658
|
+
line_number, file_name, stacktrace = get_root_exception_file_and_line_number()
|
|
659
|
+
error_string = f"{repr(e)} in file {file_name}, line_number: {line_number}\nStacktrace:\n{stacktrace}"
|
|
660
|
+
test_result.display[TestingSectionEnum.Errors.name] = error_string
|
|
661
|
+
test_result.is_passed = False
|
|
662
|
+
return test_result
|
|
663
|
+
|
|
645
664
|
def _check_autoregressive_step(self) -> Optional[DatasetTestResultPayload]:
|
|
646
665
|
handler = global_leap_binder.setup_container.autoregressive_step
|
|
647
666
|
if handler is None:
|
|
@@ -1056,7 +1075,10 @@ class LeapLoader(LeapLoaderBase):
|
|
|
1056
1075
|
encoder cannot be masked. Preprocessing has already run by the time this is called (the
|
|
1057
1076
|
lengths above come from it), so reading the mappings costs nothing extra.
|
|
1058
1077
|
"""
|
|
1078
|
+
self.exec_script()
|
|
1059
1079
|
setup = global_leap_binder.setup_container
|
|
1080
|
+
if setup.false_positive_instances is not None:
|
|
1081
|
+
return True
|
|
1060
1082
|
if not setup.instance_masks:
|
|
1061
1083
|
return False
|
|
1062
1084
|
try:
|
|
@@ -1768,6 +1790,75 @@ class LeapLoader(LeapLoaderBase):
|
|
|
1768
1790
|
return [prediction_type.name for prediction_type in
|
|
1769
1791
|
global_leap_binder.setup_container.prediction_types]
|
|
1770
1792
|
|
|
1793
|
+
def has_false_positive_instances(self) -> bool:
|
|
1794
|
+
self.exec_script()
|
|
1795
|
+
return global_leap_binder.setup_container.false_positive_instances is not None
|
|
1796
|
+
|
|
1797
|
+
def _native_sample_id(self, sample_id: Union[str, int]) -> Union[str, int]:
|
|
1798
|
+
# numpy ints / stringified ids from the engine -> the type the preprocess declared.
|
|
1799
|
+
return self.get_sample_id_type()(sample_id)
|
|
1800
|
+
|
|
1801
|
+
def get_false_positive_instances(self, state: DataStateEnum, sample_ids: List[Union[str, int]],
|
|
1802
|
+
predictions: Dict[str, npt.NDArray[np.float32]]
|
|
1803
|
+
) -> List[Optional[List[ElementInstance]]]:
|
|
1804
|
+
"""Run the false-positive encoder once per sample. `predictions` arrays carry a leading
|
|
1805
|
+
batch axis of len(sample_ids); row i is handed to the user function for sample_ids[i].
|
|
1806
|
+
|
|
1807
|
+
Returns one entry per sample id, in order: the sample's list of ElementInstance (`[]` when
|
|
1808
|
+
it has no false positives), or None when the user function raised for that sample or
|
|
1809
|
+
returned something that is not a list of ElementInstance. A failed sample does not fail
|
|
1810
|
+
the others; its error is printed with the sample id. A batch-size mismatch between
|
|
1811
|
+
`predictions` and `sample_ids`, or a missing encoder, still raises: those are caller errors.
|
|
1812
|
+
"""
|
|
1813
|
+
self.exec_script()
|
|
1814
|
+
handler = global_leap_binder.setup_container.false_positive_instances
|
|
1815
|
+
if handler is None:
|
|
1816
|
+
raise Exception("No tensorleap_false_positive_instances_encoder is registered.")
|
|
1817
|
+
preprocess_response = self._preprocess_result()[state]
|
|
1818
|
+
for name, array in predictions.items():
|
|
1819
|
+
if len(array) != len(sample_ids):
|
|
1820
|
+
raise Exception(
|
|
1821
|
+
f"predictions['{name}'] has batch size {len(array)} but {len(sample_ids)} sample ids were given.")
|
|
1822
|
+
|
|
1823
|
+
results: List[Optional[List[ElementInstance]]] = []
|
|
1824
|
+
for i, sample_id in enumerate(sample_ids):
|
|
1825
|
+
row = {name: array[i] for name, array in predictions.items()}
|
|
1826
|
+
try:
|
|
1827
|
+
instances = handler.function(self._native_sample_id(sample_id), preprocess_response, row)
|
|
1828
|
+
self._validate_false_positive_instances(instances)
|
|
1829
|
+
except Exception as e:
|
|
1830
|
+
print(f"tensorleap_false_positive_instances_encoder failed for sample {sample_id!r} "
|
|
1831
|
+
f"(state {state.name}): {e!r}")
|
|
1832
|
+
results.append(None)
|
|
1833
|
+
continue
|
|
1834
|
+
results.append(instances)
|
|
1835
|
+
return results
|
|
1836
|
+
|
|
1837
|
+
@staticmethod
|
|
1838
|
+
def _validate_false_positive_instances(instances: Any) -> None:
|
|
1839
|
+
prefix = "tensorleap_false_positive_instances_encoder validation failed: "
|
|
1840
|
+
if not isinstance(instances, list):
|
|
1841
|
+
raise Exception(f"{prefix}The return type should be a list of ElementInstance. "
|
|
1842
|
+
f"Got {type(instances)}.")
|
|
1843
|
+
for j, instance in enumerate(instances):
|
|
1844
|
+
if not isinstance(instance, ElementInstance):
|
|
1845
|
+
raise Exception(f"{prefix}Element {j} of the returned list should be an ElementInstance. "
|
|
1846
|
+
f"Got {type(instance)}.")
|
|
1847
|
+
|
|
1848
|
+
def get_false_positive_empty_gt(self, state: DataStateEnum,
|
|
1849
|
+
sample_id: Union[str, int]) -> Dict[str, npt.NDArray[np.float32]]:
|
|
1850
|
+
self.exec_script()
|
|
1851
|
+
preprocess_response = self._preprocess_result()[state]
|
|
1852
|
+
sample_id = self._native_sample_id(sample_id)
|
|
1853
|
+
empty_gt: Dict[str, npt.NDArray[np.float32]] = {}
|
|
1854
|
+
for gt_name, function in global_leap_binder.setup_container.false_positive_empty_gt.items():
|
|
1855
|
+
value = function(sample_id, preprocess_response)
|
|
1856
|
+
if not isinstance(value, np.ndarray):
|
|
1857
|
+
raise Exception(f"tensorleap_false_positive_empty_gt validation failed: "
|
|
1858
|
+
f"The return type for '{gt_name}' should be a numpy array. Got {type(value)}.")
|
|
1859
|
+
empty_gt[gt_name] = value.astype(np.float32, copy=False)
|
|
1860
|
+
return empty_gt
|
|
1861
|
+
|
|
1771
1862
|
def get_instances_data(self, state: DataStateEnum) -> Tuple[Dict[str, List[str]], Dict[str, str]]:
|
|
1772
1863
|
preprocess_result = self._preprocess_result()
|
|
1773
1864
|
preprocess_state = preprocess_result.get(state)
|
|
@@ -9,7 +9,7 @@ import numpy.typing as npt
|
|
|
9
9
|
|
|
10
10
|
from code_loader.contract.datasetclasses import DatasetSample, LeapData, \
|
|
11
11
|
PredictionTypeHandler, CustomLayerHandler, VisualizerHandlerData, MetricHandlerData, MetricCallableReturnType, \
|
|
12
|
-
CustomLossHandlerData
|
|
12
|
+
CustomLossHandlerData, ElementInstance
|
|
13
13
|
from code_loader.contract.enums import DataStateEnum, DataStateType
|
|
14
14
|
from code_loader.contract.responsedataclasses import DatasetIntegParseResult, DatasetTestResultPayload, \
|
|
15
15
|
DatasetSetup, ModelSetup
|
|
@@ -72,6 +72,21 @@ class LeapLoaderBase:
|
|
|
72
72
|
def get_instances_data(self, state: DataStateEnum) -> Tuple[Dict[str, List[str]], Dict[str, str]]:
|
|
73
73
|
pass
|
|
74
74
|
|
|
75
|
+
# Not abstract: a loader that predates false-positive instances (or a stand-in) has none.
|
|
76
|
+
def has_false_positive_instances(self) -> bool:
|
|
77
|
+
return False
|
|
78
|
+
|
|
79
|
+
def get_false_positive_instances(self, state: DataStateEnum, sample_ids: List[Union[str, int]],
|
|
80
|
+
predictions: Dict[str, npt.NDArray[np.float32]]
|
|
81
|
+
) -> List[Optional[List[ElementInstance]]]:
|
|
82
|
+
"""One entry per sample id: its false-positive instances, or None if the encoder failed
|
|
83
|
+
for that sample (see LeapLoader.get_false_positive_instances)."""
|
|
84
|
+
raise NotImplementedError("get_false_positive_instances is not implemented by this loader")
|
|
85
|
+
|
|
86
|
+
def get_false_positive_empty_gt(self, state: DataStateEnum,
|
|
87
|
+
sample_id: Union[str, int]) -> Dict[str, npt.NDArray[np.float32]]:
|
|
88
|
+
raise NotImplementedError("get_false_positive_empty_gt is not implemented by this loader")
|
|
89
|
+
|
|
75
90
|
def get_metadata_multiple_samples(self, state: DataStateEnum, sample_ids: Union[List[int], List[str]],
|
|
76
91
|
requested_metadata_names: Optional[List[str]] = None
|
|
77
92
|
) -> Tuple[Dict[str, Union[List[str], List[int], List[bool],
|
|
@@ -53,6 +53,22 @@ 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:
|
|
57
|
+
def numpy_encoder_function(idx: Union[int, str], samples: PreprocessResponse, predictions: Dict[str, Any]) -> List[ElementInstance]:
|
|
58
|
+
result = encoder_function(idx, samples, predictions)
|
|
59
|
+
if not isinstance(result, list):
|
|
60
|
+
return result # malformed: the loader reports it with a clear message
|
|
61
|
+
for instance in result:
|
|
62
|
+
if not isinstance(instance, ElementInstance):
|
|
63
|
+
continue
|
|
64
|
+
instance.mask = np.array(instance.mask)
|
|
65
|
+
if instance.instance_metadata is not None and instance.instance_metadata_is_none is None:
|
|
66
|
+
instance.instance_metadata_is_none = {
|
|
67
|
+
k: is_absent_metadata_value(v) for k, v in instance.instance_metadata.items()}
|
|
68
|
+
return result
|
|
69
|
+
return numpy_encoder_function
|
|
70
|
+
|
|
71
|
+
|
|
56
72
|
# The engine downcasts every tensor to float16 before pushing it to Redis, and metrics and losses
|
|
57
73
|
# read their tensors back from there — so on the platform they are handed float16 arrays. A local
|
|
58
74
|
# run feeds them the float32 arrays straight from the encoders and the model, which is why a
|
|
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.212 → code_loader-1.0.214.dev1}/code_loader/contract/responsedataclasses.py
RENAMED
|
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.212 → code_loader-1.0.214.dev1}/code_loader/experiment_api/cli_config_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/experiment_api/experiment_context.py
RENAMED
|
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.212 → code_loader-1.0.214.dev1}/code_loader/plot_functions/plot_functions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_loader-1.0.212 → code_loader-1.0.214.dev1}/code_loader/visualizers/default_visualizers.py
RENAMED
|
File without changes
|