ultralytics 8.1.28__py3-none-any.whl → 8.3.62__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.
- tests/__init__.py +22 -0
- tests/conftest.py +83 -0
- tests/test_cli.py +122 -0
- tests/test_cuda.py +155 -0
- tests/test_engine.py +131 -0
- tests/test_exports.py +216 -0
- tests/test_integrations.py +150 -0
- tests/test_python.py +615 -0
- tests/test_solutions.py +94 -0
- ultralytics/__init__.py +11 -8
- ultralytics/cfg/__init__.py +569 -131
- ultralytics/cfg/datasets/Argoverse.yaml +2 -1
- ultralytics/cfg/datasets/DOTAv1.5.yaml +3 -2
- ultralytics/cfg/datasets/DOTAv1.yaml +3 -2
- ultralytics/cfg/datasets/GlobalWheat2020.yaml +3 -2
- ultralytics/cfg/datasets/ImageNet.yaml +2 -1
- ultralytics/cfg/datasets/Objects365.yaml +5 -4
- ultralytics/cfg/datasets/SKU-110K.yaml +2 -1
- ultralytics/cfg/datasets/VOC.yaml +3 -2
- ultralytics/cfg/datasets/VisDrone.yaml +6 -5
- ultralytics/cfg/datasets/african-wildlife.yaml +25 -0
- ultralytics/cfg/datasets/brain-tumor.yaml +23 -0
- ultralytics/cfg/datasets/carparts-seg.yaml +3 -2
- ultralytics/cfg/datasets/coco-pose.yaml +7 -6
- ultralytics/cfg/datasets/coco.yaml +3 -2
- ultralytics/cfg/datasets/coco128-seg.yaml +4 -3
- ultralytics/cfg/datasets/coco128.yaml +4 -3
- ultralytics/cfg/datasets/coco8-pose.yaml +3 -2
- ultralytics/cfg/datasets/coco8-seg.yaml +3 -2
- ultralytics/cfg/datasets/coco8.yaml +3 -2
- ultralytics/cfg/datasets/crack-seg.yaml +3 -2
- ultralytics/cfg/datasets/dog-pose.yaml +24 -0
- ultralytics/cfg/datasets/dota8.yaml +3 -2
- ultralytics/cfg/datasets/hand-keypoints.yaml +26 -0
- ultralytics/cfg/datasets/lvis.yaml +1236 -0
- ultralytics/cfg/datasets/medical-pills.yaml +22 -0
- ultralytics/cfg/datasets/open-images-v7.yaml +2 -1
- ultralytics/cfg/datasets/package-seg.yaml +5 -4
- ultralytics/cfg/datasets/signature.yaml +21 -0
- ultralytics/cfg/datasets/tiger-pose.yaml +3 -2
- ultralytics/cfg/datasets/xView.yaml +2 -1
- ultralytics/cfg/default.yaml +14 -11
- ultralytics/cfg/models/11/yolo11-cls-resnet18.yaml +24 -0
- ultralytics/cfg/models/11/yolo11-cls.yaml +33 -0
- ultralytics/cfg/models/11/yolo11-obb.yaml +50 -0
- ultralytics/cfg/models/11/yolo11-pose.yaml +51 -0
- ultralytics/cfg/models/11/yolo11-seg.yaml +50 -0
- ultralytics/cfg/models/11/yolo11.yaml +50 -0
- ultralytics/cfg/models/rt-detr/rtdetr-l.yaml +5 -2
- ultralytics/cfg/models/rt-detr/rtdetr-resnet101.yaml +5 -2
- ultralytics/cfg/models/rt-detr/rtdetr-resnet50.yaml +5 -2
- ultralytics/cfg/models/rt-detr/rtdetr-x.yaml +5 -2
- ultralytics/cfg/models/v10/yolov10b.yaml +45 -0
- ultralytics/cfg/models/v10/yolov10l.yaml +45 -0
- ultralytics/cfg/models/v10/yolov10m.yaml +45 -0
- ultralytics/cfg/models/v10/yolov10n.yaml +45 -0
- ultralytics/cfg/models/v10/yolov10s.yaml +45 -0
- ultralytics/cfg/models/v10/yolov10x.yaml +45 -0
- ultralytics/cfg/models/v3/yolov3-spp.yaml +5 -2
- ultralytics/cfg/models/v3/yolov3-tiny.yaml +5 -2
- ultralytics/cfg/models/v3/yolov3.yaml +5 -2
- ultralytics/cfg/models/v5/yolov5-p6.yaml +5 -2
- ultralytics/cfg/models/v5/yolov5.yaml +5 -2
- ultralytics/cfg/models/v6/yolov6.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-cls-resnet101.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-cls-resnet50.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-cls.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-ghost-p2.yaml +6 -2
- ultralytics/cfg/models/v8/yolov8-ghost-p6.yaml +6 -2
- ultralytics/cfg/models/v8/yolov8-ghost.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-obb.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-p2.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-p6.yaml +10 -7
- ultralytics/cfg/models/v8/yolov8-pose-p6.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-pose.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-rtdetr.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-seg-p6.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-seg.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-world.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8-worldv2.yaml +5 -2
- ultralytics/cfg/models/v8/yolov8.yaml +5 -2
- ultralytics/cfg/models/v9/yolov9c-seg.yaml +41 -0
- ultralytics/cfg/models/v9/yolov9c.yaml +30 -25
- ultralytics/cfg/models/v9/yolov9e-seg.yaml +64 -0
- ultralytics/cfg/models/v9/yolov9e.yaml +46 -42
- ultralytics/cfg/models/v9/yolov9m.yaml +41 -0
- ultralytics/cfg/models/v9/yolov9s.yaml +41 -0
- ultralytics/cfg/models/v9/yolov9t.yaml +41 -0
- ultralytics/cfg/solutions/default.yaml +24 -0
- ultralytics/cfg/trackers/botsort.yaml +8 -5
- ultralytics/cfg/trackers/bytetrack.yaml +8 -5
- ultralytics/data/__init__.py +14 -3
- ultralytics/data/annotator.py +37 -15
- ultralytics/data/augment.py +1783 -289
- ultralytics/data/base.py +62 -27
- ultralytics/data/build.py +36 -8
- ultralytics/data/converter.py +196 -36
- ultralytics/data/dataset.py +233 -94
- ultralytics/data/loaders.py +199 -96
- ultralytics/data/split_dota.py +39 -29
- ultralytics/data/utils.py +110 -40
- ultralytics/engine/__init__.py +1 -1
- ultralytics/engine/exporter.py +569 -242
- ultralytics/engine/model.py +604 -252
- ultralytics/engine/predictor.py +22 -11
- ultralytics/engine/results.py +1228 -218
- ultralytics/engine/trainer.py +190 -129
- ultralytics/engine/tuner.py +18 -18
- ultralytics/engine/validator.py +18 -15
- ultralytics/hub/__init__.py +31 -13
- ultralytics/hub/auth.py +11 -7
- ultralytics/hub/google/__init__.py +159 -0
- ultralytics/hub/session.py +128 -94
- ultralytics/hub/utils.py +20 -21
- ultralytics/models/__init__.py +4 -2
- ultralytics/models/fastsam/__init__.py +2 -3
- ultralytics/models/fastsam/model.py +26 -4
- ultralytics/models/fastsam/predict.py +127 -63
- ultralytics/models/fastsam/utils.py +1 -44
- ultralytics/models/fastsam/val.py +1 -1
- ultralytics/models/nas/__init__.py +1 -1
- ultralytics/models/nas/model.py +21 -10
- ultralytics/models/nas/predict.py +3 -6
- ultralytics/models/nas/val.py +4 -4
- ultralytics/models/rtdetr/__init__.py +1 -1
- ultralytics/models/rtdetr/model.py +1 -1
- ultralytics/models/rtdetr/predict.py +6 -8
- ultralytics/models/rtdetr/train.py +6 -2
- ultralytics/models/rtdetr/val.py +3 -3
- ultralytics/models/sam/__init__.py +3 -3
- ultralytics/models/sam/amg.py +29 -23
- ultralytics/models/sam/build.py +211 -13
- ultralytics/models/sam/model.py +91 -30
- ultralytics/models/sam/modules/__init__.py +1 -1
- ultralytics/models/sam/modules/blocks.py +1129 -0
- ultralytics/models/sam/modules/decoders.py +381 -53
- ultralytics/models/sam/modules/encoders.py +515 -324
- ultralytics/models/sam/modules/memory_attention.py +237 -0
- ultralytics/models/sam/modules/sam.py +969 -21
- ultralytics/models/sam/modules/tiny_encoder.py +425 -154
- ultralytics/models/sam/modules/transformer.py +159 -60
- ultralytics/models/sam/modules/utils.py +293 -0
- ultralytics/models/sam/predict.py +1263 -132
- ultralytics/models/utils/__init__.py +1 -1
- ultralytics/models/utils/loss.py +36 -24
- ultralytics/models/utils/ops.py +3 -7
- ultralytics/models/yolo/__init__.py +3 -3
- ultralytics/models/yolo/classify/__init__.py +1 -1
- ultralytics/models/yolo/classify/predict.py +7 -8
- ultralytics/models/yolo/classify/train.py +17 -22
- ultralytics/models/yolo/classify/val.py +8 -4
- ultralytics/models/yolo/detect/__init__.py +1 -1
- ultralytics/models/yolo/detect/predict.py +3 -5
- ultralytics/models/yolo/detect/train.py +11 -4
- ultralytics/models/yolo/detect/val.py +90 -52
- ultralytics/models/yolo/model.py +14 -9
- ultralytics/models/yolo/obb/__init__.py +1 -1
- ultralytics/models/yolo/obb/predict.py +2 -2
- ultralytics/models/yolo/obb/train.py +5 -3
- ultralytics/models/yolo/obb/val.py +41 -23
- ultralytics/models/yolo/pose/__init__.py +1 -1
- ultralytics/models/yolo/pose/predict.py +3 -5
- ultralytics/models/yolo/pose/train.py +2 -2
- ultralytics/models/yolo/pose/val.py +51 -17
- ultralytics/models/yolo/segment/__init__.py +1 -1
- ultralytics/models/yolo/segment/predict.py +3 -5
- ultralytics/models/yolo/segment/train.py +2 -2
- ultralytics/models/yolo/segment/val.py +60 -19
- ultralytics/models/yolo/world/__init__.py +5 -0
- ultralytics/models/yolo/world/train.py +92 -0
- ultralytics/models/yolo/world/train_world.py +109 -0
- ultralytics/nn/__init__.py +1 -1
- ultralytics/nn/autobackend.py +228 -93
- ultralytics/nn/modules/__init__.py +39 -14
- ultralytics/nn/modules/activation.py +21 -0
- ultralytics/nn/modules/block.py +527 -67
- ultralytics/nn/modules/conv.py +24 -7
- ultralytics/nn/modules/head.py +177 -34
- ultralytics/nn/modules/transformer.py +6 -5
- ultralytics/nn/modules/utils.py +1 -2
- ultralytics/nn/tasks.py +225 -77
- ultralytics/solutions/__init__.py +30 -1
- ultralytics/solutions/ai_gym.py +96 -143
- ultralytics/solutions/analytics.py +247 -0
- ultralytics/solutions/distance_calculation.py +78 -135
- ultralytics/solutions/heatmap.py +93 -247
- ultralytics/solutions/object_counter.py +184 -259
- ultralytics/solutions/parking_management.py +246 -0
- ultralytics/solutions/queue_management.py +112 -0
- ultralytics/solutions/region_counter.py +116 -0
- ultralytics/solutions/security_alarm.py +144 -0
- ultralytics/solutions/solutions.py +178 -0
- ultralytics/solutions/speed_estimation.py +86 -174
- ultralytics/solutions/streamlit_inference.py +190 -0
- ultralytics/solutions/trackzone.py +68 -0
- ultralytics/trackers/__init__.py +1 -1
- ultralytics/trackers/basetrack.py +32 -13
- ultralytics/trackers/bot_sort.py +61 -28
- ultralytics/trackers/byte_tracker.py +83 -51
- ultralytics/trackers/track.py +21 -6
- ultralytics/trackers/utils/__init__.py +1 -1
- ultralytics/trackers/utils/gmc.py +62 -48
- ultralytics/trackers/utils/kalman_filter.py +166 -35
- ultralytics/trackers/utils/matching.py +40 -21
- ultralytics/utils/__init__.py +511 -239
- ultralytics/utils/autobatch.py +40 -22
- ultralytics/utils/benchmarks.py +266 -85
- ultralytics/utils/callbacks/__init__.py +1 -1
- ultralytics/utils/callbacks/base.py +1 -3
- ultralytics/utils/callbacks/clearml.py +7 -6
- ultralytics/utils/callbacks/comet.py +39 -17
- ultralytics/utils/callbacks/dvc.py +1 -1
- ultralytics/utils/callbacks/hub.py +16 -16
- ultralytics/utils/callbacks/mlflow.py +28 -24
- ultralytics/utils/callbacks/neptune.py +6 -2
- ultralytics/utils/callbacks/raytune.py +3 -4
- ultralytics/utils/callbacks/tensorboard.py +18 -18
- ultralytics/utils/callbacks/wb.py +27 -20
- ultralytics/utils/checks.py +160 -100
- ultralytics/utils/dist.py +2 -1
- ultralytics/utils/downloads.py +44 -37
- ultralytics/utils/errors.py +1 -1
- ultralytics/utils/files.py +72 -38
- ultralytics/utils/instance.py +41 -19
- ultralytics/utils/loss.py +84 -56
- ultralytics/utils/metrics.py +61 -56
- ultralytics/utils/ops.py +94 -89
- ultralytics/utils/patches.py +30 -14
- ultralytics/utils/plotting.py +600 -269
- ultralytics/utils/tal.py +67 -26
- ultralytics/utils/torch_utils.py +302 -102
- ultralytics/utils/triton.py +2 -1
- ultralytics/utils/tuner.py +21 -12
- ultralytics-8.3.62.dist-info/METADATA +370 -0
- ultralytics-8.3.62.dist-info/RECORD +241 -0
- {ultralytics-8.1.28.dist-info → ultralytics-8.3.62.dist-info}/WHEEL +1 -1
- ultralytics/data/explorer/__init__.py +0 -5
- ultralytics/data/explorer/explorer.py +0 -472
- ultralytics/data/explorer/gui/__init__.py +0 -1
- ultralytics/data/explorer/gui/dash.py +0 -268
- ultralytics/data/explorer/utils.py +0 -166
- ultralytics/models/fastsam/prompt.py +0 -357
- ultralytics-8.1.28.dist-info/METADATA +0 -373
- ultralytics-8.1.28.dist-info/RECORD +0 -197
- {ultralytics-8.1.28.dist-info → ultralytics-8.3.62.dist-info}/LICENSE +0 -0
- {ultralytics-8.1.28.dist-info → ultralytics-8.3.62.dist-info}/entry_points.txt +0 -0
- {ultralytics-8.1.28.dist-info → ultralytics-8.3.62.dist-info}/top_level.txt +0 -0
ultralytics/utils/benchmarks.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Ultralytics
|
1
|
+
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
2
2
|
"""
|
3
3
|
Benchmark a YOLO model formats for speed and accuracy.
|
4
4
|
|
@@ -21,83 +21,106 @@ TensorFlow Lite | `tflite` | yolov8n.tflite
|
|
21
21
|
TensorFlow Edge TPU | `edgetpu` | yolov8n_edgetpu.tflite
|
22
22
|
TensorFlow.js | `tfjs` | yolov8n_web_model/
|
23
23
|
PaddlePaddle | `paddle` | yolov8n_paddle_model/
|
24
|
+
MNN | `mnn` | yolov8n.mnn
|
24
25
|
NCNN | `ncnn` | yolov8n_ncnn_model/
|
25
26
|
"""
|
26
27
|
|
27
28
|
import glob
|
29
|
+
import os
|
28
30
|
import platform
|
31
|
+
import re
|
32
|
+
import shutil
|
29
33
|
import time
|
30
34
|
from pathlib import Path
|
31
35
|
|
32
36
|
import numpy as np
|
33
37
|
import torch.cuda
|
38
|
+
import yaml
|
34
39
|
|
35
40
|
from ultralytics import YOLO, YOLOWorld
|
36
41
|
from ultralytics.cfg import TASK2DATA, TASK2METRIC
|
37
42
|
from ultralytics.engine.exporter import export_formats
|
38
|
-
from ultralytics.utils import ASSETS, LINUX, LOGGER, MACOS, TQDM, WEIGHTS_DIR
|
43
|
+
from ultralytics.utils import ARM64, ASSETS, IS_JETSON, IS_RASPBERRYPI, LINUX, LOGGER, MACOS, TQDM, WEIGHTS_DIR
|
39
44
|
from ultralytics.utils.checks import IS_PYTHON_3_12, check_requirements, check_yolo
|
45
|
+
from ultralytics.utils.downloads import safe_download
|
40
46
|
from ultralytics.utils.files import file_size
|
41
|
-
from ultralytics.utils.torch_utils import select_device
|
47
|
+
from ultralytics.utils.torch_utils import get_cpu_info, select_device
|
42
48
|
|
43
49
|
|
44
50
|
def benchmark(
|
45
|
-
model=WEIGHTS_DIR / "
|
51
|
+
model=WEIGHTS_DIR / "yolo11n.pt",
|
52
|
+
data=None,
|
53
|
+
imgsz=160,
|
54
|
+
half=False,
|
55
|
+
int8=False,
|
56
|
+
device="cpu",
|
57
|
+
verbose=False,
|
58
|
+
eps=1e-3,
|
46
59
|
):
|
47
60
|
"""
|
48
61
|
Benchmark a YOLO model across different formats for speed and accuracy.
|
49
62
|
|
50
63
|
Args:
|
51
|
-
model (str | Path
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
Default is False.
|
64
|
+
model (str | Path): Path to the model file or directory.
|
65
|
+
data (str | None): Dataset to evaluate on, inherited from TASK2DATA if not passed.
|
66
|
+
imgsz (int): Image size for the benchmark.
|
67
|
+
half (bool): Use half-precision for the model if True.
|
68
|
+
int8 (bool): Use int8-precision for the model if True.
|
69
|
+
device (str): Device to run the benchmark on, either 'cpu' or 'cuda'.
|
70
|
+
verbose (bool | float): If True or a float, assert benchmarks pass with given metric.
|
71
|
+
eps (float): Epsilon value for divide by zero prevention.
|
60
72
|
|
61
73
|
Returns:
|
62
|
-
|
63
|
-
|
74
|
+
(pandas.DataFrame): A pandas DataFrame with benchmark results for each format, including file size, metric,
|
75
|
+
and inference time.
|
64
76
|
|
65
|
-
|
66
|
-
|
67
|
-
from ultralytics.utils.benchmarks import benchmark
|
68
|
-
|
69
|
-
benchmark(model='yolov8n.pt', imgsz=640)
|
70
|
-
```
|
77
|
+
Examples:
|
78
|
+
Benchmark a YOLO model with default settings:
|
79
|
+
>>> from ultralytics.utils.benchmarks import benchmark
|
80
|
+
>>> benchmark(model="yolo11n.pt", imgsz=640)
|
71
81
|
"""
|
72
|
-
|
73
|
-
import pandas as pd
|
82
|
+
import pandas as pd # scope for faster 'import ultralytics'
|
74
83
|
|
75
84
|
pd.options.display.max_columns = 10
|
76
85
|
pd.options.display.width = 120
|
77
86
|
device = select_device(device, verbose=False)
|
78
87
|
if isinstance(model, (str, Path)):
|
79
88
|
model = YOLO(model)
|
89
|
+
is_end2end = getattr(model.model.model[-1], "end2end", False)
|
80
90
|
|
81
91
|
y = []
|
82
92
|
t0 = time.time()
|
83
|
-
for i, (name, format, suffix, cpu, gpu) in export_formats().
|
93
|
+
for i, (name, format, suffix, cpu, gpu, _) in enumerate(zip(*export_formats().values())):
|
84
94
|
emoji, filename = "❌", None # export defaults
|
85
95
|
try:
|
86
96
|
# Checks
|
87
|
-
if i ==
|
88
|
-
assert LINUX, "Edge TPU export only supported on Linux"
|
89
|
-
elif i == 7: # TF GraphDef
|
97
|
+
if i == 7: # TF GraphDef
|
90
98
|
assert model.task != "obb", "TensorFlow GraphDef not supported for OBB task"
|
99
|
+
elif i == 9: # Edge TPU
|
100
|
+
assert LINUX and not ARM64, "Edge TPU export only supported on non-aarch64 Linux"
|
91
101
|
elif i in {5, 10}: # CoreML and TF.js
|
92
|
-
assert MACOS or LINUX, "export only supported on macOS and Linux"
|
93
|
-
|
94
|
-
assert not
|
95
|
-
if i in {
|
102
|
+
assert MACOS or LINUX, "CoreML and TF.js export only supported on macOS and Linux"
|
103
|
+
assert not IS_RASPBERRYPI, "CoreML and TF.js export not supported on Raspberry Pi"
|
104
|
+
assert not IS_JETSON, "CoreML and TF.js export not supported on NVIDIA Jetson"
|
105
|
+
if i in {5}: # CoreML
|
106
|
+
assert not IS_PYTHON_3_12, "CoreML not supported on Python 3.12"
|
107
|
+
if i in {6, 7, 8}: # TF SavedModel, TF GraphDef, and TFLite
|
108
|
+
assert not isinstance(model, YOLOWorld), "YOLOWorldv2 TensorFlow exports not supported by onnx2tf yet"
|
109
|
+
if i in {9, 10}: # TF EdgeTPU and TF.js
|
96
110
|
assert not isinstance(model, YOLOWorld), "YOLOWorldv2 TensorFlow exports not supported by onnx2tf yet"
|
97
|
-
if i
|
111
|
+
if i == 11: # Paddle
|
98
112
|
assert not isinstance(model, YOLOWorld), "YOLOWorldv2 Paddle exports not supported yet"
|
99
|
-
|
113
|
+
assert not is_end2end, "End-to-end models not supported by PaddlePaddle yet"
|
114
|
+
assert LINUX or MACOS, "Windows Paddle exports not supported yet"
|
115
|
+
if i == 12: # MNN
|
116
|
+
assert not isinstance(model, YOLOWorld), "YOLOWorldv2 MNN exports not supported yet"
|
117
|
+
if i == 13: # NCNN
|
100
118
|
assert not isinstance(model, YOLOWorld), "YOLOWorldv2 NCNN exports not supported yet"
|
119
|
+
if i == 14: # IMX
|
120
|
+
assert not is_end2end
|
121
|
+
assert not isinstance(model, YOLOWorld), "YOLOWorldv2 IMX exports not supported"
|
122
|
+
assert model.task == "detect", "IMX only supported for detection task"
|
123
|
+
assert "C2f" in model.__str__(), "IMX only supported for YOLOv8"
|
101
124
|
if "cpu" in device.type:
|
102
125
|
assert cpu, "inference not supported on CPU"
|
103
126
|
if "cuda" in device.type:
|
@@ -115,8 +138,10 @@ def benchmark(
|
|
115
138
|
|
116
139
|
# Predict
|
117
140
|
assert model.task != "pose" or i != 7, "GraphDef Pose inference is not supported"
|
118
|
-
assert i not in
|
141
|
+
assert i not in {9, 10}, "inference not supported" # Edge TPU and TF.js are unsupported
|
119
142
|
assert i != 5 or platform.system() == "Darwin", "inference only supported on macOS>=10.13" # CoreML
|
143
|
+
if i in {13}:
|
144
|
+
assert not is_end2end, "End-to-end torch.topk operation is not supported for NCNN prediction yet"
|
120
145
|
exported_model.predict(ASSETS / "bus.jpg", imgsz=imgsz, device=device, half=half)
|
121
146
|
|
122
147
|
# Validate
|
@@ -126,16 +151,17 @@ def benchmark(
|
|
126
151
|
data=data, batch=1, imgsz=imgsz, plots=False, device=device, half=half, int8=int8, verbose=False
|
127
152
|
)
|
128
153
|
metric, speed = results.results_dict[key], results.speed["inference"]
|
129
|
-
|
154
|
+
fps = round(1000 / (speed + eps), 2) # frames per second
|
155
|
+
y.append([name, "✅", round(file_size(filename), 1), round(metric, 4), round(speed, 2), fps])
|
130
156
|
except Exception as e:
|
131
157
|
if verbose:
|
132
158
|
assert type(e) is AssertionError, f"Benchmark failure for {name}: {e}"
|
133
159
|
LOGGER.warning(f"ERROR ❌️ Benchmark failure for {name}: {e}")
|
134
|
-
y.append([name, emoji, round(file_size(filename), 1), None, None]) # mAP, t_inference
|
160
|
+
y.append([name, emoji, round(file_size(filename), 1), None, None, None]) # mAP, t_inference
|
135
161
|
|
136
162
|
# Print results
|
137
163
|
check_yolo(device=device) # print system info
|
138
|
-
df = pd.DataFrame(y, columns=["Format", "Status❔", "Size (MB)", key, "Inference time (ms/im)"])
|
164
|
+
df = pd.DataFrame(y, columns=["Format", "Status❔", "Size (MB)", key, "Inference time (ms/im)", "FPS"])
|
139
165
|
|
140
166
|
name = Path(model.ckpt_path).name
|
141
167
|
s = f"\nBenchmarks complete for {name} on {data} at imgsz={imgsz} ({time.time() - t0:.2f}s)\n{df}\n"
|
@@ -151,6 +177,141 @@ def benchmark(
|
|
151
177
|
return df
|
152
178
|
|
153
179
|
|
180
|
+
class RF100Benchmark:
|
181
|
+
"""Benchmark YOLO model performance across various formats for speed and accuracy."""
|
182
|
+
|
183
|
+
def __init__(self):
|
184
|
+
"""Initialize the RF100Benchmark class for benchmarking YOLO model performance across various formats."""
|
185
|
+
self.ds_names = []
|
186
|
+
self.ds_cfg_list = []
|
187
|
+
self.rf = None
|
188
|
+
self.val_metrics = ["class", "images", "targets", "precision", "recall", "map50", "map95"]
|
189
|
+
|
190
|
+
def set_key(self, api_key):
|
191
|
+
"""
|
192
|
+
Set Roboflow API key for processing.
|
193
|
+
|
194
|
+
Args:
|
195
|
+
api_key (str): The API key.
|
196
|
+
|
197
|
+
Examples:
|
198
|
+
Set the Roboflow API key for accessing datasets:
|
199
|
+
>>> benchmark = RF100Benchmark()
|
200
|
+
>>> benchmark.set_key("your_roboflow_api_key")
|
201
|
+
"""
|
202
|
+
check_requirements("roboflow")
|
203
|
+
from roboflow import Roboflow
|
204
|
+
|
205
|
+
self.rf = Roboflow(api_key=api_key)
|
206
|
+
|
207
|
+
def parse_dataset(self, ds_link_txt="datasets_links.txt"):
|
208
|
+
"""
|
209
|
+
Parse dataset links and download datasets.
|
210
|
+
|
211
|
+
Args:
|
212
|
+
ds_link_txt (str): Path to the file containing dataset links.
|
213
|
+
|
214
|
+
Examples:
|
215
|
+
>>> benchmark = RF100Benchmark()
|
216
|
+
>>> benchmark.set_key("api_key")
|
217
|
+
>>> benchmark.parse_dataset("datasets_links.txt")
|
218
|
+
"""
|
219
|
+
(shutil.rmtree("rf-100"), os.mkdir("rf-100")) if os.path.exists("rf-100") else os.mkdir("rf-100")
|
220
|
+
os.chdir("rf-100")
|
221
|
+
os.mkdir("ultralytics-benchmarks")
|
222
|
+
safe_download("https://github.com/ultralytics/assets/releases/download/v0.0.0/datasets_links.txt")
|
223
|
+
|
224
|
+
with open(ds_link_txt) as file:
|
225
|
+
for line in file:
|
226
|
+
try:
|
227
|
+
_, url, workspace, project, version = re.split("/+", line.strip())
|
228
|
+
self.ds_names.append(project)
|
229
|
+
proj_version = f"{project}-{version}"
|
230
|
+
if not Path(proj_version).exists():
|
231
|
+
self.rf.workspace(workspace).project(project).version(version).download("yolov8")
|
232
|
+
else:
|
233
|
+
print("Dataset already downloaded.")
|
234
|
+
self.ds_cfg_list.append(Path.cwd() / proj_version / "data.yaml")
|
235
|
+
except Exception:
|
236
|
+
continue
|
237
|
+
|
238
|
+
return self.ds_names, self.ds_cfg_list
|
239
|
+
|
240
|
+
@staticmethod
|
241
|
+
def fix_yaml(path):
|
242
|
+
"""
|
243
|
+
Fixes the train and validation paths in a given YAML file.
|
244
|
+
|
245
|
+
Args:
|
246
|
+
path (str): Path to the YAML file to be fixed.
|
247
|
+
|
248
|
+
Examples:
|
249
|
+
>>> RF100Benchmark.fix_yaml("path/to/data.yaml")
|
250
|
+
"""
|
251
|
+
with open(path) as file:
|
252
|
+
yaml_data = yaml.safe_load(file)
|
253
|
+
yaml_data["train"] = "train/images"
|
254
|
+
yaml_data["val"] = "valid/images"
|
255
|
+
with open(path, "w") as file:
|
256
|
+
yaml.safe_dump(yaml_data, file)
|
257
|
+
|
258
|
+
def evaluate(self, yaml_path, val_log_file, eval_log_file, list_ind):
|
259
|
+
"""
|
260
|
+
Evaluate model performance on validation results.
|
261
|
+
|
262
|
+
Args:
|
263
|
+
yaml_path (str): Path to the YAML configuration file.
|
264
|
+
val_log_file (str): Path to the validation log file.
|
265
|
+
eval_log_file (str): Path to the evaluation log file.
|
266
|
+
list_ind (int): Index of the current dataset in the list.
|
267
|
+
|
268
|
+
Returns:
|
269
|
+
(float): The mean average precision (mAP) value for the evaluated model.
|
270
|
+
|
271
|
+
Examples:
|
272
|
+
Evaluate a model on a specific dataset
|
273
|
+
>>> benchmark = RF100Benchmark()
|
274
|
+
>>> benchmark.evaluate("path/to/data.yaml", "path/to/val_log.txt", "path/to/eval_log.txt", 0)
|
275
|
+
"""
|
276
|
+
skip_symbols = ["🚀", "⚠️", "💡", "❌"]
|
277
|
+
with open(yaml_path) as stream:
|
278
|
+
class_names = yaml.safe_load(stream)["names"]
|
279
|
+
with open(val_log_file, encoding="utf-8") as f:
|
280
|
+
lines = f.readlines()
|
281
|
+
eval_lines = []
|
282
|
+
for line in lines:
|
283
|
+
if any(symbol in line for symbol in skip_symbols):
|
284
|
+
continue
|
285
|
+
entries = line.split(" ")
|
286
|
+
entries = list(filter(lambda val: val != "", entries))
|
287
|
+
entries = [e.strip("\n") for e in entries]
|
288
|
+
eval_lines.extend(
|
289
|
+
{
|
290
|
+
"class": entries[0],
|
291
|
+
"images": entries[1],
|
292
|
+
"targets": entries[2],
|
293
|
+
"precision": entries[3],
|
294
|
+
"recall": entries[4],
|
295
|
+
"map50": entries[5],
|
296
|
+
"map95": entries[6],
|
297
|
+
}
|
298
|
+
for e in entries
|
299
|
+
if e in class_names or (e == "all" and "(AP)" not in entries and "(AR)" not in entries)
|
300
|
+
)
|
301
|
+
map_val = 0.0
|
302
|
+
if len(eval_lines) > 1:
|
303
|
+
print("There's more dicts")
|
304
|
+
for lst in eval_lines:
|
305
|
+
if lst["class"] == "all":
|
306
|
+
map_val = lst["map50"]
|
307
|
+
else:
|
308
|
+
print("There's only one dict res")
|
309
|
+
map_val = [res["map50"] for res in eval_lines][0]
|
310
|
+
|
311
|
+
with open(eval_log_file, "a") as f:
|
312
|
+
f.write(f"{self.ds_names[list_ind]}: {map_val}\n")
|
313
|
+
|
314
|
+
|
154
315
|
class ProfileModels:
|
155
316
|
"""
|
156
317
|
ProfileModels class for profiling different models on ONNX and TensorRT.
|
@@ -158,21 +319,23 @@ class ProfileModels:
|
|
158
319
|
This class profiles the performance of different models, returning results such as model speed and FLOPs.
|
159
320
|
|
160
321
|
Attributes:
|
161
|
-
paths (
|
162
|
-
num_timed_runs (int): Number of timed runs for the profiling.
|
163
|
-
num_warmup_runs (int): Number of warmup runs before profiling.
|
164
|
-
min_time (float): Minimum number of seconds to profile for.
|
165
|
-
imgsz (int): Image size used in the models.
|
322
|
+
paths (List[str]): Paths of the models to profile.
|
323
|
+
num_timed_runs (int): Number of timed runs for the profiling.
|
324
|
+
num_warmup_runs (int): Number of warmup runs before profiling.
|
325
|
+
min_time (float): Minimum number of seconds to profile for.
|
326
|
+
imgsz (int): Image size used in the models.
|
327
|
+
half (bool): Flag to indicate whether to use FP16 half-precision for TensorRT profiling.
|
328
|
+
trt (bool): Flag to indicate whether to profile using TensorRT.
|
329
|
+
device (torch.device): Device used for profiling.
|
166
330
|
|
167
331
|
Methods:
|
168
|
-
profile
|
332
|
+
profile: Profiles the models and prints the result.
|
169
333
|
|
170
|
-
|
171
|
-
|
172
|
-
from ultralytics.utils.benchmarks import ProfileModels
|
173
|
-
|
174
|
-
|
175
|
-
```
|
334
|
+
Examples:
|
335
|
+
Profile models and print results
|
336
|
+
>>> from ultralytics.utils.benchmarks import ProfileModels
|
337
|
+
>>> profiler = ProfileModels(["yolov8n.yaml", "yolov8s.yaml"], imgsz=640)
|
338
|
+
>>> profiler.profile()
|
176
339
|
"""
|
177
340
|
|
178
341
|
def __init__(
|
@@ -190,14 +353,23 @@ class ProfileModels:
|
|
190
353
|
Initialize the ProfileModels class for profiling models.
|
191
354
|
|
192
355
|
Args:
|
193
|
-
paths (
|
194
|
-
num_timed_runs (int
|
195
|
-
num_warmup_runs (int
|
196
|
-
min_time (float
|
197
|
-
imgsz (int
|
198
|
-
half (bool
|
199
|
-
trt (bool
|
200
|
-
device (torch.device
|
356
|
+
paths (List[str]): List of paths of the models to be profiled.
|
357
|
+
num_timed_runs (int): Number of timed runs for the profiling.
|
358
|
+
num_warmup_runs (int): Number of warmup runs before the actual profiling starts.
|
359
|
+
min_time (float): Minimum time in seconds for profiling a model.
|
360
|
+
imgsz (int): Size of the image used during profiling.
|
361
|
+
half (bool): Flag to indicate whether to use FP16 half-precision for TensorRT profiling.
|
362
|
+
trt (bool): Flag to indicate whether to profile using TensorRT.
|
363
|
+
device (torch.device | None): Device used for profiling. If None, it is determined automatically.
|
364
|
+
|
365
|
+
Notes:
|
366
|
+
FP16 'half' argument option removed for ONNX as slower on CPU than FP32.
|
367
|
+
|
368
|
+
Examples:
|
369
|
+
Initialize and profile models
|
370
|
+
>>> from ultralytics.utils.benchmarks import ProfileModels
|
371
|
+
>>> profiler = ProfileModels(["yolov8n.yaml", "yolov8s.yaml"], imgsz=640)
|
372
|
+
>>> profiler.profile()
|
201
373
|
"""
|
202
374
|
self.paths = paths
|
203
375
|
self.num_timed_runs = num_timed_runs
|
@@ -209,7 +381,7 @@ class ProfileModels:
|
|
209
381
|
self.device = device or torch.device(0 if torch.cuda.is_available() else "cpu")
|
210
382
|
|
211
383
|
def profile(self):
|
212
|
-
"""
|
384
|
+
"""Profiles YOLO models for speed and accuracy across various formats including ONNX and TensorRT."""
|
213
385
|
files = self.get_files()
|
214
386
|
|
215
387
|
if not files:
|
@@ -220,16 +392,23 @@ class ProfileModels:
|
|
220
392
|
output = []
|
221
393
|
for file in files:
|
222
394
|
engine_file = file.with_suffix(".engine")
|
223
|
-
if file.suffix in
|
395
|
+
if file.suffix in {".pt", ".yaml", ".yml"}:
|
224
396
|
model = YOLO(str(file))
|
225
397
|
model.fuse() # to report correct params and GFLOPs in model.info()
|
226
398
|
model_info = model.info()
|
227
399
|
if self.trt and self.device.type != "cpu" and not engine_file.is_file():
|
228
400
|
engine_file = model.export(
|
229
|
-
format="engine",
|
401
|
+
format="engine",
|
402
|
+
half=self.half,
|
403
|
+
imgsz=self.imgsz,
|
404
|
+
device=self.device,
|
405
|
+
verbose=False,
|
230
406
|
)
|
231
407
|
onnx_file = model.export(
|
232
|
-
format="onnx",
|
408
|
+
format="onnx",
|
409
|
+
imgsz=self.imgsz,
|
410
|
+
device=self.device,
|
411
|
+
verbose=False,
|
233
412
|
)
|
234
413
|
elif file.suffix == ".onnx":
|
235
414
|
model_info = self.get_onnx_model_info(file)
|
@@ -261,15 +440,14 @@ class ProfileModels:
|
|
261
440
|
print(f"Profiling: {sorted(files)}")
|
262
441
|
return [Path(file) for file in sorted(files)]
|
263
442
|
|
264
|
-
|
265
|
-
|
266
|
-
file.
|
267
|
-
"""
|
443
|
+
@staticmethod
|
444
|
+
def get_onnx_model_info(onnx_file: str):
|
445
|
+
"""Extracts metadata from an ONNX model file including parameters, GFLOPs, and input shape."""
|
268
446
|
return 0.0, 0.0, 0.0, 0.0 # return (num_layers, num_params, num_gradients, num_flops)
|
269
447
|
|
270
448
|
@staticmethod
|
271
449
|
def iterative_sigma_clipping(data, sigma=2, max_iters=3):
|
272
|
-
"""Applies
|
450
|
+
"""Applies iterative sigma clipping to data to remove outliers based on specified sigma and iteration count."""
|
273
451
|
data = np.array(data)
|
274
452
|
for _ in range(max_iters):
|
275
453
|
mean, std = np.mean(data), np.std(data)
|
@@ -280,13 +458,13 @@ class ProfileModels:
|
|
280
458
|
return data
|
281
459
|
|
282
460
|
def profile_tensorrt_model(self, engine_file: str, eps: float = 1e-3):
|
283
|
-
"""Profiles
|
461
|
+
"""Profiles YOLO model performance with TensorRT, measuring average run time and standard deviation."""
|
284
462
|
if not self.trt or not Path(engine_file).is_file():
|
285
463
|
return 0.0, 0.0
|
286
464
|
|
287
465
|
# Model and input
|
288
466
|
model = YOLO(engine_file)
|
289
|
-
input_data = np.
|
467
|
+
input_data = np.zeros((self.imgsz, self.imgsz, 3), dtype=np.uint8) # use uint8 for Classify
|
290
468
|
|
291
469
|
# Warmup runs
|
292
470
|
elapsed = 0.0
|
@@ -309,9 +487,7 @@ class ProfileModels:
|
|
309
487
|
return np.mean(run_times), np.std(run_times)
|
310
488
|
|
311
489
|
def profile_onnx_model(self, onnx_file: str, eps: float = 1e-3):
|
312
|
-
"""Profiles an ONNX model
|
313
|
-
times.
|
314
|
-
"""
|
490
|
+
"""Profiles an ONNX model, measuring average inference time and standard deviation across multiple runs."""
|
315
491
|
check_requirements("onnxruntime")
|
316
492
|
import onnxruntime as ort
|
317
493
|
|
@@ -323,6 +499,8 @@ class ProfileModels:
|
|
323
499
|
|
324
500
|
input_tensor = sess.get_inputs()[0]
|
325
501
|
input_type = input_tensor.type
|
502
|
+
dynamic = not all(isinstance(dim, int) and dim >= 0 for dim in input_tensor.shape) # dynamic input shape
|
503
|
+
input_shape = (1, 3, self.imgsz, self.imgsz) if dynamic else input_tensor.shape
|
326
504
|
|
327
505
|
# Mapping ONNX datatype to numpy datatype
|
328
506
|
if "float16" in input_type:
|
@@ -338,7 +516,7 @@ class ProfileModels:
|
|
338
516
|
else:
|
339
517
|
raise ValueError(f"Unsupported ONNX datatype {input_type}")
|
340
518
|
|
341
|
-
input_data = np.random.rand(*
|
519
|
+
input_data = np.random.rand(*input_shape).astype(input_dtype)
|
342
520
|
input_name = input_tensor.name
|
343
521
|
output_name = sess.get_outputs()[0].name
|
344
522
|
|
@@ -364,16 +542,16 @@ class ProfileModels:
|
|
364
542
|
return np.mean(run_times), np.std(run_times)
|
365
543
|
|
366
544
|
def generate_table_row(self, model_name, t_onnx, t_engine, model_info):
|
367
|
-
"""Generates a
|
545
|
+
"""Generates a table row string with model performance metrics including inference times and model details."""
|
368
546
|
layers, params, gradients, flops = model_info
|
369
547
|
return (
|
370
|
-
f"| {model_name:18s} | {self.imgsz} | - | {t_onnx[0]:.
|
371
|
-
f"{t_engine[1]:.
|
548
|
+
f"| {model_name:18s} | {self.imgsz} | - | {t_onnx[0]:.1f}±{t_onnx[1]:.1f} ms | {t_engine[0]:.1f}±"
|
549
|
+
f"{t_engine[1]:.1f} ms | {params / 1e6:.1f} | {flops:.1f} |"
|
372
550
|
)
|
373
551
|
|
374
552
|
@staticmethod
|
375
553
|
def generate_results_dict(model_name, t_onnx, t_engine, model_info):
|
376
|
-
"""Generates a dictionary of
|
554
|
+
"""Generates a dictionary of profiling results including model name, parameters, GFLOPs, and speed metrics."""
|
377
555
|
layers, params, gradients, flops = model_info
|
378
556
|
return {
|
379
557
|
"model/name": model_name,
|
@@ -385,16 +563,19 @@ class ProfileModels:
|
|
385
563
|
|
386
564
|
@staticmethod
|
387
565
|
def print_table(table_rows):
|
388
|
-
"""
|
566
|
+
"""Prints a formatted table of model profiling results, including speed and accuracy metrics."""
|
389
567
|
gpu = torch.cuda.get_device_name(0) if torch.cuda.is_available() else "GPU"
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
"
|
396
|
-
"
|
397
|
-
|
568
|
+
headers = [
|
569
|
+
"Model",
|
570
|
+
"size<br><sup>(pixels)",
|
571
|
+
"mAP<sup>val<br>50-95",
|
572
|
+
f"Speed<br><sup>CPU ({get_cpu_info()}) ONNX<br>(ms)",
|
573
|
+
f"Speed<br><sup>{gpu} TensorRT<br>(ms)",
|
574
|
+
"params<br><sup>(M)",
|
575
|
+
"FLOPs<br><sup>(B)",
|
576
|
+
]
|
577
|
+
header = "|" + "|".join(f" {h} " for h in headers) + "|"
|
578
|
+
separator = "|" + "|".join("-" * (len(h) + 2) for h in headers) + "|"
|
398
579
|
|
399
580
|
print(f"\n\n{header}")
|
400
581
|
print(separator)
|
@@ -1,10 +1,9 @@
|
|
1
|
-
# Ultralytics
|
1
|
+
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
2
2
|
"""Base callbacks."""
|
3
3
|
|
4
4
|
from collections import defaultdict
|
5
5
|
from copy import deepcopy
|
6
6
|
|
7
|
-
|
8
7
|
# Trainer callbacks ----------------------------------------------------------------------------------------------------
|
9
8
|
|
10
9
|
|
@@ -193,7 +192,6 @@ def add_integration_callbacks(instance):
|
|
193
192
|
instance (Trainer, Predictor, Validator, Exporter): An object with a 'callbacks' attribute that is a dictionary
|
194
193
|
of callback lists.
|
195
194
|
"""
|
196
|
-
|
197
195
|
# Load HUB callbacks
|
198
196
|
from .hub import callbacks as hub_cb
|
199
197
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Ultralytics
|
1
|
+
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
2
2
|
|
3
3
|
from ultralytics.utils import LOGGER, SETTINGS, TESTS_RUNNING
|
4
4
|
|
@@ -7,8 +7,6 @@ try:
|
|
7
7
|
assert SETTINGS["clearml"] is True # verify integration is enabled
|
8
8
|
import clearml
|
9
9
|
from clearml import Task
|
10
|
-
from clearml.binding.frameworks.pytorch_bind import PatchPyTorchModelIO
|
11
|
-
from clearml.binding.matplotlib_bind import PatchedMatplotlib
|
12
10
|
|
13
11
|
assert hasattr(clearml, "__version__") # verify package is not directory
|
14
12
|
|
@@ -61,15 +59,18 @@ def on_pretrain_routine_start(trainer):
|
|
61
59
|
"""Runs at start of pretraining routine; initializes and connects/ logs task to ClearML."""
|
62
60
|
try:
|
63
61
|
if task := Task.current_task():
|
64
|
-
#
|
62
|
+
# WARNING: make sure the automatic pytorch and matplotlib bindings are disabled!
|
65
63
|
# We are logging these plots and model files manually in the integration
|
64
|
+
from clearml.binding.frameworks.pytorch_bind import PatchPyTorchModelIO
|
65
|
+
from clearml.binding.matplotlib_bind import PatchedMatplotlib
|
66
|
+
|
66
67
|
PatchPyTorchModelIO.update_current_task(None)
|
67
68
|
PatchedMatplotlib.update_current_task(None)
|
68
69
|
else:
|
69
70
|
task = Task.init(
|
70
|
-
project_name=trainer.args.project or "
|
71
|
+
project_name=trainer.args.project or "Ultralytics",
|
71
72
|
task_name=trainer.args.name,
|
72
|
-
tags=["
|
73
|
+
tags=["Ultralytics"],
|
73
74
|
output_uri=True,
|
74
75
|
reuse_last_task_id=False,
|
75
76
|
auto_connect_frameworks={"pytorch": False, "matplotlib": False},
|