目录
避免过拟合
overfitting即过拟合,典型的表现为训练集损失远远小于验证集损失。而欠拟合则表现为训练集损失大于验证集损失。
我们要清楚远远大于的概念,如果训练集损失只比验证集损失多一点点的话,同等数量级(例如0.8与0.9)这种情况下并不是过拟合的表现。我们一般遇到的过拟合应该是0.8(训练集损失)与2.0(验证集损失)这种不在一个量级的损失比。
- Trick:Dropout
Dropout类似于bagging ensemble减少variance。通过投票来减少可变性。通常我们在全连接层部分使用dropout,在卷积层则不使用。Dropout一般适合于全连接层部分,而卷积层由于其参数并不是很多,所以不需要dropout,加上的话对模型的泛化能力并没有太大的影响。一般情况,在全连接层部分,采用较大概率的dropout而在卷积层采用低概率或者不采用dropout。
数据的问题
数据集的好坏是算法泛化好坏的一个非常重要的前提条件,我们通常在构建深度学习的任务中,所得到的数据集一般不会是非常完美的。(不论是自己搭建还是利用他人的数据,在数据集量过大的时候,数据集中难免会有图像损坏或者错误的个例)。
因此在一开始得到数据集的时候最好不要直接开始训练,应该去仔细检查自己的数据集是否有问题,这样可以避免很多之后训练时需要的处理的麻烦。比例图像是否损坏、内容缺失、标签不一致等等。
关于数据集
如果数据集极其不平衡,假如我们有个检测船只的任务,在100000图中只有30000张图中含有船只,其余图像都是不含船只的图像,这时候如果对此直接进行训练效果应该会很差。为此,首先可以挑选出只有船只的图像集合进行初步训练。其次,使用训练好的模型去检测没有训练的部分(不含船只),挑选出检测失败的false positive(也就是在没有船的图像集中检测出船只了)加入之前的训练集再次进行训练。
数据增强
深度学习为什么需要那么多的数据?
这里只简单说下我们常用的数据增强的Transform。
大部分我们使用的图像增强技术一般是随机旋转,水平翻转,高斯模糊和尺度变化还有什么拉伸等操作。这些图像变化对大部分的任务是比较适合的,但针对特定的任务,存在某一簇特殊的图像增强技术可以达到比普通图像增强技术更好的效果。例如夜视图或者光照:
但也需要提个醒,并不是所有的图像增强都可以提升模型的泛化能力。
而且有些图像增强技术会对原始图像造成损失从而导致神经网络学习到错误的信息,这点是我们比较容易忽视的问题,同样重要,相关内容可以查看fastai中的图像增强技术为什么相对比较好。
TTA(Test Time Augmentation)
最初这个概念是在fastai课程中看到的,这个过程在训练阶段不会参与,是通过在验证和测试阶段进行的。具体过程是,对所要处理的图像进行几种随机的图像增强变化,然后对每种图像增强后的图像进行预测,对预测结果取平均值。原理类似于模型平均,牺牲推断速度来实现推断精度的提升
难以区分的数据hard-negative-mining
在任何一个深度学习任务中,我们都会遇到一些比较“棘手”的数据,这些数据相比较于其他的普通数据更难识别,这种特比容易识别错误的例子就称为hard-negative。
- Trick:错误样本反复训练
先用初始的正负样本(一般是正样本+与正样本同规模的负样本的一个子集)训练分类器, 然后再用训练出的分类器对样本进行分类, 把其中负样本中错误分类的那些样本(hard negative)放入负样本集合, 再继续训练分类器, 如此反复, 直到达到停止条件(比如分类器性能不再提升)。也就是不停滴将困难样本拿去训练,让分类器更好地学习到难以学习的特征。
尝试过拟合一个小数据集
这是一个经典的小trick了,但是很多人并不这样做,可以尝试一下。
关闭正则化/随机失活/数据扩充,使用训练集的一小部分,让神经网络训练几个周期。确保可以实现零损失,如果没有,那么很可能什么地方出错了。
学习率
合适的学习率(learning rate)
学习率是一个非常非常重要的超参数,面对不同规模、不同batch-size、不同优化方式、不同数据集,其最合适的值都是不确定的,我们无法光凭经验来准确地确定lr的值,我们唯一可以做的,就是在训练中不断寻找最合适当前状态的学习率。
比如下图利用fastai中的lr_find()函数寻找合适的学习率,根据下方的学习率-损失曲线得到此时合适的学习率为1e-2。
如果想要了解更多,这里推荐一篇fastai首席设计师Sylvain Gugger的一篇博客:How Do You Find A Good Learning Rate 以及相关的论文Cyclical Learning Rates for Training Neural Networks。
学习率与batch-size的关系
一般来说,越大的batch-size使用越大的学习率。
原理很简单,越大的batch-size意味着我们学习的时候,收敛方向的confidence越大,我们前进的方向更加坚定,而小的batch-size则显得比较杂乱,毫无规律性,因为相比批次大的时候,批次小的情况下无法照顾到更多的情况,所以需要小的学习率来保证不至于出错。可以看下图损失Loss与学习率Lr的关系(Visualizing Learning rate vs Batch size):
当然我们也可以从上图中看出,当batchsize变大后,得到好的测试结果所能允许的lr范围在变小,也就是说,当batchsize很小时,比较容易找打一个合适的lr达到不错的结果,当batchsize变大后,可能需要精细地找一个合适的lr才能达到较好的结果,这也给实际的large batch分布式训练带来了困难。所以说,在显存足够的条件下,最好采用较大的batch-size进行训练,找到合适的学习率后,可以加快收敛速度。另外,较大的batch-size可以避免batch normalization出现的一些小问题:https://github.com/pytorch/pytorch/issues/4534
分布式训练learning rate与Batch size :https://www.zhihu.com/question/64134994/answer/216895968
查分学习率与迁移学习
首先说下迁移学习,迁移学习是一种很常见的深度学习技巧,我们利用很多预训练的经典模型直接去训练我们自己的任务。虽然说领域不同,但是在学习权重的广度方面,两个任务之间还是有联系的。
由上图,我们拿来model A训练好的模型权重去训练我们自己的模型权重(Model B),其中,modelA可能是ImageNet的预训练权重,而ModelB则是我们自己想要用来识别猫和狗的预训练权重。那么差分学习率和迁移学习有什么关系呢?我们直接拿来其他任务的训练权重,在进行optimize的时候,如何选择适当的学习率是一个很重要的问题。一般地,我们设计的神经网络(如下图)一般分为三个部分,输入层,隐含层和输出层,随着层数的增加,神经网络学习到的特征越抽象。因此,下图中的卷积层和全连接层的学习率也应该设置的不一样,一般来说,卷积层设置的学习率应该更低一些,而全连接层的学习率可以适当提高。
这就是差分学习率的意思,在不同的层设置不同的学习率,可以提高神经网络的训练效果,具体的介绍可以查看连接transfer-learning-using-differential-learning-rates。
余弦退火(cosine annealing)和热重启的随机梯度下降
余弦就是类似于余弦函数的曲线,退火就是下降,余弦退火就是学习率类似余弦函数慢慢下降。
热重启就是在学习的过程中,学习率慢慢下降然后突然再回弹(重启)然后继续慢慢下降。
两个结合起来就是下方的学习率变化图:
更多详细的介绍可以查看知乎机器学习算法如何调参?这里有一份神经网络学习速率设置指南
以及相关论文SGDR: Stochastic Gradient Descent with Warm Restarts
权重初始化
因为大部分人使用的模型都是预训练模型,使用的权重都是在大型数据集上训练好的模型,当然不需要自己去初始化权重了。只有没有预训练模型的领域会自己初始化权重,或者在模型中去初始化神经网络最后那几个全连接层的权重。权重初始化方法有kaiming_normal、xavier_normal。
Xavier随机初始化: 假设某全连接层的输入个数为
a
a
a ,输出个数为
b
b
b ,Xavier随机初始化将使该层中权重参数的每个元素都随机采样于均匀分布
U ( − 6 a + b , 6 a + b ) U\left ( -\sqrt{\frac{6}{a+b}},\sqrt{\frac{6}{a+b}} \right ) U(−a+b6,a+b6)
它的设计主要考虑到,模型参数初始化后,每层输出的方差不该受该层输入个数影响,且每层梯度的方差也不该受该层输出个数影响。
另外各种框架里也有封装好的权重初始化函数,例如pytorch中的nn.Module 的模块参数都采取了较为合理的初始化策略(不同类型的layer具体采样的哪一种初始化方法的可参考源代码),因此一般不用我们考虑。
相关论文:
Delving deep into rectifiers: Surpassing human-level performance on ImageNet classification
Understanding the difficulty of training deep feedforward neural networks
多尺度训练
多尺度训练是一种直接有效的方法,通过输入不同尺度的图像数据集,因为神经网络卷积池化的特殊性,这样可以让神经网络充分地学习不同分辨率下图像的特征,可以提高机器学习的性能。也可以用来处理过拟合效应,在图像数据集不是特别充足的情况下,可以先训练小尺寸图像,然后增大尺寸并再次训练相同模型,这样的思想在Yolo-v2的论文中也提到过
需要注意的是:多尺度训练并不是适合所有的深度学习应用,多尺度训练可以算是特殊的数据增强方法,在图像大小这一块做了调整。如果有可能最好利用可视化代码将多尺度后的图像近距离观察一下,看看多尺度会对图像的整体信息有没有影响,如果对图像信息有影响的话,这样直接训练的话会误导算法导致得不到应有的结果。
Cross Validation 交叉验证
在李航的统计学方法中说到,交叉验证往往是对实际应用中数据不充足而采用的,基本目的就是重复使用数据。在平常中我们将所有的数据分为训练集和验证集就已经是简单的交叉验证了,可以称为1折交叉验证。注意,交叉验证和测试集没关系,测试集是用来衡量我们的算法标准的,不参与到交叉验证中来。交叉验证只针对训练集和验证集。交叉验证是Kaggle比赛中特别推崇的一种技巧,我们经常使用的是5-折(5-fold)交叉验证,将训练集分成5份,随机挑一份做验证集其余为训练集,循环5次,这种比较常见计算量也不是很大。还有一种叫做leave-one-out cross validation 留一交叉验证,这种交叉验证就是n-折交叉,n表示数据集的容量,这种方法只适合数据量比较小的情况,计算量非常大的情况很少用到这种方法。
吴恩达有一节课The nuts and bolts of building applications using deep learning中也提到了
关于优化算法
按理说不同的优化算法适合于不同的任务,不过我们大多数采用的优化算法还是是adam和SGD+monmentum。