深度学习模型训练的tricks总结

1、数据与标签角度

1.1 数据归一化

https://blog.csdn.net/ytusdc/article/details/128504272

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方法需要较长的时间才能收敛得比较好。

1.3、标签平滑(Label Smoothing)

参考:

标签平滑(Label Smoothing)详解_ytusdc的博客-CSDN博客

2、权重初始化 (Weight Initialization)

权重初始化相比于其他的trick来说在平常使用并不是很频繁。因为大部分人使用的模型都是预训练模型,使用的权重都是在大型数据集上训练好的模型,当然不需要自己去初始化权重了。只有没有预训练模型的领域会自己初始化权重,或者在模型中去初始化神经网络最后那几个全连接层的权重。常用的权重初始化算法是「kaiming_normal」或者「xavier_normal」。

初始化参数尽量小一些,这样 softmax 的回归输出更加接近均匀分布,使得刚开始网络并不确信数据属于哪一类;另一方面从数值优化上看我们希望我们的参数具有一致的方差(一致的数量级),这样我们的梯度下降法下降也会更快。同时为了使每一层的激励值保持一定的方差,我们在初始化参数(不包括偏置项)的方差可以与输入神经元的平方根成反比

  • uniform均匀分布初始化:
  • Xavier初始法,适用于普通激活函数(tanh, sigmoid):
  • He初始化,适用于ReLU:
  • normal高斯分布初始化, 其中stdev为高斯分布的标准差,均值设为0:

3、学习率角度

学习率是一个非常非常重要的超参数,这个参数呢,面对不同规模、不同batch-size、不同优化方式、不同数据集,其最合适的值都是不确定的,我们无法光凭经验来准确地确定lr的值,我们唯一可以做的,就是在训练中不断寻找最合适当前状态的学习率。

学习率设置太大会导致训练十分不稳定,设置太小会导致损失下降太慢。学习率一般要随着训练进行衰减。衰减系数设0.1,0.3,0.5均可,衰减时机,可以是验证集准确率不再上升时,或固定训练多少个周期以后自动衰减

比如下图利用fastai中的lr_find()函数寻找合适的学习率,根据下方的学习率-损失曲线得到此时合适的学习率为1e-2。

深度学习模型训练的tricks总结_第1张图片

推荐一篇fastai首席设计师「Sylvain Gugger」的一篇博客:How Do You Find A Good Learning Rate[1], 以及相关的论文Cyclical Learning Rates for Training Neural Networks[2]。

3.1、Warm up

深度学习训练策略--学习率预热Warmup_ytusdc的博客-CSDN博客_warmup_steps

        训练初始阶段:由于刚开始训练时模型的权重(weights)是随机初始化的,此时选择一个较大的学习率,可能会带来模型的不稳定。学习率预热就是在刚开始训练的时候先使用一个较小的学习率,训练一些epoches或iterations,等模型稳定时再修改为预先设置的学习率进行训练。
        上述的方法是constant warmup,18年Facebook又针对上面的warmup进行了改进,因为从一个很小的学习率一下变为比较大的学习率可能会导致训练误差突然增大。提出了gradual warmup来解决这个问题,即从最开始的小学习率开始,每个iteration增大一点,直到最初设置的比较大的学习率。

3.2、Linear scaling learning rate —— learning-rate与batch-size的关系

        实验证明,大的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出现的一些小问题,

深度学习模型训练的tricks总结_第2张图片

 3.3、学习率衰减策略

在warmup之后的训练过程中,学习率不断衰减是一个提高精度的好方法。因此可以选择合适的学习率衰减策略:

学习率衰减策略 - 知乎

余弦退火(cosine annealing)和热重启的随机梯度下降

「余弦」就是类似于余弦函数的曲线,「退火」就是下降,「余弦退火」就是学习率类似余弦函数慢慢下降。

「热重启」就是在学习的过程中,「学习率」慢慢下降然后突然再「回弹」(重启)然后继续慢慢下降。

还要注意一点有些参数有更快、或更慢的学习速率,因此我们可以针对模型中的不同参数组,设定不同的学习率。在上述链接中也有介绍

4、难例挖掘 hard-negative-mining

1、分析模型难以预测正确的样本,给出针对性方法。

2、badcase 分析

5、模型的角度

5.1 多模型融合(Ensemble)

