code-loader 1.0.202.dev0__tar.gz → 1.0.202.dev2__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.
Files changed (37) hide show
  1. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/PKG-INFO +1 -1
  2. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/contract/datasetclasses.py +11 -0
  3. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/inner_leap_binder/leapbinder.py +23 -2
  4. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/inner_leap_binder/leapbinder_decorators.py +26 -39
  5. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/leaploader.py +16 -1
  6. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/leaploaderbase.py +5 -0
  7. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/pyproject.toml +1 -1
  8. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/LICENSE +0 -0
  9. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/README.md +0 -0
  10. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/__init__.py +0 -0
  11. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/contract/__init__.py +0 -0
  12. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/contract/enums.py +0 -0
  13. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/contract/exceptions.py +0 -0
  14. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/contract/mapping.py +0 -0
  15. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/contract/responsedataclasses.py +0 -0
  16. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/contract/sim_config.py +0 -0
  17. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/contract/visualizer_classes.py +0 -0
  18. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/default_losses.py +0 -0
  19. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/default_metrics.py +0 -0
  20. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/experiment_api/__init__.py +0 -0
  21. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/experiment_api/api.py +0 -0
  22. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/experiment_api/cli_config_utils.py +0 -0
  23. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/experiment_api/client.py +0 -0
  24. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/experiment_api/epoch.py +0 -0
  25. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/experiment_api/experiment.py +0 -0
  26. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/experiment_api/experiment_context.py +0 -0
  27. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/experiment_api/types.py +0 -0
  28. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/experiment_api/utils.py +0 -0
  29. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/experiment_api/workingspace_config_utils.py +0 -0
  30. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/inner_leap_binder/__init__.py +0 -0
  31. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/mixpanel_tracker.py +0 -0
  32. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/plot_functions/__init__.py +0 -0
  33. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/plot_functions/plot_functions.py +0 -0
  34. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/plot_functions/visualize.py +0 -0
  35. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/utils.py +0 -0
  36. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/visualizers/__init__.py +0 -0
  37. {code_loader-1.0.202.dev0 → code_loader-1.0.202.dev2}/code_loader/visualizers/default_visualizers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-loader
3
- Version: 1.0.202.dev0
3
+ Version: 1.0.202.dev2
4
4
  Summary:
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -318,6 +318,11 @@ class CustomLatentSpaceHandler:
318
318
  # dominates the model inputs). 'mean': every latent space is the elementwise mean over all steps.
319
319
  AUTOREGRESSIVE_LATENT_SPACE_AGGREGATIONS = ('last_step', 'mean')
320
320
 
321
+ # Default axis of a KV-cache tensor that indexes token positions: (batch, heads, position,
322
+ # head_dim), the layout HF-style exports produce. Overridable per integration via
323
+ # tensorleap_autoregressive_step(cache_seq_axis=...).
324
+ DEFAULT_CACHE_SEQ_AXIS = 2
325
+
321
326
  # Reserved argument names of autoregressive metrics/losses/visualizers, fed implicitly by the
322
327
  # platform from the finished chain (per-chain dicts, no batch axis). Any other argument is wired
323
328
  # to a ground-truth encoder through the integration test.
@@ -337,6 +342,12 @@ class AutoregressiveStepHandler:
337
342
  # are never passed to the hook and never reported — so the hook must NOT return them. Empty
338
343
  # when the model has no cache, in which case the chain re-feeds its full prompt each step.
339
344
  cache_tensors: Optional[Dict[str, str]] = None
345
+ # Which axis of a cache tensor indexes token positions, i.e. where its capacity is read from.
346
+ # 2 matches the (batch, heads, position, head_dim) layout every HF-style export uses. Declared
347
+ # rather than inferred because the platform cannot tell positions from heads or head_dim — in
348
+ # a (1, 3, 64, 64) tensor two of the dims are 64 — and reading the wrong axis silently caps
349
+ # chains at the number of heads instead of the cache capacity.
350
+ cache_seq_axis: int = DEFAULT_CACHE_SEQ_AXIS
340
351
 
341
352
 
342
353
  # Per-chain, unbatched callables: called once per finished chain with the final step's tensors —
@@ -18,6 +18,7 @@ from code_loader.contract.datasetclasses import SectionCallableInterface, InputH
18
18
  ElementInstanceMasksHandler, InstanceCallableInterface, CustomLatentSpaceHandler, InstanceMetricHandler, \
19
19
  SimulationHandler, _simulation_context, AutoregressiveStepHandler, AutoregressiveStepCallableInterface, \
20
20
  AUTOREGRESSIVE_LATENT_SPACE_AGGREGATIONS, AUTOREGRESSIVE_IMPLICIT_ARG_NAMES, \
