import os import random import torch import torch.distributed as dist import torch.nn as nn # Dynamically import BaseExp from fixed path import importlib.util import sys base_exp_path = '/home/kitraining/Yolox/YOLOX-main/yolox/exp/base_exp.py' spec = importlib.util.spec_from_file_location('base_exp', base_exp_path) base_exp = importlib.util.module_from_spec(spec) sys.modules['base_exp'] = base_exp spec.loader.exec_module(base_exp) BaseExp = base_exp.BaseExp __all__ = ["Exp", "check_exp_value"] class Exp(BaseExp): def __init__(self): super().__init__() self.seed = None self.data_dir = r'/home/kitraining/To_Annotate/' self.train_ann = 'coco_project_37_train.json' self.val_ann = 'coco_project_37_valid.json' self.test_ann = 'coco_project_37_test.json' self.num_classes = 80 self.pretrained_ckpt = r'/home/kitraining/Yolox/YOLOX-main/pretrained/YOLOX-l.pth' self.depth = 1.00 self.width = 1.00 self.act = 'silu' self.data_num_workers = 4 self.input_size = (640, 640) self.multiscale_range = 5 self.mosaic_prob = 1.0 self.mixup_prob = 1.0 self.hsv_prob = 1.0 self.flip_prob = 0.5 self.degrees = (10.0, 10.0) self.translate = (0.1, 0.1) self.mosaic_scale = (0.1, 2) self.enable_mixup = True self.mixup_scale = (0.5, 1.5) self.shear = (2.0, 2.0) self.warmup_epochs = 5 self.max_epoch = 300 self.warmup_lr = 0 self.min_lr_ratio = 0.05 self.basic_lr_per_img = 0.01 / 64.0 self.scheduler = 'yoloxwarmcos' self.no_aug_epochs = 15 self.ema = True self.weight_decay = 5e-4 self.momentum = 0.9 self.print_interval = 10 self.eval_interval = 10 self.save_history_ckpt = True self.exp_name = os.path.split(os.path.realpath(__file__))[1].split('.')[0] self.test_size = (640, 640) self.test_conf = 0.01 self.nmsthre = 0.65 self.exp_name = 'custom_exp123' self.max_epoch = 300 self.depth = 1 self.width = 1 self.activation = 'silu' self.warmup_epochs = 5 self.warmup_lr = 0 self.scheduler = 'yoloxwarmcos' self.no_aug_epochs = 15 self.min_lr_ratio = 0.05 self.ema = True self.weight_decay = 0.0005 self.momentum = 0.9 self.input_size = (640, 640) self.print_interval = 10 self.eval_interval = 10 self.save_history_ckpt = True self.test_size = (640, 640) self.test_conf = 0.01 self.multiscale_range = 5 self.enable_mixup = True self.mosaic_prob = 1 self.mixup_prob = 1 self.hsv_prob = 1 self.flip_prob = 0.5 self.degrees = (10, 10) self.mosaic_scale = (0.1, 2) self.mixup_scale = (0.5, 1.5) self.translate = (0.1, 0.1) self.shear = (2, 2) self.project_details_id = 37 self.selected_model = 'YOLOX-l' self.transfer_learning = 'coco' def get_model(self): from yolox.models import YOLOX, YOLOPAFPN, YOLOXHead def init_yolo(M): for m in M.modules(): if isinstance(m, nn.BatchNorm2d): m.eps = 1e-3 m.momentum = 0.03 if getattr(self, 'model', None) is None: in_channels = [256, 512, 1024] backbone = YOLOPAFPN(self.depth, self.width, in_channels=in_channels, act=self.act) head = YOLOXHead(self.num_classes, self.width, in_channels=in_channels, act=self.act) self.model = YOLOX(backbone, head) self.model.apply(init_yolo) self.model.head.initialize_biases(1e-2) self.model.train() return self.model def get_dataset(self, cache=False, cache_type='ram'): from yolox.data import COCODataset, TrainTransform return COCODataset( data_dir=self.data_dir, json_file=self.train_ann, img_size=self.input_size, preproc=TrainTransform( max_labels=50, flip_prob=self.flip_prob, hsv_prob=self.hsv_prob ), cache=cache, cache_type=cache_type, ) def get_data_loader(self, batch_size, is_distributed, no_aug=False, cache_img=None): from yolox.data import ( TrainTransform, YoloBatchSampler, DataLoader, InfiniteSampler, MosaicDetection, worker_init_reset_seed, ) from yolox.utils import wait_for_the_master if self.dataset is None: with wait_for_the_master(): assert cache_img is None, 'cache_img must be None if you did not create self.dataset before launch' self.dataset = self.get_dataset(cache=False, cache_type=cache_img) self.dataset = MosaicDetection( dataset=self.dataset, mosaic=not no_aug, img_size=self.input_size, preproc=TrainTransform( max_labels=120, flip_prob=self.flip_prob, hsv_prob=self.hsv_prob), degrees=self.degrees, translate=self.translate, mosaic_scale=self.mosaic_scale, mixup_scale=self.mixup_scale, shear=self.shear, enable_mixup=self.enable_mixup, mosaic_prob=self.mosaic_prob, mixup_prob=self.mixup_prob, ) if is_distributed: batch_size = batch_size // dist.get_world_size() sampler = InfiniteSampler(len(self.dataset), seed=self.seed if self.seed else 0) batch_sampler = YoloBatchSampler( sampler=sampler, batch_size=batch_size, drop_last=False, mosaic=not no_aug, ) dataloader_kwargs = {'num_workers': self.data_num_workers, 'pin_memory': True} dataloader_kwargs['batch_sampler'] = batch_sampler dataloader_kwargs['worker_init_fn'] = worker_init_reset_seed train_loader = DataLoader(self.dataset, **dataloader_kwargs) return train_loader def random_resize(self, data_loader, epoch, rank, is_distributed): tensor = torch.LongTensor(2).cuda() if rank == 0: size_factor = self.input_size[1] * 1.0 / self.input_size[0] if not hasattr(self, 'random_size'): min_size = int(self.input_size[0] / 32) - self.multiscale_range max_size = int(self.input_size[0] / 32) + self.multiscale_range self.random_size = (min_size, max_size) size = random.randint(*self.random_size) size = (int(32 * size), 32 * int(size * size_factor)) tensor[0] = size[0] tensor[1] = size[1] if is_distributed: dist.barrier() dist.broadcast(tensor, 0) input_size = (tensor[0].item(), tensor[1].item()) return input_size def preprocess(self, inputs, targets, tsize): scale_y = tsize[0] / self.input_size[0] scale_x = tsize[1] / self.input_size[1] if scale_x != 1 or scale_y != 1: inputs = nn.functional.interpolate( inputs, size=tsize, mode='bilinear', align_corners=False ) targets[..., 1::2] = targets[..., 1::2] * scale_x targets[..., 2::2] = targets[..., 2::2] * scale_y return inputs, targets def get_optimizer(self, batch_size): if 'optimizer' not in self.__dict__: if self.warmup_epochs > 0: lr = self.warmup_lr else: lr = self.basic_lr_per_img * batch_size pg0, pg1, pg2 = [], [], [] for k, v in self.model.named_modules(): if hasattr(v, 'bias') and isinstance(v.bias, nn.Parameter): pg2.append(v.bias) if isinstance(v, nn.BatchNorm2d) or 'bn' in k: pg0.append(v.weight) elif hasattr(v, 'weight') and isinstance(v.weight, nn.Parameter): pg1.append(v.weight) optimizer = torch.optim.SGD( pg0, lr=lr, momentum=self.momentum, nesterov=True ) optimizer.add_param_group({'params': pg1, 'weight_decay': self.weight_decay}) optimizer.add_param_group({'params': pg2}) self.optimizer = optimizer return self.optimizer def get_lr_scheduler(self, lr, iters_per_epoch): from yolox.utils import LRScheduler scheduler = LRScheduler( self.scheduler, lr, iters_per_epoch, self.max_epoch, warmup_epochs=self.warmup_epochs, warmup_lr_start=self.warmup_lr, no_aug_epochs=self.no_aug_epochs, min_lr_ratio=self.min_lr_ratio, ) return scheduler def get_eval_dataset(self, **kwargs): from yolox.data import COCODataset, ValTransform testdev = kwargs.get('testdev', False) legacy = kwargs.get('legacy', False) return COCODataset( data_dir=self.data_dir, json_file=self.val_ann if not testdev else self.test_ann, name='' if not testdev else 'test2017', img_size=self.test_size, preproc=ValTransform(legacy=legacy), ) def get_eval_loader(self, batch_size, is_distributed, **kwargs): valdataset = self.get_eval_dataset(**kwargs) if is_distributed: batch_size = batch_size // dist.get_world_size() sampler = torch.utils.data.distributed.DistributedSampler( valdataset, shuffle=False ) else: sampler = torch.utils.data.SequentialSampler(valdataset) dataloader_kwargs = { 'num_workers': self.data_num_workers, 'pin_memory': True, 'sampler': sampler, } dataloader_kwargs['batch_size'] = batch_size val_loader = torch.utils.data.DataLoader(valdataset, **dataloader_kwargs) return val_loader def get_evaluator(self, batch_size, is_distributed, testdev=False, legacy=False): from yolox.evaluators import COCOEvaluator return COCOEvaluator( dataloader=self.get_eval_loader(batch_size, is_distributed, testdev=testdev, legacy=legacy), img_size=self.test_size, confthre=self.test_conf, nmsthre=self.nmsthre, num_classes=self.num_classes, testdev=testdev, ) def get_trainer(self, args): from yolox.core import Trainer trainer = Trainer(self, args) return trainer def eval(self, model, evaluator, is_distributed, half=False, return_outputs=False): return evaluator.evaluate(model, is_distributed, half, return_outputs=return_outputs) def check_exp_value(exp): h, w = exp.input_size assert h % 32 == 0 and w % 32 == 0, 'input size must be multiples of 32'