CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hukaixuan19970627

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

GitHub Repository: hukaixuan19970627/yolov5_obb
Path: blob/master/utils/loggers/__init__.py
Views: 475
1
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
2
"""
3
Logging utils
4
"""
5
6
import os
7
import warnings
8
from threading import Thread
9
10
import pkg_resources as pkg
11
import torch
12
from torch.utils.tensorboard import SummaryWriter
13
14
from utils.general import colorstr, emojis
15
from utils.loggers.wandb.wandb_utils import WandbLogger
16
from utils.plots import plot_images, plot_results
17
from utils.torch_utils import de_parallel
18
19
LOGGERS = ('csv', 'tb', 'wandb') # text-file, TensorBoard, Weights & Biases
20
RANK = int(os.getenv('RANK', -1))
21
22
try:
23
import wandb
24
25
assert hasattr(wandb, '__version__') # verify package import not local dir
26
if pkg.parse_version(wandb.__version__) >= pkg.parse_version('0.12.2') and RANK in [0, -1]:
27
try:
28
wandb_login_success = wandb.login(timeout=30)
29
except wandb.errors.UsageError: # known non-TTY terminal issue
30
wandb_login_success = False
31
if not wandb_login_success:
32
wandb = None
33
except (ImportError, AssertionError):
34
wandb = None
35
36
37
class Loggers():
38
# YOLOv5 Loggers class
39
def __init__(self, save_dir=None, weights=None, opt=None, hyp=None, logger=None, include=LOGGERS):
40
self.save_dir = save_dir
41
self.weights = weights
42
self.opt = opt
43
self.hyp = hyp
44
self.logger = logger # for printing results to console
45
self.include = include
46
# self.keys = ['train/box_loss', 'train/obj_loss', 'train/cls_loss', # train loss
47
# 'metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/mAP_0.5:0.95', # metrics
48
# 'val/box_loss', 'val/obj_loss', 'val/cls_loss', # val loss
49
# 'x/lr0', 'x/lr1', 'x/lr2'] # params
50
self.keys = ['train/box_loss', 'train/obj_loss', 'train/cls_loss', 'train/theta_loss', # train loss
51
'metrics/precision', 'metrics/recall', 'metrics/HBBmAP.5', 'metrics/HBBmAP.5:.95', # metrics
52
'val/box_loss', 'val/obj_loss', 'val/cls_loss', 'val/theta_loss', # val loss
53
'x/lr0', 'x/lr1', 'x/lr2'] # params
54
for k in LOGGERS:
55
setattr(self, k, None) # init empty logger dictionary
56
self.csv = True # always log to csv
57
58
# Message
59
if not wandb:
60
prefix = colorstr('Weights & Biases: ')
61
s = f"{prefix}run 'pip install wandb' to automatically track and visualize YOLOv5 🚀 runs (RECOMMENDED)"
62
print(emojis(s))
63
64
# TensorBoard
65
s = self.save_dir
66
if 'tb' in self.include and not self.opt.evolve:
67
prefix = colorstr('TensorBoard: ')
68
self.logger.info(f"{prefix}Start with 'tensorboard --logdir {s.parent}', view at http://localhost:6006/")
69
self.tb = SummaryWriter(str(s))
70
71
# W&B
72
if wandb and 'wandb' in self.include:
73
wandb_artifact_resume = isinstance(self.opt.resume, str) and self.opt.resume.startswith('wandb-artifact://')
74
run_id = torch.load(self.weights).get('wandb_id') if self.opt.resume and not wandb_artifact_resume else None
75
self.opt.hyp = self.hyp # add hyperparameters
76
self.wandb = WandbLogger(self.opt, run_id)
77
else:
78
self.wandb = None
79
80
def on_pretrain_routine_end(self):
81
# Callback runs on pre-train routine end
82
paths = self.save_dir.glob('*labels*.jpg') # training labels
83
if self.wandb:
84
self.wandb.log({"Labels": [wandb.Image(str(x), caption=x.name) for x in paths]})
85
86
def on_train_batch_end(self, ni, model, imgs, targets, paths, plots, sync_bn):
87
"""
88
Args:
89
imgs (tensor): (b, 3, height, width)
90
targets (tensor): (n_targets, [img_index clsid cx cy l s theta gaussian_θ_labels])
91
paths (list[str,...]): (b)
92
"""
93
# Callback runs on train batch end
94
if plots:
95
if ni == 0:
96
if not sync_bn: # tb.add_graph() --sync known issue https://github.com/ultralytics/yolov5/issues/3754
97
with warnings.catch_warnings():
98
warnings.simplefilter('ignore') # suppress jit trace warning
99
self.tb.add_graph(torch.jit.trace(de_parallel(model), imgs[0:1], strict=False), [])
100
if ni < 8:
101
f = self.save_dir / f'train_batch{ni}.jpg' # filename
102
Thread(target=plot_images, args=(imgs, targets, paths, f), daemon=True).start()
103
if self.wandb and ni == 10:
104
files = sorted(self.save_dir.glob('train*.jpg'))
105
self.wandb.log({'Mosaics': [wandb.Image(str(f), caption=f.name) for f in files if f.exists()]})
106
107
def on_train_epoch_end(self, epoch):
108
# Callback runs on train epoch end
109
if self.wandb:
110
self.wandb.current_epoch = epoch + 1
111
112
def on_val_image_end(self, pred, predn, path, names, im):
113
# Callback runs on val image end
114
if self.wandb:
115
self.wandb.val_one_image(pred, predn, path, names, im)
116
117
def on_val_end(self):
118
# Callback runs on val end
119
if self.wandb:
120
files = sorted(self.save_dir.glob('val*.jpg'))
121
self.wandb.log({"Validation": [wandb.Image(str(f), caption=f.name) for f in files]})
122
123
def on_fit_epoch_end(self, vals, epoch, best_fitness, fi):
124
# Callback runs at the end of each fit (train+val) epoch
125
x = {k: v for k, v in zip(self.keys, vals)} # dict
126
if self.csv:
127
file = self.save_dir / 'results.csv'
128
n = len(x) + 1 # number of cols
129
s = '' if file.exists() else (('%20s,' * n % tuple(['epoch'] + self.keys)).rstrip(',') + '\n') # add header
130
with open(file, 'a') as f:
131
f.write(s + ('%20.5g,' * n % tuple([epoch] + vals)).rstrip(',') + '\n')
132
133
if self.tb:
134
for k, v in x.items():
135
self.tb.add_scalar(k, v, epoch)
136
137
if self.wandb:
138
self.wandb.log(x)
139
self.wandb.end_epoch(best_result=best_fitness == fi)
140
141
def on_model_save(self, last, epoch, final_epoch, best_fitness, fi):
142
# Callback runs on model save event
143
if self.wandb:
144
if ((epoch + 1) % self.opt.save_period == 0 and not final_epoch) and self.opt.save_period != -1:
145
self.wandb.log_model(last.parent, self.opt, epoch, fi, best_model=best_fitness == fi)
146
147
def on_train_end(self, last, best, plots, epoch, results):
148
# Callback runs on training end
149
if plots:
150
plot_results(file=self.save_dir / 'results.csv') # save results.png
151
files = ['results.png', 'confusion_matrix.png', *(f'{x}_curve.png' for x in ('F1', 'PR', 'P', 'R'))]
152
files = [(self.save_dir / f) for f in files if (self.save_dir / f).exists()] # filter
153
154
if self.tb:
155
import cv2
156
for f in files:
157
self.tb.add_image(f.stem, cv2.imread(str(f))[..., ::-1], epoch, dataformats='HWC')
158
159
if self.wandb:
160
self.wandb.log({"Results": [wandb.Image(str(f), caption=f.name) for f in files]})
161
# Calling wandb.log. TODO: Refactor this into WandbLogger.log_model
162
if not self.opt.evolve:
163
wandb.log_artifact(str(best if best.exists() else last), type='model',
164
name='run_' + self.wandb.wandb_run.id + '_model',
165
aliases=['latest', 'best', 'stripped'])
166
self.wandb.finish_run()
167
else:
168
self.wandb.finish_run()
169
self.wandb = WandbLogger(self.opt)
170
171
def on_params_update(self, params):
172
# Update hyperparams or configs of the experiment
173
# params: A dict containing {param: value} pairs
174
if self.wandb:
175
self.wandb.wandb_run.config.update(params, allow_val_change=True)
176
177