21
+ DEFAULT_CACHE_SEQ_AXIS, \
21
22
  AutoregressiveMetricHandler, AutoregressiveLossHandler, AutoregressiveVisualizerHandler
22
23
  from code_loader.contract.enums import LeapDataType, DataStateEnum, DataStateType, MetricDirection, DatasetMetadataType, \
23
24
  TestingSectionEnum
@@ -622,9 +623,25 @@ class LeapBinder:
622
623
  seen_outputs[output_name] = input_name
623
624
  return dict(cache_tensors)
624
625
 
626
+ @staticmethod
627
+ def _validated_cache_seq_axis(cache_seq_axis: int,
628
+ cache_tensors: Optional[Dict[str, str]]) -> int:
629
+ """The axis must be a non-negative int, and declaring one without a cache is a mistake
630
+ worth naming — it reads as if it had an effect."""
631
+ if not isinstance(cache_seq_axis, int) or isinstance(cache_seq_axis, bool) \
632
+ or cache_seq_axis < 0:
633
+ raise Exception(f'tensorleap_autoregressive_step: cache_seq_axis must be a '
634
+ f'non-negative int axis index, got {cache_seq_axis!r}.')
635
+ if not cache_tensors and cache_seq_axis != DEFAULT_CACHE_SEQ_AXIS:
636
+ raise Exception('tensorleap_autoregressive_step: cache_seq_axis was declared without '
637
+ 'cache_tensors. The axis describes the declared cache tensors, so it '
638
+ 'has no meaning on its own.')
639
+ return cache_seq_axis
640
+
625
641
  def set_autoregressive_step(self, function: AutoregressiveStepCallableInterface,
626
642
  latent_space_aggregation: str = 'last_step',
627
- cache_tensors: Optional[Dict[str, str]] = None) -> None:
643
+ cache_tensors: Optional[Dict[str, str]] = None,
644
+ cache_seq_axis: int = DEFAULT_CACHE_SEQ_AXIS) -> None:
628
645
  """
629
646
  Set the autoregressive step hook — the feedback function that drives a chain:
630
647
  it supplies the model's initial inputs on its first call (prev_inputs=None, prev_outputs=None)
@@ -634,6 +651,9 @@ class LeapBinder:
634
651
  its steps (see AUTOREGRESSIVE_LATENT_SPACE_AGGREGATIONS).
635
652
  cache_tensors declares a KV-cache as {model_input_name: model_output_name}; the platform
636
653
  threads those tensors itself and the hook neither receives nor returns them.
654
+ cache_seq_axis declares which axis of those tensors indexes token positions, i.e. where
655
+ the platform reads the cache capacity from (default 2, for (batch, heads, position,
656
+ head_dim)).
637
657
  """
638
658
  if self.setup_container.autoregressive_step is not None:
639
659
  raise Exception('tensorleap_autoregressive_step is already defined. '
@@ -643,9 +663,10 @@ class LeapBinder:
643
663
  f'{latent_space_aggregation!r}. Supported values: '
644
664
  f'{", ".join(AUTOREGRESSIVE_LATENT_SPACE_AGGREGATIONS)}.')
645
665
  cache_tensors = self._validated_cache_tensors(cache_tensors)
666
+ cache_seq_axis = self._validated_cache_seq_axis(cache_seq_axis, cache_tensors)
646
667
  self.setup_container.autoregressive_step = AutoregressiveStepHandler(
647
668
  function, latent_space_aggregation=latent_space_aggregation,
648
- cache_tensors=cache_tensors)
669
+ cache_tensors=cache_tensors, cache_seq_axis=cache_seq_axis)
649
670
 
650
671
  # Builtin chain metadata, declared at parse time so it survives the reporter's
651
672
  # metadata type mapping; the placeholder values are overwritten by the engine when a
@@ -24,7 +24,7 @@ from code_loader.contract.datasetclasses import CustomCallableInterfaceMultiArgs
24
24
  CustomMultipleReturnCallableInterfaceMultiArgs, ConfusionMatrixCallableInterfaceMultiArgs, CustomCallableInterface, \
25
25
  VisualizerCallableInterface, MetadataSectionCallableInterface, PreprocessResponse, SectionCallableInterface, \
26
26
  ConfusionMatrixElement, SamplePreprocessResponse, PredictionTypeHandler, InstanceCallableInterface, ElementInstance, \
27
- InstanceLengthCallableInterface, AutoregressiveStepCallableInterface
27
+ InstanceLengthCallableInterface, AutoregressiveStepCallableInterface, DEFAULT_CACHE_SEQ_AXIS
28
28
  from code_loader.contract.enums import MetricDirection, LeapDataType, DatasetMetadataType, DataStateType
29
29
  from code_loader import leap_binder, LeapLoader
30
30
  from code_loader.contract.mapping import NodeMapping, NodeMappingType, NodeConnection
