supervisely 6.73.243__py3-none-any.whl → 6.73.245__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 supervisely might be problematic. Click here for more details.
- supervisely/__init__.py +1 -1
- supervisely/_utils.py +18 -0
- supervisely/app/widgets/__init__.py +1 -0
- supervisely/app/widgets/card/card.py +3 -0
- supervisely/app/widgets/classes_table/classes_table.py +15 -1
- supervisely/app/widgets/custom_models_selector/custom_models_selector.py +25 -7
- supervisely/app/widgets/custom_models_selector/template.html +1 -1
- supervisely/app/widgets/experiment_selector/__init__.py +0 -0
- supervisely/app/widgets/experiment_selector/experiment_selector.py +500 -0
- supervisely/app/widgets/experiment_selector/style.css +27 -0
- supervisely/app/widgets/experiment_selector/template.html +82 -0
- supervisely/app/widgets/pretrained_models_selector/pretrained_models_selector.py +25 -3
- supervisely/app/widgets/random_splits_table/random_splits_table.py +41 -17
- supervisely/app/widgets/select_dataset_tree/select_dataset_tree.py +12 -5
- supervisely/app/widgets/train_val_splits/train_val_splits.py +99 -10
- supervisely/app/widgets/tree_select/tree_select.py +2 -0
- supervisely/nn/__init__.py +3 -1
- supervisely/nn/artifacts/artifacts.py +10 -0
- supervisely/nn/artifacts/detectron2.py +2 -0
- supervisely/nn/artifacts/hrda.py +3 -0
- supervisely/nn/artifacts/mmclassification.py +2 -0
- supervisely/nn/artifacts/mmdetection.py +6 -3
- supervisely/nn/artifacts/mmsegmentation.py +2 -0
- supervisely/nn/artifacts/ritm.py +3 -1
- supervisely/nn/artifacts/rtdetr.py +2 -0
- supervisely/nn/artifacts/unet.py +2 -0
- supervisely/nn/artifacts/yolov5.py +3 -0
- supervisely/nn/artifacts/yolov8.py +7 -1
- supervisely/nn/experiments.py +113 -0
- supervisely/nn/inference/gui/__init__.py +3 -1
- supervisely/nn/inference/gui/gui.py +31 -232
- supervisely/nn/inference/gui/serving_gui.py +223 -0
- supervisely/nn/inference/gui/serving_gui_template.py +240 -0
- supervisely/nn/inference/inference.py +225 -24
- supervisely/nn/training/__init__.py +0 -0
- supervisely/nn/training/gui/__init__.py +1 -0
- supervisely/nn/training/gui/classes_selector.py +100 -0
- supervisely/nn/training/gui/gui.py +539 -0
- supervisely/nn/training/gui/hyperparameters_selector.py +117 -0
- supervisely/nn/training/gui/input_selector.py +70 -0
- supervisely/nn/training/gui/model_selector.py +95 -0
- supervisely/nn/training/gui/train_val_splits_selector.py +200 -0
- supervisely/nn/training/gui/training_logs.py +93 -0
- supervisely/nn/training/gui/training_process.py +114 -0
- supervisely/nn/training/gui/utils.py +128 -0
- supervisely/nn/training/loggers/__init__.py +0 -0
- supervisely/nn/training/loggers/base_train_logger.py +58 -0
- supervisely/nn/training/loggers/tensorboard_logger.py +46 -0
- supervisely/nn/training/train_app.py +2038 -0
- supervisely/nn/utils.py +5 -0
- {supervisely-6.73.243.dist-info → supervisely-6.73.245.dist-info}/METADATA +3 -1
- {supervisely-6.73.243.dist-info → supervisely-6.73.245.dist-info}/RECORD +56 -34
- {supervisely-6.73.243.dist-info → supervisely-6.73.245.dist-info}/LICENSE +0 -0
- {supervisely-6.73.243.dist-info → supervisely-6.73.245.dist-info}/WHEEL +0 -0
- {supervisely-6.73.243.dist-info → supervisely-6.73.245.dist-info}/entry_points.txt +0 -0
- {supervisely-6.73.243.dist-info → supervisely-6.73.245.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from os.path import join
|
|
2
2
|
from re import compile as re_compile
|
|
3
|
+
from typing import List
|
|
3
4
|
|
|
4
5
|
from supervisely.nn.artifacts.artifacts import BaseTrainArtifacts
|
|
5
6
|
|
|
@@ -8,7 +9,7 @@ class YOLOv8(BaseTrainArtifacts):
|
|
|
8
9
|
def __init__(self, team_id: int):
|
|
9
10
|
super().__init__(team_id)
|
|
10
11
|
|
|
11
|
-
self._app_name = "Train YOLOv8"
|
|
12
|
+
self._app_name = "Train YOLOv8 | v9 | v10 | v11"
|
|
12
13
|
self._framework_folder = "/yolov8_train"
|
|
13
14
|
self._weights_folder = "weights"
|
|
14
15
|
self._task_type = None
|
|
@@ -17,6 +18,11 @@ class YOLOv8(BaseTrainArtifacts):
|
|
|
17
18
|
self._pattern = re_compile(
|
|
18
19
|
r"^/yolov8_train/(object detection|instance segmentation|pose estimation)/[^/]+/\d+/?$"
|
|
19
20
|
)
|
|
21
|
+
self._available_task_types: List[str] = [
|
|
22
|
+
"object detection",
|
|
23
|
+
"instance segmentation",
|
|
24
|
+
"pose estimation",
|
|
25
|
+
]
|
|
20
26
|
|
|
21
27
|
def get_task_id(self, artifacts_folder: str) -> str:
|
|
22
28
|
parts = artifacts_folder.split("/")
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
2
|
+
from json import JSONDecodeError
|
|
3
|
+
from os.path import dirname, join
|
|
4
|
+
from typing import Any, Dict, List, NamedTuple
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
|
|
8
|
+
from supervisely import logger
|
|
9
|
+
from supervisely.api.api import Api, ApiField
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ExperimentInfo(NamedTuple):
|
|
13
|
+
experiment_name: str
|
|
14
|
+
"""Name of the experiment. Defined by the user in the training app"""
|
|
15
|
+
framework_name: str
|
|
16
|
+
"""Name of the framework used in the experiment"""
|
|
17
|
+
model_name: str
|
|
18
|
+
"""Name of the model used in the experiment. Defined by the user in the training app"""
|
|
19
|
+
task_type: str
|
|
20
|
+
"""Task type of the experiment"""
|
|
21
|
+
project_id: int
|
|
22
|
+
"""Project ID in Supervisely"""
|
|
23
|
+
task_id: int
|
|
24
|
+
"""Task ID in Supervisely"""
|
|
25
|
+
model_files: Dict[str, str]
|
|
26
|
+
"""Dictionary with paths to model files that needs to be downloaded for training"""
|
|
27
|
+
checkpoints: List[str]
|
|
28
|
+
"""List of relative paths to checkpoints"""
|
|
29
|
+
best_checkpoint: str
|
|
30
|
+
"""Name of the best checkpoint. Defined by the user in the training app"""
|
|
31
|
+
app_state: str
|
|
32
|
+
"""Path to file with settings that were used in the app"""
|
|
33
|
+
model_meta: str
|
|
34
|
+
"""Path to file with model metadata such as model name, project id, project name and classes used for training"""
|
|
35
|
+
train_val_split: str
|
|
36
|
+
"""Path to train and validation splits, which contains IDs of the images used in each split"""
|
|
37
|
+
hyperparameters: str
|
|
38
|
+
"""Path to .yaml file with hyperparameters used in the experiment"""
|
|
39
|
+
artifacts_dir: str
|
|
40
|
+
"""Path to the directory with artifacts"""
|
|
41
|
+
datetime: str
|
|
42
|
+
"""Date and time when the experiment was started"""
|
|
43
|
+
evaluation_report_id: int
|
|
44
|
+
"""ID of the evaluation report"""
|
|
45
|
+
eval_metrics: Dict[str, Any]
|
|
46
|
+
"""Evaluation metrics"""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_experiment_infos(api: Api, team_id: int, framework_name: str) -> List[ExperimentInfo]:
|
|
50
|
+
"""
|
|
51
|
+
Get experiments from the specified framework folder for Train v2
|
|
52
|
+
|
|
53
|
+
:param api: Supervisely API client
|
|
54
|
+
:type api: Api
|
|
55
|
+
:param team_id: Team ID
|
|
56
|
+
:type team_id: int
|
|
57
|
+
:param framework_name: Name of the framework
|
|
58
|
+
:type framework_name: str
|
|
59
|
+
:return: List of ExperimentInfo objects
|
|
60
|
+
:rtype: List[ExperimentInfo]
|
|
61
|
+
:Usage example:
|
|
62
|
+
|
|
63
|
+
.. code-block:: python
|
|
64
|
+
|
|
65
|
+
import supervisely as sly
|
|
66
|
+
|
|
67
|
+
api = sly.Api.from_env()
|
|
68
|
+
team_id = sly.env.team_id()
|
|
69
|
+
framework_name = "rt-detr"
|
|
70
|
+
experiment_infos = sly.nn.training.experiments.get_experiment_infos(api, team_id, framework_name)
|
|
71
|
+
"""
|
|
72
|
+
metadata_name = "experiment_info.json"
|
|
73
|
+
experiments_folder = "/experiments"
|
|
74
|
+
experiment_infos = []
|
|
75
|
+
|
|
76
|
+
file_infos = api.file.list(team_id, experiments_folder, recursive=True, return_type="fileinfo")
|
|
77
|
+
sorted_file_infos = []
|
|
78
|
+
for file_info in file_infos:
|
|
79
|
+
if not file_info.path.endswith(metadata_name):
|
|
80
|
+
continue
|
|
81
|
+
|
|
82
|
+
experiment_dir = dirname(file_info.path)
|
|
83
|
+
if experiment_dir.endswith(framework_name):
|
|
84
|
+
experiment_path = join(experiment_dir, metadata_name)
|
|
85
|
+
sorted_file_infos.append(experiment_path)
|
|
86
|
+
|
|
87
|
+
def fetch_experiment_data(file_info):
|
|
88
|
+
try:
|
|
89
|
+
response = api.post(
|
|
90
|
+
"file-storage.download",
|
|
91
|
+
{ApiField.TEAM_ID: team_id, ApiField.PATH: file_info},
|
|
92
|
+
stream=True,
|
|
93
|
+
)
|
|
94
|
+
response.raise_for_status()
|
|
95
|
+
response_json = response.json()
|
|
96
|
+
required_fields = {field for field in ExperimentInfo._fields}
|
|
97
|
+
if not required_fields.issubset(response_json.keys()):
|
|
98
|
+
logger.debug(
|
|
99
|
+
f"Missing required fields in JSON from '{experiment_path}': {required_fields - response_json.keys()}"
|
|
100
|
+
)
|
|
101
|
+
return None
|
|
102
|
+
return ExperimentInfo(**response_json)
|
|
103
|
+
except requests.exceptions.RequestException as e:
|
|
104
|
+
logger.debug(f"Failed to fetch train metadata from '{experiment_path}': {e}")
|
|
105
|
+
except JSONDecodeError as e:
|
|
106
|
+
logger.debug(f"Failed to decode JSON from '{experiment_path}': {e}")
|
|
107
|
+
return None
|
|
108
|
+
|
|
109
|
+
with ThreadPoolExecutor() as executor:
|
|
110
|
+
experiment_infos = list(executor.map(fetch_experiment_data, sorted_file_infos))
|
|
111
|
+
|
|
112
|
+
experiment_infos = [info for info in experiment_infos if info is not None]
|
|
113
|
+
return experiment_infos
|
|
@@ -1 +1,3 @@
|
|
|
1
|
-
from supervisely.nn.inference.gui.gui import BaseInferenceGUI, InferenceGUI
|
|
1
|
+
from supervisely.nn.inference.gui.gui import BaseInferenceGUI, InferenceGUI
|
|
2
|
+
from supervisely.nn.inference.gui.serving_gui import ServingGUI
|
|
3
|
+
from supervisely.nn.inference.gui.serving_gui_template import ServingGUITemplate
|
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
from functools import wraps
|
|
6
6
|
from typing import Callable, Dict, List, Optional, Union
|
|
7
7
|
|
|
8
|
-
import yaml
|
|
9
|
-
|
|
10
8
|
import supervisely.app.widgets as Widgets
|
|
11
9
|
import supervisely.io.env as env
|
|
10
|
+
import yaml
|
|
12
11
|
from supervisely import Api
|
|
13
12
|
from supervisely._utils import abs_url, is_debug_with_sly_net, is_development
|
|
14
13
|
from supervisely.api.file_api import FileApi
|
|
@@ -97,7 +96,9 @@ class InferenceGUI(BaseInferenceGUI):
|
|
|
97
96
|
self._serve_button = Widgets.Button("SERVE")
|
|
98
97
|
self._success_label = Widgets.DoneLabel()
|
|
99
98
|
self._success_label.hide()
|
|
100
|
-
self._download_progress = Widgets.Progress(
|
|
99
|
+
self._download_progress = Widgets.Progress(
|
|
100
|
+
"Downloading model...", hide_on_finish=True
|
|
101
|
+
)
|
|
101
102
|
self._download_progress.hide()
|
|
102
103
|
self._change_model_button = Widgets.Button(
|
|
103
104
|
"STOP AND CHOOSE ANOTHER MODEL", button_type="danger"
|
|
@@ -123,7 +124,9 @@ class InferenceGUI(BaseInferenceGUI):
|
|
|
123
124
|
self._model_classes_widget = Widgets.ClassesTable(selectable=False)
|
|
124
125
|
self._model_classes_plug = Widgets.Text("No classes provided")
|
|
125
126
|
self._model_classes_widget_container = Widgets.Field(
|
|
126
|
-
content=Widgets.Container(
|
|
127
|
+
content=Widgets.Container(
|
|
128
|
+
[self._model_classes_widget, self._model_classes_plug]
|
|
129
|
+
),
|
|
127
130
|
title="Model classes",
|
|
128
131
|
description="List of classes model predicts",
|
|
129
132
|
)
|
|
@@ -152,7 +155,9 @@ class InferenceGUI(BaseInferenceGUI):
|
|
|
152
155
|
|
|
153
156
|
self._model_full_info_card.collapse()
|
|
154
157
|
self._additional_ui_content = []
|
|
155
|
-
self.get_ui = self.__add_content_and_model_info_to_default_ui(
|
|
158
|
+
self.get_ui = self.__add_content_and_model_info_to_default_ui(
|
|
159
|
+
self._model_full_info_card
|
|
160
|
+
)
|
|
156
161
|
|
|
157
162
|
tabs_titles = []
|
|
158
163
|
tabs_contents = []
|
|
@@ -166,7 +171,9 @@ class InferenceGUI(BaseInferenceGUI):
|
|
|
166
171
|
def update_table(selected_model):
|
|
167
172
|
cols = [
|
|
168
173
|
model_key
|
|
169
|
-
for model_key in self._models[selected_model]["checkpoints"][
|
|
174
|
+
for model_key in self._models[selected_model]["checkpoints"][
|
|
175
|
+
0
|
|
176
|
+
].keys()
|
|
170
177
|
]
|
|
171
178
|
rows = [
|
|
172
179
|
[value for param_name, value in model.items()]
|
|
@@ -255,7 +262,9 @@ class InferenceGUI(BaseInferenceGUI):
|
|
|
255
262
|
custom_tab_content = Widgets.Container(custom_tab_widgets)
|
|
256
263
|
tabs_titles.append("Custom models")
|
|
257
264
|
tabs_contents.append(custom_tab_content)
|
|
258
|
-
tabs_descriptions.append(
|
|
265
|
+
tabs_descriptions.append(
|
|
266
|
+
"Models trained in Supervisely and located in Team Files"
|
|
267
|
+
)
|
|
259
268
|
|
|
260
269
|
self._tabs = Widgets.RadioTabs(
|
|
261
270
|
titles=tabs_titles,
|
|
@@ -263,7 +272,9 @@ class InferenceGUI(BaseInferenceGUI):
|
|
|
263
272
|
descriptions=tabs_descriptions,
|
|
264
273
|
)
|
|
265
274
|
|
|
266
|
-
self.on_change_model_callbacks: List[CallbackT] = [
|
|
275
|
+
self.on_change_model_callbacks: List[CallbackT] = [
|
|
276
|
+
InferenceGUI._hide_info_after_change
|
|
277
|
+
]
|
|
267
278
|
self.on_serve_callbacks: List[CallbackT] = []
|
|
268
279
|
|
|
269
280
|
@self.serve_button.click
|
|
@@ -334,7 +345,9 @@ class InferenceGUI(BaseInferenceGUI):
|
|
|
334
345
|
|
|
335
346
|
table_subtitles, cols = self._get_table_subtitles(cols)
|
|
336
347
|
if self._models_table is None:
|
|
337
|
-
self._models_table = Widgets.RadioTable(
|
|
348
|
+
self._models_table = Widgets.RadioTable(
|
|
349
|
+
cols, rows, subtitles=table_subtitles
|
|
350
|
+
)
|
|
338
351
|
else:
|
|
339
352
|
self._models_table.set_data(cols, rows, subtitles=table_subtitles)
|
|
340
353
|
|
|
@@ -470,15 +483,21 @@ class InferenceGUI(BaseInferenceGUI):
|
|
|
470
483
|
try:
|
|
471
484
|
classes = inference.get_classes()
|
|
472
485
|
except NotImplementedError:
|
|
473
|
-
logger.warn(
|
|
486
|
+
logger.warn(
|
|
487
|
+
f"get_classes() function not implemented for {type(inference)} object."
|
|
488
|
+
)
|
|
474
489
|
except AttributeError:
|
|
475
|
-
logger.warn(
|
|
490
|
+
logger.warn(
|
|
491
|
+
"Probably, get_classes() function not working without model deploy."
|
|
492
|
+
)
|
|
476
493
|
except Exception as exc:
|
|
477
494
|
logger.warn("Skip getting classes info due to exception")
|
|
478
495
|
logger.exception(exc)
|
|
479
496
|
|
|
480
497
|
if classes is None or len(classes) == 0:
|
|
481
|
-
logger.warn(
|
|
498
|
+
logger.warn(
|
|
499
|
+
f"get_classes() function return {classes}; skip classes processing."
|
|
500
|
+
)
|
|
482
501
|
return None
|
|
483
502
|
return classes
|
|
484
503
|
|
|
@@ -518,223 +537,3 @@ class InferenceGUI(BaseInferenceGUI):
|
|
|
518
537
|
return wrapper
|
|
519
538
|
|
|
520
539
|
return decorator(self.get_ui)
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
class ServingGUI:
|
|
524
|
-
def __init__(self) -> None:
|
|
525
|
-
device_values = []
|
|
526
|
-
device_names = []
|
|
527
|
-
try:
|
|
528
|
-
import torch
|
|
529
|
-
|
|
530
|
-
if torch.cuda.is_available():
|
|
531
|
-
gpus = torch.cuda.device_count()
|
|
532
|
-
for i in range(gpus):
|
|
533
|
-
device_values.append(f"cuda:{i}")
|
|
534
|
-
device_names.append(f"{torch.cuda.get_device_name(i)} (cuda:{i})")
|
|
535
|
-
except:
|
|
536
|
-
pass
|
|
537
|
-
device_values.append("cpu")
|
|
538
|
-
device_names.append("CPU")
|
|
539
|
-
|
|
540
|
-
self._device_select = Widgets.SelectString(
|
|
541
|
-
values=device_values,
|
|
542
|
-
labels=device_names,
|
|
543
|
-
width_percent=30,
|
|
544
|
-
)
|
|
545
|
-
self._device_field = Widgets.Field(self._device_select, title="Device")
|
|
546
|
-
self._serve_button = Widgets.Button("SERVE")
|
|
547
|
-
self._success_label = Widgets.DoneLabel()
|
|
548
|
-
self._success_label.hide()
|
|
549
|
-
self._download_progress = Widgets.Progress("Downloading model...", hide_on_finish=True)
|
|
550
|
-
self._download_progress.hide()
|
|
551
|
-
self._change_model_button = Widgets.Button(
|
|
552
|
-
"STOP AND CHOOSE ANOTHER MODEL", button_type="danger"
|
|
553
|
-
)
|
|
554
|
-
self._change_model_button.hide()
|
|
555
|
-
|
|
556
|
-
self._model_inference_settings_widget = Widgets.Editor(
|
|
557
|
-
readonly=True, restore_default_button=False
|
|
558
|
-
)
|
|
559
|
-
self._model_inference_settings_container = Widgets.Field(
|
|
560
|
-
self._model_inference_settings_widget,
|
|
561
|
-
title="Inference settings",
|
|
562
|
-
description="Model allows user to configure the following parameters on prediction phase",
|
|
563
|
-
)
|
|
564
|
-
|
|
565
|
-
self._model_info_widget = Widgets.ModelInfo()
|
|
566
|
-
self._model_info_widget_container = Widgets.Field(
|
|
567
|
-
self._model_info_widget,
|
|
568
|
-
title="Session Info",
|
|
569
|
-
description="Basic information about the deployed model",
|
|
570
|
-
)
|
|
571
|
-
|
|
572
|
-
self._model_classes_widget = Widgets.ClassesTable(selectable=False)
|
|
573
|
-
self._model_classes_plug = Widgets.Text("No classes provided")
|
|
574
|
-
self._model_classes_widget_container = Widgets.Field(
|
|
575
|
-
content=Widgets.Container([self._model_classes_widget, self._model_classes_plug]),
|
|
576
|
-
title="Model classes",
|
|
577
|
-
description="List of classes model predicts",
|
|
578
|
-
)
|
|
579
|
-
|
|
580
|
-
self._model_full_info = Widgets.Container(
|
|
581
|
-
[
|
|
582
|
-
self._model_info_widget_container,
|
|
583
|
-
self._model_inference_settings_container,
|
|
584
|
-
self._model_classes_widget_container,
|
|
585
|
-
]
|
|
586
|
-
)
|
|
587
|
-
self._model_full_info.hide()
|
|
588
|
-
self._before_deploy_msg = Widgets.Text("Deploy model to see the information.")
|
|
589
|
-
|
|
590
|
-
self._model_full_info_card = Widgets.Card(
|
|
591
|
-
title="Full model info",
|
|
592
|
-
description="Inference settings, session parameters and model classes",
|
|
593
|
-
collapsable=True,
|
|
594
|
-
content=Widgets.Container(
|
|
595
|
-
[
|
|
596
|
-
self._model_full_info,
|
|
597
|
-
self._before_deploy_msg,
|
|
598
|
-
]
|
|
599
|
-
),
|
|
600
|
-
)
|
|
601
|
-
|
|
602
|
-
self._model_full_info_card.collapse()
|
|
603
|
-
self._additional_ui_content = []
|
|
604
|
-
self.get_ui = self.__add_content_and_model_info_to_default_ui(self._model_full_info_card)
|
|
605
|
-
|
|
606
|
-
self.on_change_model_callbacks: List[CallbackT] = [ServingGUI._hide_info_after_change]
|
|
607
|
-
self.on_serve_callbacks: List[CallbackT] = []
|
|
608
|
-
|
|
609
|
-
@self.serve_button.click
|
|
610
|
-
def serve_model():
|
|
611
|
-
self.deploy_with_current_params()
|
|
612
|
-
|
|
613
|
-
@self._change_model_button.click
|
|
614
|
-
def change_model():
|
|
615
|
-
for cb in self.on_change_model_callbacks:
|
|
616
|
-
cb(self)
|
|
617
|
-
self.change_model()
|
|
618
|
-
|
|
619
|
-
def deploy_with_current_params(self):
|
|
620
|
-
for cb in self.on_serve_callbacks:
|
|
621
|
-
cb(self)
|
|
622
|
-
self.set_deployed()
|
|
623
|
-
|
|
624
|
-
def change_model(self):
|
|
625
|
-
self._success_label.text = ""
|
|
626
|
-
self._success_label.hide()
|
|
627
|
-
self._serve_button.show()
|
|
628
|
-
self._device_select.enable()
|
|
629
|
-
self._change_model_button.hide()
|
|
630
|
-
Progress("model deployment canceled", 1).iter_done_report()
|
|
631
|
-
|
|
632
|
-
def _hide_info_after_change(self):
|
|
633
|
-
self._model_full_info_card.collapse()
|
|
634
|
-
self._model_full_info.hide()
|
|
635
|
-
self._before_deploy_msg.show()
|
|
636
|
-
|
|
637
|
-
def get_device(self) -> str:
|
|
638
|
-
return self._device_select.get_value()
|
|
639
|
-
|
|
640
|
-
@property
|
|
641
|
-
def serve_button(self) -> Widgets.Button:
|
|
642
|
-
return self._serve_button
|
|
643
|
-
|
|
644
|
-
@property
|
|
645
|
-
def download_progress(self) -> Widgets.Progress:
|
|
646
|
-
return self._download_progress
|
|
647
|
-
|
|
648
|
-
def set_deployed(self, device: str = None):
|
|
649
|
-
if device is not None:
|
|
650
|
-
self._device_select.set_value(device)
|
|
651
|
-
self._success_label.text = f"Model has been successfully loaded on {self._device_select.get_value().upper()} device"
|
|
652
|
-
self._success_label.show()
|
|
653
|
-
self._serve_button.hide()
|
|
654
|
-
self._device_select.disable()
|
|
655
|
-
self._change_model_button.show()
|
|
656
|
-
Progress("Model deployed", 1).iter_done_report()
|
|
657
|
-
|
|
658
|
-
def show_deployed_model_info(self, inference):
|
|
659
|
-
self.set_inference_settings(inference)
|
|
660
|
-
self.set_project_meta(inference)
|
|
661
|
-
self.set_model_info(inference)
|
|
662
|
-
self._before_deploy_msg.hide()
|
|
663
|
-
self._model_full_info.show()
|
|
664
|
-
self._model_full_info_card.uncollapse()
|
|
665
|
-
|
|
666
|
-
def set_inference_settings(self, inference):
|
|
667
|
-
if len(inference.custom_inference_settings_dict.keys()) == 0:
|
|
668
|
-
inference_settings_str = "# inference settings dict is empty"
|
|
669
|
-
else:
|
|
670
|
-
inference_settings_str = yaml.dump(inference.custom_inference_settings_dict)
|
|
671
|
-
self._model_inference_settings_widget.set_text(inference_settings_str, "yaml")
|
|
672
|
-
self._model_inference_settings_widget.show()
|
|
673
|
-
|
|
674
|
-
def set_project_meta(self, inference):
|
|
675
|
-
if self._get_classes_from_inference(inference) is None:
|
|
676
|
-
logger.warn("Skip loading project meta.")
|
|
677
|
-
self._model_classes_widget.hide()
|
|
678
|
-
self._model_classes_plug.show()
|
|
679
|
-
return
|
|
680
|
-
|
|
681
|
-
self._model_classes_widget.set_project_meta(inference.model_meta)
|
|
682
|
-
self._model_classes_plug.hide()
|
|
683
|
-
self._model_classes_widget.show()
|
|
684
|
-
|
|
685
|
-
def set_model_info(self, inference):
|
|
686
|
-
info = inference.get_human_readable_info(replace_none_with="Not provided")
|
|
687
|
-
self._model_info_widget.set_model_info(inference.task_id, info)
|
|
688
|
-
|
|
689
|
-
def _get_classes_from_inference(self, inference) -> Optional[List[str]]:
|
|
690
|
-
classes = None
|
|
691
|
-
try:
|
|
692
|
-
classes = inference.get_classes()
|
|
693
|
-
except NotImplementedError:
|
|
694
|
-
logger.warn(f"get_classes() function not implemented for {type(inference)} object.")
|
|
695
|
-
except AttributeError:
|
|
696
|
-
logger.warn("Probably, get_classes() function not working without model deploy.")
|
|
697
|
-
except Exception as exc:
|
|
698
|
-
logger.warn("Skip getting classes info due to exception")
|
|
699
|
-
logger.exception(exc)
|
|
700
|
-
|
|
701
|
-
if classes is None or len(classes) == 0:
|
|
702
|
-
logger.warn(f"get_classes() function return {classes}; skip classes processing.")
|
|
703
|
-
return None
|
|
704
|
-
return classes
|
|
705
|
-
|
|
706
|
-
def get_ui(self) -> Widgets.Widget:
|
|
707
|
-
return Widgets.Container(
|
|
708
|
-
[
|
|
709
|
-
self._device_field,
|
|
710
|
-
self._download_progress,
|
|
711
|
-
self._success_label,
|
|
712
|
-
self._serve_button,
|
|
713
|
-
self._change_model_button,
|
|
714
|
-
],
|
|
715
|
-
gap=3,
|
|
716
|
-
)
|
|
717
|
-
|
|
718
|
-
def add_content_to_default_ui(
|
|
719
|
-
self, widgets: Union[Widgets.Widget, List[Widgets.Widget]]
|
|
720
|
-
) -> None:
|
|
721
|
-
if isinstance(widgets, List):
|
|
722
|
-
self._additional_ui_content.extend(widgets)
|
|
723
|
-
else:
|
|
724
|
-
self._additional_ui_content.append(widgets)
|
|
725
|
-
|
|
726
|
-
def __add_content_and_model_info_to_default_ui(
|
|
727
|
-
self,
|
|
728
|
-
model_info_widget: Widgets.Widget,
|
|
729
|
-
) -> Callable:
|
|
730
|
-
def decorator(get_ui):
|
|
731
|
-
@wraps(get_ui)
|
|
732
|
-
def wrapper(*args, **kwargs):
|
|
733
|
-
ui = get_ui(*args, **kwargs)
|
|
734
|
-
content = [ui, *self._additional_ui_content, model_info_widget]
|
|
735
|
-
ui_with_info = Widgets.Container(content)
|
|
736
|
-
return ui_with_info
|
|
737
|
-
|
|
738
|
-
return wrapper
|
|
739
|
-
|
|
740
|
-
return decorator(self.get_ui)
|