训练技巧详解【含有部分代码】Bag of Tricks for Image Classification with Convolutional Neural Networks

训练技巧详解【含有部分代码】Bag of Tricks for Image Classification with Convolutional Neural Networks

置顶 2018-12-11 22:07:40 Snoopy_Dream 阅读数 1332更多

分类专栏: 计算机视觉 pytorch 深度学习tricks

版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/e01528/article/details/84961432

论文地址:https://arxiv.org/pdf/1812.01187.pdf

更多方法和代码可见:图像分类任务中的tricks总结

更多更全的tricks补充(补充链接也是福利满满~)

目录

2 训练过程(baseline复现原文精度,作为下面的基础)

3 高效训练(大BS为出发,但部分小BS也适用)(效率改进)

3.1 大批量训练(主要是学习率)

3.1.1 线性扩展学习率

3.1.2 学习率预热(warmup)+0.8%

3.1.3 Zero γ +0.4%

3.1.4 无偏衰减 -0.3%(预防过拟合)

3.2 低精度训练(相对于无偏衰减+0.2%)

3.3 实验结果分析

4 模型变体(模型上改进)

经典ResNet 架构重温

改进版本(一个比一个精度高)

5 训练方法改进

5.1 余弦学习率衰减(pytorch有)

5.2 标签平滑(带代码)

5.3 知识蒸馏(模型压缩中的)

5.4 混合训练

5.5 实验结果

6 迁移学习



综述:我们可以看到作者从普通的tricks,随机翻转这些出发。构造baseline证明了,作者复现的精度是可信的。然后在此基础上,考虑高效率的训练,大BS为背景,主要从学习率角度出发改进,之后改进了ResNet,然后又说了一些训练方法的技巧。

2 训练过程

实验实现建立第一个baseline,利用下面的6个步骤,小批量 SGD。下图中reference是模型在其原文中的精度。发现利用下面baseline的方法,复现精度左右稍有偏差,合情合理。

  1. 随机采样一张图片,并解码为 32 位的原始像素浮点值,每一个像素值的取值范围为 [0, 255]。
  2. 随机以 [3/4, 4/3] 为长宽比、[8%, 100%] 为比例裁减矩形区域,然后再缩放为 224*224 的方图。
  3. 以 0.5 的概率随机水平翻转图像。
  4. 从均匀分布 [0.6, 1.4] 中抽取系数,并用于缩放色调和明亮度等。
  5. 从正态分布 N (0, 0.1) 中采样一个系数,以添加 PCA 噪声。
  6. 图像分别通过减去(123.68, 116.779, 103.939),并除以(58.393, 57.12, 57.375)而获得经归一化的 RGB 三通道。

除此之外,我们学习一下自定义初始化~~附赠:

  1. for m in self.modules():

  2.  

    if isinstance(m, nn.Conv2d):

  3.  

    n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels

  4.  

    m.weight.data.normal_(0, math.sqrt(2. / n))

  5.  

    elif isinstance(m, sn.SwitchNorm2d):##SN层的

  6.  

    m.weight.data.fill_(1)

  7.  

    m.bias.data.zero_()

表 2:文献中实现的验证准确率与我们基线模型的验证准确率,注意 Inception V3 的输入图像大小是 299*299。

3 高效训练(大BS为出发,但部分小BS也适用)

随着 GPU 等硬件的流行,很多与性能相关的权衡取舍或最优选择都已经发生了改变【例如下面的低精度训练】。在这一章节中,我们研究了能利用低精度和大批量训练优势的多种技术,它们都不会损害模型的准确率,甚至有一些技术还能同时提升准确率与训练速度。

3.1 大批量训练

对于凸优化问题,随着批量的增加,收敛速度会降低。对于相同数量的 epoch,大批量训练的模型与使用较小批量训练的模型相比,验证准确率会降低。因此有很多方法与技巧都旨在解决这个问题:

3.1.1 线性扩展学习率

思路:原先BS(batchsize)大的时候,因为凸优化,收敛速度变慢收缩的慢,1000那我可以不可以提高学习率,让收敛的快些呢?

理论依据:BS增大,mini-batch梯度的噪声减少,随机梯度的期望不变,但是方差降低,因此初试学习率可以变大。

实际方法:0.1*bs/256 【对应的,传统的bs=256,初试学习率为0.1,在30 60 90 各变为原来的0.1倍】

3.1.2 学习率预热(warmup)+0.8%

