dgenerate-ultralytics-headless 8.3.195__py3-none-any.whl → 8.3.197__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 (37) hide show
  1. {dgenerate_ultralytics_headless-8.3.195.dist-info → dgenerate_ultralytics_headless-8.3.197.dist-info}/METADATA +1 -1
  2. {dgenerate_ultralytics_headless-8.3.195.dist-info → dgenerate_ultralytics_headless-8.3.197.dist-info}/RECORD +37 -36
  3. ultralytics/__init__.py +1 -1
  4. ultralytics/cfg/__init__.py +1 -0
  5. ultralytics/cfg/datasets/construction-ppe.yaml +32 -0
  6. ultralytics/cfg/default.yaml +1 -0
  7. ultralytics/data/augment.py +1 -1
  8. ultralytics/data/build.py +5 -1
  9. ultralytics/engine/exporter.py +20 -31
  10. ultralytics/engine/model.py +1 -2
  11. ultralytics/engine/predictor.py +3 -1
  12. ultralytics/engine/trainer.py +17 -8
  13. ultralytics/engine/validator.py +6 -2
  14. ultralytics/models/yolo/classify/train.py +1 -11
  15. ultralytics/models/yolo/detect/train.py +27 -6
  16. ultralytics/models/yolo/detect/val.py +6 -5
  17. ultralytics/models/yolo/obb/train.py +0 -9
  18. ultralytics/models/yolo/pose/train.py +0 -9
  19. ultralytics/models/yolo/pose/val.py +1 -1
  20. ultralytics/models/yolo/segment/train.py +0 -9
  21. ultralytics/models/yolo/segment/val.py +5 -5
  22. ultralytics/models/yolo/world/train.py +4 -4
  23. ultralytics/models/yolo/world/train_world.py +2 -2
  24. ultralytics/models/yolo/yoloe/train.py +3 -12
  25. ultralytics/models/yolo/yoloe/val.py +0 -7
  26. ultralytics/nn/tasks.py +4 -2
  27. ultralytics/utils/__init__.py +30 -19
  28. ultralytics/utils/callbacks/tensorboard.py +2 -2
  29. ultralytics/utils/checks.py +2 -0
  30. ultralytics/utils/loss.py +12 -7
  31. ultralytics/utils/nms.py +3 -1
  32. ultralytics/utils/plotting.py +1 -0
  33. ultralytics/utils/torch_utils.py +89 -9
  34. {dgenerate_ultralytics_headless-8.3.195.dist-info → dgenerate_ultralytics_headless-8.3.197.dist-info}/WHEEL +0 -0
  35. {dgenerate_ultralytics_headless-8.3.195.dist-info → dgenerate_ultralytics_headless-8.3.197.dist-info}/entry_points.txt +0 -0
  36. {dgenerate_ultralytics_headless-8.3.195.dist-info → dgenerate_ultralytics_headless-8.3.197.dist-info}/licenses/LICENSE +0 -0
  37. {dgenerate_ultralytics_headless-8.3.195.dist-info → dgenerate_ultralytics_headless-8.3.197.dist-info}/top_level.txt +0 -0
@@ -8,16 +8,17 @@ from copy import copy
8
8
  from typing import Any
9
9
 
10
10
  import numpy as np
11
+ import torch
11
12
  import torch.nn as nn
12
13
 
13
14
  from ultralytics.data import build_dataloader, build_yolo_dataset
14
15
  from ultralytics.engine.trainer import BaseTrainer
15
16
  from ultralytics.models import yolo
16
17
  from ultralytics.nn.tasks import DetectionModel
17
- from ultralytics.utils import LOGGER, RANK
18
+ from ultralytics.utils import DEFAULT_CFG, LOGGER, RANK
18
19
  from ultralytics.utils.patches import override_configs
19
20
  from ultralytics.utils.plotting import plot_images, plot_labels, plot_results
20
- from ultralytics.utils.torch_utils import de_parallel, torch_distributed_zero_first
21
+ from ultralytics.utils.torch_utils import torch_distributed_zero_first, unwrap_model
21
22
 
22
23
 
23
24
  class DetectionTrainer(BaseTrainer):
@@ -53,6 +54,17 @@ class DetectionTrainer(BaseTrainer):
53
54
  >>> trainer.train()
