supervisely 6.73.390__py3-none-any.whl → 6.73.392__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.
Files changed (34) hide show
  1. supervisely/app/widgets/experiment_selector/experiment_selector.py +21 -3
  2. supervisely/app/widgets/experiment_selector/template.html +49 -70
  3. supervisely/app/widgets/report_thumbnail/report_thumbnail.py +19 -4
  4. supervisely/decorators/profile.py +20 -0
  5. supervisely/nn/benchmark/utils/detection/utlis.py +7 -0
  6. supervisely/nn/experiments.py +4 -0
  7. supervisely/nn/inference/gui/serving_gui_template.py +71 -11
  8. supervisely/nn/inference/inference.py +108 -6
  9. supervisely/nn/training/gui/classes_selector.py +246 -27
  10. supervisely/nn/training/gui/gui.py +318 -234
  11. supervisely/nn/training/gui/hyperparameters_selector.py +2 -2
  12. supervisely/nn/training/gui/model_selector.py +42 -1
  13. supervisely/nn/training/gui/tags_selector.py +1 -1
  14. supervisely/nn/training/gui/train_val_splits_selector.py +8 -7
  15. supervisely/nn/training/gui/training_artifacts.py +10 -1
  16. supervisely/nn/training/gui/training_process.py +17 -1
  17. supervisely/nn/training/train_app.py +227 -72
  18. supervisely/template/__init__.py +2 -0
  19. supervisely/template/base_generator.py +90 -0
  20. supervisely/template/experiment/__init__.py +0 -0
  21. supervisely/template/experiment/experiment.html.jinja +537 -0
  22. supervisely/template/experiment/experiment_generator.py +996 -0
  23. supervisely/template/experiment/header.html.jinja +154 -0
  24. supervisely/template/experiment/sidebar.html.jinja +240 -0
  25. supervisely/template/experiment/sly-style.css +397 -0
  26. supervisely/template/experiment/template.html.jinja +18 -0
  27. supervisely/template/extensions.py +172 -0
  28. supervisely/template/template_renderer.py +253 -0
  29. {supervisely-6.73.390.dist-info → supervisely-6.73.392.dist-info}/METADATA +3 -1
  30. {supervisely-6.73.390.dist-info → supervisely-6.73.392.dist-info}/RECORD +34 -23
  31. {supervisely-6.73.390.dist-info → supervisely-6.73.392.dist-info}/LICENSE +0 -0
  32. {supervisely-6.73.390.dist-info → supervisely-6.73.392.dist-info}/WHEEL +0 -0
  33. {supervisely-6.73.390.dist-info → supervisely-6.73.392.dist-info}/entry_points.txt +0 -0
  34. {supervisely-6.73.390.dist-info → supervisely-6.73.392.dist-info}/top_level.txt +0 -0
@@ -14,7 +14,7 @@ from supervisely.app.widgets import (
14
14
  class HyperparametersSelector:
15
15
  title = "Hyperparameters"
16
16
  description = "Set hyperparameters for training"
17
- lock_message = "Select model to unlock"
17
+ lock_message = "Select previous step to unlock"
18
18
 
19
19
  def __init__(self, hyperparameters: dict, app_options: dict = {}):
20
20
  # Init widgets
@@ -60,7 +60,7 @@ class HyperparametersSelector:
60
60
  f"Learn more about Model Benchmark in the {docs_link}.", status="info"
61
61
  )
62
62
  self.model_benchmark_auto_convert_warning = Text(
63
- text="Project will be automatically converted according to CV task for Model Evaluation.",
63
+ text="Project will be automatically converted according to CV task and uploaded for Model Evaluation.",
64
64
  status="warning",
65
65
  )
66
66
  self.model_benchmark_auto_convert_warning.hide()
@@ -1,6 +1,7 @@
1
1
  from typing import Literal
2
2
 
3
3
  import supervisely.io.env as sly_env
4
+ import supervisely.io.fs as sly_fs
4
5
  from supervisely import logger
5
6
  from supervisely.api.api import Api