为什么:因为刚开始训练,所有的参数都是初始化的结果,离最终差很远,如果采用太大的学习率,容易导致numerical instability

怎么办:在刚开始训练用小学习率预热一下,知道训练稳定后,再变成初始学习率。具体方法:假设初始学习率为0.1,决定让前4个epoch作为预热,那么,学习率分别设置为0.1*i/5,i表示epoch,当然我自己觉得不用那么多预热,我也可以设置前4000个分别为0.02,0.04,0.06 0.08

3.1.3 Zero γ +0.4%

γx ^ + β.

原理:注意 ResNet 块的最后一层可以是批归一化层(BN)。在 zero γ启发式方法中,我们对所有残差块末端的 BN 层初始化γ=0。因此,所有的残差块仅返回输入值,这相当于网络拥有更少的层,在初始阶段更容易训练。

操作:普通的BN初始化,γ=1,β=0,残差块末端BN的γ=0,β=0。

我不懂的地方,请教诸神一下。到底对应的是下面的哪一个啊,是右边残差块,最下面的一个BN吗?

3.1.4 无偏衰减 -0.3%

无偏衰减启发式方法仅应用权重衰减到卷积层和全连接层的权重,其它如 BN 中的γ和β都不进行衰减。原理类似于L2正则化,防止权重过拟合。(具体我也不清楚)

3.2 低精度训练(相对于无偏衰减+0.2%)

训练更快,有时候甚至更准。。由于硬件的原因和TFLOPS有关。

一般我们用到的是float point 32(FP32),由于硬件的更新,导致FP16,速度会快2-3倍。但是FP32的还没有针对增强。

然而,新硬件可能具有增强的算术逻辑单元以用于较低精度的数据类型。尽管具备性能优势,但是精度降低具有较窄的取值范围,因此有可能出现超出范围而扰乱训练进度的情况。

所以存储参数和计算梯度用FP16,参数更新用,复制了的FP32格式的。【有点不明白,求更清楚的解说】

表 3:ResNet-50 在基线(BS = 256 与 FP32)和更高效硬件设置(BS = 1024 与 FP16)之间的训练时间和验证准确率的比较。

3.3 实验结果分析

注意哈,上面所有的实验都是验证BS大的情况,所以先看BS=1024的情况,BS=256 是对看的。

初试学习率BS=1024对应的是0.4(线性扩展学习率算来的),就算经过了他,BS大的还是比小的-0.9%,要不用估计会更低。

可以看出无偏衰减没卵用啊,对于大的BS,FP16有用,小的不管用。不考虑大BS的话,我们能常用到的就是第二个和第三个了。

4 模型变体

经典ResNet 架构重温

我们将简要介绍 ResNet 架构,特别是与模型变体调整相关的模块。ResNet 网络由一个输入主干、四个后续阶段和一个最终输出层组成,如图 1 所示。输入主干有一个 7×7 卷积,输出通道有 64 个,步幅为 2,接着是 3 ×3 最大池化层,步幅为 2。输入主干(input stem)将输入宽度和高度减小 4 倍,并将其通道尺寸增加到 64。

从阶段 2 开始,每个阶段从下采样块开始,然后是几个残差块。在下采样块中,存在路径 A 和路径 B。路径 A 具有三个卷积,其卷积核大小分别为 1×1、3×3 和 1×1。第一个卷积的步幅为 2,以将输入长度和宽度减半,最后一个卷积的输出通道比前两个大 4 倍,称为瓶颈结构。路径 B 使用步长为 2 的 1×1 卷积将输入形状变换为路径 A 的输出形状,因此我们可以对两个路径的输出求和以获得下采样块的输出。残差块类似于下采样块,除了仅使用步幅为 1 的卷积。

我们可以改变每个阶段中残差块的数量以获得不同的 ResNet 模型,例如 ResNet-50 和 ResNet-152,其中的数字表示网络中卷积层的数量。

改进版本(一个比一个精度高)

1*1的卷积,最好不用于stride=2,降低特征图尺寸用,原文说会丢失3/4的信息(但是精度为什么没有降很多呢?)

resnet-B 就把降低特征图尺寸的任务交给了3*3的卷积。

resnet-C 把最开始的7*7*64大卷积换成下面图中的表示,红体字表示channel。ResNet-50-C这种修改,虽然对计算量影响不大,不过根据我的经验,对速度的影响应该会比较大。

resnet-D 不用1*1的卷积降低特征图尺寸用,用到的x部分。