54
55
  """
55
56
 
57
+ def __init__(self, cfg=DEFAULT_CFG, overrides: dict[str, Any] | None = None, _callbacks=None):
58
+ """
59
+ Initialize a DetectionTrainer object for training YOLO object detection model training.
60
+
61
+ Args:
62
+ cfg (dict, optional): Default configuration dictionary containing training parameters.
63
+ overrides (dict, optional): Dictionary of parameter overrides for the default configuration.
64
+ _callbacks (list, optional): List of callback functions to be executed during training.
65
+ """
66
+ super().__init__(cfg, overrides, _callbacks)
67
+
56
68
  def build_dataset(self, img_path: str, mode: str = "train", batch: int | None = None):
57
69
  """
58
70
  Build YOLO Dataset for training or validation.
@@ -65,7 +77,7 @@ class DetectionTrainer(BaseTrainer):
65
77
  Returns:
66
78
  (Dataset): YOLO dataset object configured for the specified mode.
67
79
  """
68
- gs = max(int(de_parallel(self.model).stride.max() if self.model else 0), 32)
80
+ gs = max(int(unwrap_model(self.model).stride.max() if self.model else 0), 32)
69
81
  return build_yolo_dataset(self.args, img_path, batch, self.data, mode=mode, rect=mode == "val", stride=gs)
70
82
 
71
83
  def get_dataloader(self, dataset_path: str, batch_size: int = 16, rank: int = 0, mode: str = "train"):
@@ -88,8 +100,14 @@ class DetectionTrainer(BaseTrainer):
88
100
  if getattr(dataset, "rect", False) and shuffle:
89
101
  LOGGER.warning("'rect=True' is incompatible with DataLoader shuffle, setting shuffle=False")
90
102
  shuffle = False
91
- workers = self.args.workers if mode == "train" else self.args.workers * 2
92
- return build_dataloader(dataset, batch_size, workers, shuffle, rank) # return dataloader
103
+ return build_dataloader(
104
+ dataset,
105
+ batch=batch_size,
106
+ workers=self.args.workers if mode == "train" else self.args.workers * 2,
107
+ shuffle=shuffle,
108
+ rank=rank,
109
+ drop_last=self.args.compile and mode == "train",
110
+ )
93
111
 
94
112
  def preprocess_batch(self, batch: dict) -> dict:
95
113
  """
@@ -101,7 +119,10 @@ class DetectionTrainer(BaseTrainer):
101
119
  Returns:
102
120
  (dict): Preprocessed batch with normalized images.
103
121
  """
104
- batch["img"] = batch["img"].to(self.device, non_blocking=True).float() / 255
122
+ for k, v in batch.items():
123
+ if isinstance(v, torch.Tensor):
124
+ batch[k] = v.to(self.device, non_blocking=True)
125
+ batch["img"] = batch["img"].float() / 255
105
126
  if self.args.multi_scale:
106
127
  imgs = batch["img"]
107
128
  sz = (
@@ -71,11 +71,10 @@ class DetectionValidator(BaseValidator):
71
71
  Returns:
72
72
  (dict[str, Any]): Preprocessed batch.
73
73
  """
74
- batch["img"] = batch["img"].to(self.device, non_blocking=True)
74
+ for k, v in batch.items():
75
+ if isinstance(v, torch.Tensor):
76
+ batch[k] = v.to(self.device, non_blocking=True)
75
77
  batch["img"] = (batch["img"].half() if self.args.half else batch["img"].float()) / 255
76
- for k in {"batch_idx", "cls", "bboxes"}:
77
- batch[k] = batch[k].to(self.device, non_blocking=True)
78
-
79
78
  return batch
80
79
 
81
80
  def init_metrics(self, model: torch.nn.Module) -> None:
@@ -300,7 +299,9 @@ class DetectionValidator(BaseValidator):
300
299
  (torch.utils.data.DataLoader): Dataloader for validation.
301
300
  """
302
301
  dataset = self.build_dataset(dataset_path, batch=batch_size, mode="val")
303
- return build_dataloader(dataset, batch_size, self.args.workers, shuffle=False, rank=-1) # return dataloader
302
+ return build_dataloader(
303
+ dataset, batch_size, self.args.workers, shuffle=False, rank=-1, drop_last=self.args.compile
304
+ )
304
305
 
305
306
  def plot_val_samples(self, batch: dict[str, Any], ni: int) -> None:
306
307
  """
@@ -37,21 +37,12 @@ class OBBTrainer(yolo.detect.DetectionTrainer):
37
37
  """
38
38
  Initialize an OBBTrainer object for training Oriented Bounding Box (OBB) models.
39
39
 
40
- This trainer extends the DetectionTrainer class to specialize in training models that detect oriented
41
- bounding boxes. It automatically sets the task to 'obb' in the configuration.
42
-
43
40
  Args:
44
41
  cfg (dict, optional): Configuration dictionary for the trainer. Contains training parameters and
45
42
  model configuration.
46
43
  overrides (dict, optional): Dictionary of parameter overrides for the configuration. Any values here
47
44
  will take precedence over those in cfg.
48
45
  _callbacks (list[Any], optional): List of callback functions to be invoked during training.
49
-
50
- Examples:
51
- >>> from ultralytics.models.yolo.obb import OBBTrainer
52
- >>> args = dict(model="yolo11n-obb.pt", data="dota8.yaml", epochs=3)
53
- >>> trainer = OBBTrainer(overrides=args)
54
- >>> trainer.train()
55
46
  """
56
47
  if overrides is None:
57
48
  overrides = {}
@@ -44,9 +44,6 @@ class PoseTrainer(yolo.detect.DetectionTrainer):
44
44
  """
45
45
  Initialize a PoseTrainer object for training YOLO pose estimation models.
46
46
 
47
- This initializes a trainer specialized for pose estimation tasks, setting the task to 'pose' and
48
- handling specific configurations needed for keypoint detection models.
49
-
50
47
  Args:
51
48
  cfg (dict, optional): Default configuration dictionary containing training parameters.
52
49
  overrides (dict, optional): Dictionary of parameter overrides for the default configuration.
@@ -55,12 +52,6 @@ class PoseTrainer(yolo.detect.DetectionTrainer):
55
52
  Notes:
56
53
  This trainer will automatically set the task to 'pose' regardless of what is provided in overrides.
57
54
  A warning is issued when using Apple MPS device due to known bugs with pose models.
58
-
59
- Examples:
60
- >>> from ultralytics.models.yolo.pose import PoseTrainer
61
- >>> args = dict(model="yolo11n-pose.pt", data="coco8-pose.yaml", epochs=3)
62
- >>> trainer = PoseTrainer(overrides=args)
63
- >>> trainer.train()
64
55
  """
65
56
  if overrides is None:
66
57
  overrides = {}
@@ -86,7 +86,7 @@ class PoseValidator(DetectionValidator):
86
86
  def preprocess(self, batch: dict[str, Any]) -> dict[str, Any]:
87
87
  """Preprocess batch by converting keypoints data to float and moving it to the device."""
88
88
  batch = super().preprocess(batch)
89
- batch["keypoints"] = batch["keypoints"].to(self.device, non_blocking=True).float()
89
+ batch["keypoints"] = batch["keypoints"].float()
90
90
  return batch
91
91
 
92
92
  def get_desc(self) -> str:
@@ -32,19 +32,10 @@ class SegmentationTrainer(yolo.detect.DetectionTrainer):
32
32
  """
33
33
  Initialize a SegmentationTrainer object.
34
34
 
35
- This initializes a trainer for segmentation tasks, extending the detection trainer with segmentation-specific
36
- functionality. It sets the task to 'segment' and prepares the trainer for training segmentation models.
37
-
38
35
  Args:
39
36
  cfg (dict): Configuration dictionary with default training settings.
40
37
  overrides (dict, optional): Dictionary of parameter overrides for the default configuration.
41
38
  _callbacks (list, optional): List of callback functions to be executed during training.
42
-
43
- Examples:
44
- >>> from ultralytics.models.yolo.segment import SegmentationTrainer
45
- >>> args = dict(model="yolo11n-seg.pt", data="coco8-seg.yaml", epochs=3)
46
- >>> trainer = SegmentationTrainer(overrides=args)
47
- >>> trainer.train()
48
39
  """
49
40
  if overrides is None:
50
41
  overrides = {}
@@ -63,7 +63,7 @@ class SegmentationValidator(DetectionValidator):
63
63
  (dict[str, Any]): Preprocessed batch.
64
64
  """
65
65
  batch = super().preprocess(batch)
66
- batch["masks"] = batch["masks"].to(self.device, non_blocking=True).float()
66
+ batch["masks"] = batch["masks"].float()
67
67
  return batch
68
68
 
69
69
  def init_metrics(self, model: torch.nn.Module) -> None:
@@ -187,10 +187,10 @@ class SegmentationValidator(DetectionValidator):
187
187
  """
