code-loader 1.0.207.dev0__py3-none-any.whl → 1.0.208__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.
@@ -6,13 +6,21 @@ import numpy as np
6
6
  import numpy.typing as npt
7
7
 
8
8
  from code_loader.contract.enums import DataStateType, DataStateEnum, LeapDataType, ConfusionMatrixValue, \
9
- MetricDirection, DatasetMetadataType
9
+ MetricDirection, DatasetMetadataType, LatentSpaceReduction, CustomLatentSpaceComputedAt
10
10
  from code_loader.contract.visualizer_classes import LeapImage, LeapText, LeapGraph, LeapHorizontalBar, \
11
11
  LeapTextMask, LeapImageMask, LeapImageWithBBox, LeapImageWithHeatmap, LeapVideo, LeapAudio
12
12
  from code_loader.contract.sim_config import SimConfig
13
13
 
14
14
  custom_latent_space_attribute = "custom_latent_space"
15
15
 
16
+ # Hard cap on a custom latent space's per-sample width, applied AFTER any reduction. The
17
+ # soft threshold only warns. MAX_CUSTOM_LATENT_SPACES mirrors the engine's
18
+ # src_tensorleap/common/types.py (source of truth) so an over-budget registration fails
19
+ # locally instead of being silently dropped at eval time; keep the two in sync.
20
+ MAX_CUSTOM_LATENT_SPACE_DIM = 4096
21
+ CUSTOM_LATENT_SPACE_WARN_DIM = 1024
22
+ MAX_CUSTOM_LATENT_SPACES = 10
23
+
16
24
  _simulation_context: Dict[str, bool] = {"active": False}
17
25
 
18
26
  SampleId = Union[int, str]
@@ -317,6 +325,11 @@ class CustomLatentSpaceHandler:
317
325
  name: str = 'custom_latent_space'
318
326
  use_ls_for_analysis: bool = False
319
327
  instance_aware: bool = False
328
+ computed_at: CustomLatentSpaceComputedAt = CustomLatentSpaceComputedAt.DATASET
329
+ arg_names: Optional[List[str]] = None
330
+ reduce: Optional[LatentSpaceReduction] = None
331
+ n_components: int = 512
332
+ channel_axis: int = -1
320
333
 
321
334
 
322
335
  # How a chain's latent-space vectors are derived from its per-step forward passes.
@@ -68,3 +68,13 @@ class ConfusionMatrixValue(Enum):
68
68
  class TestingSectionEnum(Enum):
69
69
  Warnings = "Warnings"
70
70
  Errors = "Errors"
71
+
72
+
73
+ class LatentSpaceReduction(Enum):
74
+ MEAN_POOL = 'MEAN_POOL'
75
+ RANDOM_PROJECTION = 'RANDOM_PROJECTION'
76
+
77
+
78
+ class CustomLatentSpaceComputedAt(Enum):
79
+ DATASET = 'dataset'
80
+ MODEL = 'model'
@@ -38,6 +38,7 @@ class NodeMappingType(Enum):
38
38
  Input8 = 'Input8'
39
39
  Input9 = 'Input9'
40
40
  PredictionLabels = 'PredictionLabels'
41
+ CustomLatentSpace = 'CustomLatentSpace'
41
42
 
42
43
 
43
44
  @dataclass
@@ -17,12 +17,12 @@ from code_loader.contract.datasetclasses import SectionCallableInterface, InputH
17
17
  CustomMultipleReturnCallableInterfaceMultiArgs, DatasetBaseHandler, custom_latent_space_attribute, \
18
18
  RawInputsForHeatmap, VisualizerHandlerData, MetricHandlerData, CustomLossHandlerData, SamplePreprocessResponse, \
19
19
  ElementInstanceMasksHandler, InstanceCallableInterface, InstanceSectionCallableInterface, \
20
- CustomLatentSpaceHandler, InstanceMetricHandler, \
20
+ CustomLatentSpaceHandler, InstanceMetricHandler, MAX_CUSTOM_LATENT_SPACES, \
21
21
  SimulationHandler, _simulation_context, AutoregressiveStepHandler, AutoregressiveStepCallableInterface, \
22
22
  AUTOREGRESSIVE_LATENT_SPACE_AGGREGATIONS, AUTOREGRESSIVE_IMPLICIT_ARG_NAMES, \
23
23
  AutoregressiveMetricHandler, AutoregressiveLossHandler, AutoregressiveVisualizerHandler
24
24
  from code_loader.contract.enums import LeapDataType, DataStateEnum, DataStateType, MetricDirection, DatasetMetadataType, \
25
- TestingSectionEnum
25
+ TestingSectionEnum, LatentSpaceReduction, CustomLatentSpaceComputedAt
26
26
  from code_loader.contract.mapping import NodeConnection, NodeMapping, NodeMappingType
27
27
  from code_loader.contract.responsedataclasses import DatasetTestResultPayload, LeapAnalysisConfiguration
28
28
  from code_loader.contract.visualizer_classes import map_leap_data_type_to_visualizer_class
@@ -67,16 +67,24 @@ def _stringized_annotation_type_name(annotation: Any) -> Optional[str]:
67
67
  return None
68
68
 
69
69
 
70
- def _reject_stringized_sample_preprocess_response(function: Callable[..., Any], arg_name: str, annotation: Any) -> None:
71
- """Fail fast on a stringized SamplePreprocessResponse arg (otherwise it silently
72
- mis-wires as a regular input, surfacing only on the platform)."""
73
- if _stringized_annotation_type_name(annotation) == SamplePreprocessResponse.__name__:
70
+ def _reject_stringized_annotation(function: Callable[..., Any], arg_name: str, annotation: Any,
71
+ expected_cls: type, why: str) -> None:
72
+ """Fail fast on a stringized `expected_cls` arg (otherwise it silently mis-wires,
73
+ surfacing only on the platform)."""
74
+ if _stringized_annotation_type_name(annotation) == expected_cls.__name__:
74
75
  raise Exception(
75
76
  f"Argument '{arg_name}' of function '{function.__name__}' is annotated with a string "
76
- f"('{annotation}') instead of the SamplePreprocessResponse type. This usually means the "
77
+ f"('{annotation}') instead of the {expected_cls.__name__} type. This usually means the "
77
78
  f"file uses 'from __future__ import annotations' (or a quoted hint), which stringizes "
78
- f"annotations and breaks Tensorleap type detection. Remove that import (or the quotes) so "
79
- f"SamplePreprocessResponse is referenced as a real type.")
79
+ f"annotations. {why} Remove that import (or the quotes).")
80
+
81
+
82
+ def _reject_stringized_sample_preprocess_response(function: Callable[..., Any], arg_name: str, annotation: Any) -> None:
83
+ _reject_stringized_annotation(
84
+ function, arg_name, annotation, SamplePreprocessResponse,
85
+ "This breaks Tensorleap type detection, so it must be referenced as a real type.")
86
+
87
+
80
88
 
