ultralytics 8.3.143__py3-none-any.whl → 8.3.144__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.
Files changed (148) hide show
  1. tests/conftest.py +7 -24
  2. tests/test_cli.py +1 -1
  3. tests/test_cuda.py +7 -2
  4. tests/test_engine.py +7 -8
  5. tests/test_exports.py +16 -16
  6. tests/test_integrations.py +1 -1
  7. tests/test_solutions.py +11 -11
  8. ultralytics/__init__.py +1 -1
  9. ultralytics/cfg/__init__.py +16 -13
  10. ultralytics/data/annotator.py +6 -5
  11. ultralytics/data/augment.py +127 -126
  12. ultralytics/data/base.py +54 -51
  13. ultralytics/data/build.py +47 -23
  14. ultralytics/data/converter.py +47 -43
  15. ultralytics/data/dataset.py +51 -50
  16. ultralytics/data/loaders.py +77 -44
  17. ultralytics/data/split.py +22 -9
  18. ultralytics/data/split_dota.py +63 -39
  19. ultralytics/data/utils.py +59 -39
  20. ultralytics/engine/exporter.py +79 -27
  21. ultralytics/engine/model.py +39 -39
  22. ultralytics/engine/predictor.py +37 -28
  23. ultralytics/engine/results.py +187 -157
  24. ultralytics/engine/trainer.py +36 -19
  25. ultralytics/engine/tuner.py +12 -9
  26. ultralytics/engine/validator.py +7 -9
  27. ultralytics/hub/__init__.py +11 -13
  28. ultralytics/hub/auth.py +22 -2
  29. ultralytics/hub/google/__init__.py +19 -19
  30. ultralytics/hub/session.py +37 -51
  31. ultralytics/hub/utils.py +19 -5
  32. ultralytics/models/fastsam/model.py +30 -12
  33. ultralytics/models/fastsam/predict.py +5 -6
  34. ultralytics/models/fastsam/utils.py +3 -3
  35. ultralytics/models/fastsam/val.py +10 -6
  36. ultralytics/models/nas/model.py +9 -5
  37. ultralytics/models/nas/predict.py +6 -6
  38. ultralytics/models/nas/val.py +3 -3
  39. ultralytics/models/rtdetr/model.py +7 -6
  40. ultralytics/models/rtdetr/predict.py +14 -7
  41. ultralytics/models/rtdetr/train.py +10 -4
  42. ultralytics/models/rtdetr/val.py +36 -9
  43. ultralytics/models/sam/amg.py +30 -12
  44. ultralytics/models/sam/build.py +22 -22
  45. ultralytics/models/sam/model.py +10 -9
  46. ultralytics/models/sam/modules/blocks.py +76 -80
  47. ultralytics/models/sam/modules/decoders.py +6 -8
  48. ultralytics/models/sam/modules/encoders.py +23 -26
  49. ultralytics/models/sam/modules/memory_attention.py +13 -1
  50. ultralytics/models/sam/modules/sam.py +57 -26
  51. ultralytics/models/sam/modules/tiny_encoder.py +232 -237
  52. ultralytics/models/sam/modules/transformer.py +13 -13
  53. ultralytics/models/sam/modules/utils.py +11 -19
  54. ultralytics/models/sam/predict.py +114 -101
  55. ultralytics/models/utils/loss.py +98 -77
  56. ultralytics/models/utils/ops.py +116 -67
  57. ultralytics/models/yolo/classify/predict.py +5 -5
  58. ultralytics/models/yolo/classify/train.py +32 -28
  59. ultralytics/models/yolo/classify/val.py +7 -8
  60. ultralytics/models/yolo/detect/predict.py +1 -0
  61. ultralytics/models/yolo/detect/train.py +15 -14
  62. ultralytics/models/yolo/detect/val.py +37 -36
  63. ultralytics/models/yolo/model.py +106 -23
  64. ultralytics/models/yolo/obb/predict.py +3 -4
  65. ultralytics/models/yolo/obb/train.py +14 -6
  66. ultralytics/models/yolo/obb/val.py +29 -23
  67. ultralytics/models/yolo/pose/predict.py +9 -8
  68. ultralytics/models/yolo/pose/train.py +24 -16
  69. ultralytics/models/yolo/pose/val.py +44 -26
  70. ultralytics/models/yolo/segment/predict.py +5 -5
  71. ultralytics/models/yolo/segment/train.py +11 -7
  72. ultralytics/models/yolo/segment/val.py +2 -2
  73. ultralytics/models/yolo/world/train.py +33 -23
  74. ultralytics/models/yolo/world/train_world.py +11 -3
  75. ultralytics/models/yolo/yoloe/predict.py +11 -11
  76. ultralytics/models/yolo/yoloe/train.py +73 -21
  77. ultralytics/models/yolo/yoloe/train_seg.py +10 -7
  78. ultralytics/models/yolo/yoloe/val.py +42 -18
  79. ultralytics/nn/autobackend.py +59 -15
  80. ultralytics/nn/modules/__init__.py +4 -4
  81. ultralytics/nn/modules/activation.py +4 -1
  82. ultralytics/nn/modules/block.py +178 -111
  83. ultralytics/nn/modules/conv.py +6 -5
  84. ultralytics/nn/modules/head.py +469 -121
  85. ultralytics/nn/modules/transformer.py +147 -58
  86. ultralytics/nn/tasks.py +227 -20
  87. ultralytics/nn/text_model.py +30 -33
  88. ultralytics/solutions/ai_gym.py +1 -1
  89. ultralytics/solutions/analytics.py +7 -4
  90. ultralytics/solutions/config.py +10 -10
  91. ultralytics/solutions/distance_calculation.py +11 -10
  92. ultralytics/solutions/heatmap.py +1 -1
  93. ultralytics/solutions/instance_segmentation.py +6 -3
  94. ultralytics/solutions/object_blurrer.py +3 -3
  95. ultralytics/solutions/object_counter.py +15 -7
  96. ultralytics/solutions/object_cropper.py +3 -2
  97. ultralytics/solutions/parking_management.py +29 -28
  98. ultralytics/solutions/queue_management.py +6 -6
  99. ultralytics/solutions/region_counter.py +10 -3
  100. ultralytics/solutions/security_alarm.py +3 -3
  101. ultralytics/solutions/similarity_search.py +85 -24
  102. ultralytics/solutions/solutions.py +184 -75
  103. ultralytics/solutions/speed_estimation.py +28 -22
  104. ultralytics/solutions/streamlit_inference.py +17 -12
  105. ultralytics/solutions/trackzone.py +4 -4
  106. ultralytics/trackers/basetrack.py +16 -23
  107. ultralytics/trackers/bot_sort.py +30 -20
  108. ultralytics/trackers/byte_tracker.py +70 -64
  109. ultralytics/trackers/track.py +4 -8
  110. ultralytics/trackers/utils/gmc.py +31 -58
  111. ultralytics/trackers/utils/kalman_filter.py +37 -37
  112. ultralytics/trackers/utils/matching.py +1 -1
  113. ultralytics/utils/__init__.py +105 -89
  114. ultralytics/utils/autobatch.py +16 -3
  115. ultralytics/utils/autodevice.py +54 -24
  116. ultralytics/utils/benchmarks.py +42 -28
  117. ultralytics/utils/callbacks/base.py +3 -3
  118. ultralytics/utils/callbacks/clearml.py +9 -9
  119. ultralytics/utils/callbacks/comet.py +67 -25
  120. ultralytics/utils/callbacks/dvc.py +7 -10
  121. ultralytics/utils/callbacks/mlflow.py +2 -5
  122. ultralytics/utils/callbacks/neptune.py +7 -13
  123. ultralytics/utils/callbacks/raytune.py +1 -1
  124. ultralytics/utils/callbacks/tensorboard.py +5 -6
  125. ultralytics/utils/callbacks/wb.py +14 -14
  126. ultralytics/utils/checks.py +14 -13
  127. ultralytics/utils/dist.py +5 -5
  128. ultralytics/utils/downloads.py +94 -67
  129. ultralytics/utils/errors.py +5 -5
  130. ultralytics/utils/export.py +61 -47
  131. ultralytics/utils/files.py +23 -22
  132. ultralytics/utils/instance.py +48 -52
  133. ultralytics/utils/loss.py +78 -40
  134. ultralytics/utils/metrics.py +186 -130
  135. ultralytics/utils/ops.py +186 -190
  136. ultralytics/utils/patches.py +15 -17
  137. ultralytics/utils/plotting.py +71 -27
  138. ultralytics/utils/tal.py +21 -15
  139. ultralytics/utils/torch_utils.py +53 -50
  140. ultralytics/utils/triton.py +5 -4
  141. ultralytics/utils/tuner.py +5 -5
  142. {ultralytics-8.3.143.dist-info → ultralytics-8.3.144.dist-info}/METADATA +1 -1
  143. ultralytics-8.3.144.dist-info/RECORD +272 -0
  144. ultralytics-8.3.143.dist-info/RECORD +0 -272
  145. {ultralytics-8.3.143.dist-info → ultralytics-8.3.144.dist-info}/WHEEL +0 -0
  146. {ultralytics-8.3.143.dist-info → ultralytics-8.3.144.dist-info}/entry_points.txt +0 -0
  147. {ultralytics-8.3.143.dist-info → ultralytics-8.3.144.dist-info}/licenses/LICENSE +0 -0
  148. {ultralytics-8.3.143.dist-info → ultralytics-8.3.144.dist-info}/top_level.txt +0 -0
