dgenerate-ultralytics-headless 8.3.196__py3-none-any.whl → 8.3.248__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 (243) hide show
  1. {dgenerate_ultralytics_headless-8.3.196.dist-info → dgenerate_ultralytics_headless-8.3.248.dist-info}/METADATA +33 -34
  2. dgenerate_ultralytics_headless-8.3.248.dist-info/RECORD +298 -0
  3. tests/__init__.py +5 -7
  4. tests/conftest.py +8 -15
  5. tests/test_cli.py +8 -10
  6. tests/test_cuda.py +9 -10
  7. tests/test_engine.py +29 -2
  8. tests/test_exports.py +69 -21
  9. tests/test_integrations.py +8 -11
  10. tests/test_python.py +109 -71
  11. tests/test_solutions.py +170 -159
  12. ultralytics/__init__.py +27 -9
  13. ultralytics/cfg/__init__.py +57 -64
  14. ultralytics/cfg/datasets/Argoverse.yaml +7 -6
  15. ultralytics/cfg/datasets/DOTAv1.5.yaml +1 -1
  16. ultralytics/cfg/datasets/DOTAv1.yaml +1 -1
  17. ultralytics/cfg/datasets/ImageNet.yaml +1 -1
  18. ultralytics/cfg/datasets/Objects365.yaml +19 -15
  19. ultralytics/cfg/datasets/SKU-110K.yaml +1 -1
  20. ultralytics/cfg/datasets/VOC.yaml +19 -21
  21. ultralytics/cfg/datasets/VisDrone.yaml +5 -5
  22. ultralytics/cfg/datasets/african-wildlife.yaml +1 -1
  23. ultralytics/cfg/datasets/coco-pose.yaml +24 -2
  24. ultralytics/cfg/datasets/coco.yaml +2 -2
  25. ultralytics/cfg/datasets/coco128-seg.yaml +1 -1
  26. ultralytics/cfg/datasets/coco8-pose.yaml +21 -0
  27. ultralytics/cfg/datasets/construction-ppe.yaml +32 -0
  28. ultralytics/cfg/datasets/dog-pose.yaml +28 -0
  29. ultralytics/cfg/datasets/dota8-multispectral.yaml +1 -1
  30. ultralytics/cfg/datasets/dota8.yaml +2 -2
  31. ultralytics/cfg/datasets/hand-keypoints.yaml +26 -2
  32. ultralytics/cfg/datasets/kitti.yaml +27 -0
  33. ultralytics/cfg/datasets/lvis.yaml +7 -7
  34. ultralytics/cfg/datasets/open-images-v7.yaml +1 -1
  35. ultralytics/cfg/datasets/tiger-pose.yaml +16 -0
  36. ultralytics/cfg/datasets/xView.yaml +16 -16
  37. ultralytics/cfg/default.yaml +96 -94
  38. ultralytics/cfg/models/11/yolo11-pose.yaml +1 -1
  39. ultralytics/cfg/models/11/yoloe-11-seg.yaml +2 -2
  40. ultralytics/cfg/models/11/yoloe-11.yaml +2 -2
  41. ultralytics/cfg/models/rt-detr/rtdetr-l.yaml +1 -1
  42. ultralytics/cfg/models/rt-detr/rtdetr-resnet101.yaml +1 -1
  43. ultralytics/cfg/models/rt-detr/rtdetr-resnet50.yaml +1 -1
  44. ultralytics/cfg/models/rt-detr/rtdetr-x.yaml +1 -1
  45. ultralytics/cfg/models/v10/yolov10b.yaml +2 -2
  46. ultralytics/cfg/models/v10/yolov10l.yaml +2 -2
  47. ultralytics/cfg/models/v10/yolov10m.yaml +2 -2
  48. ultralytics/cfg/models/v10/yolov10n.yaml +2 -2
  49. ultralytics/cfg/models/v10/yolov10s.yaml +2 -2
  50. ultralytics/cfg/models/v10/yolov10x.yaml +2 -2
  51. ultralytics/cfg/models/v3/yolov3-tiny.yaml +1 -1
  52. ultralytics/cfg/models/v6/yolov6.yaml +1 -1
  53. ultralytics/cfg/models/v8/yoloe-v8-seg.yaml +9 -6
  54. ultralytics/cfg/models/v8/yoloe-v8.yaml +9 -6
  55. ultralytics/cfg/models/v8/yolov8-cls-resnet101.yaml +1 -1
  56. ultralytics/cfg/models/v8/yolov8-cls-resnet50.yaml +1 -1
  57. ultralytics/cfg/models/v8/yolov8-ghost-p2.yaml +2 -2
  58. ultralytics/cfg/models/v8/yolov8-ghost-p6.yaml +2 -2
  59. ultralytics/cfg/models/v8/yolov8-ghost.yaml +2 -2
  60. ultralytics/cfg/models/v8/yolov8-obb.yaml +1 -1
  61. ultralytics/cfg/models/v8/yolov8-p2.yaml +1 -1
  62. ultralytics/cfg/models/v8/yolov8-pose-p6.yaml +1 -1
  63. ultralytics/cfg/models/v8/yolov8-rtdetr.yaml +1 -1
  64. ultralytics/cfg/models/v8/yolov8-seg-p6.yaml +1 -1
  65. ultralytics/cfg/models/v8/yolov8-world.yaml +1 -1
  66. ultralytics/cfg/models/v8/yolov8-worldv2.yaml +6 -6
  67. ultralytics/cfg/models/v9/yolov9s.yaml +1 -1
  68. ultralytics/cfg/trackers/botsort.yaml +16 -17
  69. ultralytics/cfg/trackers/bytetrack.yaml +9 -11
  70. ultralytics/data/__init__.py +4 -4
  71. ultralytics/data/annotator.py +3 -4
  72. ultralytics/data/augment.py +286 -476
  73. ultralytics/data/base.py +18 -26
  74. ultralytics/data/build.py +151 -26
  75. ultralytics/data/converter.py +38 -50
  76. ultralytics/data/dataset.py +47 -75
  77. ultralytics/data/loaders.py +42 -49
  78. ultralytics/data/split.py +5 -6
  79. ultralytics/data/split_dota.py +8 -15
  80. ultralytics/data/utils.py +41 -45
  81. ultralytics/engine/exporter.py +462 -462
  82. ultralytics/engine/model.py +150 -191
  83. ultralytics/engine/predictor.py +30 -40
  84. ultralytics/engine/results.py +177 -311
  85. ultralytics/engine/trainer.py +193 -120
  86. ultralytics/engine/tuner.py +77 -63
  87. ultralytics/engine/validator.py +39 -22
  88. ultralytics/hub/__init__.py +16 -19
  89. ultralytics/hub/auth.py +6 -12
  90. ultralytics/hub/google/__init__.py +7 -10
  91. ultralytics/hub/session.py +15 -25
  92. ultralytics/hub/utils.py +5 -8
  93. ultralytics/models/__init__.py +1 -1
  94. ultralytics/models/fastsam/__init__.py +1 -1
  95. ultralytics/models/fastsam/model.py +8 -10
  96. ultralytics/models/fastsam/predict.py +19 -30
  97. ultralytics/models/fastsam/utils.py +1 -2
  98. ultralytics/models/fastsam/val.py +5 -7
  99. ultralytics/models/nas/__init__.py +1 -1
  100. ultralytics/models/nas/model.py +5 -8
  101. ultralytics/models/nas/predict.py +7 -9
  102. ultralytics/models/nas/val.py +1 -2
  103. ultralytics/models/rtdetr/__init__.py +1 -1
  104. ultralytics/models/rtdetr/model.py +7 -8
  105. ultralytics/models/rtdetr/predict.py +15 -19
  106. ultralytics/models/rtdetr/train.py +10 -13
  107. ultralytics/models/rtdetr/val.py +21 -23
  108. ultralytics/models/sam/__init__.py +15 -2
  109. ultralytics/models/sam/amg.py +14 -20
  110. ultralytics/models/sam/build.py +26 -19
  111. ultralytics/models/sam/build_sam3.py +377 -0
  112. ultralytics/models/sam/model.py +29 -32
  113. ultralytics/models/sam/modules/blocks.py +83 -144
  114. ultralytics/models/sam/modules/decoders.py +22 -40
  115. ultralytics/models/sam/modules/encoders.py +44 -101
  116. ultralytics/models/sam/modules/memory_attention.py +16 -30
  117. ultralytics/models/sam/modules/sam.py +206 -79
  118. ultralytics/models/sam/modules/tiny_encoder.py +64 -83
  119. ultralytics/models/sam/modules/transformer.py +18 -28
  120. ultralytics/models/sam/modules/utils.py +174 -50
  121. ultralytics/models/sam/predict.py +2268 -366
  122. ultralytics/models/sam/sam3/__init__.py +3 -0
  123. ultralytics/models/sam/sam3/decoder.py +546 -0
  124. ultralytics/models/sam/sam3/encoder.py +529 -0
  125. ultralytics/models/sam/sam3/geometry_encoders.py +415 -0
  126. ultralytics/models/sam/sam3/maskformer_segmentation.py +286 -0
  127. ultralytics/models/sam/sam3/model_misc.py +199 -0
  128. ultralytics/models/sam/sam3/necks.py +129 -0
  129. ultralytics/models/sam/sam3/sam3_image.py +339 -0
  130. ultralytics/models/sam/sam3/text_encoder_ve.py +307 -0
  131. ultralytics/models/sam/sam3/vitdet.py +547 -0
  132. ultralytics/models/sam/sam3/vl_combiner.py +160 -0
  133. ultralytics/models/utils/loss.py +14 -26
  134. ultralytics/models/utils/ops.py +13 -17
  135. ultralytics/models/yolo/__init__.py +1 -1
  136. ultralytics/models/yolo/classify/predict.py +9 -12
  137. ultralytics/models/yolo/classify/train.py +15 -41
  138. ultralytics/models/yolo/classify/val.py +34 -32
  139. ultralytics/models/yolo/detect/predict.py +8 -11
  140. ultralytics/models/yolo/detect/train.py +13 -32
  141. ultralytics/models/yolo/detect/val.py +75 -63
  142. ultralytics/models/yolo/model.py +37 -53
  143. ultralytics/models/yolo/obb/predict.py +5 -14
  144. ultralytics/models/yolo/obb/train.py +11 -14
  145. ultralytics/models/yolo/obb/val.py +42 -39
  146. ultralytics/models/yolo/pose/__init__.py +1 -1
  147. ultralytics/models/yolo/pose/predict.py +7 -22
  148. ultralytics/models/yolo/pose/train.py +10 -22
  149. ultralytics/models/yolo/pose/val.py +40 -59
  150. ultralytics/models/yolo/segment/predict.py +16 -20
  151. ultralytics/models/yolo/segment/train.py +3 -12
  152. ultralytics/models/yolo/segment/val.py +106 -56
  153. ultralytics/models/yolo/world/train.py +12 -16
  154. ultralytics/models/yolo/world/train_world.py +11 -34
  155. ultralytics/models/yolo/yoloe/__init__.py +7 -7
  156. ultralytics/models/yolo/yoloe/predict.py +16 -23
  157. ultralytics/models/yolo/yoloe/train.py +31 -56
  158. ultralytics/models/yolo/yoloe/train_seg.py +5 -10
  159. ultralytics/models/yolo/yoloe/val.py +16 -21
  160. ultralytics/nn/__init__.py +7 -7
  161. ultralytics/nn/autobackend.py +152 -80
  162. ultralytics/nn/modules/__init__.py +60 -60
  163. ultralytics/nn/modules/activation.py +4 -6
  164. ultralytics/nn/modules/block.py +133 -217
  165. ultralytics/nn/modules/conv.py +52 -97
  166. ultralytics/nn/modules/head.py +64 -116
  167. ultralytics/nn/modules/transformer.py +79 -89
  168. ultralytics/nn/modules/utils.py +16 -21
  169. ultralytics/nn/tasks.py +111 -156
  170. ultralytics/nn/text_model.py +40 -67
  171. ultralytics/solutions/__init__.py +12 -12
  172. ultralytics/solutions/ai_gym.py +11 -17
  173. ultralytics/solutions/analytics.py +15 -16
  174. ultralytics/solutions/config.py +5 -6
  175. ultralytics/solutions/distance_calculation.py +10 -13
  176. ultralytics/solutions/heatmap.py +7 -13
  177. ultralytics/solutions/instance_segmentation.py +5 -8
  178. ultralytics/solutions/object_blurrer.py +7 -10
  179. ultralytics/solutions/object_counter.py +12 -19
  180. ultralytics/solutions/object_cropper.py +8 -14
  181. ultralytics/solutions/parking_management.py +33 -31
  182. ultralytics/solutions/queue_management.py +10 -12
  183. ultralytics/solutions/region_counter.py +9 -12
  184. ultralytics/solutions/security_alarm.py +15 -20
  185. ultralytics/solutions/similarity_search.py +13 -17
  186. ultralytics/solutions/solutions.py +75 -74
  187. ultralytics/solutions/speed_estimation.py +7 -10
  188. ultralytics/solutions/streamlit_inference.py +4 -7
  189. ultralytics/solutions/templates/similarity-search.html +7 -18
  190. ultralytics/solutions/trackzone.py +7 -10
  191. ultralytics/solutions/vision_eye.py +5 -8
  192. ultralytics/trackers/__init__.py +1 -1
  193. ultralytics/trackers/basetrack.py +3 -5
  194. ultralytics/trackers/bot_sort.py +10 -27
  195. ultralytics/trackers/byte_tracker.py +14 -30
  196. ultralytics/trackers/track.py +3 -6
  197. ultralytics/trackers/utils/gmc.py +11 -22
  198. ultralytics/trackers/utils/kalman_filter.py +37 -48
  199. ultralytics/trackers/utils/matching.py +12 -15
  200. ultralytics/utils/__init__.py +116 -116
  201. ultralytics/utils/autobatch.py +2 -4
  202. ultralytics/utils/autodevice.py +17 -18
  203. ultralytics/utils/benchmarks.py +70 -70
  204. ultralytics/utils/callbacks/base.py +8 -10
  205. ultralytics/utils/callbacks/clearml.py +5 -13
  206. ultralytics/utils/callbacks/comet.py +32 -46
  207. ultralytics/utils/callbacks/dvc.py +13 -18
  208. ultralytics/utils/callbacks/mlflow.py +4 -5
  209. ultralytics/utils/callbacks/neptune.py +7 -15
  210. ultralytics/utils/callbacks/platform.py +314 -38
  211. ultralytics/utils/callbacks/raytune.py +3 -4
  212. ultralytics/utils/callbacks/tensorboard.py +23 -31
  213. ultralytics/utils/callbacks/wb.py +10 -13
  214. ultralytics/utils/checks.py +151 -87
  215. ultralytics/utils/cpu.py +3 -8
  216. ultralytics/utils/dist.py +19 -15
  217. ultralytics/utils/downloads.py +29 -41
  218. ultralytics/utils/errors.py +6 -14
  219. ultralytics/utils/events.py +2 -4
  220. ultralytics/utils/export/__init__.py +7 -0
  221. ultralytics/utils/{export.py → export/engine.py} +16 -16
  222. ultralytics/utils/export/imx.py +325 -0
  223. ultralytics/utils/export/tensorflow.py +231 -0
  224. ultralytics/utils/files.py +24 -28
  225. ultralytics/utils/git.py +9 -11
  226. ultralytics/utils/instance.py +30 -51
  227. ultralytics/utils/logger.py +212 -114
  228. ultralytics/utils/loss.py +15 -24
  229. ultralytics/utils/metrics.py +131 -160
  230. ultralytics/utils/nms.py +21 -30
  231. ultralytics/utils/ops.py +107 -165
  232. ultralytics/utils/patches.py +33 -21
  233. ultralytics/utils/plotting.py +122 -119
  234. ultralytics/utils/tal.py +28 -44
  235. ultralytics/utils/torch_utils.py +70 -187
  236. ultralytics/utils/tqdm.py +20 -20
  237. ultralytics/utils/triton.py +13 -19
  238. ultralytics/utils/tuner.py +17 -5
  239. dgenerate_ultralytics_headless-8.3.196.dist-info/RECORD +0 -281
  240. {dgenerate_ultralytics_headless-8.3.196.dist-info → dgenerate_ultralytics_headless-8.3.248.dist-info}/WHEEL +0 -0
  241. {dgenerate_ultralytics_headless-8.3.196.dist-info → dgenerate_ultralytics_headless-8.3.248.dist-info}/entry_points.txt +0 -0
  242. {dgenerate_ultralytics_headless-8.3.196.dist-info → dgenerate_ultralytics_headless-8.3.248.dist-info}/licenses/LICENSE +0 -0
  243. {dgenerate_ultralytics_headless-8.3.196.dist-info → dgenerate_ultralytics_headless-8.3.248.dist-info}/top_level.txt +0 -0