@@ -733,12 +733,22 @@ def tensorleap_load_model(prediction_types: Optional[List[PredictionTypeHandler]
733
733
  assert isinstance(input_dict, dict), \
734
734
  f'Expected input_dict to be a dict, got {type(input_dict)} instead.'
735
735
  seen: set = set()
736
- for i, (input_key, elem) in enumerate(input_dict.items()):
736
+ # A declared KV-cache is threaded by the platform, not wired from an input
737
+ # encoder, so those slots have no mapping node to assign — the loop feeds
738
+ # them real arrays even in mapping mode. Skip them, and count only the wired
739
+ # inputs so the remaining slot indices stay contiguous.
740
+ step_handler = leap_binder.setup_container.autoregressive_step
741
+ cache_tensors = (step_handler.cache_tensors if step_handler else None) or {}
742
+ slot = 0
743
+ for input_key, elem in input_dict.items():
744
+ if input_key in cache_tensors:
745
+ continue
737
746
  self._reject_reused_input_source(elem, seen)
738
747
  if isinstance(input_key, NodeMappingType):
739
748
  elem.node_mapping.type = input_key
740
749
  else:
741
- elem.node_mapping.type = _safe_get_item(i)
750
+ elem.node_mapping.type = _safe_get_item(slot)
751
+ slot += 1
742
752
 
743
753
  return ModelOutputPlaceholder()
744
754
 
@@ -1893,18 +1903,6 @@ class _MappingStatePlaceholder:
1893
1903
  self._unsupported()
1894
1904
 
1895
1905
 
1896
- def _shares_base(leaf, original):
1897
- """True when `leaf` is `original` or a view onto it (e.g. original[None])."""
1898
- if leaf is original:
1899
- return True
1900
- base = getattr(leaf, 'base', None)
1901
- while base is not None:
1902
- if base is original:
1903
- return True
1904
- base = getattr(base, 'base', None)
1905
- return False
1906
-
1907
-
1908
1906
  class _ModelLoopContext:
1909
1907
  def __init__(self, sample_id, preprocess_response, prediction_names, is_mapping,
1910
1908
  cache_tensors=None):
@@ -2016,29 +2014,9 @@ class _ModelLoopContext:
2016
2014
  # identity check rather than demanding the hook produce tensors it cannot see.
2017
2015
  if isinstance(fed, dict) and self.cache_tensors:
2018
2016
  fed = {key: value for key, value in fed.items() if key not in self.cache_tensors}
2017
+ fed_ids = {id(leaf) for leaf in _ndarray_leaves(fed)}
2019
2018
  hook_ids = {id(value) for value in self.fed_inputs.values()}
2020
- # A leaf may be the hook's array itself, or a VIEW of it: `arr[None]` adds the batch
2021
- # axis an ONNX model needs and shares its memory, so `.base` is the original. Allowing
2022
- # views keeps the guarantee that matters — no tensor may be COMPUTED between the hook
2023
- # and the model, since the platform would not see that work — while not forcing every
2024
- # integration to choose between the identity check and a model that expects a batch
2025
- # dimension. A genuinely new array has no base among the hook's tensors.
2026
- def _from_hook(leaf):
2027
- if id(leaf) in hook_ids:
2028
- return True
2029
- base = getattr(leaf, 'base', None)
2030
- while base is not None:
2031
- if id(base) in hook_ids:
2032
- return True
2033
- base = getattr(base, 'base', None)
2034
- return False
2035
-
2036
- fed_leaves = list(_ndarray_leaves(fed))
2037
- matched = {id(value) for value in self.fed_inputs.values()
2038
- if any(_from_hook(leaf) and (id(leaf) == id(value)
2039
- or _shares_base(leaf, value))
2040
- for leaf in fed_leaves)}
2041
- if not all(_from_hook(leaf) for leaf in fed_leaves) or matched != hook_ids:
2019
+ if fed_ids != hook_ids:
2042
2020
  extra = (' (the declared KV-cache inputs are exempt — those are threaded for you)'
2043
2021
  if self.cache_tensors else '')
2044
2022
  self._fail('the model must be fed exactly the tensors the last hook call returned — '
@@ -2106,7 +2084,8 @@ class _ModelLoopModelProxy:
2106
2084
 
2107
2085
 
2108
2086
  def tensorleap_autoregressive_step(latent_space_aggregation: str = 'last_step',
2109
- cache_tensors: Optional[Dict[str, str]] = None):
2087
+ cache_tensors: Optional[Dict[str, str]] = None,
2088
+ cache_seq_axis: int = DEFAULT_CACHE_SEQ_AXIS):
2110
2089
  """The feedback hook that drives an autoregressive chain.
2111
2090
 
2112
2091
  Signature of the decorated function:
@@ -2146,6 +2125,13 @@ def tensorleap_autoregressive_step(latent_space_aggregation: str = 'last_step',
2146
2125
  })
2147
2126
 
2148
2127
  Omit it for a model with no cache — the chain then re-feeds its whole prompt every step.
2128
+
2129
+ cache_seq_axis declares which axis of those cache tensors indexes token positions — the axis
2130
+ whose length IS the cache capacity, which the platform reads to cap chain length. The default
2131
+ 2 matches (batch, heads, position, head_dim), the layout HF-style exports produce. Set it
2132
+ when yours differs, e.g. 1 for (batch, position, heads, head_dim). It cannot be inferred: in
2133
+ a (1, 3, 64, 64) tensor two dims are 64, so a wrong guess would silently cap chains at the
2134
+ number of heads and truncate every chain a few steps in.
2149
2135
  """
2150
2136
  assert isinstance(latent_space_aggregation, str), \
2151
2137
  ('tensorleap_autoregressive_step must be called with parentheses: '
@@ -2294,7 +2280,8 @@ def tensorleap_autoregressive_step(latent_space_aggregation: str = 'last_step',
2294
2280
 
2295
2281
  leap_binder.set_autoregressive_step(inner_without_validate,
2296
2282
  latent_space_aggregation=latent_space_aggregation,
2297
- cache_tensors=cache_tensors)
2283
+ cache_tensors=cache_tensors,
2284
+ cache_seq_axis=cache_seq_axis)
2298
2285
 
2299
2286
  def inner(*args, **kwargs):
2300
2287
  if not _call_from_tl_platform:
@@ -16,7 +16,8 @@ from code_loader.contract.datasetclasses import DatasetSample, DatasetBaseHandle
16
16
  PreprocessResponse, VisualizerHandler, LeapData, \
17
17
  PredictionTypeHandler, MetadataHandler, CustomLayerHandler, MetricHandler, VisualizerHandlerData, MetricHandlerData, \
18
18
  MetricCallableReturnType, CustomLossHandlerData, CustomLossHandler, RawInputsForHeatmap, SamplePreprocessResponse, \
19
- ElementInstance, custom_latent_space_attribute, DatasetIntegrationSetup, InstanceMetricHandler, _simulation_context
19
+ ElementInstance, custom_latent_space_attribute, DatasetIntegrationSetup, InstanceMetricHandler, \
20
+ _simulation_context, DEFAULT_CACHE_SEQ_AXIS
20
21
  from code_loader.contract.enums import DataStateEnum, TestingSectionEnum, DataStateType, DatasetMetadataType
21
22
  from code_loader.contract.exceptions import DatasetScriptException
22
23
  from code_loader.contract.responsedataclasses import DatasetIntegParseResult, DatasetTestResultPayload, \
@@ -1396,6 +1397,20 @@ class LeapLoader(LeapLoaderBase):
1396
1397
  return {}
1397
1398
  return dict(handler.cache_tensors)
1398
1399
 
1400
+ @lru_cache()
1401
+ def get_autoregressive_cache_seq_axis(self) -> int:
1402
+ """Which axis of the declared cache tensors indexes token positions.
1403
+
1404
+ The platform reads the cache capacity off this axis to cap chain length. Defaults to 2
1405
+ ((batch, heads, position, head_dim)) — including when nothing is declared, where it is
1406
+ simply unused.
1407
+ """
1408
+ self.exec_script()
1409
+ handler = global_leap_binder.setup_container.autoregressive_step
1410
+ if handler is None:
1411
+ return DEFAULT_CACHE_SEQ_AXIS
1412
+ return int(handler.cache_seq_axis)
1413
+
1399
1414
  def run_autoregressive_step(self, sample_id: Union[int, str],
1400
1415
  prev_inputs: Optional[Dict[str, npt.NDArray[np.float32]]],
1401
1416
  prev_outputs: Optional[Dict[str, npt.NDArray[np.float32]]],
@@ -181,6 +181,11 @@ class LeapLoaderBase:
181
181
  raise NotImplementedError(f'{type(self).__name__} does not implement '
182
182
  'get_autoregressive_cache_tensors.')
183
183
 
184
+ @abstractmethod
185
+ def get_autoregressive_cache_seq_axis(self) -> int:
186
+ raise NotImplementedError(f'{type(self).__name__} does not implement '
187
+ 'get_autoregressive_cache_seq_axis.')
188
+
184
189
  @abstractmethod
185
190
  def get_autoregressive_decorator_names(self) -> Dict[str, List[str]]:
186
191
  raise NotImplementedError(f'{type(self).__name__} does not implement '
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "code-loader"
3
- version = "1.0.202.dev0"
3
+ version = "1.0.202.dev2"
4
4
  description = ""
5
5
  authors = ["dorhar <doron.harnoy@tensorleap.ai>"]
6
6
  license = "MIT"