| import os |
| import logging |
| import time |
| from collections import namedtuple |
| from pathlib import Path |
|
|
| import torch |
| import torch.optim as optim |
| import torch.nn as nn |
| import numpy as np |
| from torch.utils.data import DataLoader |
| from prefetch_generator import BackgroundGenerator |
| from contextlib import contextmanager |
| import re |
|
|
| def clean_str(s): |
| |
| return re.sub(pattern="[|@#!¡·$€%&()=?¿^*;:,¨´><+]", repl="_", string=s) |
|
|
| def create_logger(cfg, cfg_path, phase='train', rank=-1): |
| |
| dataset = cfg.DATASET.DATASET |
| dataset = dataset.replace(':', '_') |
| model = cfg.MODEL.NAME |
| cfg_path = os.path.basename(cfg_path).split('.')[0] |
|
|
| if rank in [-1, 0]: |
| time_str = time.strftime('%Y-%m-%d-%H-%M') |
| log_file = '{}_{}_{}.log'.format(cfg_path, time_str, phase) |
| |
| tensorboard_log_dir = Path(cfg.LOG_DIR) / dataset / model / \ |
| (cfg_path + '_' + time_str) |
| final_output_dir = tensorboard_log_dir |
| if not tensorboard_log_dir.exists(): |
| print('=> creating {}'.format(tensorboard_log_dir)) |
| tensorboard_log_dir.mkdir(parents=True) |
|
|
| final_log_file = tensorboard_log_dir / log_file |
| head = '%(asctime)-15s %(message)s' |
| logging.basicConfig(filename=str(final_log_file), |
| format=head) |
| logger = logging.getLogger() |
| logger.setLevel(logging.INFO) |
| console = logging.StreamHandler() |
| logging.getLogger('').addHandler(console) |
|
|
| return logger, str(final_output_dir), str(tensorboard_log_dir) |
| else: |
| return None, None, None |
|
|
|
|
| def select_device(logger, device='', batch_size=None): |
| |
| cpu_request = device.lower() == 'cpu' |
| if device and not cpu_request: |
| os.environ['CUDA_VISIBLE_DEVICES'] = device |
| assert torch.cuda.is_available(), 'CUDA unavailable, invalid device %s requested' % device |
|
|
| cuda = False if cpu_request else torch.cuda.is_available() |
| if cuda: |
| c = 1024 ** 2 |
| ng = torch.cuda.device_count() |
| if ng > 1 and batch_size: |
| assert batch_size % ng == 0, 'batch-size %g not multiple of GPU count %g' % (batch_size, ng) |
| x = [torch.cuda.get_device_properties(i) for i in range(ng)] |
| s = f'Using torch {torch.__version__} ' |
| for i in range(0, ng): |
| if i == 1: |
| s = ' ' * len(s) |
| if logger: |
| logger.info("%sCUDA:%g (%s, %dMB)" % (s, i, x[i].name, x[i].total_memory / c)) |
| else: |
| logger.info(f'Using torch {torch.__version__} CPU') |
|
|
| if logger: |
| logger.info('') |
| return torch.device('cuda:0' if cuda else 'cpu') |
|
|
|
|
| def get_optimizer(cfg, model): |
| optimizer = None |
| if cfg.TRAIN.OPTIMIZER == 'sgd': |
| optimizer = optim.SGD( |
| filter(lambda p: p.requires_grad, model.parameters()), |
| lr=cfg.TRAIN.LR0, |
| momentum=cfg.TRAIN.MOMENTUM, |
| weight_decay=cfg.TRAIN.WD, |
| nesterov=cfg.TRAIN.NESTEROV |
| ) |
| elif cfg.TRAIN.OPTIMIZER == 'adam': |
| optimizer = optim.Adam( |
| filter(lambda p: p.requires_grad, model.parameters()), |
| |
| lr=cfg.TRAIN.LR0, |
| betas=(cfg.TRAIN.MOMENTUM, 0.999) |
| ) |
|
|
| return optimizer |
|
|
|
|
| def save_checkpoint(epoch, name, model, optimizer, output_dir, filename, is_best=False): |
| model_state = model.module.state_dict() if is_parallel(model) else model.state_dict() |
| checkpoint = { |
| 'epoch': epoch, |
| 'model': name, |
| 'state_dict': model_state, |
| |
| |
| 'optimizer': optimizer.state_dict(), |
| } |
| torch.save(checkpoint, os.path.join(output_dir, filename)) |
| if is_best and 'state_dict' in checkpoint: |
| torch.save(checkpoint['best_state_dict'], |
| os.path.join(output_dir, 'model_best.pth')) |
|
|
|
|
| def initialize_weights(model): |
| for m in model.modules(): |
| t = type(m) |
| if t is nn.Conv2d: |
| pass |
| elif t is nn.BatchNorm2d: |
| m.eps = 1e-3 |
| m.momentum = 0.03 |
| elif t in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6]: |
| |
| m.inplace = True |
|
|
|
|
| def xyxy2xywh(x): |
| |
| y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) |
| y[:, 0] = (x[:, 0] + x[:, 2]) / 2 |
| y[:, 1] = (x[:, 1] + x[:, 3]) / 2 |
| y[:, 2] = x[:, 2] - x[:, 0] |
| y[:, 3] = x[:, 3] - x[:, 1] |
| return y |
|
|
|
|
| def is_parallel(model): |
| return type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) |
|
|
|
|
| def time_synchronized(): |
| torch.cuda.synchronize() if torch.cuda.is_available() else None |
| return time.time() |
|
|
|
|
| class DataLoaderX(DataLoader): |
| """prefetch dataloader""" |
| def __iter__(self): |
| return BackgroundGenerator(super().__iter__()) |
|
|
| @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. |
| """ |
| if local_rank not in [-1, 0]: |
| torch.distributed.barrier() |
| yield |
| if local_rank == 0: |
| torch.distributed.barrier() |
|
|