ultralytics/data/base.py CHANGED
@@ -21,11 +21,10 @@ from ultralytics.utils.patches import imread
21
21
 
22
22
 
23
23
  class BaseDataset(Dataset):
24
- """
25
- Base dataset class for loading and processing image data.
24
+ """Base dataset class for loading and processing image data.
26
25
 
27
- This class provides core functionality for loading images, caching, and preparing data for training and inference
28
- in object detection tasks.
26
+ This class provides core functionality for loading images, caching, and preparing data for training and inference in
27
+ object detection tasks.
29
28
 
30
29
  Attributes:
31
30
  img_path (str): Path to the folder containing images.
@@ -34,7 +33,8 @@ class BaseDataset(Dataset):
34
33
  single_cls (bool): Whether to treat all objects as a single class.
35
34
  prefix (str): Prefix to print in log messages.
36
35
  fraction (float): Fraction of dataset to utilize.
37
- channels (int): Number of channels in the images (1 for grayscale, 3 for RGB).
36
+ channels (int): Number of channels in the images (1 for grayscale, 3 for color). Color images loaded with OpenCV
37
+ are in BGR channel order.
38
38
  cv2_flag (int): OpenCV flag for reading images.
39
39
  im_files (list[str]): List of image file paths.
40
40
  labels (list[dict]): List of label data dictionaries.