81
89
 
82
90
 
@@ -546,7 +554,12 @@ class LeapBinder:
546
554
  def set_custom_latent_space(self, function: Union[SectionCallableInterface, InstanceSectionCallableInterface],
547
555
  name: Optional[str] = None,
548
556
  use_ls_for_analysis: bool = False,
549
- instance_aware: bool = False) -> None:
557
+ instance_aware: bool = False,
558
+ computed_at: CustomLatentSpaceComputedAt = CustomLatentSpaceComputedAt.DATASET,
559
+ arg_names: Optional[List[str]] = None,
560
+ reduce: Optional[LatentSpaceReduction] = None,
561
+ n_components: int = 512,
562
+ channel_axis: int = -1) -> None:
550
563
  """
551
564
  Register a custom latent space function.
552
565
 
@@ -579,6 +592,14 @@ class LeapBinder:
579
592
  f"@tensorleap_custom_latent_space must have a unique name "
580
593
  f"(pass name='...' to distinguish them)."
581
594
  )
595
+ if len(self.setup_container.custom_latent_spaces) >= MAX_CUSTOM_LATENT_SPACES:
596
+ raise Exception(
597
+ f"Cannot register custom latent space '{name}': Tensorleap supports at most "
598
+ f"{MAX_CUSTOM_LATENT_SPACES} custom latent spaces, and "
599
+ f"{len(self.setup_container.custom_latent_spaces)} are already registered "
600
+ f"({sorted(self.setup_container.custom_latent_spaces)}). Dataset-computed and "
601
+ f"model-computed latent spaces share this budget."
602
+ )
582
603
  # use_ls_for_analysis is not currently wired for instance-aware latent spaces (OOD /
583
604
  # Domain-Gap analyze the sample-level population, not instance rows) — force it off rather
584
605
  # than silently accepting a flag that has no effect.
@@ -602,8 +623,25 @@ class LeapBinder:
602
623
  f"Out-Of-Distribution and Domain-Gap insights). Set it on '{name}' "
603
624
  f"or '{already_flagged[0]}', not both."
604
625
  )
626
+ if reduce is not None:
627
+ if not isinstance(reduce, LatentSpaceReduction):
628
+ raise Exception(
629
+ f"Custom latent space '{name}': reduce must be a LatentSpaceReduction, got "
630
+ f"{type(reduce).__name__}.")
631
+ if reduce is LatentSpaceReduction.RANDOM_PROJECTION and (
632
+ not isinstance(n_components, int) or isinstance(n_components, bool) or n_components <= 0):
633
+ raise Exception(
634
+ f"Custom latent space '{name}': n_components must be a positive int for "
635
+ f"LatentSpaceReduction.RANDOM_PROJECTION, got {n_components!r}.")
636
+ if reduce is LatentSpaceReduction.MEAN_POOL and (
637
+ not isinstance(channel_axis, int) or isinstance(channel_axis, bool)):
638
+ raise Exception(
639
+ f"Custom latent space '{name}': channel_axis must be an int for "
640
+ f"LatentSpaceReduction.MEAN_POOL, got {channel_axis!r}.")
605
641
  self.setup_container.custom_latent_spaces[name] = CustomLatentSpaceHandler(
606
- function=function, name=name, use_ls_for_analysis=use_ls_for_analysis, instance_aware=instance_aware)
642
+ function=function, name=name, use_ls_for_analysis=use_ls_for_analysis, instance_aware=instance_aware,
643
+ computed_at=computed_at, arg_names=arg_names, reduce=reduce, n_components=n_components,
644
+ channel_axis=channel_axis)
607
645
 
608
646
  def set_autoregressive_step(self, function: AutoregressiveStepCallableInterface,
609
647
  latent_space_aggregation: str = 'last_step') -> None:
@@ -7,6 +7,7 @@ import warnings
7
7
  import logging
8
8
  from collections import defaultdict
9
9
  import functools
10
+ import typing
10
11
  from functools import lru_cache
11
12
  from pathlib import Path
12
13
  from typing import Optional, Union, Callable, List, Dict, Set, Any
@@ -18,7 +19,7 @@ import numpy.typing as npt
18
19
  from code_loader.utils import map_dict_to_metadata_types, is_absent_metadata_value, \
19
20
  validate_autoregressive_state_types, autoregressive_nests_equal, \
20
21
  simulate_engine_float16_downcast_on_call_args, ENGINE_STORAGE_DTYPE, \
21
- TL_DISABLE_ENGINE_FLOAT16_SIMULATION_ENV_VAR
22
+ TL_DISABLE_ENGINE_FLOAT16_SIMULATION_ENV_VAR, sample_preprocess_response_arg_name
22
23
 
23
24
  logger = logging.getLogger(__name__)
24
25
 
@@ -26,15 +27,17 @@ from code_loader.contract.datasetclasses import CustomCallableInterfaceMultiArgs
26
27
  CustomMultipleReturnCallableInterfaceMultiArgs, ConfusionMatrixCallableInterfaceMultiArgs, CustomCallableInterface, \
27
28
  VisualizerCallableInterface, MetadataSectionCallableInterface, PreprocessResponse, SectionCallableInterface, \
28
29
  ConfusionMatrixElement, SamplePreprocessResponse, PredictionTypeHandler, InstanceCallableInterface, ElementInstance, \
29
- InstanceLengthCallableInterface, InstanceSectionCallableInterface, AutoregressiveStepCallableInterface
30
+ InstanceLengthCallableInterface, InstanceSectionCallableInterface, AutoregressiveStepCallableInterface, \
31
+ MAX_CUSTOM_LATENT_SPACE_DIM, CUSTOM_LATENT_SPACE_WARN_DIM
30
32
  from code_loader.contract.enums import MetricDirection, LeapDataType, DatasetMetadataType, DataStateType, \
31
- DataStateEnum
33
+ DataStateEnum, LatentSpaceReduction, CustomLatentSpaceComputedAt
32
34
  from code_loader import leap_binder, LeapLoader
33
35
  from code_loader.contract.mapping import NodeMapping, NodeMappingType, NodeConnection
34
36
  from code_loader.contract.visualizer_classes import LeapImage, LeapImageMask, LeapTextMask, LeapText, LeapGraph, \
35
37
  LeapHorizontalBar, LeapImageWithBBox, LeapImageWithHeatmap, LeapVideo, LeapAudio, LeapValidationError, \
36
38
  map_leap_data_type_to_visualizer_class
37
- from code_loader.inner_leap_binder.leapbinder import mapping_runtime_mode_env_var_mame
39
+ from code_loader.inner_leap_binder.leapbinder import mapping_runtime_mode_env_var_mame, \
40
+ _reject_stringized_sample_preprocess_response
38
41
  from code_loader.mixpanel_tracker import clear_integration_events, AnalyticsEvent, emit_integration_event_once
39
42
 
40
43
  _called_from_inside_tl_decorator = 0
@@ -264,7 +267,8 @@ def _validate_grouped_result(result, group_size, func_name, validate_single):
264
267
  f'{group_size} arrays, got {type(result)}.')
265
268
 
266
269
 
267
- def _add_mapping_connection(user_unique_name, connection_destinations, arg_names, name, node_mapping_type):
270
+ def _add_mapping_connection(user_unique_name, connection_destinations, arg_names, name, node_mapping_type,
271
+ target_list=None):
268
272
  connection_destinations = [connection_destination for connection_destination in connection_destinations
269
273
  if not isinstance(connection_destination, SamplePreprocessResponse)]
270
274
 
@@ -274,7 +278,9 @@ def _add_mapping_connection(user_unique_name, connection_destinations, arg_names
274
278
  for arg_name, destination in zip(arg_names, connection_destinations):
275
279
  node_inputs[arg_name] = destination.node_mapping
276
280
 
277
- leap_binder.mapping_connections.append(NodeConnection(main_node_mapping, node_inputs))
281
+ if target_list is None:
282
+ target_list = leap_binder.mapping_connections
283
+ target_list.append(NodeConnection(main_node_mapping, node_inputs))
278
284
 
279
285
 
280
286
  def _add_mapping_connections(connects_to, arg_names, node_mapping_type, name):
@@ -286,11 +292,7 @@ def _require_sample_preprocess_response_supplied(user_function: Callable, args:
286
292
  """A SamplePreprocessResponse argument is auto-injected by the platform / check_dataset
