dgenerate-ultralytics-headless 8.3.253__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 (299) hide show
  1. dgenerate_ultralytics_headless-8.3.253.dist-info/METADATA +405 -0
  2. dgenerate_ultralytics_headless-8.3.253.dist-info/RECORD +299 -0
  3. dgenerate_ultralytics_headless-8.3.253.dist-info/WHEEL +5 -0
  4. dgenerate_ultralytics_headless-8.3.253.dist-info/entry_points.txt +3 -0
  5. dgenerate_ultralytics_headless-8.3.253.dist-info/licenses/LICENSE +661 -0
  6. dgenerate_ultralytics_headless-8.3.253.dist-info/top_level.txt +1 -0
  7. tests/__init__.py +23 -0
  8. tests/conftest.py +59 -0
  9. tests/test_cli.py +131 -0
  10. tests/test_cuda.py +216 -0
  11. tests/test_engine.py +157 -0
  12. tests/test_exports.py +309 -0
  13. tests/test_integrations.py +151 -0
  14. tests/test_python.py +777 -0
  15. tests/test_solutions.py +371 -0
  16. ultralytics/__init__.py +48 -0
  17. ultralytics/assets/bus.jpg +0 -0
  18. ultralytics/assets/zidane.jpg +0 -0
  19. ultralytics/cfg/__init__.py +1028 -0
  20. ultralytics/cfg/datasets/Argoverse.yaml +78 -0
  21. ultralytics/cfg/datasets/DOTAv1.5.yaml +37 -0
  22. ultralytics/cfg/datasets/DOTAv1.yaml +36 -0
  23. ultralytics/cfg/datasets/GlobalWheat2020.yaml +68 -0
  24. ultralytics/cfg/datasets/HomeObjects-3K.yaml +32 -0
  25. ultralytics/cfg/datasets/ImageNet.yaml +2025 -0
  26. ultralytics/cfg/datasets/Objects365.yaml +447 -0
  27. ultralytics/cfg/datasets/SKU-110K.yaml +58 -0
  28. ultralytics/cfg/datasets/TT100K.yaml +346 -0
  29. ultralytics/cfg/datasets/VOC.yaml +102 -0
  30. ultralytics/cfg/datasets/VisDrone.yaml +87 -0
  31. ultralytics/cfg/datasets/african-wildlife.yaml +25 -0
  32. ultralytics/cfg/datasets/brain-tumor.yaml +22 -0
  33. ultralytics/cfg/datasets/carparts-seg.yaml +44 -0
  34. ultralytics/cfg/datasets/coco-pose.yaml +64 -0
  35. ultralytics/cfg/datasets/coco.yaml +118 -0
  36. ultralytics/cfg/datasets/coco128-seg.yaml +101 -0
  37. ultralytics/cfg/datasets/coco128.yaml +101 -0
  38. ultralytics/cfg/datasets/coco8-grayscale.yaml +103 -0
  39. ultralytics/cfg/datasets/coco8-multispectral.yaml +104 -0
  40. ultralytics/cfg/datasets/coco8-pose.yaml +47 -0
  41. ultralytics/cfg/datasets/coco8-seg.yaml +101 -0
  42. ultralytics/cfg/datasets/coco8.yaml +101 -0
  43. ultralytics/cfg/datasets/construction-ppe.yaml +32 -0
  44. ultralytics/cfg/datasets/crack-seg.yaml +22 -0
  45. ultralytics/cfg/datasets/dog-pose.yaml +52 -0
  46. ultralytics/cfg/datasets/dota8-multispectral.yaml +38 -0
  47. ultralytics/cfg/datasets/dota8.yaml +35 -0
  48. ultralytics/cfg/datasets/hand-keypoints.yaml +50 -0
  49. ultralytics/cfg/datasets/kitti.yaml +27 -0
  50. ultralytics/cfg/datasets/lvis.yaml +1240 -0
  51. ultralytics/cfg/datasets/medical-pills.yaml +21 -0
  52. ultralytics/cfg/datasets/open-images-v7.yaml +663 -0
  53. ultralytics/cfg/datasets/package-seg.yaml +22 -0
  54. ultralytics/cfg/datasets/signature.yaml +21 -0
  55. ultralytics/cfg/datasets/tiger-pose.yaml +41 -0
  56. ultralytics/cfg/datasets/xView.yaml +155 -0
  57. ultralytics/cfg/default.yaml +130 -0
  58. ultralytics/cfg/models/11/yolo11-cls-resnet18.yaml +17 -0
  59. ultralytics/cfg/models/11/yolo11-cls.yaml +33 -0
  60. ultralytics/cfg/models/11/yolo11-obb.yaml +50 -0
  61. ultralytics/cfg/models/11/yolo11-pose.yaml +51 -0
  62. ultralytics/cfg/models/11/yolo11-seg.yaml +50 -0
  63. ultralytics/cfg/models/11/yolo11.yaml +50 -0
  64. ultralytics/cfg/models/11/yoloe-11-seg.yaml +48 -0
  65. ultralytics/cfg/models/11/yoloe-11.yaml +48 -0
  66. ultralytics/cfg/models/12/yolo12-cls.yaml +32 -0
  67. ultralytics/cfg/models/12/yolo12-obb.yaml +48 -0
  68. ultralytics/cfg/models/12/yolo12-pose.yaml +49 -0
  69. ultralytics/cfg/models/12/yolo12-seg.yaml +48 -0
  70. ultralytics/cfg/models/12/yolo12.yaml +48 -0
  71. ultralytics/cfg/models/rt-detr/rtdetr-l.yaml +53 -0
  72. ultralytics/cfg/models/rt-detr/rtdetr-resnet101.yaml +45 -0
  73. ultralytics/cfg/models/rt-detr/rtdetr-resnet50.yaml +45 -0
  74. ultralytics/cfg/models/rt-detr/rtdetr-x.yaml +57 -0
  75. ultralytics/cfg/models/v10/yolov10b.yaml +45 -0
  76. ultralytics/cfg/models/v10/yolov10l.yaml +45 -0
  77. ultralytics/cfg/models/v10/yolov10m.yaml +45 -0
  78. ultralytics/cfg/models/v10/yolov10n.yaml +45 -0
  79. ultralytics/cfg/models/v10/yolov10s.yaml +45 -0
  80. ultralytics/cfg/models/v10/yolov10x.yaml +45 -0
  81. ultralytics/cfg/models/v3/yolov3-spp.yaml +49 -0
  82. ultralytics/cfg/models/v3/yolov3-tiny.yaml +40 -0
  83. ultralytics/cfg/models/v3/yolov3.yaml +49 -0
  84. ultralytics/cfg/models/v5/yolov5-p6.yaml +62 -0
  85. ultralytics/cfg/models/v5/yolov5.yaml +51 -0
  86. ultralytics/cfg/models/v6/yolov6.yaml +56 -0
  87. ultralytics/cfg/models/v8/yoloe-v8-seg.yaml +48 -0
  88. ultralytics/cfg/models/v8/yoloe-v8.yaml +48 -0
  89. ultralytics/cfg/models/v8/yolov8-cls-resnet101.yaml +28 -0
  90. ultralytics/cfg/models/v8/yolov8-cls-resnet50.yaml +28 -0
  91. ultralytics/cfg/models/v8/yolov8-cls.yaml +32 -0
  92. ultralytics/cfg/models/v8/yolov8-ghost-p2.yaml +58 -0
  93. ultralytics/cfg/models/v8/yolov8-ghost-p6.yaml +60 -0
  94. ultralytics/cfg/models/v8/yolov8-ghost.yaml +50 -0
  95. ultralytics/cfg/models/v8/yolov8-obb.yaml +49 -0
  96. ultralytics/cfg/models/v8/yolov8-p2.yaml +57 -0
  97. ultralytics/cfg/models/v8/yolov8-p6.yaml +59 -0
  98. ultralytics/cfg/models/v8/yolov8-pose-p6.yaml +60 -0
  99. ultralytics/cfg/models/v8/yolov8-pose.yaml +50 -0
  100. ultralytics/cfg/models/v8/yolov8-rtdetr.yaml +49 -0
  101. ultralytics/cfg/models/v8/yolov8-seg-p6.yaml +59 -0
  102. ultralytics/cfg/models/v8/yolov8-seg.yaml +49 -0
  103. ultralytics/cfg/models/v8/yolov8-world.yaml +51 -0
  104. ultralytics/cfg/models/v8/yolov8-worldv2.yaml +49 -0
  105. ultralytics/cfg/models/v8/yolov8.yaml +49 -0
  106. ultralytics/cfg/models/v9/yolov9c-seg.yaml +41 -0
  107. ultralytics/cfg/models/v9/yolov9c.yaml +41 -0
  108. ultralytics/cfg/models/v9/yolov9e-seg.yaml +64 -0
  109. ultralytics/cfg/models/v9/yolov9e.yaml +64 -0
  110. ultralytics/cfg/models/v9/yolov9m.yaml +41 -0
  111. ultralytics/cfg/models/v9/yolov9s.yaml +41 -0
  112. ultralytics/cfg/models/v9/yolov9t.yaml +41 -0
  113. ultralytics/cfg/trackers/botsort.yaml +21 -0
  114. ultralytics/cfg/trackers/bytetrack.yaml +12 -0
  115. ultralytics/data/__init__.py +26 -0
  116. ultralytics/data/annotator.py +66 -0
  117. ultralytics/data/augment.py +2801 -0
  118. ultralytics/data/base.py +435 -0
  119. ultralytics/data/build.py +437 -0
  120. ultralytics/data/converter.py +855 -0
  121. ultralytics/data/dataset.py +834 -0
  122. ultralytics/data/loaders.py +704 -0
  123. ultralytics/data/scripts/download_weights.sh +18 -0
  124. ultralytics/data/scripts/get_coco.sh +61 -0
  125. ultralytics/data/scripts/get_coco128.sh +18 -0
  126. ultralytics/data/scripts/get_imagenet.sh +52 -0
  127. ultralytics/data/split.py +138 -0
  128. ultralytics/data/split_dota.py +344 -0
  129. ultralytics/data/utils.py +798 -0
  130. ultralytics/engine/__init__.py +1 -0
  131. ultralytics/engine/exporter.py +1580 -0
  132. ultralytics/engine/model.py +1125 -0
  133. ultralytics/engine/predictor.py +508 -0
  134. ultralytics/engine/results.py +1522 -0
  135. ultralytics/engine/trainer.py +977 -0
  136. ultralytics/engine/tuner.py +449 -0
  137. ultralytics/engine/validator.py +387 -0
  138. ultralytics/hub/__init__.py +166 -0
  139. ultralytics/hub/auth.py +151 -0
  140. ultralytics/hub/google/__init__.py +174 -0
  141. ultralytics/hub/session.py +422 -0
  142. ultralytics/hub/utils.py +162 -0
  143. ultralytics/models/__init__.py +9 -0
  144. ultralytics/models/fastsam/__init__.py +7 -0
  145. ultralytics/models/fastsam/model.py +79 -0
  146. ultralytics/models/fastsam/predict.py +169 -0
  147. ultralytics/models/fastsam/utils.py +23 -0
  148. ultralytics/models/fastsam/val.py +38 -0
  149. ultralytics/models/nas/__init__.py +7 -0
  150. ultralytics/models/nas/model.py +98 -0
  151. ultralytics/models/nas/predict.py +56 -0
  152. ultralytics/models/nas/val.py +38 -0
  153. ultralytics/models/rtdetr/__init__.py +7 -0
  154. ultralytics/models/rtdetr/model.py +63 -0
  155. ultralytics/models/rtdetr/predict.py +88 -0
  156. ultralytics/models/rtdetr/train.py +89 -0
  157. ultralytics/models/rtdetr/val.py +216 -0
  158. ultralytics/models/sam/__init__.py +25 -0
  159. ultralytics/models/sam/amg.py +275 -0
  160. ultralytics/models/sam/build.py +365 -0
  161. ultralytics/models/sam/build_sam3.py +377 -0
  162. ultralytics/models/sam/model.py +169 -0
  163. ultralytics/models/sam/modules/__init__.py +1 -0
  164. ultralytics/models/sam/modules/blocks.py +1067 -0
  165. ultralytics/models/sam/modules/decoders.py +495 -0
  166. ultralytics/models/sam/modules/encoders.py +794 -0
  167. ultralytics/models/sam/modules/memory_attention.py +298 -0
  168. ultralytics/models/sam/modules/sam.py +1160 -0
  169. ultralytics/models/sam/modules/tiny_encoder.py +979 -0
  170. ultralytics/models/sam/modules/transformer.py +344 -0
  171. ultralytics/models/sam/modules/utils.py +512 -0
  172. ultralytics/models/sam/predict.py +3940 -0
  173. ultralytics/models/sam/sam3/__init__.py +3 -0
  174. ultralytics/models/sam/sam3/decoder.py +546 -0
  175. ultralytics/models/sam/sam3/encoder.py +529 -0
  176. ultralytics/models/sam/sam3/geometry_encoders.py +415 -0
  177. ultralytics/models/sam/sam3/maskformer_segmentation.py +286 -0
  178. ultralytics/models/sam/sam3/model_misc.py +199 -0
  179. ultralytics/models/sam/sam3/necks.py +129 -0
  180. ultralytics/models/sam/sam3/sam3_image.py +339 -0
  181. ultralytics/models/sam/sam3/text_encoder_ve.py +307 -0
  182. ultralytics/models/sam/sam3/vitdet.py +547 -0
  183. ultralytics/models/sam/sam3/vl_combiner.py +160 -0
  184. ultralytics/models/utils/__init__.py +1 -0
  185. ultralytics/models/utils/loss.py +466 -0
  186. ultralytics/models/utils/ops.py +315 -0
  187. ultralytics/models/yolo/__init__.py +7 -0
  188. ultralytics/models/yolo/classify/__init__.py +7 -0
  189. ultralytics/models/yolo/classify/predict.py +90 -0
  190. ultralytics/models/yolo/classify/train.py +202 -0
  191. ultralytics/models/yolo/classify/val.py +216 -0
  192. ultralytics/models/yolo/detect/__init__.py +7 -0
  193. ultralytics/models/yolo/detect/predict.py +122 -0
  194. ultralytics/models/yolo/detect/train.py +227 -0
  195. ultralytics/models/yolo/detect/val.py +507 -0
  196. ultralytics/models/yolo/model.py +430 -0
  197. ultralytics/models/yolo/obb/__init__.py +7 -0
  198. ultralytics/models/yolo/obb/predict.py +56 -0
  199. ultralytics/models/yolo/obb/train.py +79 -0
  200. ultralytics/models/yolo/obb/val.py +302 -0
  201. ultralytics/models/yolo/pose/__init__.py +7 -0
  202. ultralytics/models/yolo/pose/predict.py +65 -0
  203. ultralytics/models/yolo/pose/train.py +110 -0
  204. ultralytics/models/yolo/pose/val.py +248 -0
  205. ultralytics/models/yolo/segment/__init__.py +7 -0
  206. ultralytics/models/yolo/segment/predict.py +109 -0
  207. ultralytics/models/yolo/segment/train.py +69 -0
  208. ultralytics/models/yolo/segment/val.py +307 -0
  209. ultralytics/models/yolo/world/__init__.py +5 -0
  210. ultralytics/models/yolo/world/train.py +173 -0
  211. ultralytics/models/yolo/world/train_world.py +178 -0
  212. ultralytics/models/yolo/yoloe/__init__.py +22 -0
  213. ultralytics/models/yolo/yoloe/predict.py +162 -0
  214. ultralytics/models/yolo/yoloe/train.py +287 -0
  215. ultralytics/models/yolo/yoloe/train_seg.py +122 -0
  216. ultralytics/models/yolo/yoloe/val.py +206 -0
  217. ultralytics/nn/__init__.py +27 -0
  218. ultralytics/nn/autobackend.py +964 -0
  219. ultralytics/nn/modules/__init__.py +182 -0
  220. ultralytics/nn/modules/activation.py +54 -0
  221. ultralytics/nn/modules/block.py +1947 -0
  222. ultralytics/nn/modules/conv.py +669 -0
  223. ultralytics/nn/modules/head.py +1183 -0
  224. ultralytics/nn/modules/transformer.py +793 -0
  225. ultralytics/nn/modules/utils.py +159 -0
  226. ultralytics/nn/tasks.py +1768 -0
  227. ultralytics/nn/text_model.py +356 -0
  228. ultralytics/py.typed +1 -0
  229. ultralytics/solutions/__init__.py +41 -0
  230. ultralytics/solutions/ai_gym.py +108 -0
  231. ultralytics/solutions/analytics.py +264 -0
  232. ultralytics/solutions/config.py +107 -0
  233. ultralytics/solutions/distance_calculation.py +123 -0
  234. ultralytics/solutions/heatmap.py +125 -0
  235. ultralytics/solutions/instance_segmentation.py +86 -0
  236. ultralytics/solutions/object_blurrer.py +89 -0
  237. ultralytics/solutions/object_counter.py +190 -0
  238. ultralytics/solutions/object_cropper.py +87 -0
  239. ultralytics/solutions/parking_management.py +280 -0
  240. ultralytics/solutions/queue_management.py +93 -0
  241. ultralytics/solutions/region_counter.py +133 -0
  242. ultralytics/solutions/security_alarm.py +151 -0
  243. ultralytics/solutions/similarity_search.py +219 -0
  244. ultralytics/solutions/solutions.py +828 -0
  245. ultralytics/solutions/speed_estimation.py +114 -0
  246. ultralytics/solutions/streamlit_inference.py +260 -0
  247. ultralytics/solutions/templates/similarity-search.html +156 -0
  248. ultralytics/solutions/trackzone.py +88 -0
  249. ultralytics/solutions/vision_eye.py +67 -0
  250. ultralytics/trackers/__init__.py +7 -0
  251. ultralytics/trackers/basetrack.py +115 -0
  252. ultralytics/trackers/bot_sort.py +257 -0
  253. ultralytics/trackers/byte_tracker.py +469 -0
  254. ultralytics/trackers/track.py +116 -0
  255. ultralytics/trackers/utils/__init__.py +1 -0
  256. ultralytics/trackers/utils/gmc.py +339 -0
  257. ultralytics/trackers/utils/kalman_filter.py +482 -0
  258. ultralytics/trackers/utils/matching.py +154 -0
  259. ultralytics/utils/__init__.py +1450 -0
  260. ultralytics/utils/autobatch.py +118 -0
  261. ultralytics/utils/autodevice.py +205 -0
  262. ultralytics/utils/benchmarks.py +728 -0
  263. ultralytics/utils/callbacks/__init__.py +5 -0
  264. ultralytics/utils/callbacks/base.py +233 -0
  265. ultralytics/utils/callbacks/clearml.py +146 -0
  266. ultralytics/utils/callbacks/comet.py +625 -0
  267. ultralytics/utils/callbacks/dvc.py +197 -0
  268. ultralytics/utils/callbacks/hub.py +110 -0
  269. ultralytics/utils/callbacks/mlflow.py +134 -0
  270. ultralytics/utils/callbacks/neptune.py +126 -0
  271. ultralytics/utils/callbacks/platform.py +453 -0
  272. ultralytics/utils/callbacks/raytune.py +42 -0
  273. ultralytics/utils/callbacks/tensorboard.py +123 -0
  274. ultralytics/utils/callbacks/wb.py +188 -0
  275. ultralytics/utils/checks.py +1020 -0
  276. ultralytics/utils/cpu.py +85 -0
  277. ultralytics/utils/dist.py +123 -0
  278. ultralytics/utils/downloads.py +529 -0
  279. ultralytics/utils/errors.py +35 -0
  280. ultralytics/utils/events.py +113 -0
  281. ultralytics/utils/export/__init__.py +7 -0
  282. ultralytics/utils/export/engine.py +237 -0
  283. ultralytics/utils/export/imx.py +325 -0
  284. ultralytics/utils/export/tensorflow.py +231 -0
  285. ultralytics/utils/files.py +219 -0
  286. ultralytics/utils/git.py +137 -0
  287. ultralytics/utils/instance.py +484 -0
  288. ultralytics/utils/logger.py +506 -0
  289. ultralytics/utils/loss.py +849 -0
  290. ultralytics/utils/metrics.py +1563 -0
  291. ultralytics/utils/nms.py +337 -0
  292. ultralytics/utils/ops.py +664 -0
  293. ultralytics/utils/patches.py +201 -0
  294. ultralytics/utils/plotting.py +1047 -0
  295. ultralytics/utils/tal.py +404 -0
  296. ultralytics/utils/torch_utils.py +984 -0
  297. ultralytics/utils/tqdm.py +443 -0
  298. ultralytics/utils/triton.py +112 -0
  299. ultralytics/utils/tuner.py +168 -0
