敞开生长之旅!这是我参加「日新方案 2 月更文应战」的第 3 天,点击查看活动概况。
前语
所谓深度神经网络的优化算法,即用来更新神经网络参数,并使丢失函数最小化的算法。优化算法关于深度学习非常重要,如果说网络参数初始化(模型迭代的初始点)能够决定模型是否收敛,那优化算法的功能则直接影响模型的练习效率。
了解不同优化算法的原理及其超参数的作用将使咱们更有用的调整优化器的超参数,然后进步模型的功能。
本文的优化算法特指: 寻找神经网络上的一组参数 \theta,它能明显地下降丢失函数 J()J(\theta ),该丢失函数一般包括整个练习集上的功能评价和额定的正则化项。
本文丢失函数、方针函数、代价函数不严厉区分界说。
一,梯度下降优化算法
1.1,随机梯度下降 SGD
梯度下降法是最基本的一类优化器,现在首要分为三种梯度下降法:规范梯度下降法(GD, Gradient Descent),随机梯度下降法(SGD, Stochastic Gradient Descent)及批量梯度下降法(BGD, Batch Gradient Descent)。
深度学习项目中的 SGD
优化一般默许指批量梯度下降法。其算法描绘如下:
-
输入和超参数: \eta 大局学习率
-
核算梯度:gt=∇J(t−1)g_t = \nabla_\theta J(\theta_{t-1})
-
更新参数:t=t−1−⋅gt\theta_t = \theta_{t-1} – \eta \cdot g_t
SGD 优化算法是最经典的神经网络优化办法,尽管收敛速度慢,可是收敛作用比较稳定。
下图1展现了随机梯度下降算法的梯度查找轨道示意图。能够看出由于梯度的随机性质,梯度查找轨道要很喧闹(动乱现象)。
因而,在实践运用中,随机梯度下降 SGD 法必须和动态学习率办法结合起来运用,不然运用固定学习率 + SGD的组合会使得模型收敛进程变得更复杂。
1.2,动量 Momentum
尽管随机梯度下降仍然是非常受欢迎的优化办法,但其学习进程有时会很慢且其梯度更新方向完全依赖于当时 batch
样本数据核算出的梯度,因而非常不稳定,因为数据可能有噪音。
受启示于物理学研讨领域研讨,依据动量 Momentum (Polyak, 1964) 的 SGD 算法用于改进参数更新时可能发生的振荡现象。动量算法旨在加快学习,特别是处理高曲率、小但一致的梯度,或是带噪声的梯度。两种算法作用比照如下图 2所示。
花书中对动量算法对目的解说是,处理两个问题: Hessian 矩阵的病态条件和随机梯度的方差。更偏学术化一点。
Momentum 算法的通俗理解便是,其模拟了物体运动时的惯性,即更新参数的时分会一起结合曩昔以及当时 batch 的梯度。算法在更新的时分会一定程度上保存之前更新的方向,一起运用当时 batch 的梯度微调终究的更新方向。这样一来,能够在一定程度上添加稳定性,然后学习地更快,而且还有一定脱节局部最优的才能。
下图3动量算法的前进方向。第一次的梯度更新完毕后,会记载 v1v1 的动量值。在“求梯度点”进行第二次梯度查看时,得到2号方向,与 v1v1 的动量组合后,终究的更新为2’方向。这样一来,由于有 v1v1 的存在,会迫使梯度更新方向具有“惯性”,然后能够减小随机样本形成的震荡。
Momentum 算法描绘如下:
1,输入和参数:
- \eta – 大局学习率
-
\alpha – 动量参数,一般取值为 0.5, 0.9, 0.99,取
0
,则等效于惯例的随机梯度下降法,其控制动量信息对全体梯度更新的影响程度。 - vtv_t – 当时时刻的动量,初值为 0。
2,算法核算进程:
-
核算梯度:gt=∇J(t−1)g_t = \nabla_\theta J(\theta_{t-1})
-
核算速度更新:vt=⋅vt−1+⋅gtv_t = \alpha \cdot v_{t-1} + \eta \cdot g_t (公式1)
-
更新参数:t=t−1−vt\theta_t = \theta_{t-1} – v_t (公式2)
留意,这儿的公式1和公式2和花书上的公式方式上略有不同,但其终究结果是相同的。本文给出的手艺推导迭代公式,来源文章 15.2 梯度下降优化算法。
通过推导参数更新迭代公式,更容易理解算法,依据算法公式(1)(2),以WW参数为例,有:
- v0=0v_0 = 0
- dW0=∇J(w)dW_0 = \nabla J(w)
- v1=v0+⋅dW0=⋅dW0v_1 = \alpha v_0 + \eta \cdot dW_0 = \eta \cdot dW_0
- W1=W0−v1=W0−⋅dW0W_1 = W_0 – v_1=W_0 – \eta \cdot dW_0
- dW1=∇J(w)dW_1 = \nabla J(w)
- v2=v1+dW1v_2 = \alpha v_1 + \eta dW_1
- W2=W1−v2=W1−(v1+dW1)=W1−⋅⋅dW0−⋅dW1W_2 = W_1 – v_2 = W_1 – (\alpha v_1 +\eta dW_1) = W_1 – \alpha \cdot \eta \cdot dW_0 – \eta \cdot dW_1
- dW2=∇J(w)dW_2 = \nabla J(w)
- v3=v2+dW2v_3=\alpha v_2 + \eta dW_2
- W3=W2−v3=W2−(v2+dW2)=W2−2dW0−dW1−dW2W_3 = W_2 – v_3=W_2-(\alpha v_2 + \eta dW_2) = W_2 – \alpha^2 \eta dW_0 – \alpha \eta dW_1 – \eta dW_2
能够看出与一般 SGD 的算法 W3=W2−dW2W_3 = W_2 – \eta dW_2 比较,**动量法不光每次要减去当时梯度,还要减去历史梯度W0,W1W_0, W_1 乘以一个不断削弱的因子\alpha、2\alpha^2,因为\alpha小于1,所以2\alpha^2比\alpha小,3\alpha^3比2\alpha^2小。这种方式的学名叫做指数加权均匀。
在实践模型练习中,SGD 和动量法的比较如下表所示。
试验作用比照图来源于材料 1。
算法 | 丢失函数和准确率 |
---|---|
SGD | |
Momentum |
从上表的比照能够看出,同一个深度模型, 一般随机梯度下降法的曲线震荡很严重,且通过 epoch=10000 次也没有到达预定 0.001 的丢失值;但动量算法通过 2000 个 epoch 就迭代完毕。
1.3,Nesterov 动量
受 Nesterov 加快梯度算法 (Nesterov, 1983, 2004) 启示,Sutskever et al. (2013) 提出了动量算法的一个变种,Nesterov 动量随机下降法(NAG
,英文全称是 Nesterov Accelerated Gradient,或许叫做 Nesterov Momentum 。
Nesterov 动量随机梯度下降办法是在上述动量梯度下降法更新梯度时参加对当时梯度的校对,简略解说便是往规范动量办法中添加了一个校对因子。
NAG 算法描绘如下:
1,输入和参数:
- \eta – 大局学习率
- \alpha – 动量参数,缺省取值0.9
- vv – 动量,初始值为0
2,算法核算进程:
- 参数暂时更新:=t−1−⋅vt−1\hat \theta = \theta_{t-1} – \alpha \cdot v_{t-1}
- 网络前向传达核算:f()f(\hat \theta)
- 核算梯度:gt=∇J()g_t = \nabla_{\hat\theta} J(\hat \theta)
- 核算速度更新:vt=⋅vt−1+⋅gtv_t = \alpha \cdot v_{t-1} + \eta \cdot g_t
- 更新参数:t=t−1−vt\theta_t = \theta_{t-1} – v_t
1.4,代码实践
Pytorch 结构中把一般 SGD、Momentum 算法和 Nesterov Momentum 算法的完成结合在一起了,对应的类是 torch.optim.SGD
。留意,其更新公式与其他结构略有不同,其间 pp、gg、vv、\mu 表明别离是参数、梯度、速度和动量。
# 和源码比省略了部分不常用参数
class torch.optim.SGD(params, lr=required, momentum=0, dampening=0,
weight_decay=0, nesterov=False)
1,功能解说:
可完成 SGD 优化算法、带动量 SGD 优化算法、带 NAG(Nesterov accelerated gradient)动量 SGD 优化算法,而且均可具有 weight_decay 项。
2,参数解说:
-
params
(iterable): 参数组(参数组的概念参考优化器基类:Optimizer
),即优化器要办理的那部分参数。 -
lr
(float): 初始学习率,可按需随着练习进程不断调整学习率。 -
momentum
(float): 动量因子,一般设置为 0.9,0.8。 -
weight_decay
(float): 权值衰减系数,也便是 L2 正则项的系数。 -
nesterov
(bool)- bool 选项,是否运用 NAG(Nesterov accelerated gradient)。
练习模型时常用装备如下:
torch.optim.SGD(lr=0.02, momentum=0.9, weight_decay=0.0001)
二,自适应学习率算法
神经网络研讨员早就意识到学习率肯定是难以设置的超参数之一,因为它对深度学习模型的功能有着明显的影响。
2.1,AdaGrad
在 AdaGrad 提出之前,咱们关于一切的参数运用相同的学习率进行更新,它是第一个自适应学习率算法,通过一切梯度历史平方值之和的平方根,然后使得步长单调递减。它依据自变量在每个维度的梯度值的大小来调整各个维度上的学习率,然后避免一致的学习率难以适应一切维度的问题。
AdaGrad
法依据练习轮数的不同,对学习率进行了动态调整。具体表现在,对低频呈现的参数进行大的更新(快速下降的学习率),对高频呈现的参数进行小的更新(相对较小的下降学习率)。因而,他很适合于处理稀少数据。
AdaGrad 算法描绘如下:
1,输入和参数
- \eta – 大局学习率
-
\epsilon – 用于数值稳定的小常数,主张缺省值为
1e-6
- r=0r=0 初始值
2,算法核算进程:
-
核算梯度:gt=∇J(t−1)g_t = \nabla_\theta J(\theta_{t-1})
-
累计平方梯度:rt=rt−1+gt⊙gtr_t = r_{t-1} + g_t \odot g_t
-
核算梯度更新:=+rt⊙gt\Delta \theta = {\eta \over \epsilon + \sqrt{r_t}} \odot g_t(和动手学深度学习给出的学习率调整公式方式不同)
-
更新参数:t=t−1−\theta_t=\theta_{t-1} – \Delta \theta
⊙\odot 按元素相乘,开方、除法和乘法的运算都是按元素运算的。这些按元素运算使得方针函数自变量中每个元素都别离具有自己的学习率。
AdaGrad 总结:在凸优化布景中,AdaGrad 算法具有一些令人满意的理论性质。可是,经历上已经发现,关于练习深度神经网络模型而言,从练习开始时积累梯度平方会导致有用学习率过早和过量的减小。AdaGrad 在某些深度学习模型上作用不错,但不是全部。
Pytorch 结构中 AdaGrad 优化器:
class torch.optim.Adagrad(params, lr=0.01, lr_decay=0, weight_decay=0, initial _accumulator_value=0)
2.2,RMSProp
RMSProp
(Root Mean Square Prop),均方根反向传达。
RMSProp 算法 (Hinton, 2012) 和 AdaGrad 算法的不同在于, RMSProp算法使⽤了小批量随机梯度按元素平⽅的指数加权移动均匀来调整学习率。
RMSProp 算法描绘如下:
1,输入和参数:
- \eta – 大局学习率,主张设置为0.001
- \epsilon – 用于数值稳定的小常数,主张缺省值为1e-8
- \alpha – 衰减速率,主张缺省取值0.9
- rr – 累积变量矩阵,与\theta尺度相同,初始化为0
2,算法核算进程(核算梯度和更新参数公式和 AdaGrad 算法相同):
-
累计平方梯度:r=⋅r+(1−)(gt⊙gt)r = \alpha \cdot r + (1-\alpha)(g_t \odot g_t)
-
核算梯度更新:=r+⊙gt\Delta \theta = {\eta \over \sqrt{r + \epsilon}} \odot g_t
RMSProp 总结:经历上,RMSProp 已被证明是一种有用且实用的深度神经网络优化算法。现在,它是深度学习从业者常常选用的优化办法之一。其初始学习率设置为 0.01
时比较抱负。
Pytorch 结构中 RMSProp 优化器:
class torch.optim.RMSprop(params, lr=0.01, alpha=0.99, eps=1e- 08, weight_decay=0, momentum=0, centered=False)
2.3,AdaDelta
AdaDelta 法也是对 AdaGrad 法的一种改进,它旨在处理深度模型练习后期,学习率过小问题。比较核算之前一切梯度值的平方和,AdaDelta 法仅核算在一个大小为 ww 的时刻区间内梯度值的累积和。
RMSProp 算法核算进程如下:
1,参数界说:
-
Adadelta 没有学习率参数。相反,它运用参数本身的改变率来调整学习率。
-
ss – 累积变量,初始值 0
2,算法核算进程:
- 核算梯度:gt=∇J(t−1)g_t = \nabla_\theta J(\theta_{t-1})
- 累积平方梯度:st=⋅st−1+(1−)⋅gt⊙gts_t = \alpha \cdot s_{t-1} + (1-\alpha) \cdot g_t \odot g_t
- 核算梯度更新:=rt−1+st+⊙gt\Delta \theta = \sqrt{r_{t-1} + \epsilon \over s_t + \epsilon} \odot g_t
- 更新梯度:t=t−1−\theta_t = \theta_{t-1} – \Delta \theta
- 更新改变量:r=⋅rt−1+(1−)⋅⊙r = \alpha \cdot r_{t-1} + (1-\alpha) \cdot \Delta \theta \odot \Delta \theta
Pytorch 结构中 AdaDelta 优化器:
class torch.optim.Adadelta(params, lr=1.0, rho=0.9, eps=1e- 06, weight_decay=0)
2.4,Adam
Adam (Adaptive Moment Estimation,Kingma and Ba, 2014) 是另一种学习率自适应的优化算法,相当于 RMSProp + Momentum
的作用,即动量项的 RMSprop 算法。
Adam 算法在 RMSProp 算法基础上对小批量随机梯度也做了指数加权移动均匀。和 AdaGrad 算法、RMSProp 算法以及 AdaDelta 算法相同,方针函数自变量中每个元素都别离具有自己的学习率。
Adam 算法核算进程如下:
1,参数界说:
- tt – 当时迭代次数
- \eta – 大局学习率,主张缺省值为0.001
- \epsilon – 用于数值稳定的小常数,主张缺省值为1e-8
- 1,2\beta_1, \beta_2 – 矩估量的指数衰减速率,∈[0,1)\in[0,1),主张缺省值别离为0.9和0.999
2,算法核算进程:
-
核算梯度:gt=∇J(t−1)g_t = \nabla_\theta J(\theta_{t-1})
-
计数器加一:t=t+1t=t+1
-
更新有偏一阶矩估量:mt=1⋅mt−1+(1−1)⋅gtm_t = \beta_1 \cdot m_{t-1} + (1-\beta_1) \cdot g_t
-
更新有偏二阶矩估量:vt=2⋅vt−1+(1−2)(gt⊙gt)v_t = \beta_2 \cdot v_{t-1} + (1-\beta_2)(g_t \odot g_t)
-
修正一阶矩的误差:mt=mt/(1−1t)\hat m_t = m_t / (1-\beta_1^t)
-
修正二阶矩的误差:vt=vt/(1−2t)\hat v_t = v_t / (1-\beta_2^t)
-
核算梯度更新:=⋅mt/(+vt)\Delta \theta = \eta \cdot \hat m_t /(\epsilon + \sqrt{\hat v_t})
-
更新参数:t=t−1−\theta_t=\theta_{t-1} – \Delta \theta
从上述公式能够看出 Adam 运用指数加权移动均匀值来预算梯度的动量和二次矩,即运用了状态变量 mt、vtm_t、v_t。
怎样理解 Adam 算法?
首要,在 Adam 中,动量直接并入了梯度一阶矩(指数加权)的估量。将动量参加 RMSProp 最直观的办法是将动量运用于缩放后的梯度。结合缩放的动量运用没有清晰的理论动机。其次,Adam 包括偏置修正,修正从原点初始化的一阶矩(动量项)和(非中心的)二阶矩的估量。RMSProp 也选用了(非中心的)二阶矩估量,然而缺失了修正因子。因而,不像 Adam,RMSProp 二阶矩估量可能在练习初期有很高的偏置。 Adam 一般被认为对超参数的选择相当鲁棒,尽管学习率有时需要从主张的默许修改。
初学者看看公式就行,这段话我也是摘抄花书,现在没有很深入理解。
Adam 算法完成过程如下。
Adam 总结:由于 Adam 承继了 RMSProp 的传统,所以学习率相同不宜设置太高,初始学习率设置为 0.01
时比较抱负。
Pytorch 结构中 Adam 优化器:
class torch.optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e- 08, weight_decay=0, amsgrad=False)
三,总结
3.1,PyTorch 的十个优化器
PyTorch 中一切的优化器基类是 Optimizer
类,在 Optimizer 类中界说了 5 个 实用的基本办法,别离是
-
zero_grad()
:将梯度清零。 -
step(closure)
:履行一步权重参数值更新, 其间可传入参数 closure(一个闭包)。 -
state_dict()
:获取模型当时参数,以一个有序字典方式返回,key 是参数名,value 是参数。 -
load_state_dict(state_dict)
:将 state_dict 中的参数加载到当时网络,常用于 finetune。 -
add_param_group(param_group)
:给 optimizer 办理的参数组中添加一组参数,可为该组参数定制 lr, momentum, weight_decay 等,在 finetune 中常用。
PyTorch 依据 Optimizer
基类构建了十种优化器,有常见的 SGD、ASGD、Rprop、 RMSprop、Adam 等等。留意 PyTorch 中的优化器和前文描绘的优化算法略有不同,PyTorch 中 给出的优化器与原始论文中提出的优化办法,多少是有些改动的,概况可直接阅览源码。
3.2,优化算法总结
-
Adam 等自适应学习率算法关于稀少数据具有优势,且收敛速度很快;但精调参数的 SGD(+Momentum)往往能够获得更好的终究结果。
-
用相同数量的超参数来调参,尽管有时自适应优化算法在练习集上的 loss 更小,可是他们在测验集上的 loss 却可能比 SGD 系列办法高。
-
自适应优化算法在练习前期阶段在练习集上收敛的更快,但可能在测验集上的泛化性欠好。
-
现在,最盛行而且运用很高的优化算法包括 SGD、具动量的 SGD、RMSProp、 具动量的 RMSProp、AdaDelta 和 Adam。但选择哪一个算法首要取决于运用者对算法的熟悉程度(更方便调理超参数)。
参考材料
- 《智能之门-神经网络与深度学习入门》-15.2 梯度下降优化算法
- 《深度学习》-第八章 深度模型中的优化
- 《动手学深度学习》-优化算法