188
188
  for p in preds:
189
189
  masks = p["masks"]
190
- if masks.shape[0] > 50:
191
- LOGGER.warning("Limiting validation plots to first 50 items per image for speed...")
192
- p["masks"] = torch.as_tensor(masks[:50], dtype=torch.uint8).cpu()
193
- super().plot_predictions(batch, preds, ni, max_det=50) # plot bboxes
190
+ if masks.shape[0] > self.args.max_det:
191
+ LOGGER.warning(f"Limiting validation plots to 'max_det={self.args.max_det}' items.")
192
+ p["masks"] = torch.as_tensor(masks[: self.args.max_det], dtype=torch.uint8).cpu()
193
+ super().plot_predictions(batch, preds, ni, max_det=self.args.max_det) # plot bboxes
194
194
 
195
195
  def save_one_txt(self, predn: torch.Tensor, save_conf: bool, shape: tuple[int, int], file: Path) -> None:
196
196
  """
@@ -12,7 +12,7 @@ from ultralytics.data import build_yolo_dataset
12
12
  from ultralytics.models.yolo.detect import DetectionTrainer
13
13
  from ultralytics.nn.tasks import WorldModel
14
14
  from ultralytics.utils import DEFAULT_CFG, LOGGER, RANK
15
- from ultralytics.utils.torch_utils import de_parallel
15
+ from ultralytics.utils.torch_utils import unwrap_model
16
16
 
17
17
 
18
18
  def on_pretrain_routine_end(trainer) -> None:
@@ -20,7 +20,7 @@ def on_pretrain_routine_end(trainer) -> None:
20
20
  if RANK in {-1, 0}:
21
21
  # Set class names for evaluation
22
22
  names = [name.split("/", 1)[0] for name in list(trainer.test_loader.dataset.data["names"].values())]
23
- de_parallel(trainer.ema.ema).set_classes(names, cache_clip_model=False)
23
+ unwrap_model(trainer.ema.ema).set_classes(names, cache_clip_model=False)
24
24
 
25
25
 
26
26
  class WorldTrainer(DetectionTrainer):
@@ -105,7 +105,7 @@ class WorldTrainer(DetectionTrainer):
105
105
  Returns:
106
106
  (Any): YOLO dataset configured for training or validation.
107
107
  """
108
- gs = max(int(de_parallel(self.model).stride.max() if self.model else 0), 32)
108
+ gs = max(int(unwrap_model(self.model).stride.max() if self.model else 0), 32)
109
109
  dataset = build_yolo_dataset(
110
110
  self.args, img_path, batch, self.data, mode=mode, rect=mode == "val", stride=gs, multi_modal=mode == "train"
111
111
  )
@@ -160,7 +160,7 @@ class WorldTrainer(DetectionTrainer):
160
160
  return txt_map
161
161
  LOGGER.info(f"Caching text embeddings to '{cache_path}'")
162
162
  assert self.model is not None
163
- txt_feats = de_parallel(self.model).get_text_pe(texts, batch, cache_clip_model=False)
163
+ txt_feats = unwrap_model(self.model).get_text_pe(texts, batch, cache_clip_model=False)
164
164
  txt_map = dict(zip(texts, txt_feats.squeeze(0)))
165
165
  torch.save(txt_map, cache_path)
166
166
  return txt_map
@@ -6,7 +6,7 @@ from ultralytics.data import YOLOConcatDataset, build_grounding, build_yolo_data
6
6
  from ultralytics.data.utils import check_det_dataset
7
7
  from ultralytics.models.yolo.world import WorldTrainer
8
8
  from ultralytics.utils import DATASETS_DIR, DEFAULT_CFG, LOGGER
9
- from ultralytics.utils.torch_utils import de_parallel
9
+ from ultralytics.utils.torch_utils import unwrap_model
10
10
 
11
11
 
12
12
  class WorldTrainerFromScratch(WorldTrainer):
@@ -101,7 +101,7 @@ class WorldTrainerFromScratch(WorldTrainer):
101
101
  Returns:
102
102
  (YOLOConcatDataset | Dataset): The constructed dataset for training or validation.
