大部分的计算机视觉任务使用很多的数据,所以数据扩充是经常使用的一种技巧来提高计算机视觉系统的表现。通过增强数据集,可以防止神经网络学习到不相关的模式,根本上提升整体性能。
(一)常用的图像增强方法
预备知识:
def set_figsize(figsize=(3.5, 2.5)):
"""Set matplotlib figure size."""
use_svg_display()
plt.rcParams['figure.figsize'] = figsize
mxnet.image.imread()或者cv.imread()用来读取图像,需要注意的是:
- mxnet是RGB格式,不是BGR格式,所以opencv读取需要变换BGR到RGB。
- 默认格式是[batch,channel,h,w],而一般读取图像的接口默认channel是要放到后面的,比如opencv读取的图像一般是放到后面的,比如opencv读取的图像一般是[h,w,channel],所以需要变换。
asnumpy()把NDArray转化成numpy
显示的图像像素为1080 x 1563
plt.subplots创建一个图和一组子图,注意该函数返回的时俩个值fig和axt(它是元组的方式)
matplotlib.pyplot.subplots(nrows,ncols,sharex,sharey,squeeze,subplot_kw,gridspec_kw,**fig_kw)
nrows: 子区网格的行数,默认是1
ncols:子区网格的列数,默认是1
sharex:控制x轴之间的属性共享
sharey:控制y轴之间的属性共享:
False或无:默认值,每个子图x或y轴之间将是独立的。
True或all:x或y轴将在所有子图中共享
‘row’:每个子图行将共享一个x或y轴,这时只有底部子图的x刻度标签可见
‘col’:每个子图列将共享一个x或y轴,只有第一列子图的y刻度标签可见
squeeze:对生成的axes对象是否进行压缩,默认是False不压缩
subplot_kw:带关键字的Dict传递给add_subplot()用于创建每个子区域的子图
gridspec_kw:带有关键字的Dict传递给GridSpec构造函数,用于创建子图所在的网格
定义绘图函数:
def show_images(imgs, num_rows, num_cols, scale=2):
figsize = (num_cols * scale, num_rows * scale) # 图像大小变换
_, axes = d2l.plt.subplots(num_rows, num_cols, figsize=figsize) #定义了变量nrows,ncols和subplot_kw
for i in range(num_rows):
for j in range(num_cols):
axes[i][j].imshow(imgs[i * num_cols + j].asnumpy())
axes[i][j].axes.get_xaxis().set_visible(False) # ax..get_xaxis().set_visible(False) 不显示x轴
axes[i][j].axes.get_yaxis().set_visible(False) # ax.get_yaxis().set_visible(False) 不显示y轴
return axes
我们来试一下,如果注释掉不显示x,y轴的代码
调整scale,画布大小改变:
改变ncols和nrows:
不显示x,y轴信息:
大部分图像增广方法都有一定的随机性。为了方便观察图像增广的效果,接下来我们定义一个辅助函数apply。这个函数对输入图像img多次运行图像增广方法aug并展示所有的结果。
def apply(img, aug, num_rows=2, num_cols=4, scale=1.5):
Y = [aug(img) for _ in range(num_rows * num_cols)] # 使用aug图像增广方式,处理方式随机,生成了num_rows×num_cols个(h×w×c)数组
show_images(Y, num_rows, num_cols, scale) #得到子图
(二)翻转和裁剪
左右翻转图像通常不改变物体的类别。它是最早也是最广泛使用的一种图像增广方法。下面我们通过transforms模块创建RandomFlipLeftRight实例来实现一半概率的图像左右翻转。
apply(img, gdata.vision.transforms.RandomFlipLeftRight())
上下翻转不如左右翻转通用。但是至少对于样例图像,上下翻转不会造成识别障碍。下面我们创建RandomFlipTopBottom实例来实现一半概率的图像上下翻转。
apply(img, gdata.vision.transforms.RandomFlipTopBottom())
在“池化层”一节里我们解释了池化层能降低卷积层对目标位置的敏感度。除此之外,我们还可以通过对图像随机裁剪来让物体以不同的比例出现在图像的不同位置,这同样能够降低模型对目标位置的敏感性。
shape_aug = gdata.vision.transforms.RandomResizedCrop(
(200, 200), scale=(0.1, 1), ratio=(0.5, 2)) # 图像像素强制设为200×200
# 随机裁剪出一块面积为原面积10%∼100%的区域,该区域的宽和高之比随机取自0.5∼2
apply(img, shape_aug)
(三)变换颜色
另一类增广方法是变化颜色。我们可以从4个方面改变图像的颜色:亮度、对比度、饱和度和色调。
随机改变图片亮度到0.5–1.5倍:
apply(img, gdata.vision.transforms.RandomBrightness(0.5))
随机改变图像色调到0.5–1.5倍:
apply(img, gdata.vision.transforms.RandomHue(0.5))
可以创建RandomColorJitter实例并同时设置如何随机变化图像的亮度(brightness)、对比度(contrast)、饱和度(saturation)和色调(hue)。并且都设为0.5–1.5倍
color_aug = gdata.vision.transforms.RandomColorJitter(
brightness=0.5, contrast=0.5, saturation=0.5, hue=0.5)
apply(img, color_aug)
其中一种影响颜色失真的算法是PCA,即主成分分析,但具体颜色改变的细节在AlexNet的论文中有时候被称作PCA颜色增强,PCA颜色增强的大概含义是,比如说,如果你的图片呈现紫色,即主要含有红色和蓝色,绿色很少,然后PCA颜色增强算法就会对红色和蓝色增减很多,绿色变化相对少一点,所以使总体的颜色保持一致。如果这些你都不懂,不需要担心,可以在网上搜索你想要了解的东西,如果你愿意的话可以阅读AlexNet论文中的细节,你也能找到PCA颜色增强的开源实现方法,然后直接使用它。
(四)叠加多个图像增广
augs = gdata.vision.transforms.Compose([
gdata.vision.transforms.RandomFlipLeftRight(), color_aug, shape_aug])
# 图像左右随机翻转,颜色变换和裁剪同时使用
apply(img, augs)
(五)使用图像增广训练模型
使用CIFAR-10数据集,其中物体的颜色和大小区别更加显著。我们使用ToTensor实例将小批量图像转成MXNet需要的格式,即形状为(批量大小,通道数, 高, 宽)、值域在0到1之间且类型为32位浮点数。
show_images(gdata.vision.CIFAR10(train=True)[0:32][0], 4, 8, scale=0.8) # 显示前32张图片
flip_aug=gdata.vision.transforms.Compose([gdata.vision.transforms.RandomFlipLeftRight(),
gdata.vision.transforms.ToTensor()]) # 对图像同时进行左右翻转和ToTensor变换
no_aug=gdata.vision.transforms.Compose([gdata.vision.transforms.ToTensor()]) # 只进行ToTensor变换
num_workers = 0 if sys.platform.startswith('win32') else 4 # windows系统不支持多线程加速
def load_cifar10(is_train, augs, batch_size):
return gdata.DataLoader( # 实例每次读取一个样本数为batch_size的小批量数据
gdata.vision.CIFAR10(train=is_train).transform_first(augs),
# transform_first函数将图像增广应用在每个训练样本(图像和标签)的第一个元素,即图像之上
batch_size=batch_size, shuffle=is_train, num_workers=num_workers)
除了上述的翻转,裁剪,颜色变换的图像增广外,还有高斯噪声:
过拟合(Overfitting)经常会发生在神经网络试图学习高频特征(即非常频繁出现的无意义模式)的时候,而学习这些高频特征对模型提升没什么帮助。那么如何处理这些高频特征呢?
一种方法是采用具有零均值特性的高斯噪声,它实质上在所有频率上都能产生数据点,可以有效的使高频特征失真,减弱其对模型的影响。但这也意味着低频的成分(通常是你关心的特征)同时也会受到影响,但是神经网络能够通过学习来忽略那些影响。事实证明,通过添加适量的噪声能够有效提升神经网络的学习能力。一个“弱化”的版本是椒盐噪声,它以随机的白色和黑色像素点呈现并铺满整个图片。这种方式对图像产生的作用和添加高斯噪声产生的作用是一样的,只是效果相对较弱。