图像分类训练技巧集锦(论文笔记)

Bag of Tricks for Image Classification with Convolutional Neural Networks

《Bag of Tricks for Image Classification with Convolutional Neural Networks》阅读笔记。

论文根据近几年来的关于训练过程优化的大量的优秀论文,总结整理了一大袋用于提升网络模型性能的技巧,这些技巧包含了数据增广、大批量训练、低精度训练、模型调整、学习率调整策略等等。

下面按照大纲,记录论文总结的方法。

大纲

  • 训练基本过程(baseline training procedure ):包括训练集和测试集的数据增广、参数初始化、优化方法、学习率调整策略。
  • 高效训练(efficient training):包括大批量训练、低精度训练等。
  • 模型调整(model tweak):比较三种ResNet变体的优劣。
  • 训练改进(training refinement):包括Cosine Learning rate decaying、Label smoothing、knowledge distillation、mixup training。
  • 图像分类模型与迁移学习:讲了图像分类模型准确率的提高有助于迁移至其他领域,如目标检测、语义分割。

训练流程(Baseline Training Procedure)

论文选取了ResNet-50、Inception-V3和MobileNet作为baseline model。

其中,ResNet有许多实现版本,论文使用的是这个实现方式Training and investigating Residual Nets

baseline的训练步骤如图:

baseline

其中,训练和测试的不同在于数据预处理的不同,主要为测试时不进行数据增广,区别如下:

训练时的预处理(train)

  1. 随即采样一幅图像,像素值取值范围[0,255],解码为32位浮点数类型。
  2. 随机裁剪矩形区域图像,长宽比在 [3/4, 4/3]范围随机取值,裁剪面积在[8%, 100%]范围随机取值,然后将裁剪区域缩放为224x224的方形图像。
  3. 以0.5的概率随机水平翻转图像。
  4. 缩放色调hue,饱和度saturation,明亮度brightness,缩放系数在[0.6,1.4]范围均匀采样。
  5. 从正太分布 $N (0, 0.1)$ 采样参数用于添加PCA噪声.
  6. 通过减去[123.68, 116.779, 103.939]并除以[58.393, 57.12,57.375]进行数据的归一化RGB通道。(ImageNet)。

测试时的预处理(validation and test)

  1. 保持长宽比,缩放图像使短边长度为256像素。
  2. 在图像中心裁剪出224x224区域。
  3. 同样通过减去[123.68, 116.779, 103.939]并除以[58.393, 57.12,57.375]进行数据的归一化RGB通道。(ImageNet)

Xavier Initialization

使用Xavier 算法进行卷积层和全连接层的参数初始化。

Xavier初始化的paper:Understanding the difficulty of training deep feedforward neural networks

具体来说,就是公式
$$
W \sim U[-\frac{\sqrt6}{n_j + n_{j+1}},\frac{\sqrt6}{n_j + n_{j+1}}]
$$
每一层的参数都从上式范围内随机均匀抽取,其中 $n_j$ 是 第$j$层的输入通道数。

NAG替代SGD

训练时使用Nesterov Accelerated Gradient(NAG)作为优化器。

高效训练(Efficient Training)

large-batch训练

数据量大,GPU显存大,大家自然就想用大的Batch Size进行训练,但是大的batch size可能会减慢训练的进程。对于凸优化问题来说,收敛的速度随着batch size的增加而减小。

换句话说,就是训练同样数目的epoch,使用大的batch size会降低模型在验证集上的准确率。

下面是四种对该问题的解决方案:

学习率线性扩大

提升batch size并没有改变随机梯度的期望,但是减小了随机梯度的方差,换句话说,大的batch szie减小了梯度中的噪声,因此可以通过增大学习率来保持梯度方向的优化。

举例来说,对于初始设置:$lr = 0.5, batch size=256$,则随着batch size的改变,学习率应当调整成$lr = 0.5 * \frac {b}{256}$。

学习率预热(warm up)

学习率预热应该是针对上一条学习率扩大来讲的,因为学习率变大之后,较大的初始学习率容易导致数值的不稳定。

在学习率预热的想法里,先用较小的学习进行训练,等到训练过程稳定之后再切换到设置的初始学习率。

也有的做法是,切换这一个步骤改进为从较小的学习率线性变为设置的初始学习率。

举例来说,设置$m$个bacth用于预热,设置初始学习率为$\eta$。则在预热阶段,第$i$个batch时,学习率为$i*\eta/m$。

Zero $\gamma$

ResNet的每个block的最后一层都有BN层,BN层首先标准化输入,记为$\hat{x}$,然后进行尺度变换$\gamma \hat{x} + \beta$。其中,$\hat{x}和\gamma$都是可以学习的参数,通常分别初始为0和1。

Zero $\gamma$的想法是,在所有BN层中将$\gamma$初始化为0,这样就相当于在训练的初始阶段减少了网络的层数,易于训练。

No bias decay

就是只对卷积层和全连接层的权重进行衰减,而不去正则化所有的biases、BN层的$\gamma$和$ \beta$。

low-precision训练

一般来讲,神经网络的训练是使用32位float类型(FP32)的,所有的数据和参数都用32位浮点来存储和计算。

最近几年呢,新的计算设备提供了低精度的16位float类型(FP16)的计算能力,于是就有了拿FP16来进行计算的方式。

总的来说呢,用更低的精度进行神经网络的训练,有好处有坏处:

  • 好处就是精度低了,训练速度就上来了;
  • 坏处就是,精度低了,数值的范围就债了,计算结果容易溢出。

针对缺点,有人提出的解决方案是,在整个训练过程中,用FP16来存储参数、计算梯度,同时留一个32位精度的参数的备份,用于更新参数。

还有一种实用的方案是计算损失函数时,乘以一个数(尺度),将梯度的范围更好地对齐到FP16上。

模型调整(Model Tweaks)

这里主要讲了ResNet及其变体。

ResNet架构和常见的ResNet配置

resnet50

resnet50

三种调整的ResNet变体

resnet_other

ResNet-B

调整原因:原有的residual block的下采样部分,使用了kernel=1x1和stride=2,忽略掉了3/4的信息,所以改进为kernel=3x3和stride=2。

ResNet-C

调整原因:鉴于卷积操作时,kernel size与计算消耗呈平方关系,因此将输入时的卷积操作的7x7的kernel,改为3个3x3的卷积操作。

ResNet-D

调整原因:与ResNet-B相似,下采样的右边通道同样存在着忽略3/4信息的问题,因此进行改进。实验发现,将卷积改为sride=1,同时在前面加上一个kernel=2x2,stride=2的平均池化层,效果理想。

训练改进(Training Refinement)

余弦学习率衰减(Cosine Learning rate decay)

常用的Learning Rate Decay是Step Decay,即每隔N个Epoch,learning rate乘上一个固定decay系数。

但是Step Decay不好的地方在于学习率衰减的时候,跳跃变化较大,带来了较大的冲量Momentum,引起的训练不稳定需要Optimizer用几个迭代去稳定他。有人就提出使用余弦学习率衰减的方式,Cosine Learning rate decay。公式如下,也很好理解:

$$\eta_t=\frac{1}{2} (1+cos(\frac{t\pi}{T}))$$

但是论文中的结果是这样子的,余弦衰减不一定比步进衰减(Step decay)好:

cos

虽然论文中解释说,当Step Decay方法的学习率已经较小的时候,Cos Decay方法的学习仍比较大,因而能够加速整个训练的过程。但是看图中b,很明显Step Decay再衰减之后,准确率就上来了,说明衰减之前的数量级效用已经不强了,这个时候Cos decay还是那个数量级,所以速度就比Step Decay慢了。显然Step Decay方法60-80个Epoch就达到的水准,要Cos Decay120个Epoch去达到,说服力不强。

但Cosine Decay总归是一个思路,大家都推崇,必然有其优越性,是骡子是马,两种方法都测试下就好了。

Label Smoothing

Label Smoothing就是一种抑制过拟合的手段。

产生的原因就是分类任务的标签即GroundTruth是一个one-hot的分布,而神经网络的预测输出很明显是达不到one-hot分布的,这样就一直产生一个不必要的loss,容易导致过拟合,影响泛化能力。

实际的手段就是计算Loss时,修改一下GoundTruth的分布即可,即

$$
q_i=
\begin{cases}
1-\varepsilon, & \text{if $i=y$,} \\
\frac{\varepsilon}{K-1}, & \text{others}
\end{cases}
$$

知识蒸馏(Knowledge Distillation)

知识蒸馏是指用一个准确率较高的复杂的预训练模型(teacher model)来训练一个结构较为简单的模型(student model),来提升student model的准确率。尽可能压榨teacher model来训练student model的好处有,又能获取复杂模型的预测能力,又能简化网络结构提高推理速度。

训练时,使用蒸馏损失(distillation loss)来对teacher model和student model的输出差异进行惩罚,辅助学习。
对于给定的输入,假设$p$为真实的概率分布,$z$和$r$分别为student model和teacher model的最后一层全连接层的输出。使用交叉熵Cross Entropy来计算损失,因此整个训练的损失函数为:
$$l(p,softmax(z)) + T^2 l(softmax(r/T), softmax(z/T))$$
其中T是一个超参数,用来平滑整个Loss的。

混合训练(Mixup Training)

Mixup就是数据增广的一个方法,随机取两个样本,通过加权线性插值构建一个新的样本。
新的样本的输入和真实概率分布为:
$$
\hat{x} = \lambda x_i + (1-\lambda)x_j, \\
\hat{y} = \lambda y_i + (1-\lambda)y_j.
$$

对迁移学习的帮助

分类模型具备更高的准确率之后,再将分类模型作为其他任务的backbone,显然是有帮助的,毕竟分类模型说到底就是一个提取图像特征的过程。

目标检测

实验结果:
目标检测

语义分割

实验结果:
语义分割