深度学习调优总结
寻找合适的学习率
学习率是一个非常重要的超参数,在面对不同规模的网络、不同batch-size、不同优化方式,不同数据集,甚至可能不同时间段训练的合适值都不确定。我们唯一可以做的是在训练中不断寻找最合适当前状态的学习率。比如利用fastai中的lr_find()函数寻找合适的学习率。
-
较大的学习率加速了网络训练,但可能无法达到最优解。
-
较小的学习率会使网络训练缓慢。除此之外,过小的学习率可能会使网络陷入局部最优解。
-
学习率过大的情况小,网络无法学习到有效的知识。
策略:在网络训练初期使用大的学习率加速收敛,之后降低学习率提高模型训练效果。这被称为学习率衰减(Learning Rate Decay)。
learning-rate与batch-size的关系
越大的batch-size使用越大的学习率。在显存足够的条件下 ,最好采用较大的batch-size进行训练,找到合适的学习率后,可以加快收敛速度。另外较大的batch-size可以避免一些小问题,参考pytorch库的issue。
权重初始化
权重初始化一般使用模型都是一些在大型数据集上已经预训练好的模型。只有没有预训练模型的领域会自己初始化权重,或者在模型中去初始化神经网络最后那几个全连接层的权重。常用的权重初始化算法是【Kaiming_normal】或者【Xavier_normal】
Dropout
Dropout指的是在深度学习网络的训练过程中,对于神经网络单元,按照一定的概率将其暂时从网络中丢弃。对于随机梯度下降而言,由于是随机丢弃,故而每一个mini-batch都在训练不同的网络。
Dropout类似于bagging ensemble减少variance。通常在全连接层使用dropout,在卷积层不使用,注意Dropout并不适合所有的情况。
数据集处理
数据筛选以及数据增强
难例挖掘
分析模型难以预测正确的样本,给出针对性方法
多模型融合
- 同样的参数,不同的初始化方式
- 不同的参数,通过cross-validation,选取最好的几组
- 同样的参数,模型训练的不同阶段,即不同迭代次数的模型
- 不同的模型,进行线性融合。
- probs融合和投票法
差分学习率与迁移学习
迁移学习是利用很多预训练的经典模型直接训练我们自己的任务,虽然说领域不同,但是在学习权重的广度方面,两个任务之间还是有联系的。差分学习率在拿其他任务的训练权重的时候,进行optimize需要选择一个适当的学习率。在不同层提高设计不同的学习率,可以提高神经网络训练的效果。调整差分学习率可以通过余弦退火和热重启的随机梯度下降。
尝试过拟合一个小的数据集
关闭正则化、Dropout,数据增强,使用训练集一小部分,让神经网络训练几个周期。确保可以实现零损失。
多尺度训练
多尺度训练是一种直接有效的方法,由于神经网络卷积池化的特殊性,通过输入不同尺度的图像数据集,能让神经网络充分地学习不同分辨率下图像特征,提高机器学习的性能。同时也可以处理过拟合效应,在图像数据集不是特别充足的情况下,可以先训练小尺寸图像,然后增大尺寸并再次训练相同模型。需要注意:多尺度训练并不是所有的深度学习应用都适用,要看多尺度会不会对图像的整体信息有没有影响,如果有影响,直接训练会误导算法,导致产生不良效果。
Cross Validation交叉验证
交叉验证往往是对实际应用中数据不充足而采用的,基本目的就是重复使用数据。
优化算法
不同优化算法适用于不同的任务,大多数采用的优化算法是adam和SGD+monmentum。详细的优化算法可以参考:一个框架看懂优化算法之异同 SGD/AdaGrad/Adam
训练技巧
- 要做梯度归一化,即梯度/minibatch size
- 尽量对数据做shuffle
- 在数据集很大的情况下,建议先用数据集的1/100,1/10的数据跑一下,对模型的性能和训练时间有个底,外推全量数据到底需要跑多久。
- GPU上报错时尽量放在CPU上重跑,错误信息更友好。
- 在确定初始学习率时,从一个很小的值开始,然后每一步指数增大学习率进行训练。
- 注意实验的可复现性和一致性,注意养成良好的实验记录习惯。
- 在超参数上,learning rate最重要,推荐了解cosine learning rate和cyclic learning rate,其次是batchsize和weight decay。
训练过程的效果较好,但是预测的时候出现NAN
请检查下数据集是否混进了误差数据,导致模型学习的时候出现偏差
Warm up
目前在做深度学习任务的时候,都会在tensorflow的github上下载一些预训练好的模型。也有尝试过权重初始化为0进行训练,然而收敛不太好。除此之外对于学习率的选择,一开始是选择较大的学习率,然后随着训练的推移,逐步调整学习率。
Label-smoothing
标签平滑是为了解决模型的过拟合问题。具体思想是降低对于标签的信任。
Batch size
Batch Size主要影响的是每个Epoch的训练时长和每次迭代的梯度平滑度。
假设全量样本为n,Batch Size设置为b,则每个Epoch的迭代次数为n/b。从这个点来看,当Batch Size减小时,迭代次数变多,每次迭代的训练时长减少,但整个Epoch的训练时长是增加的。
Batch Size过小:
迭代的梯度不平滑,模型训练loss振荡。模型的训练更偏重于拟合个体,导致在训练过程中模型容易忽视数据的整体规律性。
训练时长增加。
内存利用率低。
Batch Size过大:
容易陷入局部最优,从而影响模型效果。过大的Batch Size容易忽视数据中的个体差异性,并使得模型的梯度下降方向固定。
内存容易溢出。在实际训练中,如果新进程导致了额外的内存占用,容易强行终止模型训练。
需要强调的是,大的Batch Size会降低模型精度,但模型的梯度下降方向更为准确,所以辅以设置更大的学习率可以加速模型的收敛;小的Batch Size可以更好的捕获到模型的个体差异性,从而具有较高的模型精度,并且应该设置更小的学习率缓解loss振荡问题。
数据集增广
数据集增广有多种方式,裁剪取样,旋转,翻转,加噪声等,还有Cutout(随意把图像的一部分减掉,提升模型的鲁棒性,思想来源于视觉任务中物体被遮挡了。),Random erasing,Mixup training等
Cyclical Learning Rates for Training Neural Networks
CLR可操作性地消除往常需要实验般地去手动寻找最佳的最佳学习率和全局的学习率的schedule调整方案,CLR通过调整学习率在上边界和下边界中变化,而不是单调地减少学习率来达到网络的最佳拟合状态。关于CLR在分类任务上的表现,作者提到,通过CLR的表现,可以避免再微调和用更少的iterations达到最佳精度。使用了triangular的变化策略,使得一个范围(base_lr ~ max_lr)里的学习率在训练中都能得到运用,也就是说,在下边界和上边界中,那个最佳的学习率将会在训练中有机会运用到训练中,通过绘制精度走势图,我们也可以看出这点。在论文中,作者是通过一种更为实际的理由来进行这般解释的。
针对CNN的调优总结
针对CNN优化的总结
可以阅读以下论文:Systematic evaluation of CNN advances on the ImageNet
- 使用没有barchnorm的ELU非线性或者由batchnorm的ReLu
- 用类似 1 × 1 1\times1 1×1的网络结构预训练
- 使用线性学习率衰退策略
- 使用平均和最大池化层的和
- mini-batch的大小最好使用128~256
- 使用卷积层代替之前之前的MLP中的线性层,并用平均池化层预测
- 当研究增加训练集大小的时候,需要确定数据集对性能提升的平衡点
- 数据质量比数据数量更重要
- 如果网络结构比较复杂,且经过高度优化,如GoogleNet,建议不要再进行修改。
充分利用DNN的小技巧
- shuffle
- 扩充数据集
- 在训练之前,先在非常小的子数据集上训练进行过拟合,通过这样来验证网络是可以收敛,网络结构没有问题
- 使用Dropout避免过拟合
- 避免LRN池化,MAX池化会更快
- 网络越深,尽可能使用ReLu或者LeakyRelu,而不是Sigmoid、Tanh
- 要能适用更小的模型
- 使用小模型的时候,可以试试ensemble
- 尽可能使用 xavier 初始化
- 如果你的输入数据有空间参数,可以试试端到端的 CNN。可以阅读这篇论文:SqueezeNet: AlexNet-level accuracy with 50x fewer parameters and <0.5MB model size [Forrest N. Iandola et. al. 2016],它介绍了一种新的方法,而且性能非常好,你可以尝试应用上面提到的tips。
- 了解自己的任务
提升算法的思路
获取更多的数据
深度学习是以数据为驱动的技术。深度学习模型的质量通常受到训练数据质量的限制。为了得到更好的模型,需要获取更多更好的数据,可阅读:Datasets Over Algorithms(www.edge.org/response-detail/26587)
数据增广
在训练数据有限的情况下,可以通过数据增广的方式扩充你的训练数据,如图像数据可以通过平移,旋转,加噪声等方式扩增数据集,以此来提高模型的泛化能力。数据增广可以参考:
- Image Augmentation for Deep Learning With Keras(http://machinelearningmastery.com/image-augmentation-deep-learning-keras/)
- What is jitter? (Training with noise)(ftp://ftp.sas.com/pub/neural/FAQ3.html#A_jitter)
Rescale
在神经网络中,大的数值累积效应并不是好事,通过Rescale将数据归一化到某个区间,从而提升网络的性能。
- Should I standardize the input variables (column vectors)?
- How To Prepare Your Data For Machine Learning in Python with Scikit-Learn
数据转换
- How to Define Your Machine Learning Problem
- Discover Feature Engineering, How to Engineer Features and How to Get Good at It
- How To Prepare Your Data For Machine Learning in Python with Scikit-Learn
特征选择
重构问题
- 看看能够在一个时间窗(时间周期)内对已有的特征/数据做一个合并。
- 或许你的分类问题可以成为一个回归问题(有时候是回归到分类)。
- 或许你的二元输出可以变成softmax输出?
- 或许你可以转而对子问题进行建模。
通过算法提升性能
对算法进行抽样调查
首先尝试评估一些线性方法,例如逻辑回归(logistic regression)和线性判别分析(linear discriminate analysis)。评估一些树类模型,例如CART, 随机森林(Random Forest)和Gradient Boosting。评估一些实例方法,例如支持向量机(SVM)和K-近邻(kNN)。评估一些其他的神经网络方法,例如LVQ, MLP, CNN, LSTM, hybrids等。
- A Data-Driven Approach to Machine Learning
- Why you should be Spot-Checking Algorithms on your Machine Learning Problem
- Spot-Check Classification Machine Learning Algorithms in Python with scikit-learn
借鉴已有文献
多读论文
重采样方法
对模型的评估:
- Evaluate the Performance Of Deep Learning Models in Keras
- Evaluate the Performance of Machine Learning Algorithms in Python using Resamplin
通过算法调参提升性能
参数优化:How to Grid Search Hyperparameters for Deep Learning Models in Python With Keras
Diagnostics
确定你的模型是过拟合还是欠拟合,通过训练过程中模型的训练集和验证集上的性能来判断,从而对症下药。
权重初始化
- 尝试所有不同的初始化方法,考察是否有一种方法在其他情况不变的情况下(效果)更优。
- 尝试用无监督的方法,例如自动编码(autoencoder),来进行预先学习。
- 尝试使用一个已经存在的模型,只是针对你的问题重新训练输入层和输出层(迁移学习(transfer learning))
Initialization of deep networks
Early Stopping
一旦训练过程中出现(验证集)性能开始下降,你可以停止训练与学习。这可以节省很多时间,而且甚至可以让你使用更详尽的重采样方法来评估你的模型的性能。
早停法是一种用来避免模型在训练数据上的过拟合的正则化方式,它需要你监测模型在训练集以及验证集上每一轮的效果。一旦验证集上的模型性能开始下降,训练就可以停止。
如果某个条件满足(衡量准确率的损失),你还可以设置检查点(Checkpointing)来储存模型,使得模型能够继续学习。检查点使你能够早停而非真正的停止训练,因此在最后,你将有一些模型可供选择。
以下是相关阅读:
嵌套模型
- 组合方式
- 组合视角
- stacking/堆叠
小目标检测
特征融合FPN
不同阶段的特征图对应的感受野不一样,它们表达的信息抽象程序也不一样。浅层的特征图感受野小,比较适合检测小目标;深层的特征图感受野大,适合检测大目标。
另外一个思路:既然可以在不同分辨率特征图做融合来提升特征的丰富度和信息含量来检测不同大小的目标,那么自然也有人会进一步地猜想,如果只用高分辨率的特征图(浅层特征)去检测小脸;用中间分辨率的特征图(中层特征)去检测大脸;最后用低分辨率的特征图(深层特征)去检测小脸。比如人脸检测中的[SSH]。
合适的训练方法SNIP,SNIPER,SAN
机器学习里面有个重要的观点,模型预训练的分布要尽可能地接近测试输入的分布。
所以,在大分辨率(比如常见的224 x 224)下训练出来的模型,不适合检测本身是小分辨率再经放大送入模型的图片。如果是小分辨率的图片做输入,应该在小分辨率的图片上训练模型;再不行,应该用大分辨率的图片训练的模型上用小分辨率的图片来微调fine-tune;最差的就是直接用大分辨率的图片来预测小分辨率的图(通过上采样放大)。
但是这是在理想的情况下的(训练样本数量、丰富程度都一样的前提下,但实际上,很多数据集都是小样本严重缺乏的),所以放大输入图像+使用高分率图像预训练再在小图上微调,在实践中要优于专门针对小目标训练一个分类器。
在下图中示意的是SNIP训练方法,训练时只训练合适尺寸的目标样本,只有真值的尺度和Anchor的尺度接近时来用来训练检测器,太小太大的都不要,预测时输入图像多尺度,总有一个尺寸的Anchor是合适的,选择那个最合适的尺度来预测。
更稠密的Anchor采样和匹配策略S3FD,FaceBoxes
利用Context信息的Relation Network和PyramidBox
小目标,特别是像人脸这样的目标,不会单独地出现在图片中(想想单独一个脸出现在图片中,而没有头、肩膀和身体也是很恐怖的)。像[PyramidBox](PyramidBox: A Context-assisted Single Shot Face Detector)方法,加上一些头、肩膀这样的上下文Context信息,那么目标就相当于变大了一些,上下文信息加上检测也就更容易了。另外[Relation Networks](Relation Networks for Object Detection)虽然主要是解决提升识别性能和过滤重复检测而不是专门针对小目标检测的,但是也和上面的PyramidBox思想很像的,都是利用上下文信息来提升检测性能,可以归类为Context一类。
参考
- 写给新手炼丹师:2021版调参上分手册
- 我们是如何改进YOLOv3进行红外小目标检测的?
- CNN调优总结
- 小目标检测
- Joint Face Detection and Alignment using Multi-task Cascaded Convolutional Networks
- 《深度学习中不平衡样本的处理》
- Augmentation for small object detection
- Feature Pyramid Networks for Object Detection
- RetinaFace: Single-stage Dense Face Localisation in the Wild
- SSH: Single Stage Headless Face Detector
- An Analysis of Scale Invariance in Object Detection - SNIP
- R-FCN: Object Detection via Region-based Fully Convolutional Networks
- SNIPER: Efficient Multi-Scale Training
- SAN: Learning Relationship between Convolutional Features for Multi-Scale Object Detection
- ScratchDet: Training Single-Shot Object Detectors from Scratch
- FaceBoxes: A CPU Real-time Face Detector with High Accuracy
- S3FD: Single Shot Scale-Invariant Face Detector
- Perceptual Generative Adversarial Networks for Small Object Detection
- PyramidBox: A Context-assisted Single Shot Face Detector
- Relation Networks for Object Detection