计算机视觉中的数据预处理与模型训练技巧总结
来源⼁机器学习⼩王⼦,转载⾃⼁极市平台
导读
针对图像分类任务提升准确率的⽅法主要有两条:⼀个是模型的修改,另⼀个是各种数据处理和训练的技巧。本⽂在精读论⽂的基础上,总结了图像分类任务的11个tricks。
计算机视觉主要问题有图像分类、⽬标检测和图像分割等。针对图像分类任务,提升准确率的⽅法路线有两条,⼀个是模型的修改,另⼀个是各种数据处理和训练的技巧(tricks)。图像分类中的各种技巧对于⽬标检测、图像分割等任务也有很好的作⽤,因此值得好好总结。本⽂在精读论⽂的基础上,总结了图像分类任务的各种tricks如下:
Warmup
简历怎么制作Linear scaling learning rate
Label-smoothing
Random image cropping and patching
Knowledge Distillation
Cutout
Random erasing
Cosine learning rate decay
Mixup training
AdaBoud
AutoAugment
其他经典的tricks
Warmup
学习率是神经⽹络训练中最重要的超参数之⼀,针对学习率的技巧有很多。Warm up是在ResNet论⽂[1]中提到的⼀种学习率预热的⽅法。由于刚开始训练时模型的权重(weights)是随机初始化的(全部置为0是⼀个坑,原因见[2]),此时选择⼀个较⼤的学习率,可能会带来模型的不稳定。学习率预热就是在
刚开始训练的时候先使⽤⼀个较⼩的学习率,训练⼀些epoches或iterations,等模型稳定时再修改为预先设置的学习率进⾏训练。论⽂[1]中使⽤⼀个110层的ResNet在cifar10上训练时,先⽤0.01的学习率训练直到训练误差低于80%(⼤概训练了400个iterations),然后使⽤0.1的学习率进⾏训练。
上述的⽅法是constant warmup,18年Facebook⼜针对上⾯的warmup进⾏了改进[3],因为从⼀个很⼩的学习率⼀下变为⽐较⼤的学习率可能会导致训练误差突然增⼤。论⽂[3]提出了gradual warmup来解决这个问题,即从最开始的⼩学习率开始,每个iteration增⼤⼀点,直到最初设置的⽐较⼤的学习率。
Gradual warmup代码如下:
from torch.optim.lr_scheduler import _LRScheduler
class GradualWarmupScheduler(_LRScheduler):
"""
Args:
optimizer (Optimizer): Wrapped optimizer.
multiplier: target learning rate = ba lr * multiplier
total_epoch: target learning rate is reached at total_epoch, gradually
after_scheduler: after target_epoch, u this scheduler(eg. ReduceLROnPlateau)
"""
def __init__(lf, optimizer, multiplier, total_epoch, after_scheduler=None):
lf.multiplier = multiplier
if lf.multiplier <= 1.:
rai ValueError('multiplier should be greater than 1.')
lf.after_scheduler = after_scheduler
lf.finished = Fal
super().__init__(optimizer)
def get_lr(lf):
玉鸟吃什么饲料好if lf.last_epoch > lf.total_epoch:
if lf.after_scheduler:
if not lf.finished:
lf.after_scheduler.ba_lrs = [ba_lr * lf.multiplier for ba_lr in lf.ba_lrs]
lf.finished = True
return lf._lr()
return [ba_lr * lf.multiplier for ba_lr in lf.ba_lrs]
return [ba_lr * ((lf.multiplier - 1.) * lf.last_epoch / lf.total_epoch + 1.) for ba_lr in lf.ba_lrs]
def step(lf, epoch=None):
if lf.finished and lf.after_scheduler:
return lf.after_scheduler.step(epoch)
el:
return super(GradualWarmupScheduler, lf).step(epoch)
Linear scaling learning rate
孕妇能用的护肤品Linear scaling learning rate是在论⽂[3]中针对⽐较⼤的batch size⽽提出的⼀种⽅法。
在凸优化问题中,随着批量的增加,收敛速度会降低,神经⽹络也有类似的实证结果。随着batch size的增⼤,处理相同数据量的速度会越来越快,但是达到相同精度所需要的epoch数量越来越多。也就是说,使⽤相同的epoch时,⼤batch size训练的模型与⼩batch size训练的模型相⽐,验证准确率会减⼩。
上⾯提到的gradual warmup是解决此问题的⽅法之⼀。另外,linear scaling learning rate也是⼀种有效的⽅法。在mini-batch SGD训练时,梯度下降的值是随机的,因为每⼀个batch的数据是随机选择的。增⼤batch size不会改变梯度的期望,但是会降低它的⽅差。也就是说,⼤batch size会降低梯度中的噪声,所以我们可以增⼤学习率来加快收敛。
具体做法很简单,⽐如ResNet原论⽂[1]中,batch size为256时选择的学习率是0.1,当我们把batch size变为⼀个较⼤的数b时,学习率应该变为 0.1 × b/256。
Label-smoothing
在分类问题中,我们的最后⼀层⼀般是全连接层,然后对应标签的one-hot编码,即把对应类别的值编码为1,其他为0。这种编码⽅式和通过降低交叉熵损失来调整参数的⽅式结合起来,会有⼀些问题。这种⽅式会⿎励模型对不同类别的输出分数差异⾮常⼤,或者说,模型过分相信它的判断。但是,对于⼀个由多⼈标注的数据集,不同⼈标注的准则可能不同,每个⼈的标注也可能会有⼀些错误。模型对标签的过分相信会导致过拟合。
标签平滑(Label-smoothing regularization,LSR)是应对该问题的有效⽅法之⼀,它的具体思想是降低我们对于标签的信任,例如我们可以将损失的⽬标值从1稍微降到0.9,或者将从0稍微升到0.1。标签平滑最早在inception-v2[4]中被提出,它将真实的概率改造为:
其中,ε是⼀个⼩的常数,K是类别的数⽬,y是图⽚的真正的标签,i代表第i个类别,是图⽚为第i类的概率。
总的来说,LSR是⼀种通过在标签y中加⼊噪声,实现对模型约束,降低模型过拟合程度的⼀种正则化⽅法。
LSR代码如下:
import torch
as nn
class LSR(nn.Module):
def __init__(lf, e=0.1, reduction='mean'):
super().__init__()
lf.log_softmax = nn.LogSoftmax(dim=1)
lf.e = e
def _one_hot(lf, labels, class, value=1):
"""
Convert labels to one hot vectors
Args:
labels: torch tensor in format [label1, label2, label3, ...]
class: int, number of class
value: label value in one hot vector, default to 1
Returns:
return one hot format labels in shape [batchsize, class]
"""
one_hot = s(labels.size(0), class)泡脚放什么好
#labels and value_added size must match
田园春色labels = labels.view(labels.size(0), -1)
value_added = torch.Tensor(labels.size(0), 1).fill_(value)
value_added = (labels.device)
one_hot = (labels.device)
one_hot.scatter_add_(1, labels, value_added)
return one_hot
def _smooth_label(lf, target, length, smooth_factor):
分销渠道设计"""convert targets to one-hot format, and smooth
them.
Args:
target: target in form with [label1, label2, label_batchsize]
length: length of one-hot format(number of class)
smooth_factor: smooth factor for label smooth
Returns:
smoothed labels in one hot format
"""
one_hot = lf._one_hot(target, length, value=1 - smooth_factor)
one_hot += smooth_factor / length
return (target.device)
Random image cropping and patching
Random image cropping and patching (RICAP)[7]⽅法随机裁剪四个图⽚的中部分,然后把它们拼接为⼀个图⽚,同时混合这四个图⽚的标签。
RICAP在caifar10上达到了2.19%的错误率。
如下图所⽰,Ix, Iy是原始图⽚的宽和⾼。w和h称为boundary position,它决定了四个裁剪得到的⼩图⽚的尺⼨。w和h从beta分布Beta(β, β)中随机⽣成,β也是RICAP的超参数。最终拼接的图⽚尺⼨和原图⽚尺⼨保持⼀致。
RICAP的代码如下:
beta = 0.3 # hyperparameter
for (images, targets) in train_loader:
# get the image size
I_x, I_y = images.size()[2:]
# draw a boundry position (w, h)
寒山寺简介w = und(I_x * np.random.beta(beta, beta)))
h = und(I_y * np.random.beta(beta, beta)))
陕西高考分数w_ = [w, I_x - w, w, I_x - w]
h_ = [h, h, I_y - h, I_y - h]
# lect and crop four images
cropped_images = {}
c_ = {}
W_ = {}
for k in range(4):
index = torch.randperm(images.size(0))
x_k = np.random.randint(0, I_x - w_[k] + 1)
y_k = np.random.randint(0, I_y - h_[k] + 1)
cropped_images[k] = images[index][:, :, x_k:x_k + w_[k], y_k:y_k + h_[k]]
c_[k] = target[index].cuda()
W_[k] = w_[k] * h_[k] / (I_x * I_y)
# patch cropped images
patched_images = torch.cat(
(torch.cat((cropped_images[0], cropped_images[1]), 2),
torch.cat((cropped_images[2], cropped_images[3]), 2)),
3)
#patched_images = patched_images.cuda()
# get output
output = model(patched_images)
# calculate loss and accuracy
loss = sum([W_[k] * criterion(output, c_[k]) for k in range(4)])
acc = sum([W_[k] * accuracy(output, c_[k])[0] for k in range(4)])
Knowledge Distillation
提⾼⼏乎所有机器学习算法性能的⼀种⾮常简单的⽅法是在相同的数据上训练许多不同的模型,然后对它们的预测进⾏平均。但是使⽤所有的模型集成进⾏预测是⽐较⿇烦的,并且可能计算量太⼤⽽⽆法部署到⼤量⽤户。Knowledge Distillation(知识蒸馏)[8]⽅法就是应对这种问题的有效⽅法之⼀。
在知识蒸馏⽅法中,我们使⽤⼀个教师模型来帮助当前的模型(学⽣模型)训练。教师模型是⼀个较⾼准确率的预训练模型,因此学⽣模型可以在保持模型复杂度不变的情况下提升准确率。⽐如,可以使⽤ResNet-152作为教师模型来帮助学⽣模型ResNet-50训练。在训练过程中,我们会加⼀个蒸馏损失来惩罚学⽣模型和教师模型的输出之间的差异。
给定输⼊,假定p是真正的概率分布,z和r分别是学⽣模型和教师模型最后⼀个全连接层的输出。之前我们会⽤交叉熵损失l(p,softmax(z))来度量p和z之间的差异,这⾥的蒸馏损失同样⽤交叉熵。所以,使⽤知识蒸馏⽅法总的损失函数是
上式中,第⼀项还是原来的损失函数,第⼆项是添加的⽤来惩罚学⽣模型和教师模型输出差异的蒸馏损失。其中,T是⼀个温度超参数,⽤来使softmax的输出更加平滑的。实验证明,⽤ResNet-152作为教师模型来训练ResNet-50,可以提⾼后者的准确率。
Cutout
Cutout[9]是⼀种新的正则化⽅法。原理是在训练时随机把图⽚的⼀部分减掉,这样能提⾼模型的鲁棒性。它的来源是计算机视觉任务中经常遇到的物体遮挡问题。通过cutout⽣成⼀些类似被遮挡的物体,不仅可以让模型在遇到遮挡问题时表现更好,还能让模型在做决定时更多地考虑环境(context)。
代码如下: