pytorch日积月累6-pytorch数据预处理机制

1.1概述

  • torchvision.transforms : 常用的图像预处理方法
  • torchvision.datasets : 常用数据集的dataset实现,MNIST,CIFAR-10,ImageNet等
  • torchvision.model : 常用的模型预训练,AlexNet,VGG, ResNet,GoogLeNet等

torchvision.transforms : 常用的图像预处理方法:数据中心化,数据标准化,缩放,裁剪,旋转,翻转,填充,噪声添加,灰度变换,线性变换,仿射变换,亮度、饱和度及对比度变换。

示例:

1
2
3
4
5
6
train_transform = transforms.Compose([
transforms.Resize((32, 32)), #图像大小变化
transforms.RandomCrop(32, padding=4), #随机裁剪
transforms.ToTensor(), #图片转化为张量
transforms.Normalize(norm_mean, norm_std),#图像归一化
])

image-20200820223032848

  • transforms.Normalize
  • 功能:逐channel的对图像进行标准化output = (input - mean) / std
1
2
3
transforms.Normalize(mean,          #各通道的均值
std, #各通道的标准差
inplace=False) #是否原地操作

数据增强

数据增强又称为数据增广,数据扩增,它是对训练集进行变换,使训练集更丰富,从而让模型更具泛化能力。

image-20200820223726630

1.2剪裁

1.transforms.CenterCrop

  • 功能:从图像中心裁剪图片
  • size:所需裁剪图片尺寸
1
2
3
4
5
6
train_transform = transforms.Compose([
transforms.Resize((224, 224)),
# CenterCrop
transforms.CenterCrop(200)
#如果超出了范围自动补充黑色区域
])

2.transforms.RandomCrop

功能:从图片中随机裁剪出尺寸为size的图片

  • padding_mode:填充模式,有4种模式
    • constant:像素值由fill设定
    • edge:像素值由图像边缘像素决定
    • reflect:镜像填充,最后一个像素不镜像,eg:[1,2,3,4] → [3,2,1,2,3,4,3,2]
    • symmetric:镜像填充,最后一个像素镜像,eg:[1,2,3,4] → [2,1,1,2,3,4,4,3]
  • padding:设置填充大小

    • 当为a时,上下左右均填充a个像素
    • 当为(a,b)时,上下填充b个像素,左右填充a个像素
    • 当为(a,b,c,d)时,左上右下填充abcd
  • fill:constant时,设置填充的像素值,可以设置其他的RGB值

  • pad_if_needed:若图像小于设定size,则填充
1
2
3
4
5
transforms.RandomCrop(size,#所需裁剪图片尺寸 
padding=None, #设置填充大小
pad_if_needed=False,
fill=0,
padding_mode='constant')
1
2
3
4
5
6
7
8
9
10
11
train_transform = transforms.Compose([
transforms.Resize((224, 224)),
# 2 RandomCrop
transforms.RandomCrop(224, padding=16),
transforms.RandomCrop(224, padding=(16, 64)),
transforms.RandomCrop(224, padding=16, fill=(255, 0, 0)),
transforms.RandomCrop(512, pad_if_needed=True),# pad_if_needed=True
transforms.RandomCrop(224, padding=64, padding_mode='edge'),
transforms.RandomCrop(224, padding=64, padding_mode='reflect'),
transforms.RandomCrop(1024, padding=1024, padding_mode='symmetric')
])
  1. transforms.RandomResizedCrop()

功能:随机大小,长宽比裁剪图片:

  • size:所需裁剪图片尺寸
  • scale:随机裁剪面积比例, 默认(0.08, 1)
  • ratio:随机长宽比,默认(3/4, 4/3)
  • interpolation:插值方法
    • PIL.Image.NEAREST
    • PIL.Image.BILINEAR
    • PIL.Image.BICUBIC
1
2
3
4
RandomResizedCrop(size, 
scale=(0.08, 1.0),
ratio=(3/4, 4/3),
interpolation)
1
2
3
4
train_transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.RandomResizedCrop(size=224, scale=(0.5, 0.5))
])

4.transforms.FiveCrop

  • 功能:在图像的上下左右以及中心裁剪出尺寸为size的5张图片
  • TenCrop对这5张图片进行水平或者垂直镜像获得10张图片
    • size:所需裁剪图片尺寸
    • vertical_flip:是否垂直翻转
1
2
transforms.FiveCrop(size)
transforms.TenCrop(size, vertical_flip=False)
1
2
3
4
5
6
7
train_transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.FiveCrop(112),
transforms.Lambda(lambda crops: torch.stack([(transforms.ToTensor()(crop)) for crop in crops]))
transforms.TenCrop(112, vertical_flip=False),
transforms.Lambda(lambda crops: torch.stack([(transforms.ToTensor()(crop)) for crop in crops])),
])

1.3翻转

1.RandomHorizontalFlipRandomVerticalFlip

  • 功能:依概率水平(左右)或垂直(上下)翻转图片
    • p:翻转概率
