CoreML NMS and half fixes (#143)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
single_channel
Glenn Jocher 2 years ago committed by GitHub
parent 55bdca6768
commit 172cef2d20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,6 +1,6 @@
[![Ultralytics CI](https://github.com/ultralytics/ultralytics/actions/workflows/ci.yaml/badge.svg)](https://github.com/ultralytics/ultralytics/actions/workflows/ci.yaml) [![Ultralytics CI](https://github.com/ultralytics/ultralytics/actions/workflows/ci.yaml/badge.svg)](https://github.com/ultralytics/ultralytics/actions/workflows/ci.yaml)
### Install ## Install
```bash ```bash
pip install ultralytics pip install ultralytics
@ -38,10 +38,39 @@ model = YOLO("yolov8n.yaml") # create a new model from scratch
model = YOLO( model = YOLO(
"yolov8n.pt" "yolov8n.pt"
) # load a pretrained model (recommended for best training results) ) # load a pretrained model (recommended for best training results)
results = model.train(data="coco128.yaml", epochs=100, imgsz=640, ...) results = model.train(data="coco128.yaml", epochs=100, imgsz=640)
results = model.val() results = model.val()
results = model.predict(source="bus.jpg") results = model.predict(source="bus.jpg")
success = model.export(format="onnx") success = model.export(format="onnx")
``` ```
## Models
| Model | size<br><sup>(pixels) | mAP<sup>val<br>50-95 | Speed<br><sup>CPU<br>(ms) | Speed<br><sup>T4 GPU<br>(ms) | params<br><sup>(M) | FLOPs<br><sup>(B) |
| ------------------------------------------------------------------------------------------------ | --------------------- | -------------------- | ------------------------- | ---------------------------- | ------------------ | ----------------- |
| [YOLOv5n](https://github.com/ultralytics/yolov5/releases/download/v6.2/yolov5n.pt) | 640 | 28.0 | - | - | **1.9** | **4.5** |
| [YOLOv6n](url) | 640 | 35.9 | - | - | 4.3 | 11.1 |
| **[YOLOv8n](url)** | 640 | **37.5** | - | - | 3.2 | 8.9 |
| | | | | | | |
| [YOLOv5s](https://github.com/ultralytics/yolov5/releases/download/v6.2/yolov5s.pt) | 640 | 37.4 | - | - | 7.2 | 16.5 |
| [YOLOv6s](url) | 640 | 43.5 | - | - | 17.2 | 44.2 |
| **[YOLOv8s](url)** | 640 | **44.7** | - | - | 11.2 | 28.8 |
| | | | | | | |
| [YOLOv5m](https://github.com/ultralytics/yolov5/releases/download/v6.2/yolov5m.pt) | 640 | 45.4 | - | - | 21.2 | 49.0 |
| [YOLOv6m](url) | 640 | 49.5 | - | - | 34.3 | 82.2 |
| **[YOLOv8m](url)** | 640 | **50.3** | - | - | 25.9 | 79.3 |
| | | | | | | |
| [YOLOv5l](https://github.com/ultralytics/yolov5/releases/download/v6.2/yolov5l.pt) | 640 | 49.0 | - | - | 46.5 | 109.1 |
| [YOLOv6l](url) | 640 | 52.5 | - | - | 58.5 | 144.0 |
| [YOLOv7](url) | 640 | 51.2 | - | - | 36.9 | 104.7 |
| **[YOLOv8l](url)** | 640 | **52.8** | - | - | 43.7 | 165.7 |
| | | | | | | |
| [YOLOv5x](https://github.com/ultralytics/yolov5/releases/download/v6.2/yolov5x.pt) | 640 | 50.7 | - | - | 86.7 | 205.7 |
| [YOLOv7-X](url) | 640 | 52.9 | - | - | 71.3 | 189.9 |
| **[YOLOv8x](url)** | 640 | **53.7** | - | - | 68.2 | 258.5 |
| | | | | | | |
| [YOLOv5x6](https://github.com/ultralytics/yolov5/releases/download/v6.2/yolov5x6.pt) | 1280 | 55.0 | - | - | 140.7 | 839.2 |
| [YOLOv7-E6E](url) | 1280 | 56.8 | - | - | 151.7 | 843.2 |
| **[YOLOv8x6](https://github.com/ultralytics/yolov5/releases/download/v6.2/yolov5x6.pt)**<br>+TTA | 1280 | -<br>- | -<br>- | -<br>- | 97.4 | 1047.2<br>- |
If you're looking to modify YOLO for R&D or to build on top of it, refer to [Using Trainer](<>) Guide on our docs. If you're looking to modify YOLO for R&D or to build on top of it, refer to [Using Trainer](<>) Guide on our docs.

@ -1,15 +0,0 @@
from ultralytics import YOLO
from ultralytics.yolo.utils import ROOT
if __name__ == "__main__":
for m in list((ROOT / 'yolo/v8/models').rglob('*.yaml')):
try:
YOLO(m.name, verbose=True)
except Exception as e:
print(f'ERROR for {m}: {e}')
# n vs n-seg: 8.9GFLOPs vs 12.8GFLOPs, 3.16M vs 3.6M. ch[0] // 4 (11.9GFLOPs, 3.39M)
# s vs s-seg: 28.8GFLOPs vs 44.4GFLOPs, 11.1M vs 12.9M. ch[0] // 4 (39.5GFLOPs, 11.7M)
# m vs m-seg: 79.3GFLOPs vs 113.8GFLOPs, 25.9M vs 29.5M. ch[0] // 4 (103.GFLOPs, 27.1M)
# l vs l-seg: 165.7GFLOPs vs 226.3GFLOPs, 43.7M vs 49.6M. ch[0] // 4 (207GFLOPs, 45.7M)
# x vs x-seg: 258.5GFLOPs vs 353.0GFLOPs, 68.3M vs 77.5M. ch[0] // 4 (324GFLOPs, 71.4M)

@ -1,29 +0,0 @@
lr0: 0.001 # initial learning rate (SGD=1E-2, Adam=1E-3)
lrf: 0.01 # final OneCycleLR learning rate (lr0 * lrf)
momentum: 0.937 # SGD momentum/Adam beta1
weight_decay: 0.0005 # optimizer weight decay 5e-4
warmup_epochs: 3.0 # warmup epochs (fractions ok)
warmup_momentum: 0.8 # warmup initial momentum
warmup_bias_lr: 0.1 # warmup initial bias lr
box: 0.05 # box loss gain
cls: 0.5 # cls loss gain
cls_pw: 1.0 # cls BCELoss positive_weight
obj: 1.0 # obj loss gain (scale with pixels)
obj_pw: 1.0 # obj BCELoss positive_weight
iou_t: 0.20 # IoU training threshold
anchor_t: 4.0 # anchor-multiple threshold
# anchors: 3 # anchors per output layer (0 to ignore)
fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5)
hsv_h: 0.015 # image HSV-Hue augmentation (fraction)
hsv_s: 0.7 # image HSV-Saturation augmentation (fraction)
hsv_v: 0.4 # image HSV-Value augmentation (fraction)
degrees: 0.0 # image rotation (+/- deg)
translate: 0.1 # image translation (+/- fraction)
scale: 0.5 # image scale (+/- gain)
shear: 0.0 # image shear (+/- deg)
perspective: 0.0 # image perspective (+/- fraction), range 0-0.001
flipud: 0.0 # image flip up-down (probability)
fliplr: 0.5 # image flip left-right (probability)
mosaic: 1.0 # image mosaic (probability)
mixup: 0.0 # image mixup (probability)
copy_paste: 0.5 # segment copy-paste (probability)

@ -1,85 +0,0 @@
import cv2
import hydra
from ultralytics.yolo.data import build_dataloader
from ultralytics.yolo.utils import DEFAULT_CONFIG
from ultralytics.yolo.utils.plotting import plot_images
class Colors:
# Ultralytics color palette https://ultralytics.com/
def __init__(self):
# hex = matplotlib.colors.TABLEAU_COLORS.values()
hexs = ('FF3838', 'FF9D97', 'FF701F', 'FFB21D', 'CFD231', '48F90A', '92CC17', '3DDB86', '1A9334', '00D4BB',
'2C99A8', '00C2FF', '344593', '6473FF', '0018EC', '8438FF', '520085', 'CB38FF', 'FF95C8', 'FF37C7')
self.palette = [self.hex2rgb(f'#{c}') for c in hexs]
self.n = len(self.palette)
def __call__(self, i, bgr=False):
c = self.palette[int(i) % self.n]
return (c[2], c[1], c[0]) if bgr else c
@staticmethod
def hex2rgb(h): # rgb order (PIL)
return tuple(int(h[1 + i:1 + i + 2], 16) for i in (0, 2, 4))
colors = Colors() # create instance for 'from utils.plots import colors'
def plot_one_box(x, img, color=None, label=None, line_thickness=None):
import random
# Plots one bounding box on image img
tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # line/font thickness
color = color or [random.randint(0, 255) for _ in range(3)]
c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3]))
cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA)
if label:
tf = max(tl - 1, 1) # font thickness
t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0]
c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3
cv2.rectangle(img, c1, c2, color, -1, cv2.LINE_AA) # filled
cv2.putText(
img,
label,
(c1[0], c1[1] - 2),
0,
tl / 3,
[225, 255, 255],
thickness=tf,
lineType=cv2.LINE_AA,
)
@hydra.main(version_base=None, config_path=str(DEFAULT_CONFIG.parent), config_name=DEFAULT_CONFIG.name)
def test(cfg):
cfg.task = "detect"
cfg.mode = "train"
dataloader, _ = build_dataloader(
cfg=cfg,
batch_size=4,
img_path="/d/dataset/COCO/coco128-seg/images",
stride=32,
label_path=None,
mode=cfg.mode,
)
for d in dataloader:
images = d["img"]
cls = d["cls"].squeeze(-1)
bboxes = d["bboxes"]
paths = d["im_file"]
batch_idx = d["batch_idx"]
result = plot_images(images, batch_idx, cls, bboxes, paths=paths)
cv2.imshow("p", result)
if cv2.waitKey(0) == ord("q"):
break
if __name__ == "__main__":
test()
# test(augment=True, rect=False)
# test(augment=False, rect=True)
# test(augment=False, rect=False)

@ -1,125 +0,0 @@
import cv2
import numpy as np
from omegaconf import OmegaConf
from ultralytics.yolo.data import build_dataloader
class Colors:
# Ultralytics color palette https://ultralytics.com/
def __init__(self):
# hex = matplotlib.colors.TABLEAU_COLORS.values()
hexs = ('FF3838', 'FF9D97', 'FF701F', 'FFB21D', 'CFD231', '48F90A', '92CC17', '3DDB86', '1A9334', '00D4BB',
'2C99A8', '00C2FF', '344593', '6473FF', '0018EC', '8438FF', '520085', 'CB38FF', 'FF95C8', 'FF37C7')
self.palette = [self.hex2rgb(f'#{c}') for c in hexs]
self.n = len(self.palette)
def __call__(self, i, bgr=False):
c = self.palette[int(i) % self.n]
return (c[2], c[1], c[0]) if bgr else c
@staticmethod
def hex2rgb(h): # rgb order (PIL)
return tuple(int(h[1 + i:1 + i + 2], 16) for i in (0, 2, 4))
colors = Colors() # create instance for 'from utils.plots import colors'
def plot_one_box(x, img, keypoints=None, color=None, label=None, line_thickness=None):
import random
# Plots one bounding box on image img
tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # line/font thickness
color = color or [random.randint(0, 255) for _ in range(3)]
c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3]))
cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA)
if label:
tf = max(tl - 1, 1) # font thickness
t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0]
c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3
cv2.rectangle(img, c1, c2, color, -1, cv2.LINE_AA) # filled
cv2.putText(
img,
label,
(c1[0], c1[1] - 2),
0,
tl / 3,
[225, 255, 255],
thickness=tf,
lineType=cv2.LINE_AA,
)
if keypoints is not None:
plot_keypoint(img, keypoints, color, tl)
def plot_keypoint(img, keypoints, color, tl):
num_l = len(keypoints)
# clors = [(255, 0, 0),(0, 255, 0),(0, 0, 255),(255, 255, 0),(0, 255, 255)]
# clors = [[random.randint(0, 255) for _ in range(3)] for _ in range(num_l)]
for i in range(num_l):
point_x = int(keypoints[i][0])
point_y = int(keypoints[i][1])
cv2.circle(img, (point_x, point_y), tl + 3, color, -1)
with open("ultralytics/tests/data/dataloader/hyp_test.yaml") as f:
hyp = OmegaConf.load(f)
def test(augment, rect):
dataloader, _ = build_dataloader(
img_path="/d/dataset/COCO/images/val2017",
imgsz=640,
label_path=None,
cache=False,
hyp=hyp,
augment=augment,
prefix="",
rect=rect,
batch_size=4,
stride=32,
pad=0.5,
use_segments=False,
use_keypoints=True,
)
for d in dataloader:
idx = 1 # show which image inside one batch
img = d["img"][idx].numpy()
img = np.ascontiguousarray(img.transpose(1, 2, 0))
ih, iw = img.shape[:2]
# print(img.shape)
bidx = d["batch_idx"]
cls = d["cls"][bidx == idx].numpy()
bboxes = d["bboxes"][bidx == idx].numpy()
bboxes[:, [0, 2]] *= iw
bboxes[:, [1, 3]] *= ih
keypoints = d["keypoints"][bidx == idx]
keypoints[..., 0] *= iw
keypoints[..., 1] *= ih
# print(keypoints, keypoints.shape)
# print(d["im_file"])
for i, b in enumerate(bboxes):
x, y, w, h = b
x1 = x - w / 2
x2 = x + w / 2
y1 = y - h / 2
y2 = y + h / 2
c = int(cls[i][0])
# print(x1, y1, x2, y2)
plot_one_box([int(x1), int(y1), int(x2), int(y2)],
img,
keypoints=keypoints[i],
label=f"{c}",
color=colors(c))
cv2.imshow("p", img)
if cv2.waitKey(0) == ord("q"):
break
if __name__ == "__main__":
test(augment=True, rect=False)
test(augment=False, rect=True)
test(augment=False, rect=False)