287
293
  but NOT inside integration_test, where the author calls the function directly. Fail fast
288
294
  with an actionable message instead of a raw 'missing argument' TypeError."""
289
- spr_arg_name = None
290
- for arg_name, arg_type in inspect.getfullargspec(user_function).annotations.items():
291
- if arg_type == SamplePreprocessResponse:
292
- spr_arg_name = arg_name
293
- break
295
+ spr_arg_name = sample_preprocess_response_arg_name(user_function)
294
296
  if spr_arg_name is None:
295
297
  return
296
298
  signature = inspect.signature(user_function)
@@ -1750,7 +1752,175 @@ def tensorleap_metadata(
1750
1752
  return decorating_function
1751
1753
 
1752
1754
 
1753
- def tensorleap_custom_latent_space(name: Optional[str] = None, use_ls_for_analysis: bool = False):
1755
+ def _is_preprocess_response_type(annotation: Any) -> bool:
1756
+ if isinstance(annotation, type):
1757
+ return issubclass(annotation, PreprocessResponse)
1758
+ return any(_is_preprocess_response_type(arg) for arg in get_args(annotation))
1759
+
1760
+
1761
+ def _classify_custom_latent_space_signature(user_function) -> str:
1762
+ """Dataset-computed when a parameter is typed PreprocessResponse (a subclass or an
1763
+ Optional[...] of it included), model-computed otherwise."""
1764
+ params = list(inspect.signature(user_function).parameters.values())
1765
+ try:
1766
+ hints = typing.get_type_hints(user_function)
1767
+ except NameError as e:
1768
+ raise Exception(
1769
+ f"tensorleap_custom_latent_space validation failed: could not resolve the type "
1770
+ f"annotations of '{user_function.__name__}' ({e}). Tensorleap reads them to tell a "
1771
+ f"dataset-computed latent space from a model-computed one, so every annotation, the "
1772
+ f"return type included, must be resolvable when the function is decorated. Import the "
1773
+ f"annotated types at module level (not only under TYPE_CHECKING) or remove the "
1774
+ f"annotation.") from e
1775
+ preprocess_params = [p.name for p in params if _is_preprocess_response_type(hints.get(p.name))]
1776
+ if preprocess_params:
1777
+ positional = [p.name for p in params
1778
+ if p.kind in (inspect.Parameter.POSITIONAL_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD)]
1779
+ if positional[1:2] != preprocess_params[:1] or len(preprocess_params) > 1:
1780
+ raise Exception(
1781
+ f"tensorleap_custom_latent_space validation failed: '{user_function.__name__}' is "
1782
+ f"dataset-computed (it takes a PreprocessResponse), so it is called as "
1783
+ f"{user_function.__name__}(sample_id, preprocess) and its PreprocessResponse must be "
1784
+ f"the second positional parameter, and the only one. Got parameters "
1785
+ f"{[p.name for p in params]} with PreprocessResponse on {preprocess_params}.")
1786
+ return 'dataset'
1787
+
1788
+ if len(params) == 2 and params[1].name not in hints:
1789
+ first, second = params[0].name, params[1].name
1790
+ raise Exception(
1791
+ f"tensorleap_custom_latent_space validation failed: '{user_function.__name__}' has "
1792
+ f"exactly two parameters ('{first}', '{second}') and '{second}' has no type "
1793
+ f"annotation, so Tensorleap cannot tell whether this is a dataset-computed latent "
1794
+ f"space (one sample at a time) or a model-computed one (a batch of model tensors). "
1795
+ f"Please annotate the second parameter '{second}' to disambiguate:\n"
1796
+ f" dataset-computed: def {user_function.__name__}({first}, {second}: PreprocessResponse) -> (d,)\n"
1797
+ f" model-computed: def {user_function.__name__}({first}: np.ndarray, {second}: np.ndarray) -> (batch, d)\n"
1798
+ f"If you are upgrading an existing project, this signature used to be accepted "
1799
+ f"unannotated as dataset-computed; add ': PreprocessResponse' to '{second}' to keep "
1800
+ f"the previous behavior.")
1801
+ if len(params) > 2 and not any(p.name in hints for p in params):
1802
+ names = [p.name for p in params]
1803
+ raise Exception(
1804
+ f"tensorleap_custom_latent_space validation failed: '{user_function.__name__}' has "
1805
+ f"parameters {names} and none of them has a type annotation, so Tensorleap cannot "
1806
+ f"tell whether this is a dataset-computed latent space (one sample at a time) or a "
1807
+ f"model-computed one (a batch of model tensors). Please annotate them:\n"
1808
+ f" dataset-computed: def {user_function.__name__}({names[0]}, {names[1]}: PreprocessResponse, ...) -> (d,)\n"
1809
+ f" model-computed: def {user_function.__name__}({names[0]}: np.ndarray, {names[1]}: np.ndarray, ...) -> (batch, d)")
1810
+ return 'model'
1811
+
1812
+
1813
+ def _model_latent_space_arg_names(user_function) -> List[str]:
1814
+ # inspect.signature follows functools.wraps' __wrapped__, as the classifier does.
1815
+ params = inspect.signature(user_function).parameters.values()
1816
+ arg_names = [p.name for p in params
1817
+ if p.kind in (inspect.Parameter.POSITIONAL_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD)]
1818
+ spr_count = 0
1819
+ for param in params:
1820
+ if param.annotation is inspect.Parameter.empty:
1821
+ continue
1822
+ _reject_stringized_sample_preprocess_response(user_function, param.name, param.annotation)
1823
+ if param.annotation == SamplePreprocessResponse:
1824
+ spr_count += 1
1825
+ if spr_count > 1:
1826
+ raise Exception(
1827
+ f"tensorleap_custom_latent_space validation failed: only one argument of "
1828
+ f"'{user_function.__name__}' can be of type SamplePreprocessResponse.")
1829
+ spr_arg_name = sample_preprocess_response_arg_name(user_function)
1830
+ if spr_arg_name is not None:
1831
+ arg_names.remove(spr_arg_name)
1832
+ if not arg_names:
1833
+ raise Exception(
1834
+ f"tensorleap_custom_latent_space validation failed: '{user_function.__name__}' is "
1835
+ f"model-computed and expects at least one np.ndarray argument, but its signature "
1836
+ f"declares none.")
1837
+ return arg_names
1838
+
1839
+
1840
+ def _custom_latent_space_width(result, ls_name, reduce, n_components, channel_axis,
1841
+ has_batch_axis: bool) -> int:
1842
+ if reduce is LatentSpaceReduction.RANDOM_PROJECTION:
1843
+ return n_components
1844
+ if reduce is LatentSpaceReduction.MEAN_POOL:
1845
+ axis = channel_axis if channel_axis >= 0 else result.ndim + channel_axis
1846
+ min_axis = 1 if has_batch_axis else 0
1847
+ if axis < min_axis or axis >= result.ndim:
1848
+ raise Exception(
1849
+ f"tensorleap_custom_latent_space validation failed: '{ls_name}' uses "
1850
+ f"LatentSpaceReduction.MEAN_POOL with channel_axis={channel_axis}, which does not "
1851
+ f"select a non-batch axis of the returned shape {tuple(result.shape)}."
1852
+ + (" Axis 0 is the batch." if has_batch_axis else ""))
1853
+ return int(result.shape[axis])
1854
+ dims = result.shape[1:] if has_batch_axis else result.shape
1855
+ return int(np.prod(dims))
1856
+
1857
+
1858
+ def _check_custom_latent_space_width(result, ls_name, reduce, n_components, channel_axis,
1859
+ has_batch_axis: bool) -> None:
1860
+ width = _custom_latent_space_width(result, ls_name, reduce, n_components, channel_axis,
1861
+ has_batch_axis)
1862
+ if width > MAX_CUSTOM_LATENT_SPACE_DIM:
1863
+ raise Exception(
1864
+ f"tensorleap_custom_latent_space validation failed: '{ls_name}' produces "
1865
+ f"{width} dimensions per sample, above the {MAX_CUSTOM_LATENT_SPACE_DIM} limit. "
1866
+ f"Pass reduce=LatentSpaceReduction.RANDOM_PROJECTION (with n_components) to "
1867
+ f"project it down, or reduce=LatentSpaceReduction.MEAN_POOL (with channel_axis) "
1868
+ f"to average the non-channel axes, or return a smaller array.")
1869
+ if width > CUSTOM_LATENT_SPACE_WARN_DIM:
1870
+ store_general_warning(
1871
+ key=("tensorleap_custom_latent_space_width", ls_name, width),
1872
+ message=(
1873
+ f"Custom latent space '{ls_name}' produces {width} dimensions per sample. "
1874
+ f"Wide latent spaces are slow to transit and store. Consider "
1875
+ f"reduce=LatentSpaceReduction.MEAN_POOL or "
1876
+ f"reduce=LatentSpaceReduction.RANDOM_PROJECTION."))
1877
+
1878
+
1879
+ _FLOAT16_MAX = float(np.finfo(np.float16).max)
1880
+
1881
+
1882
+ def _check_custom_latent_space_values(result: np.ndarray, ls_name: str, has_batch_axis: bool) -> None:
1883
+ """Reject what no sample could store and warn about values the engine handles per sample."""
1884
+ if isinstance(result, np.ma.MaskedArray):
1885
+ raise Exception(
1886
+ f"tensorleap_custom_latent_space validation failed: '{ls_name}' returned a numpy masked "
1887
+ f"array; the mask would be ignored. Return a plain ndarray, with np.nan for a sample "
1888
+ f"you cannot compute.")
1889
+ if result.dtype.kind not in 'biuf':
1890
+ raise Exception(
1891
+ f"tensorleap_custom_latent_space validation failed: '{ls_name}' returned dtype "
1892
+ f"{result.dtype}. Return a real-valued numeric array (bool, int or float), with np.nan "
1893
+ f"for a sample you cannot compute.")
1894
+ dims = result.shape[1:] if has_batch_axis else result.shape
1895
+ if int(np.prod(dims)) == 0:
1896
+ raise Exception(
1897
+ f"tensorleap_custom_latent_space validation failed: '{ls_name}' returned shape "
1898
+ f"{tuple(result.shape)}, which has no features per sample.")
1899
+ finite = np.isfinite(result)
1900
+ if not finite.all():
1901
+ store_general_warning(
1902
+ key=("tensorleap_custom_latent_space_nonfinite", ls_name),
1903
+ message=(
1904
+ f"Custom latent space '{ls_name}' returned NaN or inf. Those samples are left out of "
1905
+ f"this latent space; if they exceed 15% of the evaluated samples the latent space is "
1906
+ f"dropped."))
1907
+ peak = 0.0
1908
+ if result.size and result.dtype.kind == 'f':
1909
+ peak = float(np.max(np.abs(result), where=finite, initial=0.0))
1910
+ elif result.size and result.dtype.kind in 'iu':
1911
+ peak = float(max(abs(int(result.min())), abs(int(result.max()))))
1912
+ if peak > _FLOAT16_MAX:
1913
+ store_general_warning(
1914
+ key=("tensorleap_custom_latent_space_clipped", ls_name),
1915
+ message=(
1916
+ f"Custom latent space '{ls_name}' returned values beyond +-{_FLOAT16_MAX:.0f}. Latent "
1917
+ f"spaces are stored as float16, so they are clipped to that range; scale or normalize "
1918
+ f"them inside the function to keep their relative size."))
1919
+
1920
+
1921
+ def tensorleap_custom_latent_space(name: Optional[str] = None, use_ls_for_analysis: bool = False,
1922
+ reduce: Optional[LatentSpaceReduction] = None,
1923
+ n_components: int = 512, channel_axis: int = -1):
1754
1924
  assert isinstance(use_ls_for_analysis, bool), \
1755
1925
  ("tensorleap_custom_latent_space validation failed: use_ls_for_analysis must be a bool. "
1756
1926
  f"Got {type(use_ls_for_analysis)}.")
@@ -1758,6 +1928,10 @@ def tensorleap_custom_latent_space(name: Optional[str] = None, use_ls_for_analys
1758
1928
  def decorating_function(user_function: SectionCallableInterface):
1759
1929
  ls_name = name if name is not None else user_function.__name__
1760
1930
 
1931
+ if _classify_custom_latent_space_signature(user_function) == 'model':
1932
+ return _decorate_model_latent_space(user_function, ls_name, use_ls_for_analysis,
1933
+ reduce, n_components, channel_axis)
1934
+
1761
1935
  def _validate_input_args(sample_id: Union[int, str, list], preprocess_response: PreprocessResponse):
1762
1936
  _validate_id_or_group(sample_id, preprocess_response, 'tensorleap_custom_latent_space')
1763
1937
 
@@ -1765,6 +1939,7 @@ def tensorleap_custom_latent_space(name: Optional[str] = None, use_ls_for_analys
1765
1939
  assert isinstance(single_result, np.ndarray), \
1766
1940
  (f'tensorleap_custom_latent_space validation failed: '
1767
1941
  f'The return type should be a numpy array. Got {type(single_result)}.')
1942
+ _check_custom_latent_space_values(single_result, ls_name, has_batch_axis=False)
1768
1943
  if single_result.ndim > 1:
1769
1944
  flat_dim = int(np.prod(single_result.shape))
1770
1945
  store_general_warning(
@@ -1777,6 +1952,8 @@ def tensorleap_custom_latent_space(name: Optional[str] = None, use_ls_for_analys
1777
1952
  f"inside your function."
1778
1953
  ),
1779
1954
  )
1955
+ _check_custom_latent_space_width(single_result, ls_name, reduce, n_components, channel_axis,
1956
+ has_batch_axis=False)
1780
1957
 
1781
1958
  def _validate_result(result, grouped=False, group_size=None):
1782
1959
  if not grouped:
@@ -1814,7 +1991,9 @@ def tensorleap_custom_latent_space(name: Optional[str] = None, use_ls_for_analys
1814
1991
  return result
1815
1992
 
1816
1993
  leap_binder.set_custom_latent_space(inner_without_validate, ls_name,
1817
- use_ls_for_analysis=use_ls_for_analysis)
1994
+ use_ls_for_analysis=use_ls_for_analysis,
1995
+ computed_at=CustomLatentSpaceComputedAt.DATASET, reduce=reduce,
1996
+ n_components=n_components, channel_axis=channel_axis)
1818
1997
 
1819
1998
  def inner(sample_id, preprocess_response):
1820
1999
  if os.environ.get(mapping_runtime_mode_env_var_mame):
@@ -1834,6 +2013,98 @@ def tensorleap_custom_latent_space(name: Optional[str] = None, use_ls_for_analys
1834
2013
  return decorating_function
1835
2014
 
1836
2015
 
2016
+ def _decorate_model_latent_space(user_function, ls_name, use_ls_for_analysis, reduce, n_components,
2017
+ channel_axis):
2018
+ arg_names = _model_latent_space_arg_names(user_function)
2019
+
2020
+ def _validate_input_args(*args, **kwargs):
2021
+ # Every bound argument must be an array: a ground truth is never passed as None, so a
2022
+ # model-computed LS cannot fall back from ground truth to predictions on unlabeled rows.
2023
+ # The engine skips the LS for those rows instead (see leaploader._check_model_latent_spaces).
2024
+ assert len(args) + len(kwargs) > 0, (
2025
+ f"tensorleap_custom_latent_space validation failed: '{user_function.__name__}' is "
2026
+ f"model-computed and expects at least one np.ndarray argument, but received none.")
2027
+ for i, arg in enumerate(args):
2028
+ assert isinstance(arg, (np.ndarray, SamplePreprocessResponse)), (
2029
+ f"tensorleap_custom_latent_space validation failed: Argument #{i} of "
2030
+ f"'{user_function.__name__}' should be a numpy array. Got {type(arg)}.")
2031
+ for arg_name, arg in kwargs.items():
2032
+ assert isinstance(arg, (np.ndarray, SamplePreprocessResponse)), (
2033
+ f"tensorleap_custom_latent_space validation failed: Argument {arg_name} of "
2034
+ f"'{user_function.__name__}' should be a numpy array. Got {type(arg)}.")
2035
+
2036
+ def _validate_result(result):
2037
+ assert isinstance(result, np.ndarray), (
2038
+ f"tensorleap_custom_latent_space validation failed: '{user_function.__name__}' is "
2039
+ f"model-computed and should return a numpy array of shape (batch, d). "
2040
+ f"Got {type(result)}.")
2041
+ assert result.ndim >= 2, (
2042
+ f"tensorleap_custom_latent_space validation failed: '{user_function.__name__}' "
2043
+ f"returned shape {tuple(result.shape)}. A model-computed latent space returns "
2044
+ f"(batch, d), so the result needs a batch axis and at least one feature axis.")
2045
+ _check_custom_latent_space_values(result, ls_name, has_batch_axis=True)
2046
+ if leap_binder.batch_size_to_validate:
2047
+ assert result.shape[0] == leap_binder.batch_size_to_validate, (
2048
+ f"tensorleap_custom_latent_space validation failed: '{user_function.__name__}' "
2049
+ f"returned leading dim {result.shape[0]} instead of the batch size "
2050
+ f"{leap_binder.batch_size_to_validate}.")
2051
+
2052
+ _check_custom_latent_space_width(result, ls_name, reduce, n_components, channel_axis,
2053
+ has_batch_axis=True)
2054
+
2055
+ def inner_without_validate(*args, **kwargs):
2056
+ global _called_from_inside_tl_decorator
2057
+ _called_from_inside_tl_decorator += 1
2058
+
2059
+ try:
2060
+ _require_sample_preprocess_response_supplied(user_function, args, kwargs)
2061
+ result = user_function(*args, **kwargs)
2062
+ finally:
2063
+ _called_from_inside_tl_decorator -= 1
2064
+
2065
+ return result
2066
+
2067
+ inner_without_validate.__signature__ = inspect.signature(user_function)
2068
+
2069
+ leap_binder.set_custom_latent_space(inner_without_validate, ls_name,
2070
+ use_ls_for_analysis=use_ls_for_analysis,
2071
+ computed_at=CustomLatentSpaceComputedAt.MODEL, arg_names=arg_names, reduce=reduce,
2072
+ n_components=n_components, channel_axis=channel_axis)
2073
+
2074
+ def inner(*args, **kwargs):
2075
+ args, kwargs, _was_downcast = _simulate_engine_tensor_dtype(args, kwargs)
2076
+ _validate_input_args(*args, **kwargs)
2077
+ result = inner_without_validate(*args, **kwargs)
2078
+ _validate_result(result)
2079
+ return result
2080
+
2081
+ def mapping_inner(*args, **kwargs):
2082
+ if _mapping_dataset_is_grouped:
2083
+ raise LeapValidationError(
2084
+ f"tensorleap_custom_latent_space validation failed: '{ls_name}' is model-computed, "
2085
+ f"which is not supported for a grouped preprocess response. Use the "
2086
+ f"(sample_id, preprocess: PreprocessResponse) form instead.")
2087
+
2088
+ ordered_connections = [kwargs[arg_name] for arg_name in arg_names if arg_name in kwargs]
2089
+ ordered_connections = list(args) + ordered_connections
2090
+
2091
+ leap_binder.mapping_connections[:] = [
2092
+ connection for connection in leap_binder.mapping_connections
2093
+ if not (connection.node.type is NodeMappingType.CustomLatentSpace
2094
+ and connection.node.name == ls_name)]
2095
+ _add_mapping_connection(ls_name, ordered_connections, arg_names, ls_name,
2096
+ NodeMappingType.CustomLatentSpace)
2097
+ return None
2098
+
2099
+ @functools.wraps(user_function)
2100
+ def final_inner(*args, **kwargs):
2101
+ if os.environ.get(mapping_runtime_mode_env_var_mame):
2102
+ return mapping_inner(*args, **kwargs)
2103
+ return inner(*args, **kwargs)
2104
+
2105
+ return final_inner
2106
+
2107
+
1837
2108
  def tensorleap_instance_custom_latent_space(name: Optional[str] = None, use_ls_for_analysis: bool = False):
1838
2109
  assert isinstance(use_ls_for_analysis, bool), \
1839
2110
  ("tensorleap_instance_custom_latent_space validation failed: use_ls_for_analysis must be a bool. "
@@ -1859,6 +2130,7 @@ def tensorleap_instance_custom_latent_space(name: Optional[str] = None, use_ls_f
1859
2130
  assert isinstance(result, np.ndarray), \
1860
2131
  (f'tensorleap_instance_custom_latent_space validation failed: '
1861
2132
  f'The return type should be a numpy array. Got {type(result)}.')
2133
+ _check_custom_latent_space_values(result, ls_name, has_batch_axis=False)
1862
2134
  if result.ndim > 1:
1863
2135
  flat_dim = int(np.prod(result.shape))
1864
2136
  store_general_warning(
code_loader/leaploader.py CHANGED
@@ -17,7 +17,9 @@ from code_loader.contract.datasetclasses import DatasetSample, DatasetBaseHandle
17
17
  PredictionTypeHandler, MetadataHandler, CustomLayerHandler, MetricHandler, VisualizerHandlerData, MetricHandlerData, \
18
18
  MetricCallableReturnType, CustomLossHandlerData, CustomLossHandler, RawInputsForHeatmap, SamplePreprocessResponse, \
19
19
  ElementInstance, custom_latent_space_attribute, DatasetIntegrationSetup, InstanceMetricHandler, _simulation_context
20
- from code_loader.contract.enums import DataStateEnum, TestingSectionEnum, DataStateType, DatasetMetadataType
20
+ from code_loader.contract.enums import DataStateEnum, TestingSectionEnum, DataStateType, DatasetMetadataType, \
21
+ CustomLatentSpaceComputedAt
22
+ from code_loader.contract.mapping import NodeMappingType
21
23
  from code_loader.contract.exceptions import DatasetScriptException
22
24
  from code_loader.contract.responsedataclasses import DatasetIntegParseResult, DatasetTestResultPayload, \
23
25
  DatasetPreprocess, DatasetSetup, DatasetInputInstance, DatasetOutputInstance, DatasetMetadataInstance, \
@@ -28,7 +30,8 @@ from code_loader.inner_leap_binder import global_leap_binder
28
30
  from code_loader.inner_leap_binder.leapbinder import mapping_runtime_mode_env_var_mame
29
31
  from code_loader.leaploaderbase import LeapLoaderBase
30
32
  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, is_absent_metadata_value
33
+ validate_autoregressive_state_types, autoregressive_nests_equal, is_absent_metadata_value, \
34
+ sample_preprocess_response_arg_name
32
35
 
33
36
 
34
37
  def _serialize_sim_bounds(bounds) -> dict:
@@ -352,6 +355,9 @@ class LeapLoader(LeapLoaderBase):
352
355
  instance_ls_test_payload = self._check_instance_custom_latent_spaces()
353
356
  if instance_ls_test_payload is not None:
354
357
  test_payloads.append(instance_ls_test_payload)
358
+ model_ls_test_payload = self._check_model_latent_spaces()
359
+ if model_ls_test_payload is not None:
360
+ test_payloads.append(model_ls_test_payload)
355
361
  handlers_test_payloads = self._check_handlers()
356
362
  test_payloads.extend(handlers_test_payloads)
357
363
  simulation_test_payloads = self._check_simulations()
@@ -386,8 +392,9 @@ class LeapLoader(LeapLoaderBase):
386
392
  is_valid_for_model=is_valid_for_model, setup=setup_response,
387
393
  model_setup=model_setup, general_error=general_error,
388
394
  print_log=print_log,
389
- engine_file_contract=EngineFileContract(global_leap_binder.mapping_connections,
390
- global_leap_binder.leap_analysis_configuration))
395
+ engine_file_contract=EngineFileContract(
396
+ global_leap_binder.mapping_connections,
397
+ global_leap_binder.leap_analysis_configuration))
391
398
 
392
399
  def _check_integration_test_exists(self) -> DatasetTestResultPayload:
393
400
  test_result = DatasetTestResultPayload('integration_test')
@@ -425,6 +432,42 @@ class LeapLoader(LeapLoaderBase):
425
432
  test_result.is_passed = False
426
433
  return test_result
427
434
 
435
+ def _check_model_latent_spaces(self) -> Optional[DatasetTestResultPayload]:
436
+ model_names = [
437
+ name for name, handler in global_leap_binder.setup_container.custom_latent_spaces.items()
438
+ if handler.computed_at == CustomLatentSpaceComputedAt.MODEL
439
+ ]
440
+ if not model_names:
441
+ return None
442
+
443
+ test_result = DatasetTestResultPayload('model_custom_latent_space')
444
+ grouped_states = [
445
+ state.name for state, preprocess_response in self._preprocess_result().items()
446
+ if preprocess_response.is_grouped
447
+ ]
448
+ if grouped_states:
449
+ test_result.is_passed = False
450
+ test_result.display[TestingSectionEnum.Errors.name] = (
451
+ f"Model-computed custom latent space(s) {model_names} are not supported with a "
452
+ f"grouped preprocess response (grouped: {grouped_states}). Use the "
453
+ f"(sample_id, preprocess: PreprocessResponse) form instead."
454
+ )
455
+ if global_leap_binder.setup_container.unlabeled_data_preprocess is not None:
456
+ gt_bound_names = [
457
+ connection.node.name for connection in global_leap_binder.mapping_connections
458
+ if connection.node.type is NodeMappingType.CustomLatentSpace
459
+ and any(node_input.type == NodeMappingType.GroundTruth
460
+ for node_input in (connection.node_inputs or {}).values())
461
+ ]
462
+ if gt_bound_names:
463
+ test_result.display[TestingSectionEnum.Warnings.name] = (
464
+ f"Model-computed custom latent space(s) {gt_bound_names} read a ground truth, so "
465
+ f"they are skipped for unlabeled samples, which will have no vector in them. A "
466
+ f"latent space cannot fall back from ground truth to predictions; to cover "
467
+ f"unlabeled samples, add one bound only to model predictions."
468
+ )
469
+ return test_result
470
+
428
471
  def _check_instance_custom_latent_spaces(self) -> Optional[DatasetTestResultPayload]:
429
472
  instance_aware_names = [
430
473
  name for name, handler in global_leap_binder.setup_container.custom_latent_spaces.items()
@@ -773,10 +816,7 @@ class LeapLoader(LeapLoaderBase):
773
816
  @staticmethod
774
817
  def _get_preprocess_response_arg_name(
775
818
  func: Callable) -> Optional[str]:
776
- for arg_name, arg_type in inspect.getfullargspec(func).annotations.items():
777
- if arg_type == SamplePreprocessResponse:
778
- return arg_name
779
- return None
819
+ return sample_preprocess_response_arg_name(func)
780
820
 
781
821
  def run_custom_loss(self, custom_loss_name: str, sample_ids: np.array, state: DataStateEnum,
782
822
  input_tensors_by_arg_name: Dict[str, npt.NDArray[np.float32]]):
@@ -1166,6 +1206,14 @@ class LeapLoader(LeapLoaderBase):
1166
1206
  if any(handler.instance_aware for handler in latent_handlers.values()):
1167
1207
  raise Exception(
1168
1208
  "instance-aware custom latent spaces are not supported with grouped preprocess responses")
1209
+ # TODO: support model-computed custom latent spaces on grouped datasets (skip them here,
1210
+ # as the per-sample path does, once the grouped metrics path is verified to compute them).
1211
+ model_ls_names = [name for name, handler in latent_handlers.items()
1212
+ if handler.computed_at == CustomLatentSpaceComputedAt.MODEL]
1213
+ if model_ls_names:
1214
+ raise Exception(
1215
+ f"model-computed custom latent spaces {model_ls_names} are not supported with "
1216
+ f"grouped preprocess responses yet")
1169
1217
  custom_latent_spaces = {
1170
1218
  name: self._to_grouped_list(handler.function(group_ids, preprocess_state))
1171
1219
  for name, handler in latent_handlers.items()
@@ -1390,7 +1438,9 @@ class LeapLoader(LeapLoaderBase):
1390
1438
  sample_id: Union[int, str],
1391
1439
  preprocess: "PreprocessResponse",
1392
1440
  instance_id: Optional[int] = None) -> Optional[Dict[str, npt.NDArray[np.float32]]]:
1393
- handlers = global_leap_binder.setup_container.custom_latent_spaces
1441
+ handlers = {handler_name: handler for handler_name, handler
1442
+ in global_leap_binder.setup_container.custom_latent_spaces.items()
1443
+ if handler.computed_at != CustomLatentSpaceComputedAt.MODEL}
1394
1444
  if not handlers:
1395
1445
  return None
1396
1446
  if preprocess.is_grouped:
@@ -1428,6 +1478,47 @@ class LeapLoader(LeapLoaderBase):
1428
1478
  self.exec_script()
1429
1479
  return tuple(global_leap_binder.setup_container.custom_latent_spaces.keys())
1430
1480
 
1481
+ @lru_cache()
1482
+ def get_dataset_custom_latent_space_names(self) -> Tuple[str, ...]:
1483
+ self.exec_script()
1484
+ return tuple(name for name, handler in global_leap_binder.setup_container.custom_latent_spaces.items()
1485
+ if handler.computed_at != CustomLatentSpaceComputedAt.MODEL)
1486
+
1487
+ @lru_cache()
1488
+ def get_custom_latent_space_specs(self) -> Dict[str, Dict[str, Any]]:
1489
+ self.exec_script()
1490
+ return {
1491
+ name: {
1492
+ 'computed_at': handler.computed_at.value,
1493
+ 'arg_names': list(handler.arg_names or []),
1494
+ 'reduce': handler.reduce.value if handler.reduce is not None else None,
1495
+ 'n_components': handler.n_components,
1496
+ 'channel_axis': handler.channel_axis,
1497
+ }
1498
+ for name, handler in global_leap_binder.setup_container.custom_latent_spaces.items()
1499
+ }
1500
+
1501
+ @lru_cache()
1502
+ def get_model_custom_latent_space_specs(self) -> Dict[str, Dict[str, Any]]:
1503
+ return {name: spec for name, spec in self.get_custom_latent_space_specs().items()
1504
+ if spec['computed_at'] == 'model'}
1505
+
1506
+ def run_model_latent_space(self, ls_name: str, sample_ids: np.array, state: DataStateEnum,
1507
+ input_tensors_by_arg_name: Dict[str, npt.NDArray[np.float32]]
1508
+ ) -> npt.NDArray[np.float32]:
1509
+ self.exec_script()
1510
+ handler = global_leap_binder.setup_container.custom_latent_spaces[ls_name]
1511
+ preprocess_response_arg_name = self._get_preprocess_response_arg_name(handler.function)
1512
+
1513
+ # Preprocess runs only when the function asks for a SamplePreprocessResponse; the metrics
1514
+ # pod that calls this has no other reason to pay for it.
1515
+ if preprocess_response_arg_name is not None:
1516
+ input_tensors_by_arg_name = {
1517
+ **input_tensors_by_arg_name,
1518
+ preprocess_response_arg_name: SamplePreprocessResponse(sample_ids, self._preprocess_result()[state])}
1519
+
1520
+ return handler.function(**input_tensors_by_arg_name)
1521
+
1431
1522
  @lru_cache()
1432
1523
  def get_instance_custom_latent_space_names(self) -> Tuple[str, ...]:
1433
1524
  """Names of registered custom latent spaces that are instance-aware.
