ultralytics 8.3.153__py3-none-any.whl → 8.3.155__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 (48) hide show
  1. tests/test_python.py +1 -0
  2. ultralytics/__init__.py +1 -1
  3. ultralytics/cfg/__init__.py +2 -0
  4. ultralytics/engine/predictor.py +1 -1
  5. ultralytics/engine/validator.py +0 -6
  6. ultralytics/models/fastsam/val.py +0 -2
  7. ultralytics/models/rtdetr/val.py +28 -16
  8. ultralytics/models/yolo/classify/val.py +26 -23
  9. ultralytics/models/yolo/detect/train.py +4 -7
  10. ultralytics/models/yolo/detect/val.py +88 -90
  11. ultralytics/models/yolo/obb/val.py +52 -44
  12. ultralytics/models/yolo/pose/train.py +1 -35
  13. ultralytics/models/yolo/pose/val.py +77 -176
  14. ultralytics/models/yolo/segment/train.py +1 -41
  15. ultralytics/models/yolo/segment/val.py +64 -176
  16. ultralytics/models/yolo/yoloe/val.py +2 -1
  17. ultralytics/nn/autobackend.py +2 -2
  18. ultralytics/nn/tasks.py +0 -1
  19. ultralytics/solutions/ai_gym.py +5 -5
  20. ultralytics/solutions/analytics.py +2 -2
  21. ultralytics/solutions/config.py +2 -2
  22. ultralytics/solutions/distance_calculation.py +1 -1
  23. ultralytics/solutions/heatmap.py +5 -3
  24. ultralytics/solutions/instance_segmentation.py +4 -2
  25. ultralytics/solutions/object_blurrer.py +4 -2
  26. ultralytics/solutions/object_counter.py +5 -5
  27. ultralytics/solutions/object_cropper.py +3 -2
  28. ultralytics/solutions/parking_management.py +9 -9
  29. ultralytics/solutions/queue_management.py +4 -2
  30. ultralytics/solutions/region_counter.py +13 -5
  31. ultralytics/solutions/security_alarm.py +6 -4
  32. ultralytics/solutions/similarity_search.py +6 -6
  33. ultralytics/solutions/solutions.py +9 -7
  34. ultralytics/solutions/speed_estimation.py +3 -2
  35. ultralytics/solutions/streamlit_inference.py +6 -6
  36. ultralytics/solutions/templates/similarity-search.html +31 -0
  37. ultralytics/solutions/trackzone.py +4 -2
  38. ultralytics/solutions/vision_eye.py +4 -2
  39. ultralytics/utils/callbacks/comet.py +1 -1
  40. ultralytics/utils/metrics.py +146 -317
  41. ultralytics/utils/ops.py +4 -4
  42. ultralytics/utils/plotting.py +31 -56
  43. {ultralytics-8.3.153.dist-info → ultralytics-8.3.155.dist-info}/METADATA +1 -1
  44. {ultralytics-8.3.153.dist-info → ultralytics-8.3.155.dist-info}/RECORD +48 -48
  45. {ultralytics-8.3.153.dist-info → ultralytics-8.3.155.dist-info}/WHEEL +0 -0
  46. {ultralytics-8.3.153.dist-info → ultralytics-8.3.155.dist-info}/entry_points.txt +0 -0
  47. {ultralytics-8.3.153.dist-info → ultralytics-8.3.155.dist-info}/licenses/LICENSE +0 -0
  48. {ultralytics-8.3.153.dist-info → ultralytics-8.3.155.dist-info}/top_level.txt +0 -0
tests/test_python.py CHANGED
@@ -285,6 +285,7 @@ def test_results(model: str):
285
285
  temp_s = "https://ultralytics.com/images/boats.jpg" if model == "yolo11n-obb.pt" else SOURCE
286
286
  results = YOLO(WEIGHTS_DIR / model)([temp_s, temp_s], imgsz=160)
287
287
  for r in results:
288
+ assert len(r), f"'{model}' results should not be empty!"
288
289
  r = r.cpu().numpy()
289
290
  print(r, len(r), r.path) # print numpy attributes
290
291
  r = r.to(device="cpu", dtype=torch.float32)
ultralytics/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
2
 
3
- __version__ = "8.3.153"
3
+ __version__ = "8.3.155"
4
4
 
5
5
  import os
