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,12 +1,14 @@
1
1
  # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import ast
4
6
  import json
5
7
  import platform
6
8
  import zipfile
7
9
  from collections import OrderedDict, namedtuple
8
10
  from pathlib import Path
9
- from typing import List, Optional, Union
11
+ from typing import Any
10
12
 
11
13
  import cv2
12
14
  import numpy as np
@@ -14,13 +16,24 @@ import torch
14
16
  import torch.nn as nn
15
17
  from PIL import Image
16
18
 
17
- from ultralytics.utils import ARM64, IS_JETSON, LINUX, LOGGER, PYTHON_VERSION, ROOT, YAML
19
+ from ultralytics.utils import ARM64, IS_JETSON, LINUX, LOGGER, PYTHON_VERSION, ROOT, YAML, is_jetson
18
20
  from ultralytics.utils.checks import check_requirements, check_suffix, check_version, check_yaml, is_rockchip
19
21
  from ultralytics.utils.downloads import attempt_download_asset, is_url
22
+ from ultralytics.utils.nms import non_max_suppression
23
+
24
+
25
+ def check_class_names(names: list | dict) -> dict[int, str]:
26
+ """Check class names and convert to dict format if needed.
27
+
28
+ Args:
29
+ names (list | dict): Class names as list or dict format.
20
30
 
31
+ Returns:
32
+ (dict): Class names in dict format with integer keys and string values.
21
33
 
22
- def check_class_names(names):
23
- """Check class names and convert to dict format if needed."""
34
+ Raises:
35
+ KeyError: If class indices are invalid for the dataset size.
36
+ """
24
37
  if isinstance(names, list): # names is a list
25
38
  names = dict(enumerate(names)) # convert to dict
26
39
  if isinstance(names, dict):
@@ -38,8 +51,15 @@ def check_class_names(names):
38
51
  return names
39
52
 
40
53
 
41
- def default_class_names(data=None):
42
- """Applies default class names to an input YAML file or returns numerical class names."""
54
+ def default_class_names(data: str | Path | None = None) -> dict[int, str]:
55
+ """Apply default class names to an input YAML file or return numerical class names.
56
+
57
+ Args:
58
+ data (str | Path, optional): Path to YAML file containing class names.
59
+
60
+ Returns:
61
+ (dict): Dictionary mapping class indices to class names.
62
+ """
43
63
  if data:
44
64
  try:
45
65
  return YAML.load(check_yaml(data))["names"]
@@ -49,8 +69,7 @@ def default_class_names(data=None):
49
69
 
50
70
 
51
71
  class AutoBackend(nn.Module):
52
- """
53
- Handles dynamic backend selection for running inference using Ultralytics YOLO models.
72
+ """Handle dynamic backend selection for running inference using Ultralytics YOLO models.
54
73
 
55
74
  The AutoBackend class is designed to provide an abstraction layer for various inference engines. It supports a wide
56
75
  range of formats, each with specific naming conventions as outlined below:
@@ -74,6 +93,8 @@ class AutoBackend(nn.Module):
74
93
  | NCNN | *_ncnn_model/ |
75
94
  | IMX | *_imx_model/ |
76
95
  | RKNN | *_rknn_model/ |
96
+ | Triton Inference | triton://model |
97
+ | ExecuTorch | *.pte |
77
98
 
78
99
  Attributes:
79
100
  model (torch.nn.Module): The loaded YOLO model.
@@ -82,6 +103,25 @@ class AutoBackend(nn.Module):
82
103
  names (dict): A dictionary of class names that the model can detect.
83
104
  stride (int): The model stride, typically 32 for YOLO models.
84
105
  fp16 (bool): Whether the model uses half-precision (FP16) inference.