103
103
  """
104
- gs = max(int(de_parallel(self.model).stride.max() if self.model else 0), 32)
104
+ gs = max(int(unwrap_model(self.model).stride.max() if self.model else 0), 32)
105
105
  if mode != "train":
106
106
  return build_yolo_dataset(self.args, img_path, batch, self.data, mode=mode, rect=False, stride=gs)
107
107
  datasets = [
@@ -13,7 +13,7 @@ from ultralytics.data.augment import LoadVisualPrompt
13
13
  from ultralytics.models.yolo.detect import DetectionTrainer, DetectionValidator
14
14
  from ultralytics.nn.tasks import YOLOEModel
15
15
  from ultralytics.utils import DEFAULT_CFG, LOGGER, RANK
16
- from ultralytics.utils.torch_utils import de_parallel
16
+ from ultralytics.utils.torch_utils import unwrap_model
17
17
 
18
18
  from ..world.train_world import WorldTrainerFromScratch
19
19
  from .val import YOLOEDetectValidator
@@ -39,9 +39,6 @@ class YOLOETrainer(DetectionTrainer):
39
39
  """
40
40
  Initialize the YOLOE Trainer with specified configurations.
41
41
 
42
- This method sets up the YOLOE trainer with the provided configuration and overrides, initializing
43
- the training environment, model, and callbacks for YOLOE object detection training.
44
-
45
42
  Args:
46
43
  cfg (dict): Configuration dictionary with default training settings from DEFAULT_CFG.
47
44
  overrides (dict, optional): Dictionary of parameter overrides for the default configuration.
@@ -102,7 +99,7 @@ class YOLOETrainer(DetectionTrainer):
102
99
  Returns:
103
100
  (Dataset): YOLO dataset configured for training or validation.
104
101
  """
105
- gs = max(int(de_parallel(self.model).stride.max() if self.model else 0), 32)
102
+ gs = max(int(unwrap_model(self.model).stride.max() if self.model else 0), 32)
106
103
  return build_yolo_dataset(
107
104
  self.args, img_path, batch, self.data, mode=mode, rect=mode == "val", stride=gs, multi_modal=mode == "train"
108
105
  )
@@ -223,7 +220,7 @@ class YOLOETrainerFromScratch(YOLOETrainer, WorldTrainerFromScratch):
223
220
  return txt_map
224
221
  LOGGER.info(f"Caching text embeddings to '{cache_path}'")
225
222
  assert self.model is not None
226
- txt_feats = de_parallel(self.model).get_text_pe(texts, batch, without_reprta=True, cache_clip_model=False)
223
+ txt_feats = unwrap_model(self.model).get_text_pe(texts, batch, without_reprta=True, cache_clip_model=False)
227
224
  txt_map = dict(zip(texts, txt_feats.squeeze(0)))
228
225
  torch.save(txt_map, cache_path)
229
226
  return txt_map
@@ -313,9 +310,3 @@ class YOLOEVPTrainer(YOLOETrainerFromScratch):
313
310
  d.transforms.append(LoadVisualPrompt())
314
311
  else:
315
312
  self.train_loader.dataset.transforms.append(LoadVisualPrompt())
316
-
317
- def preprocess_batch(self, batch):
318
- """Preprocess a batch of images for YOLOE training, moving visual prompts to the appropriate device."""
319
- batch = super().preprocess_batch(batch)
320
- batch["visuals"] = batch["visuals"].to(self.device, non_blocking=True)
321
- return batch
@@ -98,13 +98,6 @@ class YOLOEDetectValidator(DetectionValidator):
98
98
  visual_pe[cls_visual_num == 0] = 0
99
99
  return visual_pe.unsqueeze(0)
100
100
 
101
- def preprocess(self, batch: dict[str, Any]) -> dict[str, Any]:
102
- """Preprocess batch data, ensuring visuals are on the same device as images."""
103
- batch = super().preprocess(batch)
104
- if "visuals" in batch:
105
- batch["visuals"] = batch["visuals"].to(batch["img"].device, non_blocking=True)
106
- return batch
107
-
108
101
  def get_vpe_dataloader(self, data: dict[str, Any]) -> torch.utils.data.DataLoader:
109
102
  """
110
103
  Create a dataloader for LVIS training visual prompt samples.
ultralytics/nn/tasks.py CHANGED
@@ -334,7 +334,8 @@ class BaseModel(torch.nn.Module):
334
334
  if getattr(self, "criterion", None) is None:
335
335
  self.criterion = self.init_criterion()
336
336
 
