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.
- tests/conftest.py +2 -2
- tests/test_python.py +4 -3
- ultralytics/__init__.py +1 -1
- ultralytics/cfg/datasets/Argoverse.yaml +1 -1
- ultralytics/cfg/datasets/DOTAv1.5.yaml +1 -1
- ultralytics/cfg/datasets/DOTAv1.yaml +1 -1
- ultralytics/cfg/datasets/GlobalWheat2020.yaml +1 -1
- ultralytics/cfg/datasets/HomeObjects-3K.yaml +1 -1
- ultralytics/cfg/datasets/ImageNet.yaml +1 -1
- ultralytics/cfg/datasets/Objects365.yaml +1 -1
- ultralytics/cfg/datasets/SKU-110K.yaml +1 -1
- ultralytics/cfg/datasets/VOC.yaml +1 -1
- ultralytics/cfg/datasets/VisDrone.yaml +6 -3
- ultralytics/cfg/datasets/african-wildlife.yaml +1 -1
- ultralytics/cfg/datasets/brain-tumor.yaml +1 -1
- ultralytics/cfg/datasets/carparts-seg.yaml +1 -1
- ultralytics/cfg/datasets/coco-pose.yaml +1 -1
- ultralytics/cfg/datasets/coco.yaml +1 -1
- ultralytics/cfg/datasets/coco128-seg.yaml +1 -1
- ultralytics/cfg/datasets/coco128.yaml +1 -1
- ultralytics/cfg/datasets/coco8-grayscale.yaml +1 -1
- ultralytics/cfg/datasets/coco8-multispectral.yaml +1 -1
- ultralytics/cfg/datasets/coco8-pose.yaml +1 -1
- ultralytics/cfg/datasets/coco8-seg.yaml +1 -1
- ultralytics/cfg/datasets/coco8.yaml +1 -1
- ultralytics/cfg/datasets/crack-seg.yaml +1 -1
- ultralytics/cfg/datasets/dog-pose.yaml +1 -1
- ultralytics/cfg/datasets/dota8-multispectral.yaml +1 -1
- ultralytics/cfg/datasets/dota8.yaml +1 -1
- ultralytics/cfg/datasets/hand-keypoints.yaml +1 -1
- ultralytics/cfg/datasets/lvis.yaml +1 -1
- ultralytics/cfg/datasets/medical-pills.yaml +1 -1
- ultralytics/cfg/datasets/open-images-v7.yaml +1 -1
- ultralytics/cfg/datasets/package-seg.yaml +1 -1
- ultralytics/cfg/datasets/signature.yaml +1 -1
- ultralytics/cfg/datasets/tiger-pose.yaml +1 -1
- ultralytics/cfg/datasets/xView.yaml +1 -1
- ultralytics/data/augment.py +2 -0
- ultralytics/data/converter.py +5 -7
- ultralytics/data/dataset.py +1 -1
- ultralytics/data/split.py +1 -1
- ultralytics/data/split_dota.py +1 -1
- ultralytics/engine/exporter.py +15 -5
- ultralytics/engine/results.py +1 -1
- ultralytics/engine/tuner.py +2 -2
- ultralytics/models/nas/model.py +2 -1
- ultralytics/models/sam/modules/tiny_encoder.py +1 -1
- ultralytics/models/yolo/detect/val.py +1 -1
- ultralytics/models/yolo/world/train.py +1 -1
- ultralytics/models/yolo/world/train_world.py +17 -9
- ultralytics/models/yolo/yoloe/train.py +1 -1
- ultralytics/nn/autobackend.py +7 -1
- ultralytics/nn/tasks.py +4 -3
- ultralytics/solutions/similarity_search.py +11 -12
- ultralytics/solutions/solutions.py +53 -54
- ultralytics/utils/__init__.py +1 -2
- ultralytics/utils/checks.py +21 -0
- ultralytics/utils/metrics.py +10 -9
- ultralytics/utils/patches.py +1 -2
- ultralytics/utils/plotting.py +2 -2
- ultralytics/utils/torch_utils.py +2 -1
- {ultralytics-8.3.160.dist-info → ultralytics-8.3.162.dist-info}/METADATA +9 -1
- {ultralytics-8.3.160.dist-info → ultralytics-8.3.162.dist-info}/RECORD +67 -67
- {ultralytics-8.3.160.dist-info → ultralytics-8.3.162.dist-info}/WHEEL +0 -0
- {ultralytics-8.3.160.dist-info → ultralytics-8.3.162.dist-info}/entry_points.txt +0 -0
- {ultralytics-8.3.160.dist-info → ultralytics-8.3.162.dist-info}/licenses/LICENSE +0 -0
- {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
|
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="
|
39
|
-
... json_file="
|
40
|
+
... img_path="flickr30k/images",
|
41
|
+
... json_file="flickr30k/final_flickr_separateGT_train.json",
|
40
42
|
... ),
|
41
43
|
... dict(
|
42
|
-
... img_path="
|
43
|
-
... json_file="
|
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="
|
74
|
-
... json_file="
|
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
|
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
|
-
|
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}'")
|
ultralytics/nn/autobackend.py
CHANGED
@@ -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(
|
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 =
|
1445
|
+
ckpt = torch_load(f, pickle_module=safe_pickle)
|
1445
1446
|
else:
|
1446
|
-
ckpt =
|
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 =
|
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.
|
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
|
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(
|
58
|
-
self.device = select_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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
154
|
+
LOGGER.info("\nRanked Results:")
|
156
155
|
for name, score in results:
|
157
|
-
|
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
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
self.
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
if
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
self.
|
135
|
-
|
136
|
-
|
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
|
"""
|
ultralytics/utils/__init__.py
CHANGED
@@ -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,
|
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
|
ultralytics/utils/checks.py
CHANGED
@@ -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.
|
ultralytics/utils/metrics.py
CHANGED
@@ -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
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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")
|
ultralytics/utils/patches.py
CHANGED
@@ -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
|
118
|
+
return torch.load(*args, **kwargs)
|
120
119
|
|
121
120
|
|
122
121
|
def torch_save(*args, **kwargs):
|
ultralytics/utils/plotting.py
CHANGED
@@ -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
|
614
|
-
for s in
|
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"
|
ultralytics/utils/torch_utils.py
CHANGED
@@ -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 =
|
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.
|
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">
|