image-augmentation.md 6.8 KB
Newer Older
A
Aston Zhang 已提交
1
# 图片增广
M
Mu Li 已提交
2

3
[“深度卷积神经网络:AlexNet”](../chapter_convolutional-neural-networks/alexnet.md)小节里我们提到过,大规模数据集是成功使用深度网络的前提。图片增广(image augmentation)技术通过对训练图片做一系列随机变化,来产生相似但又有不同的训练样本,从而扩大训练数据集规模。图片增广的另一种解释是,通过对训练样本做一些随机变形,可以降低模型对某些属性的依赖,从而提高泛化能力。例如我们可以对图片进行不同的裁剪,使得感兴趣的物体出现在不同的位置中,从而使得模型减小对物体出现位置的依赖性。也可以调整亮度色彩等因素来降低模型对色彩的敏感度。在AlexNet的成功中,图片增广技术功不可没。本小节我们将讨论这个在计算机视觉里被广泛使用的技术。
M
Mu Li 已提交
4

A
Aston Zhang 已提交
5
## 常用增广方法
M
Mu Li 已提交
6

7
我们首先读取一张$400\times 500$的图片作为样例。
M
Mu Li 已提交
8 9

```{.python .input  n=1}
M
muli 已提交
10 11 12
import sys
sys.path.insert(0, '..')
import gluonbook as gb
A
Aston Zhang 已提交
13 14
from mxnet import gluon, image, init, nd 
from mxnet.gluon import data as gdata, loss as gloss
M
Mu Li 已提交
15

M
muli 已提交
16 17
img = image.imread('../img/cat1.jpg')
gb.plt.imshow(img.asnumpy())
M
Mu Li 已提交
18 19
```

20
因为大部分的增广方法都有一定的随机性。接下来我们定义一个辅助函数,它对输入图片`img`运行多次增广方法`aug`并显示所有结果。
M
Mu Li 已提交
21

M
muli 已提交
22
```{.python .input  n=2}
M
muli 已提交
23
def apply(img, aug, num_rows=2, num_cols=4, scale=1.5):
A
Aston Zhang 已提交
24
    Y = [aug(img) for _ in range(num_rows * num_cols)]
M
muli 已提交
25
    gb.show_images(Y, num_rows, num_cols, scale)
M
Mu Li 已提交
26 27 28 29
```

### 变形

30
左右翻转图片通常不物体的类别,它是最早也是最广泛使用的一种增广。下面我们使用transform模块里的`RandomFlipLeftRight`类来实现按0.5的概率左右翻转图片:
M
Mu Li 已提交
31 32

```{.python .input  n=3}
A
Aston Zhang 已提交
33
apply(img, gdata.vision.transforms.RandomFlipLeftRight())
M
Mu Li 已提交
34 35
```

36
上下翻转不如水平翻转通用,但是至少对于样例图片,上下翻转不会造成识别障碍。
M
Mu Li 已提交
37 38

```{.python .input  n=4}
A
Aston Zhang 已提交
39
apply(img, gdata.vision.transforms.RandomFlipTopBottom())
M
Mu Li 已提交
40 41
```

42
我们使用的样例图片里,猫在图片正中间,但一般情况下可能不是这样。[“池化层”](../chapter_convolutional-neural-networks/pooling.md)一节里我们解释了池化层能弱化卷积层对目标位置的敏感度,另一方面我们可以通过对图片随机剪裁来让物体以不同的比例出现在不同位置。
M
muli 已提交
43

44
下面代码里我们每次随机裁剪一片面积为原面积10%到100%的区域,其宽和高的比例在0.5和2之间,然后再将高宽缩放到200像素大小。
M
Mu Li 已提交
45 46

```{.python .input  n=5}
A
Aston Zhang 已提交
47
shape_aug = gdata.vision.transforms.RandomResizedCrop(
48
    (200, 200), scale=(0.1, 1), ratio=(0.5, 2))
M
muli 已提交
49
apply(img, shape_aug)
M
Mu Li 已提交
50 51 52 53
```

### 颜色变化

A
Aston Zhang 已提交
54
另一类增广方法是变化颜色。我们可以从四个维度改变图片的颜色:亮度、对比、饱和度和色相。在下面的例子里,我们将随机亮度改为原图的50%到150%。
M
Mu Li 已提交
55 56

```{.python .input  n=6}
A
Aston Zhang 已提交
57
apply(img, gdata.vision.transforms.RandomBrightness(0.5))
M
Mu Li 已提交
58 59
```

60
类似的,我们可以修改色相。
M
muli 已提交
61

M
Mu Li 已提交
62
```{.python .input  n=7}
A
Aston Zhang 已提交
63
apply(img, gdata.vision.transforms.RandomHue(0.5))
M
Mu Li 已提交
64 65
```

M
muli 已提交
66
或者用使用`RandomColorJitter`来一起使用。
M
Mu Li 已提交
67

M
muli 已提交
68
```{.python .input  n=8}
A
Aston Zhang 已提交
69
color_aug = gdata.vision.transforms.RandomColorJitter(
70
    brightness=0.5, contrast=0.5, saturation=0.5, hue=0.5)
M
muli 已提交
71
apply(img, color_aug)
M
Mu Li 已提交
72 73
```

M
muli 已提交
74 75
### 使用多个增广

76
实际应用中我们会将多个增广叠加使用。Compose类可以将多个增广串联起来。
M
Mu Li 已提交
77

