ultralytics 8.3.160__py3-none-any.whl → 8.3.162__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 (67) hide show
  1. tests/conftest.py +2 -2
  2. tests/test_python.py +4 -3
  3. ultralytics/__init__.py +1 -1
  4. ultralytics/cfg/datasets/Argoverse.yaml +1 -1
  5. ultralytics/cfg/datasets/DOTAv1.5.yaml +1 -1
  6. ultralytics/cfg/datasets/DOTAv1.yaml +1 -1
  7. ultralytics/cfg/datasets/GlobalWheat2020.yaml +1 -1
  8. ultralytics/cfg/datasets/HomeObjects-3K.yaml +1 -1
  9. ultralytics/cfg/datasets/ImageNet.yaml +1 -1
  10. ultralytics/cfg/datasets/Objects365.yaml +1 -1
  11. ultralytics/cfg/datasets/SKU-110K.yaml +1 -1
  12. ultralytics/cfg/datasets/VOC.yaml +1 -1
  13. ultralytics/cfg/datasets/VisDrone.yaml +6 -3
  14. ultralytics/cfg/datasets/african-wildlife.yaml +1 -1
  15. ultralytics/cfg/datasets/brain-tumor.yaml +1 -1
  16. ultralytics/cfg/datasets/carparts-seg.yaml +1 -1
  17. ultralytics/cfg/datasets/coco-pose.yaml +1 -1
  18. ultralytics/cfg/datasets/coco.yaml +1 -1
  19. ultralytics/cfg/datasets/coco128-seg.yaml +1 -1
  20. ultralytics/cfg/datasets/coco128.yaml +1 -1
  21. ultralytics/cfg/datasets/coco8-grayscale.yaml +1 -1
  22. ultralytics/cfg/datasets/coco8-multispectral.yaml +1 -1
  23. ultralytics/cfg/datasets/coco8-pose.yaml +1 -1
  24. ultralytics/cfg/datasets/coco8-seg.yaml +1 -1
  25. ultralytics/cfg/datasets/coco8.yaml +1 -1
  26. ultralytics/cfg/datasets/crack-seg.yaml +1 -1
  27. ultralytics/cfg/datasets/dog-pose.yaml +1 -1
  28. ultralytics/cfg/datasets/dota8-multispectral.yaml +1 -1
  29. ultralytics/cfg/datasets/dota8.yaml +1 -1
  30. ultralytics/cfg/datasets/hand-keypoints.yaml +1 -1
  31. ultralytics/cfg/datasets/lvis.yaml +1 -1
  32. ultralytics/cfg/datasets/medical-pills.yaml +1 -1
  33. ultralytics/cfg/datasets/open-images-v7.yaml +1 -1
  34. ultralytics/cfg/datasets/package-seg.yaml +1 -1
  35. ultralytics/cfg/datasets/signature.yaml +1 -1
  36. ultralytics/cfg/datasets/tiger-pose.yaml +1 -1
  37. ultralytics/cfg/datasets/xView.yaml +1 -1
  38. ultralytics/data/augment.py +2 -0
  39. ultralytics/data/converter.py +5 -7
  40. ultralytics/data/dataset.py +1 -1
  41. ultralytics/data/split.py +1 -1
  42. ultralytics/data/split_dota.py +1 -1
  43. ultralytics/engine/exporter.py +15 -5
  44. ultralytics/engine/results.py +1 -1
  45. ultralytics/engine/tuner.py +2 -2
  46. ultralytics/models/nas/model.py +2 -1
  47. ultralytics/models/sam/modules/tiny_encoder.py +1 -1
  48. ultralytics/models/yolo/detect/val.py +1 -1
  49. ultralytics/models/yolo/world/train.py +1 -1
  50. ultralytics/models/yolo/world/train_world.py +17 -9
  51. ultralytics/models/yolo/yoloe/train.py +1 -1
  52. ultralytics/nn/autobackend.py +7 -1
  53. ultralytics/nn/tasks.py +4 -3
  54. ultralytics/solutions/similarity_search.py +11 -12
  55. ultralytics/solutions/solutions.py +53 -54
  56. ultralytics/utils/__init__.py +1 -2
  57. ultralytics/utils/checks.py +21 -0
  58. ultralytics/utils/metrics.py +10 -9
  59. ultralytics/utils/patches.py +1 -2
  60. ultralytics/utils/plotting.py +2 -2
  61. ultralytics/utils/torch_utils.py +2 -1
  62. {ultralytics-8.3.160.dist-info → ultralytics-8.3.162.dist-info}/METADATA +9 -1
  63. {ultralytics-8.3.160.dist-info → ultralytics-8.3.162.dist-info}/RECORD +67 -67
  64. {ultralytics-8.3.160.dist-info → ultralytics-8.3.162.dist-info}/WHEEL +0 -0
  65. {ultralytics-8.3.160.dist-info → ultralytics-8.3.162.dist-info}/entry_points.txt +0 -0
  66. {ultralytics-8.3.160.dist-info → ultralytics-8.3.162.dist-info}/licenses/LICENSE +0 -0
  67. {ultralytics-8.3.160.dist-info → ultralytics-8.3.162.dist-info}/top_level.txt +0 -0