6
7
  from supervisely.app.widgets import (
@@ -15,12 +16,13 @@ from supervisely.app.widgets import (
15
16
  from supervisely.nn.artifacts.utils import FrameworkMapper
16
17
  from supervisely.nn.experiments import get_experiment_infos
17
18
  from supervisely.nn.utils import ModelSource, _get_model_name
19
+ from supervisely._utils import get_filename_from_headers
18
20
 
19
21
 
20
22
  class ModelSelector:
21
23
  title = "Select Model"
22
24
  description = "Select a model for training"
23
- lock_message = "Select classes to unlock"
25
+ lock_message = "Select previous step to unlock"
24
26
 
25
27
  def __init__(self, api: Api, framework: str, models: list, app_options: dict = {}):
26
28
  # Init widgets
@@ -125,6 +127,45 @@ class ModelSelector:
125
127
  else:
126
128
  return self.experiment_selector.get_selected_experiment_info()
127
129
 
130
+ def get_checkpoint_name(self) -> str:
131
+ if self.get_model_source() == ModelSource.PRETRAINED:
132
+ selected_row = self.pretrained_models_table.get_selected_row()
133
+ meta = selected_row.get("meta", None)
134
+ if meta is not None:
135
+ model_files = meta.get("model_files", None)
136
+ if model_files is not None:
137
+ checkpoint_name = model_files.get("checkpoint", None)
138
+ if checkpoint_name is not None:
139
+ is_url = sly_fs.str_is_url(checkpoint_name)
140
+ if (not is_url) or checkpoint_name.lower().endswith((".pth", ".pt")):
141
+ checkpoint_name = sly_fs.get_file_name_with_ext(checkpoint_name)
142
+ else:
143
+ checkpoint_name = get_filename_from_headers(checkpoint_name)
144
+ return checkpoint_name
145
+ return None
146
+ else:
147
+ checkpoint_name = self.experiment_selector.get_selected_checkpoint_name()
148
+ return checkpoint_name
149
+
150
+ def get_checkpoint_link(self) -> str:
151
+ if self.get_model_source() == ModelSource.PRETRAINED:
152
+ selected_row = self.pretrained_models_table.get_selected_row()
153
+ meta = selected_row.get("meta", None)
154
+ if meta is not None:
155
+ model_files = meta.get("model_files", None)
156
+ if model_files is not None:
157
+ checkpoint_link = model_files.get("checkpoint", None)
158
+ if checkpoint_link is not None:
159
+ is_url = sly_fs.str_is_url(checkpoint_link)
160
+ if checkpoint_link.startswith("/experiments/"):
161
+ is_url = True
162
+ if is_url:
163
+ return checkpoint_link
164
+ return None
165
+ else:
166
+ checkpoint_link = self.experiment_selector.get_selected_checkpoint_path()
167
+ return checkpoint_link
168
+
128
169
  def validate_step(self) -> bool:
129
170
  self.validator_text.hide()
130
171
  model_info = self.get_model_info()
@@ -5,7 +5,7 @@ from supervisely.app.widgets import Button, Card, Container, TagsTable, Text
5
5
  class TagsSelector:
6
6
  title = "Tags Selector"
7
7
  description = "Select tags that will be used for training"
8
- lock_message = "Select training and validation splits to unlock"
8
+ lock_message = "Select previous step to unlock"
9
9
 
10
10
  def __init__(self, project_id: int, tags: list, app_options: dict = {}):
11
11
  # Init widgets
@@ -2,12 +2,12 @@ from typing import List
2
2
 
3
3
  from supervisely import Api, Project
4
4
  from supervisely.app.widgets import Button, Card, Container, Text, TrainValSplits
5
-
5
+ from supervisely.api.module_api import ApiField
6
6
 
7
7
  class TrainValSplitsSelector:
8
8
  title = "Train / Val Splits"
9
9
  description = "Select train and val splits for training"
10
- lock_message = "Select input options to unlock"
10
+ lock_message = "Select previous step to unlock"
11
11
 
12
12
  def __init__(self, api: Api, project_id: int, app_options: dict = {}):
13
13
  # Init widgets
@@ -222,12 +222,13 @@ class TrainValSplitsSelector:
222
222
  return False
223
223
 
224
224
  # Check if datasets are not empty
225
- stats = self.api.project.get_stats(self.project_id)
225
+ filters = [{ ApiField.FIELD: ApiField.ID, ApiField.OPERATOR: "in", ApiField.VALUE: train_dataset_id + val_dataset_id}]
226
+ selected_datasets = self.api.dataset.get_list(self.project_id, filters, recursive=True)
226
227
  datasets_count = {}
227
- for dataset in stats["images"]["datasets"]:
228
- datasets_count[dataset["id"]] = {
229
- "name": dataset["name"],
230
- "total": dataset["imagesInDataset"],
228
+ for dataset in selected_datasets:
229
+ datasets_count[dataset.id] = {
230
+ "name": dataset.name,
231
+ "total": dataset.images_count,
231
232
  }
232
233
 
233
234
  empty_dataset_names = []
@@ -64,7 +64,16 @@ class TrainingArtifacts:
64
64
  self.display_widgets.extend([self.validator_text])
65
65
 
66
66
  # Outputs
67
- self.artifacts_thumbnail = FolderThumbnail()
67
+ need_generate_report = self.app_options.get("generate_report", True)
68
+ if need_generate_report:
69
+ self.artifacts_thumbnail = ReportThumbnail(
70
+ title="Experiment Report",
71
+ color="#5fa8ff",
72
+ bg_color="#e6f3ff",
73
+ report_type="experiment",
74
+ )
75
+ else:
76
+ self.artifacts_thumbnail = FolderThumbnail()
68
77
  self.artifacts_thumbnail.hide()
69
78
 
70
79
  self.artifacts_field = Field(
@@ -1,5 +1,11 @@
1
1
  from typing import Any, Dict
2
2
 
3
+ # Safe optional import for torch to prevent pylint import-error when the library is absent.
4
+ try:
5
+ import torch # type: ignore
6
+ except ImportError: # pragma: no cover
7
+ torch = None # type: ignore
8
+
3
9
  from supervisely.app.widgets import (
4
10
  Button,
5
11
  Card,
@@ -15,7 +21,7 @@ from supervisely.app.widgets import (
15
21
  class TrainingProcess:
16
22
  title = "Training Process"
17
23
  description = "Manage training process"
18
- lock_message = "Select hyperparameters to unlock"
24
+ lock_message = "Select previous step to unlock"
19
25
 
20
26
  def __init__(self, app_options: Dict[str, Any]):
21
27
  # Initialize widgets to None
@@ -93,6 +99,16 @@ class TrainingProcess:
93
99
  else:
94
100
  return "cuda:0"
95
101
 
102
+ def get_device_name(self) -> str:
103
+ device = self.get_device()
104
+
105
+ if torch is not None and device.startswith("cuda"):
106
+ device_name = torch.cuda.get_device_name(device)
107
+ else:
108
+ device_name = "CPU"
109
+
110
+ return device_name
111
+
96
112
  def get_experiment_name(self) -> str:
97
113
  return self.experiment_name_input.get_value()
98
114