6
6
 
@@ -621,6 +621,8 @@ def handle_yolo_settings(args: List[str]) -> None:
621
621
  new = dict(parse_key_value_pair(a) for a in args)
622
622
  check_dict_alignment(SETTINGS, new)
623
623
  SETTINGS.update(new)
624
+ for k, v in new.items():
625
+ LOGGER.info(f"✅ Updated '{k}={v}'")
624
626
 
625
627
  LOGGER.info(SETTINGS) # print the current settings
626
628
  LOGGER.info(f"💡 Learn more about Ultralytics Settings at {url}")
@@ -401,7 +401,7 @@ class BasePredictor:
401
401
 
402
402
  self.device = self.model.device # update device
403
403
  self.args.half = self.model.fp16 # update half
404
- if hasattr(self.model, "imgsz"):
404
+ if hasattr(self.model, "imgsz") and not getattr(self.model, "dynamic", False):
405
405
  self.args.imgsz = self.model.imgsz # reuse imgsz from export metadata
406
406
  self.model.eval()
407
407
 
@@ -82,7 +82,6 @@ class BaseValidator:
82
82
  update_metrics: Update metrics based on predictions and batch.
83
83
  finalize_metrics: Finalize and return all metrics.
84
84
  get_stats: Return statistics about the model's performance.
85
- check_stats: Check statistics.
86
85
  print_results: Print the results of the model's predictions.
87
86
  get_desc: Get description of the YOLO model.
88
87
  on_plot: Register plots for visualization.
@@ -226,7 +225,6 @@ class BaseValidator:
226
225
 
227
226
  self.run_callbacks("on_val_batch_end")
228
227
  stats = self.get_stats()
229
- self.check_stats(stats)
230
228
  self.speed = dict(zip(self.speed.keys(), (x.t / len(self.dataloader.dataset) * 1e3 for x in dt)))
231
229
  self.finalize_metrics()
232
230
  self.print_results()
@@ -334,10 +332,6 @@ class BaseValidator:
334
332
  """Return statistics about the model's performance."""
335
333
  return {}
336
334
 
337
- def check_stats(self, stats):
338
- """Check statistics."""
339
- pass
340
-
341
335
  def print_results(self):
342
336
  """Print the results of the model's predictions."""
343
337
  pass
@@ -1,7 +1,6 @@
1
1
  # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
2
 
3
3
  from ultralytics.models.yolo.segment import SegmentationValidator
4
- from ultralytics.utils.metrics import SegmentMetrics
5
4
 
6
5
 
7
6
  class FastSAMValidator(SegmentationValidator):
@@ -39,4 +38,3 @@ class FastSAMValidator(SegmentationValidator):
39
38
  super().__init__(dataloader, save_dir, args, _callbacks)
40
39
  self.args.task = "segment"
41
40
  self.args.plots = False # disable ConfusionMatrix and other plots to avoid errors
42
- self.metrics = SegmentMetrics(save_dir=self.save_dir)
@@ -1,5 +1,7 @@
1
1
  # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
2
 
3
+ from typing import Any, Dict, List, Tuple, Union
4
+
3
5
  import torch
4
6
 
5
7
  from ultralytics.data import YOLODataset
@@ -151,15 +153,21 @@ class RTDETRValidator(DetectionValidator):
151
153
  data=self.data,
152
154
  )
153
155
 
154
- def postprocess(self, preds):
156
+ def postprocess(
157
+ self, preds: Union[torch.Tensor, List[torch.Tensor], Tuple[torch.Tensor]]
158
+ ) -> List[Dict[str, torch.Tensor]]:
155
159
  """
156
160
  Apply Non-maximum suppression to prediction outputs.
157
161
 
158
162
  Args:
159
- preds (list | tuple | torch.Tensor): Raw predictions from the model.
163
+ preds (torch.Tensor | List | Tuple): Raw predictions from the model. If tensor, should have shape
164
+ (batch_size, num_predictions, num_classes + 4) where last dimension contains bbox coords and class scores.
160
165
 
161
166
  Returns:
162
- (list[torch.Tensor]): List of processed predictions for each image in batch.
167
+ (List[Dict[str, torch.Tensor]]): List of dictionaries for each image, each containing:
168
+ - 'bboxes': Tensor of shape (N, 4) with bounding box coordinates
169
+ - 'conf': Tensor of shape (N,) with confidence scores
170
+ - 'cls': Tensor of shape (N,) with class indices
163
171
  """
