code-loader 1.0.214.dev1__tar.gz → 1.0.214.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.214.dev1 → code_loader-1.0.214.dev2}/PKG-INFO +1 -1
  2. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/contract/datasetclasses.py +4 -0
  3. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/inner_leap_binder/leapbinder.py +56 -0
  4. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/inner_leap_binder/leapbinder_decorators.py +48 -0
  5. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/leaploader.py +40 -3
  6. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/leaploaderbase.py +4 -0
  7. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/pyproject.toml +1 -1
  8. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/LICENSE +0 -0
  9. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/README.md +0 -0
  10. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/__init__.py +0 -0
  11. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/contract/__init__.py +0 -0
  12. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/contract/enums.py +0 -0
  13. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/contract/exceptions.py +0 -0
  14. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/contract/mapping.py +0 -0
  15. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/contract/responsedataclasses.py +0 -0
  16. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/contract/sim_config.py +0 -0
  17. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/contract/visualizer_classes.py +0 -0
  18. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/default_losses.py +0 -0
  19. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/default_metrics.py +0 -0
  20. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/experiment_api/__init__.py +0 -0
  21. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/experiment_api/api.py +0 -0
  22. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/experiment_api/cli_config_utils.py +0 -0
  23. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/experiment_api/client.py +0 -0
  24. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/experiment_api/epoch.py +0 -0
  25. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/experiment_api/experiment.py +0 -0
  26. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/experiment_api/experiment_context.py +0 -0
  27. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/experiment_api/types.py +0 -0
  28. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/experiment_api/utils.py +0 -0
  29. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/experiment_api/workingspace_config_utils.py +0 -0
  30. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/inner_leap_binder/__init__.py +0 -0
  31. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/mixpanel_tracker.py +0 -0
  32. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/plot_functions/__init__.py +0 -0
  33. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/plot_functions/plot_functions.py +0 -0
  34. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/plot_functions/visualize.py +0 -0
  35. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/utils.py +0 -0
  36. {code_loader-1.0.214.dev1 → code_loader-1.0.214.dev2}/code_loader/visualizers/__init__.py +0 -0
  37. {code_loader-1.0.214.dev1 → code_loader-1.0.214.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.214.dev1
3
+ Version: 1.0.214.dev2
4
4
  Summary:
5
5
  Home-page: https://github.com/tensorleap/code-loader
6
6
  License: MIT
@@ -155,6 +155,9 @@ class ElementInstance:
155
155
  # masks funnel (utils.to_numpy_return_masks_wrapper) so the engine copies flags rather than
156
156
  # deriving them, exactly as it does for sample-level metadata.
157
157
  instance_metadata_is_none: Optional[Dict[str, bool]] = None
158
+ # Per-instance metric values keyed by the registered name of a tensorleap_custom_instances_metric.
159
+ # Only meaningful on false-positive instances (they have no ground-truth row for the metric to run on).
160
+ instance_metrics: Optional[Dict[str, float]] = None
158
161
 
159
162
  SectionCallableInterface = Callable[[Union[int, str], PreprocessResponse], npt.NDArray[np.float32]]
160
163
  InstanceCallableInterface = Callable[[Union[int, str], PreprocessResponse, int], Optional[ElementInstance]]
@@ -412,6 +415,7 @@ class DatasetIntegrationSetup:
412
415
  instance_masks: List[ElementInstanceMasksHandler] = field(default_factory=list)
413
416
  false_positive_instances: Optional[FalsePositiveInstancesHandler] = None
414
417
  false_positive_empty_gt: Dict[str, Callable] = field(default_factory=dict)
418
+ false_positive_custom_latent_spaces: Dict[str, Callable] = field(default_factory=dict)
415
419
  ground_truths: List[GroundTruthHandler] = field(default_factory=list)
416
420
  metadata: List[MetadataHandler] = field(default_factory=list)
417
421
  prediction_types: List[PredictionTypeHandler] = field(default_factory=list)
@@ -392,6 +392,61 @@ class LeapBinder:
392
392
  f"tensorleap_false_positive_empty_gt for '{name}' returned dtype {empty.dtype}, "
393
393
  f"which cannot be cast to float32.")
394
394
 
395
+ def set_false_positive_custom_latent_space(self, function: Callable, name: str) -> None:
396
+ """
397
+ Set the custom latent space hook for false-positive instance rows. It receives
398
+ (sample_id, preprocess, fp_instance) and returns a 1-D vector for the instance-aware
399
+ custom latent space registered under `name`.
400
+ """
401
+ if name in self.setup_container.false_positive_custom_latent_spaces:
402
+ raise Exception(f"tensorleap_false_positive_custom_latent_space for '{name}' is already defined")
403
+ self.setup_container.false_positive_custom_latent_spaces[name] = function
404
+
405
+ def check_false_positive_custom_latent_spaces(
406
+ self, preprocess_result: Optional[Dict[DataStateEnum, PreprocessResponse]] = None) -> None:
407
+ """Every FP latent-space hook must name an instance-aware custom latent space and, when a
408
+ preprocess result is given, return the same shape as it (no-op without an FP encoder)."""
409
+ if self.setup_container.false_positive_instances is None:
410
+ return
411
+ for name in self.setup_container.false_positive_custom_latent_spaces:
412
+ handler = self.setup_container.custom_latent_spaces.get(name)
413
+ if handler is None or not handler.instance_aware:
414
+ raise Exception(
415
+ f"tensorleap_false_positive_custom_latent_space validation failed: '{name}' is not an "
416
+ f"instance custom latent space (tensorleap_instance_custom_latent_space)")
417
+ if preprocess_result is not None:
418
+ self._check_false_positive_custom_latent_space_shapes(preprocess_result)
419
+
420
+ def _check_false_positive_custom_latent_space_shapes(
421
+ self, preprocess_result: Dict[DataStateEnum, PreprocessResponse]) -> None:
422
+ """Call each FP latent-space hook with a real GT ElementInstance and compare its shape with
423
+ the instance custom latent space's. FP and GT rows of one latent space are usually stored in
424
+ different bulks, so a width mismatch would otherwise be dropped silently at load time.
425
+ Skipped when there is no GT instance to probe with (no mask encoder, or no training sample
426
+ with an instance)."""
427
+ fp_hooks = self.setup_container.false_positive_custom_latent_spaces
428
+ if not fp_hooks or not self.setup_container.instance_masks:
429
+ return
430
+ training = preprocess_result.get(DataStateEnum.training)
431
+ if training is None or not training.sample_ids_to_instance_mappings:
432
+ return
433
+ sample_id = next((sid for sid, instance_ids in training.sample_ids_to_instance_mappings.items()
434
+ if instance_ids), None)
435
+ if sample_id is None:
436
+ return
437
+ gt_instance = self.setup_container.instance_masks[0].function(sample_id, training, 0)
438
+ if gt_instance is None:
439
+ return
440
+ for name, fp_hook in fp_hooks.items():
441
+ instance_ls = cast(InstanceSectionCallableInterface,
442
+ self.setup_container.custom_latent_spaces[name].function)
443
+ gt_shape = np.asarray(instance_ls(sample_id, training, 0)).shape
444
+ fp_shape = np.asarray(fp_hook(sample_id, training, gt_instance)).shape
445
+ if fp_shape != gt_shape:
446
+ raise Exception(
447
+ f"tensorleap_false_positive_custom_latent_space validation failed: '{name}' returns shape "
448
+ f"{fp_shape} but the instance custom latent space returns {gt_shape}")
449
+
395
450
  def add_custom_loss(self, function: CustomCallableInterface, name: str) -> None:
396
451
  """
397
452
  Add a custom loss function to the setup.
@@ -1075,6 +1130,7 @@ class LeapBinder:
1075
1130
  self.check_preprocess(preprocess_result)
1076
1131
  self.check_handlers(preprocess_result)
1077
1132
  self.check_false_positive_empty_gt(preprocess_result)
1133
+ self.check_false_positive_custom_latent_spaces(preprocess_result)
1078
1134
  self.check_simulations()
1079
1135
  self.validate_ignore_latent_spaces()
1080
1136
  print("Successful!")
@@ -3603,6 +3603,54 @@ def tensorleap_false_positive_empty_gt(gt_name: str):
3603
3603
  return decorating_function
3604
3604
 
3605
3605
 
3606
+ def tensorleap_false_positive_custom_latent_space(name: str):
3607
+ """Compute the instance custom latent space `name` (a tensorleap_instance_custom_latent_space)
3608
+ for a false-positive instance. Signature: fn(sample_id, preprocess, fp_instance) -> 1-D np.ndarray."""
3609
+ def decorating_function(user_function: Callable):
3610
+ def _validate_input_args(sample_id, preprocess_response, fp_instance):
3611
+ assert isinstance(sample_id, (str, int)), \
3612
+ (f'tensorleap_false_positive_custom_latent_space validation failed: '
3613
+ f'Argument sample_id should be str or int. Got {type(sample_id)}.')
3614
+ assert isinstance(preprocess_response, PreprocessResponse), \
3615
+ (f'tensorleap_false_positive_custom_latent_space validation failed: '
3616
+ f'Argument preprocess_response should be a PreprocessResponse. Got {type(preprocess_response)}.')
3617
+ assert isinstance(fp_instance, ElementInstance), \
3618
+ (f'tensorleap_false_positive_custom_latent_space validation failed: '
3619
+ f'Argument fp_instance should be an ElementInstance. Got {type(fp_instance)}.')
3620
+
3621
+ def _validate_result(result):
3622
+ assert isinstance(result, np.ndarray), \
3623
+ (f'tensorleap_false_positive_custom_latent_space validation failed: '
3624
+ f'The return type should be a numpy array. Got {type(result)}.')
3625
+ assert result.ndim == 1, \
3626
+ (f'tensorleap_false_positive_custom_latent_space validation failed: '
3627
+ f'The returned array should be 1-D. Got shape {result.shape}.')
3628
+
3629
+ def inner_without_validate(sample_id, preprocess_response, fp_instance):
3630
+ global _called_from_inside_tl_decorator
3631
+ _called_from_inside_tl_decorator += 1
3632
+ try:
3633
+ result = user_function(sample_id, preprocess_response, fp_instance)
3634
+ finally:
3635
+ _called_from_inside_tl_decorator -= 1
3636
+ return result
3637
+
3638
+ leap_binder.set_false_positive_custom_latent_space(inner_without_validate, name)
3639
+
3640
+ def inner(sample_id, preprocess_response, fp_instance):
3641
+ if os.environ.get(mapping_runtime_mode_env_var_mame):
3642
+ return np.zeros(0, dtype=np.float32)
3643
+
3644
+ _validate_input_args(sample_id, preprocess_response, fp_instance)
3645
+ result = inner_without_validate(sample_id, preprocess_response, fp_instance)
3646
+ _validate_result(result)
3647
+ return result
3648
+
3649
+ return inner
3650
+
3651
+ return decorating_function
3652
+
3653
+
3606
3654
  def tensorleap_instances_length_encoder(name: str):
3607
3655
  def decorating_function(user_function: InstanceLengthCallableInterface):
3608
3656
  def _validate_input_args(sample_id: str, preprocess_response: PreprocessResponse):
@@ -653,7 +653,9 @@ class LeapLoader(LeapLoaderBase):
653
653
  return None
654
654
  test_result = DatasetTestResultPayload(handler.name)
655
655
  try:
656
- global_leap_binder.check_false_positive_empty_gt(self._preprocess_result())
656
+ preprocess_result = self._preprocess_result()
657
+ global_leap_binder.check_false_positive_empty_gt(preprocess_result)
658
+ global_leap_binder.check_false_positive_custom_latent_spaces(preprocess_result)
657
659
  except Exception as e:
658
660
  line_number, file_name, stacktrace = get_root_exception_file_and_line_number()
659
661
  error_string = f"{repr(e)} in file {file_name}, line_number: {line_number}\nStacktrace:\n{stacktrace}"
@@ -1825,7 +1827,7 @@ class LeapLoader(LeapLoaderBase):
1825
1827
  row = {name: array[i] for name, array in predictions.items()}
1826
1828
  try:
1827
1829
  instances = handler.function(self._native_sample_id(sample_id), preprocess_response, row)
1828
- self._validate_false_positive_instances(instances)
1830
+ self._validate_false_positive_instances(instances, set(self._instance_metric_handler_by_name()))
1829
1831
  except Exception as e:
1830
1832
  print(f"tensorleap_false_positive_instances_encoder failed for sample {sample_id!r} "
1831
1833
  f"(state {state.name}): {e!r}")
@@ -1835,7 +1837,7 @@ class LeapLoader(LeapLoaderBase):
1835
1837
  return results
1836
1838
 
1837
1839
  @staticmethod
1838
- def _validate_false_positive_instances(instances: Any) -> None:
1840
+ def _validate_false_positive_instances(instances: Any, registered_instance_metrics: Set[str]) -> None:
1839
1841
  prefix = "tensorleap_false_positive_instances_encoder validation failed: "
1840
1842
  if not isinstance(instances, list):
1841
1843
  raise Exception(f"{prefix}The return type should be a list of ElementInstance. "
@@ -1844,6 +1846,21 @@ class LeapLoader(LeapLoaderBase):
1844
1846
  if not isinstance(instance, ElementInstance):
1845
1847
  raise Exception(f"{prefix}Element {j} of the returned list should be an ElementInstance. "
1846
1848
  f"Got {type(instance)}.")
1849
+ if instance.instance_metrics is None:
1850
+ continue
1851
+ if not isinstance(instance.instance_metrics, dict):
1852
+ raise Exception(f"{prefix}instance_metrics of element {j} should be a dict. "
1853
+ f"Got {type(instance.instance_metrics)}.")
1854
+ for key, value in instance.instance_metrics.items():
1855
+ if key not in registered_instance_metrics:
1856
+ raise Exception(f"{prefix}instance_metrics key {key!r} of element {j} is not the name of a "
1857
+ f"registered tensorleap_custom_instances_metric. "
1858
+ f"Registered: {sorted(registered_instance_metrics)}.")
1859
+ try:
1860
+ instance.instance_metrics[key] = float(value)
1861
+ except (TypeError, ValueError):
1862
+ raise Exception(f"{prefix}instance_metrics[{key!r}] of element {j} should be castable to "
1863
+ f"float. Got {type(value)}.")
1847
1864
 
1848
1865
  def get_false_positive_empty_gt(self, state: DataStateEnum,
1849
1866
  sample_id: Union[str, int]) -> Dict[str, npt.NDArray[np.float32]]:
@@ -1859,6 +1876,26 @@ class LeapLoader(LeapLoaderBase):
1859
1876
  empty_gt[gt_name] = value.astype(np.float32, copy=False)
1860
1877
  return empty_gt
1861
1878
 
1879
+ def get_false_positive_custom_latent_spaces(self, state: DataStateEnum, sample_id: Union[str, int],
1880
+ fp_instance: ElementInstance) -> Dict[str, npt.NDArray[np.float32]]:
1881
+ self.exec_script()
1882
+ hooks = global_leap_binder.setup_container.false_positive_custom_latent_spaces
1883
+ if not hooks:
1884
+ return {}
1885
+ preprocess_response = self._preprocess_result()[state]
1886
+ sample_id = self._native_sample_id(sample_id)
1887
+ vectors: Dict[str, npt.NDArray[np.float32]] = {}
1888
+ for name, function in hooks.items():
1889
+ value = function(sample_id, preprocess_response, fp_instance)
1890
+ if not isinstance(value, np.ndarray):
1891
+ raise Exception(f"tensorleap_false_positive_custom_latent_space validation failed: "
1892
+ f"The return type for '{name}' should be a numpy array. Got {type(value)}.")
1893
+ if value.ndim != 1:
1894
+ raise Exception(f"tensorleap_false_positive_custom_latent_space validation failed: "
1895
+ f"The return value for '{name}' should be a 1-D array. Got shape {value.shape}.")
1896
+ vectors[name] = value.astype(np.float32, copy=False)
1897
+ return vectors
1898
+
1862
1899
  def get_instances_data(self, state: DataStateEnum) -> Tuple[Dict[str, List[str]], Dict[str, str]]:
1863
1900
  preprocess_result = self._preprocess_result()
1864
1901
  preprocess_state = preprocess_result.get(state)
@@ -87,6 +87,10 @@ class LeapLoaderBase:
87
87
  sample_id: Union[str, int]) -> Dict[str, npt.NDArray[np.float32]]:
88
88
  raise NotImplementedError("get_false_positive_empty_gt is not implemented by this loader")
89
89
 
90
+ def get_false_positive_custom_latent_spaces(self, state: DataStateEnum, sample_id: Union[str, int],
91
+ fp_instance: ElementInstance) -> Dict[str, npt.NDArray[np.float32]]:
92
+ return {}
93
+
90
94
  def get_metadata_multiple_samples(self, state: DataStateEnum, sample_ids: Union[List[int], List[str]],
91
95
  requested_metadata_names: Optional[List[str]] = None
92
96
  ) -> Tuple[Dict[str, Union[List[str], List[int], List[bool],
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "code-loader"
3
- version = "1.0.214.dev1"
3
+ version = "1.0.214.dev2"
4
4
  description = ""
5
5
  authors = ["dorhar <doron.harnoy@tensorleap.ai>"]
6
6
  license = "MIT"