106
+ nhwc (bool): Whether the model expects NHWC input format instead of NCHW.
107
+ pt (bool): Whether the model is a PyTorch model.
108
+ jit (bool): Whether the model is a TorchScript model.
109
+ onnx (bool): Whether the model is an ONNX model.
110
+ xml (bool): Whether the model is an OpenVINO model.
111
+ engine (bool): Whether the model is a TensorRT engine.
112
+ coreml (bool): Whether the model is a CoreML model.
113
+ saved_model (bool): Whether the model is a TensorFlow SavedModel.
114
+ pb (bool): Whether the model is a TensorFlow GraphDef.
115
+ tflite (bool): Whether the model is a TensorFlow Lite model.
116
+ edgetpu (bool): Whether the model is a TensorFlow Edge TPU model.
117
+ tfjs (bool): Whether the model is a TensorFlow.js model.
118
+ paddle (bool): Whether the model is a PaddlePaddle model.
119
+ mnn (bool): Whether the model is an MNN model.
120
+ ncnn (bool): Whether the model is an NCNN model.
121
+ imx (bool): Whether the model is an IMX model.
122
+ rknn (bool): Whether the model is an RKNN model.
123
+ triton (bool): Whether the model is a Triton Inference Server model.
124
+ pte (bool): Whether the model is a PyTorch ExecuTorch model.
85
125
 
86
126
  Methods:
87
127
  forward: Run inference on an input image.
@@ -90,38 +130,34 @@ class AutoBackend(nn.Module):
90
130
  _model_type: Determine the model type from file path.
91
131
 
92
132
  Examples:
93
- >>> model = AutoBackend(weights="yolo11n.pt", device="cuda")
133
+ >>> model = AutoBackend(model="yolo11n.pt", device="cuda")
94
134
  >>> results = model(img)
95
135
  """
96
136
 
97
137
  @torch.no_grad()
98
138
  def __init__(
99
139
  self,
100
- weights: Union[str, List[str], torch.nn.Module] = "yolo11n.pt",
140
+ model: str | torch.nn.Module = "yolo11n.pt",
101
141
  device: torch.device = torch.device("cpu"),
102
142
  dnn: bool = False,
103
- data: Optional[Union[str, Path]] = None,
143
+ data: str | Path | None = None,
104
144
  fp16: bool = False,
105
- batch: int = 1,
106
145
  fuse: bool = True,
107
146
  verbose: bool = True,
108
147
  ):
109
- """
110
- Initialize the AutoBackend for inference.
148
+ """Initialize the AutoBackend for inference.
111
149
 
112
150
  Args:
113
- weights (str | List[str] | torch.nn.Module): Path to the model weights file or a module instance.
151
+ model (str | torch.nn.Module): Path to the model weights file or a module instance.
114
152
  device (torch.device): Device to run the model on.
115
153
  dnn (bool): Use OpenCV DNN module for ONNX inference.
116
- data (str | Path | optional): Path to the additional data.yaml file containing class names.
154
+ data (str | Path, optional): Path to the additional data.yaml file containing class names.
117
155
  fp16 (bool): Enable half-precision inference. Supported only on specific backends.
118
- batch (int): Batch-size to assume for inference.
119
156
  fuse (bool): Fuse Conv2D + BatchNorm layers for optimization.
120
157
  verbose (bool): Enable verbose logging.
121
158
  """
122
159
  super().__init__()
123
- w = str(weights[0] if isinstance(weights, list) else weights)
124
- nn_module = isinstance(weights, torch.nn.Module)
160
+ nn_module = isinstance(model, torch.nn.Module)
125
161
  (
126
162
  pt,
127
163
  jit,
@@ -139,13 +175,14 @@ class AutoBackend(nn.Module):
139
175
  ncnn,
140
176
  imx,
141
177
  rknn,
178
+ pte,
142
179
  triton,
143
- ) = self._model_type(w)
180
+ ) = self._model_type("" if nn_module else model)
144
181
  fp16 &= pt or jit or onnx or xml or engine or nn_module or triton # FP16
145
182
  nhwc = coreml or saved_model or pb or tflite or edgetpu or rknn # BHWC formats (vs torch BCWH)
146
183
  stride, ch = 32, 3 # default stride and channels
147
184
  end2end, dynamic = False, False
148
- model, metadata, task = None, None, None
185
+ metadata, task = None, None
149
186
 
150
187
  # Set device
151
188
  cuda = isinstance(device, torch.device) and torch.cuda.is_available() and device.type != "cpu" # use CUDA
@@ -154,36 +191,32 @@ class AutoBackend(nn.Module):
154
191
  cuda = False
155
192
 
156
193
  # Download if not local