164
172
  if not isinstance(preds, (list, tuple)): # list for PyTorch inference but list[0] Tensor for export inference
165
173
  preds = [preds, None]
@@ -176,18 +184,19 @@ class RTDETRValidator(DetectionValidator):
176
184
  pred = pred[score.argsort(descending=True)]
177
185
  outputs[i] = pred[score > self.args.conf]
178
186
 
179
- return outputs
187
+ return [{"bboxes": x[:, :4], "conf": x[:, 4], "cls": x[:, 5]} for x in outputs]
180
188
 
181
- def _prepare_batch(self, si, batch):
189
+ def _prepare_batch(self, si: int, batch: Dict[str, Any]) -> Dict[str, Any]:
182
190
  """
183
191
  Prepare a batch for validation by applying necessary transformations.
184
192
 
185
193
  Args:
186
194
  si (int): Batch index.
187
- batch (dict): Batch data containing images and annotations.
195
+ batch (Dict[str, Any]): Batch data containing images and annotations.
188
196
 
189
197
  Returns:
190
- (dict): Prepared batch with transformed annotations.
198
+ (Dict[str, Any]): Prepared batch with transformed annotations containing cls, bboxes,
199
+ ori_shape, imgsz, and ratio_pad.
191
200
  """
192
201
  idx = batch["batch_idx"] == si
193
202
  cls = batch["cls"][idx].squeeze(-1)
@@ -199,20 +208,23 @@ class RTDETRValidator(DetectionValidator):
199
208
  bbox = ops.xywh2xyxy(bbox) # target boxes
200
209
  bbox[..., [0, 2]] *= ori_shape[1] # native-space pred
201
210
  bbox[..., [1, 3]] *= ori_shape[0] # native-space pred
202
- return {"cls": cls, "bbox": bbox, "ori_shape": ori_shape, "imgsz": imgsz, "ratio_pad": ratio_pad}
211
+ return {"cls": cls, "bboxes": bbox, "ori_shape": ori_shape, "imgsz": imgsz, "ratio_pad": ratio_pad}
203
212
 
204
- def _prepare_pred(self, pred, pbatch):
213
+ def _prepare_pred(self, pred: Dict[str, torch.Tensor], pbatch: Dict[str, Any]) -> Dict[str, torch.Tensor]:
205
214
  """
206
215
  Prepare predictions by scaling bounding boxes to original image dimensions.
207
216
 
208
217
  Args:
209
- pred (torch.Tensor): Raw predictions.
210
- pbatch (dict): Prepared batch information.
218
+ pred (Dict[str, torch.Tensor]): Raw predictions containing 'cls', 'bboxes', and 'conf'.
219
+ pbatch (Dict[str, torch.Tensor]): Prepared batch information containing 'ori_shape' and other metadata.
211
220
 
212
221
  Returns:
213
- (torch.Tensor): Predictions scaled to original image dimensions.
222
+ (Dict[str, torch.Tensor]): Predictions scaled to original image dimensions.
214
223
  """
215
- predn = pred.clone()
216
- predn[..., [0, 2]] *= pbatch["ori_shape"][1] / self.args.imgsz # native-space pred
217
- predn[..., [1, 3]] *= pbatch["ori_shape"][0] / self.args.imgsz # native-space pred
218
- return predn.float()
224
+ cls = pred["cls"]
225
+ if self.args.single_cls:
226
+ cls *= 0
227
+ bboxes = pred["bboxes"].clone()
228
+ bboxes[..., [0, 2]] *= pbatch["ori_shape"][1] / self.args.imgsz # native-space pred
229
+ bboxes[..., [1, 3]] *= pbatch["ori_shape"][0] / self.args.imgsz # native-space pred
230
+ return {"bboxes": bboxes, "conf": pred["conf"], "cls": cls}
@@ -1,5 +1,8 @@
1
1
  # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
2
 
3
+ from pathlib import Path
4
+ from typing import Any, Dict, List, Tuple, Union
5
+
3
6
  import torch
4
7
 
5
8
  from ultralytics.data import ClassificationDataset, build_dataloader
@@ -48,7 +51,7 @@ class ClassificationValidator(BaseValidator):
48
51
  Torchvision classification models can also be passed to the 'model' argument, i.e. model='resnet18'.