@@ -71,7 +71,7 @@ class DetectionValidator(BaseValidator):
71
71
  """
72
72
  batch["img"] = batch["img"].to(self.device, non_blocking=True)
73
73
  batch["img"] = (batch["img"].half() if self.args.half else batch["img"].float()) / 255
74
- for k in ["batch_idx", "cls", "bboxes"]:
74
+ for k in {"batch_idx", "cls", "bboxes"}:
75
75
  batch[k] = batch[k].to(self.device)
76
76
 
77
77
  return batch
@@ -153,7 +153,7 @@ class WorldTrainer(DetectionTrainer):
153
153
  cache_path = cache_dir / f"text_embeddings_{model.replace(':', '_').replace('/', '_')}.pt"
154
154
  if cache_path.exists():
155
155
  LOGGER.info(f"Reading existed cache from '{cache_path}'")
156
- txt_map = torch.load(cache_path)
156
+ txt_map = torch.load(cache_path, map_location=self.device)
157
157
  if sorted(txt_map.keys()) == sorted(texts):
158
158
  return txt_map
159
159
  LOGGER.info(f"Caching text embeddings to '{cache_path}'")
@@ -1,9 +1,11 @@
1
1
  # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
2
 
3
+ from pathlib import Path
4
+
3
5
  from ultralytics.data import YOLOConcatDataset, build_grounding, build_yolo_dataset
4
6
  from ultralytics.data.utils import check_det_dataset
5
7
  from ultralytics.models.yolo.world import WorldTrainer
6
- from ultralytics.utils import DEFAULT_CFG, LOGGER
8
+ from ultralytics.utils import DATASETS_DIR, DEFAULT_CFG, LOGGER
7
9
  from ultralytics.utils.torch_utils import de_parallel
8
10
 
9
11
 
@@ -35,12 +37,12 @@ class WorldTrainerFromScratch(WorldTrainer):
35
37
  ... yolo_data=["Objects365.yaml"],
36
38
  ... grounding_data=[
37
39
  ... dict(
38
- ... img_path="../datasets/flickr30k/images",
39
- ... json_file="../datasets/flickr30k/final_flickr_separateGT_train.json",
40
+ ... img_path="flickr30k/images",
41
+ ... json_file="flickr30k/final_flickr_separateGT_train.json",
40
42
  ... ),
41
43
  ... dict(
42
- ... img_path="../datasets/GQA/images",
43
- ... json_file="../datasets/GQA/final_mixed_train_no_coco.json",
44
+ ... img_path="GQA/images",
45
+ ... json_file="GQA/final_mixed_train_no_coco.json",
44
46
  ... ),
45
47
  ... ],
46
48
  ... ),
@@ -70,8 +72,8 @@ class WorldTrainerFromScratch(WorldTrainer):
70
72
  ... yolo_data=["Objects365.yaml"],
71
73
  ... grounding_data=[
72
74
  ... dict(
73
- ... img_path="../datasets/flickr30k/images",
74
- ... json_file="../datasets/flickr30k/final_flickr_separateGT_train.json",
75
+ ... img_path="flickr30k/images",
76
+ ... json_file="flickr30k/final_flickr_separateGT_train.json",
75
77
  ... ),
76
78
  ... ],
77
79
  ... ),
@@ -136,7 +138,7 @@ class WorldTrainerFromScratch(WorldTrainer):
136
138
  if d.get("minival") is None: # for lvis dataset
137
139
  continue
138
140
  d["minival"] = str(d["path"] / d["minival"])
139
- for s in ["train", "val"]:
141
+ for s in {"train", "val"}:
140
142
  final_data[s] = [d["train" if s == "train" else val_split] for d in data[s]]
141
143
  # save grounding data if there's one
142
144
  grounding_data = data_yaml[s].get("grounding_data")
@@ -145,8 +147,14 @@ class WorldTrainerFromScratch(WorldTrainer):
145
147
  grounding_data = grounding_data if isinstance(grounding_data, list) else [grounding_data]
146
148
  for g in grounding_data:
147
149
  assert isinstance(g, dict), f"Grounding data should be provided in dict format, but got {type(g)}"
150
+ for k in {"img_path", "json_file"}:
151
+ path = Path(g[k])
152
+ if not path.exists() and not path.is_absolute():
153
+ g[k] = str((DATASETS_DIR / g[k]).resolve()) # path relative to DATASETS_DIR
148
154
  final_data[s] += grounding_data
149
- data["val"] = data["val"][0] # assign the first val dataset as currently only one validation set is supported
155
+ # assign the first val dataset as currently only one validation set is supported
156
+ data["val"] = data["val"][0]
157
+ final_data["val"] = final_data["val"][0]
150
158
  # NOTE: to make training work properly, set `nc` and `names`
151
159
  final_data["nc"] = data["val"]["nc"]
152
160
  final_data["names"] = data["val"]["names"]
@@ -217,7 +217,7 @@ class YOLOETrainerFromScratch(YOLOETrainer, WorldTrainerFromScratch):
217
217
  cache_path = cache_dir / f"text_embeddings_{model.replace(':', '_').replace('/', '_')}.pt"
218
218
  if cache_path.exists():
219
219
  LOGGER.info(f"Reading existed cache from '{cache_path}'")
220
- txt_map = torch.load(cache_path)
220
+ txt_map = torch.load(cache_path, map_location=self.device)
221
221
  if sorted(txt_map.keys()) == sorted(texts):
222
222
  return txt_map
223
223
  LOGGER.info(f"Caching text embeddings to '{cache_path}'")
@@ -487,7 +487,13 @@ class AutoBackend(nn.Module):
487
487
  # PaddlePaddle
488
488
  elif paddle:
489
489
  LOGGER.info(f"Loading {w} for PaddlePaddle inference...")
490
- check_requirements("paddlepaddle-gpu" if cuda else "paddlepaddle>=3.0.0")
490
+ check_requirements(
491
+ "paddlepaddle-gpu"
492
+ if torch.cuda.is_available()
493
+ else "paddlepaddle==3.0.0" # pin 3.0.0 for ARM64
494
+ if ARM64
495
+ else "paddlepaddle>=3.0.0"
496
+ )
491
497
  import paddle.inference as pdi # noqa
492
498
 
493
499
  w = Path(w)
ultralytics/nn/tasks.py CHANGED
@@ -80,6 +80,7 @@ from ultralytics.utils.loss import (
80
80
  v8SegmentationLoss,
81
81
  )
82
82
  from ultralytics.utils.ops import make_divisible
83
+ from ultralytics.utils.patches import torch_load
83
84
  from ultralytics.utils.plotting import feature_visualization
84
85
  from ultralytics.utils.torch_utils import (
85
86
  fuse_conv_and_bn,
@@ -1441,9 +1442,9 @@ def torch_safe_load(weight, safe_only=False):
1441
1442
  safe_pickle.Unpickler = SafeUnpickler
1442
1443
  safe_pickle.load = lambda file_obj: SafeUnpickler(file_obj).load()
1443
1444
  with open(file, "rb") as f:
1444
- ckpt = torch.load(f, pickle_module=safe_pickle)
1445
+ ckpt = torch_load(f, pickle_module=safe_pickle)
1445
1446
  else:
1446
- ckpt = torch.load(file, map_location="cpu")
1447
+ ckpt = torch_load(file, map_location="cpu")
1447
1448
 
1448
1449
  except ModuleNotFoundError as e: # e.name is missing module name
1449
1450
  if e.name == "models":
@@ -1469,7 +1470,7 @@ def torch_safe_load(weight, safe_only=False):
1469
1470
  f"run a command with an official Ultralytics model, i.e. 'yolo predict model=yolo11n.pt'"
1470
1471
  )
1471
1472
  check_requirements(e.name) # install missing module
1472
- ckpt = torch.load(file, map_location="cpu")
1473
+ ckpt = torch_load(file, map_location="cpu")
1473
1474
 
1474
1475
  if not isinstance(ckpt, dict):
1475
1476
  # File is likely a YOLO instance saved with i.e. torch.save(model, "saved_model.pt")
@@ -9,14 +9,14 @@ from PIL import Image
9
9
 
10
10
  from ultralytics.data.utils import IMG_FORMATS
11
11
  from ultralytics.nn.text_model import build_text_model
12
- from ultralytics.solutions.solutions import BaseSolution
12
+ from ultralytics.utils import LOGGER
13
13
  from ultralytics.utils.checks import check_requirements
14
14
  from ultralytics.utils.torch_utils import select_device
15
15
 
16
16
  os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE" # Avoid OpenMP conflict on some systems
17
17
 
18
18
 
19
- class VisualAISearch(BaseSolution):
19
+ class VisualAISearch:
20
20
  """