@@ -226,6 +226,31 @@ class LeapLoaderBase:
226
226
  def get_custom_latent_space_for_analysis(self) -> Optional[str]:
227
227
  pass
228
228
 
229
+ # These raise rather than `pass` for the same reason as the autoregressive entry points
230
+ # above: an un-overridden `pass` body would report "no model-computed latent spaces" on a
231
+ # loader that simply predates them, and the engine would silently skip computing them.
232
+ @abstractmethod
233
+ def get_dataset_custom_latent_space_names(self) -> Tuple[str, ...]:
234
+ raise NotImplementedError(f'{type(self).__name__} does not implement '
235
+ 'get_dataset_custom_latent_space_names.')
236
+
237
+ @abstractmethod
238
+ def get_custom_latent_space_specs(self) -> Dict[str, Dict[str, Any]]:
239
+ raise NotImplementedError(f'{type(self).__name__} does not implement '
240
+ 'get_custom_latent_space_specs.')
241
+
242
+ @abstractmethod
243
+ def get_model_custom_latent_space_specs(self) -> Dict[str, Dict[str, Any]]:
244
+ raise NotImplementedError(f'{type(self).__name__} does not implement '
245
+ 'get_model_custom_latent_space_specs.')
246
+
247
+ @abstractmethod
248
+ def run_model_latent_space(self, ls_name: str, sample_ids: np.array, state: DataStateEnum,
249
+ input_tensors_by_arg_name: Dict[str, npt.NDArray[np.float32]]
250
+ ) -> npt.NDArray[np.float32]:
251
+ raise NotImplementedError(f'{type(self).__name__} does not implement '
252
+ 'run_model_latent_space.')
253
+
229
254
  @abstractmethod
