dgenerate-ultralytics-headless 8.3.214__py3-none-any.whl → 8.4.7__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 (249) hide show
  1. {dgenerate_ultralytics_headless-8.3.214.dist-info → dgenerate_ultralytics_headless-8.4.7.dist-info}/METADATA +64 -74
  2. dgenerate_ultralytics_headless-8.4.7.dist-info/RECORD +311 -0
  3. {dgenerate_ultralytics_headless-8.3.214.dist-info → dgenerate_ultralytics_headless-8.4.7.dist-info}/WHEEL +1 -1
  4. tests/__init__.py +7 -9
  5. tests/conftest.py +8 -15
  6. tests/test_cli.py +1 -1
  7. tests/test_cuda.py +13 -10
  8. tests/test_engine.py +9 -9
  9. tests/test_exports.py +65 -13
  10. tests/test_integrations.py +13 -13
  11. tests/test_python.py +125 -69
  12. tests/test_solutions.py +161 -152
  13. ultralytics/__init__.py +1 -1
  14. ultralytics/cfg/__init__.py +86 -92
  15. ultralytics/cfg/datasets/Argoverse.yaml +7 -6
  16. ultralytics/cfg/datasets/DOTAv1.5.yaml +1 -1
  17. ultralytics/cfg/datasets/DOTAv1.yaml +1 -1
  18. ultralytics/cfg/datasets/ImageNet.yaml +1 -1
  19. ultralytics/cfg/datasets/TT100K.yaml +346 -0
  20. ultralytics/cfg/datasets/VOC.yaml +15 -16
  21. ultralytics/cfg/datasets/african-wildlife.yaml +1 -1
  22. ultralytics/cfg/datasets/coco-pose.yaml +21 -0
  23. ultralytics/cfg/datasets/coco12-formats.yaml +101 -0
  24. ultralytics/cfg/datasets/coco128-seg.yaml +1 -1
  25. ultralytics/cfg/datasets/coco8-pose.yaml +21 -0
  26. ultralytics/cfg/datasets/dog-pose.yaml +28 -0
  27. ultralytics/cfg/datasets/dota8-multispectral.yaml +1 -1
  28. ultralytics/cfg/datasets/dota8.yaml +2 -2
  29. ultralytics/cfg/datasets/hand-keypoints.yaml +26 -2
  30. ultralytics/cfg/datasets/kitti.yaml +27 -0
  31. ultralytics/cfg/datasets/lvis.yaml +5 -5
  32. ultralytics/cfg/datasets/open-images-v7.yaml +1 -1
  33. ultralytics/cfg/datasets/tiger-pose.yaml +16 -0
  34. ultralytics/cfg/datasets/xView.yaml +16 -16
  35. ultralytics/cfg/default.yaml +4 -2
  36. ultralytics/cfg/models/11/yolo11-pose.yaml +1 -1
  37. ultralytics/cfg/models/11/yoloe-11-seg.yaml +2 -2
  38. ultralytics/cfg/models/11/yoloe-11.yaml +2 -2
  39. ultralytics/cfg/models/26/yolo26-cls.yaml +33 -0
  40. ultralytics/cfg/models/26/yolo26-obb.yaml +52 -0
  41. ultralytics/cfg/models/26/yolo26-p2.yaml +60 -0
  42. ultralytics/cfg/models/26/yolo26-p6.yaml +62 -0
  43. ultralytics/cfg/models/26/yolo26-pose.yaml +53 -0
  44. ultralytics/cfg/models/26/yolo26-seg.yaml +52 -0
  45. ultralytics/cfg/models/26/yolo26.yaml +52 -0
  46. ultralytics/cfg/models/26/yoloe-26-seg.yaml +53 -0
  47. ultralytics/cfg/models/26/yoloe-26.yaml +53 -0
  48. ultralytics/cfg/models/rt-detr/rtdetr-l.yaml +1 -1
  49. ultralytics/cfg/models/rt-detr/rtdetr-resnet101.yaml +1 -1
  50. ultralytics/cfg/models/rt-detr/rtdetr-resnet50.yaml +1 -1
  51. ultralytics/cfg/models/rt-detr/rtdetr-x.yaml +1 -1
  52. ultralytics/cfg/models/v10/yolov10b.yaml +2 -2
  53. ultralytics/cfg/models/v10/yolov10l.yaml +2 -2
  54. ultralytics/cfg/models/v10/yolov10m.yaml +2 -2
  55. ultralytics/cfg/models/v10/yolov10n.yaml +2 -2
  56. ultralytics/cfg/models/v10/yolov10s.yaml +2 -2
  57. ultralytics/cfg/models/v10/yolov10x.yaml +2 -2
  58. ultralytics/cfg/models/v3/yolov3-tiny.yaml +1 -1
  59. ultralytics/cfg/models/v6/yolov6.yaml +1 -1
  60. ultralytics/cfg/models/v8/yoloe-v8-seg.yaml +9 -6
  61. ultralytics/cfg/models/v8/yoloe-v8.yaml +9 -6
  62. ultralytics/cfg/models/v8/yolov8-cls-resnet101.yaml +1 -1
  63. ultralytics/cfg/models/v8/yolov8-cls-resnet50.yaml +1 -1
  64. ultralytics/cfg/models/v8/yolov8-ghost-p2.yaml +2 -2
  65. ultralytics/cfg/models/v8/yolov8-ghost-p6.yaml +2 -2
  66. ultralytics/cfg/models/v8/yolov8-ghost.yaml +2 -2
  67. ultralytics/cfg/models/v8/yolov8-obb.yaml +1 -1
  68. ultralytics/cfg/models/v8/yolov8-p2.yaml +1 -1
  69. ultralytics/cfg/models/v8/yolov8-pose-p6.yaml +1 -1
  70. ultralytics/cfg/models/v8/yolov8-rtdetr.yaml +1 -1
  71. ultralytics/cfg/models/v8/yolov8-seg-p6.yaml +1 -1
  72. ultralytics/cfg/models/v8/yolov8-world.yaml +1 -1
  73. ultralytics/cfg/models/v8/yolov8-worldv2.yaml +6 -6
  74. ultralytics/cfg/models/v9/yolov9s.yaml +1 -1
  75. ultralytics/data/__init__.py +4 -4
  76. ultralytics/data/annotator.py +5 -6
  77. ultralytics/data/augment.py +300 -475
  78. ultralytics/data/base.py +18 -26
  79. ultralytics/data/build.py +147 -25
  80. ultralytics/data/converter.py +108 -87
  81. ultralytics/data/dataset.py +47 -75
  82. ultralytics/data/loaders.py +42 -49
  83. ultralytics/data/split.py +5 -6
  84. ultralytics/data/split_dota.py +8 -15
  85. ultralytics/data/utils.py +36 -45
  86. ultralytics/engine/exporter.py +351 -263
  87. ultralytics/engine/model.py +186 -225
  88. ultralytics/engine/predictor.py +45 -54
  89. ultralytics/engine/results.py +198 -325
  90. ultralytics/engine/trainer.py +165 -106
  91. ultralytics/engine/tuner.py +41 -43
  92. ultralytics/engine/validator.py +55 -38
  93. ultralytics/hub/__init__.py +16 -19
  94. ultralytics/hub/auth.py +6 -12
  95. ultralytics/hub/google/__init__.py +7 -10
  96. ultralytics/hub/session.py +15 -25
  97. ultralytics/hub/utils.py +5 -8
  98. ultralytics/models/__init__.py +1 -1
  99. ultralytics/models/fastsam/__init__.py +1 -1
  100. ultralytics/models/fastsam/model.py +8 -10
  101. ultralytics/models/fastsam/predict.py +18 -30
  102. ultralytics/models/fastsam/utils.py +1 -2
  103. ultralytics/models/fastsam/val.py +5 -7
  104. ultralytics/models/nas/__init__.py +1 -1
  105. ultralytics/models/nas/model.py +5 -8
  106. ultralytics/models/nas/predict.py +7 -9
  107. ultralytics/models/nas/val.py +1 -2
  108. ultralytics/models/rtdetr/__init__.py +1 -1
  109. ultralytics/models/rtdetr/model.py +5 -8
  110. ultralytics/models/rtdetr/predict.py +15 -19
  111. ultralytics/models/rtdetr/train.py +10 -13
  112. ultralytics/models/rtdetr/val.py +21 -23
  113. ultralytics/models/sam/__init__.py +15 -2
  114. ultralytics/models/sam/amg.py +14 -20
  115. ultralytics/models/sam/build.py +26 -19
  116. ultralytics/models/sam/build_sam3.py +377 -0
  117. ultralytics/models/sam/model.py +29 -32
  118. ultralytics/models/sam/modules/blocks.py +83 -144
  119. ultralytics/models/sam/modules/decoders.py +19 -37
  120. ultralytics/models/sam/modules/encoders.py +44 -101
  121. ultralytics/models/sam/modules/memory_attention.py +16 -30
  122. ultralytics/models/sam/modules/sam.py +200 -73
  123. ultralytics/models/sam/modules/tiny_encoder.py +64 -83
  124. ultralytics/models/sam/modules/transformer.py +18 -28
  125. ultralytics/models/sam/modules/utils.py +174 -50
  126. ultralytics/models/sam/predict.py +2248 -350
  127. ultralytics/models/sam/sam3/__init__.py +3 -0
  128. ultralytics/models/sam/sam3/decoder.py +546 -0
  129. ultralytics/models/sam/sam3/encoder.py +529 -0
  130. ultralytics/models/sam/sam3/geometry_encoders.py +415 -0
  131. ultralytics/models/sam/sam3/maskformer_segmentation.py +286 -0
  132. ultralytics/models/sam/sam3/model_misc.py +199 -0
  133. ultralytics/models/sam/sam3/necks.py +129 -0
  134. ultralytics/models/sam/sam3/sam3_image.py +339 -0
  135. ultralytics/models/sam/sam3/text_encoder_ve.py +307 -0
  136. ultralytics/models/sam/sam3/vitdet.py +547 -0
  137. ultralytics/models/sam/sam3/vl_combiner.py +160 -0
  138. ultralytics/models/utils/loss.py +14 -26
  139. ultralytics/models/utils/ops.py +13 -17
  140. ultralytics/models/yolo/__init__.py +1 -1
  141. ultralytics/models/yolo/classify/predict.py +10 -13
  142. ultralytics/models/yolo/classify/train.py +12 -33
  143. ultralytics/models/yolo/classify/val.py +30 -29
  144. ultralytics/models/yolo/detect/predict.py +9 -12
  145. ultralytics/models/yolo/detect/train.py +17 -23
  146. ultralytics/models/yolo/detect/val.py +77 -59
  147. ultralytics/models/yolo/model.py +43 -60
  148. ultralytics/models/yolo/obb/predict.py +7 -16
  149. ultralytics/models/yolo/obb/train.py +14 -17
  150. ultralytics/models/yolo/obb/val.py +40 -37
  151. ultralytics/models/yolo/pose/__init__.py +1 -1
  152. ultralytics/models/yolo/pose/predict.py +7 -22
  153. ultralytics/models/yolo/pose/train.py +13 -16
  154. ultralytics/models/yolo/pose/val.py +39 -58
  155. ultralytics/models/yolo/segment/predict.py +17 -21
  156. ultralytics/models/yolo/segment/train.py +7 -10
  157. ultralytics/models/yolo/segment/val.py +95 -47
  158. ultralytics/models/yolo/world/train.py +8 -14
  159. ultralytics/models/yolo/world/train_world.py +11 -34
  160. ultralytics/models/yolo/yoloe/__init__.py +7 -7
  161. ultralytics/models/yolo/yoloe/predict.py +16 -23
  162. ultralytics/models/yolo/yoloe/train.py +36 -44
  163. ultralytics/models/yolo/yoloe/train_seg.py +11 -11
  164. ultralytics/models/yolo/yoloe/val.py +15 -20
  165. ultralytics/nn/__init__.py +7 -7
  166. ultralytics/nn/autobackend.py +159 -85
  167. ultralytics/nn/modules/__init__.py +68 -60
  168. ultralytics/nn/modules/activation.py +4 -6
  169. ultralytics/nn/modules/block.py +260 -224
  170. ultralytics/nn/modules/conv.py +52 -97
  171. ultralytics/nn/modules/head.py +831 -299
  172. ultralytics/nn/modules/transformer.py +76 -88
  173. ultralytics/nn/modules/utils.py +16 -21
  174. ultralytics/nn/tasks.py +180 -195
  175. ultralytics/nn/text_model.py +45 -69
  176. ultralytics/optim/__init__.py +5 -0
  177. ultralytics/optim/muon.py +338 -0
  178. ultralytics/solutions/__init__.py +12 -12
  179. ultralytics/solutions/ai_gym.py +13 -19
  180. ultralytics/solutions/analytics.py +15 -16
  181. ultralytics/solutions/config.py +6 -7
  182. ultralytics/solutions/distance_calculation.py +10 -13
  183. ultralytics/solutions/heatmap.py +8 -14
  184. ultralytics/solutions/instance_segmentation.py +6 -9
  185. ultralytics/solutions/object_blurrer.py +7 -10
  186. ultralytics/solutions/object_counter.py +12 -19
  187. ultralytics/solutions/object_cropper.py +8 -14
  188. ultralytics/solutions/parking_management.py +34 -32
  189. ultralytics/solutions/queue_management.py +10 -12
  190. ultralytics/solutions/region_counter.py +9 -12
  191. ultralytics/solutions/security_alarm.py +15 -20
  192. ultralytics/solutions/similarity_search.py +10 -15
  193. ultralytics/solutions/solutions.py +77 -76
  194. ultralytics/solutions/speed_estimation.py +7 -10
  195. ultralytics/solutions/streamlit_inference.py +2 -4
  196. ultralytics/solutions/templates/similarity-search.html +7 -18
  197. ultralytics/solutions/trackzone.py +7 -10
  198. ultralytics/solutions/vision_eye.py +5 -8
  199. ultralytics/trackers/__init__.py +1 -1
  200. ultralytics/trackers/basetrack.py +3 -5
  201. ultralytics/trackers/bot_sort.py +10 -27
  202. ultralytics/trackers/byte_tracker.py +21 -37
  203. ultralytics/trackers/track.py +4 -7
  204. ultralytics/trackers/utils/gmc.py +11 -22
  205. ultralytics/trackers/utils/kalman_filter.py +37 -48
  206. ultralytics/trackers/utils/matching.py +12 -15
  207. ultralytics/utils/__init__.py +124 -124
  208. ultralytics/utils/autobatch.py +2 -4
  209. ultralytics/utils/autodevice.py +17 -18
  210. ultralytics/utils/benchmarks.py +57 -71
  211. ultralytics/utils/callbacks/base.py +8 -10
  212. ultralytics/utils/callbacks/clearml.py +5 -13
  213. ultralytics/utils/callbacks/comet.py +32 -46
  214. ultralytics/utils/callbacks/dvc.py +13 -18
  215. ultralytics/utils/callbacks/mlflow.py +4 -5
  216. ultralytics/utils/callbacks/neptune.py +7 -15
  217. ultralytics/utils/callbacks/platform.py +423 -38
  218. ultralytics/utils/callbacks/raytune.py +3 -4
  219. ultralytics/utils/callbacks/tensorboard.py +25 -31
  220. ultralytics/utils/callbacks/wb.py +16 -14
  221. ultralytics/utils/checks.py +127 -85
  222. ultralytics/utils/cpu.py +3 -8
  223. ultralytics/utils/dist.py +9 -12
  224. ultralytics/utils/downloads.py +25 -33
  225. ultralytics/utils/errors.py +6 -14
  226. ultralytics/utils/events.py +2 -4
  227. ultralytics/utils/export/__init__.py +4 -236
  228. ultralytics/utils/export/engine.py +246 -0
  229. ultralytics/utils/export/imx.py +117 -63
  230. ultralytics/utils/export/tensorflow.py +231 -0
  231. ultralytics/utils/files.py +26 -30
  232. ultralytics/utils/git.py +9 -11
  233. ultralytics/utils/instance.py +30 -51
  234. ultralytics/utils/logger.py +212 -114
  235. ultralytics/utils/loss.py +601 -215
  236. ultralytics/utils/metrics.py +128 -156
  237. ultralytics/utils/nms.py +13 -16
  238. ultralytics/utils/ops.py +117 -166
  239. ultralytics/utils/patches.py +75 -21
  240. ultralytics/utils/plotting.py +75 -80
  241. ultralytics/utils/tal.py +125 -59
  242. ultralytics/utils/torch_utils.py +53 -79
  243. ultralytics/utils/tqdm.py +24 -21
  244. ultralytics/utils/triton.py +13 -19
  245. ultralytics/utils/tuner.py +19 -10
  246. dgenerate_ultralytics_headless-8.3.214.dist-info/RECORD +0 -283
  247. {dgenerate_ultralytics_headless-8.3.214.dist-info → dgenerate_ultralytics_headless-8.4.7.dist-info}/entry_points.txt +0 -0
  248. {dgenerate_ultralytics_headless-8.3.214.dist-info → dgenerate_ultralytics_headless-8.4.7.dist-info}/licenses/LICENSE +0 -0
  249. {dgenerate_ultralytics_headless-8.3.214.dist-info → dgenerate_ultralytics_headless-8.4.7.dist-info}/top_level.txt +0 -0
