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,11 +1,13 @@
1
1
  # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import shutil
4
6
  import subprocess
5
7
  import sys
6
8
  from pathlib import Path
7
9
  from types import SimpleNamespace
8
- from typing import Any, Dict, List, Union
10
+ from typing import Any
9
11
 
10
12
  from ultralytics import __version__
11
13
  from ultralytics.utils import (
@@ -13,6 +15,7 @@ from ultralytics.utils import (
13
15
  DEFAULT_CFG,
14
16
  DEFAULT_CFG_DICT,
15
17
  DEFAULT_CFG_PATH,
18
+ FLOAT_OR_INT,
16
19
  IS_VSCODE,
17
20
  LOGGER,
18
21
  RANK,
@@ -20,6 +23,7 @@ from ultralytics.utils import (
20
23
  RUNS_DIR,
21
24
  SETTINGS,
22
25
  SETTINGS_FILE,
26
+ STR_OR_PATH,
23
27
  TESTS_RUNNING,
24
28
  YAML,
25
29
  IterableSimpleNamespace,
@@ -70,18 +74,17 @@ TASK2METRIC = {
70
74
  "pose": "metrics/mAP50-95(P)",
71
75
  "obb": "metrics/mAP50-95(B)",
72
76
  }
73
- MODELS = frozenset({TASK2MODEL[task] for task in TASKS})
74
77
 
75
78
  ARGV = sys.argv or ["", ""] # sometimes sys.argv = []
76
79
  SOLUTIONS_HELP_MSG = f"""
77
- Arguments received: {str(["yolo"] + ARGV[1:])}. Ultralytics 'yolo solutions' usage overview:
80
+ Arguments received: {["yolo", *ARGV[1:]]!s}. Ultralytics 'yolo solutions' usage overview:
78
81
 
79
82
  yolo solutions SOLUTION ARGS
80
83
 
81
84
  Where SOLUTION (optional) is one of {list(SOLUTION_MAP.keys())[:-1]}
82
- ARGS (optional) are any number of custom 'arg=value' pairs like 'show_in=True' that override defaults
85
+ ARGS (optional) are any number of custom 'arg=value' pairs like 'show_in=True' that override defaults
83
86
  at https://docs.ultralytics.com/usage/cfg
84
-
87
+
85
88
  1. Call object counting solution
86
89
  yolo solutions count source="path/to/video.mp4" region="[(20, 400), (1080, 400), (1080, 360), (20, 360)]"
87
90
 
@@ -96,20 +99,20 @@ SOLUTIONS_HELP_MSG = f"""
96
99
 
97
100
  5. Generate analytical graphs
98
101
  yolo solutions analytics analytics_type="pie"
99
-
102
+
100
103
  6. Track objects within specific zones
101
104
  yolo solutions trackzone source="path/to/video.mp4" region="[(150, 150), (1130, 150), (1130, 570), (150, 570)]"
102
-
105
+
103
106
  7. Streamlit real-time webcam inference GUI
104
107
  yolo streamlit-predict
105
108
  """
106
109
  CLI_HELP_MSG = f"""
107
- Arguments received: {str(["yolo"] + ARGV[1:])}. Ultralytics 'yolo' commands use the following syntax:
110
+ Arguments received: {["yolo", *ARGV[1:]]!s}. Ultralytics 'yolo' commands use the following syntax:
108
111
 
109
112
  yolo TASK MODE ARGS
110
113
 
111
- Where TASK (optional) is one of {TASKS}
112
- MODE (required) is one of {MODES}
114
+ Where TASK (optional) is one of {list(TASKS)}
115
+ MODE (required) is one of {list(MODES)}
113
116
  ARGS (optional) are any number of custom 'arg=value' pairs like 'imgsz=320' that override defaults.
114
117
  See all ARGS at https://docs.ultralytics.com/usage/cfg or with 'yolo cfg'
115
118
 
@@ -238,13 +241,12 @@ CFG_BOOL_KEYS = frozenset(
238
241
  )
239
242
 
240
243
 
241
- def cfg2dict(cfg: Union[str, Path, Dict, SimpleNamespace]) -> Dict:
242
- """
243
- Converts a configuration object to a dictionary.
244
+ def cfg2dict(cfg: str | Path | dict | SimpleNamespace) -> dict:
245
+ """Convert a configuration object to a dictionary.
244
246
 
245
247
  Args:
246
- cfg (str | Path | Dict | SimpleNamespace): Configuration object to be converted. Can be a file path,
247
- a string, a dictionary, or a SimpleNamespace object.
248
+ cfg (str | Path | dict | SimpleNamespace): Configuration object to be converted. Can be a file path, a string, a
249
+ dictionary, or a SimpleNamespace object.
248
250
 
249
251
  Returns:
250
252
  (dict): Configuration object in dictionary format.
@@ -266,21 +268,22 @@ def cfg2dict(cfg: Union[str, Path, Dict, SimpleNamespace]) -> Dict:
266
268
  - If cfg is a SimpleNamespace object, it's converted to a dictionary using vars().
267
269
  - If cfg is already a dictionary, it's returned unchanged.
268
270
  """
269
- if isinstance(cfg, (str, Path)):
271
+ if isinstance(cfg, STR_OR_PATH):
270
272
  cfg = YAML.load(cfg) # load dict
271
273
  elif isinstance(cfg, SimpleNamespace):
272
274
  cfg = vars(cfg) # convert to dict
273
275
  return cfg
274
276
 
275
277
 
276
- def get_cfg(cfg: Union[str, Path, Dict, SimpleNamespace] = DEFAULT_CFG_DICT, overrides: Dict = None) -> SimpleNamespace:
277
- """
278
- Load and merge configuration data from a file or dictionary, with optional overrides.
278
+ def get_cfg(
279
+ cfg: str | Path | dict | SimpleNamespace = DEFAULT_CFG_DICT, overrides: dict | None = None
280
+ ) -> SimpleNamespace:
281
+ """Load and merge configuration data from a file or dictionary, with optional overrides.
279
282
 
280
283
  Args:
281
- cfg (str | Path | Dict | SimpleNamespace): Configuration data source. Can be a file path, dictionary, or
284
+ cfg (str | Path | dict | SimpleNamespace): Configuration data source. Can be a file path, dictionary, or
282
285
  SimpleNamespace object.
283
- overrides (Dict | None): Dictionary containing key-value pairs to override the base configuration.
286
+ overrides (dict | None): Dictionary containing key-value pairs to override the base configuration.
284
287
 
285
288
  Returns:
286
289
  (SimpleNamespace): Namespace containing the merged configuration arguments.
@@ -308,10 +311,10 @@ def get_cfg(cfg: Union[str, Path, Dict, SimpleNamespace] = DEFAULT_CFG_DICT, ove
308
311
 
309
312
  # Special handling for numeric project/name
310
313
  for k in "project", "name":
311
- if k in cfg and isinstance(cfg[k], (int, float)):
314
+ if k in cfg and isinstance(cfg[k], FLOAT_OR_INT):
312
315
  cfg[k] = str(cfg[k])
313
316
  if cfg.get("name") == "model": # assign model to 'name' arg
314
- cfg["name"] = str(cfg.get("model", "")).split(".")[0]
317
+ cfg["name"] = str(cfg.get("model", "")).partition(".")[0]
315
318
  LOGGER.warning(f"'name=model' automatically updated to 'name={cfg['name']}'.")
316
319
 
317
320
  # Type and Value checks
@@ -321,12 +324,11 @@ def get_cfg(cfg: Union[str, Path, Dict, SimpleNamespace] = DEFAULT_CFG_DICT, ove
321
324
  return IterableSimpleNamespace(**cfg)
322
325
 
323
326
 
324
- def check_cfg(cfg: Dict, hard: bool = True) -> None:
325
- """
326
- Checks configuration argument types and values for the Ultralytics library.
327
+ def check_cfg(cfg: dict, hard: bool = True) -> None:
328
+ """Check configuration argument types and values for the Ultralytics library.
327
329
 
328
- This function validates the types and values of configuration arguments, ensuring correctness and converting
329
- them if necessary. It checks for specific key types defined in global variables such as `CFG_FLOAT_KEYS`,
330
+ This function validates the types and values of configuration arguments, ensuring correctness and converting them if
331
+ necessary. It checks for specific key types defined in global variables such as `CFG_FLOAT_KEYS`,
330
332
  `CFG_FRACTION_KEYS`, `CFG_INT_KEYS`, and `CFG_BOOL_KEYS`.
331
333
 
332
334
  Args:
@@ -351,7 +353,7 @@ def check_cfg(cfg: Dict, hard: bool = True) -> None:
351
353
  """
352
354
  for k, v in cfg.items():
353
355
  if v is not None: # None values may be from optional args
354
- if k in CFG_FLOAT_KEYS and not isinstance(v, (int, float)):
356
+ if k in CFG_FLOAT_KEYS and not isinstance(v, FLOAT_OR_INT):
355
357
  if hard:
356
358
  raise TypeError(
357
359
  f"'{k}={v}' is of invalid type {type(v).__name__}. "
@@ -359,7 +361,7 @@ def check_cfg(cfg: Dict, hard: bool = True) -> None:
359
361
  )
360
362
  cfg[k] = float(v)
361
363
  elif k in CFG_FRACTION_KEYS:
362
- if not isinstance(v, (int, float)):
364
+ if not isinstance(v, FLOAT_OR_INT):
363
365
  if hard:
364
366
  raise TypeError(
365
367
  f"'{k}={v}' is of invalid type {type(v).__name__}. "
@@ -383,15 +385,14 @@ def check_cfg(cfg: Dict, hard: bool = True) -> None:
383
385
  cfg[k] = bool(v)
384
386
 
385
387
 
386
- def get_save_dir(args: SimpleNamespace, name: str = None) -> Path:
387
- """
388
- Returns the directory path for saving outputs, derived from arguments or default settings.
388
+ def get_save_dir(args: SimpleNamespace, name: str | None = None) -> Path:
389
+ """Return the directory path for saving outputs, derived from arguments or default settings.
389
390
 
390
391
  Args:
391
- args (SimpleNamespace): Namespace object containing configurations such as 'project', 'name', 'task',
392
- 'mode', and 'save_dir'.
393
- name (str | None): Optional name for the output directory. If not provided, it defaults to 'args.name'
394
- or the 'args.mode'.
392
+ args (SimpleNamespace): Namespace object containing configurations such as 'project', 'name', 'task', 'mode',
393
+ and 'save_dir'.
394
+ name (str | None): Optional name for the output directory. If not provided, it defaults to 'args.name' or the
395
+ 'args.mode'.
395
396
 
396
397
  Returns:
397
398
  (Path): Directory path where outputs should be saved.
@@ -412,16 +413,18 @@ def get_save_dir(args: SimpleNamespace, name: str = None) -> Path:
412
413
  name = name or args.name or f"{args.mode}"
413
414
  save_dir = increment_path(Path(project) / name, exist_ok=args.exist_ok if RANK in {-1, 0} else True)
414
415
 
415
- return Path(save_dir)
416
+ return Path(save_dir).resolve() # resolve to display full path in console
416
417
 
417
418
 
418
- def _handle_deprecation(custom: Dict) -> Dict:
419
- """
420
- Handles deprecated configuration keys by mapping them to current equivalents with deprecation warnings.
419
+ def _handle_deprecation(custom: dict) -> dict:
420
+ """Handle deprecated configuration keys by mapping them to current equivalents with deprecation warnings.
421
421
 
422
422
  Args:
423
423
  custom (dict): Configuration dictionary potentially containing deprecated keys.
424
424
 
425
+ Returns:
426
+ (dict): Updated configuration dictionary with deprecated keys replaced.
427
+
425
428
  Examples:
426
429
  >>> custom_config = {"boxes": True, "hide_labels": "False", "line_thickness": 2}
427
430
  >>> _handle_deprecation(custom_config)
@@ -456,9 +459,8 @@ def _handle_deprecation(custom: Dict) -> Dict:
456
459
  return custom
457
460
 
458
461
 
459
- def check_dict_alignment(base: Dict, custom: Dict, e: Exception = None) -> None:
460
- """
461
- Checks alignment between custom and base configuration dictionaries, handling deprecated keys and providing error
462
+ def check_dict_alignment(base: dict, custom: dict, e: Exception | None = None) -> None:
463
+ """Check alignment between custom and base configuration dictionaries, handling deprecated keys and providing error
462
464
  messages for mismatched keys.
463
465
 
464
466
  Args:
@@ -496,9 +498,8 @@ def check_dict_alignment(base: Dict, custom: Dict, e: Exception = None) -> None:
496
498
  raise SyntaxError(string + CLI_HELP_MSG) from e
497
499
 
498
500
 
499
- def merge_equals_args(args: List[str]) -> List[str]:
500
- """
501
- Merges arguments around isolated '=' in a list of strings and joins fragments with brackets.
501
+ def merge_equals_args(args: list[str]) -> list[str]:
502
+ """Merge arguments around isolated '=' in a list of strings and join fragments with brackets.
502
503
 
503
504
  This function handles the following cases:
504
505
  1. ['arg', '=', 'val'] becomes ['arg=val']
@@ -507,10 +508,11 @@ def merge_equals_args(args: List[str]) -> List[str]:
507
508
  4. Joins fragments with brackets, e.g., ['imgsz=[3,', '640,', '640]'] becomes ['imgsz=[3,640,640]']
508
509
 
509
510
  Args:
510
- args (List[str]): A list of strings where each element represents an argument or fragment.
511
+ args (list[str]): A list of strings where each element represents an argument or fragment.
511
512
 
512
513
  Returns:
513
- (List[str]): A list of strings where the arguments around isolated '=' are merged and fragments with brackets are joined.
514
+ (list[str]): A list of strings where the arguments around isolated '=' are merged and fragments with brackets
515
+ are joined.
514
516
 
515
517
  Examples:
516
518
  >>> args = ["arg1", "=", "value", "arg2=", "value2", "arg3", "=value3", "imgsz=[3,", "640,", "640]"]
@@ -555,16 +557,15 @@ def merge_equals_args(args: List[str]) -> List[str]:
555
557
  return new_args
556
558
 
557
559
 
558
- def handle_yolo_hub(args: List[str]) -> None:
559
- """
560
- Handles Ultralytics HUB command-line interface (CLI) commands for authentication.
560
+ def handle_yolo_hub(args: list[str]) -> None:
561
+ """Handle Ultralytics HUB command-line interface (CLI) commands for authentication.
561
562
 
562
563
  This function processes Ultralytics HUB CLI commands such as login and logout. It should be called when executing a
563
564
  script with arguments related to HUB authentication.
564
565
 
565
566
  Args:
566
- args (List[str]): A list of command line arguments. The first argument should be either 'login'
567
- or 'logout'. For 'login', an optional second argument can be the API key.
567
+ args (list[str]): A list of command line arguments. The first argument should be either 'login' or 'logout'. For
568
+ 'login', an optional second argument can be the API key.
568
569
 
569
570
  Examples:
570
571
  $ yolo login YOUR_API_KEY
@@ -585,15 +586,14 @@ def handle_yolo_hub(args: List[str]) -> None:
585
586
  hub.logout()
586
587
 
587
588
 
588
- def handle_yolo_settings(args: List[str]) -> None:
589
- """
590
- Handles YOLO settings command-line interface (CLI) commands.
589
+ def handle_yolo_settings(args: list[str]) -> None:
590
+ """Handle YOLO settings command-line interface (CLI) commands.
591
591
 
592
592
  This function processes YOLO settings CLI commands such as reset and updating individual settings. It should be
593
593
  called when executing a script with arguments related to YOLO settings management.
594
594
 
595
595
  Args:
596
- args (List[str]): A list of command line arguments for YOLO settings management.
596
+ args (list[str]): A list of command line arguments for YOLO settings management.
597
597
 
598
598
  Examples:
599
599
  >>> handle_yolo_settings(["reset"]) # Reset YOLO settings
@@ -619,6 +619,8 @@ def handle_yolo_settings(args: List[str]) -> None:
619
619
  new = dict(parse_key_value_pair(a) for a in args)
620
620
  check_dict_alignment(SETTINGS, new)
621
621
  SETTINGS.update(new)
622
+ for k, v in new.items():
623
+ LOGGER.info(f"✅ Updated '{k}={v}'")
622
624
 
623
625
  LOGGER.info(SETTINGS) # print the current settings
624
626
  LOGGER.info(f"💡 Learn more about Ultralytics Settings at {url}")
@@ -626,14 +628,11 @@ def handle_yolo_settings(args: List[str]) -> None:
626
628
  LOGGER.warning(f"settings error: '{e}'. Please see {url} for help.")
627
629
 
628
630
 
629
- def handle_yolo_solutions(args: List[str]) -> None:
630
- """
631
- Processes YOLO solutions arguments and runs the specified computer vision solutions pipeline.
631
+ def handle_yolo_solutions(args: list[str]) -> None:
632
+ """Process YOLO solutions arguments and run the specified computer vision solutions pipeline.
632
633
 
633
634
  Args:
634
- args (List[str]): Command-line arguments for configuring and running the Ultralytics YOLO
635
- solutions: https://docs.ultralytics.com/solutions/, It can include solution name, source,
636
- and other configuration parameters.
635
+ args (list[str]): Command-line arguments for configuring and running the Ultralytics YOLO solutions.
637
636
 
638
637
  Examples:
639
638
  Run people counting solution with default settings:
@@ -739,8 +738,7 @@ def handle_yolo_solutions(args: List[str]) -> None:
739
738
 
740
739
 
741
740
  def parse_key_value_pair(pair: str = "key=value") -> tuple:
742
- """
743
- Parses a key-value pair string into separate key and value components.
741
+ """Parse a key-value pair string into separate key and value components.
744
742
 
745
743
  Args:
746
744
  pair (str): A string containing a key-value pair in the format "key=value".
@@ -773,8 +771,7 @@ def parse_key_value_pair(pair: str = "key=value") -> tuple:
773
771
 
774
772
 
775
773
  def smart_value(v: str) -> Any:
776
- """
777
- Converts a string representation of a value to its appropriate Python type.
774
+ """Convert a string representation of a value to its appropriate Python type.
778
775
 
779
776
  This function attempts to convert a given string into a Python object of the most appropriate type. It handles
780
777
  conversions to None, bool, int, float, and other types that can be evaluated safely.
@@ -783,8 +780,8 @@ def smart_value(v: str) -> Any:
783
780
  v (str): The string representation of the value to be converted.
784
781
 
785
782
  Returns:
786
- (Any): The converted value. The type can be None, bool, int, float, or the original string if no conversion
787
- is applicable.
783
+ (Any): The converted value. The type can be None, bool, int, float, or the original string if no conversion is
784
+ applicable.
788
785
 
789
786
  Examples:
790
787
  >>> smart_value("42")
@@ -818,11 +815,10 @@ def smart_value(v: str) -> Any:
818
815
 
819
816
 
820
817
  def entrypoint(debug: str = "") -> None:
821
- """
822
- Ultralytics entrypoint function for parsing and executing command-line arguments.
818
+ """Ultralytics entrypoint function for parsing and executing command-line arguments.
823
819
 
824
- This function serves as the main entry point for the Ultralytics CLI, parsing command-line arguments and
825
- executing the corresponding tasks such as training, validation, prediction, exporting models, and more.
820
+ This function serves as the main entry point for the Ultralytics CLI, parsing command-line arguments and executing
821
+ the corresponding tasks such as training, validation, prediction, exporting models, and more.
826
822
 
827
823
  Args:
828
824
  debug (str): Space-separated string of command-line arguments for debugging purposes.
@@ -848,7 +844,6 @@ def entrypoint(debug: str = "") -> None:
848
844
  return
849
845
 
850
846
  special = {
851
- "help": lambda: LOGGER.info(CLI_HELP_MSG),
852
847
  "checks": checks.collect_system_info,
853
848
  "version": lambda: LOGGER.info(__version__),
854
849
  "settings": lambda: handle_yolo_settings(args[1:]),
@@ -858,6 +853,7 @@ def entrypoint(debug: str = "") -> None:
858
853
  "logout": lambda: handle_yolo_hub(args),
859
854
  "copy-cfg": copy_default_cfg,
860
855
  "solutions": lambda: handle_yolo_solutions(args[1:]),
856
+ "help": lambda: LOGGER.info(CLI_HELP_MSG), # help below hub for -h flag precedence
861
857
  }
862
858
  full_args_dict = {**DEFAULT_CFG_DICT, **{k: None for k in TASKS}, **{k: None for k in MODES}, **special}
863
859
 
@@ -909,9 +905,9 @@ def entrypoint(debug: str = "") -> None:
909
905
  mode = overrides.get("mode")
910
906
  if mode is None:
911
907
  mode = DEFAULT_CFG.mode or "predict"
912
- LOGGER.warning(f"'mode' argument is missing. Valid modes are {MODES}. Using default 'mode={mode}'.")
908
+ LOGGER.warning(f"'mode' argument is missing. Valid modes are {list(MODES)}. Using default 'mode={mode}'.")
913
909
  elif mode not in MODES:
914
- raise ValueError(f"Invalid 'mode={mode}'. Valid modes are {MODES}.\n{CLI_HELP_MSG}")
910
+ raise ValueError(f"Invalid 'mode={mode}'. Valid modes are {list(MODES)}.\n{CLI_HELP_MSG}")
915
911
 
916
912
  # Task
917
913
  task = overrides.pop("task", None)
@@ -919,11 +915,11 @@ def entrypoint(debug: str = "") -> None:
919
915
  if task not in TASKS:
920
916
  if task == "track":
921
917
  LOGGER.warning(
922
- f"invalid 'task=track', setting 'task=detect' and 'mode=track'. Valid tasks are {TASKS}.\n{CLI_HELP_MSG}."
918
+ f"invalid 'task=track', setting 'task=detect' and 'mode=track'. Valid tasks are {list(TASKS)}.\n{CLI_HELP_MSG}."
923
919
  )
924
920
  task, mode = "detect", "track"
925
921
  else:
926
- raise ValueError(f"Invalid 'task={task}'. Valid tasks are {TASKS}.\n{CLI_HELP_MSG}")
922
+ raise ValueError(f"Invalid 'task={task}'. Valid tasks are {list(TASKS)}.\n{CLI_HELP_MSG}")
927
923
  if "model" not in overrides:
928
924
  overrides["model"] = TASK2MODEL[task]
929
925
 
@@ -950,9 +946,10 @@ def entrypoint(debug: str = "") -> None:
950
946
  from ultralytics import YOLO
951
947
 
952
948
  model = YOLO(model, task=task)
953
- if isinstance(overrides.get("pretrained"), str):
954
- model.load(overrides["pretrained"])
955
-
949
+ if "yoloe" in stem or "world" in stem:
950
+ cls_list = overrides.pop("classes", DEFAULT_CFG.classes)
951
+ if cls_list is not None and isinstance(cls_list, str):
952
+ model.set_classes(cls_list.split(",")) # convert "person, bus" -> ['person', ' bus'].
956
953
  # Task Update
957
954
  if task != model.task:
958
955
  if task:
@@ -990,12 +987,11 @@ def entrypoint(debug: str = "") -> None:
990
987
 
991
988
  # Special modes --------------------------------------------------------------------------------------------------------
992
989
  def copy_default_cfg() -> None:
993
- """
994
- Copies the default configuration file and creates a new one with '_copy' appended to its name.
990
+ """Copy the default configuration file and create a new one with '_copy' appended to its name.
995
991
 
996
- This function duplicates the existing default configuration file (DEFAULT_CFG_PATH) and saves it
997
- with '_copy' appended to its name in the current working directory. It provides a convenient way
998
- to create a custom configuration file based on the default settings.
992
+ This function duplicates the existing default configuration file (DEFAULT_CFG_PATH) and saves it with '_copy'
993
+ appended to its name in the current working directory. It provides a convenient way to create a custom configuration
994
+ file based on the default settings.
999
995
 
1000
996
  Examples:
1001
997
  >>> copy_default_cfg()
@@ -6,10 +6,10 @@
6
6
  # parent
7
7
  # ├── ultralytics
8
8
  # └── datasets
9
- # └── Argoverse ← downloads here (31.5 GB)
9
+ # └── Argoverse ← downloads here (31.5 GB)
10
10
 
11
11
  # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
12
- path: ../datasets/Argoverse # dataset root dir
12
+ path: Argoverse # dataset root dir
13
13
  train: Argoverse-1.1/images/train/ # train images (relative to 'path') 39384 images
14
14
  val: Argoverse-1.1/images/val/ # val images (relative to 'path') 15062 images
15
15
  test: Argoverse-1.1/images/test/ # test images (optional) https://eval.ai/web/challenges/challenge-page/800/overview
@@ -30,14 +30,14 @@ download: |
30
30
  import json
31
31
  from pathlib import Path
32
32
 
33
- from tqdm import tqdm
33
+ from ultralytics.utils import TQDM
34
34
  from ultralytics.utils.downloads import download
35
35
 
36
36
  def argoverse2yolo(set):
37
37
  """Convert Argoverse dataset annotations to YOLO format for object detection tasks."""
38
38
  labels = {}
39
39
  a = json.load(open(set, "rb"))
40
- for annot in tqdm(a["annotations"], desc=f"Converting {set} to YOLOv5 format..."):
40
+ for annot in TQDM(a["annotations"], desc=f"Converting {set} to YOLOv5 format..."):
41
41
  img_id = annot["image_id"]
42
42
  img_name = a["images"][img_id]["name"]
43
43
  img_label_name = f"{img_name[:-3]}txt"
@@ -6,10 +6,10 @@
6
6
  # parent
7
7
  # ├── ultralytics
8
8
  # └── datasets
9
- # └── dota1.5 ← downloads here (2GB)
9
+ # └── dota1.5 ← downloads here (2GB)
10
10
 
11
11
  # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
12
- path: ../datasets/DOTAv1.5 # dataset root dir
12
+ path: DOTAv1.5 # dataset root dir
13
13
  train: images/train # train images (relative to 'path') 1411 images
14
14
  val: images/val # val images (relative to 'path') 458 images
15
15
  test: images/test # test images (optional) 937 images
@@ -6,10 +6,10 @@
6
6
  # parent
7
7
  # ├── ultralytics
8
8
  # └── datasets
9
- # └── dota1 ← downloads here (2GB)
9
+ # └── dota1 ← downloads here (2GB)
10
10
 
11
11
  # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
12
- path: ../datasets/DOTAv1 # dataset root dir
12
+ path: DOTAv1 # dataset root dir
13
13
  train: images/train # train images (relative to 'path') 1411 images
14
14
  val: images/val # val images (relative to 'path') 458 images
15
15
  test: images/test # test images (optional) 937 images
@@ -6,10 +6,10 @@
6
6
  # parent
7
7
  # ├── ultralytics
8
8
  # └── datasets
9
- # └── GlobalWheat2020 ← downloads here (7.0 GB)
9
+ # └── GlobalWheat2020 ← downloads here (7.0 GB)
10
10
 
11
11
  # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
12
- path: ../datasets/GlobalWheat2020 # dataset root dir
12
+ path: GlobalWheat2020 # dataset root dir
13
13
  train: # train images (relative to 'path') 3422 images
14
14
  - images/arvalis_1
15
15
  - images/arvalis_2
@@ -6,13 +6,12 @@
6
6
  # parent
7
7
  # ├── ultralytics
8
8
  # └── datasets
9
- # └── homeobjects-3K ← downloads here (390 MB)
9
+ # └── homeobjects-3K ← downloads here (390 MB)
10
10
 
11
11
  # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
12
- path: ../datasets/homeobjects-3K # dataset root dir
13
- train: train/images # train images (relative to 'path') 2285 images
14
- val: valid/images # val images (relative to 'path') 404 images
15
- test: # test images (relative to 'path')
12
+ path: homeobjects-3K # dataset root dir
13
+ train: images/train # train images (relative to 'path') 2285 images
14
+ val: images/val # val images (relative to 'path') 404 images
16
15
 
17
16
  # Classes
18
17
  names:
@@ -7,10 +7,10 @@
7
7
  # parent
8
8
  # ├── ultralytics
9
9
  # └── datasets
10
- # └── imagenet ← downloads here (144 GB)
10
+ # └── imagenet ← downloads here (144 GB)
11
11
 
12
12
  # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
13
- path: ../datasets/imagenet # dataset root dir
13
+ path: imagenet # dataset root dir
14
14
  train: train # train images (relative to 'path') 1281167 images
15
15
  val: val # val images (relative to 'path') 50000 images
16
16
  test: # test images (optional)
@@ -342,7 +342,7 @@ names:
342
342
  322: ringlet
343
343
  323: monarch butterfly
344
344
  324: small white
345
- 325: sulphur butterfly
345
+ 325: sulfur butterfly
346
346
  326: gossamer-winged butterfly
347
347
  327: starfish
348
348
  328: sea urchin
@@ -6,10 +6,10 @@
6
6
  # parent
7
7
  # ├── ultralytics
8
8
  # └── datasets
9
- # └── Objects365 ← downloads here (712 GB = 367G data + 345G zips)
9
+ # └── Objects365 ← downloads here (712 GB = 367G data + 345G zips)
10
10
 
11
11
  # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
12
- path: ../datasets/Objects365 # dataset root dir
12
+ path: Objects365 # dataset root dir
13
13
  train: images/train # train images (relative to 'path') 1742289 images
14
14
  val: images/val # val images (relative to 'path') 80000 images
15
15
  test: # test images (optional)
@@ -384,43 +384,41 @@ names:
384
384
 
385
385
  # Download script/URL (optional) ---------------------------------------------------------------------------------------
386
386
  download: |
387
+ from concurrent.futures import ThreadPoolExecutor
387
388
  from pathlib import Path
388
389
 
389
390
  import numpy as np
390
- from tqdm import tqdm
391
391
 
392
+ from ultralytics.utils import TQDM
392
393
  from ultralytics.utils.checks import check_requirements
393
394
  from ultralytics.utils.downloads import download
394
395
  from ultralytics.utils.ops import xyxy2xywhn
395
396
 
396
- check_requirements(("pycocotools>=2.0",))
397
- from pycocotools.coco import COCO
398
-
399
- # Make Directories
400
- dir = Path(yaml["path"]) # dataset root dir
401
- for p in "images", "labels":
402
- (dir / p).mkdir(parents=True, exist_ok=True)
403
- for q in "train", "val":
404
- (dir / p / q).mkdir(parents=True, exist_ok=True)
397
+ check_requirements("faster-coco-eval")
398
+ from faster_coco_eval import COCO
405
399
 
406
400
  # Train, Val Splits
401
+ dir = Path(yaml["path"])
407
402
  for split, patches in [("train", 50 + 1), ("val", 43 + 1)]:
408
403
  print(f"Processing {split} in {patches} patches ...")
409
404
  images, labels = dir / "images" / split, dir / "labels" / split
405
+ images.mkdir(parents=True, exist_ok=True)
406
+ labels.mkdir(parents=True, exist_ok=True)
410
407
 
411
408
  # Download
412
409
  url = f"https://dorc.ks3-cn-beijing.ksyun.com/data-set/2020Objects365%E6%95%B0%E6%8D%AE%E9%9B%86/{split}/"
413
410
  if split == "train":
414
411
  download([f"{url}zhiyuan_objv2_{split}.tar.gz"], dir=dir) # annotations json
415
- download([f"{url}patch{i}.tar.gz" for i in range(patches)], dir=images, curl=True, threads=8)
412
+ download([f"{url}patch{i}.tar.gz" for i in range(patches)], dir=images, threads=17) # 51 patches / 17 threads = 3
416
413
  elif split == "val":
417
414
  download([f"{url}zhiyuan_objv2_{split}.json"], dir=dir) # annotations json
418
- download([f"{url}images/v1/patch{i}.tar.gz" for i in range(15 + 1)], dir=images, curl=True, threads=8)
419
- download([f"{url}images/v2/patch{i}.tar.gz" for i in range(16, patches)], dir=images, curl=True, threads=8)
415
+ download([f"{url}images/v1/patch{i}.tar.gz" for i in range(15 + 1)], dir=images, threads=16)
416
+ download([f"{url}images/v2/patch{i}.tar.gz" for i in range(16, patches)], dir=images, threads=16)
420
417
 
421
418
  # Move
422
- for f in tqdm(images.rglob("*.jpg"), desc=f"Moving {split} images"):
423
- f.rename(images / f.name) # move to /images/{split}
419
+ files = list(images.rglob("*.jpg"))
420
+ with ThreadPoolExecutor(max_workers=16) as executor:
421
+ list(TQDM(executor.map(lambda f: f.rename(images / f.name), files), total=len(files), desc=f"Moving {split} images"))
424
422
 
425
423
  # Labels
426
424
  coco = COCO(dir / f"zhiyuan_objv2_{split}.json")
@@ -428,10 +426,12 @@ download: |
428
426
  for cid, cat in enumerate(names):
429
427
  catIds = coco.getCatIds(catNms=[cat])
430
428
  imgIds = coco.getImgIds(catIds=catIds)
431
- for im in tqdm(coco.loadImgs(imgIds), desc=f"Class {cid + 1}/{len(names)} {cat}"):
432
- width, height = im["width"], im["height"]
433
- path = Path(im["file_name"]) # image filename
429
+
430
+ def process_annotation(im):
431
+ """Process and write annotations for a single image."""
434
432
  try:
433
+ width, height = im["width"], im["height"]
434
+ path = Path(im["file_name"])
435
435
  with open(labels / path.with_suffix(".txt").name, "a", encoding="utf-8") as file:
436
436
  annIds = coco.getAnnIds(imgIds=im["id"], catIds=catIds, iscrowd=None)
437
437
  for a in coco.loadAnns(annIds):
@@ -441,3 +441,7 @@ download: |
441
441
  file.write(f"{cid} {x:.5f} {y:.5f} {w:.5f} {h:.5f}\n")
442
442
  except Exception as e:
443
443
  print(e)
444
+
445
+ images_list = coco.loadImgs(imgIds)
446
+ with ThreadPoolExecutor(max_workers=16) as executor:
447
+ list(TQDM(executor.map(process_annotation, images_list), total=len(images_list), desc=f"Class {cid + 1}/{len(names)} {cat}"))