157
- if not (pt or triton or nn_module):
158
- w = attempt_download_asset(w)
159
-
160
- # In-memory PyTorch model
161
- if nn_module:
162
- if fuse:
163
- weights = weights.fuse(verbose=verbose) # fuse before move to gpu
164
- model = weights.to(device)
165
- if hasattr(model, "kpt_shape"):
166
- kpt_shape = model.kpt_shape # pose-only
167
- stride = max(int(model.stride.max()), 32) # model stride
168
- names = model.module.names if hasattr(model, "module") else model.names # get class names
169
- model.half() if fp16 else model.float()
170
- ch = model.yaml.get("channels", 3)
171
- self.model = model # explicitly assign for to(), cpu(), cuda(), half()
172
- pt = True
173
-
174
- # PyTorch
175
- elif pt:
176
- from ultralytics.nn.tasks import attempt_load_weights
177
-
178
- model = attempt_load_weights(
179
- weights if isinstance(weights, list) else w, device=device, inplace=True, fuse=fuse
180
- )
194
+ w = attempt_download_asset(model) if pt else model # weights path
195
+
196
+ # PyTorch (in-memory or file)
197
+ if nn_module or pt:
198
+ if nn_module:
199
+ pt = True
200
+ if fuse:
201
+ if IS_JETSON and is_jetson(jetpack=5):
202
+ # Jetson Jetpack5 requires device before fuse https://github.com/ultralytics/ultralytics/pull/21028
203
+ model = model.to(device)
204
+ model = model.fuse(verbose=verbose)
205
+ model = model.to(device)
206
+ else: # pt file
207
+ from ultralytics.nn.tasks import load_checkpoint
208
+
209
+ model, _ = load_checkpoint(model, device=device, fuse=fuse) # load model, ckpt
210
+
211
+ # Common PyTorch model processing
181
212
  if hasattr(model, "kpt_shape"):
182
213
  kpt_shape = model.kpt_shape # pose-only
183
214
  stride = max(int(model.stride.max()), 32) # model stride
184
215
  names = model.module.names if hasattr(model, "module") else model.names # get class names
185
216
  model.half() if fp16 else model.float()
186
217
  ch = model.yaml.get("channels", 3)
218
+ for p in model.parameters():
219
+ p.requires_grad = False
187
220
  self.model = model # explicitly assign for to(), cpu(), cuda(), half()
188
221
 
189
222
  # TorchScript
@@ -212,17 +245,17 @@ class AutoBackend(nn.Module):
212
245
  providers = ["CPUExecutionProvider"]
213
246
  if cuda:
214
247
  if "CUDAExecutionProvider" in onnxruntime.get_available_providers():
215
- providers.insert(0, "CUDAExecutionProvider")
248
+ providers.insert(0, ("CUDAExecutionProvider", {"device_id": device.index}))
216
249
  else: # Only log warning if CUDA was requested but unavailable
217
250
  LOGGER.warning("Failed to start ONNX Runtime with CUDA. Using CPU...")
218
251
  device = torch.device("cpu")
219
252
  cuda = False
220
- LOGGER.info(f"Using ONNX Runtime {providers[0]}")
253
+ LOGGER.info(f"Using ONNX Runtime {onnxruntime.__version__} {providers[0]}")
221
254
  if onnx:
222
255
  session = onnxruntime.InferenceSession(w, providers=providers)
223
256
  else:
224
257
  check_requirements(
225
- ["model-compression-toolkit>=2.3.0", "sony-custom-layers[torch]>=0.3.0", "onnxruntime-extensions"]
258
+ ("model-compression-toolkit>=2.4.1", "sony-custom-layers[torch]>=0.3.0", "onnxruntime-extensions")
226
259
  )
227
260
  w = next(Path(w).glob("*.onnx"))
228
261
  LOGGER.info(f"Loading {w} for ONNX IMX inference...")
@@ -232,7 +265,6 @@ class AutoBackend(nn.Module):
232
265
  session_options = mctq.get_ort_session_options()
233
266
  session_options.enable_mem_reuse = False # fix the shape mismatch from onnxruntime
234
267
  session = onnxruntime.InferenceSession(w, session_options, providers=["CPUExecutionProvider"])
235
- task = "detect"
236
268
 
237
269
  output_names = [x.name for x in session.get_outputs()]
238
270
  metadata = session.get_modelmeta().custom_metadata_map
@@ -275,16 +307,22 @@ class AutoBackend(nn.Module):
275
307
  if ov_model.get_parameters()[0].get_layout().empty:
276
308
  ov_model.get_parameters()[0].set_layout(ov.Layout("NCHW"))
277
309
 
310
+ metadata = w.parent / "metadata.yaml"
311
+ if metadata.exists():
312
+ metadata = YAML.load(metadata)
313
+ batch = metadata["batch"]
314
+ dynamic = metadata.get("args", {}).get("dynamic", dynamic)
278
315
  # OpenVINO inference modes are 'LATENCY', 'THROUGHPUT' (not recommended), or 'CUMULATIVE_THROUGHPUT'
279
- inference_mode = "CUMULATIVE_THROUGHPUT" if batch > 1 else "LATENCY"
280
- LOGGER.info(f"Using OpenVINO {inference_mode} mode for batch={batch} inference...")
316
+ inference_mode = "CUMULATIVE_THROUGHPUT" if batch > 1 and dynamic else "LATENCY"
281
317
  ov_compiled_model = core.compile_model(
282
318
  ov_model,
283
319
  device_name=device_name,
284
320
  config={"PERFORMANCE_HINT": inference_mode},
285
321
  )
322
+ LOGGER.info(
323
+ f"Using OpenVINO {inference_mode} mode for batch={batch} inference on {', '.join(ov_compiled_model.get_property('EXECUTION_DEVICES'))}..."
324
+ )
286
325
  input_name = ov_compiled_model.input().get_any_name()
287
- metadata = w.parent / "metadata.yaml"
288
326
 
289
327
  # TensorRT
290
328
  elif engine:
@@ -295,11 +333,11 @@ class AutoBackend(nn.Module):
295
333
  check_requirements("numpy==1.23.5")
296
334
 
297
335
  try: # https://developer.nvidia.com/nvidia-tensorrt-download
298
- import tensorrt as trt # noqa
336
+ import tensorrt as trt
299
337
  except ImportError:
300
338
  if LINUX:
301
339
  check_requirements("tensorrt>7.0.0,!=10.1.0")
302
- import tensorrt as trt # noqa
340
+ import tensorrt as trt
303
341
  check_version(trt.__version__, ">=7.0.0", hard=True)
304
342
  check_version(trt.__version__, "!=10.1.0", msg="https://github.com/ultralytics/ultralytics/pull/14239")
305
343
  if device.type == "cpu":
@@ -361,14 +399,15 @@ class AutoBackend(nn.Module):
361
399
  im = torch.from_numpy(np.empty(shape, dtype=dtype)).to(device)
362
400
  bindings[name] = Binding(name, dtype, shape, im, int(im.data_ptr()))
363
401
  binding_addrs = OrderedDict((n, d.ptr) for n, d in bindings.items())
364
- batch_size = bindings["images"].shape[0] # if dynamic, this is instead max batch size
365
402
 
366
403
  # CoreML
367
404
  elif coreml:
405
+ check_requirements("coremltools>=8.0")
368
406
  LOGGER.info(f"Loading {w} for CoreML inference...")
369
407
  import coremltools as ct
370
408
 
371
409
  model = ct.models.MLModel(w)
410
+ dynamic = model.get_spec().description.input[0].type.HasField("multiArrayType")
372
411
  metadata = dict(model.user_defined_metadata)
373
412
 
374
413
  # TF SavedModel
@@ -385,7 +424,7 @@ class AutoBackend(nn.Module):
385
424
  LOGGER.info(f"Loading {w} for TensorFlow GraphDef inference...")
386
425
  import tensorflow as tf
387
426
 
388
- from ultralytics.engine.exporter import gd_outputs
427
+ from ultralytics.utils.export.tensorflow import gd_outputs
389
428
 
390
429
  def wrap_frozen_graph(gd, inputs, outputs):
391
430
  """Wrap frozen graphs for deployment."""
@@ -441,13 +480,19 @@ class AutoBackend(nn.Module):
441
480
 
442
481
  # TF.js
443
482
  elif tfjs:
444
- raise NotImplementedError("YOLOv8 TF.js inference is not currently supported.")
483
+ raise NotImplementedError("Ultralytics TF.js inference is not currently supported.")
445
484
 
446
485
  # PaddlePaddle
447
486
  elif paddle:
448
487
  LOGGER.info(f"Loading {w} for PaddlePaddle inference...")
449
- check_requirements("paddlepaddle-gpu" if cuda else "paddlepaddle>=3.0.0")
450
- import paddle.inference as pdi # noqa
488
+ check_requirements(
489
+ "paddlepaddle-gpu"
490
+ if torch.cuda.is_available()
491
+ else "paddlepaddle==3.0.0" # pin 3.0.0 for ARM64
492
+ if ARM64
493
+ else "paddlepaddle>=3.0.0"
494
+ )
495
+ import paddle.inference as pdi
451
496
 
