New PERSISTENT_CACHE (#16373)

Signed-off-by: UltralyticsAssistant <web@ultralytics.com>
Co-authored-by: UltralyticsAssistant <web@ultralytics.com>
This commit is contained in:
Glenn Jocher 2024-09-19 21:06:57 +02:00 committed by GitHub
parent 5024bcac9d
commit 641d09164c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 72 additions and 6 deletions

View file

@ -39,6 +39,10 @@ keywords: Ultralytics, utils, TQDM, Python, ML, Machine Learning utilities, YOLO
<br><br><hr><br>
## ::: ultralytics.utils.PersistentCacheDict
<br><br><hr><br>
## ::: ultralytics.utils.plt_settings
<br><br><hr><br>

View file

@ -3,6 +3,7 @@
import contextlib
import importlib.metadata
import inspect
import json
import logging.config
import os
import platform
@ -14,6 +15,7 @@ import time
import urllib
import uuid
from pathlib import Path
from threading import Lock
from types import SimpleNamespace
from typing import Union
@ -1136,6 +1138,61 @@ class SettingsManager(dict):
self.save()
class PersistentCacheDict(dict):
"""A thread-safe dictionary that persists data to a JSON file for caching purposes."""
def __init__(self, file_path=USER_CONFIG_DIR / "persistent_cache.json"):
"""Initializes a thread-safe persistent cache dictionary with a specified file path for storage."""
super().__init__()
self.file_path = Path(file_path)
self.lock = Lock()
self._load()
def _load(self):
"""Load the persistent cache from a JSON file into the dictionary, handling errors gracefully."""
try:
if self.file_path.exists():
with open(self.file_path) as f:
self.update(json.load(f))
except json.JSONDecodeError:
print(f"Error decoding JSON from {self.file_path}. Starting with an empty cache.")
except Exception as e:
print(f"Error reading from {self.file_path}: {e}")
def _save(self):
"""Save the current state of the cache dictionary to a JSON file, ensuring thread safety."""
try:
self.file_path.parent.mkdir(parents=True, exist_ok=True)
with open(self.file_path, "w") as f:
json.dump(dict(self), f, indent=2)
except Exception as e:
print(f"Error writing to {self.file_path}: {e}")
def __setitem__(self, key, value):
"""Store a key-value pair in the cache and persist the updated cache to disk."""
with self.lock:
super().__setitem__(key, value)
self._save()
def __delitem__(self, key):
"""Remove an item from the PersistentCacheDict and update the persistent storage."""
with self.lock:
super().__delitem__(key)
self._save()
def update(self, *args, **kwargs):
"""Update the dictionary with key-value pairs from other mappings or iterables, ensuring thread safety."""
with self.lock:
super().update(*args, **kwargs)
self._save()
def clear(self):
"""Clears all entries from the persistent cache dictionary, ensuring thread safety."""
with self.lock:
super().clear()
self._save()
def deprecation_warn(arg, new_arg):
"""Issue a deprecation warning when a deprecated argument is used, suggesting an updated argument."""
LOGGER.warning(
@ -1171,6 +1228,7 @@ def vscode_msg(ext="ultralytics.ultralytics-snippets") -> str:
# Check first-install steps
PREFIX = colorstr("Ultralytics: ")
SETTINGS = SettingsManager() # initialize settings
PERSISTENT_CACHE = PersistentCacheDict() # initialize persistent cache
DATASETS_DIR = Path(SETTINGS["datasets_dir"]) # global datasets directory
WEIGHTS_DIR = Path(SETTINGS["weights_dir"]) # global weights directory
RUNS_DIR = Path(SETTINGS["runs_dir"]) # global runs directory

View file

@ -110,13 +110,17 @@ def autocast(enabled: bool, device: str = "cuda"):
def get_cpu_info():
"""Return a string with system CPU information, i.e. 'Apple M2'."""
from ultralytics.utils import PERSISTENT_CACHE # avoid circular import error
if "cpu_info" not in PERSISTENT_CACHE:
with contextlib.suppress(Exception):
import cpuinfo # pip install py-cpuinfo
k = "brand_raw", "hardware_raw", "arch_string_raw" # keys sorted by preference (not all keys always available)
k = "brand_raw", "hardware_raw", "arch_string_raw" # keys sorted by preference
info = cpuinfo.get_cpu_info() # info dict
string = info.get(k[0] if k[0] in info else k[1] if k[1] in info else k[2], "unknown")
return string.replace("(R)", "").replace("CPU ", "").replace("@ ", "")
PERSISTENT_CACHE["cpu_info"] = string.replace("(R)", "").replace("CPU ", "").replace("@ ", "")
return PERSISTENT_CACHE.get("cpu_info", "unknown")
return "unknown"