New `ASSETS` and trackers GMC cleanup (#4425)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
single_channel
Glenn Jocher 1 year ago committed by GitHub
parent aaba14e6b2
commit 9d27e7ada4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -13,6 +13,10 @@ keywords: Ultralytics, Data Converter, coco91_to_coco80_class, merge_multi_segme
## ::: ultralytics.data.converter.coco91_to_coco80_class ## ::: ultralytics.data.converter.coco91_to_coco80_class
<br><br> <br><br>
---
## ::: ultralytics.data.converter.coco80_to_coco91_class
<br><br>
--- ---
## ::: ultralytics.data.converter.convert_coco ## ::: ultralytics.data.converter.convert_coco
<br><br> <br><br>

@ -36,7 +36,3 @@ keywords: Ultralytics, utility functions, file operations, working directory, fi
--- ---
## ::: ultralytics.utils.files.get_latest_run ## ::: ultralytics.utils.files.get_latest_run
<br><br> <br><br>
---
## ::: ultralytics.utils.files.make_dirs
<br><br>

@ -13,10 +13,6 @@ keywords: Ultralytics YOLO, Utility Operations, segment2box, make_divisible, cli
## ::: ultralytics.utils.ops.Profile ## ::: ultralytics.utils.ops.Profile
<br><br> <br><br>
---
## ::: ultralytics.utils.ops.coco80_to_coco91_class
<br><br>
--- ---
## ::: ultralytics.utils.ops.segment2box ## ::: ultralytics.utils.ops.segment2box
<br><br> <br><br>

@ -5,7 +5,7 @@ import numpy as np
import onnxruntime as ort import onnxruntime as ort
import torch import torch
from ultralytics.utils import ROOT, yaml_load from ultralytics.utils import ASSETS, yaml_load
from ultralytics.utils.checks import check_requirements, check_yaml from ultralytics.utils.checks import check_requirements, check_yaml
@ -198,17 +198,14 @@ class Yolov8:
outputs = session.run(None, {model_inputs[0].name: img_data}) outputs = session.run(None, {model_inputs[0].name: img_data})
# Perform post-processing on the outputs to obtain output image. # Perform post-processing on the outputs to obtain output image.
output_img = self.postprocess(self.img, outputs) return self.postprocess(self.img, outputs) # output image
# Return the resulting output image
return output_img
if __name__ == '__main__': if __name__ == '__main__':
# Create an argument parser to handle command-line arguments # Create an argument parser to handle command-line arguments
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--model', type=str, default='yolov8n.onnx', help='Input your ONNX model.') parser.add_argument('--model', type=str, default='yolov8n.onnx', help='Input your ONNX model.')
parser.add_argument('--img', type=str, default=str(ROOT / 'assets/bus.jpg'), help='Path to input image.') parser.add_argument('--img', type=str, default=str(ASSETS / 'bus.jpg'), help='Path to input image.')
parser.add_argument('--conf-thres', type=float, default=0.5, help='Confidence threshold') parser.add_argument('--conf-thres', type=float, default=0.5, help='Confidence threshold')
parser.add_argument('--iou-thres', type=float, default=0.5, help='NMS IoU threshold') parser.add_argument('--iou-thres', type=float, default=0.5, help='NMS IoU threshold')
args = parser.parse_args() args = parser.parse_args()

@ -3,7 +3,7 @@ import argparse
import cv2.dnn import cv2.dnn
import numpy as np import numpy as np
from ultralytics.utils import ROOT, yaml_load from ultralytics.utils import ASSETS, yaml_load
from ultralytics.utils.checks import check_yaml from ultralytics.utils.checks import check_yaml
CLASSES = yaml_load(check_yaml('coco128.yaml'))['names'] CLASSES = yaml_load(check_yaml('coco128.yaml'))['names']
@ -75,6 +75,6 @@ def main(onnx_model, input_image):
if __name__ == '__main__': if __name__ == '__main__':
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--model', default='yolov8n.onnx', help='Input your onnx model.') parser.add_argument('--model', default='yolov8n.onnx', help='Input your onnx model.')
parser.add_argument('--img', default=str(ROOT / 'assets/bus.jpg'), help='Path to input image.') parser.add_argument('--img', default=str(ASSETS / 'bus.jpg'), help='Path to input image.')
args = parser.parse_args() args = parser.parse_args()
main(args.model, args.img) main(args.model, args.img)

@ -5,7 +5,7 @@ from pathlib import Path
import pytest import pytest
from ultralytics.utils import ROOT, SETTINGS from ultralytics.utils import ASSETS, SETTINGS
WEIGHTS_DIR = Path(SETTINGS['weights_dir']) WEIGHTS_DIR = Path(SETTINGS['weights_dir'])
TASK_ARGS = [ TASK_ARGS = [
@ -40,12 +40,12 @@ def test_train(task, model, data):
@pytest.mark.parametrize('task,model,data', TASK_ARGS) @pytest.mark.parametrize('task,model,data', TASK_ARGS)
def test_val(task, model, data): def test_val(task, model, data):
run(f'yolo val {task} model={WEIGHTS_DIR / model}.pt data={data} imgsz=32') run(f'yolo val {task} model={WEIGHTS_DIR / model}.pt data={data} imgsz=32 save_txt save_json')
@pytest.mark.parametrize('task,model,data', TASK_ARGS) @pytest.mark.parametrize('task,model,data', TASK_ARGS)
def test_predict(task, model, data): def test_predict(task, model, data):
run(f"yolo predict model={WEIGHTS_DIR / model}.pt source={ROOT / 'assets'} imgsz=32 save save_crop save_txt") run(f'yolo predict model={WEIGHTS_DIR / model}.pt source={ASSETS} imgsz=32 save save_crop save_txt')
@pytest.mark.parametrize('model,format', EXPORT_ARGS) @pytest.mark.parametrize('model,format', EXPORT_ARGS)
@ -56,11 +56,11 @@ def test_export(model, format):
def test_rtdetr(task='detect', model='yolov8n-rtdetr.yaml', data='coco8.yaml'): def test_rtdetr(task='detect', model='yolov8n-rtdetr.yaml', data='coco8.yaml'):
# Warning: MUST use imgsz=640 # Warning: MUST use imgsz=640
run(f'yolo train {task} model={model} data={data} imgsz=640 epochs=1 cache=disk') run(f'yolo train {task} model={model} data={data} imgsz=640 epochs=1 cache=disk')
run(f"yolo predict {task} model={model} source={ROOT / 'assets/bus.jpg'} imgsz=640 save save_crop save_txt") run(f"yolo predict {task} model={model} source={ASSETS / 'bus.jpg'} imgsz=640 save save_crop save_txt")
def test_fastsam(task='segment', model=WEIGHTS_DIR / 'FastSAM-s.pt', data='coco8-seg.yaml'): def test_fastsam(task='segment', model=WEIGHTS_DIR / 'FastSAM-s.pt', data='coco8-seg.yaml'):
source = ROOT / 'assets/bus.jpg' source = ASSETS / 'bus.jpg'
run(f'yolo segment val {task} model={model} data={data} imgsz=32') run(f'yolo segment val {task} model={model} data={data} imgsz=32')
run(f'yolo segment predict model={model} source={source} imgsz=32 save save_crop save_txt') run(f'yolo segment predict model={model} source={source} imgsz=32 save save_crop save_txt')
@ -98,7 +98,7 @@ def test_mobilesam():
model = SAM(WEIGHTS_DIR / 'mobile_sam.pt') model = SAM(WEIGHTS_DIR / 'mobile_sam.pt')
# Source # Source
source = ROOT / 'assets/zidane.jpg' source = ASSETS / 'zidane.jpg'
# Predict a segment based on a point prompt # Predict a segment based on a point prompt
model.predict(source, points=[900, 370], labels=[1]) model.predict(source, points=[900, 370], labels=[1])

@ -6,14 +6,13 @@ from ultralytics import YOLO
from ultralytics.cfg import get_cfg from ultralytics.cfg import get_cfg
from ultralytics.engine.exporter import Exporter from ultralytics.engine.exporter import Exporter
from ultralytics.models.yolo import classify, detect, segment from ultralytics.models.yolo import classify, detect, segment
from ultralytics.utils import DEFAULT_CFG, ROOT, SETTINGS from ultralytics.utils import ASSETS, DEFAULT_CFG, SETTINGS
CFG_DET = 'yolov8n.yaml' CFG_DET = 'yolov8n.yaml'
CFG_SEG = 'yolov8n-seg.yaml' CFG_SEG = 'yolov8n-seg.yaml'
CFG_CLS = 'yolov8n-cls.yaml' # or 'squeezenet1_0' CFG_CLS = 'yolov8n-cls.yaml' # or 'squeezenet1_0'
CFG = get_cfg(DEFAULT_CFG) CFG = get_cfg(DEFAULT_CFG)
MODEL = Path(SETTINGS['weights_dir']) / 'yolov8n' MODEL = Path(SETTINGS['weights_dir']) / 'yolov8n'
SOURCE = ROOT / 'assets'
def test_func(*args): # noqa def test_func(*args): # noqa
@ -25,7 +24,7 @@ def test_export():
exporter.add_callback('on_export_start', test_func) exporter.add_callback('on_export_start', test_func)
assert test_func in exporter.callbacks['on_export_start'], 'callback test failed' assert test_func in exporter.callbacks['on_export_start'], 'callback test failed'
f = exporter(model=YOLO(CFG_DET).model) f = exporter(model=YOLO(CFG_DET).model)
YOLO(f)(SOURCE) # exported model inference YOLO(f)(ASSETS) # exported model inference
def test_detect(): def test_detect():
@ -49,7 +48,7 @@ def test_detect():
pred = detect.DetectionPredictor(overrides={'imgsz': [64, 64]}) pred = detect.DetectionPredictor(overrides={'imgsz': [64, 64]})
pred.add_callback('on_predict_start', test_func) pred.add_callback('on_predict_start', test_func)
assert test_func in pred.callbacks['on_predict_start'], 'callback test failed' assert test_func in pred.callbacks['on_predict_start'], 'callback test failed'
result = pred(source=SOURCE, model=f'{MODEL}.pt') result = pred(source=ASSETS, model=f'{MODEL}.pt')
assert len(result), 'predictor test failed' assert len(result), 'predictor test failed'
overrides['resume'] = trainer.last overrides['resume'] = trainer.last
@ -85,7 +84,7 @@ def test_segment():
pred = segment.SegmentationPredictor(overrides={'imgsz': [64, 64]}) pred = segment.SegmentationPredictor(overrides={'imgsz': [64, 64]})
pred.add_callback('on_predict_start', test_func) pred.add_callback('on_predict_start', test_func)
assert test_func in pred.callbacks['on_predict_start'], 'callback test failed' assert test_func in pred.callbacks['on_predict_start'], 'callback test failed'
result = pred(source=SOURCE, model=f'{MODEL}-seg.pt') result = pred(source=ASSETS, model=f'{MODEL}-seg.pt')
assert len(result), 'predictor test failed' assert len(result), 'predictor test failed'
# Test resume # Test resume
@ -122,5 +121,5 @@ def test_classify():
pred = classify.ClassificationPredictor(overrides={'imgsz': [64, 64]}) pred = classify.ClassificationPredictor(overrides={'imgsz': [64, 64]})
pred.add_callback('on_predict_start', test_func) pred.add_callback('on_predict_start', test_func)
assert test_func in pred.callbacks['on_predict_start'], 'callback test failed' assert test_func in pred.callbacks['on_predict_start'], 'callback test failed'
result = pred(source=SOURCE, model=trainer.best) result = pred(source=ASSETS, model=trainer.best)
assert len(result), 'predictor test failed' assert len(result), 'predictor test failed'

@ -13,14 +13,14 @@ from torchvision.transforms import ToTensor
from ultralytics import RTDETR, YOLO from ultralytics import RTDETR, YOLO
from ultralytics.data.build import load_inference_source from ultralytics.data.build import load_inference_source
from ultralytics.utils import DEFAULT_CFG, LINUX, ONLINE, ROOT, SETTINGS from ultralytics.utils import ASSETS, DEFAULT_CFG, LINUX, ONLINE, ROOT, SETTINGS
from ultralytics.utils.downloads import download from ultralytics.utils.downloads import download
from ultralytics.utils.torch_utils import TORCH_1_9 from ultralytics.utils.torch_utils import TORCH_1_9
WEIGHTS_DIR = Path(SETTINGS['weights_dir']) WEIGHTS_DIR = Path(SETTINGS['weights_dir'])
MODEL = WEIGHTS_DIR / 'path with spaces' / 'yolov8n.pt' # test spaces in path MODEL = WEIGHTS_DIR / 'path with spaces' / 'yolov8n.pt' # test spaces in path
CFG = 'yolov8n.yaml' CFG = 'yolov8n.yaml'
SOURCE = ROOT / 'assets/bus.jpg' SOURCE = ASSETS / 'bus.jpg'
TMP = (ROOT / '../tests/tmp').resolve() # temp directory for test files TMP = (ROOT / '../tests/tmp').resolve() # temp directory for test files
@ -29,9 +29,14 @@ def test_model_forward():
model(SOURCE, imgsz=32, augment=True) model(SOURCE, imgsz=32, augment=True)
def test_model_info(): def test_model_methods():
model = YOLO(MODEL) model = YOLO(MODEL)
model.info(verbose=True) model.info(verbose=True, detailed=True)
model = model.reset_weights()
model = model.load(MODEL)
model.to('cpu')
_ = model.names
_ = model.device
def test_model_fuse(): def test_model_fuse():
@ -41,7 +46,7 @@ def test_model_fuse():
def test_predict_dir(): def test_predict_dir():
model = YOLO(MODEL) model = YOLO(MODEL)
model(source=ROOT / 'assets', imgsz=32) model(source=ASSETS, imgsz=32)
def test_predict_img(): def test_predict_img():
@ -102,11 +107,23 @@ def test_predict_grey_and_4ch():
def test_track_stream(): def test_track_stream():
# Test YouTube streaming inference (short 10 frame video) with non-default ByteTrack tracker # Test YouTube streaming inference (short 10 frame video) with non-default ByteTrack tracker
# imgsz=160 required for tracking for higher confidence and better matches # imgsz=160 required for tracking for higher confidence and better matches
import yaml
model = YOLO(MODEL) model = YOLO(MODEL)
model.predict('https://youtu.be/G17sBkb38XQ', imgsz=96) model.predict('https://youtu.be/G17sBkb38XQ', imgsz=96)
model.track('https://ultralytics.com/assets/decelera_portrait_min.mov', imgsz=160, tracker='bytetrack.yaml') model.track('https://ultralytics.com/assets/decelera_portrait_min.mov', imgsz=160, tracker='bytetrack.yaml')
model.track('https://ultralytics.com/assets/decelera_portrait_min.mov', imgsz=160, tracker='botsort.yaml') model.track('https://ultralytics.com/assets/decelera_portrait_min.mov', imgsz=160, tracker='botsort.yaml')
# Test Global Motion Compensation (GMC) methods
for gmc in 'orb', 'sift', 'ecc':
with open(ROOT / 'cfg/trackers/botsort.yaml') as f:
data = yaml.safe_load(f)
tracker = TMP / f'botsort-{gmc}.yaml'
data['gmc_method'] = gmc
with open(tracker, 'w') as f:
yaml.safe_dump(data, f)
model.track('https://ultralytics.com/assets/decelera_portrait_min.mov', imgsz=160, tracker=tracker)
def test_val(): def test_val():
model = YOLO(MODEL) model = YOLO(MODEL)
@ -133,7 +150,7 @@ def test_export_torchscript():
def test_export_onnx(): def test_export_onnx():
model = YOLO(MODEL) model = YOLO(MODEL)
f = model.export(format='onnx') f = model.export(format='onnx', dynamic=True)
YOLO(f)(SOURCE) # exported model inference YOLO(f)(SOURCE) # exported model inference
@ -173,6 +190,12 @@ def test_export_paddle(enabled=False):
model.export(format='paddle') model.export(format='paddle')
def test_export_ncnn(enabled=False):
model = YOLO(MODEL)
f = model.export(format='ncnn')
YOLO(f)(SOURCE) # exported model inference
def test_all_model_yamls(): def test_all_model_yamls():
for m in (ROOT / 'cfg' / 'models').rglob('*.yaml'): for m in (ROOT / 'cfg' / 'models').rglob('*.yaml'):
if 'rtdetr' in m.name: if 'rtdetr' in m.name:
@ -251,12 +274,13 @@ def test_data_utils():
@pytest.mark.skipif(not ONLINE, reason='environment is offline') @pytest.mark.skipif(not ONLINE, reason='environment is offline')
def test_data_converter(): def test_data_converter():
# Test dataset converters # Test dataset converters
from ultralytics.data.converter import convert_coco from ultralytics.data.converter import coco80_to_coco91_class, convert_coco
file = 'instances_val2017.json' file = 'instances_val2017.json'
download(f'https://github.com/ultralytics/yolov5/releases/download/v1.0/{file}') download(f'https://github.com/ultralytics/yolov5/releases/download/v1.0/{file}')
shutil.move(file, TMP) shutil.move(file, TMP)
convert_coco(labels_dir=TMP, use_segments=True, use_keypoints=False, cls91to80=True) convert_coco(labels_dir=TMP, use_segments=True, use_keypoints=False, cls91to80=True)
coco80_to_coco91_class()
def test_events(): def test_events():
@ -270,9 +294,64 @@ def test_events():
events(cfg) events(cfg)
def test_utils_init():
from ultralytics.utils import (get_git_branch, get_git_origin_url, get_ubuntu_version, is_github_actions_ci,
is_ubuntu)
is_ubuntu()
get_ubuntu_version()
is_github_actions_ci()
get_git_origin_url()
get_git_branch()
def test_utils_checks(): def test_utils_checks():
from ultralytics.utils.checks import check_yolov5u_filename, git_describe from ultralytics.utils.checks import check_requirements, check_yolov5u_filename, git_describe
check_yolov5u_filename('yolov5.pt') check_yolov5u_filename('yolov5n.pt')
# check_imshow(warn=True) # check_imshow(warn=True)
git_describe(ROOT) git_describe(ROOT)
check_requirements() # check requirements.txt
def test_utils_benchmarks():
from ultralytics.utils.benchmarks import ProfileModels
ProfileModels(['yolov8n.yaml'], imgsz=32, min_time=1, num_timed_runs=3, num_warmup_runs=1).profile()
def test_utils_torchutils():
from ultralytics.nn.modules.conv import Conv
from ultralytics.utils.torch_utils import get_flops_with_torch_profiler, profile, time_sync
x = torch.randn(1, 64, 20, 20)
m = Conv(64, 64, k=1, s=2)
profile(x, [m], n=3)
get_flops_with_torch_profiler(m)
time_sync()
def test_utils_downloads():
from ultralytics.utils.downloads import get_google_drive_file_info
get_google_drive_file_info('https://drive.google.com/file/d/1cqT-cJgANNrhIHCrEufUYhQ4RqiWG_lJ/view?usp=drive_link')
def test_utils_ops():
from ultralytics.utils.ops import make_divisible
make_divisible(17, 8)
def test_utils_files():
from ultralytics.utils.files import file_age, file_date, get_latest_run, spaces_in_path
file_age(SOURCE)
file_date(SOURCE)
get_latest_run(ROOT / 'runs')
path = TMP / 'path/with spaces'
path.mkdir(parents=True, exist_ok=True)
with spaces_in_path(path) as new_path:
print(new_path)

@ -9,7 +9,7 @@ from pathlib import Path
from types import SimpleNamespace from types import SimpleNamespace
from typing import Dict, List, Union from typing import Dict, List, Union
from ultralytics.utils import (DEFAULT_CFG, DEFAULT_CFG_DICT, DEFAULT_CFG_PATH, LOGGER, ROOT, SETTINGS, SETTINGS_YAML, from ultralytics.utils import (ASSETS, DEFAULT_CFG, DEFAULT_CFG_DICT, DEFAULT_CFG_PATH, LOGGER, SETTINGS, SETTINGS_YAML,
IterableSimpleNamespace, __version__, checks, colorstr, deprecation_warn, yaml_load, IterableSimpleNamespace, __version__, checks, colorstr, deprecation_warn, yaml_load,
yaml_print) yaml_print)
@ -415,8 +415,7 @@ def entrypoint(debug=''):
# Mode # Mode
if mode in ('predict', 'track') and 'source' not in overrides: if mode in ('predict', 'track') and 'source' not in overrides:
overrides['source'] = DEFAULT_CFG.source or ROOT / 'assets' if (ROOT / 'assets').exists() \ overrides['source'] = DEFAULT_CFG.source or ASSETS
else 'https://ultralytics.com/images/bus.jpg'
LOGGER.warning(f"WARNING ⚠️ 'source' is missing. Using default 'source={overrides['source']}'.") LOGGER.warning(f"WARNING ⚠️ 'source' is missing. Using default 'source={overrides['source']}'.")
elif mode in ('train', 'val'): elif mode in ('train', 'val'):
if 'data' not in overrides: if 'data' not in overrides:

@ -11,7 +11,7 @@ match_thresh: 0.8 # threshold for matching tracks
# mot20: False # for tracker evaluation(not used for now) # mot20: False # for tracker evaluation(not used for now)
# BoT-SORT settings # BoT-SORT settings
cmc_method: sparseOptFlow # method of global motion compensation gmc_method: sparseOptFlow # method of global motion compensation
# ReID model related thresh (not supported yet) # ReID model related thresh (not supported yet)
proximity_thresh: 0.5 proximity_thresh: 0.5
appearance_thresh: 0.25 appearance_thresh: 0.25

@ -1,6 +1,7 @@
# Ultralytics YOLO 🚀, AGPL-3.0 license # Ultralytics YOLO 🚀, AGPL-3.0 license
import json import json
import shutil
from collections import defaultdict from collections import defaultdict
from pathlib import Path from pathlib import Path
@ -9,7 +10,6 @@ import numpy as np
from tqdm import tqdm from tqdm import tqdm
from ultralytics.utils.checks import check_requirements from ultralytics.utils.checks import check_requirements
from ultralytics.utils.files import make_dirs
def coco91_to_coco80_class(): def coco91_to_coco80_class():
@ -27,6 +27,27 @@ def coco91_to_coco80_class():
None, 73, 74, 75, 76, 77, 78, 79, None] None, 73, 74, 75, 76, 77, 78, 79, None]
def coco80_to_coco91_class(): #
"""
Converts 80-index (val2014) to 91-index (paper).
For details see https://tech.amikelive.com/node-718/what-object-categories-labels-are-in-coco-dataset/.
Example:
```python
import numpy as np
a = np.loadtxt('data/coco.names', dtype='str', delimiter='\n')
b = np.loadtxt('data/coco_paper.names', dtype='str', delimiter='\n')
x1 = [list(a[i] == b).index(True) + 1 for i in range(80)] # darknet to coco
x2 = [list(b[i] == a).index(True) if any(b[i] == a) else None for i in range(91)] # coco to darknet
```
"""
return [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 67, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90]
def convert_coco(labels_dir='../coco/annotations/', use_segments=False, use_keypoints=False, cls91to80=True): def convert_coco(labels_dir='../coco/annotations/', use_segments=False, use_keypoints=False, cls91to80=True):
"""Converts COCO dataset annotations to a format suitable for training YOLOv5 models. """Converts COCO dataset annotations to a format suitable for training YOLOv5 models.
@ -47,7 +68,14 @@ def convert_coco(labels_dir='../coco/annotations/', use_segments=False, use_keyp
Generates output files in the specified output directory. Generates output files in the specified output directory.
""" """
save_dir = make_dirs('yolo_labels') # output directory # Create dataset directory
save_dir = Path('yolo_labels')
if save_dir.exists():
shutil.rmtree(save_dir) # delete dir
for p in save_dir / 'labels', save_dir / 'images':
p.mkdir(parents=True, exist_ok=True) # make dir
# Convert classes
coco80 = coco91_to_coco80_class() coco80 = coco91_to_coco80_class()
# Import json # Import json

@ -16,7 +16,7 @@ import torch
from PIL import Image from PIL import Image
from ultralytics.data.utils import IMG_FORMATS, VID_FORMATS from ultralytics.data.utils import IMG_FORMATS, VID_FORMATS
from ultralytics.utils import LOGGER, ROOT, is_colab, is_kaggle, ops from ultralytics.utils import ASSETS, LOGGER, is_colab, is_kaggle, ops
from ultralytics.utils.checks import check_requirements from ultralytics.utils.checks import check_requirements
@ -403,7 +403,7 @@ def get_best_youtube_url(url, use_pafy=False):
if __name__ == '__main__': if __name__ == '__main__':
img = cv2.imread(str(ROOT / 'assets/bus.jpg')) img = cv2.imread(str(ASSETS / 'bus.jpg'))
dataset = LoadPilAndNumpy(im0=img) dataset = LoadPilAndNumpy(im0=img)
for d in dataset: for d in dataset:
print(d[0]) print(d[0])

@ -9,8 +9,8 @@ from ultralytics.cfg import get_cfg
from ultralytics.engine.exporter import Exporter from ultralytics.engine.exporter import Exporter
from ultralytics.hub.utils import HUB_WEB_ROOT from ultralytics.hub.utils import HUB_WEB_ROOT
from ultralytics.nn.tasks import attempt_load_one_weight, guess_model_task, nn, yaml_model_load from ultralytics.nn.tasks import attempt_load_one_weight, guess_model_task, nn, yaml_model_load
from ultralytics.utils import (DEFAULT_CFG, DEFAULT_CFG_DICT, DEFAULT_CFG_KEYS, LOGGER, RANK, ROOT, callbacks, emojis, from ultralytics.utils import (ASSETS, DEFAULT_CFG, DEFAULT_CFG_DICT, DEFAULT_CFG_KEYS, LOGGER, RANK, callbacks, emojis,
is_git_dir, yaml_load) yaml_load)
from ultralytics.utils.checks import check_file, check_imgsz, check_pip_update_available, check_yaml from ultralytics.utils.checks import check_file, check_imgsz, check_pip_update_available, check_yaml
from ultralytics.utils.downloads import GITHUB_ASSET_STEMS from ultralytics.utils.downloads import GITHUB_ASSET_STEMS
from ultralytics.utils.torch_utils import smart_inference_mode from ultralytics.utils.torch_utils import smart_inference_mode
@ -218,7 +218,7 @@ class Model:
(List[ultralytics.engine.results.Results]): The prediction results. (List[ultralytics.engine.results.Results]): The prediction results.
""" """
if source is None: if source is None:
source = ROOT / 'assets' if is_git_dir() else 'https://ultralytics.com/images/bus.jpg' source = ASSETS
LOGGER.warning(f"WARNING ⚠️ 'source' is missing. Using 'source={source}'.") LOGGER.warning(f"WARNING ⚠️ 'source' is missing. Using 'source={source}'.")
is_cli = (sys.argv[0].endswith('yolo') or sys.argv[0].endswith('ultralytics')) and any( is_cli = (sys.argv[0].endswith('yolo') or sys.argv[0].endswith('ultralytics')) and any(
x in sys.argv for x in ('predict', 'track', 'mode=predict', 'mode=track')) x in sys.argv for x in ('predict', 'track', 'mode=predict', 'mode=track'))
@ -390,6 +390,7 @@ class Model:
""" """
self._check_is_pytorch_model() self._check_is_pytorch_model()
self.model.to(device) self.model.to(device)
return self
def tune(self, *args, **kwargs): def tune(self, *args, **kwargs):
""" """

@ -47,7 +47,7 @@ STREAM_WARNING = """
WARNING stream/video/webcam/dir predict source will accumulate results in RAM unless `stream=True` is passed, WARNING stream/video/webcam/dir predict source will accumulate results in RAM unless `stream=True` is passed,
causing potential out-of-memory errors for large sources or long-running streams/videos. causing potential out-of-memory errors for large sources or long-running streams/videos.
Usage: Example:
results = model(source=..., stream=True) # generator of Results objects results = model(source=..., stream=True) # generator of Results objects
for r in results: for r in results:
boxes = r.boxes # Boxes object for bbox outputs boxes = r.boxes # Boxes object for bbox outputs

@ -59,7 +59,7 @@ class RTDETRTrainer(DetectionTrainer):
def train(cfg=DEFAULT_CFG, use_python=False): def train(cfg=DEFAULT_CFG, use_python=False):
"""Train and optimize RTDETR model given training data and device.""" """Train and optimize RTDETR model given training data and device."""
model = 'rtdetr-l.yaml' model = 'rtdetr-l.yaml'
data = cfg.data or 'coco128.yaml' # or yolo.ClassificationDataset("mnist") data = cfg.data or 'coco8.yaml' # or yolo.ClassificationDataset("mnist")
device = cfg.device if cfg.device is not None else '' device = cfg.device if cfg.device is not None else ''
# NOTE: F.grid_sample which is in rt-detr does not support deterministic=True # NOTE: F.grid_sample which is in rt-detr does not support deterministic=True

@ -4,7 +4,7 @@ import torch
from ultralytics.engine.predictor import BasePredictor from ultralytics.engine.predictor import BasePredictor
from ultralytics.engine.results import Results from ultralytics.engine.results import Results
from ultralytics.utils import DEFAULT_CFG, ROOT from ultralytics.utils import ASSETS, DEFAULT_CFG
class ClassificationPredictor(BasePredictor): class ClassificationPredictor(BasePredictor):
@ -35,8 +35,7 @@ class ClassificationPredictor(BasePredictor):
def predict(cfg=DEFAULT_CFG, use_python=False): def predict(cfg=DEFAULT_CFG, use_python=False):
"""Run YOLO model predictions on input images/videos.""" """Run YOLO model predictions on input images/videos."""
model = cfg.model or 'yolov8n-cls.pt' # or "resnet18" model = cfg.model or 'yolov8n-cls.pt' # or "resnet18"
source = cfg.source if cfg.source is not None else ROOT / 'assets' if (ROOT / 'assets').exists() \ source = cfg.source or ASSETS
else 'https://ultralytics.com/images/bus.jpg'
args = dict(model=model, source=source) args = dict(model=model, source=source)
if use_python: if use_python:

@ -4,7 +4,7 @@ import torch
from ultralytics.engine.predictor import BasePredictor from ultralytics.engine.predictor import BasePredictor
from ultralytics.engine.results import Results from ultralytics.engine.results import Results
from ultralytics.utils import DEFAULT_CFG, ROOT, ops from ultralytics.utils import ASSETS, DEFAULT_CFG, ops
class DetectionPredictor(BasePredictor): class DetectionPredictor(BasePredictor):
@ -32,8 +32,7 @@ class DetectionPredictor(BasePredictor):
def predict(cfg=DEFAULT_CFG, use_python=False): def predict(cfg=DEFAULT_CFG, use_python=False):
"""Runs YOLO model inference on input image(s).""" """Runs YOLO model inference on input image(s)."""
model = cfg.model or 'yolov8n.pt' model = cfg.model or 'yolov8n.pt'
source = cfg.source if cfg.source is not None else ROOT / 'assets' if (ROOT / 'assets').exists() \ source = cfg.source or ASSETS
else 'https://ultralytics.com/images/bus.jpg'
args = dict(model=model, source=source) args = dict(model=model, source=source)
if use_python: if use_python:

@ -107,7 +107,7 @@ class DetectionTrainer(BaseTrainer):
def train(cfg=DEFAULT_CFG, use_python=False): def train(cfg=DEFAULT_CFG, use_python=False):
"""Train and optimize YOLO model given training data and device.""" """Train and optimize YOLO model given training data and device."""
model = cfg.model or 'yolov8n.pt' model = cfg.model or 'yolov8n.pt'
data = cfg.data or 'coco128.yaml' # or yolo.ClassificationDataset("mnist") data = cfg.data or 'coco8.yaml' # or yolo.ClassificationDataset("mnist")
device = cfg.device if cfg.device is not None else '' device = cfg.device if cfg.device is not None else ''
args = dict(model=model, data=data, device=device) args = dict(model=model, data=data, device=device)

@ -6,7 +6,7 @@ from pathlib import Path
import numpy as np import numpy as np
import torch import torch
from ultralytics.data import build_dataloader, build_yolo_dataset from ultralytics.data import build_dataloader, build_yolo_dataset, converter
from ultralytics.engine.validator import BaseValidator from ultralytics.engine.validator import BaseValidator
from ultralytics.utils import DEFAULT_CFG, LOGGER, ops from ultralytics.utils import DEFAULT_CFG, LOGGER, ops
from ultralytics.utils.checks import check_requirements from ultralytics.utils.checks import check_requirements
@ -50,7 +50,7 @@ class DetectionValidator(BaseValidator):
"""Initialize evaluation metrics for YOLO.""" """Initialize evaluation metrics for YOLO."""
val = self.data.get(self.args.split, '') # validation path val = self.data.get(self.args.split, '') # validation path
self.is_coco = isinstance(val, str) and 'coco' in val and val.endswith(f'{os.sep}val2017.txt') # is COCO self.is_coco = isinstance(val, str) and 'coco' in val and val.endswith(f'{os.sep}val2017.txt') # is COCO
self.class_map = ops.coco80_to_coco91_class() if self.is_coco else list(range(1000)) self.class_map = converter.coco80_to_coco91_class() if self.is_coco else list(range(1000))
self.args.save_json |= self.is_coco and not self.training # run on final val if training COCO self.args.save_json |= self.is_coco and not self.training # run on final val if training COCO
self.names = model.names self.names = model.names
self.nc = len(model.names) self.nc = len(model.names)
@ -259,7 +259,7 @@ class DetectionValidator(BaseValidator):
def val(cfg=DEFAULT_CFG, use_python=False): def val(cfg=DEFAULT_CFG, use_python=False):
"""Validate trained YOLO model on validation dataset.""" """Validate trained YOLO model on validation dataset."""
model = cfg.model or 'yolov8n.pt' model = cfg.model or 'yolov8n.pt'
data = cfg.data or 'coco128.yaml' data = cfg.data or 'coco8.yaml'
args = dict(model=model, data=data) args = dict(model=model, data=data)
if use_python: if use_python:

@ -2,7 +2,7 @@
from ultralytics.engine.results import Results from ultralytics.engine.results import Results
from ultralytics.models.yolo.detect.predict import DetectionPredictor from ultralytics.models.yolo.detect.predict import DetectionPredictor
from ultralytics.utils import DEFAULT_CFG, LOGGER, ROOT, ops from ultralytics.utils import ASSETS, DEFAULT_CFG, LOGGER, ops
class PosePredictor(DetectionPredictor): class PosePredictor(DetectionPredictor):
@ -45,8 +45,7 @@ class PosePredictor(DetectionPredictor):
def predict(cfg=DEFAULT_CFG, use_python=False): def predict(cfg=DEFAULT_CFG, use_python=False):
"""Runs YOLO to predict objects in an image or video.""" """Runs YOLO to predict objects in an image or video."""
model = cfg.model or 'yolov8n-pose.pt' model = cfg.model or 'yolov8n-pose.pt'
source = cfg.source if cfg.source is not None else ROOT / 'assets' if (ROOT / 'assets').exists() \ source = cfg.source or ASSETS
else 'https://ultralytics.com/images/bus.jpg'
args = dict(model=model, source=source) args = dict(model=model, source=source)
if use_python: if use_python:

@ -4,7 +4,7 @@ import torch
from ultralytics.engine.results import Results from ultralytics.engine.results import Results
from ultralytics.models.yolo.detect.predict import DetectionPredictor from ultralytics.models.yolo.detect.predict import DetectionPredictor
from ultralytics.utils import DEFAULT_CFG, ROOT, ops from ultralytics.utils import ASSETS, DEFAULT_CFG, ops
class SegmentationPredictor(DetectionPredictor): class SegmentationPredictor(DetectionPredictor):
@ -47,8 +47,7 @@ class SegmentationPredictor(DetectionPredictor):
def predict(cfg=DEFAULT_CFG, use_python=False): def predict(cfg=DEFAULT_CFG, use_python=False):
"""Runs YOLO object detection on an image or video source.""" """Runs YOLO object detection on an image or video source."""
model = cfg.model or 'yolov8n-seg.pt' model = cfg.model or 'yolov8n-seg.pt'
source = cfg.source if cfg.source is not None else ROOT / 'assets' if (ROOT / 'assets').exists() \ source = cfg.source or ASSETS
else 'https://ultralytics.com/images/bus.jpg'
args = dict(model=model, source=source) args = dict(model=model, source=source)
if use_python: if use_python:

@ -49,7 +49,7 @@ class SegmentationTrainer(yolo.detect.DetectionTrainer):
def train(cfg=DEFAULT_CFG, use_python=False): def train(cfg=DEFAULT_CFG, use_python=False):
"""Train a YOLO segmentation model based on passed arguments.""" """Train a YOLO segmentation model based on passed arguments."""
model = cfg.model or 'yolov8n-seg.pt' model = cfg.model or 'yolov8n-seg.pt'
data = cfg.data or 'coco128-seg.yaml' # or yolo.ClassificationDataset("mnist") data = cfg.data or 'coco8-seg.yaml'
device = cfg.device if cfg.device is not None else '' device = cfg.device if cfg.device is not None else ''
args = dict(model=model, data=data, device=device) args = dict(model=model, data=data, device=device)

@ -236,7 +236,7 @@ class SegmentationValidator(DetectionValidator):
def val(cfg=DEFAULT_CFG, use_python=False): def val(cfg=DEFAULT_CFG, use_python=False):
"""Validate trained YOLO model on validation data.""" """Validate trained YOLO model on validation data."""
model = cfg.model or 'yolov8n-seg.pt' model = cfg.model or 'yolov8n-seg.pt'
data = cfg.data or 'coco128-seg.yaml' data = cfg.data or 'coco8-seg.yaml'
args = dict(model=model, data=data) args = dict(model=model, data=data)
if use_python: if use_python:

@ -303,13 +303,6 @@ class SegmentationModel(DetectionModel):
def init_criterion(self): def init_criterion(self):
return v8SegmentationLoss(self) return v8SegmentationLoss(self)
def _predict_augment(self, x):
"""Perform augmentations on input image x and return augmented inference."""
LOGGER.warning(
f'WARNING ⚠️ {self.__class__.__name__} has not supported augment inference yet! Now using single-scale inference instead.'
)
return self._predict_once(x)
class PoseModel(DetectionModel): class PoseModel(DetectionModel):
"""YOLOv8 pose model.""" """YOLOv8 pose model."""
@ -326,13 +319,6 @@ class PoseModel(DetectionModel):
def init_criterion(self): def init_criterion(self):
return v8PoseLoss(self) return v8PoseLoss(self)
def _predict_augment(self, x):
"""Perform augmentations on input image x and return augmented inference."""
LOGGER.warning(
f'WARNING ⚠️ {self.__class__.__name__} has not supported augment inference yet! Now using single-scale inference instead.'
)
return self._predict_once(x)
class ClassificationModel(BaseModel): class ClassificationModel(BaseModel):
"""YOLOv8 classification model.""" """YOLOv8 classification model."""

@ -110,8 +110,7 @@ class BOTSORT(BYTETracker):
if args.with_reid: if args.with_reid:
# Haven't supported BoT-SORT(reid) yet # Haven't supported BoT-SORT(reid) yet
self.encoder = None self.encoder = None
# self.gmc = GMC(method=args.cmc_method, verbose=[args.name, args.ablation]) self.gmc = GMC(method=args.gmc_method)
self.gmc = GMC(method=args.cmc_method)
def get_kalmanfilter(self): def get_kalmanfilter(self):
"""Returns an instance of KalmanFilterXYWH for object tracking.""" """Returns an instance of KalmanFilterXYWH for object tracking."""

@ -10,7 +10,7 @@ from ultralytics.utils import LOGGER
class GMC: class GMC:
def __init__(self, method='sparseOptFlow', downscale=2, verbose=None): def __init__(self, method='sparseOptFlow', downscale=2):
"""Initialize a video tracker with specified parameters.""" """Initialize a video tracker with specified parameters."""
super().__init__() super().__init__()
@ -40,28 +40,11 @@ class GMC:
blockSize=3, blockSize=3,
useHarrisDetector=False, useHarrisDetector=False,
k=0.04) k=0.04)
# self.gmc_file = open('GMC_results.txt', 'w')
elif self.method in ['none', 'None', None]:
elif self.method in ['file', 'files']: self.method = None
seqName = verbose[0]
ablation = verbose[1]
if ablation:
filePath = r'tracker/GMC_files/MOT17_ablation'
else:
filePath = r'tracker/GMC_files/MOTChallenge'
if '-FRCNN' in seqName:
seqName = seqName[:-6]
elif '-DPM' in seqName or '-SDP' in seqName:
seqName = seqName[:-4]
self.gmcFile = open(f'{filePath}/GMC-{seqName}.txt')
if self.gmcFile is None:
raise ValueError(f'Error: Unable to open GMC file in directory:{filePath}')
elif self.method in ['none', 'None']:
self.method = 'none'
else: else:
raise ValueError(f'Error: Unknown CMC method:{method}') raise ValueError(f'Error: Unknown GMC method:{method}')
self.prevFrame = None self.prevFrame = None
self.prevKeyPoints = None self.prevKeyPoints = None
@ -77,10 +60,6 @@ class GMC:
return self.applyEcc(raw_frame, detections) return self.applyEcc(raw_frame, detections)
elif self.method == 'sparseOptFlow': elif self.method == 'sparseOptFlow':
return self.applySparseOptFlow(raw_frame, detections) return self.applySparseOptFlow(raw_frame, detections)
elif self.method == 'file':
return self.applyFile(raw_frame, detections)
elif self.method == 'none':
return np.eye(2, 3)
else: else:
return np.eye(2, 3) return np.eye(2, 3)
@ -244,7 +223,6 @@ class GMC:
def applySparseOptFlow(self, raw_frame, detections=None): def applySparseOptFlow(self, raw_frame, detections=None):
"""Initialize.""" """Initialize."""
# t0 = time.time()
height, width, _ = raw_frame.shape height, width, _ = raw_frame.shape
frame = cv2.cvtColor(raw_frame, cv2.COLOR_BGR2GRAY) frame = cv2.cvtColor(raw_frame, cv2.COLOR_BGR2GRAY)
H = np.eye(2, 3) H = np.eye(2, 3)
@ -298,22 +276,4 @@ class GMC:
self.prevFrame = frame.copy() self.prevFrame = frame.copy()
self.prevKeyPoints = copy.copy(keypoints) self.prevKeyPoints = copy.copy(keypoints)
# gmc_line = str(1000 * (time.time() - t0)) + "\t" + str(H[0, 0]) + "\t" + str(H[0, 1]) + "\t" + str(
# H[0, 2]) + "\t" + str(H[1, 0]) + "\t" + str(H[1, 1]) + "\t" + str(H[1, 2]) + "\n"
# self.gmc_file.write(gmc_line)
return H
def applyFile(self, raw_frame, detections=None):
"""Return the homography matrix based on the GCPs in the next line of the input GMC file."""
line = self.gmcFile.readline()
tokens = line.split('\t')
H = np.eye(2, 3, dtype=np.float_)
H[0, 0] = float(tokens[1])
H[0, 1] = float(tokens[2])
H[0, 2] = float(tokens[3])
H[1, 0] = float(tokens[4])
H[1, 1] = float(tokens[5])
H[1, 2] = float(tokens[6])
return H return H

@ -30,6 +30,7 @@ LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable
# Other Constants # Other Constants
FILE = Path(__file__).resolve() FILE = Path(__file__).resolve()
ROOT = FILE.parents[1] # YOLO ROOT = FILE.parents[1] # YOLO
ASSETS = ROOT / 'assets' # default images
DEFAULT_CFG_PATH = ROOT / 'cfg/default.yaml' DEFAULT_CFG_PATH = ROOT / 'cfg/default.yaml'
NUM_THREADS = min(8, max(1, os.cpu_count() - 1)) # number of YOLOv5 multiprocessing threads NUM_THREADS = min(8, max(1, os.cpu_count() - 1)) # number of YOLOv5 multiprocessing threads
AUTOINSTALL = str(os.getenv('YOLO_AUTOINSTALL', True)).lower() == 'true' # global auto-install mode AUTOINSTALL = str(os.getenv('YOLO_AUTOINSTALL', True)).lower() == 'true' # global auto-install mode
@ -260,11 +261,15 @@ class ThreadingLocked:
Attributes: Attributes:
lock (threading.Lock): A lock object used to manage access to the decorated function. lock (threading.Lock): A lock object used to manage access to the decorated function.
Usage: Example:
```python
from ultralytics.utils import ThreadingLocked
@ThreadingLocked() @ThreadingLocked()
def my_function(): def my_function():
# Your code here # Your code here
pass pass
```
""" """
def __init__(self): def __init__(self):
@ -518,7 +523,6 @@ def get_git_dir():
for d in Path(__file__).parents: for d in Path(__file__).parents:
if (d / '.git').is_dir(): if (d / '.git').is_dir():
return d return d
return None # no .git dir found
def get_git_origin_url(): def get_git_origin_url():
@ -526,13 +530,12 @@ def get_git_origin_url():
Retrieves the origin URL of a git repository. Retrieves the origin URL of a git repository.
Returns: Returns:
(str | None): The origin URL of the git repository. (str | None): The origin URL of the git repository or None if not git directory.
""" """
if is_git_dir(): if is_git_dir():
with contextlib.suppress(subprocess.CalledProcessError): with contextlib.suppress(subprocess.CalledProcessError):
origin = subprocess.check_output(['git', 'config', '--get', 'remote.origin.url']) origin = subprocess.check_output(['git', 'config', '--get', 'remote.origin.url'])
return origin.decode().strip() return origin.decode().strip()
return None # if not git dir or on error
def get_git_branch(): def get_git_branch():
@ -540,13 +543,12 @@ def get_git_branch():
Returns the current git branch name. If not in a git repository, returns None. Returns the current git branch name. If not in a git repository, returns None.
Returns: Returns:
(str | None): The current git branch name. (str | None): The current git branch name or None if not a git directory.
""" """
if is_git_dir(): if is_git_dir():
with contextlib.suppress(subprocess.CalledProcessError): with contextlib.suppress(subprocess.CalledProcessError):
origin = subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD']) origin = subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD'])
return origin.decode().strip() return origin.decode().strip()
return None # if not git dir or on error
def get_default_args(func): def get_default_args(func):
@ -572,7 +574,6 @@ def get_ubuntu_version():
with contextlib.suppress(FileNotFoundError, AttributeError): with contextlib.suppress(FileNotFoundError, AttributeError):
with open('/etc/os-release') as f: with open('/etc/os-release') as f:
return re.search(r'VERSION_ID="(\d+\.\d+)"', f.read())[1] return re.search(r'VERSION_ID="(\d+\.\d+)"', f.read())[1]
return None
def get_user_config_dir(sub_dir='Ultralytics'): def get_user_config_dir(sub_dir='Ultralytics'):

@ -37,9 +37,8 @@ from tqdm import tqdm
from ultralytics import YOLO from ultralytics import YOLO
from ultralytics.cfg import TASK2DATA, TASK2METRIC from ultralytics.cfg import TASK2DATA, TASK2METRIC
from ultralytics.engine.exporter import export_formats from ultralytics.engine.exporter import export_formats
from ultralytics.utils import LINUX, LOGGER, MACOS, ROOT, SETTINGS from ultralytics.utils import ASSETS, LINUX, LOGGER, MACOS, SETTINGS
from ultralytics.utils.checks import check_requirements, check_yolo from ultralytics.utils.checks import check_requirements, check_yolo
from ultralytics.utils.downloads import download
from ultralytics.utils.files import file_size from ultralytics.utils.files import file_size
from ultralytics.utils.torch_utils import select_device from ultralytics.utils.torch_utils import select_device
@ -68,6 +67,13 @@ def benchmark(model=Path(SETTINGS['weights_dir']) / 'yolov8n.pt',
Returns: Returns:
df (pandas.DataFrame): A pandas DataFrame with benchmark results for each format, including file size, df (pandas.DataFrame): A pandas DataFrame with benchmark results for each format, including file size,
metric, and inference time. metric, and inference time.
Example:
```python
from ultralytics.utils.benchmarks import benchmark
benchmark(model='yolov8n.pt', imgsz=640)
```
""" """
import pandas as pd import pandas as pd
@ -106,9 +112,7 @@ def benchmark(model=Path(SETTINGS['weights_dir']) / 'yolov8n.pt',
assert model.task != 'pose' or i != 7, 'GraphDef Pose inference is not supported' assert model.task != 'pose' or i != 7, 'GraphDef Pose inference is not supported'
assert i not in (9, 10), 'inference not supported' # Edge TPU and TF.js are unsupported assert i not in (9, 10), 'inference not supported' # Edge TPU and TF.js are unsupported
assert i != 5 or platform.system() == 'Darwin', 'inference only supported on macOS>=10.13' # CoreML assert i != 5 or platform.system() == 'Darwin', 'inference only supported on macOS>=10.13' # CoreML
if not (ROOT / 'assets/bus.jpg').exists(): export.predict(ASSETS / 'bus.jpg', imgsz=imgsz, device=device, half=half)
download(url='https://ultralytics.com/images/bus.jpg', dir=ROOT / 'assets')
export.predict(ROOT / 'assets/bus.jpg', imgsz=imgsz, device=device, half=half)
# Validate # Validate
data = data or TASK2DATA[model.task] # task to dataset, i.e. coco8.yaml for task=detect data = data or TASK2DATA[model.task] # task to dataset, i.e. coco8.yaml for task=detect
@ -163,6 +167,13 @@ class ProfileModels:
Methods: Methods:
profile(): Profiles the models and prints the result. profile(): Profiles the models and prints the result.
Example:
```python
from ultralytics.utils.benchmarks import ProfileModels
ProfileModels(['yolov8n.yaml', 'yolov8s.yaml'], imgsz=640).profile()
```
""" """
def __init__(self, def __init__(self,
@ -353,11 +364,3 @@ class ProfileModels:
print(separator) print(separator)
for row in table_rows: for row in table_rows:
print(row) print(row)
if __name__ == '__main__':
# Benchmark all export formats
benchmark()
# Profiling models on ONNX and TensorRT
ProfileModels(['yolov8n.yaml', 'yolov8s.yaml'])

@ -20,7 +20,7 @@ import requests
import torch import torch
from matplotlib import font_manager from matplotlib import font_manager
from ultralytics.utils import (AUTOINSTALL, LOGGER, ONLINE, ROOT, USER_CONFIG_DIR, ThreadingLocked, TryExcept, from ultralytics.utils import (ASSETS, AUTOINSTALL, LOGGER, ONLINE, ROOT, USER_CONFIG_DIR, ThreadingLocked, TryExcept,
clean_url, colorstr, downloads, emojis, is_colab, is_docker, is_jupyter, is_kaggle, clean_url, colorstr, downloads, emojis, is_colab, is_docker, is_jupyter, is_kaggle,
is_online, is_pip_package, url2file) is_online, is_pip_package, url2file)
@ -460,8 +460,7 @@ def check_amp(model):
del m del m
return a.shape == b.shape and torch.allclose(a, b.float(), atol=0.5) # close to 0.5 absolute tolerance return a.shape == b.shape and torch.allclose(a, b.float(), atol=0.5) # close to 0.5 absolute tolerance
f = ROOT / 'assets/bus.jpg' # image to check im = ASSETS / 'bus.jpg' # image to check
im = f if f.exists() else 'https://ultralytics.com/images/bus.jpg' if ONLINE else np.ones((640, 640, 3))
prefix = colorstr('AMP: ') prefix = colorstr('AMP: ')
LOGGER.info(f'{prefix}running Automatic Mixed Precision (AMP) checks with YOLOv8n...') LOGGER.info(f'{prefix}running Automatic Mixed Precision (AMP) checks with YOLOv8n...')
warning_msg = "Setting 'amp=True'. If you experience zero-mAP or NaN losses you can disable AMP with amp=False." warning_msg = "Setting 'amp=True'. If you experience zero-mAP or NaN losses you can disable AMP with amp=False."
@ -484,11 +483,9 @@ def check_amp(model):
def git_describe(path=ROOT): # path must be a directory def git_describe(path=ROOT): # path must be a directory
"""Return human-readable git description, i.e. v5.0-5-g3e25f1e https://git-scm.com/docs/git-describe.""" """Return human-readable git description, i.e. v5.0-5-g3e25f1e https://git-scm.com/docs/git-describe."""
try: with contextlib.suppress(Exception):
assert (Path(path) / '.git').is_dir()
return subprocess.check_output(f'git -C {path} describe --tags --long --always', shell=True).decode()[:-1] return subprocess.check_output(f'git -C {path} describe --tags --long --always', shell=True).decode()[:-1]
except AssertionError: return ''
return ''
def print_args(args: Optional[dict] = None, show_file=True, show_func=False): def print_args(args: Optional[dict] = None, show_file=True, show_func=False):

@ -42,6 +42,8 @@ def spaces_in_path(path):
Example: Example:
```python ```python
with ultralytics.utils.files import spaces_in_path
with spaces_in_path('/path/with spaces') as new_path: with spaces_in_path('/path/with spaces') as new_path:
# your code here # your code here
``` ```
@ -143,13 +145,3 @@ def get_latest_run(search_dir='.'):
"""Return path to most recent 'last.pt' in /runs (i.e. to --resume from).""" """Return path to most recent 'last.pt' in /runs (i.e. to --resume from)."""
last_list = glob.glob(f'{search_dir}/**/last*.pt', recursive=True) last_list = glob.glob(f'{search_dir}/**/last*.pt', recursive=True)
return max(last_list, key=os.path.getctime) if last_list else '' return max(last_list, key=os.path.getctime) if last_list else ''
def make_dirs(dir='new_dir/'):
"""Create directories."""
dir = Path(dir)
if dir.exists():
shutil.rmtree(dir) # delete dir
for p in dir, dir / 'labels', dir / 'images':
p.mkdir(parents=True, exist_ok=True) # make dir
return dir

@ -55,27 +55,6 @@ class Profile(contextlib.ContextDecorator):
return time.time() return time.time()
def coco80_to_coco91_class(): #
"""
Converts 80-index (val2014) to 91-index (paper).
For details see https://tech.amikelive.com/node-718/what-object-categories-labels-are-in-coco-dataset/.
Example:
```python
import numpy as np
a = np.loadtxt('data/coco.names', dtype='str', delimiter='\n')
b = np.loadtxt('data/coco_paper.names', dtype='str', delimiter='\n')
x1 = [list(a[i] == b).index(True) + 1 for i in range(80)] # darknet to coco
x2 = [list(b[i] == a).index(True) if any(b[i] == a) else None for i in range(91)] # coco to darknet
```
"""
return [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 67, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90]
def segment2box(segment, width=640, height=640): def segment2box(segment, width=640, height=640):
""" """
Convert 1 segment label to 1 box label, applying inside-image constraint, i.e. (xy1, xy2, ...) to (xyxy) Convert 1 segment label to 1 box label, applying inside-image constraint, i.e. (xy1, xy2, ...) to (xyxy)

@ -239,16 +239,18 @@ def get_flops(model, imgsz=640):
def get_flops_with_torch_profiler(model, imgsz=640): def get_flops_with_torch_profiler(model, imgsz=640):
"""Compute model FLOPs (thop alternative).""" """Compute model FLOPs (thop alternative)."""
model = de_parallel(model) if TORCH_2_0:
p = next(model.parameters()) model = de_parallel(model)
stride = (max(int(model.stride.max()), 32) if hasattr(model, 'stride') else 32) * 2 # max stride p = next(model.parameters())
im = torch.zeros((1, p.shape[1], stride, stride), device=p.device) # input image in BCHW format stride = (max(int(model.stride.max()), 32) if hasattr(model, 'stride') else 32) * 2 # max stride
with torch.profiler.profile(with_flops=True) as prof: im = torch.zeros((1, p.shape[1], stride, stride), device=p.device) # input image in BCHW format
model(im) with torch.profiler.profile(with_flops=True) as prof:
flops = sum(x.flops for x in prof.key_averages()) / 1E9 model(im)
imgsz = imgsz if isinstance(imgsz, list) else [imgsz, imgsz] # expand if int/float flops = sum(x.flops for x in prof.key_averages()) / 1E9
flops = flops * imgsz[0] / stride * imgsz[1] / stride # 640x640 GFLOPs imgsz = imgsz if isinstance(imgsz, list) else [imgsz, imgsz] # expand if int/float
return flops flops = flops * imgsz[0] / stride * imgsz[1] / stride # 640x640 GFLOPs
return flops
return 0
def initialize_weights(model): def initialize_weights(model):
@ -384,11 +386,14 @@ def strip_optimizer(f: Union[str, Path] = 'best.pt', s: str = '') -> None:
Returns: Returns:
None None
Usage: Example:
```python
from pathlib import Path from pathlib import Path
from ultralytics.utils.torch_utils import strip_optimizer from ultralytics.utils.torch_utils import strip_optimizer
for f in Path('/Users/glennjocher/Downloads/weights').rglob('*.pt'):
for f in Path('path/to/weights').rglob('*.pt'):
strip_optimizer(f) strip_optimizer(f)
```
""" """
# Use dill (if exists) to serialize the lambda functions where pickle does not do this # Use dill (if exists) to serialize the lambda functions where pickle does not do this
try: try:
@ -421,13 +426,17 @@ def strip_optimizer(f: Union[str, Path] = 'best.pt', s: str = '') -> None:
def profile(input, ops, n=10, device=None): def profile(input, ops, n=10, device=None):
""" """
YOLOv8 speed/memory/FLOPs profiler Ultralytics speed, memory and FLOPs profiler.
Example:
```python
from ultralytics.utils.torch_utils import profile
Usage:
input = torch.randn(16, 3, 640, 640) input = torch.randn(16, 3, 640, 640)
m1 = lambda x: x * torch.sigmoid(x) m1 = lambda x: x * torch.sigmoid(x)
m2 = nn.SiLU() m2 = nn.SiLU()
profile(input, [m1, m2], n=100) # profile over 100 iterations profile(input, [m1, m2], n=100) # profile over 100 iterations
```
""" """
results = [] results = []
if not isinstance(device, torch.device): if not isinstance(device, torch.device):

Loading…
Cancel
Save