337
- preds = self.forward(batch["img"]) if preds is None else preds
337
+ if preds is None:
338
+ preds = self.forward(batch["img"])
338
339
  return self.criterion(preds, batch)
339
340
 
340
341
  def init_criterion(self):
@@ -775,7 +776,8 @@ class RTDETRDetectionModel(DetectionModel):
775
776
  "gt_groups": gt_groups,
776
777
  }
777
778
 
778
- preds = self.predict(img, batch=targets) if preds is None else preds
779
+ if preds is None:
780
+ preds = self.predict(img, batch=targets)
779
781
  dec_bboxes, dec_scores, enc_bboxes, enc_scores, dn_meta = preds if self.training else preds[1]
780
782
  if dn_meta is None:
781
783
  dn_bboxes, dn_scores = None, None
@@ -857,7 +857,7 @@ def get_ubuntu_version():
857
857
 
858
858
  def get_user_config_dir(sub_dir="Ultralytics"):
859
859
  """
860
- Return the appropriate config directory based on the environment operating system.
860
+ Return a writable config dir, preferring YOLO_CONFIG_DIR and being OS-aware.
861
861
 
862
862
  Args:
863
863
  sub_dir (str): The name of the subdirectory to create.
@@ -865,27 +865,38 @@ def get_user_config_dir(sub_dir="Ultralytics"):
865
865
  Returns:
866
866
  (Path): The path to the user config directory.
867
867
  """
868
- if WINDOWS:
869
- path = Path.home() / "AppData" / "Roaming" / sub_dir
870
- elif MACOS: # macOS
871
- path = Path.home() / "Library" / "Application Support" / sub_dir
868
+ if env_dir := os.getenv("YOLO_CONFIG_DIR"):
869
+ p = Path(env_dir).expanduser() / sub_dir
872
870
  elif LINUX:
873
- path = Path.home() / ".config" / sub_dir
871
+ p = Path(os.getenv("XDG_CONFIG_HOME", Path.home() / ".config")) / sub_dir
872
+ elif WINDOWS:
873
+ p = Path.home() / "AppData" / "Roaming" / sub_dir
874
+ elif MACOS:
875
+ p = Path.home() / "Library" / "Application Support" / sub_dir
874
876
  else:
875
877
  raise ValueError(f"Unsupported operating system: {platform.system()}")
876
878
 
877
- # GCP and AWS lambda fix, only /tmp is writeable
878
- if not is_dir_writeable(path.parent):
879
- LOGGER.warning(
880
- f"user config directory '{path}' is not writeable, defaulting to '/tmp' or CWD. "
881
- "Alternatively you can define a YOLO_CONFIG_DIR environment variable for this path."
882
- )
883
- path = Path("/tmp") / sub_dir if is_dir_writeable("/tmp") else Path().cwd() / sub_dir
884
-
885
- # Create the subdirectory if it does not exist
886
- path.mkdir(parents=True, exist_ok=True)
879
+ if p.exists(): # already created trust it
880
+ return p
881
+ if is_dir_writeable(p.parent): # create if possible
882
+ p.mkdir(parents=True, exist_ok=True)
883
+ return p
884
+
885
+ # Fallbacks for Docker, GCP/AWS functions where only /tmp is writeable
886
+ for alt in [Path("/tmp") / sub_dir, Path.cwd() / sub_dir]:
887
+ if alt.exists():
888
+ return alt
889
+ if is_dir_writeable(alt.parent):
890
+ alt.mkdir(parents=True, exist_ok=True)
891
+ LOGGER.warning(
892
+ f"user config directory '{p}' is not writeable, using '{alt}'. Set YOLO_CONFIG_DIR to override."
893
+ )
894
+ return alt
887
895
 
888
- return path
896
+ # Last fallback → CWD
897
+ p = Path.cwd() / sub_dir
898
+ p.mkdir(parents=True, exist_ok=True)
899
+ return p
889
900
 
890
901
 
891
902
  # Define constants (required below)
@@ -899,7 +910,7 @@ IS_JUPYTER = is_jupyter()
899
910
  IS_PIP_PACKAGE = is_pip_package()
900
911
  IS_RASPBERRYPI = is_raspberrypi()
901
912
  GIT = GitRepo()
902
- USER_CONFIG_DIR = Path(os.getenv("YOLO_CONFIG_DIR") or get_user_config_dir()) # Ultralytics settings dir
913
+ USER_CONFIG_DIR = get_user_config_dir() # Ultralytics settings dir
903
914
  SETTINGS_FILE = USER_CONFIG_DIR / "settings.json"