230
255
  def get_heatmap_visualizer_raw_vis_input_arg_name(self, visualizer_name: str) -> Optional[str]:
231
256
  pass
code_loader/utils.py CHANGED
@@ -1,3 +1,4 @@
1
+ import inspect
1
2
  import io
2
3
  import math
3
4
  import os
@@ -11,7 +12,7 @@ import numpy as np
11
12
  import numpy.typing as npt
12
13
 
13
14
  from code_loader.contract.datasetclasses import SectionCallableInterface, PreprocessResponse, \
14
- InstanceCallableInterface, ElementInstance
15
+ InstanceCallableInterface, ElementInstance, SamplePreprocessResponse
15
16
  from code_loader.contract.enums import DatasetMetadataType
16
17
 
17
18
 
@@ -246,3 +247,11 @@ def autoregressive_nests_equal(a: Any, b: Any) -> bool:
246
247
  math.isnan(a) and math.isnan(b):
247
248
  return True
248
249
  return bool(a == b)
250
+
251
+
252
+ def sample_preprocess_response_arg_name(func: Callable[..., Any]) -> Optional[str]:
253
+ # inspect.signature follows functools.wraps' __wrapped__; getfullargspec does not.
254
+ for param in inspect.signature(func).parameters.values():
255
+ if param.annotation == SamplePreprocessResponse:
256
+ return param.name
257
+ return None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: code-loader
3
- Version: 1.0.207.dev0
3
+ Version: 1.0.208
4
4
  Summary:
5
5
  Home-page: https://github.com/tensorleap/code-loader
6
6
  License: MIT
@@ -1,10 +1,10 @@
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=6Ozy9_C7HCP6YHqM27teBLe503MRvn7jg7h8uXHPuUY,17395
5
- code_loader/contract/enums.py,sha256=__GkPkwAXi2agmDGtEQgbMucPm4-n80maG6n_MmObPA,1691
4
+ code_loader/contract/datasetclasses.py,sha256=yNEPIyZqCO54fKBgmgbFIKEMVBzvpf4n8U2zmPhXv88,18110
5
+ code_loader/contract/enums.py,sha256=R4Ge9-oSO7-GYjZAKMTB8Ws5FNsxhCQAYAJruxViJxk,1886
6
6
  code_loader/contract/exceptions.py,sha256=jWqu5i7t-0IG0jGRsKF4DjJdrsdpJjIYpUkN1F4RiyQ,51
7
- code_loader/contract/mapping.py,sha256=sWJhpng-IkOzQnWQdMT5w2ZZ3X1Z_OOzSwCLXIS7oxE,1446
7
+ code_loader/contract/mapping.py,sha256=i-yVyFuGUITL5lchPNfYlu7bhwk-yuoHPacAeFhcYr8,1490
8
8
  code_loader/contract/responsedataclasses.py,sha256=2SQCccuIlSeUJT0igyvIJRYtmaWSqqlQwtaAA1iEuSI,5044