@ -1,85 +0,0 @@
import cv2
import hydra
from ultralytics.yolo.data import build_dataloader
from ultralytics.yolo.utils import DEFAULT_CONFIG
from ultralytics.yolo.utils.plotting import plot_images
class Colors:
# Ultralytics color palette https://ultralytics.com/
def __init__(self):
# hex = matplotlib.colors.TABLEAU_COLORS.values()
hexs = ('FF3838', 'FF9D97', 'FF701F', 'FFB21D', 'CFD231', '48F90A', '92CC17', '3DDB86', '1A9334', '00D4BB',
'2C99A8', '00C2FF', '344593', '6473FF', '0018EC', '8438FF', '520085', 'CB38FF', 'FF95C8', 'FF37C7')
self.palette = [self.hex2rgb(f'#{c}') for c in hexs]
self.n = len(self.palette)
def __call__(self, i, bgr=False):
c = self.palette[int(i) % self.n]
return (c[2], c[1], c[0]) if bgr else c
@staticmethod
def hex2rgb(h): # rgb order (PIL)
return tuple(int(h[1 + i:1 + i + 2], 16) for i in (0, 2, 4))
colors = Colors() # create instance for 'from utils.plots import colors'
def plot_one_box(x, img, color=None, label=None, line_thickness=None):
import random
# Plots one bounding box on image img
tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # line/font thickness
color = color or [random.randint(0, 255) for _ in range(3)]
c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3]))
cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA)
if label:
tf = max(tl - 1, 1) # font thickness
t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0]
c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3
cv2.rectangle(img, c1, c2, color, -1, cv2.LINE_AA) # filled
cv2.putText(
img,
label,
(c1[0], c1[1] - 2),
0,
tl / 3,
[225, 255, 255],
thickness=tf,
lineType=cv2.LINE_AA,
)
@hydra.main(version_base=None, config_path=str(DEFAULT_CONFIG.parent), config_name=DEFAULT_CONFIG.name)
def test(cfg):
cfg.task = "segment"
cfg.mode = "train"
dataloader, _ = build_dataloader(
cfg=cfg,
batch_size=4,
img_path="/d/dataset/COCO/coco128-seg/images",
stride=32,
label_path=None,
mode=cfg.mode,
)
for d in dataloader:
images = d["img"]
masks = d["masks"]
cls = d["cls"].squeeze(-1)
bboxes = d["bboxes"]
paths = d["im_file"]
batch_idx = d["batch_idx"]
result = plot_images(images, batch_idx, cls, bboxes, masks, paths=paths)
cv2.imshow("p", result)
if cv2.waitKey(0) == ord("q"):
break
if __name__ == "__main__":
test()
# test(augment=True, rect=False)
# test(augment=False, rect=True)
# test(augment=False, rect=False)