49
52
  """
50
53
 
51
- def __init__(self, dataloader=None, save_dir=None, args=None, _callbacks=None):
54
+ def __init__(self, dataloader=None, save_dir=None, args=None, _callbacks=None) -> None:
52
55
  """
53
56
  Initialize ClassificationValidator with dataloader, save directory, and other parameters.
54
57
 
@@ -70,28 +73,26 @@ class ClassificationValidator(BaseValidator):
70
73
  self.args.task = "classify"
71
74
  self.metrics = ClassifyMetrics()
72
75
 
73
- def get_desc(self):
76
+ def get_desc(self) -> str:
74
77
  """Return a formatted string summarizing classification metrics."""
75
78
  return ("%22s" + "%11s" * 2) % ("classes", "top1_acc", "top5_acc")
76
79
 
77
- def init_metrics(self, model):
80
+ def init_metrics(self, model: torch.nn.Module) -> None:
78
81
  """Initialize confusion matrix, class names, and tracking containers for predictions and targets."""
79
82
  self.names = model.names
80
83
  self.nc = len(model.names)
81
- self.confusion_matrix = ConfusionMatrix(
82
- nc=self.nc, conf=self.args.conf, names=self.names.values(), task="classify"
83
- )
84
84
  self.pred = []
85
85
  self.targets = []
86
+ self.confusion_matrix = ConfusionMatrix(names=list(model.names.values()))
86
87
 
87
- def preprocess(self, batch):
88
+ def preprocess(self, batch: Dict[str, Any]) -> Dict[str, Any]:
88
89
  """Preprocess input batch by moving data to device and converting to appropriate dtype."""
89
90
  batch["img"] = batch["img"].to(self.device, non_blocking=True)
90
91
  batch["img"] = batch["img"].half() if self.args.half else batch["img"].float()
91
92
  batch["cls"] = batch["cls"].to(self.device)
92
93
  return batch
93
94
 
94
- def update_metrics(self, preds, batch):
95
+ def update_metrics(self, preds: torch.Tensor, batch: Dict[str, Any]) -> None:
95
96
  """
96
97
  Update running metrics with model predictions and batch targets.
97
98
 
@@ -127,23 +128,23 @@ class ClassificationValidator(BaseValidator):
127
128
  for normalize in True, False:
128
129
  self.confusion_matrix.plot(save_dir=self.save_dir, normalize=normalize, on_plot=self.on_plot)
129
130
  self.metrics.speed = self.speed
130
- self.metrics.confusion_matrix = self.confusion_matrix
131
131
  self.metrics.save_dir = self.save_dir
132
+ self.metrics.confusion_matrix = self.confusion_matrix
132
133
 
133
- def postprocess(self, preds):
134
+ def postprocess(self, preds: Union[torch.Tensor, List[torch.Tensor], Tuple[torch.Tensor]]) -> torch.Tensor:
134
135
  """Extract the primary prediction from model output if it's in a list or tuple format."""
135
136
  return preds[0] if isinstance(preds, (list, tuple)) else preds
136
137
 
137
- def get_stats(self):
138
+ def get_stats(self) -> Dict[str, float]:
138
139
  """Calculate and return a dictionary of metrics by processing targets and predictions."""
139
140
  self.metrics.process(self.targets, self.pred)
140
141
  return self.metrics.results_dict
141
142
 
142
- def build_dataset(self, img_path):
143
+ def build_dataset(self, img_path: str) -> ClassificationDataset:
143
144
  """Create a ClassificationDataset instance for validation."""
144
145
  return ClassificationDataset(root=img_path, args=self.args, augment=False, prefix=self.args.split)
145
146
 
146
- def get_dataloader(self, dataset_path, batch_size):
147
+ def get_dataloader(self, dataset_path: Union[Path, str], batch_size: int) -> torch.utils.data.DataLoader:
147
148
  """
148
149
  Build and return a data loader for classification validation.
149
150
 
@@ -157,17 +158,17 @@ class ClassificationValidator(BaseValidator):
157
158
  dataset = self.build_dataset(dataset_path)
158
159
  return build_dataloader(dataset, batch_size, self.args.workers, rank=-1)
159
160
 
160
- def print_results(self):
161
+ def print_results(self) -> None:
161
162
  """Print evaluation metrics for the classification model."""
162
163
  pf = "%22s" + "%11.3g" * len(self.metrics.keys) # print format
163
164
  LOGGER.info(pf % ("all", self.metrics.top1, self.metrics.top5))
164
165
 
165
- def plot_val_samples(self, batch, ni):
166
+ def plot_val_samples(self, batch: Dict[str, Any], ni: int) -> None:
166
167
  """