tests/conftest.py CHANGED
@@ -7,15 +7,7 @@ from tests import TMP
7
7
 
8
8
 
9
9
  def pytest_addoption(parser):
10
- """
11
- Add custom command-line options to pytest.
12
-
13
- Args:
14
- parser (pytest.config.Parser): The pytest parser object for adding custom command-line options.
15
-
16
- Returns:
17
- (None)
18
- """
10
+ """Add custom command-line options to pytest."""
19
11
  parser.addoption("--slow", action="store_true", default=False, help="Run slow tests")
20
12
 
21
13
 
@@ -24,11 +16,8 @@ def pytest_collection_modifyitems(config, items):
24
16
  Modify the list of test items to exclude tests marked as slow if the --slow option is not specified.
25
17
 
26
18
  Args:
27
- config (pytest.config.Config): The pytest configuration object that provides access to command-line options.
19
+ config: The pytest configuration object that provides access to command-line options.
28
20
  items (list): The list of collected pytest item objects to be modified based on the presence of --slow option.
29
-
30
- Returns:
31
- (None): The function modifies the 'items' list in place.
32
21
  """
33
22
  if not config.getoption("--slow"):
34
23
  # Remove the item entirely from the list of test items if it's marked as 'slow'
@@ -43,16 +32,13 @@ def pytest_sessionstart(session):
43
32
  test collection. It sets the initial seeds and prepares the temporary directory for the test session.
44
33
 
45
34
  Args:
46
- session (pytest.Session): The pytest session object.
47
-
48
- Returns:
49
- (None)
35
+ session: The pytest session object.
50
36
  """
51
37
  from ultralytics.utils.torch_utils import init_seeds
52
38
 
53
39
  init_seeds()
54
- shutil.rmtree(TMP, ignore_errors=True) # delete any existing tests/tmp directory
55
- TMP.mkdir(parents=True, exist_ok=True) # create a new empty directory
40
+ shutil.rmtree(TMP, ignore_errors=True) # Delete any existing tests/tmp directory
41
+ TMP.mkdir(parents=True, exist_ok=True) # Create a new empty directory
56
42
 
57
43
 
58
44
  def pytest_terminal_summary(terminalreporter, exitstatus, config):
@@ -63,12 +49,9 @@ def pytest_terminal_summary(terminalreporter, exitstatus, config):
63
49
  and directories used during testing.
64
50
 
65
51
  Args:
66
- terminalreporter (pytest.terminal.TerminalReporter): The terminal reporter object used for terminal output.
52
+ terminalreporter: The terminal reporter object used for terminal output.
67
53
  exitstatus (int): The exit status of the test run.
68
- config (pytest.config.Config): The pytest config object.
69
-
70
- Returns:
71
- (None)
54
+ config: The pytest config object.
72
55
  """
73
56
  from ultralytics.utils import WEIGHTS_DIR
74
57
 
tests/test_cli.py CHANGED
@@ -55,7 +55,7 @@ def test_export(model: str) -> None:
55
55
 
56
56
  def test_rtdetr(task: str = "detect", model: str = "yolov8n-rtdetr.yaml", data: str = "coco8.yaml") -> None:
57
57
  """Test the RTDETR functionality within Ultralytics for detection tasks using specified model and data."""
58
- # Warning: must use imgsz=640 (note also add coma, spaces, fraction=0.25 args to test single-image training)
58
+ # Warning: must use imgsz=640 (note also add comma, spaces, fraction=0.25 args to test single-image training)
59
59
  run(f"yolo train {task} model={model} data={data} --imgsz= 160 epochs =1, cache = disk fraction=0.25") # spaces
60
60
  run(f"yolo predict {task} model={model} source={ASSETS / 'bus.jpg'} imgsz=160 save save_crop save_txt")
61
61
  if TORCH_1_9:
tests/test_cuda.py CHANGED
@@ -22,7 +22,10 @@ if CUDA_IS_AVAILABLE:
22
22
  else:
23
23
  gpu_info = GPUInfo()
24
24
  gpu_info.print_status()
25
- idle_gpus = gpu_info.select_idle_gpu(count=2, min_memory_fraction=0.2)
25
+ autodevice_fraction = __import__("os").environ.get("YOLO_AUTODEVICE_FRACTION_FREE", 0.3)
26
+ idle_gpus = gpu_info.select_idle_gpu(
27
+ count=2, min_memory_fraction=autodevice_fraction, min_util_fraction=autodevice_fraction
28
+ )
26
29
  if idle_gpus:
27
30
  DEVICES = idle_gpus
28
31
 
@@ -114,7 +117,9 @@ def test_train():
114
117
  if not IS_JETSON:
115
118
  visible = eval(os.environ["CUDA_VISIBLE_DEVICES"])
116
119
  assert visible == device, f"Passed GPUs '{device}', but used GPUs '{visible}'"
117
- assert results is (None if len(DEVICES) > 1 else not None) # DDP returns None, single-GPU returns metrics
120
+ assert (
121
+ (results is None) if len(DEVICES) > 1 else (results is not None)
122
+ ) # DDP returns None, single-GPU returns metrics
118
123
 
119
124
 
120
125
  @pytest.mark.slow
tests/test_engine.py CHANGED
@@ -17,7 +17,7 @@ def test_func(*args): # noqa
17
17
 
18
18
 
19
19
  def test_export():
20
- """Tests the model exporting function by adding a callback and asserting its execution."""
20
+ """Test model exporting functionality by adding a callback and verifying its execution."""
21
21
  exporter = Exporter()
22
22
  exporter.add_callback("on_export_start", test_func)
23
23
  assert test_func in exporter.callbacks["on_export_start"], "callback test failed"
@@ -48,11 +48,12 @@ def test_detect():
48
48
  pred = detect.DetectionPredictor(overrides={"imgsz": [64, 64]})
49
49
  pred.add_callback("on_predict_start", test_func)
50
50
  assert test_func in pred.callbacks["on_predict_start"], "callback test failed"
51
- # Confirm there is no issue with sys.argv being empty.
51
+ # Confirm there is no issue with sys.argv being empty
52
52
  with mock.patch.object(sys, "argv", []):
53
53
  result = pred(source=ASSETS, model=MODEL)
54
54
  assert len(result), "predictor test failed"
55
55
 
56
+ # Test resume functionality
56
57
  overrides["resume"] = trainer.last
57
58
  trainer = detect.DetectionTrainer(overrides=overrides)
58
59
  try:
@@ -61,16 +62,15 @@ def test_detect():
61
62
  print(f"Expected exception caught: {e}")
62
63
  return
63
64
 
64
- Exception("Resume test failed!")
65
+ raise Exception("Resume test failed!")
65
66
 
66
67
 
67
68
  def test_segment():
68
- """Tests image segmentation training, validation, and prediction pipelines using YOLO models."""
69
+ """Test image segmentation training, validation, and prediction pipelines using YOLO models."""
69
70
  overrides = {"data": "coco8-seg.yaml", "model": "yolo11n-seg.yaml", "imgsz": 32, "epochs": 1, "save": False}
70
71
  cfg = get_cfg(DEFAULT_CFG)
71
72
  cfg.data = "coco8-seg.yaml"
72
73
  cfg.imgsz = 32
73
- # YOLO(CFG_SEG).train(**overrides) # works
74
74
 
75
75
  # Trainer
76
76
  trainer = segment.SegmentationTrainer(overrides=overrides)
@@ -91,7 +91,7 @@ def test_segment():
91
91
  result = pred(source=ASSETS, model=WEIGHTS_DIR / "yolo11n-seg.pt")
92
92
  assert len(result), "predictor test failed"
93
93
 
94
- # Test resume
94
+ # Test resume functionality
95
95
  overrides["resume"] = trainer.last
96
96
  trainer = segment.SegmentationTrainer(overrides=overrides)
97
97
  try:
@@ -100,7 +100,7 @@ def test_segment():
100
100
  print(f"Expected exception caught: {e}")
101
101
  return
102
102
 
103
- Exception("Resume test failed!")
103
+ raise Exception("Resume test failed!")
104
104
 
105
105
 
106
106
  def test_classify():
@@ -109,7 +109,6 @@ def test_classify():
109
109
  cfg = get_cfg(DEFAULT_CFG)
110
110
  cfg.data = "imagenet10"
111
111
  cfg.imgsz = 32
112
- # YOLO(CFG_SEG).train(**overrides) # works
113
112
 
114
113
  # Trainer
115
114
  trainer = classify.ClassificationTrainer(overrides=overrides)
tests/test_exports.py CHANGED
@@ -24,7 +24,7 @@ from ultralytics.utils.torch_utils import TORCH_1_9, TORCH_1_13
24
24
 
25
25
 
26
26
  def test_export_torchscript():
27
- """Test YOLO model exporting to TorchScript format for compatibility and correctness."""
27
+ """Test YOLO model export to TorchScript format for compatibility and correctness."""
28
28
  file = YOLO(MODEL).export(format="torchscript", optimize=False, imgsz=32)
29
29
  YOLO(file)(SOURCE, imgsz=32) # exported model inference
30
30
 
@@ -37,7 +37,7 @@ def test_export_onnx():
37
37
 
38
38
  @pytest.mark.skipif(not TORCH_1_13, reason="OpenVINO requires torch>=1.13")
39
39
  def test_export_openvino():
40
- """Test YOLO exports to OpenVINO format for model inference compatibility."""
40
+ """Test YOLO export to OpenVINO format for model inference compatibility."""
41
41
  file = YOLO(MODEL).export(format="openvino", imgsz=32)
42
42
  YOLO(file)(SOURCE, imgsz=32) # exported model inference
43
43
 
@@ -55,7 +55,7 @@ def test_export_openvino():
55
55
  ],
56
56
  )
57
57
  def test_export_openvino_matrix(task, dynamic, int8, half, batch, nms):
58
- """Test YOLO model exports to OpenVINO under various configuration matrix conditions."""
58
+ """Test YOLO model export to OpenVINO under various configuration matrix conditions."""
59
59
  file = YOLO(TASK2MODEL[task]).export(
60
60
  format="openvino",
61
61
  imgsz=32,
@@ -87,7 +87,7 @@ def test_export_openvino_matrix(task, dynamic, int8, half, batch, nms):
87
87
  ],
88
88
  )
89
89
  def test_export_onnx_matrix(task, dynamic, int8, half, batch, simplify, nms):
90
- """Test YOLO exports to ONNX format with various configurations and parameters."""
90
+ """Test YOLO export to ONNX format with various configurations and parameters."""
91
91
  file = YOLO(TASK2MODEL[task]).export(
92
92
  format="onnx", imgsz=32, dynamic=dynamic, int8=int8, half=half, batch=batch, simplify=simplify, nms=nms
93
93
  )
@@ -105,7 +105,7 @@ def test_export_onnx_matrix(task, dynamic, int8, half, batch, simplify, nms):
105
105
  ],
106
106
  )
107
107
  def test_export_torchscript_matrix(task, dynamic, int8, half, batch, nms):
108
- """Tests YOLO model exports to TorchScript format under varied configurations."""
108
+ """Test YOLO model export to TorchScript format under varied configurations."""
109
109
  file = YOLO(TASK2MODEL[task]).export(
110
110
  format="torchscript", imgsz=32, dynamic=dynamic, int8=int8, half=half, batch=batch, nms=nms
111
111
  )
@@ -126,7 +126,7 @@ def test_export_torchscript_matrix(task, dynamic, int8, half, batch, nms):
126
126
  ],
127
127
  )
128
128
  def test_export_coreml_matrix(task, dynamic, int8, half, batch):
129
- """Test YOLO exports to CoreML format with various parameter configurations."""
129
+ """Test YOLO export to CoreML format with various parameter configurations."""
130
130
  file = YOLO(TASK2MODEL[task]).export(
131
131
  format="coreml",
132
132
  imgsz=32,
@@ -135,7 +135,7 @@ def test_export_coreml_matrix(task, dynamic, int8, half, batch):
135
135
  half=half,
136
136
  batch=batch,
137
137
  )
138
- YOLO(file)([SOURCE] * batch, imgsz=32) # exported model inference at batch=3
138
+ YOLO(file)([SOURCE] * batch, imgsz=32) # exported model inference
139
139
  shutil.rmtree(file) # cleanup
140
140
 
141
141
 
@@ -156,11 +156,11 @@ def test_export_coreml_matrix(task, dynamic, int8, half, batch):
156
156
  ],
157
157
  )
158
158
  def test_export_tflite_matrix(task, dynamic, int8, half, batch, nms):
159
- """Test YOLO exports to TFLite format considering various export configurations."""
159
+ """Test YOLO export to TFLite format considering various export configurations."""
160
160
  file = YOLO(TASK2MODEL[task]).export(
161
161
  format="tflite", imgsz=32, dynamic=dynamic, int8=int8, half=half, batch=batch, nms=nms
162
162
  )
163
- YOLO(file)([SOURCE] * batch, imgsz=32) # exported model inference at batch=3
163
+ YOLO(file)([SOURCE] * batch, imgsz=32) # exported model inference
164
164
  Path(file).unlink() # cleanup
165
165
 
166
166
 
@@ -169,7 +169,7 @@ def test_export_tflite_matrix(task, dynamic, int8, half, batch, nms):
169
169
  @pytest.mark.skipif(LINUX and ARM64, reason="CoreML not supported on aarch64 Linux")
170
170
  @pytest.mark.skipif(checks.IS_PYTHON_3_13, reason="CoreML not supported in Python 3.13")
171
171
  def test_export_coreml():
172
- """Test YOLO exports to CoreML format and check for errors."""
172
+ """Test YOLO export to CoreML format and check for errors."""
173
173
  # Capture stdout and stderr
174
174
  stdout, stderr = io.StringIO(), io.StringIO()
175
175
  with redirect_stdout(stdout), redirect_stderr(stderr):
@@ -187,7 +187,7 @@ def test_export_coreml():
187
187
  @pytest.mark.skipif(not checks.IS_PYTHON_MINIMUM_3_10, reason="TFLite export requires Python>=3.10")
188
188
  @pytest.mark.skipif(not LINUX, reason="Test disabled as TF suffers from install conflicts on Windows and macOS")
189
189
  def test_export_tflite():
190
- """Test YOLO exports to TFLite format under specific OS and Python version conditions."""
190
+ """Test YOLO export to TFLite format under specific OS and Python version conditions."""
191
191
  model = YOLO(MODEL)
192
192
  file = model.export(format="tflite", imgsz=32)
193
193
  YOLO(file)(SOURCE, imgsz=32)
@@ -196,7 +196,7 @@ def test_export_tflite():
196
196
  @pytest.mark.skipif(True, reason="Test disabled")
197
197
  @pytest.mark.skipif(not LINUX, reason="TF suffers from install conflicts on Windows and macOS")
198
198
  def test_export_pb():
199
- """Test YOLO exports to TensorFlow's Protobuf (*.pb) format."""
199
+ """Test YOLO export to TensorFlow's Protobuf (*.pb) format."""
200
200
  model = YOLO(MODEL)
