From 15b3b0365ab2f12993a58985f3cb7f2137409a0c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 25 Jan 2023 21:21:39 +0100 Subject: [PATCH] `ultralytics 8.0.20` CLI `yolo` simplifications, DDP and ONNX fixes (#608) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Sid Prabhakaran --- ultralytics/__init__.py | 2 +- ultralytics/hub/utils.py | 79 +++++++++++++++++++------ ultralytics/nn/tasks.py | 26 ++++---- ultralytics/yolo/cfg/__init__.py | 60 +++++++++++-------- ultralytics/yolo/cfg/default.yaml | 28 ++++----- ultralytics/yolo/utils/__init__.py | 11 ++-- ultralytics/yolo/utils/callbacks/hub.py | 8 +-- ultralytics/yolo/utils/torch_utils.py | 2 +- ultralytics/yolo/v8/classify/predict.py | 17 ++++-- ultralytics/yolo/v8/classify/train.py | 27 ++++----- ultralytics/yolo/v8/classify/val.py | 17 ++++-- ultralytics/yolo/v8/detect/predict.py | 17 ++++-- ultralytics/yolo/v8/detect/train.py | 23 +++---- ultralytics/yolo/v8/detect/val.py | 17 ++++-- ultralytics/yolo/v8/segment/predict.py | 18 ++++-- ultralytics/yolo/v8/segment/train.py | 23 +++---- ultralytics/yolo/v8/segment/val.py | 16 +++-- 17 files changed, 247 insertions(+), 144 deletions(-) diff --git a/ultralytics/__init__.py b/ultralytics/__init__.py index f429865..6d1cc9f 100644 --- a/ultralytics/__init__.py +++ b/ultralytics/__init__.py @@ -1,6 +1,6 @@ # Ultralytics YOLO 🚀, GPL-3.0 license -__version__ = "8.0.19" +__version__ = "8.0.20" from ultralytics.yolo.engine.model import YOLO from ultralytics.yolo.utils import ops diff --git a/ultralytics/hub/utils.py b/ultralytics/hub/utils.py index 54fdfed..50d6f42 100644 --- a/ultralytics/hub/utils.py +++ b/ultralytics/hub/utils.py @@ -1,14 +1,19 @@ # Ultralytics YOLO 🚀, GPL-3.0 license import os +import platform import shutil +import sys import threading import time +from pathlib import Path from random import random import requests -from ultralytics.yolo.utils import DEFAULT_CFG_DICT, LOGGER, RANK, SETTINGS, TryExcept, colorstr, emojis +from ultralytics.yolo.utils import (DEFAULT_CFG_DICT, LOGGER, RANK, SETTINGS, TryExcept, colorstr, emojis, + get_git_origin_url, is_colab, is_docker, is_git_dir, is_github_actions_ci, + is_jupyter, is_kaggle, is_pip_package, is_pytest_running) PREFIX = colorstr('Ultralytics: ') HELP_MSG = 'If this issue persists please visit https://github.com/ultralytics/hub/issues for assistance.' @@ -131,21 +136,57 @@ def smart_request(*args, retry=3, timeout=30, thread=True, code=-1, method="post return func(*args, **kwargs) -@TryExcept(verbose=False) -def traces(cfg, all_keys=False, traces_sample_rate=0.0): - """ - Sync traces data if enabled in the global settings - - Args: - cfg (IterableSimpleNamespace): Configuration for the task and mode. - all_keys (bool): Sync all items, not just non-default values. - traces_sample_rate (float): Fraction of traces captured from 0.0 to 1.0 - """ - if SETTINGS['sync'] and RANK in {-1, 0} and (random() < traces_sample_rate): - cfg = vars(cfg) # convert type from IterableSimpleNamespace to dict - if not all_keys: - cfg = {k: v for k, v in cfg.items() if v != DEFAULT_CFG_DICT.get(k, None)} # retain non-default values - cfg['uuid'] = SETTINGS['uuid'] # add the device UUID to the configuration data - - # Send a request to the HUB API to sync analytics - smart_request(f'{HUB_API_ROOT}/v1/usage/anonymous', json=cfg, headers=None, code=3, retry=0, verbose=False) +class Traces: + + def __init__(self): + """ + Initialize Traces for error tracking and reporting if tests are not currently running. + """ + from ultralytics import __version__ + env = 'Colab' if is_colab() else 'Kaggle' if is_kaggle() else 'Jupyter' if is_jupyter() else \ + 'Docker' if is_docker() else platform.system() + self.rate_limit = 3.0 # rate limit (seconds) + self.t = time.time() # rate limit timer (seconds) + self.metadata = { + "sys_argv_name": Path(sys.argv[0]).name, + "install": 'git' if is_git_dir() else 'pip' if is_pip_package() else 'other', + "python": platform.python_version(), + "release": __version__, + "environment": env} + self.enabled = SETTINGS['sync'] and \ + RANK in {-1, 0} and \ + not is_pytest_running() and \ + not is_github_actions_ci() and \ + (is_pip_package() or get_git_origin_url() == "https://github.com/ultralytics/ultralytics.git") + + @TryExcept(verbose=False) + def __call__(self, cfg, all_keys=False, traces_sample_rate=1.0): + """ + Sync traces data if enabled in the global settings + + Args: + cfg (IterableSimpleNamespace): Configuration for the task and mode. + all_keys (bool): Sync all items, not just non-default values. + traces_sample_rate (float): Fraction of traces captured from 0.0 to 1.0 + """ + t = time.time() # current time + if self.enabled and random() < traces_sample_rate and (t - self.t) > self.rate_limit: + self.t = t # reset rate limit timer + cfg = vars(cfg) # convert type from IterableSimpleNamespace to dict + if not all_keys: # filter cfg + include_keys = {'task', 'mode'} # always include + cfg = {k: v for k, v in cfg.items() if v != DEFAULT_CFG_DICT.get(k, None) or k in include_keys} + trace = {'uuid': SETTINGS['uuid'], 'cfg': cfg, 'metadata': self.metadata} + + # Send a request to the HUB API to sync analytics + smart_request(f'{HUB_API_ROOT}/v1/usage/anonymous', + json=trace, + headers=None, + code=3, + retry=0, + verbose=False) + + +# Run below code on hub/utils init ------------------------------------------------------------------------------------- + +traces = Traces() diff --git a/ultralytics/nn/tasks.py b/ultralytics/nn/tasks.py index 2f18597..472e1e1 100644 --- a/ultralytics/nn/tasks.py +++ b/ultralytics/nn/tasks.py @@ -472,10 +472,13 @@ def guess_model_task(model): Raises: SyntaxError: If the task of the model could not be determined. """ - cfg, task = None, None + cfg = None if isinstance(model, dict): cfg = model elif isinstance(model, nn.Module): # PyTorch model + for x in 'model.args', 'model.model.args', 'model.model.model.args': + with contextlib.suppress(Exception): + return eval(x)['task'] for x in 'model.yaml', 'model.model.yaml', 'model.model.model.yaml': with contextlib.suppress(Exception): cfg = eval(x) @@ -485,25 +488,22 @@ def guess_model_task(model): if cfg: m = cfg["head"][-1][-2].lower() # output module name if m in ["classify", "classifier", "cls", "fc"]: - task = "classify" + return "classify" if m in ["detect"]: - task = "detect" + return "detect" if m in ["segment"]: - task = "segment" + return "segment" # Guess from PyTorch model - if task is None and isinstance(model, nn.Module): + if isinstance(model, nn.Module): for m in model.modules(): if isinstance(m, Detect): - task = "detect" + return "detect" elif isinstance(m, Segment): - task = "segment" + return "segment" elif isinstance(m, Classify): - task = "classify" + return "classify" # Unable to determine task from model - if task is None: - raise SyntaxError("YOLO is unable to automatically guess model task. Explicitly define task for your model, " - "i.e. 'task=detect', 'task=segment' or 'task=classify'.") - else: - return task + raise SyntaxError("YOLO is unable to automatically guess model task. Explicitly define task for your model, " + "i.e. 'task=detect', 'task=segment' or 'task=classify'.") diff --git a/ultralytics/yolo/cfg/__init__.py b/ultralytics/yolo/cfg/__init__.py index a14d67b..1293463 100644 --- a/ultralytics/yolo/cfg/__init__.py +++ b/ultralytics/yolo/cfg/__init__.py @@ -8,8 +8,8 @@ from pathlib import Path from types import SimpleNamespace from typing import Dict, List, Union -from ultralytics import __version__, yolo -from ultralytics.yolo.utils import (DEFAULT_CFG_DICT, DEFAULT_CFG_PATH, LOGGER, PREFIX, USER_CONFIG_DIR, +from ultralytics import __version__ +from ultralytics.yolo.utils import (DEFAULT_CFG_DICT, DEFAULT_CFG_PATH, LOGGER, PREFIX, ROOT, USER_CONFIG_DIR, IterableSimpleNamespace, colorstr, yaml_load, yaml_print) from ultralytics.yolo.utils.checks import check_yolo @@ -211,30 +211,42 @@ def entrypoint(debug=False): else: raise argument_error(a) - cfg = get_cfg(DEFAULT_CFG_DICT, overrides) # create CFG instance - - # Checks error catch - if cfg.mode == 'checks': - LOGGER.warning( - "WARNING ⚠️ 'yolo mode=checks' is deprecated and will be removed in the future. Use 'yolo checks' instead.") + # Mode + mode = overrides.pop('mode', None) + model = overrides.pop('model', None) + if mode == 'checks': + LOGGER.warning("WARNING ⚠️ 'yolo mode=checks' is deprecated. Use 'yolo checks' instead.") check_yolo() return - - # Mapping from task to module - module = {"detect": yolo.v8.detect, "segment": yolo.v8.segment, "classify": yolo.v8.classify}.get(cfg.task) - if not module: - raise SyntaxError(f"yolo task={cfg.task} is invalid. Valid tasks are: {', '.join(tasks)}\n{CLI_HELP_MSG}") - - # Mapping from mode to function - func = { - "train": module.train, - "val": module.val, - "predict": module.predict, - "export": yolo.engine.exporter.export}.get(cfg.mode) - if not func: - raise SyntaxError(f"yolo mode={cfg.mode} is invalid. Valid modes are: {', '.join(modes)}\n{CLI_HELP_MSG}") - - func(cfg) + elif mode is None: + mode = DEFAULT_CFG_DICT['mode'] or 'predict' + LOGGER.warning(f"WARNING ⚠️ 'mode' is missing. Valid modes are {modes}. Using default 'mode={mode}'.") + + # Model + if model is None: + model = DEFAULT_CFG_DICT['model'] or 'yolov8n.pt' + LOGGER.warning(f"WARNING ⚠️ 'model' is missing. Using default 'model={model}'.") + from ultralytics.yolo.engine.model import YOLO + model = YOLO(model) + task = model.task + + # Task + if mode == 'predict' and 'source' not in overrides: + overrides['source'] = DEFAULT_CFG_DICT['source'] or ROOT / "assets" if (ROOT / "assets").exists() \ + else "https://ultralytics.com/images/bus.jpg" + LOGGER.warning(f"WARNING ⚠️ 'source' is missing. Using default 'source={overrides['source']}'.") + elif mode in ('train', 'val'): + if 'data' not in overrides: + overrides['data'] = DEFAULT_CFG_DICT['data'] or 'mnist160' if task == 'classify' \ + else 'coco128-seg.yaml' if task == 'segment' else 'coco128.yaml' + LOGGER.warning(f"WARNING ⚠️ 'data' is missing. Using default 'data={overrides['data']}'.") + elif mode == 'export': + if 'format' not in overrides: + overrides['format'] = DEFAULT_CFG_DICT['format'] or 'torchscript' + LOGGER.warning(f"WARNING ⚠️ 'format' is missing. Using default 'format={overrides['format']}'.") + + # Run command in python + getattr(model, mode)(verbose=True, **overrides) # Special modes -------------------------------------------------------------------------------------------------------- diff --git a/ultralytics/yolo/cfg/default.yaml b/ultralytics/yolo/cfg/default.yaml index 55dc670..789f2b7 100644 --- a/ultralytics/yolo/cfg/default.yaml +++ b/ultralytics/yolo/cfg/default.yaml @@ -1,26 +1,26 @@ # Ultralytics YOLO 🚀, GPL-3.0 license # Default training settings and hyperparameters for medium-augmentation COCO training -task: "detect" # inference task, i.e. detect, segment, classify -mode: "train" # YOLO mode, i.e. train, val, predict, export +task: detect # inference task, i.e. detect, segment, classify +mode: train # YOLO mode, i.e. train, val, predict, export # Train settings ------------------------------------------------------------------------------------------------------- -model: null # path to model file, i.e. yolov8n.pt, yolov8n.yaml -data: null # path to data file, i.e. i.e. coco128.yaml +model: # path to model file, i.e. yolov8n.pt, yolov8n.yaml +data: # path to data file, i.e. i.e. coco128.yaml epochs: 100 # number of epochs to train for patience: 50 # epochs to wait for no observable improvement for early stopping of training batch: 16 # number of images per batch (-1 for AutoBatch) imgsz: 640 # size of input images as integer or w,h save: True # save train checkpoints and predict results cache: False # True/ram, disk or False. Use cache for data loading -device: null # device to run on, i.e. cuda device=0 or device=0,1,2,3 or device=cpu +device: # device to run on, i.e. cuda device=0 or device=0,1,2,3 or device=cpu workers: 8 # number of worker threads for data loading (per RANK if DDP) -project: null # project name -name: null # experiment name +project: # project name +name: # experiment name exist_ok: False # whether to overwrite existing experiment pretrained: False # whether to use a pretrained model -optimizer: 'SGD' # optimizer to use, choices=['SGD', 'Adam', 'AdamW', 'RMSProp'] -verbose: False # whether to print verbose output +optimizer: SGD # optimizer to use, choices=['SGD', 'Adam', 'AdamW', 'RMSProp'] +verbose: True # whether to print verbose output seed: 0 # random seed for reproducibility deterministic: True # whether to enable deterministic mode single_cls: False # train multi-class data as single-class @@ -39,7 +39,7 @@ dropout: 0.0 # use dropout regularization (classify train only) val: True # validate/test during training save_json: False # save results to JSON file save_hybrid: False # save hybrid version of labels (labels + additional predictions) -conf: null # object confidence threshold for detection (default 0.25 predict, 0.001 val) +conf: # object confidence threshold for detection (default 0.25 predict, 0.001 val) iou: 0.7 # intersection over union (IoU) threshold for NMS max_det: 300 # maximum number of detections per image half: False # use half precision (FP16) @@ -47,7 +47,7 @@ dnn: False # use OpenCV DNN for ONNX inference plots: True # save plots during train/val # Prediction settings -------------------------------------------------------------------------------------------------- -source: null # source directory for images or videos +source: # source directory for images or videos show: False # show results if possible save_txt: False # save results as .txt file save_conf: False # save results with confidence scores @@ -59,7 +59,7 @@ line_thickness: 3 # bounding box thickness (pixels) visualize: False # visualize model features augment: False # apply image augmentation to prediction sources agnostic_nms: False # class-agnostic NMS -classes: null # filter results by class, i.e. class=0, or class=[0,2,3] +classes: # filter results by class, i.e. class=0, or class=[0,2,3] retina_masks: False # use high-resolution segmentation masks boxes: True # Show boxes in segmentation predictions @@ -70,7 +70,7 @@ optimize: False # TorchScript: optimize for mobile int8: False # CoreML/TF INT8 quantization dynamic: False # ONNX/TF/TensorRT: dynamic axes simplify: False # ONNX: simplify model -opset: 17 # ONNX: opset version +opset: # ONNX: opset version (optional) workspace: 4 # TensorRT: workspace size (GB) nms: False # CoreML: add NMS @@ -103,7 +103,7 @@ mixup: 0.0 # image mixup (probability) copy_paste: 0.0 # segment copy-paste (probability) # Custom config.yaml --------------------------------------------------------------------------------------------------- -cfg: null # for overriding defaults.yaml +cfg: # for overriding defaults.yaml # Debug, do not modify ------------------------------------------------------------------------------------------------- v5loader: False # use legacy YOLOv5 dataloader diff --git a/ultralytics/yolo/utils/__init__.py b/ultralytics/yolo/utils/__init__.py index bf447e1..128f00f 100644 --- a/ultralytics/yolo/utils/__init__.py +++ b/ultralytics/yolo/utils/__init__.py @@ -116,6 +116,9 @@ class IterableSimpleNamespace(SimpleNamespace): # Default configuration with open(DEFAULT_CFG_PATH, errors='ignore') as f: DEFAULT_CFG_DICT = yaml.safe_load(f) + for k, v in DEFAULT_CFG_DICT.items(): + if isinstance(v, str) and v.lower() == 'none': + DEFAULT_CFG_DICT[k] = None DEFAULT_CFG_KEYS = DEFAULT_CFG_DICT.keys() DEFAULT_CFG = IterableSimpleNamespace(**DEFAULT_CFG_DICT) @@ -448,13 +451,13 @@ def set_sentry(): """ def before_send(event, hint): - oss = 'colab' if is_colab() else 'kaggle' if is_kaggle() else 'jupyter' if is_jupyter() else \ - 'docker' if is_docker() else platform.system() + env = 'Colab' if is_colab() else 'Kaggle' if is_kaggle() else 'Jupyter' if is_jupyter() else \ + 'Docker' if is_docker() else platform.system() event['tags'] = { "sys_argv": sys.argv[0], "sys_argv_name": Path(sys.argv[0]).name, "install": 'git' if is_git_dir() else 'pip' if is_pip_package() else 'other', - "os": oss} + "os": env} return event if SETTINGS['sync'] and \ @@ -529,7 +532,7 @@ def set_settings(kwargs, file=USER_CONFIG_DIR / 'settings.yaml'): yaml_save(file, SETTINGS) -# Run below code on utils init ----------------------------------------------------------------------------------------- +# Run below code on yolo/utils init ------------------------------------------------------------------------------------ # Set logger set_logging(LOGGING_NAME) # run before defining LOGGER diff --git a/ultralytics/yolo/utils/callbacks/hub.py b/ultralytics/yolo/utils/callbacks/hub.py index ffea13e..3376945 100644 --- a/ultralytics/yolo/utils/callbacks/hub.py +++ b/ultralytics/yolo/utils/callbacks/hub.py @@ -48,19 +48,19 @@ def on_train_end(trainer): def on_train_start(trainer): - traces(trainer.args, traces_sample_rate=0.0) + traces(trainer.args, traces_sample_rate=1.0) def on_val_start(validator): - traces(validator.args, traces_sample_rate=0.0) + traces(validator.args, traces_sample_rate=1.0) def on_predict_start(predictor): - traces(predictor.args, traces_sample_rate=0.0) + traces(predictor.args, traces_sample_rate=1.0) def on_export_start(exporter): - traces(exporter.args, traces_sample_rate=0.0) + traces(exporter.args, traces_sample_rate=1.0) callbacks = { diff --git a/ultralytics/yolo/utils/torch_utils.py b/ultralytics/yolo/utils/torch_utils.py index 280ad4f..4010eca 100644 --- a/ultralytics/yolo/utils/torch_utils.py +++ b/ultralytics/yolo/utils/torch_utils.py @@ -31,7 +31,7 @@ WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) @contextmanager def torch_distributed_zero_first(local_rank: int): # Decorator to make all processes in distributed training wait for each local_master to do something - initialized = torch.distributed.is_initialized() # prevent 'Default process group has not been initialized' errors + initialized = torch.distributed.is_available() and torch.distributed.is_initialized() if initialized and local_rank not in {-1, 0}: dist.barrier(device_ids=[local_rank]) yield diff --git a/ultralytics/yolo/v8/classify/predict.py b/ultralytics/yolo/v8/classify/predict.py index 917d606..f6c05cf 100644 --- a/ultralytics/yolo/v8/classify/predict.py +++ b/ultralytics/yolo/v8/classify/predict.py @@ -1,4 +1,5 @@ # Ultralytics YOLO 🚀, GPL-3.0 license +import sys import torch @@ -63,12 +64,18 @@ class ClassificationPredictor(BasePredictor): return log_string -def predict(cfg=DEFAULT_CFG): - cfg.model = cfg.model or "yolov8n-cls.pt" # or "resnet18" - cfg.source = cfg.source if cfg.source is not None else ROOT / "assets" if (ROOT / "assets").exists() \ +def predict(cfg=DEFAULT_CFG, use_python=False): + 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() \ else "https://ultralytics.com/images/bus.jpg" - predictor = ClassificationPredictor(cfg) - predictor.predict_cli() + + args = dict(model=model, source=source, verbose=True) + if use_python: + from ultralytics import YOLO + YOLO(model)(**args) + else: + predictor = ClassificationPredictor(args) + predictor.predict_cli() if __name__ == "__main__": diff --git a/ultralytics/yolo/v8/classify/train.py b/ultralytics/yolo/v8/classify/train.py index 2e2a6b9..c26524d 100644 --- a/ultralytics/yolo/v8/classify/train.py +++ b/ultralytics/yolo/v8/classify/train.py @@ -1,4 +1,5 @@ # Ultralytics YOLO 🚀, GPL-3.0 license +import sys import torch import torchvision @@ -135,22 +136,18 @@ class ClassificationTrainer(BaseTrainer): # self.run_callbacks('on_fit_epoch_end') -def train(cfg=DEFAULT_CFG): - cfg.model = cfg.model or "yolov8n-cls.pt" # or "resnet18" - cfg.data = cfg.data or "mnist160" # or yolo.ClassificationDataset("mnist") +def train(cfg=DEFAULT_CFG, use_python=False): + model = cfg.model or "yolov8n-cls.pt" # or "resnet18" + data = cfg.data or "mnist160" # or yolo.ClassificationDataset("mnist") + device = cfg.device if cfg.device is not None else '' - # Reproduce ImageNet results - # cfg.lr0 = 0.1 - # cfg.weight_decay = 5e-5 - # cfg.label_smoothing = 0.1 - # cfg.warmup_epochs = 0.0 - - cfg.device = cfg.device if cfg.device is not None else '' - # trainer = ClassificationTrainer(cfg) - # trainer.train() - from ultralytics import YOLO - model = YOLO(cfg.model) - model.train(**vars(cfg)) + args = dict(model=model, data=data, device=device, verbose=True) + if use_python: + from ultralytics import YOLO + YOLO(model).train(**args) + else: + trainer = ClassificationTrainer(args) + trainer.train() if __name__ == "__main__": diff --git a/ultralytics/yolo/v8/classify/val.py b/ultralytics/yolo/v8/classify/val.py index b28b9ed..21cb159 100644 --- a/ultralytics/yolo/v8/classify/val.py +++ b/ultralytics/yolo/v8/classify/val.py @@ -1,4 +1,5 @@ # Ultralytics YOLO 🚀, GPL-3.0 license +import sys from ultralytics.yolo.data import build_classification_dataloader from ultralytics.yolo.engine.validator import BaseValidator @@ -45,11 +46,17 @@ class ClassificationValidator(BaseValidator): self.logger.info(pf % ("all", self.metrics.top1, self.metrics.top5)) -def val(cfg=DEFAULT_CFG): - cfg.model = cfg.model or "yolov8n-cls.pt" # or "resnet18" - cfg.data = cfg.data or "mnist160" - validator = ClassificationValidator(args=cfg) - validator(model=cfg.model) +def val(cfg=DEFAULT_CFG, use_python=False): + model = cfg.model or "yolov8n-cls.pt" # or "resnet18" + data = cfg.data or "mnist160" + + args = dict(model=model, data=data, verbose=True) + if use_python: + from ultralytics import YOLO + YOLO(model).val(**args) + else: + validator = ClassificationValidator(args=args) + validator(model=args['model']) if __name__ == "__main__": diff --git a/ultralytics/yolo/v8/detect/predict.py b/ultralytics/yolo/v8/detect/predict.py index 581b686..2131b83 100644 --- a/ultralytics/yolo/v8/detect/predict.py +++ b/ultralytics/yolo/v8/detect/predict.py @@ -1,4 +1,5 @@ # Ultralytics YOLO 🚀, GPL-3.0 license +import sys import torch @@ -81,12 +82,18 @@ class DetectionPredictor(BasePredictor): return log_string -def predict(cfg=DEFAULT_CFG): - cfg.model = cfg.model or "yolov8n.pt" - cfg.source = cfg.source if cfg.source is not None else ROOT / "assets" if (ROOT / "assets").exists() \ +def predict(cfg=DEFAULT_CFG, use_python=False): + model = cfg.model or "yolov8n.pt" + source = cfg.source if cfg.source is not None else ROOT / "assets" if (ROOT / "assets").exists() \ else "https://ultralytics.com/images/bus.jpg" - predictor = DetectionPredictor(cfg) - predictor.predict_cli() + + args = dict(model=model, source=source, verbose=True) + if use_python: + from ultralytics import YOLO + YOLO(model)(**args) + else: + predictor = DetectionPredictor(args) + predictor.predict_cli() if __name__ == "__main__": diff --git a/ultralytics/yolo/v8/detect/train.py b/ultralytics/yolo/v8/detect/train.py index 6c5d6e9..719568b 100644 --- a/ultralytics/yolo/v8/detect/train.py +++ b/ultralytics/yolo/v8/detect/train.py @@ -1,5 +1,5 @@ # Ultralytics YOLO 🚀, GPL-3.0 license - +import sys from copy import copy import torch @@ -194,15 +194,18 @@ class Loss: return loss.sum() * batch_size, loss.detach() # loss(box, cls, dfl) -def train(cfg=DEFAULT_CFG): - cfg.model = cfg.model or "yolov8n.pt" - cfg.data = cfg.data or "coco128.yaml" # or yolo.ClassificationDataset("mnist") - cfg.device = cfg.device if cfg.device is not None else '' - # trainer = DetectionTrainer(cfg) - # trainer.train() - from ultralytics import YOLO - model = YOLO(cfg.model) - model.train(**vars(cfg)) +def train(cfg=DEFAULT_CFG, use_python=False): + model = cfg.model or "yolov8n.pt" + data = cfg.data or "coco128.yaml" # or yolo.ClassificationDataset("mnist") + device = cfg.device if cfg.device is not None else '' + + args = dict(model=model, data=data, device=device, verbose=True) + if use_python: + from ultralytics import YOLO + YOLO(model).train(**args) + else: + trainer = DetectionTrainer(args) + trainer.train() if __name__ == "__main__": diff --git a/ultralytics/yolo/v8/detect/val.py b/ultralytics/yolo/v8/detect/val.py index e338964..ab6e465 100644 --- a/ultralytics/yolo/v8/detect/val.py +++ b/ultralytics/yolo/v8/detect/val.py @@ -1,6 +1,7 @@ # Ultralytics YOLO 🚀, GPL-3.0 license import os +import sys from pathlib import Path import numpy as np @@ -232,11 +233,17 @@ class DetectionValidator(BaseValidator): return stats -def val(cfg=DEFAULT_CFG): - cfg.model = cfg.model or "yolov8n.pt" - cfg.data = cfg.data or "coco128.yaml" - validator = DetectionValidator(args=cfg) - validator(model=cfg.model) +def val(cfg=DEFAULT_CFG, use_python=False): + model = cfg.model or "yolov8n.pt" + data = cfg.data or "coco128.yaml" + + args = dict(model=model, data=data, verbose=True) + if use_python: + from ultralytics import YOLO + YOLO(model).val(**args) + else: + validator = DetectionValidator(args=args) + validator(model=args['model']) if __name__ == "__main__": diff --git a/ultralytics/yolo/v8/segment/predict.py b/ultralytics/yolo/v8/segment/predict.py index 78c48d6..76bd0eb 100644 --- a/ultralytics/yolo/v8/segment/predict.py +++ b/ultralytics/yolo/v8/segment/predict.py @@ -1,5 +1,7 @@ # Ultralytics YOLO 🚀, GPL-3.0 license +import sys + import torch from ultralytics.yolo.engine.results import Results @@ -98,12 +100,18 @@ class SegmentationPredictor(DetectionPredictor): return log_string -def predict(cfg=DEFAULT_CFG): - cfg.model = cfg.model or "yolov8n-seg.pt" - cfg.source = cfg.source if cfg.source is not None else ROOT / "assets" if (ROOT / "assets").exists() \ +def predict(cfg=DEFAULT_CFG, use_python=False): + model = cfg.model or "yolov8n-seg.pt" + source = cfg.source if cfg.source is not None else ROOT / "assets" if (ROOT / "assets").exists() \ else "https://ultralytics.com/images/bus.jpg" - predictor = SegmentationPredictor(cfg) - predictor.predict_cli() + + args = dict(model=model, source=source, verbose=True) + if use_python: + from ultralytics import YOLO + YOLO(model)(**args) + else: + predictor = SegmentationPredictor(args) + predictor.predict_cli() if __name__ == "__main__": diff --git a/ultralytics/yolo/v8/segment/train.py b/ultralytics/yolo/v8/segment/train.py index fbd96f8..8964e0b 100644 --- a/ultralytics/yolo/v8/segment/train.py +++ b/ultralytics/yolo/v8/segment/train.py @@ -1,5 +1,5 @@ # Ultralytics YOLO 🚀, GPL-3.0 license - +import sys from copy import copy import torch @@ -140,15 +140,18 @@ class SegLoss(Loss): return (crop_mask(loss, xyxy).mean(dim=(1, 2)) / area).mean() -def train(cfg=DEFAULT_CFG): - cfg.model = cfg.model or "yolov8n-seg.pt" - cfg.data = cfg.data or "coco128-seg.yaml" # or yolo.ClassificationDataset("mnist") - cfg.device = cfg.device if cfg.device is not None else '' - # trainer = SegmentationTrainer(cfg) - # trainer.train() - from ultralytics import YOLO - model = YOLO(cfg.model) - model.train(**vars(cfg)) +def train(cfg=DEFAULT_CFG, use_python=False): + model = cfg.model or "yolov8n-seg.pt" + data = cfg.data or "coco128-seg.yaml" # or yolo.ClassificationDataset("mnist") + device = cfg.device if cfg.device is not None else '' + + args = dict(model=model, data=data, device=device, verbose=True) + if use_python: + from ultralytics import YOLO + YOLO(model).train(**args) + else: + trainer = SegmentationTrainer(args) + trainer.train() if __name__ == "__main__": diff --git a/ultralytics/yolo/v8/segment/val.py b/ultralytics/yolo/v8/segment/val.py index 276a50b..492a682 100644 --- a/ultralytics/yolo/v8/segment/val.py +++ b/ultralytics/yolo/v8/segment/val.py @@ -1,6 +1,7 @@ # Ultralytics YOLO 🚀, GPL-3.0 license import os +import sys from multiprocessing.pool import ThreadPool from pathlib import Path @@ -242,10 +243,17 @@ class SegmentationValidator(DetectionValidator): return stats -def val(cfg=DEFAULT_CFG): - cfg.data = cfg.data or "coco128-seg.yaml" - validator = SegmentationValidator(args=cfg) - validator(model=cfg.model) +def val(cfg=DEFAULT_CFG, use_python=False): + model = cfg.model or "yolov8n-seg.pt" + data = cfg.data or "coco128-seg.yaml" + + args = dict(model=model, data=data, verbose=True) + if use_python: + from ultralytics import YOLO + YOLO(model).val(**args) + else: + validator = SegmentationValidator(args=args) + validator(model=args['model']) if __name__ == "__main__":