@@ -86,8 +86,7 @@ class BaseDataset(Dataset):
86
86
  fraction: float = 1.0,
87
87
  channels: int = 3,
88
88
  ):
89
- """
90
- Initialize BaseDataset with given configuration and options.
89
+ """Initialize BaseDataset with given configuration and options.
91
90
 
92
91
  Args:
93
92
  img_path (str | list[str]): Path to the folder containing images or list of image paths.
@@ -103,7 +102,8 @@ class BaseDataset(Dataset):
103
102
  single_cls (bool): If True, single class training is used.
104
103
  classes (list[int], optional): List of included classes.
105
104
  fraction (float): Fraction of dataset to utilize.
106
- channels (int): Number of channels in the images (1 for grayscale, 3 for RGB).
105
+ channels (int): Number of channels in the images (1 for grayscale, 3 for color). Color images loaded with
106
+ OpenCV are in BGR channel order.
107
107
  """
108
108
  super().__init__()
109
109
  self.img_path = img_path
@@ -148,8 +148,7 @@ class BaseDataset(Dataset):
148
148
  self.transforms = self.build_transforms(hyp=hyp)
149
149
 
150
150
  def get_img_files(self, img_path: str | list[str]) -> list[str]:
151
- """
152
- Read image files from the specified path.
151
+ """Read image files from the specified path.
153
152
 
154
153
  Args:
155
154
  img_path (str | list[str]): Path or list of paths to image directories or files.
@@ -186,8 +185,7 @@ class BaseDataset(Dataset):
186
185
  return im_files
187
186
 
188
187
  def update_labels(self, include_class: list[int] | None) -> None:
189
- """
190
- Update labels to include only specified classes.
188
+ """Update labels to include only specified classes.
191
189
 
192
190
  Args:
193
191
  include_class (list[int], optional): List of classes to include. If None, all classes are included.
@@ -210,8 +208,7 @@ class BaseDataset(Dataset):
210
208
  self.labels[i]["cls"][:, 0] = 0
211
209
 
212
210
  def load_image(self, i: int, rect_mode: bool = True) -> tuple[np.ndarray, tuple[int, int], tuple[int, int]]:
213
- """
214
- Load an image from dataset index 'i'.
211
+ """Load an image from dataset index 'i'.
215
212
 
216
213
  Args:
217
214
  i (int): Index of the image to load.
@@ -286,8 +283,7 @@ class BaseDataset(Dataset):
286
283
  np.save(f.as_posix(), imread(self.im_files[i]), allow_pickle=False)
287
284
 
288
285
  def check_cache_disk(self, safety_margin: float = 0.5) -> bool:
289
- """
290
- Check if there's enough disk space for caching images.
286
+ """Check if there's enough disk space for caching images.
291
287
 
292
288
  Args:
293
289
  safety_margin (float): Safety margin factor for disk space calculation.
@@ -307,10 +303,10 @@ class BaseDataset(Dataset):
307
303
  b += im.nbytes
308
304
  if not os.access(Path(im_file).parent, os.W_OK):
309
305
  self.cache = None
310
- LOGGER.warning(f"{self.prefix}Skipping caching images to disk, directory not writeable")
306
+ LOGGER.warning(f"{self.prefix}Skipping caching images to disk, directory not writable")
311
307
  return False
312
308
  disk_required = b * self.ni / n * (1 + safety_margin) # bytes required to cache dataset to disk
313
- total, used, free = shutil.disk_usage(Path(self.im_files[0]).parent)
309
+ total, _used, free = shutil.disk_usage(Path(self.im_files[0]).parent)
314
310
  if disk_required > free:
315
311
  self.cache = None
316
312
  LOGGER.warning(
@@ -322,8 +318,7 @@ class BaseDataset(Dataset):
322
318
  return True
323
319
 
324
320
  def check_cache_ram(self, safety_margin: float = 0.5) -> bool:
325
- """
326
- Check if there's enough RAM for caching images.
321
+ """Check if there's enough RAM for caching images.
327
322
 
328
323
  Args:
329
324
  safety_margin (float): Safety margin factor for RAM calculation.
@@ -381,8 +376,7 @@ class BaseDataset(Dataset):
381
376
  return self.transforms(self.get_image_and_label(index))
382
377
 
383
378
  def get_image_and_label(self, index: int) -> dict[str, Any]:
384
- """
385
- Get and return label information from the dataset.
379
+ """Get and return label information from the dataset.
386
380
 
387
381
  Args:
388
382
  index (int): Index of the image to retrieve.
@@ -410,8 +404,7 @@ class BaseDataset(Dataset):
410
404
  return label
411
405
 
412
406
  def build_transforms(self, hyp: dict[str, Any] | None = None):
413
- """
414
- Users can customize augmentations here.
407
+ """Users can customize augmentations here.
415
408
 
416
409
  Examples:
417
410
  >>> if self.augment:
@@ -424,8 +417,7 @@ class BaseDataset(Dataset):
424
417
  raise NotImplementedError
425
418
 
426
419
  def get_labels(self) -> list[dict[str, Any]]:
427
- """
428
- Users can customize their own format here.
420
+ """Users can customize their own format here.
429
421
 
430
422
  Examples:
431
423
  Ensure output is a dictionary with the following keys:
ultralytics/data/build.py CHANGED
@@ -2,16 +2,19 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import math
5
6
  import os
6
7
  import random
7
8
  from collections.abc import Iterator
8
9
  from pathlib import Path
9
10
  from typing import Any
11
+ from urllib.parse import urlsplit
10
12
 
11
13
  import numpy as np
12
14
  import torch
15
+ import torch.distributed as dist
13
16
  from PIL import Image
14
- from torch.utils.data import dataloader, distributed
17
+ from torch.utils.data import Dataset, dataloader, distributed
15
18
 
16
19
  from ultralytics.cfg import IterableSimpleNamespace
17
20
  from ultralytics.data.dataset import GroundingDataset, YOLODataset, YOLOMultiModalDataset
@@ -32,8 +35,7 @@ from ultralytics.utils.torch_utils import TORCH_2_0
32
35
 
33
36
 
34
37
  class InfiniteDataLoader(dataloader.DataLoader):
35
- """
36
- Dataloader that reuses workers for infinite iteration.
38
+ """DataLoader that reuses workers for infinite iteration.
37
39
 
38
40
  This dataloader extends the PyTorch DataLoader to provide infinite recycling of workers, which improves efficiency
39
41
  for training loops that need to iterate through the dataset multiple times without recreating workers.
@@ -49,7 +51,7 @@ class InfiniteDataLoader(dataloader.DataLoader):
49
51
  reset: Reset the iterator, useful when modifying dataset settings during training.
50
52
 
51
53
  Examples:
52
- Create an infinite dataloader for training
54
+ Create an infinite DataLoader for training
53
55
  >>> dataset = YOLODataset(...)
54
56
  >>> dataloader = InfiniteDataLoader(dataset, batch_size=16, shuffle=True)
55
57
  >>> for batch in dataloader: # Infinite iteration
@@ -74,7 +76,7 @@ class InfiniteDataLoader(dataloader.DataLoader):
74
76
  yield next(self.iterator)
75
77
 
76
78
  def __del__(self):
77
- """Ensure that workers are properly terminated when the dataloader is deleted."""
79
+ """Ensure that workers are properly terminated when the DataLoader is deleted."""
78
80
  try:
79
81
  if not hasattr(self.iterator, "_workers"):
80
82
  return
@@ -91,11 +93,10 @@ class InfiniteDataLoader(dataloader.DataLoader):
91
93
 
92
94
 
93
95
  class _RepeatSampler:
94
- """
95
- Sampler that repeats forever for infinite iteration.
96
+ """Sampler that repeats forever for infinite iteration.
96
97
 
97
- This sampler wraps another sampler and yields its contents indefinitely, allowing for infinite iteration
98
- over a dataset without recreating the sampler.
98
+ This sampler wraps another sampler and yields its contents indefinitely, allowing for infinite iteration over a
99
+ dataset without recreating the sampler.
99
100
 
100
101
  Attributes:
101
102
  sampler (Dataset.sampler): The sampler to repeat.
@@ -111,7 +112,109 @@ class _RepeatSampler:
111
112
  yield from iter(self.sampler)
112
113
 
113
114
 
114
- def seed_worker(worker_id: int): # noqa
115
+ class ContiguousDistributedSampler(torch.utils.data.Sampler):
116
+ """Distributed sampler that assigns contiguous batch-aligned chunks of the dataset to each GPU.
117
+
118
+ Unlike PyTorch's DistributedSampler which distributes samples in a round-robin fashion (GPU 0 gets indices
119
+ [0,2,4,...], GPU 1 gets [1,3,5,...]), this sampler gives each GPU contiguous batches of the dataset (GPU 0 gets
120
+ batches [0,1,2,...], GPU 1 gets batches [k,k+1,...], etc.). This preserves any ordering or grouping in the original
121
+ dataset, which is critical when samples are organized by similarity (e.g., images sorted by size to enable efficient
122
+ batching without padding when using rect=True).
123
+
124
+ The sampler handles uneven batch counts by distributing remainder batches to the first few ranks, ensuring all
125
+ samples are covered exactly once across all GPUs.
126
+
127
+ Args:
128
+ dataset (Dataset): Dataset to sample from. Must implement __len__.
129
+ num_replicas (int, optional): Number of distributed processes. Defaults to world size.
130
+ batch_size (int, optional): Batch size used by dataloader. Defaults to dataset batch size.
131
+ rank (int, optional): Rank of current process. Defaults to current rank.
132
+ shuffle (bool, optional): Whether to shuffle indices within each rank's chunk. Defaults to False. When True,
133
+ shuffling is deterministic and controlled by set_epoch() for reproducibility.
134
+
135
+ Examples:
136
+ >>> # For validation with size-grouped images
137
+ >>> sampler = ContiguousDistributedSampler(val_dataset, batch_size=32, shuffle=False)
138
+ >>> loader = DataLoader(val_dataset, batch_size=32, sampler=sampler)
139
+ >>> # For training with shuffling
140
+ >>> sampler = ContiguousDistributedSampler(train_dataset, batch_size=32, shuffle=True)
141
+ >>> for epoch in range(num_epochs):
142
+ ... sampler.set_epoch(epoch)
143
+ ... for batch in loader:
144
+ ... ...
145
+ """
146
+
147
+ def __init__(
148
+ self,
149
+ dataset: Dataset,
150
+ num_replicas: int | None = None,
151
+ batch_size: int | None = None,
152
+ rank: int | None = None,
153
+ shuffle: bool = False,
154
+ ) -> None:
155
+ """Initialize the sampler with dataset and distributed training parameters."""
156
+ if num_replicas is None:
157
+ num_replicas = dist.get_world_size() if dist.is_initialized() else 1
158
+ if rank is None:
159
+ rank = dist.get_rank() if dist.is_initialized() else 0
160
+ if batch_size is None:
161
+ batch_size = getattr(dataset, "batch_size", 1)
162
+
163
+ self.num_replicas = num_replicas
164
+ self.rank = rank
165
+ self.epoch = 0
166
+ self.shuffle = shuffle
167
+ self.total_size = len(dataset)
168
+ # ensure all ranks have a sample if batch size >= total size; degenerates to round-robin sampler
169
+ self.batch_size = 1 if batch_size >= self.total_size else batch_size
170
+ self.num_batches = math.ceil(self.total_size / self.batch_size)
171
+
172
+ def _get_rank_indices(self) -> tuple[int, int]:
173
+ """Calculate the start and end sample indices for this rank."""
174
+ # Calculate which batches this rank handles
175
+ batches_per_rank_base = self.num_batches // self.num_replicas
176
+ remainder = self.num_batches % self.num_replicas
177
+
178
+ # This rank gets an extra batch if rank < remainder
179
+ batches_for_this_rank = batches_per_rank_base + (1 if self.rank < remainder else 0)
180
+
181
+ # Calculate starting batch: base position + number of extra batches given to earlier ranks
182
+ start_batch = self.rank * batches_per_rank_base + min(self.rank, remainder)
183
+ end_batch = start_batch + batches_for_this_rank
184
+
185
+ # Convert batch indices to sample indices
186
+ start_idx = start_batch * self.batch_size
187
+ end_idx = min(end_batch * self.batch_size, self.total_size)
188
+
189
+ return start_idx, end_idx
190
+
191
+ def __iter__(self) -> Iterator:
192
+ """Generate indices for this rank's contiguous chunk of the dataset."""
193
+ start_idx, end_idx = self._get_rank_indices()
194
+ indices = list(range(start_idx, end_idx))
195
+
196
+ if self.shuffle:
197
+ g = torch.Generator()
198
+ g.manual_seed(self.epoch)
199
+ indices = [indices[i] for i in torch.randperm(len(indices), generator=g).tolist()]
200
+
201
+ return iter(indices)
202
+
203
+ def __len__(self) -> int:
204
+ """Return the number of samples in this rank's chunk."""
205
+ start_idx, end_idx = self._get_rank_indices()
206
+ return end_idx - start_idx
207
+
208
+ def set_epoch(self, epoch: int) -> None:
209
+ """Set the epoch for this sampler to ensure different shuffling patterns across epochs.
210
+
211
+ Args:
212
+ epoch (int): Epoch number to use as the random seed for shuffling.
213
+ """
214
+ self.epoch = epoch
215
+
216
+
217
+ def seed_worker(worker_id: int) -> None:
115
218
  """Set dataloader worker seed for reproducibility across worker processes."""