Ensemble是论文刷结果的终极核武器,深度学习中一般有以下几种方式

  1. 同样的参数,不同的初始化方式
  2. 不同的参数,通过cross-validation,选取最好的几组
  3. 同样的参数,模型训练的不同阶段,即不同迭代次数的模型。
  4. 不同的模型,进行线性融合. 例如RNN和传统模型.
  5. 提高模型性能和鲁棒性大法:probs融合 和 投票法。

假设这里有model 1, model 2, model 3,可以这样融合:

  1. model1 probs + model2 probs + model3 probs ==> final label
  2. model1 label , model2 label , model3 label ==> voting ==> final label
  3. model1_1 probs + ... + model1_n probs ==> mode1 label, model2 label与model3获取的label方式与1相同 ==> voting ==> final label

第三个方式的启发来源于,如果一个model的随机种子没有固定,多次预测得到的结果可能不同。以上方式的效果要根据label个数,数据集规模等特征具体问题具体分析,表现可能不同,方式无非是probs融合和投票法的单独使用or结合。

5.2、知识蒸馏(Knowledge Distillation)

这个其实是从代价函数的角度来分析的。用一个教师模型来帮助当前的模型(学生模型)训练,学生模型会使用新的代价函数,具体请参考知识蒸馏

使用所有的模型集成进行预测是比较麻烦的,并且可能计算量太大而无法部署到大量用户。Knowledge Distillation(知识蒸馏)方法就是应对这种问题的有效方法之一。

在知识蒸馏方法中,我们使用一个教师模型来帮助当前的模型(学生模型)训练。教师模型是一个较高准确率的预训练模型,因此学生模型可以在保持模型复杂度不变的情况下提升准确率。比如,可以使用ResNet-152作为教师模型来帮助学生模型ResNet-50训练。在训练过程中,我们会加一个蒸馏损失来惩罚学生模型和教师模型的输出之间的差异。
这个技术出自Hinton之手,通过效果更好的网络来指导轻量级网络训练,最终取得更好的训练效果。
 

5.3、指数移动平均(Exponential Moving Average)EMA

滑动平均模型,在训练的过程中不断的对参数求滑动平均这样能够更有效的保持稳定性,使其对当前参数更新不敏感。例如加动量项的随机梯度下降法就是在学习率上应用滑动平均模型。

参考文章:

指数移动平均(EMA)【在一定程度上提高最终模型在测试数据上的表现(例如accuracy、FID、泛化能力...)】

5.4、TTA(Test Time Augmentation)

最初这个概念是在fastai课程中看到的,这个过程在训练阶段不会参与,是通过在验证和测试阶段进行的。具体过程是,对所要处理的图像进行几种随机的图像增强变化,然后对每种图像增强后的图像进行预测,对预测结果取平均值。

原理类似于模型平均,牺牲推断速度来实现推断精度的提升。当然,这个技术也有好有坏,在我自己跑的卫星图数据集中采用TTA的精确度比不采用低了0.03个百分点

6、差分学习率与迁移学习

首先说下迁移学习,迁移学习是一种很常见的深度学习技巧,我们利用很多预训练的经典模型直接去训练我们自己的任务。虽然说领域不同,但是在学习权重的广度方面,两个任务之间还是有联系的。

深度学习模型训练的tricks总结_第3张图片

 由上图,我们拿来「model A」训练好的模型权重去训练我们自己的模型权重(「Model B」),其中,modelA可能是ImageNet的预训练权重,而ModelB则是我们自己想要用来识别猫和狗的预训练权重。

那么差分学习率和迁移学习有什么关系呢?我们直接拿来其他任务的训练权重,在进行optimize的时候,如何选择适当的学习率是一个很重要的问题。

一般地,我们设计的神经网络(如下图)一般分为三个部分,输入层,隐含层和输出层,随着层数的增加,神经网络学习到的特征越抽象。因此,下图中的卷积层和全连接层的学习率也应该设置的不一样,一般来说,卷积层设置的学习率应该更低一些,而全连接层的学习率可以适当提高。

深度学习模型训练的tricks总结_第4张图片

 这就是差分学习率的意思,在不同的层设置不同的学习率,可以提高神经网络的训练效果,具体的介绍可以查看下方的连接。

深度学习模型训练的tricks总结_第5张图片

7、 多尺度训练

多尺度训练是一种「直接有效」的方法,通过输入不同尺度的图像数据集,因为神经网络卷积池化的特殊性,这样可以让神经网络充分地学习不同分辨率下图像的特征,可以提高机器学习的性能,也可以用来处理过拟合效应,在图像数据集不是特别充足的情况下,可以先训练小尺寸图像,然后增大尺寸并再次训练相同模型,这样的思想在Yolo-v2的论文中也提到过。

