def aug_preprocess(resize): return Compose([ RandomResizedCrop(height=resize, width=resize, scale=(0.8, 1.0), ratio=(4 / 5, 5 / 4)), RandomBrightnessContrast(0.1, 0.1), HorizontalFlip(p=0.5), Lambda(image=preprocess_input) ], p=1) # always apply augmentation
def __init__(self): self.transforms = Compose([ HueSaturationValue(p=0.5), RandomBrightnessContrast(), GaussianBlur(), HorizontalFlip(p=.5), Normalize(mean=(0.4914, 0.4822, 0.4465), std=(0.2023, 0.1994, 0.2010), max_pixel_value=255.0, always_apply=True, p=1.0) ])
def train_transfrom(image, size=256): transform = Compose([ Resize(size, size, interpolation=cv2.INTER_AREA), Flip(), RandomBrightnessContrast(), HueSaturationValue(), Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ToTensorV2() ]) image_transform = transform(image=image)['image'] return image_transform
def get_train_transform(): return A.Compose( [ Flip(), RandomBrightnessContrast(brightness_limit=0.2, contrast_limit=0.2), A.OneOf([CLAHE(), FancyPCA()]), HueSaturationValue( hue_shift_limit=10, sat_shift_limit=50, val_shift_limit=50, p=0.8 ), ToFloat(255), ToTensorV2(), ], bbox_params=A.BboxParams(format="pascal_voc", label_fields=["labels"]), )
def get_transfrom(image, size=512, crop_size=256): transform = Compose([ Resize(size, size, interpolation=cv2.INTER_AREA), RandomCrop(crop_size, crop_size), Cutout(num_holes=4), HueSaturationValue(hue_shift_limit=0.2, sat_shift_limit=0.2, val_shift_limit=0.2), RandomBrightnessContrast(brightness_limit=0.2, contrast_limit=0.2), Flip(), Normalize(mean=[0.3835, 0.3737, 0.3698], std=[1.0265, 1.0440, 1.0499]), ToTensorV2() ]) image_transform = transform(image=image)['image'] return image_transform
def __init__(self, df=None, size=150, mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225], augment=True, frames=30, stochastic=True): """ Dataset initialization Parameters ---------- df : pd.DataFrame Dataframe with preprocessed data transform : torchvision.transforms Transformation operations for loaded images path : str Path to folder with the data frames : int Frames to load per video """ assert df is not None, 'Missing dataframe for data' self.frames = frames self.df = df[df['nframes'] >= frames] self.stochastic = stochastic addtl_img = {} for idx in range(frames): addtl_img['image{}'.format(idx)] = 'image' if augment: self.transform = albumentations.Compose( [ ShiftScaleRotate(p=0.3, scale_limit=0.25, border_mode=1, rotate_limit=15), HorizontalFlip(p=0.2), RandomBrightnessContrast( p=0.3, brightness_limit=0.25, contrast_limit=0.5), MotionBlur(p=.2), GaussNoise(p=.2), JpegCompression(p=.2, quality_lower=50), Normalize(mean, std) ], additional_targets=addtl_img) else: self.transform = albumentations.Compose([Normalize(mean, std)]) self.resize = transforms.Resize((size, size))
def apply_background(img): if ".png" in img: # Import the render render = Image.open(WORK_DIR + "/renders/" + img).convert("RGBA") rw, rh = render.size # Choose a random background background = random.choice(os.listdir(WORK_DIR + "/backgrounds/")) background = Image.open(WORK_DIR + "/backgrounds/" + background).convert("RGBA") bw, bh = render.size # Resize the background to match the render background = background.resize((rw, rh)) # Center crop the background based on the render size # background = background.crop(((bw - rw) / 2, (bh - rh)/2, (bw + rw)/2, (bh + rh)/2)) # Merge the background and the render background.paste(render, (0, 0), mask=render) background.save(WORK_DIR + "/renders/" + img) # Set the image transforms transforms = albumentations.Compose([ GaussNoise(), # HorizontalFlip(), # Rotate(limit=45), HueSaturationValue(hue_shift_limit=5, sat_shift_limit=10, val_shift_limit=50), RandomBrightnessContrast(), ]) # Apply the transforms to the image image = imread(WORK_DIR + "/renders/" + img, pilmode="RGB") image = transforms(image=image) print( f"Applying background and augmentations to {WORK_DIR + '/renders/' + img}" ) imsave(WORK_DIR + "/renders/" + img, image["image"])
def train_dataloader(self): augmentations = Compose([ RandomResizedCrop( height=self.hparams.sz, width=self.hparams.sz, scale=(0.7, 1.0), ), # ToGray(), GridDistortion(), RandomBrightnessContrast(), ShiftScaleRotate(), Flip(p=0.5), CoarseDropout( max_height=int(self.hparams.sz / 10), max_width=int(self.hparams.sz / 10), ), Normalize( mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225], max_pixel_value=255, ), ToTensorV2(), ]) train_ds = MelanomaDataset( df=self.train_df, images_path=self.train_images_path, augmentations=augmentations, train_or_valid=True, ) return DataLoader( train_ds, # sampler=sampler, batch_size=self.hparams.bs, shuffle=True, num_workers=os.cpu_count(), pin_memory=False, )
### Dataloaders X, val_X, y, val_y = get_random_sampling(paths, y, val_paths, val_y) print('There are ' + str(y.count(1)) + ' fake train samples') print('There are ' + str(y.count(0)) + ' real train samples') print('There are ' + str(val_y.count(1)) + ' fake val samples') print('There are ' + str(val_y.count(0)) + ' real val samples') import albumentations from albumentations.augmentations.transforms import ShiftScaleRotate, HorizontalFlip, Normalize, RandomBrightnessContrast, MotionBlur, Blur, GaussNoise, JpegCompression train_transform = albumentations.Compose([ ShiftScaleRotate(p=0.3, scale_limit=0.25, border_mode=1, rotate_limit=25), HorizontalFlip(p=0.2), RandomBrightnessContrast(p=0.3, brightness_limit=0.25, contrast_limit=0.5), MotionBlur(p=.2), GaussNoise(p=.2), JpegCompression(p=.2, quality_lower=50), Normalize() ]) val_transform = albumentations.Compose([ Normalize() ]) train_dataset = ImageDataset(X, y, transform=train_transform) val_dataset = ImageDataset(val_X, val_y, transform=val_transform) ### Train
def run(base_path, model_path, gpu_name, batch_size, num_epochs, num_workers): """ Main method to train, evaluate and test the instanced-based approach to classify the Paxos dataset into refer- and nonreferable retinopathy. :param base_path: Absolute path to the dataset. The folder should have folders for training (train), evaluation (val) and corresponding label files :param model_path: Absolute path to the pretrained model :param gpu_name: ID of the gpu (e.g. cuda0) :param batch_size: Bath size :param num_epochs: Maximum number of training epochs :param num_workers: Number of threads used for data loading :return: f1-score for the evaluation (or test) set """ device = torch.device(gpu_name if torch.cuda.is_available() else "cpu") print(f'Using device {device}') hyperparameter = { 'data': os.path.basename(os.path.normpath(base_path)), 'learning_rate': 1e-4, 'weight_decay': 1e-4, 'num_epochs': num_epochs, 'batch_size': batch_size, 'optimizer': optim.Adam.__name__, 'freeze': 0.0, 'balance': 0.3, 'image_size': 450, 'crop_size': 399, 'pretraining': True, 'preprocessing': False, 'multi_channel': False, 'boosting': 1.00, 'use_clahe': False, 'narrow_model': False, 'remove_glare': False, 'voting_percentage': 1.0, 'validation': 'tv', # tvt = train / val / test, tt = train(train + val) / test, tv = train / val 'network': 'alexnet' # alexnet / inception } aug_pipeline_train = A.Compose([ A.CLAHE(always_apply=hyperparameter['use_clahe'], p=1.0 if hyperparameter['use_clahe'] else 0.0), ThresholdGlare(always_apply=hyperparameter['remove_glare'], p=1.0 if hyperparameter['remove_glare'] else 0.0), A.Resize(hyperparameter['image_size'], hyperparameter['image_size'], always_apply=True, p=1.0), A.RandomCrop(hyperparameter['crop_size'], hyperparameter['crop_size'], always_apply=True, p=1.0), A.HorizontalFlip(p=0.5), A.CoarseDropout(min_holes=1, max_holes=3, max_width=75, max_height=75, min_width=25, min_height=25, p=0.5), A.ShiftScaleRotate(shift_limit=0.1, scale_limit=0.3, rotate_limit=45, border_mode=cv2.BORDER_CONSTANT, value=0, p=0.5), A.OneOf([ A.GaussNoise(p=0.5), A.ISONoise(p=0.5), A.IAAAdditiveGaussianNoise(p=0.25), A.MultiplicativeNoise(p=0.25) ], p=0.3), A.OneOf([ A.ElasticTransform(border_mode=cv2.BORDER_CONSTANT, value=0, p=0.5), A.GridDistortion(p=0.5) ], p=0.3), A.OneOf( [A.HueSaturationValue(p=0.5), A.ToGray(p=0.5), A.RGBShift(p=0.5)], p=0.3), A.OneOf([ RandomBrightnessContrast(brightness_limit=0.1, contrast_limit=0.2), A.RandomGamma() ], p=0.3), A.Normalize(always_apply=True, p=1.0), ToTensorV2(always_apply=True, p=1.0) ], p=1.0) aug_pipeline_val = A.Compose([ A.CLAHE(always_apply=hyperparameter['use_clahe'], p=1.0 if hyperparameter['use_clahe'] else 0.0), ThresholdGlare(always_apply=hyperparameter['remove_glare'], p=1.0 if hyperparameter['remove_glare'] else 0.0), A.Resize(hyperparameter['image_size'], hyperparameter['image_size'], always_apply=True, p=1.0), A.CenterCrop(hyperparameter['crop_size'], hyperparameter['crop_size'], always_apply=True, p=1.0), A.Normalize(always_apply=True, p=1.0), ToTensorV2(always_apply=True, p=1.0) ], p=1.0) hyperparameter_str = str(hyperparameter).replace(', \'', ',\n \'')[1:-1] print(f'Hyperparameter info:\n {hyperparameter_str}') loaders = prepare_dataset(os.path.join(base_path, ''), hyperparameter, aug_pipeline_train, aug_pipeline_val, num_workers) net = prepare_model(model_path, hyperparameter, device) optimizer_ft = optim.Adam([{ 'params': net.features.parameters(), 'lr': 1e-5 }, { 'params': net.classifier.parameters() }], lr=hyperparameter['learning_rate'], weight_decay=hyperparameter['weight_decay']) criterion = nn.CrossEntropyLoss() plateau_scheduler = lr_scheduler.ReduceLROnPlateau(optimizer_ft, mode='min', factor=0.1, patience=10, verbose=True) desc = f'_paxos_frames_{str("_".join([k[0] + str(hp) for k, hp in hyperparameter.items()]))}' writer = SummaryWriter(comment=desc) model_path, f1 = train_model(net, criterion, optimizer_ft, plateau_scheduler, loaders, device, writer, hyperparameter, num_epochs=hyperparameter['num_epochs'], description=desc) print('Best identified model: ', model_path) print('Performance F1: ', f1) return f1
def main(): global args, config, best_loss args = parser.parse_args() with open(args.config) as f: config = yaml.load(f) for k, v in config['common'].items(): setattr(args, k, v) config = EasyDict(config['common']) rank, world_size, device_id = dist_init( os.path.join(args.distributed_path, config.distributed_file)) args.save_path_dated = args.save_path + '/' + args.datetime if args.run_tag != '': args.save_path_dated += '-' + args.run_tag # create model model = model_entry(config.model) model.cuda() model = nn.parallel.DistributedDataParallel(model, device_ids=[device_id]) # create optimizer opt_config = config.optimizer opt_config.kwargs.lr = config.lr_scheduler.base_lr opt_config.kwargs.params = model.parameters() optimizer = optim_entry(opt_config) # optionally resume from a checkpoint last_iter = -1 best_loss = 1e9 if args.load_path: if args.recover: best_loss, last_iter = load_state(args.load_path, model, optimizer=optimizer) else: load_state(args.load_path, model) cudnn.benchmark = True # train augmentation if config.augmentation.get('imgnet_mean', False): model_mean = (0.485, 0.456, 0.406) model_std = (0.229, 0.224, 0.225) else: model_mean = (0.5, 0.5, 0.5) model_std = (0.5, 0.5, 0.5) trans = albumentations.Compose([ RandomResizedCrop(config.augmentation.input_size, config.augmentation.input_size, scale=(config.augmentation.min_scale**2., 1.), ratio=(1., 1.)), HorizontalFlip(p=0.5), RandomBrightnessContrast(brightness_limit=0.25, contrast_limit=0.1, p=0.5), JpegCompression(p=.2, quality_lower=50), MotionBlur(p=0.5), Normalize(mean=model_mean, std=model_std), ToTensorV2() ]) train_dataset = FaceDataset(config.train_root, config.train_source, transform=trans, resize=config.augmentation.input_size, image_format=config.get('image_format', None), random_frame=config.get( 'train_random_frame', False), bgr=config.augmentation.get('bgr', False)) train_sampler = DistributedGivenIterationSampler( train_dataset, config.lr_scheduler.max_iter, config.batch_size, last_iter=last_iter) train_loader = DataLoader(train_dataset, batch_size=config.batch_size, shuffle=False, num_workers=config.workers, pin_memory=True, sampler=train_sampler) # validation augmentation trans = albumentations.Compose([ Resize(config.augmentation.input_size, config.augmentation.input_size), Normalize(mean=model_mean, std=model_std), ToTensorV2() ]) val_multi_loader = [] if args.val_source != '': for dataset_idx in range(len(args.val_source)): val_dataset = FaceDataset( args.val_root[dataset_idx], args.val_source[dataset_idx], transform=trans, output_index=True, resize=config.augmentation.input_size, image_format=config.get('image_format', None), bgr=config.augmentation.get('bgr', False)) val_sampler = DistributedSampler(val_dataset, round_up=False) val_loader = DataLoader(val_dataset, batch_size=config.batch_size, shuffle=False, num_workers=config.workers, pin_memory=True, sampler=val_sampler) val_multi_loader.append(val_loader) config.lr_scheduler['optimizer'] = optimizer config.lr_scheduler['last_iter'] = last_iter lr_scheduler = get_scheduler(config.lr_scheduler) if rank == 0: mkdir(args.save_path) mkdir(args.save_path_dated) tb_logger = SummaryWriter(args.save_path_dated) logger = create_logger('global_logger', args.save_path_dated + '-log.txt') logger.info('{}'.format(args)) logger.info(model) logger.info(parameters_string(model)) logger.info('len(train dataset) = %d' % len(train_loader.dataset)) for dataset_idx in range(len(val_multi_loader)): logger.info( 'len(val%d dataset) = %d' % (dataset_idx, len(val_multi_loader[dataset_idx].dataset))) mkdir(args.save_path_dated + '/saves') else: tb_logger = None positive_weight = config.get('positive_weight', 0.5) weight = torch.tensor([1. - positive_weight, positive_weight]) * 2. if rank == 0: logger.info('using class weights: {}'.format(weight.tolist())) criterion = nn.CrossEntropyLoss(weight=weight).cuda() if args.evaluate: if args.evaluate_path: all_ckpt = get_all_checkpoint(args.evaluate_path, args.range_list, rank) for ckpt in all_ckpt: if rank == 0: logger.info('Testing ckpt: ' + ckpt) last_iter = -1 _, last_iter = load_state(ckpt, model, optimizer=optimizer) for dataset_idx in range(len(val_multi_loader)): validate(dataset_idx, val_multi_loader[dataset_idx], model, criterion, tb_logger, curr_step=last_iter, save_softmax=True) else: for dataset_idx in range(len(val_multi_loader)): validate(dataset_idx, val_multi_loader[dataset_idx], model, criterion, tb_logger, curr_step=last_iter, save_softmax=True) return train(train_loader, val_multi_loader, model, criterion, optimizer, lr_scheduler, last_iter + 1, tb_logger) return
def prepare_dataset(base_name: str, hp): aug_pipeline_train = A.Compose([ A.Resize(hp['image_size'], hp['image_size'], always_apply=True, p=1.0), A.RandomCrop( hp['crop_size'], hp['crop_size'], always_apply=True, p=1.0), A.HorizontalFlip(p=0.5), A.CoarseDropout(min_holes=1, max_holes=3, max_width=100, max_height=100, min_width=25, min_height=25, p=0.5), A.ShiftScaleRotate(shift_limit=0.2, scale_limit=0.3, rotate_limit=45, border_mode=cv2.BORDER_CONSTANT, value=0, p=0.5), A.OneOf([ A.GaussNoise(p=0.5), A.ISONoise(p=0.5), A.IAAAdditiveGaussianNoise(p=0.25), A.MultiplicativeNoise(p=0.25) ], p=0.3), A.OneOf([ A.ElasticTransform(border_mode=cv2.BORDER_CONSTANT, value=0, p=0.5), A.GridDistortion(p=0.5) ], p=0.3), A.OneOf( [A.HueSaturationValue(p=0.5), A.ToGray(p=0.5), A.RGBShift(p=0.5)], p=0.3), A.OneOf([ RandomBrightnessContrast(brightness_limit=0.2, contrast_limit=0.2), A.RandomGamma() ], p=0.3), A.Normalize(always_apply=True, p=1.0), ToTensorV2(always_apply=True, p=1.0) ], p=1.0) aug_pipeline_val = A.Compose([ A.Resize(hp['image_size'], hp['image_size'], always_apply=True, p=1.0), A.CenterCrop( hp['crop_size'], hp['crop_size'], always_apply=True, p=1.0), A.Normalize(always_apply=True, p=1.0), ToTensorV2(always_apply=True, p=1.0) ], p=1.0) train_dataset = RetinaDataset( os.path.join(BASE_PATH, f'{base_name}_labels_train.csv'), os.path.join(BASE_PATH, f'{base_name}_processed_data_train'), augmentations=aug_pipeline_train, file_type='.jpg', balance_ratio=0.25) val_dataset = RetinaDataset( os.path.join(BASE_PATH, f'{base_name}_labels_val.csv'), os.path.join(BASE_PATH, f'{base_name}_processed_data_val'), augmentations=aug_pipeline_val, file_type='.jpg') sample_weights = [ train_dataset.get_weight(i) for i in range(len(train_dataset)) ] sampler = torch.utils.data.sampler.WeightedRandomSampler( sample_weights, len(train_dataset), replacement=True) train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=False, sampler=sampler, num_workers=16) val_loader = torch.utils.data.DataLoader(val_dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=16) print( f'Dataset info:\n Train size: {len(train_dataset)},\n Validation size: {len(val_dataset)}' ) return train_loader, val_loader
def run(base_path, gpu_name, batch_size, num_epochs, num_workers): """ Main method to train a network for the DR challenge and saving the model as pretrained stump. Can evaluate different types of network. :param base_path: Absolute path to the dataset. The folder should have folders for training (train), evaluation (val) and corresponding label files :param gpu_name: ID of the gpu (e.g. cuda0) :param batch_size: Batch size :param num_epochs: Maximum number of training epochs :param num_workers: Number of threads used for data loading :return: """ device = torch.device(gpu_name if torch.cuda.is_available() else "cpu") print(f'Using device {device}') hyperparameter = { 'data': os.path.basename(base_path), 'learning_rate': 1e-4, 'weight_decay': 1e-3, 'num_epochs': num_epochs, 'batch_size': batch_size, 'optimizer': optim.Adam.__name__, 'network': 'Efficient', # AlexNet / VGG / Inception / Efficient 'image_size': 700, 'crop_size': 600, 'freeze': 0.0, 'balance': 0.25, 'preprocessing': False, 'pretraining': None #'/home/simon/Data/20211020_stump_extracted.pth' } aug_pipeline_train = alb.Compose( [ alb.Resize(hyperparameter['image_size'], hyperparameter['image_size'], always_apply=True, p=1.0), alb.RandomCrop(hyperparameter['crop_size'], hyperparameter['crop_size'], always_apply=True, p=1.0), # RandomFiveCrop(hyperparameter['crop_size'], hyperparameter['crop_size'], always_apply=True, p=1.0), alb.HorizontalFlip(p=0.5), alb.ShiftScaleRotate(shift_limit=0.1, scale_limit=0.2, rotate_limit=20, border_mode=cv2.BORDER_CONSTANT, value=0, p=0.5), alb.OneOf([ alb.GaussNoise(p=0.5), alb.ISONoise(p=0.5), alb.IAAAdditiveGaussianNoise(p=0.25), alb.MultiplicativeNoise(p=0.25) ], p=0.3), alb.OneOf([ alb.ElasticTransform( border_mode=cv2.BORDER_CONSTANT, value=0, p=0.5), alb.GridDistortion(p=0.5) ], p=0.25), alb.OneOf([ alb.HueSaturationValue(p=0.5), alb.ToGray(p=0.5), alb.RGBShift(p=0.5) ], p=0.3), alb.OneOf([ RandomBrightnessContrast(brightness_limit=0.2, contrast_limit=0.2), alb.RandomGamma() ], p=0.3), alb.Normalize(always_apply=True, p=1.0), ToTensorV2(always_apply=True, p=1.0) ], p=1.0) aug_pipeline_val = alb.Compose([ alb.Resize(hyperparameter['image_size'], hyperparameter['image_size'], always_apply=True, p=1.0), alb.CenterCrop(hyperparameter['crop_size'], hyperparameter['crop_size'], always_apply=True, p=1.0), alb.Normalize(always_apply=True, p=1.0), ToTensorV2(always_apply=True, p=1.0) ], p=1.0) hyperparameter_str = str(hyperparameter).replace(', \'', ',\n \'')[1:-1] print(f'Hyperparameter info:\n {hyperparameter_str}') loaders = prepare_dataset(os.path.join(base_path, ''), hyperparameter, aug_pipeline_train, aug_pipeline_val, num_workers) net: inceptionv4 = prepare_model(hyperparameter, device) optimizer_ft = optim.Adam(filter(lambda p: p.requires_grad, net.parameters()), lr=hyperparameter['learning_rate'], weight_decay=hyperparameter['weight_decay']) criterion = CrossEntropyLoss() plateau_scheduler = lr_scheduler.ReduceLROnPlateau(optimizer_ft, mode='min', factor=0.3, patience=7, verbose=True) desc = f'_pretraining_{str("_".join([k[0] + str(hp) for k, hp in hyperparameter.items()]))}' writer = SummaryWriter(comment=desc) train_model(net, criterion, optimizer_ft, plateau_scheduler, loaders, device, writer, num_epochs=hyperparameter['num_epochs'], description=desc)
def get_transforms(config, mode: str = "train") -> Compose: """ Composes albumentations transforms. Returns the full list of transforms when mode is "train". mode should be one of "train", "val". """ # compose validation transforms if mode == "val": transforms = Compose( [], bbox_params=BboxParams( format="pascal_voc", min_area=0.0, min_visibility=0.0, label_fields=["category_id"], ), ) # compose train transforms # TODO: make transformation parameters configurable from yml elif mode == "train": transforms = Compose( [ LongestMaxSize( max_size=config["LONGESTMAXSIZE_MAXSIZE"], p=config["LONGESTMAXSIZE_P"], ), # PadIfNeeded(min_height=768, min_width=768, border_mode=0, p=1), RandomSizedBBoxSafeCrop( height=config["RANDOMSIZEDBBOXSAFECROP_HEIGHT"], width=config["RANDOMSIZEDBBOXSAFECROP_WIDTH"], p=config["LONGESTMAXSIZE_P"], ), ShiftScaleRotate( shift_limit=config["SHIFTSCALEROTATE_SHIFTLIMIT"], scale_limit=config["SHIFTSCALEROTATE_SCALELIMIT"], rotate_limit=config["SHIFTSCALEROTATE_ROTATELIMIT"], p=config["SHIFTSCALEROTATE_P"], ), HorizontalFlip(p=config["HORIZONTALFLIP_P"]), RandomRotate90(p=config["RANDOMROTATE90_P"]), RandomBrightnessContrast( brightness_limit=config[ "RANDOMBRIGHTNESSCONTRAST_BRIGHTNESSLIMIT"], contrast_limit=config[ "RANDOMBRIGHTNESSCONTRAST_CONTRASTLIMIT"], p=config["RANDOMBRIGHTNESSCONTRAST_P"], ), RandomGamma( gamma_limit=config["RANDOMGAMMA_GAMMALIMIT"], p=config["RANDOMGAMMA_P"], ), HueSaturationValue( hue_shift_limit=config["HUESATURATIONVALUE_HUESHIFTLIMIT"], sat_shift_limit=config["HUESATURATIONVALUE_SATSHIFTLIMIT"], val_shift_limit=config["HUESATURATIONVALUE_VALSHIFTLIMIT"], p=config["HUESATURATIONVALUE_P"], ), MotionBlur( blur_limit=tuple(config["MOTIONBLUR_BLURLIMIT"]), p=config["MOTIONBLUR_P"], ), JpegCompression( quality_lower=config["JPEGCOMPRESSION_QUALITYLOWER"], quality_upper=config["JPEGCOMPRESSION_QUALITYUPPER"], p=config["JPEGCOMPRESSION_P"], ), ], bbox_params=BboxParams( format="pascal_voc", min_area=0.0, min_visibility=0.0, label_fields=["category_id"], ), ) return transforms