supervisely 6.73.357__py3-none-any.whl → 6.73.359__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/_utils.py +12 -0
- supervisely/api/annotation_api.py +3 -0
- supervisely/api/api.py +2 -2
- supervisely/api/app_api.py +27 -2
- supervisely/api/entity_annotation/tag_api.py +0 -1
- supervisely/api/nn/__init__.py +0 -0
- supervisely/api/nn/deploy_api.py +821 -0
- supervisely/api/nn/neural_network_api.py +248 -0
- supervisely/api/task_api.py +26 -467
- supervisely/app/fastapi/subapp.py +1 -0
- supervisely/nn/__init__.py +2 -1
- supervisely/nn/artifacts/artifacts.py +5 -5
- supervisely/nn/benchmark/object_detection/metric_provider.py +3 -0
- supervisely/nn/experiments.py +28 -5
- supervisely/nn/inference/cache.py +178 -114
- supervisely/nn/inference/gui/gui.py +18 -35
- supervisely/nn/inference/gui/serving_gui.py +3 -1
- supervisely/nn/inference/inference.py +1421 -1265
- supervisely/nn/inference/inference_request.py +412 -0
- supervisely/nn/inference/object_detection_3d/object_detection_3d.py +31 -24
- supervisely/nn/inference/session.py +2 -2
- supervisely/nn/inference/tracking/base_tracking.py +45 -79
- supervisely/nn/inference/tracking/bbox_tracking.py +220 -155
- supervisely/nn/inference/tracking/mask_tracking.py +274 -250
- supervisely/nn/inference/tracking/tracker_interface.py +23 -0
- supervisely/nn/inference/uploader.py +164 -0
- supervisely/nn/model/__init__.py +0 -0
- supervisely/nn/model/model_api.py +259 -0
- supervisely/nn/model/prediction.py +311 -0
- supervisely/nn/model/prediction_session.py +632 -0
- supervisely/nn/tracking/__init__.py +1 -0
- supervisely/nn/tracking/boxmot.py +114 -0
- supervisely/nn/tracking/tracking.py +24 -0
- supervisely/nn/training/train_app.py +61 -19
- supervisely/nn/utils.py +43 -3
- supervisely/task/progress.py +12 -2
- supervisely/video/video.py +107 -1
- {supervisely-6.73.357.dist-info → supervisely-6.73.359.dist-info}/METADATA +2 -1
- {supervisely-6.73.357.dist-info → supervisely-6.73.359.dist-info}/RECORD +43 -32
- supervisely/api/neural_network_api.py +0 -202
- {supervisely-6.73.357.dist-info → supervisely-6.73.359.dist-info}/LICENSE +0 -0
- {supervisely-6.73.357.dist-info → supervisely-6.73.359.dist-info}/WHEEL +0 -0
- {supervisely-6.73.357.dist-info → supervisely-6.73.359.dist-info}/entry_points.txt +0 -0
- {supervisely-6.73.357.dist-info → supervisely-6.73.359.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Dict, List
|
|
4
|
+
|
|
5
|
+
import supervisely.io.env as sly_env
|
|
6
|
+
import supervisely.io.env as env
|
|
7
|
+
from supervisely.sly_logger import logger
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class NeuralNetworkApi:
|
|
11
|
+
"""
|
|
12
|
+
API to interact with neural networks in Supervisely.
|
|
13
|
+
It provides methods to deploy and connect to models for running inference.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, api: "Api"):
|
|
17
|
+
from supervisely.api.nn.deploy_api import DeployApi
|
|
18
|
+
|
|
19
|
+
self._api = api
|
|
20
|
+
self._deploy_api = DeployApi(api)
|
|
21
|
+
|
|
22
|
+
def deploy(
|
|
23
|
+
self,
|
|
24
|
+
model: str,
|
|
25
|
+
device: str = None,
|
|
26
|
+
runtime: str = None,
|
|
27
|
+
workspace_id: int = None,
|
|
28
|
+
agent_id: int = None,
|
|
29
|
+
**kwargs,
|
|
30
|
+
) -> "ModelAPI":
|
|
31
|
+
"""
|
|
32
|
+
Deploy a pretrained model or a custom model checkpoint in Supervisely platform.
|
|
33
|
+
This method will start a new Serving App in Supervisely, deploy a given model, and return a `ModelAPI` object for running predictions and managing the model.
|
|
34
|
+
- To deploy a pretrained model, pass the model name in the format `framework/model_name` (e.g., "RT-DETRv2/RT-DETRv2-M").
|
|
35
|
+
- To deploy a custom model, pass the path to the model checkpoint in team files (e.g., "/experiments/1089_RT-DETRv2/checkpoints/best.pt").
|
|
36
|
+
|
|
37
|
+
:param model: Either a path to a model checkpoint in team files or model name in format `framework/model_name` (e.g., "RT-DETRv2/RT-DETRv2-M").
|
|
38
|
+
:type model: str
|
|
39
|
+
:param device: Device to run the model on (e.g., "cuda:0" or "cpu"). If not specified, will automatically use GPU device if available, otherwise CPU will be used.
|
|
40
|
+
:type device: Optional[str]
|
|
41
|
+
:param runtime: If specified, the model will be converted to the given format (e.g., "onnx", "tensorrt") and will be deployed in the corresponding accelerated runtime. This option is used for pretrained models. For custom models, the runtime will be defined automatically based on the model checkpoint.
|
|
42
|
+
:type runtime: Optional[str]
|
|
43
|
+
:param workspace_id: Workspace ID, if None, will be got from env.
|
|
44
|
+
:type workspace_id: Optional[int]
|
|
45
|
+
:param agent_id: Agent ID, if not present will be defined automatically.
|
|
46
|
+
:type agent_id: Optional[int]
|
|
47
|
+
:param kwargs: Additional parameters for deployment.
|
|
48
|
+
:return: A :class:`ModelAPI` object for the deployed model.
|
|
49
|
+
:rtype: ModelAPI
|
|
50
|
+
:Usage example:
|
|
51
|
+
.. code-block:: python
|
|
52
|
+
|
|
53
|
+
import supervisely as sly
|
|
54
|
+
|
|
55
|
+
api = sly.Api()
|
|
56
|
+
model = api.nn.deploy(model="RT-DETRv2/RT-DETRv2-M")
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
from supervisely.nn.model.model_api import ModelAPI
|
|
60
|
+
|
|
61
|
+
checkpoint = None
|
|
62
|
+
pretrained = None
|
|
63
|
+
team_id = None
|
|
64
|
+
if workspace_id is None:
|
|
65
|
+
workspace_id = sly_env.workspace_id(raise_not_found=False)
|
|
66
|
+
if workspace_id is None:
|
|
67
|
+
raise ValueError(
|
|
68
|
+
"Workspace ID is not specified. Please, provide it in the function call, or set 'WORKSPACE_ID' variable in the environment."
|
|
69
|
+
)
|
|
70
|
+
if team_id is None:
|
|
71
|
+
workspace_info = self._api.workspace.get_info_by_id(workspace_id)
|
|
72
|
+
team_id = workspace_info.team_id
|
|
73
|
+
if agent_id is None:
|
|
74
|
+
agent_id = self._deploy_api._find_agent(team_id)
|
|
75
|
+
|
|
76
|
+
if model.startswith("/"):
|
|
77
|
+
checkpoint = model
|
|
78
|
+
else:
|
|
79
|
+
found_team_id = self._deploy_api._find_team_by_path(
|
|
80
|
+
f"/{model}", team_id=team_id, raise_not_found=False
|
|
81
|
+
)
|
|
82
|
+
if found_team_id is not None:
|
|
83
|
+
checkpoint = f"/{model}"
|
|
84
|
+
team_id = found_team_id
|
|
85
|
+
logger.debug(f"Found checkpoint in team {team_id}")
|
|
86
|
+
else:
|
|
87
|
+
pretrained = model
|
|
88
|
+
|
|
89
|
+
if checkpoint is not None:
|
|
90
|
+
logger.debug(f"Deploying model by checkpoint: {checkpoint}")
|
|
91
|
+
task_info = self._deploy_api.deploy_custom_model_by_checkpoint(
|
|
92
|
+
checkpoint=checkpoint,
|
|
93
|
+
device=device,
|
|
94
|
+
runtime=runtime,
|
|
95
|
+
team_id=team_id,
|
|
96
|
+
workspace_id=workspace_id,
|
|
97
|
+
agent_id=agent_id,
|
|
98
|
+
**kwargs,
|
|
99
|
+
)
|
|
100
|
+
else:
|
|
101
|
+
framework, model_name = pretrained.split("/", 1)
|
|
102
|
+
logger.debug(
|
|
103
|
+
f"Deploying pretrained model. Framework: {framework}, Model name: {model_name}"
|
|
104
|
+
)
|
|
105
|
+
task_info = self._deploy_api.deploy_pretrained_model(
|
|
106
|
+
framework=framework,
|
|
107
|
+
model_name=model_name,
|
|
108
|
+
device=device,
|
|
109
|
+
runtime=runtime,
|
|
110
|
+
workspace_id=workspace_id,
|
|
111
|
+
agent_id=agent_id,
|
|
112
|
+
**kwargs,
|
|
113
|
+
)
|
|
114
|
+
return ModelAPI(self._api, task_id=task_info["id"])
|
|
115
|
+
|
|
116
|
+
def list_deployed_models(
|
|
117
|
+
self,
|
|
118
|
+
model: str = None,
|
|
119
|
+
framework: str = None,
|
|
120
|
+
task_type: str = None,
|
|
121
|
+
team_id: int = None,
|
|
122
|
+
workspace_id: int = None,
|
|
123
|
+
) -> List[Dict]:
|
|
124
|
+
"""
|
|
125
|
+
Returns a list of deployed models in the Supervisely platform.
|
|
126
|
+
The list can be filtered by model name, framework, task type, team ID, and workspace ID.
|
|
127
|
+
|
|
128
|
+
:param model: Model name or checkpoint path to filter the results. If None, all models will be returned.
|
|
129
|
+
:type model: Optional[str]
|
|
130
|
+
:param framework: Framework name to filter the results. If None, all frameworks will be returned.
|
|
131
|
+
:type framework: Optional[str]
|
|
132
|
+
:param task_type: CV Task to filter the results, e.g., "object detection", "instance segmentation", etc. If None, all task types will be returned.
|
|
133
|
+
:type task_type: Optional[str]
|
|
134
|
+
:param team_id: Team ID to filter the results. If None, the team ID from the environment will be used.
|
|
135
|
+
:type team_id: Optional[int]
|
|
136
|
+
:param workspace_id: Workspace ID to filter the results. If None, the workspace ID from the environment will be used.
|
|
137
|
+
:type workspace_id: Optional[int]
|
|
138
|
+
:return: A list of dictionaries containing information about the deployed models.
|
|
139
|
+
:rtype: List[Dict]
|
|
140
|
+
:Usage example:
|
|
141
|
+
.. code-block:: python
|
|
142
|
+
|
|
143
|
+
import supervisely as sly
|
|
144
|
+
|
|
145
|
+
api = sly.Api()
|
|
146
|
+
deployed_models = api.nn.list_deployed_models(framework="RT-DETRv2")
|
|
147
|
+
"""
|
|
148
|
+
# 1. Define apps
|
|
149
|
+
categories = ["serve"]
|
|
150
|
+
if framework is not None:
|
|
151
|
+
categories.append(f"framework:{framework}")
|
|
152
|
+
serve_apps = self._api.app.get_list_ecosystem_modules(
|
|
153
|
+
categories=categories, categories_operation="and"
|
|
154
|
+
)
|
|
155
|
+
if not serve_apps:
|
|
156
|
+
return []
|
|
157
|
+
serve_apps_module_ids = {app["id"] for app in serve_apps}
|
|
158
|
+
# 2. Get tasks infos
|
|
159
|
+
if workspace_id is not None:
|
|
160
|
+
workspaces = [workspace_id]
|
|
161
|
+
elif team_id is not None:
|
|
162
|
+
workspaces = self._api.workspace.get_list(team_id)
|
|
163
|
+
workspaces = [workspace["id"] for workspace in workspaces]
|
|
164
|
+
else:
|
|
165
|
+
workspace_id = env.workspace_id(raise_not_found=False)
|
|
166
|
+
if workspace_id is None:
|
|
167
|
+
team_id = env.team_id(raise_not_found=False)
|
|
168
|
+
if team_id is None:
|
|
169
|
+
raise ValueError(
|
|
170
|
+
"Workspace ID and Team ID are not specified and cannot be found in the environment."
|
|
171
|
+
)
|
|
172
|
+
workspaces = self._api.workspace.get_list(team_id)
|
|
173
|
+
workspaces = [workspace["id"] for workspace in workspaces]
|
|
174
|
+
else:
|
|
175
|
+
workspaces = [workspace_id]
|
|
176
|
+
|
|
177
|
+
all_tasks = []
|
|
178
|
+
for workspace_id in workspaces:
|
|
179
|
+
all_tasks.extend(
|
|
180
|
+
self._api.task.get_list(
|
|
181
|
+
workspace_id=workspace_id,
|
|
182
|
+
filters=[
|
|
183
|
+
{
|
|
184
|
+
"field": "status",
|
|
185
|
+
"operator": "in",
|
|
186
|
+
"value": [str(self._api.task.Status.STARTED)],
|
|
187
|
+
}
|
|
188
|
+
],
|
|
189
|
+
)
|
|
190
|
+
)
|
|
191
|
+
all_tasks = [
|
|
192
|
+
task for task in all_tasks if task["meta"]["app"]["moduleId"] in serve_apps_module_ids
|
|
193
|
+
]
|
|
194
|
+
# get deploy infos and filter results
|
|
195
|
+
result = []
|
|
196
|
+
for task in all_tasks:
|
|
197
|
+
deploy_info = self._deploy_api.get_deploy_info(task["id"])
|
|
198
|
+
if model is not None:
|
|
199
|
+
checkpoint = deploy_info["checkpoint_name"]
|
|
200
|
+
deployed_model = deploy_info["model_name"]
|
|
201
|
+
if checkpoint != model and not model.endswith(deployed_model):
|
|
202
|
+
continue
|
|
203
|
+
if task_type is not None:
|
|
204
|
+
if deploy_info["task_type"] != task_type:
|
|
205
|
+
continue
|
|
206
|
+
result.append(
|
|
207
|
+
{
|
|
208
|
+
"task_info": task,
|
|
209
|
+
"model_info": deploy_info,
|
|
210
|
+
}
|
|
211
|
+
)
|
|
212
|
+
return result
|
|
213
|
+
|
|
214
|
+
def get_experiment_info(self, task_id: int) -> "ExperimentInfo":
|
|
215
|
+
"""
|
|
216
|
+
Returns the experiment info of a finished training task by its task_id.
|
|
217
|
+
|
|
218
|
+
:param task_id: the task_id of a finished training task in the Supervisely platform.
|
|
219
|
+
:type task_id: int
|
|
220
|
+
:return: an :class:`ExperimentInfo` object with information about the training, model, and results.
|
|
221
|
+
:rtype: ExperimentInfo
|
|
222
|
+
"""
|
|
223
|
+
from supervisely.nn.experiments import ExperimentInfo
|
|
224
|
+
|
|
225
|
+
task_info = self._api.task.get_info_by_id(task_id)
|
|
226
|
+
if task_info is None:
|
|
227
|
+
raise ValueError(f"Task with ID '{task_id}' not found")
|
|
228
|
+
try:
|
|
229
|
+
data = task_info["meta"]["output"]["experiment"]["data"]
|
|
230
|
+
return ExperimentInfo(**data)
|
|
231
|
+
except KeyError:
|
|
232
|
+
raise ValueError("Task output does not contain experiment data")
|
|
233
|
+
|
|
234
|
+
def connect(
|
|
235
|
+
self,
|
|
236
|
+
task_id: int,
|
|
237
|
+
) -> "ModelAPI":
|
|
238
|
+
"""
|
|
239
|
+
Connect to a running Serving App by its `task_id`. This allows you to make predictions and control the model state via API.
|
|
240
|
+
|
|
241
|
+
:param task_id: the task_id of a running Serving App session in the Supervisely platform.
|
|
242
|
+
:type task_id: int
|
|
243
|
+
:return: a :class:`ModelAPI` object
|
|
244
|
+
:rtype: ModelAPI
|
|
245
|
+
"""
|
|
246
|
+
from supervisely.nn.model.model_api import ModelAPI
|
|
247
|
+
|
|
248
|
+
return ModelAPI(self._api, task_id)
|