ultralytics 8.3.188__py3-none-any.whl → 8.3.190__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.
- ultralytics/__init__.py +1 -1
- ultralytics/data/utils.py +2 -2
- ultralytics/engine/exporter.py +5 -2
- ultralytics/engine/predictor.py +1 -1
- ultralytics/engine/results.py +5 -5
- ultralytics/engine/trainer.py +2 -0
- ultralytics/engine/validator.py +3 -1
- ultralytics/hub/__init__.py +6 -2
- ultralytics/hub/auth.py +2 -2
- ultralytics/hub/google/__init__.py +2 -2
- ultralytics/hub/session.py +3 -5
- ultralytics/hub/utils.py +5 -5
- ultralytics/models/yolo/detect/predict.py +2 -2
- ultralytics/models/yolo/detect/val.py +2 -2
- ultralytics/models/yolo/obb/val.py +2 -1
- ultralytics/nn/autobackend.py +29 -36
- ultralytics/nn/modules/__init__.py +3 -3
- ultralytics/nn/modules/head.py +5 -1
- ultralytics/nn/tasks.py +2 -2
- ultralytics/utils/__init__.py +49 -14
- ultralytics/utils/callbacks/platform.py +2 -1
- ultralytics/utils/checks.py +3 -3
- ultralytics/utils/downloads.py +2 -2
- ultralytics/utils/logger.py +7 -6
- ultralytics/utils/nms.py +346 -0
- ultralytics/utils/ops.py +80 -249
- ultralytics/utils/tal.py +1 -1
- ultralytics/utils/torch_utils.py +50 -47
- ultralytics/utils/tqdm.py +34 -23
- {ultralytics-8.3.188.dist-info → ultralytics-8.3.190.dist-info}/METADATA +1 -1
- {ultralytics-8.3.188.dist-info → ultralytics-8.3.190.dist-info}/RECORD +35 -34
- {ultralytics-8.3.188.dist-info → ultralytics-8.3.190.dist-info}/WHEEL +0 -0
- {ultralytics-8.3.188.dist-info → ultralytics-8.3.190.dist-info}/entry_points.txt +0 -0
- {ultralytics-8.3.188.dist-info → ultralytics-8.3.190.dist-info}/licenses/LICENSE +0 -0
- {ultralytics-8.3.188.dist-info → ultralytics-8.3.190.dist-info}/top_level.txt +0 -0
ultralytics/__init__.py
CHANGED
ultralytics/data/utils.py
CHANGED
@@ -464,7 +464,7 @@ def check_det_dataset(dataset: str, autodownload: bool = True) -> Dict[str, Any]
|
|
464
464
|
safe_download(url=s, dir=DATASETS_DIR, delete=True)
|
465
465
|
elif s.startswith("bash "): # bash script
|
466
466
|
LOGGER.info(f"Running {s} ...")
|
467
|
-
|
467
|
+
subprocess.run(s.split(), check=True)
|
468
468
|
else: # python script
|
469
469
|
exec(s, {"yaml": data})
|
470
470
|
dt = f"({round(time.time() - t, 1)}s)"
|
@@ -509,7 +509,7 @@ def check_cls_dataset(dataset: Union[str, Path], split: str = "") -> Dict[str, A
|
|
509
509
|
LOGGER.warning(f"Dataset not found, missing path {data_dir}, attempting download...")
|
510
510
|
t = time.time()
|
511
511
|
if str(dataset) == "imagenet":
|
512
|
-
subprocess.run(
|
512
|
+
subprocess.run(["bash", str(ROOT / "data/scripts/get_imagenet.sh")], check=True)
|
513
513
|
else:
|
514
514
|
url = f"https://github.com/ultralytics/assets/releases/download/v0.0.0/{dataset}.zip"
|
515
515
|
download(url, dir=data_dir.parent)
|
ultralytics/engine/exporter.py
CHANGED
@@ -107,7 +107,9 @@ from ultralytics.utils.checks import (
|
|
107
107
|
from ultralytics.utils.downloads import attempt_download_asset, get_github_assets, safe_download
|
108
108
|
from ultralytics.utils.export import export_engine, export_onnx
|
109
109
|
from ultralytics.utils.files import file_size, spaces_in_path
|
110
|
-
from ultralytics.utils.
|
110
|
+
from ultralytics.utils.metrics import batch_probiou
|
111
|
+
from ultralytics.utils.nms import TorchNMS
|
112
|
+
from ultralytics.utils.ops import Profile
|
111
113
|
from ultralytics.utils.patches import arange_patch
|
112
114
|
from ultralytics.utils.torch_utils import TORCH_1_13, get_latest_opset, select_device
|
113
115
|
|
@@ -1562,12 +1564,13 @@ class NMSModel(torch.nn.Module):
|
|
1562
1564
|
nmsbox = torch.cat((offbox, nmsbox[:, end:]), dim=-1)
|
1563
1565
|
nms_fn = (
|
1564
1566
|
partial(
|
1565
|
-
|
1567
|
+
TorchNMS.fast_nms,
|
1566
1568
|
use_triu=not (
|
1567
1569
|
self.is_tf
|
1568
1570
|
or (self.args.opset or 14) < 14
|
1569
1571
|
or (self.args.format == "openvino" and self.args.int8) # OpenVINO int8 error with triu
|
1570
1572
|
),
|
1573
|
+
iou_func=batch_probiou,
|
1571
1574
|
)
|
1572
1575
|
if self.obb
|
1573
1576
|
else nms
|
ultralytics/engine/predictor.py
CHANGED
@@ -389,7 +389,7 @@ class BasePredictor:
|
|
389
389
|
verbose (bool): Whether to print verbose output.
|
390
390
|
"""
|
391
391
|
self.model = AutoBackend(
|
392
|
-
|
392
|
+
model=model or self.args.model,
|
393
393
|
device=select_device(self.args.device, verbose=verbose),
|
394
394
|
dnn=self.args.dnn,
|
395
395
|
data=self.args.data,
|
ultralytics/engine/results.py
CHANGED
@@ -681,12 +681,12 @@ class Results(SimpleClass, DataExportMixin):
|
|
681
681
|
- For classification tasks, it returns the top 5 class probabilities and their corresponding class names.
|
682
682
|
- The returned string is comma-separated and ends with a comma and a space.
|
683
683
|
"""
|
684
|
-
|
684
|
+
boxes = self.obb if self.obb is not None else self.boxes
|
685
685
|
if len(self) == 0:
|
686
|
-
return "" if probs is not None else "(no detections), "
|
687
|
-
if probs is not None:
|
688
|
-
return f"{', '.join(f'{self.names[j]} {probs.data[j]:.2f}' for j in probs.top5)}, "
|
689
|
-
if boxes
|
686
|
+
return "" if self.probs is not None else "(no detections), "
|
687
|
+
if self.probs is not None:
|
688
|
+
return f"{', '.join(f'{self.names[j]} {self.probs.data[j]:.2f}' for j in self.probs.top5)}, "
|
689
|
+
if boxes:
|
690
690
|
counts = boxes.cls.int().bincount()
|
691
691
|
return "".join(f"{n} {self.names[i]}{'s' * (n > 1)}, " for i, n in enumerate(counts) if n > 0)
|
692
692
|
|
ultralytics/engine/trainer.py
CHANGED
@@ -36,6 +36,7 @@ from ultralytics.utils import (
|
|
36
36
|
clean_url,
|
37
37
|
colorstr,
|
38
38
|
emojis,
|
39
|
+
get_git_commit,
|
39
40
|
)
|
40
41
|
from ultralytics.utils.autobatch import check_train_batch_size
|
41
42
|
from ultralytics.utils.checks import check_amp, check_file, check_imgsz, check_model_file_from_stem, print_args
|
@@ -572,6 +573,7 @@ class BaseTrainer:
|
|
572
573
|
"train_results": self.read_results_csv(),
|
573
574
|
"date": datetime.now().isoformat(),
|
574
575
|
"version": __version__,
|
576
|
+
"git_commit": get_git_commit(),
|
575
577
|
"license": "AGPL-3.0 (https://ultralytics.com/license)",
|
576
578
|
"docs": "https://docs.ultralytics.com",
|
577
579
|
},
|
ultralytics/engine/validator.py
CHANGED
@@ -101,6 +101,8 @@ class BaseValidator:
|
|
101
101
|
args (SimpleNamespace, optional): Configuration for the validator.
|
102
102
|
_callbacks (dict, optional): Dictionary to store various callback functions.
|
103
103
|
"""
|
104
|
+
import torchvision # noqa (import here so torchvision import time not recorded in postprocess time)
|
105
|
+
|
104
106
|
self.args = get_cfg(overrides=args)
|
105
107
|
self.dataloader = dataloader
|
106
108
|
self.stride = None
|
@@ -155,7 +157,7 @@ class BaseValidator:
|
|
155
157
|
LOGGER.warning("validating an untrained model YAML will result in 0 mAP.")
|
156
158
|
callbacks.add_integration_callbacks(self)
|
157
159
|
model = AutoBackend(
|
158
|
-
|
160
|
+
model=model or self.args.model,
|
159
161
|
device=select_device(self.args.device, self.args.batch),
|
160
162
|
dnn=self.args.dnn,
|
161
163
|
data=self.args.data,
|
ultralytics/hub/__init__.py
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
2
2
|
|
3
|
-
import requests
|
4
|
-
|
5
3
|
from ultralytics.data.utils import HUBDatasetStats
|
6
4
|
from ultralytics.hub.auth import Auth
|
7
5
|
from ultralytics.hub.session import HUBTrainingSession
|
@@ -75,6 +73,8 @@ def logout():
|
|
75
73
|
|
76
74
|
def reset_model(model_id: str = ""):
|
77
75
|
"""Reset a trained model to an untrained state."""
|
76
|
+
import requests # scoped as slow import
|
77
|
+
|
78
78
|
r = requests.post(f"{HUB_API_ROOT}/model-reset", json={"modelId": model_id}, headers={"x-api-key": Auth().api_key})
|
79
79
|
if r.status_code == 200:
|
80
80
|
LOGGER.info(f"{PREFIX}Model reset successfully")
|
@@ -105,6 +105,8 @@ def export_model(model_id: str = "", format: str = "torchscript"):
|
|
105
105
|
>>> from ultralytics import hub
|
106
106
|
>>> hub.export_model(model_id="your_model_id", format="torchscript")
|
107
107
|
"""
|
108
|
+
import requests # scoped as slow import
|
109
|
+
|
108
110
|
assert format in export_fmts_hub(), f"Unsupported export format '{format}', valid formats are {export_fmts_hub()}"
|
109
111
|
r = requests.post(
|
110
112
|
f"{HUB_API_ROOT}/v1/models/{model_id}/export", json={"format": format}, headers={"x-api-key": Auth().api_key}
|
@@ -132,6 +134,8 @@ def get_export(model_id: str = "", format: str = "torchscript"):
|
|
132
134
|
>>> from ultralytics import hub
|
133
135
|
>>> result = hub.get_export(model_id="your_model_id", format="torchscript")
|
134
136
|
"""
|
137
|
+
import requests # scoped as slow import
|
138
|
+
|
135
139
|
assert format in export_fmts_hub(), f"Unsupported export format '{format}', valid formats are {export_fmts_hub()}"
|
136
140
|
r = requests.post(
|
137
141
|
f"{HUB_API_ROOT}/get-export",
|
ultralytics/hub/auth.py
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
2
2
|
|
3
|
-
import requests
|
4
|
-
|
5
3
|
from ultralytics.hub.utils import HUB_API_ROOT, HUB_WEB_ROOT, PREFIX, request_with_credentials
|
6
4
|
from ultralytics.utils import IS_COLAB, LOGGER, SETTINGS, emojis
|
7
5
|
|
@@ -110,6 +108,8 @@ class Auth:
|
|
110
108
|
Returns:
|
111
109
|
(bool): True if authentication is successful, False otherwise.
|
112
110
|
"""
|
111
|
+
import requests # scoped as slow import
|
112
|
+
|
113
113
|
try:
|
114
114
|
if header := self.get_auth_header():
|
115
115
|
r = requests.post(f"{HUB_API_ROOT}/v1/auth", headers=header)
|
@@ -5,8 +5,6 @@ import statistics
|
|
5
5
|
import time
|
6
6
|
from typing import List, Optional, Tuple
|
7
7
|
|
8
|
-
import requests
|
9
|
-
|
10
8
|
|
11
9
|
class GCPRegions:
|
12
10
|
"""
|
@@ -101,6 +99,8 @@ class GCPRegions:
|
|
101
99
|
>>> region, mean, std, min_lat, max_lat = GCPRegions._ping_region("us-central1", attempts=3)
|
102
100
|
>>> print(f"Region {region} has mean latency: {mean:.2f}ms")
|
103
101
|
"""
|
102
|
+
import requests # scoped as slow import
|
103
|
+
|
104
104
|
url = f"https://{region}-docker.pkg.dev"
|
105
105
|
latencies = []
|
106
106
|
for _ in range(attempts):
|
ultralytics/hub/session.py
CHANGED
@@ -8,8 +8,6 @@ from pathlib import Path
|
|
8
8
|
from typing import Any, Dict, Optional
|
9
9
|
from urllib.parse import parse_qs, urlparse
|
10
10
|
|
11
|
-
import requests
|
12
|
-
|
13
11
|
from ultralytics import __version__
|
14
12
|
from ultralytics.hub.utils import HELP_MSG, HUB_WEB_ROOT, PREFIX
|
15
13
|
from ultralytics.utils import IS_COLAB, LOGGER, SETTINGS, TQDM, checks, emojis
|
@@ -341,7 +339,7 @@ class HUBTrainingSession:
|
|
341
339
|
}
|
342
340
|
return status_code in retry_codes
|
343
341
|
|
344
|
-
def _get_failure_message(self, response
|
342
|
+
def _get_failure_message(self, response, retry: int, timeout: int) -> str:
|
345
343
|
"""
|
346
344
|
Generate a retry message based on the response status code.
|
347
345
|
|
@@ -419,14 +417,14 @@ class HUBTrainingSession:
|
|
419
417
|
)
|
420
418
|
|
421
419
|
@staticmethod
|
422
|
-
def _show_upload_progress(content_length: int, response
|
420
|
+
def _show_upload_progress(content_length: int, response) -> None:
|
423
421
|
"""Display a progress bar to track the upload progress of a file download."""
|
424
422
|
with TQDM(total=content_length, unit="B", unit_scale=True, unit_divisor=1024) as pbar:
|
425
423
|
for data in response.iter_content(chunk_size=1024):
|
426
424
|
pbar.update(len(data))
|
427
425
|
|
428
426
|
@staticmethod
|
429
|
-
def _iterate_content(response
|
427
|
+
def _iterate_content(response) -> None:
|
430
428
|
"""Process the streamed HTTP response data."""
|
431
429
|
for _ in response.iter_content(chunk_size=1024):
|
432
430
|
pass # Do nothing with data chunks
|
ultralytics/hub/utils.py
CHANGED
@@ -5,9 +5,7 @@ import random
|
|
5
5
|
import threading
|
6
6
|
import time
|
7
7
|
from pathlib import Path
|
8
|
-
from typing import Any
|
9
|
-
|
10
|
-
import requests
|
8
|
+
from typing import Any
|
11
9
|
|
12
10
|
from ultralytics import __version__
|
13
11
|
from ultralytics.utils import (
|
@@ -78,7 +76,7 @@ def request_with_credentials(url: str) -> Any:
|
|
78
76
|
return output.eval_js("_hub_tmp")
|
79
77
|
|
80
78
|
|
81
|
-
def requests_with_progress(method: str, url: str, **kwargs)
|
79
|
+
def requests_with_progress(method: str, url: str, **kwargs):
|
82
80
|
"""
|
83
81
|
Make an HTTP request using the specified method and URL, with an optional progress bar.
|
84
82
|
|
@@ -95,6 +93,8 @@ def requests_with_progress(method: str, url: str, **kwargs) -> requests.Response
|
|
95
93
|
content length.
|
96
94
|
- If 'progress' is a number then progress bar will display assuming content length = progress.
|
97
95
|
"""
|
96
|
+
import requests # scoped as slow import
|
97
|
+
|
98
98
|
progress = kwargs.pop("progress", False)
|
99
99
|
if not progress:
|
100
100
|
return requests.request(method, url, **kwargs)
|
@@ -120,7 +120,7 @@ def smart_request(
|
|
120
120
|
verbose: bool = True,
|
121
121
|
progress: bool = False,
|
122
122
|
**kwargs,
|
123
|
-
)
|
123
|
+
):
|
124
124
|
"""
|
125
125
|
Make an HTTP request using the 'requests' library, with exponential backoff retries up to a specified timeout.
|
126
126
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
from ultralytics.engine.predictor import BasePredictor
|
4
4
|
from ultralytics.engine.results import Results
|
5
|
-
from ultralytics.utils import ops
|
5
|
+
from ultralytics.utils import nms, ops
|
6
6
|
|
7
7
|
|
8
8
|
class DetectionPredictor(BasePredictor):
|
@@ -53,7 +53,7 @@ class DetectionPredictor(BasePredictor):
|
|
53
53
|
>>> processed_results = predictor.postprocess(preds, img, orig_imgs)
|
54
54
|
"""
|
55
55
|
save_feats = getattr(self, "_feats", None) is not None
|
56
|
-
preds =
|
56
|
+
preds = nms.non_max_suppression(
|
57
57
|
preds,
|
58
58
|
self.args.conf,
|
59
59
|
self.args.iou,
|
@@ -9,7 +9,7 @@ import torch
|
|
9
9
|
|
10
10
|
from ultralytics.data import build_dataloader, build_yolo_dataset, converter
|
11
11
|
from ultralytics.engine.validator import BaseValidator
|
12
|
-
from ultralytics.utils import LOGGER, ops
|
12
|
+
from ultralytics.utils import LOGGER, nms, ops
|
13
13
|
from ultralytics.utils.checks import check_requirements
|
14
14
|
from ultralytics.utils.metrics import ConfusionMatrix, DetMetrics, box_iou
|
15
15
|
from ultralytics.utils.plotting import plot_images
|
@@ -115,7 +115,7 @@ class DetectionValidator(BaseValidator):
|
|
115
115
|
(List[Dict[str, torch.Tensor]]): Processed predictions after NMS, where each dict contains
|
116
116
|
'bboxes', 'conf', 'cls', and 'extra' tensors.
|
117
117
|
"""
|
118
|
-
outputs =
|
118
|
+
outputs = nms.non_max_suppression(
|
119
119
|
preds,
|
120
120
|
self.args.conf,
|
121
121
|
self.args.iou,
|
@@ -9,6 +9,7 @@ import torch
|
|
9
9
|
from ultralytics.models.yolo.detect import DetectionValidator
|
10
10
|
from ultralytics.utils import LOGGER, ops
|
11
11
|
from ultralytics.utils.metrics import OBBMetrics, batch_probiou
|
12
|
+
from ultralytics.utils.nms import TorchNMS
|
12
13
|
|
13
14
|
|
14
15
|
class OBBValidator(DetectionValidator):
|
@@ -281,7 +282,7 @@ class OBBValidator(DetectionValidator):
|
|
281
282
|
b = bbox[:, :5].clone()
|
282
283
|
b[:, :2] += c
|
283
284
|
# 0.3 could get results close to the ones from official merging script, even slightly better.
|
284
|
-
i =
|
285
|
+
i = TorchNMS.fast_nms(b, scores, 0.3, iou_func=batch_probiou)
|
285
286
|
bbox = bbox[i]
|
286
287
|
|
287
288
|
b = ops.xywhr2xyxyxyxy(bbox[:, :5]).view(-1, 8)
|
ultralytics/nn/autobackend.py
CHANGED
@@ -14,7 +14,7 @@ import torch
|
|
14
14
|
import torch.nn as nn
|
15
15
|
from PIL import Image
|
16
16
|
|
17
|
-
from ultralytics.utils import ARM64, IS_JETSON, LINUX, LOGGER, PYTHON_VERSION, ROOT, YAML
|
17
|
+
from ultralytics.utils import ARM64, IS_JETSON, LINUX, LOGGER, PYTHON_VERSION, ROOT, YAML, is_jetson
|
18
18
|
from ultralytics.utils.checks import check_requirements, check_suffix, check_version, check_yaml, is_rockchip
|
19
19
|
from ultralytics.utils.downloads import attempt_download_asset, is_url
|
20
20
|
|
@@ -127,14 +127,14 @@ class AutoBackend(nn.Module):
|
|
127
127
|
_model_type: Determine the model type from file path.
|
128
128
|
|
129
129
|
Examples:
|
130
|
-
>>> model = AutoBackend(
|
130
|
+
>>> model = AutoBackend(model="yolo11n.pt", device="cuda")
|
131
131
|
>>> results = model(img)
|
132
132
|
"""
|
133
133
|
|
134
134
|
@torch.no_grad()
|
135
135
|
def __init__(
|
136
136
|
self,
|
137
|
-
|
137
|
+
model: Union[str, List[str], torch.nn.Module] = "yolo11n.pt",
|
138
138
|
device: torch.device = torch.device("cpu"),
|
139
139
|
dnn: bool = False,
|
140
140
|
data: Optional[Union[str, Path]] = None,
|
@@ -146,7 +146,7 @@ class AutoBackend(nn.Module):
|
|
146
146
|
Initialize the AutoBackend for inference.
|
147
147
|
|
148
148
|
Args:
|
149
|
-
|
149
|
+
model (str | List[str] | torch.nn.Module): Path to the model weights file or a module instance.
|
150
150
|
device (torch.device): Device to run the model on.
|
151
151
|
dnn (bool): Use OpenCV DNN module for ONNX inference.
|
152
152
|
data (str | Path, optional): Path to the additional data.yaml file containing class names.
|
@@ -155,8 +155,8 @@ class AutoBackend(nn.Module):
|
|
155
155
|
verbose (bool): Enable verbose logging.
|
156
156
|
"""
|
157
157
|
super().__init__()
|
158
|
-
w = str(
|
159
|
-
nn_module = isinstance(
|
158
|
+
w = str(model[0] if isinstance(model, list) else model)
|
159
|
+
nn_module = isinstance(model, torch.nn.Module)
|
160
160
|
(
|
161
161
|
pt,
|
162
162
|
jit,
|
@@ -180,7 +180,7 @@ class AutoBackend(nn.Module):
|
|
180
180
|
nhwc = coreml or saved_model or pb or tflite or edgetpu or rknn # BHWC formats (vs torch BCWH)
|
181
181
|
stride, ch = 32, 3 # default stride and channels
|
182
182
|
end2end, dynamic = False, False
|
183
|
-
|
183
|
+
metadata, task = None, None
|
184
184
|
|
185
185
|
# Set device
|
186
186
|
cuda = isinstance(device, torch.device) and torch.cuda.is_available() and device.type != "cpu" # use CUDA
|
@@ -192,33 +192,32 @@ class AutoBackend(nn.Module):
|
|
192
192
|
if not (pt or triton or nn_module):
|
193
193
|
w = attempt_download_asset(w)
|
194
194
|
|
195
|
-
#
|
196
|
-
if nn_module:
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
from ultralytics.nn.tasks import attempt_load_weights
|
195
|
+
# PyTorch (in-memory or file)
|
196
|
+
if nn_module or pt:
|
197
|
+
if nn_module:
|
198
|
+
pt = True
|
199
|
+
if fuse:
|
200
|
+
if IS_JETSON and is_jetson(jetpack=5):
|
201
|
+
# Jetson Jetpack5 requires device before fuse https://github.com/ultralytics/ultralytics/pull/21028
|
202
|
+
model = model.to(device)
|
203
|
+
model = model.fuse(verbose=verbose)
|
204
|
+
model = model.to(device)
|
205
|
+
else: # pt file
|
206
|
+
from ultralytics.nn.tasks import attempt_load_weights
|
207
|
+
|
208
|
+
model = attempt_load_weights(
|
209
|
+
model if isinstance(model, list) else w, device=device, inplace=True, fuse=fuse
|
210
|
+
)
|
212
211
|
|
213
|
-
model
|
214
|
-
weights if isinstance(weights, list) else w, device=device, inplace=True, fuse=fuse
|
215
|
-
)
|
212
|
+
# Common PyTorch model processing
|
216
213
|
if hasattr(model, "kpt_shape"):
|
217
214
|
kpt_shape = model.kpt_shape # pose-only
|
218
215
|
stride = max(int(model.stride.max()), 32) # model stride
|
219
216
|
names = model.module.names if hasattr(model, "module") else model.names # get class names
|
220
217
|
model.half() if fp16 else model.float()
|
221
218
|
ch = model.yaml.get("channels", 3)
|
219
|
+
for p in model.parameters():
|
220
|
+
p.requires_grad = False
|
222
221
|
self.model = model # explicitly assign for to(), cpu(), cuda(), half()
|
223
222
|
|
224
223
|
# TorchScript
|
@@ -404,6 +403,7 @@ class AutoBackend(nn.Module):
|
|
404
403
|
|
405
404
|
# CoreML
|
406
405
|
elif coreml:
|
406
|
+
check_requirements("coremltools>=8.0")
|
407
407
|
LOGGER.info(f"Loading {w} for CoreML inference...")
|
408
408
|
import coremltools as ct
|
409
409
|
|
@@ -598,18 +598,13 @@ class AutoBackend(nn.Module):
|
|
598
598
|
dynamic = metadata.get("args", {}).get("dynamic", dynamic)
|
599
599
|
ch = metadata.get("channels", 3)
|
600
600
|
elif not (pt or triton or nn_module):
|
601
|
-
LOGGER.warning(f"Metadata not found for 'model={
|
601
|
+
LOGGER.warning(f"Metadata not found for 'model={w}'")
|
602
602
|
|
603
603
|
# Check names
|
604
604
|
if "names" not in locals(): # names missing
|
605
605
|
names = default_class_names(data)
|
606
606
|
names = check_class_names(names)
|
607
607
|
|
608
|
-
# Disable gradients
|
609
|
-
if pt:
|
610
|
-
for p in model.parameters():
|
611
|
-
p.requires_grad = False
|
612
|
-
|
613
608
|
self.__dict__.update(locals()) # assign all variables to self
|
614
609
|
|
615
610
|
def forward(
|
@@ -855,8 +850,6 @@ class AutoBackend(nn.Module):
|
|
855
850
|
Args:
|
856
851
|
imgsz (tuple): The shape of the dummy input tensor in the format (batch_size, channels, height, width)
|
857
852
|
"""
|
858
|
-
import torchvision # noqa (import here so torchvision import time not recorded in postprocess time)
|
859
|
-
|
860
853
|
warmup_types = self.pt, self.jit, self.onnx, self.engine, self.saved_model, self.pb, self.triton, self.nn_module
|
861
854
|
if any(warmup_types) and (self.device.type != "cpu" or self.triton):
|
862
855
|
im = torch.empty(*imgsz, dtype=torch.half if self.fp16 else torch.float, device=self.device) # input
|
@@ -875,7 +868,7 @@ class AutoBackend(nn.Module):
|
|
875
868
|
(List[bool]): List of booleans indicating the model type.
|
876
869
|
|
877
870
|
Examples:
|
878
|
-
>>> model = AutoBackend(
|
871
|
+
>>> model = AutoBackend(model="path/to/model.onnx")
|
879
872
|
>>> model_type = model._model_type() # returns "onnx"
|
880
873
|
"""
|
881
874
|
from ultralytics.engine.exporter import export_formats
|
@@ -7,14 +7,14 @@ blocks, attention mechanisms, transformer components, and detection/segmentation
|
|
7
7
|
|
8
8
|
Examples:
|
9
9
|
Visualize a module with Netron
|
10
|
-
>>> from ultralytics.nn.modules import
|
10
|
+
>>> from ultralytics.nn.modules import Conv
|
11
11
|
>>> import torch
|
12
|
-
>>> import
|
12
|
+
>>> import subprocess
|
13
13
|
>>> x = torch.ones(1, 128, 40, 40)
|
14
14
|
>>> m = Conv(128, 128)
|
15
15
|
>>> f = f"{m._get_name()}.onnx"
|
16
16
|
>>> torch.onnx.export(m, x, f)
|
17
|
-
>>>
|
17
|
+
>>> subprocess.run(f"onnxslim {f} {f} && open {f}", shell=True, check=True) # pip install onnxslim
|
18
18
|
"""
|
19
19
|
|
20
20
|
from .block import (
|
ultralytics/nn/modules/head.py
CHANGED
@@ -10,6 +10,7 @@ import torch.nn as nn
|
|
10
10
|
import torch.nn.functional as F
|
11
11
|
from torch.nn.init import constant_, xavier_uniform_
|
12
12
|
|
13
|
+
from ultralytics.utils import NOT_MACOS14
|
13
14
|
from ultralytics.utils.tal import TORCH_1_10, dist2bbox, dist2rbox, make_anchors
|
14
15
|
from ultralytics.utils.torch_utils import fuse_conv_and_bn, smart_inference_mode
|
15
16
|
|
@@ -408,7 +409,10 @@ class Pose(Detect):
|
|
408
409
|
else:
|
409
410
|
y = kpts.clone()
|
410
411
|
if ndim == 3:
|
411
|
-
|
412
|
+
if NOT_MACOS14:
|
413
|
+
y[:, 2::ndim].sigmoid_()
|
414
|
+
else: # Apple macOS14 MPS bug https://github.com/ultralytics/ultralytics/pull/21878
|
415
|
+
y[:, 2::ndim] = y[:, 2::ndim].sigmoid()
|
412
416
|
y[:, 0::ndim] = (y[:, 0::ndim] * 2.0 + (self.anchors[0] - 0.5)) * self.strides
|
413
417
|
y[:, 1::ndim] = (y[:, 1::ndim] * 2.0 + (self.anchors[1] - 0.5)) * self.strides
|
414
418
|
return y
|
ultralytics/nn/tasks.py
CHANGED
@@ -1500,7 +1500,7 @@ def attempt_load_weights(weights, device=None, inplace=True, fuse=False):
|
|
1500
1500
|
for w in weights if isinstance(weights, list) else [weights]:
|
1501
1501
|
ckpt, w = torch_safe_load(w) # load ckpt
|
1502
1502
|
args = {**DEFAULT_CFG_DICT, **ckpt["train_args"]} if "train_args" in ckpt else None # combined args
|
1503
|
-
model = (ckpt.get("ema") or ckpt["model"]).
|
1503
|
+
model = (ckpt.get("ema") or ckpt["model"]).float() # FP32 model
|
1504
1504
|
|
1505
1505
|
# Model compatibility updates
|
1506
1506
|
model.args = args # attach args to model
|
@@ -1510,7 +1510,7 @@ def attempt_load_weights(weights, device=None, inplace=True, fuse=False):
|
|
1510
1510
|
model.stride = torch.tensor([32.0])
|
1511
1511
|
|
1512
1512
|
# Append
|
1513
|
-
ensemble.append(model.fuse().eval() if fuse and hasattr(model, "fuse") else model.eval())
|
1513
|
+
ensemble.append((model.fuse().eval() if fuse and hasattr(model, "fuse") else model.eval()).to(device))
|
1514
1514
|
|
1515
1515
|
# Module updates
|
1516
1516
|
for m in ensemble.modules():
|
ultralytics/utils/__init__.py
CHANGED
@@ -8,10 +8,12 @@ import logging
|
|
8
8
|
import os
|
9
9
|
import platform
|
10
10
|
import re
|
11
|
+
import socket
|
11
12
|
import subprocess
|
12
13
|
import sys
|
13
14
|
import threading
|
14
15
|
import time
|
16
|
+
from functools import lru_cache
|
15
17
|
from pathlib import Path
|
16
18
|
from threading import Lock
|
17
19
|
from types import SimpleNamespace
|
@@ -43,6 +45,7 @@ VERBOSE = str(os.getenv("YOLO_VERBOSE", True)).lower() == "true" # global verbo
|
|
43
45
|
LOGGING_NAME = "ultralytics"
|
44
46
|
MACOS, LINUX, WINDOWS = (platform.system() == x for x in ["Darwin", "Linux", "Windows"]) # environment booleans
|
45
47
|
MACOS_VERSION = platform.mac_ver()[0] if MACOS else None
|
48
|
+
NOT_MACOS14 = not (MACOS and MACOS_VERSION.startswith("14."))
|
46
49
|
ARM64 = platform.machine() in {"arm64", "aarch64"} # ARM64 booleans
|
47
50
|
PYTHON_VERSION = platform.python_version()
|
48
51
|
TORCH_VERSION = torch.__version__
|
@@ -727,32 +730,45 @@ def is_raspberrypi() -> bool:
|
|
727
730
|
return "rpi" in DEVICE_MODEL
|
728
731
|
|
729
732
|
|
730
|
-
|
733
|
+
@lru_cache(maxsize=3)
|
734
|
+
def is_jetson(jetpack=None) -> bool:
|
731
735
|
"""
|
732
736
|
Determine if the Python environment is running on an NVIDIA Jetson device.
|
733
737
|
|
738
|
+
Args:
|
739
|
+
jetpack (int | None): If specified, check for specific JetPack version (4, 5, 6).
|
740
|
+
|
734
741
|
Returns:
|
735
742
|
(bool): True if running on an NVIDIA Jetson device, False otherwise.
|
736
743
|
"""
|
737
|
-
|
744
|
+
if jetson := ("tegra" in DEVICE_MODEL):
|
745
|
+
if jetpack:
|
746
|
+
try:
|
747
|
+
content = open("/etc/nv_tegra_release").read()
|
748
|
+
version_map = {4: "R32", 5: "R35", 6: "R36"} # JetPack to L4T major version mapping
|
749
|
+
return jetpack in version_map and version_map[jetpack] in content
|
750
|
+
except Exception:
|
751
|
+
return False
|
752
|
+
return jetson
|
738
753
|
|
739
754
|
|
740
755
|
def is_online() -> bool:
|
741
756
|
"""
|
742
|
-
|
757
|
+
Fast online check using DNS (v4/v6) resolution (Cloudflare + Google).
|
743
758
|
|
744
759
|
Returns:
|
745
760
|
(bool): True if connection is successful, False otherwise.
|
746
761
|
"""
|
747
|
-
|
748
|
-
|
749
|
-
import socket
|
762
|
+
if str(os.getenv("YOLO_OFFLINE", "")).lower() == "true":
|
763
|
+
return False
|
750
764
|
|
751
|
-
|
752
|
-
|
765
|
+
for host in ("one.one.one.one", "dns.google"):
|
766
|
+
try:
|
767
|
+
socket.getaddrinfo(host, 0, socket.AF_UNSPEC, 0, 0, socket.AI_ADDRCONFIG)
|
753
768
|
return True
|
754
|
-
|
755
|
-
|
769
|
+
except OSError:
|
770
|
+
continue
|
771
|
+
return False
|
756
772
|
|
757
773
|
|
758
774
|
def is_pip_package(filepath: str = __name__) -> bool:
|
@@ -829,6 +845,7 @@ def is_git_dir():
|
|
829
845
|
return GIT_DIR is not None
|
830
846
|
|
831
847
|
|
848
|
+
@lru_cache(maxsize=1)
|
832
849
|
def get_git_origin_url():
|
833
850
|
"""
|
834
851
|
Retrieve the origin URL of a git repository.
|
@@ -838,12 +855,14 @@ def get_git_origin_url():
|
|
838
855
|
"""
|
839
856
|
if IS_GIT_DIR:
|
840
857
|
try:
|
841
|
-
|
842
|
-
|
858
|
+
return subprocess.check_output(
|
859
|
+
["git", "config", "--get", "remote.origin.url"], stderr=subprocess.DEVNULL, text=True
|
860
|
+
).strip()
|
843
861
|
except subprocess.CalledProcessError:
|
844
862
|
return None
|
845
863
|
|
846
864
|
|
865
|
+
@lru_cache(maxsize=1)
|
847
866
|
def get_git_branch():
|
848
867
|
"""
|
849
868
|
Return the current git branch name. If not in a git repository, return None.
|
@@ -853,8 +872,24 @@ def get_git_branch():
|
|
853
872
|
"""
|
854
873
|
if IS_GIT_DIR:
|
855
874
|
try:
|
856
|
-
|
857
|
-
|
875
|
+
return subprocess.check_output(
|
876
|
+
["git", "rev-parse", "--abbrev-ref", "HEAD"], stderr=subprocess.DEVNULL, text=True
|
877
|
+
).strip()
|
878
|
+
except subprocess.CalledProcessError:
|
879
|
+
return None
|
880
|
+
|
881
|
+
|
882
|
+
@lru_cache(maxsize=1)
|
883
|
+
def get_git_commit():
|
884
|
+
"""
|
885
|
+
Return the current git commit hash. If not in a git repository, return None.
|
886
|
+
|
887
|
+
Returns:
|
888
|
+
(str | None): The current git commit hash or None if not a git directory.
|
889
|
+
"""
|
890
|
+
if IS_GIT_DIR:
|
891
|
+
try:
|
892
|
+
return subprocess.check_output(["git", "rev-parse", "HEAD"], stderr=subprocess.DEVNULL, text=True).strip()
|
858
893
|
except subprocess.CalledProcessError:
|
859
894
|
return None
|
860
895
|
|