201
201
  file = model.export(format="pb", imgsz=32)
202
202
  YOLO(file)(SOURCE, imgsz=32)
@@ -204,20 +204,20 @@ def test_export_pb():
204
204
 
205
205
  @pytest.mark.skipif(True, reason="Test disabled as Paddle protobuf and ONNX protobuf requirements conflict.")
206
206
  def test_export_paddle():
207
- """Test YOLO exports to Paddle format, noting protobuf conflicts with ONNX."""
207
+ """Test YOLO export to Paddle format, noting protobuf conflicts with ONNX."""
208
208
  YOLO(MODEL).export(format="paddle", imgsz=32)
209
209
 
210
210
 
211
211
  @pytest.mark.slow
212
212
  def test_export_mnn():
213
- """Test YOLO exports to MNN format (WARNING: MNN test must precede NCNN test or CI error on Windows)."""
213
+ """Test YOLO export to MNN format (WARNING: MNN test must precede NCNN test or CI error on Windows)."""
214
214
  file = YOLO(MODEL).export(format="mnn", imgsz=32)
215
215
  YOLO(file)(SOURCE, imgsz=32) # exported model inference
216
216
 
217
217
 
218
218
  @pytest.mark.slow
219
219
  def test_export_ncnn():
220
- """Test YOLO exports to NCNN format."""
220
+ """Test YOLO export to NCNN format."""
221
221
  file = YOLO(MODEL).export(format="ncnn", imgsz=32)
