code-loader 1.0.139.dev5__py3-none-any.whl → 1.0.153.dev3__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.
Potentially problematic release.
This version of code-loader might be problematic. Click here for more details.
- code_loader/contract/datasetclasses.py +12 -4
- code_loader/inner_leap_binder/leapbinder_decorators.py +413 -128
- code_loader/leaploader.py +19 -2
- code_loader/leaploaderbase.py +25 -0
- code_loader/mixpanel_tracker.py +97 -9
- code_loader/plot_functions/plot_functions.py +1 -1
- {code_loader-1.0.139.dev5.dist-info → code_loader-1.0.153.dev3.dist-info}/METADATA +1 -1
- {code_loader-1.0.139.dev5.dist-info → code_loader-1.0.153.dev3.dist-info}/RECORD +10 -10
- {code_loader-1.0.139.dev5.dist-info → code_loader-1.0.153.dev3.dist-info}/WHEEL +1 -1
- {code_loader-1.0.139.dev5.dist-info → code_loader-1.0.153.dev3.dist-info}/LICENSE +0 -0
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
# mypy: ignore-errors
|
|
2
2
|
import os
|
|
3
3
|
import warnings
|
|
4
|
+
import logging
|
|
4
5
|
from collections import defaultdict
|
|
5
6
|
from functools import lru_cache
|
|
6
7
|
from pathlib import Path
|
|
7
|
-
from typing import Optional, Union, Callable, List, Dict,
|
|
8
|
+
from typing import Optional, Union, Callable, List, Dict, Set, Any
|
|
9
|
+
from typing import Optional, Union, Callable, List, Dict, get_args, get_origin, DefaultDict
|
|
8
10
|
|
|
9
11
|
import numpy as np
|
|
10
12
|
import numpy.typing as npt
|
|
11
13
|
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
12
16
|
from code_loader.contract.datasetclasses import CustomCallableInterfaceMultiArgs, \
|
|
13
17
|
CustomMultipleReturnCallableInterfaceMultiArgs, ConfusionMatrixCallableInterfaceMultiArgs, CustomCallableInterface, \
|
|
14
18
|
VisualizerCallableInterface, MetadataSectionCallableInterface, PreprocessResponse, SectionCallableInterface, \
|
|
@@ -20,15 +24,70 @@ from code_loader.contract.mapping import NodeMapping, NodeMappingType, NodeConne
|
|
|
20
24
|
from code_loader.contract.visualizer_classes import LeapImage, LeapImageMask, LeapTextMask, LeapText, LeapGraph, \
|
|
21
25
|
LeapHorizontalBar, LeapImageWithBBox, LeapImageWithHeatmap
|
|
22
26
|
from code_loader.inner_leap_binder.leapbinder import mapping_runtime_mode_env_var_mame
|
|
27
|
+
from code_loader.mixpanel_tracker import clear_integration_events, AnalyticsEvent, emit_integration_event_once
|
|
23
28
|
|
|
24
29
|
import inspect
|
|
25
30
|
import functools
|
|
31
|
+
from pathlib import Path
|
|
26
32
|
|
|
27
33
|
_called_from_inside_tl_decorator = 0
|
|
28
34
|
_called_from_inside_tl_integration_test_decorator = False
|
|
29
|
-
|
|
35
|
+
_call_from_tl_platform = os.environ.get('IS_TENSORLEAP_PLATFORM') == 'true'
|
|
36
|
+
|
|
37
|
+
# ---- warnings store (module-level) ----
|
|
38
|
+
_UNSET = object()
|
|
39
|
+
_STORED_WARNINGS: List[Dict[str, Any]] = []
|
|
40
|
+
_STORED_WARNING_KEYS: Set[tuple] = set()
|
|
41
|
+
# param_name -> set(user_func_name)
|
|
42
|
+
_PARAM_DEFAULT_FUNCS: DefaultDict[str, Set[str]] = defaultdict(set)
|
|
43
|
+
# param_name -> default_value used (repr-able)
|
|
44
|
+
_PARAM_DEFAULT_VALUE: Dict[str, Any] = {}
|
|
45
|
+
_PARAM_DEFAULT_DOCS: Dict[str, str] = {}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def get_entry_script_path() -> str:
|
|
49
|
+
import sys
|
|
50
|
+
argv0 = sys.argv[0] if sys.argv else ""
|
|
51
|
+
if argv0:
|
|
52
|
+
return str(Path(argv0).resolve())
|
|
53
|
+
import __main__
|
|
54
|
+
main_file = getattr(__main__, "__file__", "") or ""
|
|
55
|
+
return str(Path(main_file).resolve()) if main_file else ""
|
|
56
|
+
|
|
57
|
+
def started_from(filename: str) -> bool:
|
|
58
|
+
entry = get_entry_script_path()
|
|
59
|
+
return bool(entry) and Path(entry).name == filename
|
|
30
60
|
|
|
31
61
|
|
|
62
|
+
def store_warning_by_param(
|
|
63
|
+
*,
|
|
64
|
+
param_name: str,
|
|
65
|
+
user_func_name: str,
|
|
66
|
+
default_value: Any,
|
|
67
|
+
link_to_docs: str = None,
|
|
68
|
+
) -> None:
|
|
69
|
+
_PARAM_DEFAULT_FUNCS[param_name].add(user_func_name)
|
|
70
|
+
|
|
71
|
+
if param_name not in _PARAM_DEFAULT_VALUE:
|
|
72
|
+
_PARAM_DEFAULT_VALUE[param_name] = default_value
|
|
73
|
+
|
|
74
|
+
if link_to_docs and param_name not in _PARAM_DEFAULT_DOCS:
|
|
75
|
+
_PARAM_DEFAULT_DOCS[param_name] = link_to_docs
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _get_param_default_warnings() -> Dict[str, Dict[str, Any]]:
|
|
79
|
+
out: Dict[str, Dict[str, Any]] = {}
|
|
80
|
+
for p, funcs in _PARAM_DEFAULT_FUNCS.items():
|
|
81
|
+
out[p] = {
|
|
82
|
+
"default_value": _PARAM_DEFAULT_VALUE.get(p, None),
|
|
83
|
+
"funcs": set(funcs),
|
|
84
|
+
"link_to_docs": _PARAM_DEFAULT_DOCS.get(p),
|
|
85
|
+
}
|
|
86
|
+
return out
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _get_stored_warnings() -> List[Dict[str, Any]]:
|
|
90
|
+
return list(_STORED_WARNINGS)
|
|
32
91
|
|
|
33
92
|
|
|
34
93
|
def validate_args_structure(*args, types_order, func_name, expected_names, **kwargs):
|
|
@@ -89,7 +148,7 @@ def validate_args_structure(*args, types_order, func_name, expected_names, **kwa
|
|
|
89
148
|
)
|
|
90
149
|
|
|
91
150
|
|
|
92
|
-
def validate_output_structure(result, func_name: str, expected_type_name="np.ndarray",gt_flag=False):
|
|
151
|
+
def validate_output_structure(result, func_name: str, expected_type_name="np.ndarray", gt_flag=False):
|
|
93
152
|
if result is None or (isinstance(result, float) and np.isnan(result)):
|
|
94
153
|
if gt_flag:
|
|
95
154
|
raise AssertionError(
|
|
@@ -127,8 +186,9 @@ def validate_output_structure(result, func_name: str, expected_type_name="np.nda
|
|
|
127
186
|
f"{expected_type_name} (e.g., by concatenation or stacking)."
|
|
128
187
|
)
|
|
129
188
|
|
|
189
|
+
|
|
130
190
|
def batch_warning(result, func_name):
|
|
131
|
-
if result.shape[0] == 1:
|
|
191
|
+
if len(result.shape) > 0 and result.shape[0] == 1:
|
|
132
192
|
warnings.warn(
|
|
133
193
|
f"{func_name} warning: Tensorleap will add a batch dimension at axis 0 to the output of {func_name}, "
|
|
134
194
|
f"although the detected size of axis 0 is already 1. "
|
|
@@ -136,6 +196,8 @@ def batch_warning(result, func_name):
|
|
|
136
196
|
f"Please ensure that the output of '{func_name}' is not already batched "
|
|
137
197
|
f"to avoid computation errors."
|
|
138
198
|
)
|
|
199
|
+
|
|
200
|
+
|
|
139
201
|
def _add_mapping_connection(user_unique_name, connection_destinations, arg_names, name, node_mapping_type):
|
|
140
202
|
connection_destinations = [connection_destination for connection_destination in connection_destinations
|
|
141
203
|
if not isinstance(connection_destination, SamplePreprocessResponse)]
|
|
@@ -159,7 +221,7 @@ def tensorleap_integration_test():
|
|
|
159
221
|
leap_binder.integration_test_func = integration_test_function
|
|
160
222
|
|
|
161
223
|
def _validate_input_args(*args, **kwargs):
|
|
162
|
-
sample_id,preprocess_response=args
|
|
224
|
+
sample_id, preprocess_response = args
|
|
163
225
|
assert type(sample_id) == preprocess_response.sample_id_type, (
|
|
164
226
|
f"tensorleap_integration_test validation failed: "
|
|
165
227
|
f"sample_id type ({type(sample_id).__name__}) does not match the expected "
|
|
@@ -167,15 +229,23 @@ def tensorleap_integration_test():
|
|
|
167
229
|
)
|
|
168
230
|
|
|
169
231
|
def inner(*args, **kwargs):
|
|
232
|
+
if not _call_from_tl_platform:
|
|
233
|
+
set_current('tensorleap_integration_test')
|
|
170
234
|
validate_args_structure(*args, types_order=[Union[int, str], PreprocessResponse],
|
|
171
|
-
func_name='integration_test',expected_names=["idx", "preprocess"]
|
|
235
|
+
func_name='integration_test', expected_names=["idx", "preprocess"], **kwargs)
|
|
172
236
|
_validate_input_args(*args, **kwargs)
|
|
173
237
|
|
|
174
238
|
global _called_from_inside_tl_integration_test_decorator
|
|
239
|
+
# Clear integration test events for new test
|
|
240
|
+
try:
|
|
241
|
+
clear_integration_events()
|
|
242
|
+
except Exception as e:
|
|
243
|
+
logger.debug(f"Failed to clear integration events: {e}")
|
|
175
244
|
try:
|
|
176
245
|
_called_from_inside_tl_integration_test_decorator = True
|
|
177
|
-
if not
|
|
178
|
-
|
|
246
|
+
if not _call_from_tl_platform:
|
|
247
|
+
update_env_params_func("tensorleap_integration_test",
|
|
248
|
+
"v") # put here because otherwise it will become v only if it finishes all the script
|
|
179
249
|
ret = integration_test_function(*args, **kwargs)
|
|
180
250
|
|
|
181
251
|
try:
|
|
@@ -187,12 +257,15 @@ def tensorleap_integration_test():
|
|
|
187
257
|
file_name = Path(first_tb.filename).name
|
|
188
258
|
line_number = first_tb.lineno
|
|
189
259
|
if isinstance(e, TypeError) and 'is not subscriptable' in str(e):
|
|
190
|
-
|
|
191
|
-
|
|
260
|
+
update_env_params_func("code_mapping", "x")
|
|
261
|
+
raise (f'Invalid integration code. File {file_name}, line {line_number}: '
|
|
262
|
+
f"indexing is supported only on the model's predictions inside the integration test. Please remove this indexing operation usage from the integration test code.")
|
|
192
263
|
else:
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
264
|
+
update_env_params_func("code_mapping", "x")
|
|
265
|
+
|
|
266
|
+
raise (f'Invalid integration code. File {file_name}, line {line_number}: '
|
|
267
|
+
f'Integration test is only allowed to call Tensorleap decorators. '
|
|
268
|
+
f'Ensure any arithmetics, external library use, Python logic is placed within Tensorleap decoders')
|
|
196
269
|
finally:
|
|
197
270
|
if mapping_runtime_mode_env_var_mame in os.environ:
|
|
198
271
|
del os.environ[mapping_runtime_mode_env_var_mame]
|
|
@@ -200,31 +273,55 @@ def tensorleap_integration_test():
|
|
|
200
273
|
_called_from_inside_tl_integration_test_decorator = False
|
|
201
274
|
|
|
202
275
|
leap_binder.check()
|
|
203
|
-
return inner
|
|
204
276
|
|
|
277
|
+
return inner
|
|
205
278
|
|
|
206
279
|
return decorating_function
|
|
207
280
|
|
|
281
|
+
|
|
208
282
|
def _safe_get_item(key):
|
|
209
283
|
try:
|
|
210
284
|
return NodeMappingType[f'Input{str(key)}']
|
|
211
285
|
except ValueError:
|
|
212
286
|
raise Exception(f'Tensorleap currently supports models with no more then 10 inputs')
|
|
213
287
|
|
|
214
|
-
|
|
215
|
-
|
|
288
|
+
|
|
289
|
+
def tensorleap_load_model(prediction_types: Optional[List[PredictionTypeHandler]] = _UNSET):
|
|
290
|
+
prediction_types_was_provided = prediction_types is not _UNSET
|
|
291
|
+
|
|
292
|
+
if not prediction_types_was_provided:
|
|
293
|
+
prediction_types = []
|
|
294
|
+
if not _call_from_tl_platform:
|
|
295
|
+
store_warning_by_param(
|
|
296
|
+
param_name="prediction_types",
|
|
297
|
+
user_func_name="tensorleap_load_model",
|
|
298
|
+
default_value=prediction_types,
|
|
299
|
+
link_to_docs="https://docs.tensorleap.ai/tensorleap-integration/integration-test#tensorleap_load_model"
|
|
300
|
+
)
|
|
301
|
+
assert isinstance(prediction_types, list), (
|
|
216
302
|
f"tensorleap_load_model validation failed: "
|
|
217
|
-
|
|
303
|
+
f" prediction_types is an optional argument of type List[PredictionTypeHandler]] but got {type(prediction_types).__name__}."
|
|
218
304
|
)
|
|
219
305
|
for i, prediction_type in enumerate(prediction_types):
|
|
220
|
-
assert isinstance(prediction_type, PredictionTypeHandler),(f"tensorleap_load_model validation failed: "
|
|
221
|
-
|
|
306
|
+
assert isinstance(prediction_type, PredictionTypeHandler), (f"tensorleap_load_model validation failed: "
|
|
307
|
+
f" prediction_types at position {i} must be of type PredictionTypeHandler but got {type(prediction_types[i]).__name__}.")
|
|
308
|
+
prediction_type_channel_dim_was_provided = prediction_type.channel_dim != "tl_default_value"
|
|
309
|
+
if not prediction_type_channel_dim_was_provided:
|
|
310
|
+
prediction_types[i].channel_dim = -1
|
|
311
|
+
if not _call_from_tl_platform:
|
|
312
|
+
store_warning_by_param(
|
|
313
|
+
param_name=f"prediction_types[{i}].channel_dim",
|
|
314
|
+
user_func_name="tensorleap_load_model",
|
|
315
|
+
default_value=prediction_types[i].channel_dim,
|
|
316
|
+
link_to_docs="https://docs.tensorleap.ai/tensorleap-integration/integration-test#tensorleap_load_model"
|
|
317
|
+
)
|
|
222
318
|
leap_binder.add_prediction(prediction_type.name, prediction_type.labels, prediction_type.channel_dim, i)
|
|
223
319
|
|
|
224
320
|
def _validate_result(result) -> None:
|
|
225
|
-
valid_types=["onnxruntime","keras"]
|
|
226
|
-
err_message=f"tensorleap_load_model validation failed:\nSupported models are Keras and onnxruntime only and non of them was returned."
|
|
227
|
-
validate_output_structure(result, func_name="tensorleap_load_model",
|
|
321
|
+
valid_types = ["onnxruntime", "keras"]
|
|
322
|
+
err_message = f"tensorleap_load_model validation failed:\nSupported models are Keras and onnxruntime only and non of them was returned."
|
|
323
|
+
validate_output_structure(result, func_name="tensorleap_load_model",
|
|
324
|
+
expected_type_name=[" | ".join(t for t in valid_types)][0])
|
|
228
325
|
try:
|
|
229
326
|
import keras
|
|
230
327
|
except ImportError:
|
|
@@ -248,28 +345,41 @@ def tensorleap_load_model(prediction_types: Optional[List[PredictionTypeHandler]
|
|
|
248
345
|
is_onnx_model = bool(onnxruntime and isinstance(result, onnxruntime.InferenceSession))
|
|
249
346
|
|
|
250
347
|
if not any([is_keras_model, is_onnx_model]):
|
|
251
|
-
raise AssertionError(
|
|
252
|
-
|
|
253
|
-
|
|
348
|
+
raise AssertionError(err_message)
|
|
254
349
|
|
|
255
|
-
def decorating_function(load_model_func):
|
|
350
|
+
def decorating_function(load_model_func, prediction_types=prediction_types):
|
|
256
351
|
class TempMapping:
|
|
257
352
|
pass
|
|
258
353
|
|
|
259
354
|
@lru_cache()
|
|
260
355
|
def inner(*args, **kwargs):
|
|
356
|
+
if not _call_from_tl_platform:
|
|
357
|
+
set_current('tensorleap_load_model')
|
|
261
358
|
validate_args_structure(*args, types_order=[],
|
|
262
|
-
func_name='tensorleap_load_model',expected_names=[]
|
|
359
|
+
func_name='tensorleap_load_model', expected_names=[], **kwargs)
|
|
360
|
+
|
|
263
361
|
class ModelPlaceholder:
|
|
264
|
-
def __init__(self):
|
|
265
|
-
self.model = load_model_func()
|
|
362
|
+
def __init__(self, prediction_types):
|
|
363
|
+
self.model = load_model_func() # TODO- check why this fails on onnx model
|
|
364
|
+
self.prediction_types = prediction_types
|
|
266
365
|
_validate_result(self.model)
|
|
267
366
|
|
|
268
367
|
# keras interface
|
|
269
368
|
def __call__(self, arg):
|
|
270
369
|
ret = self.model(arg)
|
|
370
|
+
self.validate_declared_prediction_types(ret)
|
|
371
|
+
if isinstance(ret, list):
|
|
372
|
+
return [r.numpy() for r in ret]
|
|
271
373
|
return ret.numpy()
|
|
272
374
|
|
|
375
|
+
def validate_declared_prediction_types(self, ret):
|
|
376
|
+
if not (len(self.prediction_types) == len(ret) if isinstance(ret, list) else 1) and len(
|
|
377
|
+
self.prediction_types) != 0:
|
|
378
|
+
if not _call_from_tl_platform:
|
|
379
|
+
update_env_params_func("tensorleap_load_model", "x")
|
|
380
|
+
raise Exception(
|
|
381
|
+
f"tensorleap_load_model validation failed: number of declared prediction types({len(prediction_types)}) != number of model outputs({len(ret) if isinstance(ret, list) else 1})")
|
|
382
|
+
|
|
273
383
|
def _convert_onnx_inputs_to_correct_type(
|
|
274
384
|
self, float_arrays_inputs: Dict[str, np.ndarray]
|
|
275
385
|
) -> Dict[str, np.ndarray]:
|
|
@@ -323,13 +433,16 @@ def tensorleap_load_model(prediction_types: Optional[List[PredictionTypeHandler]
|
|
|
323
433
|
# onnx runtime interface
|
|
324
434
|
def run(self, output_names, input_dict):
|
|
325
435
|
corrected_type_inputs = self._convert_onnx_inputs_to_correct_type(input_dict)
|
|
326
|
-
|
|
436
|
+
ret = self.model.run(output_names, corrected_type_inputs)
|
|
437
|
+
self.validate_declared_prediction_types(ret)
|
|
438
|
+
return ret
|
|
327
439
|
|
|
328
440
|
def get_inputs(self):
|
|
329
441
|
return self.model.get_inputs()
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
442
|
+
|
|
443
|
+
model_placeholder = ModelPlaceholder(prediction_types)
|
|
444
|
+
if not _call_from_tl_platform:
|
|
445
|
+
update_env_params_func("tensorleap_load_model", "v")
|
|
333
446
|
return model_placeholder
|
|
334
447
|
|
|
335
448
|
def mapping_inner():
|
|
@@ -377,7 +490,7 @@ def tensorleap_load_model(prediction_types: Optional[List[PredictionTypeHandler]
|
|
|
377
490
|
def get_inputs(self):
|
|
378
491
|
class FollowIndex:
|
|
379
492
|
def __init__(self, index):
|
|
380
|
-
self.name =
|
|
493
|
+
self.name = _safe_get_item(index)
|
|
381
494
|
|
|
382
495
|
class FollowInputIndex:
|
|
383
496
|
def __init__(self):
|
|
@@ -398,19 +511,35 @@ def tensorleap_load_model(prediction_types: Optional[List[PredictionTypeHandler]
|
|
|
398
511
|
return mapping_inner()
|
|
399
512
|
else:
|
|
400
513
|
return inner(*args, **kwargs)
|
|
514
|
+
|
|
401
515
|
return final_inner
|
|
402
516
|
|
|
403
517
|
return decorating_function
|
|
404
518
|
|
|
405
519
|
|
|
406
520
|
def tensorleap_custom_metric(name: str,
|
|
407
|
-
direction: Union[MetricDirection, Dict[str, MetricDirection]] =
|
|
521
|
+
direction: Union[MetricDirection, Dict[str, MetricDirection]] = _UNSET,
|
|
408
522
|
compute_insights: Optional[Union[bool, Dict[str, bool]]] = None,
|
|
409
523
|
connects_to=None):
|
|
410
524
|
name_to_unique_name = defaultdict(set)
|
|
525
|
+
|
|
411
526
|
def decorating_function(
|
|
412
527
|
user_function: Union[CustomCallableInterfaceMultiArgs, CustomMultipleReturnCallableInterfaceMultiArgs,
|
|
413
528
|
ConfusionMatrixCallableInterfaceMultiArgs]):
|
|
529
|
+
nonlocal direction
|
|
530
|
+
|
|
531
|
+
direction_was_provided = direction is not _UNSET
|
|
532
|
+
|
|
533
|
+
if not direction_was_provided:
|
|
534
|
+
direction = MetricDirection.Downward
|
|
535
|
+
if not _call_from_tl_platform:
|
|
536
|
+
store_warning_by_param(
|
|
537
|
+
param_name="direction",
|
|
538
|
+
user_func_name=user_function.__name__,
|
|
539
|
+
default_value=direction,
|
|
540
|
+
link_to_docs="https://docs.tensorleap.ai/tensorleap-integration/writing-integration-code/custom-metrics"
|
|
541
|
+
|
|
542
|
+
)
|
|
414
543
|
|
|
415
544
|
def _validate_decorators_signature():
|
|
416
545
|
err_message = f"{user_function.__name__} validation failed.\n"
|
|
@@ -480,7 +609,6 @@ def tensorleap_custom_metric(name: str,
|
|
|
480
609
|
f"but found element types: {invalid_elems}."
|
|
481
610
|
)
|
|
482
611
|
|
|
483
|
-
|
|
484
612
|
_validate_decorators_signature()
|
|
485
613
|
|
|
486
614
|
for metric_handler in leap_binder.setup_container.metrics:
|
|
@@ -489,7 +617,7 @@ def tensorleap_custom_metric(name: str,
|
|
|
489
617
|
f'Please choose another')
|
|
490
618
|
|
|
491
619
|
def _validate_input_args(*args, **kwargs) -> None:
|
|
492
|
-
assert len(args) > 0, (
|
|
620
|
+
assert len(args) + len(kwargs) > 0, (
|
|
493
621
|
f"{user_function.__name__}() validation failed: "
|
|
494
622
|
f"Expected at least one positional|key-word argument of type np.ndarray, "
|
|
495
623
|
f"but received none. "
|
|
@@ -522,7 +650,7 @@ def tensorleap_custom_metric(name: str,
|
|
|
522
650
|
f'{user_function.__name__}() has returned unsupported type.\nSupported types are List[float|int|None], '
|
|
523
651
|
f'List[List[ConfusionMatrixElement]], NDArray[np.float32] or dictonary with one of these types as its values types. ')
|
|
524
652
|
|
|
525
|
-
def _validate_single_metric(single_metric_result,key=None):
|
|
653
|
+
def _validate_single_metric(single_metric_result, key=None):
|
|
526
654
|
if isinstance(single_metric_result, list):
|
|
527
655
|
if isinstance(single_metric_result[0], list):
|
|
528
656
|
assert all(isinstance(cm, ConfusionMatrixElement) for cm in single_metric_result[0]), (
|
|
@@ -532,7 +660,7 @@ def tensorleap_custom_metric(name: str,
|
|
|
532
660
|
)
|
|
533
661
|
|
|
534
662
|
else:
|
|
535
|
-
assert all(isinstance(v, (float,int,type(None),np.float32)) for v in single_metric_result), (
|
|
663
|
+
assert all(isinstance(v, (float, int, type(None), np.float32)) for v in single_metric_result), (
|
|
536
664
|
f"{supported_types_message}\n"
|
|
537
665
|
f"Got {'a dict where the value of ' + str(key) + ' is of type ' if key is not None else ''}"
|
|
538
666
|
f"List[{', '.join(type(v).__name__ for v in single_metric_result)}]."
|
|
@@ -549,7 +677,7 @@ def tensorleap_custom_metric(name: str,
|
|
|
549
677
|
|
|
550
678
|
if isinstance(result, dict):
|
|
551
679
|
for key, value in result.items():
|
|
552
|
-
_validate_single_metric(value,key)
|
|
680
|
+
_validate_single_metric(value, key)
|
|
553
681
|
|
|
554
682
|
assert isinstance(key, str), \
|
|
555
683
|
(f'{user_function.__name__}() validation failed: '
|
|
@@ -604,13 +732,15 @@ def tensorleap_custom_metric(name: str,
|
|
|
604
732
|
_add_mapping_connections(connects_to, arg_names, NodeMappingType.Metric, name)
|
|
605
733
|
|
|
606
734
|
def inner(*args, **kwargs):
|
|
735
|
+
if not _call_from_tl_platform:
|
|
736
|
+
set_current('tensorleap_custom_metric')
|
|
607
737
|
_validate_input_args(*args, **kwargs)
|
|
608
738
|
|
|
609
739
|
result = inner_without_validate(*args, **kwargs)
|
|
610
740
|
|
|
611
741
|
_validate_result(result)
|
|
612
|
-
if not
|
|
613
|
-
|
|
742
|
+
if not _call_from_tl_platform:
|
|
743
|
+
update_env_params_func("tensorleap_custom_metric", "v")
|
|
614
744
|
return result
|
|
615
745
|
|
|
616
746
|
def mapping_inner(*args, **kwargs):
|
|
@@ -650,17 +780,16 @@ def tensorleap_custom_visualizer(name: str, visualizer_type: LeapDataType,
|
|
|
650
780
|
name_to_unique_name = defaultdict(set)
|
|
651
781
|
|
|
652
782
|
def decorating_function(user_function: VisualizerCallableInterface):
|
|
653
|
-
assert isinstance(visualizer_type,LeapDataType),(f"{user_function.__name__} validation failed: "
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
783
|
+
assert isinstance(visualizer_type, LeapDataType), (f"{user_function.__name__} validation failed: "
|
|
784
|
+
f"visualizer_type should be of type {LeapDataType.__name__} but got {type(visualizer_type)}"
|
|
785
|
+
)
|
|
657
786
|
for viz_handler in leap_binder.setup_container.visualizers:
|
|
658
787
|
if viz_handler.visualizer_handler_data.name == name:
|
|
659
788
|
raise Exception(f'Visualizer with name {name} already exists. '
|
|
660
789
|
f'Please choose another')
|
|
661
790
|
|
|
662
791
|
def _validate_input_args(*args, **kwargs):
|
|
663
|
-
assert len(args) > 0, (
|
|
792
|
+
assert len(args) + len(kwargs) > 0, (
|
|
664
793
|
f"{user_function.__name__}() validation failed: "
|
|
665
794
|
f"Expected at least one positional|key-word argument of type np.ndarray, "
|
|
666
795
|
f"but received none. "
|
|
@@ -726,13 +855,15 @@ def tensorleap_custom_visualizer(name: str, visualizer_type: LeapDataType,
|
|
|
726
855
|
_add_mapping_connections(connects_to, arg_names, NodeMappingType.Visualizer, name)
|
|
727
856
|
|
|
728
857
|
def inner(*args, **kwargs):
|
|
858
|
+
if not _call_from_tl_platform:
|
|
859
|
+
set_current('tensorleap_custom_visualizer')
|
|
729
860
|
_validate_input_args(*args, **kwargs)
|
|
730
861
|
|
|
731
862
|
result = inner_without_validate(*args, **kwargs)
|
|
732
863
|
|
|
733
864
|
_validate_result(result)
|
|
734
|
-
if not
|
|
735
|
-
|
|
865
|
+
if not _call_from_tl_platform:
|
|
866
|
+
update_env_params_func("tensorleap_custom_visualizer", "v")
|
|
736
867
|
return result
|
|
737
868
|
|
|
738
869
|
def mapping_inner(*args, **kwargs):
|
|
@@ -810,19 +941,21 @@ def tensorleap_metadata(
|
|
|
810
941
|
|
|
811
942
|
leap_binder.set_metadata(inner_without_validate, name, metadata_type)
|
|
812
943
|
|
|
813
|
-
def inner(*args
|
|
944
|
+
def inner(*args, **kwargs):
|
|
945
|
+
if not _call_from_tl_platform:
|
|
946
|
+
set_current('tensorleap_metadata')
|
|
814
947
|
if os.environ.get(mapping_runtime_mode_env_var_mame):
|
|
815
948
|
return None
|
|
816
949
|
validate_args_structure(*args, types_order=[Union[int, str], PreprocessResponse],
|
|
817
|
-
func_name=user_function.__name__, expected_names=["idx", "preprocess"]
|
|
818
|
-
sample_id, preprocess_response = args if len(args)!=0 else
|
|
950
|
+
func_name=user_function.__name__, expected_names=["idx", "preprocess"], **kwargs)
|
|
951
|
+
sample_id, preprocess_response = args if len(args) != 0 else kwargs.values()
|
|
819
952
|
_validate_input_args(sample_id, preprocess_response)
|
|
820
953
|
|
|
821
954
|
result = inner_without_validate(sample_id, preprocess_response)
|
|
822
955
|
|
|
823
956
|
_validate_result(result)
|
|
824
|
-
if not
|
|
825
|
-
|
|
957
|
+
if not _call_from_tl_platform:
|
|
958
|
+
update_env_params_func("tensorleap_metadata", "v")
|
|
826
959
|
return result
|
|
827
960
|
|
|
828
961
|
return inner
|
|
@@ -830,7 +963,6 @@ def tensorleap_metadata(
|
|
|
830
963
|
return decorating_function
|
|
831
964
|
|
|
832
965
|
|
|
833
|
-
|
|
834
966
|
def tensorleap_custom_latent_space():
|
|
835
967
|
def decorating_function(user_function: SectionCallableInterface):
|
|
836
968
|
def _validate_input_args(sample_id: Union[int, str], preprocess_response: PreprocessResponse):
|
|
@@ -884,7 +1016,7 @@ def tensorleap_preprocess():
|
|
|
884
1016
|
leap_binder.set_preprocess(user_function)
|
|
885
1017
|
|
|
886
1018
|
def _validate_input_args(*args, **kwargs):
|
|
887
|
-
assert len(args)
|
|
1019
|
+
assert len(args) + len(kwargs) == 0, \
|
|
888
1020
|
(f'{user_function.__name__}() validation failed: '
|
|
889
1021
|
f'The function should not take any arguments. Got {args} and {kwargs}.')
|
|
890
1022
|
|
|
@@ -905,14 +1037,24 @@ def tensorleap_preprocess():
|
|
|
905
1037
|
f'The return list should not contain duplicate PreprocessResponse objects.')
|
|
906
1038
|
|
|
907
1039
|
def inner(*args, **kwargs):
|
|
1040
|
+
if not _call_from_tl_platform:
|
|
1041
|
+
set_current('tensorleap_metadata')
|
|
908
1042
|
if os.environ.get(mapping_runtime_mode_env_var_mame):
|
|
909
1043
|
return [None, None, None, None]
|
|
910
1044
|
|
|
911
1045
|
_validate_input_args(*args, **kwargs)
|
|
912
1046
|
result = user_function()
|
|
913
1047
|
_validate_result(result)
|
|
914
|
-
|
|
915
|
-
|
|
1048
|
+
|
|
1049
|
+
# Emit integration test event once per test
|
|
1050
|
+
try:
|
|
1051
|
+
emit_integration_event_once(AnalyticsEvent.PREPROCESS_INTEGRATION_TEST, {
|
|
1052
|
+
'preprocess_responses_count': len(result)
|
|
1053
|
+
})
|
|
1054
|
+
except Exception as e:
|
|
1055
|
+
logger.debug(f"Failed to emit preprocess integration test event: {e}")
|
|
1056
|
+
if not _call_from_tl_platform:
|
|
1057
|
+
update_env_params_func("tensorleap_preprocess", "v")
|
|
916
1058
|
return result
|
|
917
1059
|
|
|
918
1060
|
return inner
|
|
@@ -943,11 +1085,33 @@ def tensorleap_element_instance_preprocess(
|
|
|
943
1085
|
preprocess_response.sample_ids = all_sample_ids
|
|
944
1086
|
return result
|
|
945
1087
|
|
|
1088
|
+
# def extract_extra_instance_metadata():
|
|
1089
|
+
# result = user_function()
|
|
1090
|
+
# for preprocess_response in result:
|
|
1091
|
+
# for sample_id in preprocess_response.sample_ids:
|
|
1092
|
+
# instances_length = instance_length_encoder(sample_id, preprocess_response)
|
|
1093
|
+
# if instances_length > 0:
|
|
1094
|
+
# element_instance = instance_mask_encoder(sample_id, preprocess_response, 0)
|
|
1095
|
+
# instance_metadata = element_instance.instance_metadata
|
|
1096
|
+
# if instance_metadata is None:
|
|
1097
|
+
# return {}
|
|
1098
|
+
# return instance_metadata
|
|
1099
|
+
# return {}
|
|
1100
|
+
|
|
1101
|
+
|
|
946
1102
|
def builtin_instance_metadata(idx: str, preprocess: PreprocessResponse) -> Dict[str, str]:
|
|
947
1103
|
return {'is_instance': '0', 'original_sample_id': idx, 'instance_name': 'none'}
|
|
948
1104
|
|
|
1105
|
+
# def builtin_instance_extra_metadata(idx: str, preprocess: PreprocessResponse) -> Dict[str, str]:
|
|
1106
|
+
# instance_metadata = extract_extra_instance_metadata()
|
|
1107
|
+
# for key, value in instance_metadata.items():
|
|
1108
|
+
# instance_metadata[key] = 'unset'
|
|
1109
|
+
# return instance_metadata
|
|
1110
|
+
|
|
949
1111
|
leap_binder.set_preprocess(user_function_instance)
|
|
950
1112
|
leap_binder.set_metadata(builtin_instance_metadata, "builtin_instance_metadata")
|
|
1113
|
+
# leap_binder.set_metadata(builtin_instance_extra_metadata, "builtin_instance_extra_metadata")
|
|
1114
|
+
|
|
951
1115
|
|
|
952
1116
|
def _validate_input_args(*args, **kwargs):
|
|
953
1117
|
assert len(args) == 0 and len(kwargs) == 0, \
|
|
@@ -974,6 +1138,8 @@ def tensorleap_element_instance_preprocess(
|
|
|
974
1138
|
|
|
975
1139
|
result = user_function_instance()
|
|
976
1140
|
_validate_result(result)
|
|
1141
|
+
if not _call_from_tl_platform:
|
|
1142
|
+
update_env_params_func("tensorleap_preprocess", "v")
|
|
977
1143
|
return result
|
|
978
1144
|
|
|
979
1145
|
return inner
|
|
@@ -1056,10 +1222,11 @@ def tensorleap_instances_masks_encoder(name: str):
|
|
|
1056
1222
|
|
|
1057
1223
|
return decorating_function
|
|
1058
1224
|
|
|
1225
|
+
|
|
1059
1226
|
def tensorleap_instances_length_encoder(name: str):
|
|
1060
1227
|
def decorating_function(user_function: InstanceLengthCallableInterface):
|
|
1061
1228
|
def _validate_input_args(sample_id: str, preprocess_response: PreprocessResponse):
|
|
1062
|
-
assert isinstance(sample_id, str), \
|
|
1229
|
+
assert isinstance(sample_id, (str, int)), \
|
|
1063
1230
|
(f'tensorleap_instances_length_encoder validation failed: '
|
|
1064
1231
|
f'Argument sample_id should be str. Got {type(sample_id)}.')
|
|
1065
1232
|
assert isinstance(preprocess_response, PreprocessResponse), \
|
|
@@ -1101,12 +1268,28 @@ def tensorleap_instances_length_encoder(name: str):
|
|
|
1101
1268
|
|
|
1102
1269
|
return decorating_function
|
|
1103
1270
|
|
|
1104
|
-
|
|
1271
|
+
|
|
1272
|
+
def tensorleap_input_encoder(name: str, channel_dim=_UNSET, model_input_index=None):
|
|
1105
1273
|
def decorating_function(user_function: SectionCallableInterface):
|
|
1106
1274
|
for input_handler in leap_binder.setup_container.inputs:
|
|
1107
1275
|
if input_handler.name == name:
|
|
1108
1276
|
raise Exception(f'Input with name {name} already exists. '
|
|
1109
1277
|
f'Please choose another')
|
|
1278
|
+
nonlocal channel_dim
|
|
1279
|
+
|
|
1280
|
+
channel_dim_was_provided = channel_dim is not _UNSET
|
|
1281
|
+
|
|
1282
|
+
if not channel_dim_was_provided:
|
|
1283
|
+
channel_dim = -1
|
|
1284
|
+
if not _call_from_tl_platform:
|
|
1285
|
+
store_warning_by_param(
|
|
1286
|
+
param_name="channel_dim",
|
|
1287
|
+
user_func_name=user_function.__name__,
|
|
1288
|
+
default_value=channel_dim,
|
|
1289
|
+
link_to_docs="https://docs.tensorleap.ai/tensorleap-integration/writing-integration-code/input-encoder"
|
|
1290
|
+
|
|
1291
|
+
)
|
|
1292
|
+
|
|
1110
1293
|
if channel_dim <= 0 and channel_dim != -1:
|
|
1111
1294
|
raise Exception(f"Channel dim for input {name} is expected to be either -1 or positive")
|
|
1112
1295
|
|
|
@@ -1117,7 +1300,7 @@ def tensorleap_input_encoder(name: str, channel_dim=-1, model_input_index=None):
|
|
|
1117
1300
|
f'{preprocess_response.sample_id_type}. Got {type(sample_id)}.')
|
|
1118
1301
|
|
|
1119
1302
|
def _validate_result(result):
|
|
1120
|
-
validate_output_structure(result, func_name=user_function.__name__, expected_type_name
|
|
1303
|
+
validate_output_structure(result, func_name=user_function.__name__, expected_type_name="np.ndarray")
|
|
1121
1304
|
assert isinstance(result, np.ndarray), \
|
|
1122
1305
|
(f'{user_function.__name__}() validation failed: '
|
|
1123
1306
|
f'Unsupported return type. Should be a numpy array. Got {type(result)}.')
|
|
@@ -1140,11 +1323,12 @@ def tensorleap_input_encoder(name: str, channel_dim=-1, model_input_index=None):
|
|
|
1140
1323
|
|
|
1141
1324
|
leap_binder.set_input(inner_without_validate, name, channel_dim=channel_dim)
|
|
1142
1325
|
|
|
1143
|
-
|
|
1144
1326
|
def inner(*args, **kwargs):
|
|
1327
|
+
if not _call_from_tl_platform:
|
|
1328
|
+
set_current("tensorleap_input_encoder")
|
|
1145
1329
|
validate_args_structure(*args, types_order=[Union[int, str], PreprocessResponse],
|
|
1146
|
-
func_name=user_function.__name__,
|
|
1147
|
-
sample_id, preprocess_response = args if len(args)!=0 else
|
|
1330
|
+
func_name=user_function.__name__, expected_names=["idx", "preprocess"], **kwargs)
|
|
1331
|
+
sample_id, preprocess_response = args if len(args) != 0 else kwargs.values()
|
|
1148
1332
|
_validate_input_args(sample_id, preprocess_response)
|
|
1149
1333
|
|
|
1150
1334
|
result = inner_without_validate(sample_id, preprocess_response)
|
|
@@ -1152,14 +1336,22 @@ def tensorleap_input_encoder(name: str, channel_dim=-1, model_input_index=None):
|
|
|
1152
1336
|
_validate_result(result)
|
|
1153
1337
|
|
|
1154
1338
|
if _called_from_inside_tl_decorator == 0 and _called_from_inside_tl_integration_test_decorator:
|
|
1155
|
-
batch_warning(result,user_function.__name__)
|
|
1339
|
+
batch_warning(result, user_function.__name__)
|
|
1156
1340
|
result = np.expand_dims(result, axis=0)
|
|
1157
|
-
|
|
1158
|
-
|
|
1341
|
+
# Emit integration test event once per test
|
|
1342
|
+
try:
|
|
1343
|
+
emit_integration_event_once(AnalyticsEvent.INPUT_ENCODER_INTEGRATION_TEST, {
|
|
1344
|
+
'encoder_name': name,
|
|
1345
|
+
'channel_dim': channel_dim,
|
|
1346
|
+
'model_input_index': model_input_index
|
|
1347
|
+
})
|
|
1348
|
+
except Exception as e:
|
|
1349
|
+
logger.debug(f"Failed to emit input_encoder integration test event: {e}")
|
|
1350
|
+
if not _call_from_tl_platform:
|
|
1351
|
+
update_env_params_func("tensorleap_input_encoder", "v")
|
|
1159
1352
|
|
|
1160
1353
|
return result
|
|
1161
1354
|
|
|
1162
|
-
|
|
1163
1355
|
node_mapping_type = NodeMappingType.Input
|
|
1164
1356
|
if model_input_index is not None:
|
|
1165
1357
|
node_mapping_type = NodeMappingType(f'Input{str(model_input_index)}')
|
|
@@ -1204,7 +1396,8 @@ def tensorleap_gt_encoder(name: str):
|
|
|
1204
1396
|
f'{preprocess_response.sample_id_type}. Got {type(sample_id)}.')
|
|
1205
1397
|
|
|
1206
1398
|
def _validate_result(result):
|
|
1207
|
-
validate_output_structure(result, func_name=user_function.__name__, expected_type_name
|
|
1399
|
+
validate_output_structure(result, func_name=user_function.__name__, expected_type_name="np.ndarray",
|
|
1400
|
+
gt_flag=True)
|
|
1208
1401
|
assert isinstance(result, np.ndarray), \
|
|
1209
1402
|
(f'{user_function.__name__}() validation failed: '
|
|
1210
1403
|
f'Unsupported return type. Should be a numpy array. Got {type(result)}.')
|
|
@@ -1225,8 +1418,9 @@ def tensorleap_gt_encoder(name: str):
|
|
|
1225
1418
|
|
|
1226
1419
|
leap_binder.set_ground_truth(inner_without_validate, name)
|
|
1227
1420
|
|
|
1228
|
-
|
|
1229
1421
|
def inner(*args, **kwargs):
|
|
1422
|
+
if not _call_from_tl_platform:
|
|
1423
|
+
set_current("tensorleap_gt_encoder")
|
|
1230
1424
|
validate_args_structure(*args, types_order=[Union[int, str], PreprocessResponse],
|
|
1231
1425
|
func_name=user_function.__name__, expected_names=["idx", "preprocess"], **kwargs)
|
|
1232
1426
|
sample_id, preprocess_response = args
|
|
@@ -1239,8 +1433,15 @@ def tensorleap_gt_encoder(name: str):
|
|
|
1239
1433
|
if _called_from_inside_tl_decorator == 0 and _called_from_inside_tl_integration_test_decorator:
|
|
1240
1434
|
batch_warning(result, user_function.__name__)
|
|
1241
1435
|
result = np.expand_dims(result, axis=0)
|
|
1242
|
-
|
|
1243
|
-
|
|
1436
|
+
# Emit integration test event once per test
|
|
1437
|
+
try:
|
|
1438
|
+
emit_integration_event_once(AnalyticsEvent.GT_ENCODER_INTEGRATION_TEST, {
|
|
1439
|
+
'encoder_name': name
|
|
1440
|
+
})
|
|
1441
|
+
except Exception as e:
|
|
1442
|
+
logger.debug(f"Failed to emit gt_encoder integration test event: {e}")
|
|
1443
|
+
if not _call_from_tl_platform:
|
|
1444
|
+
update_env_params_func("tensorleap_gt_encoder", "v")
|
|
1244
1445
|
return result
|
|
1245
1446
|
|
|
1246
1447
|
inner.node_mapping = NodeMapping(name, NodeMappingType.GroundTruth)
|
|
@@ -1281,28 +1482,18 @@ def tensorleap_custom_loss(name: str, connects_to=None):
|
|
|
1281
1482
|
valid_types = (np.ndarray, SamplePreprocessResponse)
|
|
1282
1483
|
|
|
1283
1484
|
def _validate_input_args(*args, **kwargs):
|
|
1284
|
-
assert len(args)
|
|
1485
|
+
assert len(args) + len(kwargs) > 0, (
|
|
1285
1486
|
f"{user_function.__name__}() validation failed: "
|
|
1286
|
-
f"Expected at least one positional|key-word argument of the allowed types (np.ndarray|SamplePreprocessResponse|
|
|
1487
|
+
f"Expected at least one positional|key-word argument of the allowed types (np.ndarray|SamplePreprocessResponse|). "
|
|
1287
1488
|
f"but received none. "
|
|
1288
1489
|
f"Correct usage example: {user_function.__name__}(input_array: np.ndarray, ...)"
|
|
1289
1490
|
)
|
|
1290
1491
|
for i, arg in enumerate(args):
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
assert isinstance(elem, valid_types), (f'{user_function.__name__}() validation failed: '
|
|
1294
|
-
f'Element #{y} of list should be a numpy array. Got {type(elem)}.')
|
|
1295
|
-
else:
|
|
1296
|
-
assert isinstance(arg, valid_types), (f'{user_function.__name__}() validation failed: '
|
|
1297
|
-
f'Argument #{i} should be a numpy array. Got {type(arg)}.')
|
|
1492
|
+
assert isinstance(arg, valid_types), (f'{user_function.__name__}() validation failed: '
|
|
1493
|
+
f'Argument #{i} should be a numpy array. Got {type(arg)}.')
|
|
1298
1494
|
for _arg_name, arg in kwargs.items():
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
assert isinstance(elem, valid_types), (f'{user_function.__name__}() validation failed: '
|
|
1302
|
-
f'Element #{y} of list should be a numpy array. Got {type(elem)}.')
|
|
1303
|
-
else:
|
|
1304
|
-
assert isinstance(arg, valid_types), (f'{user_function.__name__}() validation failed: '
|
|
1305
|
-
f'Argument #{_arg_name} should be a numpy array. Got {type(arg)}.')
|
|
1495
|
+
assert isinstance(arg, valid_types), (f'{user_function.__name__}() validation failed: '
|
|
1496
|
+
f'Argument #{_arg_name} should be a numpy array. Got {type(arg)}.')
|
|
1306
1497
|
|
|
1307
1498
|
def _validate_result(result):
|
|
1308
1499
|
validate_output_structure(result, func_name=user_function.__name__,
|
|
@@ -1310,8 +1501,8 @@ def tensorleap_custom_loss(name: str, connects_to=None):
|
|
|
1310
1501
|
assert isinstance(result, np.ndarray), \
|
|
1311
1502
|
(f'{user_function.__name__} validation failed: '
|
|
1312
1503
|
f'The return type should be a numpy array. Got {type(result)}.')
|
|
1313
|
-
assert
|
|
1314
|
-
|
|
1504
|
+
assert result.ndim < 2, (f'{user_function.__name__} validation failed: '
|
|
1505
|
+
f'The return type should be a 1Dim numpy array but got {result.ndim}Dim.')
|
|
1315
1506
|
|
|
1316
1507
|
@functools.wraps(user_function)
|
|
1317
1508
|
def inner_without_validate(*args, **kwargs):
|
|
@@ -1337,13 +1528,15 @@ def tensorleap_custom_loss(name: str, connects_to=None):
|
|
|
1337
1528
|
_add_mapping_connections(connects_to, arg_names, NodeMappingType.CustomLoss, name)
|
|
1338
1529
|
|
|
1339
1530
|
def inner(*args, **kwargs):
|
|
1531
|
+
if not _call_from_tl_platform:
|
|
1532
|
+
set_current("tensorleap_custom_loss")
|
|
1340
1533
|
_validate_input_args(*args, **kwargs)
|
|
1341
1534
|
|
|
1342
1535
|
result = inner_without_validate(*args, **kwargs)
|
|
1343
1536
|
|
|
1344
1537
|
_validate_result(result)
|
|
1345
|
-
if not
|
|
1346
|
-
|
|
1538
|
+
if not _call_from_tl_platform:
|
|
1539
|
+
update_env_params_func("tensorleap_custom_loss", "v")
|
|
1347
1540
|
|
|
1348
1541
|
return result
|
|
1349
1542
|
|
|
@@ -1404,80 +1597,172 @@ def tensorleap_custom_layer(name: str):
|
|
|
1404
1597
|
|
|
1405
1598
|
|
|
1406
1599
|
def tensorleap_status_table():
|
|
1407
|
-
'''
|
|
1408
|
-
Usage example:
|
|
1409
|
-
###################
|
|
1410
|
-
leap_integration.py
|
|
1411
|
-
###################
|
|
1412
|
-
from code_loader.inner_leap_binder.leapbinder_decorators import tensorleap_status_table
|
|
1413
|
-
...
|
|
1414
|
-
...
|
|
1415
|
-
...
|
|
1416
|
-
if __name__ == '__main__':
|
|
1417
|
-
tensorleap_status_table()
|
|
1418
|
-
...
|
|
1419
|
-
'''
|
|
1420
1600
|
import atexit
|
|
1421
1601
|
import sys
|
|
1422
1602
|
import traceback
|
|
1603
|
+
from typing import Any
|
|
1604
|
+
|
|
1423
1605
|
CHECK = "✅"
|
|
1424
1606
|
CROSS = "❌"
|
|
1607
|
+
UNKNOWN = "❔"
|
|
1425
1608
|
|
|
1426
|
-
|
|
1427
|
-
{"name": "tensorleap_preprocess", "Added to integration": CROSS},
|
|
1428
|
-
{"name": "tensorleap_integration_test", "Added to integration": CROSS},
|
|
1429
|
-
{"name": "tensorleap_input_encoder", "Added to integration": CROSS},
|
|
1430
|
-
{"name": "tensorleap_gt_encoder", "Added to integration": CROSS},
|
|
1431
|
-
{"name": "tensorleap_load_model", "Added to integration": CROSS},
|
|
1432
|
-
{"name": "tensorleap_custom_loss", "Added to integration": CROSS},
|
|
1433
|
-
{"name": "tensorleap_custom_metric (optional)", "Added to integration": CROSS},
|
|
1434
|
-
{"name": "tensorleap_metadata (optional)", "Added to integration": CROSS},
|
|
1435
|
-
{"name": "tensorleap_custom_visualizer (optional)", "Added to integration": CROSS},
|
|
1609
|
+
code_mapping_failure = [0]
|
|
1436
1610
|
|
|
1611
|
+
table = [
|
|
1612
|
+
{"name": "tensorleap_preprocess", "Added to integration": UNKNOWN},
|
|
1613
|
+
{"name": "tensorleap_integration_test", "Added to integration": UNKNOWN},
|
|
1614
|
+
{"name": "tensorleap_input_encoder", "Added to integration": UNKNOWN},
|
|
1615
|
+
{"name": "tensorleap_gt_encoder", "Added to integration": UNKNOWN},
|
|
1616
|
+
{"name": "tensorleap_load_model", "Added to integration": UNKNOWN},
|
|
1617
|
+
{"name": "tensorleap_custom_loss", "Added to integration": UNKNOWN},
|
|
1618
|
+
{"name": "tensorleap_custom_metric (optional)", "Added to integration": UNKNOWN},
|
|
1619
|
+
{"name": "tensorleap_metadata (optional)", "Added to integration": UNKNOWN},
|
|
1620
|
+
{"name": "tensorleap_custom_visualizer (optional)", "Added to integration": UNKNOWN},
|
|
1437
1621
|
]
|
|
1438
1622
|
|
|
1439
1623
|
_finalizer_called = {"done": False}
|
|
1624
|
+
_crashed = {"value": False}
|
|
1625
|
+
_current_func = {"name": None}
|
|
1626
|
+
|
|
1627
|
+
def _link(url: str) -> str:
|
|
1628
|
+
return f"\033{url}\033"
|
|
1629
|
+
|
|
1630
|
+
def _remove_suffix(s: str, suffix: str) -> str:
|
|
1631
|
+
if suffix and s.endswith(suffix):
|
|
1632
|
+
return s[:-len(suffix)]
|
|
1633
|
+
return s
|
|
1634
|
+
|
|
1635
|
+
def _find_row(name: str):
|
|
1636
|
+
for row in table:
|
|
1637
|
+
if _remove_suffix(row["name"], " (optional)") == name:
|
|
1638
|
+
return row
|
|
1639
|
+
return None
|
|
1640
|
+
|
|
1641
|
+
def _set_status(name: str, status_symbol: str):
|
|
1642
|
+
row = _find_row(name)
|
|
1643
|
+
if not row:
|
|
1644
|
+
return
|
|
1645
|
+
|
|
1646
|
+
cur = row["Added to integration"]
|
|
1647
|
+
if status_symbol == UNKNOWN:
|
|
1648
|
+
return
|
|
1649
|
+
if cur == CHECK and status_symbol != CHECK:
|
|
1650
|
+
return
|
|
1651
|
+
|
|
1652
|
+
row["Added to integration"] = status_symbol
|
|
1653
|
+
|
|
1654
|
+
def _mark_unknowns_as_cross():
|
|
1655
|
+
for row in table:
|
|
1656
|
+
if row["Added to integration"] == UNKNOWN:
|
|
1657
|
+
row["Added to integration"] = CROSS
|
|
1658
|
+
|
|
1659
|
+
def _format_default_value(v: Any) -> str:
|
|
1660
|
+
if hasattr(v, "name"):
|
|
1661
|
+
return str(v.name)
|
|
1662
|
+
if isinstance(v, str):
|
|
1663
|
+
return v
|
|
1664
|
+
s = repr(v)
|
|
1665
|
+
return s if len(s) <= 120 else s[:120] + "..."
|
|
1666
|
+
|
|
1667
|
+
def _print_param_default_warnings():
|
|
1668
|
+
data = _get_param_default_warnings()
|
|
1669
|
+
if not data:
|
|
1670
|
+
return
|
|
1671
|
+
|
|
1672
|
+
print("\nWarnings (Default use. It is recommended to set values explicitly):")
|
|
1673
|
+
for param_name in sorted(data.keys()):
|
|
1674
|
+
default_value = data[param_name]["default_value"]
|
|
1675
|
+
funcs = ", ".join(sorted(data[param_name]["funcs"]))
|
|
1676
|
+
dv = _format_default_value(default_value)
|
|
1677
|
+
|
|
1678
|
+
docs_link = data[param_name].get("link_to_docs")
|
|
1679
|
+
docs_part = f" {_link(docs_link)}" if docs_link else ""
|
|
1680
|
+
print(
|
|
1681
|
+
f" ⚠️ Parameter '{param_name}' defaults to {dv} in the following functions: [{funcs}]. "
|
|
1682
|
+
f"For more information, check {docs_part}")
|
|
1683
|
+
print("\nIf this isn’t the intended behaviour, set them explicitly.")
|
|
1440
1684
|
|
|
1441
1685
|
def _print_table():
|
|
1686
|
+
_print_param_default_warnings()
|
|
1687
|
+
|
|
1688
|
+
if not started_from("leap_integration.py"):
|
|
1689
|
+
return
|
|
1690
|
+
|
|
1442
1691
|
ready_mess = "\nAll parts have been successfully set. If no errors accured, you can now push the project to the Tensorleap system."
|
|
1443
1692
|
not_ready_mess = "\nSome mandatory components have not yet been added to the Integration test. Recommended next interface to add is: "
|
|
1444
1693
|
mandatory_ready_mess = "\nAll mandatory parts have been successfully set. If no errors accured, you can now push the project to the Tensorleap system or continue to the next optional reccomeded interface,adding: "
|
|
1694
|
+
code_mapping_failure_mes = "Tensorleap_integration_test code flow failed, check raised exception."
|
|
1445
1695
|
|
|
1446
1696
|
name_width = max(len(row["name"]) for row in table)
|
|
1447
1697
|
status_width = max(len(row["Added to integration"]) for row in table)
|
|
1698
|
+
|
|
1448
1699
|
header = f"{'Decorator Name'.ljust(name_width)} | {'Added to integration'.ljust(status_width)}"
|
|
1449
1700
|
sep = "-" * len(header)
|
|
1701
|
+
|
|
1450
1702
|
print("\n" + header)
|
|
1451
1703
|
print(sep)
|
|
1452
|
-
|
|
1704
|
+
|
|
1705
|
+
ready = True
|
|
1706
|
+
next_step = None
|
|
1707
|
+
|
|
1453
1708
|
for row in table:
|
|
1454
1709
|
print(f"{row['name'].ljust(name_width)} | {row['Added to integration'].ljust(status_width)}")
|
|
1455
|
-
if
|
|
1456
|
-
|
|
1457
|
-
|
|
1710
|
+
if not _crashed["value"] and ready:
|
|
1711
|
+
if row["Added to integration"] != CHECK:
|
|
1712
|
+
ready = False
|
|
1713
|
+
next_step = row["name"]
|
|
1458
1714
|
|
|
1715
|
+
if _crashed["value"]:
|
|
1716
|
+
print(f"\nScript crashed before completing all steps. crashed at function '{_current_func['name']}'.")
|
|
1717
|
+
return
|
|
1718
|
+
|
|
1719
|
+
if code_mapping_failure[0]:
|
|
1720
|
+
print(f"\n{CROSS + code_mapping_failure_mes}.")
|
|
1721
|
+
return
|
|
1722
|
+
|
|
1723
|
+
print(ready_mess) if ready else print(
|
|
1724
|
+
mandatory_ready_mess + next_step
|
|
1725
|
+
) if (next_step and "optional" in next_step) else print(not_ready_mess + (next_step or ""))
|
|
1726
|
+
|
|
1727
|
+
def set_current(name: str):
|
|
1728
|
+
_current_func["name"] = name
|
|
1729
|
+
|
|
1730
|
+
def update_env_params(name: str, status: str = "v"):
|
|
1731
|
+
if name == "code_mapping":
|
|
1732
|
+
code_mapping_failure[0] = 1
|
|
1733
|
+
if status == "v":
|
|
1734
|
+
_set_status(name, CHECK)
|
|
1735
|
+
else:
|
|
1736
|
+
_set_status(name, CROSS)
|
|
1459
1737
|
|
|
1460
|
-
print(ready_mess) if ready else print(mandatory_ready_mess+next_step) if "optional" in next_step else print(not_ready_mess+next_step)
|
|
1461
|
-
def update_env_params(name: str, status: str = "✓"):
|
|
1462
|
-
for row in table:
|
|
1463
|
-
if row["name"].removesuffix(" (optional)") == name:
|
|
1464
|
-
row["Added to integration"] = CHECK if status=="v" else CROSS
|
|
1465
|
-
break
|
|
1466
1738
|
def run_on_exit():
|
|
1467
1739
|
if _finalizer_called["done"]:
|
|
1468
1740
|
return
|
|
1469
1741
|
_finalizer_called["done"] = True
|
|
1742
|
+
if not _crashed["value"]:
|
|
1743
|
+
_mark_unknowns_as_cross()
|
|
1744
|
+
|
|
1470
1745
|
_print_table()
|
|
1746
|
+
|
|
1471
1747
|
def handle_exception(exc_type, exc_value, exc_traceback):
|
|
1748
|
+
_crashed["value"] = True
|
|
1749
|
+
crashed_name = _current_func["name"]
|
|
1750
|
+
if crashed_name:
|
|
1751
|
+
row = _find_row(crashed_name)
|
|
1752
|
+
if row and row["Added to integration"] != CHECK:
|
|
1753
|
+
row["Added to integration"] = CROSS
|
|
1754
|
+
|
|
1472
1755
|
traceback.print_exception(exc_type, exc_value, exc_traceback)
|
|
1473
1756
|
run_on_exit()
|
|
1757
|
+
|
|
1474
1758
|
atexit.register(run_on_exit)
|
|
1475
1759
|
sys.excepthook = handle_exception
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
return update_env_params
|
|
1760
|
+
|
|
1761
|
+
return set_current, update_env_params
|
|
1479
1762
|
|
|
1480
1763
|
|
|
1764
|
+
if not _call_from_tl_platform:
|
|
1765
|
+
set_current, update_env_params_func = tensorleap_status_table()
|
|
1481
1766
|
|
|
1482
1767
|
|
|
1483
1768
|
|