452
497
  w = Path(w)
453
498
  model_file, params_file = None, None
@@ -489,7 +534,7 @@ class AutoBackend(nn.Module):
489
534
  # NCNN
490
535
  elif ncnn:
491
536
  LOGGER.info(f"Loading {w} for NCNN inference...")
492
- check_requirements("git+https://github.com/Tencent/ncnn.git" if ARM64 else "ncnn") # requires NCNN
537
+ check_requirements("git+https://github.com/Tencent/ncnn.git" if ARM64 else "ncnn", cmds="--no-deps")
493
538
  import ncnn as pyncnn
494
539
 
495
540
  net = pyncnn.Net()
@@ -525,6 +570,25 @@ class AutoBackend(nn.Module):
525
570
  rknn_model.init_runtime()
526
571
  metadata = w.parent / "metadata.yaml"
527
572
 
573
+ # ExecuTorch
574
+ elif pte:
575
+ LOGGER.info(f"Loading {w} for ExecuTorch inference...")
576
+ # TorchAO release compatibility table bug https://github.com/pytorch/ao/issues/2919
577
+ check_requirements("setuptools<71.0.0") # Setuptools bug: https://github.com/pypa/setuptools/issues/4483
578
+ check_requirements(("executorch==1.0.0", "flatbuffers"))
579
+ from executorch.runtime import Runtime
580
+
581
+ w = Path(w)
582
+ if w.is_dir():
583
+ model_file = next(w.rglob("*.pte"))
584
+ metadata = w / "metadata.yaml"
585
+ else:
586
+ model_file = w
587
+ metadata = w.parent / "metadata.yaml"
588
+
589
+ program = Runtime.get().load_program(str(model_file))
590
+ model = program.load_method("forward")
591
+
528
592
  # Any other format (unsupported)
529
593
  else:
530
594
  from ultralytics.engine.exporter import export_formats
@@ -541,7 +605,7 @@ class AutoBackend(nn.Module):
541
605
  for k, v in metadata.items():
542
606
  if k in {"stride", "batch", "channels"}:
543
607
  metadata[k] = int(v)
544
- elif k in {"imgsz", "names", "kpt_shape", "args"} and isinstance(v, str):
608
+ elif k in {"imgsz", "names", "kpt_shape", "kpt_names", "args"} and isinstance(v, str):
545
609
  metadata[k] = eval(v)
546
610
  stride = metadata["stride"]
547
611
  task = metadata["task"]
@@ -549,39 +613,41 @@ class AutoBackend(nn.Module):
549
613
  imgsz = metadata["imgsz"]
550
614
  names = metadata["names"]
551
615
  kpt_shape = metadata.get("kpt_shape")
616
+ kpt_names = metadata.get("kpt_names")
552
617
  end2end = metadata.get("args", {}).get("nms", False)
553
618
  dynamic = metadata.get("args", {}).get("dynamic", dynamic)
554
619
  ch = metadata.get("channels", 3)
555
620
  elif not (pt or triton or nn_module):
556
- LOGGER.warning(f"Metadata not found for 'model={weights}'")
621
+ LOGGER.warning(f"Metadata not found for 'model={w}'")
557
622
 
558
623
  # Check names
559
624
  if "names" not in locals(): # names missing
560
625
  names = default_class_names(data)
561
626
  names = check_class_names(names)
562
627
 
563
- # Disable gradients
564
- if pt:
565
- for p in model.parameters():
566
- p.requires_grad = False
567
-
568
628
  self.__dict__.update(locals()) # assign all variables to self
569
629
 
570
- def forward(self, im, augment=False, visualize=False, embed=None, **kwargs):
571
- """
572
- Runs inference on the YOLOv8 MultiBackend model.
630
+ def forward(
631
+ self,
632
+ im: torch.Tensor,
633
+ augment: bool = False,
634
+ visualize: bool = False,
635
+ embed: list | None = None,
636
+ **kwargs: Any,
637
+ ) -> torch.Tensor | list[torch.Tensor]:
638
+ """Run inference on an AutoBackend model.
573
639
 
574
640
  Args:
575
641
  im (torch.Tensor): The image tensor to perform inference on.