1
2
RandomHorizontalFlip(p=0.5)
RandomVerticalFlip(p=0.5)
1
2
3
4
5
6
7
train_transform = transforms.Compose([
transforms.Resize((224, 224)),
# 1 Horizontal Flip
transforms.RandomHorizontalFlip(p=1),
# 2 Vertical Flip
transforms.RandomVerticalFlip(p=0.5),
])

2.RandomRotation

  • 功能:随机旋转图片
  • degrees:旋转角度
    • 当为a时,在(-a,a)之间选择旋转角度
    • 当为(a, b)时,在(a, b)之间选择旋转角度
  • resample:重采样方法
  • expand:是否扩大图片
  • center:默认为中心旋转,也可以设置左上角旋转
1
2
3
4
RandomRotation(degrees, 
resample=False,
expand=False,
center=None)
1
2
3
4
5
6
7
8
train_transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.RandomRotation(90),
transforms.RandomRotation((90), expand=True),
transforms.RandomRotation(30, center=(0, 0)),
transforms.RandomRotation(30, center=(0, 0), expand=True),
# expand only for center rotation
])

1.4图像变换

1.transforms.Pad()

功能:对图片边缘进行填充

  • padding:设置填充大小

    • 当为a时,上下左右均填充a个像素
    • 当为(a, b)时,上下填充b个像素,左右填充a个像素
    • 当为(a, b, c, d)时,左,上,右,下分别填充a, b, c, d
  • padding_mode:填充模式,有4种模式,constant、edge、reflect和symmetric

  • fill:constant时,设置填充的像素值,(R, G, B) or (Gray)
1
2
3
transforms.Pad(padding, 
fill=0,
padding_mode='constant')
1
2
3
4
transforms.Pad(padding=32, fill=(255, 0, 0), padding_mode='constant'),
transforms.Pad(padding=(8, 64), fill=(255, 0, 0), padding_mode='constant'),
transforms.Pad(padding=(8, 16, 32, 64), fill=(255, 0, 0), padding_mode='constant'),
transforms.Pad(padding=(8, 16, 32, 64), fill=(255, 0, 0), padding_mode='symmetric')

2.transforms.ColorJitter

功能:调整亮度,对比度,饱和度和色相

  • 功能:调整亮度、对比度、饱和度和色相
  • hue:色相参数
    • 当为a时,从[-a, a]中选择参数,注: 0<= a <= 0.5
    • 当为(a, b)时,从[a, b]中选择参数,注:-0.5 <= a <= b <= 0.5
  • brightness:亮度调整因子
    • 当为a时,从[max(0, 1-a), 1+a]中随机选择
    • 当为(a, b)时,从[a, b]中随机选择
  • contrast:对比度参数,同brightness
  • saturation:饱和度参数,同brightness
1
2
3
4
transforms.ColorJitter(brightness=0, 
contrast=0,
saturation=0,
hue=0)
1
2
3
4
transforms.ColorJitter(brightness=0.5),
transforms.ColorJitter(contrast=0.5),
transforms.ColorJitter(saturation=0.5),
transforms.ColorJitter(hue=0.3),

3.GrayscaleRandomGrayscale

  • 功能:依概率将图片转换为灰度图
  • num_ouput_channels:输出通道数,只能设1或3
  • p:概率值,图像被转换为灰度图的概率
1
2
3
4
5
RandomGrayscale(num_output_channels,
p=0.1)
Grayscale(num_output_channels)

Grayscale(num_output_channels)#p=1的RandomGrayscale

4.RandomAffine

功能:对图像进行仿射变换,仿射变换是二维的线性变换,由五种基本原子变换构成,分别是旋转、平移、缩放、错切和翻转。

  • degrees:旋转角度设置
  • translate:平移区间设置,如(a, b), a设置宽(width),b设置高(height)
    • 图像在宽维度平移的区间为
  • scale:缩放比例(以面积为单位)
  • fill_color:填充颜色设置
  • shear:错切角度设置,有水平错切和垂直错切
    • 若为,则仅在x轴错切,错切角度在之间
    • 若为,则a设置x轴角度,b设置y的角度
    • 若为,则a, b设置x轴角度,c, d设置y轴角度
  • resample:重采样方式,有NEARESTBILINEARBICUBIC
1
2
3
4
5
6
RandomAffine(degrees, 
translate=None,
scale=None,
shear=None,
resample=False,
fillcolor=0)
1
2
3
4
5
transforms.RandomAffine(degrees=30),
transforms.RandomAffine(degrees=0, translate=(0.2, 0.2), fillcolor=(255, 0, 0)),
transforms.RandomAffine(degrees=0, scale=(0.7, 0.7)),
transforms.RandomAffine(degrees=0, shear=(0, 0, 0, 45)),
transforms.RandomAffine(degrees=0, shear=90, fillcolor=(255, 0, 0)),

5.RandomErasing

