code-loader 1.0.205.dev2__tar.gz → 1.0.206.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.205.dev2 → code_loader-1.0.206.dev2}/PKG-INFO +1 -1
  2. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/contract/datasetclasses.py +4 -0
  3. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/contract/responsedataclasses.py +0 -2
  4. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/inner_leap_binder/leapbinder_decorators.py +61 -13
  5. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/leaploader.py +3 -19
  6. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/utils.py +9 -0
  7. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/pyproject.toml +1 -1
  8. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/LICENSE +0 -0
  9. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/README.md +0 -0
  10. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/__init__.py +0 -0
  11. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/contract/__init__.py +0 -0
  12. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/contract/enums.py +0 -0
  13. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/contract/exceptions.py +0 -0
  14. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/contract/mapping.py +0 -0
  15. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/contract/sim_config.py +0 -0
  16. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/contract/visualizer_classes.py +0 -0
  17. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/default_losses.py +0 -0
  18. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/default_metrics.py +0 -0
  19. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/experiment_api/__init__.py +0 -0
  20. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/experiment_api/api.py +0 -0
  21. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/experiment_api/cli_config_utils.py +0 -0
  22. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/experiment_api/client.py +0 -0
  23. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/experiment_api/epoch.py +0 -0
  24. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/experiment_api/experiment.py +0 -0
  25. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/experiment_api/experiment_context.py +0 -0
  26. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/experiment_api/types.py +0 -0
  27. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/experiment_api/utils.py +0 -0
  28. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/experiment_api/workingspace_config_utils.py +0 -0
  29. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/inner_leap_binder/__init__.py +0 -0
  30. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/inner_leap_binder/leapbinder.py +0 -0
  31. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/leaploaderbase.py +0 -0
  32. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/mixpanel_tracker.py +0 -0
  33. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/plot_functions/__init__.py +0 -0
  34. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/plot_functions/plot_functions.py +0 -0
  35. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/plot_functions/visualize.py +0 -0
  36. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/visualizers/__init__.py +0 -0
  37. {code_loader-1.0.205.dev2 → code_loader-1.0.206.dev2}/code_loader/visualizers/default_visualizers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: code-loader
3
- Version: 1.0.205.dev2
3
+ Version: 1.0.206.dev2
4
4
  Summary:
5
5
  Home-page: https://github.com/tensorleap/code-loader
6
6
  License: MIT
@@ -143,6 +143,10 @@ class ElementInstance:
143
143
  name: str
144
144
  mask: npt.NDArray[np.float32]
145
145
  instance_metadata: Optional[Dict[str, Union[Optional[str], int, bool, Optional[float]]]] = None
146
+ # Per-key "this value is absent", the same pair shape DatasetSample carries. Populated at the
147
+ # masks funnel (utils.to_numpy_return_masks_wrapper) so the engine copies flags rather than
148
+ # deriving them, exactly as it does for sample-level metadata.
149
+ instance_metadata_is_none: Optional[Dict[str, bool]] = None
146
150
 
147
151
  SectionCallableInterface = Callable[[Union[int, str], PreprocessResponse], npt.NDArray[np.float32]]
148
152
  InstanceCallableInterface = Callable[[Union[int, str], PreprocessResponse, int], Optional[ElementInstance]]
@@ -86,8 +86,6 @@ class DatasetSetup:
86
86
  custom_losses: List[CustomLossInstance]
87
87
  metrics: List[MetricInstance] = field(default_factory=list)
88
88
  simulations: List[SimulationInstance] = field(default_factory=list)
89
- # Structural: the integration registered an element-instance mask encoder.
90
- has_element_instances: bool = False
91
89
 
92
90
 
93
91
  @dataclass
@@ -15,7 +15,7 @@ from typing import Optional, Union, Callable, List, Dict, get_args, get_origin,
15
15
  import numpy as np
16
16
  import numpy.typing as npt
17
17
 
18
- from code_loader.utils import get_metadata_type_from_variable, map_dict_to_metadata_types, \
18
+ from code_loader.utils import get_metadata_type_from_variable, is_absent_metadata_value, \
19
19
  validate_autoregressive_state_types, autoregressive_nests_equal, \
20
20
  simulate_engine_float16_downcast_on_call_args, ENGINE_STORAGE_DTYPE, \
21
21
  TL_DISABLE_ENGINE_FLOAT16_SIMULATION_ENV_VAR
@@ -27,7 +27,8 @@ from code_loader.contract.datasetclasses import CustomCallableInterfaceMultiArgs
27
27
  VisualizerCallableInterface, MetadataSectionCallableInterface, PreprocessResponse, SectionCallableInterface, \
28
28
  ConfusionMatrixElement, SamplePreprocessResponse, PredictionTypeHandler, InstanceCallableInterface, ElementInstance, \
29
29
  InstanceLengthCallableInterface, InstanceSectionCallableInterface, AutoregressiveStepCallableInterface
30
- from code_loader.contract.enums import MetricDirection, LeapDataType, DatasetMetadataType, DataStateType
30
+ from code_loader.contract.enums import MetricDirection, LeapDataType, DatasetMetadataType, DataStateType, \
31
+ DataStateEnum
31
32
  from code_loader import leap_binder, LeapLoader