需要注意的是:多尺度训练并不是适合所有的深度学习应用,多尺度训练可以算是特殊的数据增强方法,在图像大小这一块做了调整。如果有可能最好利用可视化代码将多尺度后的图像近距离观察一下,「看看多尺度会对图像的整体信息有没有影响」,如果对图像信息有影响的话,这样直接训练的话会误导算法导致得不到应有的结果。

8、Cross Validation 交叉验证

在李航的统计学方法中说到,交叉验证往往是对实际应用中「数据不充足」而采用的,基本目的就是重复使用数据。在平常中我们将所有的数据分为训练集和验证集就已经是简单的交叉验证了,可以称为1折交叉验证。「注意,交叉验证和测试集没关系,测试集是用来衡量我们的算法标准的,不参与到交叉验证中来。」

交叉验证只针对训练集和验证集。

交叉验证是Kaggle比赛中特别推崇的一种技巧,我们经常使用的是5-折(5-fold)交叉验证,将训练集分成5份,随机挑一份做验证集其余为训练集,循环5次,这种比较常见计算量也不是很大。还有一种叫做leave-one-out cross validation留一交叉验证,这种交叉验证就是n-折交叉,n表示数据集的容量,这种方法只适合数据量比较小的情况,计算量非常大的情况很少用到这种方法。

9、选择合适的优化算法

按理说不同的优化算法适合于不同的任务,不过我们大多数采用的优化算法还是是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。

10、尝试过拟合一个小数据集

这是一个经典的小trick了,但是很多人并不这样做,可以尝试一下。关闭正则化/随机失活/数据扩充,使用训练集的一小部分,让神经网络训练几个周期。确保可以实现零损失,如果没有,那么很可能什么地方出错了。

其他tricks
除了上面很多很高级的tricks,为了提升性能还有很多比较小的trick,有些是特别常用的特别普遍的,这里还是总结一下:

11、训练技巧

  1. 在数据集很大的情况下,别一上来就跑全量数据。先在一个较小(建议先用 1/100、1/10 )的训练集上train和test,对模型性能和训练时间有个底,外推一下全量数据到底需要跑多久。在没有足够的信心前不做大规模实验。  看看小数据集上它能不能过拟合或者预测结果比较理想。如果不能,可能是学习率太大,或者代码写错了。先调小学习率试一下,如果还不行就去检查代码,先看dataloader输出的数据对不对,再看模型每一步的size是否符合自己期待。例如: 一开始不用大数据集,先在一个大概2w训练集,2k测试集的小数据集上调参。
  2. 看train/eval的loss曲线,正常的情况应该是train loss呈log状一直下降最后趋于稳定,eval loss开始时一直下降到某一个epoch之后开始趋于稳定或开始上升,这时候可以用early stopping保存eval loss最低的那个模型。a、如果loss曲线非常不正常,很有可能是数据处理出了问题,比如label对应错了,回去检查代码。 b、如果我们设计的网络不work,在训练集的正确率也很低的话,我们可以减小样本数量同时去掉正则化项,然后进行调参,如果正确率还是不高的话,就说明我们设计的网络结果可能有问题。
  3. 优化器优先用adam,学习率设1e-3或1e-4,再试Radam(LiyuanLucasLiu/RAdam)。不推荐sgd,因为很慢。 sgd收敛速度会慢一些,但是最终收敛后的结果,一般都比较好。如果使用sgd的话,可以选择从1.0或者0.1的学习率开始,隔一段时间,在验证集上检查一下,如果cost没有下降,就对学习率减半. 我看过很多论文都这么搞,我自己实验的结果也很好. 当然,也可以先用ada系列先跑,最后快收敛的时候,更换成sgd继续训练.同样也会有提升.据说adadelta一般在分类问题上效果比较好,adam在生成问题上效果比较好。
  4. fine-tuning的时候,可以把新加层的学习率调高,重用层的学习率可以设置的相对较低。
  5. 激活函数用relu一般就够了,也可以试试leaky relu。当激活函数是RELU时,我们在初始化偏置项时,为了避免过多的死亡节点(激活值为0)一般可以初始化为一个较小的正值。
  6. 训练过程不仅要观察训练集和测试集的loss是否下降、正确率是否提高,对于参数以及激活值的分布情况也要及时观察,要有一定的波动。一个很好的措施是采用可视化库(visualization library ),在几个训练样例之后、或者周期之间,生成权重柱状图。这或许能帮助我们追踪深度学习模型中的一些常见问题,比如梯度消失与梯度爆发(Exploding Gradient)
  7. 要做梯度归一化,即算出来的梯度除以minibatch size
  8. 梯度检验:当我们的算法在训练出现问题而进行debug时,可以考虑使用近似的数值梯度和计算的梯度作比较检验梯度是否计算正确。
  9. gradient clipping(梯度裁剪):有一些任务(尤其是有RNN的)要做梯度裁剪(torch.nn.utils.clip_grad_norm),限制最大梯度可以防止梯度爆炸,其实是  value = sqrt(w1^2+w2^2….) ,  如果value超过了阈值,就算一个衰减系系数,让value的值等于阈值: 5,10,15。 训 RNN ,如果不加梯度裁剪导致训练一段时间以后 loss 突然变成 Nan。
  10. batchnorm和dropout可以试,放的位置很重要。优先尝试放在最后输出层之前,以及embedding层之后。RNN可以试layer_norm。但是有些任务上加了这些层可能会有负作用。dropout对小数据防止过拟合有很好的效果,值一般设为0.5, 小数据上dropout+sgd在我的大部分实验中,效果提升都非常明显。因此可能的话,建议一定要尝试一下。dropout的位置比较有讲究, 对于RNN,建议放到输入->RNN与RNN->输出的位置
  11. lrscheduler用torch.optim.lr_scheduler.CosineAnnealingLR,T_max设32或64,几个任务上试效果都不错。(用这个lr_scheduler加上adam系的optimizer基本就不用怎么调学习率了)
  12. 超参上,learning rate 最重要,推荐了解 cosine learning rate 和 cyclic learning
    rate,其次是 batchsize 和 weight decay。当你的模型还不错的时候,可以试着做数据增广和改损失函数锦上添花了。weight decay可以试一下,我一般用1e-4。
  13. 在确定初始学习率的时候,从一个很小的值(例如 1e-7)开始,然后每一步指数增大学习率(例如扩大1.05 倍)进行训练。训练几百步应该能观察到损失函数随训练步数呈对勾形,选择损失下降最快那一段的学习率即可。
  14. 除了gate之类的地方,需要把输出限制成0-1之外,尽量不要用sigmoid,可以用tanh或者relu之类的激活函数. sigmoid函数在[-4,4]的区间里,才有较大的梯度。之外的区间,梯度接近0,很容易造成梯度消失问题。 输入0均值,sigmoid函数的输出不是0均值的。
  15. 尽量对数据做shuffle
  16. 如果你的模型包含全连接层(MLP),并且输入和输出大小一样,可以考虑将MLP替换成Highway Network,我尝试对结果有一点提升,建议作为最后提升模型的手段,原理很简单,就是给输出加了一个gate来控制信息的流动。
  17. 一轮加正则,一轮不加正则,反复进行。
  18. 有CNN的地方就用shortcut。CNN层数加到某一个值之后对结果影响就不大了,这个值作为参数可以调一下。
  19. 注意实验的可复现性和一致性,注意养成良好的实验记录习惯 ==> 不然如何分析出实验结论。
  20. 对于大多数任务,数据比模型重要。面对新任务时先分析数据,再根据数据设计模型,并决定各个参数。例如nlp有些任务中的padding长度,通常需要达到数据集的90%以上,可用pandas的describe函数进行分析。

rnn调参技巧

  1. LSTM 的forget gate的bias,用1.0或者更大的值做初始化,可以取得更好的结果, 我这里实验设成1.0,可以提高收敛速度.实际使用中,不同的任务,可能需要尝试不同的值.
  2. 补充一个rnn trick,仍然是不考虑时间成本的情况下,batch size=1是一个很不错的regularizer,
  3. word2vec初始化,在小数据上,不仅可以有效提高收敛速度,也可以可以提高结果.
  4. rnn的dim和embdding size,一般从128上下开始调整. batch size,一般从128左右开始调整. batch size合适最重要,并不是越大越好.
  5. GPU 上报错时尽量放在 CPU 上重跑,错误信息更友好。例如 GPU 报 “ERROR:tensorflow:Model diverged with loss = NaN” 其实很有可能是输入 ID 超出了 softmax 词表的范围。

你可能感兴趣的:(AI之路,-,Face,深度学习,人工智能,神经网络)