ultralytics 8.2.48__py3-none-any.whl → 8.2.50__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 +156 -39
- ultralytics/data/augment.py +3 -3
- ultralytics/data/explorer/explorer.py +3 -0
- ultralytics/engine/model.py +1 -1
- ultralytics/engine/results.py +160 -68
- ultralytics/hub/session.py +2 -0
- ultralytics/models/fastsam/prompt.py +1 -1
- ultralytics/models/sam/amg.py +1 -1
- ultralytics/models/sam/modules/tiny_encoder.py +1 -1
- ultralytics/models/yolo/classify/train.py +7 -16
- ultralytics/models/yolo/world/train_world.py +2 -2
- ultralytics/nn/modules/block.py +1 -0
- ultralytics/nn/tasks.py +1 -1
- ultralytics/solutions/__init__.py +1 -0
- ultralytics/solutions/ai_gym.py +3 -3
- ultralytics/solutions/streamlit_inference.py +154 -0
- ultralytics/utils/__init__.py +0 -1
- ultralytics/utils/metrics.py +1 -2
- ultralytics/utils/plotting.py +3 -3
- ultralytics/utils/torch_utils.py +22 -8
- {ultralytics-8.2.48.dist-info → ultralytics-8.2.50.dist-info}/METADATA +3 -3
- {ultralytics-8.2.48.dist-info → ultralytics-8.2.50.dist-info}/RECORD +35 -34
- {ultralytics-8.2.48.dist-info → ultralytics-8.2.50.dist-info}/WHEEL +1 -1
- {ultralytics-8.2.48.dist-info → ultralytics-8.2.50.dist-info}/LICENSE +0 -0
- {ultralytics-8.2.48.dist-info → ultralytics-8.2.50.dist-info}/entry_points.txt +0 -0
- {ultralytics-8.2.48.dist-info → ultralytics-8.2.50.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
|
@@ -78,10 +78,13 @@ CLI_HELP_MSG = f"""
|
|
|
78
78
|
4. Export a YOLOv8n classification model to ONNX format at image size 224 by 128 (no TASK required)
|
|
79
79
|
yolo export model=yolov8n-cls.pt format=onnx imgsz=224,128
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
5. Explore your datasets using semantic search and SQL with a simple GUI powered by Ultralytics Explorer API
|
|
82
82
|
yolo explorer
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
|
|
84
|
+
6. Streamlit real-time object detection on your webcam with Ultralytics YOLOv8
|
|
85
|
+
yolo streamlit-predict
|
|
86
|
+
|
|
87
|
+
7. Run special commands:
|
|
85
88
|
yolo help
|
|
86
89
|
yolo checks
|
|
87
90
|
yolo version
|
|
@@ -187,10 +190,31 @@ def cfg2dict(cfg):
|
|
|
187
190
|
Convert a configuration object to a dictionary, whether it is a file path, a string, or a SimpleNamespace object.
|
|
188
191
|
|
|
189
192
|
Args:
|
|
190
|
-
cfg (str | Path | dict | SimpleNamespace): Configuration object to be converted to a dictionary.
|
|
193
|
+
cfg (str | Path | dict | SimpleNamespace): Configuration object to be converted to a dictionary. This may be a
|
|
194
|
+
path to a configuration file, a dictionary, or a SimpleNamespace object.
|
|
191
195
|
|
|
192
196
|
Returns:
|
|
193
|
-
|
|
197
|
+
(dict): Configuration object in dictionary format.
|
|
198
|
+
|
|
199
|
+
Example:
|
|
200
|
+
```python
|
|
201
|
+
from ultralytics.cfg import cfg2dict
|
|
202
|
+
from types import SimpleNamespace
|
|
203
|
+
|
|
204
|
+
# Example usage with a file path
|
|
205
|
+
config_dict = cfg2dict('config.yaml')
|
|
206
|
+
|
|
207
|
+
# Example usage with a SimpleNamespace
|
|
208
|
+
config_sn = SimpleNamespace(param1='value1', param2='value2')
|
|
209
|
+
config_dict = cfg2dict(config_sn)
|
|
210
|
+
|
|
211
|
+
# Example usage with a dictionary (returns the same dictionary)
|
|
212
|
+
config_dict = cfg2dict({'param1': 'value1', 'param2': 'value2'})
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Notes:
|
|
216
|
+
- If `cfg` is a path or a string, it will be loaded as YAML and converted to a dictionary.
|
|
217
|
+
- If `cfg` is a SimpleNamespace object, it will be converted to a dictionary using `vars()`.
|
|
194
218
|
"""
|
|
195
219
|
if isinstance(cfg, (str, Path)):
|
|
196
220
|
cfg = yaml_load(cfg) # load dict
|
|
@@ -201,14 +225,36 @@ def cfg2dict(cfg):
|
|
|
201
225
|
|
|
202
226
|
def get_cfg(cfg: Union[str, Path, Dict, SimpleNamespace] = DEFAULT_CFG_DICT, overrides: Dict = None):
|
|
203
227
|
"""
|
|
204
|
-
Load and merge configuration data from a file or dictionary.
|
|
228
|
+
Load and merge configuration data from a file or dictionary, with optional overrides.
|
|
205
229
|
|
|
206
230
|
Args:
|
|
207
|
-
cfg (str | Path |
|
|
208
|
-
overrides (
|
|
231
|
+
cfg (str | Path | dict | SimpleNamespace, optional): Configuration data source. Defaults to `DEFAULT_CFG_DICT`.
|
|
232
|
+
overrides (dict | None, optional): Dictionary containing key-value pairs to override the base configuration.
|
|
233
|
+
Defaults to None.
|
|
209
234
|
|
|
210
235
|
Returns:
|
|
211
|
-
(SimpleNamespace):
|
|
236
|
+
(SimpleNamespace): Namespace containing the merged training arguments.
|
|
237
|
+
|
|
238
|
+
Notes:
|
|
239
|
+
- If both `cfg` and `overrides` are provided, the values in `overrides` will take precedence.
|
|
240
|
+
- Special handling ensures alignment and correctness of the configuration, such as converting numeric `project`
|
|
241
|
+
and `name` to strings and validating the configuration keys and values.
|
|
242
|
+
|
|
243
|
+
Example:
|
|
244
|
+
```python
|
|
245
|
+
from ultralytics.cfg import get_cfg
|
|
246
|
+
|
|
247
|
+
# Load default configuration
|
|
248
|
+
config = get_cfg()
|
|
249
|
+
|
|
250
|
+
# Load from a custom file with overrides
|
|
251
|
+
config = get_cfg('path/to/config.yaml', overrides={'epochs': 50, 'batch_size': 16})
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Configuration dictionary merged with overrides:
|
|
255
|
+
```python
|
|
256
|
+
{'epochs': 50, 'batch_size': 16, ...}
|
|
257
|
+
```
|
|
212
258
|
"""
|
|
213
259
|
cfg = cfg2dict(cfg)
|
|
214
260
|
|
|
@@ -236,7 +282,7 @@ def get_cfg(cfg: Union[str, Path, Dict, SimpleNamespace] = DEFAULT_CFG_DICT, ove
|
|
|
236
282
|
|
|
237
283
|
|
|
238
284
|
def check_cfg(cfg, hard=True):
|
|
239
|
-
"""
|
|
285
|
+
"""Validate Ultralytics configuration argument types and values, converting them if necessary."""
|
|
240
286
|
for k, v in cfg.items():
|
|
241
287
|
if v is not None: # None values may be from optional args
|
|
242
288
|
if k in CFG_FLOAT_KEYS and not isinstance(v, (int, float)):
|
|
@@ -272,7 +318,7 @@ def check_cfg(cfg, hard=True):
|
|
|
272
318
|
|
|
273
319
|
|
|
274
320
|
def get_save_dir(args, name=None):
|
|
275
|
-
"""
|
|
321
|
+
"""Returns the directory path for saving outputs, derived from arguments or default settings."""
|
|
276
322
|
|
|
277
323
|
if getattr(args, "save_dir", None):
|
|
278
324
|
save_dir = args.save_dir
|
|
@@ -287,7 +333,7 @@ def get_save_dir(args, name=None):
|
|
|
287
333
|
|
|
288
334
|
|
|
289
335
|
def _handle_deprecation(custom):
|
|
290
|
-
"""
|
|
336
|
+
"""Handles deprecated configuration keys by mapping them to current equivalents with deprecation warnings."""
|
|
291
337
|
|
|
292
338
|
for key in custom.copy().keys():
|
|
293
339
|
if key == "boxes":
|
|
@@ -308,13 +354,35 @@ def _handle_deprecation(custom):
|
|
|
308
354
|
|
|
309
355
|
def check_dict_alignment(base: Dict, custom: Dict, e=None):
|
|
310
356
|
"""
|
|
311
|
-
|
|
312
|
-
|
|
357
|
+
Check for key alignment between custom and base configuration dictionaries, catering for deprecated keys and
|
|
358
|
+
providing informative error messages for mismatched keys.
|
|
313
359
|
|
|
314
360
|
Args:
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
e (
|
|
361
|
+
base (dict): The base configuration dictionary containing valid keys.
|
|
362
|
+
custom (dict): The custom configuration dictionary to be checked for alignment.
|
|
363
|
+
e (Exception, optional): An optional error instance passed by the calling function. Default is None.
|
|
364
|
+
|
|
365
|
+
Raises:
|
|
366
|
+
SystemExit: Terminates the program execution if mismatched keys are found.
|
|
367
|
+
|
|
368
|
+
Notes:
|
|
369
|
+
- The function provides suggestions for mismatched keys based on their similarity to valid keys in the
|
|
370
|
+
base configuration.
|
|
371
|
+
- Deprecated keys in the custom configuration are automatically handled and replaced with their updated
|
|
372
|
+
equivalents.
|
|
373
|
+
- A detailed error message is printed for each mismatched key, helping users to quickly identify and correct
|
|
374
|
+
their custom configurations.
|
|
375
|
+
|
|
376
|
+
Example:
|
|
377
|
+
```python
|
|
378
|
+
base_cfg = {'epochs': 50, 'lr0': 0.01, 'batch_size': 16}
|
|
379
|
+
custom_cfg = {'epoch': 100, 'lr': 0.02, 'batch_size': 32}
|
|
380
|
+
|
|
381
|
+
try:
|
|
382
|
+
check_dict_alignment(base_cfg, custom_cfg)
|
|
383
|
+
except SystemExit:
|
|
384
|
+
# Handle the error or correct the configuration
|
|
385
|
+
```
|
|
318
386
|
"""
|
|
319
387
|
custom = _handle_deprecation(custom)
|
|
320
388
|
base_keys, custom_keys = (set(x.keys()) for x in (base, custom))
|
|
@@ -341,6 +409,22 @@ def merge_equals_args(args: List[str]) -> List[str]:
|
|
|
341
409
|
|
|
342
410
|
Returns:
|
|
343
411
|
(List[str]): A list of strings where the arguments around isolated '=' are merged.
|
|
412
|
+
|
|
413
|
+
Example:
|
|
414
|
+
The function modifies the argument list as follows:
|
|
415
|
+
```python
|
|
416
|
+
args = ["arg1", "=", "value"]
|
|
417
|
+
new_args = merge_equals_args(args)
|
|
418
|
+
print(new_args) # Output: ["arg1=value"]
|
|
419
|
+
|
|
420
|
+
args = ["arg1=", "value"]
|
|
421
|
+
new_args = merge_equals_args(args)
|
|
422
|
+
print(new_args) # Output: ["arg1=value"]
|
|
423
|
+
|
|
424
|
+
args = ["arg1", "=value"]
|
|
425
|
+
new_args = merge_equals_args(args)
|
|
426
|
+
print(new_args) # Output: ["arg1=value"]
|
|
427
|
+
```
|
|
344
428
|
"""
|
|
345
429
|
new_args = []
|
|
346
430
|
for i, arg in enumerate(args):
|
|
@@ -361,15 +445,18 @@ def handle_yolo_hub(args: List[str]) -> None:
|
|
|
361
445
|
"""
|
|
362
446
|
Handle Ultralytics HUB command-line interface (CLI) commands.
|
|
363
447
|
|
|
364
|
-
This function processes Ultralytics HUB CLI commands such as login and logout.
|
|
365
|
-
|
|
448
|
+
This function processes Ultralytics HUB CLI commands such as login and logout. It should be called when executing
|
|
449
|
+
a script with arguments related to HUB authentication.
|
|
366
450
|
|
|
367
451
|
Args:
|
|
368
|
-
args (List[str]): A list of command line arguments
|
|
452
|
+
args (List[str]): A list of command line arguments.
|
|
453
|
+
|
|
454
|
+
Returns:
|
|
455
|
+
None
|
|
369
456
|
|
|
370
457
|
Example:
|
|
371
458
|
```bash
|
|
372
|
-
|
|
459
|
+
yolo hub login YOUR_API_KEY
|
|
373
460
|
```
|
|
374
461
|
"""
|
|
375
462
|
from ultralytics import hub
|
|
@@ -387,16 +474,23 @@ def handle_yolo_settings(args: List[str]) -> None:
|
|
|
387
474
|
"""
|
|
388
475
|
Handle YOLO settings command-line interface (CLI) commands.
|
|
389
476
|
|
|
390
|
-
This function processes YOLO settings CLI commands such as reset.
|
|
391
|
-
|
|
477
|
+
This function processes YOLO settings CLI commands such as reset. It should be called when executing a script with
|
|
478
|
+
arguments related to YOLO settings management.
|
|
392
479
|
|
|
393
480
|
Args:
|
|
394
481
|
args (List[str]): A list of command line arguments for YOLO settings management.
|
|
395
482
|
|
|
483
|
+
Returns:
|
|
484
|
+
None
|
|
485
|
+
|
|
396
486
|
Example:
|
|
397
487
|
```bash
|
|
398
|
-
|
|
488
|
+
yolo settings reset
|
|
399
489
|
```
|
|
490
|
+
|
|
491
|
+
Notes:
|
|
492
|
+
For more information on handling YOLO settings, visit:
|
|
493
|
+
https://docs.ultralytics.com/quickstart/#ultralytics-settings
|
|
400
494
|
"""
|
|
401
495
|
url = "https://docs.ultralytics.com/quickstart/#ultralytics-settings" # help URL
|
|
402
496
|
try:
|
|
@@ -417,12 +511,19 @@ def handle_yolo_settings(args: List[str]) -> None:
|
|
|
417
511
|
|
|
418
512
|
|
|
419
513
|
def handle_explorer():
|
|
420
|
-
"""Open the Ultralytics Explorer GUI."""
|
|
514
|
+
"""Open the Ultralytics Explorer GUI for dataset exploration and analysis."""
|
|
421
515
|
checks.check_requirements("streamlit")
|
|
422
516
|
LOGGER.info("💡 Loading Explorer dashboard...")
|
|
423
517
|
subprocess.run(["streamlit", "run", ROOT / "data/explorer/gui/dash.py", "--server.maxMessageSize", "2048"])
|
|
424
518
|
|
|
425
519
|
|
|
520
|
+
def handle_streamlit_inference():
|
|
521
|
+
"""Open the Ultralytics Live Inference streamlit app for real time object detection."""
|
|
522
|
+
checks.check_requirements(["streamlit", "opencv-python", "torch"])
|
|
523
|
+
LOGGER.info("💡 Loading Ultralytics Live Inference app...")
|
|
524
|
+
subprocess.run(["streamlit", "run", ROOT / "solutions/streamlit_inference.py", "--server.headless", "true"])
|
|
525
|
+
|
|
526
|
+
|
|
426
527
|
def parse_key_value_pair(pair):
|
|
427
528
|
"""Parse one 'key=value' pair and return key and value."""
|
|
428
529
|
k, v = pair.split("=", 1) # split on first '=' sign
|
|
@@ -432,7 +533,7 @@ def parse_key_value_pair(pair):
|
|
|
432
533
|
|
|
433
534
|
|
|
434
535
|
def smart_value(v):
|
|
435
|
-
"""Convert a string to
|
|
536
|
+
"""Convert a string to its appropriate type (int, float, bool, None, etc.)."""
|
|
436
537
|
v_lower = v.lower()
|
|
437
538
|
if v_lower == "none":
|
|
438
539
|
return None
|
|
@@ -448,18 +549,33 @@ def smart_value(v):
|
|
|
448
549
|
|
|
449
550
|
def entrypoint(debug=""):
|
|
450
551
|
"""
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
552
|
+
Ultralytics entrypoint function for parsing and executing command-line arguments.
|
|
553
|
+
|
|
554
|
+
This function serves as the main entry point for the Ultralytics CLI, parsing command-line arguments and
|
|
555
|
+
executing the corresponding tasks such as training, validation, prediction, exporting models, and more.
|
|
556
|
+
|
|
557
|
+
Args:
|
|
558
|
+
debug (str, optional): Space-separated string of command-line arguments for debugging purposes. Default is "".
|
|
559
|
+
|
|
560
|
+
Returns:
|
|
561
|
+
(None): This function does not return any value.
|
|
562
|
+
|
|
563
|
+
Notes:
|
|
564
|
+
- For a list of all available commands and their arguments, see the provided help messages and the Ultralytics
|
|
565
|
+
documentation at https://docs.ultralytics.com.
|
|
566
|
+
- If no arguments are passed, the function will display the usage help message.
|
|
567
|
+
|
|
568
|
+
Example:
|
|
569
|
+
```python
|
|
570
|
+
# Train a detection model for 10 epochs with an initial learning_rate of 0.01
|
|
571
|
+
entrypoint("train data=coco8.yaml model=yolov8n.pt epochs=10 lr0=0.01")
|
|
572
|
+
|
|
573
|
+
# Predict a YouTube video using a pretrained segmentation model at image size 320
|
|
574
|
+
entrypoint("predict model=yolov8n-seg.pt source='https://youtu.be/LNwODJXcvt4' imgsz=320")
|
|
575
|
+
|
|
576
|
+
# Validate a pretrained detection model at batch-size 1 and image size 640
|
|
577
|
+
entrypoint("val model=yolov8n.pt data=coco8.yaml batch=1 imgsz=640")
|
|
578
|
+
```
|
|
463
579
|
"""
|
|
464
580
|
args = (debug.split(" ") if debug else ARGV)[1:]
|
|
465
581
|
if not args: # no arguments passed
|
|
@@ -476,6 +592,7 @@ def entrypoint(debug=""):
|
|
|
476
592
|
"login": lambda: handle_yolo_hub(args),
|
|
477
593
|
"copy-cfg": copy_default_cfg,
|
|
478
594
|
"explorer": lambda: handle_explorer(),
|
|
595
|
+
"streamlit-predict": lambda: handle_streamlit_inference(),
|
|
479
596
|
}
|
|
480
597
|
full_args_dict = {**DEFAULT_CFG_DICT, **{k: None for k in TASKS}, **{k: None for k in MODES}, **special}
|
|
481
598
|
|
|
@@ -596,7 +713,7 @@ def entrypoint(debug=""):
|
|
|
596
713
|
|
|
597
714
|
# Special modes --------------------------------------------------------------------------------------------------------
|
|
598
715
|
def copy_default_cfg():
|
|
599
|
-
"""Copy and create a new default configuration file with '_copy' appended to its name."""
|
|
716
|
+
"""Copy and create a new default configuration file with '_copy' appended to its name, providing usage example."""
|
|
600
717
|
new_file = Path.cwd() / DEFAULT_CFG_PATH.name.replace(".yaml", "_copy.yaml")
|
|
601
718
|
shutil.copy2(DEFAULT_CFG_PATH, new_file)
|
|
602
719
|
LOGGER.info(
|
ultralytics/data/augment.py
CHANGED
|
@@ -686,7 +686,7 @@ class RandomFlip:
|
|
|
686
686
|
flip_idx (array-like, optional): Index mapping for flipping keypoints, if any.
|
|
687
687
|
"""
|
|
688
688
|
assert direction in {"horizontal", "vertical"}, f"Support direction `horizontal` or `vertical`, got {direction}"
|
|
689
|
-
assert 0 <= p <= 1.0
|
|
689
|
+
assert 0 <= p <= 1.0, f"The probability should be in range [0, 1], but got {p}."
|
|
690
690
|
|
|
691
691
|
self.p = p
|
|
692
692
|
self.direction = direction
|
|
@@ -1210,7 +1210,7 @@ def classify_transforms(
|
|
|
1210
1210
|
import torchvision.transforms as T # scope for faster 'import ultralytics'
|
|
1211
1211
|
|
|
1212
1212
|
if isinstance(size, (tuple, list)):
|
|
1213
|
-
assert len(size) == 2
|
|
1213
|
+
assert len(size) == 2, f"'size' tuples must be length 2, not length {len(size)}"
|
|
1214
1214
|
scale_size = tuple(math.floor(x / crop_fraction) for x in size)
|
|
1215
1215
|
else:
|
|
1216
1216
|
scale_size = math.floor(size / crop_fraction)
|
|
@@ -1288,7 +1288,7 @@ def classify_augmentations(
|
|
|
1288
1288
|
secondary_tfl = []
|
|
1289
1289
|
disable_color_jitter = False
|
|
1290
1290
|
if auto_augment:
|
|
1291
|
-
assert isinstance(auto_augment, str)
|
|
1291
|
+
assert isinstance(auto_augment, str), f"Provided argument should be string, but got type {type(auto_augment)}"
|
|
1292
1292
|
# color jitter is typically disabled if AA/RA on,
|
|
1293
1293
|
# this allows override without breaking old hparm cfgs
|
|
1294
1294
|
disable_color_jitter = not force_color_jitter
|