图 2:三个 ResNet 变体。ResNet-B 修改 ResNet 的下采样模块。ResNet-C 进一步修改输入主干。在此基础上,ResNet-D 再次修改了下采样块。

表 5:将 ResNet-50 与三种模型变体进行模型大小(参数数量)、FLOPs 和 ImageNet 验证准确率(top-1、top-5)的比较。

5 训练方法改进

5.1 余弦学习率衰减(pytorch有)

pytorch:scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=5,eta_min=4e-08)

传统的两种衰减:

He et al. [9] decreases rate at 0.1 for every 30 epochs, we call it “step decay”. Szegedy et al. [26]
decreases rate at 0.94 for every two epochs

Loshchilov 等人 [18] 提出余弦退火策略,其简化版本是按照余弦函数将学习速率从初始值降低到 0。假设批次总数为 T(忽略预热阶段),然后在批次 t,学习率η_t 计算如下:

5.2 标签平滑(带代码)

补充:在这里学习到论文里说到的两个迭代之间相差0.94倍。

标签平滑的想法首先被提出用于训练 Inception-v2 [26]。它将真实概率的构造改成:

其中ε是一个小常数,K 是标签总数量。

图 4:ImageNet 上标签平滑效果的可视化。顶部:当增加ε时,目标类别与其它类别之间的理论差距减小。下图:最大预测与其它类别平均值之间差距的经验分布。很明显,通过标签平滑,分布中心处于理论值并具有较少的极端值。

  1. # -*- coding: utf-8 -*-

  2.  

  3.  

    """

  4.  

    qi=1-smoothing(if i=y)

  5.  

    qi=smoothing / (self.size - 1) (otherwise)#所以默认可以fill这个数,只在i=y的地方执行1-smoothing

  6.  

    另外KLDivLoss和crossentroy的不同是前者有一个常数

  7.  

    predict = torch.FloatTensor([[0, 0.2, 0.7, 0.1, 0],

  8.  

  9.  

    [0, 0.9, 0.2, 0.1, 0],

  10.  

  11.  

    [1, 0.2, 0.7, 0.1, 0]])

  12.  

    对应的label为

  13.  

    tensor([[ 0.0250, 0.0250, 0.9000, 0.0250, 0.0250],

  14.  

    [ 0.9000, 0.0250, 0.0250, 0.0250, 0.0250],

  15.  

    [ 0.0250, 0.0250, 0.0250, 0.9000, 0.0250]])

  16.  

    区别于one-hot的

  17.  

    tensor([[ 0., 0., 1., 0., 0.],

  18.  

    [ 1., 0., 0., 0., 0.],

  19.  

    [ 0., 1., 0., 0., 0.]])

  20.  

    """

  21.  

    import torch

  22.  

    import torch.nn as nn

  23.  

    from torch.autograd import Variable

  24.  

    import matplotlib.pyplot as plt

  25.  

    import numpy as np

  26.  

  27.  

  28.  

    class LabelSmoothing(nn.Module):

  29.  

    "Implement label smoothing. size表示类别总数 "

  30.  

  31.  

    def __init__(self, size, smoothing=0.0):

  32.  

  33.  

    super(LabelSmoothing, self).__init__()

  34.  

  35.  

    self.criterion = nn.KLDivLoss(size_average=False)

  36.  

  37.  

    #self.padding_idx = padding_idx

  38.  

  39.  

    self.confidence = 1.0 - smoothing#if i=y的公式

  40.  

  41.  

    self.smoothing = smoothing

  42.  

  43.  

    self.size = size

  44.  

  45.  

    self.true_dist = None

  46.  

  47.  

  48.  

  49.  

    def forward(self, x, target):

  50.  

    """

  51.  

    x表示输入 (N,M)N个样本,M表示总类数,每一个类的概率log P

  52.  

    target表示label(M,)

  53.  

    """

  54.  

    assert x.size(1) == self.size

  55.  

    true_dist = x.data.clone()#先深复制过来

  56.  

    #print true_dist

  57.  

    true_dist.fill_(self.smoothing / (self.size - 1))#otherwise的公式

  58.  

    #print true_dist

  59.  

    #变成one-hot编码,1表示按列填充,

  60.  

    #target.data.unsqueeze(1)表示索引,confidence表示填充的数字

  61.  

    true_dist.scatter_(1, target.data.unsqueeze(1), self.confidence)

  62.  

  63.  

    self.true_dist = true_dist

  64.  

  65.  

    return self.criterion(x, Variable(true_dist, requires_grad=False))

  66.  

  67.  

    if __name__=="__main__":

  68.  

    # Example of label smoothing.

  69.  

  70.  

    crit = LabelSmoothing(size=5,smoothing= 0.1)

  71.  

    #predict.shape 3 5

  72.  

    predict = torch.FloatTensor([[0, 0.2, 0.7, 0.1, 0],

  73.  

  74.  

    [0, 0.9, 0.2, 0.1, 0],

  75.  

  76.  

    [1, 0.2, 0.7, 0.1, 0]])

  77.  

  78.  

    v = crit(Variable(predict.log()),

  79.  

  80.  

    Variable(torch.LongTensor([2, 1, 0])))

  81.  

  82.  

    # Show the target distributions expected by the system.

  83.  

  84.  

    plt.imshow(crit.true_dist)

  85.  

  86.  

  87.  

