dgenerate-ultralytics-headless 8.3.137__py3-none-any.whl → 8.3.224__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.137.dist-info → dgenerate_ultralytics_headless-8.3.224.dist-info}/METADATA +41 -34
- dgenerate_ultralytics_headless-8.3.224.dist-info/RECORD +285 -0
- {dgenerate_ultralytics_headless-8.3.137.dist-info → dgenerate_ultralytics_headless-8.3.224.dist-info}/WHEEL +1 -1
- tests/__init__.py +7 -6
- tests/conftest.py +15 -39
- tests/test_cli.py +17 -17
- tests/test_cuda.py +17 -8
- tests/test_engine.py +36 -10
- tests/test_exports.py +98 -37
- tests/test_integrations.py +12 -15
- tests/test_python.py +126 -82
- tests/test_solutions.py +319 -135
- ultralytics/__init__.py +27 -9
- ultralytics/cfg/__init__.py +83 -87
- ultralytics/cfg/datasets/Argoverse.yaml +4 -4
- ultralytics/cfg/datasets/DOTAv1.5.yaml +2 -2
- ultralytics/cfg/datasets/DOTAv1.yaml +2 -2
- ultralytics/cfg/datasets/GlobalWheat2020.yaml +2 -2
- ultralytics/cfg/datasets/HomeObjects-3K.yaml +4 -5
- ultralytics/cfg/datasets/ImageNet.yaml +3 -3
- ultralytics/cfg/datasets/Objects365.yaml +24 -20
- ultralytics/cfg/datasets/SKU-110K.yaml +9 -9
- ultralytics/cfg/datasets/VOC.yaml +10 -13
- ultralytics/cfg/datasets/VisDrone.yaml +43 -33
- ultralytics/cfg/datasets/african-wildlife.yaml +5 -5
- ultralytics/cfg/datasets/brain-tumor.yaml +4 -5
- ultralytics/cfg/datasets/carparts-seg.yaml +5 -5
- ultralytics/cfg/datasets/coco-pose.yaml +26 -4
- ultralytics/cfg/datasets/coco.yaml +4 -4
- ultralytics/cfg/datasets/coco128-seg.yaml +2 -2
- ultralytics/cfg/datasets/coco128.yaml +2 -2
- ultralytics/cfg/datasets/coco8-grayscale.yaml +103 -0
- ultralytics/cfg/datasets/coco8-multispectral.yaml +2 -2
- ultralytics/cfg/datasets/coco8-pose.yaml +23 -2
- ultralytics/cfg/datasets/coco8-seg.yaml +2 -2
- ultralytics/cfg/datasets/coco8.yaml +2 -2
- ultralytics/cfg/datasets/construction-ppe.yaml +32 -0
- ultralytics/cfg/datasets/crack-seg.yaml +5 -5
- ultralytics/cfg/datasets/dog-pose.yaml +32 -4
- ultralytics/cfg/datasets/dota8-multispectral.yaml +2 -2
- ultralytics/cfg/datasets/dota8.yaml +2 -2
- ultralytics/cfg/datasets/hand-keypoints.yaml +29 -4
- ultralytics/cfg/datasets/lvis.yaml +9 -9
- ultralytics/cfg/datasets/medical-pills.yaml +4 -5
- ultralytics/cfg/datasets/open-images-v7.yaml +7 -10
- ultralytics/cfg/datasets/package-seg.yaml +5 -5
- ultralytics/cfg/datasets/signature.yaml +4 -4
- ultralytics/cfg/datasets/tiger-pose.yaml +20 -4
- ultralytics/cfg/datasets/xView.yaml +5 -5
- ultralytics/cfg/default.yaml +96 -93
- ultralytics/cfg/trackers/botsort.yaml +16 -17
- ultralytics/cfg/trackers/bytetrack.yaml +9 -11
- ultralytics/data/__init__.py +4 -4
- ultralytics/data/annotator.py +12 -12
- ultralytics/data/augment.py +531 -564
- ultralytics/data/base.py +76 -81
- ultralytics/data/build.py +206 -42
- ultralytics/data/converter.py +179 -78
- ultralytics/data/dataset.py +121 -121
- ultralytics/data/loaders.py +114 -91
- ultralytics/data/split.py +28 -15
- ultralytics/data/split_dota.py +67 -48
- ultralytics/data/utils.py +110 -89
- ultralytics/engine/exporter.py +422 -460
- ultralytics/engine/model.py +224 -252
- ultralytics/engine/predictor.py +94 -89
- ultralytics/engine/results.py +345 -595
- ultralytics/engine/trainer.py +231 -134
- ultralytics/engine/tuner.py +279 -73
- ultralytics/engine/validator.py +53 -46
- ultralytics/hub/__init__.py +26 -28
- ultralytics/hub/auth.py +30 -16
- ultralytics/hub/google/__init__.py +34 -36
- ultralytics/hub/session.py +53 -77
- ultralytics/hub/utils.py +23 -109
- ultralytics/models/__init__.py +1 -1
- ultralytics/models/fastsam/__init__.py +1 -1
- ultralytics/models/fastsam/model.py +36 -18
- ultralytics/models/fastsam/predict.py +33 -44
- ultralytics/models/fastsam/utils.py +4 -5
- ultralytics/models/fastsam/val.py +12 -14
- ultralytics/models/nas/__init__.py +1 -1
- ultralytics/models/nas/model.py +16 -20
- ultralytics/models/nas/predict.py +12 -14
- ultralytics/models/nas/val.py +4 -5
- ultralytics/models/rtdetr/__init__.py +1 -1
- ultralytics/models/rtdetr/model.py +9 -9
- ultralytics/models/rtdetr/predict.py +22 -17
- ultralytics/models/rtdetr/train.py +20 -16
- ultralytics/models/rtdetr/val.py +79 -59
- ultralytics/models/sam/__init__.py +8 -2
- ultralytics/models/sam/amg.py +53 -38
- ultralytics/models/sam/build.py +29 -31
- ultralytics/models/sam/model.py +33 -38
- ultralytics/models/sam/modules/blocks.py +159 -182
- ultralytics/models/sam/modules/decoders.py +38 -47
- ultralytics/models/sam/modules/encoders.py +114 -133
- ultralytics/models/sam/modules/memory_attention.py +38 -31
- ultralytics/models/sam/modules/sam.py +114 -93
- ultralytics/models/sam/modules/tiny_encoder.py +268 -291
- ultralytics/models/sam/modules/transformer.py +59 -66
- ultralytics/models/sam/modules/utils.py +55 -72
- ultralytics/models/sam/predict.py +745 -341
- ultralytics/models/utils/loss.py +118 -107
- ultralytics/models/utils/ops.py +118 -71
- ultralytics/models/yolo/__init__.py +1 -1
- ultralytics/models/yolo/classify/predict.py +28 -26
- ultralytics/models/yolo/classify/train.py +50 -81
- ultralytics/models/yolo/classify/val.py +68 -61
- ultralytics/models/yolo/detect/predict.py +12 -15
- ultralytics/models/yolo/detect/train.py +56 -46
- ultralytics/models/yolo/detect/val.py +279 -223
- ultralytics/models/yolo/model.py +167 -86
- ultralytics/models/yolo/obb/predict.py +7 -11
- ultralytics/models/yolo/obb/train.py +23 -25
- ultralytics/models/yolo/obb/val.py +107 -99
- ultralytics/models/yolo/pose/__init__.py +1 -1
- ultralytics/models/yolo/pose/predict.py +12 -14
- ultralytics/models/yolo/pose/train.py +31 -69
- ultralytics/models/yolo/pose/val.py +119 -254
- ultralytics/models/yolo/segment/predict.py +21 -25
- ultralytics/models/yolo/segment/train.py +12 -66
- ultralytics/models/yolo/segment/val.py +126 -305
- ultralytics/models/yolo/world/train.py +53 -45
- ultralytics/models/yolo/world/train_world.py +51 -32
- ultralytics/models/yolo/yoloe/__init__.py +7 -7
- ultralytics/models/yolo/yoloe/predict.py +30 -37
- ultralytics/models/yolo/yoloe/train.py +89 -71
- ultralytics/models/yolo/yoloe/train_seg.py +15 -17
- ultralytics/models/yolo/yoloe/val.py +56 -41
- ultralytics/nn/__init__.py +9 -11
- ultralytics/nn/autobackend.py +179 -107
- ultralytics/nn/modules/__init__.py +67 -67
- ultralytics/nn/modules/activation.py +8 -7
- ultralytics/nn/modules/block.py +302 -323
- ultralytics/nn/modules/conv.py +61 -104
- ultralytics/nn/modules/head.py +488 -186
- ultralytics/nn/modules/transformer.py +183 -123
- ultralytics/nn/modules/utils.py +15 -20
- ultralytics/nn/tasks.py +327 -203
- ultralytics/nn/text_model.py +81 -65
- ultralytics/py.typed +1 -0
- ultralytics/solutions/__init__.py +12 -12
- ultralytics/solutions/ai_gym.py +19 -27
- ultralytics/solutions/analytics.py +36 -26
- ultralytics/solutions/config.py +29 -28
- ultralytics/solutions/distance_calculation.py +23 -24
- ultralytics/solutions/heatmap.py +17 -19
- ultralytics/solutions/instance_segmentation.py +21 -19
- ultralytics/solutions/object_blurrer.py +16 -17
- ultralytics/solutions/object_counter.py +48 -53
- ultralytics/solutions/object_cropper.py +22 -16
- ultralytics/solutions/parking_management.py +61 -58
- ultralytics/solutions/queue_management.py +19 -19
- ultralytics/solutions/region_counter.py +63 -50
- ultralytics/solutions/security_alarm.py +22 -25
- ultralytics/solutions/similarity_search.py +107 -60
- ultralytics/solutions/solutions.py +343 -262
- ultralytics/solutions/speed_estimation.py +35 -31
- ultralytics/solutions/streamlit_inference.py +104 -40
- ultralytics/solutions/templates/similarity-search.html +31 -24
- ultralytics/solutions/trackzone.py +24 -24
- ultralytics/solutions/vision_eye.py +11 -12
- ultralytics/trackers/__init__.py +1 -1
- ultralytics/trackers/basetrack.py +18 -27
- ultralytics/trackers/bot_sort.py +48 -39
- ultralytics/trackers/byte_tracker.py +94 -94
- ultralytics/trackers/track.py +7 -16
- ultralytics/trackers/utils/gmc.py +37 -69
- ultralytics/trackers/utils/kalman_filter.py +68 -76
- ultralytics/trackers/utils/matching.py +13 -17
- ultralytics/utils/__init__.py +251 -275
- ultralytics/utils/autobatch.py +19 -7
- ultralytics/utils/autodevice.py +68 -38
- ultralytics/utils/benchmarks.py +169 -130
- ultralytics/utils/callbacks/base.py +12 -13
- ultralytics/utils/callbacks/clearml.py +14 -15
- ultralytics/utils/callbacks/comet.py +139 -66
- ultralytics/utils/callbacks/dvc.py +19 -27
- ultralytics/utils/callbacks/hub.py +8 -6
- ultralytics/utils/callbacks/mlflow.py +6 -10
- ultralytics/utils/callbacks/neptune.py +11 -19
- ultralytics/utils/callbacks/platform.py +73 -0
- ultralytics/utils/callbacks/raytune.py +3 -4
- ultralytics/utils/callbacks/tensorboard.py +9 -12
- ultralytics/utils/callbacks/wb.py +33 -30
- ultralytics/utils/checks.py +163 -114
- ultralytics/utils/cpu.py +89 -0
- ultralytics/utils/dist.py +24 -20
- ultralytics/utils/downloads.py +176 -146
- ultralytics/utils/errors.py +11 -13
- ultralytics/utils/events.py +113 -0
- ultralytics/utils/export/__init__.py +7 -0
- ultralytics/utils/{export.py → export/engine.py} +81 -63
- ultralytics/utils/export/imx.py +294 -0
- ultralytics/utils/export/tensorflow.py +217 -0
- ultralytics/utils/files.py +33 -36
- ultralytics/utils/git.py +137 -0
- ultralytics/utils/instance.py +105 -120
- ultralytics/utils/logger.py +404 -0
- ultralytics/utils/loss.py +99 -61
- ultralytics/utils/metrics.py +649 -478
- ultralytics/utils/nms.py +337 -0
- ultralytics/utils/ops.py +263 -451
- ultralytics/utils/patches.py +70 -31
- ultralytics/utils/plotting.py +253 -223
- ultralytics/utils/tal.py +48 -61
- ultralytics/utils/torch_utils.py +244 -251
- ultralytics/utils/tqdm.py +438 -0
- ultralytics/utils/triton.py +22 -23
- ultralytics/utils/tuner.py +11 -10
- dgenerate_ultralytics_headless-8.3.137.dist-info/RECORD +0 -272
- {dgenerate_ultralytics_headless-8.3.137.dist-info → dgenerate_ultralytics_headless-8.3.224.dist-info}/entry_points.txt +0 -0
- {dgenerate_ultralytics_headless-8.3.137.dist-info → dgenerate_ultralytics_headless-8.3.224.dist-info}/licenses/LICENSE +0 -0
- {dgenerate_ultralytics_headless-8.3.137.dist-info → dgenerate_ultralytics_headless-8.3.224.dist-info}/top_level.txt +0 -0
tests/test_integrations.py
CHANGED
|
@@ -8,9 +8,9 @@ from pathlib import Path
|
|
|
8
8
|
|
|
9
9
|
import pytest
|
|
10
10
|
|
|
11
|
-
from tests import MODEL, SOURCE
|
|
11
|
+
from tests import MODEL, SOURCE
|
|
12
12
|
from ultralytics import YOLO, download
|
|
13
|
-
from ultralytics.utils import DATASETS_DIR, SETTINGS
|
|
13
|
+
from ultralytics.utils import ASSETS_URL, DATASETS_DIR, SETTINGS
|
|
14
14
|
from ultralytics.utils.checks import check_requirements
|
|
15
15
|
|
|
16
16
|
|
|
@@ -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
|
|
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
|
|
@@ -71,14 +71,14 @@ def test_mlflow_keep_run_active():
|
|
|
71
71
|
|
|
72
72
|
|
|
73
73
|
@pytest.mark.skipif(not check_requirements("tritonclient", install=False), reason="tritonclient[all] not installed")
|
|
74
|
-
def test_triton():
|
|
74
|
+
def test_triton(tmp_path):
|
|
75
75
|
"""Test NVIDIA Triton Server functionalities with YOLO model."""
|
|
76
76
|
check_requirements("tritonclient[all]")
|
|
77
|
-
from tritonclient.http import InferenceServerClient
|
|
77
|
+
from tritonclient.http import InferenceServerClient
|
|
78
78
|
|
|
79
79
|
# Create variables
|
|
80
80
|
model_name = "yolo"
|
|
81
|
-
triton_repo =
|
|
81
|
+
triton_repo = tmp_path / "triton_repo" # Triton repo path
|
|
82
82
|
triton_model = triton_repo / model_name # Triton model path
|
|
83
83
|
|
|
84
84
|
# Export model to ONNX
|
|
@@ -122,33 +122,30 @@ def test_triton():
|
|
|
122
122
|
subprocess.call(f"docker kill {container_id}", shell=True)
|
|
123
123
|
|
|
124
124
|
|
|
125
|
-
@pytest.mark.skipif(not check_requirements("
|
|
126
|
-
def
|
|
127
|
-
"""Validate YOLO model predictions on COCO dataset using
|
|
125
|
+
@pytest.mark.skipif(not check_requirements("faster-coco-eval", install=False), reason="faster-coco-eval not installed")
|
|
126
|
+
def test_faster_coco_eval():
|
|
127
|
+
"""Validate YOLO model predictions on COCO dataset using faster-coco-eval."""
|
|
128
128
|
from ultralytics.models.yolo.detect import DetectionValidator
|
|
129
129
|
from ultralytics.models.yolo.pose import PoseValidator
|
|
130
130
|
from ultralytics.models.yolo.segment import SegmentationValidator
|
|
131
131
|
|
|
132
|
-
# Download annotations after each dataset downloads first
|
|
133
|
-
url = "https://github.com/ultralytics/assets/releases/download/v0.0.0/"
|
|
134
|
-
|
|
135
132
|
args = {"model": "yolo11n.pt", "data": "coco8.yaml", "save_json": True, "imgsz": 64}
|
|
136
133
|
validator = DetectionValidator(args=args)
|
|
137
134
|
validator()
|
|
138
135
|
validator.is_coco = True
|
|
139
|
-
download(f"{
|
|
136
|
+
download(f"{ASSETS_URL}/instances_val2017.json", dir=DATASETS_DIR / "coco8/annotations")
|
|
140
137
|
_ = validator.eval_json(validator.stats)
|
|
141
138
|
|
|
142
139
|
args = {"model": "yolo11n-seg.pt", "data": "coco8-seg.yaml", "save_json": True, "imgsz": 64}
|
|
143
140
|
validator = SegmentationValidator(args=args)
|
|
144
141
|
validator()
|
|
145
142
|
validator.is_coco = True
|
|
146
|
-
download(f"{
|
|
143
|
+
download(f"{ASSETS_URL}/instances_val2017.json", dir=DATASETS_DIR / "coco8-seg/annotations")
|
|
147
144
|
_ = validator.eval_json(validator.stats)
|
|
148
145
|
|
|
149
146
|
args = {"model": "yolo11n-pose.pt", "data": "coco8-pose.yaml", "save_json": True, "imgsz": 64}
|
|
150
147
|
validator = PoseValidator(args=args)
|
|
151
148
|
validator()
|
|
152
149
|
validator.is_coco = True
|
|
153
|
-
download(f"{
|
|
150
|
+
download(f"{ASSETS_URL}/person_keypoints_val2017.json", dir=DATASETS_DIR / "coco8-pose/annotations")
|
|
154
151
|
_ = validator.eval_json(validator.stats)
|
tests/test_python.py
CHANGED
|
@@ -12,15 +12,19 @@ import pytest
|
|
|
12
12
|
import torch
|
|
13
13
|
from PIL import Image
|
|
14
14
|
|
|
15
|
-
from tests import CFG, MODEL, SOURCE, SOURCES_LIST,
|
|
15
|
+
from tests import CFG, MODEL, MODELS, SOURCE, SOURCES_LIST, TASK_MODEL_DATA
|
|
16
16
|
from ultralytics import RTDETR, YOLO
|
|
17
|
-
from ultralytics.cfg import
|
|
17
|
+
from ultralytics.cfg import TASK2DATA, TASKS
|
|
18
18
|
from ultralytics.data.build import load_inference_source
|
|
19
|
+
from ultralytics.data.utils import check_det_dataset
|
|
19
20
|
from ultralytics.utils import (
|
|
20
21
|
ARM64,
|
|
21
22
|
ASSETS,
|
|
23
|
+
ASSETS_URL,
|
|
22
24
|
DEFAULT_CFG,
|
|
23
25
|
DEFAULT_CFG_PATH,
|
|
26
|
+
IS_JETSON,
|
|
27
|
+
IS_RASPBERRYPI,
|
|
24
28
|
LINUX,
|
|
25
29
|
LOGGER,
|
|
26
30
|
ONLINE,
|
|
@@ -29,13 +33,10 @@ from ultralytics.utils import (
|
|
|
29
33
|
WINDOWS,
|
|
30
34
|
YAML,
|
|
31
35
|
checks,
|
|
32
|
-
is_dir_writeable,
|
|
33
36
|
is_github_action_running,
|
|
34
37
|
)
|
|
35
38
|
from ultralytics.utils.downloads import download
|
|
36
|
-
from ultralytics.utils.torch_utils import
|
|
37
|
-
|
|
38
|
-
IS_TMP_WRITEABLE = is_dir_writeable(TMP) # WARNING: must be run once tests start as TMP does not exist on tests/init
|
|
39
|
+
from ultralytics.utils.torch_utils import TORCH_1_11, TORCH_1_13
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
def test_model_forward():
|
|
@@ -73,10 +74,9 @@ def test_model_profile():
|
|
|
73
74
|
_ = model.predict(im, profile=True)
|
|
74
75
|
|
|
75
76
|
|
|
76
|
-
|
|
77
|
-
def test_predict_txt():
|
|
77
|
+
def test_predict_txt(tmp_path):
|
|
78
78
|
"""Test YOLO predictions with file, directory, and pattern sources listed in a text file."""
|
|
79
|
-
file =
|
|
79
|
+
file = tmp_path / "sources_multi_row.txt"
|
|
80
80
|
with open(file, "w") as f:
|
|
81
81
|
for src in SOURCES_LIST:
|
|
82
82
|
f.write(f"{src}\n")
|
|
@@ -85,10 +85,9 @@ def test_predict_txt():
|
|
|
85
85
|
|
|
86
86
|
|
|
87
87
|
@pytest.mark.skipif(True, reason="disabled for testing")
|
|
88
|
-
|
|
89
|
-
def test_predict_csv_multi_row():
|
|
88
|
+
def test_predict_csv_multi_row(tmp_path):
|
|
90
89
|
"""Test YOLO predictions with sources listed in multiple rows of a CSV file."""
|
|
91
|
-
file =
|
|
90
|
+
file = tmp_path / "sources_multi_row.csv"
|
|
92
91
|
with open(file, "w", newline="") as f:
|
|
93
92
|
writer = csv.writer(f)
|
|
94
93
|
writer.writerow(["source"])
|
|
@@ -98,10 +97,9 @@ def test_predict_csv_multi_row():
|
|
|
98
97
|
|
|
99
98
|
|
|
100
99
|
@pytest.mark.skipif(True, reason="disabled for testing")
|
|
101
|
-
|
|
102
|
-
def test_predict_csv_single_row():
|
|
100
|
+
def test_predict_csv_single_row(tmp_path):
|
|
103
101
|
"""Test YOLO predictions with sources listed in a single row of a CSV file."""
|
|
104
|
-
file =
|
|
102
|
+
file = tmp_path / "sources_single_row.csv"
|
|
105
103
|
with open(file, "w", newline="") as f:
|
|
106
104
|
writer = csv.writer(f)
|
|
107
105
|
writer.writerow(SOURCES_LIST)
|
|
@@ -112,21 +110,22 @@ def test_predict_csv_single_row():
|
|
|
112
110
|
@pytest.mark.parametrize("model_name", MODELS)
|
|
113
111
|
def test_predict_img(model_name):
|
|
114
112
|
"""Test YOLO model predictions on various image input types and sources, including online images."""
|
|
113
|
+
channels = 1 if model_name == "yolo11n-grayscale.pt" else 3
|
|
115
114
|
model = YOLO(WEIGHTS_DIR / model_name)
|
|
116
|
-
im = cv2.imread(str(SOURCE)) # uint8 numpy array
|
|
115
|
+
im = cv2.imread(str(SOURCE), flags=cv2.IMREAD_GRAYSCALE if channels == 1 else cv2.IMREAD_COLOR) # uint8 numpy array
|
|
117
116
|
assert len(model(source=Image.open(SOURCE), save=True, verbose=True, imgsz=32)) == 1 # PIL
|
|
118
117
|
assert len(model(source=im, save=True, save_txt=True, imgsz=32)) == 1 # ndarray
|
|
119
|
-
assert len(model(torch.rand((2,
|
|
118
|
+
assert len(model(torch.rand((2, channels, 32, 32)), imgsz=32)) == 2 # batch-size 2 Tensor, FP32 0.0-1.0 RGB order
|
|
120
119
|
assert len(model(source=[im, im], save=True, save_txt=True, imgsz=32)) == 2 # batch
|
|
121
120
|
assert len(list(model(source=[im, im], save=True, stream=True, imgsz=32))) == 2 # stream
|
|
122
|
-
assert len(model(torch.zeros(320, 640,
|
|
121
|
+
assert len(model(torch.zeros(320, 640, channels).numpy().astype(np.uint8), imgsz=32)) == 1 # tensor to numpy
|
|
123
122
|
batch = [
|
|
124
123
|
str(SOURCE), # filename
|
|
125
124
|
Path(SOURCE), # Path
|
|
126
|
-
"
|
|
127
|
-
|
|
125
|
+
f"{ASSETS_URL}/zidane.jpg?token=123" if ONLINE else SOURCE, # URI
|
|
126
|
+
im, # OpenCV
|
|
128
127
|
Image.open(SOURCE), # PIL
|
|
129
|
-
np.zeros((320, 640,
|
|
128
|
+
np.zeros((320, 640, channels), dtype=np.uint8), # numpy
|
|
130
129
|
]
|
|
131
130
|
assert len(model(batch, imgsz=32, classes=0)) == len(batch) # multiple sources in a batch
|
|
132
131
|
|
|
@@ -137,25 +136,23 @@ def test_predict_visualize(model):
|
|
|
137
136
|
YOLO(WEIGHTS_DIR / model)(SOURCE, imgsz=32, visualize=True)
|
|
138
137
|
|
|
139
138
|
|
|
140
|
-
def
|
|
141
|
-
"""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."""
|
|
142
141
|
im = Image.open(SOURCE)
|
|
143
|
-
directory = TMP / "im4"
|
|
144
|
-
directory.mkdir(parents=True, exist_ok=True)
|
|
145
142
|
|
|
146
|
-
|
|
147
|
-
source_rgba =
|
|
148
|
-
source_non_utf =
|
|
149
|
-
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"
|
|
150
147
|
|
|
151
|
-
im.convert("L").save(
|
|
148
|
+
im.convert("L").save(source_grayscale) # grayscale
|
|
152
149
|
im.convert("RGBA").save(source_rgba) # 4-ch PNG with alpha
|
|
153
150
|
im.save(source_non_utf) # non-UTF characters in filename
|
|
154
151
|
im.save(source_spaces) # spaces in filename
|
|
155
152
|
|
|
156
153
|
# Inference
|
|
157
154
|
model = YOLO(MODEL)
|
|
158
|
-
for f in source_rgba,
|
|
155
|
+
for f in source_rgba, source_grayscale, source_non_utf, source_spaces:
|
|
159
156
|
for source in Image.open(f), cv2.imread(str(f)), f:
|
|
160
157
|
results = model(source, save=True, verbose=True, imgsz=32)
|
|
161
158
|
assert len(results) == 1 # verify that an image was run
|
|
@@ -176,31 +173,43 @@ def test_youtube():
|
|
|
176
173
|
|
|
177
174
|
|
|
178
175
|
@pytest.mark.skipif(not ONLINE, reason="environment is offline")
|
|
179
|
-
@pytest.mark.
|
|
180
|
-
def test_track_stream():
|
|
181
|
-
"""
|
|
182
|
-
Test streaming tracking on a short 10 frame video using ByteTrack tracker and different GMC methods.
|
|
176
|
+
@pytest.mark.parametrize("model", MODELS)
|
|
177
|
+
def test_track_stream(model, tmp_path):
|
|
178
|
+
"""Test streaming tracking on a short 10 frame video using ByteTrack tracker and different GMC methods.
|
|
183
179
|
|
|
184
180
|
Note imgsz=160 required for tracking for higher confidence and better matches.
|
|
185
181
|
"""
|
|
186
|
-
|
|
187
|
-
|
|
182
|
+
if model == "yolo11n-cls.pt": # classification model not supported for tracking
|
|
183
|
+
return
|
|
184
|
+
video_url = f"{ASSETS_URL}/decelera_portrait_min.mov"
|
|
185
|
+
model = YOLO(model)
|
|
188
186
|
model.track(video_url, imgsz=160, tracker="bytetrack.yaml")
|
|
189
187
|
model.track(video_url, imgsz=160, tracker="botsort.yaml", save_frames=True) # test frame saving also
|
|
190
188
|
|
|
191
189
|
# Test Global Motion Compensation (GMC) methods and ReID
|
|
192
190
|
for gmc, reidm in zip(["orb", "sift", "ecc"], ["auto", "auto", "yolo11n-cls.pt"]):
|
|
193
191
|
default_args = YAML.load(ROOT / "cfg/trackers/botsort.yaml")
|
|
194
|
-
custom_yaml =
|
|
192
|
+
custom_yaml = tmp_path / f"botsort-{gmc}.yaml"
|
|
195
193
|
YAML.save(custom_yaml, {**default_args, "gmc_method": gmc, "with_reid": True, "model": reidm})
|
|
196
194
|
model.track(video_url, imgsz=160, tracker=custom_yaml)
|
|
197
195
|
|
|
198
196
|
|
|
199
|
-
|
|
197
|
+
@pytest.mark.parametrize("task,weight,data", TASK_MODEL_DATA)
|
|
198
|
+
def test_val(task: str, weight: str, data: str) -> None:
|
|
200
199
|
"""Test the validation mode of the YOLO model."""
|
|
201
|
-
YOLO(
|
|
202
|
-
|
|
203
|
-
|
|
200
|
+
model = YOLO(weight)
|
|
201
|
+
for plots in {True, False}: # Test both cases i.e. plots=True and plots=False
|
|
202
|
+
metrics = model.val(data=data, imgsz=32, plots=plots)
|
|
203
|
+
metrics.to_df()
|
|
204
|
+
metrics.to_csv()
|
|
205
|
+
metrics.to_json()
|
|
206
|
+
# Tests for confusion matrix export
|
|
207
|
+
metrics.confusion_matrix.to_df()
|
|
208
|
+
metrics.confusion_matrix.to_csv()
|
|
209
|
+
metrics.confusion_matrix.to_json()
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
@pytest.mark.skipif(IS_JETSON or IS_RASPBERRYPI, reason="Edge devices not intended for training")
|
|
204
213
|
def test_train_scratch():
|
|
205
214
|
"""Test training the YOLO model from scratch using the provided configuration."""
|
|
206
215
|
model = YOLO(CFG)
|
|
@@ -208,6 +217,13 @@ def test_train_scratch():
|
|
|
208
217
|
model(SOURCE)
|
|
209
218
|
|
|
210
219
|
|
|
220
|
+
@pytest.mark.skipif(not ONLINE, reason="environment is offline")
|
|
221
|
+
def test_train_ndjson():
|
|
222
|
+
"""Test training the YOLO model using NDJSON format dataset."""
|
|
223
|
+
model = YOLO(WEIGHTS_DIR / "yolo11n.pt")
|
|
224
|
+
model.train(data=f"{ASSETS_URL}/coco8-ndjson.ndjson", epochs=1, imgsz=32)
|
|
225
|
+
|
|
226
|
+
|
|
211
227
|
@pytest.mark.parametrize("scls", [False, True])
|
|
212
228
|
def test_train_pretrained(scls):
|
|
213
229
|
"""Test training of the YOLO model starting from a pre-trained checkpoint."""
|
|
@@ -222,7 +238,7 @@ def test_all_model_yamls():
|
|
|
222
238
|
"""Test YOLO model creation for all available YAML configurations in the `cfg/models` directory."""
|
|
223
239
|
for m in (ROOT / "cfg" / "models").rglob("*.yaml"):
|
|
224
240
|
if "rtdetr" in m.name:
|
|
225
|
-
if
|
|
241
|
+
if TORCH_1_11:
|
|
226
242
|
_ = RTDETR(m.name)(SOURCE, imgsz=640) # must be 640
|
|
227
243
|
else:
|
|
228
244
|
YOLO(m.name)
|
|
@@ -246,13 +262,13 @@ def test_predict_callback_and_setup():
|
|
|
246
262
|
path, im0s, _ = predictor.batch
|
|
247
263
|
im0s = im0s if isinstance(im0s, list) else [im0s]
|
|
248
264
|
bs = [predictor.dataset.bs for _ in range(len(path))]
|
|
249
|
-
predictor.results = zip(predictor.results, im0s, bs) # results is
|
|
265
|
+
predictor.results = zip(predictor.results, im0s, bs) # results is list[batch_size]
|
|
250
266
|
|
|
251
267
|
model = YOLO(MODEL)
|
|
252
268
|
model.add_callback("on_predict_batch_end", on_predict_batch_end)
|
|
253
269
|
|
|
254
270
|
dataset = load_inference_source(source=SOURCE)
|
|
255
|
-
bs = dataset.bs #
|
|
271
|
+
bs = dataset.bs # access predictor properties
|
|
256
272
|
results = model.predict(dataset, stream=True, imgsz=160) # source already setup
|
|
257
273
|
for r, im0, bs in results:
|
|
258
274
|
print("test_callback", im0.shape)
|
|
@@ -262,22 +278,21 @@ def test_predict_callback_and_setup():
|
|
|
262
278
|
|
|
263
279
|
|
|
264
280
|
@pytest.mark.parametrize("model", MODELS)
|
|
265
|
-
def test_results(model):
|
|
281
|
+
def test_results(model: str, tmp_path):
|
|
266
282
|
"""Test YOLO model results processing and output in various formats."""
|
|
267
|
-
|
|
283
|
+
im = f"{ASSETS_URL}/boats.jpg" if model == "yolo11n-obb.pt" else SOURCE
|
|
284
|
+
results = YOLO(WEIGHTS_DIR / model)([im, im], imgsz=160)
|
|
268
285
|
for r in results:
|
|
286
|
+
assert len(r), f"'{model}' results should not be empty!"
|
|
269
287
|
r = r.cpu().numpy()
|
|
270
288
|
print(r, len(r), r.path) # print numpy attributes
|
|
271
289
|
r = r.to(device="cpu", dtype=torch.float32)
|
|
272
|
-
r.save_txt(txt_file=
|
|
273
|
-
r.save_crop(save_dir=
|
|
290
|
+
r.save_txt(txt_file=tmp_path / "runs/tests/label.txt", save_conf=True)
|
|
291
|
+
r.save_crop(save_dir=tmp_path / "runs/tests/crops/")
|
|
274
292
|
r.to_df(decimals=3) # Align to_ methods: https://docs.ultralytics.com/modes/predict/#working-with-results
|
|
275
293
|
r.to_csv()
|
|
276
|
-
r.to_xml()
|
|
277
|
-
r.to_html()
|
|
278
294
|
r.to_json(normalize=True)
|
|
279
|
-
r.
|
|
280
|
-
r.plot(pil=True, save=True, filename=TMP / "results_plot_save.jpg")
|
|
295
|
+
r.plot(pil=True, save=True, filename=tmp_path / "results_plot_save.jpg")
|
|
281
296
|
r.plot(conf=True, boxes=True)
|
|
282
297
|
print(r, len(r), r.path) # print after methods
|
|
283
298
|
|
|
@@ -307,7 +322,7 @@ def test_labels_and_crops():
|
|
|
307
322
|
|
|
308
323
|
|
|
309
324
|
@pytest.mark.skipif(not ONLINE, reason="environment is offline")
|
|
310
|
-
def test_data_utils():
|
|
325
|
+
def test_data_utils(tmp_path):
|
|
311
326
|
"""Test utility functions in ultralytics/data/utils.py, including dataset stats and auto-splitting."""
|
|
312
327
|
from ultralytics.data.split import autosplit
|
|
313
328
|
from ultralytics.data.utils import HUBDatasetStats
|
|
@@ -318,27 +333,28 @@ def test_data_utils():
|
|
|
318
333
|
|
|
319
334
|
for task in TASKS:
|
|
320
335
|
file = Path(TASK2DATA[task]).with_suffix(".zip") # i.e. coco8.zip
|
|
321
|
-
download(f"https://github.com/ultralytics/hub/raw/main/example_datasets/{file}", unzip=False, dir=
|
|
322
|
-
stats = HUBDatasetStats(
|
|
336
|
+
download(f"https://github.com/ultralytics/hub/raw/main/example_datasets/{file}", unzip=False, dir=tmp_path)
|
|
337
|
+
stats = HUBDatasetStats(tmp_path / file, task=task)
|
|
323
338
|
stats.get_json(save=True)
|
|
324
339
|
stats.process_images()
|
|
325
340
|
|
|
326
|
-
autosplit(
|
|
327
|
-
zip_directory(
|
|
341
|
+
autosplit(tmp_path / "coco8")
|
|
342
|
+
zip_directory(tmp_path / "coco8/images/val") # zip
|
|
328
343
|
|
|
329
344
|
|
|
330
345
|
@pytest.mark.skipif(not ONLINE, reason="environment is offline")
|
|
331
|
-
def test_data_converter():
|
|
346
|
+
def test_data_converter(tmp_path):
|
|
332
347
|
"""Test dataset conversion functions from COCO to YOLO format and class mappings."""
|
|
333
348
|
from ultralytics.data.converter import coco80_to_coco91_class, convert_coco
|
|
334
349
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
350
|
+
download(f"{ASSETS_URL}/instances_val2017.json", dir=tmp_path)
|
|
351
|
+
convert_coco(
|
|
352
|
+
labels_dir=tmp_path, save_dir=tmp_path / "yolo_labels", use_segments=True, use_keypoints=False, cls91to80=True
|
|
353
|
+
)
|
|
338
354
|
coco80_to_coco91_class()
|
|
339
355
|
|
|
340
356
|
|
|
341
|
-
def test_data_annotator():
|
|
357
|
+
def test_data_annotator(tmp_path):
|
|
342
358
|
"""Test automatic annotation of data using detection and segmentation models."""
|
|
343
359
|
from ultralytics.data.annotator import auto_annotate
|
|
344
360
|
|
|
@@ -346,13 +362,13 @@ def test_data_annotator():
|
|
|
346
362
|
ASSETS,
|
|
347
363
|
det_model=WEIGHTS_DIR / "yolo11n.pt",
|
|
348
364
|
sam_model=WEIGHTS_DIR / "mobile_sam.pt",
|
|
349
|
-
output_dir=
|
|
365
|
+
output_dir=tmp_path / "auto_annotate_labels",
|
|
350
366
|
)
|
|
351
367
|
|
|
352
368
|
|
|
353
369
|
def test_events():
|
|
354
370
|
"""Test event sending functionality."""
|
|
355
|
-
from ultralytics.
|
|
371
|
+
from ultralytics.utils.events import Events
|
|
356
372
|
|
|
357
373
|
events = Events()
|
|
358
374
|
events.enabled = True
|
|
@@ -369,24 +385,21 @@ def test_cfg_init():
|
|
|
369
385
|
check_dict_alignment({"a": 1}, {"b": 2})
|
|
370
386
|
copy_default_cfg()
|
|
371
387
|
(Path.cwd() / DEFAULT_CFG_PATH.name.replace(".yaml", "_copy.yaml")).unlink(missing_ok=False)
|
|
372
|
-
[smart_value(x) for x in
|
|
388
|
+
[smart_value(x) for x in {"none", "true", "false"}]
|
|
373
389
|
|
|
374
390
|
|
|
375
391
|
def test_utils_init():
|
|
376
392
|
"""Test initialization utilities in the Ultralytics library."""
|
|
377
|
-
from ultralytics.utils import
|
|
393
|
+
from ultralytics.utils import get_ubuntu_version, is_github_action_running
|
|
378
394
|
|
|
379
395
|
get_ubuntu_version()
|
|
380
396
|
is_github_action_running()
|
|
381
|
-
get_git_origin_url()
|
|
382
|
-
get_git_branch()
|
|
383
397
|
|
|
384
398
|
|
|
385
399
|
def test_utils_checks():
|
|
386
400
|
"""Test various utility checks for filenames, git status, requirements, image sizes, and versions."""
|
|
387
401
|
checks.check_yolov5u_filename("yolov5n.pt")
|
|
388
|
-
checks.
|
|
389
|
-
checks.check_requirements() # check requirements.txt
|
|
402
|
+
checks.check_requirements("numpy") # check requirements.txt
|
|
390
403
|
checks.check_imgsz([600, 600], max_dim=1)
|
|
391
404
|
checks.check_imshow(warn=True)
|
|
392
405
|
checks.check_version("ultralytics", "8.0.0")
|
|
@@ -443,7 +456,7 @@ def test_utils_ops():
|
|
|
443
456
|
torch.allclose(boxes, xyxyxyxy2xywhr(xywhr2xyxyxyxy(boxes)), rtol=1e-3)
|
|
444
457
|
|
|
445
458
|
|
|
446
|
-
def test_utils_files():
|
|
459
|
+
def test_utils_files(tmp_path):
|
|
447
460
|
"""Test file handling utilities including file age, date, and paths with spaces."""
|
|
448
461
|
from ultralytics.utils.files import file_age, file_date, get_latest_run, spaces_in_path
|
|
449
462
|
|
|
@@ -451,14 +464,14 @@ def test_utils_files():
|
|
|
451
464
|
file_date(SOURCE)
|
|
452
465
|
get_latest_run(ROOT / "runs")
|
|
453
466
|
|
|
454
|
-
path =
|
|
467
|
+
path = tmp_path / "path/with spaces"
|
|
455
468
|
path.mkdir(parents=True, exist_ok=True)
|
|
456
469
|
with spaces_in_path(path) as new_path:
|
|
457
470
|
print(new_path)
|
|
458
471
|
|
|
459
472
|
|
|
460
473
|
@pytest.mark.slow
|
|
461
|
-
def test_utils_patches_torch_save():
|
|
474
|
+
def test_utils_patches_torch_save(tmp_path):
|
|
462
475
|
"""Test torch_save backoff when _torch_save raises RuntimeError."""
|
|
463
476
|
from unittest.mock import MagicMock, patch
|
|
464
477
|
|
|
@@ -468,7 +481,7 @@ def test_utils_patches_torch_save():
|
|
|
468
481
|
|
|
469
482
|
with patch("ultralytics.utils.patches._torch_save", new=mock):
|
|
470
483
|
with pytest.raises(RuntimeError):
|
|
471
|
-
torch_save(torch.zeros(1),
|
|
484
|
+
torch_save(torch.zeros(1), tmp_path / "test.pt")
|
|
472
485
|
|
|
473
486
|
assert mock.call_count == 4, "torch_save was not attempted the expected number of times"
|
|
474
487
|
|
|
@@ -614,7 +627,8 @@ def test_yolo_world():
|
|
|
614
627
|
)
|
|
615
628
|
|
|
616
629
|
|
|
617
|
-
@pytest.mark.skipif(
|
|
630
|
+
@pytest.mark.skipif(not TORCH_1_13, reason="YOLOE with CLIP requires torch>=1.13")
|
|
631
|
+
@pytest.mark.skipif(checks.IS_PYTHON_3_12, reason="YOLOE with CLIP is not supported in Python 3.12")
|
|
618
632
|
@pytest.mark.skipif(
|
|
619
633
|
checks.IS_PYTHON_3_8 and LINUX and ARM64,
|
|
620
634
|
reason="YOLOE with CLIP is not supported in Python 3.8 and aarch64 Linux",
|
|
@@ -628,16 +642,12 @@ def test_yoloe():
|
|
|
628
642
|
model.set_classes(names, model.get_text_pe(names))
|
|
629
643
|
model(SOURCE, conf=0.01)
|
|
630
644
|
|
|
631
|
-
import numpy as np
|
|
632
|
-
|
|
633
645
|
from ultralytics import YOLOE
|
|
634
646
|
from ultralytics.models.yolo.yoloe import YOLOEVPSegPredictor
|
|
635
647
|
|
|
636
648
|
# visual-prompts
|
|
637
649
|
visuals = dict(
|
|
638
|
-
bboxes=np.array(
|
|
639
|
-
[[221.52, 405.8, 344.98, 857.54], [120, 425, 160, 445]],
|
|
640
|
-
),
|
|
650
|
+
bboxes=np.array([[221.52, 405.8, 344.98, 857.54], [120, 425, 160, 445]]),
|
|
641
651
|
cls=np.array([0, 1]),
|
|
642
652
|
)
|
|
643
653
|
model.predict(
|
|
@@ -654,7 +664,7 @@ def test_yoloe():
|
|
|
654
664
|
model.val(data="coco128-seg.yaml", load_vp=True, imgsz=32)
|
|
655
665
|
|
|
656
666
|
# Train, fine-tune
|
|
657
|
-
from ultralytics.models.yolo.yoloe import YOLOEPESegTrainer
|
|
667
|
+
from ultralytics.models.yolo.yoloe import YOLOEPESegTrainer, YOLOESegTrainerFromScratch
|
|
658
668
|
|
|
659
669
|
model = YOLOE("yoloe-11s-seg.pt")
|
|
660
670
|
model.train(
|
|
@@ -664,6 +674,15 @@ def test_yoloe():
|
|
|
664
674
|
trainer=YOLOEPESegTrainer,
|
|
665
675
|
imgsz=32,
|
|
666
676
|
)
|
|
677
|
+
# Train, from scratch
|
|
678
|
+
model = YOLOE("yoloe-11s-seg.yaml")
|
|
679
|
+
model.train(
|
|
680
|
+
data=dict(train=dict(yolo_data=["coco128-seg.yaml"]), val=dict(yolo_data=["coco128-seg.yaml"])),
|
|
681
|
+
epochs=1,
|
|
682
|
+
close_mosaic=1,
|
|
683
|
+
trainer=YOLOESegTrainerFromScratch,
|
|
684
|
+
imgsz=32,
|
|
685
|
+
)
|
|
667
686
|
|
|
668
687
|
# prompt-free
|
|
669
688
|
# predict
|
|
@@ -692,3 +711,28 @@ def test_multichannel():
|
|
|
692
711
|
im = np.zeros((32, 32, 10), dtype=np.uint8)
|
|
693
712
|
model.predict(source=im, imgsz=32, save_txt=True, save_crop=True, augment=True)
|
|
694
713
|
model.export(format="onnx")
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
@pytest.mark.parametrize("task,model,data", TASK_MODEL_DATA)
|
|
717
|
+
def test_grayscale(task: str, model: str, data: str, tmp_path) -> None:
|
|
718
|
+
"""Test YOLO model grayscale training, validation, and prediction functionality."""
|
|
719
|
+
if task == "classify": # not support grayscale classification yet
|
|
720
|
+
return
|
|
721
|
+
grayscale_data = tmp_path / f"{Path(data).stem}-grayscale.yaml"
|
|
722
|
+
data = check_det_dataset(data)
|
|
723
|
+
data["channels"] = 1 # add additional channels key for grayscale
|
|
724
|
+
YAML.save(grayscale_data, data)
|
|
725
|
+
# remove npy files in train/val splits if exists, might be created by previous tests
|
|
726
|
+
for split in {"train", "val"}:
|
|
727
|
+
for npy_file in (Path(data["path"]) / data[split]).glob("*.npy"):
|
|
728
|
+
npy_file.unlink()
|
|
729
|
+
|
|
730
|
+
model = YOLO(model)
|
|
731
|
+
model.train(data=grayscale_data, epochs=1, imgsz=32, close_mosaic=1)
|
|
732
|
+
model.val(data=grayscale_data)
|
|
733
|
+
im = np.zeros((32, 32, 1), dtype=np.uint8)
|
|
734
|
+
model.predict(source=im, imgsz=32, save_txt=True, save_crop=True, augment=True)
|
|
735
|
+
export_model = model.export(format="onnx")
|
|
736
|
+
|
|
737
|
+
model = YOLO(export_model, task=task)
|
|
738
|
+
model.predict(source=im, imgsz=32)
|