文章目录
- 前言
- 一 优化器
- 二 超参数
- 参考
前言
一 优化器
机器学习的五个步骤: 数据 -> 模型 -> 损失 -> 优化器 -> 迭代训练。 我们通过前向传播的过程,得到了模型输出与真实标签的差异,我们称之为损失, 有了损失,我们会进入反向传播过程得到参数的梯度,那么接下来就是优化器干活了,优化器要根据我们的这个梯度去更新参数,使得损失不断的降低。 那么优化器是怎么做到的呢? 该博主从三部分进行展开,首先是优化器的概念,然后是优化器的属性和方法,最后是常用的优化器。
深度学习优化算法经历了 SGD -> SGDM -> NAG ->AdaGrad -> AdaDelta -> Adam -> Nadam 这样的发展历程。该博主详细告诉你这些算法是如何一步一步演变而来的。
optim.SGD: 随机梯度下降法
optim.Adagrad: 自适应学习率梯度下降法
optim.RMSprop: Adagrad的改进
optim.Adadelta: Adagrad的改进
optim.Adam: RMSprop结合Momentum
optim.Adamax: Adam增加学习率上限
optim.SparseAdam: 稀疏版的Adam
optim.ASGD: 随机平均梯度下降
optim.Rprop: 弹性反向传播
optim.LBFGS: BFGS的改进
SGD:选择合适的learning rate比较困难 - 对所有的参数更新使用同样的learning rate.我们常用的mini-batch SGD训练算法,然而虽然这种算法能够带来很好的训练速度,但是在到达最优点的时候并不能够总是真正到达最优点,而是在最优点附近徘徊。另一个缺点就是这种算法需要我们挑选一个合适的学习率,当我们采用小的学习率的时候,会导致网络在训练的时候收敛太慢;当我们采用大的学习率的时候,会导致在训练过程中优化的幅度跳过函数的范围,也就是可能跳过最优点
SGD+Momentum:基于梯度的移动指数加权平均解决mini-batch SGD优化算法更新幅度摆动大的问题,同时可以使得网络的收敛速度更快(注意:使用Momentum时偏差修正可用可不用–吴恩达深度学习)
Momentum原理:积累之前的动量来替代真正的梯度,计算梯度的指数加权平均数,并利用该梯度更新权重,相关方向加速SGD,抑制振荡,从而加快收敛。
RMSprop:积累之前的动量来替代真正的梯度对梯度计算微分平方加权平均数,进一步优化损失函数在更新中存在摆动幅度过大的问题,并且进一步加快函数的收敛速度.(对学习率加了一定的约束,但事实上仍依赖于人工设置的一个全局学习率)
Adam:将Momentum算法和RMSProp算法结合起来使用的一种算法,表现比前两种更好,所以它也是解决摆动幅度过大,加快函数的收敛速度;同时利用梯度的一阶矩估计和二阶矩估计动态调整每个参数的学习率,实现学习率自适应。(注意:在Adam中Momentum的偏差修正是必须使用的!)
parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW'], default='SGD', help='optimizer')
实际上学术界上对于SGD和Adam哪个更好,一直没有统一的定论,取决于实际项目情况。
YOLO V5的作者建议是,如果需要训练较小的自定义数据集,Adam是更合适的选择,并且可以在较大的数据集上提供良好的初始结果,尽管Adam的学习率通常比SGD低(一般Adam为SGD的0.1倍)。但是 SGD 从长远来看往往会表现出色,尤其是训练大型数据集,并且似乎可以更好地推广到现实世界的结果。对于YOLOV5框架在VOC数据集的训练结果来说,效果:SGD > AdamW > Adam 。结果来自该issue。
SGD最大的缺点是下降速度慢,而且可能会在沟壑的两边持续震荡,停留在一个局部最优点。
所以,谈到现在,到底Adam好还是SGD好?这可能是很难一句话说清楚的事情。去看学术会议中的各种paper,用SGD的很多,Adam的也不少,还有很多偏爱AdaGrad或者AdaDelta。可能研究员把每个算法都试了一遍,哪个出来的效果好就用哪个了。毕竟paper的重点是突出自己某方面的贡献,其他方面当然是无所不用其极,怎么能输在细节上呢?
而从这几篇怒怼Adam的paper来看,多数都构造了一些比较极端的例子来演示了Adam失效的可能性。这些例子一般过于极端,实际情况中可能未必会这样,但这提醒了我们,理解数据对于设计算法的必要性。优化算法的演变历史,都是基于对数据的某种假设而进行的优化,那么某种算法是否有效,就要看你的数据是否符合该算法的胃口了。算法固然美好,数据才是根本。另一方面,Adam之流虽然说已经简化了调参,但是并没有一劳永逸地解决问题,默认的参数虽然好,但也不是放之四海而皆准。因此,在充分理解数据的基础上,依然需要根据数据特性、算法特性进行充分的调参。
二 超参数
parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch.yaml', help='hyperparameters path')
超参数data/hyps/下有以下五个:
关于选择哪种,作者的解释是:
参考
- SGD -> SGDM -> NAG ->AdaGrad -> AdaDelta -> Adam -> Nadam 发展历程
- YOLOv5-优化器和学习率调整策略
- https://pypi.org/project/torch-optimizer/