点击上方“计算机视觉工坊”,选择“星标”

干货第一时间送达

作者丨Jack Stark

来源丨机器学习小王子

原文链接|https://mp.weixin.qq.com/s/ujr8XubG9jpvM-zOGcZxRw

编辑丨极市平台

导读

本文总结了多种图像分类任务中的重要技巧,对于目标检测和图像分割等任务,也起到了不错的作用。

计算机视觉主要问题有图像分类、目标检测和图像分割等。针对图像分类任务,提升准确率的方法路线有两条,一个是模型的修改,另一个是各种数据处理和训练的技巧(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
classGradualWarmupScheduler(_LRScheduler):
"""Args:optimizer (Optimizer): Wrapped optimizer.multiplier: target learning rate = base lr * multipliertotal_epoch: target learning rate is reached at total_epoch, graduallyafter_scheduler: after target_epoch, use this scheduler(eg. ReduceLROnPlateau)"""
def __init__(self, optimizer, multiplier, total_epoch, after_scheduler=None):self.multiplier = multiplier
if self.multiplier <= 1.:
raiseValueError('multiplier should be greater than 1.')self.total_epoch = total_epochself.after_scheduler = after_schedulerself.finished = Falsesuper().__init__(optimizer)
def get_lr(self):
if self.last_epoch > self.total_epoch:
if self.after_scheduler:
ifnot self.finished:self.after_scheduler.base_lrs = [base_lr * self.multiplier for base_lr in self.base_lrs]self.finished = True
return self.after_scheduler.get_lr()
return[base_lr * self.multiplier for base_lr in self.base_lrs]
return[base_lr * ((self.multiplier - 1.) * self.last_epoch / self.total_epoch + 1.) for base_lr in self.base_lrs]
def step(self, epoch=None):
if self.finished and self.after_scheduler:
return self.after_scheduler.step(epoch)
else:
return super(GradualWarmupScheduler, self).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个类别,q_i是图片为第i类的概率。

总的来说,LSR是一种通过在标签y中加入噪声,实现对模型约束,降低模型过拟合程度的一种正则化方法。

LSR代码如下:

import torch
import torch.nn as nn
class LSR(nn.Module):
def __init__(self, e=0.1, reduction='mean'):super().__init__()self.log_softmax = nn.LogSoftmax(dim=1)self.e = eself.reduction = reduction
def _one_hot(self, labels, classes, value=1):
"""Convert labels to one hot vectorsArgs:labels: torch tensor in format [label1, label2, label3, ...]classes: int, number of classesvalue: label value in one hot vector, default to 1Returns:return one hot format labels in shape [batchsize, classes]"""one_hot = torch.zeros(labels.size(0), classes)
#labels and value_added  size must matchlabels = labels.view(labels.size(0), -1)value_added = torch.Tensor(labels.size(0), 1).fill_(value)value_added = value_added.to(labels.device)one_hot = one_hot.to(labels.device)one_hot.scatter_add_(1, labels, value_added)
return one_hot
def _smooth_label(self, target, length, smooth_factor):
"""convert targets to one-hot format, and smooththem.Args:target: target in form with [label1, label2, label_batchsize]length: length of one-hot format(number of classes)smooth_factor: smooth factor for label smoothReturns:smoothed labels in one hot format"""one_hot = self._one_hot(target, length, value=1- smooth_factor)one_hot += smooth_factor / length
return one_hot.to(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 sizeI_x, I_y = images.size()[2:]
# draw a boundry position (w, h)w = int(np.round(I_x * np.random.beta(beta, beta)))h = int(np.round(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]
# select and crop four imagescropped_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 imagespatched_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 outputoutput = model(patched_images)
# calculate loss and accuracyloss = 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)。

代码如下:

import torch
import numpy as np
classCutout(object):
"""Randomly mask out one or more patches from an image.Args:n_holes (int): Number of patches to cut out of each image.length (int): The length (in pixels) of each square patch."""
def __init__(self, n_holes, length):self.n_holes = n_holesself.length = length
def __call__(self, img):
"""Args:img (Tensor): Tensor image of size (C, H, W).Returns:Tensor: Image with n_holes of dimension length x length cut out of it."""h = img.size(1)w = img.size(2)mask = np.ones((h, w), np.float32)
for n in range(self.n_holes):y = np.random.randint(h)x = np.random.randint(w)y1 = np.clip(y - self.length // 2, 0, h)y2 = np.clip(y + self.length // 2, 0, h)x1 = np.clip(x - self.length // 2, 0, w)x2 = np.clip(x + self.length // 2, 0, w)mask[y1: y2, x1: x2] = 0.mask = torch.from_numpy(mask)mask = mask.expand_as(img)img = img * mask
return img

效果如下图,每个图片的一小部分被cutout了。

Random erasing

Random erasing[6]其实和cutout非常类似,也是一种模拟物体遮挡情况的数据增强方法。区别在于,cutout是把图片中随机抽中的矩形区域的像素值置为0,相当于裁剪掉,random erasing是用随机数或者数据集中像素的平均值替换原来的像素值。而且,cutout每次裁剪掉的区域大小是固定的,Random erasing替换掉的区域大小是随机的。

Random erasing代码如下:

from __future__ import absolute_import
from torchvision.transforms import*
from PIL importImage
import random
import math
import numpy as np
import torch
classRandomErasing(object):
'''probability: The probability that the operation will be performed.sl: min erasing areash: max erasing arear1: min aspect ratiomean: erasing value'''
def __init__(self, probability = 0.5, sl = 0.02, sh = 0.4, r1 = 0.3, mean=[0.4914, 0.4822, 0.4465]):self.probability = probabilityself.mean = meanself.sl = slself.sh = shself.r1 = r1
def __call__(self, img):
if random.uniform(0, 1) > self.probability:
return img
for attempt in range(100):area = img.size()[1] * img.size()[2]target_area = random.uniform(self.sl, self.sh) * areaaspect_ratio = random.uniform(self.r1, 1/self.r1)h = int(round(math.sqrt(target_area * aspect_ratio)))w = int(round(math.sqrt(target_area / aspect_ratio)))
if w < img.size()[2] and h < img.size()[1]:x1 = random.randint(0, img.size()[1] - h)y1 = random.randint(0, img.size()[2] - w)
if img.size()[0] == 3:img[0, x1:x1+h, y1:y1+w] = self.mean[0]img[1, x1:x1+h, y1:y1+w] = self.mean[1]img[2, x1:x1+h, y1:y1+w] = self.mean[2]
else:img[0, x1:x1+h, y1:y1+w] = self.mean[0]
return img
return img

Cosine learning rate decay

在warmup之后的训练过程中,学习率不断衰减是一个提高精度的好方法。其中有step decay和cosine decay等,前者是随着epoch增大学习率不断减去一个小的数,后者是让学习率随着训练过程曲线下降。

对于cosine decay,假设总共有T个batch(不考虑warmup阶段),在第t个batch时,学习率η_t为:

这里,η代表初始设置的学习率。这种学习率递减的方式称之为cosine decay。

下面是带有warmup的学习率衰减的可视化图[4]。其中,图(a)是学习率随epoch增大而下降的图,可以看出cosine decay比step decay更加平滑一点。图(b)是准确率随epoch的变化图,两者最终的准确率没有太大差别,不过cosine decay的学习过程更加平滑。

在pytorch的torch.optim.lr_scheduler中有更多的学习率衰减的方法,至于哪个效果好,可能对于不同问题答案是不一样的。对于step decay,使用方法如下:

# Assuming optimizer uses lr = 0.05 for all groups
# lr = 0.05     if epoch < 30
# lr = 0.005    if 30 <= epoch < 60
# lr = 0.0005   if 60 <= epoch < 90
from torch.optim.lr_scheduler importStepLR
scheduler = StepLR(optimizer, step_size=30, gamma=0.1)
for epoch in range(100):scheduler.step()train(...)validate(...)

Mixup training

Mixup[10]是一种新的数据增强的方法。Mixup training,就是每次取出2张图片,然后将它们线性组合,得到新的图片,以此来作为新的训练样本,进行网络的训练,如下公式,其中x代表图像数据,y代表标签,则得到的新的xhat, yhat。

其中,λ是从Beta(α, α)随机采样的数,在[0,1]之间。在训练过程中,仅使用(xhat, yhat)。

Mixup方法主要增强了训练样本之间的线性表达,增强网络的泛化能力,不过mixup方法需要较长的时间才能收敛得比较好。

Mixup代码如下:

for(images, labels) in train_loader:l = np.random.beta(mixup_alpha, mixup_alpha)index = torch.randperm(images.size(0))images_a, images_b = images, images[index]labels_a, labels_b = labels, labels[index]mixed_images = l * images_a + (1- l) * images_boutputs = model(mixed_images)loss = l * criterion(outputs, labels_a) + (1- l) * criterion(outputs, labels_b)acc = l * accuracy(outputs, labels_a)[0] + (1- l) * accuracy(outputs, labels_b)[0]

AdaBound

AdaBound是最近一篇论文[5]中提到的,按照作者的说法,AdaBound会让你的训练过程像adam一样快,并且像SGD一样好。

如下图所示,使用AdaBound会收敛速度更快,过程更平滑,结果更好。

另外,这种方法相对于SGD对超参数的变化不是那么敏感,也就是说鲁棒性更好。但是,针对不同的问题还是需要调节超参数的,只是所用的时间可能变少了。

当然,AdaBound还没有经过普遍的检验,也有可能只是对于某些问题效果好。

使用方法如下:安装AdaBound

pip install adabound

使用AdaBound(和其他PyTorch optimizers用法一致)

optimizer = adabound.AdaBound(model.parameters(), lr=1e-3, final_lr=0.1)

AutoAugment

数据增强在图像分类问题上有很重要的作用,但是增强的方法有很多,并非一股脑地用上所有的方法就是最好的。那么,如何选择最佳的数据增强方法呢?AutoAugment[11]就是一种搜索适合当前问题的数据增强方法的方法。该方法创建一个数据增强策略的搜索空间,利用搜索算法选取适合特定数据集的数据增强策略。此外,从一个数据集中学到的策略能够很好地迁移到其它相似的数据集上。

AutoAugment在cifar10上的表现如下表,达到了98.52%的准确率。

其他经典的tricks

常用的正则化方法为

  • Dropout

  • L1/L2正则

  • Batch Normalization

  • Early stopping

  • Random cropping

  • Mirroring

  • Rotation

  • Color shifting

  • PCA color augmentation

  • ...

其他

  • Xavier init[12]

  • ...

参考资料

[1] Deep Residual Learning for Image

Recognition(https://arxiv.org/pdf/1512.03385.pdf

[2] http://cs231n.github.io/neural-networks-2/

[3] Accurate, Large Minibatch SGD:

Training ImageNet in 1 Hour

https://arxiv.org/pdf/1706.02677v2.pdf

[4] Rethinking the Inception Architecture for Computer Vision

https://arxiv.org/pdf/1512.00567v3.pdf

[5]Bag of Tricks for Image Classification with Convolutional Neural Networks

https://arxiv.org/pdf/1812.01187.pdf

[6] Adaptive Gradient Methods with Dynamic Bound of Learning Rate

https://www.luolc.com/publications/adabound/

[7] Random erasing

https://arxiv.org/pdf/1708.04896v2.pdf

[8] RICAP https://arxiv.org/pdf/1811.09030.pdf

[9] Distilling the Knowledge in a Neural Network

https://arxiv.org/pdf/1503.02531.pdf

[10] Improved Regularization of Convolutional Neural Networks with Cutout

https://arxiv.org/pdf/1708.04552.pdf

[11] Mixup: BEYOND EMPIRICAL RISK MINIMIZATION

https://arxiv.org/pdf/1710.09412.pdf

[12] AutoAugment: Learning Augmentation Policies from Data

https://arxiv.org/pdf/1805.09501.pdf

[13] Understanding the difficulty of training deep feedforward neural networks

http://proceedings.mlr.press/v9/glorot10a/glorot10a.pdf

本文仅做学术分享,如有侵权,请联系删文。

下载1

在「计算机视觉工坊」公众号后台回复:深度学习,即可下载深度学习算法、3D深度学习、深度学习框架、目标检测、GAN等相关内容近30本pdf书籍。

下载2

在「计算机视觉工坊」公众号后台回复:计算机视觉,即可下载计算机视觉相关17本pdf书籍,包含计算机视觉算法、Python视觉实战、Opencv3.0学习等。

下载3

在「计算机视觉工坊」公众号后台回复:SLAM,即可下载独家SLAM相关视频课程,包含视觉SLAM、激光SLAM精品课程。

重磅!计算机视觉工坊-学习交流群已成立

扫码添加小助手微信,可申请加入3D视觉工坊-学术论文写作与投稿 微信交流群,旨在交流顶会、顶刊、SCI、EI等写作与投稿事宜。

同时也可申请加入我们的细分方向交流群,目前主要有3D视觉CV&深度学习SLAM三维重建点云后处理自动驾驶、CV入门、三维测量、VR/AR、3D人脸识别、医疗影像、缺陷检测、行人重识别、目标跟踪、视觉产品落地、视觉竞赛、车牌识别、硬件选型、学术交流、求职交流等微信群,请扫描下面微信号加群,备注:”研究方向+学校/公司+昵称“,例如:”3D视觉 + 上海交大 + 静静“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进去相关微信群。原创投稿也请联系。

▲长按加微信群或投稿

▲长按关注公众号

觉得有用,麻烦给个赞和在看~  

深度神经网络模型训练中的 tricks(原理与代码汇总)相关推荐

  1. 深度学习网络模型训练中loss为nans的总结

    在网络训练中经常出现loss为nans的情况. 主要原因有如下: 梯度爆炸 原因:巨大的梯度值使model的学习过程off-track. 检测方法:查看运行时日志,您应该查看每个迭代的损失值.您会注意 ...

  2. 【火炉炼AI】深度学习003-构建并训练深度神经网络模型

    [火炉炼AI]深度学习003-构建并训练深度神经网络模型 (本文所使用的Python库和版本号: Python 3.6, Numpy 1.14, scikit-learn 0.19, matplotl ...

  3. 神经网络模型训练简记(二)

    神经网络模型训练简记(二) 内容简述 三.机器视觉网络模型分类及简介 3.2目标检测 3.2.1RCNN 3.2.2SPPNet 3.2.3Fast RCNN 3.2.4Faster RCNN 3.2 ...

  4. 怎么训练神经网络模型,神经网络模型训练过程

    1.有哪些深度神经网络模型? 目前经常使用的深度神经网络模型主要有卷积神经网络(CNN) .递归神经网络(RNN).深信度网络(DBN) .深度自动编码器(AutoEncoder) 和生成对抗网络(G ...

  5. 深度神经网络模型压缩与加速研究综述

    深度神经网络模型压缩与加速研究综述 文章目录 深度神经网络模型压缩与加速研究综述 前言 介绍 PARAMETER PRUNING AND SHARING A. quantization and bin ...

  6. 图片2分类卷积神经网络模型训练、分类预测案例全过程(1)

    图片2分类卷积神经网络模型训练.分类预测案例全过程(1) 前言 (1)尽管目前有关卷积神经网络深度学习的相关材料较多,但深度学习牵涉到数据预处理.模型构建.模型调用等环节,我也是一个初学者,中间有很多 ...

  7. 神经网络训练中的Tricks之高效BP(反向传播算法)

    神经网络训练中的Tricks之高效BP(反向传播算法) zouxy09@qq.com http://blog.csdn.net/zouxy09 Tricks!这是一个让人听了充满神秘和好奇的词.对于我 ...

  8. OpenCV-6-ANN_MLP神经网络模型训练

    OpenCV-6-ANN_MLP神经网络模型训练 文章目录 OpenCV-6-ANN_MLP神经网络模型训练 @[toc] ANN_MLP神经网络理论介绍 神经网络介绍 MLP多层感知器神经网络 理论 ...

  9. 用于异常检测的深度神经网络模型融合

    用于异常检测的深度神经网络模型融合 在当今的数字时代,网络安全至关重要,因为全球数十亿台计算机通过网络连接.近年来,网络攻击的数量大幅增加.因此,网络威胁检测旨在通过观察一段时间内的流量数据来检测这些 ...

最新文章

  1. Mac系统的JDK8默认安装路径
  2. 订单×××的算法研究与实现
  3. 一道关于 ARRAY 深度展开的面试题
  4. 2台服务器虚拟存储,虚拟存储的主要用途
  5. VTK:baking烘焙阴影贴图用法实战
  6. Mvc中使用MvcSiteMapProvider实现站点地图之基础篇
  7. java 8 stream_Java 8 Stream示例
  8. Kafka的配置文件详细描述
  9. MongoDB数据表基本操作
  10. 【Pytorch】X.view(-1)操作
  11. linux驱动编写(声卡驱动之asoc移植)
  12. 网络编程之 listen()函数的使用与三次握手的理解
  13. C语言如何实现模拟栈
  14. java设计模式 观察者模式_JAVA设计模式之观察者模式
  15. 还担心学习AI没有数学基础吗?读完它们,你就有了!!!
  16. appium历史版本下载
  17. github博客绑定个性域名
  18. RVN 一种新的聚类算法
  19. 造型简约的机箱,安装简单兼容性好,安钛克P20C体验
  20. 怎么在Windows电脑更新 DirectX ?

热门文章

  1. C++实现SECS/GEM
  2. Maven锦集:在IDEA中以5种不同的入口,执行Maven命令
  3. Arduino与485协议电流变送器进行通信
  4. UI设计师作品准备以及面试攻略
  5. 【Echarts】echarts地图展示、自定义点位、地图及点位的点击事件
  6. 数据探索(数据清洗)①—数据质量分析(对数据中的缺失值、异常值和一致性进行分析)
  7. 小议手机软件平台开发(2) - 开发一个开放平台
  8. putextra 传递对象_intent.putextra用法 使用Intent传递对象的两种方式 - 电脑常识 - 服务器之家...
  9. Irvue for Mac v2.7.12 来自 Unsplash 的桌面壁纸
  10. subprocess模块最全笔记