dgenerate-ultralytics-headless 8.3.137__py3-none-any.whl → 8.3.224__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.
Files changed (215) hide show
  1. {dgenerate_ultralytics_headless-8.3.137.dist-info → dgenerate_ultralytics_headless-8.3.224.dist-info}/METADATA +41 -34
  2. dgenerate_ultralytics_headless-8.3.224.dist-info/RECORD +285 -0
  3. {dgenerate_ultralytics_headless-8.3.137.dist-info → dgenerate_ultralytics_headless-8.3.224.dist-info}/WHEEL +1 -1
  4. tests/__init__.py +7 -6
  5. tests/conftest.py +15 -39
  6. tests/test_cli.py +17 -17
  7. tests/test_cuda.py +17 -8
  8. tests/test_engine.py +36 -10
  9. tests/test_exports.py +98 -37
  10. tests/test_integrations.py +12 -15
  11. tests/test_python.py +126 -82
  12. tests/test_solutions.py +319 -135
  13. ultralytics/__init__.py +27 -9
  14. ultralytics/cfg/__init__.py +83 -87
  15. ultralytics/cfg/datasets/Argoverse.yaml +4 -4
  16. ultralytics/cfg/datasets/DOTAv1.5.yaml +2 -2
  17. ultralytics/cfg/datasets/DOTAv1.yaml +2 -2
  18. ultralytics/cfg/datasets/GlobalWheat2020.yaml +2 -2
  19. ultralytics/cfg/datasets/HomeObjects-3K.yaml +4 -5
  20. ultralytics/cfg/datasets/ImageNet.yaml +3 -3
  21. ultralytics/cfg/datasets/Objects365.yaml +24 -20
  22. ultralytics/cfg/datasets/SKU-110K.yaml +9 -9
  23. ultralytics/cfg/datasets/VOC.yaml +10 -13
  24. ultralytics/cfg/datasets/VisDrone.yaml +43 -33
  25. ultralytics/cfg/datasets/african-wildlife.yaml +5 -5
  26. ultralytics/cfg/datasets/brain-tumor.yaml +4 -5
  27. ultralytics/cfg/datasets/carparts-seg.yaml +5 -5
  28. ultralytics/cfg/datasets/coco-pose.yaml +26 -4
  29. ultralytics/cfg/datasets/coco.yaml +4 -4
  30. ultralytics/cfg/datasets/coco128-seg.yaml +2 -2
  31. ultralytics/cfg/datasets/coco128.yaml +2 -2
  32. ultralytics/cfg/datasets/coco8-grayscale.yaml +103 -0
  33. ultralytics/cfg/datasets/coco8-multispectral.yaml +2 -2
  34. ultralytics/cfg/datasets/coco8-pose.yaml +23 -2
  35. ultralytics/cfg/datasets/coco8-seg.yaml +2 -2
  36. ultralytics/cfg/datasets/coco8.yaml +2 -2
  37. ultralytics/cfg/datasets/construction-ppe.yaml +32 -0
  38. ultralytics/cfg/datasets/crack-seg.yaml +5 -5
  39. ultralytics/cfg/datasets/dog-pose.yaml +32 -4
  40. ultralytics/cfg/datasets/dota8-multispectral.yaml +2 -2
  41. ultralytics/cfg/datasets/dota8.yaml +2 -2
  42. ultralytics/cfg/datasets/hand-keypoints.yaml +29 -4
  43. ultralytics/cfg/datasets/lvis.yaml +9 -9
  44. ultralytics/cfg/datasets/medical-pills.yaml +4 -5
  45. ultralytics/cfg/datasets/open-images-v7.yaml +7 -10
  46. ultralytics/cfg/datasets/package-seg.yaml +5 -5
  47. ultralytics/cfg/datasets/signature.yaml +4 -4
  48. ultralytics/cfg/datasets/tiger-pose.yaml +20 -4
  49. ultralytics/cfg/datasets/xView.yaml +5 -5
  50. ultralytics/cfg/default.yaml +96 -93
  51. ultralytics/cfg/trackers/botsort.yaml +16 -17
  52. ultralytics/cfg/trackers/bytetrack.yaml +9 -11
  53. ultralytics/data/__init__.py +4 -4
  54. ultralytics/data/annotator.py +12 -12
  55. ultralytics/data/augment.py +531 -564
  56. ultralytics/data/base.py +76 -81
  57. ultralytics/data/build.py +206 -42
  58. ultralytics/data/converter.py +179 -78
  59. ultralytics/data/dataset.py +121 -121
  60. ultralytics/data/loaders.py +114 -91
  61. ultralytics/data/split.py +28 -15
  62. ultralytics/data/split_dota.py +67 -48
  63. ultralytics/data/utils.py +110 -89
  64. ultralytics/engine/exporter.py +422 -460
  65. ultralytics/engine/model.py +224 -252
  66. ultralytics/engine/predictor.py +94 -89
  67. ultralytics/engine/results.py +345 -595
  68. ultralytics/engine/trainer.py +231 -134
  69. ultralytics/engine/tuner.py +279 -73
  70. ultralytics/engine/validator.py +53 -46
  71. ultralytics/hub/__init__.py +26 -28
  72. ultralytics/hub/auth.py +30 -16
  73. ultralytics/hub/google/__init__.py +34 -36
  74. ultralytics/hub/session.py +53 -77
  75. ultralytics/hub/utils.py +23 -109
  76. ultralytics/models/__init__.py +1 -1
  77. ultralytics/models/fastsam/__init__.py +1 -1
  78. ultralytics/models/fastsam/model.py +36 -18
  79. ultralytics/models/fastsam/predict.py +33 -44
  80. ultralytics/models/fastsam/utils.py +4 -5
  81. ultralytics/models/fastsam/val.py +12 -14
  82. ultralytics/models/nas/__init__.py +1 -1
  83. ultralytics/models/nas/model.py +16 -20
  84. ultralytics/models/nas/predict.py +12 -14
  85. ultralytics/models/nas/val.py +4 -5
  86. ultralytics/models/rtdetr/__init__.py +1 -1
  87. ultralytics/models/rtdetr/model.py +9 -9
  88. ultralytics/models/rtdetr/predict.py +22 -17
  89. ultralytics/models/rtdetr/train.py +20 -16
  90. ultralytics/models/rtdetr/val.py +79 -59
  91. ultralytics/models/sam/__init__.py +8 -2
  92. ultralytics/models/sam/amg.py +53 -38
  93. ultralytics/models/sam/build.py +29 -31
  94. ultralytics/models/sam/model.py +33 -38
  95. ultralytics/models/sam/modules/blocks.py +159 -182
  96. ultralytics/models/sam/modules/decoders.py +38 -47
  97. ultralytics/models/sam/modules/encoders.py +114 -133
  98. ultralytics/models/sam/modules/memory_attention.py +38 -31
  99. ultralytics/models/sam/modules/sam.py +114 -93
  100. ultralytics/models/sam/modules/tiny_encoder.py +268 -291
  101. ultralytics/models/sam/modules/transformer.py +59 -66
  102. ultralytics/models/sam/modules/utils.py +55 -72
  103. ultralytics/models/sam/predict.py +745 -341
  104. ultralytics/models/utils/loss.py +118 -107
  105. ultralytics/models/utils/ops.py +118 -71
  106. ultralytics/models/yolo/__init__.py +1 -1
  107. ultralytics/models/yolo/classify/predict.py +28 -26
  108. ultralytics/models/yolo/classify/train.py +50 -81
  109. ultralytics/models/yolo/classify/val.py +68 -61
  110. ultralytics/models/yolo/detect/predict.py +12 -15
  111. ultralytics/models/yolo/detect/train.py +56 -46
  112. ultralytics/models/yolo/detect/val.py +279 -223
  113. ultralytics/models/yolo/model.py +167 -86
  114. ultralytics/models/yolo/obb/predict.py +7 -11
  115. ultralytics/models/yolo/obb/train.py +23 -25
  116. ultralytics/models/yolo/obb/val.py +107 -99
  117. ultralytics/models/yolo/pose/__init__.py +1 -1
  118. ultralytics/models/yolo/pose/predict.py +12 -14
  119. ultralytics/models/yolo/pose/train.py +31 -69
  120. ultralytics/models/yolo/pose/val.py +119 -254
  121. ultralytics/models/yolo/segment/predict.py +21 -25
  122. ultralytics/models/yolo/segment/train.py +12 -66
  123. ultralytics/models/yolo/segment/val.py +126 -305
  124. ultralytics/models/yolo/world/train.py +53 -45
  125. ultralytics/models/yolo/world/train_world.py +51 -32
  126. ultralytics/models/yolo/yoloe/__init__.py +7 -7
  127. ultralytics/models/yolo/yoloe/predict.py +30 -37
  128. ultralytics/models/yolo/yoloe/train.py +89 -71
  129. ultralytics/models/yolo/yoloe/train_seg.py +15 -17
  130. ultralytics/models/yolo/yoloe/val.py +56 -41
  131. ultralytics/nn/__init__.py +9 -11
  132. ultralytics/nn/autobackend.py +179 -107
  133. ultralytics/nn/modules/__init__.py +67 -67
  134. ultralytics/nn/modules/activation.py +8 -7
  135. ultralytics/nn/modules/block.py +302 -323
  136. ultralytics/nn/modules/conv.py +61 -104
  137. ultralytics/nn/modules/head.py +488 -186
  138. ultralytics/nn/modules/transformer.py +183 -123
  139. ultralytics/nn/modules/utils.py +15 -20
  140. ultralytics/nn/tasks.py +327 -203
  141. ultralytics/nn/text_model.py +81 -65
  142. ultralytics/py.typed +1 -0
  143. ultralytics/solutions/__init__.py +12 -12
  144. ultralytics/solutions/ai_gym.py +19 -27
  145. ultralytics/solutions/analytics.py +36 -26
  146. ultralytics/solutions/config.py +29 -28
  147. ultralytics/solutions/distance_calculation.py +23 -24
  148. ultralytics/solutions/heatmap.py +17 -19
  149. ultralytics/solutions/instance_segmentation.py +21 -19
  150. ultralytics/solutions/object_blurrer.py +16 -17
  151. ultralytics/solutions/object_counter.py +48 -53
  152. ultralytics/solutions/object_cropper.py +22 -16
  153. ultralytics/solutions/parking_management.py +61 -58
  154. ultralytics/solutions/queue_management.py +19 -19
  155. ultralytics/solutions/region_counter.py +63 -50
  156. ultralytics/solutions/security_alarm.py +22 -25
  157. ultralytics/solutions/similarity_search.py +107 -60
  158. ultralytics/solutions/solutions.py +343 -262
  159. ultralytics/solutions/speed_estimation.py +35 -31
  160. ultralytics/solutions/streamlit_inference.py +104 -40
  161. ultralytics/solutions/templates/similarity-search.html +31 -24
  162. ultralytics/solutions/trackzone.py +24 -24
  163. ultralytics/solutions/vision_eye.py +11 -12
  164. ultralytics/trackers/__init__.py +1 -1
  165. ultralytics/trackers/basetrack.py +18 -27
  166. ultralytics/trackers/bot_sort.py +48 -39
  167. ultralytics/trackers/byte_tracker.py +94 -94
  168. ultralytics/trackers/track.py +7 -16
  169. ultralytics/trackers/utils/gmc.py +37 -69
  170. ultralytics/trackers/utils/kalman_filter.py +68 -76
  171. ultralytics/trackers/utils/matching.py +13 -17
  172. ultralytics/utils/__init__.py +251 -275
  173. ultralytics/utils/autobatch.py +19 -7
  174. ultralytics/utils/autodevice.py +68 -38
  175. ultralytics/utils/benchmarks.py +169 -130
  176. ultralytics/utils/callbacks/base.py +12 -13
  177. ultralytics/utils/callbacks/clearml.py +14 -15
  178. ultralytics/utils/callbacks/comet.py +139 -66
  179. ultralytics/utils/callbacks/dvc.py +19 -27
  180. ultralytics/utils/callbacks/hub.py +8 -6
  181. ultralytics/utils/callbacks/mlflow.py +6 -10
  182. ultralytics/utils/callbacks/neptune.py +11 -19
  183. ultralytics/utils/callbacks/platform.py +73 -0
  184. ultralytics/utils/callbacks/raytune.py +3 -4
  185. ultralytics/utils/callbacks/tensorboard.py +9 -12
  186. ultralytics/utils/callbacks/wb.py +33 -30
  187. ultralytics/utils/checks.py +163 -114
  188. ultralytics/utils/cpu.py +89 -0
  189. ultralytics/utils/dist.py +24 -20
  190. ultralytics/utils/downloads.py +176 -146
  191. ultralytics/utils/errors.py +11 -13
  192. ultralytics/utils/events.py +113 -0
  193. ultralytics/utils/export/__init__.py +7 -0
  194. ultralytics/utils/{export.py → export/engine.py} +81 -63
  195. ultralytics/utils/export/imx.py +294 -0
  196. ultralytics/utils/export/tensorflow.py +217 -0
  197. ultralytics/utils/files.py +33 -36
  198. ultralytics/utils/git.py +137 -0
  199. ultralytics/utils/instance.py +105 -120
  200. ultralytics/utils/logger.py +404 -0
  201. ultralytics/utils/loss.py +99 -61
  202. ultralytics/utils/metrics.py +649 -478
  203. ultralytics/utils/nms.py +337 -0
  204. ultralytics/utils/ops.py +263 -451
  205. ultralytics/utils/patches.py +70 -31
  206. ultralytics/utils/plotting.py +253 -223
  207. ultralytics/utils/tal.py +48 -61
  208. ultralytics/utils/torch_utils.py +244 -251
  209. ultralytics/utils/tqdm.py +438 -0
  210. ultralytics/utils/triton.py +22 -23
  211. ultralytics/utils/tuner.py +11 -10
  212. dgenerate_ultralytics_headless-8.3.137.dist-info/RECORD +0 -272
  213. {dgenerate_ultralytics_headless-8.3.137.dist-info → dgenerate_ultralytics_headless-8.3.224.dist-info}/entry_points.txt +0 -0
  214. {dgenerate_ultralytics_headless-8.3.137.dist-info → dgenerate_ultralytics_headless-8.3.224.dist-info}/licenses/LICENSE +0 -0
  215. {dgenerate_ultralytics_headless-8.3.137.dist-info → dgenerate_ultralytics_headless-8.3.224.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,7 @@
1
1
  # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import functools
4
6
  import glob
5
7
  import inspect
@@ -13,7 +15,6 @@ import time
13
15
  from importlib import metadata
14
16
  from pathlib import Path
15
17
  from types import SimpleNamespace
16
- from typing import Optional
17
18
 
18
19
  import cv2
19
20
  import numpy as np
@@ -22,9 +23,10 @@ import torch
22
23
  from ultralytics.utils import (
23
24
  ARM64,
24
25
  ASSETS,
26
+ ASSETS_URL,
25
27
  AUTOINSTALL,
28
+ GIT,
26
29
  IS_COLAB,
27
- IS_GIT_DIR,
28
30
  IS_JETSON,
29
31
  IS_KAGGLE,
30
32
  IS_PIP_PACKAGE,
@@ -35,6 +37,7 @@ from ultralytics.utils import (
35
37
  PYTHON_VERSION,
36
38
  RKNN_CHIPS,
37
39
  ROOT,
40
+ TORCH_VERSION,
38
41
  TORCHVISION_VERSION,
39
42
  USER_CONFIG_DIR,
40
43
  WINDOWS,
@@ -50,15 +53,15 @@ from ultralytics.utils import (
50
53
 
51
54
 
52
55
  def parse_requirements(file_path=ROOT.parent / "requirements.txt", package=""):
53
- """
54
- Parse a requirements.txt file, ignoring lines that start with '#' and any text after '#'.
56
+ """Parse a requirements.txt file, ignoring lines that start with '#' and any text after '#'.
55
57
 
56
58
  Args:
57
59
  file_path (Path): Path to the requirements.txt file.
58
60
  package (str, optional): Python package to use instead of requirements.txt file.
59
61
 
60
62
  Returns:
61
- (List[SimpleNamespace]): List of parsed requirements as SimpleNamespace objects with `name` and `specifier` attributes.
63
+ requirements (list[SimpleNamespace]): List of parsed requirements as SimpleNamespace objects with `name` and
64
+ `specifier` attributes.
62
65
 
63
66
  Examples:
64
67
  >>> from ultralytics.utils.checks import parse_requirements
@@ -73,7 +76,7 @@ def parse_requirements(file_path=ROOT.parent / "requirements.txt", package=""):
73
76
  for line in requires:
74
77
  line = line.strip()
75
78
  if line and not line.startswith("#"):
76
- line = line.split("#")[0].strip() # ignore inline comments
79
+ line = line.partition("#")[0].strip() # ignore inline comments
77
80
  if match := re.match(r"([a-zA-Z0-9-_]+)\s*([<>!=~]+.*)?", line):
78
81
  requirements.append(SimpleNamespace(name=match[1], specifier=match[2].strip() if match[2] else ""))
79
82
 
@@ -82,14 +85,13 @@ def parse_requirements(file_path=ROOT.parent / "requirements.txt", package=""):
82
85
 
83
86
  @functools.lru_cache
84
87
  def parse_version(version="0.0.0") -> tuple:
85
- """
86
- Convert a version string to a tuple of integers, ignoring any extra non-numeric string attached to the version.
88
+ """Convert a version string to a tuple of integers, ignoring any extra non-numeric string attached to the version.
87
89
 
88
90
  Args:
89
91
  version (str): Version string, i.e. '2.0.1+cpu'
90
92
 
91
93
  Returns:
92
- (Tuple[int, int, int]): Tuple of integers representing the numeric part of the version, i.e. (2, 0, 1)
94
+ (tuple): Tuple of integers representing the numeric part of the version, i.e. (2, 0, 1)
93
95
  """
94
96
  try:
95
97
  return tuple(map(int, re.findall(r"\d+", version)[:3])) # '2.0.1+cpu' -> (2, 0, 1)
@@ -99,8 +101,7 @@ def parse_version(version="0.0.0") -> tuple:
99
101
 
100
102
 
101
103
  def is_ascii(s) -> bool:
102
- """
103
- Check if a string is composed of only ASCII characters.
104
+ """Check if a string is composed of only ASCII characters.
104
105
 
105
106
  Args:
106
107
  s (str | list | tuple | dict): Input to be checked (all are converted to string for checking).
@@ -112,19 +113,18 @@ def is_ascii(s) -> bool:
112
113
 
113
114
 
114
115
  def check_imgsz(imgsz, stride=32, min_dim=1, max_dim=2, floor=0):
115
- """
116
- Verify image size is a multiple of the given stride in each dimension. If the image size is not a multiple of the
116
+ """Verify image size is a multiple of the given stride in each dimension. If the image size is not a multiple of the
117
117
  stride, update it to the nearest multiple of the stride that is greater than or equal to the given floor value.
118
118
 
119
119
  Args:
120
- imgsz (int | List[int]): Image size.
120
+ imgsz (int | list[int]): Image size.
121
121
  stride (int): Stride value.
122
122
  min_dim (int): Minimum number of dimensions.
123
123
  max_dim (int): Maximum number of dimensions.
124
124
  floor (int): Minimum allowed value for image size.
125
125
 
126
126
  Returns:
127
- (List[int] | int): Updated image size.
127
+ (list[int] | int): Updated image size.
128
128
  """
129
129
  # Convert stride to integer if it is a tensor
130
130
  stride = int(stride.max() if isinstance(stride, torch.Tensor) else stride)
@@ -165,6 +165,15 @@ def check_imgsz(imgsz, stride=32, min_dim=1, max_dim=2, floor=0):
165
165
  return sz
166
166
 
167
167
 
168
+ @functools.lru_cache
169
+ def check_uv():
170
+ """Check if uv package manager is installed and can run successfully."""
171
+ try:
172
+ return subprocess.run(["uv", "-V"], capture_output=True).returncode == 0
173
+ except FileNotFoundError:
174
+ return False
175
+
176
+
168
177
  @functools.lru_cache
169
178
  def check_version(
170
179
  current: str = "0.0.0",
@@ -174,8 +183,7 @@ def check_version(
174
183
  verbose: bool = False,
175
184
  msg: str = "",
176
185
  ) -> bool:
177
- """
178
- Check current version against the required version or range.
186
+ """Check current version against the required version or range.
179
187
 
180
188
  Args:
181
189
  current (str): Current version or package name to get version from.
@@ -255,8 +263,7 @@ def check_version(
255
263
 
256
264
 
257
265
  def check_latest_pypi_version(package_name="ultralytics"):
258
- """
259
- Returns the latest version of a PyPI package without downloading or installing it.
266
+ """Return the latest version of a PyPI package without downloading or installing it.
260
267
 
261
268
  Args:
262
269
  package_name (str): The name of the package to find the latest version for.
@@ -264,7 +271,7 @@ def check_latest_pypi_version(package_name="ultralytics"):
264
271
  Returns:
265
272
  (str): The latest version of the package.
266
273
  """
267
- import requests # slow import
274
+ import requests # scoped as slow import
268
275
 
269
276
  try:
270
277
  requests.packages.urllib3.disable_warnings() # Disable the InsecureRequestWarning
@@ -276,8 +283,7 @@ def check_latest_pypi_version(package_name="ultralytics"):
276
283
 
277
284
 
278
285
  def check_pip_update_available():
279
- """
280
- Checks if a new version of the ultralytics package is available on PyPI.
286
+ """Check if a new version of the ultralytics package is available on PyPI.
281
287
 
282
288
  Returns:
283
289
  (bool): True if an update is available, False otherwise.
@@ -301,8 +307,7 @@ def check_pip_update_available():
301
307
  @ThreadingLocked()
302
308
  @functools.lru_cache
303
309
  def check_font(font="Arial.ttf"):
304
- """
305
- Find font locally or download to user's configuration directory if it does not already exist.
310
+ """Find font locally or download to user's configuration directory if it does not already exist.
306
311
 
307
312
  Args:
308
313
  font (str): Path or name of font.
@@ -324,15 +329,14 @@ def check_font(font="Arial.ttf"):
324
329
  return matches[0]
325
330
 
326
331
  # Download to USER_CONFIG_DIR if missing
327
- url = f"https://github.com/ultralytics/assets/releases/download/v0.0.0/{name}"
332
+ url = f"{ASSETS_URL}/{name}"
328
333
  if downloads.is_url(url, check=True):
329
334
  downloads.safe_download(url=url, file=file)
330
335
  return file
331
336
 
332
337
 
333
338
  def check_python(minimum: str = "3.8.0", hard: bool = True, verbose: bool = False) -> bool:
334
- """
335
- Check current python version against the required minimum version.
339
+ """Check current python version against the required minimum version.
336
340
 
337
341
  Args:
338
342
  minimum (str): Required minimum version of python.
@@ -347,13 +351,13 @@ def check_python(minimum: str = "3.8.0", hard: bool = True, verbose: bool = Fals
347
351
 
348
352
  @TryExcept()
349
353
  def check_requirements(requirements=ROOT.parent / "requirements.txt", exclude=(), install=True, cmds=""):
350
- """
351
- Check if installed dependencies meet Ultralytics YOLO models requirements and attempt to auto-update if needed.
354
+ """Check if installed dependencies meet Ultralytics YOLO models requirements and attempt to auto-update if needed.
352
355
 
353
356
  Args:
354
- requirements (Union[Path, str, List[str]]): Path to a requirements.txt file, a single package requirement as a
355
- string, or a list of package requirements as strings.
356
- exclude (Tuple[str]): Tuple of package names to exclude from checking.
357
+ requirements (Path | str | list[str|tuple] | tuple[str]): Path to a requirements.txt file, a single package
358
+ requirement as a string, a list of package requirements as strings, or a list containing strings and tuples
359
+ of interchangeable packages.
360
+ exclude (tuple): Tuple of package names to exclude from checking.
357
361
  install (bool): If True, attempt to auto-update packages that don't meet requirements.
358
362
  cmds (str): Additional commands to pass to the pip install command when auto-updating.
359
363
 
@@ -364,10 +368,13 @@ def check_requirements(requirements=ROOT.parent / "requirements.txt", exclude=()
364
368
  >>> check_requirements("path/to/requirements.txt")
365
369
 
366
370
  Check a single package
367
- >>> check_requirements("ultralytics>=8.0.0")
371
+ >>> check_requirements("ultralytics>=8.3.200", cmds="--index-url https://download.pytorch.org/whl/cpu")
368
372
 
369
373
  Check multiple packages
370
- >>> check_requirements(["numpy", "ultralytics>=8.0.0"])
374
+ >>> check_requirements(["numpy", "ultralytics"])
375
+
376
+ Check with interchangeable packages
377
+ >>> check_requirements([("onnxruntime", "onnxruntime-gpu"), "numpy"])
371
378
  """
372
379
  prefix = colorstr("red", "bold", "requirements:")
373
380
  if isinstance(requirements, Path): # requirements.txt file
@@ -379,30 +386,56 @@ def check_requirements(requirements=ROOT.parent / "requirements.txt", exclude=()
379
386
 
380
387
  pkgs = []
381
388
  for r in requirements:
382
- r_stripped = r.split("/")[-1].replace(".git", "") # replace git+https://org/repo.git -> 'repo'
383
- match = re.match(r"([a-zA-Z0-9-_]+)([<>!=~]+.*)?", r_stripped)
384
- name, required = match[1], match[2].strip() if match[2] else ""
385
- try:
386
- assert check_version(metadata.version(name), required) # exception if requirements not met
387
- except (AssertionError, metadata.PackageNotFoundError):
388
- pkgs.append(r)
389
+ candidates = r if isinstance(r, (list, tuple)) else [r]
390
+ satisfied = False
391
+
392
+ for candidate in candidates:
393
+ r_stripped = candidate.rpartition("/")[-1].replace(".git", "") # replace git+https://org/repo.git -> 'repo'
394
+ match = re.match(r"([a-zA-Z0-9-_]+)([<>!=~]+.*)?", r_stripped)
395
+ name, required = match[1], match[2].strip() if match[2] else ""
396
+ try:
397
+ if check_version(metadata.version(name), required):
398
+ satisfied = True
399
+ break
400
+ except (AssertionError, metadata.PackageNotFoundError):
401
+ continue
402
+
403
+ if not satisfied:
404
+ pkgs.append(candidates[0])
389
405
 
390
406
  @Retry(times=2, delay=1)
391
- def attempt_install(packages, commands):
392
- """Attempt pip install command with retries on failure."""
393
- return subprocess.check_output(f"pip install --no-cache-dir {packages} {commands}", shell=True).decode()
407
+ def attempt_install(packages, commands, use_uv):
408
+ """Attempt package installation with uv if available, falling back to pip."""
409
+ if use_uv:
410
+ base = (
411
+ f"uv pip install --no-cache-dir {packages} {commands} "
412
+ f"--index-strategy=unsafe-best-match --break-system-packages --prerelease=allow"
413
+ )
414
+ try:
415
+ return subprocess.check_output(base, shell=True, stderr=subprocess.PIPE, text=True)
416
+ except subprocess.CalledProcessError as e:
417
+ if e.stderr and "No virtual environment found" in e.stderr:
418
+ return subprocess.check_output(
419
+ base.replace("uv pip install", "uv pip install --system"),
420
+ shell=True,
421
+ stderr=subprocess.PIPE,
422
+ text=True,
423
+ )
424
+ raise
425
+ return subprocess.check_output(f"pip install --no-cache-dir {packages} {commands}", shell=True, text=True)
394
426
 
395
427
  s = " ".join(f'"{x}"' for x in pkgs) # console string
396
428
  if s:
397
429
  if install and AUTOINSTALL: # check environment variable
430
+ # Note uv fails on arm64 macOS and Raspberry Pi runners
398
431
  n = len(pkgs) # number of packages updates
399
432
  LOGGER.info(f"{prefix} Ultralytics requirement{'s' * (n > 1)} {pkgs} not found, attempting AutoUpdate...")
400
433
  try:
401
434
  t = time.time()
402
435
  assert ONLINE, "AutoUpdate skipped (offline)"
403
- LOGGER.info(attempt_install(s, cmds))
436
+ LOGGER.info(attempt_install(s, cmds, use_uv=not ARM64 and check_uv()))
404
437
  dt = time.time() - t
405
- LOGGER.info(f"{prefix} AutoUpdate success ✅ {dt:.1f}s, installed {n} package{'s' * (n > 1)}: {pkgs}")
438
+ LOGGER.info(f"{prefix} AutoUpdate success ✅ {dt:.1f}s")
406
439
  LOGGER.warning(
407
440
  f"{prefix} {colorstr('bold', 'Restart runtime or rerun command for updates to take effect')}\n"
408
441
  )
@@ -416,13 +449,15 @@ def check_requirements(requirements=ROOT.parent / "requirements.txt", exclude=()
416
449
 
417
450
 
418
451
  def check_torchvision():
419
- """
420
- Checks the installed versions of PyTorch and Torchvision to ensure they're compatible.
452
+ """Check the installed versions of PyTorch and Torchvision to ensure they're compatible.
421
453
 
422
454
  This function checks the installed versions of PyTorch and Torchvision, and warns if they're incompatible according
423
455
  to the compatibility table based on: https://github.com/pytorch/vision#installation.
424
456
  """
425
457
  compatibility_table = {
458
+ "2.9": ["0.24"],
459
+ "2.8": ["0.23"],
460
+ "2.7": ["0.22"],
426
461
  "2.6": ["0.21"],
427
462
  "2.5": ["0.20"],
428
463
  "2.4": ["0.19"],
@@ -435,10 +470,10 @@ def check_torchvision():
435
470
  }
436
471
 
437
472
  # Check major and minor versions
438
- v_torch = ".".join(torch.__version__.split("+")[0].split(".")[:2])
473
+ v_torch = ".".join(TORCH_VERSION.split("+", 1)[0].split(".")[:2])
439
474
  if v_torch in compatibility_table:
440
475
  compatible_versions = compatibility_table[v_torch]
441
- v_torchvision = ".".join(TORCHVISION_VERSION.split("+")[0].split(".")[:2])
476
+ v_torchvision = ".".join(TORCHVISION_VERSION.split("+", 1)[0].split(".")[:2])
442
477
  if all(v_torchvision != v for v in compatible_versions):
443
478
  LOGGER.warning(
444
479
  f"torchvision=={v_torchvision} is incompatible with torch=={v_torch}.\n"
@@ -449,26 +484,23 @@ def check_torchvision():
449
484
 
450
485
 
451
486
  def check_suffix(file="yolo11n.pt", suffix=".pt", msg=""):
452
- """
453
- Check file(s) for acceptable suffix.
487
+ """Check file(s) for acceptable suffix.
454
488
 
455
489
  Args:
456
- file (str | List[str]): File or list of files to check.
457
- suffix (str | Tuple[str]): Acceptable suffix or tuple of suffixes.
490
+ file (str | list[str]): File or list of files to check.
491
+ suffix (str | tuple): Acceptable suffix or tuple of suffixes.
458
492
  msg (str): Additional message to display in case of error.
459
493
  """
460
494
  if file and suffix:
461
495
  if isinstance(suffix, str):
462
496
  suffix = {suffix}
463
497
  for f in file if isinstance(file, (list, tuple)) else [file]:
464
- s = Path(f).suffix.lower().strip() # file suffix
465
- if len(s):
466
- assert s in suffix, f"{msg}{f} acceptable suffix is {suffix}, not {s}"
498
+ if s := str(f).rpartition(".")[-1].lower().strip(): # file suffix
499
+ assert f".{s}" in suffix, f"{msg}{f} acceptable suffix is {suffix}, not .{s}"
467
500
 
468
501
 
469
502
  def check_yolov5u_filename(file: str, verbose: bool = True):
470
- """
471
- Replace legacy YOLOv5 filenames with updated YOLOv5u filenames.
503
+ """Replace legacy YOLOv5 filenames with updated YOLOv5u filenames.
472
504
 
473
505
  Args:
474
506
  file (str): Filename to check and potentially update.
@@ -495,8 +527,7 @@ def check_yolov5u_filename(file: str, verbose: bool = True):
495
527
 
496
528
 
497
529
  def check_model_file_from_stem(model="yolo11n"):
498
- """
499
- Return a model filename from a valid model stem.
530
+ """Return a model filename from a valid model stem.
500
531
 
501
532
  Args:
502
533
  model (str): Model stem to check.
@@ -504,19 +535,18 @@ def check_model_file_from_stem(model="yolo11n"):
504
535
  Returns:
505
536
  (str | Path): Model filename with appropriate suffix.
506
537
  """
507
- if model and not Path(model).suffix and Path(model).stem in downloads.GITHUB_ASSETS_STEMS:
508
- return Path(model).with_suffix(".pt") # add suffix, i.e. yolo11n -> yolo11n.pt
509
- else:
510
- return model
538
+ path = Path(model)
539
+ if not path.suffix and path.stem in downloads.GITHUB_ASSETS_STEMS:
540
+ return path.with_suffix(".pt") # add suffix, i.e. yolo11n -> yolo11n.pt
541
+ return model
511
542
 
512
543
 
513
544
  def check_file(file, suffix="", download=True, download_dir=".", hard=True):
514
- """
515
- Search/download file (if necessary), check suffix (if provided), and return path.
545
+ """Search/download file (if necessary), check suffix (if provided), and return path.
516
546
 
517
547
  Args:
518
548
  file (str): File name or path.
519
- suffix (str | Tuple[str]): Acceptable suffix or tuple of suffixes to validate against the file.
549
+ suffix (str | tuple): Acceptable suffix or tuple of suffixes to validate against the file.
520
550
  download (bool): Whether to download the file if it doesn't exist locally.
521
551
  download_dir (str): Directory to download the file to.
522
552
  hard (bool): Whether to raise an error if the file is not found.
@@ -551,12 +581,11 @@ def check_file(file, suffix="", download=True, download_dir=".", hard=True):
551
581
 
552
582
 
553
583
  def check_yaml(file, suffix=(".yaml", ".yml"), hard=True):
554
- """
555
- Search/download YAML file (if necessary) and return path, checking suffix.
584
+ """Search/download YAML file (if necessary) and return path, checking suffix.
556
585
 
557
586
  Args:
558
587
  file (str | Path): File name or path.
559
- suffix (Tuple[str]): Tuple of acceptable YAML file suffixes.
588
+ suffix (tuple): Tuple of acceptable YAML file suffixes.
560
589
  hard (bool): Whether to raise an error if the file is not found or multiple files are found.
561
590
 
562
591
  Returns:
@@ -566,8 +595,7 @@ def check_yaml(file, suffix=(".yaml", ".yml"), hard=True):
566
595
 
567
596
 
568
597
  def check_is_path_safe(basedir, path):
569
- """
570
- Check if the resolved path is under the intended directory to prevent path traversal.
598
+ """Check if the resolved path is under the intended directory to prevent path traversal.
571
599
 
572
600
  Args:
573
601
  basedir (Path | str): The intended directory.
@@ -584,8 +612,7 @@ def check_is_path_safe(basedir, path):
584
612
 
585
613
  @functools.lru_cache
586
614
  def check_imshow(warn=False):
587
- """
588
- Check if environment supports image displays.
615
+ """Check if environment supports image displays.
589
616
 
590
617
  Args:
591
618
  warn (bool): Whether to warn if environment doesn't support image displays.
@@ -609,14 +636,13 @@ def check_imshow(warn=False):
609
636
 
610
637
 
611
638
  def check_yolo(verbose=True, device=""):
612
- """
613
- Return a human-readable YOLO software and hardware summary.
639
+ """Return a human-readable YOLO software and hardware summary.
614
640
 
615
641
  Args:
616
642
  verbose (bool): Whether to print verbose information.
617
643
  device (str | torch.device): Device to use for YOLO.
618
644
  """
619
- import psutil
645
+ import psutil # scoped as slow import
620
646
 
621
647
  from ultralytics.utils.torch_utils import select_device
622
648
 
@@ -627,7 +653,7 @@ def check_yolo(verbose=True, device=""):
627
653
  # System info
628
654
  gib = 1 << 30 # bytes per GiB
629
655
  ram = psutil.virtual_memory().total
630
- total, used, free = shutil.disk_usage("/")
656
+ total, _used, free = shutil.disk_usage("/")
631
657
  s = f"({os.cpu_count()} CPUs, {ram / gib:.1f} GB RAM, {(total - free) / gib:.1f}/{total / gib:.1f} GB disk)"
632
658
  try:
633
659
  from IPython import display
@@ -638,32 +664,34 @@ def check_yolo(verbose=True, device=""):
638
664
  else:
639
665
  s = ""
640
666
 
667
+ if GIT.is_repo:
668
+ check_multiple_install() # check conflicting installation if using local clone
669
+
641
670
  select_device(device=device, newline=False)
642
671
  LOGGER.info(f"Setup complete ✅ {s}")
643
672
 
644
673
 
645
674
  def collect_system_info():
646
- """
647
- Collect and print relevant system information including OS, Python, RAM, CPU, and CUDA.
675
+ """Collect and print relevant system information including OS, Python, RAM, CPU, and CUDA.
648
676
 
649
677
  Returns:
650
678
  (dict): Dictionary containing system information.
651
679
  """
652
- import psutil
680
+ import psutil # scoped as slow import
653
681
 
654
682
  from ultralytics.utils import ENVIRONMENT # scope to avoid circular import
655
683
  from ultralytics.utils.torch_utils import get_cpu_info, get_gpu_info
656
684
 
657
685
  gib = 1 << 30 # bytes per GiB
658
- cuda = torch and torch.cuda.is_available()
686
+ cuda = torch.cuda.is_available()
659
687
  check_yolo()
660
- total, used, free = shutil.disk_usage("/")
688
+ total, _used, free = shutil.disk_usage("/")
661
689
 
662
690
  info_dict = {
663
691
  "OS": platform.platform(),
664
692
  "Environment": ENVIRONMENT,
665
693
  "Python": PYTHON_VERSION,
666
- "Install": "git" if IS_GIT_DIR else "pip" if IS_PIP_PACKAGE else "other",
694
+ "Install": "git" if GIT.is_repo else "pip" if IS_PIP_PACKAGE else "other",
667
695
  "Path": str(ROOT),
668
696
  "RAM": f"{psutil.virtual_memory().total / gib:.2f} GB",
669
697
  "Disk": f"{(total - free) / gib:.1f}/{total / gib:.1f} GB",
@@ -673,7 +701,7 @@ def collect_system_info():
673
701
  "GPU count": torch.cuda.device_count() if cuda else None,
674
702
  "CUDA": torch.version.cuda if cuda else None,
675
703
  }
676
- LOGGER.info("\n" + "\n".join(f"{k:<20}{v}" for k, v in info_dict.items()) + "\n")
704
+ LOGGER.info("\n" + "\n".join(f"{k:<23}{v}" for k, v in info_dict.items()) + "\n")
677
705
 
678
706
  package_info = {}
679
707
  for r in parse_requirements(package="ultralytics"):
@@ -684,7 +712,7 @@ def collect_system_info():
684
712
  current = "(not installed)"
685
713
  is_met = "❌ "
686
714
  package_info[r.name] = f"{is_met}{current}{r.specifier}"
687
- LOGGER.info(f"{r.name:<20}{package_info[r.name]}")
715
+ LOGGER.info(f"{r.name:<23}{package_info[r.name]}")
688
716
 
689
717
  info_dict["Package Info"] = package_info
690
718
 
@@ -704,14 +732,13 @@ def collect_system_info():
704
732
 
705
733
 
706
734
  def check_amp(model):
707
- """
708
- Checks the PyTorch Automatic Mixed Precision (AMP) functionality of a YOLO11 model.
735
+ """Check the PyTorch Automatic Mixed Precision (AMP) functionality of a YOLO model.
709
736
 
710
737
  If the checks fail, it means there are anomalies with AMP on the system that may cause NaN losses or zero-mAP
711
738
  results, so AMP will be disabled during training.
712
739
 
713
740
  Args:
714
- model (nn.Module): A YOLO11 model instance.
741
+ model (torch.nn.Module): A YOLO model instance.
715
742
 
716
743
  Returns:
717
744
  (bool): Returns True if the AMP functionality works correctly with YOLO11 model, else False.
@@ -776,25 +803,32 @@ def check_amp(model):
776
803
  return True
777
804
 
778
805
 
779
- def git_describe(path=ROOT): # path must be a directory
780
- """
781
- Return human-readable git description, i.e. v5.0-5-g3e25f1e https://git-scm.com/docs/git-describe.
806
+ def check_multiple_install():
807
+ """Check if there are multiple Ultralytics installations."""
808
+ import sys
782
809
 
783
- Args:
784
- path (Path): Path to git repository.
785
-
786
- Returns:
787
- (str): Human-readable git description.
788
- """
789
810
  try:
790
- return subprocess.check_output(f"git -C {path} describe --tags --long --always", shell=True).decode()[:-1]
811
+ result = subprocess.run([sys.executable, "-m", "pip", "show", "ultralytics"], capture_output=True, text=True)
812
+ install_msg = (
813
+ f"Install your local copy in editable mode with 'pip install -e {ROOT.parent}' to avoid "
814
+ "issues. See https://docs.ultralytics.com/quickstart/"
815
+ )
816
+ if result.returncode != 0:
817
+ if "not found" in result.stderr.lower(): # Package not pip-installed but locally imported
818
+ LOGGER.warning(f"Ultralytics not found via pip but importing from: {ROOT}. {install_msg}")
819
+ return
820
+ yolo_path = (Path(re.findall(r"location:\s+(.+)", result.stdout, flags=re.I)[-1]) / "ultralytics").resolve()
821
+ if not yolo_path.samefile(ROOT.resolve()):
822
+ LOGGER.warning(
823
+ f"Multiple Ultralytics installations detected. The `yolo` command uses: {yolo_path}, "
824
+ f"but current session imports from: {ROOT}. This may cause version conflicts. {install_msg}"
825
+ )
791
826
  except Exception:
792
- return ""
827
+ return
793
828
 
794
829
 
795
- def print_args(args: Optional[dict] = None, show_file=True, show_func=False):
796
- """
797
- Print function arguments (optional args dict).
830
+ def print_args(args: dict | None = None, show_file=True, show_func=False):
831
+ """Print function arguments (optional args dict).
798
832
 
799
833
  Args:
800
834
  args (dict, optional): Arguments to print.
@@ -820,8 +854,7 @@ def print_args(args: Optional[dict] = None, show_file=True, show_func=False):
820
854
 
821
855
 
822
856
  def cuda_device_count() -> int:
823
- """
824
- Get the number of NVIDIA GPUs available in the environment.
857
+ """Get the number of NVIDIA GPUs available in the environment.
825
858
 
826
859
  Returns:
827
860
  (int): The number of NVIDIA GPUs available.
@@ -837,7 +870,7 @@ def cuda_device_count() -> int:
837
870
  )
838
871
 
839
872
  # Take the first line and strip any leading/trailing white space
840
- first_line = output.strip().split("\n")[0]
873
+ first_line = output.strip().split("\n", 1)[0]
841
874
 
842
875
  return int(first_line)
843
876
  except (subprocess.CalledProcessError, FileNotFoundError, ValueError):
@@ -846,8 +879,7 @@ def cuda_device_count() -> int:
846
879
 
847
880
 
848
881
  def cuda_is_available() -> bool:
849
- """
850
- Check if CUDA is available in the environment.
882
+ """Check if CUDA is available in the environment.
851
883
 
852
884
  Returns:
853
885
  (bool): True if one or more NVIDIA GPUs are available, False otherwise.
@@ -856,8 +888,7 @@ def cuda_is_available() -> bool:
856
888
 
857
889
 
858
890
  def is_rockchip():
859
- """
860
- Check if the current environment is running on a Rockchip SoC.
891
+ """Check if the current environment is running on a Rockchip SoC.
861
892
 
862
893
  Returns:
863
894
  (bool): True if running on a Rockchip SoC, False otherwise.
@@ -875,9 +906,28 @@ def is_rockchip():
875
906
  return False
876
907
 
877
908
 
878
- def is_sudo_available() -> bool:
909
+ def is_intel():
910
+ """Check if the system has Intel hardware (CPU or GPU).
911
+
912
+ Returns:
913
+ (bool): True if Intel hardware is detected, False otherwise.
879
914
  """
880
- Check if the sudo command is available in the environment.
915
+ from ultralytics.utils.torch_utils import get_cpu_info
916
+
917
+ # Check CPU
918
+ if "intel" in get_cpu_info().lower():
919
+ return True
920
+
921
+ # Check GPU via xpu-smi
922
+ try:
923
+ result = subprocess.run(["xpu-smi", "discovery"], capture_output=True, text=True, timeout=5)
924
+ return "intel" in result.stdout.lower()
925
+ except Exception: # broad clause to capture all Intel GPU exception types
926
+ return False
927
+
928
+
929
+ def is_sudo_available() -> bool:
930
+ """Check if the sudo command is available in the environment.
881
931
 
882
932
  Returns:
883
933
  (bool): True if the sudo command is available, False otherwise.
@@ -894,7 +944,6 @@ check_torchvision() # check torch-torchvision compatibility
894
944
 
895
945
  # Define constants
896
946
  IS_PYTHON_3_8 = PYTHON_VERSION.startswith("3.8")
897
- IS_PYTHON_3_11 = PYTHON_VERSION.startswith("3.11")
898
947
  IS_PYTHON_3_12 = PYTHON_VERSION.startswith("3.12")
899
948
  IS_PYTHON_3_13 = PYTHON_VERSION.startswith("3.13")
900
949