@ -1,32 +0,0 @@
from ultralytics.nn.tasks import DetectionModel
from ultralytics.yolo.utils.checks import check_yaml
def test_model_parser():
cfg = check_yaml("yolov8n.yaml") # check YAML
# Create model
model = DetectionModel(cfg)
model.info()
'''
# Options
if opt.line_profile: # profile layer by layer
model(im, profile=True)
elif opt.profile: # profile forward-backward
results = profile(input=im, ops=[model], n=3)
elif opt.test: # test all models
for cfg in Path(ROOT / 'models').rglob('yolo*.yaml'):
try:
_ = Model(cfg)
except Exception as e:
print(f'Error in {cfg}: {e}')
else: # report fused model summary
model.fuse()
'''
if __name__ == "__main__":
test_model_parser()

@ -1,6 +1,10 @@
import os import os
from pathlib import Path
from ultralytics.yolo.utils import ROOT from ultralytics.yolo.utils import ROOT, SETTINGS
MODEL = Path(SETTINGS['weights_dir']) / 'yolov8n.pt'
CFG = 'yolov8n.yaml'
def test_checks(): def test_checks():
@ -9,7 +13,7 @@ def test_checks():
# Train checks --------------------------------------------------------------------------------------------------------- # Train checks ---------------------------------------------------------------------------------------------------------
def test_train_detect(): def test_train_detect():
os.system('yolo mode=train task=detect model=yolov8n.yaml data=coco128.yaml imgsz=32 epochs=1') os.system(f'yolo mode=train task=detect model={MODEL} data=coco128.yaml imgsz=32 epochs=1')
def test_train_segment(): def test_train_segment():
@ -22,7 +26,7 @@ def test_train_classify():
# Val checks ----------------------------------------------------------------------------------------------------------- # Val checks -----------------------------------------------------------------------------------------------------------
def test_val_detect(): def test_val_detect():
os.system('yolo mode=val task=detect model=yolov8n.pt data=coco128.yaml imgsz=32 epochs=1') os.system(f'yolo mode=val task=detect model={MODEL} data=coco128.yaml imgsz=32 epochs=1')
def test_val_segment(): def test_val_segment():
@ -35,7 +39,7 @@ def test_val_classify():
# Predict checks ------------------------------------------------------------------------------------------------------- # Predict checks -------------------------------------------------------------------------------------------------------
def test_predict_detect(): def test_predict_detect():
os.system(f"yolo mode=predict model=yolov8n.pt source={ROOT / 'assets'}") os.system(f"yolo mode=predict model={MODEL} source={ROOT / 'assets'}")
def test_predict_segment(): def test_predict_segment():
@ -48,7 +52,7 @@ def test_predict_classify():
# Export checks -------------------------------------------------------------------------------------------------------- # Export checks --------------------------------------------------------------------------------------------------------
def test_export_detect_torchscript(): def test_export_detect_torchscript():
os.system('yolo mode=export model=yolov8n.pt format=torchscript') os.system(f'yolo mode=export model={MODEL} format=torchscript')
def test_export_segment_torchscript(): def test_export_segment_torchscript():

