ultralytics 8.2.48__py3-none-any.whl → 8.2.49__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/conftest.py +17 -5
- tests/test_cli.py +8 -8
- tests/test_cuda.py +5 -5
- tests/test_engine.py +5 -5
- tests/test_explorer.py +4 -4
- tests/test_exports.py +12 -24
- tests/test_integrations.py +9 -5
- tests/test_python.py +35 -39
- ultralytics/__init__.py +1 -1
- ultralytics/cfg/__init__.py +142 -36
- ultralytics/data/explorer/explorer.py +3 -0
- ultralytics/engine/model.py +1 -1
- ultralytics/engine/results.py +159 -67
- ultralytics/hub/session.py +2 -0
- ultralytics/models/yolo/classify/train.py +7 -16
- ultralytics/nn/modules/block.py +1 -0
- ultralytics/solutions/ai_gym.py +3 -3
- ultralytics/utils/__init__.py +0 -1
- ultralytics/utils/metrics.py +1 -2
- ultralytics/utils/torch_utils.py +22 -8
- {ultralytics-8.2.48.dist-info → ultralytics-8.2.49.dist-info}/METADATA +1 -1
- {ultralytics-8.2.48.dist-info → ultralytics-8.2.49.dist-info}/RECORD +26 -26
- {ultralytics-8.2.48.dist-info → ultralytics-8.2.49.dist-info}/WHEEL +1 -1
- {ultralytics-8.2.48.dist-info → ultralytics-8.2.49.dist-info}/LICENSE +0 -0
- {ultralytics-8.2.48.dist-info → ultralytics-8.2.49.dist-info}/entry_points.txt +0 -0
- {ultralytics-8.2.48.dist-info → ultralytics-8.2.49.dist-info}/top_level.txt +0 -0
tests/test_python.py
CHANGED
|
@@ -38,7 +38,7 @@ def test_model_forward():
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
def test_model_methods():
|
|
41
|
-
"""Test various methods and properties of the YOLO model."""
|
|
41
|
+
"""Test various methods and properties of the YOLO model to ensure correct functionality."""
|
|
42
42
|
model = YOLO(MODEL)
|
|
43
43
|
|
|
44
44
|
# Model methods
|
|
@@ -58,7 +58,7 @@ def test_model_methods():
|
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
def test_model_profile():
|
|
61
|
-
"""Test profiling of the YOLO model with
|
|
61
|
+
"""Test profiling of the YOLO model with `profile=True` to assess performance and resource usage."""
|
|
62
62
|
from ultralytics.nn.tasks import DetectionModel
|
|
63
63
|
|
|
64
64
|
model = DetectionModel() # build model
|
|
@@ -68,7 +68,7 @@ def test_model_profile():
|
|
|
68
68
|
|
|
69
69
|
@pytest.mark.skipif(not IS_TMP_WRITEABLE, reason="directory is not writeable")
|
|
70
70
|
def test_predict_txt():
|
|
71
|
-
"""
|
|
71
|
+
"""Tests YOLO predictions with file, directory, and pattern sources listed in a text file."""
|
|
72
72
|
txt_file = TMP / "sources.txt"
|
|
73
73
|
with open(txt_file, "w") as f:
|
|
74
74
|
for x in [ASSETS / "bus.jpg", ASSETS, ASSETS / "*", ASSETS / "**/*.jpg"]:
|
|
@@ -78,7 +78,7 @@ def test_predict_txt():
|
|
|
78
78
|
|
|
79
79
|
@pytest.mark.parametrize("model_name", MODELS)
|
|
80
80
|
def test_predict_img(model_name):
|
|
81
|
-
"""Test YOLO
|
|
81
|
+
"""Test YOLO model predictions on various image input types and sources, including online images."""
|
|
82
82
|
model = YOLO(WEIGHTS_DIR / model_name)
|
|
83
83
|
im = cv2.imread(str(SOURCE)) # uint8 numpy array
|
|
84
84
|
assert len(model(source=Image.open(SOURCE), save=True, verbose=True, imgsz=32)) == 1 # PIL
|
|
@@ -100,12 +100,12 @@ def test_predict_img(model_name):
|
|
|
100
100
|
|
|
101
101
|
@pytest.mark.parametrize("model", MODELS)
|
|
102
102
|
def test_predict_visualize(model):
|
|
103
|
-
"""Test model
|
|
103
|
+
"""Test model prediction methods with 'visualize=True' to generate and display prediction visualizations."""
|
|
104
104
|
YOLO(WEIGHTS_DIR / model)(SOURCE, imgsz=32, visualize=True)
|
|
105
105
|
|
|
106
106
|
|
|
107
107
|
def test_predict_grey_and_4ch():
|
|
108
|
-
"""Test YOLO prediction on SOURCE converted to greyscale and 4-channel images."""
|
|
108
|
+
"""Test YOLO prediction on SOURCE converted to greyscale and 4-channel images with various filenames."""
|
|
109
109
|
im = Image.open(SOURCE)
|
|
110
110
|
directory = TMP / "im4"
|
|
111
111
|
directory.mkdir(parents=True, exist_ok=True)
|
|
@@ -132,11 +132,7 @@ def test_predict_grey_and_4ch():
|
|
|
132
132
|
@pytest.mark.slow
|
|
133
133
|
@pytest.mark.skipif(not ONLINE, reason="environment is offline")
|
|
134
134
|
def test_youtube():
|
|
135
|
-
"""
|
|
136
|
-
Test YouTube inference.
|
|
137
|
-
|
|
138
|
-
Note: ConnectionError may occur during this test due to network instability or YouTube server availability.
|
|
139
|
-
"""
|
|
135
|
+
"""Test YOLO model on a YouTube video stream, handling potential network-related errors."""
|
|
140
136
|
model = YOLO(MODEL)
|
|
141
137
|
try:
|
|
142
138
|
model.predict("https://youtu.be/G17sBkb38XQ", imgsz=96, save=True)
|
|
@@ -149,9 +145,9 @@ def test_youtube():
|
|
|
149
145
|
@pytest.mark.skipif(not IS_TMP_WRITEABLE, reason="directory is not writeable")
|
|
150
146
|
def test_track_stream():
|
|
151
147
|
"""
|
|
152
|
-
|
|
148
|
+
Tests streaming tracking on a short 10 frame video using ByteTrack tracker and different GMC methods.
|
|
153
149
|
|
|
154
|
-
Note imgsz=160 required for tracking for higher confidence and better matches
|
|
150
|
+
Note imgsz=160 required for tracking for higher confidence and better matches.
|
|
155
151
|
"""
|
|
156
152
|
video_url = "https://ultralytics.com/assets/decelera_portrait_min.mov"
|
|
157
153
|
model = YOLO(MODEL)
|
|
@@ -175,21 +171,21 @@ def test_val():
|
|
|
175
171
|
|
|
176
172
|
|
|
177
173
|
def test_train_scratch():
|
|
178
|
-
"""Test training the YOLO model from scratch."""
|
|
174
|
+
"""Test training the YOLO model from scratch using the provided configuration."""
|
|
179
175
|
model = YOLO(CFG)
|
|
180
176
|
model.train(data="coco8.yaml", epochs=2, imgsz=32, cache="disk", batch=-1, close_mosaic=1, name="model")
|
|
181
177
|
model(SOURCE)
|
|
182
178
|
|
|
183
179
|
|
|
184
180
|
def test_train_pretrained():
|
|
185
|
-
"""Test training the YOLO model from a pre-trained
|
|
181
|
+
"""Test training of the YOLO model starting from a pre-trained checkpoint."""
|
|
186
182
|
model = YOLO(WEIGHTS_DIR / "yolov8n-seg.pt")
|
|
187
183
|
model.train(data="coco8-seg.yaml", epochs=1, imgsz=32, cache="ram", copy_paste=0.5, mixup=0.5, name=0)
|
|
188
184
|
model(SOURCE)
|
|
189
185
|
|
|
190
186
|
|
|
191
187
|
def test_all_model_yamls():
|
|
192
|
-
"""Test YOLO model creation for all available YAML configurations."""
|
|
188
|
+
"""Test YOLO model creation for all available YAML configurations in the `cfg/models` directory."""
|
|
193
189
|
for m in (ROOT / "cfg" / "models").rglob("*.yaml"):
|
|
194
190
|
if "rtdetr" in m.name:
|
|
195
191
|
if TORCH_1_9: # torch<=1.8 issue - TypeError: __init__() got an unexpected keyword argument 'batch_first'
|
|
@@ -208,7 +204,7 @@ def test_workflow():
|
|
|
208
204
|
|
|
209
205
|
|
|
210
206
|
def test_predict_callback_and_setup():
|
|
211
|
-
"""Test callback functionality during YOLO prediction."""
|
|
207
|
+
"""Test callback functionality during YOLO prediction setup and execution."""
|
|
212
208
|
|
|
213
209
|
def on_predict_batch_end(predictor):
|
|
214
210
|
"""Callback function that handles operations at the end of a prediction batch."""
|
|
@@ -232,7 +228,7 @@ def test_predict_callback_and_setup():
|
|
|
232
228
|
|
|
233
229
|
@pytest.mark.parametrize("model", MODELS)
|
|
234
230
|
def test_results(model):
|
|
235
|
-
"""
|
|
231
|
+
"""Ensure YOLO model predictions can be processed and printed in various formats."""
|
|
236
232
|
results = YOLO(WEIGHTS_DIR / model)([SOURCE, SOURCE], imgsz=160)
|
|
237
233
|
for r in results:
|
|
238
234
|
r = r.cpu().numpy()
|
|
@@ -247,7 +243,7 @@ def test_results(model):
|
|
|
247
243
|
|
|
248
244
|
|
|
249
245
|
def test_labels_and_crops():
|
|
250
|
-
"""Test output from prediction args for saving detection labels and crops."""
|
|
246
|
+
"""Test output from prediction args for saving YOLO detection labels and crops; ensures accurate saving."""
|
|
251
247
|
imgs = [SOURCE, ASSETS / "zidane.jpg"]
|
|
252
248
|
results = YOLO(WEIGHTS_DIR / "yolov8n.pt")(imgs, imgsz=160, save_txt=True, save_crop=True)
|
|
253
249
|
save_path = Path(results[0].save_dir)
|
|
@@ -270,7 +266,7 @@ def test_labels_and_crops():
|
|
|
270
266
|
|
|
271
267
|
@pytest.mark.skipif(not ONLINE, reason="environment is offline")
|
|
272
268
|
def test_data_utils():
|
|
273
|
-
"""Test utility functions in ultralytics/data/utils.py."""
|
|
269
|
+
"""Test utility functions in ultralytics/data/utils.py, including dataset stats and auto-splitting."""
|
|
274
270
|
from ultralytics.data.utils import HUBDatasetStats, autosplit
|
|
275
271
|
from ultralytics.utils.downloads import zip_directory
|
|
276
272
|
|
|
@@ -290,7 +286,7 @@ def test_data_utils():
|
|
|
290
286
|
|
|
291
287
|
@pytest.mark.skipif(not ONLINE, reason="environment is offline")
|
|
292
288
|
def test_data_converter():
|
|
293
|
-
"""Test dataset
|
|
289
|
+
"""Test dataset conversion functions from COCO to YOLO format and class mappings."""
|
|
294
290
|
from ultralytics.data.converter import coco80_to_coco91_class, convert_coco
|
|
295
291
|
|
|
296
292
|
file = "instances_val2017.json"
|
|
@@ -300,7 +296,7 @@ def test_data_converter():
|
|
|
300
296
|
|
|
301
297
|
|
|
302
298
|
def test_data_annotator():
|
|
303
|
-
"""
|
|
299
|
+
"""Automatically annotate data using specified detection and segmentation models."""
|
|
304
300
|
from ultralytics.data.annotator import auto_annotate
|
|
305
301
|
|
|
306
302
|
auto_annotate(
|
|
@@ -323,7 +319,7 @@ def test_events():
|
|
|
323
319
|
|
|
324
320
|
|
|
325
321
|
def test_cfg_init():
|
|
326
|
-
"""Test configuration initialization utilities."""
|
|
322
|
+
"""Test configuration initialization utilities from the 'ultralytics.cfg' module."""
|
|
327
323
|
from ultralytics.cfg import check_dict_alignment, copy_default_cfg, smart_value
|
|
328
324
|
|
|
329
325
|
with contextlib.suppress(SyntaxError):
|
|
@@ -334,7 +330,7 @@ def test_cfg_init():
|
|
|
334
330
|
|
|
335
331
|
|
|
336
332
|
def test_utils_init():
|
|
337
|
-
"""Test initialization utilities."""
|
|
333
|
+
"""Test initialization utilities in the Ultralytics library."""
|
|
338
334
|
from ultralytics.utils import get_git_branch, get_git_origin_url, get_ubuntu_version, is_github_action_running
|
|
339
335
|
|
|
340
336
|
get_ubuntu_version()
|
|
@@ -344,7 +340,7 @@ def test_utils_init():
|
|
|
344
340
|
|
|
345
341
|
|
|
346
342
|
def test_utils_checks():
|
|
347
|
-
"""Test various utility checks."""
|
|
343
|
+
"""Test various utility checks for filenames, git status, requirements, image sizes, and versions."""
|
|
348
344
|
checks.check_yolov5u_filename("yolov5n.pt")
|
|
349
345
|
checks.git_describe(ROOT)
|
|
350
346
|
checks.check_requirements() # check requirements.txt
|
|
@@ -356,14 +352,14 @@ def test_utils_checks():
|
|
|
356
352
|
|
|
357
353
|
@pytest.mark.skipif(WINDOWS, reason="Windows profiling is extremely slow (cause unknown)")
|
|
358
354
|
def test_utils_benchmarks():
|
|
359
|
-
"""
|
|
355
|
+
"""Benchmark model performance using 'ProfileModels' from 'ultralytics.utils.benchmarks'."""
|
|
360
356
|
from ultralytics.utils.benchmarks import ProfileModels
|
|
361
357
|
|
|
362
358
|
ProfileModels(["yolov8n.yaml"], imgsz=32, min_time=1, num_timed_runs=3, num_warmup_runs=1).profile()
|
|
363
359
|
|
|
364
360
|
|
|
365
361
|
def test_utils_torchutils():
|
|
366
|
-
"""Test Torch utility functions."""
|
|
362
|
+
"""Test Torch utility functions including profiling and FLOP calculations."""
|
|
367
363
|
from ultralytics.nn.modules.conv import Conv
|
|
368
364
|
from ultralytics.utils.torch_utils import get_flops_with_torch_profiler, profile, time_sync
|
|
369
365
|
|
|
@@ -378,14 +374,14 @@ def test_utils_torchutils():
|
|
|
378
374
|
@pytest.mark.slow
|
|
379
375
|
@pytest.mark.skipif(not ONLINE, reason="environment is offline")
|
|
380
376
|
def test_utils_downloads():
|
|
381
|
-
"""Test file download utilities."""
|
|
377
|
+
"""Test file download utilities from ultralytics.utils.downloads."""
|
|
382
378
|
from ultralytics.utils.downloads import get_google_drive_file_info
|
|
383
379
|
|
|
384
380
|
get_google_drive_file_info("https://drive.google.com/file/d/1cqT-cJgANNrhIHCrEufUYhQ4RqiWG_lJ/view?usp=drive_link")
|
|
385
381
|
|
|
386
382
|
|
|
387
383
|
def test_utils_ops():
|
|
388
|
-
"""Test
|
|
384
|
+
"""Test utility operations functions for coordinate transformation and normalization."""
|
|
389
385
|
from ultralytics.utils.ops import (
|
|
390
386
|
ltwh2xywh,
|
|
391
387
|
ltwh2xyxy,
|
|
@@ -414,7 +410,7 @@ def test_utils_ops():
|
|
|
414
410
|
|
|
415
411
|
|
|
416
412
|
def test_utils_files():
|
|
417
|
-
"""Test file handling utilities."""
|
|
413
|
+
"""Test file handling utilities including file age, date, and paths with spaces."""
|
|
418
414
|
from ultralytics.utils.files import file_age, file_date, get_latest_run, spaces_in_path
|
|
419
415
|
|
|
420
416
|
file_age(SOURCE)
|
|
@@ -429,7 +425,7 @@ def test_utils_files():
|
|
|
429
425
|
|
|
430
426
|
@pytest.mark.slow
|
|
431
427
|
def test_utils_patches_torch_save():
|
|
432
|
-
"""Test torch_save backoff when _torch_save
|
|
428
|
+
"""Test torch_save backoff when _torch_save raises RuntimeError to ensure robustness."""
|
|
433
429
|
from unittest.mock import MagicMock, patch
|
|
434
430
|
|
|
435
431
|
from ultralytics.utils.patches import torch_save
|
|
@@ -444,7 +440,7 @@ def test_utils_patches_torch_save():
|
|
|
444
440
|
|
|
445
441
|
|
|
446
442
|
def test_nn_modules_conv():
|
|
447
|
-
"""Test Convolutional Neural Network modules."""
|
|
443
|
+
"""Test Convolutional Neural Network modules including CBAM, Conv2, and ConvTranspose."""
|
|
448
444
|
from ultralytics.nn.modules.conv import CBAM, Conv2, ConvTranspose, DWConvTranspose2d, Focus
|
|
449
445
|
|
|
450
446
|
c1, c2 = 8, 16 # input and output channels
|
|
@@ -463,7 +459,7 @@ def test_nn_modules_conv():
|
|
|
463
459
|
|
|
464
460
|
|
|
465
461
|
def test_nn_modules_block():
|
|
466
|
-
"""Test
|
|
462
|
+
"""Test various blocks in neural network modules including C1, C3TR, BottleneckCSP, C3Ghost, and C3x."""
|
|
467
463
|
from ultralytics.nn.modules.block import C1, C3TR, BottleneckCSP, C3Ghost, C3x
|
|
468
464
|
|
|
469
465
|
c1, c2 = 8, 16 # input and output channels
|
|
@@ -479,7 +475,7 @@ def test_nn_modules_block():
|
|
|
479
475
|
|
|
480
476
|
@pytest.mark.skipif(not ONLINE, reason="environment is offline")
|
|
481
477
|
def test_hub():
|
|
482
|
-
"""Test Ultralytics HUB functionalities."""
|
|
478
|
+
"""Test Ultralytics HUB functionalities (e.g. export formats, logout)."""
|
|
483
479
|
from ultralytics.hub import export_fmts_hub, logout
|
|
484
480
|
from ultralytics.hub.utils import smart_request
|
|
485
481
|
|
|
@@ -490,7 +486,7 @@ def test_hub():
|
|
|
490
486
|
|
|
491
487
|
@pytest.fixture
|
|
492
488
|
def image():
|
|
493
|
-
"""
|
|
489
|
+
"""Load and return an image from a predefined source using OpenCV."""
|
|
494
490
|
return cv2.imread(str(SOURCE))
|
|
495
491
|
|
|
496
492
|
|
|
@@ -504,7 +500,7 @@ def image():
|
|
|
504
500
|
],
|
|
505
501
|
)
|
|
506
502
|
def test_classify_transforms_train(image, auto_augment, erasing, force_color_jitter):
|
|
507
|
-
"""Tests classification transforms during training with various
|
|
503
|
+
"""Tests classification transforms during training with various augmentations to ensure proper functionality."""
|
|
508
504
|
from ultralytics.data.augment import classify_augmentations
|
|
509
505
|
|
|
510
506
|
transform = classify_augmentations(
|
|
@@ -533,7 +529,7 @@ def test_classify_transforms_train(image, auto_augment, erasing, force_color_jit
|
|
|
533
529
|
@pytest.mark.slow
|
|
534
530
|
@pytest.mark.skipif(not ONLINE, reason="environment is offline")
|
|
535
531
|
def test_model_tune():
|
|
536
|
-
"""Tune YOLO model for performance."""
|
|
532
|
+
"""Tune YOLO model for performance improvement."""
|
|
537
533
|
YOLO("yolov8n-pose.pt").tune(data="coco8-pose.yaml", plots=False, imgsz=32, epochs=1, iterations=2, device="cpu")
|
|
538
534
|
YOLO("yolov8n-cls.pt").tune(data="imagenet10", plots=False, imgsz=32, epochs=1, iterations=2, device="cpu")
|
|
539
535
|
|
|
@@ -550,7 +546,7 @@ def test_model_embeddings():
|
|
|
550
546
|
|
|
551
547
|
@pytest.mark.skipif(checks.IS_PYTHON_3_12, reason="YOLOWorld with CLIP is not supported in Python 3.12")
|
|
552
548
|
def test_yolo_world():
|
|
553
|
-
"""Tests YOLO world models with
|
|
549
|
+
"""Tests YOLO world models with CLIP support, including detection and training scenarios."""
|
|
554
550
|
model = YOLO("yolov8s-world.pt") # no YOLOv8n-world model yet
|
|
555
551
|
model.set_classes(["tree", "window"])
|
|
556
552
|
model(SOURCE, conf=0.01)
|
|
@@ -581,7 +577,7 @@ def test_yolo_world():
|
|
|
581
577
|
|
|
582
578
|
|
|
583
579
|
def test_yolov10():
|
|
584
|
-
"""
|
|
580
|
+
"""Test YOLOv10 model training, validation, and prediction steps with minimal configurations."""
|
|
585
581
|
model = YOLO("yolov10n.yaml")
|
|
586
582
|
# train/val/predict
|
|
587
583
|
model.train(data="coco8.yaml", epochs=1, imgsz=32, close_mosaic=1, cache="disk")
|
ultralytics/__init__.py
CHANGED
ultralytics/cfg/__init__.py
CHANGED
|
@@ -187,10 +187,31 @@ def cfg2dict(cfg):
|
|
|
187
187
|
Convert a configuration object to a dictionary, whether it is a file path, a string, or a SimpleNamespace object.
|
|
188
188
|
|
|
189
189
|
Args:
|
|
190
|
-
cfg (str | Path | dict | SimpleNamespace): Configuration object to be converted to a dictionary.
|
|
190
|
+
cfg (str | Path | dict | SimpleNamespace): Configuration object to be converted to a dictionary. This may be a
|
|
191
|
+
path to a configuration file, a dictionary, or a SimpleNamespace object.
|
|
191
192
|
|
|
192
193
|
Returns:
|
|
193
|
-
|
|
194
|
+
(dict): Configuration object in dictionary format.
|
|
195
|
+
|
|
196
|
+
Example:
|
|
197
|
+
```python
|
|
198
|
+
from ultralytics.cfg import cfg2dict
|
|
199
|
+
from types import SimpleNamespace
|
|
200
|
+
|
|
201
|
+
# Example usage with a file path
|
|
202
|
+
config_dict = cfg2dict('config.yaml')
|
|
203
|
+
|
|
204
|
+
# Example usage with a SimpleNamespace
|
|
205
|
+
config_sn = SimpleNamespace(param1='value1', param2='value2')
|
|
206
|
+
config_dict = cfg2dict(config_sn)
|
|
207
|
+
|
|
208
|
+
# Example usage with a dictionary (returns the same dictionary)
|
|
209
|
+
config_dict = cfg2dict({'param1': 'value1', 'param2': 'value2'})
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Notes:
|
|
213
|
+
- If `cfg` is a path or a string, it will be loaded as YAML and converted to a dictionary.
|
|
214
|
+
- If `cfg` is a SimpleNamespace object, it will be converted to a dictionary using `vars()`.
|
|
194
215
|
"""
|
|
195
216
|
if isinstance(cfg, (str, Path)):
|
|
196
217
|
cfg = yaml_load(cfg) # load dict
|
|
@@ -201,14 +222,36 @@ def cfg2dict(cfg):
|
|
|
201
222
|
|
|
202
223
|
def get_cfg(cfg: Union[str, Path, Dict, SimpleNamespace] = DEFAULT_CFG_DICT, overrides: Dict = None):
|
|
203
224
|
"""
|
|
204
|
-
Load and merge configuration data from a file or dictionary.
|
|
225
|
+
Load and merge configuration data from a file or dictionary, with optional overrides.
|
|
205
226
|
|
|
206
227
|
Args:
|
|
207
|
-
cfg (str | Path |
|
|
208
|
-
overrides (
|
|
228
|
+
cfg (str | Path | dict | SimpleNamespace, optional): Configuration data source. Defaults to `DEFAULT_CFG_DICT`.
|
|
229
|
+
overrides (dict | None, optional): Dictionary containing key-value pairs to override the base configuration.
|
|
230
|
+
Defaults to None.
|
|
209
231
|
|
|
210
232
|
Returns:
|
|
211
|
-
(SimpleNamespace):
|
|
233
|
+
(SimpleNamespace): Namespace containing the merged training arguments.
|
|
234
|
+
|
|
235
|
+
Notes:
|
|
236
|
+
- If both `cfg` and `overrides` are provided, the values in `overrides` will take precedence.
|
|
237
|
+
- Special handling ensures alignment and correctness of the configuration, such as converting numeric `project`
|
|
238
|
+
and `name` to strings and validating the configuration keys and values.
|
|
239
|
+
|
|
240
|
+
Example:
|
|
241
|
+
```python
|
|
242
|
+
from ultralytics.cfg import get_cfg
|
|
243
|
+
|
|
244
|
+
# Load default configuration
|
|
245
|
+
config = get_cfg()
|
|
246
|
+
|
|
247
|
+
# Load from a custom file with overrides
|
|
248
|
+
config = get_cfg('path/to/config.yaml', overrides={'epochs': 50, 'batch_size': 16})
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Configuration dictionary merged with overrides:
|
|
252
|
+
```python
|
|
253
|
+
{'epochs': 50, 'batch_size': 16, ...}
|
|
254
|
+
```
|
|
212
255
|
"""
|
|
213
256
|
cfg = cfg2dict(cfg)
|
|
214
257
|
|
|
@@ -236,7 +279,7 @@ def get_cfg(cfg: Union[str, Path, Dict, SimpleNamespace] = DEFAULT_CFG_DICT, ove
|
|
|
236
279
|
|
|
237
280
|
|
|
238
281
|
def check_cfg(cfg, hard=True):
|
|
239
|
-
"""
|
|
282
|
+
"""Validate Ultralytics configuration argument types and values, converting them if necessary."""
|
|
240
283
|
for k, v in cfg.items():
|
|
241
284
|
if v is not None: # None values may be from optional args
|
|
242
285
|
if k in CFG_FLOAT_KEYS and not isinstance(v, (int, float)):
|
|
@@ -272,7 +315,7 @@ def check_cfg(cfg, hard=True):
|
|
|
272
315
|
|
|
273
316
|
|
|
274
317
|
def get_save_dir(args, name=None):
|
|
275
|
-
"""
|
|
318
|
+
"""Returns the directory path for saving outputs, derived from arguments or default settings."""
|
|
276
319
|
|
|
277
320
|
if getattr(args, "save_dir", None):
|
|
278
321
|
save_dir = args.save_dir
|
|
@@ -287,7 +330,7 @@ def get_save_dir(args, name=None):
|
|
|
287
330
|
|
|
288
331
|
|
|
289
332
|
def _handle_deprecation(custom):
|
|
290
|
-
"""
|
|
333
|
+
"""Handles deprecated configuration keys by mapping them to current equivalents with deprecation warnings."""
|
|
291
334
|
|
|
292
335
|
for key in custom.copy().keys():
|
|
293
336
|
if key == "boxes":
|
|
@@ -308,13 +351,35 @@ def _handle_deprecation(custom):
|
|
|
308
351
|
|
|
309
352
|
def check_dict_alignment(base: Dict, custom: Dict, e=None):
|
|
310
353
|
"""
|
|
311
|
-
|
|
312
|
-
|
|
354
|
+
Check for key alignment between custom and base configuration dictionaries, catering for deprecated keys and
|
|
355
|
+
providing informative error messages for mismatched keys.
|
|
313
356
|
|
|
314
357
|
Args:
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
e (
|
|
358
|
+
base (dict): The base configuration dictionary containing valid keys.
|
|
359
|
+
custom (dict): The custom configuration dictionary to be checked for alignment.
|
|
360
|
+
e (Exception, optional): An optional error instance passed by the calling function. Default is None.
|
|
361
|
+
|
|
362
|
+
Raises:
|
|
363
|
+
SystemExit: Terminates the program execution if mismatched keys are found.
|
|
364
|
+
|
|
365
|
+
Notes:
|
|
366
|
+
- The function provides suggestions for mismatched keys based on their similarity to valid keys in the
|
|
367
|
+
base configuration.
|
|
368
|
+
- Deprecated keys in the custom configuration are automatically handled and replaced with their updated
|
|
369
|
+
equivalents.
|
|
370
|
+
- A detailed error message is printed for each mismatched key, helping users to quickly identify and correct
|
|
371
|
+
their custom configurations.
|
|
372
|
+
|
|
373
|
+
Example:
|
|
374
|
+
```python
|
|
375
|
+
base_cfg = {'epochs': 50, 'lr0': 0.01, 'batch_size': 16}
|
|
376
|
+
custom_cfg = {'epoch': 100, 'lr': 0.02, 'batch_size': 32}
|
|
377
|
+
|
|
378
|
+
try:
|
|
379
|
+
check_dict_alignment(base_cfg, custom_cfg)
|
|
380
|
+
except SystemExit:
|
|
381
|
+
# Handle the error or correct the configuration
|
|
382
|
+
```
|
|
318
383
|
"""
|
|
319
384
|
custom = _handle_deprecation(custom)
|
|
320
385
|
base_keys, custom_keys = (set(x.keys()) for x in (base, custom))
|
|
@@ -341,6 +406,22 @@ def merge_equals_args(args: List[str]) -> List[str]:
|
|
|
341
406
|
|
|
342
407
|
Returns:
|
|
343
408
|
(List[str]): A list of strings where the arguments around isolated '=' are merged.
|
|
409
|
+
|
|
410
|
+
Example:
|
|
411
|
+
The function modifies the argument list as follows:
|
|
412
|
+
```python
|
|
413
|
+
args = ["arg1", "=", "value"]
|
|
414
|
+
new_args = merge_equals_args(args)
|
|
415
|
+
print(new_args) # Output: ["arg1=value"]
|
|
416
|
+
|
|
417
|
+
args = ["arg1=", "value"]
|
|
418
|
+
new_args = merge_equals_args(args)
|
|
419
|
+
print(new_args) # Output: ["arg1=value"]
|
|
420
|
+
|
|
421
|
+
args = ["arg1", "=value"]
|
|
422
|
+
new_args = merge_equals_args(args)
|
|
423
|
+
print(new_args) # Output: ["arg1=value"]
|
|
424
|
+
```
|
|
344
425
|
"""
|
|
345
426
|
new_args = []
|
|
346
427
|
for i, arg in enumerate(args):
|
|
@@ -361,15 +442,18 @@ def handle_yolo_hub(args: List[str]) -> None:
|
|
|
361
442
|
"""
|
|
362
443
|
Handle Ultralytics HUB command-line interface (CLI) commands.
|
|
363
444
|
|
|
364
|
-
This function processes Ultralytics HUB CLI commands such as login and logout.
|
|
365
|
-
|
|
445
|
+
This function processes Ultralytics HUB CLI commands such as login and logout. It should be called when executing
|
|
446
|
+
a script with arguments related to HUB authentication.
|
|
366
447
|
|
|
367
448
|
Args:
|
|
368
|
-
args (List[str]): A list of command line arguments
|
|
449
|
+
args (List[str]): A list of command line arguments.
|
|
450
|
+
|
|
451
|
+
Returns:
|
|
452
|
+
None
|
|
369
453
|
|
|
370
454
|
Example:
|
|
371
455
|
```bash
|
|
372
|
-
|
|
456
|
+
yolo hub login YOUR_API_KEY
|
|
373
457
|
```
|
|
374
458
|
"""
|
|
375
459
|
from ultralytics import hub
|
|
@@ -387,16 +471,23 @@ def handle_yolo_settings(args: List[str]) -> None:
|
|
|
387
471
|
"""
|
|
388
472
|
Handle YOLO settings command-line interface (CLI) commands.
|
|
389
473
|
|
|
390
|
-
This function processes YOLO settings CLI commands such as reset.
|
|
391
|
-
|
|
474
|
+
This function processes YOLO settings CLI commands such as reset. It should be called when executing a script with
|
|
475
|
+
arguments related to YOLO settings management.
|
|
392
476
|
|
|
393
477
|
Args:
|
|
394
478
|
args (List[str]): A list of command line arguments for YOLO settings management.
|
|
395
479
|
|
|
480
|
+
Returns:
|
|
481
|
+
None
|
|
482
|
+
|
|
396
483
|
Example:
|
|
397
484
|
```bash
|
|
398
|
-
|
|
485
|
+
yolo settings reset
|
|
399
486
|
```
|
|
487
|
+
|
|
488
|
+
Notes:
|
|
489
|
+
For more information on handling YOLO settings, visit:
|
|
490
|
+
https://docs.ultralytics.com/quickstart/#ultralytics-settings
|
|
400
491
|
"""
|
|
401
492
|
url = "https://docs.ultralytics.com/quickstart/#ultralytics-settings" # help URL
|
|
402
493
|
try:
|
|
@@ -417,7 +508,7 @@ def handle_yolo_settings(args: List[str]) -> None:
|
|
|
417
508
|
|
|
418
509
|
|
|
419
510
|
def handle_explorer():
|
|
420
|
-
"""Open the Ultralytics Explorer GUI."""
|
|
511
|
+
"""Open the Ultralytics Explorer GUI for dataset exploration and analysis."""
|
|
421
512
|
checks.check_requirements("streamlit")
|
|
422
513
|
LOGGER.info("💡 Loading Explorer dashboard...")
|
|
423
514
|
subprocess.run(["streamlit", "run", ROOT / "data/explorer/gui/dash.py", "--server.maxMessageSize", "2048"])
|
|
@@ -432,7 +523,7 @@ def parse_key_value_pair(pair):
|
|
|
432
523
|
|
|
433
524
|
|
|
434
525
|
def smart_value(v):
|
|
435
|
-
"""Convert a string to
|
|
526
|
+
"""Convert a string to its appropriate type (int, float, bool, None, etc.)."""
|
|
436
527
|
v_lower = v.lower()
|
|
437
528
|
if v_lower == "none":
|
|
438
529
|
return None
|
|
@@ -448,18 +539,33 @@ def smart_value(v):
|
|
|
448
539
|
|
|
449
540
|
def entrypoint(debug=""):
|
|
450
541
|
"""
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
542
|
+
Ultralytics entrypoint function for parsing and executing command-line arguments.
|
|
543
|
+
|
|
544
|
+
This function serves as the main entry point for the Ultralytics CLI, parsing command-line arguments and
|
|
545
|
+
executing the corresponding tasks such as training, validation, prediction, exporting models, and more.
|
|
546
|
+
|
|
547
|
+
Args:
|
|
548
|
+
debug (str, optional): Space-separated string of command-line arguments for debugging purposes. Default is "".
|
|
549
|
+
|
|
550
|
+
Returns:
|
|
551
|
+
(None): This function does not return any value.
|
|
552
|
+
|
|
553
|
+
Notes:
|
|
554
|
+
- For a list of all available commands and their arguments, see the provided help messages and the Ultralytics
|
|
555
|
+
documentation at https://docs.ultralytics.com.
|
|
556
|
+
- If no arguments are passed, the function will display the usage help message.
|
|
557
|
+
|
|
558
|
+
Example:
|
|
559
|
+
```python
|
|
560
|
+
# Train a detection model for 10 epochs with an initial learning_rate of 0.01
|
|
561
|
+
entrypoint("train data=coco8.yaml model=yolov8n.pt epochs=10 lr0=0.01")
|
|
562
|
+
|
|
563
|
+
# Predict a YouTube video using a pretrained segmentation model at image size 320
|
|
564
|
+
entrypoint("predict model=yolov8n-seg.pt source='https://youtu.be/LNwODJXcvt4' imgsz=320")
|
|
565
|
+
|
|
566
|
+
# Validate a pretrained detection model at batch-size 1 and image size 640
|
|
567
|
+
entrypoint("val model=yolov8n.pt data=coco8.yaml batch=1 imgsz=640")
|
|
568
|
+
```
|
|
463
569
|
"""
|
|
464
570
|
args = (debug.split(" ") if debug else ARGV)[1:]
|
|
465
571
|
if not args: # no arguments passed
|
|
@@ -596,7 +702,7 @@ def entrypoint(debug=""):
|
|
|
596
702
|
|
|
597
703
|
# Special modes --------------------------------------------------------------------------------------------------------
|
|
598
704
|
def copy_default_cfg():
|
|
599
|
-
"""Copy and create a new default configuration file with '_copy' appended to its name."""
|
|
705
|
+
"""Copy and create a new default configuration file with '_copy' appended to its name, providing usage example."""
|
|
600
706
|
new_file = Path.cwd() / DEFAULT_CFG_PATH.name.replace(".yaml", "_copy.yaml")
|
|
601
707
|
shutil.copy2(DEFAULT_CFG_PATH, new_file)
|
|
602
708
|
LOGGER.info(
|
|
@@ -22,6 +22,7 @@ from .utils import get_sim_index_schema, get_table_schema, plot_query_result, pr
|
|
|
22
22
|
|
|
23
23
|
class ExplorerDataset(YOLODataset):
|
|
24
24
|
def __init__(self, *args, data: dict = None, **kwargs) -> None:
|
|
25
|
+
"""Initializes the ExplorerDataset with the provided data arguments, extending the YOLODataset class."""
|
|
25
26
|
super().__init__(*args, data=data, **kwargs)
|
|
26
27
|
|
|
27
28
|
def load_image(self, i: int) -> Union[Tuple[np.ndarray, Tuple[int, int], Tuple[int, int]], Tuple[None, None, None]]:
|
|
@@ -59,6 +60,7 @@ class Explorer:
|
|
|
59
60
|
model: str = "yolov8n.pt",
|
|
60
61
|
uri: str = USER_CONFIG_DIR / "explorer",
|
|
61
62
|
) -> None:
|
|
63
|
+
"""Initializes the Explorer class with dataset path, model, and URI for database connection."""
|
|
62
64
|
# Note duckdb==0.10.0 bug https://github.com/ultralytics/ultralytics/pull/8181
|
|
63
65
|
checks.check_requirements(["lancedb>=0.4.3", "duckdb<=0.9.2"])
|
|
64
66
|
import lancedb
|
|
@@ -416,6 +418,7 @@ class Explorer:
|
|
|
416
418
|
def _check_imgs_or_idxs(
|
|
417
419
|
self, img: Union[str, np.ndarray, List[str], List[np.ndarray], None], idx: Union[None, int, List[int]]
|
|
418
420
|
) -> List[np.ndarray]:
|
|
421
|
+
"""Determines whether to fetch images or indexes based on provided arguments and returns image paths."""
|
|
419
422
|
if img is None and idx is None:
|
|
420
423
|
raise ValueError("Either img or idx must be provided.")
|
|
421
424
|
if img is not None and idx is not None:
|
ultralytics/engine/model.py
CHANGED
|
@@ -505,7 +505,7 @@ class Model(nn.Module):
|
|
|
505
505
|
used to customize various aspects of the validation process.
|
|
506
506
|
|
|
507
507
|
Returns:
|
|
508
|
-
(
|
|
508
|
+
(ultralytics.utils.metrics.DetMetrics): Validation metrics obtained from the validation process.
|
|
509
509
|
|
|
510
510
|
Raises:
|
|
511
511
|
AssertionError: If the model is not a PyTorch model.
|