904
915
 
905
916
 
@@ -1383,7 +1394,7 @@ class SettingsManager(JSONDict):
1383
1394
 
1384
1395
  def deprecation_warn(arg, new_arg=None):
1385
1396
  """Issue a deprecation warning when a deprecated argument is used, suggesting an updated argument."""
1386
- msg = f"'{arg}' is deprecated and will be removed in in the future."
1397
+ msg = f"'{arg}' is deprecated and will be removed in the future."
1387
1398
  if new_arg is not None:
1388
1399
  msg += f" Use '{new_arg}' instead."
1389
1400
  LOGGER.warning(msg)
@@ -70,14 +70,14 @@ def _log_tensorboard_graph(trainer) -> None:
70
70
  # Try simple method first (YOLO)
71
71
  try:
72
72
  trainer.model.eval() # place in .eval() mode to avoid BatchNorm statistics changes
73
- WRITER.add_graph(torch.jit.trace(torch_utils.de_parallel(trainer.model), im, strict=False), [])
73
+ WRITER.add_graph(torch.jit.trace(torch_utils.unwrap_model(trainer.model), im, strict=False), [])
74
74
  LOGGER.info(f"{PREFIX}model graph visualization added ✅")
75
75
  return
76
76
 
77
77
  except Exception:
78
78
  # Fallback to TorchScript export steps (RTDETR)
79
79
  try:
80
- model = deepcopy(torch_utils.de_parallel(trainer.model))
80
+ model = deepcopy(torch_utils.unwrap_model(trainer.model))
81
81
  model.eval()
82
82
  model = model.fuse(verbose=False)
83
83
  for m in model.modules():
@@ -452,6 +452,8 @@ def check_torchvision():
452
452
  to the compatibility table based on: https://github.com/pytorch/vision#installation.