@ -1,9 +1,11 @@
from pathlib import Path
import torch import torch
from ultralytics import YOLO from ultralytics import YOLO
from ultralytics.yolo.utils import ROOT from ultralytics.yolo.utils import ROOT, SETTINGS
MODEL = ROOT / 'weights/yolov8n.pt' MODEL = Path(SETTINGS['weights_dir']) / 'yolov8n.pt'
CFG = 'yolov8n.yaml' CFG = 'yolov8n.yaml'
@ -95,6 +97,11 @@ def test_export_paddle():
model.export(format='paddle') model.export(format='paddle')
def test_all_model_yamls():
for m in list((ROOT / 'yolo/v8/models').rglob('*.yaml')):
YOLO(m.name)
# def run_all_tests(): # do not name function test_... # def run_all_tests(): # do not name function test_...
# pass # pass
# #

@ -142,7 +142,7 @@ class DetectionModel(BaseModel):
# YOLOv5 detection model # YOLOv5 detection model
def __init__(self, cfg='yolov8n.yaml', ch=3, nc=None, verbose=True): # model, input channels, number of classes def __init__(self, cfg='yolov8n.yaml', ch=3, nc=None, verbose=True): # model, input channels, number of classes
super().__init__() super().__init__()
self.yaml = cfg if isinstance(cfg, dict) else yaml_load(check_yaml(cfg)) # cfg dict self.yaml = cfg if isinstance(cfg, dict) else yaml_load(check_yaml(cfg), append_filename=True) # cfg dict
# Define model # Define model
ch = self.yaml['ch'] = self.yaml.get('ch', ch) # input channels ch = self.yaml['ch'] = self.yaml.get('ch', ch) # input channels