576
642
  augment (bool): Whether to perform data augmentation during inference.
577
643
  visualize (bool): Whether to visualize the output predictions.
578
- embed (list | None): A list of feature vectors/embeddings to return.
644
+ embed (list, optional): A list of feature vectors/embeddings to return.
579
645
  **kwargs (Any): Additional keyword arguments for model configuration.
580
646
 
581
647
  Returns:
582
- (torch.Tensor | List[torch.Tensor]): The raw output tensor(s) from the model.
648
+ (torch.Tensor | list[torch.Tensor]): The raw output tensor(s) from the model.
583
649
  """
584
- b, ch, h, w = im.shape # batch, channel, height, width
650
+ _b, _ch, h, w = im.shape # batch, channel, height, width
585
651
  if self.fp16 and im.dtype != torch.float16:
586
652
  im = im.half() # to FP16
587
653
  if self.nhwc:
@@ -620,8 +686,12 @@ class AutoBackend(nn.Module):
620
686
  self.session.run_with_iobinding(self.io)
621
687
  y = self.bindings
622
688
  if self.imx:
623
- # boxes, conf, cls
624
- y = np.concatenate([y[0], y[1][:, :, None], y[2][:, :, None]], axis=-1)
689
+ if self.task == "detect":
690
+ # boxes, conf, cls
691
+ y = np.concatenate([y[0], y[1][:, :, None], y[2][:, :, None]], axis=-1)
692
+ elif self.task == "pose":
693
+ # boxes, conf, kpts
694
+ y = np.concatenate([y[0], y[1][:, :, None], y[2][:, :, None], y[3]], axis=-1)
625
695
 
626
696
  # OpenVINO
627
697
  elif self.xml:
@@ -632,7 +702,7 @@ class AutoBackend(nn.Module):
632
702
  results = [None] * n # preallocate list with None to match the number of images
633
703
 
634
704
  def callback(request, userdata):
635
- """Places result in preallocated list using userdata index."""
705
+ """Place result in preallocated list using userdata index."""
636
706
  results[userdata] = request.results
637
707
 
638
708
  # Create AsyncInferQueue, set the callback and start asynchronous inference for each input image
@@ -642,8 +712,8 @@ class AutoBackend(nn.Module):
642
712
  # Start async inference with userdata=i to specify the position in results list
643
713
  async_queue.start_async(inputs={self.input_name: im[i : i + 1]}, userdata=i) # keep image as BCHW
644
714
  async_queue.wait_all() # wait for all inference requests to complete
645
- y = np.concatenate([list(r.values())[0] for r in results])
646
-
715
+ y = [list(r.values()) for r in results]
716
+ y = [np.concatenate(x) for x in zip(*y)]
647
717
  else: # inference_mode = "LATENCY", optimized for fastest first result at batch-size 1
648
718
  y = list(self.ov_compiled_model(im).values())
649
719
 
@@ -671,21 +741,21 @@ class AutoBackend(nn.Module):
671
741
 
672
742
  # CoreML
673
743
  elif self.coreml:
674
- im = im[0].cpu().numpy()
675
- im_pil = Image.fromarray((im * 255).astype("uint8"))
744
+ im = im.cpu().numpy()
745
+ if self.dynamic:
746
+ im = im.transpose(0, 3, 1, 2)
747
+ else:
748
+ im = Image.fromarray((im[0] * 255).astype("uint8"))
676
749
  # im = im.resize((192, 320), Image.BILINEAR)
677
- y = self.model.predict({"image": im_pil}) # coordinates are xywh normalized
678
- if "confidence" in y:
679
- raise TypeError(
680
- "Ultralytics only supports inference of non-pipelined CoreML models exported with "
681
- f"'nms=False', but 'model={w}' has an NMS pipeline created by an 'nms=True' export."
682
- )
683
- # TODO: CoreML NMS inference handling
684
- # from ultralytics.utils.ops import xywh2xyxy
685
- # box = xywh2xyxy(y['coordinates'] * [[w, h, w, h]]) # xyxy pixels
686
- # conf, cls = y['confidence'].max(1), y['confidence'].argmax(1).astype(np.float32)
687
- # y = np.concatenate((box, conf.reshape(-1, 1), cls.reshape(-1, 1)), 1)
688
- y = list(y.values())
750
+ y = self.model.predict({"image": im}) # coordinates are xywh normalized
751
+ if "confidence" in y: # NMS included
752
+ from ultralytics.utils.ops import xywh2xyxy
753
+
754
+ box = xywh2xyxy(y["coordinates"] * [[w, h, w, h]]) # xyxy pixels
755
+ cls = y["confidence"].argmax(1, keepdims=True)
756
+ y = np.concatenate((box, np.take_along_axis(y["confidence"], cls, axis=1), cls), 1)[None]
757
+ else:
758
+ y = list(y.values())
689
759
  if len(y) == 2 and len(y[1].shape) != 4: # segmentation model
690
760
  y = list(reversed(y)) # reversed for segmentation models (pred, proto)
691
761
 
@@ -721,6 +791,10 @@ class AutoBackend(nn.Module):
721
791
  im = im if isinstance(im, (list, tuple)) else [im]
722
792
  y = self.rknn_model.inference(inputs=im)
723
793
 
794
+ # ExecuTorch
795
+ elif self.pte:
796
+ y = self.model.execute([im])
797
+
724
798
  # TensorFlow (SavedModel, GraphDef, Lite, Edge TPU)
725
799
  else:
726
800
  im = im.cpu().numpy()
@@ -780,9 +854,8 @@ class AutoBackend(nn.Module):
780
854
  else:
781
855
  return self.from_numpy(y)
782
856
 
783
- def from_numpy(self, x):
784
- """
785
- Convert a numpy array to a tensor.
857
+ def from_numpy(self, x: np.ndarray) -> torch.Tensor:
858
+ """Convert a numpy array to a tensor.
786
859
 
787
860
  Args:
788
861
  x (np.ndarray): The array to be converted.
@@ -792,34 +865,33 @@ class AutoBackend(nn.Module):
792
865
  """