M
muli 已提交
78
```{.python .input  n=9}
A
Aston Zhang 已提交
79 80
augs = gdata.vision.transforms.Compose([
    gdata.vision.transforms.RandomFlipLeftRight(), color_aug, shape_aug])
M
muli 已提交
81
apply(img, augs)
M
Mu Li 已提交
82 83
```

M
muli 已提交
84 85
## 使用图片增广来训练

86
接下来我们来看一个将图片增广应用在实际训练中的例子,并比较其与不使用时的区别。这里我们使用CIFAR-10数据集,而不是之前我们一直使用的FashionMNIST。原因在于FashionMNIST中物体位置和尺寸都已经归一化了,而CIFAR-10中物体颜色和大小区别更加显著。下面我们展示CIFAR-10中的前32张训练图片。
M
Mu Li 已提交
87

M
muli 已提交
88
```{.python .input  n=10}
89 90
gb.show_images(gluon.data.vision.CIFAR10(train=True)[0:32][0], 4, 8,
               scale=0.8);
M
Mu Li 已提交
91 92
```

93
我们通常将图片增广用在训练样本上,但是在预测的时候并不使用随机增广。这里我们仅仅使用最简单的随机水平翻转。此外,我们使用`ToTensor`变换来将图片转成MXNet需要的格式,即格式为(批量,通道,高,宽)以及类型为32位浮点数。
M
Mu Li 已提交
94

M
muli 已提交
95
```{.python .input  n=11}
A
Aston Zhang 已提交
96 97 98
train_augs = gdata.vision.transforms.Compose([
    gdata.vision.transforms.RandomFlipLeftRight(),
    gdata.vision.transforms.ToTensor(),
M
muli 已提交
99 100
])

A
Aston Zhang 已提交
101 102
test_augs = gdata.vision.transforms.Compose([
    gdata.vision.transforms.ToTensor(),
M
muli 已提交
103
])
M
Mu Li 已提交
104 105
```

106
接下来我们定义一个辅助函数来方便读取图片并应用增广。Gluon的数据集提供`transform_first`函数来对数据里面的第一项(数据一般有图片和标签两项)来应用增广。另外图片增广将增加计算复杂度,我们使用两个额外CPU进程加来加速计算。
M
muli 已提交
107

M
muli 已提交
108
```{.python .input  n=12}
M
muli 已提交
109 110 111 112
def load_cifar10(is_train, augs, batch_size):
    return gluon.data.DataLoader(gluon.data.vision.CIFAR10(
        train=is_train).transform_first(augs),
        batch_size=batch_size, shuffle=is_train, num_workers=2)
M
muli 已提交
113 114
```

M
muli 已提交
115
### 模型训练
M
Mu Li 已提交
116

A
img aug  
Aston Zhang 已提交
117
我们使用ResNet-18来训练CIFAR-10。训练的代码与[“残差网络:ResNet”](../chapter_convolutional-neural-networks/resnet.md)中一致,除了使用所有可用的GPU和不同的学习率外。
M
Mu Li 已提交
118

M
muli 已提交
119
```{.python .input  n=13}
A
img aug  
Aston Zhang 已提交
120
def train_with_data_aug(train_augs, test_augs, lr=0.1):
M
muli 已提交
121
    batch_size = 256
A
Aston Zhang 已提交
122
    ctx = gb.try_all_gpus()
M
muli 已提交
123
    net = gb.resnet18(10)
M
Mu Li 已提交
124
    net.initialize(ctx=ctx, init=init.Xavier())
A
Aston Zhang 已提交
125 126
    trainer = gluon.Trainer(net.collect_params(), 'sgd',
                            {'learning_rate': lr})
A
Aston Zhang 已提交
127 128 129 130
    loss = gloss.SoftmaxCrossEntropyLoss()
    train_iter = load_cifar10(True, train_augs, batch_size)
    test_iter = load_cifar10(False, test_augs, batch_size)
    gb.train(train_iter, test_iter, net, loss, trainer, ctx, num_epochs=8)
M
Mu Li 已提交
131 132
```

M
muli 已提交
133
首先我们看使用了图片增广的情况。
M
Mu Li 已提交
134

M
muli 已提交
135
```{.python .input  n=14}
A
img aug  
Aston Zhang 已提交
136
train_with_data_aug(train_augs, test_augs)
M
Mu Li 已提交
137 138
```

139
作为对比,我们尝试只对训练数据做中间剪裁。
M
Mu Li 已提交
140

M
muli 已提交
141
```{.python .input  n=15}
A
img aug  
Aston Zhang 已提交
142
train_with_data_aug(test_augs, test_augs)
M
Mu Li 已提交
143 144
```

145
可以看到,即使是简单的随机翻转也会有明显的效果。图片增广类似于正则项,它使得训练精度变低,但可以提高测试精度。
M
Mu Li 已提交
146

A
Aston Zhang 已提交
147
## 小结
M
Mu Li 已提交
148

149
* 图片增广基于现有训练数据生成大量随机图片来有效避免过拟合。
M
Mu Li 已提交
150 151 152

## 练习

A
Aston Zhang 已提交
153
* 尝试在CIFAR-10训练中增加不同的增广方法。
S
Sheng Zha 已提交
154

A
Aston Zhang 已提交
155
## 扫码直达[讨论区](https://discuss.gluon.ai/t/topic/1666)
S
Sheng Zha 已提交
156

A
Aston Zhang 已提交
157
![](../img/qr_image-augmentation.svg)