@ -201,7 +201,7 @@ def check_dataset_yaml(data, autodownload=True):
extract_dir, autodownload = data.parent, False extract_dir, autodownload = data.parent, False
# Read yaml (optional) # Read yaml (optional)
if isinstance(data, (str, Path)): if isinstance(data, (str, Path)):
data = yaml_load(data) # dictionary data = yaml_load(data, append_filename=True) # dictionary
# Checks # Checks
for k in 'train', 'val', 'names': for k in 'train', 'val', 'names':

@ -67,7 +67,7 @@ import torch
import ultralytics import ultralytics
from ultralytics.nn.modules import Detect, Segment from ultralytics.nn.modules import Detect, Segment
from ultralytics.nn.tasks import ClassificationModel, DetectionModel, SegmentationModel, attempt_load_weights from ultralytics.nn.tasks import ClassificationModel, DetectionModel, SegmentationModel
from ultralytics.yolo.configs import get_config from ultralytics.yolo.configs import get_config
from ultralytics.yolo.data.dataloaders.stream_loaders import LoadImages from ultralytics.yolo.data.dataloaders.stream_loaders import LoadImages
from ultralytics.yolo.data.utils import check_dataset from ultralytics.yolo.data.utils import check_dataset
@ -154,7 +154,7 @@ class Exporter:
# Load PyTorch model # Load PyTorch model
self.device = select_device(self.args.device or 'cpu') self.device = select_device(self.args.device or 'cpu')
if self.args.half: if self.args.half:
if self.device.type == 'cpu' or not coreml: if self.device.type == 'cpu' and not coreml:
LOGGER.info('half=True only compatible with GPU or CoreML export, i.e. use device=0 or format=coreml') LOGGER.info('half=True only compatible with GPU or CoreML export, i.e. use device=0 or format=coreml')
self.args.half = False self.args.half = False
assert not self.args.dynamic, '--half not compatible with --dynamic, i.e. use either --half or --dynamic' assert not self.args.dynamic, '--half not compatible with --dynamic, i.e. use either --half or --dynamic'
@ -769,17 +769,22 @@ class Exporter:
def export(cfg): def export(cfg):
cfg.model = cfg.model or "yolov8n.yaml" cfg.model = cfg.model or "yolov8n.yaml"
cfg.format = cfg.format or "torchscript" cfg.format = cfg.format or "torchscript"
exporter = Exporter(cfg)
# exporter = Exporter(cfg)
model = None #
if isinstance(cfg.model, (str, Path)): # model = None
if Path(cfg.model).suffix == '.yaml': # if isinstance(cfg.model, (str, Path)):
model = DetectionModel(cfg.model) # if Path(cfg.model).suffix == '.yaml':
elif Path(cfg.model).suffix == '.pt': # model = DetectionModel(cfg.model)
model = attempt_load_weights(cfg.model, fuse=True) # elif Path(cfg.model).suffix == '.pt':
else: # model = attempt_load_weights(cfg.model, fuse=True)
TypeError(f'Unsupported model type {cfg.model}') # else:
exporter(model=model) # TypeError(f'Unsupported model type {cfg.model}')
# exporter(model=model)
from ultralytics import YOLO
model = YOLO(cfg.model)
model.export(**cfg)
if __name__ == "__main__": if __name__ == "__main__":