167
168
  Plot validation image samples with their ground truth labels.
168
169
 
169
170
  Args:
170
- batch (dict): Dictionary containing batch data with 'img' (images) and 'cls' (class labels).
171
+ batch (Dict[str, Any]): Dictionary containing batch data with 'img' (images) and 'cls' (class labels).
171
172
  ni (int): Batch index used for naming the output file.
172
173
 
173
174
  Examples:
@@ -175,21 +176,20 @@ class ClassificationValidator(BaseValidator):
175
176
  >>> batch = {"img": torch.rand(16, 3, 224, 224), "cls": torch.randint(0, 10, (16,))}
176
177
  >>> validator.plot_val_samples(batch, 0)
177
178
  """
179
+ batch["batch_idx"] = torch.arange(len(batch["img"])) # add batch index for plotting
178
180
  plot_images(
179
- images=batch["img"],
180
- batch_idx=torch.arange(len(batch["img"])),
181
- cls=batch["cls"].view(-1), # warning: use .view(), not .squeeze() for Classify models
181
+ labels=batch,
182
182
  fname=self.save_dir / f"val_batch{ni}_labels.jpg",
183
183
  names=self.names,
184
184
  on_plot=self.on_plot,
185
185
  )
186
186
 
187
- def plot_predictions(self, batch, preds, ni):
187
+ def plot_predictions(self, batch: Dict[str, Any], preds: torch.Tensor, ni: int) -> None:
188
188
  """
189
189
  Plot images with their predicted class labels and save the visualization.
190
190
 
191
191
  Args:
192
- batch (dict): Batch data containing images and other information.
192
+ batch (Dict[str, Any]): Batch data containing images and other information.
193
193
  preds (torch.Tensor): Model predictions with shape (batch_size, num_classes).
194
194
  ni (int): Batch index used for naming the output file.
195
195
 
@@ -199,10 +199,13 @@ class ClassificationValidator(BaseValidator):
199
199
  >>> preds = torch.rand(16, 10) # 16 images, 10 classes
200
200
  >>> validator.plot_predictions(batch, preds, 0)
201
201
  """
202
- plot_images(
203
- batch["img"],
202
+ batched_preds = dict(
203
+ img=batch["img"],
204
204
  batch_idx=torch.arange(len(batch["img"])),
205
205
  cls=torch.argmax(preds, dim=1),
206
+ )
207
+ plot_images(
208
+ batched_preds,
206
209
  fname=self.save_dir / f"val_batch{ni}_pred.jpg",
207
210
  names=self.names,
208
211
  on_plot=self.on_plot,
@@ -3,7 +3,7 @@
3
3
  import math
4
4
  import random
5
5
  from copy import copy
6
- from typing import Dict, List, Optional
6
+ from typing import Any, Dict, List, Optional
7
7
 
8
8
  import numpy as np
9
9
  import torch.nn as nn
@@ -178,19 +178,16 @@ class DetectionTrainer(BaseTrainer):
178
178
  "Size",
179
179
  )
180
180
 
181
- def plot_training_samples(self, batch: Dict, ni: int):
181
+ def plot_training_samples(self, batch: Dict[str, Any], ni: int) -> None:
182
182
  """
183
183
  Plot training samples with their annotations.
184
184
 
185
185
  Args:
186
- batch (Dict): Dictionary containing batch data.
186
+ batch (Dict[str, Any]): Dictionary containing batch data.
187
187
  ni (int): Number of iterations.
188
188
  """
189
189
  plot_images(
190
- images=batch["img"],
191
- batch_idx=batch["batch_idx"],
192
- cls=batch["cls"].squeeze(-1),
193
- bboxes=batch["bboxes"],
190
+ labels=batch,
194
191
  paths=batch["im_file"],
195
192
  fname=self.save_dir / f"train_batch{ni}.jpg",
196
193
  on_plot=self.on_plot,