9
9
  code_loader/contract/sim_config.py,sha256=le8KMALZiP0WU4UcuKnTOSWBW2rNjpnWYfII502NqDM,3493
10
10
  code_loader/contract/visualizer_classes.py,sha256=vzX9YcwxKOm3IpYj8OaqsA1odPlRgj2Cfvglwd88Wbw,18213
@@ -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=mWcjx31fnrtRfV5agveW79lcMGJhwhDfLz7brpexBv0,60408
25
- code_loader/inner_leap_binder/leapbinder_decorators.py,sha256=rvd9wJuWn8_Yf_s0QFoI4q50pA8xNKtrJ4-01FMKiPE,196641
26
- code_loader/leaploader.py,sha256=dwBQmfL9e2X_l8-O53ga5oADi2SxL5exlC4X2Aat_uk,92568
27
- code_loader/leaploaderbase.py,sha256=Aa8wCcxojf8EBn_14W5I1gKI4OMBdpdEcNAZ_6E2eV4,10940
24
+ code_loader/inner_leap_binder/leapbinder.py,sha256=fplNN3TfJHg79YpEPHKK3b6CxrR7W0ugDeHhAZfYty0,62784
25
+ code_loader/inner_leap_binder/leapbinder_decorators.py,sha256=WNaV9M02Mh8OkPiOrZlnmj_GquGKTa1IxIsaLNk6R2E,212474
26
+ code_loader/leaploader.py,sha256=GAGkIWJIt9g_a2Aj4ZakBBcKymbQD7BN-EcuCDlwD70,97599
27
+ code_loader/leaploaderbase.py,sha256=JzgpEfY-kNUWbWUb_cZ1G1zHo6oSci6QhT7hqw3E1Jg,12371
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=Auw39lKpEQ7Ld2q1nj6S18GIDKWcjCxU0TDrur2UEko,11968
32
+ code_loader/utils.py,sha256=Yuv2hPx4G70RV2x0Fc_UCube9BLpEryyq4cuKIcsq7s,12347
33
33
  code_loader/visualizers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
34
  code_loader/visualizers/default_visualizers.py,sha256=grTPin_lCE9aci8i8CqA7DqQwAyXRB7_EamA3na_pls,5438
35
- code_loader-1.0.207.dev0.dist-info/LICENSE,sha256=qIwWjdspQeSMTtnFZBC8MuT-95L02FPvzRUdWFxrwJY,1067
36
- code_loader-1.0.207.dev0.dist-info/METADATA,sha256=3dh9WdOLBNx4tbYLSxohQQarGGzzQEs3IFH49NvmsOE,1095
37
- code_loader-1.0.207.dev0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
38
- code_loader-1.0.207.dev0.dist-info/RECORD,,
35
+ code_loader-1.0.208.dist-info/LICENSE,sha256=qIwWjdspQeSMTtnFZBC8MuT-95L02FPvzRUdWFxrwJY,1067
36
+ code_loader-1.0.208.dist-info/METADATA,sha256=mDaljR7xkrd2QeONwX9U9msymlqphtsV1OkYbezdIMQ,1090
37
+ code_loader-1.0.208.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
38
+ code_loader-1.0.208.dist-info/RECORD,,