supervisely 6.73.394__py3-none-any.whl → 6.73.396__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.
- supervisely/convert/converter.py +18 -6
- supervisely/convert/image/sly/sly_image_helper.py +4 -1
- supervisely/convert/volume/nii/nii_volume_converter.py +2 -2
- supervisely/io/env.py +85 -0
- supervisely/io/fs.py +4 -3
- supervisely/nn/inference/inference.py +274 -35
- supervisely/nn/training/gui/gui.py +1 -1
- supervisely/nn/training/train_app.py +19 -20
- supervisely/template/experiment/experiment.html.jinja +4 -4
- supervisely/template/experiment/experiment_generator.py +1 -1
- {supervisely-6.73.394.dist-info → supervisely-6.73.396.dist-info}/METADATA +1 -1
- {supervisely-6.73.394.dist-info → supervisely-6.73.396.dist-info}/RECORD +16 -16
- {supervisely-6.73.394.dist-info → supervisely-6.73.396.dist-info}/LICENSE +0 -0
- {supervisely-6.73.394.dist-info → supervisely-6.73.396.dist-info}/WHEEL +0 -0
- {supervisely-6.73.394.dist-info → supervisely-6.73.396.dist-info}/entry_points.txt +0 -0
- {supervisely-6.73.394.dist-info → supervisely-6.73.396.dist-info}/top_level.txt +0 -0
supervisely/convert/converter.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
from typing import Optional
|
|
3
|
+
from typing import List, Optional, Union
|
|
4
4
|
|
|
5
5
|
from tqdm import tqdm
|
|
6
6
|
|
|
7
|
+
from supervisely import fs
|
|
7
8
|
from supervisely._utils import is_production
|
|
8
9
|
from supervisely.api.api import Api
|
|
9
10
|
from supervisely.app import get_data_dir
|
|
@@ -40,7 +41,7 @@ class ImportManager:
|
|
|
40
41
|
|
|
41
42
|
def __init__(
|
|
42
43
|
self,
|
|
43
|
-
input_data: str,
|
|
44
|
+
input_data: Union[str, List[str]],
|
|
44
45
|
project_type: ProjectType,
|
|
45
46
|
team_id: Optional[int] = None,
|
|
46
47
|
labeling_interface: LabelingInterface = LabelingInterface.DEFAULT,
|
|
@@ -60,7 +61,12 @@ class ImportManager:
|
|
|
60
61
|
self._remote_files_map = {}
|
|
61
62
|
self._modality = project_type
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
if isinstance(input_data, str):
|
|
65
|
+
input_data = [input_data]
|
|
66
|
+
|
|
67
|
+
self._input_data = get_data_dir()
|
|
68
|
+
for data in input_data:
|
|
69
|
+
self._prepare_input_data(data)
|
|
64
70
|
self._unpack_archives(self._input_data)
|
|
65
71
|
remove_junk_from_dir(self._input_data)
|
|
66
72
|
|
|
@@ -90,6 +96,7 @@ class ImportManager:
|
|
|
90
96
|
}
|
|
91
97
|
if str(self._modality) not in modality_converter_map:
|
|
92
98
|
raise ValueError(f"Unsupported project type selected: {self._modality}")
|
|
99
|
+
|
|
93
100
|
modality_converter = modality_converter_map[str(self._modality)](
|
|
94
101
|
self._input_data,
|
|
95
102
|
self._labeling_interface,
|
|
@@ -106,12 +113,17 @@ class ImportManager:
|
|
|
106
113
|
# raise NotImplementedError
|
|
107
114
|
|
|
108
115
|
def _prepare_input_data(self, input_data):
|
|
116
|
+
logger.debug(f"Preparing input data: {input_data}")
|
|
109
117
|
if dir_exists(input_data):
|
|
110
118
|
logger.info(f"Input data is a local directory: {input_data}")
|
|
111
|
-
return input_data
|
|
119
|
+
# return input_data
|
|
120
|
+
dst_dir = os.path.join(get_data_dir(), os.path.basename(os.path.normpath(input_data)))
|
|
121
|
+
fs.copy_dir_recursively(input_data, dst_dir)
|
|
112
122
|
elif file_exists(input_data):
|
|
113
123
|
logger.info(f"Input data is a local file: {input_data}. Will use its directory")
|
|
114
|
-
return os.path.dirname(input_data)
|
|
124
|
+
# return os.path.dirname(input_data)
|
|
125
|
+
dst_file = os.path.join(get_data_dir(), os.path.basename(input_data))
|
|
126
|
+
fs.copy_file(input_data, dst_file)
|
|
115
127
|
elif self._api.storage.exists(self._team_id, input_data):
|
|
116
128
|
if self._upload_as_links and str(self._modality) in [
|
|
117
129
|
ProjectType.IMAGES.value,
|
|
@@ -145,7 +157,7 @@ class ImportManager:
|
|
|
145
157
|
if not is_dir:
|
|
146
158
|
dir_name = "Import data"
|
|
147
159
|
local_path = os.path.join(get_data_dir(), dir_name)
|
|
148
|
-
mkdir(local_path, remove_content_if_exists=
|
|
160
|
+
mkdir(local_path, remove_content_if_exists=False)
|
|
149
161
|
save_path = os.path.join(local_path, os.path.basename(remote_path))
|
|
150
162
|
else:
|
|
151
163
|
dir_name = os.path.basename(os.path.normpath(remote_path))
|
|
@@ -19,7 +19,10 @@ SLY_OBJECT_KEYS = [
|
|
|
19
19
|
LabelJsonFields.TAGS,
|
|
20
20
|
LabelJsonFields.GEOMETRY_TYPE,
|
|
21
21
|
]
|
|
22
|
-
SLY_TAG_KEYS = [
|
|
22
|
+
SLY_TAG_KEYS = [
|
|
23
|
+
TagJsonFields.TAG_NAME,
|
|
24
|
+
# TagJsonFields.VALUE
|
|
25
|
+
]
|
|
23
26
|
|
|
24
27
|
|
|
25
28
|
# Check the annotation format documentation at
|
|
@@ -197,8 +197,8 @@ class NiiConverter(VolumeConverter):
|
|
|
197
197
|
leave=True if progress_cb is None else False,
|
|
198
198
|
position=1,
|
|
199
199
|
)
|
|
200
|
-
if item.custom_data
|
|
201
|
-
volume_meta
|
|
200
|
+
if isinstance(item.custom_data, dict) and "remote_path" in item.custom_data:
|
|
201
|
+
volume_meta["remote_path"] = item.custom_data["remote_path"]
|
|
202
202
|
api.volume.upload_np(dataset_id, item.name, volume_np, volume_meta, progress_nrrd)
|
|
203
203
|
info = api.volume.get_info_by_name(dataset_id, item.name)
|
|
204
204
|
item.volume_meta = info.meta
|
supervisely/io/env.py
CHANGED
|
@@ -36,6 +36,12 @@ def _int_from_env(value):
|
|
|
36
36
|
return int(value)
|
|
37
37
|
|
|
38
38
|
|
|
39
|
+
def _parse_list_from_env(value: str) -> List[str]:
|
|
40
|
+
import ast
|
|
41
|
+
|
|
42
|
+
return [str(x).strip() for x in ast.literal_eval(value)]
|
|
43
|
+
|
|
44
|
+
|
|
39
45
|
def _parse_from_env(
|
|
40
46
|
name: str,
|
|
41
47
|
keys: List[str],
|
|
@@ -214,6 +220,32 @@ def team_files_folder(raise_not_found: Optional[bool] = True) -> str:
|
|
|
214
220
|
)
|
|
215
221
|
|
|
216
222
|
|
|
223
|
+
def team_files_folders(raise_not_found: Optional[bool] = True) -> List[str]:
|
|
224
|
+
"""Returns paths to the team files folders from environment variable using following keys:
|
|
225
|
+
- CONTEXT_SLYFOLDERS
|
|
226
|
+
- context.slyFolders
|
|
227
|
+
- modal.state.slyFolders
|
|
228
|
+
- FOLDERS
|
|
229
|
+
NOTE: same as team_files_folders
|
|
230
|
+
:param raise_not_found: if True, raises KeyError if team files folders are not found in environment variables
|
|
231
|
+
:type raise_not_found: Optional[bool]
|
|
232
|
+
:return: path to the team files folders
|
|
233
|
+
:rtype: str
|
|
234
|
+
"""
|
|
235
|
+
return _parse_from_env(
|
|
236
|
+
name="team_files_folders",
|
|
237
|
+
keys=[
|
|
238
|
+
"CONTEXT_SLYFOLDERS",
|
|
239
|
+
"context.slyFolders",
|
|
240
|
+
"modal.state.slyFolders",
|
|
241
|
+
"FOLDERS",
|
|
242
|
+
],
|
|
243
|
+
postprocess_fn=_parse_list_from_env,
|
|
244
|
+
default=[],
|
|
245
|
+
raise_not_found=raise_not_found,
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
|
|
217
249
|
def folder(raise_not_found: Optional[bool] = True) -> str:
|
|
218
250
|
"""Returns path to the team files folder from environment variable using following keys:
|
|
219
251
|
- CONTEXT_SLYFOLDER
|
|
@@ -229,6 +261,21 @@ def folder(raise_not_found: Optional[bool] = True) -> str:
|
|
|
229
261
|
return team_files_folder(raise_not_found)
|
|
230
262
|
|
|
231
263
|
|
|
264
|
+
def folders(raise_not_found: Optional[bool] = True) -> List[str]:
|
|
265
|
+
"""Returns paths to the team files folders from environment variable using following keys:
|
|
266
|
+
- CONTEXT_SLYFOLDERS
|
|
267
|
+
- context.slyFolders
|
|
268
|
+
- modal.state.slyFolders
|
|
269
|
+
- FOLDERS
|
|
270
|
+
NOTE: Same as team_files_folders
|
|
271
|
+
:param raise_not_found: if True, raises KeyError if team files folders are not found in environment variables
|
|
272
|
+
:type raise_not_found: Optional[bool]
|
|
273
|
+
:return: path to the team files folders
|
|
274
|
+
:rtype: str
|
|
275
|
+
"""
|
|
276
|
+
return team_files_folders(raise_not_found)
|
|
277
|
+
|
|
278
|
+
|
|
232
279
|
def team_files_file(raise_not_found: Optional[bool] = True) -> str:
|
|
233
280
|
"""Returns path to the file in the team files from environment variable using following keys:
|
|
234
281
|
- CONTEXT_SLYFILE
|
|
@@ -251,6 +298,28 @@ def team_files_file(raise_not_found: Optional[bool] = True) -> str:
|
|
|
251
298
|
)
|
|
252
299
|
|
|
253
300
|
|
|
301
|
+
def team_files_files(raise_not_found: Optional[bool] = True) -> List[str]:
|
|
302
|
+
"""Returns paths to the files in the team files from environment variable using following keys:
|
|
303
|
+
- CONTEXT_SLYFILES
|
|
304
|
+
- context.slyFiles
|
|
305
|
+
- modal.state.slyFiles
|
|
306
|
+
- FILES
|
|
307
|
+
|
|
308
|
+
NOTE: same as team_files_file
|
|
309
|
+
:param raise_not_found: if True, raises KeyError if file is not found in environment variables
|
|
310
|
+
:type raise_not_found: Optional[bool]
|
|
311
|
+
:return: path to the file in the team files
|
|
312
|
+
:rtype: str
|
|
313
|
+
"""
|
|
314
|
+
return _parse_from_env(
|
|
315
|
+
name="team_files_files",
|
|
316
|
+
keys=["CONTEXT_SLYFILES", "context.slyFiles", "modal.state.slyFiles", "FILES"],
|
|
317
|
+
postprocess_fn=_parse_list_from_env,
|
|
318
|
+
default=[],
|
|
319
|
+
raise_not_found=raise_not_found,
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
|
|
254
323
|
def server_address(raise_not_found: Optional[bool] = True) -> str:
|
|
255
324
|
"""Returns server address from environment variable using following keys:
|
|
256
325
|
- SERVER_ADDRESS
|
|
@@ -321,6 +390,22 @@ def file(raise_not_found: Optional[bool] = True) -> str:
|
|
|
321
390
|
return team_files_file(raise_not_found)
|
|
322
391
|
|
|
323
392
|
|
|
393
|
+
def files(raise_not_found: Optional[bool] = True) -> List[str]:
|
|
394
|
+
"""Returns paths to the files in the team files from environment variable using following keys:
|
|
395
|
+
- CONTEXT_SLYFILES
|
|
396
|
+
- context.slyFiles
|
|
397
|
+
- modal.state.slyFiles
|
|
398
|
+
- FILES
|
|
399
|
+
|
|
400
|
+
NOTE: Same as team_files_files
|
|
401
|
+
:param raise_not_found: if True, raises KeyError if file is not found in environment variables
|
|
402
|
+
:type raise_not_found: Optional[bool]
|
|
403
|
+
:return: path to the file in the team files
|
|
404
|
+
:rtype: str
|
|
405
|
+
"""
|
|
406
|
+
return team_files_files(raise_not_found)
|
|
407
|
+
|
|
408
|
+
|
|
324
409
|
def task_id(raise_not_found: Optional[bool] = True) -> int:
|
|
325
410
|
"""Returns task id from environment variable using following keys:
|
|
326
411
|
- TASK_ID
|
supervisely/io/fs.py
CHANGED
|
@@ -1154,14 +1154,15 @@ def copy_dir_recursively(
|
|
|
1154
1154
|
src_dir: str, dst_dir: str, progress_cb: Optional[Union[tqdm, Callable]] = None
|
|
1155
1155
|
) -> List[str]:
|
|
1156
1156
|
mkdir(dst_dir)
|
|
1157
|
+
src_dir_norm = src_dir.rstrip(os.sep)
|
|
1157
1158
|
|
|
1158
|
-
for rel_sub_dir in get_subdirs(
|
|
1159
|
+
for rel_sub_dir in get_subdirs(src_dir_norm, recursive=True):
|
|
1159
1160
|
dst_sub_dir = os.path.join(dst_dir, rel_sub_dir)
|
|
1160
1161
|
mkdir(dst_sub_dir)
|
|
1161
1162
|
|
|
1162
|
-
files = list_files_recursively(
|
|
1163
|
+
files = list_files_recursively(src_dir_norm)
|
|
1163
1164
|
for src_file_path in files:
|
|
1164
|
-
dst_file_path = os.path.normpath(src_file_path.replace(
|
|
1165
|
+
dst_file_path = os.path.normpath(src_file_path.replace(src_dir_norm, dst_dir))
|
|
1165
1166
|
ensure_base_path(dst_file_path)
|
|
1166
1167
|
if not file_exists(dst_file_path):
|
|
1167
1168
|
copy_file(src_file_path, dst_file_path)
|
|
@@ -93,6 +93,7 @@ from supervisely.project.project_meta import ProjectMeta
|
|
|
93
93
|
from supervisely.sly_logger import logger
|
|
94
94
|
from supervisely.task.progress import Progress
|
|
95
95
|
from supervisely.video.video import ALLOWED_VIDEO_EXTENSIONS, VideoFrameReader
|
|
96
|
+
from supervisely.nn.model.model_api import ModelAPI
|
|
96
97
|
|
|
97
98
|
try:
|
|
98
99
|
from typing import Literal
|
|
@@ -150,12 +151,15 @@ class Inference:
|
|
|
150
151
|
use_gui: Optional[bool] = False,
|
|
151
152
|
multithread_inference: Optional[bool] = True,
|
|
152
153
|
use_serving_gui_template: Optional[bool] = False,
|
|
154
|
+
model: Optional[str] = None,
|
|
155
|
+
device: Optional[str] = None,
|
|
156
|
+
runtime: Optional[str] = None,
|
|
153
157
|
):
|
|
154
158
|
|
|
155
159
|
self.pretrained_models = self._load_models_json_file(self.MODELS) if self.MODELS else None
|
|
156
|
-
self._args, self.
|
|
160
|
+
self._args, self._is_cli_deploy = self._parse_cli_deploy_args()
|
|
157
161
|
if model_dir is None:
|
|
158
|
-
if self.
|
|
162
|
+
if self._is_cli_deploy is True:
|
|
159
163
|
try:
|
|
160
164
|
model_dir = get_data_dir()
|
|
161
165
|
except:
|
|
@@ -165,8 +169,12 @@ class Inference:
|
|
|
165
169
|
sly_fs.mkdir(model_dir)
|
|
166
170
|
|
|
167
171
|
self.autorestart = None
|
|
172
|
+
_deploy_model = model
|
|
173
|
+
_deploy_device = device
|
|
174
|
+
_deploy_runtime = runtime
|
|
168
175
|
self.device: str = None
|
|
169
176
|
self.runtime: str = None
|
|
177
|
+
self._is_quick_deploy = False
|
|
170
178
|
self.model_precision: str = None
|
|
171
179
|
self.model_source: str = None
|
|
172
180
|
self.checkpoint_info: CheckpointInfo = None
|
|
@@ -208,12 +216,14 @@ class Inference:
|
|
|
208
216
|
|
|
209
217
|
self.load_model = LOAD_MODEL_DECORATOR(self.load_model)
|
|
210
218
|
|
|
211
|
-
if self.
|
|
219
|
+
if self._is_cli_deploy:
|
|
212
220
|
self._use_gui = False
|
|
213
221
|
deploy_params, need_download = self._get_deploy_params_from_args()
|
|
214
222
|
if need_download:
|
|
223
|
+
logger.debug("Downloading model files")
|
|
215
224
|
local_model_files = self._download_model_files(deploy_params, False)
|
|
216
225
|
deploy_params["model_files"] = local_model_files
|
|
226
|
+
logger.debug("Loading model...")
|
|
217
227
|
self._load_model_headless(**deploy_params)
|
|
218
228
|
|
|
219
229
|
if self._use_gui:
|
|
@@ -307,6 +317,97 @@ class Inference:
|
|
|
307
317
|
)
|
|
308
318
|
|
|
309
319
|
self.inference_requests_manager = InferenceRequestsManager(executor=self._executor)
|
|
320
|
+
if _deploy_model is not None and not self._model_served:
|
|
321
|
+
self._is_quick_deploy = True
|
|
322
|
+
self.serve()
|
|
323
|
+
self._deploy_headless(_deploy_model, _deploy_device, _deploy_runtime)
|
|
324
|
+
|
|
325
|
+
def __call__(
|
|
326
|
+
self,
|
|
327
|
+
input: Union[np.ndarray, str, os.PathLike, list] = None,
|
|
328
|
+
image_id: Union[List[int], int] = None,
|
|
329
|
+
video_id: Union[List[int], int] = None,
|
|
330
|
+
dataset_id: Union[List[int], int] = None,
|
|
331
|
+
project_id: Union[List[int], int] = None,
|
|
332
|
+
batch_size: int = None,
|
|
333
|
+
conf: float = None,
|
|
334
|
+
img_size: int = None,
|
|
335
|
+
classes: List[str] = None,
|
|
336
|
+
upload_mode: str = None,
|
|
337
|
+
recursive: bool = None,
|
|
338
|
+
**kwargs,
|
|
339
|
+
):
|
|
340
|
+
return ModelAPI(api=self._api, url="http://0.0.0.0:8000").predict(
|
|
341
|
+
input,
|
|
342
|
+
image_id,
|
|
343
|
+
video_id,
|
|
344
|
+
dataset_id,
|
|
345
|
+
project_id,
|
|
346
|
+
batch_size,
|
|
347
|
+
conf,
|
|
348
|
+
img_size,
|
|
349
|
+
classes,
|
|
350
|
+
upload_mode,
|
|
351
|
+
recursive,
|
|
352
|
+
**kwargs,
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
def _deploy_headless(self, model: str, device: str, runtime: Optional[str] = None):
|
|
356
|
+
"""Deploy model immediately from constructor arguments."""
|
|
357
|
+
# Clean model_dir before deploying
|
|
358
|
+
sly_fs.mkdir(self._model_dir, True)
|
|
359
|
+
|
|
360
|
+
def get_runtime(runtime: Optional[str]) -> str:
|
|
361
|
+
if runtime is None:
|
|
362
|
+
runtime = RuntimeType.PYTORCH
|
|
363
|
+
else:
|
|
364
|
+
if runtime.lower() in ["torch", RuntimeType.PYTORCH.lower()]:
|
|
365
|
+
runtime = RuntimeType.PYTORCH
|
|
366
|
+
elif runtime.lower() in ["onnx", RuntimeType.ONNXRUNTIME.lower()]:
|
|
367
|
+
runtime = RuntimeType.ONNXRUNTIME
|
|
368
|
+
elif runtime.lower() in ["trt", RuntimeType.TENSORRT.lower()]:
|
|
369
|
+
runtime = RuntimeType.TENSORRT
|
|
370
|
+
else:
|
|
371
|
+
raise ValueError(f"Invalid runtime: {runtime}. Please use one of the following values: {RuntimeType.PYTORCH}, {RuntimeType.ONNXRUNTIME}, {RuntimeType.TENSORRT}.")
|
|
372
|
+
return runtime
|
|
373
|
+
|
|
374
|
+
def get_pretrained_model(model: str) -> dict:
|
|
375
|
+
if self.pretrained_models is not None:
|
|
376
|
+
for m in self.pretrained_models:
|
|
377
|
+
m_name = _get_model_name(m)
|
|
378
|
+
if m_name and m_name.lower() == model.lower():
|
|
379
|
+
return m
|
|
380
|
+
return None
|
|
381
|
+
|
|
382
|
+
runtime = get_runtime(runtime)
|
|
383
|
+
logger.debug(f"Runtime: {runtime}")
|
|
384
|
+
|
|
385
|
+
# Pretrained models
|
|
386
|
+
selected_pretrained = get_pretrained_model(model)
|
|
387
|
+
if selected_pretrained is not None:
|
|
388
|
+
logger.debug("Pretrained model found")
|
|
389
|
+
model_files_remote = selected_pretrained["meta"]["model_files"]
|
|
390
|
+
model_files_local = self._download_pretrained_model(model_files_remote, headless=True)
|
|
391
|
+
|
|
392
|
+
deploy_params = {
|
|
393
|
+
"model_source": ModelSource.PRETRAINED,
|
|
394
|
+
"model_files": model_files_local,
|
|
395
|
+
"model_info": selected_pretrained,
|
|
396
|
+
"device": device,
|
|
397
|
+
"runtime": runtime,
|
|
398
|
+
}
|
|
399
|
+
logger.debug(f"Deploying pretrained model '{model}' ...")
|
|
400
|
+
logger.debug(f"Deploy parameters: {deploy_params}")
|
|
401
|
+
self._load_model_headless(**deploy_params)
|
|
402
|
+
return self
|
|
403
|
+
|
|
404
|
+
# Custom Models
|
|
405
|
+
checkpoint_path = model
|
|
406
|
+
checkpoint_name = sly_fs.get_file_name_with_ext(checkpoint_path)
|
|
407
|
+
deploy_params = self._get_deploy_parameters_from_custom_checkpoint(checkpoint_path, device, runtime)
|
|
408
|
+
logger.debug(f"Deploying custom model '{checkpoint_name}'...")
|
|
409
|
+
self._load_model_headless(**deploy_params)
|
|
410
|
+
return self
|
|
310
411
|
|
|
311
412
|
def get_batch_size(self):
|
|
312
413
|
if self.max_batch_size is not None:
|
|
@@ -808,6 +909,101 @@ class Inference:
|
|
|
808
909
|
if log_progress:
|
|
809
910
|
self.gui.download_progress.hide()
|
|
810
911
|
return local_model_files
|
|
912
|
+
|
|
913
|
+
def _get_deploy_parameters_from_custom_checkpoint(self, checkpoint_path: str, device: str, runtime: str) -> dict:
|
|
914
|
+
def _read_experiment_info(artifacts_dir: str) -> Optional[dict]:
|
|
915
|
+
exp_path = os.path.join(artifacts_dir, "experiment_info.json")
|
|
916
|
+
if sly_fs.file_exists(exp_path):
|
|
917
|
+
return self._load_json_file(exp_path)
|
|
918
|
+
return None
|
|
919
|
+
|
|
920
|
+
def _compose_model_files(artifacts_dir: str, checkpoint_path: str, files_map: dict) -> dict:
|
|
921
|
+
model_files = {k: os.path.join(artifacts_dir, v) for k, v in files_map.items()}
|
|
922
|
+
model_files["checkpoint"] = checkpoint_path
|
|
923
|
+
return model_files
|
|
924
|
+
|
|
925
|
+
is_local = sly_fs.file_exists(checkpoint_path)
|
|
926
|
+
if not is_local:
|
|
927
|
+
team_id = sly_env.team_id()
|
|
928
|
+
if self.api is None:
|
|
929
|
+
raise ValueError(
|
|
930
|
+
f"File: '{checkpoint_path}' not found in local storage. "
|
|
931
|
+
"Initialize API by providing 'API_TOKEN' and 'SERVER_ADDRESS' "
|
|
932
|
+
"environment variables to use remote checkpoint."
|
|
933
|
+
)
|
|
934
|
+
if not self.api.file.exists(team_id, checkpoint_path):
|
|
935
|
+
raise FileNotFoundError(
|
|
936
|
+
f"Checkpoint '{checkpoint_path}' not found locally and remotely. "
|
|
937
|
+
"Make sure you have provided correct checkpoint path."
|
|
938
|
+
)
|
|
939
|
+
|
|
940
|
+
artifacts_dir = os.path.dirname(os.path.dirname(checkpoint_path))
|
|
941
|
+
if not is_local:
|
|
942
|
+
logger.debug("Remote checkpoint found")
|
|
943
|
+
# --- REMOTE ---
|
|
944
|
+
# experiment_info.json
|
|
945
|
+
logger.debug("Getting experiment_info.json...")
|
|
946
|
+
remote_exp_info = os.path.join(artifacts_dir, "experiment_info.json")
|
|
947
|
+
local_exp_info = os.path.join(self.model_dir, "experiment_info.json")
|
|
948
|
+
self.download(remote_exp_info, local_exp_info)
|
|
949
|
+
experiment_info = self._load_json_file(local_exp_info)
|
|
950
|
+
|
|
951
|
+
# model_meta.json
|
|
952
|
+
logger.debug("Getting model_meta.json...")
|
|
953
|
+
meta_name = experiment_info.get("model_meta") or "model_meta.json"
|
|
954
|
+
remote_meta = os.path.join(artifacts_dir, meta_name)
|
|
955
|
+
local_meta = os.path.join(self.model_dir, meta_name)
|
|
956
|
+
self.download(remote_meta, local_meta)
|
|
957
|
+
model_meta = self._load_json_file(local_meta)
|
|
958
|
+
experiment_info["model_meta"] = model_meta
|
|
959
|
+
|
|
960
|
+
# model files
|
|
961
|
+
logger.debug("Getting model files...")
|
|
962
|
+
remote_files_rel = experiment_info.get("model_files", {})
|
|
963
|
+
remote_files_full = _compose_model_files(artifacts_dir, checkpoint_path, remote_files_rel)
|
|
964
|
+
local_model_files = self._download_custom_model(remote_files_full, False)
|
|
965
|
+
model_files = local_model_files
|
|
966
|
+
model_info = experiment_info
|
|
967
|
+
logger.debug("Deploy parameters extracted from remote checkpoint successfully")
|
|
968
|
+
else:
|
|
969
|
+
logger.debug("Local checkpoint found")
|
|
970
|
+
# --- LOCAL ---
|
|
971
|
+
try:
|
|
972
|
+
logger.debug("Reading state dict...")
|
|
973
|
+
import torch # pylint: disable=import-error
|
|
974
|
+
ckpt = torch.load(checkpoint_path, map_location="cpu")
|
|
975
|
+
model_info = ckpt.get("model_info", {})
|
|
976
|
+
model_files = self._extract_model_files_from_checkpoint(checkpoint_path)
|
|
977
|
+
model_files["checkpoint"] = checkpoint_path
|
|
978
|
+
meta_path = os.path.join(self.model_dir, "model_meta.json")
|
|
979
|
+
if sly_fs.file_exists(meta_path):
|
|
980
|
+
model_info["model_meta"] = self._load_json_file(meta_path)
|
|
981
|
+
logger.debug("Deploy parameters extracted from state dict successfully")
|
|
982
|
+
except:
|
|
983
|
+
logger.debug(f"Failed to read model metadata from checkpoint '{checkpoint_path}'. Trying to find local files...")
|
|
984
|
+
experiment_info = _read_experiment_info(artifacts_dir)
|
|
985
|
+
if experiment_info:
|
|
986
|
+
logger.debug("Reading experiment_info.json...")
|
|
987
|
+
model_files = _compose_model_files(artifacts_dir, checkpoint_path, experiment_info.get("model_files", {}))
|
|
988
|
+
meta_name = experiment_info.get("model_meta") or "model_meta.json"
|
|
989
|
+
meta_path = os.path.join(artifacts_dir, meta_name)
|
|
990
|
+
if not sly_fs.file_exists(meta_path):
|
|
991
|
+
raise FileNotFoundError(f"Model meta file not found: '{meta_path}'")
|
|
992
|
+
experiment_info["model_meta"] = self._load_json_file(meta_path)
|
|
993
|
+
model_info = experiment_info
|
|
994
|
+
logger.debug("Deploy parameters extracted from experiment_info.json successfully")
|
|
995
|
+
else:
|
|
996
|
+
raise FileNotFoundError(f"'experiment_info.json' not found in '{artifacts_dir}'")
|
|
997
|
+
|
|
998
|
+
deploy_params = {
|
|
999
|
+
"model_source": ModelSource.CUSTOM,
|
|
1000
|
+
"model_files": model_files,
|
|
1001
|
+
"model_info": model_info,
|
|
1002
|
+
"device": device,
|
|
1003
|
+
"runtime": runtime,
|
|
1004
|
+
}
|
|
1005
|
+
logger.debug(f"Deploy parameters: {deploy_params}")
|
|
1006
|
+
return deploy_params
|
|
811
1007
|
|
|
812
1008
|
def _extract_model_files_from_checkpoint(self, checkpoint_path: str) -> dict:
|
|
813
1009
|
extracted_files: dict = {}
|
|
@@ -816,7 +1012,6 @@ class Inference:
|
|
|
816
1012
|
return extracted_files
|
|
817
1013
|
|
|
818
1014
|
import torch # pylint: disable=import-error
|
|
819
|
-
|
|
820
1015
|
logger.debug(f"Reading checkpoint: {checkpoint_path}")
|
|
821
1016
|
checkpoint = torch.load(checkpoint_path, map_location="cpu")
|
|
822
1017
|
|
|
@@ -1008,11 +1203,12 @@ class Inference:
|
|
|
1008
1203
|
model_files = deploy_params.get("model_files", {})
|
|
1009
1204
|
if model_info:
|
|
1010
1205
|
checkpoint_name = os.path.basename(model_files.get("checkpoint"))
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1206
|
+
artifacts_dir = model_info.get("artifacts_dir")
|
|
1207
|
+
if artifacts_dir is None:
|
|
1208
|
+
artifacts_dir = os.path.dirname(os.path.dirname(model_files.get("checkpoint")))
|
|
1209
|
+
checkpoint_file_path = os.path.join(artifacts_dir, "checkpoints", checkpoint_name)
|
|
1014
1210
|
checkpoint_file_info = None
|
|
1015
|
-
if not self.
|
|
1211
|
+
if not self._is_cli_deploy:
|
|
1016
1212
|
checkpoint_file_info = self.api.file.get_info_by_path(
|
|
1017
1213
|
sly_env.team_id(), checkpoint_file_path
|
|
1018
1214
|
)
|
|
@@ -1115,7 +1311,7 @@ class Inference:
|
|
|
1115
1311
|
def api(self) -> Api:
|
|
1116
1312
|
if self._api is None:
|
|
1117
1313
|
if (
|
|
1118
|
-
self.
|
|
1314
|
+
self._is_cli_deploy
|
|
1119
1315
|
and os.getenv("SERVER_ADDRESS") is None
|
|
1120
1316
|
and os.getenv("API_TOKEN") is None
|
|
1121
1317
|
):
|
|
@@ -2538,7 +2734,7 @@ class Inference:
|
|
|
2538
2734
|
inference_request.done(len(results))
|
|
2539
2735
|
|
|
2540
2736
|
def serve(self):
|
|
2541
|
-
if not self._use_gui and not self.
|
|
2737
|
+
if not self._use_gui and not self._is_cli_deploy:
|
|
2542
2738
|
Progress("Deploying model ...", 1)
|
|
2543
2739
|
|
|
2544
2740
|
if is_debug_with_sly_net():
|
|
@@ -2553,30 +2749,31 @@ class Inference:
|
|
|
2553
2749
|
self._task_id = task["id"]
|
|
2554
2750
|
os.environ["TASK_ID"] = str(self._task_id)
|
|
2555
2751
|
else:
|
|
2556
|
-
if not self.
|
|
2752
|
+
if not self._is_cli_deploy:
|
|
2557
2753
|
self._task_id = sly_env.task_id() if is_production() else None
|
|
2558
2754
|
|
|
2559
|
-
if self.
|
|
2755
|
+
if self._is_cli_deploy:
|
|
2560
2756
|
# Predict and shutdown
|
|
2561
|
-
if self._args.mode == "predict"
|
|
2757
|
+
if self._args.mode == "predict":
|
|
2758
|
+
if any(
|
|
2562
2759
|
[
|
|
2563
2760
|
self._args.input,
|
|
2564
2761
|
self._args.project_id,
|
|
2565
2762
|
self._args.dataset_id,
|
|
2566
2763
|
self._args.image_id,
|
|
2567
2764
|
]
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2765
|
+
):
|
|
2766
|
+
self._parse_inference_settings_from_args()
|
|
2767
|
+
self._inference_by_cli_deploy_args()
|
|
2768
|
+
exit(0)
|
|
2769
|
+
else:
|
|
2770
|
+
logger.error("Predict mode requires one of the following arguments: --input, --project_id, --dataset_id, --image_id")
|
|
2771
|
+
exit(0)
|
|
2573
2772
|
|
|
2574
2773
|
if isinstance(self.gui, GUI.InferenceGUI):
|
|
2575
2774
|
self._app = Application(layout=self.get_ui())
|
|
2576
2775
|
elif isinstance(self.gui, GUI.ServingGUI):
|
|
2577
2776
|
self._app = Application(layout=self._app_layout)
|
|
2578
|
-
# elif isinstance(self.gui, GUI.InferenceGUI):
|
|
2579
|
-
# self._app = Application(layout=self.get_ui())
|
|
2580
2777
|
else:
|
|
2581
2778
|
self._app = Application(layout=self.get_ui())
|
|
2582
2779
|
|
|
@@ -3283,10 +3480,12 @@ class Inference:
|
|
|
3283
3480
|
}
|
|
3284
3481
|
|
|
3285
3482
|
# Local deploy without predict args
|
|
3286
|
-
if self.
|
|
3483
|
+
if self._is_cli_deploy:
|
|
3287
3484
|
self._run_server()
|
|
3485
|
+
elif self._is_quick_deploy:
|
|
3486
|
+
self._run_server_in_thread()
|
|
3288
3487
|
|
|
3289
|
-
def
|
|
3488
|
+
def _parse_cli_deploy_args(self):
|
|
3290
3489
|
parser = argparse.ArgumentParser(description="Run Inference Serving")
|
|
3291
3490
|
|
|
3292
3491
|
# Positional args
|
|
@@ -3403,6 +3602,7 @@ class Inference:
|
|
|
3403
3602
|
return args, True
|
|
3404
3603
|
|
|
3405
3604
|
def _parse_inference_settings_from_args(self):
|
|
3605
|
+
logger.debug("Parsing inference settings from args")
|
|
3406
3606
|
def parse_value(value: str):
|
|
3407
3607
|
if value.lower() in ("true", "false"):
|
|
3408
3608
|
return value.lower() == "true"
|
|
@@ -3438,6 +3638,7 @@ class Inference:
|
|
|
3438
3638
|
args.settings = settings_dict
|
|
3439
3639
|
args.settings = self._read_settings(args.settings)
|
|
3440
3640
|
self._validate_settings(args.settings)
|
|
3641
|
+
logger.debug("Inference settings were successfully parsed from args")
|
|
3441
3642
|
|
|
3442
3643
|
def _get_pretrained_model_params_from_args(self):
|
|
3443
3644
|
model_files = None
|
|
@@ -3473,8 +3674,12 @@ class Inference:
|
|
|
3473
3674
|
def _get_custom_model_params_from_args(self):
|
|
3474
3675
|
def _load_experiment_info(artifacts_dir):
|
|
3475
3676
|
experiment_path = os.path.join(artifacts_dir, "experiment_info.json")
|
|
3677
|
+
if not os.path.exists(experiment_path):
|
|
3678
|
+
raise ValueError(f"Experiment info file not found in {artifacts_dir}")
|
|
3476
3679
|
model_info = self._load_json_file(experiment_path)
|
|
3477
3680
|
model_meta_path = os.path.join(artifacts_dir, "model_meta.json")
|
|
3681
|
+
if not os.path.exists(model_meta_path):
|
|
3682
|
+
raise ValueError(f"Model meta file not found in {artifacts_dir}")
|
|
3478
3683
|
model_info["model_meta"] = self._load_json_file(model_meta_path)
|
|
3479
3684
|
original_model_files = model_info.get("model_files")
|
|
3480
3685
|
return model_info, original_model_files
|
|
@@ -3500,6 +3705,7 @@ class Inference:
|
|
|
3500
3705
|
else:
|
|
3501
3706
|
loop.run_until_complete(coro)
|
|
3502
3707
|
|
|
3708
|
+
logger.debug("Getting custom model params from args")
|
|
3503
3709
|
model_source = ModelSource.CUSTOM
|
|
3504
3710
|
need_download = False
|
|
3505
3711
|
checkpoint_path = self._args.model
|
|
@@ -3510,6 +3716,8 @@ class Inference:
|
|
|
3510
3716
|
raise ValueError(
|
|
3511
3717
|
"Team ID not found in env. Required for remote custom checkpoints."
|
|
3512
3718
|
)
|
|
3719
|
+
if self.api is None:
|
|
3720
|
+
raise ValueError("API is not initialized. Please provide .env file with 'API_TOKEN' and 'SERVER_ADDRESS' environment variables.")
|
|
3513
3721
|
file_info = self.api.file.get_info_by_path(team_id, checkpoint_path)
|
|
3514
3722
|
if not file_info:
|
|
3515
3723
|
raise ValueError(
|
|
@@ -3517,26 +3725,46 @@ class Inference:
|
|
|
3517
3725
|
)
|
|
3518
3726
|
need_download = True
|
|
3519
3727
|
|
|
3728
|
+
if not need_download:
|
|
3729
|
+
try:
|
|
3730
|
+
# Read data from checkpoint
|
|
3731
|
+
logger.debug(f"Reading data from checkpoint: {checkpoint_path}")
|
|
3732
|
+
import torch # pylint: disable=import-error
|
|
3733
|
+
checkpoint = torch.load(checkpoint_path)
|
|
3734
|
+
model_info = checkpoint["model_info"]
|
|
3735
|
+
model_files = self._extract_model_files_from_checkpoint(checkpoint_path)
|
|
3736
|
+
model_meta = os.path.join(self.model_dir, "model_meta.json")
|
|
3737
|
+
model_info["model_meta"] = self._load_json_file(model_meta)
|
|
3738
|
+
model_files["checkpoint"] = checkpoint_path
|
|
3739
|
+
need_download = False
|
|
3740
|
+
return model_files, model_source, model_info, need_download
|
|
3741
|
+
except Exception as e:
|
|
3742
|
+
logger.debug(f"Failed to read data from checkpoint: {repr(e)}")
|
|
3743
|
+
|
|
3520
3744
|
artifacts_dir = os.path.dirname(os.path.dirname(checkpoint_path))
|
|
3521
3745
|
if not need_download:
|
|
3746
|
+
logger.debug(f"Looking for data in artifacts: '{artifacts_dir}'")
|
|
3522
3747
|
model_info, original_model_files = _load_experiment_info(artifacts_dir)
|
|
3523
3748
|
model_files = _prepare_local_model_files(
|
|
3524
3749
|
artifacts_dir, checkpoint_path, original_model_files
|
|
3525
3750
|
)
|
|
3526
|
-
|
|
3751
|
+
logger.debug(f"Data was found in artifacts directory: '{artifacts_dir}'")
|
|
3527
3752
|
else:
|
|
3753
|
+
logger.debug(f"Downloading data from remote directory: '{artifacts_dir}'")
|
|
3528
3754
|
local_artifacts_dir = os.path.join(
|
|
3529
|
-
self.model_dir, "
|
|
3755
|
+
self.model_dir, "cli_deploy", os.path.basename(artifacts_dir)
|
|
3530
3756
|
)
|
|
3531
3757
|
_download_remote_files(team_id, artifacts_dir, local_artifacts_dir)
|
|
3532
|
-
|
|
3533
3758
|
model_info, original_model_files = _load_experiment_info(local_artifacts_dir)
|
|
3534
3759
|
model_files = _prepare_local_model_files(
|
|
3535
3760
|
local_artifacts_dir, checkpoint_path, original_model_files
|
|
3536
3761
|
)
|
|
3762
|
+
logger.debug(f"Data was downloaded from remote directory: '{artifacts_dir}'")
|
|
3763
|
+
logger.debug("Custom model params were successfully parsed from args")
|
|
3537
3764
|
return model_files, model_source, model_info, need_download
|
|
3538
3765
|
|
|
3539
3766
|
def _get_deploy_params_from_args(self):
|
|
3767
|
+
logger.debug("Getting deploy params from args")
|
|
3540
3768
|
# Ensure model directory exists
|
|
3541
3769
|
device = self._args.device if self._args.device else "cuda:0"
|
|
3542
3770
|
runtime = self._args.runtime if self._args.runtime else RuntimeType.PYTORCH
|
|
@@ -3563,7 +3791,6 @@ class Inference:
|
|
|
3563
3791
|
"device": device,
|
|
3564
3792
|
"runtime": runtime,
|
|
3565
3793
|
}
|
|
3566
|
-
|
|
3567
3794
|
logger.debug(f"Deploy parameters: {deploy_params}")
|
|
3568
3795
|
return deploy_params, need_download
|
|
3569
3796
|
|
|
@@ -3572,6 +3799,18 @@ class Inference:
|
|
|
3572
3799
|
self._uvicorn_server = uvicorn.Server(config)
|
|
3573
3800
|
self._uvicorn_server.run()
|
|
3574
3801
|
|
|
3802
|
+
def _run_server_in_thread(self):
|
|
3803
|
+
"""Run Uvicorn server in a separate thread so that this method doesn't block the caller."""
|
|
3804
|
+
import threading
|
|
3805
|
+
|
|
3806
|
+
def _serve():
|
|
3807
|
+
config = uvicorn.Config(app=self._app, host="0.0.0.0", port=8000, ws="websockets")
|
|
3808
|
+
self._uvicorn_server = uvicorn.Server(config)
|
|
3809
|
+
self._uvicorn_server.run()
|
|
3810
|
+
|
|
3811
|
+
self._server_thread = threading.Thread(target=_serve, daemon=True)
|
|
3812
|
+
self._server_thread.start()
|
|
3813
|
+
|
|
3575
3814
|
def _read_settings(self, settings: Union[str, Dict[str, Any]]):
|
|
3576
3815
|
if isinstance(settings, dict):
|
|
3577
3816
|
return settings
|
|
@@ -3598,7 +3837,8 @@ class Inference:
|
|
|
3598
3837
|
f"Inference settings doesn't have key: '{key}'. Available keys are: '{acceptable_keys}'"
|
|
3599
3838
|
)
|
|
3600
3839
|
|
|
3601
|
-
def
|
|
3840
|
+
def _inference_by_cli_deploy_args(self):
|
|
3841
|
+
logger.debug("Starting inference by CLI deploy args")
|
|
3602
3842
|
missing_env_message = "Set 'SERVER_ADDRESS' and 'API_TOKEN' environment variables to predict data on Supervisely platform."
|
|
3603
3843
|
|
|
3604
3844
|
def predict_project_id_by_args(
|
|
@@ -3612,14 +3852,13 @@ class Inference:
|
|
|
3612
3852
|
):
|
|
3613
3853
|
if self.api is None:
|
|
3614
3854
|
raise ValueError(missing_env_message)
|
|
3855
|
+
if draw:
|
|
3856
|
+
raise ValueError("Draw visualization is not supported for project inference")
|
|
3615
3857
|
|
|
3616
3858
|
if dataset_ids:
|
|
3617
|
-
logger.info(f"Predicting
|
|
3859
|
+
logger.info(f"Predicting Dataset(s) by ID(s): '{', '.join(str(dataset_id) for dataset_id in dataset_ids)}'")
|
|
3618
3860
|
else:
|
|
3619
|
-
logger.info(f"Predicting
|
|
3620
|
-
|
|
3621
|
-
if draw:
|
|
3622
|
-
raise ValueError("Draw visualization is not supported for project inference")
|
|
3861
|
+
logger.info(f"Predicting Project by ID: {project_id}")
|
|
3623
3862
|
|
|
3624
3863
|
state = {
|
|
3625
3864
|
"projectId": project_id,
|
|
@@ -3659,6 +3898,7 @@ class Inference:
|
|
|
3659
3898
|
draw: bool = False,
|
|
3660
3899
|
upload: bool = False,
|
|
3661
3900
|
):
|
|
3901
|
+
logger.info(f"Predicting Dataset(s) by ID(s): {', '.join(str(dataset_id) for dataset_id in dataset_ids)}")
|
|
3662
3902
|
if draw:
|
|
3663
3903
|
raise ValueError("Draw visualization is not supported for dataset inference")
|
|
3664
3904
|
if self.api is None:
|
|
@@ -3682,7 +3922,7 @@ class Inference:
|
|
|
3682
3922
|
if self.api is None:
|
|
3683
3923
|
raise ValueError(missing_env_message)
|
|
3684
3924
|
|
|
3685
|
-
logger.info(f"Predicting
|
|
3925
|
+
logger.info(f"Predicting Image by ID: {image_id}")
|
|
3686
3926
|
|
|
3687
3927
|
def predict_image_np(image_np):
|
|
3688
3928
|
anns, _ = self._inference_auto([image_np], settings)
|
|
@@ -3719,8 +3959,7 @@ class Inference:
|
|
|
3719
3959
|
output_dir: str = "./predictions",
|
|
3720
3960
|
draw: bool = False,
|
|
3721
3961
|
):
|
|
3722
|
-
logger.info(f"Predicting
|
|
3723
|
-
|
|
3962
|
+
logger.info(f"Predicting Local Data: {input_path}")
|
|
3724
3963
|
def postprocess_image(image_path: str, ann: Annotation, pred_dir: str = None):
|
|
3725
3964
|
image_name = sly_fs.get_file_name_with_ext(image_path)
|
|
3726
3965
|
if pred_dir is not None:
|
|
@@ -259,7 +259,7 @@ class TrainGUI:
|
|
|
259
259
|
self.workspace_id = sly_env.workspace_id(raise_not_found=False)
|
|
260
260
|
self.project_id = sly_env.project_id()
|
|
261
261
|
self.project_info = self._api.project.get_info_by_id(self.project_id)
|
|
262
|
-
if self.project_info
|
|
262
|
+
if self.project_info is None:
|
|
263
263
|
raise ValueError(f"Project with ID: '{self.project_id}' does not exist or was archived")
|
|
264
264
|
|
|
265
265
|
self.project_meta = ProjectMeta.from_json(self._api.project.get_meta(self.project_id))
|
|
@@ -1667,26 +1667,25 @@ class TrainApp:
|
|
|
1667
1667
|
checkpoint_name = sly_fs.get_file_name_with_ext(checkpoint_path)
|
|
1668
1668
|
new_checkpoint_path = join(self._output_checkpoints_dir, checkpoint_name)
|
|
1669
1669
|
shutil.move(checkpoint_path, new_checkpoint_path)
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
continue
|
|
1670
|
+
try:
|
|
1671
|
+
# pylint: disable=import-error
|
|
1672
|
+
import torch
|
|
1673
|
+
state_dict = torch.load(new_checkpoint_path)
|
|
1674
|
+
state_dict["model_info"] = {
|
|
1675
|
+
"task_id": self.task_id,
|
|
1676
|
+
"model_name": experiment_info["model_name"],
|
|
1677
|
+
"framework": self.framework_name,
|
|
1678
|
+
"checkpoint": checkpoint_name,
|
|
1679
|
+
"experiment": self.gui.training_process.get_experiment_name(),
|
|
1680
|
+
}
|
|
1681
|
+
state_dict["model_meta"] = model_meta.to_json()
|
|
1682
|
+
state_dict["model_files"] = ckpt_files
|
|
1683
|
+
torch.save(state_dict, new_checkpoint_path)
|
|
1684
|
+
except Exception as e:
|
|
1685
|
+
logger.warning(
|
|
1686
|
+
f"Error writing info to checkpoint: '{checkpoint_name}'. Error:{e}"
|
|
1687
|
+
)
|
|
1688
|
+
continue
|
|
1690
1689
|
|
|
1691
1690
|
new_checkpoint_paths.append(new_checkpoint_path)
|
|
1692
1691
|
if sly_fs.get_file_name_with_ext(checkpoint_path) == best_checkpoints_name:
|
|
@@ -329,7 +329,7 @@ docker image for the corresponding model's framework, and run the `docker run` c
|
|
|
329
329
|
2. Pull the Docker image
|
|
330
330
|
|
|
331
331
|
```bash
|
|
332
|
-
docker pull {{ code.docker.
|
|
332
|
+
docker pull {{ code.docker.deploy }}
|
|
333
333
|
```
|
|
334
334
|
|
|
335
335
|
3. Run the Docker container
|
|
@@ -339,7 +339,7 @@ docker image for the corresponding model's framework, and run the `docker run` c
|
|
|
339
339
|
--runtime=nvidia \
|
|
340
340
|
-v "./{{ experiment.paths.experiment_dir.path }}:/model" \ # Mount the experiment directory to the container
|
|
341
341
|
-p 8000:8000 \
|
|
342
|
-
{{ code.docker.
|
|
342
|
+
{{ code.docker.deploy }} \
|
|
343
343
|
deploy \
|
|
344
344
|
--model "/model/checkpoints/{{ experiment.training.checkpoints.pytorch.name }}" \
|
|
345
345
|
--device "cuda:0"
|
|
@@ -371,7 +371,7 @@ docker run \
|
|
|
371
371
|
--runtime=nvidia \
|
|
372
372
|
-v "./{{ experiment.paths.experiment_dir.path }}:/model" \
|
|
373
373
|
-p 8000:8000 \
|
|
374
|
-
{{ code.docker.
|
|
374
|
+
{{ code.docker.deploy }} \
|
|
375
375
|
predict \
|
|
376
376
|
"./image.jpg" \ # Put your image/video/directory here
|
|
377
377
|
--model "/model/checkpoints/{{ experiment.training.checkpoints.pytorch.name }}" \
|
|
@@ -416,7 +416,7 @@ This approach helps you to quickly set up the environment and run inference with
|
|
|
416
416
|
)
|
|
417
417
|
|
|
418
418
|
# Predict
|
|
419
|
-
predictions = model
|
|
419
|
+
predictions = model(
|
|
420
420
|
# 'input' can accept various formats: image paths, np.arrays, Supervisely IDs and others.
|
|
421
421
|
input=["path/to/image1.jpg", "path/to/image2.jpg"],
|
|
422
422
|
conf=0.5, # confidence threshold
|
|
@@ -138,7 +138,7 @@ class ExperimentGenerator(BaseGenerator):
|
|
|
138
138
|
pytorch_demo, onnx_demo, trt_demo = self._get_demo_scripts()
|
|
139
139
|
|
|
140
140
|
return {
|
|
141
|
-
"docker": {"image": docker_image},
|
|
141
|
+
"docker": {"image": docker_image, "deploy": f"{docker_image}-deploy"},
|
|
142
142
|
"local_prediction": {
|
|
143
143
|
"repo": repo_info,
|
|
144
144
|
"serving_module": (
|
|
@@ -576,7 +576,7 @@ supervisely/collection/key_indexed_collection.py,sha256=x2UVlkprspWhhae9oLUzjTWB
|
|
|
576
576
|
supervisely/collection/str_enum.py,sha256=Zp29yFGvnxC6oJRYNNlXhO2lTSdsriU1wiGHj6ahEJE,1250
|
|
577
577
|
supervisely/convert/__init__.py,sha256=ropgB1eebG2bfLoJyf2jp8Vv9UkFujaW3jVX-71ho1g,1353
|
|
578
578
|
supervisely/convert/base_converter.py,sha256=bc-QlT7kliHxrhM0bdHzgNVSfzDGgecrmaZH_nFZsL0,18597
|
|
579
|
-
supervisely/convert/converter.py,sha256=
|
|
579
|
+
supervisely/convert/converter.py,sha256=aOURdIdWWbK2JT5X-kUr8JfAatr1NUkwnv1mAmFS5y0,11426
|
|
580
580
|
supervisely/convert/image/__init__.py,sha256=JEuyaBiiyiYmEUYqdn8Mog5FVXpz0H1zFubKkOOm73I,1395
|
|
581
581
|
supervisely/convert/image/image_converter.py,sha256=8vak8ZoKTN1ye2ZmCTvCZ605-Rw1AFLIEo7bJMfnR68,10426
|
|
582
582
|
supervisely/convert/image/image_helper.py,sha256=VfFJmMEdMTOZ-G15lFEYUuFC0z62aHWrw8MLigxJS58,3647
|
|
@@ -618,7 +618,7 @@ supervisely/convert/image/pdf/pdf_helper.py,sha256=IDwLEvsVy8lu-KC1lXvSRkZZ9BCC6
|
|
|
618
618
|
supervisely/convert/image/sly/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
619
619
|
supervisely/convert/image/sly/fast_sly_image_converter.py,sha256=r_Nhowicm-oah-XfGEeAOrGNbIzMh63m6ZRYaLKHUu0,5903
|
|
620
620
|
supervisely/convert/image/sly/sly_image_converter.py,sha256=dT7fVivM-u2hhKehGJWPeLsVTi4nW-WX1X6Lktl2mks,14812
|
|
621
|
-
supervisely/convert/image/sly/sly_image_helper.py,sha256=
|
|
621
|
+
supervisely/convert/image/sly/sly_image_helper.py,sha256=8zSWtLlF5fZUaR8UMUqqEvLqyz8HrsDxfb5AcwYW3Qs,7385
|
|
622
622
|
supervisely/convert/image/yolo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
623
623
|
supervisely/convert/image/yolo/yolo_converter.py,sha256=Wn5dR05y4SEPONcaxWr9ofnbvbf-SbRZN0fkksk5Dps,11391
|
|
624
624
|
supervisely/convert/image/yolo/yolo_helper.py,sha256=5b0ShsVlqikA071VT8AiRW_079_WD6pdB5Bx3OU12Bw,25989
|
|
@@ -675,7 +675,7 @@ supervisely/convert/volume/dicom/dicom_converter.py,sha256=Hw4RxU_qvllk6M26udZE6
|
|
|
675
675
|
supervisely/convert/volume/dicom/dicom_helper.py,sha256=OrKlyt1hA5BOXKhE1LF1WxBIv3b6t96xRras4OSAuNM,2891
|
|
676
676
|
supervisely/convert/volume/nii/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
677
677
|
supervisely/convert/volume/nii/nii_planes_volume_converter.py,sha256=QTdmtqLrRBFSa0IZKhAnFkLl1J3nayzQQDwpglvEN64,16915
|
|
678
|
-
supervisely/convert/volume/nii/nii_volume_converter.py,sha256=
|
|
678
|
+
supervisely/convert/volume/nii/nii_volume_converter.py,sha256=gR1_dfUf0L-K49B8qVHF7DiiDKDmxUQKKSPLdlqoYC4,8691
|
|
679
679
|
supervisely/convert/volume/nii/nii_volume_helper.py,sha256=nkfTG2NGmnf4AfrZ0lULSHaUBx1G24NJUO_5FNejolE,16032
|
|
680
680
|
supervisely/convert/volume/sly/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
681
681
|
supervisely/convert/volume/sly/sly_volume_converter.py,sha256=TI1i_aVYFFoqLHqVzCXnFeR6xobhGcgN_xWFZcpRqbE,6730
|
|
@@ -723,9 +723,9 @@ supervisely/imaging/font.py,sha256=0XcmWhlw7y2PAhrWgcsfInyRWj0WnlFpMSEXXilR8UA,2
|
|
|
723
723
|
supervisely/imaging/image.py,sha256=1KNc4qRbP9OlI4Yta07Kc2ohAgSBJ_9alF9Jag74w30,41873
|
|
724
724
|
supervisely/io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
725
725
|
supervisely/io/docker_utils.py,sha256=hb_HXGM8IYB0PF-nD7NxMwaHgzaxIFxofsUzQ_RCUZI,7935
|
|
726
|
-
supervisely/io/env.py,sha256=
|
|
726
|
+
supervisely/io/env.py,sha256=l-Xkil6FVxMP8FmnjF4H4p3RJQ3AoBd0OUjZHA2QVTc,21193
|
|
727
727
|
supervisely/io/exception_handlers.py,sha256=_nAgMFeE94bCxEvWakR82hMtdOJUyn7Gc7OymMxI9WI,36484
|
|
728
|
-
supervisely/io/fs.py,sha256=
|
|
728
|
+
supervisely/io/fs.py,sha256=pzNAK5fbT3G-7PKRY5oYcOPjgXeZ9x5Dyry7fzzZsr8,63604
|
|
729
729
|
supervisely/io/fs_cache.py,sha256=985gvBGzveLcDudgz10E4EWVjP9jxdU1Pa0GFfCBoCA,6520
|
|
730
730
|
supervisely/io/github_utils.py,sha256=jGmvQJ5bjtACuSFABzrxL0jJdh14SezovrHp8T-9y8g,1779
|
|
731
731
|
supervisely/io/json.py,sha256=25gBqA8nkKZW1xvssdmRYuJrO5fmIR0Z5cZGePfrJV4,8539
|
|
@@ -893,7 +893,7 @@ supervisely/nn/benchmark/visualization/widgets/table/__init__.py,sha256=47DEQpj8
|
|
|
893
893
|
supervisely/nn/benchmark/visualization/widgets/table/table.py,sha256=atmDnF1Af6qLQBUjLhK18RMDKAYlxnsuVHMSEa5a-e8,4319
|
|
894
894
|
supervisely/nn/inference/__init__.py,sha256=QFukX2ip-U7263aEPCF_UCFwj6EujbMnsgrXp5Bbt8I,1623
|
|
895
895
|
supervisely/nn/inference/cache.py,sha256=yqVPIWzhIDRHwrCIpdm-gPxUM2rH8BD98omF659RElw,34938
|
|
896
|
-
supervisely/nn/inference/inference.py,sha256=
|
|
896
|
+
supervisely/nn/inference/inference.py,sha256=L14M8qGofz6EGrgJvGMcz0h3vsu-AnHPeL_iUO8Kf3Y,195721
|
|
897
897
|
supervisely/nn/inference/inference_request.py,sha256=y6yw0vbaRRcEBS27nq3y0sL6Gmq2qLA_Bm0GrnJGegE,14267
|
|
898
898
|
supervisely/nn/inference/session.py,sha256=dIg2F-OBl68pUzcmtmcI0YQIp1WWNnrJTVMjwFN91Q4,35824
|
|
899
899
|
supervisely/nn/inference/uploader.py,sha256=21a9coOimCHhEqAbV-llZWcp12847DEMoQp3N16bpK0,5425
|
|
@@ -999,10 +999,10 @@ supervisely/nn/tracking/__init__.py,sha256=Ld1ed7ZZQZPkhX-5Xr-UbHZx5zLCm2-tInHnP
|
|
|
999
999
|
supervisely/nn/tracking/boxmot.py,sha256=H9cQjYGL9nX_TLrfKDChhljTIiE9lffcgbwWCf_4PJU,4277
|
|
1000
1000
|
supervisely/nn/tracking/tracking.py,sha256=WNrNm02B1pspA3d_AmzSJ-54RZTqWV2NZiC7FHe88bo,857
|
|
1001
1001
|
supervisely/nn/training/__init__.py,sha256=gY4PCykJ-42MWKsqb9kl-skemKa8yB6t_fb5kzqR66U,111
|
|
1002
|
-
supervisely/nn/training/train_app.py,sha256=
|
|
1002
|
+
supervisely/nn/training/train_app.py,sha256=mPSCxcAvw5k_YzyaztvOmUr26ni6J624LIIb_Zxa-9g,123596
|
|
1003
1003
|
supervisely/nn/training/gui/__init__.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
|
|
1004
1004
|
supervisely/nn/training/gui/classes_selector.py,sha256=tqmVwUfC2u5K53mZmvDvNOhu9Mw5mddjpB2kxRXXUO8,12453
|
|
1005
|
-
supervisely/nn/training/gui/gui.py,sha256=
|
|
1005
|
+
supervisely/nn/training/gui/gui.py,sha256=RLCVtKefWYPHlPN-U8iyAdPHH6Qvx6HE3fFCqyq3rZ4,49210
|
|
1006
1006
|
supervisely/nn/training/gui/hyperparameters_selector.py,sha256=bcCxJ9-8NjZa0U9XWHysrMzr8dxqXiqUgX5lbDiAm5A,7767
|
|
1007
1007
|
supervisely/nn/training/gui/input_selector.py,sha256=rmirJzpdxuYONI6y5_cvMdGWBJ--T20YTsISghATHu4,2510
|
|
1008
1008
|
supervisely/nn/training/gui/model_selector.py,sha256=Fvsja7n75PzqxDkDhPEkCltYsbAPPRpUxgWgIZCseks,7439
|
|
@@ -1065,8 +1065,8 @@ supervisely/template/base_generator.py,sha256=3nesbfRpueyRYljQSTnkMjeC8ERTOfjI88
|
|
|
1065
1065
|
supervisely/template/extensions.py,sha256=kTYxu_LrvFyUN3HByCebGq8ra7zUygcEyw4qTUHq3M4,5255
|
|
1066
1066
|
supervisely/template/template_renderer.py,sha256=SzGxRdbP59uxqcZT8kZbaHN2epK8Vjfh-0jKBpkdCBY,9709
|
|
1067
1067
|
supervisely/template/experiment/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
1068
|
-
supervisely/template/experiment/experiment.html.jinja,sha256=
|
|
1069
|
-
supervisely/template/experiment/experiment_generator.py,sha256=
|
|
1068
|
+
supervisely/template/experiment/experiment.html.jinja,sha256=vU-mI0Tp_PO5Qy_iiuJFoHUAK4eFqe0QXfpG9hDbf6Y,17613
|
|
1069
|
+
supervisely/template/experiment/experiment_generator.py,sha256=3R_yeoMX5qjskE7GBSUFE_oYJ0RAgLAeHvMRlJ0SYQY,37425
|
|
1070
1070
|
supervisely/template/experiment/header.html.jinja,sha256=vm0XfXoMBU6nvHPrhX9k4OkkKkmu69OJFGWYvsRTrcs,12801
|
|
1071
1071
|
supervisely/template/experiment/sidebar.html.jinja,sha256=4IxuJzcU1OT93mXMixE7EAMYfcn_lOVfCjS3VkEieSk,9323
|
|
1072
1072
|
supervisely/template/experiment/sly-style.css,sha256=cl_wJfM-KOL0DumW5vdyLavF7mc6_hb9kh15qhD7MqM,8344
|
|
@@ -1114,9 +1114,9 @@ supervisely/worker_proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
|
|
|
1114
1114
|
supervisely/worker_proto/worker_api_pb2.py,sha256=VQfi5JRBHs2pFCK1snec3JECgGnua3Xjqw_-b3aFxuM,59142
|
|
1115
1115
|
supervisely/worker_proto/worker_api_pb2_grpc.py,sha256=3BwQXOaP9qpdi0Dt9EKG--Lm8KGN0C5AgmUfRv77_Jk,28940
|
|
1116
1116
|
supervisely_lib/__init__.py,sha256=7-3QnN8Zf0wj8NCr2oJmqoQWMKKPKTECvjH9pd2S5vY,159
|
|
1117
|
-
supervisely-6.73.
|
|
1118
|
-
supervisely-6.73.
|
|
1119
|
-
supervisely-6.73.
|
|
1120
|
-
supervisely-6.73.
|
|
1121
|
-
supervisely-6.73.
|
|
1122
|
-
supervisely-6.73.
|
|
1117
|
+
supervisely-6.73.396.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
1118
|
+
supervisely-6.73.396.dist-info/METADATA,sha256=IvMoQjk-TwkKaKU3kEJ39kiZRrQqsFO0nBk0-7SxHuA,35254
|
|
1119
|
+
supervisely-6.73.396.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
|
|
1120
|
+
supervisely-6.73.396.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
|
|
1121
|
+
supervisely-6.73.396.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
|
|
1122
|
+
supervisely-6.73.396.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|