222
222
  YOLO(file)(SOURCE, imgsz=32) # exported model inference
223
223
 
@@ -225,7 +225,7 @@ def test_export_ncnn():
225
225
  @pytest.mark.skipif(True, reason="Test disabled as keras and tensorflow version conflicts with TFlite export.")
226
226
  @pytest.mark.skipif(not LINUX or MACOS, reason="Skipping test on Windows and Macos")
227
227
  def test_export_imx():
228
- """Test YOLO exports to IMX format."""
228
+ """Test YOLO export to IMX format."""
229
229
  model = YOLO("yolov8n.pt")
230
230
  file = model.export(format="imx", imgsz=32)
231
231
  YOLO(file)(SOURCE, imgsz=32)
@@ -32,7 +32,7 @@ def test_model_ray_tune():
32
32
 
33
33
  @pytest.mark.skipif(not check_requirements("mlflow", install=False), reason="mlflow not installed")
34
34
  def test_mlflow():
35
- """Test training with MLflow tracking enabled (see https://mlflow.org/ for details)."""
35
+ """Test training with MLflow tracking enabled."""
36
36
  SETTINGS["mlflow"] = True
37
37
  YOLO("yolo11n-cls.yaml").train(data="imagenet10", imgsz=32, epochs=3, plots=False, device="cpu")