@@ -0,0 +1,507 @@
1
+ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ import numpy as np
10
+ import torch
11
+ import torch.distributed as dist
12
+
13
+ from ultralytics.data import build_dataloader, build_yolo_dataset, converter
14
+ from ultralytics.engine.validator import BaseValidator
15
+ from ultralytics.utils import LOGGER, RANK, nms, ops
16
+ from ultralytics.utils.checks import check_requirements
17
+ from ultralytics.utils.metrics import ConfusionMatrix, DetMetrics, box_iou
18
+ from ultralytics.utils.plotting import plot_images
19
+
20
+
21
+ class DetectionValidator(BaseValidator):
22
+ """A class extending the BaseValidator class for validation based on a detection model.
23
+
24
+ This class implements validation functionality specific to object detection tasks, including metrics calculation,
25
+ prediction processing, and visualization of results.
26
+
27
+ Attributes:
28
+ is_coco (bool): Whether the dataset is COCO.
29
+ is_lvis (bool): Whether the dataset is LVIS.
30
+ class_map (list[int]): Mapping from model class indices to dataset class indices.
31
+ metrics (DetMetrics): Object detection metrics calculator.
32
+ iouv (torch.Tensor): IoU thresholds for mAP calculation.
33
+ niou (int): Number of IoU thresholds.
34
+ lb (list[Any]): List for storing ground truth labels for hybrid saving.
35
+ jdict (list[dict[str, Any]]): List for storing JSON detection results.
36
+ stats (dict[str, list[torch.Tensor]]): Dictionary for storing statistics during validation.
37
+
38
+ Examples:
39
+ >>> from ultralytics.models.yolo.detect import DetectionValidator
40
+ >>> args = dict(model="yolo11n.pt", data="coco8.yaml")
41
+ >>> validator = DetectionValidator(args=args)
42
+ >>> validator()
43
+ """
44
+
45
+ def __init__(self, dataloader=None, save_dir=None, args=None, _callbacks=None) -> None:
46
+ """Initialize detection validator with necessary variables and settings.
47
+
48
+ Args:
49
+ dataloader (torch.utils.data.DataLoader, optional): DataLoader to use for validation.
50
+ save_dir (Path, optional): Directory to save results.
51
+ args (dict[str, Any], optional): Arguments for the validator.
52
+ _callbacks (list[Any], optional): List of callback functions.
53
+ """
54
+ super().__init__(dataloader, save_dir, args, _callbacks)
55
+ self.is_coco = False
56
+ self.is_lvis = False
57
+ self.class_map = None
58
+ self.args.task = "detect"
59
+ self.iouv = torch.linspace(0.5, 0.95, 10) # IoU vector for mAP@0.5:0.95
60
+ self.niou = self.iouv.numel()
61
+ self.metrics = DetMetrics()
62
+
63
+ def preprocess(self, batch: dict[str, Any]) -> dict[str, Any]:
64
+ """Preprocess batch of images for YOLO validation.
65
+
66
+ Args:
67
+ batch (dict[str, Any]): Batch containing images and annotations.
68
+
69
+ Returns:
70
+ (dict[str, Any]): Preprocessed batch.
71
+ """
72
+ for k, v in batch.items():
73
+ if isinstance(v, torch.Tensor):
74
+ batch[k] = v.to(self.device, non_blocking=self.device.type == "cuda")
75
+ batch["img"] = (batch["img"].half() if self.args.half else batch["img"].float()) / 255
76
+ return batch
77
+
78
+ def init_metrics(self, model: torch.nn.Module) -> None:
79
+ """Initialize evaluation metrics for YOLO detection validation.
80
+
81
+ Args:
82
+ model (torch.nn.Module): Model to validate.
83
+ """
84
+ val = self.data.get(self.args.split, "") # validation path
85
+ self.is_coco = (
86
+ isinstance(val, str)
87
+ and "coco" in val
88
+ and (val.endswith(f"{os.sep}val2017.txt") or val.endswith(f"{os.sep}test-dev2017.txt"))
89
+ ) # is COCO
90
+ self.is_lvis = isinstance(val, str) and "lvis" in val and not self.is_coco # is LVIS
91
+ self.class_map = converter.coco80_to_coco91_class() if self.is_coco else list(range(1, len(model.names) + 1))
92
+ self.args.save_json |= self.args.val and (self.is_coco or self.is_lvis) and not self.training # run final val
93
+ self.names = model.names
94
+ self.nc = len(model.names)
95
+ self.end2end = getattr(model, "end2end", False)
96
+ self.seen = 0
97
+ self.jdict = []
98
+ self.metrics.names = model.names
99
+ self.confusion_matrix = ConfusionMatrix(names=model.names, save_matches=self.args.plots and self.args.visualize)
100
+
101
+ def get_desc(self) -> str:
102
+ """Return a formatted string summarizing class metrics of YOLO model."""
103
+ return ("%22s" + "%11s" * 6) % ("Class", "Images", "Instances", "Box(P", "R", "mAP50", "mAP50-95)")
104
+
105
+ def postprocess(self, preds: torch.Tensor) -> list[dict[str, torch.Tensor]]:
106
+ """Apply Non-maximum suppression to prediction outputs.
107
+
108
+ Args:
109
+ preds (torch.Tensor): Raw predictions from the model.
110
+
111
+ Returns:
112
+ (list[dict[str, torch.Tensor]]): Processed predictions after NMS, where each dict contains 'bboxes', 'conf',
113
+ 'cls', and 'extra' tensors.
114
+ """
115
+ outputs = nms.non_max_suppression(
116
+ preds,
117
+ self.args.conf,
118
+ self.args.iou,
119
+ nc=0 if self.args.task == "detect" else self.nc,
120
+ multi_label=True,
121
+ agnostic=self.args.single_cls or self.args.agnostic_nms,
122
+ max_det=self.args.max_det,
123
+ end2end=self.end2end,
124
+ rotated=self.args.task == "obb",
125
+ )
126
+ return [{"bboxes": x[:, :4], "conf": x[:, 4], "cls": x[:, 5], "extra": x[:, 6:]} for x in outputs]
127
+
128
+ def _prepare_batch(self, si: int, batch: dict[str, Any]) -> dict[str, Any]:
129
+ """Prepare a batch of images and annotations for validation.
130
+
131
+ Args:
132
+ si (int): Batch index.
133
+ batch (dict[str, Any]): Batch data containing images and annotations.
134
+
135
+ Returns:
136
+ (dict[str, Any]): Prepared batch with processed annotations.
137
+ """
138
+ idx = batch["batch_idx"] == si
139
+ cls = batch["cls"][idx].squeeze(-1)
140
+ bbox = batch["bboxes"][idx]
141
+ ori_shape = batch["ori_shape"][si]
142
+ imgsz = batch["img"].shape[2:]
143
+ ratio_pad = batch["ratio_pad"][si]
144
+ if cls.shape[0]:
145
+ bbox = ops.xywh2xyxy(bbox) * torch.tensor(imgsz, device=self.device)[[1, 0, 1, 0]] # target boxes
146
+ return {
147
+ "cls": cls,
148
+ "bboxes": bbox,
149
+ "ori_shape": ori_shape,
150
+ "imgsz": imgsz,
151
+ "ratio_pad": ratio_pad,
152
+ "im_file": batch["im_file"][si],
153
+ }
154
+
155
+ def _prepare_pred(self, pred: dict[str, torch.Tensor]) -> dict[str, torch.Tensor]:
156
+ """Prepare predictions for evaluation against ground truth.
157
+
158
+ Args:
159
+ pred (dict[str, torch.Tensor]): Post-processed predictions from the model.
160
+
161
+ Returns:
162
+ (dict[str, torch.Tensor]): Prepared predictions in native space.
163
+ """
164
+ if self.args.single_cls:
165
+ pred["cls"] *= 0
166
+ return pred
167
+
168
+ def update_metrics(self, preds: list[dict[str, torch.Tensor]], batch: dict[str, Any]) -> None:
169
+ """Update metrics with new predictions and ground truth.
170
+
171
+ Args:
172
+ preds (list[dict[str, torch.Tensor]]): List of predictions from the model.
173
+ batch (dict[str, Any]): Batch data containing ground truth.
174
+ """
175
+ for si, pred in enumerate(preds):
176
+ self.seen += 1
177
+ pbatch = self._prepare_batch(si, batch)
178
+ predn = self._prepare_pred(pred)
179
+
180
+ cls = pbatch["cls"].cpu().numpy()
181
+ no_pred = predn["cls"].shape[0] == 0
182
+ self.metrics.update_stats(
183
+ {
184
+ **self._process_batch(predn, pbatch),
185
+ "target_cls": cls,
186
+ "target_img": np.unique(cls),
187
+ "conf": np.zeros(0) if no_pred else predn["conf"].cpu().numpy(),
188
+ "pred_cls": np.zeros(0) if no_pred else predn["cls"].cpu().numpy(),
189
+ }
190
+ )
191
+ # Evaluate
192
+ if self.args.plots:
193
+ self.confusion_matrix.process_batch(predn, pbatch, conf=self.args.conf)
194
+ if self.args.visualize:
195
+ self.confusion_matrix.plot_matches(batch["img"][si], pbatch["im_file"], self.save_dir)
196
+
197
+ if no_pred:
198
+ continue
199
+
200
+ # Save
201
+ if self.args.save_json or self.args.save_txt:
202
+ predn_scaled = self.scale_preds(predn, pbatch)
203
+ if self.args.save_json:
204
+ self.pred_to_json(predn_scaled, pbatch)
205
+ if self.args.save_txt:
206
+ self.save_one_txt(
207
+ predn_scaled,
208
+ self.args.save_conf,
209
+ pbatch["ori_shape"],
210
+ self.save_dir / "labels" / f"{Path(pbatch['im_file']).stem}.txt",
211
+ )
212
+
213
+ def finalize_metrics(self) -> None:
214
+ """Set final values for metrics speed and confusion matrix."""
215
+ if self.args.plots:
216
+ for normalize in True, False:
217
+ self.confusion_matrix.plot(save_dir=self.save_dir, normalize=normalize, on_plot=self.on_plot)
218
+ self.metrics.speed = self.speed
219
+ self.metrics.confusion_matrix = self.confusion_matrix
220
+ self.metrics.save_dir = self.save_dir
221
+
222
+ def gather_stats(self) -> None:
223
+ """Gather stats from all GPUs."""
224
+ if RANK == 0:
225
+ gathered_stats = [None] * dist.get_world_size()
226
+ dist.gather_object(self.metrics.stats, gathered_stats, dst=0)
227
+ merged_stats = {key: [] for key in self.metrics.stats.keys()}
228
+ for stats_dict in gathered_stats:
229
+ for key in merged_stats:
230
+ merged_stats[key].extend(stats_dict[key])
231
+ gathered_jdict = [None] * dist.get_world_size()
232
+ dist.gather_object(self.jdict, gathered_jdict, dst=0)
233
+ self.jdict = []
234
+ for jdict in gathered_jdict:
235
+ self.jdict.extend(jdict)
236
+ self.metrics.stats = merged_stats
237
+ self.seen = len(self.dataloader.dataset) # total image count from dataset
238
+ elif RANK > 0:
239
+ dist.gather_object(self.metrics.stats, None, dst=0)
240
+ dist.gather_object(self.jdict, None, dst=0)
241
+ self.jdict = []
242
+ self.metrics.clear_stats()
243
+
244
+ def get_stats(self) -> dict[str, Any]:
245
+ """Calculate and return metrics statistics.
246
+
247
+ Returns:
248
+ (dict[str, Any]): Dictionary containing metrics results.
249
+ """
250
+ self.metrics.process(save_dir=self.save_dir, plot=self.args.plots, on_plot=self.on_plot)
251
+ self.metrics.clear_stats()
252
+ return self.metrics.results_dict
253
+
254
+ def print_results(self) -> None:
255
+ """Print training/validation set metrics per class."""
256
+ pf = "%22s" + "%11i" * 2 + "%11.3g" * len(self.metrics.keys) # print format
257
+ LOGGER.info(pf % ("all", self.seen, self.metrics.nt_per_class.sum(), *self.metrics.mean_results()))
258
+ if self.metrics.nt_per_class.sum() == 0:
259
+ LOGGER.warning(f"no labels found in {self.args.task} set, cannot compute metrics without labels")
260
+
261
+ # Print results per class
262
+ if self.args.verbose and not self.training and self.nc > 1 and len(self.metrics.stats):
263
+ for i, c in enumerate(self.metrics.ap_class_index):
264
+ LOGGER.info(
265
+ pf
266
+ % (
267
+ self.names[c],
268
+ self.metrics.nt_per_image[c],
269
+ self.metrics.nt_per_class[c],
270
+ *self.metrics.class_result(i),
271
+ )
272
+ )
273
+
274
+ def _process_batch(self, preds: dict[str, torch.Tensor], batch: dict[str, Any]) -> dict[str, np.ndarray]:
275
+ """Return correct prediction matrix.
276
+
277
+ Args:
278
+ preds (dict[str, torch.Tensor]): Dictionary containing prediction data with 'bboxes' and 'cls' keys.
279
+ batch (dict[str, Any]): Batch dictionary containing ground truth data with 'bboxes' and 'cls' keys.
280
+
281
+ Returns:
282
+ (dict[str, np.ndarray]): Dictionary containing 'tp' key with correct prediction matrix of shape (N, 10) for
283
+ 10 IoU levels.
284
+ """
285
+ if batch["cls"].shape[0] == 0 or preds["cls"].shape[0] == 0:
286
+ return {"tp": np.zeros((preds["cls"].shape[0], self.niou), dtype=bool)}
287
+ iou = box_iou(batch["bboxes"], preds["bboxes"])
288
+ return {"tp": self.match_predictions(preds["cls"], batch["cls"], iou).cpu().numpy()}
289
+
290
+ def build_dataset(self, img_path: str, mode: str = "val", batch: int | None = None) -> torch.utils.data.Dataset:
291
+ """Build YOLO Dataset.
292
+
293
+ Args:
294
+ img_path (str): Path to the folder containing images.
295
+ mode (str): `train` mode or `val` mode, users are able to customize different augmentations for each mode.
296
+ batch (int, optional): Size of batches, this is for `rect`.
297
+
298
+ Returns:
299
+ (Dataset): YOLO dataset.
300
+ """
301
+ return build_yolo_dataset(self.args, img_path, batch, self.data, mode=mode, stride=self.stride)
302
+
303
+ def get_dataloader(self, dataset_path: str, batch_size: int) -> torch.utils.data.DataLoader:
304
+ """Construct and return dataloader.
305
+
306
+ Args:
307
+ dataset_path (str): Path to the dataset.
308
+ batch_size (int): Size of each batch.
309
+
310
+ Returns:
311
+ (torch.utils.data.DataLoader): DataLoader for validation.
312
+ """
313
+ dataset = self.build_dataset(dataset_path, batch=batch_size, mode="val")
314
+ return build_dataloader(
315
+ dataset,
316
+ batch_size,
317
+ self.args.workers,
318
+ shuffle=False,
319
+ rank=-1,
320
+ drop_last=self.args.compile,
321
+ pin_memory=self.training,
322
+ )
323
+
324
+ def plot_val_samples(self, batch: dict[str, Any], ni: int) -> None:
325
+ """Plot validation image samples.
326
+
327
+ Args:
328
+ batch (dict[str, Any]): Batch containing images and annotations.
329
+ ni (int): Batch index.
330
+ """
331
+ plot_images(
332
+ labels=batch,
333
+ paths=batch["im_file"],
334
+ fname=self.save_dir / f"val_batch{ni}_labels.jpg",
335
+ names=self.names,
336
+ on_plot=self.on_plot,
337
+ )
338
+
339
+ def plot_predictions(
340
+ self, batch: dict[str, Any], preds: list[dict[str, torch.Tensor]], ni: int, max_det: int | None = None
341
+ ) -> None:
342
+ """Plot predicted bounding boxes on input images and save the result.
343
+
344
+ Args:
345
+ batch (dict[str, Any]): Batch containing images and annotations.
346
+ preds (list[dict[str, torch.Tensor]]): List of predictions from the model.
347
+ ni (int): Batch index.
348
+ max_det (Optional[int]): Maximum number of detections to plot.
349
+ """
350
+ if not preds:
351
+ return
352
+ for i, pred in enumerate(preds):
353
+ pred["batch_idx"] = torch.ones_like(pred["conf"]) * i # add batch index to predictions
354
+ keys = preds[0].keys()
355
+ max_det = max_det or self.args.max_det
356
+ batched_preds = {k: torch.cat([x[k][:max_det] for x in preds], dim=0) for k in keys}
357
+ batched_preds["bboxes"] = ops.xyxy2xywh(batched_preds["bboxes"]) # convert to xywh format
358
+ plot_images(
359
+ images=batch["img"],
360
+ labels=batched_preds,
361
+ paths=batch["im_file"],
362
+ fname=self.save_dir / f"val_batch{ni}_pred.jpg",
363
+ names=self.names,
364
+ on_plot=self.on_plot,
365
+ ) # pred
366
+
367
+ def save_one_txt(self, predn: dict[str, torch.Tensor], save_conf: bool, shape: tuple[int, int], file: Path) -> None:
368
+ """Save YOLO detections to a txt file in normalized coordinates in a specific format.
369
+
370
+ Args:
371
+ predn (dict[str, torch.Tensor]): Dictionary containing predictions with keys 'bboxes', 'conf', and 'cls'.
372
+ save_conf (bool): Whether to save confidence scores.
373
+ shape (tuple[int, int]): Shape of the original image (height, width).
374
+ file (Path): File path to save the detections.
375
+ """
376
+ from ultralytics.engine.results import Results
377
+
378
+ Results(
379
+ np.zeros((shape[0], shape[1]), dtype=np.uint8),
380
+ path=None,
381
+ names=self.names,
382
+ boxes=torch.cat([predn["bboxes"], predn["conf"].unsqueeze(-1), predn["cls"].unsqueeze(-1)], dim=1),
383
+ ).save_txt(file, save_conf=save_conf)
384
+
385
+ def pred_to_json(self, predn: dict[str, torch.Tensor], pbatch: dict[str, Any]) -> None:
386
+ """Serialize YOLO predictions to COCO json format.
387
+
388
+ Args:
389
+ predn (dict[str, torch.Tensor]): Predictions dictionary containing 'bboxes', 'conf', and 'cls' keys with
390
+ bounding box coordinates, confidence scores, and class predictions.
391
+ pbatch (dict[str, Any]): Batch dictionary containing 'imgsz', 'ori_shape', 'ratio_pad', and 'im_file'.
392
+
393
+ Examples:
394
+ >>> result = {
395
+ ... "image_id": 42,
396
+ ... "file_name": "42.jpg",
397
+ ... "category_id": 18,
398
+ ... "bbox": [258.15, 41.29, 348.26, 243.78],
399
+ ... "score": 0.236,
400
+ ... }
401
+ """
402
+ path = Path(pbatch["im_file"])
403
+ stem = path.stem
404
+ image_id = int(stem) if stem.isnumeric() else stem
405
+ box = ops.xyxy2xywh(predn["bboxes"]) # xywh
406
+ box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner
407
+ for b, s, c in zip(box.tolist(), predn["conf"].tolist(), predn["cls"].tolist()):
408
+ self.jdict.append(
409
+ {
410
+ "image_id": image_id,
411
+ "file_name": path.name,
412
+ "category_id": self.class_map[int(c)],
413
+ "bbox": [round(x, 3) for x in b],
414
+ "score": round(s, 5),
415
+ }
416
+ )
417
+
418
+ def scale_preds(self, predn: dict[str, torch.Tensor], pbatch: dict[str, Any]) -> dict[str, torch.Tensor]:
419
+ """Scales predictions to the original image size."""
420
+ return {
421
+ **predn,
422
+ "bboxes": ops.scale_boxes(
423
+ pbatch["imgsz"],
424
+ predn["bboxes"].clone(),
425
+ pbatch["ori_shape"],
426
+ ratio_pad=pbatch["ratio_pad"],
427
+ ),
428
+ }
429
+
430
+ def eval_json(self, stats: dict[str, Any]) -> dict[str, Any]:
431
+ """Evaluate YOLO output in JSON format and return performance statistics.
432
+
433
+ Args:
434
+ stats (dict[str, Any]): Current statistics dictionary.
435
+
436
+ Returns:
437
+ (dict[str, Any]): Updated statistics dictionary with COCO/LVIS evaluation results.
438
+ """
439
+ pred_json = self.save_dir / "predictions.json" # predictions
440
+ anno_json = (
441
+ self.data["path"]
442
+ / "annotations"
443
+ / ("instances_val2017.json" if self.is_coco else f"lvis_v1_{self.args.split}.json")
444
+ ) # annotations
445
+ return self.coco_evaluate(stats, pred_json, anno_json)
446
+
447
+ def coco_evaluate(
448
+ self,
449
+ stats: dict[str, Any],
450
+ pred_json: str,
451
+ anno_json: str,
452
+ iou_types: str | list[str] = "bbox",
453
+ suffix: str | list[str] = "Box",
454
+ ) -> dict[str, Any]:
455
+ """Evaluate COCO/LVIS metrics using faster-coco-eval library.
456
+
457
+ Performs evaluation using the faster-coco-eval library to compute mAP metrics for object detection. Updates the
458
+ provided stats dictionary with computed metrics including mAP50, mAP50-95, and LVIS-specific metrics if
459
+ applicable.
460
+
461
+ Args:
462
+ stats (dict[str, Any]): Dictionary to store computed metrics and statistics.
463
+ pred_json (str | Path): Path to JSON file containing predictions in COCO format.
464
+ anno_json (str | Path): Path to JSON file containing ground truth annotations in COCO format.
465
+ iou_types (str | list[str]): IoU type(s) for evaluation. Can be single string or list of strings. Common
466
+ values include "bbox", "segm", "keypoints". Defaults to "bbox".
467
+ suffix (str | list[str]): Suffix to append to metric names in stats dictionary. Should correspond to
468
+ iou_types if multiple types provided. Defaults to "Box".
469
+
470
+ Returns:
471
+ (dict[str, Any]): Updated stats dictionary containing the computed COCO/LVIS evaluation metrics.
472
+ """
473
+ if self.args.save_json and (self.is_coco or self.is_lvis) and len(self.jdict):
474
+ LOGGER.info(f"\nEvaluating faster-coco-eval mAP using {pred_json} and {anno_json}...")
475
+ try:
476
+ for x in pred_json, anno_json:
477
+ assert x.is_file(), f"{x} file not found"
478
+ iou_types = [iou_types] if isinstance(iou_types, str) else iou_types
479
+ suffix = [suffix] if isinstance(suffix, str) else suffix
480
+ check_requirements("faster-coco-eval>=1.6.7")
481
+ from faster_coco_eval import COCO, COCOeval_faster
482
+
483
+ anno = COCO(anno_json)
484
+ pred = anno.loadRes(pred_json)
485
+ for i, iou_type in enumerate(iou_types):
486
+ val = COCOeval_faster(
487
+ anno, pred, iouType=iou_type, lvis_style=self.is_lvis, print_function=LOGGER.info
488
+ )
489
+ val.params.imgIds = [int(Path(x).stem) for x in self.dataloader.dataset.im_files] # images to eval
490
+ val.evaluate()
491
+ val.accumulate()
492
+ val.summarize()
493
+
494
+ # update mAP50-95 and mAP50
495
+ stats[f"metrics/mAP50({suffix[i][0]})"] = val.stats_as_dict["AP_50"]
496
+ stats[f"metrics/mAP50-95({suffix[i][0]})"] = val.stats_as_dict["AP_all"]
497
+
498
+ if self.is_lvis:
499
+ stats[f"metrics/APr({suffix[i][0]})"] = val.stats_as_dict["APr"]
500
+ stats[f"metrics/APc({suffix[i][0]})"] = val.stats_as_dict["APc"]
501
+ stats[f"metrics/APf({suffix[i][0]})"] = val.stats_as_dict["APf"]
502
+
503
+ if self.is_lvis:
504
+ stats["fitness"] = stats["metrics/mAP50-95(B)"] # always use box mAP50-95 for fitness
505
+ except Exception as e:
506
+ LOGGER.warning(f"faster-coco-eval unable to run: {e}")
507
+ return stats