调用的时候注意

  1. module的init函数里面,fc后面要加上LogSoftmax函数,因为KLV要求输入log概率

  2.  

    self.Logsoftmax=nn.LogSoftmax()

  3.  

    forward函数里

  4.  

    x = self.fc(x)

  5.  

    x=self.Logsoftmax(x)

5.3 知识蒸馏(模型压缩中的)

在知识蒸馏 [10] 中,我们使用教师模型来帮助训练当前模型(被称为学生模型)。教师模型通常是具有更高准确率的预训练模型,因此通过模仿,学生模型能够在保持模型复杂性相同的同时提高其自身的准确率。一个例子是使用 ResNet-152 作为教师模型来帮助训练 ResNet-50。

5.4 混合训练

在混合训练(mixup)中,每次我们随机抽样两个样本 (x_i,y_i) 和 (x_j,y_j)。然后我们通过这两个样本的加权线性插值构建一个新的样本,训练只在新样本中训练:

其中 λ∈[0,1] 是从 Beta(α, α) 分布提取的随机数。在混合训练中,我们只使用新的样本 (x hat, y hat)。

5.5 实验结果

表 6:通过堆叠训练改进方法,得到的 ImageNet 验证准确率。基线模型为第 3 节所描述的。

作者之后又在另外一个数据集上试了下,证明可以。

6 迁移学习

自 2012 年 AlexNet 大展神威以来,研究者已经提出了各种卷积架构,包括 VGG、NiN、Inception、ResNet、DenseNet 和 NASNet 等,我们会发现模型的准确率正稳定提升。

但是现在这些提升并不仅仅来源于架构的修正,还来源于训练过程的改进:包括损失函数的优化、数据预处理方法的提炼和最优化方法的提升等。在过去几年中,卷积网络与图像分割出现大量的改进,但大多数在文献中只作为实现细节而简要提及,而其它还有一些技巧甚至只能在源代码中找到。

在这篇论文中,李沐等研究者研究了一系列训练过程和模型架构的改进方法。这些方法都能提升模型的准确率,且几乎不增加任何计算复杂度。它们大多数都是次要的「技巧」,例如修正卷积步幅大小或调整学习率策略等。总的来说,采用这些技巧会产生很大的不同。因此研究者希望在多个神经网络架构和数据集上评估它们,并研究它们对最终模型准确率的影响。

研究者的实验表明,一些技巧可以显著提升准确率,且将它们组合在一起能进一步提升模型的准确率。研究者还对比了基线 ResNet 、加了各种技巧的 ResNet、以及其它相关的神经网络,下表 1 展示了所有的准确率对比。这些技巧将 ResNet50 的 Top-1 验证准确率从 75.3%提高到 79.29%,还优于其他更新和改进的网络架构。此外,研究者还表示这些技巧很多都可以迁移到其它领域和数据集,例如目标检测和语义分割等。

原文地址:https://www.cnblogs.com/think90/p/11610923.html

时间: 2024-10-10 04:28:42

训练技巧详解【含有部分代码】Bag of Tricks for Image Classification with Convolutional Neural Networks的相关文章

Bag of Tricks for Image Classification with Convolutional Neural Networks

这篇文章来自李沐大神团队,使用各种CNN tricks,将原始的resnet在imagenet上提升了四个点.记录一下,可以用到自己的网络上.如果图片显示不了,点击链接观看 baseline model: resnet50 transform部分使用pytorch的torchvision接口 train transform: transforms.RandomResizedCrop(224) transforms.RandomHorizontalFlip(0.5) transforms.Colo

代码解读 Aittala_ECCV18_Burst Image Deblurring Using Permutation Invariant Convolutional Neural Networks

此文档用于记录Aittala_ECCV18 的代码学习过程,Tensorflow implement:http://people.csail.mit.edu/miika/eccv18_deblur/ Pytorch implement:https://github.com/FrederikWarburg/Burst-Image-Deblurring Pytorch下作者没有提供训练的参数,因此需要我们重新训练,其中涉及数据集下载,合成模糊和配准.这个留给以后做 Tensorflow 下作者训练了

Web攻防系列教程之跨站脚本攻击和防范技巧详解

Web攻防系列教程之跨站脚本攻击和防范技巧详解[XSS] 收藏:http://www.rising.com.cn/newsletter/news/2012-04-25/11387.html 来源:瑞星 2012-04-25 14:33:46 摘要:XSS跨站脚本攻击一直都被认为是客户端Web安全中最主流的攻击方式.因为Web环境的复杂性 以及XSS跨站脚本攻击的多变性,使得该类型攻击很难彻底解决.那么,XSS跨站脚本攻击具体攻击行为是什么,又该如何进行有效的防范呢?本文对此进行了 有针对性的具体

css sprite技巧详解

Css  sprite做为一个前端人员来说必须要掌握,但是这个对于刚学习的同学来说是由困难的,下面我就专门为这个内容做一次分享,这里没有网络图片地址,若内容显示不全面你可以到我的个人博客中?1. [代码][CSS]代码    CSSSprites在国内很多人叫css精灵,是一种网页图片应用处理方式.它允许你将一个页面涉及到的所有零星图片都包含到一张大图中去,这样一来,当访问该页面时,载入的图片就不会像以前那样一幅一幅地慢慢显示出来了.对于当前网络流行的速度而言,不高于200KB的单张图片的所需载

Navicat for MySQL 选项设置技巧详解

Navicat for MySQL给用户提供了完整的用户自定义设置界面选项,从主菜单选择工具->选项,但是很多的用户第一次接触,对这方面如何设置不是很了解,本教程将详细的给大家介绍介绍Navicat for MySQL 选项设置技巧详解.希望可以帮到大家. Navicat for MySQL 常规选项 Navicat 常规选项主要包括以下内容: 窗口在工作列显示:每打开一个新窗口时会自动显示在 Windows 任务栏.停用该选项后,当退出 Navicat 主窗口时,所有窗口(例如:表.查询)将会

深度学习原理详解及Python代码实现

深度学习框架如Tensorflow和Pytorch等为用户提供了可供调用的API,但也隐藏了深度学习底层的实现细节. 为方便大家更加深入地理解深度学习原理并了解其底层实现方法,特此推出了<课程深度学习原理详解及Python代码实现>.期望能"掀起你的盖头来,让我看看你的模样",为深度学习进一步的优化和创新打下根基. 课程链接:https://edu.51cto.com/course/21426.html 本课程详细讲解深度学习原理并进行Python代码实现.课程内容涵盖感知

JavaScript 身份证号有效验证详解及实例代码

JavaScript 身份证号有效验证详解及实例代码 这篇文章主要介绍了JavaScript 身份证号有效验证详解及实例代码的相关资料,需要的朋友可以参考下 JavaScript验证身份证号 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 <%@ page language="jav

KMP算法详解(图示+代码)

算法过程非常绕,不要企图一次就能看明白,多尝试就会明白一些.下面试图用比较直观的方法解释这个算法,对KMP算法的解释如下: 1. 首先,字符串"BBC ABCDAB ABCDABCDABDE"的第一个字符与搜索词"ABCDABD"的第一个字符,进行比较.因为B与A不匹配,所以搜索词后移一位. 2. 因为B与A不匹配,搜索词再往后移. 3. 就这样,直到字符串有一个字符,与搜索词的第一个字符相同为止. 4. 接着比较字符串和搜索词的下一个字符,还是相同. 5. 直到字

iOS插件详解之----CLangFormat(代码格式化管理插件)(2016.1.12王彬)

iOS插件详解之----CLangFormat(代码格式化管理)(2016.1.12王彬) 虽然在项目创建和团队组建的初期,我们就把公共约定以及一些规范定下来了,并且由于我们的代码是通过Git来做版本控制的,web上直接就支持Markdown格式的readme文件,可以随时看到最新的版本,但是这种规范只能依靠个人的意识,或者通过代码Review来解决,而且做代码Review的时候,你也不好意思总是写上一堆诸如“这里要加个空格”.“那里要加上换行”的评论吧?如果不管,久而久之,会因为每个人的习惯不