ultralytics 8.3.101__py3-none-any.whl → 8.3.103__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/test_exports.py +14 -5
- tests/test_solutions.py +140 -76
- ultralytics/__init__.py +1 -1
- ultralytics/cfg/__init__.py +1 -1
- ultralytics/engine/exporter.py +23 -8
- ultralytics/engine/tuner.py +8 -2
- ultralytics/hub/__init__.py +29 -2
- ultralytics/hub/google/__init__.py +18 -1
- ultralytics/models/fastsam/predict.py +12 -1
- ultralytics/models/nas/predict.py +21 -3
- ultralytics/models/rtdetr/val.py +26 -2
- ultralytics/models/sam/amg.py +22 -1
- ultralytics/models/sam/modules/encoders.py +85 -4
- ultralytics/models/sam/modules/memory_attention.py +61 -3
- ultralytics/models/sam/modules/utils.py +108 -5
- ultralytics/models/utils/loss.py +38 -2
- ultralytics/models/utils/ops.py +15 -1
- ultralytics/models/yolo/classify/predict.py +11 -1
- ultralytics/models/yolo/classify/train.py +17 -1
- ultralytics/models/yolo/classify/val.py +82 -6
- ultralytics/models/yolo/detect/predict.py +20 -1
- ultralytics/models/yolo/model.py +55 -4
- ultralytics/models/yolo/obb/predict.py +16 -1
- ultralytics/models/yolo/obb/train.py +35 -2
- ultralytics/models/yolo/obb/val.py +87 -6
- ultralytics/models/yolo/pose/predict.py +18 -1
- ultralytics/models/yolo/pose/train.py +48 -3
- ultralytics/models/yolo/pose/val.py +113 -8
- ultralytics/models/yolo/segment/predict.py +27 -2
- ultralytics/models/yolo/segment/train.py +61 -3
- ultralytics/models/yolo/segment/val.py +10 -1
- ultralytics/models/yolo/world/train_world.py +29 -1
- ultralytics/models/yolo/yoloe/train.py +47 -3
- ultralytics/nn/autobackend.py +9 -8
- ultralytics/nn/modules/activation.py +26 -3
- ultralytics/nn/modules/block.py +89 -0
- ultralytics/nn/modules/head.py +3 -92
- ultralytics/nn/modules/utils.py +70 -4
- ultralytics/nn/tasks.py +3 -0
- ultralytics/nn/text_model.py +93 -17
- ultralytics/solutions/instance_segmentation.py +15 -7
- ultralytics/solutions/solutions.py +2 -47
- ultralytics/utils/benchmarks.py +1 -1
- ultralytics/utils/callbacks/base.py +22 -5
- ultralytics/utils/callbacks/comet.py +93 -5
- ultralytics/utils/callbacks/dvc.py +64 -5
- ultralytics/utils/callbacks/neptune.py +25 -2
- ultralytics/utils/callbacks/tensorboard.py +30 -2
- ultralytics/utils/callbacks/wb.py +16 -1
- ultralytics/utils/dist.py +35 -2
- ultralytics/utils/errors.py +27 -6
- ultralytics/utils/metrics.py +1 -1
- ultralytics/utils/patches.py +33 -5
- ultralytics/utils/torch_utils.py +14 -6
- ultralytics/utils/triton.py +16 -3
- ultralytics/utils/tuner.py +17 -9
- {ultralytics-8.3.101.dist-info → ultralytics-8.3.103.dist-info}/METADATA +3 -4
- {ultralytics-8.3.101.dist-info → ultralytics-8.3.103.dist-info}/RECORD +62 -62
- {ultralytics-8.3.101.dist-info → ultralytics-8.3.103.dist-info}/WHEEL +0 -0
- {ultralytics-8.3.101.dist-info → ultralytics-8.3.103.dist-info}/entry_points.txt +0 -0
- {ultralytics-8.3.101.dist-info → ultralytics-8.3.103.dist-info}/licenses/LICENSE +0 -0
- {ultralytics-8.3.101.dist-info → ultralytics-8.3.103.dist-info}/top_level.txt +0 -0
tests/test_exports.py
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
2
2
|
|
3
|
+
import io
|
3
4
|
import shutil
|
4
5
|
import uuid
|
6
|
+
from contextlib import redirect_stderr, redirect_stdout
|
5
7
|
from itertools import product
|
6
8
|
from pathlib import Path
|
7
9
|
|
@@ -167,12 +169,19 @@ def test_export_tflite_matrix(task, dynamic, int8, half, batch, nms):
|
|
167
169
|
@pytest.mark.skipif(LINUX and ARM64, reason="CoreML not supported on aarch64 Linux")
|
168
170
|
@pytest.mark.skipif(checks.IS_PYTHON_3_13, reason="CoreML not supported in Python 3.13")
|
169
171
|
def test_export_coreml():
|
170
|
-
"""Test YOLO exports to CoreML format
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
else:
|
172
|
+
"""Test YOLO exports to CoreML format and check for errors."""
|
173
|
+
# Capture stdout and stderr
|
174
|
+
stdout, stderr = io.StringIO(), io.StringIO()
|
175
|
+
with redirect_stdout(stdout), redirect_stderr(stderr):
|
175
176
|
YOLO(MODEL).export(format="coreml", nms=True, imgsz=32)
|
177
|
+
if MACOS:
|
178
|
+
file = YOLO(MODEL).export(format="coreml", imgsz=32)
|
179
|
+
YOLO(file)(SOURCE, imgsz=32) # model prediction only supported on macOS for nms=False models
|
180
|
+
|
181
|
+
# Check captured output for errors
|
182
|
+
output = stdout.getvalue() + stderr.getvalue()
|
183
|
+
assert "Error" not in output, f"CoreML export produced errors: {output}"
|
184
|
+
assert "You will not be able to run predict()" not in output, "CoreML export has predict() error"
|
176
185
|
|
177
186
|
|
178
187
|
@pytest.mark.skipif(not checks.IS_PYTHON_MINIMUM_3_10, reason="TFLite export requires Python>=3.10")
|
tests/test_solutions.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
3
|
+
# Tests Ultralytics Solutions: https://docs.ultralytics.com/solutions/,
|
4
|
+
# including every solution excluding DistanceCalculation and Security Alarm System.
|
5
5
|
|
6
6
|
import cv2
|
7
7
|
import pytest
|
@@ -11,93 +11,157 @@ from ultralytics import solutions
|
|
11
11
|
from ultralytics.utils import ASSETS_URL
|
12
12
|
from ultralytics.utils.downloads import safe_download
|
13
13
|
|
14
|
-
|
14
|
+
# Pre-defined arguments values
|
15
|
+
SHOW = False
|
16
|
+
DEMO_VIDEO = "solutions_ci_demo.mp4" # for all the solutions, except workout, object cropping and parking management
|
17
|
+
CROP_VIDEO = "decelera_landscape_min.mov" # for object cropping solution
|
15
18
|
POSE_VIDEO = "solution_ci_pose_demo.mp4" # only for workouts monitoring solution
|
16
19
|
PARKING_VIDEO = "solution_ci_parking_demo.mp4" # only for parking management solution
|
17
20
|
PARKING_AREAS_JSON = "solution_ci_parking_areas.json" # only for parking management solution
|
18
21
|
PARKING_MODEL = "solutions_ci_parking_model.pt" # only for parking management solution
|
22
|
+
MODEL_FILE = "yolo11n.pt" # model file used for solutions, except parking management and instance segmentation
|
23
|
+
REGION = [(20, 400), (1080, 400), (1080, 360), (20, 360)] # for object counting, speed estimation and queue management
|
19
24
|
|
25
|
+
# Test configs for each solution : (name, class, needs_frame_count, video, kwargs)
|
26
|
+
SOLUTIONS = [
|
27
|
+
(
|
28
|
+
"ObjectCounter",
|
29
|
+
solutions.ObjectCounter,
|
30
|
+
False,
|
31
|
+
DEMO_VIDEO,
|
32
|
+
{"region": REGION, "model": MODEL_FILE, "show": SHOW},
|
33
|
+
),
|
34
|
+
(
|
35
|
+
"Heatmap",
|
36
|
+
solutions.Heatmap,
|
37
|
+
False,
|
38
|
+
DEMO_VIDEO,
|
39
|
+
{"colormap": cv2.COLORMAP_PARULA, "model": MODEL_FILE, "show": SHOW, "region": None},
|
40
|
+
),
|
41
|
+
(
|
42
|
+
"HeatmapWithRegion",
|
43
|
+
solutions.Heatmap,
|
44
|
+
False,
|
45
|
+
DEMO_VIDEO,
|
46
|
+
{"colormap": cv2.COLORMAP_PARULA, "region": REGION, "model": MODEL_FILE, "show": SHOW},
|
47
|
+
),
|
48
|
+
(
|
49
|
+
"SpeedEstimator",
|
50
|
+
solutions.SpeedEstimator,
|
51
|
+
False,
|
52
|
+
DEMO_VIDEO,
|
53
|
+
{"region": REGION, "model": MODEL_FILE, "show": SHOW},
|
54
|
+
),
|
55
|
+
(
|
56
|
+
"QueueManager",
|
57
|
+
solutions.QueueManager,
|
58
|
+
False,
|
59
|
+
DEMO_VIDEO,
|
60
|
+
{"region": REGION, "model": MODEL_FILE, "show": SHOW},
|
61
|
+
),
|
62
|
+
(
|
63
|
+
"LineAnalytics",
|
64
|
+
solutions.Analytics,
|
65
|
+
True,
|
66
|
+
DEMO_VIDEO,
|
67
|
+
{"analytics_type": "line", "model": MODEL_FILE, "show": SHOW},
|
68
|
+
),
|
69
|
+
(
|
70
|
+
"PieAnalytics",
|
71
|
+
solutions.Analytics,
|
72
|
+
True,
|
73
|
+
DEMO_VIDEO,
|
74
|
+
{"analytics_type": "pie", "model": MODEL_FILE, "show": SHOW},
|
75
|
+
),
|
76
|
+
(
|
77
|
+
"BarAnalytics",
|
78
|
+
solutions.Analytics,
|
79
|
+
True,
|
80
|
+
DEMO_VIDEO,
|
81
|
+
{"analytics_type": "bar", "model": MODEL_FILE, "show": SHOW},
|
82
|
+
),
|
83
|
+
(
|
84
|
+
"AreaAnalytics",
|
85
|
+
solutions.Analytics,
|
86
|
+
True,
|
87
|
+
DEMO_VIDEO,
|
88
|
+
{"analytics_type": "area", "model": MODEL_FILE, "show": SHOW},
|
89
|
+
),
|
90
|
+
("TrackZone", solutions.TrackZone, False, DEMO_VIDEO, {"region": REGION, "model": MODEL_FILE, "show": SHOW}),
|
91
|
+
(
|
92
|
+
"ObjectCropper",
|
93
|
+
solutions.ObjectCropper,
|
94
|
+
False,
|
95
|
+
CROP_VIDEO,
|
96
|
+
{"crop_dir": str(TMP / "cropped-detections"), "model": MODEL_FILE, "show": SHOW},
|
97
|
+
),
|
98
|
+
(
|
99
|
+
"ObjectBlurrer",
|
100
|
+
solutions.ObjectBlurrer,
|
101
|
+
False,
|
102
|
+
DEMO_VIDEO,
|
103
|
+
{"blur_ratio": 0.5, "model": MODEL_FILE, "show": SHOW},
|
104
|
+
),
|
105
|
+
(
|
106
|
+
"InstanceSegmentation",
|
107
|
+
solutions.InstanceSegmentation,
|
108
|
+
False,
|
109
|
+
DEMO_VIDEO,
|
110
|
+
{"model": "yolo11n-seg.pt", "show": SHOW},
|
111
|
+
),
|
112
|
+
("VisionEye", solutions.VisionEye, False, DEMO_VIDEO, {"model": MODEL_FILE, "show": SHOW}),
|
113
|
+
(
|
114
|
+
"RegionCounter",
|
115
|
+
solutions.RegionCounter,
|
116
|
+
False,
|
117
|
+
DEMO_VIDEO,
|
118
|
+
{"region": REGION, "model": MODEL_FILE, "show": SHOW},
|
119
|
+
),
|
120
|
+
("AIGym", solutions.AIGym, False, POSE_VIDEO, {"kpts": [6, 8, 10], "show": SHOW}),
|
121
|
+
(
|
122
|
+
"ParkingManager",
|
123
|
+
solutions.ParkingManagement,
|
124
|
+
False,
|
125
|
+
PARKING_VIDEO,
|
126
|
+
{"model": str(TMP / PARKING_MODEL), "show": SHOW, "json_file": str(TMP / PARKING_AREAS_JSON)},
|
127
|
+
),
|
128
|
+
(
|
129
|
+
"StreamlitInference",
|
130
|
+
solutions.Inference,
|
131
|
+
False,
|
132
|
+
None, # streamlit application don't require video file
|
133
|
+
{}, # streamlit application don't accept arguments
|
134
|
+
),
|
135
|
+
]
|
20
136
|
|
21
|
-
@pytest.mark.slow
|
22
|
-
def test_major_solutions():
|
23
|
-
"""Test the object counting, heatmap, speed estimation, trackzone and queue management solution."""
|
24
|
-
safe_download(url=f"{ASSETS_URL}/{DEMO_VIDEO}", dir=TMP)
|
25
|
-
cap = cv2.VideoCapture(str(TMP / DEMO_VIDEO))
|
26
|
-
assert cap.isOpened(), "Error reading video file"
|
27
|
-
region_points = [(20, 400), (1080, 400), (1080, 360), (20, 360)]
|
28
|
-
counter = solutions.ObjectCounter(region=region_points, model="yolo11n.pt", show=False) # Test object counter
|
29
|
-
heatmap = solutions.Heatmap(colormap=cv2.COLORMAP_PARULA, model="yolo11n.pt", show=False) # Test heatmaps
|
30
|
-
heatmapcounter = solutions.Heatmap(
|
31
|
-
colormap=cv2.COLORMAP_PARULA, model="yolo11n.pt", show=False, region=region_points
|
32
|
-
) # Test heatmaps with object counting
|
33
|
-
speed = solutions.SpeedEstimator(region=region_points, model="yolo11n.pt", show=False) # Test speed estimation
|
34
|
-
queue = solutions.QueueManager(region=region_points, model="yolo11n.pt", show=False) # Test queue management
|
35
|
-
lineanalytics = solutions.Analytics(analytics_type="line", model="yolo11n.pt", show=False) # Line analytics
|
36
|
-
pieanalytics = solutions.Analytics(analytics_type="pie", model="yolo11n.pt", show=False) # Pie analytics
|
37
|
-
baranalytics = solutions.Analytics(analytics_type="bar", model="yolo11n.pt", show=False) # Bar analytics
|
38
|
-
areaanalytics = solutions.Analytics(analytics_type="area", model="yolo11n.pt", show=False) # Area analytics
|
39
|
-
trackzone = solutions.TrackZone(region=region_points, model="yolo11n.pt", show=False) # Track zone monitoring
|
40
|
-
objectcropper = solutions.ObjectCropper(
|
41
|
-
model="yolo11n.pt", show=False, crop_dir=str(TMP / "cropped-detections")
|
42
|
-
) # Object cropping
|
43
|
-
objectblurrer = solutions.ObjectBlurrer(blur_ratio=0.5, model="yolo11n.pt", show=False) # Object blurring
|
44
|
-
isegment = solutions.InstanceSegmentation(model="yolo11n-seg.pt", show=False) # Instance segmentation
|
45
|
-
visioneye = solutions.VisionEye(model="yolo11n.pt", show=False) # Vision Eye solution
|
46
|
-
regioncounter = solutions.RegionCounter(region=region_points, model="yolo11n.pt", show=False) # Region counter
|
47
|
-
frame_count = 0 # Required for analytics
|
48
|
-
while cap.isOpened():
|
49
|
-
success, im0 = cap.read()
|
50
|
-
if not success:
|
51
|
-
break
|
52
|
-
frame_count += 1
|
53
|
-
original_im0 = im0.copy()
|
54
|
-
_ = counter(original_im0.copy())
|
55
|
-
_ = heatmap(original_im0.copy())
|
56
|
-
_ = heatmapcounter(original_im0.copy())
|
57
|
-
_ = speed(original_im0.copy())
|
58
|
-
_ = queue(original_im0.copy())
|
59
|
-
_ = lineanalytics(original_im0.copy(), frame_count)
|
60
|
-
_ = pieanalytics(original_im0.copy(), frame_count)
|
61
|
-
_ = baranalytics(original_im0.copy(), frame_count)
|
62
|
-
_ = areaanalytics(original_im0.copy(), frame_count)
|
63
|
-
_ = trackzone(original_im0.copy())
|
64
|
-
_ = objectcropper(original_im0.copy())
|
65
|
-
_ = isegment(original_im0.copy())
|
66
|
-
_ = objectblurrer(original_im0.copy())
|
67
|
-
_ = visioneye(original_im0.copy())
|
68
|
-
_ = regioncounter(original_im0.copy())
|
69
|
-
cap.release()
|
70
137
|
|
71
|
-
|
72
|
-
|
73
|
-
cap = cv2.VideoCapture(
|
74
|
-
assert cap.isOpened(), "Error reading video file"
|
75
|
-
gym = solutions.AIGym(kpts=[5, 11, 13], show=False)
|
76
|
-
while cap.isOpened():
|
77
|
-
success, im0 = cap.read()
|
78
|
-
if not success:
|
79
|
-
break
|
80
|
-
_ = gym(im0)
|
81
|
-
cap.release()
|
138
|
+
def process_video(solution, video_path, needs_frame_count=False):
|
139
|
+
"""Process video with solution, feeding frames and optional frame count."""
|
140
|
+
cap = cv2.VideoCapture(video_path)
|
141
|
+
assert cap.isOpened(), f"Error reading video file {video_path}"
|
82
142
|
|
83
|
-
|
84
|
-
safe_download(url=f"{ASSETS_URL}/{PARKING_VIDEO}", dir=TMP)
|
85
|
-
safe_download(url=f"{ASSETS_URL}/{PARKING_AREAS_JSON}", dir=TMP)
|
86
|
-
safe_download(url=f"{ASSETS_URL}/{PARKING_MODEL}", dir=TMP)
|
87
|
-
cap = cv2.VideoCapture(str(TMP / PARKING_VIDEO))
|
88
|
-
assert cap.isOpened(), "Error reading video file"
|
89
|
-
parkingmanager = solutions.ParkingManagement(
|
90
|
-
json_file=str(TMP / PARKING_AREAS_JSON), model=str(TMP / PARKING_MODEL), show=False
|
91
|
-
)
|
143
|
+
frame_count = 0
|
92
144
|
while cap.isOpened():
|
93
145
|
success, im0 = cap.read()
|
94
146
|
if not success:
|
95
147
|
break
|
96
|
-
|
148
|
+
frame_count += 1
|
149
|
+
im_copy = im0.copy()
|
150
|
+
args = [im_copy, frame_count] if needs_frame_count else [im_copy]
|
151
|
+
_ = solution(*args)
|
152
|
+
|
97
153
|
cap.release()
|
98
154
|
|
99
155
|
|
100
156
|
@pytest.mark.slow
|
101
|
-
|
102
|
-
|
103
|
-
|
157
|
+
@pytest.mark.parametrize("name, solution_class, needs_frame_count, video, kwargs", SOLUTIONS)
|
158
|
+
def test_solution(name, solution_class, needs_frame_count, video, kwargs):
|
159
|
+
"""Test individual Ultralytics solution."""
|
160
|
+
safe_download(url=f"{ASSETS_URL}/{video}", dir=TMP)
|
161
|
+
if name == "ParkingManager":
|
162
|
+
safe_download(url=f"{ASSETS_URL}/{PARKING_AREAS_JSON}", dir=TMP)
|
163
|
+
safe_download(url=f"{ASSETS_URL}/{PARKING_MODEL}", dir=TMP)
|
164
|
+
solution = solution_class(**kwargs)
|
165
|
+
solution.inference() if name == "StreamlitInference" else process_video(
|
166
|
+
solution, str(TMP / video), needs_frame_count
|
167
|
+
)
|
ultralytics/__init__.py
CHANGED
ultralytics/cfg/__init__.py
CHANGED
@@ -700,7 +700,7 @@ def handle_yolo_solutions(args: List[str]) -> None:
|
|
700
700
|
solution_name = "count" # Default for invalid solution
|
701
701
|
|
702
702
|
if solution_name == "inference":
|
703
|
-
checks.check_requirements("streamlit>=1.29.0")
|
703
|
+
checks.check_requirements("streamlit>=1.29.0,<1.44.0")
|
704
704
|
LOGGER.info("💡 Loading Ultralytics live inference app...")
|
705
705
|
subprocess.run(
|
706
706
|
[ # Run subprocess with Streamlit custom argument
|
ultralytics/engine/exporter.py
CHANGED
@@ -115,18 +115,32 @@ def export_formats():
|
|
115
115
|
["PyTorch", "-", ".pt", True, True, []],
|
116
116
|
["TorchScript", "torchscript", ".torchscript", True, True, ["batch", "optimize", "nms"]],
|
117
117
|
["ONNX", "onnx", ".onnx", True, True, ["batch", "dynamic", "half", "opset", "simplify", "nms"]],
|
118
|
-
[
|
119
|
-
|
118
|
+
[
|
119
|
+
"OpenVINO",
|
120
|
+
"openvino",
|
121
|
+
"_openvino_model",
|
122
|
+
True,
|
123
|
+
False,
|
124
|
+
["batch", "dynamic", "half", "int8", "nms", "fraction"],
|
125
|
+
],
|
126
|
+
[
|
127
|
+
"TensorRT",
|
128
|
+
"engine",
|
129
|
+
".engine",
|
130
|
+
False,
|
131
|
+
True,
|
132
|
+
["batch", "dynamic", "half", "int8", "simplify", "nms", "fraction"],
|
133
|
+
],
|
120
134
|
["CoreML", "coreml", ".mlpackage", True, False, ["batch", "half", "int8", "nms"]],
|
121
135
|
["TensorFlow SavedModel", "saved_model", "_saved_model", True, True, ["batch", "int8", "keras", "nms"]],
|
122
136
|
["TensorFlow GraphDef", "pb", ".pb", True, True, ["batch"]],
|
123
|
-
["TensorFlow Lite", "tflite", ".tflite", True, False, ["batch", "half", "int8", "nms"]],
|
137
|
+
["TensorFlow Lite", "tflite", ".tflite", True, False, ["batch", "half", "int8", "nms", "fraction"]],
|
124
138
|
["TensorFlow Edge TPU", "edgetpu", "_edgetpu.tflite", True, False, []],
|
125
139
|
["TensorFlow.js", "tfjs", "_web_model", True, False, ["batch", "half", "int8", "nms"]],
|
126
140
|
["PaddlePaddle", "paddle", "_paddle_model", True, True, ["batch"]],
|
127
141
|
["MNN", "mnn", ".mnn", True, True, ["batch", "half", "int8"]],
|
128
142
|
["NCNN", "ncnn", "_ncnn_model", True, True, ["batch", "half"]],
|
129
|
-
["IMX", "imx", "_imx_model", True, True, ["int8"]],
|
143
|
+
["IMX", "imx", "_imx_model", True, True, ["int8", "fraction"]],
|
130
144
|
["RKNN", "rknn", "_rknn_model", False, False, ["batch", "name"]],
|
131
145
|
]
|
132
146
|
return dict(zip(["Format", "Argument", "Suffix", "CPU", "GPU", "Arguments"], zip(*x)))
|
@@ -144,7 +158,7 @@ def validate_args(format, passed_args, valid_args):
|
|
144
158
|
Raises:
|
145
159
|
AssertionError: If an unsupported argument is used, or if the format lacks supported argument listings.
|
146
160
|
"""
|
147
|
-
export_args = ["half", "int8", "dynamic", "keras", "nms", "batch"]
|
161
|
+
export_args = ["half", "int8", "dynamic", "keras", "nms", "batch", "fraction"]
|
148
162
|
|
149
163
|
assert valid_args is not None, f"ERROR ❌️ valid arguments for '{format}' not listed."
|
150
164
|
custom = {"batch": 1, "data": None, "device": None} # exporter defaults
|
@@ -493,6 +507,7 @@ class Exporter:
|
|
493
507
|
dataset = YOLODataset(
|
494
508
|
data[self.args.split or "val"],
|
495
509
|
data=data,
|
510
|
+
fraction=self.args.fraction,
|
496
511
|
task=self.model.task,
|
497
512
|
imgsz=self.imgsz[0],
|
498
513
|
augment=False,
|
@@ -803,7 +818,7 @@ class Exporter:
|
|
803
818
|
ts,
|
804
819
|
inputs=[ct.ImageType("image", shape=self.im.shape, scale=scale, bias=bias)], # expects ct.TensorType
|
805
820
|
classifier_config=classifier_config,
|
806
|
-
minimum_deployment_target=ct.target.
|
821
|
+
minimum_deployment_target=ct.target.iOS15, # warning: >=16 causes pipeline errors
|
807
822
|
convert_to="neuralnetwork" if mlmodel else "mlprogram",
|
808
823
|
)
|
809
824
|
bits, mode = (8, "kmeans") if self.args.int8 else (16, "linear") if self.args.half else (32, None)
|
@@ -1449,7 +1464,7 @@ class Exporter:
|
|
1449
1464
|
|
1450
1465
|
# 3. Create NMS protobuf
|
1451
1466
|
nms_spec = ct.proto.Model_pb2.Model()
|
1452
|
-
nms_spec.specificationVersion =
|
1467
|
+
nms_spec.specificationVersion = 9
|
1453
1468
|
for i in range(2):
|
1454
1469
|
decoder_output = model._spec.description.output[i].SerializeToString()
|
1455
1470
|
nms_spec.description.input.add()
|
@@ -1502,7 +1517,7 @@ class Exporter:
|
|
1502
1517
|
pipeline.spec.description.output[1].ParseFromString(nms_model._spec.description.output[1].SerializeToString())
|
1503
1518
|
|
1504
1519
|
# Update metadata
|
1505
|
-
pipeline.spec.specificationVersion =
|
1520
|
+
pipeline.spec.specificationVersion = 9
|
1506
1521
|
pipeline.spec.description.metadata.userDefined.update(
|
1507
1522
|
{"IoU threshold": str(nms.iouThreshold), "Confidence threshold": str(nms.confidenceThreshold)}
|
1508
1523
|
)
|
ultralytics/engine/tuner.py
CHANGED
@@ -93,8 +93,9 @@ class Tuner:
|
|
93
93
|
"copy_paste": (0.0, 1.0), # segment copy-paste (probability)
|
94
94
|
}
|
95
95
|
self.args = get_cfg(overrides=args)
|
96
|
+
self.args.exist_ok = self.args.resume # resume w/ same tune_dir
|
96
97
|
self.tune_dir = get_save_dir(self.args, name=self.args.name or "tune")
|
97
|
-
self.args.name = None # reset to not affect training
|
98
|
+
self.args.name, self.args.exist_ok, self.args.resume = (None, False, False) # reset to not affect training
|
98
99
|
self.tune_csv = self.tune_dir / "tune_results.csv"
|
99
100
|
self.callbacks = _callbacks or callbacks.get_default_callbacks()
|
100
101
|
self.prefix = colorstr("Tuner: ")
|
@@ -173,7 +174,12 @@ class Tuner:
|
|
173
174
|
t0 = time.time()
|
174
175
|
best_save_dir, best_metrics = None, None
|
175
176
|
(self.tune_dir / "weights").mkdir(parents=True, exist_ok=True)
|
176
|
-
|
177
|
+
start = 0
|
178
|
+
if self.tune_csv.exists():
|
179
|
+
x = np.loadtxt(self.tune_csv, ndmin=2, delimiter=",", skiprows=1)
|
180
|
+
start = x.shape[0]
|
181
|
+
LOGGER.info(f"{self.prefix}Resuming tuning run {self.tune_dir} from iteration {start + 1}...")
|
182
|
+
for i in range(start, iterations):
|
177
183
|
# Mutate hyperparameters
|
178
184
|
mutated_hyp = self._mutate()
|
179
185
|
LOGGER.info(f"{self.prefix}Starting iteration {i + 1}/{iterations} with hyperparameters: {mutated_hyp}")
|
ultralytics/hub/__init__.py
CHANGED
@@ -96,7 +96,21 @@ def export_fmts_hub():
|
|
96
96
|
|
97
97
|
|
98
98
|
def export_model(model_id: str = "", format: str = "torchscript"):
|
99
|
-
"""
|
99
|
+
"""
|
100
|
+
Export a model to a specified format for deployment via the Ultralytics HUB API.
|
101
|
+
|
102
|
+
Args:
|
103
|
+
model_id (str): The ID of the model to export. An empty string will use the default model.
|
104
|
+
format (str): The format to export the model to. Must be one of the supported formats returned by
|
105
|
+
export_fmts_hub().
|
106
|
+
|
107
|
+
Raises:
|
108
|
+
AssertionError: If the specified format is not supported or if the export request fails.
|
109
|
+
|
110
|
+
Examples:
|
111
|
+
>>> from ultralytics import hub
|
112
|
+
>>> hub.export_model(model_id="your_model_id", format="torchscript")
|
113
|
+
"""
|
100
114
|
assert format in export_fmts_hub(), f"Unsupported export format '{format}', valid formats are {export_fmts_hub()}"
|
101
115
|
r = requests.post(
|
102
116
|
f"{HUB_API_ROOT}/v1/models/{model_id}/export", json={"format": format}, headers={"x-api-key": Auth().api_key}
|
@@ -106,7 +120,20 @@ def export_model(model_id: str = "", format: str = "torchscript"):
|
|
106
120
|
|
107
121
|
|
108
122
|
def get_export(model_id: str = "", format: str = "torchscript"):
|
109
|
-
"""
|
123
|
+
"""
|
124
|
+
Retrieve an exported model in the specified format from Ultralytics HUB using the model ID.
|
125
|
+
|
126
|
+
Args:
|
127
|
+
model_id (str): The ID of the model to retrieve from Ultralytics HUB.
|
128
|
+
format (str): The export format to retrieve. Must be one of the supported formats returned by export_fmts_hub().
|
129
|
+
|
130
|
+
Raises:
|
131
|
+
AssertionError: If the specified format is not supported or if the API request fails.
|
132
|
+
|
133
|
+
Examples:
|
134
|
+
>>> from ultralytics import hub
|
135
|
+
>>> hub.get_export(model_id="your_model_id", format="torchscript")
|
136
|
+
"""
|
110
137
|
assert format in export_fmts_hub(), f"Unsupported export format '{format}', valid formats are {export_fmts_hub()}"
|
111
138
|
r = requests.post(
|
112
139
|
f"{HUB_API_ROOT}/get-export",
|
@@ -83,7 +83,24 @@ class GCPRegions:
|
|
83
83
|
|
84
84
|
@staticmethod
|
85
85
|
def _ping_region(region: str, attempts: int = 1) -> Tuple[str, float, float, float, float]:
|
86
|
-
"""
|
86
|
+
"""
|
87
|
+
Ping a specified GCP region and measure network latency statistics.
|
88
|
+
|
89
|
+
Args:
|
90
|
+
region (str): The GCP region identifier to ping (e.g., 'us-central1').
|
91
|
+
attempts (int): Number of ping attempts to make for calculating statistics.
|
92
|
+
|
93
|
+
Returns:
|
94
|
+
region (str): The GCP region identifier that was pinged.
|
95
|
+
mean_latency (float): Mean latency in milliseconds, or infinity if all pings failed.
|
96
|
+
min_latency (float): Minimum latency in milliseconds, or infinity if all pings failed.
|
97
|
+
max_latency (float): Maximum latency in milliseconds, or infinity if all pings failed.
|
98
|
+
std_dev (float): Standard deviation of latencies in milliseconds, or infinity if all pings failed.
|
99
|
+
|
100
|
+
Examples:
|
101
|
+
>>> region, mean, min_lat, max_lat, std = GCPRegions._ping_region("us-central1", attempts=3)
|
102
|
+
>>> print(f"Region {region} has mean latency: {mean:.2f}ms")
|
103
|
+
"""
|
87
104
|
url = f"https://{region}-docker.pkg.dev"
|
88
105
|
latencies = []
|
89
106
|
for _ in range(attempts):
|
@@ -33,7 +33,18 @@ class FastSAMPredictor(SegmentationPredictor):
|
|
33
33
|
"""
|
34
34
|
|
35
35
|
def __init__(self, cfg=DEFAULT_CFG, overrides=None, _callbacks=None):
|
36
|
-
"""
|
36
|
+
"""
|
37
|
+
Initialize the FastSAMPredictor with configuration and callbacks.
|
38
|
+
|
39
|
+
This initializes a predictor specialized for Fast SAM (Segment Anything Model) segmentation tasks. The predictor
|
40
|
+
extends SegmentationPredictor with custom post-processing for mask prediction and non-maximum suppression
|
41
|
+
optimized for single-class segmentation.
|
42
|
+
|
43
|
+
Args:
|
44
|
+
cfg (dict): Configuration for the predictor. Defaults to Ultralytics DEFAULT_CFG.
|
45
|
+
overrides (dict, optional): Configuration overrides.
|
46
|
+
_callbacks (list, optional): List of callback functions.
|
47
|
+
"""
|
37
48
|
super().__init__(cfg, overrides, _callbacks)
|
38
49
|
self.prompts = {}
|
39
50
|
|
@@ -33,8 +33,26 @@ class NASPredictor(DetectionPredictor):
|
|
33
33
|
"""
|
34
34
|
|
35
35
|
def postprocess(self, preds_in, img, orig_imgs):
|
36
|
-
"""
|
37
|
-
|
36
|
+
"""
|
37
|
+
Postprocess NAS model predictions to generate final detection results.
|
38
|
+
|
39
|
+
This method takes raw predictions from a YOLO NAS model, converts bounding box formats, and applies
|
40
|
+
post-processing operations to generate the final detection results compatible with Ultralytics
|
41
|
+
result visualization and analysis tools.
|
42
|
+
|
43
|
+
Args:
|
44
|
+
preds_in (list): Raw predictions from the NAS model, typically containing bounding boxes and class scores.
|
45
|
+
img (torch.Tensor): Input image tensor that was fed to the model, with shape (B, C, H, W).
|
46
|
+
orig_imgs (list | torch.Tensor | np.ndarray): Original images before preprocessing, used for scaling
|
47
|
+
coordinates back to original dimensions.
|
48
|
+
|
49
|
+
Returns:
|
50
|
+
(list): List of Results objects containing the processed predictions for each image in the batch.
|
51
|
+
|
52
|
+
Examples:
|
53
|
+
>>> predictor = NAS("yolo_nas_s").predictor
|
54
|
+
>>> results = predictor.postprocess(raw_preds, img, orig_imgs)
|
55
|
+
"""
|
38
56
|
boxes = ops.xyxy2xywh(preds_in[0][0])
|
39
|
-
preds = torch.cat((boxes, preds_in[0][1]), -1).permute(0, 2, 1)
|
57
|
+
preds = torch.cat((boxes, preds_in[0][1]), -1).permute(0, 2, 1) # concatenate with class scores
|
40
58
|
return super().postprocess(preds, img, orig_imgs)
|
ultralytics/models/rtdetr/val.py
CHANGED
@@ -19,11 +19,35 @@ class RTDETRDataset(YOLODataset):
|
|
19
19
|
"""
|
20
20
|
|
21
21
|
def __init__(self, *args, data=None, **kwargs):
|
22
|
-
"""
|
22
|
+
"""
|
23
|
+
Initialize the RTDETRDataset class by inheriting from the YOLODataset class.
|
24
|
+
|
25
|
+
This constructor sets up a dataset specifically optimized for the RT-DETR (Real-Time DEtection and TRacking)
|
26
|
+
model, building upon the base YOLODataset functionality.
|
27
|
+
|
28
|
+
Args:
|
29
|
+
*args (Any): Variable length argument list passed to the parent YOLODataset class.
|
30
|
+
data (Dict | None): Dictionary containing dataset information. If None, default values will be used.
|
31
|
+
**kwargs (Any): Additional keyword arguments passed to the parent YOLODataset class.
|
32
|
+
"""
|
23
33
|
super().__init__(*args, data=data, **kwargs)
|
24
34
|
|
25
35
|
def load_image(self, i, rect_mode=False):
|
26
|
-
"""
|
36
|
+
"""
|
37
|
+
Load one image from dataset index 'i'.
|
38
|
+
|
39
|
+
Args:
|
40
|
+
i (int): Index of the image to load.
|
41
|
+
rect_mode (bool, optional): Whether to use rectangular mode for batch inference.
|
42
|
+
|
43
|
+
Returns:
|
44
|
+
im (numpy.ndarray): The loaded image.
|
45
|
+
resized_hw (tuple): Height and width of the resized image with shape (2,).
|
46
|
+
|
47
|
+
Examples:
|
48
|
+
>>> dataset = RTDETRDataset(...)
|
49
|
+
>>> image, hw = dataset.load_image(0)
|
50
|
+
"""
|
27
51
|
return super().load_image(i=i, rect_mode=rect_mode)
|
28
52
|
|
29
53
|
def build_transforms(self, hyp=None):
|
ultralytics/models/sam/amg.py
CHANGED
@@ -22,7 +22,28 @@ def is_box_near_crop_edge(
|
|
22
22
|
|
23
23
|
|
24
24
|
def batch_iterator(batch_size: int, *args) -> Generator[List[Any], None, None]:
|
25
|
-
"""
|
25
|
+
"""
|
26
|
+
Yield batches of data from input arguments with specified batch size for efficient processing.
|
27
|
+
|
28
|
+
This function takes a batch size and any number of iterables, then yields batches of elements from those
|
29
|
+
iterables. All input iterables must have the same length.
|
30
|
+
|
31
|
+
Args:
|
32
|
+
batch_size (int): Size of each batch to yield.
|
33
|
+
*args (Any): Variable length input iterables to batch. All iterables must have the same length.
|
34
|
+
|
35
|
+
Yields:
|
36
|
+
(List[Any]): A list of batched elements from each input iterable.
|
37
|
+
|
38
|
+
Examples:
|
39
|
+
>>> data = [1, 2, 3, 4, 5]
|
40
|
+
>>> labels = ["a", "b", "c", "d", "e"]
|
41
|
+
>>> for batch in batch_iterator(2, data, labels):
|
42
|
+
... print(batch)
|
43
|
+
[[1, 2], ['a', 'b']]
|
44
|
+
[[3, 4], ['c', 'd']]
|
45
|
+
[[5], ['e']]
|
46
|
+
"""
|
26
47
|
assert args and all(len(a) == len(args[0]) for a in args), "Batched iteration must have same-size inputs."
|
27
48
|
n_batches = len(args[0]) // batch_size + int(len(args[0]) % batch_size != 0)
|
28
49
|
for b in range(n_batches):
|