赞
踩
目录
2、权重初始化 (Weight Initialization)
3.2、Linear scaling learning rate —— learning-rate与batch-size的关系
5.2、知识蒸馏(Knowledge Distillation)
5.3、指数移动平均(Exponential Moving Average)EMA
5.4、TTA(Test Time Augmentation)
其他参考文章:
归一化 (Normalization)、标准化 (Standardization)和中心/零均值化 (Zero-centered)_ytusdc的博客-CSDN博客
1.2 数据增强
Random image cropping and patching(RICAP):随机裁剪四个图片的中部分,然后把它们拼接为一个图片,同时混合这四个图片的标签。这也是一种比较特殊的数据增强方法,一般的数据增强都是对一个样本进行操作,而该方法将样本和标签同时进行融合,在大量的数据中也会取得不错的效果。
Cutout:是一种新的正则化方法。原理是在训练时随机把图片的一部分减掉,这样能提高模型的鲁棒性。它的来源是计算机视觉任务中经常遇到的物体遮挡问题。通过cutout生成一些类似被遮挡的物体,不仅可以让模型在遇到遮挡问题时表现更好,还能让模型在做决定时更多地考虑环境(context)。 我的理解这也是一种数据增广方法,通过让图像一定程度残缺来提高泛化能力,降低过拟合风险。
Random erasing:其实和cutout非常类似,也是一种模拟物体遮挡情况的数据增强方法。区别在于,cutout是把图片中随机抽中的矩形区域的像素值置为0,相当于裁剪掉,random erasing是用随机数或者数据集中像素的平均值替换原来的像素值。而且,cutout每次裁剪掉的区域大小是固定的,Random erasing替换掉的区域大小是随机的。
Mixup training: 这个思想与上面Random image cropping and patching有相似之处。Mixup training,就是每次取出2张图片,然后将它们线性组合,得到新的图片,以此来作为新的训练样本,进行网络的训练,如下公式,其中x代表图像数据,y代表标签,则得到的新的xhat, yhat。
看起来就是对数据进行线性组合从而增广,主要增强了训练样本之间的线性表达,增强网络的泛化能力,不过mixup方法需要较长的时间才能收敛得比较好。
参考:
标签平滑(Label Smoothing)详解_ytusdc的博客-CSDN博客
权重初始化相比于其他的trick来说在平常使用并不是很频繁。因为大部分人使用的模型都是预训练模型,使用的权重都是在大型数据集上训练好的模型,当然不需要自己去初始化权重了。只有没有预训练模型的领域会自己初始化权重,或者在模型中去初始化神经网络最后那几个全连接层的权重。常用的权重初始化算法是「kaiming_normal」或者「xavier_normal」。
初始化参数尽量小一些,这样 softmax 的回归输出更加接近均匀分布,使得刚开始网络并不确信数据属于哪一类;另一方面从数值优化上看我们希望我们的参数具有一致的方差(一致的数量级),这样我们的梯度下降法下降也会更快。同时为了使每一层的激励值保持一定的方差,我们在初始化参数(不包括偏置项)的方差可以与输入神经元的平方根成反比
学习率是一个非常非常重要的超参数,这个参数呢,面对不同规模、不同batch-size、不同优化方式、不同数据集,其最合适的值都是不确定的,我们无法光凭经验来准确地确定lr的值,我们唯一可以做的,就是在训练中不断寻找最合适当前状态的学习率。
学习率设置太大会导致训练十分不稳定,设置太小会导致损失下降太慢。学习率一般要随着训练进行衰减。衰减系数设0.1,0.3,0.5均可,衰减时机,可以是验证集准确率不再上升时,或固定训练多少个周期以后自动衰减。
比如下图利用fastai中的lr_find()函数寻找合适的学习率,根据下方的学习率-损失曲线得到此时合适的学习率为1e-2。
推荐一篇fastai首席设计师「Sylvain Gugger」的一篇博客:How Do You Find A Good Learning Rate[1], 以及相关的论文Cyclical Learning Rates for Training Neural Networks[2]。
深度学习训练策略--学习率预热Warmup_ytusdc的博客-CSDN博客_warmup_steps
训练初始阶段:由于刚开始训练时模型的权重(weights)是随机初始化的,此时选择一个较大的学习率,可能会带来模型的不稳定。学习率预热就是在刚开始训练的时候先使用一个较小的学习率,训练一些epoches或iterations,等模型稳定时再修改为预先设置的学习率进行训练。
上述的方法是constant warmup,18年Facebook又针对上面的warmup进行了改进,因为从一个很小的学习率一下变为比较大的学习率可能会导致训练误差突然增大。提出了gradual warmup来解决这个问题,即从最开始的小学习率开始,每个iteration增大一点,直到最初设置的比较大的学习率。
实验证明,大的batch size在相同的epoch下准确率会更小,使用warm up可以在一定程度上解决这个问题,而Linear scaling learning rate也是一种有效的方法。
一般来说,越大的batch-size使用越大的学习率。
在mini-batch SGD训练时,梯度下降的值是随机的,因为每一个batch的数据是随机选择的。增大batch size不会改变梯度的期望,但是会降低它的方差。也就是说,大batch size会降低梯度中的噪声,所以我们可以增大学习率来加快收敛。
具体做法很简单,比如ResNet原论文中,batch size为256时选择的学习率是0.1,当我们把batch size变为一个较大的数b时,学习率应该变为 0.1 × b/256。即线性的根据batch大小设置学习率,从而达到更好的学习效果。
简单的说,大的batch size计算得到的梯度噪声更小,所以可以使用更大的学习率来加大收敛。那么这里就有一个问题了,为什么小的batch size一般收敛的更快呢?这是因为小的batch size尽管方向不一定准确,但是更新次数多,最终收敛速度会更快。而大的batch size虽然噪声小,方向也更准确,但是由于学习率效果不会很好,这样线性的增加学习率其实也是相当于用单次更新量变大弥补更新次数小的事实。
总结,越大的batch-size意味着我们学习的时候,收敛方向的confidence越大,我们前进的方向更加坚定,而小的batch-size则显得比较杂乱,毫无规律性,因为相比批次大的时候,批次小的情况下无法照顾到更多的情况,所以需要小的学习率来保证不至于出错。
可以看下图损失Loss与学习率Lr的关系:
在显存足够的条件下,最好采用较大的batch-size进行训练,找到合适的学习率后,可以加快收敛速度。另外,较大的batch-size可以避免batch normalization出现的一些小问题,
在warmup之后的训练过程中,学习率不断衰减是一个提高精度的好方法。因此可以选择合适的学习率衰减策略:
余弦退火(cosine annealing)和热重启的随机梯度下降
「余弦」就是类似于余弦函数的曲线,「退火」就是下降,「余弦退火」就是学习率类似余弦函数慢慢下降。
「热重启」就是在学习的过程中,「学习率」慢慢下降然后突然再「回弹」(重启)然后继续慢慢下降。
每隔一段时间重启学习率,这样在单位时间内能收敛到多个局部最小值,可以得到很多个模型做集成。
还要注意一点有些参数有更快、或更慢的学习速率,因此我们可以针对模型中的不同参数组,设定不同的学习率。在上述链接中也有介绍
With Flooding
当training loss大于一个阈值时,进行正常的梯度下降;当training loss低于阈值时,会反过来进行梯度上升,让training loss保持在一个阈值附近,让模型持续进行"random walk",并期望模型能被优化到一个平坦的损失区域,这样发现test loss进行了double decent。
flood = (loss - b).abs() + b
1、分析模型难以预测正确的样本,给出针对性方法。
2、badcase 分析
Ensemble是论文刷结果的终极核武器,深度学习中一般有以下几种方式
假设这里有model 1, model 2, model 3,可以这样融合:
第三个方式的启发来源于,如果一个model的随机种子没有固定,多次预测得到的结果可能不同。以上方式的效果要根据label个数,数据集规模等特征具体问题具体分析,表现可能不同,方式无非是probs融合和投票法的单独使用or结合。
这个其实是从代价函数的角度来分析的。用一个教师模型来帮助当前的模型(学生模型)训练,学生模型会使用新的代价函数,具体请参考知识蒸馏
使用所有的模型集成进行预测是比较麻烦的,并且可能计算量太大而无法部署到大量用户。Knowledge Distillation(知识蒸馏)方法就是应对这种问题的有效方法之一。
在知识蒸馏方法中,我们使用一个教师模型来帮助当前的模型(学生模型)训练。教师模型是一个较高准确率的预训练模型,因此学生模型可以在保持模型复杂度不变的情况下提升准确率。比如,可以使用ResNet-152作为教师模型来帮助学生模型ResNet-50训练。在训练过程中,我们会加一个蒸馏损失来惩罚学生模型和教师模型的输出之间的差异。
这个技术出自Hinton之手,通过效果更好的网络来指导轻量级网络训练,最终取得更好的训练效果。
滑动平均模型,在训练的过程中不断的对参数求滑动平均这样能够更有效的保持稳定性,使其对当前参数更新不敏感。例如加动量项的随机梯度下降法就是在学习率上应用滑动平均模型。
参考文章:
指数移动平均(EMA)【在一定程度上提高最终模型在测试数据上的表现(例如accuracy、FID、泛化能力...)】
最初这个概念是在fastai课程中看到的,这个过程在训练阶段不会参与,是通过在验证和测试阶段进行的。具体过程是,对所要处理的图像进行几种随机的图像增强变化,然后对每种图像增强后的图像进行预测,对预测结果取平均值。
原理类似于模型平均,牺牲推断速度来实现推断精度的提升。当然,这个技术也有好有坏,在我自己跑的卫星图数据集中采用TTA的精确度比不采用低了0.03个百分点
首先说下迁移学习,迁移学习是一种很常见的深度学习技巧,我们利用很多预训练的经典模型直接去训练我们自己的任务。虽然说领域不同,但是在学习权重的广度方面,两个任务之间还是有联系的。
由上图,我们拿来「model A」训练好的模型权重去训练我们自己的模型权重(「Model B」),其中,modelA可能是ImageNet的预训练权重,而ModelB则是我们自己想要用来识别猫和狗的预训练权重。
那么差分学习率和迁移学习有什么关系呢?我们直接拿来其他任务的训练权重,在进行optimize的时候,如何选择适当的学习率是一个很重要的问题。
一般地,我们设计的神经网络(如下图)一般分为三个部分,输入层,隐含层和输出层,随着层数的增加,神经网络学习到的特征越抽象。因此,下图中的卷积层和全连接层的学习率也应该设置的不一样,一般来说,卷积层设置的学习率应该更低一些,而全连接层的学习率可以适当提高。
这就是差分学习率的意思,在不同的层设置不同的学习率,可以提高神经网络的训练效果,具体的介绍可以查看下方的连接。
多尺度训练是一种「直接有效」的方法,通过输入不同尺度的图像数据集,因为神经网络卷积池化的特殊性,这样可以让神经网络充分地学习不同分辨率下图像的特征,可以提高机器学习的性能,也可以用来处理过拟合效应,在图像数据集不是特别充足的情况下,可以先训练小尺寸图像,然后增大尺寸并再次训练相同模型,这样的思想在Yolo-v2的论文中也提到过。
需要注意的是:多尺度训练并不是适合所有的深度学习应用,多尺度训练可以算是特殊的数据增强方法,在图像大小这一块做了调整。如果有可能最好利用可视化代码将多尺度后的图像近距离观察一下,「看看多尺度会对图像的整体信息有没有影响」,如果对图像信息有影响的话,这样直接训练的话会误导算法导致得不到应有的结果。
在李航的统计学方法中说到,交叉验证往往是对实际应用中「数据不充足」而采用的,基本目的就是重复使用数据。在平常中我们将所有的数据分为训练集和验证集就已经是简单的交叉验证了,可以称为1折交叉验证。「注意,交叉验证和测试集没关系,测试集是用来衡量我们的算法标准的,不参与到交叉验证中来。」
交叉验证只针对训练集和验证集。
交叉验证是Kaggle比赛中特别推崇的一种技巧,我们经常使用的是5-折(5-fold)交叉验证,将训练集分成5份,随机挑一份做验证集其余为训练集,循环5次,这种比较常见计算量也不是很大。还有一种叫做leave-one-out cross validation留一交叉验证,这种交叉验证就是n-折交叉,n表示数据集的容量,这种方法只适合数据量比较小的情况,计算量非常大的情况很少用到这种方法。
按理说不同的优化算法适合于不同的任务,不过我们大多数采用的优化算法还是是adam和SGD+monmentum。Adam 可以解决一堆奇奇怪怪的问题(有时 loss 降不下去,换 Adam 瞬间就好了),也可以带来一堆奇奇怪怪的问题(比如单词词频差异很大,当前 batch 没有的单词的词向量也被更新;再比如Adam和L2正则结合产生的复杂效果)。用的时候要胆大心细,万一遇到问题找各种魔改 Adam(比如 MaskedAdam[14], AdamW 啥的)抢救。
但看一些博客说adam的相比SGD,收敛快,但泛化能力差,更优结果似乎需要精调SGD。adam,adadelta等, 在小数据上,我这里实验的效果不如sgd, sgd收敛速度会慢一些,但是最终收敛后的结果,一般都比较好。如果使用sgd的话,可以选择从1.0或者0.1的学习率开始,隔一段时间,在验证集上检查一下,如果cost没有下降,就对学习率减半. 我看过很多论文都这么搞,我自己实验的结果也很好. 当然,也可以先用ada系列先跑,最后快收敛的时候,更换成sgd继续训练.同样也会有提升.据说adadelta一般在分类问题上效果比较好,adam在生成问题上效果比较好。
adam收敛虽快但是得到的解往往没有sgd+momentum得到的解更好,如果不考虑时间成本的话还是用sgd吧。adam是不需要特别调lr,sgd要多花点时间调lr和initial weights。
这是一个经典的小trick了,但是很多人并不这样做,可以尝试一下。关闭正则化/随机失活/数据扩充,使用训练集的一小部分,让神经网络训练几个周期。确保可以实现零损失,如果没有,那么很可能什么地方出错了。
其他tricks
除了上面很多很高级的tricks,为了提升性能还有很多比较小的trick,有些是特别常用的特别普遍的,这里还是总结一下:
rnn调参技巧
一些大的注意事项:
刚开始, 先上小规模数据, 模型往大了放, 只要不爆显存, 能用256个filter你就别用128个。 直接奔着过拟合去。没错, 就是训练过拟合网络。连测试集验证集这些都可以不用。
为什么?
1、你要验证自己的训练脚本的流程对不对。 这一步小数据量, 生成速度快, 但是所有的脚本都是和未来大规模训练一致的(除了少跑点循环)
2、如果小数据量下, 你这么粗暴的大网络奔着过拟合去都没效果。 那么, 你要开始反思自己了, 模型的输入输出是不是有问题? 要不要检查自己的代码(永远不要怀疑工具库, 除非你动过代码)? 模型解决的问题定义是不是有问题? 你对应用场景的理解是不是有错? 不要怀疑NN的能力, 不要怀疑NN的能力, 不要怀疑NN的能力。 就我们调参狗能遇到的问题, NN没法拟合的, 这概率是有多小? 你可以不这么做, 但是等你数据准备了两天, 结果发现有问题要重新生成的时候, 你这周时间就酱油了。
1、一般来说分类就是Softmax, 回归就是L2的loss。 但是要注意loss的错误范围(主要是回归), 你预测一个label是10000的值, 模型输出0, 你算算这loss多大, 这还是单变量的情况下。 一般结果都是nan。 所以不仅仅输入要做normalization, 输出也要这么弄。
2、多任务情况下, 各loss想法限制在一个量级上, 或者最终限制在一个量级上, 初期可以着重一个任务的loss
准确率虽然是评测指标, 但是训练过程中还是要注意loss的。 你会发现有些情况下, 准确率是突变的, 原来一直是0, 可能保持上千迭代, 然后突然变1。 要是因为这个你提前中断训练了, 只有老天替你惋惜了。 而loss是不会有这么诡异的情况发生的, 毕竟优化目标是loss。给NN一点时间, 要根据任务留给NN的学习一定空间。 不能说前面一段时间没起色就不管了。 有些情况下就是前面一段时间看不出起色, 然后开始稳定学习。
分类网络就是学习类别之间的界限。 你会发现, 网络就是慢慢的从类别模糊到类别清晰的。 怎么发现? 看Softmax输出的概率的分布。 如果是二分类, 你会发现, 刚开始的网络预测都是在0。5上下, 很模糊。 随着学习过程, 网络预测会慢慢的移动到0,1这种极值附近。 所以, 如果你的网络预测分布靠中间, 再学习学习。
太大: loss爆炸, 或者nan
太小: 半天loss没反映(但是, LR需要降低的情况也是这样, 这里可视化网络中间结果, 不是weights, 有效果, 俩者可视化结果是不一样的, 太小的话中间结果有点水波纹或者噪点的样子, 因为filter学习太慢的原因, 试过就会知道很明显)
需要进一步降低了: loss在当前LR下一路降了下来, 但是半天不再降了。
如果有个复杂点的任务, 刚开始, 是需要人肉盯着调LR的。 后面熟悉这个任务网络学习的特性后, 可以扔一边跑去了。
如果上面的Loss设计那块你没法合理, 初始情况下容易爆, 先上一个小LR保证不爆, 等loss降下来了, 再慢慢升LR, 之后当然还会慢慢再降LR, 虽然这很蛋疼。
LR在可以工作的最大值下往小收一收, 免得ReLU把神经元弄死了。 当然, 我是个心急的人, 总爱设个大点的。
判断过拟合, 训练是否足够, 是否需要early stop的依据, 这都是中规中矩的原则, 不多说了。
CV的任务, context window是很重要的。 所以你对自己模型的receptive field的大小要心中有数。 这个对效果的影响还是很显著的。 特别是用FCN, 大目标需要很大的receptive field。 不像有fully connection的网络, 好歹有个fc兜底, 全局信息都有。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。