Override fixes and general updates (#129)

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

@ -6,16 +6,11 @@ from ultralytics import YOLO
def test_model_init(): def test_model_init():
model = YOLO("yolov8n.yaml") model = YOLO("yolov8n.yaml")
model.info() model.info()
try:
YOLO()
except Exception:
print("Successfully caught constructor assert!")
raise Exception("constructor error didn't occur")
def test_model_forward(): def test_model_forward():
model = YOLO("yolov8n.yaml") model = YOLO("yolov8n.yaml")
img = torch.rand(512 * 512 * 3).view(1, 3, 512, 512) img = torch.rand(1, 3, 320, 320)
model.forward(img) model.forward(img)
model(img) model(img)
@ -23,24 +18,24 @@ def test_model_forward():
def test_model_info(): def test_model_info():
model = YOLO("yolov8n.yaml") model = YOLO("yolov8n.yaml")
model.info() model.info()
model = model.load("best.pt") model = YOLO("yolov8n.pt")
model.info(verbose=True) model.info(verbose=True)
def test_model_fuse(): def test_model_fuse():
model = YOLO("yolov8n.yaml") model = YOLO("yolov8n.yaml")
model.fuse() model.fuse()
model.load("best.pt") model = YOLO("yolov8n.pt")
model.fuse() model.fuse()
def test_visualize_preds(): def test_visualize_preds():
model = YOLO("best.pt") model = YOLO("yolov8n.pt")
model.predict(source="ultralytics/assets") model.predict(source="ultralytics/assets")
def test_val(): def test_val():
model = YOLO("best.pt") model = YOLO("yolov8n.pt")
model.val(data="coco128.yaml", imgsz=32) model.val(data="coco128.yaml", imgsz=32)
@ -54,11 +49,11 @@ def test_model_resume():
def test_model_train_pretrained(): def test_model_train_pretrained():
model = YOLO("best.pt") model = YOLO("yolov8n.pt")
model.train(data="coco128.yaml", epochs=1, imgsz=32) model.train(data="coco128.yaml", epochs=1, imgsz=32)
model = model.new("yolov8n.yaml") model = YOLO("yolov8n.yaml")
model.train(data="coco128.yaml", epochs=1, imgsz=32) model.train(data="coco128.yaml", epochs=1, imgsz=32)
img = torch.rand(512 * 512 * 3).view(1, 3, 512, 512) img = torch.rand(1, 3, 320, 320)
model(img) model(img)
@ -78,7 +73,6 @@ def test_exports():
10 TensorFlow.js tfjs _web_model False False 10 TensorFlow.js tfjs _web_model False False
11 PaddlePaddle paddle _paddle_model True True 11 PaddlePaddle paddle _paddle_model True True
""" """
from ultralytics import YOLO
from ultralytics.yolo.engine.exporter import export_formats from ultralytics.yolo.engine.exporter import export_formats
print(export_formats()) print(export_formats())

@ -1,15 +1,15 @@
import shutil import shutil
import threading import threading
import time import time
import uuid
import requests import requests
from ultralytics.hub.config import HUB_API_ROOT from ultralytics.hub.config import HUB_API_ROOT
from ultralytics.yolo.utils import LOGGER, RANK, SETTINGS, colorstr, emojis from ultralytics.yolo.utils import DEFAULT_CONFIG, LOGGER, RANK, SETTINGS, colorstr, emojis, yaml_load
PREFIX = colorstr('Ultralytics: ') PREFIX = colorstr('Ultralytics: ')
HELP_MSG = 'If this issue persists please visit https://github.com/ultralytics/hub/issues for assistance.' HELP_MSG = 'If this issue persists please visit https://github.com/ultralytics/hub/issues for assistance.'
DEFAULT_CONFIG_DICT = yaml_load(DEFAULT_CONFIG)
def check_dataset_disk_space(url='https://github.com/ultralytics/yolov5/releases/download/v1.0/coco128.zip', sf=2.0): def check_dataset_disk_space(url='https://github.com/ultralytics/yolov5/releases/download/v1.0/coco128.zip', sf=2.0):
@ -26,7 +26,7 @@ def check_dataset_disk_space(url='https://github.com/ultralytics/yolov5/releases
def request_with_credentials(url: str) -> any: def request_with_credentials(url: str) -> any:
""" Make a ajax request with cookies attached """ """ Make an ajax request with cookies attached """
from google.colab import output # noqa from google.colab import output # noqa
from IPython import display # noqa from IPython import display # noqa
display.display( display.display(
@ -92,17 +92,18 @@ def smart_request(*args, retry=3, timeout=30, thread=True, code=-1, method="post
retry_codes = (408, 500) # retry only these codes retry_codes = (408, 500) # retry only these codes
methods = {'post': requests.post, 'get': requests.get} # request methods methods = {'post': requests.post, 'get': requests.get} # request methods
def fcn(*args, **kwargs): def func(*func_args, **func_kwargs):
t0 = time.time() r = None # response
t0 = time.time() # initial time for timer
for i in range(retry + 1): for i in range(retry + 1):
if (time.time() - t0) > timeout: if (time.time() - t0) > timeout:
break break
r = methods[method](*args, **kwargs) # i.e. post(url, data, json, files) r = methods[method](*func_args, **func_kwargs) # i.e. post(url, data, json, files)
if r.status_code == 200: if r.status_code == 200:
break break
try: try:
m = r.json().get('message', 'No JSON message.') m = r.json().get('message', 'No JSON message.')
except Exception: except AttributeError:
m = 'Unable to read JSON.' m = 'Unable to read JSON.'
if i == 0: if i == 0:
if r.status_code in retry_codes: if r.status_code in retry_codes:
@ -118,22 +119,25 @@ def smart_request(*args, retry=3, timeout=30, thread=True, code=-1, method="post
return r return r
if thread: if thread:
threading.Thread(target=fcn, args=args, kwargs=kwargs, daemon=True).start() threading.Thread(target=func, args=args, kwargs=kwargs, daemon=True).start()
else: else:
return fcn(*args, **kwargs) return func(*args, **kwargs)
def sync_analytics(cfg, enabled=False): def sync_analytics(cfg, all_keys=False, enabled=True):
""" """
Sync analytics data if enabled in the global settings Sync analytics data if enabled in the global settings
Args: Args:
cfg (DictConfig): Configuration for the task and mode. cfg (DictConfig): Configuration for the task and mode.
all_keys (bool): Sync all items, not just non-default values.
enabled (bool): For debugging. enabled (bool): For debugging.
""" """
if SETTINGS['sync'] and RANK in {-1, 0} and enabled: if SETTINGS['sync'] and RANK in {-1, 0} and enabled:
cfg = dict(cfg) # convert type from DictConfig to dict cfg = dict(cfg) # convert type from DictConfig to dict
cfg['uuid'] = uuid.getnode() # add the device UUID to the configuration data if not all_keys:
cfg = {k: v for k, v in cfg.items() if v != DEFAULT_CONFIG_DICT[k]} # retain only non-default values
cfg['uuid'] = SETTINGS['uuid'] # add the device UUID to the configuration data
# Send a request to the HUB API to sync the analytics data # Send a request to the HUB API to sync the analytics data
smart_request(f'{HUB_API_ROOT}/analytics', data=cfg, headers=None, code=3, retry=0) smart_request(f'{HUB_API_ROOT}/v1/usage/anonymous', data=cfg, headers=None, code=3, retry=0)

@ -12,8 +12,8 @@ from ultralytics.nn.modules import (C1, C2, C3, C3TR, SPP, SPPF, Bottleneck, Bot
GhostBottleneck, GhostConv, Segment) GhostBottleneck, GhostConv, Segment)
from ultralytics.yolo.utils import LOGGER, colorstr, yaml_load from ultralytics.yolo.utils import LOGGER, colorstr, yaml_load
from ultralytics.yolo.utils.checks import check_yaml from ultralytics.yolo.utils.checks import check_yaml
from ultralytics.yolo.utils.torch_utils import (fuse_conv_and_bn, initialize_weights, intersect_state_dicts, from ultralytics.yolo.utils.torch_utils import (fuse_conv_and_bn, initialize_weights, intersect_dicts, make_divisible,
make_divisible, model_info, scale_img, time_sync) model_info, scale_img, time_sync)
class BaseModel(nn.Module): class BaseModel(nn.Module):
@ -150,7 +150,7 @@ class DetectionModel(BaseModel):
def load(self, weights, verbose=True): def load(self, weights, verbose=True):
csd = weights['model'].float().state_dict() # checkpoint state_dict as FP32 csd = weights['model'].float().state_dict() # checkpoint state_dict as FP32
csd = intersect_state_dicts(csd, self.state_dict()) # intersect csd = intersect_dicts(csd, self.state_dict()) # intersect
self.load_state_dict(csd, strict=False) # load self.load_state_dict(csd, strict=False) # load
if verbose: if verbose:
LOGGER.info(f'Transferred {len(csd)}/{len(self.model.state_dict())} items from pretrained weights') LOGGER.info(f'Transferred {len(csd)}/{len(self.model.state_dict())} items from pretrained weights')
@ -191,7 +191,7 @@ class ClassificationModel(BaseModel):
def load(self, weights): def load(self, weights):
model = weights["model"] if isinstance(weights, dict) else weights # torchvision models are not dicts model = weights["model"] if isinstance(weights, dict) else weights # torchvision models are not dicts
csd = model.float().state_dict() csd = model.float().state_dict()
csd = intersect_state_dicts(csd, self.state_dict()) # intersect csd = intersect_dicts(csd, self.state_dict()) # intersect
self.load_state_dict(csd, strict=False) # load self.load_state_dict(csd, strict=False) # load
@staticmethod @staticmethod

@ -1,11 +1,11 @@
# YOLO 🚀 by Ultralytics, GPL-3.0 license # YOLO 🚀 by Ultralytics, GPL-3.0 license
# Default training settings and hyperparameters for medium-augmentation COCO training # Default training settings and hyperparameters for medium-augmentation COCO training
task: "classify" # choices=['detect', 'segment', 'classify', 'init'] # init is a special case. Specify task to run. task: "detect" # choices=['detect', 'segment', 'classify', 'init'] # init is a special case. Specify task to run.
mode: "train" # choices=['train', 'val', 'predict'] # mode to run task in. mode: "train" # choices=['train', 'val', 'predict'] # mode to run task in.
# Train settings ------------------------------------------------------------------------------------------------------- # Train settings -------------------------------------------------------------------------------------------------------
model: null # i.e. yolov5s.pt, yolo.yaml. Path to model file model: null # i.e. yolov8n.pt, yolov8n.yaml. Path to model file
data: null # i.e. coco128.yaml. Path to data file data: null # i.e. coco128.yaml. Path to data file
epochs: 100 # number of epochs to train for epochs: 100 # number of epochs to train for
patience: 50 # TODO: epochs to wait for no observable improvement for early stopping of training patience: 50 # TODO: epochs to wait for no observable improvement for early stopping of training

@ -137,8 +137,6 @@ class Exporter:
""" """
if overrides is None: if overrides is None:
overrides = {} overrides = {}
if 'batch_size' not in overrides:
overrides['batch_size'] = 1 # set default export batch size
self.args = get_config(config, overrides) self.args = get_config(config, overrides)
project = self.args.project or f"runs/{self.args.task}" project = self.args.project or f"runs/{self.args.task}"
name = self.args.name or "exp" # hardcode mode as export doesn't require it name = self.args.name or "exp" # hardcode mode as export doesn't require it
@ -166,6 +164,8 @@ class Exporter:
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'
# Checks # Checks
if self.args.batch_size == 16:
self.args.batch_size = 1 # TODO: resolve batch_size 16 default in config.yaml
self.imgsz = check_imgsz(self.args.imgsz, stride=model.stride, min_dim=2) # check image size self.imgsz = check_imgsz(self.args.imgsz, stride=model.stride, min_dim=2) # check image size
if self.args.optimize: if self.args.optimize:
assert self.device.type == 'cpu', '--optimize not compatible with cuda devices, i.e. use --device cpu' assert self.device.type == 'cpu', '--optimize not compatible with cuda devices, i.e. use --device cpu'

@ -1,6 +1,7 @@
import torch
from pathlib import Path from pathlib import Path
import torch
from ultralytics import yolo # noqa from ultralytics import yolo # noqa
from ultralytics.nn.tasks import ClassificationModel, DetectionModel, SegmentationModel, attempt_load_weights from ultralytics.nn.tasks import ClassificationModel, DetectionModel, SegmentationModel, attempt_load_weights
from ultralytics.yolo.configs import get_config from ultralytics.yolo.configs import get_config

@ -107,6 +107,8 @@ class BaseTrainer:
self.device = utils.torch_utils.select_device(self.args.device, self.batch_size) self.device = utils.torch_utils.select_device(self.args.device, self.batch_size)
self.amp = self.device.type != 'cpu' self.amp = self.device.type != 'cpu'
self.scaler = amp.GradScaler(enabled=self.amp) self.scaler = amp.GradScaler(enabled=self.amp)
if self.device.type == 'cpu':
self.args.workers = 0 # faster CPU training as time dominated by inference, not dataloading
# Model and Dataloaders. # Model and Dataloaders.
self.model = self.args.model self.model = self.args.model

@ -6,6 +6,7 @@ import platform
import sys import sys
import tempfile import tempfile
import threading import threading
import uuid
from pathlib import Path from pathlib import Path
import cv2 import cv2
@ -160,7 +161,7 @@ def get_user_config_dir(sub_dir='Ultralytics'):
raise ValueError(f'Unsupported operating system: {os_name}') raise ValueError(f'Unsupported operating system: {os_name}')
# GCP and AWS lambda fix, only /tmp is writeable # GCP and AWS lambda fix, only /tmp is writeable
if not is_dir_writeable(path.parent): if not is_dir_writeable(str(path.parent)):
path = Path('/tmp') / sub_dir path = Path('/tmp') / sub_dir
# Create the subdirectory if it does not exist # Create the subdirectory if it does not exist
@ -172,9 +173,9 @@ def get_user_config_dir(sub_dir='Ultralytics'):
USER_CONFIG_DIR = get_user_config_dir() # Ultralytics settings dir USER_CONFIG_DIR = get_user_config_dir() # Ultralytics settings dir
def emojis(str=''): def emojis(string=''):
# Return platform-dependent emoji-safe version of string # Return platform-dependent emoji-safe version of string
return str.encode().decode('ascii', 'ignore') if platform.system() == 'Windows' else str return string.encode().decode('ascii', 'ignore') if platform.system() == 'Windows' else string
def colorstr(*input): def colorstr(*input):
@ -282,27 +283,39 @@ def yaml_load(file='data.yaml'):
""" """
with open(file, errors='ignore') as f: with open(file, errors='ignore') as f:
# Add YAML filename to dict and return # Add YAML filename to dict and return
return {**yaml.safe_load(f), 'yaml_file': file} return {**yaml.safe_load(f), 'yaml_file': str(file)}
def get_settings(file=USER_CONFIG_DIR / 'settings.yaml'): def get_settings(file=USER_CONFIG_DIR / 'settings.yaml'):
""" """
Function that loads a global settings YAML, or creates it and populates it with default values if it does not exist. Loads a global settings YAML file or creates one with default values if it does not exist.
If the datasets or weights directories are set to None, the current working directory will be used. Args:
The 'sync' setting determines whether analytics will be synced to help with YOLO development. file (Path): Path to the settings YAML file. Defaults to 'settings.yaml' in the USER_CONFIG_DIR.
Returns:
dict: Dictionary of settings key-value pairs.
""" """
from ultralytics.yolo.utils.torch_utils import torch_distributed_zero_first from ultralytics.yolo.utils.torch_utils import torch_distributed_zero_first
defaults = {
'datasets_dir': None, # default datasets directory. If None, current working directory is used.
'weights_dir': None, # default weights directory. If None, current working directory is used.
'runs_dir': None, # default runs directory. If None, current working directory is used.
'sync': True, # sync analytics to help with YOLO development
'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():
settings = { yaml_save(file, defaults)
'datasets_dir': None, # default datasets directory. If None, current working directory is used.
'weights_dir': None, # default weights directory. If None, current working directory is used. settings = yaml_load(file)
'sync': True} # sync analytics to help with YOLO development if settings.keys() != defaults.keys():
yaml_save(file, settings) settings = {**defaults, **settings} # merge **defaults with **settings (prefer **settings)
yaml_save(file, settings) # save updated defaults
return yaml_load(file) return settings
# Run below code on utils init ----------------------------------------------------------------------------------------- # Run below code on utils init -----------------------------------------------------------------------------------------

@ -48,7 +48,7 @@ def on_train_end(trainer):
# Upload final model and metrics with exponential standoff # Upload final model and metrics with exponential standoff
LOGGER.info(f"{PREFIX}Training completed successfully ✅\n" LOGGER.info(f"{PREFIX}Training completed successfully ✅\n"
f"{PREFIX}Uploading final {session.model_id}") f"{PREFIX}Uploading final {session.model_id}")
session.upload_model(trainer.epoch, trainer.best, map=trainer.metrics['metrics/mAP50(B)'], final=True) session.upload_model(trainer.epoch, trainer.best, map=trainer.metrics['metrics/mAP50-95(B)'], final=True)
session.alive = False # stop heartbeats session.alive = False # stop heartbeats
LOGGER.info(f"{PREFIX}View model at https://hub.ultralytics.com/models/{session.model_id} 🚀") LOGGER.info(f"{PREFIX}View model at https://hub.ultralytics.com/models/{session.model_id} 🚀")

@ -201,7 +201,7 @@ def copy_attr(a, b, include=(), exclude=()):
setattr(a, k, v) setattr(a, k, v)
def intersect_state_dicts(da, db, exclude=()): def intersect_dicts(da, db, exclude=()):
# Dictionary intersection of matching keys and shapes, omitting 'exclude' keys, using da values # Dictionary intersection of matching keys and shapes, omitting 'exclude' keys, using da values
return {k: v for k, v in da.items() if k in db and all(x not in k for x in exclude) and v.shape == db[k].shape} return {k: v for k, v in da.items() if k in db and all(x not in k for x in exclude) and v.shape == db[k].shape}

Loading…
Cancel
Save