453
453
  """
454
454
  compatibility_table = {
455
+ "2.9": ["0.24"],
456
+ "2.8": ["0.23"],
455
457
  "2.7": ["0.22"],
456
458
  "2.6": ["0.21"],
457
459
  "2.5": ["0.20"],
ultralytics/utils/loss.py CHANGED
@@ -260,7 +260,7 @@ class v8DetectionLoss:
260
260
 
261
261
  # Targets
262
262
  targets = torch.cat((batch["batch_idx"].view(-1, 1), batch["cls"].view(-1, 1), batch["bboxes"]), 1)
263
- targets = self.preprocess(targets.to(self.device), batch_size, scale_tensor=imgsz[[1, 0, 1, 0]])
263
+ targets = self.preprocess(targets, batch_size, scale_tensor=imgsz[[1, 0, 1, 0]])
264
264
  gt_labels, gt_bboxes = targets.split((1, 4), 2) # cls, xyxy
265
265
  mask_gt = gt_bboxes.sum(2, keepdim=True).gt_(0.0)
266
266
 
@@ -287,9 +287,14 @@ class v8DetectionLoss:
287
287
 
288
288
  # Bbox loss
289
289
  if fg_mask.sum():
290
- target_bboxes /= stride_tensor
291
290
  loss[0], loss[2] = self.bbox_loss(
292
- pred_distri, pred_bboxes, anchor_points, target_bboxes, target_scores, target_scores_sum, fg_mask
291
+ pred_distri,
292
+ pred_bboxes,
293
+ anchor_points,
294
+ target_bboxes / stride_tensor,
295
+ target_scores,
296
+ target_scores_sum,
297
+ fg_mask,
293
298
  )
294
299
 
295
300
  loss[0] *= self.hyp.box # box gain
@@ -329,7 +334,7 @@ class v8SegmentationLoss(v8DetectionLoss):
329
334
  try:
330
335
  batch_idx = batch["batch_idx"].view(-1, 1)
331
336
  targets = torch.cat((batch_idx, batch["cls"].view(-1, 1), batch["bboxes"]), 1)
332
- targets = self.preprocess(targets.to(self.device), batch_size, scale_tensor=imgsz[[1, 0, 1, 0]])
337
+ targets = self.preprocess(targets, batch_size, scale_tensor=imgsz[[1, 0, 1, 0]])
333
338
  gt_labels, gt_bboxes = targets.split((1, 4), 2) # cls, xyxy
334
339
  mask_gt = gt_bboxes.sum(2, keepdim=True).gt_(0.0)
335
340
  except RuntimeError as e:
@@ -388,7 +393,7 @@ class v8SegmentationLoss(v8DetectionLoss):
388
393
  loss[2] *= self.hyp.cls # cls gain
389
394
  loss[3] *= self.hyp.dfl # dfl gain
390
395
 
391
- return loss * batch_size, loss.detach() # loss(box, cls, dfl)
396
+ return loss * batch_size, loss.detach() # loss(box, seg, cls, dfl)
392
397
 
393
398
  @staticmethod
394
399
  def single_mask_loss(
@@ -516,7 +521,7 @@ class v8PoseLoss(v8DetectionLoss):
516
521
  batch_size = pred_scores.shape[0]
517
522
  batch_idx = batch["batch_idx"].view(-1, 1)
518
523
  targets = torch.cat((batch_idx, batch["cls"].view(-1, 1), batch["bboxes"]), 1)
519
- targets = self.preprocess(targets.to(self.device), batch_size, scale_tensor=imgsz[[1, 0, 1, 0]])
524
+ targets = self.preprocess(targets, batch_size, scale_tensor=imgsz[[1, 0, 1, 0]])
520
525
  gt_labels, gt_bboxes = targets.split((1, 4), 2) # cls, xyxy
521
526
  mask_gt = gt_bboxes.sum(2, keepdim=True).gt_(0.0)
522
527
 
@@ -704,7 +709,7 @@ class v8OBBLoss(v8DetectionLoss):
704
709
  targets = torch.cat((batch_idx, batch["cls"].view(-1, 1), batch["bboxes"].view(-1, 5)), 1)
705
710
  rw, rh = targets[:, 4] * imgsz[0].item(), targets[:, 5] * imgsz[1].item()
706
711
  targets = targets[(rw >= 2) & (rh >= 2)] # filter rboxes of tiny size to stabilize training
707
- targets = self.preprocess(targets.to(self.device), batch_size, scale_tensor=imgsz[[1, 0, 1, 0]])
712
+ targets = self.preprocess(targets, batch_size, scale_tensor=imgsz[[1, 0, 1, 0]])
708
713
  gt_labels, gt_bboxes = targets.split((1, 5), 2) # cls, xywhr
709
714
  mask_gt = gt_bboxes.sum(2, keepdim=True).gt_(0.0)
710
715
  except RuntimeError as e:
ultralytics/utils/nms.py CHANGED
@@ -192,6 +192,7 @@ class TorchNMS:
192
192
  iou_threshold: float,
193
193
  use_triu: bool = True,
194
194
  iou_func=box_iou,
195
+ exit_early: bool = True,
195
196
  ) -> torch.Tensor:
196
197
  """
197
198
  Fast-NMS implementation from https://arxiv.org/pdf/1904.02689 using upper triangular matrix operations.
@@ -202,6 +203,7 @@ class TorchNMS:
202
203
  iou_threshold (float): IoU threshold for suppression.
203
204
  use_triu (bool): Whether to use torch.triu operator for upper triangular matrix operations.
204
205
  iou_func (callable): Function to compute IoU between boxes.
206
+ exit_early (bool): Whether to exit early if there are no boxes.
205
207
 
206
208
  Returns:
207
209
  (torch.Tensor): Indices of boxes to keep after NMS.
@@ -212,7 +214,7 @@ class TorchNMS:
212
214
  >>> scores = torch.tensor([0.9, 0.8])
213
215
  >>> keep = TorchNMS.nms(boxes, scores, 0.5)
214
216
  """
215
- if boxes.numel() == 0:
217
+ if boxes.numel() == 0 and exit_early:
216
218
  return torch.empty((0,), dtype=torch.int64, device=boxes.device)
217
219
 
218
220
  sorted_idx = torch.argsort(scores, descending=True)
@@ -1004,6 +1004,7 @@ def plot_tune_results(csv_file: str = "tune_results.csv"):
1004
1004
  _save_one_file(csv_file.with_name("tune_fitness.png"))
1005
1005
 
1006
1006
 
1007
+ @plt_settings()
1007
1008
  def feature_visualization(x, module_type: str, stage: int, n: int = 32, save_dir: Path = Path("runs/detect/exp")):
1008
1009
  """
1009
1010
  Visualize feature maps of a given model module during inference.