ultralytics 8.2.97__py3-none-any.whl → 8.2.99__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.

Potentially problematic release.


This version of ultralytics might be problematic. Click here for more details.

tests/test_exports.py CHANGED
@@ -32,7 +32,6 @@ def test_export_onnx():
32
32
  YOLO(file)(SOURCE, imgsz=32) # exported model inference
33
33
 
34
34
 
35
- @pytest.mark.skipif(checks.IS_PYTHON_3_12, reason="OpenVINO not supported in Python 3.12")
36
35
  @pytest.mark.skipif(not TORCH_1_13, reason="OpenVINO requires torch>=1.13")
37
36
  def test_export_openvino():
38
37
  """Test YOLO exports to OpenVINO format for model inference compatibility."""
@@ -27,6 +27,7 @@ def test_mlflow():
27
27
  """Test training with MLflow tracking enabled (see https://mlflow.org/ for details)."""
28
28
  SETTINGS["mlflow"] = True
29
29
  YOLO("yolov8n-cls.yaml").train(data="imagenet10", imgsz=32, epochs=3, plots=False, device="cpu")
30
+ SETTINGS["mlflow"] = False
30
31
 
31
32
 
32
33
  @pytest.mark.skipif(True, reason="Test failing in scheduled CI https://github.com/ultralytics/ultralytics/pull/8868")
@@ -58,6 +59,7 @@ def test_mlflow_keep_run_active():
58
59
  YOLO("yolov8n-cls.yaml").train(data="imagenet10", imgsz=32, epochs=1, plots=False, device="cpu")
59
60
  status = mlflow.get_run(run_id=run_id).info.status
60
61
  assert status == "FINISHED", "MLflow run should be ended by default when MLFLOW_KEEP_RUN_ACTIVE is not set"
62
+ SETTINGS["mlflow"] = False
61
63
 
62
64
 
63
65
  @pytest.mark.skipif(not check_requirements("tritonclient", install=False), reason="tritonclient[all] not installed")
ultralytics/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # Ultralytics YOLO 🚀, AGPL-3.0 license
2
2
 
3
- __version__ = "8.2.97"
3
+ __version__ = "8.2.99"
4
4
 
5
5
 
6
6
  import os
