code-loader 1.0.195.dev1__py3-none-any.whl → 1.0.196.dev0__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.
- code_loader/contract/datasetclasses.py +45 -10
- code_loader/inner_leap_binder/leapbinder.py +99 -2
- code_loader/inner_leap_binder/leapbinder_decorators.py +846 -97
- code_loader/leaploader.py +247 -62
- code_loader/leaploaderbase.py +67 -3
- code_loader/utils.py +45 -0
- {code_loader-1.0.195.dev1.dist-info → code_loader-1.0.196.dev0.dist-info}/METADATA +1 -1
- {code_loader-1.0.195.dev1.dist-info → code_loader-1.0.196.dev0.dist-info}/RECORD +10 -10
- {code_loader-1.0.195.dev1.dist-info → code_loader-1.0.196.dev0.dist-info}/LICENSE +0 -0
- {code_loader-1.0.195.dev1.dist-info → code_loader-1.0.196.dev0.dist-info}/WHEEL +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import warnings
|
|
2
2
|
from dataclasses import dataclass, field
|
|
3
|
-
from typing import Any, Callable, List, Optional, Dict, Union, Type, Literal, cast
|
|
3
|
+
from typing import Any, Callable, List, Optional, Dict, Union, Type, Literal, Tuple, cast
|
|
4
4
|
import re
|
|
5
5
|
import numpy as np
|
|
6
6
|
import numpy.typing as npt
|
|
@@ -48,6 +48,8 @@ class PreprocessResponse:
|
|
|
48
48
|
instance_to_sample_ids_mappings: Optional[Dict[str, str]] = None # in use only for element instance
|
|
49
49
|
tl_generated: bool = False
|
|
50
50
|
_grouped: bool = field(default=False, init=False, repr=False, compare=False)
|
|
51
|
+
_group_pos_cache: Optional[Dict[SampleId, Tuple[List[SampleId], int]]] = field(
|
|
52
|
+
default=None, init=False, repr=False, compare=False)
|
|
51
53
|
|
|
52
54
|
def __post_init__(self) -> None:
|
|
53
55
|
assert self.sample_ids_to_instance_mappings is None, f"Keep sample_ids_to_instance_mappings None when initializing PreprocessResponse"
|
|
@@ -138,15 +140,19 @@ SectionCallableInterface = Callable[[Union[int, str], PreprocessResponse], npt.N
|
|
|
138
140
|
InstanceCallableInterface = Callable[[Union[int, str], PreprocessResponse, int], Optional[ElementInstance]]
|
|
139
141
|
InstanceLengthCallableInterface = Callable[[Union[int, str], PreprocessResponse], int]
|
|
140
142
|
|
|
141
|
-
# (sample_id, prev_inputs, prev_outputs, preprocess) -> next model inputs
|
|
142
|
-
# First call per chain receives prev_inputs=None, prev_outputs=None and returns the
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
#
|
|
143
|
+
# (sample_id, prev_inputs, prev_outputs, state, preprocess) -> (next model inputs | None, state).
|
|
144
|
+
# First call per chain receives prev_inputs=None, prev_outputs=None, state=None and returns the
|
|
145
|
+
# initial model inputs plus the initial state. Returning next_inputs=None ends the chain — the
|
|
146
|
+
# terminating call still returns state, so the final step participates in state aggregation.
|
|
147
|
+
# State is an arbitrary nest of dicts/lists holding numpy arrays, numbers, strings or bools; it is
|
|
148
|
+
# never fed to the model and rides the engine's redis queue on every step, so accumulate
|
|
149
|
+
# reductions, not raw per-step tensors. The hook must be stateless and deterministically seeded
|
|
150
|
+
# (the engine may replay a step after crash recovery and relies on identical results).
|
|
151
|
+
AutoregressiveChainState = Any
|
|
146
152
|
AutoregressiveStepCallableInterface = Callable[
|
|
147
153
|
[Union[int, str], Optional[Dict[str, npt.NDArray[np.float32]]], Optional[Dict[str, npt.NDArray[np.float32]]],
|
|
148
|
-
PreprocessResponse],
|
|
149
|
-
Optional[Dict[str, npt.NDArray[np.float32]]]]
|
|
154
|
+
AutoregressiveChainState, PreprocessResponse],
|
|
155
|
+
Tuple[Optional[Dict[str, npt.NDArray[np.float32]]], AutoregressiveChainState]]
|
|
150
156
|
|
|
151
157
|
MetadataSectionCallableInterface = Union[
|
|
152
158
|
Callable[[Union[int, str], PreprocessResponse], int],
|
|
@@ -302,16 +308,42 @@ class CustomLatentSpaceHandler:
|
|
|
302
308
|
# dominates the model inputs). 'mean': every latent space is the elementwise mean over all steps.
|
|
303
309
|
AUTOREGRESSIVE_LATENT_SPACE_AGGREGATIONS = ('last_step', 'mean')
|
|
304
310
|
|
|
311
|
+
# Reserved argument names of autoregressive metrics/losses/visualizers, fed implicitly by the
|
|
312
|
+
# platform from the finished chain (per-chain dicts, no batch axis). Any other argument is wired
|
|
313
|
+
# to a ground-truth encoder through the integration test.
|
|
314
|
+
AUTOREGRESSIVE_IMPLICIT_ARG_NAMES = ('inputs', 'outputs', 'state')
|
|
315
|
+
|
|
305
316
|
|
|
306
317
|
@dataclass
|
|
307
318
|
class AutoregressiveStepHandler:
|
|
308
319
|
function: AutoregressiveStepCallableInterface
|
|
309
320
|
name: str = 'autoregressive_step'
|
|
310
|
-
# Per-model-input shapes (unbatched,
|
|
311
|
-
#
|
|
321
|
+
# Per-model-input shapes (unbatched), discovered by running the hook's first call at parse
|
|
322
|
+
# time. Fills the role InputHandler.shape plays for input encoders.
|
|
312
323
|
input_shapes: Optional[Dict[str, List[int]]] = None
|
|
313
324
|
latent_space_aggregation: str = 'last_step'
|
|
314
325
|
|
|
326
|
+
|
|
327
|
+
# Per-chain, unbatched callables: called once per finished chain with the final step's tensors —
|
|
328
|
+
# inputs/outputs/state are fed implicitly by the platform (dicts, no batch axis; outputs keyed by
|
|
329
|
+
# prediction-type names), remaining args are wired ground-truth encoder results.
|
|
330
|
+
@dataclass
|
|
331
|
+
class AutoregressiveMetricHandler:
|
|
332
|
+
metric_handler_data: MetricHandlerData
|
|
333
|
+
function: CustomCallableInterfaceMultiArgs
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
@dataclass
|
|
337
|
+
class AutoregressiveLossHandler:
|
|
338
|
+
custom_loss_handler_data: CustomLossHandlerData
|
|
339
|
+
function: CustomCallableInterface
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
@dataclass
|
|
343
|
+
class AutoregressiveVisualizerHandler:
|
|
344
|
+
visualizer_handler_data: VisualizerHandlerData
|
|
345
|
+
function: VisualizerCallableInterface
|
|
346
|
+
|
|
315
347
|
@dataclass
|
|
316
348
|
class PredictionTypeHandler:
|
|
317
349
|
name: str
|
|
@@ -353,6 +385,9 @@ class DatasetIntegrationSetup:
|
|
|
353
385
|
custom_latent_space: Optional[CustomLatentSpaceHandler] = None
|
|
354
386
|
simulations: List[SimulationHandler] = field(default_factory=list)
|
|
355
387
|
autoregressive_step: Optional[AutoregressiveStepHandler] = None
|
|
388
|
+
autoregressive_metrics: List[AutoregressiveMetricHandler] = field(default_factory=list)
|
|
389
|
+
autoregressive_losses: List[AutoregressiveLossHandler] = field(default_factory=list)
|
|
390
|
+
autoregressive_visualizers: List[AutoregressiveVisualizerHandler] = field(default_factory=list)
|
|
356
391
|
|
|
357
392
|
|
|
358
393
|
@dataclass
|
|
@@ -14,7 +14,8 @@ from code_loader.contract.datasetclasses import SectionCallableInterface, InputH
|
|
|
14
14
|
RawInputsForHeatmap, VisualizerHandlerData, MetricHandlerData, CustomLossHandlerData, SamplePreprocessResponse, \
|
|
15
15
|
ElementInstanceMasksHandler, InstanceCallableInterface, CustomLatentSpaceHandler, InstanceMetricHandler, \
|
|
16
16
|
SimulationHandler, _simulation_context, AutoregressiveStepHandler, AutoregressiveStepCallableInterface, \
|
|
17
|
-
AUTOREGRESSIVE_LATENT_SPACE_AGGREGATIONS
|
|
17
|
+
AUTOREGRESSIVE_LATENT_SPACE_AGGREGATIONS, AUTOREGRESSIVE_IMPLICIT_ARG_NAMES, \
|
|
18
|
+
AutoregressiveMetricHandler, AutoregressiveLossHandler, AutoregressiveVisualizerHandler
|
|
18
19
|
from code_loader.contract.enums import LeapDataType, DataStateEnum, DataStateType, MetricDirection, DatasetMetadataType
|
|
19
20
|
from code_loader.contract.mapping import NodeConnection, NodeMapping, NodeMappingType
|
|
20
21
|
from code_loader.contract.responsedataclasses import DatasetTestResultPayload, LeapAnalysisConfiguration
|
|
@@ -548,11 +549,90 @@ class LeapBinder:
|
|
|
548
549
|
# Builtin chain metadata, declared at parse time so it survives the reporter's
|
|
549
550
|
# metadata type mapping; the placeholder values are overwritten by the engine when a
|
|
550
551
|
# chain finalizes (realized length, truncated-by-safety-cap flag).
|
|
551
|
-
def builtin_chain_metadata(idx: Any, preprocess: PreprocessResponse) ->
|
|
552
|
+
def builtin_chain_metadata(idx: Any, preprocess: PreprocessResponse) -> Any:
|
|
553
|
+
if isinstance(idx, list):
|
|
554
|
+
return [{'length': -1, 'truncated': False} for _ in idx]
|
|
552
555
|
return {'length': -1, 'truncated': False}
|
|
553
556
|
|
|
554
557
|
self.set_metadata(builtin_chain_metadata, 'builtin_chain')
|
|
555
558
|
|
|
559
|
+
def _autoregressive_arg_names(self, function: Callable[..., Any], decorator_name: str,
|
|
560
|
+
name: str) -> List[str]:
|
|
561
|
+
"""Split an autoregressive callable's signature into implicit chain args (validated
|
|
562
|
+
present) and wired arg names (returned) — the wired args connect to ground-truth
|
|
563
|
+
encoders through the integration test."""
|
|
564
|
+
argspec = inspect.getfullargspec(function)
|
|
565
|
+
for arg_name, arg_type in argspec.annotations.items():
|
|
566
|
+
_reject_stringized_sample_preprocess_response(function, arg_name, arg_type)
|
|
567
|
+
if arg_type == SamplePreprocessResponse:
|
|
568
|
+
raise Exception(
|
|
569
|
+
f'{decorator_name} "{name}": SamplePreprocessResponse arguments are not '
|
|
570
|
+
f'supported for autoregressive decorators yet. Derive what you need inside '
|
|
571
|
+
f'the autoregressive step hook and carry it in the state.')
|
|
572
|
+
implicit = [arg_name for arg_name in argspec[0]
|
|
573
|
+
if arg_name in AUTOREGRESSIVE_IMPLICIT_ARG_NAMES]
|
|
574
|
+
if not implicit:
|
|
575
|
+
raise Exception(
|
|
576
|
+
f'{decorator_name} "{name}": the function must declare at least one of the '
|
|
577
|
+
f'implicit chain arguments {list(AUTOREGRESSIVE_IMPLICIT_ARG_NAMES)} — they are '
|
|
578
|
+
f'fed by the platform from the finished chain.')
|
|
579
|
+
return [arg_name for arg_name in argspec[0]
|
|
580
|
+
if arg_name not in AUTOREGRESSIVE_IMPLICIT_ARG_NAMES]
|
|
581
|
+
|
|
582
|
+
def _assert_unique_metric_name(self, name: str) -> None:
|
|
583
|
+
existing = [handler.metric_handler_data.name for handler in self.setup_container.metrics] \
|
|
584
|
+
+ [handler.metric_handler_data.name
|
|
585
|
+
for handler in self.setup_container.autoregressive_metrics]
|
|
586
|
+
if name in existing:
|
|
587
|
+
raise Exception(f'Metric with name {name} already exists. Please choose another')
|
|
588
|
+
|
|
589
|
+
def _assert_unique_loss_name(self, name: str) -> None:
|
|
590
|
+
existing = [handler.custom_loss_handler_data.name
|
|
591
|
+
for handler in self.setup_container.custom_loss_handlers] \
|
|
592
|
+
+ [handler.custom_loss_handler_data.name
|
|
593
|
+
for handler in self.setup_container.autoregressive_losses]
|
|
594
|
+
if name in existing:
|
|
595
|
+
raise Exception(f'Custom loss with name {name} already exists. Please choose another')
|
|
596
|
+
|
|
597
|
+
def _assert_unique_visualizer_name(self, name: str) -> None:
|
|
598
|
+
existing = [handler.visualizer_handler_data.name
|
|
599
|
+
for handler in self.setup_container.visualizers] \
|
|
600
|
+
+ [handler.visualizer_handler_data.name
|
|
601
|
+
for handler in self.setup_container.autoregressive_visualizers]
|
|
602
|
+
if name in existing:
|
|
603
|
+
raise Exception(f'Visualizer with name {name} already exists. Please choose another')
|
|
604
|
+
|
|
605
|
+
def add_autoregressive_metric(self, function: CustomCallableInterfaceMultiArgs, name: str,
|
|
606
|
+
direction: Optional[Union[MetricDirection, Dict[str, MetricDirection]]]
|
|
607
|
+
= MetricDirection.Downward,
|
|
608
|
+
compute_insights: Optional[Union[bool, Dict[str, bool]]] = None) -> None:
|
|
609
|
+
self._assert_unique_metric_name(name)
|
|
610
|
+
arg_names = self._autoregressive_arg_names(function, 'tensorleap_autoregressive_metric',
|
|
611
|
+
name)
|
|
612
|
+
metric_handler_data = MetricHandlerData(name, arg_names, direction, compute_insights)
|
|
613
|
+
self.setup_container.autoregressive_metrics.append(
|
|
614
|
+
AutoregressiveMetricHandler(metric_handler_data, function))
|
|
615
|
+
|
|
616
|
+
def add_autoregressive_loss(self, function: CustomCallableInterface, name: str) -> None:
|
|
617
|
+
self._assert_unique_loss_name(name)
|
|
618
|
+
arg_names = self._autoregressive_arg_names(function, 'tensorleap_autoregressive_loss',
|
|
619
|
+
name)
|
|
620
|
+
self.setup_container.autoregressive_losses.append(
|
|
621
|
+
AutoregressiveLossHandler(CustomLossHandlerData(name, arg_names), function))
|
|
622
|
+
|
|
623
|
+
def add_autoregressive_visualizer(self, function: VisualizerCallableInterface, name: str,
|
|
624
|
+
visualizer_type: LeapDataType) -> None:
|
|
625
|
+
self._assert_unique_visualizer_name(name)
|
|
626
|
+
if visualizer_type.value not in map_leap_data_type_to_visualizer_class:
|
|
627
|
+
raise Exception(
|
|
628
|
+
f'The visualizer_type is invalid. current visualizer_type: {visualizer_type}, '
|
|
629
|
+
f'should be one of : {", ".join([arg.__name__ for arg in get_args(LeapData)])}')
|
|
630
|
+
arg_names = self._autoregressive_arg_names(
|
|
631
|
+
function, 'tensorleap_autoregressive_visualizer', name)
|
|
632
|
+
self.setup_container.autoregressive_visualizers.append(
|
|
633
|
+
AutoregressiveVisualizerHandler(VisualizerHandlerData(name, visualizer_type,
|
|
634
|
+
arg_names), function))
|
|
635
|
+
|
|
556
636
|
def set_custom_layer(self, custom_layer: Type[Any], name: str, inspect_layer: bool = False,
|
|
557
637
|
kernel_index: Optional[int] = None, use_custom_latent_space: bool = False) -> None:
|
|
558
638
|
"""
|
|
@@ -796,6 +876,23 @@ class LeapBinder:
|
|
|
796
876
|
appear in any order in the integration file.
|
|
797
877
|
"""
|
|
798
878
|
if self.setup_container.autoregressive_step is None:
|
|
879
|
+
declared_autoregressive = [
|
|
880
|
+
('tensorleap_autoregressive_metric',
|
|
881
|
+
[handler.metric_handler_data.name
|
|
882
|
+
for handler in self.setup_container.autoregressive_metrics]),
|
|
883
|
+
('tensorleap_autoregressive_loss',
|
|
884
|
+
[handler.custom_loss_handler_data.name
|
|
885
|
+
for handler in self.setup_container.autoregressive_losses]),
|
|
886
|
+
('tensorleap_autoregressive_visualizer',
|
|
887
|
+
[handler.visualizer_handler_data.name
|
|
888
|
+
for handler in self.setup_container.autoregressive_visualizers]),
|
|
889
|
+
]
|
|
890
|
+
for decorator_name, names in declared_autoregressive:
|
|
891
|
+
if names:
|
|
892
|
+
raise Exception(
|
|
893
|
+
f'{decorator_name} {names} requires a tensorleap_autoregressive_step '
|
|
894
|
+
f'hook — autoregressive decorators consume the finished chain the hook '
|
|
895
|
+
f'drives.')
|
|
799
896
|
return
|
|
800
897
|
if self.setup_container.inputs:
|
|
801
898
|
raise Exception(
|