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.

Files changed (35) hide show
  1. tests/conftest.py +17 -5
  2. tests/test_cli.py +8 -8
  3. tests/test_cuda.py +5 -5
  4. tests/test_engine.py +5 -5
  5. tests/test_explorer.py +4 -4
  6. tests/test_exports.py +12 -24
  7. tests/test_integrations.py +9 -5
  8. tests/test_python.py +35 -39
  9. ultralytics/__init__.py +1 -1
  10. ultralytics/cfg/__init__.py +156 -39
  11. ultralytics/data/augment.py +3 -3
  12. ultralytics/data/explorer/explorer.py +3 -0
  13. ultralytics/engine/model.py +1 -1
  14. ultralytics/engine/results.py +160 -68
  15. ultralytics/hub/session.py +2 -0
  16. ultralytics/models/fastsam/prompt.py +1 -1
  17. ultralytics/models/sam/amg.py +1 -1
  18. ultralytics/models/sam/modules/tiny_encoder.py +1 -1
  19. ultralytics/models/yolo/classify/train.py +7 -16
  20. ultralytics/models/yolo/world/train_world.py +2 -2
  21. ultralytics/nn/modules/block.py +1 -0
  22. ultralytics/nn/tasks.py +1 -1
  23. ultralytics/solutions/__init__.py +1 -0
  24. ultralytics/solutions/ai_gym.py +3 -3
  25. ultralytics/solutions/streamlit_inference.py +154 -0
  26. ultralytics/utils/__init__.py +0 -1
  27. ultralytics/utils/metrics.py +1 -2
  28. ultralytics/utils/plotting.py +3 -3
  29. ultralytics/utils/torch_utils.py +22 -8
  30. {ultralytics-8.2.48.dist-info → ultralytics-8.2.50.dist-info}/METADATA +3 -3
  31. {ultralytics-8.2.48.dist-info → ultralytics-8.2.50.dist-info}/RECORD +35 -34
  32. {ultralytics-8.2.48.dist-info → ultralytics-8.2.50.dist-info}/WHEEL +1 -1
  33. {ultralytics-8.2.48.dist-info → ultralytics-8.2.50.dist-info}/LICENSE +0 -0
  34. {ultralytics-8.2.48.dist-info → ultralytics-8.2.50.dist-info}/entry_points.txt +0 -0
  35. {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 'profile=True' argument."""
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
- """Test YOLO predictions with sources (file, dir, glob, recursive glob) specified in a text file."""
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 prediction on various types of image sources."""
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 predict methods with 'visualize=True' arguments."""
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
- Test streaming tracking (short 10 frame video) with non-default ByteTrack tracker.
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 state."""
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
- """Test various result formats for the YOLO model."""
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 converters."""
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
- """Test automatic data annotation."""
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
- """Test model benchmarking."""
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 various operations utilities."""
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 throws RuntimeError."""
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 Neural Network block modules."""
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
- """Loads an image from a predefined source using OpenCV."""
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 augmentation settings."""
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 different configurations, including classes, detection, and training scenarios."""
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
- """A simple test for yolov10 for now."""
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
@@ -1,6 +1,6 @@
1
1
  # Ultralytics YOLO 🚀, AGPL-3.0 license
2
2
 
3
- __version__ = "8.2.48"
3
+ __version__ = "8.2.50"
4
4
 
5
5
  import os
6
6
 
@@ -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
- 6. Explore your datasets using semantic search and SQL with a simple GUI powered by Ultralytics Explorer API
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
- 5. Run special commands:
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
- cfg (dict): Configuration object in dictionary format.
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 | Dict | SimpleNamespace): Configuration data.
208
- overrides (str | Dict | optional): Overrides in the form of a file name or a dictionary. Default is None.
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): Training arguments namespace.
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
- """Check Ultralytics configuration argument types and values."""
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
- """Return save_dir as created from train/val/predict arguments."""
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
- """Hardcoded function to handle deprecated config keys."""
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
- This function checks for any mismatched keys between a custom configuration list and a base configuration list. If
312
- any mismatched keys are found, the function prints out similar keys from the base list and exits the program.
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
- custom (dict): a dictionary of custom configuration options
316
- base (dict): a dictionary of base configuration options
317
- e (Error, optional): An optional error that is passed by the calling function.
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
- It should be called when executing a script with arguments related to HUB authentication.
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
- python my_script.py hub login your_api_key
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
- It should be called when executing a script with arguments related to YOLO settings management.
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
- python my_script.py yolo settings reset
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 an underlying type such as int, float, bool, etc."""
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
- This function is the ultralytics package entrypoint, it's responsible for parsing the command line arguments passed
452
- to the package.
453
-
454
- This function allows for:
455
- - passing mandatory YOLO args as a list of strings
456
- - specifying the task to be performed, either 'detect', 'segment' or 'classify'
457
- - specifying the mode, either 'train', 'val', 'test', or 'predict'
458
- - running special modes like 'checks'
459
- - passing overrides to the package's configuration
460
-
461
- It uses the package's default cfg and initializes it using the passed overrides.
462
- Then it calls the CLI function with the composed cfg
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(
@@ -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