@@ -19,7 +19,7 @@ from ultralytics.utils import (
19
19
  ROOT,
20
20
  RUNS_DIR,
21
21
  SETTINGS,
22
- SETTINGS_YAML,
22
+ SETTINGS_FILE,
23
23
  TESTS_RUNNING,
24
24
  IterableSimpleNamespace,
25
25
  __version__,
@@ -532,7 +532,7 @@ def handle_yolo_settings(args: List[str]) -> None:
532
532
  try:
533
533
  if any(args):
534
534
  if args[0] == "reset":
535
- SETTINGS_YAML.unlink() # delete the settings file
535
+ SETTINGS_FILE.unlink() # delete the settings file
536
536
  SETTINGS.reset() # create new settings
537
537
  LOGGER.info("Settings reset successfully") # inform the user that settings have been reset
538
538
  else: # save a new setting
@@ -540,8 +540,8 @@ def handle_yolo_settings(args: List[str]) -> None:
540
540
  check_dict_alignment(SETTINGS, new)
541
541
  SETTINGS.update(new)
542
542
 
543
- LOGGER.info(f"💡 Learn about settings at {url}")
544
- yaml_print(SETTINGS_YAML) # print the current settings
543
+ print(SETTINGS) # print the current settings
544
+ LOGGER.info(f"💡 Learn more about Ultralytics Settings at {url}")
545
545
  except Exception as e:
546
546
  LOGGER.warning(f"WARNING ⚠️ settings error: '{e}'. Please see {url} for help.")
547
547
 
ultralytics/data/utils.py CHANGED
@@ -22,7 +22,7 @@ from ultralytics.utils import (
22
22
  LOGGER,
23
23
  NUM_THREADS,
24
24
  ROOT,
25
- SETTINGS_YAML,
25
+ SETTINGS_FILE,
26
26
  TQDM,
27
27
  clean_url,
28
28
  colorstr,
@@ -324,7 +324,7 @@ def check_det_dataset(dataset, autodownload=True):
324
324
  if s and autodownload:
325
325
  LOGGER.warning(m)
326
326
  else:
327
- m += f"\nNote dataset download directory is '{DATASETS_DIR}'. You can update this in '{SETTINGS_YAML}'"
327
+ m += f"\nNote dataset download directory is '{DATASETS_DIR}'. You can update this in '{SETTINGS_FILE}'"
328
328
  raise FileNotFoundError(m)
329
329
  t = time.time()
330
330
  r = None # success
@@ -95,9 +95,7 @@ from ultralytics.utils.torch_utils import TORCH_1_13, get_latest_opset, select_d
95
95
 
96
96
 
97
97
  def export_formats():
98
- """YOLOv8 export formats."""
99
- import pandas # scope for faster 'import ultralytics'
100
-
98
+ """Ultralytics YOLO export formats."""
101
99
  x = [
102
100
  ["PyTorch", "-", ".pt", True, True],
103
101
  ["TorchScript", "torchscript", ".torchscript", True, True],
@@ -113,7 +111,7 @@ def export_formats():
113
111
  ["PaddlePaddle", "paddle", "_paddle_model", True, True],
114
112
  ["NCNN", "ncnn", "_ncnn_model", True, True],
115
113
  ]
116
- return pandas.DataFrame(x, columns=["Format", "Argument", "Suffix", "CPU", "GPU"])
114
+ return dict(zip(["Format", "Argument", "Suffix", "CPU", "GPU"], zip(*x)))
117
115
 
118
116
 
119
117
  def gd_outputs(gd):
@@ -79,7 +79,6 @@ def logout():
79
79
  ```
80
80
  """
81
81
  SETTINGS["api_key"] = ""
82
- SETTINGS.save()
83
82
  LOGGER.info(f"{PREFIX}logged out ✅. To log in again, use 'yolo hub login'.")
84
83
 
85
84
 
@@ -161,16 +161,6 @@ class HUBTrainingSession:
161
161
  HUBModelError: If the identifier format is not recognized.
162
162
  """
163
163
  api_key, model_id, filename = None, None, None
164
-
165
- # path = identifier.split(f"{HUB_WEB_ROOT}/models/")[-1]
166
- # parts = path.split("_")
167
- # if Path(path).suffix in {".pt", ".yaml"}:
168
- # filename = path
169
- # elif len(parts) == 2 and len(parts[0]) == 42 and len(parts[1]) == 20:
170
- # api_key, model_id = parts
171
- # elif len(path) == 20:
172
- # model_id = path
173
-
174
164
  if Path(identifier).suffix in {".pt", ".yaml"}:
175
165
  filename = identifier
176
166
  elif identifier.startswith(f"{HUB_WEB_ROOT}/models/"):
@@ -398,8 +398,8 @@ class AutoBackend(nn.Module):
398
398
  from ultralytics.engine.exporter import export_formats
399
399
 
400
400
  raise TypeError(
401
- f"model='{w}' is not a supported model format. "
402
- f"See https://docs.ultralytics.com/modes/predict for help.\n\n{export_formats()}"
401
+ f"model='{w}' is not a supported model format. Ultralytics supports: {export_formats()['Format']}\n"
402
+ f"See https://docs.ultralytics.com/modes/predict for help."
403
403
  )
404
404
 
405
405
  # Load external metadata YAML
@@ -653,7 +653,7 @@ class AutoBackend(nn.Module):
653
653
  """
654
654
  from ultralytics.engine.exporter import export_formats
655
655
 
656
- sf = list(export_formats().Suffix) # export suffixes
656
+ sf = export_formats()["Suffix"] # export suffixes
657
657
  if not is_url(p) and not isinstance(p, str):
658
658
  check_suffix(p, sf) # checks
659
659
  name = Path(p).name
@@ -3,6 +3,7 @@
3
3
  import contextlib
4
4
  import importlib.metadata
5
5
  import inspect
6
+ import json
6
7
  import logging.config
7
8
  import os
8
9
  import platform
@@ -14,6 +15,7 @@ import time
14
15
  import urllib
15
16
  import uuid
16
17
  from pathlib import Path
18
+ from threading import Lock
17
19
  from types import SimpleNamespace
18
20
  from typing import Union
19
21
 
@@ -800,7 +802,7 @@ IS_RASPBERRYPI = is_raspberrypi()
800
802
  GIT_DIR = get_git_dir()
801
803
  IS_GIT_DIR = is_git_dir()
802
804
  USER_CONFIG_DIR = Path(os.getenv("YOLO_CONFIG_DIR") or get_user_config_dir()) # Ultralytics settings dir
803
- SETTINGS_YAML = USER_CONFIG_DIR / "settings.yaml"
805
+ SETTINGS_FILE = USER_CONFIG_DIR / "settings.json"
804
806
 
805
807
 
806
808
  def colorstr(*input):
@@ -1038,21 +1040,121 @@ def set_sentry():
1038
1040
  sentry_sdk.set_user({"id": SETTINGS["uuid"]}) # SHA-256 anonymized UUID hash
1039
1041
 
1040
1042
 
1041
- class SettingsManager(dict):
1043
+ class JSONDict(dict):
1042
1044
  """
1043
- Manages Ultralytics settings stored in a YAML file.
1045
+ A dictionary-like class that provides JSON persistence for its contents.
1044
1046
 
1045
- Args:
1046
- file (str | Path): Path to the Ultralytics settings YAML file. Default is USER_CONFIG_DIR / 'settings.yaml'.
1047
- version (str): Settings version. In case of local version mismatch, new default settings will be saved.
1047
+ This class extends the built-in dictionary to automatically save its contents to a JSON file whenever they are
1048
+ modified. It ensures thread-safe operations using a lock.
1049
+
1050
+ Attributes:
1051
+ file_path (Path): The path to the JSON file used for persistence.
1052
+ lock (threading.Lock): A lock object to ensure thread-safe operations.
1053
+
1054
+ Methods:
1055
+ _load: Loads the data from the JSON file into the dictionary.
1056
+ _save: Saves the current state of the dictionary to the JSON file.
1057
+ __setitem__: Stores a key-value pair and persists it to disk.
1058
+ __delitem__: Removes an item and updates the persistent storage.
1059
+ update: Updates the dictionary and persists changes.
1060
+ clear: Clears all entries and updates the persistent storage.
1061
+
1062
+ Examples:
1063
+ >>> json_dict = JSONDict("data.json")
1064
+ >>> json_dict["key"] = "value"
1065
+ >>> print(json_dict["key"])
1066
+ value
1067
+ >>> del json_dict["key"]
1068
+ >>> json_dict.update({"new_key": "new_value"})
1069
+ >>> json_dict.clear()
1070
+ """
1071
+
1072
+ def __init__(self, file_path: Union[str, Path] = "data.json"):
1073
+ """Initialize a JSONDict object with a specified file path for JSON persistence."""
1074
+ super().__init__()
1075
+ self.file_path = Path(file_path)
1076
+ self.lock = Lock()
1077
+ self._load()
1078
+
1079
+ def _load(self):
1080
+ """Load the data from the JSON file into the dictionary."""
1081
+ try:
1082
+ if self.file_path.exists():
1083
+ with open(self.file_path) as f:
1084
+ self.update(json.load(f))
1085
+ except json.JSONDecodeError:
1086
+ print(f"Error decoding JSON from {self.file_path}. Starting with an empty dictionary.")
1087
+ except Exception as e:
1088
+ print(f"Error reading from {self.file_path}: {e}")
1089
+
1090
+ def _save(self):
1091
+ """Save the current state of the dictionary to the JSON file."""
1092
+ try:
1093
+ self.file_path.parent.mkdir(parents=True, exist_ok=True)
1094
+ with open(self.file_path, "w") as f:
1095
+ json.dump(dict(self), f, indent=2)
1096
+ except Exception as e:
1097
+ print(f"Error writing to {self.file_path}: {e}")
1098
+
1099
+ def __setitem__(self, key, value):
1100
+ """Store a key-value pair and persist to disk."""
1101
+ with self.lock:
1102
+ super().__setitem__(key, value)
1103
+ self._save()
1104
+
1105
+ def __delitem__(self, key):
1106
+ """Remove an item and update the persistent storage."""
1107
+ with self.lock:
1108
+ super().__delitem__(key)
1109
+ self._save()
1110
+
1111
+ def __str__(self):
1112
+ """Return a pretty-printed JSON string representation of the dictionary."""
1113
+ return f'JSONDict("{self.file_path}"):\n{json.dumps(dict(self), indent=2, ensure_ascii=False)}'
1114
+
1115
+ def update(self, *args, **kwargs):
1116
+ """Update the dictionary and persist changes."""
1117
+ with self.lock:
1118
+ super().update(*args, **kwargs)
1119
+ self._save()
1120
+
1121
+ def clear(self):
1122
+ """Clear all entries and update the persistent storage."""
1123
+ with self.lock:
1124
+ super().clear()
1125
+ self._save()
1126
+
1127
+
1128
+ class SettingsManager(JSONDict):
1129
+ """
1130
+ SettingsManager class for managing and persisting Ultralytics settings.
1131
+
1132
+ This class extends JSONDict to provide JSON persistence for settings, ensuring thread-safe operations and default
1133
+ values. It validates settings on initialization and provides methods to update or reset settings.
1134
+
1135
+ Attributes:
1136
+ file (Path): The path to the JSON file used for persistence.
1137
+ version (str): The version of the settings schema.
1138
+ defaults (Dict): A dictionary containing default settings.
1139
+ help_msg (str): A help message for users on how to view and update settings.
1140
+
1141
+ Methods:
1142
+ _validate_settings: Validates the current settings and resets if necessary.
1143
+ update: Updates settings, validating keys and types.
1144
+ reset: Resets the settings to default and saves them.
1145
+
1146
+ Examples:
1147
+ Initialize and update settings:
1148
+ >>> settings = SettingsManager()
1149
+ >>> settings.update(runs_dir="/new/runs/dir")
1150
+ >>> print(settings["runs_dir"])
1151
+ /new/runs/dir
1048
1152
  """
1049
1153
 
1050
- def __init__(self, file=SETTINGS_YAML, version="0.0.5"):
1154
+ def __init__(self, file=SETTINGS_FILE, version="0.0.6"):
1051
1155
  """Initializes the SettingsManager with default settings and loads user settings."""
1052
- import copy
1053
1156
  import hashlib
1054
1157
 
1055
- from ultralytics.utils.checks import check_version
1056
1158
  from ultralytics.utils.torch_utils import torch_distributed_zero_first
1057
1159
 
1058
1160
  root = GIT_DIR or Path()
@@ -1081,45 +1183,42 @@ class SettingsManager(dict):
1081
1183
  "vscode_msg": True,
1082
1184
  }
1083
1185
  self.help_msg = (
1084
- f"\nView settings with 'yolo settings' or at '{self.file}'"
1085
- "\nUpdate settings with 'yolo settings key=value', i.e. 'yolo settings runs_dir=path/to/dir'. "
1186
+ f"\nView Ultralytics Settings with 'yolo settings' or at '{self.file}'"
1187
+ "\nUpdate Settings with 'yolo settings key=value', i.e. 'yolo settings runs_dir=path/to/dir'. "
1086
1188
  "For help see https://docs.ultralytics.com/quickstart/#ultralytics-settings."
1087
1189
  )
1088
1190
 
1089
- super().__init__(copy.deepcopy(self.defaults))
1090
-
1091
1191
  with torch_distributed_zero_first(RANK):
1092
- if not self.file.exists():
1093
- self.save()
1094
-
1095
- self.load()
1096
- correct_keys = self.keys() == self.defaults.keys()
1097
- correct_types = all(type(a) is type(b) for a, b in zip(self.values(), self.defaults.values()))
1098
- correct_version = check_version(self["settings_version"], self.version)
1099
- if not (correct_keys and correct_types and correct_version):
1100
- LOGGER.warning(
1101
- "WARNING ⚠️ Ultralytics settings reset to default values. This may be due to a possible problem "
1102
- f"with your settings or a recent ultralytics package update. {self.help_msg}"
1103
- )
1192
+ super().__init__(self.file)
1193
+
1194
+ if not self.file.exists() or not self: # Check if file doesn't exist or is empty
1195
+ LOGGER.info(f"Creating new Ultralytics Settings v{version} file ✅ {self.help_msg}")
1104
1196
  self.reset()
1105
1197
 
1106
- if self.get("datasets_dir") == self.get("runs_dir"):
1107
- LOGGER.warning(
1108
- f"WARNING ⚠️ Ultralytics setting 'datasets_dir: {self.get('datasets_dir')}' "
1109
- f"must be different than 'runs_dir: {self.get('runs_dir')}'. "
1110
- f"Please change one to avoid possible issues during training. {self.help_msg}"
1111
- )
1198
+ self._validate_settings()
1199
+
1200
+ def _validate_settings(self):
1201
+ """Validate the current settings and reset if necessary."""
1202
+ correct_keys = set(self.keys()) == set(self.defaults.keys())
1203
+ correct_types = all(isinstance(self.get(k), type(v)) for k, v in self.defaults.items())
1204
+ correct_version = self.get("settings_version", "") == self.version
1112
1205
 
1113
- def load(self):
1114
- """Loads settings from the YAML file."""
1115
- super().update(yaml_load(self.file))
1206
+ if not (correct_keys and correct_types and correct_version):
1207
+ LOGGER.warning(
1208
+ "WARNING ⚠️ Ultralytics settings reset to default values. This may be due to a possible problem "
1209
+ f"with your settings or a recent ultralytics package update. {self.help_msg}"
1210
+ )
1211
+ self.reset()
1116
1212
 
1117
- def save(self):
1118
- """Saves the current settings to the YAML file."""
1119
- yaml_save(self.file, dict(self))
1213
+ if self.get("datasets_dir") == self.get("runs_dir"):
1214
+ LOGGER.warning(
1215
+ f"WARNING ⚠️ Ultralytics setting 'datasets_dir: {self.get('datasets_dir')}' "
1216
+ f"must be different than 'runs_dir: {self.get('runs_dir')}'. "
1217
+ f"Please change one to avoid possible issues during training. {self.help_msg}"
1218
+ )
1120
1219
 
1121
1220
  def update(self, *args, **kwargs):
1122
- """Updates a setting value in the current settings."""
1221
+ """Updates settings, validating keys and types."""
1123
1222
  for k, v in kwargs.items():
1124
1223
  if k not in self.defaults:
1125
1224
  raise KeyError(f"No Ultralytics setting '{k}'. {self.help_msg}")
@@ -1127,20 +1226,16 @@ class SettingsManager(dict):
1127
1226
  if not isinstance(v, t):
1128
1227
  raise TypeError(f"Ultralytics setting '{k}' must be of type '{t}', not '{type(v)}'. {self.help_msg}")
1129
1228
  super().update(*args, **kwargs)
1130
- self.save()
1131
1229
 
1132
1230
  def reset(self):
1133
1231
  """Resets the settings to default and saves them."""
1134
1232
  self.clear()
1135
1233
  self.update(self.defaults)
1136
- self.save()
1137
1234
 
1138
1235
 
1139
1236
  def deprecation_warn(arg, new_arg):
1140
1237
  """Issue a deprecation warning when a deprecated argument is used, suggesting an updated argument."""
1141
- LOGGER.warning(
1142
- f"WARNING ⚠️ '{arg}' is deprecated and will be removed in in the future. " f"Please use '{new_arg}' instead."
1143
- )
1238
+ LOGGER.warning(f"WARNING ⚠️ '{arg}' is deprecated and will be removed in in the future. Use '{new_arg}' instead.")
1144
1239
 
1145
1240
 
1146
1241
  def clean_url(url):
@@ -1159,11 +1254,8 @@ def vscode_msg(ext="ultralytics.ultralytics-snippets") -> str:
1159
1254
  path = (USER_CONFIG_DIR.parents[2] if WINDOWS else USER_CONFIG_DIR.parents[1]) / ".vscode/extensions"
1160
1255
  obs_file = path / ".obsolete" # file tracks uninstalled extensions, while source directory remains
1161
1256
  installed = any(path.glob(f"{ext}*")) and ext not in (obs_file.read_text("utf-8") if obs_file.exists() else "")
1162
- return (
1163
- ""
1164
- if installed
1165
- else f"{colorstr('VS Code:')} view Ultralytics VS Code Extension ⚡ at https://docs.ultralytics.com/integrations/vscode"
1166
- )
1257
+ url = "https://docs.ultralytics.com/integrations/vscode"
1258
+ return "" if installed else f"{colorstr('VS Code:')} view Ultralytics VS Code Extension ⚡ at {url}"
1167
1259
 
1168
1260
 
1169
1261
  # Run below code on utils init ------------------------------------------------------------------------------------
@@ -1171,6 +1263,7 @@ def vscode_msg(ext="ultralytics.ultralytics-snippets") -> str:
1171
1263
  # Check first-install steps
1172
1264
  PREFIX = colorstr("Ultralytics: ")
1173
1265
  SETTINGS = SettingsManager() # initialize settings
1266
+ PERSISTENT_CACHE = JSONDict(USER_CONFIG_DIR / "persistent_cache.json") # initialize persistent cache
1174
1267
  DATASETS_DIR = Path(SETTINGS["datasets_dir"]) # global datasets directory
1175
1268
  WEIGHTS_DIR = Path(SETTINGS["weights_dir"]) # global weights directory
1176
1269
  RUNS_DIR = Path(SETTINGS["runs_dir"]) # global runs directory
@@ -85,7 +85,7 @@ def benchmark(
85
85
 
86
86
  y = []
87
87
  t0 = time.time()
88
- for i, (name, format, suffix, cpu, gpu) in export_formats().iterrows(): # index, (name, format, suffix, CPU, GPU)
88
+ for i, (name, format, suffix, cpu, gpu) in enumerate(zip(*export_formats().values())):
89
89
  emoji, filename = "❌", None # export defaults
90
90
  try:
91
91
  # Checks
@@ -97,8 +97,8 @@ def benchmark(
97
97
  assert MACOS or LINUX, "CoreML and TF.js export only supported on macOS and Linux"
98
98
  assert not IS_RASPBERRYPI, "CoreML and TF.js export not supported on Raspberry Pi"
99
99
  assert not IS_JETSON, "CoreML and TF.js export not supported on NVIDIA Jetson"
100
- if i in {3, 5}: # CoreML and OpenVINO
101
- assert not IS_PYTHON_3_12, "CoreML and OpenVINO not supported on Python 3.12"
100
+ if i in {5}: # CoreML
101
+ assert not IS_PYTHON_3_12, "CoreML not supported on Python 3.12"
102
102
  if i in {6, 7, 8}: # TF SavedModel, TF GraphDef, and TFLite
103
103
  assert not isinstance(model, YOLOWorld), "YOLOWorldv2 TensorFlow exports not supported by onnx2tf yet"
104
104
  if i in {9, 10}: # TF EdgeTPU and TF.js
@@ -322,9 +322,12 @@ class ProfileModels:
322
322
  num_warmup_runs (int, optional): Number of warmup runs before the actual profiling starts. Default is 10.
323
323
  min_time (float, optional): Minimum time in seconds for profiling a model. Default is 60.
324
324
  imgsz (int, optional): Size of the image used during profiling. Default is 640.
325
- half (bool, optional): Flag to indicate whether to use half-precision floating point for profiling.
325
+ half (bool, optional): Flag to indicate whether to use FP16 half-precision for TensorRT profiling.
326
326
  trt (bool, optional): Flag to indicate whether to profile using TensorRT. Default is True.
327
327
  device (torch.device, optional): Device used for profiling. If None, it is determined automatically.
328
+
329
+ Notes:
330
+ FP16 'half' argument option removed for ONNX as slower on CPU than FP32
328
331
  """
329
332
  self.paths = paths
330
333
  self.num_timed_runs = num_timed_runs
@@ -353,10 +356,18 @@ class ProfileModels:
353
356
  model_info = model.info()
354
357
  if self.trt and self.device.type != "cpu" and not engine_file.is_file():
355
358
  engine_file = model.export(
356
- format="engine", half=self.half, imgsz=self.imgsz, device=self.device, verbose=False
359
+ format="engine",
360
+ half=self.half,
361
+ imgsz=self.imgsz,
362
+ device=self.device,
363
+ verbose=False,
357
364
  )
358
365
  onnx_file = model.export(
359
- format="onnx", half=self.half, imgsz=self.imgsz, simplify=True, device=self.device, verbose=False
366
+ format="onnx",
367
+ imgsz=self.imgsz,
368
+ simplify=True,
369
+ device=self.device,
370
+ verbose=False,
360
371
  )
361
372
  elif file.suffix == ".onnx":
362
373
  model_info = self.get_onnx_model_info(file)
@@ -419,7 +419,7 @@ class Annotator:
419
419
  # Convert im back to PIL and update draw
420
420
  self.fromarray(self.im)
421
421
 
422
- def kpts(self, kpts, shape=(640, 640), radius=5, kpt_line=True, conf_thres=0.25, kpt_color=None):
422
+ def kpts(self, kpts, shape=(640, 640), radius=None, kpt_line=True, conf_thres=0.25, kpt_color=None):
423
423
  """
424
424
  Plot keypoints on the image.
425
425
 
@@ -436,6 +436,7 @@ class Annotator:
436
436
  - Modifies self.im in-place.
437
437
  - If self.pil is True, converts image to numpy array and back to PIL.
438
438
  """
439
+ radius = radius if radius is not None else self.lw
439
440
  if self.pil:
440
441
  # Convert to numpy first
441
442
  self.im = np.asarray(self.im).copy()
@@ -471,7 +472,7 @@ class Annotator:
471
472
  pos1,
472
473
  pos2,
473
474
  kpt_color or self.limb_color[i].tolist(),
474
- thickness=2,
475
+ thickness=int(np.ceil(self.lw / 2)),
475
476
  lineType=cv2.LINE_AA,
476
477
  )
477
478
  if self.pil:
@@ -110,15 +110,17 @@ def autocast(enabled: bool, device: str = "cuda"):
110
110
 
111
111
  def get_cpu_info():
112
112
  """Return a string with system CPU information, i.e. 'Apple M2'."""
113
- with contextlib.suppress(Exception):
114
- import cpuinfo # pip install py-cpuinfo
113
+ from ultralytics.utils import PERSISTENT_CACHE # avoid circular import error
115
114
 
116
- k = "brand_raw", "hardware_raw", "arch_string_raw" # keys sorted by preference (not all keys always available)
117
- info = cpuinfo.get_cpu_info() # info dict
118
- string = info.get(k[0] if k[0] in info else k[1] if k[1] in info else k[2], "unknown")
119
- return string.replace("(R)", "").replace("CPU ", "").replace("@ ", "")
115
+ if "cpu_info" not in PERSISTENT_CACHE:
116
+ with contextlib.suppress(Exception):
117
+ import cpuinfo # pip install py-cpuinfo
120
118
 
121
- return "unknown"
119
+ k = "brand_raw", "hardware_raw", "arch_string_raw" # keys sorted by preference
120
+ info = cpuinfo.get_cpu_info() # info dict
121
+ string = info.get(k[0] if k[0] in info else k[1] if k[1] in info else k[2], "unknown")
122
+ PERSISTENT_CACHE["cpu_info"] = string.replace("(R)", "").replace("CPU ", "").replace("@ ", "")
123
+ return PERSISTENT_CACHE.get("cpu_info", "unknown")
122
124
 
123
125
 
124
126
  def select_device(device="", batch=0, newline=False, verbose=True):
@@ -247,7 +249,7 @@ def fuse_conv_and_bn(conv, bn):
247
249
  )
248
250
 
249
251
  # Prepare filters
250
- w_conv = conv.weight.clone().view(conv.out_channels, -1)
252
+ w_conv = conv.weight.view(conv.out_channels, -1)
251
253
  w_bn = torch.diag(bn.weight.div(torch.sqrt(bn.eps + bn.running_var)))
252
254
  fusedconv.weight.copy_(torch.mm(w_bn, w_conv).view(fusedconv.weight.shape))
253
255
 
@@ -278,7 +280,7 @@ def fuse_deconv_and_bn(deconv, bn):
278
280
  )
279
281
 
280
282
  # Prepare filters
281
- w_deconv = deconv.weight.clone().view(deconv.out_channels, -1)
283
+ w_deconv = deconv.weight.view(deconv.out_channels, -1)
282
284
  w_bn = torch.diag(bn.weight.div(torch.sqrt(bn.eps + bn.running_var)))
283
285
  fuseddconv.weight.copy_(torch.mm(w_bn, w_deconv).view(fuseddconv.weight.shape))
284
286
 
@@ -1,13 +1,16 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ultralytics
3
- Version: 8.2.97
3
+ Version: 8.2.99
4
4
  Summary: Ultralytics YOLO for SOTA object detection, multi-object tracking, instance segmentation, pose estimation and image classification.
5
- Author: Glenn Jocher, Ayush Chaurasia, Jing Qiu
6
- Maintainer: Glenn Jocher, Ayush Chaurasia, Jing Qiu
5
+ Author: Ayush Chaurasia
6
+ Author-email: Glenn Jocher <glenn.jocher@ultralytics.com>, Jing Qiu <jing.qiu@ultralytics.com>
7
+ Maintainer-email: Ultralytics <hello@ultralytics.com>
7
8
  License: AGPL-3.0
9
+ Project-URL: Homepage, https://ultralytics.com
10
+ Project-URL: Source, https://github.com/ultralytics/ultralytics
11
+ Project-URL: Documentation, https://docs.ultralytics.com
8
12
  Project-URL: Bug Reports, https://github.com/ultralytics/ultralytics/issues
9
- Project-URL: Funding, https://ultralytics.com
10
- Project-URL: Source, https://github.com/ultralytics/ultralytics/
13
+ Project-URL: Changelog, https://github.com/ultralytics/ultralytics/releases
11
14
  Keywords: machine-learning,deep-learning,computer-vision,ML,DL,AI,YOLO,YOLOv3,YOLOv5,YOLOv8,YOLOv9,YOLOv10,HUB,Ultralytics
12
15
  Classifier: Development Status :: 4 - Beta
13
16
  Classifier: Intended Audience :: Developers
@@ -4,14 +4,14 @@ tests/test_cli.py,sha256=E4lMt49TGo12Lb5CgQfpk1bwyFUZuFxF0V9j_ykV7xM,4821
4
4
  tests/test_cuda.py,sha256=uD-ddNEcBMFQmQ9iE4fIGh0EIcGwEoDEUNVCEHicaWE,5133
5
5
  tests/test_engine.py,sha256=xW-UT9_9xZp-7-hSnbJgMw_ezTk6NqTOIiA59XZDmxA,4934
6
6
  tests/test_explorer.py,sha256=IMFvZ9uMoEXVC5FwdaVh0821wBgs7muVF6aw1F-auAI,2572
7
- tests/test_exports.py,sha256=Uezf3OatpPHlo5qoPw-2kqkZxuMCF9L4XF2riD4vmII,8225
8
- tests/test_integrations.py,sha256=xglcfMPjfVh346PV8WTpk6tBxraCXEFJEQyyJMr5tyU,6064
7
+ tests/test_exports.py,sha256=2NILfcHbCCpmbfgG6_3BSjHaa-QrTwspAVTBf8id5vY,8134
8
+ tests/test_integrations.py,sha256=iWuqcWThasLVQzacrAwkqgU0jP-8uRkONhNLxPg2wcg,6126
9
9
  tests/test_python.py,sha256=vkA0F9XgOSpU1BxI2Lzq69f6g-vi8PtOfmb_7P96ZUk,23560
10
10
  tests/test_solutions.py,sha256=p_2edhl96Ty3jwzSf02Q2m2mTu9skc0Z-eMcUuuXfLg,3300
11
- ultralytics/__init__.py,sha256=4ko8wqP19EM9zJljwbpzSwRQRNGDBUI_jSGHJg5rmD0,695
11
+ ultralytics/__init__.py,sha256=5UH6TFz1vI7MGEBvH98kHpbFhbd96a-Dvebo_S8Ybj8,695
12
12
  ultralytics/assets/bus.jpg,sha256=wCAZxJecGR63Od3ZRERe9Aja1Weayrb9Ug751DS_vGM,137419
13
13
  ultralytics/assets/zidane.jpg,sha256=Ftc4aeMmen1O0A3o6GCDO9FlfBslLpTAw0gnetx7bts,50427
14
- ultralytics/cfg/__init__.py,sha256=7FFk0HG4AvAre9CV70QMTtx1h74pSiNSJaxKSiuFkSo,33138
14
+ ultralytics/cfg/__init__.py,sha256=dLbqNkfXWngwiibvrxH6wMe_oZG4OIsxhIiSvkrCbEk,33145
15
15
  ultralytics/cfg/default.yaml,sha256=xRKVF-Z9E3imXTU9OCK94kj3jGgYoo67VJQwuYlHiUU,8228
16
16
  ultralytics/cfg/datasets/Argoverse.yaml,sha256=FyeuJT5CHq_9d4hlfAf0kpZlnbUMO0S--UJ1yIqcdKk,3134
17
17
  ultralytics/cfg/datasets/DOTAv1.5.yaml,sha256=QVfp_Qp-4rukuicaB4qx86NxSHM8Mrzym8l_fIDo8gw,1195
@@ -91,23 +91,23 @@ ultralytics/data/converter.py,sha256=DjJ0atku2aKW0iS1PZPNX8V6WTrZ-CHZT6hopE1HSjI
91
91
  ultralytics/data/dataset.py,sha256=IS07ulk7rXPZ-SW_rjYF9mS-TxPXOY9bbo5jqfcwPqM,22874
92
92
  ultralytics/data/loaders.py,sha256=JF2Z_ESK6RweavOuYWejYSGJwmqINb5hNwwCb3AAf0M,24094
93
93
  ultralytics/data/split_dota.py,sha256=yOtypHoY5HvIVBKZgFXdfj2tuCLLEBnMwNfAeG94Eik,10680
94
- ultralytics/data/utils.py,sha256=ZvqocYXUGGhqJnLDvxF-gWChISkPZL-Bt-T2ZcA9tBI,31042
94
+ ultralytics/data/utils.py,sha256=GVTtZlFE8Q9RlNJ19Er_CdxenjeDbvQerU1jKOs76S4,31042
95
95
  ultralytics/data/explorer/__init__.py,sha256=-Y3m1ZedepOQUv_KW82zaGxvU_PSHcuwUTFqG9BhAr4,113
96
96
  ultralytics/data/explorer/explorer.py,sha256=JWmLHHhp68h2q3vx4poBou5RYoAX3R89yihR50YLDb0,18881
97
97
  ultralytics/data/explorer/utils.py,sha256=EvvukQiQUTBrsZznmMnyEX2EqTuwZo_Geyc8yfi8NIA,7085
98
98
  ultralytics/data/explorer/gui/__init__.py,sha256=mHtJuK4hwF8cuV-VHDc7tp6u6D1gHz2Z7JI8grmQDTs,42
99
99
  ultralytics/data/explorer/gui/dash.py,sha256=vZ476NaUH4FKU08rAJ1K9WNyKtg0soMyJJxqg176yWc,10498
100
100
  ultralytics/engine/__init__.py,sha256=mHtJuK4hwF8cuV-VHDc7tp6u6D1gHz2Z7JI8grmQDTs,42
101
- ultralytics/engine/exporter.py,sha256=MtBFbJp3ifhn9sQXuQb7vxxOmtS_SOw7lnQhrq4H42c,57078
101
+ ultralytics/engine/exporter.py,sha256=BFYvv763kbEm5q0-AYIh979vL0ccU4RNvON2w8qtm1s,57019
102
102
  ultralytics/engine/model.py,sha256=1sWOBvLL2JIH8JuHoxwvr1MPfKFww0ORyLESx3Fs2c8,51582
103
103
  ultralytics/engine/predictor.py,sha256=MgMWHUJdRcVCaVmOyvdy2Gjk_EyRHv-ar0SSGxQe8F4,17471
104
104
  ultralytics/engine/results.py,sha256=8RJlN8J-_9w-mrDZm9wC-DZJTPBS7v1c_r_R173QyRM,75043
105
105
  ultralytics/engine/trainer.py,sha256=VOuR9WpDgYILevpWnWAtKLEIcJ4iFG41HxOCSbOy0YA,36657
106
106
  ultralytics/engine/tuner.py,sha256=gPqDTHH7vRB2O3YyH26m1BjVKbXxuA2XAlPRzTKFZsc,11838
107
107
  ultralytics/engine/validator.py,sha256=483Ad87Irk7IBlJNLu2SQAJsb7YriALTX9GIgriCmRg,14650
108
- ultralytics/hub/__init__.py,sha256=AM_twjV9ouUmyxh3opoPgTqDpMOd8xIOHsAKdWS2L18,5663
108
+ ultralytics/hub/__init__.py,sha256=5jgMARywvUPDy-fS_Eb3e8ksd_1tAloP15pbNRKtxtg,5643
109
109
  ultralytics/hub/auth.py,sha256=kDLakGa2NbzvMAeXc2UdzZ65r0AH-XeM_JfsDY97WGk,5545
110
- ultralytics/hub/session.py,sha256=ivTJpGEKEi7F55RloWN-Ks6oeB3ll74AWGAsBtAQOPM,16715
110
+ ultralytics/hub/session.py,sha256=xD4oBiWfeIMReNxSIPE-VK5xVdUHEjS8WrpBvjlRfnU,16350
111
111
  ultralytics/hub/utils.py,sha256=I7NATG6O_QRw7EU7EHkdTVvbCkwKCyUe54BP60To_so,9715
112
112
  ultralytics/hub/google/__init__.py,sha256=uclNs-_5vAzQMgQKgl8eBvml1cx6IZYXRUhrF57v6_k,7504
113
113
  ultralytics/models/__init__.py,sha256=TT9iLCL_n9Y80dcUq0Fo-p-GRZCSU2vrWXM3CoMwqqE,265
@@ -168,7 +168,7 @@ ultralytics/models/yolo/world/__init__.py,sha256=3VTH0q4NOt2EWRom15yCymvmvm0Etp2
168
168
  ultralytics/models/yolo/world/train.py,sha256=gaDrAmLJpg9qDtmL5evA5HsV2yb4RTRSfk2EDYrHdRg,3686
169
169
  ultralytics/models/yolo/world/train_world.py,sha256=IsnCEVt6DcM9lUskCKmIN-M8MM79xLpwTRqRoAHUnZ4,4857
170
170
  ultralytics/nn/__init__.py,sha256=4BPLHY89xEM_al5uK0aOmFgiML6CMGEZbezxOvTjOEs,587
171
- ultralytics/nn/autobackend.py,sha256=DZTIHsp2PLs8H2-oQR9LqA-uPj8DARGonCXzRv2Pkdc,31546
171
+ ultralytics/nn/autobackend.py,sha256=95FVDv_l5fax5f8gmhYAIIS2e_8u6HYxNd4Saxh7E10,31573
172
172
  ultralytics/nn/tasks.py,sha256=5ESFTm1CYt7uSCyWkW7rsLAdMLPHSBla95GWj439SrA,47894
173
173
  ultralytics/nn/modules/__init__.py,sha256=m8x-XRHVLWMECPeysVlv1TQenV-n8oAbK1gxnoXzLpk,2553
174
174
  ultralytics/nn/modules/activation.py,sha256=chhn469wnRHEs5BMGNBYXwPYZc_7-urspTT8fnBd-xA,895
@@ -196,9 +196,9 @@ ultralytics/trackers/utils/__init__.py,sha256=mHtJuK4hwF8cuV-VHDc7tp6u6D1gHz2Z7J
196
196
  ultralytics/trackers/utils/gmc.py,sha256=VcURuY041qGCeWUGMxHZBr10T16LtcMqyv7AmTfE1MY,14557
197
197
  ultralytics/trackers/utils/kalman_filter.py,sha256=cH9zD3fwkuezP97H9mw8cSBN7a8hHKx_Sx1j7t3oYGs,21349
198
198
  ultralytics/trackers/utils/matching.py,sha256=3Ie1WNNRZ4_q3365F03XD7Nr9juZB_08mw4yUKC3w74,7162
199
- ultralytics/utils/__init__.py,sha256=BRqC6AE9epuZJy4XcGzGfuR2zNiXx-mfot2JQomterw,44097
199
+ ultralytics/utils/__init__.py,sha256=JtUCGKZp2rW7pXwGPRCiN8QTovnM8hlgW6XLvp9yGTs,48007
200
200
  ultralytics/utils/autobatch.py,sha256=AXboYfNSnTGsYj5FmgGYPQd0crfkeleyms6QXQfZGQ4,4194
201
- ultralytics/utils/benchmarks.py,sha256=UsVJXTgB6xQ8QBjlNghN3WuZQwXShQjuqv2RcGBLHDY,23640
201
+ ultralytics/utils/benchmarks.py,sha256=WcrIeSIkGlNH6TR_3IaeScvkZZHSUOGAMux2ocBvKTU,23844
202
202
  ultralytics/utils/checks.py,sha256=PmdN42XJ7IIUNbeiY8zjPIfJceaxAO04nc780EoYxTc,28910
203
203
  ultralytics/utils/dist.py,sha256=NDFga-uKxkBX2zLxFHSene_cCiGQJoyOeCXcN9JIOIk,2358
204
204
  ultralytics/utils/downloads.py,sha256=uLsYFN2G4g2joTNrsZsfc8ytvfNNRXDPkI20qgkZ2B8,21897
@@ -209,9 +209,9 @@ ultralytics/utils/loss.py,sha256=mDHGmF-gjggAUVhI1dkCm7TtfZHCwz25XKm4M2xJKLs,339
209
209
  ultralytics/utils/metrics.py,sha256=UgLGudWp57uXDMlMUJy4gsz6cfVjcq7tYmHeto3TqvM,53927
210
210
  ultralytics/utils/ops.py,sha256=dsXNdyrYx_p6io6zezig9p84dxS7U-10vceHNVu2IL0,32888
211
211
  ultralytics/utils/patches.py,sha256=Oo3DkP7MbXnNGvPfoFSocAkVvaPh9kwMT_9RQUfjVhI,3594
212
- ultralytics/utils/plotting.py,sha256=bud5mAvFxQ2JD29dReaO4c7Z00k6jIaPJJCznIoyy2w,61543
212
+ ultralytics/utils/plotting.py,sha256=lCx9i3USQK2KGsgD-l2cbdbv33c396gIwMFsZ9iOa1w,61629
213
213
  ultralytics/utils/tal.py,sha256=ECsu95xEqOItmxMDN4YTD3FsUiIsQNWy0pZC3TfvFfk,16877
214
- ultralytics/utils/torch_utils.py,sha256=lTTbFD8SlnXT11O9E8NKTQnrXEOsRmayywQP6niUZMc,29535
214
+ ultralytics/utils/torch_utils.py,sha256=4UaeXZYOjwel_XGFSvPJl5qm5p-_mqeob_MJqN30Tzc,29694
215
215
  ultralytics/utils/triton.py,sha256=gg1finxno_tY2Ge9PMhmu7PI9wvoFZoiicdT4Bhqv3w,3936
216
216
  ultralytics/utils/tuner.py,sha256=AtEtK6pOt9xVTyx864OpNRVxNdAxz5aKHzveiXwkD1A,6250
217
217
  ultralytics/utils/callbacks/__init__.py,sha256=YrWqC3BVVaTLob4iCPR6I36mUxIUOpPJW7B_LjT78Qw,214
@@ -225,9 +225,9 @@ ultralytics/utils/callbacks/neptune.py,sha256=5Z3ua5YBTUS56FH8VQKQG1aaIo9fH8GEyz
225
225
  ultralytics/utils/callbacks/raytune.py,sha256=ODVYzy-CoM4Uge0zjkh3Hnh9nF2M0vhDrSenXnvcizw,705
226
226
  ultralytics/utils/callbacks/tensorboard.py,sha256=0kn4IR10no99UCIheojWRujgybmUHSx5fPI6Vsq6l_g,4135
227
227
  ultralytics/utils/callbacks/wb.py,sha256=9-fjQIdLjr3b73DTE3rHO171KvbH1VweJ-bmbv-rqTw,6747
228
- ultralytics-8.2.97.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
229
- ultralytics-8.2.97.dist-info/METADATA,sha256=ZXllOjVWz8Z_-O8l8U7EAIr7Hy32uYtPLoMpa9-Vbs0,39504
230
- ultralytics-8.2.97.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
231
- ultralytics-8.2.97.dist-info/entry_points.txt,sha256=YM_wiKyTe9yRrsEfqvYolNO5ngwfoL4-NwgKzc8_7sI,93
232
- ultralytics-8.2.97.dist-info/top_level.txt,sha256=XP49TwiMw4QGsvTLSYiJhz1xF_k7ev5mQ8jJXaXi45Q,12
233
- ultralytics-8.2.97.dist-info/RECORD,,
228
+ ultralytics-8.2.99.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
229
+ ultralytics-8.2.99.dist-info/METADATA,sha256=9HgJLsxSRNmrr3zqV__zM1RqHsOySFJWEH9PR_WOIW4,39710
230
+ ultralytics-8.2.99.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
231
+ ultralytics-8.2.99.dist-info/entry_points.txt,sha256=YM_wiKyTe9yRrsEfqvYolNO5ngwfoL4-NwgKzc8_7sI,93
232
+ ultralytics-8.2.99.dist-info/top_level.txt,sha256=XP49TwiMw4QGsvTLSYiJhz1xF_k7ev5mQ8jJXaXi45Q,12
233
+ ultralytics-8.2.99.dist-info/RECORD,,