ultralytics 8.3.111__py3-none-any.whl → 8.3.112__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.
- ultralytics/__init__.py +1 -1
- ultralytics/cfg/__init__.py +14 -16
- ultralytics/cfg/datasets/coco8-multispectral.yaml +104 -0
- ultralytics/data/augment.py +16 -6
- ultralytics/data/base.py +24 -26
- ultralytics/data/converter.py +52 -3
- ultralytics/data/dataset.py +5 -5
- ultralytics/data/loaders.py +7 -9
- ultralytics/data/split.py +123 -0
- ultralytics/data/utils.py +34 -52
- ultralytics/engine/exporter.py +22 -24
- ultralytics/engine/model.py +3 -6
- ultralytics/engine/predictor.py +5 -3
- ultralytics/engine/results.py +7 -7
- ultralytics/engine/trainer.py +4 -5
- ultralytics/engine/tuner.py +1 -1
- ultralytics/engine/validator.py +4 -4
- ultralytics/hub/auth.py +1 -1
- ultralytics/hub/session.py +3 -3
- ultralytics/models/rtdetr/train.py +1 -22
- ultralytics/models/sam/modules/sam.py +2 -1
- ultralytics/models/yolo/classify/train.py +1 -1
- ultralytics/models/yolo/detect/train.py +2 -2
- ultralytics/models/yolo/detect/val.py +1 -1
- ultralytics/models/yolo/obb/train.py +1 -1
- ultralytics/models/yolo/pose/predict.py +1 -1
- ultralytics/models/yolo/pose/train.py +4 -2
- ultralytics/models/yolo/pose/val.py +1 -1
- ultralytics/models/yolo/segment/train.py +1 -1
- ultralytics/models/yolo/segment/val.py +1 -1
- ultralytics/models/yolo/world/train.py +1 -1
- ultralytics/models/yolo/world/train_world.py +1 -0
- ultralytics/models/yolo/yoloe/train.py +2 -2
- ultralytics/models/yolo/yoloe/train_seg.py +2 -2
- ultralytics/nn/autobackend.py +7 -4
- ultralytics/nn/tasks.py +11 -11
- ultralytics/solutions/instance_segmentation.py +1 -1
- ultralytics/solutions/object_blurrer.py +1 -1
- ultralytics/solutions/object_cropper.py +2 -2
- ultralytics/solutions/parking_management.py +1 -1
- ultralytics/solutions/security_alarm.py +1 -1
- ultralytics/solutions/solutions.py +3 -6
- ultralytics/trackers/byte_tracker.py +1 -1
- ultralytics/trackers/utils/gmc.py +4 -4
- ultralytics/utils/__init__.py +28 -21
- ultralytics/utils/autobatch.py +4 -4
- ultralytics/utils/benchmarks.py +8 -8
- ultralytics/utils/callbacks/clearml.py +1 -1
- ultralytics/utils/callbacks/comet.py +5 -5
- ultralytics/utils/callbacks/dvc.py +1 -1
- ultralytics/utils/callbacks/mlflow.py +2 -1
- ultralytics/utils/callbacks/neptune.py +1 -1
- ultralytics/utils/callbacks/tensorboard.py +7 -9
- ultralytics/utils/checks.py +20 -26
- ultralytics/utils/downloads.py +4 -4
- ultralytics/utils/export.py +1 -1
- ultralytics/utils/metrics.py +1 -1
- ultralytics/utils/ops.py +1 -1
- ultralytics/utils/patches.py +8 -1
- ultralytics/utils/plotting.py +27 -29
- ultralytics/utils/tal.py +1 -1
- ultralytics/utils/torch_utils.py +4 -4
- ultralytics/utils/tuner.py +2 -2
- {ultralytics-8.3.111.dist-info → ultralytics-8.3.112.dist-info}/METADATA +1 -1
- {ultralytics-8.3.111.dist-info → ultralytics-8.3.112.dist-info}/RECORD +69 -67
- {ultralytics-8.3.111.dist-info → ultralytics-8.3.112.dist-info}/WHEEL +1 -1
- {ultralytics-8.3.111.dist-info → ultralytics-8.3.112.dist-info}/entry_points.txt +0 -0
- {ultralytics-8.3.111.dist-info → ultralytics-8.3.112.dist-info}/licenses/LICENSE +0 -0
- {ultralytics-8.3.111.dist-info → ultralytics-8.3.112.dist-info}/top_level.txt +0 -0
ultralytics/engine/tuner.py
CHANGED
@@ -198,7 +198,7 @@ class Tuner:
|
|
198
198
|
assert return_code == 0, "training failed"
|
199
199
|
|
200
200
|
except Exception as e:
|
201
|
-
LOGGER.
|
201
|
+
LOGGER.error(f"training failure for hyperparameter tuning iteration {i + 1}\n{e}")
|
202
202
|
|
203
203
|
# Save results and mutated_hyp to CSV
|
204
204
|
fitness = metrics.get("fitness", 0.0)
|
ultralytics/engine/validator.py
CHANGED
@@ -155,7 +155,7 @@ class BaseValidator:
|
|
155
155
|
model.eval()
|
156
156
|
else:
|
157
157
|
if str(self.args.model).endswith(".yaml") and model is None:
|
158
|
-
LOGGER.warning("
|
158
|
+
LOGGER.warning("validating an untrained model YAML will result in 0 mAP.")
|
159
159
|
callbacks.add_integration_callbacks(self)
|
160
160
|
model = AutoBackend(
|
161
161
|
weights=model or self.args.model,
|
@@ -171,7 +171,7 @@ class BaseValidator:
|
|
171
171
|
imgsz = check_imgsz(self.args.imgsz, stride=stride)
|
172
172
|
if engine:
|
173
173
|
self.args.batch = model.batch_size
|
174
|
-
elif not pt
|
174
|
+
elif not (pt or jit or getattr(model, "dynamic", False)):
|
175
175
|
self.args.batch = model.metadata.get("batch", 1) # export.py models default to batch-size 1
|
176
176
|
LOGGER.info(f"Setting batch={self.args.batch} input of shape ({self.args.batch}, 3, {imgsz}, {imgsz})")
|
177
177
|
|
@@ -184,13 +184,13 @@ class BaseValidator:
|
|
184
184
|
|
185
185
|
if self.device.type in {"cpu", "mps"}:
|
186
186
|
self.args.workers = 0 # faster CPU val as time dominated by inference, not dataloading
|
187
|
-
if not pt:
|
187
|
+
if not (pt or getattr(model, "dynamic", False)):
|
188
188
|
self.args.rect = False
|
189
189
|
self.stride = model.stride # used in get_dataloader() for padding
|
190
190
|
self.dataloader = self.dataloader or self.get_dataloader(self.data.get(self.args.split), self.args.batch)
|
191
191
|
|
192
192
|
model.eval()
|
193
|
-
model.warmup(imgsz=(1 if pt else self.args.batch,
|
193
|
+
model.warmup(imgsz=(1 if pt else self.args.batch, self.data["channels"], imgsz, imgsz)) # warmup
|
194
194
|
|
195
195
|
self.run_callbacks("on_val_start")
|
196
196
|
dt = (
|
ultralytics/hub/auth.py
CHANGED
@@ -98,7 +98,7 @@ class Auth:
|
|
98
98
|
raise ConnectionError("User has not authenticated locally.")
|
99
99
|
except ConnectionError:
|
100
100
|
self.id_token = self.api_key = False # reset invalid
|
101
|
-
LOGGER.warning(f"{PREFIX}Invalid API key
|
101
|
+
LOGGER.warning(f"{PREFIX}Invalid API key")
|
102
102
|
return False
|
103
103
|
|
104
104
|
def auth_with_cookies(self) -> bool:
|
ultralytics/hub/session.py
CHANGED
@@ -84,7 +84,7 @@ class HUBTrainingSession:
|
|
84
84
|
except Exception:
|
85
85
|
if identifier.startswith(f"{HUB_WEB_ROOT}/models/") and not self.client.authenticated:
|
86
86
|
LOGGER.warning(
|
87
|
-
f"{PREFIX}
|
87
|
+
f"{PREFIX}Please log in using 'yolo login API_KEY'. "
|
88
88
|
"You can find your API Key at: https://hub.ultralytics.com/settings?tab=api+keys."
|
89
89
|
)
|
90
90
|
|
@@ -396,14 +396,14 @@ class HUBTrainingSession:
|
|
396
396
|
last = weights.with_name(f"last{weights.suffix}")
|
397
397
|
if final and last.is_file():
|
398
398
|
LOGGER.warning(
|
399
|
-
f"{PREFIX}
|
399
|
+
f"{PREFIX} Model 'best.pt' not found, copying 'last.pt' to 'best.pt' and uploading. "
|
400
400
|
"This often happens when resuming training in transient environments like Google Colab. "
|
401
401
|
"For more reliable training, consider using Ultralytics HUB Cloud. "
|
402
402
|
"Learn more at https://docs.ultralytics.com/hub/cloud-training."
|
403
403
|
)
|
404
404
|
shutil.copy(last, weights) # copy last.pt to best.pt
|
405
405
|
else:
|
406
|
-
LOGGER.warning(f"{PREFIX}
|
406
|
+
LOGGER.warning(f"{PREFIX} Model upload issue. Missing model {weights}.")
|
407
407
|
return
|
408
408
|
|
409
409
|
self.request_queue(
|
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
from copy import copy
|
4
4
|
|
5
|
-
import torch
|
6
|
-
|
7
5
|
from ultralytics.models.yolo.detect import DetectionTrainer
|
8
6
|
from ultralytics.nn.tasks import RTDETRDetectionModel
|
9
7
|
from ultralytics.utils import RANK, colorstr
|
@@ -49,7 +47,7 @@ class RTDETRTrainer(DetectionTrainer):
|
|
49
47
|
Returns:
|
50
48
|
(RTDETRDetectionModel): Initialized model.
|
51
49
|
"""
|
52
|
-
model = RTDETRDetectionModel(cfg, nc=self.data["nc"], verbose=verbose and RANK == -1)
|
50
|
+
model = RTDETRDetectionModel(cfg, nc=self.data["nc"], ch=self.data["channels"], verbose=verbose and RANK == -1)
|
53
51
|
if weights:
|
54
52
|
model.load(weights)
|
55
53
|
return model
|
@@ -85,22 +83,3 @@ class RTDETRTrainer(DetectionTrainer):
|
|
85
83
|
"""Returns a DetectionValidator suitable for RT-DETR model validation."""
|
86
84
|
self.loss_names = "giou_loss", "cls_loss", "l1_loss"
|
87
85
|
return RTDETRValidator(self.test_loader, save_dir=self.save_dir, args=copy(self.args))
|
88
|
-
|
89
|
-
def preprocess_batch(self, batch):
|
90
|
-
"""
|
91
|
-
Preprocess a batch of images by scaling and converting to float format.
|
92
|
-
|
93
|
-
Args:
|
94
|
-
batch (dict): Dictionary containing a batch of images, bboxes, and labels.
|
95
|
-
|
96
|
-
Returns:
|
97
|
-
(dict): Preprocessed batch with ground truth bounding boxes and classes separated by batch index.
|
98
|
-
"""
|
99
|
-
batch = super().preprocess_batch(batch)
|
100
|
-
bs = len(batch["img"])
|
101
|
-
batch_idx = batch["batch_idx"]
|
102
|
-
gt_bbox, gt_class = [], []
|
103
|
-
for i in range(bs):
|
104
|
-
gt_bbox.append(batch["bboxes"][batch_idx == i].to(batch_idx.device))
|
105
|
-
gt_class.append(batch["cls"][batch_idx == i].to(device=batch_idx.device, dtype=torch.long))
|
106
|
-
return batch
|
@@ -14,6 +14,7 @@ from torch import nn
|
|
14
14
|
from torch.nn.init import trunc_normal_
|
15
15
|
|
16
16
|
from ultralytics.nn.modules import MLP
|
17
|
+
from ultralytics.utils import LOGGER
|
17
18
|
|
18
19
|
from .blocks import SAM2TwoWayTransformer
|
19
20
|
from .decoders import MaskDecoder, SAM2MaskDecoder
|
@@ -322,7 +323,7 @@ class SAM2Model(torch.nn.Module):
|
|
322
323
|
# Model compilation
|
323
324
|
if compile_image_encoder:
|
324
325
|
# Compile the forward function (not the full module) to allow loading checkpoints.
|
325
|
-
|
326
|
+
LOGGER.info("Image encoder compilation is enabled. First forward pass will be slow.")
|
326
327
|
self.image_encoder.forward = torch.compile(
|
327
328
|
self.image_encoder.forward,
|
328
329
|
mode="max-autotune",
|
@@ -88,7 +88,7 @@ class ClassificationTrainer(BaseTrainer):
|
|
88
88
|
Returns:
|
89
89
|
(ClassificationModel): Configured PyTorch model for classification.
|
90
90
|
"""
|
91
|
-
model = ClassificationModel(cfg, nc=self.data["nc"], verbose=verbose and RANK == -1)
|
91
|
+
model = ClassificationModel(cfg, nc=self.data["nc"], ch=self.data["channels"], verbose=verbose and RANK == -1)
|
92
92
|
if weights:
|
93
93
|
model.load(weights)
|
94
94
|
|
@@ -82,7 +82,7 @@ class DetectionTrainer(BaseTrainer):
|
|
82
82
|
dataset = self.build_dataset(dataset_path, mode, batch_size)
|
83
83
|
shuffle = mode == "train"
|
84
84
|
if getattr(dataset, "rect", False) and shuffle:
|
85
|
-
LOGGER.warning("
|
85
|
+
LOGGER.warning("'rect=True' is incompatible with DataLoader shuffle, setting shuffle=False")
|
86
86
|
shuffle = False
|
87
87
|
workers = self.args.workers if mode == "train" else self.args.workers * 2
|
88
88
|
return build_dataloader(dataset, batch_size, workers, shuffle, rank) # return dataloader
|
@@ -137,7 +137,7 @@ class DetectionTrainer(BaseTrainer):
|
|
137
137
|
Returns:
|
138
138
|
(DetectionModel): YOLO detection model.
|
139
139
|
"""
|
140
|
-
model = DetectionModel(cfg, nc=self.data["nc"], verbose=verbose and RANK == -1)
|
140
|
+
model = DetectionModel(cfg, nc=self.data["nc"], ch=self.data["channels"], verbose=verbose and RANK == -1)
|
141
141
|
if weights:
|
142
142
|
model.load(weights)
|
143
143
|
return model
|
@@ -257,7 +257,7 @@ class DetectionValidator(BaseValidator):
|
|
257
257
|
pf = "%22s" + "%11i" * 2 + "%11.3g" * len(self.metrics.keys) # print format
|
258
258
|
LOGGER.info(pf % ("all", self.seen, self.nt_per_class.sum(), *self.metrics.mean_results()))
|
259
259
|
if self.nt_per_class.sum() == 0:
|
260
|
-
LOGGER.warning(f"
|
260
|
+
LOGGER.warning(f"no labels found in {self.args.task} set, can not compute metrics without labels")
|
261
261
|
|
262
262
|
# Print results per class
|
263
263
|
if self.args.verbose and not self.training and self.nc > 1 and len(self.stats):
|
@@ -67,7 +67,7 @@ class OBBTrainer(yolo.detect.DetectionTrainer):
|
|
67
67
|
>>> trainer = OBBTrainer()
|
68
68
|
>>> model = trainer.get_model(cfg="yolov8n-obb.yaml", weights="yolov8n-obb.pt")
|
69
69
|
"""
|
70
|
-
model = OBBModel(cfg,
|
70
|
+
model = OBBModel(cfg, nc=self.data["nc"], ch=self.data["channels"], verbose=verbose and RANK == -1)
|
71
71
|
if weights:
|
72
72
|
model.load(weights)
|
73
73
|
|
@@ -49,7 +49,7 @@ class PosePredictor(DetectionPredictor):
|
|
49
49
|
self.args.task = "pose"
|
50
50
|
if isinstance(self.args.device, str) and self.args.device.lower() == "mps":
|
51
51
|
LOGGER.warning(
|
52
|
-
"
|
52
|
+
"Apple MPS known Pose bug. Recommend 'device=cpu' for Pose models. "
|
53
53
|
"See https://github.com/ultralytics/ultralytics/issues/4031."
|
54
54
|
)
|
55
55
|
|
@@ -64,7 +64,7 @@ class PoseTrainer(yolo.detect.DetectionTrainer):
|
|
64
64
|
|
65
65
|
if isinstance(self.args.device, str) and self.args.device.lower() == "mps":
|
66
66
|
LOGGER.warning(
|
67
|
-
"
|
67
|
+
"Apple MPS known Pose bug. Recommend 'device=cpu' for Pose models. "
|
68
68
|
"See https://github.com/ultralytics/ultralytics/issues/4031."
|
69
69
|
)
|
70
70
|
|
@@ -80,7 +80,9 @@ class PoseTrainer(yolo.detect.DetectionTrainer):
|
|
80
80
|
Returns:
|
81
81
|
(PoseModel): Initialized pose estimation model.
|
82
82
|
"""
|
83
|
-
model = PoseModel(
|
83
|
+
model = PoseModel(
|
84
|
+
cfg, nc=self.data["nc"], ch=self.data["channels"], data_kpt_shape=self.data["kpt_shape"], verbose=verbose
|
85
|
+
)
|
84
86
|
if weights:
|
85
87
|
model.load(weights)
|
86
88
|
|
@@ -78,7 +78,7 @@ class PoseValidator(DetectionValidator):
|
|
78
78
|
self.metrics = PoseMetrics(save_dir=self.save_dir)
|
79
79
|
if isinstance(self.args.device, str) and self.args.device.lower() == "mps":
|
80
80
|
LOGGER.warning(
|
81
|
-
"
|
81
|
+
"Apple MPS known Pose bug. Recommend 'device=cpu' for Pose models. "
|
82
82
|
"See https://github.com/ultralytics/ultralytics/issues/4031."
|
83
83
|
)
|
84
84
|
|
@@ -65,7 +65,7 @@ class SegmentationTrainer(yolo.detect.DetectionTrainer):
|
|
65
65
|
>>> model = trainer.get_model(cfg="yolov8n-seg.yaml")
|
66
66
|
>>> model = trainer.get_model(weights="yolov8n-seg.pt", verbose=False)
|
67
67
|
"""
|
68
|
-
model = SegmentationModel(cfg,
|
68
|
+
model = SegmentationModel(cfg, nc=self.data["nc"], ch=self.data["channels"], verbose=verbose and RANK == -1)
|
69
69
|
if weights:
|
70
70
|
model.load(weights)
|
71
71
|
|
@@ -192,7 +192,7 @@ class SegmentationValidator(DetectionValidator):
|
|
192
192
|
if self.args.plots and self.batch_i < 3:
|
193
193
|
self.plot_masks.append(pred_masks[:50].cpu()) # Limit plotted items for speed
|
194
194
|
if pred_masks.shape[0] > 50:
|
195
|
-
LOGGER.warning("
|
195
|
+
LOGGER.warning("Limiting validation plots to first 50 items per image for speed...")
|
196
196
|
|
197
197
|
# Save
|
198
198
|
if self.args.save_json:
|
@@ -79,7 +79,7 @@ class WorldTrainer(yolo.detect.DetectionTrainer):
|
|
79
79
|
# NOTE: Following the official config, nc hard-coded to 80 for now.
|
80
80
|
model = WorldModel(
|
81
81
|
cfg["yaml_file"] if isinstance(cfg, dict) else cfg,
|
82
|
-
ch=
|
82
|
+
ch=self.data["channels"],
|
83
83
|
nc=min(self.data["nc"], 80),
|
84
84
|
verbose=verbose and RANK == -1,
|
85
85
|
)
|
@@ -140,6 +140,7 @@ class WorldTrainerFromScratch(WorldTrainer):
|
|
140
140
|
# NOTE: to make training work properly, set `nc` and `names`
|
141
141
|
final_data["nc"] = data["val"][0]["nc"]
|
142
142
|
final_data["names"] = data["val"][0]["names"]
|
143
|
+
final_data["channels"] = data["val"][0]["channels"]
|
143
144
|
self.data = final_data
|
144
145
|
return final_data["train"], final_data["val"][0]
|
145
146
|
|
@@ -59,7 +59,7 @@ class YOLOETrainer(DetectionTrainer):
|
|
59
59
|
# NOTE: Following the official config, nc hard-coded to 80 for now.
|
60
60
|
model = YOLOEModel(
|
61
61
|
cfg["yaml_file"] if isinstance(cfg, dict) else cfg,
|
62
|
-
ch=
|
62
|
+
ch=self.data["channels"],
|
63
63
|
nc=min(self.data["nc"], 80),
|
64
64
|
verbose=verbose and RANK == -1,
|
65
65
|
)
|
@@ -117,7 +117,7 @@ class YOLOEPETrainer(DetectionTrainer):
|
|
117
117
|
# NOTE: Following the official config, nc hard-coded to 80 for now.
|
118
118
|
model = YOLOEModel(
|
119
119
|
cfg["yaml_file"] if isinstance(cfg, dict) else cfg,
|
120
|
-
ch=
|
120
|
+
ch=self.data["channels"],
|
121
121
|
nc=self.data["nc"],
|
122
122
|
verbose=verbose and RANK == -1,
|
123
123
|
)
|
@@ -56,7 +56,7 @@ class YOLOESegTrainer(YOLOETrainer, SegmentationTrainer):
|
|
56
56
|
# NOTE: Following the official config, nc hard-coded to 80 for now.
|
57
57
|
model = YOLOESegModel(
|
58
58
|
cfg["yaml_file"] if isinstance(cfg, dict) else cfg,
|
59
|
-
ch=
|
59
|
+
ch=self.data["channels"],
|
60
60
|
nc=min(self.data["nc"], 80),
|
61
61
|
verbose=verbose and RANK == -1,
|
62
62
|
)
|
@@ -102,7 +102,7 @@ class YOLOEPESegTrainer(SegmentationTrainer):
|
|
102
102
|
# NOTE: Following the official config, nc hard-coded to 80 for now.
|
103
103
|
model = YOLOESegModel(
|
104
104
|
cfg["yaml_file"] if isinstance(cfg, dict) else cfg,
|
105
|
-
ch=
|
105
|
+
ch=self.data["channels"],
|
106
106
|
nc=self.data["nc"],
|
107
107
|
verbose=verbose and RANK == -1,
|
108
108
|
)
|
ultralytics/nn/autobackend.py
CHANGED
@@ -143,7 +143,7 @@ class AutoBackend(nn.Module):
|
|
143
143
|
) = self._model_type(w)
|
144
144
|
fp16 &= pt or jit or onnx or xml or engine or nn_module or triton # FP16
|
145
145
|
nhwc = coreml or saved_model or pb or tflite or edgetpu or rknn # BHWC formats (vs torch BCWH)
|
146
|
-
stride = 32 # default stride
|
146
|
+
stride, ch = 32, 3 # default stride and channels
|
147
147
|
end2end, dynamic = False, False
|
148
148
|
model, metadata, task = None, None, None
|
149
149
|
|
@@ -167,6 +167,7 @@ class AutoBackend(nn.Module):
|
|
167
167
|
stride = max(int(model.stride.max()), 32) # model stride
|
168
168
|
names = model.module.names if hasattr(model, "module") else model.names # get class names
|
169
169
|
model.half() if fp16 else model.float()
|
170
|
+
ch = model.yaml.get("channels", 3)
|
170
171
|
self.model = model # explicitly assign for to(), cpu(), cuda(), half()
|
171
172
|
pt = True
|
172
173
|
|
@@ -182,6 +183,7 @@ class AutoBackend(nn.Module):
|
|
182
183
|
stride = max(int(model.stride.max()), 32) # model stride
|
183
184
|
names = model.module.names if hasattr(model, "module") else model.names # get class names
|
184
185
|
model.half() if fp16 else model.float()
|
186
|
+
ch = model.yaml.get("channels", 3)
|
185
187
|
self.model = model # explicitly assign for to(), cpu(), cuda(), half()
|
186
188
|
|
187
189
|
# TorchScript
|
@@ -215,7 +217,7 @@ class AutoBackend(nn.Module):
|
|
215
217
|
if "CUDAExecutionProvider" in onnxruntime.get_available_providers():
|
216
218
|
providers.insert(0, "CUDAExecutionProvider")
|
217
219
|
else: # Only log warning if CUDA was requested but unavailable
|
218
|
-
LOGGER.warning("
|
220
|
+
LOGGER.warning("Failed to start ONNX Runtime with CUDA. Using CPU...")
|
219
221
|
device = torch.device("cpu")
|
220
222
|
cuda = False
|
221
223
|
LOGGER.info(f"Using ONNX Runtime {providers[0]}")
|
@@ -316,7 +318,7 @@ class AutoBackend(nn.Module):
|
|
316
318
|
try:
|
317
319
|
context = model.create_execution_context()
|
318
320
|
except Exception as e: # model is None
|
319
|
-
LOGGER.error(f"
|
321
|
+
LOGGER.error(f"TensorRT model exported with a different version than {trt.__version__}\n")
|
320
322
|
raise e
|
321
323
|
|
322
324
|
bindings = OrderedDict()
|
@@ -541,8 +543,9 @@ class AutoBackend(nn.Module):
|
|
541
543
|
kpt_shape = metadata.get("kpt_shape")
|
542
544
|
end2end = metadata.get("args", {}).get("nms", False)
|
543
545
|
dynamic = metadata.get("args", {}).get("dynamic", dynamic)
|
546
|
+
ch = metadata.get("channels", 3)
|
544
547
|
elif not (pt or triton or nn_module):
|
545
|
-
LOGGER.warning(f"
|
548
|
+
LOGGER.warning(f"Metadata not found for 'model={weights}'")
|
546
549
|
|
547
550
|
# Check names
|
548
551
|
if "names" not in locals(): # names missing
|
ultralytics/nn/tasks.py
CHANGED
@@ -169,7 +169,7 @@ class BaseModel(torch.nn.Module):
|
|
169
169
|
def _predict_augment(self, x):
|
170
170
|
"""Perform augmentations on input image x and return augmented inference."""
|
171
171
|
LOGGER.warning(
|
172
|
-
f"
|
172
|
+
f"{self.__class__.__name__} does not support 'augment=True' prediction. "
|
173
173
|
f"Reverting to single-scale prediction."
|
174
174
|
)
|
175
175
|
return self._predict_once(x)
|
@@ -308,7 +308,7 @@ class BaseModel(torch.nn.Module):
|
|
308
308
|
class DetectionModel(BaseModel):
|
309
309
|
"""YOLO detection model."""
|
310
310
|
|
311
|
-
def __init__(self, cfg="yolo11n.yaml", ch=3, nc=None, verbose=True):
|
311
|
+
def __init__(self, cfg="yolo11n.yaml", ch=3, nc=None, verbose=True):
|
312
312
|
"""
|
313
313
|
Initialize the YOLO detection model with the given config and parameters.
|
314
314
|
|
@@ -322,13 +322,13 @@ class DetectionModel(BaseModel):
|
|
322
322
|
self.yaml = cfg if isinstance(cfg, dict) else yaml_model_load(cfg) # cfg dict
|
323
323
|
if self.yaml["backbone"][0][2] == "Silence":
|
324
324
|
LOGGER.warning(
|
325
|
-
"
|
325
|
+
"YOLOv9 `Silence` module is deprecated in favor of torch.nn.Identity. "
|
326
326
|
"Please delete local *.pt file and re-download the latest model checkpoint."
|
327
327
|
)
|
328
328
|
self.yaml["backbone"][0][2] = "nn.Identity"
|
329
329
|
|
330
330
|
# Define model
|
331
|
-
|
331
|
+
self.yaml["channels"] = ch # save channels
|
332
332
|
if nc and nc != self.yaml["nc"]:
|
333
333
|
LOGGER.info(f"Overriding model.yaml nc={self.yaml['nc']} with nc={nc}")
|
334
334
|
self.yaml["nc"] = nc # override YAML value
|
@@ -372,7 +372,7 @@ class DetectionModel(BaseModel):
|
|
372
372
|
(torch.Tensor): Augmented inference output.
|
373
373
|
"""
|
374
374
|
if getattr(self, "end2end", False) or self.__class__.__name__ != "DetectionModel":
|
375
|
-
LOGGER.warning("
|
375
|
+
LOGGER.warning("Model does not support 'augment=True', reverting to single-scale prediction.")
|
376
376
|
return self._predict_once(x)
|
377
377
|
img_size = x.shape[-2:] # height, width
|
378
378
|
s = [1, 0.83, 0.67] # scales
|
@@ -528,7 +528,7 @@ class ClassificationModel(BaseModel):
|
|
528
528
|
self.yaml = cfg if isinstance(cfg, dict) else yaml_model_load(cfg) # cfg dict
|
529
529
|
|
530
530
|
# Define model
|
531
|
-
ch = self.yaml["
|
531
|
+
ch = self.yaml["channels"] = self.yaml.get("channels", ch) # input channels
|
532
532
|
if nc and nc != self.yaml["nc"]:
|
533
533
|
LOGGER.info(f"Overriding model.yaml nc={self.yaml['nc']} with nc={nc}")
|
534
534
|
self.yaml["nc"] = nc # override YAML value
|
@@ -1222,7 +1222,7 @@ def torch_safe_load(weight, safe_only=False):
|
|
1222
1222
|
)
|
1223
1223
|
) from e
|
1224
1224
|
LOGGER.warning(
|
1225
|
-
f"
|
1225
|
+
f"{weight} appears to require '{e.name}', which is not in Ultralytics requirements."
|
1226
1226
|
f"\nAutoInstall will run now for '{e.name}' but this feature will be removed in the future."
|
1227
1227
|
f"\nRecommend fixes are to train a new model using the latest 'ultralytics' package or to "
|
1228
1228
|
f"run a command with an official Ultralytics model, i.e. 'yolo predict model=yolo11n.pt'"
|
@@ -1233,7 +1233,7 @@ def torch_safe_load(weight, safe_only=False):
|
|
1233
1233
|
if not isinstance(ckpt, dict):
|
1234
1234
|
# File is likely a YOLO instance saved with i.e. torch.save(model, "saved_model.pt")
|
1235
1235
|
LOGGER.warning(
|
1236
|
-
f"
|
1236
|
+
f"The file '{weight}' appears to be improperly saved or formatted. "
|
1237
1237
|
f"For optimal results, use model.save('filename.pt') to correctly save YOLO models."
|
1238
1238
|
)
|
1239
1239
|
ckpt = {"model": ckpt.model}
|
@@ -1350,7 +1350,7 @@ def parse_model(d, ch, verbose=True): # model_dict, input_channels(3)
|
|
1350
1350
|
scale = d.get("scale")
|
1351
1351
|
if not scale:
|
1352
1352
|
scale = tuple(scales.keys())[0]
|
1353
|
-
LOGGER.warning(f"
|
1353
|
+
LOGGER.warning(f"no model scale passed. Assuming scale='{scale}'.")
|
1354
1354
|
depth, width, max_channels = scales[scale]
|
1355
1355
|
|
1356
1356
|
if act:
|
@@ -1518,7 +1518,7 @@ def yaml_model_load(path):
|
|
1518
1518
|
path = Path(path)
|
1519
1519
|
if path.stem in (f"yolov{d}{x}6" for x in "nsmlx" for d in (5, 8)):
|
1520
1520
|
new_stem = re.sub(r"(\d+)([nslmx])6(.+)?$", r"\1\2-p6\3", path.stem)
|
1521
|
-
LOGGER.warning(f"
|
1521
|
+
LOGGER.warning(f"Ultralytics YOLO P6 models now use -p6 suffix. Renaming {path.stem} to {new_stem}.")
|
1522
1522
|
path = path.with_name(new_stem + path.suffix)
|
1523
1523
|
|
1524
1524
|
unified_path = re.sub(r"(\d+)([nslmx])(.+)?$", r"\1\3", str(path)) # i.e. yolov8x.yaml -> yolov8.yaml
|
@@ -1610,7 +1610,7 @@ def guess_model_task(model):
|
|
1610
1610
|
|
1611
1611
|
# Unable to determine task from model
|
1612
1612
|
LOGGER.warning(
|
1613
|
-
"
|
1613
|
+
"Unable to automatically guess model task, assuming 'task=detect'. "
|
1614
1614
|
"Explicitly define task for your model, i.e. 'task=detect', 'segment', 'classify','pose' or 'obb'."
|
1615
1615
|
)
|
1616
1616
|
return "detect" # assume detect
|
@@ -65,7 +65,7 @@ class InstanceSegmentation(BaseSolution):
|
|
65
65
|
|
66
66
|
# Iterate over detected classes, track IDs, and segmentation masks
|
67
67
|
if self.masks is None:
|
68
|
-
self.LOGGER.warning("
|
68
|
+
self.LOGGER.warning("No masks detected! Ensure you're using a supported Ultralytics segmentation model.")
|
69
69
|
plot_im = im0
|
70
70
|
else:
|
71
71
|
results = Results(im0, path=None, names=self.names, boxes=self.track_data.data, masks=self.masks.data)
|
@@ -43,7 +43,7 @@ class ObjectBlurrer(BaseSolution):
|
|
43
43
|
super().__init__(**kwargs)
|
44
44
|
blur_ratio = kwargs.get("blur_ratio", 0.5)
|
45
45
|
if blur_ratio < 0.1:
|
46
|
-
LOGGER.warning("
|
46
|
+
LOGGER.warning("blur ratio cannot be less than 0.1, updating it to default value 0.5")
|
47
47
|
blur_ratio = 0.5
|
48
48
|
self.blur_ratio = int(blur_ratio * 100)
|
49
49
|
|
@@ -44,8 +44,8 @@ class ObjectCropper(BaseSolution):
|
|
44
44
|
if not os.path.exists(self.crop_dir):
|
45
45
|
os.mkdir(self.crop_dir) # Create directory if it does not exist
|
46
46
|
if self.CFG["show"]:
|
47
|
-
self.LOGGER.
|
48
|
-
f"
|
47
|
+
self.LOGGER.warning(
|
48
|
+
f"show=True disabled for crop solution, results will be saved in the directory named: {self.crop_dir}"
|
49
49
|
)
|
50
50
|
self.crop_idx = 0 # Initialize counter for total cropped objects
|
51
51
|
self.iou = self.CFG["iou"]
|
@@ -61,7 +61,7 @@ class ParkingPtsSelection:
|
|
61
61
|
"Darwin": "reinstall Python from https://www.python.org/downloads/macos/ or `brew install python-tk`",
|
62
62
|
}.get(platform.system(), "Unknown OS. Check your Python installation.")
|
63
63
|
|
64
|
-
LOGGER.warning(f"
|
64
|
+
LOGGER.warning(f" Tkinter is not configured or supported. Potential fix: {install_cmd}")
|
65
65
|
return
|
66
66
|
|
67
67
|
if not check_imshow(warn=True):
|
@@ -112,7 +112,7 @@ class SecurityAlarm(BaseSolution):
|
|
112
112
|
self.server.send_message(message)
|
113
113
|
LOGGER.info("✅ Email sent successfully!")
|
114
114
|
except Exception as e:
|
115
|
-
LOGGER.error(f"
|
115
|
+
LOGGER.error(f"Failed to send email: {e}")
|
116
116
|
|
117
117
|
def process(self, im0):
|
118
118
|
"""
|
@@ -95,7 +95,7 @@ class BaseSolution:
|
|
95
95
|
|
96
96
|
if is_cli and self.CFG["source"] is None:
|
97
97
|
d_s = "solutions_ci_demo.mp4" if "-pose" not in self.CFG["model"] else "solution_ci_pose_demo.mp4"
|
98
|
-
self.LOGGER.warning(f"
|
98
|
+
self.LOGGER.warning(f"source not provided. using default source {ASSETS_URL}/{d_s}")
|
99
99
|
from ultralytics.utils.downloads import safe_download
|
100
100
|
|
101
101
|
safe_download(f"{ASSETS_URL}/{d_s}") # download source from ultralytics assets
|
@@ -129,7 +129,7 @@ class BaseSolution:
|
|
129
129
|
self.clss = self.track_data.cls.cpu().tolist()
|
130
130
|
self.track_ids = self.track_data.id.int().cpu().tolist()
|
131
131
|
else:
|
132
|
-
self.LOGGER.warning("
|
132
|
+
self.LOGGER.warning("no tracks found!")
|
133
133
|
self.boxes, self.clss, self.track_ids = [], [], []
|
134
134
|
|
135
135
|
def store_tracking_history(self, track_id, box):
|
@@ -574,11 +574,8 @@ class SolutionAnnotator(Annotator):
|
|
574
574
|
txt_color (Tuple[int, int, int]): The color of the text (R, G, B).
|
575
575
|
margin (int): The margin between the text and the circle border.
|
576
576
|
"""
|
577
|
-
# If label have more than 3 characters, skip other characters, due to circle size
|
578
577
|
if len(label) > 3:
|
579
|
-
|
580
|
-
f"Length of label is {len(label)}, initial 3 label characters will be considered for circle annotation!"
|
581
|
-
)
|
578
|
+
LOGGER.warning(f"Length of label is {len(label)}, only first 3 letters will be used for circle annotation.")
|
582
579
|
label = label[:3]
|
583
580
|
|
584
581
|
# Calculate the center of the box
|
@@ -217,7 +217,7 @@ class STrack(BaseTrack):
|
|
217
217
|
def xywha(self):
|
218
218
|
"""Returns position in (center x, center y, width, height, angle) format, warning if angle is missing."""
|
219
219
|
if self.angle is None:
|
220
|
-
LOGGER.warning("
|
220
|
+
LOGGER.warning("`angle` attr not found, returning `xywh` instead.")
|
221
221
|
return self.xywh
|
222
222
|
return np.concatenate([self.xywh, self.angle[None]])
|
223
223
|
|
@@ -81,7 +81,7 @@ class GMC:
|
|
81
81
|
elif self.method in {"none", "None", None}:
|
82
82
|
self.method = None
|
83
83
|
else:
|
84
|
-
raise ValueError(f"
|
84
|
+
raise ValueError(f"Unknown GMC method: {method}")
|
85
85
|
|
86
86
|
self.prevFrame = None
|
87
87
|
self.prevKeyPoints = None
|
@@ -156,7 +156,7 @@ class GMC:
|
|
156
156
|
try:
|
157
157
|
(_, H) = cv2.findTransformECC(self.prevFrame, frame, H, self.warp_mode, self.criteria, None, 1)
|
158
158
|
except Exception as e:
|
159
|
-
LOGGER.warning(f"
|
159
|
+
LOGGER.warning(f"find transform failed. Set warp as identity {e}")
|
160
160
|
|
161
161
|
return H
|
162
162
|
|
@@ -294,7 +294,7 @@ class GMC:
|
|
294
294
|
H[0, 2] *= self.downscale
|
295
295
|
H[1, 2] *= self.downscale
|
296
296
|
else:
|
297
|
-
LOGGER.warning("
|
297
|
+
LOGGER.warning("not enough matching points")
|
298
298
|
|
299
299
|
# Store to next iteration
|
300
300
|
self.prevFrame = frame.copy()
|
@@ -361,7 +361,7 @@ class GMC:
|
|
361
361
|
H[0, 2] *= self.downscale
|
362
362
|
H[1, 2] *= self.downscale
|
363
363
|
else:
|
364
|
-
LOGGER.warning("
|
364
|
+
LOGGER.warning("not enough matching points")
|
365
365
|
|
366
366
|
self.prevFrame = frame.copy()
|
367
367
|
self.prevKeyPoints = copy.copy(keypoints)
|