793
866
  return torch.tensor(x).to(self.device) if isinstance(x, np.ndarray) else x
794
867
 
795
- def warmup(self, imgsz=(1, 3, 640, 640)):
796
- """
797
- Warm up the model by running one forward pass with a dummy input.
868
+ def warmup(self, imgsz: tuple[int, int, int, int] = (1, 3, 640, 640)) -> None:
869
+ """Warm up the model by running one forward pass with a dummy input.
798
870
 
799
871
  Args:
800
872
  imgsz (tuple): The shape of the dummy input tensor in the format (batch_size, channels, height, width)
801
873
  """
802
- import torchvision # noqa (import here so torchvision import time not recorded in postprocess time)
803
-
804
874
  warmup_types = self.pt, self.jit, self.onnx, self.engine, self.saved_model, self.pb, self.triton, self.nn_module
805
875
  if any(warmup_types) and (self.device.type != "cpu" or self.triton):
806
876
  im = torch.empty(*imgsz, dtype=torch.half if self.fp16 else torch.float, device=self.device) # input
807
877
  for _ in range(2 if self.jit else 1):
808
- self.forward(im) # warmup
878
+ self.forward(im) # warmup model
879
+ warmup_boxes = torch.rand(1, 84, 16, device=self.device) # 16 boxes works best empirically
880
+ warmup_boxes[:, :4] *= imgsz[-1]
881
+ non_max_suppression(warmup_boxes) # warmup NMS
809
882
 
810
883
  @staticmethod
811
- def _model_type(p="path/to/model.pt"):
812
- """
813
- Takes a path to a model file and returns the model type.
884
+ def _model_type(p: str = "path/to/model.pt") -> list[bool]:
885
+ """Take a path to a model file and return the model type.
814
886
 
815
887
  Args:
816
888
  p (str): Path to the model file.
817
889
 
818
890
  Returns:
819
- (List[bool]): List of booleans indicating the model type.
891
+ (list[bool]): List of booleans indicating the model type.
820
892
 
821
893
  Examples:
822
- >>> model = AutoBackend(weights="path/to/model.onnx")
894
+ >>> model = AutoBackend(model="path/to/model.onnx")
823
895
  >>> model_type = model._model_type() # returns "onnx"
824
896
  """
825
897
  from ultralytics.engine.exporter import export_formats
@@ -839,4 +911,4 @@ class AutoBackend(nn.Module):
839
911
  url = urlsplit(p)
840
912
  triton = bool(url.netloc) and bool(url.path) and url.scheme in {"http", "grpc"}
841
913
 
842
- return types + [triton]
914
+ return [*types, triton]