@ -64,7 +64,7 @@ class YOLO:
verbose (bool): display model info on load verbose (bool): display model info on load
""" """
cfg = check_yaml(cfg) # check YAML cfg = check_yaml(cfg) # check YAML
cfg_dict = yaml_load(cfg) # model dict cfg_dict = yaml_load(cfg, append_filename=True) # model dict
self.task = guess_task_from_head(cfg_dict["head"][-1][-2]) self.task = guess_task_from_head(cfg_dict["head"][-1][-2])
self.ModelClass, self.TrainerClass, self.ValidatorClass, self.PredictorClass = \ self.ModelClass, self.TrainerClass, self.ValidatorClass, self.PredictorClass = \
self._guess_ops_from_task(self.task) self._guess_ops_from_task(self.task)
@ -183,7 +183,7 @@ class YOLO:
overrides.update(kwargs) overrides.update(kwargs)
if kwargs.get("cfg"): if kwargs.get("cfg"):
LOGGER.info(f"cfg file passed. Overriding default params with {kwargs['cfg']}.") LOGGER.info(f"cfg file passed. Overriding default params with {kwargs['cfg']}.")
overrides = yaml_load(check_yaml(kwargs["cfg"])) overrides = yaml_load(check_yaml(kwargs["cfg"]), append_filename=True)
overrides["task"] = self.task overrides["task"] = self.task
overrides["mode"] = "train" overrides["mode"] = "train"
if not overrides.get("data"): if not overrides.get("data"):

