ultralytics 8.1.28__py3-none-any.whl → 8.3.62__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/__init__.py +22 -0
- tests/conftest.py +83 -0
- tests/test_cli.py +122 -0
- tests/test_cuda.py +155 -0
- tests/test_engine.py +131 -0
- tests/test_exports.py +216 -0
- tests/test_integrations.py +150 -0
- tests/test_python.py +615 -0
- tests/test_solutions.py +94 -0
- ultralytics/__init__.py +11 -8
- ultralytics/cfg/__init__.py +569 -131
- ultralytics/cfg/datasets/Argoverse.yaml +2 -1
- ultralytics/cfg/datasets/DOTAv1.5.yaml +3 -2
- ultralytics/cfg/datasets/DOTAv1.yaml +3 -2
- ultralytics/cfg/datasets/GlobalWheat2020.yaml +3 -2
- ultralytics/cfg/datasets/ImageNet.yaml +2 -1
- ultralytics/cfg/datasets/Objects365.yaml +5 -4
- ultralytics/cfg/datasets/SKU-110K.yaml +2 -1
- ultralytics/cfg/datasets/VOC.yaml +3 -2
- ultralytics/cfg/datasets/VisDrone.yaml +6 -5
- ultralytics/cfg/datasets/african-wildlife.yaml +25 -0
- ultralytics/cfg/datasets/brain-tumor.yaml +23 -0
- ultralytics/cfg/datasets/carparts-seg.yaml +3 -2
- ultralytics/cfg/datasets/coco-pose.yaml +7 -6
- ultralytics/cfg/datasets/coco.yaml +3 -2
- ultralytics/cfg/datasets/coco128-seg.yaml +4 -3
- ultralytics/cfg/datasets/coco128.yaml +4 -3
- ultralytics/cfg/datasets/coco8-pose.yaml +3 -2
- ultralytics/cfg/datasets/coco8-seg.yaml +3 -2
- ultralytics/cfg/datasets/coco8.yaml +3 -2
- ultralytics/cfg/datasets/crack-seg.yaml +3 -2
- ultralytics/cfg/datasets/dog-pose.yaml +24 -0
- ultralytics/cfg/datasets/dota8.yaml +3 -2
- ultralytics/cfg/datasets/hand-keypoints.yaml +26 -0
- ultralytics/cfg/datasets/lvis.yaml +1236 -0
- ultralytics/cfg/datasets/medical-pills.yaml +22 -0
- ultralytics/cfg/datasets/open-images-v7.yaml +2 -1
- ultralytics/cfg/datasets/package-seg.yaml +5 -4
- ultralytics/cfg/datasets/signature.yaml +21 -0
- ultralytics/cfg/datasets/tiger-pose.yaml +3 -2
- ultralytics/cfg/datasets/xView.yaml +2 -1
- ultralytics/cfg/default.yaml +14 -11
- ultralytics/cfg/models/11/yolo11-cls-resnet18.yaml +24 -0
- ultralytics/cfg/models/11/yolo11-cls.yaml +33 -0
- ultralytics/cfg/models/11/yolo11-obb.yaml +50 -0
- ultralytics/cfg/models/11/yolo11-pose.yaml +51 -0
- ultralytics/cfg/models/11/yolo11-seg.yaml +50 -0
- ultralytics/cfg/models/11/yolo11.yaml +50 -0
- ultralytics/cfg/models/rt-detr/rtdetr-l.yaml +5 -2
- ultralytics/cfg/models/rt-detr/rtdetr-resnet101.yaml +5 -2
- ultralytics/cfg/models/rt-detr/rtdetr-resnet50.yaml +5 -2
- ultralytics/cfg/models/rt-detr/rtdetr-x.yaml +5 -2
- ultralytics/cfg/models/v10/yolov10b.yaml +45 -0
- ultralytics/cfg/models/v10/yolov10l.yaml +45 -0
- ultralytics/cfg/models/v10/yolov10m.yaml +45 -0
- ultralytics/cfg/models/v10/yolov10n.yaml +45 -0
- ultralytics/cfg/models/v10/yolov10s.yaml +45 -0
- ultralytics/cfg/models/v10/yolov10x.yaml +45 -0
- ultralytics/cfg/models/v3/yolov3-spp.yaml +5 -2
- ultralytics/cfg/models/v3/yolov3-tiny.yaml +5 -2
- ultralytics/cfg/models/v3/yolov3.yaml +5 -2
- ultralytics/cfg/models/v5/yolov5-p6.yaml +5 -2
- ultralytics/cfg/models/v5/yolov5.yaml +5 -2
- ultralytics/cfg/models/v6/yolov6.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-cls-resnet101.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-cls-resnet50.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-cls.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-ghost-p2.yaml +6 -2
- ultralytics/cfg/models/v8/yolov8-ghost-p6.yaml +6 -2
- ultralytics/cfg/models/v8/yolov8-ghost.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-obb.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-p2.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-p6.yaml +10 -7
- ultralytics/cfg/models/v8/yolov8-pose-p6.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-pose.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-rtdetr.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-seg-p6.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-seg.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-world.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-worldv2.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8.yaml +5 -2
- ultralytics/cfg/models/v9/yolov9c-seg.yaml +41 -0
- ultralytics/cfg/models/v9/yolov9c.yaml +30 -25
- ultralytics/cfg/models/v9/yolov9e-seg.yaml +64 -0
- ultralytics/cfg/models/v9/yolov9e.yaml +46 -42
- ultralytics/cfg/models/v9/yolov9m.yaml +41 -0
- ultralytics/cfg/models/v9/yolov9s.yaml +41 -0
- ultralytics/cfg/models/v9/yolov9t.yaml +41 -0
- ultralytics/cfg/solutions/default.yaml +24 -0
- ultralytics/cfg/trackers/botsort.yaml +8 -5
- ultralytics/cfg/trackers/bytetrack.yaml +8 -5
- ultralytics/data/__init__.py +14 -3
- ultralytics/data/annotator.py +37 -15
- ultralytics/data/augment.py +1783 -289
- ultralytics/data/base.py +62 -27
- ultralytics/data/build.py +36 -8
- ultralytics/data/converter.py +196 -36
- ultralytics/data/dataset.py +233 -94
- ultralytics/data/loaders.py +199 -96
- ultralytics/data/split_dota.py +39 -29
- ultralytics/data/utils.py +110 -40
- ultralytics/engine/__init__.py +1 -1
- ultralytics/engine/exporter.py +569 -242
- ultralytics/engine/model.py +604 -252
- ultralytics/engine/predictor.py +22 -11
- ultralytics/engine/results.py +1228 -218
- ultralytics/engine/trainer.py +190 -129
- ultralytics/engine/tuner.py +18 -18
- ultralytics/engine/validator.py +18 -15
- ultralytics/hub/__init__.py +31 -13
- ultralytics/hub/auth.py +11 -7
- ultralytics/hub/google/__init__.py +159 -0
- ultralytics/hub/session.py +128 -94
- ultralytics/hub/utils.py +20 -21
- ultralytics/models/__init__.py +4 -2
- ultralytics/models/fastsam/__init__.py +2 -3
- ultralytics/models/fastsam/model.py +26 -4
- ultralytics/models/fastsam/predict.py +127 -63
- ultralytics/models/fastsam/utils.py +1 -44
- ultralytics/models/fastsam/val.py +1 -1
- ultralytics/models/nas/__init__.py +1 -1
- ultralytics/models/nas/model.py +21 -10
- ultralytics/models/nas/predict.py +3 -6
- ultralytics/models/nas/val.py +4 -4
- ultralytics/models/rtdetr/__init__.py +1 -1
- ultralytics/models/rtdetr/model.py +1 -1
- ultralytics/models/rtdetr/predict.py +6 -8
- ultralytics/models/rtdetr/train.py +6 -2
- ultralytics/models/rtdetr/val.py +3 -3
- ultralytics/models/sam/__init__.py +3 -3
- ultralytics/models/sam/amg.py +29 -23
- ultralytics/models/sam/build.py +211 -13
- ultralytics/models/sam/model.py +91 -30
- ultralytics/models/sam/modules/__init__.py +1 -1
- ultralytics/models/sam/modules/blocks.py +1129 -0
- ultralytics/models/sam/modules/decoders.py +381 -53
- ultralytics/models/sam/modules/encoders.py +515 -324
- ultralytics/models/sam/modules/memory_attention.py +237 -0
- ultralytics/models/sam/modules/sam.py +969 -21
- ultralytics/models/sam/modules/tiny_encoder.py +425 -154
- ultralytics/models/sam/modules/transformer.py +159 -60
- ultralytics/models/sam/modules/utils.py +293 -0
- ultralytics/models/sam/predict.py +1263 -132
- ultralytics/models/utils/__init__.py +1 -1
- ultralytics/models/utils/loss.py +36 -24
- ultralytics/models/utils/ops.py +3 -7
- ultralytics/models/yolo/__init__.py +3 -3
- ultralytics/models/yolo/classify/__init__.py +1 -1
- ultralytics/models/yolo/classify/predict.py +7 -8
- ultralytics/models/yolo/classify/train.py +17 -22
- ultralytics/models/yolo/classify/val.py +8 -4
- ultralytics/models/yolo/detect/__init__.py +1 -1
- ultralytics/models/yolo/detect/predict.py +3 -5
- ultralytics/models/yolo/detect/train.py +11 -4
- ultralytics/models/yolo/detect/val.py +90 -52
- ultralytics/models/yolo/model.py +14 -9
- ultralytics/models/yolo/obb/__init__.py +1 -1
- ultralytics/models/yolo/obb/predict.py +2 -2
- ultralytics/models/yolo/obb/train.py +5 -3
- ultralytics/models/yolo/obb/val.py +41 -23
- ultralytics/models/yolo/pose/__init__.py +1 -1
- ultralytics/models/yolo/pose/predict.py +3 -5
- ultralytics/models/yolo/pose/train.py +2 -2
- ultralytics/models/yolo/pose/val.py +51 -17
- ultralytics/models/yolo/segment/__init__.py +1 -1
- ultralytics/models/yolo/segment/predict.py +3 -5
- ultralytics/models/yolo/segment/train.py +2 -2
- ultralytics/models/yolo/segment/val.py +60 -19
- ultralytics/models/yolo/world/__init__.py +5 -0
- ultralytics/models/yolo/world/train.py +92 -0
- ultralytics/models/yolo/world/train_world.py +109 -0
- ultralytics/nn/__init__.py +1 -1
- ultralytics/nn/autobackend.py +228 -93
- ultralytics/nn/modules/__init__.py +39 -14
- ultralytics/nn/modules/activation.py +21 -0
- ultralytics/nn/modules/block.py +527 -67
- ultralytics/nn/modules/conv.py +24 -7
- ultralytics/nn/modules/head.py +177 -34
- ultralytics/nn/modules/transformer.py +6 -5
- ultralytics/nn/modules/utils.py +1 -2
- ultralytics/nn/tasks.py +225 -77
- ultralytics/solutions/__init__.py +30 -1
- ultralytics/solutions/ai_gym.py +96 -143
- ultralytics/solutions/analytics.py +247 -0
- ultralytics/solutions/distance_calculation.py +78 -135
- ultralytics/solutions/heatmap.py +93 -247
- ultralytics/solutions/object_counter.py +184 -259
- ultralytics/solutions/parking_management.py +246 -0
- ultralytics/solutions/queue_management.py +112 -0
- ultralytics/solutions/region_counter.py +116 -0
- ultralytics/solutions/security_alarm.py +144 -0
- ultralytics/solutions/solutions.py +178 -0
- ultralytics/solutions/speed_estimation.py +86 -174
- ultralytics/solutions/streamlit_inference.py +190 -0
- ultralytics/solutions/trackzone.py +68 -0
- ultralytics/trackers/__init__.py +1 -1
- ultralytics/trackers/basetrack.py +32 -13
- ultralytics/trackers/bot_sort.py +61 -28
- ultralytics/trackers/byte_tracker.py +83 -51
- ultralytics/trackers/track.py +21 -6
- ultralytics/trackers/utils/__init__.py +1 -1
- ultralytics/trackers/utils/gmc.py +62 -48
- ultralytics/trackers/utils/kalman_filter.py +166 -35
- ultralytics/trackers/utils/matching.py +40 -21
- ultralytics/utils/__init__.py +511 -239
- ultralytics/utils/autobatch.py +40 -22
- ultralytics/utils/benchmarks.py +266 -85
- ultralytics/utils/callbacks/__init__.py +1 -1
- ultralytics/utils/callbacks/base.py +1 -3
- ultralytics/utils/callbacks/clearml.py +7 -6
- ultralytics/utils/callbacks/comet.py +39 -17
- ultralytics/utils/callbacks/dvc.py +1 -1
- ultralytics/utils/callbacks/hub.py +16 -16
- ultralytics/utils/callbacks/mlflow.py +28 -24
- ultralytics/utils/callbacks/neptune.py +6 -2
- ultralytics/utils/callbacks/raytune.py +3 -4
- ultralytics/utils/callbacks/tensorboard.py +18 -18
- ultralytics/utils/callbacks/wb.py +27 -20
- ultralytics/utils/checks.py +160 -100
- ultralytics/utils/dist.py +2 -1
- ultralytics/utils/downloads.py +44 -37
- ultralytics/utils/errors.py +1 -1
- ultralytics/utils/files.py +72 -38
- ultralytics/utils/instance.py +41 -19
- ultralytics/utils/loss.py +84 -56
- ultralytics/utils/metrics.py +61 -56
- ultralytics/utils/ops.py +94 -89
- ultralytics/utils/patches.py +30 -14
- ultralytics/utils/plotting.py +600 -269
- ultralytics/utils/tal.py +67 -26
- ultralytics/utils/torch_utils.py +302 -102
- ultralytics/utils/triton.py +2 -1
- ultralytics/utils/tuner.py +21 -12
- ultralytics-8.3.62.dist-info/METADATA +370 -0
- ultralytics-8.3.62.dist-info/RECORD +241 -0
- {ultralytics-8.1.28.dist-info → ultralytics-8.3.62.dist-info}/WHEEL +1 -1
- ultralytics/data/explorer/__init__.py +0 -5
- ultralytics/data/explorer/explorer.py +0 -472
- ultralytics/data/explorer/gui/__init__.py +0 -1
- ultralytics/data/explorer/gui/dash.py +0 -268
- ultralytics/data/explorer/utils.py +0 -166
- ultralytics/models/fastsam/prompt.py +0 -357
- ultralytics-8.1.28.dist-info/METADATA +0 -373
- ultralytics-8.1.28.dist-info/RECORD +0 -197
- {ultralytics-8.1.28.dist-info → ultralytics-8.3.62.dist-info}/LICENSE +0 -0
- {ultralytics-8.1.28.dist-info → ultralytics-8.3.62.dist-info}/entry_points.txt +0 -0
- {ultralytics-8.1.28.dist-info → ultralytics-8.3.62.dist-info}/top_level.txt +0 -0
ultralytics/utils/checks.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1
|
-
# Ultralytics
|
1
|
+
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
2
2
|
|
3
|
-
import contextlib
|
4
3
|
import glob
|
5
4
|
import inspect
|
6
5
|
import math
|
@@ -18,16 +17,24 @@ import cv2
|
|
18
17
|
import numpy as np
|
19
18
|
import requests
|
20
19
|
import torch
|
21
|
-
from matplotlib import font_manager
|
22
20
|
|
23
21
|
from ultralytics.utils import (
|
24
22
|
ASSETS,
|
25
23
|
AUTOINSTALL,
|
24
|
+
IS_COLAB,
|
25
|
+
IS_GIT_DIR,
|
26
|
+
IS_KAGGLE,
|
27
|
+
IS_PIP_PACKAGE,
|
26
28
|
LINUX,
|
27
29
|
LOGGER,
|
30
|
+
MACOS,
|
28
31
|
ONLINE,
|
32
|
+
PYTHON_VERSION,
|
29
33
|
ROOT,
|
34
|
+
TORCHVISION_VERSION,
|
30
35
|
USER_CONFIG_DIR,
|
36
|
+
WINDOWS,
|
37
|
+
Retry,
|
31
38
|
SimpleNamespace,
|
32
39
|
ThreadingLocked,
|
33
40
|
TryExcept,
|
@@ -35,18 +42,10 @@ from ultralytics.utils import (
|
|
35
42
|
colorstr,
|
36
43
|
downloads,
|
37
44
|
emojis,
|
38
|
-
is_colab,
|
39
|
-
is_docker,
|
40
45
|
is_github_action_running,
|
41
|
-
is_jupyter,
|
42
|
-
is_kaggle,
|
43
|
-
is_online,
|
44
|
-
is_pip_package,
|
45
46
|
url2file,
|
46
47
|
)
|
47
48
|
|
48
|
-
PYTHON_VERSION = platform.python_version()
|
49
|
-
|
50
49
|
|
51
50
|
def parse_requirements(file_path=ROOT.parent / "requirements.txt", package=""):
|
52
51
|
"""
|
@@ -63,10 +62,9 @@ def parse_requirements(file_path=ROOT.parent / "requirements.txt", package=""):
|
|
63
62
|
```python
|
64
63
|
from ultralytics.utils.checks import parse_requirements
|
65
64
|
|
66
|
-
parse_requirements(package=
|
65
|
+
parse_requirements(package="ultralytics")
|
67
66
|
```
|
68
67
|
"""
|
69
|
-
|
70
68
|
if package:
|
71
69
|
requires = [x for x in metadata.distribution(package).requires if "extra == " not in x]
|
72
70
|
else:
|
@@ -77,8 +75,7 @@ def parse_requirements(file_path=ROOT.parent / "requirements.txt", package=""):
|
|
77
75
|
line = line.strip()
|
78
76
|
if line and not line.startswith("#"):
|
79
77
|
line = line.split("#")[0].strip() # ignore inline comments
|
80
|
-
match
|
81
|
-
if match:
|
78
|
+
if match := re.match(r"([a-zA-Z0-9-_]+)\s*([<>!=~]+.*)?", line):
|
82
79
|
requirements.append(SimpleNamespace(name=match[1], specifier=match[2].strip() if match[2] else ""))
|
83
80
|
|
84
81
|
return requirements
|
@@ -142,6 +139,8 @@ def check_imgsz(imgsz, stride=32, min_dim=1, max_dim=2, floor=0):
|
|
142
139
|
imgsz = [imgsz]
|
143
140
|
elif isinstance(imgsz, (list, tuple)):
|
144
141
|
imgsz = list(imgsz)
|
142
|
+
elif isinstance(imgsz, str): # i.e. '640' or '[640,640]'
|
143
|
+
imgsz = [int(imgsz)] if imgsz.isnumeric() else eval(imgsz)
|
145
144
|
else:
|
146
145
|
raise TypeError(
|
147
146
|
f"'imgsz={imgsz}' is of invalid type {type(imgsz).__name__}. "
|
@@ -196,16 +195,16 @@ def check_version(
|
|
196
195
|
Example:
|
197
196
|
```python
|
198
197
|
# Check if current version is exactly 22.04
|
199
|
-
check_version(current=
|
198
|
+
check_version(current="22.04", required="==22.04")
|
200
199
|
|
201
200
|
# Check if current version is greater than or equal to 22.04
|
202
|
-
check_version(current=
|
201
|
+
check_version(current="22.10", required="22.04") # assumes '>=' inequality if none passed
|
203
202
|
|
204
203
|
# Check if current version is less than or equal to 22.04
|
205
|
-
check_version(current=
|
204
|
+
check_version(current="22.04", required="<=22.04")
|
206
205
|
|
207
206
|
# Check if current version is between 20.04 (inclusive) and 22.04 (exclusive)
|
208
|
-
check_version(current=
|
207
|
+
check_version(current="21.10", required=">20.04,<22.04")
|
209
208
|
```
|
210
209
|
"""
|
211
210
|
if not current: # if current is '' or None
|
@@ -224,18 +223,27 @@ def check_version(
|
|
224
223
|
if not required: # if required is '' or None
|
225
224
|
return True
|
226
225
|
|
226
|
+
if "sys_platform" in required and ( # i.e. required='<2.4.0,>=1.8.0; sys_platform == "win32"'
|
227
|
+
(WINDOWS and "win32" not in required)
|
228
|
+
or (LINUX and "linux" not in required)
|
229
|
+
or (MACOS and "macos" not in required and "darwin" not in required)
|
230
|
+
):
|
231
|
+
return True
|
232
|
+
|
227
233
|
op = ""
|
228
234
|
version = ""
|
229
235
|
result = True
|
230
236
|
c = parse_version(current) # '1.2.3' -> (1, 2, 3)
|
231
237
|
for r in required.strip(",").split(","):
|
232
238
|
op, version = re.match(r"([^0-9]*)([\d.]+)", r).groups() # split '>=22.04' -> ('>=', '22.04')
|
239
|
+
if not op:
|
240
|
+
op = ">=" # assume >= if no op passed
|
233
241
|
v = parse_version(version) # '1.2.3' -> (1, 2, 3)
|
234
242
|
if op == "==" and c != v:
|
235
243
|
result = False
|
236
244
|
elif op == "!=" and c == v:
|
237
245
|
result = False
|
238
|
-
elif op
|
246
|
+
elif op == ">=" and not (c >= v):
|
239
247
|
result = False
|
240
248
|
elif op == "<=" and not (c <= v):
|
241
249
|
result = False
|
@@ -256,17 +264,19 @@ def check_latest_pypi_version(package_name="ultralytics"):
|
|
256
264
|
"""
|
257
265
|
Returns the latest version of a PyPI package without downloading or installing it.
|
258
266
|
|
259
|
-
|
267
|
+
Args:
|
260
268
|
package_name (str): The name of the package to find the latest version for.
|
261
269
|
|
262
270
|
Returns:
|
263
271
|
(str): The latest version of the package.
|
264
272
|
"""
|
265
|
-
|
273
|
+
try:
|
266
274
|
requests.packages.urllib3.disable_warnings() # Disable the InsecureRequestWarning
|
267
275
|
response = requests.get(f"https://pypi.org/pypi/{package_name}/json", timeout=3)
|
268
276
|
if response.status_code == 200:
|
269
277
|
return response.json()["info"]["version"]
|
278
|
+
except Exception:
|
279
|
+
return None
|
270
280
|
|
271
281
|
|
272
282
|
def check_pip_update_available():
|
@@ -276,8 +286,8 @@ def check_pip_update_available():
|
|
276
286
|
Returns:
|
277
287
|
(bool): True if an update is available, False otherwise.
|
278
288
|
"""
|
279
|
-
if ONLINE and
|
280
|
-
|
289
|
+
if ONLINE and IS_PIP_PACKAGE:
|
290
|
+
try:
|
281
291
|
from ultralytics import __version__
|
282
292
|
|
283
293
|
latest = check_latest_pypi_version()
|
@@ -287,6 +297,8 @@ def check_pip_update_available():
|
|
287
297
|
f"Update with 'pip install -U ultralytics'"
|
288
298
|
)
|
289
299
|
return True
|
300
|
+
except Exception:
|
301
|
+
pass
|
290
302
|
return False
|
291
303
|
|
292
304
|
|
@@ -301,9 +313,10 @@ def check_font(font="Arial.ttf"):
|
|
301
313
|
Returns:
|
302
314
|
file (Path): Resolved font file path.
|
303
315
|
"""
|
304
|
-
|
316
|
+
from matplotlib import font_manager
|
305
317
|
|
306
318
|
# Check USER_CONFIG_DIR
|
319
|
+
name = Path(font).name
|
307
320
|
file = USER_CONFIG_DIR / name
|
308
321
|
if file.exists():
|
309
322
|
return file
|
@@ -314,23 +327,25 @@ def check_font(font="Arial.ttf"):
|
|
314
327
|
return matches[0]
|
315
328
|
|
316
329
|
# Download to USER_CONFIG_DIR if missing
|
317
|
-
url = f"https://
|
318
|
-
if downloads.is_url(url):
|
330
|
+
url = f"https://github.com/ultralytics/assets/releases/download/v0.0.0/{name}"
|
331
|
+
if downloads.is_url(url, check=True):
|
319
332
|
downloads.safe_download(url=url, file=file)
|
320
333
|
return file
|
321
334
|
|
322
335
|
|
323
|
-
def check_python(minimum: str = "3.8.0") -> bool:
|
336
|
+
def check_python(minimum: str = "3.8.0", hard: bool = True, verbose: bool = False) -> bool:
|
324
337
|
"""
|
325
338
|
Check current python version against the required minimum version.
|
326
339
|
|
327
340
|
Args:
|
328
341
|
minimum (str): Required minimum version of python.
|
342
|
+
hard (bool, optional): If True, raise an AssertionError if the requirement is not met.
|
343
|
+
verbose (bool, optional): If True, print warning message if requirement is not met.
|
329
344
|
|
330
345
|
Returns:
|
331
346
|
(bool): Whether the installed Python version meets the minimum constraints.
|
332
347
|
"""
|
333
|
-
return check_version(PYTHON_VERSION, minimum, name="Python
|
348
|
+
return check_version(PYTHON_VERSION, minimum, name="Python", hard=hard, verbose=verbose)
|
334
349
|
|
335
350
|
|
336
351
|
@TryExcept()
|
@@ -350,19 +365,16 @@ def check_requirements(requirements=ROOT.parent / "requirements.txt", exclude=()
|
|
350
365
|
from ultralytics.utils.checks import check_requirements
|
351
366
|
|
352
367
|
# Check a requirements.txt file
|
353
|
-
check_requirements(
|
368
|
+
check_requirements("path/to/requirements.txt")
|
354
369
|
|
355
370
|
# Check a single package
|
356
|
-
check_requirements(
|
371
|
+
check_requirements("ultralytics>=8.0.0")
|
357
372
|
|
358
373
|
# Check multiple packages
|
359
|
-
check_requirements([
|
374
|
+
check_requirements(["numpy", "ultralytics>=8.0.0"])
|
360
375
|
```
|
361
376
|
"""
|
362
|
-
|
363
377
|
prefix = colorstr("red", "bold", "requirements:")
|
364
|
-
check_python() # check python version
|
365
|
-
check_torchvision() # check torch-torchvision compatibility
|
366
378
|
if isinstance(requirements, Path): # requirements.txt file
|
367
379
|
file = requirements.resolve()
|
368
380
|
assert file.exists(), f"{prefix} {file} not found, check failed."
|
@@ -380,6 +392,11 @@ def check_requirements(requirements=ROOT.parent / "requirements.txt", exclude=()
|
|
380
392
|
except (AssertionError, metadata.PackageNotFoundError):
|
381
393
|
pkgs.append(r)
|
382
394
|
|
395
|
+
@Retry(times=2, delay=1)
|
396
|
+
def attempt_install(packages, commands):
|
397
|
+
"""Attempt pip install command with retries on failure."""
|
398
|
+
return subprocess.check_output(f"pip install --no-cache-dir {packages} {commands}", shell=True).decode()
|
399
|
+
|
383
400
|
s = " ".join(f'"{x}"' for x in pkgs) # console string
|
384
401
|
if s:
|
385
402
|
if install and AUTOINSTALL: # check environment variable
|
@@ -387,8 +404,8 @@ def check_requirements(requirements=ROOT.parent / "requirements.txt", exclude=()
|
|
387
404
|
LOGGER.info(f"{prefix} Ultralytics requirement{'s' * (n > 1)} {pkgs} not found, attempting AutoUpdate...")
|
388
405
|
try:
|
389
406
|
t = time.time()
|
390
|
-
assert
|
391
|
-
LOGGER.info(
|
407
|
+
assert ONLINE, "AutoUpdate skipped (offline)"
|
408
|
+
LOGGER.info(attempt_install(s, cmds))
|
392
409
|
dt = time.time() - t
|
393
410
|
LOGGER.info(
|
394
411
|
f"{prefix} AutoUpdate success ✅ {dt:.1f}s, installed {n} package{'s' * (n > 1)}: {pkgs}\n"
|
@@ -414,18 +431,23 @@ def check_torchvision():
|
|
414
431
|
The compatibility table is a dictionary where the keys are PyTorch versions and the values are lists of compatible
|
415
432
|
Torchvision versions.
|
416
433
|
"""
|
417
|
-
|
418
|
-
import torchvision
|
419
|
-
|
420
434
|
# Compatibility table
|
421
|
-
compatibility_table = {
|
435
|
+
compatibility_table = {
|
436
|
+
"2.5": ["0.20"],
|
437
|
+
"2.4": ["0.19"],
|
438
|
+
"2.3": ["0.18"],
|
439
|
+
"2.2": ["0.17"],
|
440
|
+
"2.1": ["0.16"],
|
441
|
+
"2.0": ["0.15"],
|
442
|
+
"1.13": ["0.14"],
|
443
|
+
"1.12": ["0.13"],
|
444
|
+
}
|
422
445
|
|
423
446
|
# Extract only the major and minor versions
|
424
447
|
v_torch = ".".join(torch.__version__.split("+")[0].split(".")[:2])
|
425
|
-
v_torchvision = ".".join(torchvision.__version__.split("+")[0].split(".")[:2])
|
426
|
-
|
427
448
|
if v_torch in compatibility_table:
|
428
449
|
compatible_versions = compatibility_table[v_torch]
|
450
|
+
v_torchvision = ".".join(TORCHVISION_VERSION.split("+")[0].split(".")[:2])
|
429
451
|
if all(v_torchvision != v for v in compatible_versions):
|
430
452
|
print(
|
431
453
|
f"WARNING ⚠️ torchvision=={v_torchvision} is incompatible with torch=={v_torch}.\n"
|
@@ -435,7 +457,7 @@ def check_torchvision():
|
|
435
457
|
)
|
436
458
|
|
437
459
|
|
438
|
-
def check_suffix(file="
|
460
|
+
def check_suffix(file="yolo11n.pt", suffix=".pt", msg=""):
|
439
461
|
"""Check file(s) for acceptable suffix."""
|
440
462
|
if file and suffix:
|
441
463
|
if isinstance(suffix, str):
|
@@ -473,7 +495,7 @@ def check_model_file_from_stem(model="yolov8n"):
|
|
473
495
|
return model
|
474
496
|
|
475
497
|
|
476
|
-
def check_file(file, suffix="", download=True, hard=True):
|
498
|
+
def check_file(file, suffix="", download=True, download_dir=".", hard=True):
|
477
499
|
"""Search/download file (if necessary) and return path."""
|
478
500
|
check_suffix(file, suffix) # optional
|
479
501
|
file = str(file).strip() # convert to string and strip spaces
|
@@ -486,12 +508,12 @@ def check_file(file, suffix="", download=True, hard=True):
|
|
486
508
|
return file
|
487
509
|
elif download and file.lower().startswith(("https://", "http://", "rtsp://", "rtmp://", "tcp://")): # download
|
488
510
|
url = file # warning: Pathlib turns :// -> :/
|
489
|
-
file = url2file(file) # '%2F' to '/', split https://url.com/file.txt?auth
|
490
|
-
if
|
511
|
+
file = Path(download_dir) / url2file(file) # '%2F' to '/', split https://url.com/file.txt?auth
|
512
|
+
if file.exists():
|
491
513
|
LOGGER.info(f"Found {clean_url(url)} locally at {file}") # file already exists
|
492
514
|
else:
|
493
515
|
downloads.safe_download(url=url, file=file, unzip=False)
|
494
|
-
return file
|
516
|
+
return str(file)
|
495
517
|
else: # search
|
496
518
|
files = glob.glob(str(ROOT / "**" / file), recursive=True) or glob.glob(str(ROOT.parent / file)) # find file
|
497
519
|
if not files and hard:
|
@@ -520,14 +542,15 @@ def check_is_path_safe(basedir, path):
|
|
520
542
|
base_dir_resolved = Path(basedir).resolve()
|
521
543
|
path_resolved = Path(path).resolve()
|
522
544
|
|
523
|
-
return path_resolved.
|
545
|
+
return path_resolved.exists() and path_resolved.parts[: len(base_dir_resolved.parts)] == base_dir_resolved.parts
|
524
546
|
|
525
547
|
|
526
548
|
def check_imshow(warn=False):
|
527
549
|
"""Check if environment supports image displays."""
|
528
550
|
try:
|
529
551
|
if LINUX:
|
530
|
-
assert
|
552
|
+
assert not IS_COLAB and not IS_KAGGLE
|
553
|
+
assert "DISPLAY" in os.environ, "The DISPLAY environment variable isn't set."
|
531
554
|
cv2.imshow("test", np.zeros((8, 8, 3), dtype=np.uint8)) # show a small 8-pixel image
|
532
555
|
cv2.waitKey(1)
|
533
556
|
cv2.destroyAllWindows()
|
@@ -545,11 +568,8 @@ def check_yolo(verbose=True, device=""):
|
|
545
568
|
|
546
569
|
from ultralytics.utils.torch_utils import select_device
|
547
570
|
|
548
|
-
if
|
549
|
-
|
550
|
-
os.system("pip uninstall -y wandb") # uninstall wandb: unwanted account creation prompt with infinite hang
|
551
|
-
if is_colab():
|
552
|
-
shutil.rmtree("sample_data", ignore_errors=True) # remove colab /sample_data directory
|
571
|
+
if IS_COLAB:
|
572
|
+
shutil.rmtree("sample_data", ignore_errors=True) # remove colab /sample_data directory
|
553
573
|
|
554
574
|
if verbose:
|
555
575
|
# System info
|
@@ -557,10 +577,12 @@ def check_yolo(verbose=True, device=""):
|
|
557
577
|
ram = psutil.virtual_memory().total
|
558
578
|
total, used, free = shutil.disk_usage("/")
|
559
579
|
s = f"({os.cpu_count()} CPUs, {ram / gib:.1f} GB RAM, {(total - free) / gib:.1f}/{total / gib:.1f} GB disk)"
|
560
|
-
|
580
|
+
try:
|
561
581
|
from IPython import display
|
562
582
|
|
563
|
-
display.clear_output()
|
583
|
+
display.clear_output() # clear display if notebook
|
584
|
+
except ImportError:
|
585
|
+
pass
|
564
586
|
else:
|
565
587
|
s = ""
|
566
588
|
|
@@ -570,92 +592,126 @@ def check_yolo(verbose=True, device=""):
|
|
570
592
|
|
571
593
|
def collect_system_info():
|
572
594
|
"""Collect and print relevant system information including OS, Python, RAM, CPU, and CUDA."""
|
573
|
-
|
574
595
|
import psutil
|
575
596
|
|
576
|
-
from ultralytics.utils import ENVIRONMENT
|
577
|
-
from ultralytics.utils.torch_utils import get_cpu_info
|
597
|
+
from ultralytics.utils import ENVIRONMENT # scope to avoid circular import
|
598
|
+
from ultralytics.utils.torch_utils import get_cpu_info, get_gpu_info
|
578
599
|
|
579
|
-
|
600
|
+
gib = 1 << 30 # bytes per GiB
|
601
|
+
cuda = torch and torch.cuda.is_available()
|
580
602
|
check_yolo()
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
f"{
|
589
|
-
|
590
|
-
|
603
|
+
total, used, free = shutil.disk_usage("/")
|
604
|
+
|
605
|
+
info_dict = {
|
606
|
+
"OS": platform.platform(),
|
607
|
+
"Environment": ENVIRONMENT,
|
608
|
+
"Python": PYTHON_VERSION,
|
609
|
+
"Install": "git" if IS_GIT_DIR else "pip" if IS_PIP_PACKAGE else "other",
|
610
|
+
"RAM": f"{psutil.virtual_memory().total / gib:.2f} GB",
|
611
|
+
"Disk": f"{(total - free) / gib:.1f}/{total / gib:.1f} GB",
|
612
|
+
"CPU": get_cpu_info(),
|
613
|
+
"CPU count": os.cpu_count(),
|
614
|
+
"GPU": get_gpu_info(index=0) if cuda else None,
|
615
|
+
"GPU count": torch.cuda.device_count() if cuda else None,
|
616
|
+
"CUDA": torch.version.cuda if cuda else None,
|
617
|
+
}
|
618
|
+
LOGGER.info("\n" + "\n".join(f"{k:<20}{v}" for k, v in info_dict.items()) + "\n")
|
619
|
+
|
620
|
+
package_info = {}
|
591
621
|
for r in parse_requirements(package="ultralytics"):
|
592
622
|
try:
|
593
623
|
current = metadata.version(r.name)
|
594
|
-
is_met = "✅ " if check_version(current, str(r.specifier), hard=True) else "❌ "
|
624
|
+
is_met = "✅ " if check_version(current, str(r.specifier), name=r.name, hard=True) else "❌ "
|
595
625
|
except metadata.PackageNotFoundError:
|
596
626
|
current = "(not installed)"
|
597
627
|
is_met = "❌ "
|
598
|
-
|
628
|
+
package_info[r.name] = f"{is_met}{current}{r.specifier}"
|
629
|
+
LOGGER.info(f"{r.name:<20}{package_info[r.name]}")
|
630
|
+
|
631
|
+
info_dict["Package Info"] = package_info
|
599
632
|
|
600
633
|
if is_github_action_running():
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
634
|
+
github_info = {
|
635
|
+
"RUNNER_OS": os.getenv("RUNNER_OS"),
|
636
|
+
"GITHUB_EVENT_NAME": os.getenv("GITHUB_EVENT_NAME"),
|
637
|
+
"GITHUB_WORKFLOW": os.getenv("GITHUB_WORKFLOW"),
|
638
|
+
"GITHUB_ACTOR": os.getenv("GITHUB_ACTOR"),
|
639
|
+
"GITHUB_REPOSITORY": os.getenv("GITHUB_REPOSITORY"),
|
640
|
+
"GITHUB_REPOSITORY_OWNER": os.getenv("GITHUB_REPOSITORY_OWNER"),
|
641
|
+
}
|
642
|
+
LOGGER.info("\n" + "\n".join(f"{k}: {v}" for k, v in github_info.items()))
|
643
|
+
info_dict["GitHub Info"] = github_info
|
644
|
+
|
645
|
+
return info_dict
|
609
646
|
|
610
647
|
|
611
648
|
def check_amp(model):
|
612
649
|
"""
|
613
|
-
|
614
|
-
|
615
|
-
|
650
|
+
Checks the PyTorch Automatic Mixed Precision (AMP) functionality of a YOLO11 model. If the checks fail, it means
|
651
|
+
there are anomalies with AMP on the system that may cause NaN losses or zero-mAP results, so AMP will be disabled
|
652
|
+
during training.
|
616
653
|
|
617
654
|
Args:
|
618
|
-
model (nn.Module): A
|
655
|
+
model (nn.Module): A YOLO11 model instance.
|
619
656
|
|
620
657
|
Example:
|
621
658
|
```python
|
622
659
|
from ultralytics import YOLO
|
623
660
|
from ultralytics.utils.checks import check_amp
|
624
661
|
|
625
|
-
model = YOLO(
|
662
|
+
model = YOLO("yolo11n.pt").model.cuda()
|
626
663
|
check_amp(model)
|
627
664
|
```
|
628
665
|
|
629
666
|
Returns:
|
630
|
-
(bool): Returns True if the AMP functionality works correctly with
|
667
|
+
(bool): Returns True if the AMP functionality works correctly with YOLO11 model, else False.
|
631
668
|
"""
|
669
|
+
from ultralytics.utils.torch_utils import autocast
|
670
|
+
|
632
671
|
device = next(model.parameters()).device # get model device
|
633
|
-
|
672
|
+
prefix = colorstr("AMP: ")
|
673
|
+
if device.type in {"cpu", "mps"}:
|
634
674
|
return False # AMP only used on CUDA devices
|
675
|
+
else:
|
676
|
+
# GPUs that have issues with AMP
|
677
|
+
pattern = re.compile(
|
678
|
+
r"(nvidia|geforce|quadro|tesla).*?(1660|1650|1630|t400|t550|t600|t1000|t1200|t2000|k40m)", re.IGNORECASE
|
679
|
+
)
|
680
|
+
|
681
|
+
gpu = torch.cuda.get_device_name(device)
|
682
|
+
if bool(pattern.search(gpu)):
|
683
|
+
LOGGER.warning(
|
684
|
+
f"{prefix}checks failed ❌. AMP training on {gpu} GPU may cause "
|
685
|
+
f"NaN losses or zero-mAP results, so AMP will be disabled during training."
|
686
|
+
)
|
687
|
+
return False
|
635
688
|
|
636
689
|
def amp_allclose(m, im):
|
637
690
|
"""All close FP32 vs AMP results."""
|
638
|
-
|
639
|
-
|
640
|
-
|
691
|
+
batch = [im] * 8
|
692
|
+
imgsz = max(256, int(model.stride.max() * 4)) # max stride P5-32 and P6-64
|
693
|
+
a = m(batch, imgsz=imgsz, device=device, verbose=False)[0].boxes.data # FP32 inference
|
694
|
+
with autocast(enabled=True):
|
695
|
+
b = m(batch, imgsz=imgsz, device=device, verbose=False)[0].boxes.data # AMP inference
|
641
696
|
del m
|
642
697
|
return a.shape == b.shape and torch.allclose(a, b.float(), atol=0.5) # close to 0.5 absolute tolerance
|
643
698
|
|
644
699
|
im = ASSETS / "bus.jpg" # image to check
|
645
|
-
prefix
|
646
|
-
LOGGER.info(f"{prefix}running Automatic Mixed Precision (AMP) checks with YOLOv8n...")
|
700
|
+
LOGGER.info(f"{prefix}running Automatic Mixed Precision (AMP) checks...")
|
647
701
|
warning_msg = "Setting 'amp=True'. If you experience zero-mAP or NaN losses you can disable AMP with amp=False."
|
648
702
|
try:
|
649
703
|
from ultralytics import YOLO
|
650
704
|
|
651
|
-
assert amp_allclose(YOLO("
|
705
|
+
assert amp_allclose(YOLO("yolo11n.pt"), im)
|
652
706
|
LOGGER.info(f"{prefix}checks passed ✅")
|
653
707
|
except ConnectionError:
|
654
|
-
LOGGER.warning(
|
708
|
+
LOGGER.warning(
|
709
|
+
f"{prefix}checks skipped ⚠️. Offline and unable to download YOLO11n for AMP checks. {warning_msg}"
|
710
|
+
)
|
655
711
|
except (AttributeError, ModuleNotFoundError):
|
656
712
|
LOGGER.warning(
|
657
713
|
f"{prefix}checks skipped ⚠️. "
|
658
|
-
f"Unable to load
|
714
|
+
f"Unable to load YOLO11n for AMP checks due to possible Ultralytics package modifications. {warning_msg}"
|
659
715
|
)
|
660
716
|
except AssertionError:
|
661
717
|
LOGGER.warning(
|
@@ -668,9 +724,10 @@ def check_amp(model):
|
|
668
724
|
|
669
725
|
def git_describe(path=ROOT): # path must be a directory
|
670
726
|
"""Return human-readable git description, i.e. v5.0-5-g3e25f1e https://git-scm.com/docs/git-describe."""
|
671
|
-
|
727
|
+
try:
|
672
728
|
return subprocess.check_output(f"git -C {path} describe --tags --long --always", shell=True).decode()[:-1]
|
673
|
-
|
729
|
+
except Exception:
|
730
|
+
return ""
|
674
731
|
|
675
732
|
|
676
733
|
def print_args(args: Optional[dict] = None, show_file=True, show_func=False):
|
@@ -725,5 +782,8 @@ def cuda_is_available() -> bool:
|
|
725
782
|
return cuda_device_count() > 0
|
726
783
|
|
727
784
|
|
728
|
-
#
|
729
|
-
|
785
|
+
# Run checks and define constants
|
786
|
+
check_python("3.8", hard=False, verbose=True) # check python version
|
787
|
+
check_torchvision() # check torch-torchvision compatibility
|
788
|
+
IS_PYTHON_MINIMUM_3_10 = check_python("3.10", hard=False)
|
789
|
+
IS_PYTHON_3_12 = PYTHON_VERSION.startswith("3.12")
|
ultralytics/utils/dist.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Ultralytics
|
1
|
+
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
2
2
|
|
3
3
|
import os
|
4
4
|
import shutil
|
@@ -37,6 +37,7 @@ if __name__ == "__main__":
|
|
37
37
|
cfg = DEFAULT_CFG_DICT.copy()
|
38
38
|
cfg.update(save_dir='') # handle the extra key 'save_dir'
|
39
39
|
trainer = {name}(cfg=cfg, overrides=overrides)
|
40
|
+
trainer.args.model = "{getattr(trainer.hub_session, "model_url", trainer.args.model)}"
|
40
41
|
results = trainer.train()
|
41
42
|
"""
|
42
43
|
(USER_CONFIG_DIR / "DDP").mkdir(exist_ok=True)
|