21
21
  A semantic image search system that leverages OpenCLIP for generating high-quality image and text embeddings and
22
22
  FAISS for fast similarity-based retrieval.
@@ -48,19 +48,18 @@ class VisualAISearch(BaseSolution):
48
48
 
49
49
  def __init__(self, **kwargs: Any) -> None:
50
50
  """Initialize the VisualAISearch class with FAISS index and CLIP model."""
51
- super().__init__(**kwargs)
52
51
  check_requirements("faiss-cpu")
53
52
 
54
53
  self.faiss = __import__("faiss")
55
54
  self.faiss_index = "faiss.index"
56
55
  self.data_path_npy = "paths.npy"
57
- self.data_dir = Path(self.CFG["data"])
58
- self.device = select_device(self.CFG["device"])
56
+ self.data_dir = Path(kwargs.get("data", "images"))
57
+ self.device = select_device(kwargs.get("device", "cpu"))
59
58
 
60
59
  if not self.data_dir.exists():
61
60
  from ultralytics.utils import ASSETS_URL
62
61
 
63
- self.LOGGER.warning(f"{self.data_dir} not found. Downloading images.zip from {ASSETS_URL}/images.zip")
62
+ LOGGER.warning(f"{self.data_dir} not found. Downloading images.zip from {ASSETS_URL}/images.zip")
64
63
  from ultralytics.utils.downloads import safe_download
