ultralytics 8.0.59
new MLFlow and feature updates (#1720)
Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: St. HeMeow <sheng.heyang@gmail.com> Co-authored-by: Danny Kim <imbird0312@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Torge Kummerow <CySlider@users.noreply.github.com> Co-authored-by: dankernel <dkdkernel@gmail.com> Co-authored-by: Burhan <62214284+Burhan-Q@users.noreply.github.com> Co-authored-by: Roshanlal <roshanlaladchitre103@gmail.com> Co-authored-by: Lorenzo Mammana <lorenzo.mammana@orobix.com> Co-authored-by: Yonghye Kwon <developer.0hye@gmail.com>
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
# Ultralytics YOLO 🚀, GPL-3.0 license
|
||||
|
||||
__version__ = '8.0.58'
|
||||
__version__ = '8.0.59'
|
||||
|
||||
from ultralytics.yolo.engine.model import YOLO
|
||||
from ultralytics.yolo.utils.checks import check_yolo as checks
|
||||
|
@ -14,11 +14,7 @@ def start(key=''):
|
||||
Start training models with Ultralytics HUB. Usage: from ultralytics.hub import start; start('API_KEY')
|
||||
"""
|
||||
auth = Auth(key)
|
||||
if not auth.get_state():
|
||||
model_id = request_api_key(auth)
|
||||
else:
|
||||
_, model_id = split_key(key)
|
||||
|
||||
model_id = split_key(key)[1] if auth.get_state() else request_api_key(auth)
|
||||
if not model_id:
|
||||
raise ConnectionError(emojis('Connecting with global API key is not currently supported. ❌'))
|
||||
|
||||
@ -36,7 +32,8 @@ def request_api_key(auth, max_attempts=3):
|
||||
import getpass
|
||||
for attempts in range(max_attempts):
|
||||
LOGGER.info(f'{PREFIX}Login. Attempt {attempts + 1} of {max_attempts}')
|
||||
input_key = getpass.getpass('Enter your Ultralytics HUB API key:\n')
|
||||
input_key = getpass.getpass(
|
||||
'Enter your Ultralytics API Key from https://hub.ultralytics.com/settings?tab=api+keys:\n')
|
||||
auth.api_key, model_id = split_key(input_key)
|
||||
|
||||
if auth.authenticate():
|
||||
|
@ -12,9 +12,9 @@ from random import random
|
||||
import requests
|
||||
from tqdm import tqdm
|
||||
|
||||
from ultralytics.yolo.utils import (DEFAULT_CFG_DICT, ENVIRONMENT, LOGGER, ONLINE, RANK, SETTINGS, TESTS_RUNNING,
|
||||
TQDM_BAR_FORMAT, TryExcept, __version__, colorstr, emojis, get_git_origin_url,
|
||||
is_colab, is_git_dir, is_pip_package)
|
||||
from ultralytics.yolo.utils import (ENVIRONMENT, LOGGER, ONLINE, RANK, SETTINGS, TESTS_RUNNING, TQDM_BAR_FORMAT,
|
||||
TryExcept, __version__, colorstr, emojis, get_git_origin_url, is_colab, is_git_dir,
|
||||
is_pip_package)
|
||||
|
||||
PREFIX = colorstr('Ultralytics HUB: ')
|
||||
HELP_MSG = 'If this issue persists please visit https://github.com/ultralytics/hub/issues for assistance.'
|
||||
@ -76,7 +76,7 @@ def split_key(key=''):
|
||||
error_string = emojis(f'{PREFIX}Invalid API key ⚠️\n') # error string
|
||||
if not key:
|
||||
key = getpass.getpass('Enter model key: ')
|
||||
sep = '_' if '_' in key else '.' if '.' in key else None # separator
|
||||
sep = '_' if '_' in key else None # separator
|
||||
assert sep, error_string
|
||||
api_key, model_id = key.split(sep)
|
||||
assert len(api_key) and len(model_id), error_string
|
||||
@ -172,7 +172,8 @@ class Traces:
|
||||
"""
|
||||
Initialize Traces for error tracking and reporting if tests are not currently running.
|
||||
"""
|
||||
self.rate_limit = 3.0 # rate limit (seconds)
|
||||
from ultralytics.yolo.cfg import MODES, TASKS
|
||||
self.rate_limit = 60.0 # rate limit (seconds)
|
||||
self.t = 0.0 # rate limit timer (seconds)
|
||||
self.metadata = {
|
||||
'sys_argv_name': Path(sys.argv[0]).name,
|
||||
@ -186,6 +187,7 @@ class Traces:
|
||||
not TESTS_RUNNING and \
|
||||
ONLINE and \
|
||||
(is_pip_package() or get_git_origin_url() == 'https://github.com/ultralytics/ultralytics.git')
|
||||
self.usage = {'tasks': {k: 0 for k in TASKS}, 'modes': {k: 0 for k in MODES}}
|
||||
|
||||
def __call__(self, cfg, all_keys=False, traces_sample_rate=1.0):
|
||||
"""
|
||||
@ -197,15 +199,22 @@ class Traces:
|
||||
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:
|
||||
if not self.enabled or random() > traces_sample_rate:
|
||||
# Traces disabled or not randomly selected, do nothing
|
||||
return
|
||||
elif (t - self.t) < self.rate_limit:
|
||||
# Time is under rate limiter, do nothing
|
||||
return
|
||||
else:
|
||||
# Time is over rate limiter, send trace now
|
||||
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.split(os.sep)[-1] if isinstance(v, str) and os.sep in v else 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}
|
||||
|
||||
# Build trace
|
||||
if cfg.task in self.usage['tasks']:
|
||||
self.usage['tasks'][cfg.task] += 1
|
||||
if cfg.mode in self.usage['modes']:
|
||||
self.usage['modes'][cfg.mode] += 1
|
||||
trace = {'uuid': SETTINGS['uuid'], 'usage': self.usage, 'metadata': self.metadata}
|
||||
|
||||
# Send a request to the HUB API to sync analytics
|
||||
smart_request('post', f'{HUB_API_ROOT}/v1/usage/anonymous', json=trace, code=3, retry=0, verbose=False)
|
||||
|
@ -45,7 +45,7 @@ Any of these models can be used by loading their configs or pretrained checkpoin
|
||||
### 1. YOLOv8
|
||||
|
||||
**About** - Cutting edge Detection, Segmentation and Classification models developed by Ultralytics. </br>
|
||||
**Citation** -
|
||||
|
||||
Available Models:
|
||||
|
||||
- Detection - `yolov8n`, `yolov8s`, `yolov8m`, `yolov8l`, `yolov8x`
|
||||
@ -89,21 +89,28 @@ Available Models:
|
||||
### 2. YOLOv5u
|
||||
|
||||
**About** - Anchor-free YOLOv5 models with new detection head and better speed-accuracy tradeoff </br>
|
||||
**Citation** -
|
||||
|
||||
Available Models:
|
||||
|
||||
- Detection - `yolov5nu`, `yolov5su`, `yolov5mu`, `yolov5lu`, `yolov5xu`
|
||||
- Detection P5/32 - `yolov5nu`, `yolov5su`, `yolov5mu`, `yolov5lu`, `yolov5xu`
|
||||
- Detection P6/64 - `yolov5n6u`, `yolov5s6u`, `yolov5m6u`, `yolov5l6u`, `yolov5x6u`
|
||||
|
||||
<details><summary>Performance</summary>
|
||||
|
||||
### Detection
|
||||
|
||||
| Model | size<br><sup>(pixels) | mAP<sup>val<br>50-95 | Speed<br><sup>CPU ONNX<br>(ms) | Speed<br><sup>A100 TensorRT<br>(ms) | params<br><sup>(M) | FLOPs<br><sup>(B) |
|
||||
| -------------------------------------------------------------------------------------- | --------------------- | -------------------- | ------------------------------ | ----------------------------------- | ------------------ | ----------------- |
|
||||
| [YOLOv5nu](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov5nu.pt) | 640 | 34.3 | 73.6 | 1.06 | 2.6 | 7.7 |
|
||||
| [YOLOv5su](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov5su.pt) | 640 | 43.0 | 120.7 | 1.27 | 9.1 | 24.0 |
|
||||
| [YOLOv5mu](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov5mu.pt) | 640 | 49.0 | 233.9 | 1.86 | 25.1 | 64.2 |
|
||||
| [YOLOv5lu](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov5lu.pt) | 640 | 52.2 | 408.4 | 2.50 | 53.2 | 135.0 |
|
||||
| [YOLOv5xu](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov5xu.pt) | 640 | 53.2 | 763.2 | 3.81 | 97.2 | 246.4 |
|
||||
| Model | size<br><sup>(pixels) | mAP<sup>val<br>50-95 | Speed<br><sup>CPU ONNX<br>(ms) | Speed<br><sup>A100 TensorRT<br>(ms) | params<br><sup>(M) | FLOPs<br><sup>(B) |
|
||||
| ---------------------------------------------------------------------------------------- | --------------------- | -------------------- | ------------------------------ | ----------------------------------- | ------------------ | ----------------- |
|
||||
| [YOLOv5nu](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov5nu.pt) | 640 | 34.3 | 73.6 | 1.06 | 2.6 | 7.7 |
|
||||
| [YOLOv5su](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov5su.pt) | 640 | 43.0 | 120.7 | 1.27 | 9.1 | 24.0 |
|
||||
| [YOLOv5mu](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov5mu.pt) | 640 | 49.0 | 233.9 | 1.86 | 25.1 | 64.2 |
|
||||
| [YOLOv5lu](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov5lu.pt) | 640 | 52.2 | 408.4 | 2.50 | 53.2 | 135.0 |
|
||||
| [YOLOv5xu](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov5xu.pt) | 640 | 53.2 | 763.2 | 3.81 | 97.2 | 246.4 |
|
||||
| | | | | | | |
|
||||
| [YOLOv5n6u](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov5n6u.pt) | 1280 | 42.1 | - | - | 4.3 | 7.8 |
|
||||
| [YOLOv5s6u](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov5s6u.pt) | 1280 | 48.6 | - | - | 15.3 | 24.6 |
|
||||
| [YOLOv5m6u](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov5m6u.pt) | 1280 | 53.6 | - | - | 41.2 | 65.7 |
|
||||
| [YOLOv5l6u](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov5l6u.pt) | 1280 | 55.7 | - | - | 86.1 | 137.4 |
|
||||
| [YOLOv5x6u](https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov5x6u.pt) | 1280 | 56.8 | - | - | 155.4 | 250.7 |
|
||||
|
||||
</details>
|
||||
|
@ -11,14 +11,28 @@ from typing import Dict, List, Union
|
||||
from ultralytics.yolo.utils import (DEFAULT_CFG, DEFAULT_CFG_DICT, DEFAULT_CFG_PATH, LOGGER, ROOT, USER_CONFIG_DIR,
|
||||
IterableSimpleNamespace, __version__, checks, colorstr, yaml_load, yaml_print)
|
||||
|
||||
# Define valid tasks and modes
|
||||
MODES = 'train', 'val', 'predict', 'export', 'track', 'benchmark'
|
||||
TASKS = 'detect', 'segment', 'classify', 'pose'
|
||||
TASK2DATA = {
|
||||
'detect': 'coco128.yaml',
|
||||
'segment': 'coco128-seg.yaml',
|
||||
'pose': 'coco128-pose.yaml',
|
||||
'classify': 'imagenet100'}
|
||||
TASK2MODEL = {
|
||||
'detect': 'yolov8n.pt',
|
||||
'segment': 'yolov8n-seg.pt',
|
||||
'pose': 'yolov8n-pose.yaml',
|
||||
'classify': 'yolov8n-cls.pt'} # temp
|
||||
|
||||
CLI_HELP_MSG = \
|
||||
f"""
|
||||
Arguments received: {str(['yolo'] + sys.argv[1:])}. Ultralytics 'yolo' commands use the following syntax:
|
||||
|
||||
yolo TASK MODE ARGS
|
||||
|
||||
Where TASK (optional) is one of [detect, segment, classify]
|
||||
MODE (required) is one of [train, val, predict, export, track]
|
||||
Where TASK (optional) is one of {TASKS}
|
||||
MODE (required) is one of {MODES}
|
||||
ARGS (optional) are any number of custom 'arg=value' pairs like 'imgsz=320' that override defaults.
|
||||
See all ARGS at https://docs.ultralytics.com/usage/cfg or with 'yolo cfg'
|
||||
|
||||
@ -59,12 +73,6 @@ CFG_BOOL_KEYS = ('save', 'exist_ok', 'verbose', 'deterministic', 'single_cls', '
|
||||
'save_conf', 'save_crop', 'hide_labels', 'hide_conf', 'visualize', 'augment', 'agnostic_nms',
|
||||
'retina_masks', 'boxes', 'keras', 'optimize', 'int8', 'dynamic', 'simplify', 'nms', 'v5loader')
|
||||
|
||||
# Define valid tasks and modes
|
||||
MODES = 'train', 'val', 'predict', 'export', 'track', 'benchmark'
|
||||
TASKS = 'detect', 'segment', 'classify'
|
||||
TASK2DATA = {'detect': 'coco128.yaml', 'segment': 'coco128-seg.yaml', 'classify': 'imagenet100'}
|
||||
TASK2MODEL = {'detect': 'yolov8n.pt', 'segment': 'yolov8n-seg.pt', 'classify': 'yolov8n-cls.pt'}
|
||||
|
||||
|
||||
def cfg2dict(cfg):
|
||||
"""
|
||||
|
@ -26,7 +26,7 @@ seed: 0 # random seed for reproducibility
|
||||
deterministic: True # whether to enable deterministic mode
|
||||
single_cls: False # train multi-class data as single-class
|
||||
image_weights: False # use weighted image selection for training
|
||||
rect: False # support rectangular training if mode='train', support rectangular evaluation if mode='val'
|
||||
rect: False # rectangular training if mode='train' or rectangular validation if mode='val'
|
||||
cos_lr: False # use cosine learning rate scheduler
|
||||
close_mosaic: 10 # disable mosaic augmentation for final 10 epochs
|
||||
resume: False # resume training from last checkpoint
|
||||
|
@ -278,6 +278,7 @@ def check_cls_dataset(dataset: str):
|
||||
data (dict): A dictionary containing the following keys and values:
|
||||
'train': Path object for the directory containing the training set of the dataset
|
||||
'val': Path object for the directory containing the validation set of the dataset
|
||||
'test': Path object for the directory containing the test set of the dataset
|
||||
'nc': Number of classes in the dataset
|
||||
'names': List of class names in the dataset
|
||||
"""
|
||||
@ -293,11 +294,12 @@ def check_cls_dataset(dataset: str):
|
||||
s = f"Dataset download success ✅ ({time.time() - t:.1f}s), saved to {colorstr('bold', data_dir)}\n"
|
||||
LOGGER.info(s)
|
||||
train_set = data_dir / 'train'
|
||||
test_set = data_dir / 'test' if (data_dir / 'test').exists() else data_dir / 'val' # data/test or data/val
|
||||
val_set = data_dir / 'val' if (data_dir / 'val').exists() else None # data/test or data/val
|
||||
test_set = data_dir / 'test' if (data_dir / 'test').exists() else None # data/val or data/test
|
||||
nc = len([x for x in (data_dir / 'train').glob('*') if x.is_dir()]) # number of classes
|
||||
names = [x.name for x in (data_dir / 'train').iterdir() if x.is_dir()] # class names list
|
||||
names = dict(enumerate(sorted(names)))
|
||||
return {'train': train_set, 'val': test_set, 'nc': nc, 'names': names}
|
||||
return {'train': train_set, 'val': val_set, 'test': test_set, 'nc': nc, 'names': names}
|
||||
|
||||
|
||||
class HUBDatasetStats():
|
||||
|
@ -230,8 +230,9 @@ class YOLO:
|
||||
return self.predictor.predict_cli(source=source) if is_cli else self.predictor(source=source, stream=stream)
|
||||
|
||||
def track(self, source=None, stream=False, **kwargs):
|
||||
from ultralytics.tracker import register_tracker
|
||||
register_tracker(self)
|
||||
if not hasattr(self.predictor, 'trackers'):
|
||||
from ultralytics.tracker import register_tracker
|
||||
register_tracker(self)
|
||||
# ByteTrack-based method needs low confidence predictions as input
|
||||
conf = kwargs.get('conf') or 0.1
|
||||
kwargs['conf'] = conf
|
||||
|
@ -3,16 +3,16 @@
|
||||
Run prediction on images, videos, directories, globs, YouTube, webcam, streams, etc.
|
||||
|
||||
Usage - sources:
|
||||
$ yolo mode=predict model=yolov8n.pt --source 0 # webcam
|
||||
img.jpg # image
|
||||
vid.mp4 # video
|
||||
screen # screenshot
|
||||
path/ # directory
|
||||
list.txt # list of images
|
||||
list.streams # list of streams
|
||||
'path/*.jpg' # glob
|
||||
'https://youtu.be/Zgi9g1ksQHc' # YouTube
|
||||
'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream
|
||||
$ yolo mode=predict model=yolov8n.pt source=0 # webcam
|
||||
img.jpg # image
|
||||
vid.mp4 # video
|
||||
screen # screenshot
|
||||
path/ # directory
|
||||
list.txt # list of images
|
||||
list.streams # list of streams
|
||||
'path/*.jpg' # glob
|
||||
'https://youtu.be/Zgi9g1ksQHc' # YouTube
|
||||
'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream
|
||||
|
||||
Usage - formats:
|
||||
$ yolo mode=predict model=yolov8n.pt # PyTorch
|
||||
|
@ -14,6 +14,7 @@ import torchvision.transforms.functional as F
|
||||
|
||||
from ultralytics.yolo.utils import LOGGER, SimpleClass, ops
|
||||
from ultralytics.yolo.utils.plotting import Annotator, colors
|
||||
from ultralytics.yolo.utils.torch_utils import TORCHVISION_0_10
|
||||
|
||||
|
||||
class Results(SimpleClass):
|
||||
@ -129,7 +130,10 @@ class Results(SimpleClass):
|
||||
|
||||
if masks is not None:
|
||||
im = torch.as_tensor(annotator.im, dtype=torch.float16, device=masks.data.device).permute(2, 0, 1).flip(0)
|
||||
im = F.resize(im.contiguous(), masks.data.shape[1:]) / 255
|
||||
if TORCHVISION_0_10:
|
||||
im = F.resize(im.contiguous(), masks.data.shape[1:], antialias=True) / 255
|
||||
else:
|
||||
im = F.resize(im.contiguous(), masks.data.shape[1:]) / 255
|
||||
annotator.masks(masks.data, colors=[colors(x, True) for x in boxes.cls], im_gpu=im)
|
||||
|
||||
if probs is not None:
|
||||
@ -259,7 +263,8 @@ class Masks(SimpleClass):
|
||||
orig_shape (tuple): Original image size, in the format (height, width).
|
||||
|
||||
Properties:
|
||||
segments (list): A list of segments which includes x, y, w, h, label, confidence, and mask of each detection.
|
||||
xy (list): A list of segments (pixels) which includes x, y segments of each detection.
|
||||
xyn (list): A list of segments (normalized) which includes x, y segments of each detection.
|
||||
|
||||
Methods:
|
||||
cpu(): Returns a copy of the masks tensor on CPU memory.
|
||||
@ -272,13 +277,28 @@ class Masks(SimpleClass):
|
||||
self.masks = masks # N, h, w
|
||||
self.orig_shape = orig_shape
|
||||
|
||||
def segments(self):
|
||||
# Segments-deprecated (normalized)
|
||||
LOGGER.warning("WARNING ⚠️ 'Masks.segments' is deprecated. Use 'Masks.xyn' for segments (normalized) and "
|
||||
"'Masks.xy' for segments (pixels) instead.")
|
||||
return self.xyn
|
||||
|
||||
@property
|
||||
@lru_cache(maxsize=1)
|
||||
def segments(self):
|
||||
def xyn(self):
|
||||
# Segments (normalized)
|
||||
return [
|
||||
ops.scale_segments(self.masks.shape[1:], x, self.orig_shape, normalize=True)
|
||||
for x in ops.masks2segments(self.masks)]
|
||||
|
||||
@property
|
||||
@lru_cache(maxsize=1)
|
||||
def xy(self):
|
||||
# Segments (pixels)
|
||||
return [
|
||||
ops.scale_segments(self.masks.shape[1:], x, self.orig_shape, normalize=False)
|
||||
for x in ops.masks2segments(self.masks)]
|
||||
|
||||
@property
|
||||
def shape(self):
|
||||
return self.masks.shape
|
||||
|
@ -370,6 +370,7 @@ class BaseTrainer:
|
||||
self.epoch_time = tnow - self.epoch_time_start
|
||||
self.epoch_time_start = tnow
|
||||
self.run_callbacks('on_fit_epoch_end')
|
||||
torch.cuda.empty_cache() # clears GPU vRAM at end of epoch, can help with out of memory errors
|
||||
|
||||
# Early Stopping
|
||||
if RANK != -1: # if DDP training
|
||||
|
@ -484,7 +484,7 @@ def get_user_config_dir(sub_dir='Ultralytics'):
|
||||
return path
|
||||
|
||||
|
||||
USER_CONFIG_DIR = os.getenv('YOLO_CONFIG_DIR', get_user_config_dir()) # Ultralytics settings dir
|
||||
USER_CONFIG_DIR = Path(os.getenv('YOLO_CONFIG_DIR', get_user_config_dir())) # Ultralytics settings dir
|
||||
|
||||
|
||||
def emojis(string=''):
|
||||
|
@ -48,8 +48,6 @@ def benchmark(model=Path(SETTINGS['weights_dir']) / 'yolov8n.pt', imgsz=160, hal
|
||||
for i, (name, format, suffix, cpu, gpu) in export_formats().iterrows(): # index, (name, format, suffix, CPU, GPU)
|
||||
emoji, filename = '❌', None # export defaults
|
||||
try:
|
||||
if model.task == 'classify':
|
||||
assert i != 11, 'paddle cls exports coming soon'
|
||||
assert i != 9 or LINUX, 'Edge TPU export only supported on Linux'
|
||||
if i == 10:
|
||||
assert MACOS or LINUX, 'TF.js export only supported on macOS and Linux'
|
||||
|
@ -147,9 +147,10 @@ def add_integration_callbacks(instance):
|
||||
from .clearml import callbacks as clearml_callbacks
|
||||
from .comet import callbacks as comet_callbacks
|
||||
from .hub import callbacks as hub_callbacks
|
||||
from .mlflow import callbacks as mf_callbacks
|
||||
from .tensorboard import callbacks as tb_callbacks
|
||||
|
||||
for x in clearml_callbacks, comet_callbacks, hub_callbacks, tb_callbacks:
|
||||
for x in clearml_callbacks, comet_callbacks, hub_callbacks, tb_callbacks, mf_callbacks:
|
||||
for k, v in x.items():
|
||||
if v not in instance.callbacks[k]: # prevent duplicate callbacks addition
|
||||
instance.callbacks[k].append(v) # callback[name].append(func)
|
||||
|
@ -6,9 +6,9 @@ try:
|
||||
import clearml
|
||||
from clearml import Task
|
||||
|
||||
assert clearml.__version__ # verify package is not directory
|
||||
assert hasattr(clearml, '__version__') # verify package is not directory
|
||||
assert not TESTS_RUNNING # do not log pytest
|
||||
except (ImportError, AssertionError, AttributeError):
|
||||
except (ImportError, AssertionError):
|
||||
clearml = None
|
||||
|
||||
|
||||
|
@ -6,8 +6,8 @@ try:
|
||||
import comet_ml
|
||||
|
||||
assert not TESTS_RUNNING # do not log pytest
|
||||
assert comet_ml.__version__ # verify package is not directory
|
||||
except (ImportError, AssertionError, AttributeError):
|
||||
assert hasattr(comet_ml, '__version__') # verify package is not directory
|
||||
except (ImportError, AssertionError):
|
||||
comet_ml = None
|
||||
|
||||
|
||||
|
75
ultralytics/yolo/utils/callbacks/mlflow.py
Normal file
75
ultralytics/yolo/utils/callbacks/mlflow.py
Normal file
@ -0,0 +1,75 @@
|
||||
# Ultralytics YOLO 🚀, GPL-3.0 license
|
||||
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
from ultralytics.yolo.utils import LOGGER, TESTS_RUNNING, colorstr
|
||||
|
||||
try:
|
||||
import mlflow
|
||||
|
||||
assert not TESTS_RUNNING # do not log pytest
|
||||
assert hasattr(mlflow, '__version__') # verify package is not directory
|
||||
except (ImportError, AssertionError):
|
||||
mlflow = None
|
||||
|
||||
|
||||
def on_pretrain_routine_end(trainer):
|
||||
global mlflow, run, run_id, experiment_name
|
||||
|
||||
if os.environ.get('MLFLOW_TRACKING_URI') is None:
|
||||
mlflow = None
|
||||
|
||||
if mlflow:
|
||||
mlflow_location = os.environ['MLFLOW_TRACKING_URI'] # "http://192.168.xxx.xxx:5000"
|
||||
mlflow.set_tracking_uri(mlflow_location)
|
||||
|
||||
experiment_name = trainer.args.project or 'YOLOv8'
|
||||
experiment = mlflow.get_experiment_by_name(experiment_name)
|
||||
if experiment is None:
|
||||
mlflow.create_experiment(experiment_name)
|
||||
mlflow.set_experiment(experiment_name)
|
||||
|
||||
prefix = colorstr('MLFlow: ')
|
||||
try:
|
||||
run, active_run = mlflow, mlflow.start_run() if mlflow else None
|
||||
if active_run is not None:
|
||||
run_id = active_run.info.run_id
|
||||
LOGGER.info(f'{prefix}Using run_id({run_id}) at {mlflow_location}')
|
||||
except Exception as err:
|
||||
LOGGER.error(f'{prefix}Failing init - {repr(err)}')
|
||||
LOGGER.warning(f'{prefix}Continuing without Mlflow')
|
||||
run = None
|
||||
|
||||
run.log_params(vars(trainer.model.args))
|
||||
|
||||
|
||||
def on_fit_epoch_end(trainer):
|
||||
if mlflow:
|
||||
metrics_dict = {f"{re.sub('[()]', '', k)}": float(v) for k, v in trainer.metrics.items()}
|
||||
run.log_metrics(metrics=metrics_dict, step=trainer.epoch)
|
||||
|
||||
|
||||
def on_model_save(trainer):
|
||||
if mlflow:
|
||||
run.log_artifact(trainer.last)
|
||||
|
||||
|
||||
def on_train_end(trainer):
|
||||
if mlflow:
|
||||
root_dir = Path(__file__).resolve().parents[3]
|
||||
run.log_artifact(trainer.best)
|
||||
model_uri = f'runs:/{run_id}/'
|
||||
run.register_model(model_uri, experiment_name)
|
||||
run.pyfunc.log_model(artifact_path=experiment_name,
|
||||
code_path=[str(root_dir)],
|
||||
artifacts={'model_path': str(trainer.save_dir)},
|
||||
python_model=run.pyfunc.PythonModel())
|
||||
|
||||
|
||||
callbacks = {
|
||||
'on_pretrain_routine_end': on_pretrain_routine_end,
|
||||
'on_fit_epoch_end': on_fit_epoch_end,
|
||||
'on_model_save': on_model_save,
|
||||
'on_train_end': on_train_end} if mlflow else {}
|
@ -16,10 +16,12 @@ import torch
|
||||
import torch.distributed as dist
|
||||
import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
import torchvision
|
||||
|
||||
from ultralytics.yolo.utils import DEFAULT_CFG_DICT, DEFAULT_CFG_KEYS, LOGGER, RANK, __version__
|
||||
from ultralytics.yolo.utils.checks import check_version
|
||||
|
||||
TORCHVISION_0_10 = check_version(torchvision.__version__, '0.10.0')
|
||||
TORCH_1_9 = check_version(torch.__version__, '1.9.0')
|
||||
TORCH_1_11 = check_version(torch.__version__, '1.11.0')
|
||||
TORCH_1_12 = check_version(torch.__version__, '1.12.0')
|
||||
|
Reference in New Issue
Block a user