38
38
  SETTINGS["mlflow"] = False
tests/test_solutions.py CHANGED
@@ -156,14 +156,14 @@ SOLUTIONS = [
156
156
  "StreamlitInference",
157
157
  solutions.Inference,
158
158
  False,
159
- None, # streamlit application don't require video file
160
- {}, # streamlit application don't accept arguments
159
+ None, # streamlit application doesn't require video file
160
+ {}, # streamlit application doesn't accept arguments
161
161
  ),
162
162
  ]
163
163
 
164
164
 
165
- def process_video(solution, video_path, needs_frame_count=False):
166
- """Process video with solution, feeding frames and optional frame count."""
165
+ def process_video(solution, video_path: str, needs_frame_count: bool = False):
166
+ """Process video with solution, feeding frames and optional frame count to the solution instance."""
167
167
  cap = cv2.VideoCapture(video_path)
168
168
  assert cap.isOpened(), f"Error reading video file {video_path}"
169
169
 
@@ -183,7 +183,7 @@ def process_video(solution, video_path, needs_frame_count=False):
183
183
  @pytest.mark.skipif(IS_RASPBERRYPI, reason="Disabled for testing due to --slow test errors after YOLOE PR.")
184
184
  @pytest.mark.parametrize("name, solution_class, needs_frame_count, video, kwargs", SOLUTIONS)
185
185
  def test_solution(name, solution_class, needs_frame_count, video, kwargs):
186
- """Test individual Ultralytics solution."""
186
+ """Test individual Ultralytics solution with video processing and parameter validation."""
187
187
  if video:
188
188
  if name != "ObjectCounterVertical":
189
189
  safe_download(url=f"{ASSETS_URL}/{video}", dir=TMP)
@@ -208,14 +208,14 @@ def test_solution(name, solution_class, needs_frame_count, video, kwargs):
208
208
  @pytest.mark.skipif(checks.IS_PYTHON_3_8, reason="Disabled due to unsupported CLIP dependencies.")
209
209
  @pytest.mark.skipif(IS_RASPBERRYPI, reason="Disabled due to slow performance on Raspberry Pi.")
210
210
  def test_similarity_search():
211
- """Test similarity search solution."""
212
- safe_download(f"{ASSETS_URL}/4-imgs-similaritysearch.zip", dir=TMP) # 4 dog images for testing in a zip file.
211
+ """Test similarity search solution with sample images and text query."""
212
+ safe_download(f"{ASSETS_URL}/4-imgs-similaritysearch.zip", dir=TMP) # 4 dog images for testing in a zip file
213
213
  searcher = solutions.VisualAISearch(data=str(TMP / "4-imgs-similaritysearch"))
214
214
  _ = searcher("a dog sitting on a bench") # Returns the results in format "- img name | similarity score"
215
215
 
216
216
 
217
217
  def test_left_click_selection():
218
- """Test distance calculation left click."""
218
+ """Test distance calculation left click selection functionality."""
219
219
  dc = solutions.DistanceCalculation()
220
220
  dc.boxes, dc.track_ids = [[10, 10, 50, 50]], [1]
221
221
  dc.mouse_event_for_distance(cv2.EVENT_LBUTTONDOWN, 30, 30, None, None)
@@ -223,7 +223,7 @@ def test_left_click_selection():
223
223
 
224
224
 
225
225
  def test_right_click_reset():
226
- """Test distance calculation right click."""
226
+ """Test distance calculation right click reset functionality."""
227
227
  dc = solutions.DistanceCalculation()
228
228
  dc.selected_boxes, dc.left_mouse_count = {1: [10, 10, 50, 50]}, 1
