图像增强(albumentations)与随机种子

  • Post author:
  • Post category:其他


通过torchvision.transforms,可实现不同batch的训练样本根据transforms设置的各种图像处理的概率

我们知道,用torchvision.transforms、albumentations等库通过配置transforms pipline可以实现数据增强。根据定义的每种图像处理对应的概率,使得每个batch中,同个样本会做不同的图像处理,从而得到各种不同的变体图像。通过这样的方式,可以变相达到增加训练样本的目标,达到丰富我们的训练样本的目的。

但我有个疑问,如果固定随机种子,是否会使得不同batch中采取相同的图像处理(本人图像小白,所以如果觉得这是一个蠢问题,烦请略过… 谢谢)。所以简单做了一个实验。

先说结论:固定随机种子后,同个样本,在各个batch下所做的图像处理是不同的。

具体如下:

为了加快训练,训练样本只用了一个图像样本。如下图。

我使用的是albumentations来做数据增强,以下是我数据增强的配置文件。

{"__version__": "0.3.1", "transform": {"__class_fullname__": "albumentations.core.composition.Compose", "p": 1.0, "transforms": [{"__class_fullname__": "albumentations.augmentations.transforms.HorizontalFlip", "always_apply": false, "p": 0.5}, {"__class_fullname__": "albumentations.core.composition.OneOf", "p": 0.3, "transforms": [{"__class_fullname__": "albumentations.augmentations.transforms.RandomContrast", "always_apply": false, "p": 0.5, "limit": [-0.2, 0.2]}, {"__class_fullname__": "albumentations.augmentations.transforms.RandomGamma", "always_apply": false, "p": 0.5, "gamma_limit": [80, 120]}, {"__class_fullname__": "albumentations.augmentations.transforms.RandomBrightness", "always_apply": false, "p": 0.5, "limit": [-0.2, 0.2]}]}, {"__class_fullname__": "albumentations.core.composition.OneOf", "p": 0.3, "transforms": [{"__class_fullname__": "albumentations.augmentations.transforms.ElasticTransform", "always_apply": false, "p": 0.5, "alpha": 120, "sigma": 6.0, "alpha_affine": 3.5999999999999996, "interpolation": 1, "border_mode": 4, "value": null, "mask_value": null, "approximate": false}, {"__class_fullname__": "albumentations.augmentations.transforms.GridDistortion", "always_apply": false, "p": 0.5, "num_steps": 5, "distort_limit": [-0.3, 0.3], "interpolation": 1, "border_mode": 4, "value": null, "mask_value": null}, {"__class_fullname__": "albumentations.augmentations.transforms.OpticalDistortion", "always_apply": false, "p": 0.5, "distort_limit": [-2, 2], "shift_limit": [-0.5, 0.5], "interpolation": 1, "border_mode": 4, "value": null, "mask_value": null}]}, {"__class_fullname__": "albumentations.augmentations.transforms.ShiftScaleRotate", "always_apply": false, "p": 0.5, "shift_limit": [-0.0625, 0.0625], "scale_limit": [-0.09999999999999998, 0.10000000000000009], "rotate_limit": [-45, 45], "interpolation": 1, "border_mode": 4, "value": null, "mask_value": null}, {"__class_fullname__": "albumentations.augmentations.transforms.Resize", "always_apply": true, "p": 1, "height": 1024, "width": 1024, "interpolation": 1}], "bbox_params": {}, "keypoint_params": {}, "additional_targets": {}}}

以下是GetDataset的类定义。训练时,每个训练迭代,都会调用一次这个类的__getitem__。这里图像变换的结果会直接送入模型,所以这里面把变换后的图像保存下来以便观察。

from PIL import Image
class GetDataset(Dataset):
    def __init__(self, data_folder,sub_dir,mode, transform,
                  image_names=None):
        
        self.transform = transform
        self.mode = mode
        self.data_folder = data_folder
        self.mask_path =  os.path.join(data_folder,sub_dir +'_mask')
        self.filename_list = image_names
        self.set_mode(mode)
        self.to_tensor = ToTensor()
        self.img_list = []
        self.sub_dir = sub_dir
    def set_mode(self, mode):
        self.mode = mode

        if self.mode == 'train':
            self.num_data = len(self.filename_list)

        elif self.mode == 'val':  
            self.num_data = len(self.filename_list)

        elif self.mode == 'predict':
            self.filename_list = sorted(self.filename_list)
            self.num_data = len(self.filename_list)
                      

    def __getitem__(self,index):     
        image_path = os.path.join(self.data_folder, os.path.join(self.sub_dir,self.filename_list[index]))
        label_path = os.path.join(self.data_folder, os.path.join(self.sub_dir+'_mask',self.filename_list[index].split('.png')[0] + '_mask.png'))
        if self.mode == 'predict':
            image = cv2.imread(image_path)
            image = Image.fromarray(image)
            
            if self.transform:
                sample = {"img": image}
                sample = self.transform(**sample)              
            image_id = self.filename_list[index].replace('.png', '')

            if image==None:
                print("image为None:{}".format(image))
            
            return image_id, sample
        
        elif self.mode == 'train' or self.mode == 'val':
            image = cv2.imread(image_path)
            label = cv2.imread(label_path,0)
            
            if label is None:
                print("image_path:",image_path)
                print("label_path:",label_path)
                print("index:{} label is None".format(index))
                
                label = np.zeros(shape = (image.shape[0],image.shape[1]))
            
            if self.transform:
                sample = {"image": image, "mask": label}             
                sample = self.transform(**sample)

                # 测试变换 -start
                def save_img(data,name):
                    import time
                    if name=='data':
                        test_img = cv2.cvtColor(data,cv2.COLOR_BGR2RGB)
    
                    elif name=='label':
                        test_img = data
                    print("test_img:{},{}".format(test_img.shape,test_img))
                    tmp_path = '/home/cbl/project/MyExperiment/segmentation/output/predict/2917282960_06beee649a_b_{}_trans_test000_{}.png'.format(name,str(time.time()))
                    cv2.imwrite(tmp_path,test_img)
                    
                    print('已存储:{}'.format(tmp_path))
                save_img(sample["image"],name='data')
                save_img(sample["mask"],name='label')
                # 测试变换 -end


                sample = self.to_tensor(**sample)
                image, label = sample['image'], sample['mask']

            sample = {'img': image, 'label': label, 'img_path': image_path}
            return sample


        
    def __len__(self):
        return self.num_data



def make_loader(dataset_folder,sub_dir,images_filename_list, mode,shuffle=False, transform=None, problem_type='binary', batch_size=1):
    return DataLoader(
        dataset=GetDataset(mode=mode,data_folder = dataset_folder,sub_dir = sub_dir,image_names = images_filename_list,transform=transform),
        shuffle=shuffle,
        num_workers=0,
        batch_size=batch_size
    )

以下是每个epoch输出的图片,我们发现每次调用都会产生不同的图像变换:

epoch1

epoch2

epoch3



版权声明:本文为u010598525原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。