65
64
 
66
65
  safe_download(url=f"{ASSETS_URL}/images.zip", unzip=True, retry=3)
@@ -91,13 +90,13 @@ class VisualAISearch(BaseSolution):
91
90
  """
92
91
  # Check if the FAISS index and corresponding image paths already exist
93
92
  if Path(self.faiss_index).exists() and Path(self.data_path_npy).exists():
94
- self.LOGGER.info("Loading existing FAISS index...")
93
+ LOGGER.info("Loading existing FAISS index...")
95
94
  self.index = self.faiss.read_index(self.faiss_index) # Load the FAISS index from disk
96
95
  self.image_paths = np.load(self.data_path_npy) # Load the saved image path list
97
96
  return # Exit the function as the index is successfully loaded
98
97
 
99
98
  # If the index doesn't exist, start building it from scratch
100
- self.LOGGER.info("Building FAISS index from images...")
99
+ LOGGER.info("Building FAISS index from images...")
101
100
  vectors = [] # List to store feature vectors of images
102
101
 
103
102
  # Iterate over all image files in the data directory
@@ -110,7 +109,7 @@ class VisualAISearch(BaseSolution):
110
109
  vectors.append(self.extract_image_feature(file))
111
110
  self.image_paths.append(file.name) # Store the corresponding image name
112
111
  except Exception as e:
113
- self.LOGGER.warning(f"Skipping {file.name}: {e}")
112
+ LOGGER.warning(f"Skipping {file.name}: {e}")
114
113
 
115
114
  # If no vectors were successfully created, raise an error
116
115
  if not vectors:
@@ -124,7 +123,7 @@ class VisualAISearch(BaseSolution):
124
123
  self.faiss.write_index(self.index, self.faiss_index) # Save the newly built FAISS index to disk
125
124
  np.save(self.data_path_npy, np.array(self.image_paths)) # Save the list of image paths to disk
126
125
 
127
- self.LOGGER.info(f"Indexed {len(self.image_paths)} images.")
126
+ LOGGER.info(f"Indexed {len(self.image_paths)} images.")
128
127
 
129
128
  def search(self, query: str, k: int = 30, similarity_thresh: float = 0.1) -> List[str]:
130
129
  """
@@ -152,9 +151,9 @@ class VisualAISearch(BaseSolution):
152
151
  ]