229
229
  dc.mouse_event_for_distance(cv2.EVENT_RBUTTONDOWN, 0, 0, None, None)
@@ -232,7 +232,7 @@ def test_right_click_reset():
232
232
 
233
233
 
234
234
  def test_parking_json_none():
235
- """Test that ParkingManagement skips or errors cleanly when no JSON is provided."""
235
+ """Test that ParkingManagement handles missing JSON gracefully."""
236
236
  im0 = np.zeros((640, 480, 3), dtype=np.uint8)
237
237
  try:
238
238
  parkingmanager = solutions.ParkingManagement(json_path=None)
@@ -266,7 +266,7 @@ def test_config_update_method_with_invalid_argument():
266
266
  obj.update(invalid_key=123)
267
267
  assert False, "Expected ValueError for invalid update argument"
268
268
  except ValueError as e:
269
- assert "❌ invalid_key is not a valid solution argument" in str(e)
269
+ assert "is not a valid solution argument" in str(e)
270
270
 
271
271
 
272
272
  def test_plot_with_no_masks():
ultralytics/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
2
 
3
- __version__ = "8.3.143"
3
+ __version__ = "8.3.144"
4
4
 
5
5
  import os
6
6
 
@@ -70,7 +70,7 @@ TASK2METRIC = {
70
70
  "pose": "metrics/mAP50-95(P)",
71
71
  "obb": "metrics/mAP50-95(B)",
72
72
  }
73
- MODELS = frozenset({TASK2MODEL[task] for task in TASKS})
73
+ MODELS = frozenset(TASK2MODEL[task] for task in TASKS)
74
74
 
75
75
  ARGV = sys.argv or ["", ""] # sometimes sys.argv = []
76
76
  SOLUTIONS_HELP_MSG = f"""
@@ -240,7 +240,7 @@ CFG_BOOL_KEYS = frozenset(
240
240
 
241
241
  def cfg2dict(cfg: Union[str, Path, Dict, SimpleNamespace]) -> Dict:
242
242
  """
243
- Converts a configuration object to a dictionary.
243
+ Convert a configuration object to a dictionary.
244
244
 
245
245
  Args:
246
246
  cfg (str | Path | Dict | SimpleNamespace): Configuration object to be converted. Can be a file path,
