ultralytics-opencv-headless 8.4.7__py3-none-any.whl → 8.4.9__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.
- tests/test_cli.py +10 -3
- tests/test_cuda.py +1 -1
- tests/test_exports.py +64 -43
- tests/test_python.py +16 -12
- ultralytics/__init__.py +1 -1
- ultralytics/cfg/__init__.py +1 -0
- ultralytics/cfg/default.yaml +1 -0
- ultralytics/data/augment.py +2 -2
- ultralytics/data/converter.py +11 -0
- ultralytics/engine/exporter.py +13 -16
- ultralytics/engine/predictor.py +5 -0
- ultralytics/engine/trainer.py +3 -3
- ultralytics/engine/tuner.py +2 -2
- ultralytics/engine/validator.py +5 -0
- ultralytics/models/sam/predict.py +2 -2
- ultralytics/models/yolo/classify/train.py +14 -1
- ultralytics/models/yolo/detect/train.py +4 -2
- ultralytics/models/yolo/pose/train.py +2 -1
- ultralytics/models/yolo/world/train_world.py +21 -1
- ultralytics/models/yolo/yoloe/train.py +1 -2
- ultralytics/nn/autobackend.py +22 -6
- ultralytics/nn/modules/head.py +13 -2
- ultralytics/nn/tasks.py +18 -0
- ultralytics/solutions/security_alarm.py +1 -1
- ultralytics/utils/benchmarks.py +3 -9
- ultralytics/utils/checks.py +18 -3
- ultralytics/utils/dist.py +9 -3
- ultralytics/utils/loss.py +4 -5
- ultralytics/utils/tal.py +15 -5
- ultralytics/utils/torch_utils.py +2 -1
- {ultralytics_opencv_headless-8.4.7.dist-info → ultralytics_opencv_headless-8.4.9.dist-info}/METADATA +3 -3
- {ultralytics_opencv_headless-8.4.7.dist-info → ultralytics_opencv_headless-8.4.9.dist-info}/RECORD +36 -36
- {ultralytics_opencv_headless-8.4.7.dist-info → ultralytics_opencv_headless-8.4.9.dist-info}/WHEEL +1 -1
- {ultralytics_opencv_headless-8.4.7.dist-info → ultralytics_opencv_headless-8.4.9.dist-info}/entry_points.txt +0 -0
- {ultralytics_opencv_headless-8.4.7.dist-info → ultralytics_opencv_headless-8.4.9.dist-info}/licenses/LICENSE +0 -0
- {ultralytics_opencv_headless-8.4.7.dist-info → ultralytics_opencv_headless-8.4.9.dist-info}/top_level.txt +0 -0
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
3
5
|
from pathlib import Path
|
|
4
6
|
|
|
5
7
|
from ultralytics.data import YOLOConcatDataset, build_grounding, build_yolo_dataset
|
|
6
8
|
from ultralytics.data.utils import check_det_dataset
|
|
7
9
|
from ultralytics.models.yolo.world import WorldTrainer
|
|
8
10
|
from ultralytics.utils import DATASETS_DIR, DEFAULT_CFG, LOGGER
|
|
11
|
+
from ultralytics.utils.checks import check_file
|
|
9
12
|
from ultralytics.utils.torch_utils import unwrap_model
|
|
10
13
|
|
|
11
14
|
|
|
@@ -100,6 +103,23 @@ class WorldTrainerFromScratch(WorldTrainer):
|
|
|
100
103
|
self.set_text_embeddings(datasets, batch) # cache text embeddings to accelerate training
|
|
101
104
|
return YOLOConcatDataset(datasets) if len(datasets) > 1 else datasets[0]
|
|
102
105
|
|
|
106
|
+
@staticmethod
|
|
107
|
+
def check_data_config(data: dict | str | Path) -> dict:
|
|
108
|
+
"""Check and load the data configuration from a YAML file or dictionary.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
data (dict | str | Path): Data configuration as a dictionary or path to a YAML file.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
(dict): Data configuration dictionary loaded from YAML file or passed directly.
|
|
115
|
+
"""
|
|
116
|
+
# If string, load from YAML file
|
|
117
|
+
if not isinstance(data, dict):
|
|
118
|
+
from ultralytics.utils import YAML
|
|
119
|
+
|
|
120
|
+
return YAML.load(check_file(data))
|
|
121
|
+
return data
|
|
122
|
+
|
|
103
123
|
def get_dataset(self):
|
|
104
124
|
"""Get train and validation paths from data dictionary.
|
|
105
125
|
|
|
@@ -114,7 +134,7 @@ class WorldTrainerFromScratch(WorldTrainer):
|
|
|
114
134
|
AssertionError: If train or validation datasets are not found, or if validation has multiple datasets.
|
|
115
135
|
"""
|
|
116
136
|
final_data = {}
|
|
117
|
-
data_yaml = self.args.data
|
|
137
|
+
self.args.data = data_yaml = self.check_data_config(self.args.data)
|
|
118
138
|
assert data_yaml.get("train", False), "train dataset not found" # object365.yaml
|
|
119
139
|
assert data_yaml.get("val", False), "validation dataset not found" # lvis.yaml
|
|
120
140
|
data = {k: [check_det_dataset(d) for d in v.get("yolo_data", [])] for k, v in data_yaml.items()}
|
|
@@ -196,7 +196,7 @@ class YOLOETrainerFromScratch(YOLOETrainer, WorldTrainerFromScratch):
|
|
|
196
196
|
Returns:
|
|
197
197
|
(dict): Dictionary mapping text samples to their embeddings.
|
|
198
198
|
"""
|
|
199
|
-
model =
|
|
199
|
+
model = unwrap_model(self.model).text_model
|
|
200
200
|
cache_path = cache_dir / f"text_embeddings_{model.replace(':', '_').replace('/', '_')}.pt"
|
|
201
201
|
if cache_path.exists():
|
|
202
202
|
LOGGER.info(f"Reading existed cache from '{cache_path}'")
|
|
@@ -204,7 +204,6 @@ class YOLOETrainerFromScratch(YOLOETrainer, WorldTrainerFromScratch):
|
|
|
204
204
|
if sorted(txt_map.keys()) == sorted(texts):
|
|
205
205
|
return txt_map
|
|
206
206
|
LOGGER.info(f"Caching text embeddings to '{cache_path}'")
|
|
207
|
-
assert self.model is not None
|
|
208
207
|
txt_feats = unwrap_model(self.model).get_text_pe(texts, batch, without_reprta=True, cache_clip_model=False)
|
|
209
208
|
txt_map = dict(zip(texts, txt_feats.squeeze(0)))
|
|
210
209
|
torch.save(txt_map, cache_path)
|
ultralytics/nn/autobackend.py
CHANGED
|
@@ -16,8 +16,24 @@ import torch
|
|
|
16
16
|
import torch.nn as nn
|
|
17
17
|
from PIL import Image
|
|
18
18
|
|
|
19
|
-
from ultralytics.utils import
|
|
20
|
-
|
|
19
|
+
from ultralytics.utils import (
|
|
20
|
+
ARM64,
|
|
21
|
+
IS_JETSON,
|
|
22
|
+
LINUX,
|
|
23
|
+
LOGGER,
|
|
24
|
+
PYTHON_VERSION,
|
|
25
|
+
ROOT,
|
|
26
|
+
YAML,
|
|
27
|
+
is_jetson,
|
|
28
|
+
)
|
|
29
|
+
from ultralytics.utils.checks import (
|
|
30
|
+
check_executorch_requirements,
|
|
31
|
+
check_requirements,
|
|
32
|
+
check_suffix,
|
|
33
|
+
check_version,
|
|
34
|
+
check_yaml,
|
|
35
|
+
is_rockchip,
|
|
36
|
+
)
|
|
21
37
|
from ultralytics.utils.downloads import attempt_download_asset, is_url
|
|
22
38
|
from ultralytics.utils.nms import non_max_suppression
|
|
23
39
|
|
|
@@ -616,9 +632,9 @@ class AutoBackend(nn.Module):
|
|
|
616
632
|
# ExecuTorch
|
|
617
633
|
elif pte:
|
|
618
634
|
LOGGER.info(f"Loading {w} for ExecuTorch inference...")
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
635
|
+
|
|
636
|
+
check_executorch_requirements()
|
|
637
|
+
|
|
622
638
|
from executorch.runtime import Runtime
|
|
623
639
|
|
|
624
640
|
w = Path(w)
|
|
@@ -648,7 +664,7 @@ class AutoBackend(nn.Module):
|
|
|
648
664
|
for k, v in metadata.items():
|
|
649
665
|
if k in {"stride", "batch", "channels"}:
|
|
650
666
|
metadata[k] = int(v)
|
|
651
|
-
elif k in {"imgsz", "names", "kpt_shape", "kpt_names", "args"} and isinstance(v, str):
|
|
667
|
+
elif k in {"imgsz", "names", "kpt_shape", "kpt_names", "args", "end2end"} and isinstance(v, str):
|
|
652
668
|
metadata[k] = ast.literal_eval(v)
|
|
653
669
|
stride = metadata["stride"]
|
|
654
670
|
task = metadata["task"]
|
ultralytics/nn/modules/head.py
CHANGED
|
@@ -69,6 +69,7 @@ class Detect(nn.Module):
|
|
|
69
69
|
export = False # export mode
|
|
70
70
|
format = None # export format
|
|
71
71
|
max_det = 300 # max_det
|
|
72
|
+
agnostic_nms = False
|
|
72
73
|
shape = None
|
|
73
74
|
anchors = torch.empty(0) # init
|
|
74
75
|
strides = torch.empty(0) # init
|
|
@@ -125,7 +126,12 @@ class Detect(nn.Module):
|
|
|
125
126
|
@property
|
|
126
127
|
def end2end(self):
|
|
127
128
|
"""Checks if the model has one2one for v5/v5/v8/v9/11 backward compatibility."""
|
|
128
|
-
return hasattr(self, "one2one")
|
|
129
|
+
return getattr(self, "_end2end", True) and hasattr(self, "one2one")
|
|
130
|
+
|
|
131
|
+
@end2end.setter
|
|
132
|
+
def end2end(self, value):
|
|
133
|
+
"""Override the end-to-end detection mode."""
|
|
134
|
+
self._end2end = value
|
|
129
135
|
|
|
130
136
|
def forward_head(
|
|
131
137
|
self, x: list[torch.Tensor], box_head: torch.nn.Module = None, cls_head: torch.nn.Module = None
|
|
@@ -230,6 +236,11 @@ class Detect(nn.Module):
|
|
|
230
236
|
# Use max_det directly during export for TensorRT compatibility (requires k to be constant),
|
|
231
237
|
# otherwise use min(max_det, anchors) for safety with small inputs during Python inference
|
|
232
238
|
k = max_det if self.export else min(max_det, anchors)
|
|
239
|
+
if self.agnostic_nms:
|
|
240
|
+
scores, labels = scores.max(dim=-1, keepdim=True)
|
|
241
|
+
scores, indices = scores.topk(k, dim=1)
|
|
242
|
+
labels = labels.gather(1, indices)
|
|
243
|
+
return scores, labels, indices
|
|
233
244
|
ori_index = scores.max(dim=-1)[0].topk(k)[1].unsqueeze(-1)
|
|
234
245
|
scores = scores.gather(dim=1, index=ori_index.repeat(1, 1, nc))
|
|
235
246
|
scores, index = scores.flatten(1).topk(k)
|
|
@@ -1098,7 +1109,7 @@ class YOLOEDetect(Detect):
|
|
|
1098
1109
|
boxes, scores, index = [], [], []
|
|
1099
1110
|
bs = x[0].shape[0]
|
|
1100
1111
|
cv2 = self.cv2 if not self.end2end else self.one2one_cv2
|
|
1101
|
-
cv3 = self.cv3 if not self.end2end else self.
|
|
1112
|
+
cv3 = self.cv3 if not self.end2end else self.one2one_cv3
|
|
1102
1113
|
for i in range(self.nl):
|
|
1103
1114
|
cls_feat = cv3[i](x[i])
|
|
1104
1115
|
loc_feat = cv2[i](x[i])
|
ultralytics/nn/tasks.py
CHANGED
|
@@ -425,6 +425,24 @@ class DetectionModel(BaseModel):
|
|
|
425
425
|
"""Return whether the model uses end-to-end NMS-free detection."""
|
|
426
426
|
return getattr(self.model[-1], "end2end", False)
|
|
427
427
|
|
|
428
|
+
@end2end.setter
|
|
429
|
+
def end2end(self, value):
|
|
430
|
+
"""Override the end-to-end detection mode."""
|
|
431
|
+
self.set_head_attr(end2end=value)
|
|
432
|
+
|
|
433
|
+
def set_head_attr(self, **kwargs):
|
|
434
|
+
"""Set attributes of the model head (last layer).
|
|
435
|
+
|
|
436
|
+
Args:
|
|
437
|
+
**kwargs: Arbitrary keyword arguments representing attributes to set.
|
|
438
|
+
"""
|
|
439
|
+
head = self.model[-1]
|
|
440
|
+
for k, v in kwargs.items():
|
|
441
|
+
if not hasattr(head, k):
|
|
442
|
+
LOGGER.warning(f"Head has no attribute '{k}'.")
|
|
443
|
+
continue
|
|
444
|
+
setattr(head, k, v)
|
|
445
|
+
|
|
428
446
|
def _predict_augment(self, x):
|
|
429
447
|
"""Perform augmentations on input image x and return augmented inference and train outputs.
|
|
430
448
|
|
|
@@ -62,7 +62,7 @@ class SecurityAlarm(BaseSolution):
|
|
|
62
62
|
"""
|
|
63
63
|
import smtplib
|
|
64
64
|
|
|
65
|
-
self.server = smtplib.SMTP("smtp.gmail.com
|
|
65
|
+
self.server = smtplib.SMTP("smtp.gmail.com", 587)
|
|
66
66
|
self.server.starttls()
|
|
67
67
|
self.server.login(from_email, password)
|
|
68
68
|
self.to_email = to_email
|
ultralytics/utils/benchmarks.py
CHANGED
|
@@ -36,6 +36,7 @@ import platform
|
|
|
36
36
|
import re
|
|
37
37
|
import shutil
|
|
38
38
|
import time
|
|
39
|
+
from copy import deepcopy
|
|
39
40
|
from pathlib import Path
|
|
40
41
|
|
|
41
42
|
import numpy as np
|
|
@@ -101,7 +102,6 @@ def benchmark(
|
|
|
101
102
|
device = select_device(device, verbose=False)
|
|
102
103
|
if isinstance(model, (str, Path)):
|
|
103
104
|
model = YOLO(model)
|
|
104
|
-
is_end2end = getattr(model.model.model[-1], "end2end", False)
|
|
105
105
|
data = data or TASK2DATA[model.task] # task to dataset, i.e. coco8.yaml for task=detect
|
|
106
106
|
key = TASK2METRIC[model.task] # task to metric, i.e. metrics/mAP50-95(B) for task=detect
|
|
107
107
|
|
|
@@ -135,14 +135,12 @@ def benchmark(
|
|
|
135
135
|
if format == "paddle":
|
|
136
136
|
assert not isinstance(model, YOLOWorld), "YOLOWorldv2 Paddle exports not supported yet"
|
|
137
137
|
assert model.task != "obb", "Paddle OBB bug https://github.com/PaddlePaddle/Paddle/issues/72024"
|
|
138
|
-
assert not is_end2end, "End-to-end models not supported by PaddlePaddle yet"
|
|
139
138
|
assert (LINUX and not IS_JETSON) or MACOS, "Windows and Jetson Paddle exports not supported yet"
|
|
140
139
|
if format == "mnn":
|
|
141
140
|
assert not isinstance(model, YOLOWorld), "YOLOWorldv2 MNN exports not supported yet"
|
|
142
141
|
if format == "ncnn":
|
|
143
142
|
assert not isinstance(model, YOLOWorld), "YOLOWorldv2 NCNN exports not supported yet"
|
|
144
143
|
if format == "imx":
|
|
145
|
-
assert not is_end2end
|
|
146
144
|
assert not isinstance(model, YOLOWorld), "YOLOWorldv2 IMX exports not supported"
|
|
147
145
|
assert model.task in {"detect", "classify", "pose"}, (
|
|
148
146
|
"IMX export is only supported for detection, classification and pose estimation tasks"
|
|
@@ -150,25 +148,21 @@ def benchmark(
|
|
|
150
148
|
assert "C2f" in model.__str__(), "IMX only supported for YOLOv8n and YOLO11n"
|
|
151
149
|
if format == "rknn":
|
|
152
150
|
assert not isinstance(model, YOLOWorld), "YOLOWorldv2 RKNN exports not supported yet"
|
|
153
|
-
assert not is_end2end, "End-to-end models not supported by RKNN yet"
|
|
154
151
|
assert LINUX, "RKNN only supported on Linux"
|
|
155
152
|
assert not is_rockchip(), "RKNN Inference only supported on Rockchip devices"
|
|
156
153
|
if format == "executorch":
|
|
157
154
|
assert not isinstance(model, YOLOWorld), "YOLOWorldv2 ExecuTorch exports not supported yet"
|
|
158
|
-
assert not is_end2end, "End-to-end models not supported by ExecuTorch yet"
|
|
159
155
|
if "cpu" in device.type:
|
|
160
156
|
assert cpu, "inference not supported on CPU"
|
|
161
157
|
if "cuda" in device.type:
|
|
162
158
|
assert gpu, "inference not supported on GPU"
|
|
163
|
-
if format == "ncnn":
|
|
164
|
-
assert not is_end2end, "End-to-end torch.topk operation is not supported for NCNN prediction yet"
|
|
165
159
|
|
|
166
160
|
# Export
|
|
167
161
|
if format == "-":
|
|
168
162
|
filename = model.pt_path or model.ckpt_path or model.model_name
|
|
169
|
-
exported_model = model # PyTorch format
|
|
163
|
+
exported_model = deepcopy(model) # PyTorch format
|
|
170
164
|
else:
|
|
171
|
-
filename = model.export(
|
|
165
|
+
filename = deepcopy(model).export(
|
|
172
166
|
imgsz=imgsz, format=format, half=half, int8=int8, data=data, device=device, verbose=False, **kwargs
|
|
173
167
|
)
|
|
174
168
|
exported_model = YOLO(filename, task=model.task)
|
ultralytics/utils/checks.py
CHANGED
|
@@ -29,6 +29,7 @@ from ultralytics.utils import (
|
|
|
29
29
|
AUTOINSTALL,
|
|
30
30
|
GIT,
|
|
31
31
|
IS_COLAB,
|
|
32
|
+
IS_DOCKER,
|
|
32
33
|
IS_JETSON,
|
|
33
34
|
IS_KAGGLE,
|
|
34
35
|
IS_PIP_PACKAGE,
|
|
@@ -495,6 +496,17 @@ def check_requirements(requirements=ROOT.parent / "requirements.txt", exclude=()
|
|
|
495
496
|
return True
|
|
496
497
|
|
|
497
498
|
|
|
499
|
+
def check_executorch_requirements():
|
|
500
|
+
"""Check and install ExecuTorch requirements including platform-specific dependencies."""
|
|
501
|
+
# BUG executorch build on arm64 Docker requires packaging>=22.0 https://github.com/pypa/setuptools/issues/4483
|
|
502
|
+
if LINUX and ARM64 and IS_DOCKER:
|
|
503
|
+
check_requirements("packaging>=22.0")
|
|
504
|
+
|
|
505
|
+
check_requirements("executorch", cmds=f"torch=={TORCH_VERSION.split('+')[0]}")
|
|
506
|
+
# Pin numpy to avoid coremltools errors with numpy>=2.4.0, must be separate
|
|
507
|
+
check_requirements("numpy<=2.3.5")
|
|
508
|
+
|
|
509
|
+
|
|
498
510
|
def check_torchvision():
|
|
499
511
|
"""Check the installed versions of PyTorch and Torchvision to ensure they're compatible.
|
|
500
512
|
|
|
@@ -546,7 +558,7 @@ def check_suffix(file="yolo26n.pt", suffix=".pt", msg=""):
|
|
|
546
558
|
assert f".{s}" in suffix, f"{msg}{f} acceptable suffix is {suffix}, not .{s}"
|
|
547
559
|
|
|
548
560
|
|
|
549
|
-
def check_yolov5u_filename(file: str, verbose: bool = True):
|
|
561
|
+
def check_yolov5u_filename(file: str, verbose: bool = True) -> str:
|
|
550
562
|
"""Replace legacy YOLOv5 filenames with updated YOLOv5u filenames.
|
|
551
563
|
|
|
552
564
|
Args:
|
|
@@ -573,7 +585,7 @@ def check_yolov5u_filename(file: str, verbose: bool = True):
|
|
|
573
585
|
return file
|
|
574
586
|
|
|
575
587
|
|
|
576
|
-
def check_model_file_from_stem(model="yolo11n"):
|
|
588
|
+
def check_model_file_from_stem(model: str = "yolo11n") -> str | Path:
|
|
577
589
|
"""Return a model filename from a valid model stem.
|
|
578
590
|
|
|
579
591
|
Args:
|
|
@@ -619,6 +631,9 @@ def check_file(file, suffix="", download=True, download_dir=".", hard=True):
|
|
|
619
631
|
# Use URI path for unique directory structure: ul://user/project/model -> user/project/model/filename.pt
|
|
620
632
|
uri_path = file[5:] # Remove "ul://"
|
|
621
633
|
local_file = Path(download_dir) / uri_path / url2file(url)
|
|
634
|
+
# Always re-download NDJSON datasets (cheap, ensures fresh data after updates)
|
|
635
|
+
if local_file.suffix == ".ndjson":
|
|
636
|
+
local_file.unlink(missing_ok=True)
|
|
622
637
|
if local_file.exists():
|
|
623
638
|
LOGGER.info(f"Found {clean_url(url)} locally at {local_file}")
|
|
624
639
|
else:
|
|
@@ -660,7 +675,7 @@ def check_yaml(file, suffix=(".yaml", ".yml"), hard=True):
|
|
|
660
675
|
return check_file(file, suffix, hard=hard)
|
|
661
676
|
|
|
662
677
|
|
|
663
|
-
def check_is_path_safe(basedir, path):
|
|
678
|
+
def check_is_path_safe(basedir: Path | str, path: Path | str) -> bool:
|
|
664
679
|
"""Check if the resolved path is under the intended directory to prevent path traversal.
|
|
665
680
|
|
|
666
681
|
Args:
|
ultralytics/utils/dist.py
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
3
5
|
import os
|
|
4
6
|
import shutil
|
|
5
7
|
import sys
|
|
6
8
|
import tempfile
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
7
10
|
|
|
8
11
|
from . import USER_CONFIG_DIR
|
|
9
12
|
from .torch_utils import TORCH_1_9
|
|
10
13
|
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from ultralytics.engine.trainer import BaseTrainer
|
|
16
|
+
|
|
11
17
|
|
|
12
18
|
def find_free_network_port() -> int:
|
|
13
19
|
"""Find a free port on localhost.
|
|
@@ -25,7 +31,7 @@ def find_free_network_port() -> int:
|
|
|
25
31
|
return s.getsockname()[1] # port
|
|
26
32
|
|
|
27
33
|
|
|
28
|
-
def generate_ddp_file(trainer):
|
|
34
|
+
def generate_ddp_file(trainer: BaseTrainer) -> str:
|
|
29
35
|
"""Generate a DDP (Distributed Data Parallel) file for multi-GPU training.
|
|
30
36
|
|
|
31
37
|
This function creates a temporary Python file that enables distributed training across multiple GPUs. The file
|
|
@@ -75,7 +81,7 @@ if __name__ == "__main__":
|
|
|
75
81
|
return file.name
|
|
76
82
|
|
|
77
83
|
|
|
78
|
-
def generate_ddp_command(trainer):
|
|
84
|
+
def generate_ddp_command(trainer: BaseTrainer) -> tuple[list[str], str]:
|
|
79
85
|
"""Generate command for distributed training.
|
|
80
86
|
|
|
81
87
|
Args:
|
|
@@ -105,7 +111,7 @@ def generate_ddp_command(trainer):
|
|
|
105
111
|
return cmd, file
|
|
106
112
|
|
|
107
113
|
|
|
108
|
-
def ddp_cleanup(trainer, file):
|
|
114
|
+
def ddp_cleanup(trainer: BaseTrainer, file: str) -> None:
|
|
109
115
|
"""Delete temporary file if created during distributed data parallel (DDP) training.
|
|
110
116
|
|
|
111
117
|
This function checks if the provided file contains the trainer's ID in its name, indicating it was created as a
|
ultralytics/utils/loss.py
CHANGED
|
@@ -1105,7 +1105,7 @@ class v8OBBLoss(v8DetectionLoss):
|
|
|
1105
1105
|
pred_theta = pred_bboxes[..., 4]
|
|
1106
1106
|
target_theta = target_bboxes[..., 4]
|
|
1107
1107
|
|
|
1108
|
-
log_ar = torch.log(w_gt / h_gt)
|
|
1108
|
+
log_ar = torch.log((w_gt + 1e-9) / (h_gt + 1e-9))
|
|
1109
1109
|
scale_weight = torch.exp(-(log_ar**2) / (lambda_val**2))
|
|
1110
1110
|
|
|
1111
1111
|
delta_theta = pred_theta - target_theta
|
|
@@ -1174,9 +1174,9 @@ class E2ELoss:
|
|
|
1174
1174
|
class TVPDetectLoss:
|
|
1175
1175
|
"""Criterion class for computing training losses for text-visual prompt detection."""
|
|
1176
1176
|
|
|
1177
|
-
def __init__(self, model, tal_topk=10):
|
|
1177
|
+
def __init__(self, model, tal_topk=10, tal_topk2: int | None = None):
|
|
1178
1178
|
"""Initialize TVPDetectLoss with task-prompt and visual-prompt criteria using the provided model."""
|
|
1179
|
-
self.vp_criterion = v8DetectionLoss(model, tal_topk)
|
|
1179
|
+
self.vp_criterion = v8DetectionLoss(model, tal_topk, tal_topk2)
|
|
1180
1180
|
# NOTE: store following info as it's changeable in __call__
|
|
1181
1181
|
self.hyp = self.vp_criterion.hyp
|
|
1182
1182
|
self.ori_nc = self.vp_criterion.nc
|
|
@@ -1206,8 +1206,7 @@ class TVPDetectLoss:
|
|
|
1206
1206
|
|
|
1207
1207
|
def _get_vp_features(self, preds: dict[str, torch.Tensor]) -> list[torch.Tensor]:
|
|
1208
1208
|
"""Extract visual-prompt features from the model output."""
|
|
1209
|
-
|
|
1210
|
-
scores = preds["scores"][:, self.ori_nc :, :]
|
|
1209
|
+
scores = preds["scores"]
|
|
1211
1210
|
vnc = scores.shape[1]
|
|
1212
1211
|
|
|
1213
1212
|
self.vp_criterion.nc = vnc
|
ultralytics/utils/tal.py
CHANGED
|
@@ -24,6 +24,7 @@ class TaskAlignedAssigner(nn.Module):
|
|
|
24
24
|
alpha (float): The alpha parameter for the classification component of the task-aligned metric.
|
|
25
25
|
beta (float): The beta parameter for the localization component of the task-aligned metric.
|
|
26
26
|
stride (list): List of stride values for different feature levels.
|
|
27
|
+
stride_val (int): The stride value used for select_candidates_in_gts.
|
|
27
28
|
eps (float): A small value to prevent division by zero.
|
|
28
29
|
"""
|
|
29
30
|
|
|
@@ -55,6 +56,7 @@ class TaskAlignedAssigner(nn.Module):
|
|
|
55
56
|
self.alpha = alpha
|
|
56
57
|
self.beta = beta
|
|
57
58
|
self.stride = stride
|
|
59
|
+
self.stride_val = self.stride[1] if len(self.stride) > 1 else self.stride[0]
|
|
58
60
|
self.eps = eps
|
|
59
61
|
|
|
60
62
|
@torch.no_grad()
|
|
@@ -302,8 +304,11 @@ class TaskAlignedAssigner(nn.Module):
|
|
|
302
304
|
"""
|
|
303
305
|
gt_bboxes_xywh = xyxy2xywh(gt_bboxes)
|
|
304
306
|
wh_mask = gt_bboxes_xywh[..., 2:] < self.stride[0] # the smallest stride
|
|
305
|
-
|
|
306
|
-
|
|
307
|
+
gt_bboxes_xywh[..., 2:] = torch.where(
|
|
308
|
+
(wh_mask * mask_gt).bool(),
|
|
309
|
+
torch.tensor(self.stride_val, dtype=gt_bboxes_xywh.dtype, device=gt_bboxes_xywh.device),
|
|
310
|
+
gt_bboxes_xywh[..., 2:],
|
|
311
|
+
)
|
|
307
312
|
gt_bboxes = xywh2xyxy(gt_bboxes_xywh)
|
|
308
313
|
|
|
309
314
|
n_anchors = xy_centers.shape[0]
|
|
@@ -357,19 +362,24 @@ class RotatedTaskAlignedAssigner(TaskAlignedAssigner):
|
|
|
357
362
|
"""Calculate IoU for rotated bounding boxes."""
|
|
358
363
|
return probiou(gt_bboxes, pd_bboxes).squeeze(-1).clamp_(0)
|
|
359
364
|
|
|
360
|
-
|
|
361
|
-
def select_candidates_in_gts(xy_centers, gt_bboxes, mask_gt):
|
|
365
|
+
def select_candidates_in_gts(self, xy_centers, gt_bboxes, mask_gt):
|
|
362
366
|
"""Select the positive anchor center in gt for rotated bounding boxes.
|
|
363
367
|
|
|
364
368
|
Args:
|
|
365
369
|
xy_centers (torch.Tensor): Anchor center coordinates with shape (h*w, 2).
|
|
366
370
|
gt_bboxes (torch.Tensor): Ground truth bounding boxes with shape (b, n_boxes, 5).
|
|
367
371
|
mask_gt (torch.Tensor): Mask for valid ground truth boxes with shape (b, n_boxes, 1).
|
|
368
|
-
stride (list[int]): List of stride values for each feature map level.
|
|
369
372
|
|
|
370
373
|
Returns:
|
|
371
374
|
(torch.Tensor): Boolean mask of positive anchors with shape (b, n_boxes, h*w).
|
|
372
375
|
"""
|
|
376
|
+
wh_mask = gt_bboxes[..., 2:4] < self.stride[0]
|
|
377
|
+
gt_bboxes[..., 2:4] = torch.where(
|
|
378
|
+
(wh_mask * mask_gt).bool(),
|
|
379
|
+
torch.tensor(self.stride_val, dtype=gt_bboxes.dtype, device=gt_bboxes.device),
|
|
380
|
+
gt_bboxes[..., 2:4],
|
|
381
|
+
)
|
|
382
|
+
|
|
373
383
|
# (b, n_boxes, 5) --> (b, n_boxes, 4, 2)
|
|
374
384
|
corners = xywhr2xyxyxyxy(gt_bboxes)
|
|
375
385
|
# (b, n_boxes, 1, 2)
|
ultralytics/utils/torch_utils.py
CHANGED
|
@@ -46,6 +46,7 @@ TORCH_2_1 = check_version(TORCH_VERSION, "2.1.0")
|
|
|
46
46
|
TORCH_2_4 = check_version(TORCH_VERSION, "2.4.0")
|
|
47
47
|
TORCH_2_8 = check_version(TORCH_VERSION, "2.8.0")
|
|
48
48
|
TORCH_2_9 = check_version(TORCH_VERSION, "2.9.0")
|
|
49
|
+
TORCH_2_10 = check_version(TORCH_VERSION, "2.10.0")
|
|
49
50
|
TORCHVISION_0_10 = check_version(TORCHVISION_VERSION, "0.10.0")
|
|
50
51
|
TORCHVISION_0_11 = check_version(TORCHVISION_VERSION, "0.11.0")
|
|
51
52
|
TORCHVISION_0_13 = check_version(TORCHVISION_VERSION, "0.13.0")
|
|
@@ -78,7 +79,7 @@ def smart_inference_mode():
|
|
|
78
79
|
if TORCH_1_9 and torch.is_inference_mode_enabled():
|
|
79
80
|
return fn # already in inference_mode, act as a pass-through
|
|
80
81
|
else:
|
|
81
|
-
return (torch.inference_mode if
|
|
82
|
+
return (torch.inference_mode if TORCH_1_10 else torch.no_grad)()(fn)
|
|
82
83
|
|
|
83
84
|
return decorate
|
|
84
85
|
|
{ultralytics_opencv_headless-8.4.7.dist-info → ultralytics_opencv_headless-8.4.9.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ultralytics-opencv-headless
|
|
3
|
-
Version: 8.4.
|
|
3
|
+
Version: 8.4.9
|
|
4
4
|
Summary: Ultralytics YOLO 🚀 for SOTA object detection, multi-object tracking, instance segmentation, pose estimation and image classification.
|
|
5
5
|
Author-email: Glenn Jocher <glenn.jocher@ultralytics.com>, Jing Qiu <jing.qiu@ultralytics.com>
|
|
6
6
|
Maintainer-email: Ultralytics <hello@ultralytics.com>
|
|
@@ -39,8 +39,8 @@ Requires-Dist: pillow>=7.1.2
|
|
|
39
39
|
Requires-Dist: pyyaml>=5.3.1
|
|
40
40
|
Requires-Dist: requests>=2.23.0
|
|
41
41
|
Requires-Dist: scipy>=1.4.1
|
|
42
|
-
Requires-Dist: torch
|
|
43
|
-
Requires-Dist: torch!=2.4.0
|
|
42
|
+
Requires-Dist: torch>=1.8.0
|
|
43
|
+
Requires-Dist: torch!=2.4.0,>=1.8.0; sys_platform == "win32"
|
|
44
44
|
Requires-Dist: torchvision>=0.9.0
|
|
45
45
|
Requires-Dist: psutil>=5.8.0
|
|
46
46
|
Requires-Dist: polars>=0.20.0
|