通过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 版权协议,转载请附上原文出处链接和本声明。