diff --git a/docs/en/usage/cfg.md b/docs/en/usage/cfg.md
index 33974e9fc1..9a7e679ba6 100644
--- a/docs/en/usage/cfg.md
+++ b/docs/en/usage/cfg.md
@@ -168,7 +168,7 @@ Effective management of these aspects helps track progress and makes debugging a
| Argument | Default | Description |
| ---------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `project` | `'runs'` | Specifies the root directory for saving training runs. Each run is saved in a separate subdirectory. |
-| `name` | `'exp'` | Defines the experiment name. If unspecified, YOLO increments this name for each run (e.g., `exp`, `exp2`) to avoid overwriting. |
+| `name` | `'exp'` | Defines the experiment name. If unspecified, YOLO increments this name for each run (e.g., `exp`, `exp-2`) to avoid overwriting. |
| `exist_ok` | `False` | Determines whether to overwrite an existing experiment directory. `True` allows overwriting; `False` prevents it. |
| `plots` | `True` | Controls the generation and saving of training and validation plots. Set to `True` to create plots like loss curves, [precision](https://www.ultralytics.com/glossary/precision)-[recall](https://www.ultralytics.com/glossary/recall) curves, and sample predictions for visual tracking of performance. |
| `save` | `True` | Enables saving training checkpoints and final model weights. Set to `True` to save model states periodically, allowing training resumption or model deployment. |
diff --git a/docs/en/yolov5/tutorials/model_ensembling.md b/docs/en/yolov5/tutorials/model_ensembling.md
index d1cc654f18..b7d2de1cb1 100644
--- a/docs/en/yolov5/tutorials/model_ensembling.md
+++ b/docs/en/yolov5/tutorials/model_ensembling.md
@@ -72,7 +72,7 @@ Multiple pretrained models can be ensembled together at test and inference time
python val.py --weights yolov5x.pt yolov5l6.pt --data coco.yaml --img 640 --half
```
-You can list as many checkpoints as you would like, including custom weights such as `runs/train/exp5/weights/best.pt`. YOLOv5 will automatically run each model, align the predictions on a per-image basis, and average the outputs before performing NMS.
+You can list as many checkpoints as you would like, including custom weights such as `runs/train/exp-5/weights/best.pt`. YOLOv5 will automatically run each model, align the predictions on a per-image basis, and average the outputs before performing NMS.
Output:
@@ -91,7 +91,7 @@ val: Scanning '../datasets/coco/val2017.cache' images and labels... 4952 found,
all 5000 36335 0.747 0.637 0.692 0.502
Speed: 0.1ms pre-process, 39.5ms inference, 2.0ms NMS per image at shape (32, 3, 640, 640) # <--- ensemble speed
-Evaluating pycocotools mAP... saving runs/val/exp3/yolov5x_predictions.json...
+Evaluating pycocotools mAP... saving runs/val/exp-3/yolov5x_predictions.json...
...
Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.515 # <--- ensemble mAP
Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.699
@@ -128,7 +128,7 @@ Ensemble created with ['yolov5x.pt', 'yolov5l6.pt']
image 1/2 /content/yolov5/data/images/bus.jpg: 640x512 4 persons, 1 bus, 1 tie, Done. (0.063s)
image 2/2 /content/yolov5/data/images/zidane.jpg: 384x640 3 persons, 2 ties, Done. (0.056s)
-Results saved to runs/detect/exp2
+Results saved to runs/detect/exp-2
Done. (0.223s)
```
diff --git a/docs/en/yolov5/tutorials/model_pruning_and_sparsity.md b/docs/en/yolov5/tutorials/model_pruning_and_sparsity.md
index 0c12305d9b..606ceec1b4 100644
--- a/docs/en/yolov5/tutorials/model_pruning_and_sparsity.md
+++ b/docs/en/yolov5/tutorials/model_pruning_and_sparsity.md
@@ -50,7 +50,7 @@ val: Scanning '/content/datasets/coco/val2017.cache' images and labels... 4952 f
all 5000 36335 0.732 0.628 0.683 0.496
Speed: 0.1ms pre-process, 5.2ms inference, 1.7ms NMS per image at shape (32, 3, 640, 640) # <--- base speed
-Evaluating pycocotools mAP... saving runs/val/exp2/yolov5x_predictions.json...
+Evaluating pycocotools mAP... saving runs/val/exp-2/yolov5x_predictions.json...
...
Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.507 # <--- base mAP
Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.689
@@ -87,7 +87,7 @@ val: Scanning '/content/datasets/coco/val2017.cache' images and labels... 4952 f
all 5000 36335 0.724 0.614 0.671 0.478
Speed: 0.1ms pre-process, 5.2ms inference, 1.7ms NMS per image at shape (32, 3, 640, 640) # <--- prune speed
-Evaluating pycocotools mAP... saving runs/val/exp3/yolov5x_predictions.json...
+Evaluating pycocotools mAP... saving runs/val/exp-3/yolov5x_predictions.json...
...
Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.489 # <--- prune mAP
Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.677
@@ -101,7 +101,7 @@ Evaluating pycocotools mAP... saving runs/val/exp3/yolov5x_predictions.json...
Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.496
Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.722
Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.803
-Results saved to runs/val/exp3
+Results saved to runs/val/exp-3
```
## Results Analysis
diff --git a/docs/en/yolov5/tutorials/test_time_augmentation.md b/docs/en/yolov5/tutorials/test_time_augmentation.md
index d9f7357868..5eddbf8ea7 100644
--- a/docs/en/yolov5/tutorials/test_time_augmentation.md
+++ b/docs/en/yolov5/tutorials/test_time_augmentation.md
@@ -81,7 +81,7 @@ val: New cache created: ../datasets/coco/val2017.cache
all 5000 36335 0.718 0.656 0.695 0.503
Speed: 0.2ms pre-process, 80.6ms inference, 2.7ms NMS per image at shape (32, 3, 832, 832) # <--- TTA speed
-Evaluating pycocotools mAP... saving runs/val/exp2/yolov5x_predictions.json...
+Evaluating pycocotools mAP... saving runs/val/exp-2/yolov5x_predictions.json...
...
Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.516 # <--- TTA mAP
Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.701
diff --git a/docs/en/yolov5/tutorials/train_custom_data.md b/docs/en/yolov5/tutorials/train_custom_data.md
index 6d4048ff83..fbf0b112a7 100644
--- a/docs/en/yolov5/tutorials/train_custom_data.md
+++ b/docs/en/yolov5/tutorials/train_custom_data.md
@@ -170,7 +170,7 @@ python train.py --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yo
💡 Always train using datasets stored locally. Accessing data from network drives (like Google Drive) or remote storage can be significantly slower and impede training performance. Copying your dataset to a local SSD is often the best practice.
-All training outputs, including weights and logs, are saved in the `runs/train/` directory. Each training session creates a new subdirectory (e.g., `runs/train/exp`, `runs/train/exp2`, etc.). For an interactive, hands-on experience, explore the training section in our official tutorial notebooks:
+All training outputs, including weights and logs, are saved in the `runs/train/` directory. Each training session creates a new subdirectory (e.g., `runs/train/exp`, `runs/train/exp-2`, etc.). For an interactive, hands-on experience, explore the training section in our official tutorial notebooks:
## 4. Visualize
diff --git a/tests/test_python.py b/tests/test_python.py
index 871c7bb8af..03c22af9cf 100644
--- a/tests/test_python.py
+++ b/tests/test_python.py
@@ -549,7 +549,7 @@ def test_utils_ops():
def test_utils_files(tmp_path):
"""Test file handling utilities including file age, date, and paths with spaces."""
- from ultralytics.utils.files import file_age, file_date, get_latest_run, spaces_in_path
+ from ultralytics.utils.files import file_age, file_date, get_latest_run, increment_path, spaces_in_path
file_age(SOURCE)
file_date(SOURCE)
@@ -560,6 +560,14 @@ def test_utils_files(tmp_path):
with spaces_in_path(path) as new_path:
print(new_path)
+ exp_dir = tmp_path / "runs" / "exp"
+ exp_dir.mkdir(parents=True)
+ assert increment_path(exp_dir) == tmp_path / "runs" / "exp-2"
+
+ results_file = exp_dir / "results.txt"
+ results_file.touch()
+ assert increment_path(results_file) == exp_dir / "results-2.txt"
+
@pytest.mark.slow
def test_utils_patches_torch_save(tmp_path):
diff --git a/ultralytics/__init__.py b/ultralytics/__init__.py
index 1184e63c07..dd953fc09d 100644
--- a/ultralytics/__init__.py
+++ b/ultralytics/__init__.py
@@ -1,6 +1,6 @@
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
-__version__ = "8.4.38"
+__version__ = "8.4.39"
import importlib
import os
diff --git a/ultralytics/utils/files.py b/ultralytics/utils/files.py
index 1d40f34c45..a58083a29d 100644
--- a/ultralytics/utils/files.py
+++ b/ultralytics/utils/files.py
@@ -103,7 +103,7 @@ def spaces_in_path(path: str | Path):
yield path
-def increment_path(path: str | Path, exist_ok: bool = False, sep: str = "", mkdir: bool = False) -> Path:
+def increment_path(path: str | Path, exist_ok: bool = False, sep: str = "-", mkdir: bool = False) -> Path:
"""Increment a file or directory path, i.e., runs/exp --> runs/exp{sep}2, runs/exp{sep}3, ... etc.
If the path exists and `exist_ok` is not True, the path will be incremented by appending a number and `sep` to the
@@ -125,13 +125,13 @@ def increment_path(path: str | Path, exist_ok: bool = False, sep: str = "", mkdi
>>> path = Path("runs/exp")
>>> new_path = increment_path(path)
>>> print(new_path)
- runs/exp2
+ runs/exp-2
Increment a file path:
>>> path = Path("runs/exp/results.txt")
>>> new_path = increment_path(path)
>>> print(new_path)
- runs/exp/results2.txt
+ runs/exp/results-2.txt
"""
path = Path(path) # os-agnostic
if path.exists() and not exist_ok: