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
|
@@ -637,6 +637,29 @@ class TrackerInterfaceV2:
|
|
|
637
637
|
logger.info("Task stopped by user.", extra=self.log_extra)
|
|
638
638
|
self.stop()
|
|
639
639
|
|
|
640
|
+
def notify_error(self, exception: Exception):
|
|
641
|
+
logger.debug(f"Notify error: {str(exception)}", extra=self.log_extra)
|
|
642
|
+
error = type(exception).__name__
|
|
643
|
+
message = str(exception)
|
|
644
|
+
if self.direct_progress:
|
|
645
|
+
self.api.vid_ann_tool.set_direct_tracking_error(
|
|
646
|
+
self.session_id,
|
|
647
|
+
self.video_id,
|
|
648
|
+
self.track_id,
|
|
649
|
+
f"{type(exception).__name__}: {str(exception)}",
|
|
650
|
+
)
|
|
651
|
+
else:
|
|
652
|
+
self.api.video.notify_tracking_error(self.track_id, error, message)
|
|
653
|
+
|
|
654
|
+
def notify_warning(self, message: str):
|
|
655
|
+
logger.debug(f"Notify warning: {message}", extra=self.log_extra)
|
|
656
|
+
if self.direct_progress:
|
|
657
|
+
self.api.vid_ann_tool.set_direct_tracking_warning(
|
|
658
|
+
self.session_id, self.video_id, self.track_id, message
|
|
659
|
+
)
|
|
660
|
+
else:
|
|
661
|
+
self.api.video.notify_tracking_warning(self.track_id, self.video_id, message)
|
|
662
|
+
|
|
640
663
|
def _upload_exception_handler(self, exception: Exception):
|
|
641
664
|
logger.error(
|
|
642
665
|
"Error in upload loop: %s", str(exception), exc_info=True, extra=self.log_extra
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import threading
|
|
4
|
+
from logging import Logger
|
|
5
|
+
from queue import Empty, Queue
|
|
6
|
+
from types import TracebackType
|
|
7
|
+
from typing import Callable, Optional, Type
|
|
8
|
+
|
|
9
|
+
from supervisely.sly_logger import logger
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Uploader:
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
upload_f: Callable,
|
|
16
|
+
notify_f: Callable = None,
|
|
17
|
+
exception_handler: Callable = None,
|
|
18
|
+
logger: Logger = None,
|
|
19
|
+
):
|
|
20
|
+
self._upload_f = upload_f
|
|
21
|
+
self._notify_f = notify_f
|
|
22
|
+
self._exception_handler = exception_handler
|
|
23
|
+
if self._exception_handler is None:
|
|
24
|
+
self._exception_handler = self._default_exception_handler
|
|
25
|
+
self._logger = logger
|
|
26
|
+
self.exception = None
|
|
27
|
+
self._lock = threading.Lock()
|
|
28
|
+
self._q = Queue()
|
|
29
|
+
self._stop_event = threading.Event()
|
|
30
|
+
self._exception_event = threading.Event()
|
|
31
|
+
self._upload_thread = threading.Thread(
|
|
32
|
+
target=self._upload_loop,
|
|
33
|
+
daemon=True,
|
|
34
|
+
)
|
|
35
|
+
self.raise_from_notify = False
|
|
36
|
+
self._notify_thread = None
|
|
37
|
+
self._notify_q = Queue()
|
|
38
|
+
if self._notify_f is not None:
|
|
39
|
+
self._notify_thread = threading.Thread(target=self._notify_loop, daemon=True)
|
|
40
|
+
self._notify_thread.start()
|
|
41
|
+
self._upload_thread.start()
|
|
42
|
+
|
|
43
|
+
def _notify_loop(self):
|
|
44
|
+
try:
|
|
45
|
+
while (
|
|
46
|
+
not self._stop_event.is_set() or not self._notify_q.empty() or not self._q.empty()
|
|
47
|
+
):
|
|
48
|
+
if self._exception_event.is_set():
|
|
49
|
+
return
|
|
50
|
+
items = []
|
|
51
|
+
try:
|
|
52
|
+
timeout = 0.1 if self._stop_event.is_set() else 1.0
|
|
53
|
+
item = self._notify_q.get(timeout=timeout)
|
|
54
|
+
items.append(item)
|
|
55
|
+
while True:
|
|
56
|
+
try:
|
|
57
|
+
items.append(self._notify_q.get_nowait())
|
|
58
|
+
except Empty:
|
|
59
|
+
break
|
|
60
|
+
if items:
|
|
61
|
+
self._notify_f(items)
|
|
62
|
+
|
|
63
|
+
for _ in range(len(items)):
|
|
64
|
+
self._notify_q.task_done()
|
|
65
|
+
except Empty:
|
|
66
|
+
continue
|
|
67
|
+
except StopIteration:
|
|
68
|
+
self.stop()
|
|
69
|
+
return
|
|
70
|
+
except Exception as e:
|
|
71
|
+
try:
|
|
72
|
+
raise RuntimeError("Error in notify loop") from e
|
|
73
|
+
except RuntimeError as e_:
|
|
74
|
+
e = e_
|
|
75
|
+
if self._logger is not None:
|
|
76
|
+
self._logger.error("Error in notify loop: %s", str(e), exc_info=True)
|
|
77
|
+
if self.raise_from_notify and not self._exception_event.is_set():
|
|
78
|
+
self.set_exception(e)
|
|
79
|
+
return
|
|
80
|
+
|
|
81
|
+
def _upload_loop(self):
|
|
82
|
+
try:
|
|
83
|
+
while not self._stop_event.is_set() or not self._q.empty():
|
|
84
|
+
if self._exception_event.is_set():
|
|
85
|
+
return
|
|
86
|
+
items = []
|
|
87
|
+
try:
|
|
88
|
+
timeout = 0.1 if self._stop_event.is_set() else 1.0
|
|
89
|
+
item = self._q.get(timeout=timeout)
|
|
90
|
+
items.append(item)
|
|
91
|
+
while True:
|
|
92
|
+
try:
|
|
93
|
+
items.append(self._q.get_nowait())
|
|
94
|
+
except Empty:
|
|
95
|
+
break
|
|
96
|
+
if items:
|
|
97
|
+
self._upload_f(items)
|
|
98
|
+
self.notify(items)
|
|
99
|
+
|
|
100
|
+
for _ in range(len(items)):
|
|
101
|
+
self._q.task_done()
|
|
102
|
+
except Empty:
|
|
103
|
+
continue
|
|
104
|
+
except StopIteration:
|
|
105
|
+
self.stop()
|
|
106
|
+
return
|
|
107
|
+
except Exception as e:
|
|
108
|
+
try:
|
|
109
|
+
raise RuntimeError("Error in upload loop") from e
|
|
110
|
+
except RuntimeError as e_:
|
|
111
|
+
e = e_
|
|
112
|
+
if self._logger is not None:
|
|
113
|
+
self._logger.error("Error in upload loop: %s", str(e), exc_info=True)
|
|
114
|
+
if not self._exception_event.is_set():
|
|
115
|
+
self.set_exception(e)
|
|
116
|
+
return
|
|
117
|
+
|
|
118
|
+
def put(self, items):
|
|
119
|
+
for item in items:
|
|
120
|
+
self._q.put(item)
|
|
121
|
+
|
|
122
|
+
def notify(self, items):
|
|
123
|
+
if self._notify_thread is not None:
|
|
124
|
+
for item in items:
|
|
125
|
+
self._notify_q.put(item)
|
|
126
|
+
|
|
127
|
+
def stop(self):
|
|
128
|
+
self._stop_event.set()
|
|
129
|
+
|
|
130
|
+
def join(self, timeout=None):
|
|
131
|
+
self._upload_thread.join(timeout=timeout)
|
|
132
|
+
if self._notify_thread is not None:
|
|
133
|
+
self._notify_thread.join(timeout=timeout)
|
|
134
|
+
|
|
135
|
+
def has_exception(self):
|
|
136
|
+
return self._exception_event.is_set()
|
|
137
|
+
|
|
138
|
+
def set_exception(self, exception: Exception):
|
|
139
|
+
with self._lock:
|
|
140
|
+
self._exception_event.set()
|
|
141
|
+
self.exception = exception
|
|
142
|
+
|
|
143
|
+
def __enter__(self):
|
|
144
|
+
return self
|
|
145
|
+
|
|
146
|
+
def _default_exception_handler(
|
|
147
|
+
self,
|
|
148
|
+
exception: Exception,
|
|
149
|
+
):
|
|
150
|
+
raise exception
|
|
151
|
+
|
|
152
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
153
|
+
self.stop()
|
|
154
|
+
try:
|
|
155
|
+
self.join(timeout=5)
|
|
156
|
+
except TimeoutError:
|
|
157
|
+
_logger = logger
|
|
158
|
+
if self._logger is not None:
|
|
159
|
+
_logger = self._logger
|
|
160
|
+
_logger.warning("Uploader thread didn't finish in time")
|
|
161
|
+
if exc_type is not None:
|
|
162
|
+
exc = exc_val.with_traceback(exc_tb)
|
|
163
|
+
return self._exception_handler(exc)
|
|
164
|
+
return False
|
|
File without changes
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import os
|
|
3
|
+
from os import PathLike
|
|
4
|
+
from typing import List, Union
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import requests
|
|
8
|
+
|
|
9
|
+
import supervisely.io.env as sly_env
|
|
10
|
+
import supervisely.io.json as sly_json
|
|
11
|
+
from supervisely.api.module_api import ApiField
|
|
12
|
+
from supervisely.api.task_api import TaskApi
|
|
13
|
+
from supervisely.nn.experiments import ExperimentInfo
|
|
14
|
+
from supervisely.nn.model.prediction import Prediction
|
|
15
|
+
from supervisely.nn.model.prediction_session import PredictionSession
|
|
16
|
+
from supervisely.nn.utils import ModelSource
|
|
17
|
+
from supervisely.project.project_meta import ProjectMeta
|
|
18
|
+
from supervisely.api.api import Api
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ModelAPI:
|
|
22
|
+
def __init__(self, api: "Api" = None, task_id: int = None, url: str = None):
|
|
23
|
+
assert not (task_id is None and url is None), "Either `task_id` or `url` must be passed."
|
|
24
|
+
assert (
|
|
25
|
+
task_id is None or url is None
|
|
26
|
+
), "Either `task_id` or `url` must be passed (not both)."
|
|
27
|
+
if task_id is not None:
|
|
28
|
+
assert api is not None, "API must be provided if `task_id` is passed."
|
|
29
|
+
|
|
30
|
+
self.api = api
|
|
31
|
+
self.task_id = task_id
|
|
32
|
+
self.url = url
|
|
33
|
+
|
|
34
|
+
if self.task_id is not None:
|
|
35
|
+
task_info = self.api.task.get_info_by_id(self.task_id)
|
|
36
|
+
if task_info is None:
|
|
37
|
+
raise ValueError(f"Task with id {self.task_id} not found.")
|
|
38
|
+
self.url = f'{self.api.server_address}/net/{task_info["meta"]["sessionToken"]}'
|
|
39
|
+
|
|
40
|
+
# region Requests
|
|
41
|
+
def _post(self, method: str, data: dict, raise_for_status: bool = True):
|
|
42
|
+
url = f"{self.url.rstrip('/')}/{method.lstrip('/')}"
|
|
43
|
+
response = requests.post(url, json=data)
|
|
44
|
+
if raise_for_status:
|
|
45
|
+
response.raise_for_status()
|
|
46
|
+
return response.json()
|
|
47
|
+
|
|
48
|
+
def _get(self, method: str, params: dict = None, raise_for_status: bool = True):
|
|
49
|
+
url = f"{self.url.rstrip('/')}/{method.lstrip('/')}"
|
|
50
|
+
response = requests.get(url, params=params)
|
|
51
|
+
if raise_for_status:
|
|
52
|
+
response.raise_for_status()
|
|
53
|
+
return response.json()
|
|
54
|
+
|
|
55
|
+
# ------------------------------------ #
|
|
56
|
+
|
|
57
|
+
# region Info
|
|
58
|
+
def get_info(self):
|
|
59
|
+
if self.task_id is not None:
|
|
60
|
+
return self.api.nn._deploy_api.get_deploy_info(self.task_id)
|
|
61
|
+
return self._post("get_deploy_info", {})
|
|
62
|
+
|
|
63
|
+
def get_settings(self):
|
|
64
|
+
if self.task_id is not None:
|
|
65
|
+
return self.api.task.send_request(self.task_id, "get_custom_inference_settings", {})[
|
|
66
|
+
"settings"
|
|
67
|
+
]
|
|
68
|
+
else:
|
|
69
|
+
return self._post("get_custom_inference_settings", {})["settings"]
|
|
70
|
+
|
|
71
|
+
def get_model_meta(self):
|
|
72
|
+
if self.task_id is not None:
|
|
73
|
+
return ProjectMeta.from_json(
|
|
74
|
+
self.api.task.send_request(self.task_id, "get_output_classes_and_tags", {})
|
|
75
|
+
)
|
|
76
|
+
else:
|
|
77
|
+
return ProjectMeta.from_json(self._post("get_output_classes_and_tags", {}))
|
|
78
|
+
|
|
79
|
+
def get_classes(self):
|
|
80
|
+
model_meta = self.get_model_meta()
|
|
81
|
+
return [obj_class.name for obj_class in model_meta.obj_classes]
|
|
82
|
+
|
|
83
|
+
def list_pretrained_models(self) -> List[str]:
|
|
84
|
+
"""Return a list of pretrained model names available for deployment"""
|
|
85
|
+
return self._post("list_pretrained_models", {})
|
|
86
|
+
|
|
87
|
+
def list_pretrained_model_infos(self) -> List[dict]:
|
|
88
|
+
"""Return a list of pretrained model infos with full information about each model"""
|
|
89
|
+
return self._post("list_pretrained_model_infos", {})
|
|
90
|
+
|
|
91
|
+
def list_experiments(self) -> List[ExperimentInfo]:
|
|
92
|
+
"""Return a list of training experiments in Supervisely"""
|
|
93
|
+
raise NotImplementedError
|
|
94
|
+
|
|
95
|
+
def is_deployed(self) -> bool:
|
|
96
|
+
if self.task_id is not None:
|
|
97
|
+
return self.api.task.is_ready(self.task_id)
|
|
98
|
+
return self._post("is_ready", {})["status"] == "ready"
|
|
99
|
+
|
|
100
|
+
def status(self):
|
|
101
|
+
if self.task_id is not None:
|
|
102
|
+
return self.api.task.send_request(self.task_id, "get_status", {})
|
|
103
|
+
return self._post("get_status", {})
|
|
104
|
+
|
|
105
|
+
def shutdown(self):
|
|
106
|
+
if self.task_id is not None:
|
|
107
|
+
return self.api.task.stop(self.task_id)
|
|
108
|
+
response = self._post("tasks.stop", {ApiField.ID: id})
|
|
109
|
+
return TaskApi.Status(response[ApiField.STATUS])
|
|
110
|
+
|
|
111
|
+
# --------------------- #
|
|
112
|
+
|
|
113
|
+
# region Load
|
|
114
|
+
def load(
|
|
115
|
+
self,
|
|
116
|
+
model: str,
|
|
117
|
+
device: str = None,
|
|
118
|
+
runtime: str = None,
|
|
119
|
+
):
|
|
120
|
+
if self.url is not None:
|
|
121
|
+
if os.path.exists(model):
|
|
122
|
+
self._load_local_custom_model(model, device, runtime)
|
|
123
|
+
else:
|
|
124
|
+
self._load_local_pretrained_model(model, device, runtime)
|
|
125
|
+
|
|
126
|
+
elif model.startswith("/"):
|
|
127
|
+
team_id = sly_env.team_id()
|
|
128
|
+
artifacts_dir, checkpoint_name = (
|
|
129
|
+
self.api.nn._deploy_api._get_artifacts_dir_and_checkpoint_name(model)
|
|
130
|
+
)
|
|
131
|
+
self.api.nn._deploy_api.load_custom_model(
|
|
132
|
+
self.task_id,
|
|
133
|
+
team_id,
|
|
134
|
+
artifacts_dir,
|
|
135
|
+
checkpoint_name,
|
|
136
|
+
device=device,
|
|
137
|
+
runtime=runtime,
|
|
138
|
+
)
|
|
139
|
+
else:
|
|
140
|
+
self.api.nn._deploy_api.load_pretrained_model(
|
|
141
|
+
self.task_id, model, device=device, runtime=runtime
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
def _load_local_pretrained_model(self, model: str, device: str = None, runtime: str = None):
|
|
145
|
+
available_models = self.list_pretrained_models()
|
|
146
|
+
if model not in available_models:
|
|
147
|
+
raise ValueError(f"Model {model} not found in available models: {available_models}")
|
|
148
|
+
|
|
149
|
+
deploy_params = {
|
|
150
|
+
"model_files": {},
|
|
151
|
+
"model_source": ModelSource.PRETRAINED,
|
|
152
|
+
"model_info": {},
|
|
153
|
+
"device": device,
|
|
154
|
+
"runtime": runtime,
|
|
155
|
+
}
|
|
156
|
+
state = {"deploy_params": deploy_params, "model_name": model}
|
|
157
|
+
return self._post("deploy_from_api", {"state": state})
|
|
158
|
+
|
|
159
|
+
def _load_local_custom_model(self, model: str, device: str = None, runtime: str = None):
|
|
160
|
+
deploy_params = self._get_custom_model_params(model, device, runtime)
|
|
161
|
+
state = {"deploy_params": deploy_params, "model_name": model}
|
|
162
|
+
return self._post("deploy_from_api", {"state": state})
|
|
163
|
+
|
|
164
|
+
def _get_custom_model_params(self, model_name: str, device: str = None, runtime: str = None):
|
|
165
|
+
def _load_experiment_info(artifacts_dir):
|
|
166
|
+
experiment_path = os.path.join(artifacts_dir, "experiment_info.json")
|
|
167
|
+
model_info = sly_json.load_json_file(experiment_path)
|
|
168
|
+
model_meta_path = os.path.join(artifacts_dir, "model_meta.json")
|
|
169
|
+
model_info["model_meta"] = sly_json.load_json_file(model_meta_path)
|
|
170
|
+
original_model_files = model_info.get("model_files")
|
|
171
|
+
return model_info, original_model_files
|
|
172
|
+
|
|
173
|
+
def _prepare_local_model_files(artifacts_dir, checkpoint_path, original_model_files):
|
|
174
|
+
return {k: os.path.join(artifacts_dir, v) for k, v in original_model_files.items()} | {
|
|
175
|
+
"checkpoint": checkpoint_path
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
model_source = ModelSource.CUSTOM
|
|
179
|
+
artifacts_dir = os.path.dirname(os.path.dirname(model_name))
|
|
180
|
+
model_info, original_model_files = _load_experiment_info(artifacts_dir)
|
|
181
|
+
model_files = _prepare_local_model_files(artifacts_dir, model_name, original_model_files)
|
|
182
|
+
deploy_params = {
|
|
183
|
+
"model_files": model_files,
|
|
184
|
+
"model_source": model_source,
|
|
185
|
+
"model_info": model_info,
|
|
186
|
+
"device": device,
|
|
187
|
+
"runtime": runtime,
|
|
188
|
+
}
|
|
189
|
+
return deploy_params
|
|
190
|
+
|
|
191
|
+
# --------------------------------- #
|
|
192
|
+
|
|
193
|
+
# region Predict
|
|
194
|
+
def predict_detached(
|
|
195
|
+
self,
|
|
196
|
+
input: Union[np.ndarray, str, PathLike, list] = None,
|
|
197
|
+
image_id: int = None,
|
|
198
|
+
video_id: int = None,
|
|
199
|
+
dataset_id: int = None,
|
|
200
|
+
project_id: int = None,
|
|
201
|
+
batch_size: int = None,
|
|
202
|
+
conf: float = None,
|
|
203
|
+
classes: List[str] = None,
|
|
204
|
+
upload_mode: str = None,
|
|
205
|
+
**kwargs,
|
|
206
|
+
) -> PredictionSession:
|
|
207
|
+
if upload_mode is not None:
|
|
208
|
+
kwargs["upload_mode"] = upload_mode
|
|
209
|
+
return PredictionSession(
|
|
210
|
+
self.url,
|
|
211
|
+
input=input,
|
|
212
|
+
image_id=image_id,
|
|
213
|
+
video_id=video_id,
|
|
214
|
+
dataset_id=dataset_id,
|
|
215
|
+
project_id=project_id,
|
|
216
|
+
api=self.api,
|
|
217
|
+
batch_size=batch_size,
|
|
218
|
+
conf=conf,
|
|
219
|
+
classes=classes,
|
|
220
|
+
**kwargs,
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
def predict(
|
|
224
|
+
self,
|
|
225
|
+
input: Union[np.ndarray, str, PathLike, list] = None,
|
|
226
|
+
image_id: Union[List[int], int] = None,
|
|
227
|
+
video_id: Union[List[int], int] = None,
|
|
228
|
+
dataset_id: Union[List[int], int] = None,
|
|
229
|
+
project_id: Union[List[int], int] = None,
|
|
230
|
+
batch_size: int = None,
|
|
231
|
+
conf: float = None,
|
|
232
|
+
img_size: int = None,
|
|
233
|
+
classes: List[str] = None,
|
|
234
|
+
upload_mode: str = None,
|
|
235
|
+
recursive: bool = None,
|
|
236
|
+
**kwargs,
|
|
237
|
+
) -> List[Prediction]:
|
|
238
|
+
if "show_progress" not in kwargs:
|
|
239
|
+
kwargs["show_progress"] = True
|
|
240
|
+
if recursive is not None:
|
|
241
|
+
kwargs["recursive"] = recursive
|
|
242
|
+
if img_size is not None:
|
|
243
|
+
kwargs["img_size"] = img_size
|
|
244
|
+
return list(
|
|
245
|
+
self.predict_detached(
|
|
246
|
+
input,
|
|
247
|
+
image_id,
|
|
248
|
+
video_id,
|
|
249
|
+
dataset_id,
|
|
250
|
+
project_id,
|
|
251
|
+
batch_size,
|
|
252
|
+
conf,
|
|
253
|
+
classes,
|
|
254
|
+
upload_mode,
|
|
255
|
+
**kwargs,
|
|
256
|
+
)
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
# ------------------------------------ #
|