153
152
  results.sort(key=lambda x: x[1], reverse=True)
154
153
 
155
- self.LOGGER.info("\nRanked Results:")
154
+ LOGGER.info("\nRanked Results:")
156
155
  for name, score in results:
157
- self.LOGGER.info(f" - {name} | Similarity: {score:.4f}")
156
+ LOGGER.info(f" - {name} | Similarity: {score:.4f}")
158
157
 
159
158
  return [r[0] for r in results]
160
159
 
@@ -81,60 +81,59 @@ class BaseSolution:
81
81
  self.CFG = vars(SolutionConfig().update(**kwargs))
82
82
  self.LOGGER = LOGGER # Store logger object to be used in multiple solution classes
83
83
 
84
- if self.__class__.__name__ != "VisualAISearch":
85
- check_requirements("shapely>=2.0.0")
86
- from shapely.geometry import LineString, Point, Polygon
87
- from shapely.prepared import prep
88
-
89
- self.LineString = LineString
90
- self.Polygon = Polygon
91
- self.Point = Point
92
- self.prep = prep
93
- self.annotator = None # Initialize annotator
94
- self.tracks = None
95
- self.track_data = None
96
- self.boxes = []
97
- self.clss = []
98
- self.track_ids = []
99
- self.track_line = None
100
- self.masks = None
101
- self.r_s = None
102
- self.frame_no = -1 # Only for logging
103
-
104
- self.LOGGER.info(f"Ultralytics Solutions: ✅ {self.CFG}")
105
- self.region = self.CFG["region"] # Store region data for other classes usage
106
- self.line_width = self.CFG["line_width"]
107
-
108
- # Load Model and store additional information (classes, show_conf, show_label)
109
- if self.CFG["model"] is None:
110
- self.CFG["model"] = "yolo11n.pt"
111
- self.model = YOLO(self.CFG["model"])
112
- self.names = self.model.names
113
- self.classes = self.CFG["classes"]
114
- self.show_conf = self.CFG["show_conf"]
115
- self.show_labels = self.CFG["show_labels"]
116
- self.device = self.CFG["device"]
117
-
118
- self.track_add_args = { # Tracker additional arguments for advance configuration
119
- k: self.CFG[k] for k in ["iou", "conf", "device", "max_det", "half", "tracker"]
120
- } # verbose must be passed to track method; setting it False in YOLO still logs the track information.
121
-
122
- if is_cli and self.CFG["source"] is None:
123
- d_s = "solutions_ci_demo.mp4" if "-pose" not in self.CFG["model"] else "solution_ci_pose_demo.mp4"
124
- self.LOGGER.warning(f"source not provided. using default source {ASSETS_URL}/{d_s}")
125
- from ultralytics.utils.downloads import safe_download
126
-
127
- safe_download(f"{ASSETS_URL}/{d_s}") # download source from ultralytics assets
128
- self.CFG["source"] = d_s # set default source
129
-
130
- # Initialize environment and region setup
131
- self.env_check = check_imshow(warn=True)
132
- self.track_history = defaultdict(list)
133
-
134
- self.profilers = (
135
- ops.Profile(device=self.device), # track
136
- ops.Profile(device=self.device), # solution
137
- )
84
+ check_requirements("shapely>=2.0.0")
85
+ from shapely.geometry import LineString, Point, Polygon
86
+ from shapely.prepared import prep
87
+
88
+ self.LineString = LineString
89
+ self.Polygon = Polygon
90
+ self.Point = Point
91
+ self.prep = prep
92
+ self.annotator = None # Initialize annotator
93
+ self.tracks = None
94
+ self.track_data = None
95
+ self.boxes = []
96
+ self.clss = []
97
+ self.track_ids = []
98
+ self.track_line = None
99
+ self.masks = None
100
+ self.r_s = None
101
+ self.frame_no = -1 # Only for logging
102
+
103
+ self.LOGGER.info(f"Ultralytics Solutions: ✅ {self.CFG}")
104
+ self.region = self.CFG["region"] # Store region data for other classes usage
105
+ self.line_width = self.CFG["line_width"]
106
+
107
+ # Load Model and store additional information (classes, show_conf, show_label)
108
+ if self.CFG["model"] is None:
109
+ self.CFG["model"] = "yolo11n.pt"
110
+ self.model = YOLO(self.CFG["model"])
111
+ self.names = self.model.names
112
+ self.classes = self.CFG["classes"]
113
+ self.show_conf = self.CFG["show_conf"]
114
+ self.show_labels = self.CFG["show_labels"]
115
+ self.device = self.CFG["device"]
116
+
117
+ self.track_add_args = { # Tracker additional arguments for advance configuration
118
+ k: self.CFG[k] for k in {"iou", "conf", "device", "max_det", "half", "tracker"}
119
+ } # verbose must be passed to track method; setting it False in YOLO still logs the track information.
120
+
121
+ if is_cli and self.CFG["source"] is None:
122
+ d_s = "solutions_ci_demo.mp4" if "-pose" not in self.CFG["model"] else "solution_ci_pose_demo.mp4"
123
+ self.LOGGER.warning(f"source not provided. using default source {ASSETS_URL}/{d_s}")
124
+ from ultralytics.utils.downloads import safe_download
125
+
126
+ safe_download(f"{ASSETS_URL}/{d_s}") # download source from ultralytics assets
127
+ self.CFG["source"] = d_s # set default source
128
+
129
+ # Initialize environment and region setup
130
+ self.env_check = check_imshow(warn=True)
131
+ self.track_history = defaultdict(list)
132
+
133
+ self.profilers = (
134
+ ops.Profile(device=self.device), # track
135
+ ops.Profile(device=self.device), # solution
136
+ )
138
137
 
