dgenerate-ultralytics-headless 8.3.214__py3-none-any.whl → 8.4.7__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.
- {dgenerate_ultralytics_headless-8.3.214.dist-info → dgenerate_ultralytics_headless-8.4.7.dist-info}/METADATA +64 -74
- dgenerate_ultralytics_headless-8.4.7.dist-info/RECORD +311 -0
- {dgenerate_ultralytics_headless-8.3.214.dist-info → dgenerate_ultralytics_headless-8.4.7.dist-info}/WHEEL +1 -1
- tests/__init__.py +7 -9
- tests/conftest.py +8 -15
- tests/test_cli.py +1 -1
- tests/test_cuda.py +13 -10
- tests/test_engine.py +9 -9
- tests/test_exports.py +65 -13
- tests/test_integrations.py +13 -13
- tests/test_python.py +125 -69
- tests/test_solutions.py +161 -152
- ultralytics/__init__.py +1 -1
- ultralytics/cfg/__init__.py +86 -92
- ultralytics/cfg/datasets/Argoverse.yaml +7 -6
- ultralytics/cfg/datasets/DOTAv1.5.yaml +1 -1
- ultralytics/cfg/datasets/DOTAv1.yaml +1 -1
- ultralytics/cfg/datasets/ImageNet.yaml +1 -1
- ultralytics/cfg/datasets/TT100K.yaml +346 -0
- ultralytics/cfg/datasets/VOC.yaml +15 -16
- ultralytics/cfg/datasets/african-wildlife.yaml +1 -1
- ultralytics/cfg/datasets/coco-pose.yaml +21 -0
- ultralytics/cfg/datasets/coco12-formats.yaml +101 -0
- ultralytics/cfg/datasets/coco128-seg.yaml +1 -1
- ultralytics/cfg/datasets/coco8-pose.yaml +21 -0
- ultralytics/cfg/datasets/dog-pose.yaml +28 -0
- ultralytics/cfg/datasets/dota8-multispectral.yaml +1 -1
- ultralytics/cfg/datasets/dota8.yaml +2 -2
- ultralytics/cfg/datasets/hand-keypoints.yaml +26 -2
- ultralytics/cfg/datasets/kitti.yaml +27 -0
- ultralytics/cfg/datasets/lvis.yaml +5 -5
- ultralytics/cfg/datasets/open-images-v7.yaml +1 -1
- ultralytics/cfg/datasets/tiger-pose.yaml +16 -0
- ultralytics/cfg/datasets/xView.yaml +16 -16
- ultralytics/cfg/default.yaml +4 -2
- ultralytics/cfg/models/11/yolo11-pose.yaml +1 -1
- ultralytics/cfg/models/11/yoloe-11-seg.yaml +2 -2
- ultralytics/cfg/models/11/yoloe-11.yaml +2 -2
- ultralytics/cfg/models/26/yolo26-cls.yaml +33 -0
- ultralytics/cfg/models/26/yolo26-obb.yaml +52 -0
- ultralytics/cfg/models/26/yolo26-p2.yaml +60 -0
- ultralytics/cfg/models/26/yolo26-p6.yaml +62 -0
- ultralytics/cfg/models/26/yolo26-pose.yaml +53 -0
- ultralytics/cfg/models/26/yolo26-seg.yaml +52 -0
- ultralytics/cfg/models/26/yolo26.yaml +52 -0
- ultralytics/cfg/models/26/yoloe-26-seg.yaml +53 -0
- ultralytics/cfg/models/26/yoloe-26.yaml +53 -0
- ultralytics/cfg/models/rt-detr/rtdetr-l.yaml +1 -1
- ultralytics/cfg/models/rt-detr/rtdetr-resnet101.yaml +1 -1
- ultralytics/cfg/models/rt-detr/rtdetr-resnet50.yaml +1 -1
- ultralytics/cfg/models/rt-detr/rtdetr-x.yaml +1 -1
- ultralytics/cfg/models/v10/yolov10b.yaml +2 -2
- ultralytics/cfg/models/v10/yolov10l.yaml +2 -2
- ultralytics/cfg/models/v10/yolov10m.yaml +2 -2
- ultralytics/cfg/models/v10/yolov10n.yaml +2 -2
- ultralytics/cfg/models/v10/yolov10s.yaml +2 -2
- ultralytics/cfg/models/v10/yolov10x.yaml +2 -2
- ultralytics/cfg/models/v3/yolov3-tiny.yaml +1 -1
- ultralytics/cfg/models/v6/yolov6.yaml +1 -1
- ultralytics/cfg/models/v8/yoloe-v8-seg.yaml +9 -6
- ultralytics/cfg/models/v8/yoloe-v8.yaml +9 -6
- ultralytics/cfg/models/v8/yolov8-cls-resnet101.yaml +1 -1
- ultralytics/cfg/models/v8/yolov8-cls-resnet50.yaml +1 -1
- ultralytics/cfg/models/v8/yolov8-ghost-p2.yaml +2 -2
- ultralytics/cfg/models/v8/yolov8-ghost-p6.yaml +2 -2
- ultralytics/cfg/models/v8/yolov8-ghost.yaml +2 -2
- ultralytics/cfg/models/v8/yolov8-obb.yaml +1 -1
- ultralytics/cfg/models/v8/yolov8-p2.yaml +1 -1
- ultralytics/cfg/models/v8/yolov8-pose-p6.yaml +1 -1
- ultralytics/cfg/models/v8/yolov8-rtdetr.yaml +1 -1
- ultralytics/cfg/models/v8/yolov8-seg-p6.yaml +1 -1
- ultralytics/cfg/models/v8/yolov8-world.yaml +1 -1
- ultralytics/cfg/models/v8/yolov8-worldv2.yaml +6 -6
- ultralytics/cfg/models/v9/yolov9s.yaml +1 -1
- ultralytics/data/__init__.py +4 -4
- ultralytics/data/annotator.py +5 -6
- ultralytics/data/augment.py +300 -475
- ultralytics/data/base.py +18 -26
- ultralytics/data/build.py +147 -25
- ultralytics/data/converter.py +108 -87
- ultralytics/data/dataset.py +47 -75
- ultralytics/data/loaders.py +42 -49
- ultralytics/data/split.py +5 -6
- ultralytics/data/split_dota.py +8 -15
- ultralytics/data/utils.py +36 -45
- ultralytics/engine/exporter.py +351 -263
- ultralytics/engine/model.py +186 -225
- ultralytics/engine/predictor.py +45 -54
- ultralytics/engine/results.py +198 -325
- ultralytics/engine/trainer.py +165 -106
- ultralytics/engine/tuner.py +41 -43
- ultralytics/engine/validator.py +55 -38
- ultralytics/hub/__init__.py +16 -19
- ultralytics/hub/auth.py +6 -12
- ultralytics/hub/google/__init__.py +7 -10
- ultralytics/hub/session.py +15 -25
- ultralytics/hub/utils.py +5 -8
- ultralytics/models/__init__.py +1 -1
- ultralytics/models/fastsam/__init__.py +1 -1
- ultralytics/models/fastsam/model.py +8 -10
- ultralytics/models/fastsam/predict.py +18 -30
- ultralytics/models/fastsam/utils.py +1 -2
- ultralytics/models/fastsam/val.py +5 -7
- ultralytics/models/nas/__init__.py +1 -1
- ultralytics/models/nas/model.py +5 -8
- ultralytics/models/nas/predict.py +7 -9
- ultralytics/models/nas/val.py +1 -2
- ultralytics/models/rtdetr/__init__.py +1 -1
- ultralytics/models/rtdetr/model.py +5 -8
- ultralytics/models/rtdetr/predict.py +15 -19
- ultralytics/models/rtdetr/train.py +10 -13
- ultralytics/models/rtdetr/val.py +21 -23
- ultralytics/models/sam/__init__.py +15 -2
- ultralytics/models/sam/amg.py +14 -20
- ultralytics/models/sam/build.py +26 -19
- ultralytics/models/sam/build_sam3.py +377 -0
- ultralytics/models/sam/model.py +29 -32
- ultralytics/models/sam/modules/blocks.py +83 -144
- ultralytics/models/sam/modules/decoders.py +19 -37
- ultralytics/models/sam/modules/encoders.py +44 -101
- ultralytics/models/sam/modules/memory_attention.py +16 -30
- ultralytics/models/sam/modules/sam.py +200 -73
- ultralytics/models/sam/modules/tiny_encoder.py +64 -83
- ultralytics/models/sam/modules/transformer.py +18 -28
- ultralytics/models/sam/modules/utils.py +174 -50
- ultralytics/models/sam/predict.py +2248 -350
- ultralytics/models/sam/sam3/__init__.py +3 -0
- ultralytics/models/sam/sam3/decoder.py +546 -0
- ultralytics/models/sam/sam3/encoder.py +529 -0
- ultralytics/models/sam/sam3/geometry_encoders.py +415 -0
- ultralytics/models/sam/sam3/maskformer_segmentation.py +286 -0
- ultralytics/models/sam/sam3/model_misc.py +199 -0
- ultralytics/models/sam/sam3/necks.py +129 -0
- ultralytics/models/sam/sam3/sam3_image.py +339 -0
- ultralytics/models/sam/sam3/text_encoder_ve.py +307 -0
- ultralytics/models/sam/sam3/vitdet.py +547 -0
- ultralytics/models/sam/sam3/vl_combiner.py +160 -0
- ultralytics/models/utils/loss.py +14 -26
- ultralytics/models/utils/ops.py +13 -17
- ultralytics/models/yolo/__init__.py +1 -1
- ultralytics/models/yolo/classify/predict.py +10 -13
- ultralytics/models/yolo/classify/train.py +12 -33
- ultralytics/models/yolo/classify/val.py +30 -29
- ultralytics/models/yolo/detect/predict.py +9 -12
- ultralytics/models/yolo/detect/train.py +17 -23
- ultralytics/models/yolo/detect/val.py +77 -59
- ultralytics/models/yolo/model.py +43 -60
- ultralytics/models/yolo/obb/predict.py +7 -16
- ultralytics/models/yolo/obb/train.py +14 -17
- ultralytics/models/yolo/obb/val.py +40 -37
- ultralytics/models/yolo/pose/__init__.py +1 -1
- ultralytics/models/yolo/pose/predict.py +7 -22
- ultralytics/models/yolo/pose/train.py +13 -16
- ultralytics/models/yolo/pose/val.py +39 -58
- ultralytics/models/yolo/segment/predict.py +17 -21
- ultralytics/models/yolo/segment/train.py +7 -10
- ultralytics/models/yolo/segment/val.py +95 -47
- ultralytics/models/yolo/world/train.py +8 -14
- ultralytics/models/yolo/world/train_world.py +11 -34
- ultralytics/models/yolo/yoloe/__init__.py +7 -7
- ultralytics/models/yolo/yoloe/predict.py +16 -23
- ultralytics/models/yolo/yoloe/train.py +36 -44
- ultralytics/models/yolo/yoloe/train_seg.py +11 -11
- ultralytics/models/yolo/yoloe/val.py +15 -20
- ultralytics/nn/__init__.py +7 -7
- ultralytics/nn/autobackend.py +159 -85
- ultralytics/nn/modules/__init__.py +68 -60
- ultralytics/nn/modules/activation.py +4 -6
- ultralytics/nn/modules/block.py +260 -224
- ultralytics/nn/modules/conv.py +52 -97
- ultralytics/nn/modules/head.py +831 -299
- ultralytics/nn/modules/transformer.py +76 -88
- ultralytics/nn/modules/utils.py +16 -21
- ultralytics/nn/tasks.py +180 -195
- ultralytics/nn/text_model.py +45 -69
- ultralytics/optim/__init__.py +5 -0
- ultralytics/optim/muon.py +338 -0
- ultralytics/solutions/__init__.py +12 -12
- ultralytics/solutions/ai_gym.py +13 -19
- ultralytics/solutions/analytics.py +15 -16
- ultralytics/solutions/config.py +6 -7
- ultralytics/solutions/distance_calculation.py +10 -13
- ultralytics/solutions/heatmap.py +8 -14
- ultralytics/solutions/instance_segmentation.py +6 -9
- ultralytics/solutions/object_blurrer.py +7 -10
- ultralytics/solutions/object_counter.py +12 -19
- ultralytics/solutions/object_cropper.py +8 -14
- ultralytics/solutions/parking_management.py +34 -32
- ultralytics/solutions/queue_management.py +10 -12
- ultralytics/solutions/region_counter.py +9 -12
- ultralytics/solutions/security_alarm.py +15 -20
- ultralytics/solutions/similarity_search.py +10 -15
- ultralytics/solutions/solutions.py +77 -76
- ultralytics/solutions/speed_estimation.py +7 -10
- ultralytics/solutions/streamlit_inference.py +2 -4
- ultralytics/solutions/templates/similarity-search.html +7 -18
- ultralytics/solutions/trackzone.py +7 -10
- ultralytics/solutions/vision_eye.py +5 -8
- ultralytics/trackers/__init__.py +1 -1
- ultralytics/trackers/basetrack.py +3 -5
- ultralytics/trackers/bot_sort.py +10 -27
- ultralytics/trackers/byte_tracker.py +21 -37
- ultralytics/trackers/track.py +4 -7
- ultralytics/trackers/utils/gmc.py +11 -22
- ultralytics/trackers/utils/kalman_filter.py +37 -48
- ultralytics/trackers/utils/matching.py +12 -15
- ultralytics/utils/__init__.py +124 -124
- ultralytics/utils/autobatch.py +2 -4
- ultralytics/utils/autodevice.py +17 -18
- ultralytics/utils/benchmarks.py +57 -71
- ultralytics/utils/callbacks/base.py +8 -10
- ultralytics/utils/callbacks/clearml.py +5 -13
- ultralytics/utils/callbacks/comet.py +32 -46
- ultralytics/utils/callbacks/dvc.py +13 -18
- ultralytics/utils/callbacks/mlflow.py +4 -5
- ultralytics/utils/callbacks/neptune.py +7 -15
- ultralytics/utils/callbacks/platform.py +423 -38
- ultralytics/utils/callbacks/raytune.py +3 -4
- ultralytics/utils/callbacks/tensorboard.py +25 -31
- ultralytics/utils/callbacks/wb.py +16 -14
- ultralytics/utils/checks.py +127 -85
- ultralytics/utils/cpu.py +3 -8
- ultralytics/utils/dist.py +9 -12
- ultralytics/utils/downloads.py +25 -33
- ultralytics/utils/errors.py +6 -14
- ultralytics/utils/events.py +2 -4
- ultralytics/utils/export/__init__.py +4 -236
- ultralytics/utils/export/engine.py +246 -0
- ultralytics/utils/export/imx.py +117 -63
- ultralytics/utils/export/tensorflow.py +231 -0
- ultralytics/utils/files.py +26 -30
- ultralytics/utils/git.py +9 -11
- ultralytics/utils/instance.py +30 -51
- ultralytics/utils/logger.py +212 -114
- ultralytics/utils/loss.py +601 -215
- ultralytics/utils/metrics.py +128 -156
- ultralytics/utils/nms.py +13 -16
- ultralytics/utils/ops.py +117 -166
- ultralytics/utils/patches.py +75 -21
- ultralytics/utils/plotting.py +75 -80
- ultralytics/utils/tal.py +125 -59
- ultralytics/utils/torch_utils.py +53 -79
- ultralytics/utils/tqdm.py +24 -21
- ultralytics/utils/triton.py +13 -19
- ultralytics/utils/tuner.py +19 -10
- dgenerate_ultralytics_headless-8.3.214.dist-info/RECORD +0 -283
- {dgenerate_ultralytics_headless-8.3.214.dist-info → dgenerate_ultralytics_headless-8.4.7.dist-info}/entry_points.txt +0 -0
- {dgenerate_ultralytics_headless-8.3.214.dist-info → dgenerate_ultralytics_headless-8.4.7.dist-info}/licenses/LICENSE +0 -0
- {dgenerate_ultralytics_headless-8.3.214.dist-info → dgenerate_ultralytics_headless-8.4.7.dist-info}/top_level.txt +0 -0
tests/test_python.py
CHANGED
|
@@ -12,7 +12,7 @@ import pytest
|
|
|
12
12
|
import torch
|
|
13
13
|
from PIL import Image
|
|
14
14
|
|
|
15
|
-
from tests import CFG, MODEL, MODELS, SOURCE, SOURCES_LIST, TASK_MODEL_DATA
|
|
15
|
+
from tests import CFG, MODEL, MODELS, SOURCE, SOURCES_LIST, TASK_MODEL_DATA
|
|
16
16
|
from ultralytics import RTDETR, YOLO
|
|
17
17
|
from ultralytics.cfg import TASK2DATA, TASKS
|
|
18
18
|
from ultralytics.data.build import load_inference_source
|
|
@@ -33,14 +33,11 @@ from ultralytics.utils import (
|
|
|
33
33
|
WINDOWS,
|
|
34
34
|
YAML,
|
|
35
35
|
checks,
|
|
36
|
-
is_dir_writeable,
|
|
37
36
|
is_github_action_running,
|
|
38
37
|
)
|
|
39
38
|
from ultralytics.utils.downloads import download
|
|
40
39
|
from ultralytics.utils.torch_utils import TORCH_1_11, TORCH_1_13
|
|
41
40
|
|
|
42
|
-
IS_TMP_WRITEABLE = is_dir_writeable(TMP) # WARNING: must be run once tests start as TMP does not exist on tests/init
|
|
43
|
-
|
|
44
41
|
|
|
45
42
|
def test_model_forward():
|
|
46
43
|
"""Test the forward pass of the YOLO model."""
|
|
@@ -77,10 +74,9 @@ def test_model_profile():
|
|
|
77
74
|
_ = model.predict(im, profile=True)
|
|
78
75
|
|
|
79
76
|
|
|
80
|
-
|
|
81
|
-
def test_predict_txt():
|
|
77
|
+
def test_predict_txt(tmp_path):
|
|
82
78
|
"""Test YOLO predictions with file, directory, and pattern sources listed in a text file."""
|
|
83
|
-
file =
|
|
79
|
+
file = tmp_path / "sources_multi_row.txt"
|
|
84
80
|
with open(file, "w") as f:
|
|
85
81
|
for src in SOURCES_LIST:
|
|
86
82
|
f.write(f"{src}\n")
|
|
@@ -89,10 +85,9 @@ def test_predict_txt():
|
|
|
89
85
|
|
|
90
86
|
|
|
91
87
|
@pytest.mark.skipif(True, reason="disabled for testing")
|
|
92
|
-
|
|
93
|
-
def test_predict_csv_multi_row():
|
|
88
|
+
def test_predict_csv_multi_row(tmp_path):
|
|
94
89
|
"""Test YOLO predictions with sources listed in multiple rows of a CSV file."""
|
|
95
|
-
file =
|
|
90
|
+
file = tmp_path / "sources_multi_row.csv"
|
|
96
91
|
with open(file, "w", newline="") as f:
|
|
97
92
|
writer = csv.writer(f)
|
|
98
93
|
writer.writerow(["source"])
|
|
@@ -102,10 +97,9 @@ def test_predict_csv_multi_row():
|
|
|
102
97
|
|
|
103
98
|
|
|
104
99
|
@pytest.mark.skipif(True, reason="disabled for testing")
|
|
105
|
-
|
|
106
|
-
def test_predict_csv_single_row():
|
|
100
|
+
def test_predict_csv_single_row(tmp_path):
|
|
107
101
|
"""Test YOLO predictions with sources listed in a single row of a CSV file."""
|
|
108
|
-
file =
|
|
102
|
+
file = tmp_path / "sources_single_row.csv"
|
|
109
103
|
with open(file, "w", newline="") as f:
|
|
110
104
|
writer = csv.writer(f)
|
|
111
105
|
writer.writerow(SOURCES_LIST)
|
|
@@ -118,7 +112,7 @@ def test_predict_img(model_name):
|
|
|
118
112
|
"""Test YOLO model predictions on various image input types and sources, including online images."""
|
|
119
113
|
channels = 1 if model_name == "yolo11n-grayscale.pt" else 3
|
|
120
114
|
model = YOLO(WEIGHTS_DIR / model_name)
|
|
121
|
-
im = cv2.imread(str(SOURCE), flags=cv2.IMREAD_GRAYSCALE if channels == 1 else cv2.IMREAD_COLOR) # uint8
|
|
115
|
+
im = cv2.imread(str(SOURCE), flags=cv2.IMREAD_GRAYSCALE if channels == 1 else cv2.IMREAD_COLOR) # uint8 NumPy array
|
|
122
116
|
assert len(model(source=Image.open(SOURCE), save=True, verbose=True, imgsz=32)) == 1 # PIL
|
|
123
117
|
assert len(model(source=im, save=True, save_txt=True, imgsz=32)) == 1 # ndarray
|
|
124
118
|
assert len(model(torch.rand((2, channels, 32, 32)), imgsz=32)) == 2 # batch-size 2 Tensor, FP32 0.0-1.0 RGB order
|
|
@@ -142,31 +136,53 @@ def test_predict_visualize(model):
|
|
|
142
136
|
YOLO(WEIGHTS_DIR / model)(SOURCE, imgsz=32, visualize=True)
|
|
143
137
|
|
|
144
138
|
|
|
145
|
-
def
|
|
146
|
-
"""Test YOLO prediction on SOURCE converted to
|
|
139
|
+
def test_predict_gray_and_4ch(tmp_path):
|
|
140
|
+
"""Test YOLO prediction on SOURCE converted to grayscale and 4-channel images with various filenames."""
|
|
147
141
|
im = Image.open(SOURCE)
|
|
148
|
-
directory = TMP / "im4"
|
|
149
|
-
directory.mkdir(parents=True, exist_ok=True)
|
|
150
142
|
|
|
151
|
-
|
|
152
|
-
source_rgba =
|
|
153
|
-
source_non_utf =
|
|
154
|
-
source_spaces =
|
|
143
|
+
source_grayscale = tmp_path / "grayscale.jpg"
|
|
144
|
+
source_rgba = tmp_path / "4ch.png"
|
|
145
|
+
source_non_utf = tmp_path / "non_UTF_测试文件_tést_image.jpg"
|
|
146
|
+
source_spaces = tmp_path / "image with spaces.jpg"
|
|
155
147
|
|
|
156
|
-
im.convert("L").save(
|
|
148
|
+
im.convert("L").save(source_grayscale) # grayscale
|
|
157
149
|
im.convert("RGBA").save(source_rgba) # 4-ch PNG with alpha
|
|
158
150
|
im.save(source_non_utf) # non-UTF characters in filename
|
|
159
151
|
im.save(source_spaces) # spaces in filename
|
|
160
152
|
|
|
161
153
|
# Inference
|
|
162
154
|
model = YOLO(MODEL)
|
|
163
|
-
for f in source_rgba,
|
|
155
|
+
for f in source_rgba, source_grayscale, source_non_utf, source_spaces:
|
|
164
156
|
for source in Image.open(f), cv2.imread(str(f)), f:
|
|
165
157
|
results = model(source, save=True, verbose=True, imgsz=32)
|
|
166
158
|
assert len(results) == 1 # verify that an image was run
|
|
167
159
|
f.unlink() # cleanup
|
|
168
160
|
|
|
169
161
|
|
|
162
|
+
@pytest.mark.slow
|
|
163
|
+
@pytest.mark.skipif(not ONLINE, reason="environment is offline")
|
|
164
|
+
def test_predict_all_image_formats():
|
|
165
|
+
"""Test YOLO prediction all 12 image formats (AVIF, BMP, DNG, HEIC, JP2, JPEG, JPG, MPO, PNG, TIF, TIFF, WebP)."""
|
|
166
|
+
# Download dataset if needed
|
|
167
|
+
data = check_det_dataset("coco12-formats.yaml")
|
|
168
|
+
dataset_path = Path(data["path"])
|
|
169
|
+
|
|
170
|
+
# Collect all images from train and val
|
|
171
|
+
images = list((dataset_path / "images" / "train").glob("*.*"))
|
|
172
|
+
images += list((dataset_path / "images" / "val").glob("*.*"))
|
|
173
|
+
assert len(images) == 12, f"Expected 12 images, found {len(images)}"
|
|
174
|
+
|
|
175
|
+
# Verify all format extensions are represented
|
|
176
|
+
extensions = {img.suffix.lower().lstrip(".") for img in images}
|
|
177
|
+
expected = {"avif", "bmp", "dng", "heic", "jp2", "jpeg", "jpg", "mpo", "png", "tif", "tiff", "webp"}
|
|
178
|
+
assert extensions == expected, f"Missing formats: {expected - extensions}"
|
|
179
|
+
|
|
180
|
+
# Run inference on all images
|
|
181
|
+
model = YOLO(MODEL)
|
|
182
|
+
results = model(images, imgsz=32)
|
|
183
|
+
assert len(results) == 12, f"Expected 12 results, got {len(results)}"
|
|
184
|
+
|
|
185
|
+
|
|
170
186
|
@pytest.mark.slow
|
|
171
187
|
@pytest.mark.skipif(not ONLINE, reason="environment is offline")
|
|
172
188
|
@pytest.mark.skipif(is_github_action_running(), reason="No auth https://github.com/JuanBindez/pytubefix/issues/166")
|
|
@@ -181,15 +197,13 @@ def test_youtube():
|
|
|
181
197
|
|
|
182
198
|
|
|
183
199
|
@pytest.mark.skipif(not ONLINE, reason="environment is offline")
|
|
184
|
-
@pytest.mark.skipif(not IS_TMP_WRITEABLE, reason="directory is not writeable")
|
|
185
200
|
@pytest.mark.parametrize("model", MODELS)
|
|
186
|
-
def test_track_stream(model):
|
|
187
|
-
"""
|
|
188
|
-
Test streaming tracking on a short 10 frame video using ByteTrack tracker and different GMC methods.
|
|
201
|
+
def test_track_stream(model, tmp_path):
|
|
202
|
+
"""Test streaming tracking on a short 10 frame video using ByteTrack tracker and different GMC methods.
|
|
189
203
|
|
|
190
204
|
Note imgsz=160 required for tracking for higher confidence and better matches.
|
|
191
205
|
"""
|
|
192
|
-
if model == "
|
|
206
|
+
if model == "yolo26n-cls.pt": # classification model not supported for tracking
|
|
193
207
|
return
|
|
194
208
|
video_url = f"{ASSETS_URL}/decelera_portrait_min.mov"
|
|
195
209
|
model = YOLO(model)
|
|
@@ -197,9 +211,9 @@ def test_track_stream(model):
|
|
|
197
211
|
model.track(video_url, imgsz=160, tracker="botsort.yaml", save_frames=True) # test frame saving also
|
|
198
212
|
|
|
199
213
|
# Test Global Motion Compensation (GMC) methods and ReID
|
|
200
|
-
for gmc, reidm in zip(["orb", "sift", "ecc"], ["auto", "auto", "
|
|
214
|
+
for gmc, reidm in zip(["orb", "sift", "ecc"], ["auto", "auto", "yolo26n-cls.pt"]):
|
|
201
215
|
default_args = YAML.load(ROOT / "cfg/trackers/botsort.yaml")
|
|
202
|
-
custom_yaml =
|
|
216
|
+
custom_yaml = tmp_path / f"botsort-{gmc}.yaml"
|
|
203
217
|
YAML.save(custom_yaml, {**default_args, "gmc_method": gmc, "with_reid": True, "model": reidm})
|
|
204
218
|
model.track(video_url, imgsz=160, tracker=custom_yaml)
|
|
205
219
|
|
|
@@ -219,25 +233,26 @@ def test_val(task: str, weight: str, data: str) -> None:
|
|
|
219
233
|
metrics.confusion_matrix.to_json()
|
|
220
234
|
|
|
221
235
|
|
|
236
|
+
@pytest.mark.skipif(not ONLINE, reason="environment is offline")
|
|
222
237
|
@pytest.mark.skipif(IS_JETSON or IS_RASPBERRYPI, reason="Edge devices not intended for training")
|
|
223
238
|
def test_train_scratch():
|
|
224
|
-
"""Test training the YOLO model from scratch
|
|
239
|
+
"""Test training the YOLO model from scratch on 12 different image types in the COCO12-Formats dataset."""
|
|
225
240
|
model = YOLO(CFG)
|
|
226
|
-
model.train(data="
|
|
241
|
+
model.train(data="coco12-formats.yaml", epochs=2, imgsz=32, cache="disk", batch=-1, close_mosaic=1, name="model")
|
|
227
242
|
model(SOURCE)
|
|
228
243
|
|
|
229
244
|
|
|
230
245
|
@pytest.mark.skipif(not ONLINE, reason="environment is offline")
|
|
231
246
|
def test_train_ndjson():
|
|
232
247
|
"""Test training the YOLO model using NDJSON format dataset."""
|
|
233
|
-
model = YOLO(WEIGHTS_DIR / "
|
|
248
|
+
model = YOLO(WEIGHTS_DIR / "yolo26n.pt")
|
|
234
249
|
model.train(data=f"{ASSETS_URL}/coco8-ndjson.ndjson", epochs=1, imgsz=32)
|
|
235
250
|
|
|
236
251
|
|
|
237
252
|
@pytest.mark.parametrize("scls", [False, True])
|
|
238
253
|
def test_train_pretrained(scls):
|
|
239
254
|
"""Test training of the YOLO model starting from a pre-trained checkpoint."""
|
|
240
|
-
model = YOLO(WEIGHTS_DIR / "
|
|
255
|
+
model = YOLO(WEIGHTS_DIR / "yolo26n-seg.pt")
|
|
241
256
|
model.train(
|
|
242
257
|
data="coco8-seg.yaml", epochs=1, imgsz=32, cache="ram", copy_paste=0.5, mixup=0.5, name=0, single_cls=scls
|
|
243
258
|
)
|
|
@@ -278,7 +293,7 @@ def test_predict_callback_and_setup():
|
|
|
278
293
|
model.add_callback("on_predict_batch_end", on_predict_batch_end)
|
|
279
294
|
|
|
280
295
|
dataset = load_inference_source(source=SOURCE)
|
|
281
|
-
bs = dataset.bs #
|
|
296
|
+
bs = dataset.bs # access predictor properties
|
|
282
297
|
results = model.predict(dataset, stream=True, imgsz=160) # source already setup
|
|
283
298
|
for r, im0, bs in results:
|
|
284
299
|
print("test_callback", im0.shape)
|
|
@@ -288,21 +303,21 @@ def test_predict_callback_and_setup():
|
|
|
288
303
|
|
|
289
304
|
|
|
290
305
|
@pytest.mark.parametrize("model", MODELS)
|
|
291
|
-
def test_results(model: str):
|
|
306
|
+
def test_results(model: str, tmp_path):
|
|
292
307
|
"""Test YOLO model results processing and output in various formats."""
|
|
293
|
-
im = f"{ASSETS_URL}/boats.jpg" if model == "
|
|
308
|
+
im = f"{ASSETS_URL}/boats.jpg" if model == "yolo26n-obb.pt" else SOURCE
|
|
294
309
|
results = YOLO(WEIGHTS_DIR / model)([im, im], imgsz=160)
|
|
295
310
|
for r in results:
|
|
296
311
|
assert len(r), f"'{model}' results should not be empty!"
|
|
297
312
|
r = r.cpu().numpy()
|
|
298
313
|
print(r, len(r), r.path) # print numpy attributes
|
|
299
314
|
r = r.to(device="cpu", dtype=torch.float32)
|
|
300
|
-
r.save_txt(txt_file=
|
|
301
|
-
r.save_crop(save_dir=
|
|
315
|
+
r.save_txt(txt_file=tmp_path / "runs/tests/label.txt", save_conf=True)
|
|
316
|
+
r.save_crop(save_dir=tmp_path / "runs/tests/crops/")
|
|
302
317
|
r.to_df(decimals=3) # Align to_ methods: https://docs.ultralytics.com/modes/predict/#working-with-results
|
|
303
318
|
r.to_csv()
|
|
304
319
|
r.to_json(normalize=True)
|
|
305
|
-
r.plot(pil=True, save=True, filename=
|
|
320
|
+
r.plot(pil=True, save=True, filename=tmp_path / "results_plot_save.jpg")
|
|
306
321
|
r.plot(conf=True, boxes=True)
|
|
307
322
|
print(r, len(r), r.path) # print after methods
|
|
308
323
|
|
|
@@ -310,13 +325,13 @@ def test_results(model: str):
|
|
|
310
325
|
def test_labels_and_crops():
|
|
311
326
|
"""Test output from prediction args for saving YOLO detection labels and crops."""
|
|
312
327
|
imgs = [SOURCE, ASSETS / "zidane.jpg"]
|
|
313
|
-
results = YOLO(WEIGHTS_DIR / "
|
|
328
|
+
results = YOLO(WEIGHTS_DIR / "yolo26n.pt")(imgs, imgsz=320, save_txt=True, save_crop=True)
|
|
314
329
|
save_path = Path(results[0].save_dir)
|
|
315
330
|
for r in results:
|
|
316
331
|
im_name = Path(r.path).stem
|
|
317
332
|
cls_idxs = r.boxes.cls.int().tolist()
|
|
318
|
-
# Check
|
|
319
|
-
assert cls_idxs
|
|
333
|
+
# Check that detections are made (at least 2 detections per image expected)
|
|
334
|
+
assert len(cls_idxs) >= 2, f"Expected at least 2 detections, got {len(cls_idxs)}"
|
|
320
335
|
# Check label path
|
|
321
336
|
labels = save_path / f"labels/{im_name}.txt"
|
|
322
337
|
assert labels.exists()
|
|
@@ -332,7 +347,7 @@ def test_labels_and_crops():
|
|
|
332
347
|
|
|
333
348
|
|
|
334
349
|
@pytest.mark.skipif(not ONLINE, reason="environment is offline")
|
|
335
|
-
def test_data_utils():
|
|
350
|
+
def test_data_utils(tmp_path):
|
|
336
351
|
"""Test utility functions in ultralytics/data/utils.py, including dataset stats and auto-splitting."""
|
|
337
352
|
from ultralytics.data.split import autosplit
|
|
338
353
|
from ultralytics.data.utils import HUBDatasetStats
|
|
@@ -343,34 +358,36 @@ def test_data_utils():
|
|
|
343
358
|
|
|
344
359
|
for task in TASKS:
|
|
345
360
|
file = Path(TASK2DATA[task]).with_suffix(".zip") # i.e. coco8.zip
|
|
346
|
-
download(f"https://github.com/ultralytics/hub/raw/main/example_datasets/{file}", unzip=False, dir=
|
|
347
|
-
stats = HUBDatasetStats(
|
|
361
|
+
download(f"https://github.com/ultralytics/hub/raw/main/example_datasets/{file}", unzip=False, dir=tmp_path)
|
|
362
|
+
stats = HUBDatasetStats(tmp_path / file, task=task)
|
|
348
363
|
stats.get_json(save=True)
|
|
349
364
|
stats.process_images()
|
|
350
365
|
|
|
351
|
-
autosplit(
|
|
352
|
-
zip_directory(
|
|
366
|
+
autosplit(tmp_path / "coco8")
|
|
367
|
+
zip_directory(tmp_path / "coco8/images/val") # zip
|
|
353
368
|
|
|
354
369
|
|
|
355
370
|
@pytest.mark.skipif(not ONLINE, reason="environment is offline")
|
|
356
|
-
def test_data_converter():
|
|
371
|
+
def test_data_converter(tmp_path):
|
|
357
372
|
"""Test dataset conversion functions from COCO to YOLO format and class mappings."""
|
|
358
373
|
from ultralytics.data.converter import coco80_to_coco91_class, convert_coco
|
|
359
374
|
|
|
360
|
-
download(f"{ASSETS_URL}/instances_val2017.json", dir=
|
|
361
|
-
convert_coco(
|
|
375
|
+
download(f"{ASSETS_URL}/instances_val2017.json", dir=tmp_path)
|
|
376
|
+
convert_coco(
|
|
377
|
+
labels_dir=tmp_path, save_dir=tmp_path / "yolo_labels", use_segments=True, use_keypoints=False, cls91to80=True
|
|
378
|
+
)
|
|
362
379
|
coco80_to_coco91_class()
|
|
363
380
|
|
|
364
381
|
|
|
365
|
-
def test_data_annotator():
|
|
382
|
+
def test_data_annotator(tmp_path):
|
|
366
383
|
"""Test automatic annotation of data using detection and segmentation models."""
|
|
367
384
|
from ultralytics.data.annotator import auto_annotate
|
|
368
385
|
|
|
369
386
|
auto_annotate(
|
|
370
387
|
ASSETS,
|
|
371
|
-
det_model=WEIGHTS_DIR / "
|
|
388
|
+
det_model=WEIGHTS_DIR / "yolo26n.pt",
|
|
372
389
|
sam_model=WEIGHTS_DIR / "mobile_sam.pt",
|
|
373
|
-
output_dir=
|
|
390
|
+
output_dir=tmp_path / "auto_annotate_labels",
|
|
374
391
|
)
|
|
375
392
|
|
|
376
393
|
|
|
@@ -393,7 +410,46 @@ def test_cfg_init():
|
|
|
393
410
|
check_dict_alignment({"a": 1}, {"b": 2})
|
|
394
411
|
copy_default_cfg()
|
|
395
412
|
(Path.cwd() / DEFAULT_CFG_PATH.name.replace(".yaml", "_copy.yaml")).unlink(missing_ok=False)
|
|
396
|
-
|
|
413
|
+
|
|
414
|
+
# Test smart_value() with comprehensive cases
|
|
415
|
+
# Test None conversion
|
|
416
|
+
assert smart_value("none") is None
|
|
417
|
+
assert smart_value("None") is None
|
|
418
|
+
assert smart_value("NONE") is None
|
|
419
|
+
|
|
420
|
+
# Test boolean conversion
|
|
421
|
+
assert smart_value("true") is True
|
|
422
|
+
assert smart_value("True") is True
|
|
423
|
+
assert smart_value("TRUE") is True
|
|
424
|
+
assert smart_value("false") is False
|
|
425
|
+
assert smart_value("False") is False
|
|
426
|
+
assert smart_value("FALSE") is False
|
|
427
|
+
|
|
428
|
+
# Test numeric conversion (ast.literal_eval)
|
|
429
|
+
assert smart_value("42") == 42
|
|
430
|
+
assert smart_value("-42") == -42
|
|
431
|
+
assert smart_value("3.14") == 3.14
|
|
432
|
+
assert smart_value("-3.14") == -3.14
|
|
433
|
+
assert smart_value("1e-3") == 0.001
|
|
434
|
+
|
|
435
|
+
# Test list/tuple conversion (ast.literal_eval)
|
|
436
|
+
assert smart_value("[1, 2, 3]") == [1, 2, 3]
|
|
437
|
+
assert smart_value("(1, 2, 3)") == (1, 2, 3)
|
|
438
|
+
assert smart_value("[640, 640]") == [640, 640]
|
|
439
|
+
|
|
440
|
+
# Test dict conversion (ast.literal_eval)
|
|
441
|
+
assert smart_value("{'a': 1, 'b': 2}") == {"a": 1, "b": 2}
|
|
442
|
+
|
|
443
|
+
# Test string fallback (when ast.literal_eval fails)
|
|
444
|
+
assert smart_value("some_string") == "some_string"
|
|
445
|
+
assert smart_value("path/to/file") == "path/to/file"
|
|
446
|
+
assert smart_value("hello world") == "hello world"
|
|
447
|
+
|
|
448
|
+
# Test that code injection is prevented (ast.literal_eval safety)
|
|
449
|
+
# These should return strings, not execute code
|
|
450
|
+
assert smart_value("__import__('os').system('ls')") == "__import__('os').system('ls')"
|
|
451
|
+
assert smart_value("eval('1+1')") == "eval('1+1')"
|
|
452
|
+
assert smart_value("exec('x=1')") == "exec('x=1')"
|
|
397
453
|
|
|
398
454
|
|
|
399
455
|
def test_utils_init():
|
|
@@ -419,7 +475,7 @@ def test_utils_benchmarks():
|
|
|
419
475
|
"""Benchmark model performance using 'ProfileModels' from 'ultralytics.utils.benchmarks'."""
|
|
420
476
|
from ultralytics.utils.benchmarks import ProfileModels
|
|
421
477
|
|
|
422
|
-
ProfileModels(["
|
|
478
|
+
ProfileModels(["yolo26n.yaml"], imgsz=32, min_time=1, num_timed_runs=3, num_warmup_runs=1).run()
|
|
423
479
|
|
|
424
480
|
|
|
425
481
|
def test_utils_torchutils():
|
|
@@ -464,7 +520,7 @@ def test_utils_ops():
|
|
|
464
520
|
torch.allclose(boxes, xyxyxyxy2xywhr(xywhr2xyxyxyxy(boxes)), rtol=1e-3)
|
|
465
521
|
|
|
466
522
|
|
|
467
|
-
def test_utils_files():
|
|
523
|
+
def test_utils_files(tmp_path):
|
|
468
524
|
"""Test file handling utilities including file age, date, and paths with spaces."""
|
|
469
525
|
from ultralytics.utils.files import file_age, file_date, get_latest_run, spaces_in_path
|
|
470
526
|
|
|
@@ -472,14 +528,14 @@ def test_utils_files():
|
|
|
472
528
|
file_date(SOURCE)
|
|
473
529
|
get_latest_run(ROOT / "runs")
|
|
474
530
|
|
|
475
|
-
path =
|
|
531
|
+
path = tmp_path / "path/with spaces"
|
|
476
532
|
path.mkdir(parents=True, exist_ok=True)
|
|
477
533
|
with spaces_in_path(path) as new_path:
|
|
478
534
|
print(new_path)
|
|
479
535
|
|
|
480
536
|
|
|
481
537
|
@pytest.mark.slow
|
|
482
|
-
def test_utils_patches_torch_save():
|
|
538
|
+
def test_utils_patches_torch_save(tmp_path):
|
|
483
539
|
"""Test torch_save backoff when _torch_save raises RuntimeError."""
|
|
484
540
|
from unittest.mock import MagicMock, patch
|
|
485
541
|
|
|
@@ -489,7 +545,7 @@ def test_utils_patches_torch_save():
|
|
|
489
545
|
|
|
490
546
|
with patch("ultralytics.utils.patches._torch_save", new=mock):
|
|
491
547
|
with pytest.raises(RuntimeError):
|
|
492
|
-
torch_save(torch.zeros(1),
|
|
548
|
+
torch_save(torch.zeros(1), tmp_path / "test.pt")
|
|
493
549
|
|
|
494
550
|
assert mock.call_count == 4, "torch_save was not attempted the expected number of times"
|
|
495
551
|
|
|
@@ -541,7 +597,7 @@ def test_hub():
|
|
|
541
597
|
|
|
542
598
|
@pytest.fixture
|
|
543
599
|
def image():
|
|
544
|
-
"""Load and return an image from a predefined source."""
|
|
600
|
+
"""Load and return an image from a predefined source (OpenCV BGR)."""
|
|
545
601
|
return cv2.imread(str(SOURCE))
|
|
546
602
|
|
|
547
603
|
|
|
@@ -585,14 +641,14 @@ def test_classify_transforms_train(image, auto_augment, erasing, force_color_jit
|
|
|
585
641
|
@pytest.mark.skipif(not ONLINE, reason="environment is offline")
|
|
586
642
|
def test_model_tune():
|
|
587
643
|
"""Tune YOLO model for performance improvement."""
|
|
588
|
-
YOLO("
|
|
589
|
-
YOLO("
|
|
644
|
+
YOLO("yolo26n-pose.pt").tune(data="coco8-pose.yaml", plots=False, imgsz=32, epochs=1, iterations=2, device="cpu")
|
|
645
|
+
YOLO("yolo26n-cls.pt").tune(data="imagenet10", plots=False, imgsz=32, epochs=1, iterations=2, device="cpu")
|
|
590
646
|
|
|
591
647
|
|
|
592
648
|
def test_model_embeddings():
|
|
593
649
|
"""Test YOLO model embeddings extraction functionality."""
|
|
594
650
|
model_detect = YOLO(MODEL)
|
|
595
|
-
model_segment = YOLO(WEIGHTS_DIR / "
|
|
651
|
+
model_segment = YOLO(WEIGHTS_DIR / "yolo26n-seg.pt")
|
|
596
652
|
|
|
597
653
|
for batch in [SOURCE], [SOURCE, SOURCE]: # test batch size 1 and 2
|
|
598
654
|
assert len(model_detect.embed(source=batch, imgsz=32)) == len(batch)
|
|
@@ -713,7 +769,7 @@ def test_yolov10():
|
|
|
713
769
|
|
|
714
770
|
def test_multichannel():
|
|
715
771
|
"""Test YOLO model multi-channel training, validation, and prediction functionality."""
|
|
716
|
-
model = YOLO("
|
|
772
|
+
model = YOLO("yolo26n.pt")
|
|
717
773
|
model.train(data="coco8-multispectral.yaml", epochs=1, imgsz=32, close_mosaic=1, cache="disk")
|
|
718
774
|
model.val(data="coco8-multispectral.yaml")
|
|
719
775
|
im = np.zeros((32, 32, 10), dtype=np.uint8)
|
|
@@ -722,14 +778,14 @@ def test_multichannel():
|
|
|
722
778
|
|
|
723
779
|
|
|
724
780
|
@pytest.mark.parametrize("task,model,data", TASK_MODEL_DATA)
|
|
725
|
-
def test_grayscale(task: str, model: str, data: str) -> None:
|
|
781
|
+
def test_grayscale(task: str, model: str, data: str, tmp_path) -> None:
|
|
726
782
|
"""Test YOLO model grayscale training, validation, and prediction functionality."""
|
|
727
783
|
if task == "classify": # not support grayscale classification yet
|
|
728
784
|
return
|
|
729
|
-
grayscale_data =
|
|
785
|
+
grayscale_data = tmp_path / f"{Path(data).stem}-grayscale.yaml"
|
|
730
786
|
data = check_det_dataset(data)
|
|
731
787
|
data["channels"] = 1 # add additional channels key for grayscale
|
|
732
|
-
YAML.save(
|
|
788
|
+
YAML.save(data=data, file=grayscale_data)
|
|
733
789
|
# remove npy files in train/val splits if exists, might be created by previous tests
|
|
734
790
|
for split in {"train", "val"}:
|
|
735
791
|
for npy_file in (Path(data["path"]) / data[split]).glob("*.npy"):
|