code-loader 1.0.197.dev0__py3-none-any.whl → 1.0.197.dev2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- code_loader/contract/datasetclasses.py +67 -10
- code_loader/inner_leap_binder/leapbinder.py +98 -10
- code_loader/inner_leap_binder/leapbinder_decorators.py +226 -64
- code_loader/leaploader.py +302 -9
- code_loader/leaploaderbase.py +4 -0
- code_loader/utils.py +10 -0
- {code_loader-1.0.197.dev0.dist-info → code_loader-1.0.197.dev2.dist-info}/METADATA +1 -1
- {code_loader-1.0.197.dev0.dist-info → code_loader-1.0.197.dev2.dist-info}/RECORD +10 -10
- {code_loader-1.0.197.dev0.dist-info → code_loader-1.0.197.dev2.dist-info}/LICENSE +0 -0
- {code_loader-1.0.197.dev0.dist-info → code_loader-1.0.197.dev2.dist-info}/WHEEL +0 -0
|
@@ -40,6 +40,7 @@ _called_from_inside_tl_integration_test_decorator = False
|
|
|
40
40
|
# to tell a raise in the test body (report as code-flow failure) from a module-level crash
|
|
41
41
|
# before any test ran (report as a plain script crash).
|
|
42
42
|
_integration_test_started = False
|
|
43
|
+
_mapping_dataset_is_grouped = False
|
|
43
44
|
_call_from_tl_platform = os.environ.get('IS_TENSORLEAP_PLATFORM') == 'true'
|
|
44
45
|
|
|
45
46
|
# ---- warnings store (module-level) ----
|
|
@@ -213,6 +214,53 @@ def batch_warning(result, func_name):
|
|
|
213
214
|
)
|
|
214
215
|
|
|
215
216
|
|
|
217
|
+
def _validate_id_or_group(sample_id, preprocess_response, func_name):
|
|
218
|
+
"""Accept either a single sample id (flat dataset) or a group — a list of ids (grouped
|
|
219
|
+
dataset). The argument shape must match the dataset: a group requires a grouped
|
|
220
|
+
PreprocessResponse and a single id requires a flat one. Every id must match the declared
|
|
221
|
+
sample_id_type."""
|
|
222
|
+
is_group = isinstance(sample_id, list)
|
|
223
|
+
if is_group and not preprocess_response.is_grouped:
|
|
224
|
+
raise AssertionError(
|
|
225
|
+
f'{func_name}() validation failed: got a group (list of sample ids) but the '
|
|
226
|
+
f'PreprocessResponse is not grouped. Pass a single sample id for a flat dataset.')
|
|
227
|
+
if not is_group and preprocess_response.is_grouped:
|
|
228
|
+
raise AssertionError(
|
|
229
|
+
f'{func_name}() validation failed: got a single sample id but the PreprocessResponse '
|
|
230
|
+
f'is grouped. Pass a group (list of sample ids) for a grouped dataset.')
|
|
231
|
+
ids = sample_id if is_group else [sample_id]
|
|
232
|
+
for sid in ids:
|
|
233
|
+
assert type(sid) == preprocess_response.sample_id_type, \
|
|
234
|
+
(f'{func_name}() validation failed: '
|
|
235
|
+
f'Argument sample_id should be as the same type as defined in the preprocess response '
|
|
236
|
+
f'{preprocess_response.sample_id_type}. Got {type(sid)}.')
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _validate_grouped_result(result, group_size, func_name, validate_single):
|
|
240
|
+
"""A grouped (group) encoder result must be either a single ndarray with leading dim
|
|
241
|
+
== group_size, or a list of `group_size` per-sample results (each validated by
|
|
242
|
+
validate_single). Metadata validates its grouped result separately (list only).
|
|
243
|
+
An `(B, *)` array is validated per-sample slice (not as the whole batched array) so
|
|
244
|
+
per-sample checks (e.g. channel_dim <= rank) use the sample shape, not the batch shape."""
|
|
245
|
+
if isinstance(result, np.ndarray):
|
|
246
|
+
assert len(result.shape) > 0 and result.shape[0] == group_size, \
|
|
247
|
+
(f'{func_name}() validation failed: expected a grouped output for a group of '
|
|
248
|
+
f'{group_size}: an array with leading dim {group_size}, got shape {result.shape}.')
|
|
249
|
+
for single in result:
|
|
250
|
+
validate_single(single)
|
|
251
|
+
elif isinstance(result, list):
|
|
252
|
+
assert len(result) == group_size, \
|
|
253
|
+
(f'{func_name}() validation failed: expected a grouped output for a group of '
|
|
254
|
+
f'{group_size}: a list of {group_size} arrays, got {len(result)}.')
|
|
255
|
+
for r in result:
|
|
256
|
+
validate_single(r)
|
|
257
|
+
else:
|
|
258
|
+
raise AssertionError(
|
|
259
|
+
f'{func_name}() validation failed: expected a grouped output for a group of '
|
|
260
|
+
f'{group_size}: either an array with leading dim {group_size} or a list of '
|
|
261
|
+
f'{group_size} arrays, got {type(result)}.')
|
|
262
|
+
|
|
263
|
+
|
|
216
264
|
def _add_mapping_connection(user_unique_name, connection_destinations, arg_names, name, node_mapping_type):
|
|
217
265
|
connection_destinations = [connection_destination for connection_destination in connection_destinations
|
|
218
266
|
if not isinstance(connection_destination, SamplePreprocessResponse)]
|
|
@@ -290,11 +338,7 @@ def tensorleap_integration_test():
|
|
|
290
338
|
|
|
291
339
|
def _validate_input_args(*args, **kwargs):
|
|
292
340
|
sample_id, preprocess_response = args
|
|
293
|
-
|
|
294
|
-
f"tensorleap_integration_test validation failed: "
|
|
295
|
-
f"sample_id type ({type(sample_id).__name__}) does not match the expected "
|
|
296
|
-
f"type ({preprocess_response.sample_id_type}) from the PreprocessResponse."
|
|
297
|
-
)
|
|
341
|
+
_validate_id_or_group(sample_id, preprocess_response, 'tensorleap_integration_test')
|
|
298
342
|
|
|
299
343
|
def inner(*args, **kwargs):
|
|
300
344
|
if not _call_from_tl_platform:
|
|
@@ -305,7 +349,7 @@ def tensorleap_integration_test():
|
|
|
305
349
|
expected_names = inspect.getfullargspec(integration_test_function)[0][:2]
|
|
306
350
|
if len(expected_names) < 2:
|
|
307
351
|
expected_names = ['idx', 'preprocess']
|
|
308
|
-
validate_args_structure(*args, types_order=[Union[int, str], PreprocessResponse],
|
|
352
|
+
validate_args_structure(*args, types_order=[Union[int, str, list], PreprocessResponse],
|
|
309
353
|
func_name='integration_test', expected_names=expected_names,
|
|
310
354
|
**kwargs)
|
|
311
355
|
sample_id, preprocess_response = (
|
|
@@ -329,6 +373,8 @@ def tensorleap_integration_test():
|
|
|
329
373
|
_reset_model_loop_state()
|
|
330
374
|
ret = integration_test_function(*args, **kwargs)
|
|
331
375
|
|
|
376
|
+
global _mapping_dataset_is_grouped
|
|
377
|
+
_mapping_dataset_is_grouped = args[1].is_grouped
|
|
332
378
|
try:
|
|
333
379
|
os.environ[mapping_runtime_mode_env_var_mame] = 'True'
|
|
334
380
|
_reset_model_loop_state()
|
|
@@ -349,6 +395,7 @@ def tensorleap_integration_test():
|
|
|
349
395
|
f'Integration test is only allowed to call Tensorleap decorators. '
|
|
350
396
|
f'Ensure any arithmetics, external library use, Python logic is placed within Tensorleap decoders')
|
|
351
397
|
finally:
|
|
398
|
+
_mapping_dataset_is_grouped = False
|
|
352
399
|
if mapping_runtime_mode_env_var_mame in os.environ:
|
|
353
400
|
del os.environ[mapping_runtime_mode_env_var_mame]
|
|
354
401
|
finally:
|
|
@@ -639,10 +686,29 @@ def tensorleap_load_model(prediction_types: Optional[List[PredictionTypeHandler]
|
|
|
639
686
|
|
|
640
687
|
class ModelPlaceholder:
|
|
641
688
|
|
|
689
|
+
@staticmethod
|
|
690
|
+
def _reject_reused_input_source(elem, seen):
|
|
691
|
+
# A model input slot is wired by mutating elem.node_mapping.type, so the same
|
|
692
|
+
# source object at two positions silently overwrites the first slot. Each input
|
|
693
|
+
# encoder mints its own NodeMapping, so a collision means one source fed two
|
|
694
|
+
# slots — e.g. indexing a single grouped input, model([imgs[0], imgs[1]]), where
|
|
695
|
+
# imgs[i] returns the same node (a group is the batch dim of ONE input, not many
|
|
696
|
+
# inputs), or the flat model([img, img]). Reject it instead of mis-wiring.
|
|
697
|
+
if id(elem.node_mapping) in seen:
|
|
698
|
+
raise Exception(
|
|
699
|
+
"The same input source was passed to more than one model input slot. Each "
|
|
700
|
+
"model input must come from a distinct input encoder. Indexing a single "
|
|
701
|
+
"grouped input (e.g. model([imgs[0], imgs[1]])) feeds several samples of ONE "
|
|
702
|
+
"input into separate slots — a group is the batch dimension of one input, "
|
|
703
|
+
"not multiple inputs.")
|
|
704
|
+
seen.add(id(elem.node_mapping))
|
|
705
|
+
|
|
642
706
|
# keras interface
|
|
643
707
|
def __call__(self, arg):
|
|
644
708
|
if isinstance(arg, list):
|
|
709
|
+
seen: set = set()
|
|
645
710
|
for i, elem in enumerate(arg):
|
|
711
|
+
self._reject_reused_input_source(elem, seen)
|
|
646
712
|
elem.node_mapping.type = _safe_get_item(i)
|
|
647
713
|
else:
|
|
648
714
|
arg.node_mapping.type = NodeMappingType.Input0
|
|
@@ -656,7 +722,9 @@ def tensorleap_load_model(prediction_types: Optional[List[PredictionTypeHandler]
|
|
|
656
722
|
"use model.run(None, inputs) to return all outputs.")
|
|
657
723
|
assert isinstance(input_dict, dict), \
|
|
658
724
|
f'Expected input_dict to be a dict, got {type(input_dict)} instead.'
|
|
725
|
+
seen: set = set()
|
|
659
726
|
for i, (input_key, elem) in enumerate(input_dict.items()):
|
|
727
|
+
self._reject_reused_input_source(elem, seen)
|
|
660
728
|
if isinstance(input_key, NodeMappingType):
|
|
661
729
|
elem.node_mapping.type = input_key
|
|
662
730
|
else:
|
|
@@ -1561,13 +1629,10 @@ def tensorleap_metadata(
|
|
|
1561
1629
|
raise Exception(f'Metadata with name {name} already exists. '
|
|
1562
1630
|
f'Please choose another')
|
|
1563
1631
|
|
|
1564
|
-
def _validate_input_args(sample_id: Union[int, str], preprocess_response: PreprocessResponse):
|
|
1565
|
-
|
|
1566
|
-
(f'{user_function.__name__}() validation failed: '
|
|
1567
|
-
f'Argument sample_id should be as the same type as defined in the preprocess response '
|
|
1568
|
-
f'{preprocess_response.sample_id_type}. Got {type(sample_id)}.')
|
|
1632
|
+
def _validate_input_args(sample_id: Union[int, str, list], preprocess_response: PreprocessResponse):
|
|
1633
|
+
_validate_id_or_group(sample_id, preprocess_response, user_function.__name__)
|
|
1569
1634
|
|
|
1570
|
-
def
|
|
1635
|
+
def _validate_single(result):
|
|
1571
1636
|
supported_result_types = (type(None), int, str, bool, float, dict, np.floating,
|
|
1572
1637
|
np.bool_, np.unsignedinteger, np.signedinteger, np.integer)
|
|
1573
1638
|
if isinstance(result, tuple):
|
|
@@ -1585,6 +1650,20 @@ def tensorleap_metadata(
|
|
|
1585
1650
|
(f'{user_function.__name__}() validation failed: '
|
|
1586
1651
|
f'Values in the return dict should be of type {str(supported_result_types)}. Got {type(value)}.')
|
|
1587
1652
|
|
|
1653
|
+
def _validate_result(result, grouped=False, group_size=None):
|
|
1654
|
+
if not grouped:
|
|
1655
|
+
_validate_single(result)
|
|
1656
|
+
return
|
|
1657
|
+
# Grouped metadata: a list of `group_size` per-sample scalars/dicts.
|
|
1658
|
+
assert isinstance(result, list), \
|
|
1659
|
+
(f'{user_function.__name__}() validation failed: expected a grouped output for a group '
|
|
1660
|
+
f'of {group_size}: a list of {group_size} metadata values, got {type(result)}.')
|
|
1661
|
+
assert len(result) == group_size, \
|
|
1662
|
+
(f'{user_function.__name__}() validation failed: expected a grouped output for a group '
|
|
1663
|
+
f'of {group_size}: a list of {group_size} metadata values, got {len(result)}.')
|
|
1664
|
+
for value in result:
|
|
1665
|
+
_validate_single(value)
|
|
1666
|
+
|
|
1588
1667
|
def inner_without_validate(sample_id, preprocess_response):
|
|
1589
1668
|
|
|
1590
1669
|
global _called_from_inside_tl_decorator
|
|
@@ -1604,14 +1683,16 @@ def tensorleap_metadata(
|
|
|
1604
1683
|
set_current('tensorleap_metadata')
|
|
1605
1684
|
if os.environ.get(mapping_runtime_mode_env_var_mame):
|
|
1606
1685
|
return None
|
|
1607
|
-
validate_args_structure(*args, types_order=[Union[int, str], PreprocessResponse],
|
|
1686
|
+
validate_args_structure(*args, types_order=[Union[int, str, list], PreprocessResponse],
|
|
1608
1687
|
func_name=user_function.__name__, expected_names=["idx", "preprocess"], **kwargs)
|
|
1609
1688
|
sample_id, preprocess_response = args if len(args) != 0 else kwargs.values()
|
|
1610
1689
|
_validate_input_args(sample_id, preprocess_response)
|
|
1611
1690
|
|
|
1691
|
+
grouped = isinstance(sample_id, list)
|
|
1692
|
+
group_size = len(sample_id) if grouped else None
|
|
1612
1693
|
result = inner_without_validate(sample_id, preprocess_response)
|
|
1613
1694
|
|
|
1614
|
-
_validate_result(result)
|
|
1695
|
+
_validate_result(result, grouped, group_size)
|
|
1615
1696
|
if not _call_from_tl_platform:
|
|
1616
1697
|
update_env_params_func("tensorleap_metadata", "v")
|
|
1617
1698
|
return result
|
|
@@ -1621,38 +1702,58 @@ def tensorleap_metadata(
|
|
|
1621
1702
|
return decorating_function
|
|
1622
1703
|
|
|
1623
1704
|
|
|
1624
|
-
def tensorleap_custom_latent_space(name: Optional[str] = None):
|
|
1705
|
+
def tensorleap_custom_latent_space(name: Optional[str] = None, use_ls_for_analysis: bool = False):
|
|
1706
|
+
assert isinstance(use_ls_for_analysis, bool), \
|
|
1707
|
+
("tensorleap_custom_latent_space validation failed: use_ls_for_analysis must be a bool. "
|
|
1708
|
+
f"Got {type(use_ls_for_analysis)}.")
|
|
1709
|
+
|
|
1625
1710
|
def decorating_function(user_function: SectionCallableInterface):
|
|
1626
1711
|
ls_name = name if name is not None else user_function.__name__
|
|
1627
|
-
def _validate_input_args(sample_id: Union[int, str], preprocess_response: PreprocessResponse):
|
|
1628
|
-
assert isinstance(sample_id, (int, str)), \
|
|
1629
|
-
(f'tensorleap_custom_latent_space validation failed: '
|
|
1630
|
-
f'Argument sample_id should be either int or str. Got {type(sample_id)}.')
|
|
1631
|
-
assert isinstance(preprocess_response, PreprocessResponse), \
|
|
1632
|
-
(f'tensorleap_custom_latent_space validation failed: '
|
|
1633
|
-
f'Argument preprocess_response should be a PreprocessResponse. Got {type(preprocess_response)}.')
|
|
1634
|
-
assert type(sample_id) == preprocess_response.sample_id_type, \
|
|
1635
|
-
(f'tensorleap_custom_latent_space validation failed: '
|
|
1636
|
-
f'Argument sample_id should be as the same type as defined in the preprocess response '
|
|
1637
|
-
f'{preprocess_response.sample_id_type}. Got {type(sample_id)}.')
|
|
1638
1712
|
|
|
1639
|
-
def
|
|
1640
|
-
|
|
1713
|
+
def _validate_input_args(sample_id: Union[int, str, list], preprocess_response: PreprocessResponse):
|
|
1714
|
+
_validate_id_or_group(sample_id, preprocess_response, 'tensorleap_custom_latent_space')
|
|
1715
|
+
|
|
1716
|
+
def _validate_single(single_result):
|
|
1717
|
+
assert isinstance(single_result, np.ndarray), \
|
|
1641
1718
|
(f'tensorleap_custom_latent_space validation failed: '
|
|
1642
|
-
f'The return type should be a numpy array. Got {type(
|
|
1643
|
-
if
|
|
1644
|
-
flat_dim = int(np.prod(
|
|
1719
|
+
f'The return type should be a numpy array. Got {type(single_result)}.')
|
|
1720
|
+
if single_result.ndim > 1:
|
|
1721
|
+
flat_dim = int(np.prod(single_result.shape))
|
|
1645
1722
|
store_general_warning(
|
|
1646
|
-
key=("tensorleap_custom_latent_space_flatten", ls_name, tuple(
|
|
1723
|
+
key=("tensorleap_custom_latent_space_flatten", ls_name, tuple(single_result.shape)),
|
|
1647
1724
|
message=(
|
|
1648
|
-
f"tensorleap_custom_latent_space '{ls_name}' returned per-sample shape {tuple(
|
|
1649
|
-
f"(ndim={
|
|
1725
|
+
f"tensorleap_custom_latent_space '{ls_name}' returned per-sample shape {tuple(single_result.shape)} "
|
|
1726
|
+
f"(ndim={single_result.ndim}). Tensorleap assumes per-sample shape (d, ...) and will "
|
|
1650
1727
|
f"flatten to ({flat_dim},) before downstream visualization and clustering. "
|
|
1651
1728
|
f"If you want a different aggregation (e.g. global average pooling), do it "
|
|
1652
1729
|
f"inside your function."
|
|
1653
1730
|
),
|
|
1654
1731
|
)
|
|
1655
1732
|
|
|
1733
|
+
def _validate_result(result, grouped=False, group_size=None):
|
|
1734
|
+
if not grouped:
|
|
1735
|
+
_validate_single(result)
|
|
1736
|
+
return
|
|
1737
|
+
# Grouped: (B, *) array or list of B per-sample arrays. Validate each per-sample slice so
|
|
1738
|
+
# the per-sample flatten check/warning uses the sample shape, not the (B, *) batch shape.
|
|
1739
|
+
if isinstance(result, np.ndarray):
|
|
1740
|
+
assert result.ndim >= 1 and result.shape[0] == group_size, \
|
|
1741
|
+
(f'tensorleap_custom_latent_space validation failed: expected a grouped output for a '
|
|
1742
|
+
f'group of {group_size}: an array with leading dim {group_size}, got shape {result.shape}.')
|
|
1743
|
+
for single in result:
|
|
1744
|
+
_validate_single(single)
|
|
1745
|
+
elif isinstance(result, list):
|
|
1746
|
+
assert len(result) == group_size, \
|
|
1747
|
+
(f'tensorleap_custom_latent_space validation failed: expected a grouped output for a '
|
|
1748
|
+
f'group of {group_size}: a list of {group_size} arrays, got {len(result)}.')
|
|
1749
|
+
for single in result:
|
|
1750
|
+
_validate_single(single)
|
|
1751
|
+
else:
|
|
1752
|
+
raise AssertionError(
|
|
1753
|
+
f'tensorleap_custom_latent_space validation failed: expected a grouped output for a '
|
|
1754
|
+
f'group of {group_size}: either an array with leading dim {group_size} or a list of '
|
|
1755
|
+
f'{group_size} arrays, got {type(result)}.')
|
|
1756
|
+
|
|
1656
1757
|
def inner_without_validate(sample_id, preprocess_response):
|
|
1657
1758
|
global _called_from_inside_tl_decorator
|
|
1658
1759
|
_called_from_inside_tl_decorator += 1
|
|
@@ -1664,7 +1765,8 @@ def tensorleap_custom_latent_space(name: Optional[str] = None):
|
|
|
1664
1765
|
|
|
1665
1766
|
return result
|
|
1666
1767
|
|
|
1667
|
-
leap_binder.set_custom_latent_space(inner_without_validate, ls_name
|
|
1768
|
+
leap_binder.set_custom_latent_space(inner_without_validate, ls_name,
|
|
1769
|
+
use_ls_for_analysis=use_ls_for_analysis)
|
|
1668
1770
|
|
|
1669
1771
|
def inner(sample_id, preprocess_response):
|
|
1670
1772
|
if os.environ.get(mapping_runtime_mode_env_var_mame):
|
|
@@ -1672,9 +1774,11 @@ def tensorleap_custom_latent_space(name: Optional[str] = None):
|
|
|
1672
1774
|
|
|
1673
1775
|
_validate_input_args(sample_id, preprocess_response)
|
|
1674
1776
|
|
|
1777
|
+
grouped = isinstance(sample_id, list)
|
|
1778
|
+
group_size = len(sample_id) if grouped else None
|
|
1675
1779
|
result = inner_without_validate(sample_id, preprocess_response)
|
|
1676
1780
|
|
|
1677
|
-
_validate_result(result)
|
|
1781
|
+
_validate_result(result, grouped, group_size)
|
|
1678
1782
|
return result
|
|
1679
1783
|
|
|
1680
1784
|
return inner
|
|
@@ -2643,6 +2747,15 @@ def tensorleap_preprocess():
|
|
|
2643
2747
|
assert len(set(result)) == len(result), \
|
|
2644
2748
|
(f'{user_function.__name__}() validation failed: '
|
|
2645
2749
|
f'The return list should not contain duplicate PreprocessResponse objects.')
|
|
2750
|
+
# All-or-none: a dataset is either all grouped (nested sample_ids) or all flat.
|
|
2751
|
+
if len({response.is_grouped for response in result}) != 1:
|
|
2752
|
+
shapes = ', '.join(
|
|
2753
|
+
f"#{i}={'grouped' if response.is_grouped else 'flat'}"
|
|
2754
|
+
for i, response in enumerate(result))
|
|
2755
|
+
raise AssertionError(
|
|
2756
|
+
f'{user_function.__name__}() validation failed: '
|
|
2757
|
+
f'All PreprocessResponses must be either all grouped (nested sample_ids) '
|
|
2758
|
+
f'or all flat, but got a mix: {shapes}.')
|
|
2646
2759
|
|
|
2647
2760
|
def inner(*args, **kwargs):
|
|
2648
2761
|
if not _call_from_tl_platform:
|
|
@@ -2760,6 +2873,13 @@ def tensorleap_element_instance_preprocess(
|
|
|
2760
2873
|
result = user_function()
|
|
2761
2874
|
found_instance_metadata = False
|
|
2762
2875
|
for preprocess_response in result:
|
|
2876
|
+
if preprocess_response.is_grouped:
|
|
2877
|
+
raise Exception(
|
|
2878
|
+
"tensorleap_element_instance_preprocess validation failed: a grouped "
|
|
2879
|
+
"(nested sample_ids) PreprocessResponse cannot also declare element "
|
|
2880
|
+
"instances -- instance ids are derived per scalar sample id, and the "
|
|
2881
|
+
"engine's grouped/batch fetch path has no per-instance id to mask by. "
|
|
2882
|
+
"Remove the instance encoders or don't group this dataset.")
|
|
2763
2883
|
sample_ids_to_instance_mappings = {}
|
|
2764
2884
|
instance_to_sample_ids_mappings = {}
|
|
2765
2885
|
all_sample_ids = preprocess_response.sample_ids.copy()
|
|
@@ -2980,14 +3100,10 @@ def tensorleap_input_encoder(name: str, channel_dim=_UNSET, model_input_index=No
|
|
|
2980
3100
|
f"channel axis in the batched tensor (batch = axis 0), so 0 is invalid. Use 1 "
|
|
2981
3101
|
f"for channel-first (NCHW) and -1 for channel-last (NHWC).")
|
|
2982
3102
|
|
|
2983
|
-
def _validate_input_args(sample_id: Union[int, str], preprocess_response: PreprocessResponse):
|
|
2984
|
-
|
|
2985
|
-
(f'{user_function.__name__}() validation failed: '
|
|
2986
|
-
f'Argument sample_id should be as the same type as defined in the preprocess response '
|
|
2987
|
-
f'{preprocess_response.sample_id_type}. Got {type(sample_id)}.')
|
|
3103
|
+
def _validate_input_args(sample_id: Union[int, str, list], preprocess_response: PreprocessResponse):
|
|
3104
|
+
_validate_id_or_group(sample_id, preprocess_response, user_function.__name__)
|
|
2988
3105
|
|
|
2989
|
-
def
|
|
2990
|
-
validate_output_structure(result, func_name=user_function.__name__, expected_type_name="np.ndarray")
|
|
3106
|
+
def _validate_single(result):
|
|
2991
3107
|
assert isinstance(result, np.ndarray), \
|
|
2992
3108
|
(f'{user_function.__name__}() validation failed: '
|
|
2993
3109
|
f'Unsupported return type. Should be a numpy array. Got {type(result)}.')
|
|
@@ -2997,6 +3113,13 @@ def tensorleap_input_encoder(name: str, channel_dim=_UNSET, model_input_index=No
|
|
|
2997
3113
|
assert channel_dim - 1 <= len(result.shape), (f'{user_function.__name__}() validation failed: '
|
|
2998
3114
|
f'The channel_dim ({channel_dim}) should be <= to the rank of the resulting input rank ({len(result.shape)}).')
|
|
2999
3115
|
|
|
3116
|
+
def _validate_result(result, grouped=False, group_size=None):
|
|
3117
|
+
if not grouped:
|
|
3118
|
+
validate_output_structure(result, func_name=user_function.__name__, expected_type_name="np.ndarray")
|
|
3119
|
+
_validate_single(result)
|
|
3120
|
+
return
|
|
3121
|
+
_validate_grouped_result(result, group_size, user_function.__name__, _validate_single)
|
|
3122
|
+
|
|
3000
3123
|
def inner_without_validate(sample_id, preprocess_response):
|
|
3001
3124
|
global _called_from_inside_tl_decorator
|
|
3002
3125
|
_called_from_inside_tl_decorator += 1
|
|
@@ -3013,18 +3136,29 @@ def tensorleap_input_encoder(name: str, channel_dim=_UNSET, model_input_index=No
|
|
|
3013
3136
|
def inner(*args, **kwargs):
|
|
3014
3137
|
if not _call_from_tl_platform:
|
|
3015
3138
|
set_current("tensorleap_input_encoder")
|
|
3016
|
-
validate_args_structure(*args, types_order=[Union[int, str], PreprocessResponse],
|
|
3139
|
+
validate_args_structure(*args, types_order=[Union[int, str, list], PreprocessResponse],
|
|
3017
3140
|
func_name=user_function.__name__, expected_names=["idx", "preprocess"], **kwargs)
|
|
3018
3141
|
sample_id, preprocess_response = args if len(args) != 0 else kwargs.values()
|
|
3019
3142
|
_validate_input_args(sample_id, preprocess_response)
|
|
3020
3143
|
|
|
3144
|
+
grouped = isinstance(sample_id, list)
|
|
3145
|
+
group_size = len(sample_id) if grouped else None
|
|
3021
3146
|
result = inner_without_validate(sample_id, preprocess_response)
|
|
3022
3147
|
|
|
3023
|
-
_validate_result(result)
|
|
3148
|
+
_validate_result(result, grouped, group_size)
|
|
3024
3149
|
|
|
3025
3150
|
if _called_from_inside_tl_decorator == 0 and _called_from_inside_tl_integration_test_decorator:
|
|
3026
|
-
|
|
3027
|
-
|
|
3151
|
+
if grouped:
|
|
3152
|
+
# A grouped result is a list of per-sample arrays (never stacked, so a
|
|
3153
|
+
# B=1-only model can be fed one sample at a time). A user may also return a
|
|
3154
|
+
# supported (B, *) array; split it back into per-sample rows first (mirrors
|
|
3155
|
+
# LeapLoader._to_grouped_list) so both forms match the runtime path. Then add
|
|
3156
|
+
# a batch dim to each sample, mirroring the flat path's single-sample expand_dims.
|
|
3157
|
+
rows = result if isinstance(result, list) else [row for row in np.asarray(result)]
|
|
3158
|
+
result = [np.expand_dims(r, axis=0) for r in rows]
|
|
3159
|
+
else:
|
|
3160
|
+
batch_warning(result, user_function.__name__)
|
|
3161
|
+
result = np.expand_dims(result, axis=0)
|
|
3028
3162
|
# Emit integration test event once per test
|
|
3029
3163
|
try:
|
|
3030
3164
|
emit_integration_event_once(AnalyticsEvent.INPUT_ENCODER_INTEGRATION_TEST, {
|
|
@@ -3045,8 +3179,15 @@ def tensorleap_input_encoder(name: str, channel_dim=_UNSET, model_input_index=No
|
|
|
3045
3179
|
inner.node_mapping = NodeMapping(name, node_mapping_type)
|
|
3046
3180
|
|
|
3047
3181
|
def mapping_inner(*args, **kwargs):
|
|
3048
|
-
|
|
3049
|
-
|
|
3182
|
+
if _mapping_dataset_is_grouped:
|
|
3183
|
+
class TempMapping:
|
|
3184
|
+
def __getitem__(self, key):
|
|
3185
|
+
# Indexing a grouped input group (input_list[i]) selects a sample from the
|
|
3186
|
+
# same input source; the model wiring is identical to the un-grouped input.
|
|
3187
|
+
return self
|
|
3188
|
+
else:
|
|
3189
|
+
class TempMapping:
|
|
3190
|
+
pass
|
|
3050
3191
|
|
|
3051
3192
|
ret = TempMapping()
|
|
3052
3193
|
ret.node_mapping = mapping_inner.node_mapping
|
|
@@ -3076,15 +3217,10 @@ def tensorleap_gt_encoder(name: str):
|
|
|
3076
3217
|
raise Exception(f'GT with name {name} already exists. '
|
|
3077
3218
|
f'Please choose another')
|
|
3078
3219
|
|
|
3079
|
-
def _validate_input_args(sample_id: Union[int, str], preprocess_response: PreprocessResponse):
|
|
3080
|
-
|
|
3081
|
-
(f'{user_function.__name__}() validation failed: '
|
|
3082
|
-
f'Argument sample_id should be as the same type as defined in the preprocess response '
|
|
3083
|
-
f'{preprocess_response.sample_id_type}. Got {type(sample_id)}.')
|
|
3220
|
+
def _validate_input_args(sample_id: Union[int, str, list], preprocess_response: PreprocessResponse):
|
|
3221
|
+
_validate_id_or_group(sample_id, preprocess_response, user_function.__name__)
|
|
3084
3222
|
|
|
3085
|
-
def
|
|
3086
|
-
validate_output_structure(result, func_name=user_function.__name__, expected_type_name="np.ndarray",
|
|
3087
|
-
gt_flag=True)
|
|
3223
|
+
def _validate_single(result):
|
|
3088
3224
|
assert isinstance(result, np.ndarray), \
|
|
3089
3225
|
(f'{user_function.__name__}() validation failed: '
|
|
3090
3226
|
f'Unsupported return type. Should be a numpy array. Got {type(result)}.')
|
|
@@ -3092,6 +3228,14 @@ def tensorleap_gt_encoder(name: str):
|
|
|
3092
3228
|
(f'{user_function.__name__}() validation failed: '
|
|
3093
3229
|
f'The return type should be a numpy array of type float32. Got {result.dtype}.')
|
|
3094
3230
|
|
|
3231
|
+
def _validate_result(result, grouped=False, group_size=None):
|
|
3232
|
+
if not grouped:
|
|
3233
|
+
validate_output_structure(result, func_name=user_function.__name__, expected_type_name="np.ndarray",
|
|
3234
|
+
gt_flag=True)
|
|
3235
|
+
_validate_single(result)
|
|
3236
|
+
return
|
|
3237
|
+
_validate_grouped_result(result, group_size, user_function.__name__, _validate_single)
|
|
3238
|
+
|
|
3095
3239
|
def inner_without_validate(sample_id, preprocess_response):
|
|
3096
3240
|
global _called_from_inside_tl_decorator
|
|
3097
3241
|
_called_from_inside_tl_decorator += 1
|
|
@@ -3108,18 +3252,29 @@ def tensorleap_gt_encoder(name: str):
|
|
|
3108
3252
|
def inner(*args, **kwargs):
|
|
3109
3253
|
if not _call_from_tl_platform:
|
|
3110
3254
|
set_current("tensorleap_gt_encoder")
|
|
3111
|
-
validate_args_structure(*args, types_order=[Union[int, str], PreprocessResponse],
|
|
3255
|
+
validate_args_structure(*args, types_order=[Union[int, str, list], PreprocessResponse],
|
|
3112
3256
|
func_name=user_function.__name__, expected_names=["idx", "preprocess"], **kwargs)
|
|
3113
|
-
sample_id, preprocess_response = args
|
|
3257
|
+
sample_id, preprocess_response = args if len(args) != 0 else kwargs.values()
|
|
3114
3258
|
_validate_input_args(sample_id, preprocess_response)
|
|
3115
3259
|
|
|
3260
|
+
grouped = isinstance(sample_id, list)
|
|
3261
|
+
group_size = len(sample_id) if grouped else None
|
|
3116
3262
|
result = inner_without_validate(sample_id, preprocess_response)
|
|
3117
3263
|
|
|
3118
|
-
_validate_result(result)
|
|
3264
|
+
_validate_result(result, grouped, group_size)
|
|
3119
3265
|
|
|
3120
3266
|
if _called_from_inside_tl_decorator == 0 and _called_from_inside_tl_integration_test_decorator:
|
|
3121
|
-
|
|
3122
|
-
|
|
3267
|
+
if grouped:
|
|
3268
|
+
# A grouped result is a list of per-sample arrays (never stacked, so a
|
|
3269
|
+
# B=1-only model can be fed one sample at a time). A user may also return a
|
|
3270
|
+
# supported (B, *) array; split it back into per-sample rows first (mirrors
|
|
3271
|
+
# LeapLoader._to_grouped_list) so both forms match the runtime path. Then add
|
|
3272
|
+
# a batch dim to each sample, mirroring the flat path's single-sample expand_dims.
|
|
3273
|
+
rows = result if isinstance(result, list) else [row for row in np.asarray(result)]
|
|
3274
|
+
result = [np.expand_dims(r, axis=0) for r in rows]
|
|
3275
|
+
else:
|
|
3276
|
+
batch_warning(result, user_function.__name__)
|
|
3277
|
+
result = np.expand_dims(result, axis=0)
|
|
3123
3278
|
_register_chain_artifact(result, 'ground_truth')
|
|
3124
3279
|
# Emit integration test event once per test
|
|
3125
3280
|
try:
|
|
@@ -3135,8 +3290,15 @@ def tensorleap_gt_encoder(name: str):
|
|
|
3135
3290
|
inner.node_mapping = NodeMapping(name, NodeMappingType.GroundTruth)
|
|
3136
3291
|
|
|
3137
3292
|
def mapping_inner(*args, **kwargs):
|
|
3138
|
-
|
|
3139
|
-
|
|
3293
|
+
if _mapping_dataset_is_grouped:
|
|
3294
|
+
class TempMapping:
|
|
3295
|
+
def __getitem__(self, key):
|
|
3296
|
+
# Indexing a grouped GT group (gt_list[i]) selects a sample from the same
|
|
3297
|
+
# ground-truth source; wiring is identical to the un-grouped GT node.
|
|
3298
|
+
return self
|
|
3299
|
+
else:
|
|
3300
|
+
class TempMapping:
|
|
3301
|
+
pass
|
|
3140
3302
|
|
|
3141
3303
|
ret = TempMapping()
|
|
3142
3304
|
ret.node_mapping = mapping_inner.node_mapping
|