code-loader 1.0.195.dev0__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 +57 -9
- code_loader/inner_leap_binder/leapbinder.py +26 -6
- code_loader/inner_leap_binder/leapbinder_decorators.py +188 -65
- code_loader/leaploader.py +247 -10
- code_loader/utils.py +22 -23
- {code_loader-1.0.195.dev0.dist-info → code_loader-1.0.196.dev0.dist-info}/METADATA +1 -1
- {code_loader-1.0.195.dev0.dist-info → code_loader-1.0.196.dev0.dist-info}/RECORD +9 -9
- {code_loader-1.0.195.dev0.dist-info → code_loader-1.0.196.dev0.dist-info}/LICENSE +0 -0
- {code_loader-1.0.195.dev0.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, Tuple
|
|
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
|
|
@@ -15,6 +15,8 @@ custom_latent_space_attribute = "custom_latent_space"
|
|
|
15
15
|
|
|
16
16
|
_simulation_context: Dict[str, bool] = {"active": False}
|
|
17
17
|
|
|
18
|
+
SampleId = Union[int, str]
|
|
19
|
+
|
|
18
20
|
|
|
19
21
|
@dataclass
|
|
20
22
|
class PreprocessResponse:
|
|
@@ -39,27 +41,46 @@ class PreprocessResponse:
|
|
|
39
41
|
"""
|
|
40
42
|
length: Optional[int] = None # Deprecated. Please use sample_ids instead
|
|
41
43
|
data: Any = None
|
|
42
|
-
sample_ids: Optional[Union[List[
|
|
44
|
+
sample_ids: Optional[Union[List[SampleId], List[List[SampleId]]]] = None
|
|
43
45
|
state: Optional[DataStateType] = None
|
|
44
46
|
sample_id_type: Optional[Union[Type[str], Type[int]]] = None
|
|
45
47
|
sample_ids_to_instance_mappings: Optional[Dict[str, List[str]]] = None # in use only for element instance
|
|
46
48
|
instance_to_sample_ids_mappings: Optional[Dict[str, str]] = None # in use only for element instance
|
|
47
49
|
tl_generated: bool = False
|
|
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)
|
|
48
53
|
|
|
49
54
|
def __post_init__(self) -> None:
|
|
50
55
|
assert self.sample_ids_to_instance_mappings is None, f"Keep sample_ids_to_instance_mappings None when initializing PreprocessResponse"
|
|
51
56
|
assert self.instance_to_sample_ids_mappings is None, f"Keep instance_to_sample_ids_mappings None when initializing PreprocessResponse"
|
|
52
57
|
|
|
53
58
|
if self.length is not None and self.sample_ids is None:
|
|
54
|
-
self.sample_ids = [i for i in range(self.length)]
|
|
59
|
+
self.sample_ids = cast(List[SampleId], [i for i in range(self.length)])
|
|
55
60
|
self.sample_id_type = int
|
|
61
|
+
self._grouped = False
|
|
56
62
|
elif self.length is None and self.sample_ids is not None:
|
|
57
|
-
self.
|
|
58
|
-
if self.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
for
|
|
62
|
-
assert isinstance(
|
|
63
|
+
self._grouped = len(self.sample_ids) > 0 and isinstance(self.sample_ids[0], list)
|
|
64
|
+
if self._grouped:
|
|
65
|
+
groups = cast(List[List[SampleId]], self.sample_ids)
|
|
66
|
+
assert len(groups) >= 1, "Grouped PreprocessResponse must have at least one group."
|
|
67
|
+
for group in groups:
|
|
68
|
+
assert isinstance(group, list) and len(group) > 0, \
|
|
69
|
+
"Each group in a grouped PreprocessResponse must be a non-empty list."
|
|
70
|
+
self.sample_id_type = type(groups[0][0])
|
|
71
|
+
for group in groups:
|
|
72
|
+
for sample_id in group:
|
|
73
|
+
assert isinstance(sample_id, self.sample_id_type), \
|
|
74
|
+
f"Sample id should be of type {self.sample_id_type.__name__}. Got: {type(sample_id)}"
|
|
75
|
+
self.length = sum(len(group) for group in groups)
|
|
76
|
+
else:
|
|
77
|
+
flat_ids = cast(List[SampleId], self.sample_ids)
|
|
78
|
+
self.length = len(flat_ids)
|
|
79
|
+
if self.sample_id_type is None:
|
|
80
|
+
self.sample_id_type = str
|
|
81
|
+
if self.sample_id_type == str:
|
|
82
|
+
for sample_id in flat_ids:
|
|
83
|
+
assert isinstance(sample_id, str), f"Sample id should be of type str. Got: {type(sample_id)}"
|
|
63
84
|
else:
|
|
64
85
|
raise Exception("length is deprecated, please use sample_ids instead.")
|
|
65
86
|
|
|
@@ -79,9 +100,36 @@ class PreprocessResponse:
|
|
|
79
100
|
return id(self)
|
|
80
101
|
|
|
81
102
|
def __len__(self) -> int:
|
|
103
|
+
assert self.length is not None
|
|
104
|
+
return self.length
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def is_grouped(self) -> bool:
|
|
108
|
+
return self._grouped
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def num_groups(self) -> int:
|
|
112
|
+
# Grouped: the number of groups. Flat: the (flat) sample count, since sample_ids is the
|
|
113
|
+
# flat id list and there is one sample per "group".
|
|
82
114
|
assert self.sample_ids is not None
|
|
83
115
|
return len(self.sample_ids)
|
|
84
116
|
|
|
117
|
+
@property
|
|
118
|
+
def groups(self) -> Optional[List[List[SampleId]]]:
|
|
119
|
+
# The nested list of groups when grouped, otherwise None. Callers should
|
|
120
|
+
# branch on is_grouped before relying on this.
|
|
121
|
+
return cast(List[List[SampleId]], self.sample_ids) if self._grouped else None
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def flat_sample_ids(self) -> List[SampleId]:
|
|
125
|
+
# All sample ids in order: concatenation of the groups when grouped,
|
|
126
|
+
# otherwise the flat sample_ids list as-is.
|
|
127
|
+
assert self.sample_ids is not None
|
|
128
|
+
if self._grouped:
|
|
129
|
+
groups = cast(List[List[SampleId]], self.sample_ids)
|
|
130
|
+
return [sample_id for group in groups for sample_id in group]
|
|
131
|
+
return cast(List[SampleId], self.sample_ids)
|
|
132
|
+
|
|
85
133
|
@dataclass
|
|
86
134
|
class ElementInstance:
|
|
87
135
|
name: str
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import inspect
|
|
3
|
-
from typing import Callable, List, Optional, Dict, Any, Type, Union, get_args
|
|
3
|
+
from typing import Callable, List, Optional, Dict, Any, Type, Union, get_args, cast
|
|
4
4
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
import numpy.typing as npt
|
|
@@ -549,7 +549,9 @@ class LeapBinder:
|
|
|
549
549
|
# Builtin chain metadata, declared at parse time so it survives the reporter's
|
|
550
550
|
# metadata type mapping; the placeholder values are overwritten by the engine when a
|
|
551
551
|
# chain finalizes (realized length, truncated-by-safety-cap flag).
|
|
552
|
-
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]
|
|
553
555
|
return {'length': -1, 'truncated': False}
|
|
554
556
|
|
|
555
557
|
self.set_metadata(builtin_chain_metadata, 'builtin_chain')
|
|
@@ -713,6 +715,15 @@ class LeapBinder:
|
|
|
713
715
|
if state_enum in preprocess_result_dict:
|
|
714
716
|
preprocess_result_dict_in_correct_order[state_enum] = preprocess_result_dict[state_enum]
|
|
715
717
|
|
|
718
|
+
# All-or-none: every state must agree on grouped (nested sample_ids) vs flat.
|
|
719
|
+
if len({r.is_grouped for r in preprocess_result_dict_in_correct_order.values()}) > 1:
|
|
720
|
+
shapes = ', '.join(
|
|
721
|
+
f"{state.name}={'grouped' if r.is_grouped else 'flat'}"
|
|
722
|
+
for state, r in preprocess_result_dict_in_correct_order.items())
|
|
723
|
+
raise Exception(
|
|
724
|
+
"All preprocess states must be either all grouped (nested sample_ids) or all flat, "
|
|
725
|
+
f"but got a mix: {shapes}.")
|
|
726
|
+
|
|
716
727
|
return preprocess_result_dict_in_correct_order
|
|
717
728
|
|
|
718
729
|
def get_preprocess_unlabeled_result(self) -> Optional[PreprocessResponse]:
|
|
@@ -733,7 +744,15 @@ class LeapBinder:
|
|
|
733
744
|
preprocess_response: PreprocessResponse, test_result: List[DatasetTestResultPayload],
|
|
734
745
|
dataset_base_handler: Union[DatasetBaseHandler, MetadataHandler], state: DataStateEnum) -> List[DatasetTestResultPayload]:
|
|
735
746
|
assert preprocess_response.sample_ids is not None
|
|
736
|
-
|
|
747
|
+
if preprocess_response.is_grouped:
|
|
748
|
+
# Grouped: probe with the first group, then reduce to a single sample's result so the
|
|
749
|
+
# recorded shape/type is per-sample (matching the flat case), not the (B, *) batch.
|
|
750
|
+
# (casts: sample_ids[0] is a group list here, and the grouped result is a per-sample list.)
|
|
751
|
+
group = preprocess_response.sample_ids[0]
|
|
752
|
+
raw_result = cast(Any, dataset_base_handler.function(cast(Any, group), preprocess_response))[0]
|
|
753
|
+
else:
|
|
754
|
+
raw_result = dataset_base_handler.function(
|
|
755
|
+
cast(Union[int, str], preprocess_response.sample_ids[0]), preprocess_response)
|
|
737
756
|
handler_type = 'metadata' if isinstance(dataset_base_handler, MetadataHandler) else None
|
|
738
757
|
if isinstance(dataset_base_handler, MetadataHandler):
|
|
739
758
|
if isinstance(raw_result, dict):
|
|
@@ -829,10 +848,11 @@ class LeapBinder:
|
|
|
829
848
|
preprocess_response.tl_generated = True
|
|
830
849
|
if not preprocess_response.length or preprocess_response.length < 1:
|
|
831
850
|
raise Exception("Simulation '{}' returned PreprocessResponse with length < 1".format(sim.name))
|
|
832
|
-
preprocess_response.sample_ids = [0]
|
|
851
|
+
preprocess_response.sample_ids = cast(List[Union[int, str]], [0])
|
|
852
|
+
sim_sample_ids = cast(List[Union[int, str]], preprocess_response.sample_ids)
|
|
833
853
|
for handler in self.setup_container.inputs:
|
|
834
|
-
out1 = handler.function(
|
|
835
|
-
out2 = handler.function(
|
|
854
|
+
out1 = handler.function(sim_sample_ids[0], preprocess_response)
|
|
855
|
+
out2 = handler.function(sim_sample_ids[0], preprocess_response)
|
|
836
856
|
if not np.allclose(out1, out2):
|
|
837
857
|
raise Exception(
|
|
838
858
|
"Simulation '{}': encoder '{}' is non-deterministic — consecutive calls with seed=0 returned different outputs".format(
|
|
@@ -40,6 +40,7 @@ _called_from_inside_tl_integration_test_decorator = False
|
|
|
40
40
|
# to tell a raise in the test body (report as code-flow failure) from a module-level crash
|
|
41
41
|
# before any test ran (report as a plain script crash).
|
|
42
42
|
_integration_test_started = False
|
|
43
|
+
_mapping_dataset_is_grouped = False
|
|
43
44
|
_call_from_tl_platform = os.environ.get('IS_TENSORLEAP_PLATFORM') == 'true'
|
|
44
45
|
|
|
45
46
|
# ---- warnings store (module-level) ----
|
|
@@ -213,6 +214,53 @@ def batch_warning(result, func_name):
|
|
|
213
214
|
)
|
|
214
215
|
|
|
215
216
|
|
|
217
|
+
def _validate_id_or_group(sample_id, preprocess_response, func_name):
|
|
218
|
+
"""Accept either a single sample id (flat dataset) or a group — a list of ids (grouped
|
|
219
|
+
dataset). The argument shape must match the dataset: a group requires a grouped
|
|
220
|
+
PreprocessResponse and a single id requires a flat one. Every id must match the declared
|
|
221
|
+
sample_id_type."""
|
|
222
|
+
is_group = isinstance(sample_id, list)
|
|
223
|
+
if is_group and not preprocess_response.is_grouped:
|
|
224
|
+
raise AssertionError(
|
|
225
|
+
f'{func_name}() validation failed: got a group (list of sample ids) but the '
|
|
226
|
+
f'PreprocessResponse is not grouped. Pass a single sample id for a flat dataset.')
|
|
227
|
+
if not is_group and preprocess_response.is_grouped:
|
|
228
|
+
raise AssertionError(
|
|
229
|
+
f'{func_name}() validation failed: got a single sample id but the PreprocessResponse '
|
|
230
|
+
f'is grouped. Pass a group (list of sample ids) for a grouped dataset.')
|
|
231
|
+
ids = sample_id if is_group else [sample_id]
|
|
232
|
+
for sid in ids:
|
|
233
|
+
assert type(sid) == preprocess_response.sample_id_type, \
|
|
234
|
+
(f'{func_name}() validation failed: '
|
|
235
|
+
f'Argument sample_id should be as the same type as defined in the preprocess response '
|
|
236
|
+
f'{preprocess_response.sample_id_type}. Got {type(sid)}.')
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _validate_grouped_result(result, group_size, func_name, validate_single):
|
|
240
|
+
"""A grouped (group) encoder result must be either a single ndarray with leading dim
|
|
241
|
+
== group_size, or a list of `group_size` per-sample results (each validated by
|
|
242
|
+
validate_single). Metadata validates its grouped result separately (list only).
|
|
243
|
+
An `(B, *)` array is validated per-sample slice (not as the whole batched array) so
|
|
244
|
+
per-sample checks (e.g. channel_dim <= rank) use the sample shape, not the batch shape."""
|
|
245
|
+
if isinstance(result, np.ndarray):
|
|
246
|
+
assert len(result.shape) > 0 and result.shape[0] == group_size, \
|
|
247
|
+
(f'{func_name}() validation failed: expected a grouped output for a group of '
|
|
248
|
+
f'{group_size}: an array with leading dim {group_size}, got shape {result.shape}.')
|
|
249
|
+
for single in result:
|
|
250
|
+
validate_single(single)
|
|
251
|
+
elif isinstance(result, list):
|
|
252
|
+
assert len(result) == group_size, \
|
|
253
|
+
(f'{func_name}() validation failed: expected a grouped output for a group of '
|
|
254
|
+
f'{group_size}: a list of {group_size} arrays, got {len(result)}.')
|
|
255
|
+
for r in result:
|
|
256
|
+
validate_single(r)
|
|
257
|
+
else:
|
|
258
|
+
raise AssertionError(
|
|
259
|
+
f'{func_name}() validation failed: expected a grouped output for a group of '
|
|
260
|
+
f'{group_size}: either an array with leading dim {group_size} or a list of '
|
|
261
|
+
f'{group_size} arrays, got {type(result)}.')
|
|
262
|
+
|
|
263
|
+
|
|
216
264
|
def _add_mapping_connection(user_unique_name, connection_destinations, arg_names, name, node_mapping_type):
|
|
217
265
|
connection_destinations = [connection_destination for connection_destination in connection_destinations
|
|
218
266
|
if not isinstance(connection_destination, SamplePreprocessResponse)]
|
|
@@ -290,11 +338,7 @@ def tensorleap_integration_test():
|
|
|
290
338
|
|
|
291
339
|
def _validate_input_args(*args, **kwargs):
|
|
292
340
|
sample_id, preprocess_response = args
|
|
293
|
-
|
|
294
|
-
f"tensorleap_integration_test validation failed: "
|
|
295
|
-
f"sample_id type ({type(sample_id).__name__}) does not match the expected "
|
|
296
|
-
f"type ({preprocess_response.sample_id_type}) from the PreprocessResponse."
|
|
297
|
-
)
|
|
341
|
+
_validate_id_or_group(sample_id, preprocess_response, 'tensorleap_integration_test')
|
|
298
342
|
|
|
299
343
|
def inner(*args, **kwargs):
|
|
300
344
|
if not _call_from_tl_platform:
|
|
@@ -305,7 +349,7 @@ def tensorleap_integration_test():
|
|
|
305
349
|
expected_names = inspect.getfullargspec(integration_test_function)[0][:2]
|
|
306
350
|
if len(expected_names) < 2:
|
|
307
351
|
expected_names = ['idx', 'preprocess']
|
|
308
|
-
validate_args_structure(*args, types_order=[Union[int, str], PreprocessResponse],
|
|
352
|
+
validate_args_structure(*args, types_order=[Union[int, str, list], PreprocessResponse],
|
|
309
353
|
func_name='integration_test', expected_names=expected_names,
|
|
310
354
|
**kwargs)
|
|
311
355
|
sample_id, preprocess_response = (
|
|
@@ -329,6 +373,8 @@ def tensorleap_integration_test():
|
|
|
329
373
|
_reset_model_loop_state()
|
|
330
374
|
ret = integration_test_function(*args, **kwargs)
|
|
331
375
|
|
|
376
|
+
global _mapping_dataset_is_grouped
|
|
377
|
+
_mapping_dataset_is_grouped = args[1].is_grouped
|
|
332
378
|
try:
|
|
333
379
|
os.environ[mapping_runtime_mode_env_var_mame] = 'True'
|
|
334
380
|
_reset_model_loop_state()
|
|
@@ -349,6 +395,7 @@ def tensorleap_integration_test():
|
|
|
349
395
|
f'Integration test is only allowed to call Tensorleap decorators. '
|
|
350
396
|
f'Ensure any arithmetics, external library use, Python logic is placed within Tensorleap decoders')
|
|
351
397
|
finally:
|
|
398
|
+
_mapping_dataset_is_grouped = False
|
|
352
399
|
if mapping_runtime_mode_env_var_mame in os.environ:
|
|
353
400
|
del os.environ[mapping_runtime_mode_env_var_mame]
|
|
354
401
|
finally:
|
|
@@ -1561,13 +1608,10 @@ def tensorleap_metadata(
|
|
|
1561
1608
|
raise Exception(f'Metadata with name {name} already exists. '
|
|
1562
1609
|
f'Please choose another')
|
|
1563
1610
|
|
|
1564
|
-
def _validate_input_args(sample_id: Union[int, str], preprocess_response: PreprocessResponse):
|
|
1565
|
-
|
|
1566
|
-
(f'{user_function.__name__}() validation failed: '
|
|
1567
|
-
f'Argument sample_id should be as the same type as defined in the preprocess response '
|
|
1568
|
-
f'{preprocess_response.sample_id_type}. Got {type(sample_id)}.')
|
|
1611
|
+
def _validate_input_args(sample_id: Union[int, str, list], preprocess_response: PreprocessResponse):
|
|
1612
|
+
_validate_id_or_group(sample_id, preprocess_response, user_function.__name__)
|
|
1569
1613
|
|
|
1570
|
-
def
|
|
1614
|
+
def _validate_single(result):
|
|
1571
1615
|
supported_result_types = (type(None), int, str, bool, float, dict, np.floating,
|
|
1572
1616
|
np.bool_, np.unsignedinteger, np.signedinteger, np.integer)
|
|
1573
1617
|
if isinstance(result, tuple):
|
|
@@ -1585,6 +1629,20 @@ def tensorleap_metadata(
|
|
|
1585
1629
|
(f'{user_function.__name__}() validation failed: '
|
|
1586
1630
|
f'Values in the return dict should be of type {str(supported_result_types)}. Got {type(value)}.')
|
|
1587
1631
|
|
|
1632
|
+
def _validate_result(result, grouped=False, group_size=None):
|
|
1633
|
+
if not grouped:
|
|
1634
|
+
_validate_single(result)
|
|
1635
|
+
return
|
|
1636
|
+
# Grouped metadata: a list of `group_size` per-sample scalars/dicts.
|
|
1637
|
+
assert isinstance(result, list), \
|
|
1638
|
+
(f'{user_function.__name__}() validation failed: expected a grouped output for a group '
|
|
1639
|
+
f'of {group_size}: a list of {group_size} metadata values, got {type(result)}.')
|
|
1640
|
+
assert len(result) == group_size, \
|
|
1641
|
+
(f'{user_function.__name__}() validation failed: expected a grouped output for a group '
|
|
1642
|
+
f'of {group_size}: a list of {group_size} metadata values, got {len(result)}.')
|
|
1643
|
+
for value in result:
|
|
1644
|
+
_validate_single(value)
|
|
1645
|
+
|
|
1588
1646
|
def inner_without_validate(sample_id, preprocess_response):
|
|
1589
1647
|
|
|
1590
1648
|
global _called_from_inside_tl_decorator
|
|
@@ -1604,14 +1662,16 @@ def tensorleap_metadata(
|
|
|
1604
1662
|
set_current('tensorleap_metadata')
|
|
1605
1663
|
if os.environ.get(mapping_runtime_mode_env_var_mame):
|
|
1606
1664
|
return None
|
|
1607
|
-
validate_args_structure(*args, types_order=[Union[int, str], PreprocessResponse],
|
|
1665
|
+
validate_args_structure(*args, types_order=[Union[int, str, list], PreprocessResponse],
|
|
1608
1666
|
func_name=user_function.__name__, expected_names=["idx", "preprocess"], **kwargs)
|
|
1609
1667
|
sample_id, preprocess_response = args if len(args) != 0 else kwargs.values()
|
|
1610
1668
|
_validate_input_args(sample_id, preprocess_response)
|
|
1611
1669
|
|
|
1670
|
+
grouped = isinstance(sample_id, list)
|
|
1671
|
+
group_size = len(sample_id) if grouped else None
|
|
1612
1672
|
result = inner_without_validate(sample_id, preprocess_response)
|
|
1613
1673
|
|
|
1614
|
-
_validate_result(result)
|
|
1674
|
+
_validate_result(result, grouped, group_size)
|
|
1615
1675
|
if not _call_from_tl_platform:
|
|
1616
1676
|
update_env_params_func("tensorleap_metadata", "v")
|
|
1617
1677
|
return result
|
|
@@ -1623,35 +1683,50 @@ def tensorleap_metadata(
|
|
|
1623
1683
|
|
|
1624
1684
|
def tensorleap_custom_latent_space():
|
|
1625
1685
|
def decorating_function(user_function: SectionCallableInterface):
|
|
1626
|
-
def _validate_input_args(sample_id: Union[int, str], preprocess_response: PreprocessResponse):
|
|
1627
|
-
|
|
1628
|
-
(f'tensorleap_custom_latent_space validation failed: '
|
|
1629
|
-
f'Argument sample_id should be either int or str. Got {type(sample_id)}.')
|
|
1630
|
-
assert isinstance(preprocess_response, PreprocessResponse), \
|
|
1631
|
-
(f'tensorleap_custom_latent_space validation failed: '
|
|
1632
|
-
f'Argument preprocess_response should be a PreprocessResponse. Got {type(preprocess_response)}.')
|
|
1633
|
-
assert type(sample_id) == preprocess_response.sample_id_type, \
|
|
1634
|
-
(f'tensorleap_custom_latent_space validation failed: '
|
|
1635
|
-
f'Argument sample_id should be as the same type as defined in the preprocess response '
|
|
1636
|
-
f'{preprocess_response.sample_id_type}. Got {type(sample_id)}.')
|
|
1686
|
+
def _validate_input_args(sample_id: Union[int, str, list], preprocess_response: PreprocessResponse):
|
|
1687
|
+
_validate_id_or_group(sample_id, preprocess_response, 'tensorleap_custom_latent_space')
|
|
1637
1688
|
|
|
1638
|
-
def
|
|
1639
|
-
assert isinstance(
|
|
1689
|
+
def _validate_single(single_result):
|
|
1690
|
+
assert isinstance(single_result, np.ndarray), \
|
|
1640
1691
|
(f'tensorleap_custom_latent_space validation failed: '
|
|
1641
|
-
f'The return type should be a numpy array. Got {type(
|
|
1642
|
-
if
|
|
1643
|
-
flat_dim = int(np.prod(
|
|
1692
|
+
f'The return type should be a numpy array. Got {type(single_result)}.')
|
|
1693
|
+
if single_result.ndim > 1:
|
|
1694
|
+
flat_dim = int(np.prod(single_result.shape))
|
|
1644
1695
|
store_general_warning(
|
|
1645
|
-
key=("tensorleap_custom_latent_space_flatten", tuple(
|
|
1696
|
+
key=("tensorleap_custom_latent_space_flatten", tuple(single_result.shape)),
|
|
1646
1697
|
message=(
|
|
1647
|
-
f"tensorleap_custom_latent_space returned per-sample shape {tuple(
|
|
1648
|
-
f"(ndim={
|
|
1698
|
+
f"tensorleap_custom_latent_space returned per-sample shape {tuple(single_result.shape)} "
|
|
1699
|
+
f"(ndim={single_result.ndim}). Tensorleap assumes per-sample shape (d, ...) and will "
|
|
1649
1700
|
f"flatten to ({flat_dim},) before downstream visualization and clustering. "
|
|
1650
1701
|
f"If you want a different aggregation (e.g. global average pooling), do it "
|
|
1651
1702
|
f"inside your function."
|
|
1652
1703
|
),
|
|
1653
1704
|
)
|
|
1654
1705
|
|
|
1706
|
+
def _validate_result(result, grouped=False, group_size=None):
|
|
1707
|
+
if not grouped:
|
|
1708
|
+
_validate_single(result)
|
|
1709
|
+
return
|
|
1710
|
+
# Grouped: (B, *) array or list of B per-sample arrays. Validate each per-sample slice so
|
|
1711
|
+
# the per-sample flatten check/warning uses the sample shape, not the (B, *) batch shape.
|
|
1712
|
+
if isinstance(result, np.ndarray):
|
|
1713
|
+
assert result.ndim >= 1 and result.shape[0] == group_size, \
|
|
1714
|
+
(f'tensorleap_custom_latent_space validation failed: expected a grouped output for a '
|
|
1715
|
+
f'group of {group_size}: an array with leading dim {group_size}, got shape {result.shape}.')
|
|
1716
|
+
for single in result:
|
|
1717
|
+
_validate_single(single)
|
|
1718
|
+
elif isinstance(result, list):
|
|
1719
|
+
assert len(result) == group_size, \
|
|
1720
|
+
(f'tensorleap_custom_latent_space validation failed: expected a grouped output for a '
|
|
1721
|
+
f'group of {group_size}: a list of {group_size} arrays, got {len(result)}.')
|
|
1722
|
+
for single in result:
|
|
1723
|
+
_validate_single(single)
|
|
1724
|
+
else:
|
|
1725
|
+
raise AssertionError(
|
|
1726
|
+
f'tensorleap_custom_latent_space validation failed: expected a grouped output for a '
|
|
1727
|
+
f'group of {group_size}: either an array with leading dim {group_size} or a list of '
|
|
1728
|
+
f'{group_size} arrays, got {type(result)}.')
|
|
1729
|
+
|
|
1655
1730
|
def inner_without_validate(sample_id, preprocess_response):
|
|
1656
1731
|
global _called_from_inside_tl_decorator
|
|
1657
1732
|
_called_from_inside_tl_decorator += 1
|
|
@@ -1671,9 +1746,11 @@ def tensorleap_custom_latent_space():
|
|
|
1671
1746
|
|
|
1672
1747
|
_validate_input_args(sample_id, preprocess_response)
|
|
1673
1748
|
|
|
1749
|
+
grouped = isinstance(sample_id, list)
|
|
1750
|
+
group_size = len(sample_id) if grouped else None
|
|
1674
1751
|
result = inner_without_validate(sample_id, preprocess_response)
|
|
1675
1752
|
|
|
1676
|
-
_validate_result(result)
|
|
1753
|
+
_validate_result(result, grouped, group_size)
|
|
1677
1754
|
return result
|
|
1678
1755
|
|
|
1679
1756
|
return inner
|
|
@@ -1933,10 +2010,9 @@ def tensorleap_autoregressive_step(latent_space_aggregation: str = 'last_step'):
|
|
|
1933
2010
|
state returned by the previous call, and return the next step's full input dict together with
|
|
1934
2011
|
the updated state; returning (None, state) ends the chain — the terminating call still
|
|
1935
2012
|
returns state, so the final step participates in state aggregation. State is never fed to
|
|
1936
|
-
the model; any
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
on every step — accumulate reductions, not raw per-step tensors. The hook must be stateless and deterministically seeded (seed stochasticity from
|
|
2013
|
+
the model; it may be any nest of dicts/lists holding numpy arrays, numbers, strings or bools,
|
|
2014
|
+
and it rides the platform queue on every step — accumulate reductions, not raw per-step
|
|
2015
|
+
tensors. The hook must be stateless and deterministically seeded (seed stochasticity from
|
|
1940
2016
|
sample_id) — the engine replays steps after crash recovery and relies on identical results.
|
|
1941
2017
|
|
|
1942
2018
|
latent_space_aggregation ('last_step' | 'mean') declares how the chain's latent-space
|
|
@@ -2642,6 +2718,15 @@ def tensorleap_preprocess():
|
|
|
2642
2718
|
assert len(set(result)) == len(result), \
|
|
2643
2719
|
(f'{user_function.__name__}() validation failed: '
|
|
2644
2720
|
f'The return list should not contain duplicate PreprocessResponse objects.')
|
|
2721
|
+
# All-or-none: a dataset is either all grouped (nested sample_ids) or all flat.
|
|
2722
|
+
if len({response.is_grouped for response in result}) != 1:
|
|
2723
|
+
shapes = ', '.join(
|
|
2724
|
+
f"#{i}={'grouped' if response.is_grouped else 'flat'}"
|
|
2725
|
+
for i, response in enumerate(result))
|
|
2726
|
+
raise AssertionError(
|
|
2727
|
+
f'{user_function.__name__}() validation failed: '
|
|
2728
|
+
f'All PreprocessResponses must be either all grouped (nested sample_ids) '
|
|
2729
|
+
f'or all flat, but got a mix: {shapes}.')
|
|
2645
2730
|
|
|
2646
2731
|
def inner(*args, **kwargs):
|
|
2647
2732
|
if not _call_from_tl_platform:
|
|
@@ -2979,14 +3064,10 @@ def tensorleap_input_encoder(name: str, channel_dim=_UNSET, model_input_index=No
|
|
|
2979
3064
|
f"channel axis in the batched tensor (batch = axis 0), so 0 is invalid. Use 1 "
|
|
2980
3065
|
f"for channel-first (NCHW) and -1 for channel-last (NHWC).")
|
|
2981
3066
|
|
|
2982
|
-
def _validate_input_args(sample_id: Union[int, str], preprocess_response: PreprocessResponse):
|
|
2983
|
-
|
|
2984
|
-
(f'{user_function.__name__}() validation failed: '
|
|
2985
|
-
f'Argument sample_id should be as the same type as defined in the preprocess response '
|
|
2986
|
-
f'{preprocess_response.sample_id_type}. Got {type(sample_id)}.')
|
|
3067
|
+
def _validate_input_args(sample_id: Union[int, str, list], preprocess_response: PreprocessResponse):
|
|
3068
|
+
_validate_id_or_group(sample_id, preprocess_response, user_function.__name__)
|
|
2987
3069
|
|
|
2988
|
-
def
|
|
2989
|
-
validate_output_structure(result, func_name=user_function.__name__, expected_type_name="np.ndarray")
|
|
3070
|
+
def _validate_single(result):
|
|
2990
3071
|
assert isinstance(result, np.ndarray), \
|
|
2991
3072
|
(f'{user_function.__name__}() validation failed: '
|
|
2992
3073
|
f'Unsupported return type. Should be a numpy array. Got {type(result)}.')
|
|
@@ -2996,6 +3077,13 @@ def tensorleap_input_encoder(name: str, channel_dim=_UNSET, model_input_index=No
|
|
|
2996
3077
|
assert channel_dim - 1 <= len(result.shape), (f'{user_function.__name__}() validation failed: '
|
|
2997
3078
|
f'The channel_dim ({channel_dim}) should be <= to the rank of the resulting input rank ({len(result.shape)}).')
|
|
2998
3079
|
|
|
3080
|
+
def _validate_result(result, grouped=False, group_size=None):
|
|
3081
|
+
if not grouped:
|
|
3082
|
+
validate_output_structure(result, func_name=user_function.__name__, expected_type_name="np.ndarray")
|
|
3083
|
+
_validate_single(result)
|
|
3084
|
+
return
|
|
3085
|
+
_validate_grouped_result(result, group_size, user_function.__name__, _validate_single)
|
|
3086
|
+
|
|
2999
3087
|
def inner_without_validate(sample_id, preprocess_response):
|
|
3000
3088
|
global _called_from_inside_tl_decorator
|
|
3001
3089
|
_called_from_inside_tl_decorator += 1
|
|
@@ -3012,18 +3100,27 @@ def tensorleap_input_encoder(name: str, channel_dim=_UNSET, model_input_index=No
|
|
|
3012
3100
|
def inner(*args, **kwargs):
|
|
3013
3101
|
if not _call_from_tl_platform:
|
|
3014
3102
|
set_current("tensorleap_input_encoder")
|
|
3015
|
-
validate_args_structure(*args, types_order=[Union[int, str], PreprocessResponse],
|
|
3103
|
+
validate_args_structure(*args, types_order=[Union[int, str, list], PreprocessResponse],
|
|
3016
3104
|
func_name=user_function.__name__, expected_names=["idx", "preprocess"], **kwargs)
|
|
3017
3105
|
sample_id, preprocess_response = args if len(args) != 0 else kwargs.values()
|
|
3018
3106
|
_validate_input_args(sample_id, preprocess_response)
|
|
3019
3107
|
|
|
3108
|
+
grouped = isinstance(sample_id, list)
|
|
3109
|
+
group_size = len(sample_id) if grouped else None
|
|
3020
3110
|
result = inner_without_validate(sample_id, preprocess_response)
|
|
3021
3111
|
|
|
3022
|
-
_validate_result(result)
|
|
3112
|
+
_validate_result(result, grouped, group_size)
|
|
3023
3113
|
|
|
3024
3114
|
if _called_from_inside_tl_decorator == 0 and _called_from_inside_tl_integration_test_decorator:
|
|
3025
|
-
|
|
3026
|
-
|
|
3115
|
+
if grouped:
|
|
3116
|
+
# A grouped result is a list of per-sample arrays (never stacked, so a
|
|
3117
|
+
# B=1-only model can be fed one sample at a time). Add a batch dim to each
|
|
3118
|
+
# sample, mirroring the flat path's single-sample expand_dims.
|
|
3119
|
+
if isinstance(result, list):
|
|
3120
|
+
result = [np.expand_dims(r, axis=0) for r in result]
|
|
3121
|
+
else:
|
|
3122
|
+
batch_warning(result, user_function.__name__)
|
|
3123
|
+
result = np.expand_dims(result, axis=0)
|
|
3027
3124
|
# Emit integration test event once per test
|
|
3028
3125
|
try:
|
|
3029
3126
|
emit_integration_event_once(AnalyticsEvent.INPUT_ENCODER_INTEGRATION_TEST, {
|
|
@@ -3044,8 +3141,15 @@ def tensorleap_input_encoder(name: str, channel_dim=_UNSET, model_input_index=No
|
|
|
3044
3141
|
inner.node_mapping = NodeMapping(name, node_mapping_type)
|
|
3045
3142
|
|
|
3046
3143
|
def mapping_inner(*args, **kwargs):
|
|
3047
|
-
|
|
3048
|
-
|
|
3144
|
+
if _mapping_dataset_is_grouped:
|
|
3145
|
+
class TempMapping:
|
|
3146
|
+
def __getitem__(self, key):
|
|
3147
|
+
# Indexing a grouped input group (input_list[i]) selects a sample from the
|
|
3148
|
+
# same input source; the model wiring is identical to the un-grouped input.
|
|
3149
|
+
return self
|
|
3150
|
+
else:
|
|
3151
|
+
class TempMapping:
|
|
3152
|
+
pass
|
|
3049
3153
|
|
|
3050
3154
|
ret = TempMapping()
|
|
3051
3155
|
ret.node_mapping = mapping_inner.node_mapping
|
|
@@ -3075,15 +3179,10 @@ def tensorleap_gt_encoder(name: str):
|
|
|
3075
3179
|
raise Exception(f'GT with name {name} already exists. '
|
|
3076
3180
|
f'Please choose another')
|
|
3077
3181
|
|
|
3078
|
-
def _validate_input_args(sample_id: Union[int, str], preprocess_response: PreprocessResponse):
|
|
3079
|
-
|
|
3080
|
-
(f'{user_function.__name__}() validation failed: '
|
|
3081
|
-
f'Argument sample_id should be as the same type as defined in the preprocess response '
|
|
3082
|
-
f'{preprocess_response.sample_id_type}. Got {type(sample_id)}.')
|
|
3182
|
+
def _validate_input_args(sample_id: Union[int, str, list], preprocess_response: PreprocessResponse):
|
|
3183
|
+
_validate_id_or_group(sample_id, preprocess_response, user_function.__name__)
|
|
3083
3184
|
|
|
3084
|
-
def
|
|
3085
|
-
validate_output_structure(result, func_name=user_function.__name__, expected_type_name="np.ndarray",
|
|
3086
|
-
gt_flag=True)
|
|
3185
|
+
def _validate_single(result):
|
|
3087
3186
|
assert isinstance(result, np.ndarray), \
|
|
3088
3187
|
(f'{user_function.__name__}() validation failed: '
|
|
3089
3188
|
f'Unsupported return type. Should be a numpy array. Got {type(result)}.')
|
|
@@ -3091,6 +3190,14 @@ def tensorleap_gt_encoder(name: str):
|
|
|
3091
3190
|
(f'{user_function.__name__}() validation failed: '
|
|
3092
3191
|
f'The return type should be a numpy array of type float32. Got {result.dtype}.')
|
|
3093
3192
|
|
|
3193
|
+
def _validate_result(result, grouped=False, group_size=None):
|
|
3194
|
+
if not grouped:
|
|
3195
|
+
validate_output_structure(result, func_name=user_function.__name__, expected_type_name="np.ndarray",
|
|
3196
|
+
gt_flag=True)
|
|
3197
|
+
_validate_single(result)
|
|
3198
|
+
return
|
|
3199
|
+
_validate_grouped_result(result, group_size, user_function.__name__, _validate_single)
|
|
3200
|
+
|
|
3094
3201
|
def inner_without_validate(sample_id, preprocess_response):
|
|
3095
3202
|
global _called_from_inside_tl_decorator
|
|
3096
3203
|
_called_from_inside_tl_decorator += 1
|
|
@@ -3107,18 +3214,27 @@ def tensorleap_gt_encoder(name: str):
|
|
|
3107
3214
|
def inner(*args, **kwargs):
|
|
3108
3215
|
if not _call_from_tl_platform:
|
|
3109
3216
|
set_current("tensorleap_gt_encoder")
|
|
3110
|
-
validate_args_structure(*args, types_order=[Union[int, str], PreprocessResponse],
|
|
3217
|
+
validate_args_structure(*args, types_order=[Union[int, str, list], PreprocessResponse],
|
|
3111
3218
|
func_name=user_function.__name__, expected_names=["idx", "preprocess"], **kwargs)
|
|
3112
3219
|
sample_id, preprocess_response = args
|
|
3113
3220
|
_validate_input_args(sample_id, preprocess_response)
|
|
3114
3221
|
|
|
3222
|
+
grouped = isinstance(sample_id, list)
|
|
3223
|
+
group_size = len(sample_id) if grouped else None
|
|
3115
3224
|
result = inner_without_validate(sample_id, preprocess_response)
|
|
3116
3225
|
|
|
3117
|
-
_validate_result(result)
|
|
3226
|
+
_validate_result(result, grouped, group_size)
|
|
3118
3227
|
|
|
3119
3228
|
if _called_from_inside_tl_decorator == 0 and _called_from_inside_tl_integration_test_decorator:
|
|
3120
|
-
|
|
3121
|
-
|
|
3229
|
+
if grouped:
|
|
3230
|
+
# A grouped result is a list of per-sample arrays (never stacked, so a
|
|
3231
|
+
# B=1-only model can be fed one sample at a time). Add a batch dim to each
|
|
3232
|
+
# sample, mirroring the flat path's single-sample expand_dims.
|
|
3233
|
+
if isinstance(result, list):
|
|
3234
|
+
result = [np.expand_dims(r, axis=0) for r in result]
|
|
3235
|
+
else:
|
|
3236
|
+
batch_warning(result, user_function.__name__)
|
|
3237
|
+
result = np.expand_dims(result, axis=0)
|
|
3122
3238
|
_register_chain_artifact(result, 'ground_truth')
|
|
3123
3239
|
# Emit integration test event once per test
|
|
3124
3240
|
try:
|
|
@@ -3134,8 +3250,15 @@ def tensorleap_gt_encoder(name: str):
|
|
|
3134
3250
|
inner.node_mapping = NodeMapping(name, NodeMappingType.GroundTruth)
|
|
3135
3251
|
|
|
3136
3252
|
def mapping_inner(*args, **kwargs):
|
|
3137
|
-
|
|
3138
|
-
|
|
3253
|
+
if _mapping_dataset_is_grouped:
|
|
3254
|
+
class TempMapping:
|
|
3255
|
+
def __getitem__(self, key):
|
|
3256
|
+
# Indexing a grouped GT group (gt_list[i]) selects a sample from the same
|
|
3257
|
+
# ground-truth source; wiring is identical to the un-grouped GT node.
|
|
3258
|
+
return self
|
|
3259
|
+
else:
|
|
3260
|
+
class TempMapping:
|
|
3261
|
+
pass
|
|
3139
3262
|
|
|
3140
3263
|
ret = TempMapping()
|
|
3141
3264
|
ret.node_mapping = mapping_inner.node_mapping
|
code_loader/leaploader.py
CHANGED
|
@@ -60,14 +60,38 @@ class LeapLoader(LeapLoaderBase):
|
|
|
60
60
|
|
|
61
61
|
@lru_cache()
|
|
62
62
|
def exec_script(self) -> None:
|
|
63
|
+
from code_loader.inner_leap_binder import leapbinder_decorators as _leap_dec
|
|
63
64
|
try:
|
|
64
65
|
os.environ[mapping_runtime_mode_env_var_mame] = 'TRUE'
|
|
65
66
|
self.evaluate_module()
|
|
67
|
+
|
|
68
|
+
# A grouped integration test may index a grouped input/gt (image_list[i]) to wire a
|
|
69
|
+
# single sample of a group; that indexing is only valid when the mapping graph is
|
|
70
|
+
# built in grouped mode. Detect grouped-ness so the placeholder pass below matches
|
|
71
|
+
# the dataset. Preprocess is stubbed while mapping mode is on, so run it with mapping
|
|
72
|
+
# mode momentarily disabled, and cache it so _preprocess_result() doesn't re-run it.
|
|
73
|
+
is_grouped = False
|
|
74
|
+
if global_leap_binder.integration_test_func is not None:
|
|
75
|
+
del os.environ[mapping_runtime_mode_env_var_mame]
|
|
76
|
+
try:
|
|
77
|
+
preprocess_result = global_leap_binder.get_preprocess_result()
|
|
78
|
+
self._preprocess_result_cached = preprocess_result
|
|
79
|
+
is_grouped = any(r.is_grouped for r in preprocess_result.values())
|
|
80
|
+
except Exception:
|
|
81
|
+
is_grouped = False
|
|
82
|
+
finally:
|
|
83
|
+
os.environ[mapping_runtime_mode_env_var_mame] = 'TRUE'
|
|
84
|
+
|
|
85
|
+
_leap_dec._mapping_dataset_is_grouped = is_grouped
|
|
66
86
|
if global_leap_binder.integration_test_func is not None:
|
|
67
87
|
from code_loader.inner_leap_binder.leapbinder_decorators import \
|
|
68
88
|
_reset_model_loop_state
|
|
69
89
|
_reset_model_loop_state()
|
|
70
|
-
|
|
90
|
+
mapping_preprocess = (
|
|
91
|
+
PreprocessResponse(sample_ids=[["__mapping_placeholder__"]], state=DataStateType.training)
|
|
92
|
+
if is_grouped else
|
|
93
|
+
PreprocessResponse(state=DataStateType.training, length=0))
|
|
94
|
+
global_leap_binder.integration_test_func(None, mapping_preprocess)
|
|
71
95
|
except TypeError as e:
|
|
72
96
|
import traceback
|
|
73
97
|
global_leap_binder.setup_container = DatasetIntegrationSetup()
|
|
@@ -80,6 +104,7 @@ class LeapLoader(LeapLoaderBase):
|
|
|
80
104
|
raise DatasetScriptException(getattr(e, 'message', repr(e))) from e
|
|
81
105
|
finally:
|
|
82
106
|
# ensure that the environment variable is removed after the script execution
|
|
107
|
+
_leap_dec._mapping_dataset_is_grouped = False
|
|
83
108
|
if mapping_runtime_mode_env_var_mame in os.environ:
|
|
84
109
|
del os.environ[mapping_runtime_mode_env_var_mame]
|
|
85
110
|
|
|
@@ -209,7 +234,7 @@ class LeapLoader(LeapLoaderBase):
|
|
|
209
234
|
additional = self._preprocess_result().get(DataStateEnum.additional)
|
|
210
235
|
if additional is None:
|
|
211
236
|
return set()
|
|
212
|
-
return set(additional.
|
|
237
|
+
return set(additional.flat_sample_ids)
|
|
213
238
|
|
|
214
239
|
def _resolve_synthetic(self, sample_id: Union[int, str],
|
|
215
240
|
state: Optional[DataStateEnum] = None
|
|
@@ -250,16 +275,20 @@ class LeapLoader(LeapLoaderBase):
|
|
|
250
275
|
)
|
|
251
276
|
|
|
252
277
|
preprocess_result = self._preprocess_result()
|
|
253
|
-
if state == DataStateEnum.unlabeled and sample_id not in preprocess_result[state].
|
|
278
|
+
if state == DataStateEnum.unlabeled and sample_id not in preprocess_result[state].flat_sample_ids:
|
|
254
279
|
self._preprocess_result(update_unlabeled_preprocess=True)
|
|
255
280
|
|
|
256
281
|
metadata, metadata_is_none = self.get_metadata(state, sample_id)
|
|
257
282
|
|
|
258
283
|
custom_latent_space = None
|
|
259
284
|
if global_leap_binder.setup_container.custom_latent_space is not None:
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
285
|
+
latent_fn = global_leap_binder.setup_container.custom_latent_space.function
|
|
286
|
+
preprocess_state = preprocess_result[state]
|
|
287
|
+
if preprocess_state.is_grouped:
|
|
288
|
+
group_ids, pos = self._locate_group(preprocess_state, sample_id)
|
|
289
|
+
custom_latent_space = self._to_grouped_list(latent_fn(group_ids, preprocess_state))[pos]
|
|
290
|
+
else:
|
|
291
|
+
custom_latent_space = latent_fn(sample_id, preprocess_state)
|
|
263
292
|
instance_mask = self._get_instances_masks(state, sample_id, instance_id)
|
|
264
293
|
sample = DatasetSample(inputs=self._get_inputs(state, sample_id),
|
|
265
294
|
gt=None if state == DataStateEnum.unlabeled else self._get_gt(state, sample_id),
|
|
@@ -390,7 +419,7 @@ class LeapLoader(LeapLoaderBase):
|
|
|
390
419
|
if self.get_sample_id_type() is str:
|
|
391
420
|
max_allowed_item_size = np.dtype('<U256').itemsize
|
|
392
421
|
for state, preprocess_response in preprocess_result.items():
|
|
393
|
-
sample_ids_array = np.array(preprocess_response.
|
|
422
|
+
sample_ids_array = np.array(preprocess_response.flat_sample_ids)
|
|
394
423
|
if sample_ids_array.dtype.itemsize > max_allowed_item_size:
|
|
395
424
|
raise Exception(f"Sample id are too long. Max allowed length is 256 charecters.")
|
|
396
425
|
|
|
@@ -486,7 +515,10 @@ class LeapLoader(LeapLoaderBase):
|
|
|
486
515
|
if preprocess_response.sample_ids_to_instance_mappings:
|
|
487
516
|
raise Exception('Element instances are not supported together with '
|
|
488
517
|
'tensorleap_autoregressive_step.')
|
|
489
|
-
|
|
518
|
+
# Grouped preprocess is fine: grouping only amortizes the shared base reads
|
|
519
|
+
# (GT/metadata/custom_latent) — the AR hook always drives a single scalar chain
|
|
520
|
+
# and is never handed a group.
|
|
521
|
+
sample_id = preprocess_response.flat_sample_ids[0]
|
|
490
522
|
first_result = handler.function(sample_id, None, None, None, preprocess_response)
|
|
491
523
|
second_result = handler.function(sample_id, None, None, None, preprocess_response)
|
|
492
524
|
if not isinstance(first_result, tuple) or len(first_result) != 2:
|
|
@@ -567,7 +599,7 @@ class LeapLoader(LeapLoaderBase):
|
|
|
567
599
|
if handler.input_shapes is None:
|
|
568
600
|
preprocess_result = self._preprocess_result()
|
|
569
601
|
first_state_response = next(iter(preprocess_result.values()))
|
|
570
|
-
first_sample_id = first_state_response.
|
|
602
|
+
first_sample_id = first_state_response.flat_sample_ids[0]
|
|
571
603
|
first_result = handler.function(first_sample_id, None, None, None,
|
|
572
604
|
first_state_response)
|
|
573
605
|
if not isinstance(first_result, tuple) or len(first_result) != 2 or \
|
|
@@ -906,6 +938,57 @@ class LeapLoader(LeapLoaderBase):
|
|
|
906
938
|
|
|
907
939
|
return sample_ids
|
|
908
940
|
|
|
941
|
+
@staticmethod
|
|
942
|
+
def _grouped_dict_keys(rows: List[Dict[str, Any]], handler_name: str) -> List[str]:
|
|
943
|
+
"""Keys for a group of dict-metadata rows, requiring every row to share the same keys.
|
|
944
|
+
A group must expose a uniform metadata schema; otherwise the per-key lists would silently
|
|
945
|
+
drop or KeyError on rows that differ from row 0."""
|
|
946
|
+
keys = list(rows[0].keys())
|
|
947
|
+
key_set = set(keys)
|
|
948
|
+
for pos, row in enumerate(rows):
|
|
949
|
+
if set(row.keys()) != key_set:
|
|
950
|
+
raise ValueError(
|
|
951
|
+
f"Metadata handler {handler_name!r} returned inconsistent dict keys across the "
|
|
952
|
+
f"group: row 0 has {sorted(key_set)} but row {pos} has {sorted(row.keys())}. "
|
|
953
|
+
f"All rows in a group must share the same metadata keys.")
|
|
954
|
+
return keys
|
|
955
|
+
|
|
956
|
+
@staticmethod
|
|
957
|
+
def _to_grouped_list(raw: Any) -> List[npt.NDArray[np.float32]]:
|
|
958
|
+
"""Normalize a grouped encoder result to a list of per-sample arrays.
|
|
959
|
+
|
|
960
|
+
Grouped results are NEVER stacked into a (B, *) batch. Grouping is only a storage
|
|
961
|
+
read-unit (one file load per group); assembling the model batch (B) is the engine's
|
|
962
|
+
single responsibility, so it stays the only place samples get batched. Keeping
|
|
963
|
+
per-sample arrays lets the engine batch to any B — including a B=1-only model — without
|
|
964
|
+
an intermediate stack/unstack. A user encoder that already returned a stacked (B, *)
|
|
965
|
+
array is split back into its per-sample rows so the contract is a list either way."""
|
|
966
|
+
if isinstance(raw, list):
|
|
967
|
+
return raw
|
|
968
|
+
return [row for row in np.asarray(raw)]
|
|
969
|
+
|
|
970
|
+
def _locate_group(self, preprocess_state: PreprocessResponse,
|
|
971
|
+
sample_id: Union[int, str]) -> Tuple[List[Union[int, str]], int]:
|
|
972
|
+
"""Map a sample id to (its group, its position in that group). Cached on the
|
|
973
|
+
PreprocessResponse itself (not keyed by id() on this loader) so grouped single-sample
|
|
974
|
+
fetches don't rescan the groups, and the cache can never go stale: when the response is
|
|
975
|
+
replaced (e.g. unlabeled preprocess refresh), the old object and its cache are simply
|
|
976
|
+
discarded together instead of lingering under a possibly-reused id()."""
|
|
977
|
+
mapping = preprocess_state._group_pos_cache
|
|
978
|
+
if mapping is None:
|
|
979
|
+
mapping = {}
|
|
980
|
+
for group in preprocess_state.groups:
|
|
981
|
+
for pos, sid in enumerate(group):
|
|
982
|
+
if sid in mapping:
|
|
983
|
+
raise ValueError(
|
|
984
|
+
f"Duplicate sample id {sid!r} across groups in the preprocess response; "
|
|
985
|
+
f"sample ids must be unique within and across groups.")
|
|
986
|
+
mapping[sid] = (group, pos)
|
|
987
|
+
preprocess_state._group_pos_cache = mapping
|
|
988
|
+
if sample_id not in mapping:
|
|
989
|
+
raise KeyError(f"Sample id {sample_id!r} is not present in any group of this preprocess response.")
|
|
990
|
+
return mapping[sample_id]
|
|
991
|
+
|
|
909
992
|
def _get_dataset_handlers(self, handlers: Iterable[DatasetBaseHandler],
|
|
910
993
|
state: DataStateEnum, sample_id: Union[int, str]) -> Dict[str, npt.NDArray[np.float32]]:
|
|
911
994
|
result_agg = {}
|
|
@@ -917,12 +1000,100 @@ class LeapLoader(LeapLoaderBase):
|
|
|
917
1000
|
sample_id = original_local_id
|
|
918
1001
|
else:
|
|
919
1002
|
preprocess_state = preprocess_result[state]
|
|
1003
|
+
if preprocess_state.is_grouped:
|
|
1004
|
+
# Grouped dataset: call the encoder once with the whole group, index out the sample.
|
|
1005
|
+
group_ids, pos = self._locate_group(preprocess_state, sample_id)
|
|
1006
|
+
for handler in handlers:
|
|
1007
|
+
grouped = self._to_grouped_list(handler.function(group_ids, preprocess_state))
|
|
1008
|
+
result_agg[handler.name] = grouped[pos]
|
|
1009
|
+
return result_agg
|
|
920
1010
|
for handler in handlers:
|
|
921
1011
|
handler_result = handler.function(sample_id, preprocess_state)
|
|
922
1012
|
handler_name = handler.name
|
|
923
1013
|
result_agg[handler_name] = handler_result
|
|
924
1014
|
return result_agg
|
|
925
1015
|
|
|
1016
|
+
def get_samples(self, state: DataStateEnum, group_ids: List[Union[int, str]]) -> DatasetSample:
|
|
1017
|
+
"""Group-aware fetch: hand the whole group to each encoder in a single call and return a
|
|
1018
|
+
grouped DatasetSample (inputs/gt as per-sample lists of length B, metadata as per-key lists
|
|
1019
|
+
of length B, index = the group). Grouped results are never stacked here — batching the
|
|
1020
|
+
samples into the model's B is the engine's job. This is the path a group-aware engine calls
|
|
1021
|
+
to read a file once per group. Row order matches group_ids exactly."""
|
|
1022
|
+
self.exec_script()
|
|
1023
|
+
preprocess_result = self._preprocess_result()
|
|
1024
|
+
if state == DataStateEnum.unlabeled and any(
|
|
1025
|
+
sid not in preprocess_result[state].flat_sample_ids for sid in group_ids):
|
|
1026
|
+
# Mirrors get_sample's refresh: the unlabeled preprocess can grow between calls, so a
|
|
1027
|
+
# group_id absent from the current snapshot may just not have been generated yet.
|
|
1028
|
+
self._preprocess_result(update_unlabeled_preprocess=True)
|
|
1029
|
+
preprocess_state = preprocess_result[state]
|
|
1030
|
+
assert preprocess_state.is_grouped, (
|
|
1031
|
+
"get_samples is the group-aware fetch path and requires a grouped preprocess "
|
|
1032
|
+
"response; call get_sample for a flat (non-grouped) dataset.")
|
|
1033
|
+
# All requested ids must belong to a single group (one file). A cross-group request
|
|
1034
|
+
# would force the encoder to load multiple files, defeating the one-load-per-group
|
|
1035
|
+
# contract; partitioning a scattered request by group is the engine's responsibility.
|
|
1036
|
+
distinct_groups = {id(self._locate_group(preprocess_state, sid)[0]) for sid in group_ids}
|
|
1037
|
+
assert len(distinct_groups) == 1, (
|
|
1038
|
+
f"get_samples received sample ids spanning {len(distinct_groups)} groups; a request "
|
|
1039
|
+
f"must be confined to a single group. The engine partitions cross-group requests and "
|
|
1040
|
+
f"issues one get_samples call per group.")
|
|
1041
|
+
inputs = {handler.name: self._to_grouped_list(handler.function(group_ids, preprocess_state))
|
|
1042
|
+
for handler in global_leap_binder.setup_container.inputs}
|
|
1043
|
+
autoregressive_handler = global_leap_binder.setup_container.autoregressive_step
|
|
1044
|
+
if autoregressive_handler is not None:
|
|
1045
|
+
# AR integrations have no input encoders — the hook's first call supplies each
|
|
1046
|
+
# chain's step-0 model inputs. The hook is strictly per-scalar-chain (never handed
|
|
1047
|
+
# a group), so it is called once per flat id in the group and the per-sample results
|
|
1048
|
+
# are collected into per-key lists of length B, matching the grouped (never-stacked)
|
|
1049
|
+
# contract used for every other encoder here.
|
|
1050
|
+
step_zero_per_sample = []
|
|
1051
|
+
for sid in group_ids:
|
|
1052
|
+
step_zero_result = autoregressive_handler.function(sid, None, None, None,
|
|
1053
|
+
preprocess_state)
|
|
1054
|
+
if not isinstance(step_zero_result, tuple) or len(step_zero_result) != 2 or \
|
|
1055
|
+
not isinstance(step_zero_result[0], dict):
|
|
1056
|
+
raise Exception(
|
|
1057
|
+
'The autoregressive step hook must return a (next_inputs, state) tuple '
|
|
1058
|
+
f'with a dict of initial model inputs on its first call, got '
|
|
1059
|
+
f'{type(step_zero_result)} for sample {sid}.')
|
|
1060
|
+
self._validate_autoregressive_step_inputs(step_zero_result[0], sid)
|
|
1061
|
+
step_zero_per_sample.append(step_zero_result[0])
|
|
1062
|
+
for key in (step_zero_per_sample[0].keys() if step_zero_per_sample else []):
|
|
1063
|
+
inputs[key] = [row[key] for row in step_zero_per_sample]
|
|
1064
|
+
gt = None
|
|
1065
|
+
if state != DataStateEnum.unlabeled:
|
|
1066
|
+
gt = {handler.name: self._to_grouped_list(handler.function(group_ids, preprocess_state))
|
|
1067
|
+
for handler in global_leap_binder.setup_container.ground_truths}
|
|
1068
|
+
|
|
1069
|
+
metadata: Dict[str, Any] = {}
|
|
1070
|
+
metadata_is_none: Dict[str, Any] = {}
|
|
1071
|
+
for handler in global_leap_binder.setup_container.metadata:
|
|
1072
|
+
rows = handler.function(group_ids, preprocess_state) # list of B scalars/dicts
|
|
1073
|
+
if rows and isinstance(rows[0], dict):
|
|
1074
|
+
for key in self._grouped_dict_keys(rows, handler.name):
|
|
1075
|
+
name = "{}_{}".format(handler.name, key)
|
|
1076
|
+
converted = [self._convert_metadata_to_correct_type(name, row[key]) for row in rows]
|
|
1077
|
+
metadata[name] = [v for v, _ in converted]
|
|
1078
|
+
metadata_is_none[name] = [is_none for _, is_none in converted]
|
|
1079
|
+
else:
|
|
1080
|
+
converted = [self._convert_metadata_to_correct_type(handler.name, row) for row in rows]
|
|
1081
|
+
metadata[handler.name] = [v for v, _ in converted]
|
|
1082
|
+
metadata_is_none[handler.name] = [is_none for _, is_none in converted]
|
|
1083
|
+
|
|
1084
|
+
# custom_latent_space is group-aware like the input/GT encoders: hand it the whole group in a
|
|
1085
|
+
# single call so a file-backed latent fn loads the file once, and normalize to (B, d). This
|
|
1086
|
+
# keeps the mandatory group path non-lossy. instance_masks stay None here: they are a
|
|
1087
|
+
# per-(sample, instance) concern that needs an instance_id the group fetch does not carry.
|
|
1088
|
+
custom_latent_space = None
|
|
1089
|
+
if global_leap_binder.setup_container.custom_latent_space is not None:
|
|
1090
|
+
latent_fn = global_leap_binder.setup_container.custom_latent_space.function
|
|
1091
|
+
custom_latent_space = self._to_grouped_list(latent_fn(group_ids, preprocess_state))
|
|
1092
|
+
|
|
1093
|
+
return DatasetSample(inputs=inputs, gt=gt, metadata=metadata, metadata_is_none=metadata_is_none,
|
|
1094
|
+
index=list(group_ids), state=state, custom_latent_space=custom_latent_space,
|
|
1095
|
+
instance_masks=None)
|
|
1096
|
+
|
|
926
1097
|
def _get_inputs(self, state: DataStateEnum, sample_id: Union[int, str]) -> Dict[str, npt.NDArray[np.float32]]:
|
|
927
1098
|
inputs = self._get_dataset_handlers(global_leap_binder.setup_container.inputs, state, sample_id)
|
|
928
1099
|
autoregressive_handler = global_leap_binder.setup_container.autoregressive_step
|
|
@@ -1026,12 +1197,18 @@ class LeapLoader(LeapLoaderBase):
|
|
|
1026
1197
|
sample_id = original_local_id
|
|
1027
1198
|
else:
|
|
1028
1199
|
preprocess_state = preprocess_result[state]
|
|
1200
|
+
group_ids, pos = (None, None)
|
|
1201
|
+
if preprocess_state.is_grouped:
|
|
1202
|
+
group_ids, pos = self._locate_group(preprocess_state, sample_id)
|
|
1029
1203
|
for handler in global_leap_binder.setup_container.metadata:
|
|
1030
1204
|
if requested_metadata_names:
|
|
1031
1205
|
if not is_metadata_name_starts_with_handler_name(handler):
|
|
1032
1206
|
continue
|
|
1033
1207
|
|
|
1034
|
-
|
|
1208
|
+
if preprocess_state.is_grouped:
|
|
1209
|
+
handler_result = handler.function(group_ids, preprocess_state)[pos]
|
|
1210
|
+
else:
|
|
1211
|
+
handler_result = handler.function(sample_id, preprocess_state)
|
|
1035
1212
|
if isinstance(handler_result, dict):
|
|
1036
1213
|
for single_metadata_name, single_metadata_result in handler_result.items():
|
|
1037
1214
|
handler_name = f'{handler.name}_{single_metadata_name}'
|
|
@@ -1050,6 +1227,66 @@ class LeapLoader(LeapLoaderBase):
|
|
|
1050
1227
|
|
|
1051
1228
|
return result_agg, is_none
|
|
1052
1229
|
|
|
1230
|
+
def _grouped_metadata_for_group(self, preprocess_state: PreprocessResponse,
|
|
1231
|
+
group_ids: List[Union[int, str]],
|
|
1232
|
+
requested_metadata_names: Optional[List[str]]
|
|
1233
|
+
) -> Tuple[Dict[str, List[Any]], Dict[str, List[bool]]]:
|
|
1234
|
+
def is_wanted(_handler):
|
|
1235
|
+
if not requested_metadata_names:
|
|
1236
|
+
return True
|
|
1237
|
+
for metadata_name in requested_metadata_names:
|
|
1238
|
+
if metadata_name.startswith(_handler.name + '_') or metadata_name == _handler.name:
|
|
1239
|
+
return True
|
|
1240
|
+
return False
|
|
1241
|
+
|
|
1242
|
+
results: Dict[str, List[Any]] = {}
|
|
1243
|
+
is_none: Dict[str, List[bool]] = {}
|
|
1244
|
+
for handler in global_leap_binder.setup_container.metadata:
|
|
1245
|
+
if requested_metadata_names and not is_wanted(handler):
|
|
1246
|
+
continue
|
|
1247
|
+
rows = handler.function(group_ids, preprocess_state)
|
|
1248
|
+
if rows and isinstance(rows[0], dict):
|
|
1249
|
+
for key in self._grouped_dict_keys(rows, handler.name):
|
|
1250
|
+
name = f'{handler.name}_{key}'
|
|
1251
|
+
if requested_metadata_names and name not in requested_metadata_names:
|
|
1252
|
+
continue
|
|
1253
|
+
converted = [self._convert_metadata_to_correct_type(name, row[key]) for row in rows]
|
|
1254
|
+
results[name] = [v for v, _ in converted]
|
|
1255
|
+
is_none[name] = [n for _, n in converted]
|
|
1256
|
+
else:
|
|
1257
|
+
name = handler.name
|
|
1258
|
+
if requested_metadata_names and name not in requested_metadata_names:
|
|
1259
|
+
continue
|
|
1260
|
+
converted = [self._convert_metadata_to_correct_type(name, row) for row in rows]
|
|
1261
|
+
results[name] = [v for v, _ in converted]
|
|
1262
|
+
is_none[name] = [n for _, n in converted]
|
|
1263
|
+
return results, is_none
|
|
1264
|
+
|
|
1265
|
+
def get_metadata_multiple_samples(self, state: DataStateEnum, sample_ids: Union[List[int], List[str]],
|
|
1266
|
+
requested_metadata_names: Optional[List[str]] = None
|
|
1267
|
+
) -> Tuple[Dict[str, Union[List[str], List[int], List[bool], List[float]]],
|
|
1268
|
+
Dict[str, List[bool]]]:
|
|
1269
|
+
preprocess_state = self._preprocess_result().get(state)
|
|
1270
|
+
if preprocess_state is None or not preprocess_state.is_grouped:
|
|
1271
|
+
return super().get_metadata_multiple_samples(state, sample_ids, requested_metadata_names)
|
|
1272
|
+
|
|
1273
|
+
sample_id_type = self.get_sample_id_type()
|
|
1274
|
+
aggregated_results: Dict[str, List[Any]] = {}
|
|
1275
|
+
aggregated_is_none: Dict[str, List[bool]] = {}
|
|
1276
|
+
group_cache: Dict[int, Tuple[Dict[str, List[Any]], Dict[str, List[bool]]]] = {}
|
|
1277
|
+
for sample_id in sample_ids:
|
|
1278
|
+
sample_id = sample_id_type(sample_id)
|
|
1279
|
+
group_ids, pos = self._locate_group(preprocess_state, sample_id)
|
|
1280
|
+
key = id(group_ids)
|
|
1281
|
+
if key not in group_cache:
|
|
1282
|
+
group_cache[key] = self._grouped_metadata_for_group(
|
|
1283
|
+
preprocess_state, group_ids, requested_metadata_names)
|
|
1284
|
+
group_results, group_is_none = group_cache[key]
|
|
1285
|
+
for name, values in group_results.items():
|
|
1286
|
+
aggregated_results.setdefault(name, []).append(values[pos])
|
|
1287
|
+
aggregated_is_none.setdefault(name, []).append(group_is_none[name][pos])
|
|
1288
|
+
return aggregated_results, aggregated_is_none
|
|
1289
|
+
|
|
1053
1290
|
@lru_cache()
|
|
1054
1291
|
def get_sample_id_type(self) -> Type:
|
|
1055
1292
|
preprocess_results = list(self._preprocess_result().values())
|
code_loader/utils.py
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import io
|
|
2
1
|
import math
|
|
3
|
-
import pickle
|
|
4
2
|
import sys
|
|
5
3
|
from pathlib import Path
|
|
6
4
|
from types import TracebackType
|
|
@@ -17,6 +15,11 @@ from code_loader.contract.enums import DatasetMetadataType
|
|
|
17
15
|
def to_numpy_return_wrapper(encoder_function: SectionCallableInterface) -> SectionCallableInterface:
|
|
18
16
|
def numpy_encoder_function(idx: Union[int, str], samples: PreprocessResponse) -> npt.NDArray[np.float32]:
|
|
19
17
|
result = encoder_function(idx, samples)
|
|
18
|
+
if isinstance(result, list) and len(result) > 0 and all(isinstance(sample, np.ndarray) for sample in result):
|
|
19
|
+
# A list of per-sample arrays only comes from a grouped encoder (a flat encoder returns
|
|
20
|
+
# a single array). Never stack it into a (B, *) batch — grouping is only a storage
|
|
21
|
+
# read-unit; batching the group to the model's B is the engine's single responsibility.
|
|
22
|
+
return result
|
|
20
23
|
numpy_result: npt.NDArray[np.float32] = np.array(result)
|
|
21
24
|
return numpy_result
|
|
22
25
|
|
|
@@ -106,31 +109,27 @@ def get_metadata_type_from_variable(variable: Union[Optional[str], int, bool, Op
|
|
|
106
109
|
|
|
107
110
|
|
|
108
111
|
|
|
109
|
-
|
|
110
|
-
# WITHOUT the integration code loaded, so a class defined in the user's modules round-trips
|
|
111
|
-
# locally but crashes on the engine. Only modules importable on the engine may resolve.
|
|
112
|
-
_STATE_SAFE_PICKLE_MODULES = ('builtins', 'copyreg', 'collections', 'numpy', 'datetime')
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
class _EngineSafeUnpickler(pickle.Unpickler):
|
|
116
|
-
def find_class(self, module: str, name: str) -> Any:
|
|
117
|
-
if module.split('.')[0] in _STATE_SAFE_PICKLE_MODULES:
|
|
118
|
-
return super().find_class(module, name)
|
|
119
|
-
raise pickle.UnpicklingError(
|
|
120
|
-
f'{module}.{name} is defined in integration code, which is not importable on the '
|
|
121
|
-
f'platform engine')
|
|
112
|
+
AUTOREGRESSIVE_STATE_LEAF_TYPES = (np.ndarray, np.generic, int, float, str, bool, type(None))
|
|
122
113
|
|
|
123
114
|
|
|
124
115
|
def validate_autoregressive_state_types(value: Any, path: str = 'state') -> None:
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
116
|
+
if isinstance(value, dict):
|
|
117
|
+
for key, item in value.items():
|
|
118
|
+
if not isinstance(key, str):
|
|
119
|
+
raise AssertionError(
|
|
120
|
+
f'autoregressive state validation failed: dict key {key!r} at {path} must be '
|
|
121
|
+
f'a string. Got {type(key).__name__}.')
|
|
122
|
+
validate_autoregressive_state_types(item, f'{path}[{key!r}]')
|
|
123
|
+
return
|
|
124
|
+
if isinstance(value, (list, tuple)):
|
|
125
|
+
for i, item in enumerate(value):
|
|
126
|
+
validate_autoregressive_state_types(item, f'{path}[{i}]')
|
|
127
|
+
return
|
|
128
|
+
if not isinstance(value, AUTOREGRESSIVE_STATE_LEAF_TYPES):
|
|
128
129
|
raise AssertionError(
|
|
129
|
-
f'autoregressive state validation failed: {path}
|
|
130
|
-
'
|
|
131
|
-
'
|
|
132
|
-
'lists, tuples, sets, numbers, strings, arrays), but user-defined classes, lambdas '
|
|
133
|
-
'and open resources do not.') from e
|
|
130
|
+
f'autoregressive state validation failed: {path} holds a {type(value).__name__}. '
|
|
131
|
+
f'State must be built only from numpy arrays, numbers, strings, bools and nests of '
|
|
132
|
+
f'dicts/lists of those — it is serialized to the platform queue on every chain step.')
|
|
134
133
|
|
|
135
134
|
|
|
136
135
|
def autoregressive_nests_equal(a: Any, b: Any) -> bool:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
LICENSE,sha256=qIwWjdspQeSMTtnFZBC8MuT-95L02FPvzRUdWFxrwJY,1067
|
|
2
2
|
code_loader/__init__.py,sha256=outxRQ0M-zMfV0QGVJmAed5qWfRmyD0TV6-goEGAzBw,406
|
|
3
3
|
code_loader/contract/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
code_loader/contract/datasetclasses.py,sha256=
|
|
4
|
+
code_loader/contract/datasetclasses.py,sha256=CX4HO3xiuBUiXaeSBEyjAFV7i1NGS7KZ3JnLGxofH28,16164
|
|
5
5
|
code_loader/contract/enums.py,sha256=2q-IV_5g9lLE306DIbWA1c0tn5IhDtxsKxyV1x_Lreg,1671
|
|
6
6
|
code_loader/contract/exceptions.py,sha256=jWqu5i7t-0IG0jGRsKF4DjJdrsdpJjIYpUkN1F4RiyQ,51
|
|
7
7
|
code_loader/contract/mapping.py,sha256=sWJhpng-IkOzQnWQdMT5w2ZZ3X1Z_OOzSwCLXIS7oxE,1446
|
|
@@ -21,18 +21,18 @@ code_loader/experiment_api/types.py,sha256=MY8xFARHwdVA7p4dxyhD60ShmttgTvb4qdp1o
|
|
|
21
21
|
code_loader/experiment_api/utils.py,sha256=XZHtxge12TS4H4-8PjV3sKuhp8Ud6ojAiIzTZJEqBqc,3304
|
|
22
22
|
code_loader/experiment_api/workingspace_config_utils.py,sha256=DLzXQCg4dgTV_YgaSbeTVzq-2ja_SQw4zi7LXwKL9cY,990
|
|
23
23
|
code_loader/inner_leap_binder/__init__.py,sha256=koOlJyMNYzGbEsoIbXathSmQ-L38N_pEXH_HvL7beXU,99
|
|
24
|
-
code_loader/inner_leap_binder/leapbinder.py,sha256=
|
|
25
|
-
code_loader/inner_leap_binder/leapbinder_decorators.py,sha256=
|
|
26
|
-
code_loader/leaploader.py,sha256=
|
|
24
|
+
code_loader/inner_leap_binder/leapbinder.py,sha256=hTkOL-JLtIQSaCqg8EVxnWWaHMbChrnTkgrT1Tj5AxE,54488
|
|
25
|
+
code_loader/inner_leap_binder/leapbinder_decorators.py,sha256=1zKGCW-TgC9AYv8oc_jEplIVlnpJEwqM9o2IpGxOwTI,183070
|
|
26
|
+
code_loader/leaploader.py,sha256=k1yfKV6SBqxggUp3Yw1sNGfd50xsCaNb8-CXBsgsVY8,83459
|
|
27
27
|
code_loader/leaploaderbase.py,sha256=PvBU_2OQqBfJLDMsbK1s372954eYr4Y3O4r18y5S7uY,10739
|
|
28
28
|
code_loader/mixpanel_tracker.py,sha256=rNwRmFifNbdUoqLQvvhhgpKczWpWiEmd8MfyJe27sxw,9131
|
|
29
29
|
code_loader/plot_functions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
30
|
code_loader/plot_functions/plot_functions.py,sha256=2DC-zlVaN13P4VNx5d8csgs80C6SisaeP1-Kq2LW7iM,16075
|
|
31
31
|
code_loader/plot_functions/visualize.py,sha256=gsBAYYkwMh7jIpJeDMPS8G4CW-pxwx6LznoQIvi4vpo,657
|
|
32
|
-
code_loader/utils.py,sha256=
|
|
32
|
+
code_loader/utils.py,sha256=mt1V191TL-6goWPnsqjW76wffGFGNdx8xdQ0J4ZT9bU,6779
|
|
33
33
|
code_loader/visualizers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
34
|
code_loader/visualizers/default_visualizers.py,sha256=onRnLE_TXfgLN4o52hQIOOhUcFexGlqJ3xSpQDVLuZM,2604
|
|
35
|
-
code_loader-1.0.
|
|
36
|
-
code_loader-1.0.
|
|
37
|
-
code_loader-1.0.
|
|
38
|
-
code_loader-1.0.
|
|
35
|
+
code_loader-1.0.196.dev0.dist-info/LICENSE,sha256=qIwWjdspQeSMTtnFZBC8MuT-95L02FPvzRUdWFxrwJY,1067
|
|
36
|
+
code_loader-1.0.196.dev0.dist-info/METADATA,sha256=okTBjK87MBiyLc7eEgcuXgtl2XjCMCk_FSOtBTAnXQw,1095
|
|
37
|
+
code_loader-1.0.196.dev0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
38
|
+
code_loader-1.0.196.dev0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|