@@ -15,18 +15,17 @@ import numpy as np
15
15
  from PIL import Image
16
16
 
17
17
  from ultralytics.utils import ASSETS_URL, DATASETS_DIR, LOGGER, NUM_THREADS, TQDM, YAML
18
- from ultralytics.utils.checks import check_file, check_requirements
18
+ from ultralytics.utils.checks import check_file
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
@@ -704,11 +696,10 @@ def create_synthetic_coco_dataset():
704
696
 
705
697
 
706
698
  def convert_to_multispectral(path: str | Path, n_channels: int = 10, replace: bool = False, zip: bool = False):
707
- """
708
- Convert RGB images to multispectral images by interpolating across wavelength bands.
699
+ """Convert RGB images to multispectral images by interpolating across wavelength bands.
709
700
 
710
- This function takes RGB images and interpolates them to create multispectral images with a specified number
711
- 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.
712
703
 
713
704
  Args:
714
705
  path (str | Path): Path to an image file or directory containing images to convert.
@@ -730,7 +721,7 @@ def convert_to_multispectral(path: str | Path, n_channels: int = 10, replace: bo
730
721
  path = Path(path)
731
722
  if path.is_dir():
732
723
  # Process directory
733
- 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}")]
734
725
  for im_path in im_files:
735
726
  try:
736
727
  convert_to_multispectral(im_path, n_channels)
@@ -756,24 +747,24 @@ def convert_to_multispectral(path: str | Path, n_channels: int = 10, replace: bo
756
747
 
757
748
 
758
749
  async def convert_ndjson_to_yolo(ndjson_path: str | Path, output_path: str | Path | None = None) -> Path:
759
- """
760
- Convert NDJSON dataset format to Ultralytics YOLO11 dataset structure.
750
+ """Convert NDJSON dataset format to Ultralytics YOLO dataset structure.
761
751
 
762
- This function converts datasets stored in NDJSON (Newline Delimited JSON) format to the standard YOLO
763
- format with separate directories for images and labels. It supports parallel processing for efficient
764
- 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. For
753
+ detection/segmentation/pose/obb tasks, it creates separate directories for images and labels. For classification
754
+ tasks, it creates the ImageNet-style {split}/{class_name}/ folder structure. It supports parallel processing for
755
+ efficient conversion of large datasets and can download images from URLs.
765
756
 
766
757
  The NDJSON format consists of:
767
- - First line: Dataset metadata with class names and configuration
758
+ - First line: Dataset metadata with class names, task type, and configuration
768
759
  - Subsequent lines: Individual image records with annotations and optional URLs
769
760
 
770
761
  Args:
771
762
  ndjson_path (Union[str, Path]): Path to the input NDJSON file containing dataset information.
772
- output_path (Optional[Union[str, Path]], optional): Directory where the converted YOLO dataset
773
- will be saved. If None, uses the parent directory of the NDJSON file. Defaults to None.
763
+ output_path (Optional[Union[str, Path]], optional): Directory where the converted YOLO dataset will be saved. If
764
+ None, uses the parent directory of the NDJSON file. Defaults to None.
774
765
 
775
766
  Returns:
776
- (Path): Path to the generated data.yaml file that can be used for YOLO training.
767
+ (Path): Path to the generated data.yaml file (detection) or dataset directory (classification).
777
768
 
778
769
  Examples:
779
770
  Convert a local NDJSON file:
@@ -785,9 +776,11 @@ async def convert_ndjson_to_yolo(ndjson_path: str | Path, output_path: str | Pat
785
776
 
786
777
  Use with YOLO training
787
778
  >>> from ultralytics import YOLO
788
- >>> model = YOLO("yolo11n.pt")
779
+ >>> model = YOLO("yolo26n.pt")
789
780
  >>> model.train(data="https://github.com/ultralytics/assets/releases/download/v0.0.0/coco8-ndjson.ndjson")
790
781
  """
782
+ from ultralytics.utils.checks import check_requirements
783
+
791
784
  check_requirements("aiohttp")
792
785
  import aiohttp
793
786
 
@@ -800,50 +793,68 @@ async def convert_ndjson_to_yolo(ndjson_path: str | Path, output_path: str | Pat
800
793
  dataset_dir = output_path / ndjson_path.stem
801
794
  splits = {record["split"] for record in image_records}
802
795
 
803
- # Create directories and prepare YAML structure
804
- dataset_dir.mkdir(parents=True, exist_ok=True)
805
- data_yaml = dict(dataset_record)
806
- data_yaml["names"] = {int(k): v for k, v in dataset_record.get("class_names", {}).items()}
807
- data_yaml.pop("class_names")
796
+ # Check if this is a classification dataset
797
+ is_classification = dataset_record.get("task") == "classify"
798
+ class_names = {int(k): v for k, v in dataset_record.get("class_names", {}).items()}
808
799
 
809
- for split in sorted(splits):
810
- (dataset_dir / "images" / split).mkdir(parents=True, exist_ok=True)
811
- (dataset_dir / "labels" / split).mkdir(parents=True, exist_ok=True)
812
- data_yaml[split] = f"images/{split}"
800
+ # Create base directories
801
+ dataset_dir.mkdir(parents=True, exist_ok=True)
802
+ data_yaml = None
803
+
804
+ if not is_classification:
805
+ # Detection/segmentation/pose/obb: prepare YAML and create base structure
806
+ data_yaml = dict(dataset_record)
807
+ data_yaml["names"] = class_names
808
+ data_yaml.pop("class_names", None)
809
+ data_yaml.pop("type", None) # Remove NDJSON-specific fields
810
+ for split in sorted(splits):
811
+ (dataset_dir / "images" / split).mkdir(parents=True, exist_ok=True)
812
+ (dataset_dir / "labels" / split).mkdir(parents=True, exist_ok=True)
813
+ data_yaml[split] = f"images/{split}"
813
814
 
814
815
  async def process_record(session, semaphore, record):
815
816
  """Process single image record with async session."""
816
817
  async with semaphore:
817
818
  split, original_name = record["split"], record["file"]
818
- label_path = dataset_dir / "labels" / split / f"{Path(original_name).stem}.txt"
819
- image_path = dataset_dir / "images" / split / original_name
820
-
821
819
  annotations = record.get("annotations", {})
822
- lines_to_write = []
823
- for key in annotations.keys():
824
- lines_to_write = [" ".join(map(str, item)) for item in annotations[key]]
825
- break
826
- if "classification" in annotations:
827
- lines_to_write = [str(cls) for cls in annotations["classification"]]
828
-
829
- label_path.write_text("\n".join(lines_to_write) + "\n" if lines_to_write else "")
830
820
 
821
+ if is_classification:
822
+ # Classification: place image in {split}/{class_name}/ folder
823
+ class_ids = annotations.get("classification", [])
824
+ class_id = class_ids[0] if class_ids else 0
825
+ class_name = class_names.get(class_id, str(class_id))
826
+ image_path = dataset_dir / split / class_name / original_name
827
+ else:
828
+ # Detection: write label file and place image in images/{split}/
829
+ image_path = dataset_dir / "images" / split / original_name
830
+ label_path = dataset_dir / "labels" / split / f"{Path(original_name).stem}.txt"
831
+ lines_to_write = []
832
+ for key in annotations.keys():
833
+ lines_to_write = [" ".join(map(str, item)) for item in annotations[key]]
834
+ break
835
+ label_path.write_text("\n".join(lines_to_write) + "\n" if lines_to_write else "")
836
+
837
+ # Download image if URL provided and file doesn't exist
831
838
  if http_url := record.get("url"):
832
839
  if not image_path.exists():
833
- try:
834
- async with session.get(http_url, timeout=aiohttp.ClientTimeout(total=30)) as response:
835
- response.raise_for_status()
836
- with open(image_path, "wb") as f:
837
- async for chunk in response.content.iter_chunked(8192):
838
- f.write(chunk)
839
- return True
840
- except Exception as e:
841
- LOGGER.warning(f"Failed to download {http_url}: {e}")
842
- return False
840
+ image_path.parent.mkdir(parents=True, exist_ok=True)
841
+ # Retry with exponential backoff (3 attempts: 0s, 2s, 4s delays)
842
+ for attempt in range(3):
843
+ try:
844
+ async with session.get(http_url, timeout=aiohttp.ClientTimeout(total=30)) as response:
845
+ response.raise_for_status()
846
+ image_path.write_bytes(await response.read())
847
+ return True
848
+ except Exception as e:
849
+ if attempt < 2: # Don't sleep after last attempt
850
+ await asyncio.sleep(2**attempt) # 1s, 2s backoff
851
+ else:
852
+ LOGGER.warning(f"Failed to download {http_url} after 3 attempts: {e}")
853
+ return False
843
854
  return True
844
855
 
845
- # Process all images with async downloads
846
- semaphore = asyncio.Semaphore(64)
856
+ # Process all images with async downloads (limit connections for small datasets)
857
+ semaphore = asyncio.Semaphore(min(128, len(image_records)))
847
858
  async with aiohttp.ClientSession() as session:
848
859
  pbar = TQDM(
849
860
  total=len(image_records),
@@ -855,11 +866,21 @@ async def convert_ndjson_to_yolo(ndjson_path: str | Path, output_path: str | Pat
855
866
  pbar.update(1)
856
867
  return result
857
868
 
858
- await asyncio.gather(*[tracked_process(record) for record in image_records])
869
+ results = await asyncio.gather(*[tracked_process(record) for record in image_records])
859
870
  pbar.close()
860
871
 
861
- # Write data.yaml
862
- yaml_path = dataset_dir / "data.yaml"
863
- YAML.save(yaml_path, data_yaml)
872
+ # Validate images were downloaded successfully
873
+ success_count = sum(1 for r in results if r)
874
+ if success_count == 0:
875
+ raise RuntimeError(f"Failed to download any images from {ndjson_path}. Check network connection and URLs.")
876
+ if success_count < len(image_records):
877
+ LOGGER.warning(f"Downloaded {success_count}/{len(image_records)} images from {ndjson_path}")
864
878
 
865
- return yaml_path
879
+ if is_classification:
880
+ # Classification: return dataset directory (check_cls_dataset expects a directory path)
881
+ return dataset_dir
882
+ else:
883
+ # Detection: write data.yaml and return its path
884
+ yaml_path = dataset_dir / "data.yaml"
885
+ YAML.save(yaml_path, data_yaml)
886
+ return yaml_path