32
33
  from code_loader.contract.mapping import NodeMapping, NodeMappingType, NodeConnection
33
34
  from code_loader.contract.visualizer_classes import LeapImage, LeapImageMask, LeapTextMask, LeapText, LeapGraph, \
@@ -2981,12 +2982,64 @@ def tensorleap_simulation(name: str, sim_params: dict):
2981
2982
 
2982
2983
 
2983
2984
  def tensorleap_element_instance_preprocess(
2984
- instance_length_encoder: InstanceLengthCallableInterface, instance_mask_encoder: InstanceCallableInterface):
2985
+ instance_length_encoder: InstanceLengthCallableInterface,
2986
+ instance_mask_encoder: InstanceCallableInterface,
2987
+ instance_metadata_types: Optional[Dict[str, DatasetMetadataType]] = None):
2985
2988
  def decorating_function(user_function: Callable[[], List[PreprocessResponse]]):
2989
+ def register_instance_extra_metadata(metadata_types: Dict[str, DatasetMetadataType]) -> None:
2990
+ # Idempotent: set_metadata appends without deduping, and the probe path runs inside
2991
+ # preprocess, so a second preprocess call would register a duplicate handler.
2992
+ if any(handler.name == "builtin_instance_extra_metadata"
2993
+ for handler in leap_binder.setup_container.metadata):
2994
+ return
2995
+ names = list(metadata_types)
2996
+
2997
+ def builtin_instance_extra_metadata(idx: str, preprocess: PreprocessResponse) -> Dict[str, None]:
2998
+ # Sample rows declare the columns without claiming values; the engine injects the
2999
+ # real per-instance ones. A fresh dict, because nulling the probed
3000
+ # ElementInstance's own dict in place destroyed any encoder that returned a
3001
+ # reference into preprocess.data.
3002
+ return {name: None for name in names}
3003
+
3004
+ leap_binder.set_metadata(builtin_instance_extra_metadata,
3005
+ "builtin_instance_extra_metadata", metadata_types)
3006
+
3007
+ def resolve_instance_metadata_types(sample_id: Union[int, str], preprocess_response: PreprocessResponse,
3008
+ idx: int) -> Optional[Dict[str, DatasetMetadataType]]:
3009
+ # The probe enumerates the KEYS; the declaration, where given, supplies the TYPE. A key
3010
+ # that is absent on the probed instance and undeclared has no type available from either
3011
+ # side -- fail with mechanism (a)'s own message so both paths read the same.
3012
+ element_instance = instance_mask_encoder(sample_id, preprocess_response, idx)
3013
+ element_instance_metadata = getattr(element_instance, 'instance_metadata', None)
3014
+ if element_instance_metadata is None:
3015
+ return dict(instance_metadata_types) if instance_metadata_types else None
3016
+ declared = instance_metadata_types or {}
3017
+ resolved = {}
3018
+ for name, value in element_instance_metadata.items():
3019
+ if name in declared:
3020
+ continue
3021
+ if is_absent_metadata_value(value):
3022
+ raise Exception(
3023
+ f"Metadata {name} is None and no metadata type is provided. It is absent on "
3024
+ f"instance {idx} of sample {sample_id!r}, so the type cannot come from the "
3025
+ f"value -- declare it: tensorleap_element_instance_preprocess(..., "
3026
+ f"instance_metadata_types={{'{name}': DatasetMetadataType.float}}).")
3027
+ resolved[name] = get_metadata_type_from_variable(value)
3028
+ # Declared wins, and a declared key gets a column even when the probed instance lacks it.
3029
+ resolved.update(declared)
3030
+ return resolved
3031
+
2986
3032
  def user_function_instance() -> List[PreprocessResponse]:
2987
3033
  result = user_function()
2988
3034
  found_instance_metadata = False
2989
- for preprocess_response in result:
3035
+ # Resolve types on training, like mechanism (a) does (leapbinder.get_preprocess_result):
3036
+ # only training is allowed to fail on an unresolvable absence. `state` is still None here
3037
+ # whenever the integration did not set it, so fall back to list position -- which is what
3038
+ # get_preprocess_result would assign, and position 0 is training.
3039
+ probe_order = sorted(
3040
+ range(len(result)),
3041
+ key=lambda i: DataStateEnum[result[i].state.name] if result[i].state is not None else i)
3042
+ for preprocess_response in (result[i] for i in probe_order):
2990
3043
  if preprocess_response.is_grouped:
2991
3044
  raise Exception(
2992
3045
  "tensorleap_element_instance_preprocess validation failed: a grouped "
@@ -3009,15 +3062,10 @@ def tensorleap_element_instance_preprocess(
3009
3062
  # "Index <id> with sample_id: <id> cannot be found!".
3010
3063
  for idx, instance_id in enumerate(instances_ids):
3011
3064
  if not found_instance_metadata:
3012
- element_instance = instance_mask_encoder(sample_id, preprocess_response, idx)
3013
- element_instance_metadata = element_instance.instance_metadata
3014
- if element_instance_metadata is not None:
3015
- element_instance_metadata_types = map_dict_to_metadata_types(element_instance_metadata)
3016
- def builtin_instance_extra_metadata(idx: str, preprocess: PreprocessResponse) -> Dict[str, str]:
3017
- for k, v in element_instance_metadata.items():
3018
- element_instance_metadata[k] = None
3019
- return element_instance_metadata
3020
- leap_binder.set_metadata(builtin_instance_extra_metadata,"builtin_instance_extra_metadata", element_instance_metadata_types)
3065
+ resolved_types = resolve_instance_metadata_types(
3066
+ sample_id, preprocess_response, idx)
3067
+ if resolved_types:
3068
+ register_instance_extra_metadata(resolved_types)
3021
3069
  found_instance_metadata = True
3022
3070
 
3023
3071
  instance_to_sample_ids_mappings[instance_id] = sample_id
@@ -28,7 +28,7 @@ from code_loader.inner_leap_binder import global_leap_binder
28
28
  from code_loader.inner_leap_binder.leapbinder import mapping_runtime_mode_env_var_mame
29
29
  from code_loader.leaploaderbase import LeapLoaderBase
30
30
  from code_loader.utils import get_root_exception_file_and_line_number, get_metadata_type_from_variable, \
31
- validate_autoregressive_state_types, autoregressive_nests_equal
31
+ validate_autoregressive_state_types, autoregressive_nests_equal, is_absent_metadata_value
32
32
 
33
33
 
34
34
  def _serialize_sim_bounds(bounds) -> dict:
@@ -935,23 +935,7 @@ class LeapLoader(LeapLoaderBase):
935
935
 
936
936
  return DatasetSetup(preprocess=dataset_preprocess, inputs=inputs, outputs=ground_truths,
937
937
  metadata=metadata_instances, visualizers=visualizers, prediction_types=prediction_types,
938
- custom_losses=custom_losses, metrics=metrics, simulations=simulations,
939
- has_element_instances=self._has_element_instances())
940
-
941
- def _has_element_instances(self) -> bool:
942
- """Does this dataset have element instances? Both halves, because either alone lies.
943
-
944
- A registered mask encoder without instance mappings is an integration that declares
945
- instances and produces none: the engine would take the pooling path with nothing to pool,
946
- and ask the UI to visualize an instance population that does not exist. Mappings without an
947
- encoder cannot be masked. Preprocessing has already run by the time this is called (the
948
- lengths above come from it), so reading the mappings costs nothing extra.
949
- """
950
- setup = global_leap_binder.setup_container
951
- if not setup.instance_masks:
952
- return False
953
- return any(response.instance_to_sample_ids_mappings
954
- for response in self._preprocess_result().values())
938
+ custom_losses=custom_losses, metrics=metrics, simulations=simulations)
955
939
 
956
940
  def get_model_setup_response(self) -> ModelSetup:
957
941
  setup = global_leap_binder.setup_container
@@ -1244,7 +1228,7 @@ class LeapLoader(LeapLoaderBase):
1244
1228
 
1245
1229
  try:
1246
1230
  is_none = False
1247
- if value is None or (isinstance(value, (int, float, np.integer, np.floating)) and not np.isfinite(value)):
1231
+ if is_absent_metadata_value(value):
1248
1232
  raise ValueError()
1249
1233
  converted_value = metadata_type_to_python_type[metadata_name_to_type[metadata_name]](value)
1250
1234
  except ValueError:
@@ -15,6 +15,12 @@ from code_loader.contract.datasetclasses import SectionCallableInterface, Prepro
15
15
  from code_loader.contract.enums import DatasetMetadataType
16
16
 
17
17
 
18
+ def is_absent_metadata_value(value: Any) -> bool:
19
+ """The one definition of an absent metadata value, shared by every mechanism."""
20
+ return value is None or (isinstance(value, (int, float, np.integer, np.floating))
21
+ and not np.isfinite(value))
22
+
23
+
18
24
  def to_numpy_return_wrapper(encoder_function: SectionCallableInterface) -> SectionCallableInterface:
19
25
  def numpy_encoder_function(idx: Union[int, str], samples: PreprocessResponse) -> npt.NDArray[np.float32]:
20
26
  result = encoder_function(idx, samples)
@@ -39,6 +45,9 @@ def to_numpy_return_masks_wrapper(encoder_function: InstanceCallableInterface) -
39
45
  if result is None:
40
46
  return None
41
47
  result.mask = np.array(result.mask)
48
+ if result.instance_metadata is not None and result.instance_metadata_is_none is None:
49
+ result.instance_metadata_is_none = {
50
+ k: is_absent_metadata_value(v) for k, v in result.instance_metadata.items()}
42
51
  return result
43
52
  return numpy_encoder_function
44
53
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "code-loader"
3
- version = "1.0.205.dev2"
3
+ version = "1.0.206.dev2"
4
4
  description = ""
5
5
  authors = ["dorhar <doron.harnoy@tensorleap.ai>"]
6
6
  license = "MIT"