@@ -323,7 +323,7 @@ def get_cfg(cfg: Union[str, Path, Dict, SimpleNamespace] = DEFAULT_CFG_DICT, ove
323
323
 
324
324
  def check_cfg(cfg: Dict, hard: bool = True) -> None:
325
325
  """
326
- Checks configuration argument types and values for the Ultralytics library.
326
+ Check configuration argument types and values for the Ultralytics library.
327
327
 
328
328
  This function validates the types and values of configuration arguments, ensuring correctness and converting
329
329
  them if necessary. It checks for specific key types defined in global variables such as `CFG_FLOAT_KEYS`,
@@ -385,7 +385,7 @@ def check_cfg(cfg: Dict, hard: bool = True) -> None:
385
385
 
386
386
  def get_save_dir(args: SimpleNamespace, name: str = None) -> Path:
387
387
  """
388
- Returns the directory path for saving outputs, derived from arguments or default settings.
388
+ Return the directory path for saving outputs, derived from arguments or default settings.
389
389
 
390
390
  Args:
391
391
  args (SimpleNamespace): Namespace object containing configurations such as 'project', 'name', 'task',
@@ -417,11 +417,14 @@ def get_save_dir(args: SimpleNamespace, name: str = None) -> Path:
417
417
 
418
418
  def _handle_deprecation(custom: Dict) -> Dict:
419
419
  """
420
- Handles deprecated configuration keys by mapping them to current equivalents with deprecation warnings.
420
+ Handle deprecated configuration keys by mapping them to current equivalents with deprecation warnings.
421
421
 
422
422
  Args:
423
423
  custom (dict): Configuration dictionary potentially containing deprecated keys.
424
424
 
425
+ Returns:
426
+ (dict): Updated configuration dictionary with deprecated keys replaced.
427
+
425
428
  Examples:
426
429
  >>> custom_config = {"boxes": True, "hide_labels": "False", "line_thickness": 2}
427
430
  >>> _handle_deprecation(custom_config)
@@ -458,7 +461,7 @@ def _handle_deprecation(custom: Dict) -> Dict:
458
461
 
459
462
  def check_dict_alignment(base: Dict, custom: Dict, e: Exception = None) -> None:
460
463
  """
461
- Checks alignment between custom and base configuration dictionaries, handling deprecated keys and providing error
464
+ Check alignment between custom and base configuration dictionaries, handling deprecated keys and providing error
462
465
  messages for mismatched keys.
463
466
 
464
467
  Args:
@@ -498,7 +501,7 @@ def check_dict_alignment(base: Dict, custom: Dict, e: Exception = None) -> None:
498
501
 
499
502
  def merge_equals_args(args: List[str]) -> List[str]:
500
503
  """
501
- Merges arguments around isolated '=' in a list of strings and joins fragments with brackets.
504
+ Merge arguments around isolated '=' in a list of strings and join fragments with brackets.
502
505
 
503
506
  This function handles the following cases:
504
507
  1. ['arg', '=', 'val'] becomes ['arg=val']
@@ -557,7 +560,7 @@ def merge_equals_args(args: List[str]) -> List[str]:
557
560
 
558
561
  def handle_yolo_hub(args: List[str]) -> None:
559
562
  """
560
- Handles Ultralytics HUB command-line interface (CLI) commands for authentication.
563
+ Handle Ultralytics HUB command-line interface (CLI) commands for authentication.
561
564
 
562
565
  This function processes Ultralytics HUB CLI commands such as login and logout. It should be called when executing a
563
566
  script with arguments related to HUB authentication.
@@ -587,7 +590,7 @@ def handle_yolo_hub(args: List[str]) -> None:
587
590
 
588
591
  def handle_yolo_settings(args: List[str]) -> None:
589
592
  """
590
- Handles YOLO settings command-line interface (CLI) commands.
593
+ Handle YOLO settings command-line interface (CLI) commands.
591
594
 
592
595
  This function processes YOLO settings CLI commands such as reset and updating individual settings. It should be
593
596
  called when executing a script with arguments related to YOLO settings management.
@@ -628,7 +631,7 @@ def handle_yolo_settings(args: List[str]) -> None:
628
631
 
629
632
  def handle_yolo_solutions(args: List[str]) -> None:
630
633
  """
631
- Processes YOLO solutions arguments and runs the specified computer vision solutions pipeline.
634
+ Process YOLO solutions arguments and run the specified computer vision solutions pipeline.
632
635
 
633
636
  Args:
634
637
  args (List[str]): Command-line arguments for configuring and running the Ultralytics YOLO
@@ -740,7 +743,7 @@ def handle_yolo_solutions(args: List[str]) -> None:
740
743
 
741
744
  def parse_key_value_pair(pair: str = "key=value") -> tuple:
742
745
  """
743
- Parses a key-value pair string into separate key and value components.
746
+ Parse a key-value pair string into separate key and value components.
744
747
 
745
748
  Args:
746
749
  pair (str): A string containing a key-value pair in the format "key=value".
@@ -774,7 +777,7 @@ def parse_key_value_pair(pair: str = "key=value") -> tuple:
774
777
 
775
778
  def smart_value(v: str) -> Any:
776
779
  """
777
- Converts a string representation of a value to its appropriate Python type.
780
+ Convert a string representation of a value to its appropriate Python type.
778
781
 
779
782
  This function attempts to convert a given string into a Python object of the most appropriate type. It handles
780
783
  conversions to None, bool, int, float, and other types that can be evaluated safely.
@@ -991,7 +994,7 @@ def entrypoint(debug: str = "") -> None:
991
994
  # Special modes --------------------------------------------------------------------------------------------------------
992
995
  def copy_default_cfg() -> None:
993
996
  """
994
- Copies the default configuration file and creates a new one with '_copy' appended to its name.
997
+ Copy the default configuration file and create a new one with '_copy' appended to its name.
995
998
 
996
999
  This function duplicates the existing default configuration file (DEFAULT_CFG_PATH) and saves it
997
1000
  with '_copy' appended to its name in the current working directory. It provides a convenient way
@@ -22,19 +22,20 @@ def auto_annotate(
22
22
  Automatically annotate images using a YOLO object detection model and a SAM segmentation model.
23
23
 
24
24
  This function processes images in a specified directory, detects objects using a YOLO model, and then generates
25
- segmentation masks using a SAM model. The resulting annotations are saved as text files.
25
+ segmentation masks using a SAM model. The resulting annotations are saved as text files in YOLO format.
26
26
 
27
27
  Args:
28
28
  data (str | Path): Path to a folder containing images to be annotated.
29
29
  det_model (str): Path or name of the pre-trained YOLO detection model.
30
30
  sam_model (str): Path or name of the pre-trained SAM segmentation model.
31
- device (str): Device to run the models on (e.g., 'cpu', 'cuda', '0').
31
+ device (str): Device to run the models on (e.g., 'cpu', 'cuda', '0'). Empty string for auto-selection.
32
32
  conf (float): Confidence threshold for detection model.
33
33
  iou (float): IoU threshold for filtering overlapping boxes in detection results.
34
34
  imgsz (int): Input image resize dimension.
35
35
  max_det (int): Maximum number of detections per image.
36
- classes (List[int] | None): Filter predictions to specified class IDs, returning only relevant detections.
37
- output_dir (str | Path | None): Directory to save the annotated results. If None, a default directory is created.
36
+ classes (List[int], optional): Filter predictions to specified class IDs, returning only relevant detections.
37
+ output_dir (str | Path, optional): Directory to save the annotated results. If None, creates a default
38
+ directory based on the input data path.
38
39
 
39
40
  Examples:
40
41
  >>> from ultralytics.data.annotator import auto_annotate
@@ -53,7 +54,7 @@ def auto_annotate(
53
54
  )
54
55
 
55
56
  for result in det_results:
56
- class_ids = result.boxes.cls.int().tolist() # noqa
57
+ class_ids = result.boxes.cls.int().tolist() # Extract class IDs from detection results
57
58
  if class_ids:
58
59
  boxes = result.boxes.xyxy # Boxes object for bbox outputs
59
60
  sam_results = sam_model(result.orig_img, bboxes=boxes, verbose=False, save=False, device=device)