116
219
  worker_seed = torch.initial_seed() % 2**32
117
220
  np.random.seed(worker_seed)
@@ -127,7 +230,7 @@ def build_yolo_dataset(
127
230
  rect: bool = False,
128
231
  stride: int = 32,
129
232
  multi_modal: bool = False,
130
- ):
233
+ ) -> Dataset:
131
234
  """Build and return a YOLO dataset based on configuration parameters."""
132
235
  dataset = YOLOMultiModalDataset if multi_modal else YOLODataset
133
236
  return dataset(
@@ -158,7 +261,7 @@ def build_grounding(
158
261
  rect: bool = False,
159
262
  stride: int = 32,
160
263
  max_samples: int = 80,
161
- ):
264
+ ) -> Dataset:
162
265
  """Build and return a GroundingDataset based on configuration parameters."""
163
266
  return GroundingDataset(
164
267
  img_path=img_path,
@@ -180,9 +283,16 @@ def build_grounding(
180
283
  )
181
284
 
182
285
 
183
- def build_dataloader(dataset, batch: int, workers: int, shuffle: bool = True, rank: int = -1, drop_last: bool = False):
184
- """
185
- Create and return an InfiniteDataLoader or DataLoader for training or validation.
286
+ def build_dataloader(
287
+ dataset,
288
+ batch: int,
289
+ workers: int,
290
+ shuffle: bool = True,
291
+ rank: int = -1,
292
+ drop_last: bool = False,
293
+ pin_memory: bool = True,
294
+ ) -> InfiniteDataLoader:
295
+ """Create and return an InfiniteDataLoader or DataLoader for training or validation.
186
296
 
187
297
  Args:
188
298
  dataset (Dataset): Dataset to load data from.
@@ -191,6 +301,7 @@ def build_dataloader(dataset, batch: int, workers: int, shuffle: bool = True, ra
191
301
  shuffle (bool, optional): Whether to shuffle the dataset.
192
302
  rank (int, optional): Process rank in distributed training. -1 for single-GPU training.
193
303
  drop_last (bool, optional): Whether to drop the last incomplete batch.
304
+ pin_memory (bool, optional): Whether to use pinned memory for dataloader.
194
305
 
195
306
  Returns:
196
307
  (InfiniteDataLoader): A dataloader that can be used for training or validation.
@@ -203,7 +314,13 @@ def build_dataloader(dataset, batch: int, workers: int, shuffle: bool = True, ra
203
314
  batch = min(batch, len(dataset))
204
315
  nd = torch.cuda.device_count() # number of CUDA devices
205
316
  nw = min(os.cpu_count() // max(nd, 1), workers) # number of workers
206
- sampler = None if rank == -1 else distributed.DistributedSampler(dataset, shuffle=shuffle)
317
+ sampler = (
318
+ None
319
+ if rank == -1
320
+ else distributed.DistributedSampler(dataset, shuffle=shuffle)
321
+ if shuffle
322
+ else ContiguousDistributedSampler(dataset)
323
+ )
207
324
  generator = torch.Generator()
208
325
  generator.manual_seed(6148914691236517205 + RANK)
209
326
  return InfiniteDataLoader(
@@ -213,7 +330,7 @@ def build_dataloader(dataset, batch: int, workers: int, shuffle: bool = True, ra
213
330
  num_workers=nw,
214
331
  sampler=sampler,
215
332
  prefetch_factor=4 if nw > 0 else None, # increase over default 2
216
- pin_memory=nd > 0,
333
+ pin_memory=nd > 0 and pin_memory,
217
334
  collate_fn=getattr(dataset, "collate_fn", None),
218
335
  worker_init_fn=seed_worker,
219
336
  generator=generator,
@@ -221,9 +338,10 @@ def build_dataloader(dataset, batch: int, workers: int, shuffle: bool = True, ra
221
338
  )
222
339
 
223
340
 
224
- def check_source(source):
225
- """
226
- Check the type of input source and return corresponding flag values.
341
+ def check_source(
342
+ source: str | int | Path | list | tuple | np.ndarray | Image.Image | torch.Tensor,
343
+ ) -> tuple[Any, bool, bool, bool, bool, bool]:
344
+ """Check the type of input source and return corresponding flag values.
227
345
 
228
346
  Args:
229
347
  source (str | int | Path | list | tuple | np.ndarray | PIL.Image | torch.Tensor): The input source to check.
@@ -247,8 +365,10 @@ def check_source(source):
247
365
  if isinstance(source, (str, int, Path)): # int for local usb camera
248
366
  source = str(source)
249
367
  source_lower = source.lower()
250
- is_file = source_lower.rpartition(".")[-1] in (IMG_FORMATS | VID_FORMATS)
251
368
  is_url = source_lower.startswith(("https://", "http://", "rtsp://", "rtmp://", "tcp://"))
369
+ is_file = (urlsplit(source_lower).path if is_url else source_lower).rpartition(".")[-1] in (
370
+ IMG_FORMATS | VID_FORMATS
371
+ )
252
372
  webcam = source.isnumeric() or source.endswith(".streams") or (is_url and not is_file)
253
373
  screenshot = source_lower == "screen"
254
374
  if is_url and is_file:
@@ -268,12 +388,17 @@ def check_source(source):
268
388
  return source, webcam, screenshot, from_img, in_memory, tensor
269
389
 
270
390
 
271
- def load_inference_source(source=None, batch: int = 1, vid_stride: int = 1, buffer: bool = False, channels: int = 3):
272
- """
273
- Load an inference source for object detection and apply necessary transformations.
391
+ def load_inference_source(
392
+ source: str | int | Path | list | tuple | np.ndarray | Image.Image | torch.Tensor,
393
+ batch: int = 1,
394
+ vid_stride: int = 1,
395
+ buffer: bool = False,
396
+ channels: int = 3,
397
+ ):
398
+ """Load an inference source for object detection and apply necessary transformations.
274
399
 
275
400
  Args:
276
- source (str | Path | torch.Tensor | PIL.Image | np.ndarray, optional): The input source for inference.
401
+ source (str | Path | list | tuple | torch.Tensor | PIL.Image | np.ndarray): The input source for inference.
277
402
  batch (int, optional): Batch size for dataloaders.
278
403
  vid_stride (int, optional): The frame interval for video sources.
279
404
  buffer (bool, optional): Whether stream frames will be buffered.
@@ -292,7 +417,7 @@ def load_inference_source(source=None, batch: int = 1, vid_stride: int = 1, buff
292
417
  source, stream, screenshot, from_img, in_memory, tensor = check_source(source)
293
418
  source_type = source.source_type if in_memory else SourceTypes(stream, screenshot, from_img, tensor)
294
419
 
295
- # Dataloader
420
+ # DataLoader
296
421
  if tensor:
297
422
  dataset = LoadTensor(source)
298
423
  elif in_memory:
@@ -14,19 +14,18 @@ import cv2
14
14
  import numpy as np
15
15
  from PIL import Image
16
16
 
17
- from ultralytics.utils import DATASETS_DIR, LOGGER, NUM_THREADS, TQDM, YAML
17
+ from ultralytics.utils import ASSETS_URL, DATASETS_DIR, LOGGER, NUM_THREADS, TQDM, YAML
18
18
  from ultralytics.utils.checks import check_file, check_requirements
19
19
  from ultralytics.utils.downloads import download, zip_directory
20
20
  from ultralytics.utils.files import increment_path
21
21
 
22
22
 
23
23
  def coco91_to_coco80_class() -> list[int]:
24
- """
25
- Convert 91-index COCO class IDs to 80-index COCO class IDs.
24
+ """Convert 91-index COCO class IDs to 80-index COCO class IDs.
26
25
 
27
26
  Returns:
28
- (list[int]): A list of 91 class IDs where the index represents the 80-index class ID and the value
29
- is the corresponding 91-index class ID.
27
+ (list[int]): A list of 91 class IDs where the index represents the 80-index class ID and the value is the
28
+ corresponding 91-index class ID.
30
29
  """
31
30
  return [
32
31
  0,
@@ -124,15 +123,11 @@ def coco91_to_coco80_class() -> list[int]:
124
123
 
125
124
 
126
125
  def coco80_to_coco91_class() -> list[int]:
127
- r"""
128
- Convert 80-index (val2014) to 91-index (paper).
126
+ r"""Convert 80-index (val2014) to 91-index (paper).
129
127
 
130
128
  Returns:
131
129
  (list[int]): A list of 80 class IDs where each value is the corresponding 91-index class ID.
132
130
 
133
- References:
134
- https://tech.amikelive.com/node-718/what-object-categories-labels-are-in-coco-dataset/
135
-
136
131
  Examples:
137
132
  >>> import numpy as np
138
133
  >>> a = np.loadtxt("data/coco.names", dtype="str", delimiter="\n")
@@ -143,6 +138,9 @@ def coco80_to_coco91_class() -> list[int]:
143
138
 
144
139
  Convert the COCO to darknet format
145
140
  >>> x2 = [list(b[i] == a).index(True) if any(b[i] == a) else None for i in range(91)]
141
+
142
+ References:
143
+ https://tech.amikelive.com/node-718/what-object-categories-labels-are-in-coco-dataset/
146
144
  """
147
145
  return [
148
146
  1,
@@ -236,8 +234,7 @@ def convert_coco(
236
234
  cls91to80: bool = True,
237
235
  lvis: bool = False,
238
236
  ):
239
- """
240
- Convert COCO dataset annotations to a YOLO annotation format suitable for training YOLO models.
237
+ """Convert COCO dataset annotations to a YOLO annotation format suitable for training YOLO models.
241
238
 
242
239
  Args:
243
240
  labels_dir (str, optional): Path to directory containing COCO dataset annotation files.
@@ -308,7 +305,7 @@ def convert_coco(
308
305
  continue
309
306
 
310
307
  cls = coco80[ann["category_id"] - 1] if cls91to80 else ann["category_id"] - 1 # class
311
- box = [cls] + box.tolist()
308
+ box = [cls, *box.tolist()]
312
309
  if box not in bboxes:
313
310
  bboxes.append(box)
314
311
  if use_segments and ann.get("segmentation") is not None:
@@ -321,7 +318,7 @@ def convert_coco(
321
318
  else:
322
319
  s = [j for i in ann["segmentation"] for j in i] # all segments concatenated
323
320
  s = (np.array(s).reshape(-1, 2) / np.array([w, h])).reshape(-1).tolist()
324
- s = [cls] + s
321
+ s = [cls, *s]
325
322
  segments.append(s)
326
323
  if use_keypoints and ann.get("keypoints") is not None:
327
324
  keypoints.append(
@@ -348,8 +345,7 @@ def convert_coco(
348
345
 
349
346
 
350
347
  def convert_segment_masks_to_yolo_seg(masks_dir: str, output_dir: str, classes: int):
351
- """
352
- Convert a dataset of segmentation mask images to the YOLO segmentation format.
348
+ """Convert a dataset of segmentation mask images to the YOLO segmentation format.
353
349
 
354
350
  This function takes the directory containing the binary format mask images and converts them into YOLO segmentation
355
351
  format. The converted masks are saved in the specified output directory.
@@ -357,7 +353,7 @@ def convert_segment_masks_to_yolo_seg(masks_dir: str, output_dir: str, classes:
357
353
  Args:
358
354
  masks_dir (str): The path to the directory where all mask images (png, jpg) are stored.
359
355
  output_dir (str): The path to the directory where the converted YOLO segmentation masks will be stored.
360
- classes (int): Total classes in the dataset i.e. for COCO classes=80
356
+ classes (int): Total number of classes in the dataset, e.g., 80 for COCO.
361
357
 
362
358
  Examples:
363
359
  >>> from ultralytics.data.converter import convert_segment_masks_to_yolo_seg
@@ -424,8 +420,7 @@ def convert_segment_masks_to_yolo_seg(masks_dir: str, output_dir: str, classes:
424
420
 
425
421
 
426
422
  def convert_dota_to_yolo_obb(dota_root_path: str):
427
- """
428
- Convert DOTA dataset annotations to YOLO OBB (Oriented Bounding Box) format.
423
+ """Convert DOTA dataset annotations to YOLO OBB (Oriented Bounding Box) format.
429
424
 
430
425
  The function processes images in the 'train' and 'val' folders of the DOTA dataset. For each image, it reads the
431
426
  associated label from the original labels directory and writes new labels in YOLO OBB format to a new directory.
@@ -517,8 +512,7 @@ def convert_dota_to_yolo_obb(dota_root_path: str):
517
512
 
518
513
 
519
514
  def min_index(arr1: np.ndarray, arr2: np.ndarray):
520
- """
521
- Find a pair of indexes with the shortest distance between two arrays of 2D points.
515
+ """Find a pair of indexes with the shortest distance between two arrays of 2D points.
522
516
 
523
517
  Args:
524
518
  arr1 (np.ndarray): A NumPy array of shape (N, 2) representing N 2D points.
@@ -533,14 +527,14 @@ def min_index(arr1: np.ndarray, arr2: np.ndarray):
533
527
 
534
528
 
535
529
  def merge_multi_segment(segments: list[list]):
536
- """
537
- Merge multiple segments into one list by connecting the coordinates with the minimum distance between each segment.
530
+ """Merge multiple segments into one list by connecting the coordinates with the minimum distance between each
531
+ segment.
538
532
 
539
533
  This function connects these coordinates with a thin line to merge all segments into one.
540
534
 
541
535
  Args:
542
- segments (list[list]): Original segmentations in COCO's JSON file.
543
- Each element is a list of coordinates, like [segmentation1, segmentation2,...].
536
+ segments (list[list]): Original segmentations in COCO's JSON file. Each element is a list of coordinates, like
537
+ [segmentation1, segmentation2,...].
544
538
 
545
539
  Returns:
546
540
  s (list[np.ndarray]): A list of connected segments represented as NumPy arrays.
@@ -584,14 +578,13 @@ def merge_multi_segment(segments: list[list]):
584
578
 
585
579
 
586
580
  def yolo_bbox2segment(im_dir: str | Path, save_dir: str | Path | None = None, sam_model: str = "sam_b.pt", device=None):
587
- """
588
- Convert existing object detection dataset (bounding boxes) to segmentation dataset or oriented bounding box (OBB) in
589
- YOLO format. Generate segmentation data using SAM auto-annotator as needed.
581
+ """Convert existing object detection dataset (bounding boxes) to segmentation dataset or oriented bounding box (OBB)
582
+ in YOLO format. Generate segmentation data using SAM auto-annotator as needed.
590
583
 
591
584
  Args:
592
585
  im_dir (str | Path): Path to image directory to convert.
593
- save_dir (str | Path, optional): Path to save the generated labels, labels will be saved
594
- into `labels-segment` in the same directory level of `im_dir` if save_dir is None.
586
+ save_dir (str | Path, optional): Path to save the generated labels, labels will be saved into `labels-segment`
587
+ in the same directory level of `im_dir` if save_dir is None.
595
588
  sam_model (str): Segmentation model to use for intermediate segmentation data.
596
589
  device (int | str, optional): The specific device to run SAM models.
597
590
 
@@ -648,12 +641,11 @@ def yolo_bbox2segment(im_dir: str | Path, save_dir: str | Path | None = None, sa
648
641
 
649
642
 
650
643
  def create_synthetic_coco_dataset():
651
- """
652
- Create a synthetic COCO dataset with random images based on filenames from label lists.
644
+ """Create a synthetic COCO dataset with random images based on filenames from label lists.
653
645
 
654
- This function downloads COCO labels, reads image filenames from label list files,
655
- creates synthetic images for train2017 and val2017 subsets, and organizes
656
- them in the COCO dataset structure. It uses multithreading to generate images efficiently.
646
+ This function downloads COCO labels, reads image filenames from label list files, creates synthetic images for
647
+ train2017 and val2017 subsets, and organizes them in the COCO dataset structure. It uses multithreading to generate
648
+ images efficiently.
657
649
 
658
650
  Examples:
659
651
  >>> from ultralytics.data.converter import create_synthetic_coco_dataset
@@ -678,9 +670,7 @@ def create_synthetic_coco_dataset():
678
670
 
679
671
  # Download labels
680
672
  dir = DATASETS_DIR / "coco"
681
- url = "https://github.com/ultralytics/assets/releases/download/v0.0.0/"
682
- label_zip = "coco2017labels-segments.zip"
683
- download([url + label_zip], dir=dir.parent)
673
+ download([f"{ASSETS_URL}/coco2017labels-segments.zip"], dir=dir.parent)
684
674
 
685
675
  # Create synthetic images
686
676
  shutil.rmtree(dir / "labels" / "test2017", ignore_errors=True) # Remove test2017 directory as not needed
@@ -706,11 +696,10 @@ def create_synthetic_coco_dataset():
706
696
 
707
697
 
708
698
  def convert_to_multispectral(path: str | Path, n_channels: int = 10, replace: bool = False, zip: bool = False):
709
- """
710
- Convert RGB images to multispectral images by interpolating across wavelength bands.
699
+ """Convert RGB images to multispectral images by interpolating across wavelength bands.
711
700
 
712
- This function takes RGB images and interpolates them to create multispectral images with a specified number
713
- of channels. It can process either a single image or a directory of images.
701
+ This function takes RGB images and interpolates them to create multispectral images with a specified number of
702
+ channels. It can process either a single image or a directory of images.
714
703
 
715
704
  Args:
716
705
  path (str | Path): Path to an image file or directory containing images to convert.
@@ -732,7 +721,7 @@ def convert_to_multispectral(path: str | Path, n_channels: int = 10, replace: bo
732
721
  path = Path(path)
733
722
  if path.is_dir():
734
723
  # Process directory
735
- im_files = sum((list(path.rglob(f"*.{ext}")) for ext in (IMG_FORMATS - {"tif", "tiff"})), [])
724
+ im_files = [f for ext in (IMG_FORMATS - {"tif", "tiff"}) for f in path.rglob(f"*.{ext}")]
736
725
  for im_path in im_files:
737
726
  try:
738
727
  convert_to_multispectral(im_path, n_channels)
@@ -758,12 +747,11 @@ def convert_to_multispectral(path: str | Path, n_channels: int = 10, replace: bo
758
747
 
759
748
 
760
749
  async def convert_ndjson_to_yolo(ndjson_path: str | Path, output_path: str | Path | None = None) -> Path:
761
- """
762
- Convert NDJSON dataset format to Ultralytics YOLO11 dataset structure.
750
+ """Convert NDJSON dataset format to Ultralytics YOLO11 dataset structure.
763
751
 
764
- This function converts datasets stored in NDJSON (Newline Delimited JSON) format to the standard YOLO
765
- format with separate directories for images and labels. It supports parallel processing for efficient
766
- conversion of large datasets and can download images from URLs if they don't exist locally.
752
+ This function converts datasets stored in NDJSON (Newline Delimited JSON) format to the standard YOLO format with
753
+ separate directories for images and labels. It supports parallel processing for efficient conversion of large
754
+ datasets and can download images from URLs if they don't exist locally.
767
755
 
768
756
  The NDJSON format consists of:
769
757
  - First line: Dataset metadata with class names and configuration
@@ -771,8 +759,8 @@ async def convert_ndjson_to_yolo(ndjson_path: str | Path, output_path: str | Pat
771
759
 
772
760
  Args:
773
761
  ndjson_path (Union[str, Path]): Path to the input NDJSON file containing dataset information.
774
- output_path (Optional[Union[str, Path]], optional): Directory where the converted YOLO dataset
775
- will be saved. If None, uses the parent directory of the NDJSON file. Defaults to None.
762
+ output_path (Optional[Union[str, Path]], optional): Directory where the converted YOLO dataset will be saved. If
763
+ None, uses the parent directory of the NDJSON file. Defaults to None.
776
764
 
777
765
  Returns:
778
766
  (Path): Path to the generated data.yaml file that can be used for YOLO training.