139
138
  def adjust_box_label(self, cls: int, conf: float, track_id: Optional[int] = None) -> Optional[str]:
140
139
  """
@@ -25,7 +25,7 @@ import torch
25
25
  import tqdm
26
26
 
27
27
  from ultralytics import __version__
28
- from ultralytics.utils.patches import imread, imshow, imwrite, torch_load, torch_save # for patches
28
+ from ultralytics.utils.patches import imread, imshow, imwrite, torch_save # for patches
29
29
 
30
30
  # PyTorch Multi-GPU DDP Constants
31
31
  RANK = int(os.getenv("RANK", -1))
@@ -1593,7 +1593,6 @@ TESTS_RUNNING = is_pytest_running() or is_github_action_running()
1593
1593
  set_sentry()
1594
1594
 
1595
1595
  # Apply monkey patches
1596
- torch.load = torch_load
1597
1596
  torch.save = torch_save
1598
1597
  if WINDOWS:
1599
1598
  # Apply cv2 patches for non-ASCII and non-UTF characters in image paths
@@ -896,6 +896,27 @@ def is_rockchip():
896
896
  return False
897
897
 
898
898
 
899
+ def is_intel():
900
+ """
901
+ Check if the system has Intel hardware (CPU or GPU).
902
+
903
+ Returns:
904
+ (bool): True if Intel hardware is detected, False otherwise.
905
+ """
906
+ from ultralytics.utils.torch_utils import get_cpu_info
907
+
908
+ # Check CPU
909
+ if "intel" in get_cpu_info().lower():
910
+ return True
911
+
912
+ # Check GPU via xpu-smi
913
+ try:
914
+ result = subprocess.run(["xpu-smi", "discovery"], capture_output=True, text=True, timeout=5)
915
+ return "intel" in result.stdout.lower()
916
+ except (subprocess.TimeoutExpired, FileNotFoundError, subprocess.SubprocessError):
917
+ return False
918
+
919
+
899
920
  def is_sudo_available() -> bool:
900
921
  """
901
922
  Check if the sudo command is available in the environment.
@@ -488,7 +488,7 @@ class ConfusionMatrix(DataExportMixin):
488
488
  if ticklabels != "auto":
489
489
  ax.set_xticklabels(ticklabels, fontsize=tick_fontsize, rotation=90, ha="center")
490
490
  ax.set_yticklabels(ticklabels, fontsize=tick_fontsize)
491
- for s in ["left", "right", "bottom", "top", "outline"]:
491
+ for s in {"left", "right", "bottom", "top", "outline"}:
492
492
  if s != "outline":
493
493
  ax.spines[s].set_visible(False) # Confusion matrix plot don't have outline
494
494
  cbar.ax.spines[s].set_visible(False)
@@ -1006,6 +1006,7 @@ class DetMetrics(SimpleClass, DataExportMixin):
1006
1006
  save_dir=save_dir,
1007
1007
  names=self.names,
1008
1008
  on_plot=on_plot,
1009
+ prefix="Box",
1009
1010
  )[2:]
1010
1011
  self.box.nc = len(self.names)
1011
1012
  self.box.update(results)