@ -157,7 +157,8 @@ class BaseValidator:
self.run_callbacks('on_val_end') self.run_callbacks('on_val_end')
if self.training: if self.training:
model.float() model.float()
return {**stats, **trainer.label_loss_items(self.loss.cpu() / len(self.dataloader), prefix="val")} results = {**stats, **trainer.label_loss_items(self.loss.cpu() / len(self.dataloader), prefix="val")}
return {k: round(float(v), 5) for k, v in results.items()} # return results as 5 decimal place floats
else: else:
self.logger.info('Speed: %.1fms pre-process, %.1fms inference, %.1fms loss, %.1fms post-process per image' % self.logger.info('Speed: %.1fms pre-process, %.1fms inference, %.1fms loss, %.1fms post-process per image' %
self.speed) self.speed)

@ -3,6 +3,7 @@ import inspect
import logging.config import logging.config
import os import os
import platform import platform
import subprocess
import sys import sys
import tempfile import tempfile
import threading import threading
@ -171,6 +172,18 @@ def is_dir_writeable(dir_path: str) -> bool:
return False return False
def get_git_root_dir():
"""
Determines whether the current file is part of a git repository and if so, returns the repository root directory.
If the current file is not part of a git repository, returns None.
"""
try:
output = subprocess.run(["git", "rev-parse", "--git-dir"], capture_output=True, check=True)
return Path(output.stdout.strip().decode('utf-8')).parent # parent/.git
except subprocess.CalledProcessError:
return None
def get_default_args(func): def get_default_args(func):
# Get func() default arguments # Get func() default arguments
signature = inspect.signature(func) signature = inspect.signature(func)
@ -311,13 +324,13 @@ def yaml_save(file='data.yaml', data=None):
yaml.safe_dump({k: str(v) if isinstance(v, Path) else v for k, v in data.items()}, f, sort_keys=False) yaml.safe_dump({k: str(v) if isinstance(v, Path) else v for k, v in data.items()}, f, sort_keys=False)
def yaml_load(file='data.yaml', append_filename=True): def yaml_load(file='data.yaml', append_filename=False):
""" """
Load YAML data from a file. Load YAML data from a file.
Args: Args:
file (str, optional): File name. Default is 'data.yaml'. file (str, optional): File name. Default is 'data.yaml'.
append_filename (bool): Add the YAML filename to the YAML dictionary. Default is True. append_filename (bool): Add the YAML filename to the YAML dictionary. Default is False.
Returns: Returns:
dict: YAML data and file name. dict: YAML data and file name.
@ -339,14 +352,13 @@ def get_settings(file=USER_CONFIG_DIR / 'settings.yaml'):
""" """
from ultralytics.yolo.utils.torch_utils import torch_distributed_zero_first from ultralytics.yolo.utils.torch_utils import torch_distributed_zero_first
git_install = not is_pip_package() root = get_git_root_dir() or Path('') # not is_pip_package()
defaults = { defaults = {
'datasets_dir': str(ROOT / 'datasets') if git_install else 'datasets', # default datasets directory. 'datasets_dir': str(root / 'datasets'), # default datasets directory.
'weights_dir': str(ROOT / 'weights') if git_install else 'weights', # default weights directory. 'weights_dir': str(root / 'weights'), # default weights directory.
'runs_dir': str(ROOT / 'runs') if git_install else 'runs', # default runs directory. 'runs_dir': str(root / 'runs'), # default runs directory.
'sync': True, # sync analytics to help with YOLO development 'sync': True, # sync analytics to help with YOLO development
'uuid': uuid.getnode(), # device UUID to align analytics 'uuid': uuid.getnode()} # device UUID to align analytics
'yaml_file': str(file)} # setting YAML file path
with torch_distributed_zero_first(RANK): with torch_distributed_zero_first(RANK):
if not file.exists(): if not file.exists():

@ -18,13 +18,7 @@ def on_pretrain_routine_end(trainer):
def on_fit_epoch_end(trainer): def on_fit_epoch_end(trainer):
session = getattr(trainer, 'hub_session', None) session = getattr(trainer, 'hub_session', None)
if session: if session:
# Upload metrics after val end session.metrics_queue[trainer.epoch] = json.dumps(trainer.metrics) # json string
metrics = trainer.metrics
for k, v in metrics.items():
if isinstance(v, torch.Tensor):
metrics[k] = v.item()
session.metrics_queue[trainer.epoch] = json.dumps(metrics) # json string
if time() - session.t['metrics'] > session.rate_limits['metrics']: if time() - session.t['metrics'] > session.rate_limits['metrics']:
session.upload_metrics() session.upload_metrics()
session.t['metrics'] = time() # reset timer session.t['metrics'] = time() # reset timer

@ -153,7 +153,7 @@ def check_python(minimum: str = '3.7.0') -> bool:
@TryExcept() @TryExcept()
def check_requirements(requirements=ROOT / 'requirements.txt', exclude=(), install=True, cmds=''): def check_requirements(requirements=ROOT.parent / 'requirements.txt', exclude=(), install=True, cmds=''):
# Check installed dependencies meet YOLOv5 requirements (pass *.txt file or list of packages or single package str) # Check installed dependencies meet YOLOv5 requirements (pass *.txt file or list of packages or single package str)
prefix = colorstr('red', 'bold', 'requirements:') prefix = colorstr('red', 'bold', 'requirements:')
check_python() # check python version check_python() # check python version

@ -19,7 +19,7 @@ class DetectionValidator(BaseValidator):
def __init__(self, dataloader=None, save_dir=None, pbar=None, logger=None, args=None): def __init__(self, dataloader=None, save_dir=None, pbar=None, logger=None, args=None):
super().__init__(dataloader, save_dir, pbar, logger, args) super().__init__(dataloader, save_dir, pbar, logger, args)
self.data_dict = yaml_load(check_file(self.args.data)) if self.args.data else None self.data_dict = yaml_load(check_file(self.args.data), append_filename=True) if self.args.data else None
self.is_coco = False self.is_coco = False
self.class_map = None self.class_map = None
self.targets = None self.targets = None

Loading…
Cancel
Save