功能:对图像进行随机遮挡

  • p:概率值,执行该操作的概率
  • scale:遮挡区域的面积
  • ratio:遮挡区域长宽比
  • value:设置遮挡区域的像素值,(R, G, B) or (Gray)
1
2
3
4
5
RandomErasing(p=0.5, 
scale=(0.02, 0.33),
ratio=(0.3, 3.3),
value=0,
inplace=False)
1
2
3
4
5
6
7
#随机遮挡是在张量上操作,而不是PIL文件
#下面的代码中给出的数据是在论文中推荐的数值,可以在不损失图片信息的情况下进行遮挡
transforms.ToTensor(),
transforms.RandomErasing(p=1, scale=(0.02, 0.33),
ratio=(0.3, 3.3), value=(254/255, 0, 0)),
transforms.RandomErasing(p=1, scale=(0.02, 0.33),
ratio=(0.3, 3.3), value='1234'),
  1. transforms.Lambda

功能:用户自定义lambda方法

  • lambd:lambda匿名函数

transforms.Lambda(lambd)

lambda [arg1 [,arg2, … , argn]] : expression

1
2
3
transforms.TenCrop(200, vertical_flip=True),
transforms.Lambda(lambda crops: torch.stack([transforms.Totensor()(crop) for crop in crops])),
#把输出的十张PIL图片拼接成tensor文件

1.5transform选择操作

  1. transforms.RandomChoice

    功能:从一系列transforms方法中随机挑选一个

    1
    transforms.RandomChoice([transforms1, transforms2, transforms3])
  2. transforms.RandomApply

    功能:依据概率执行一组transforms操作

    1
    transforms.RandomApply([transforms1, transforms2, transforms3], p=0.5)
  3. transforms.RandomOrder

    功能:对一组transforms操作打乱顺序

    1
    transforms.RandomOrder([transforms1, transforms2, transforms3])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#1 RandomChoice
transforms.RandomChoice([transforms.RandomVerticalFlip(p=1),
transforms.RandomHorizontalFlip(p=1)]),


#2 RandomApply
transforms.RandomApply([
transforms.RandomAffine(degrees=0, shear=45, fillcolor=(255, 0, 0)),
transforms.Grayscale(num_output_channels=3)],
p=0.5),


#3.RandomOrder
transforms.RandomOrder([transforms.RandomRotation(15),
transforms.Pad(padding=32),
transforms.RandomAffine(degrees=0, translate=(0.01, 0.1), scale=(0.9, 1.1))])

1.6自定义transforms

自定义transforms要素:

  1. 仅接收一个参数,返回一个参数
  2. 注意上下游的输出与输入
1
2
3
4
5
class Compose(object):
def __call__(self, img):
for t in self.transforms:
img = t(img)
return img

通过类实现多参数输入:

1
2
3
4
5
6
class YourTransforms(object):
def __init__(self, ...):
#.....
def __call__(self, img):
#....
return img
  • 椒盐噪声椒盐噪声又称为脉冲噪声,是一种随机出现的白点或者黑点, 白点称为盐噪声,黑色为椒噪声。
  • 信噪比(Signal-Noise Rate, SNR)是衡量噪声的比例,图像中为图像像素的占比。

image-20200820235156068

1
2
3
4
5
6
7
8
9
class AddPepperNoise(object):
def __init__(self, snr, p):
self.snr = snr
self.p = p
def __call__(self, img):
'''
添加椒盐噪声具体实现过程
'''
return img
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class AddPepperNoise(object):
"""增加椒盐噪声
Args:
snr (float): Signal Noise Rate
p (float): 概率值,依概率执行该操作
"""
def __init__(self, snr, p=0.9):
assert isinstance(snr, float) and (isinstance(p, float))
self.snr = snr
self.p = p
def __call__(self, img):
"""
Args:img (PIL Image): PIL Image
Returns:PIL Image: PIL image.
"""
if random.uniform(0, 1) < self.p:#依据概率
img_ = np.array(img).copy()
h, w, c = img_.shape
signal_pct = self.snr
noise_pct = (1 - self.snr)
mask = np.random.choice((0, 1, 2),
size=(h, w, 1),
p=[signal_pct,
noise_pct/2.,
noise_pct/2.])
mask = np.repeat(mask, c, axis=2)
img_[mask == 1] = 255 # 盐噪声
img_[mask == 2] = 0 # 椒噪声
return Image.fromarray(img_.astype('uint8')).convert('RGB')
else:
return img
1
2
3
4
5
6
train_transform = transforms.Compose([
transforms.Resize((224, 224)),
AddPepperNoise(0.9, p=0.5),#接受PIL文件,返回PIL文件
transforms.ToTensor(),
transforms.Normalize(norm_mean, norm_std),
])

1.7总结

image-20200821000030886

数据增强原则:让训练集与测试集更接近

• 空间位置:平移

• 色彩:灰度图,色彩抖动

• 形状:仿射变换

• 上下文场景:遮挡,填充