@@ -1061,7 +1062,7 @@ class DetMetrics(SimpleClass, DataExportMixin):
1061
1062
  """Return dictionary of computed performance metrics and statistics."""
1062
1063
  return self.box.curves_results
1063
1064
 
1064
- def summary(self, normalize: bool = True, decimals: int = 5) -> List[Dict[str, Union[str, float]]]:
1065
+ def summary(self, normalize: bool = True, decimals: int = 5) -> List[Dict[str, Any]]:
1065
1066
  """
1066
1067
  Generate a summarized representation of per-class detection metrics as a list of dictionaries. Includes shared
1067
1068
  scalar metrics (mAP, mAP50, mAP75) alongside precision, recall, and F1-score for each class.
@@ -1071,7 +1072,7 @@ class DetMetrics(SimpleClass, DataExportMixin):
1071
1072
  decimals (int): Number of decimal places to round the metrics values to.
1072
1073
 
1073
1074
  Returns:
1074
- (List[Dict[str, Union[str, float]]]): A list of dictionaries, each representing one class with corresponding metric values.
1075
+ (List[Dict[str, Any]]): A list of dictionaries, each representing one class with corresponding metric values.
1075
1076
 
1076
1077
  Examples:
1077
1078
  >>> results = model.val(data="coco8.yaml")
@@ -1135,7 +1136,7 @@ class SegmentMetrics(DetMetrics):
1135
1136
  Returns:
1136
1137
  (Dict[str, np.ndarray]): Dictionary containing concatenated statistics arrays.
1137
1138
  """
1138
- stats = DetMetrics.process(self, on_plot=on_plot) # process box stats
1139
+ stats = DetMetrics.process(self, save_dir, plot, on_plot=on_plot) # process box stats
1139
1140
  results_mask = ap_per_class(
1140
1141
  stats["tp_m"],
1141
1142
  stats["conf"],
@@ -1194,7 +1195,7 @@ class SegmentMetrics(DetMetrics):
1194
1195
  """Return dictionary of computed performance metrics and statistics."""
1195
1196
  return DetMetrics.curves_results.fget(self) + self.seg.curves_results
1196
1197
 
1197
- def summary(self, normalize: bool = True, decimals: int = 5) -> List[Dict[str, Union[str, float]]]:
1198
+ def summary(self, normalize: bool = True, decimals: int = 5) -> List[Dict[str, Any]]:
1198
1199
  """
1199
1200
  Generate a summarized representation of per-class segmentation metrics as a list of dictionaries. Includes both
1200
1201
  box and mask scalar metrics (mAP, mAP50, mAP75) alongside precision, recall, and F1-score for each class.
@@ -1204,7 +1205,7 @@ class SegmentMetrics(DetMetrics):
1204
1205
  decimals (int): Number of decimal places to round the metrics values to.
1205
1206
 
1206
1207
  Returns:
1207
- (List[Dict[str, Union[str, float]]]): A list of dictionaries, each representing one class with corresponding metric values.
1208
+ (List[Dict[str, Any]]): A list of dictionaries, each representing one class with corresponding metric values.
1208
1209
 
1209
1210
  Examples:
1210
1211
  >>> results = model.val(data="coco8-seg.yaml")
@@ -1270,7 +1271,7 @@ class PoseMetrics(DetMetrics):
1270
1271
  Returns:
1271
1272
  (Dict[str, np.ndarray]): Dictionary containing concatenated statistics arrays.
1272
1273
  """
1273
- stats = DetMetrics.process(self, on_plot=on_plot) # process box stats
1274
+ stats = DetMetrics.process(self, save_dir, plot, on_plot=on_plot) # process box stats
1274
1275
  results_pose = ap_per_class(
1275
1276
  stats["tp_p"],
1276
1277
  stats["conf"],
@@ -1333,7 +1334,7 @@ class PoseMetrics(DetMetrics):
1333
1334
  """Return dictionary of computed performance metrics and statistics."""
1334
1335
  return DetMetrics.curves_results.fget(self) + self.pose.curves_results
1335
1336
 
1336
- def summary(self, normalize: bool = True, decimals: int = 5) -> List[Dict[str, Union[str, float]]]:
1337
+ def summary(self, normalize: bool = True, decimals: int = 5) -> List[Dict[str, Any]]:
1337
1338
  """
1338
1339
  Generate a summarized representation of per-class pose metrics as a list of dictionaries. Includes both box and
1339
1340
  pose scalar metrics (mAP, mAP50, mAP75) alongside precision, recall, and F1-score for each class.
@@ -1343,7 +1344,7 @@ class PoseMetrics(DetMetrics):
1343
1344
  decimals (int): Number of decimal places to round the metrics values to.
1344
1345
 
1345
1346
  Returns:
1346
- (List[Dict[str, Union[str, float]]]): A list of dictionaries, each representing one class with corresponding metric values.
1347
+ (List[Dict[str, Any]]): A list of dictionaries, each representing one class with corresponding metric values.
1347
1348
 
1348
1349
  Examples:
1349
1350
  >>> results = model.val(data="coco8-pose.yaml")
@@ -90,7 +90,6 @@ def imshow(winname: str, mat: np.ndarray) -> None:
90
90
 
91
91
 
92
92
  # PyTorch functions ----------------------------------------------------------------------------------------------------
93
- _torch_load = torch.load # copy to avoid recursion errors
94
93
  _torch_save = torch.save
95
94
 
96
95
 
@@ -116,7 +115,7 @@ def torch_load(*args, **kwargs):
116
115
  if TORCH_1_13 and "weights_only" not in kwargs:
117
116
  kwargs["weights_only"] = False
118
117
 
119
- return _torch_load(*args, **kwargs)
118
+ return torch.load(*args, **kwargs)
120
119
 
121
120
 
122
121
  def torch_save(*args, **kwargs):
@@ -610,8 +610,8 @@ def plot_labels(boxes, cls, names=(), save_dir=Path(""), on_plot=None):
610
610
  ax[3].hist2d(x["width"], x["height"], bins=50, cmap=subplot_3_4_color)
611
611
  ax[3].set_xlabel("width")
612
612
  ax[3].set_ylabel("height")
613
- for a in [0, 1, 2, 3]:
614
- for s in ["top", "right", "left", "bottom"]:
613
+ for a in {0, 1, 2, 3}:
614
+ for s in {"top", "right", "left", "bottom"}:
615
615
  ax[a].spines[s].set_visible(False)
616
616
 
617
617
  fname = save_dir / "labels.jpg"
@@ -30,6 +30,7 @@ from ultralytics.utils import (
30
30
  colorstr,
31
31
  )
32
32
  from ultralytics.utils.checks import check_version
33
+ from ultralytics.utils.patches import torch_load
33
34
 
34
35
  # Version checks (all default to version>=min_version)
35
36
  TORCH_1_9 = check_version(torch.__version__, "1.9.0")
@@ -724,7 +725,7 @@ def strip_optimizer(f: Union[str, Path] = "best.pt", s: str = "", updates: Dict[
724
725
  >>> strip_optimizer(f)
725
726
  """
726
727
  try:
727
- x = torch.load(f, map_location=torch.device("cpu"))
728
+ x = torch_load(f, map_location=torch.device("cpu"))
728
729
  assert isinstance(x, dict), "checkpoint is not a Python dictionary"
729
730
  assert "model" in x, "'model' missing from checkpoint"
730
731
  except Exception as e:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ultralytics
3
- Version: 8.3.160
3
+ Version: 8.3.162
4
4
  Summary: Ultralytics YOLO 🚀 for SOTA object detection, multi-object tracking, instance segmentation, pose estimation and image classification.
5
5
  Author-email: Glenn Jocher <glenn.jocher@ultralytics.com>, Jing Qiu <jing.qiu@ultralytics.com>
6
6
  Maintainer-email: Ultralytics <hello@ultralytics.com>
@@ -79,6 +79,14 @@ Requires-Dist: hub-sdk>=0.0.12; extra == "extra"
79
79
  Requires-Dist: ipython; extra == "extra"
80
80
  Requires-Dist: albumentations>=1.4.6; extra == "extra"
81
81
  Requires-Dist: faster-coco-eval>=1.6.7; extra == "extra"
82
+ Provides-Extra: typing
83
+ Requires-Dist: pandas-stubs; extra == "typing"
84
+ Requires-Dist: scipy-stubs; extra == "typing"
85
+ Requires-Dist: types-pillow; extra == "typing"
86
+ Requires-Dist: types-psutil; extra == "typing"
87
+ Requires-Dist: types-pyyaml; extra == "typing"
88
+ Requires-Dist: types-requests; extra == "typing"
89
+ Requires-Dist: types-shapely; extra == "typing"
82
90
  Dynamic: license-file
83
91
 
84
92
  <div align="center">