优化器用通俗的话来说就是一种算法,是一种计算导数的算法。各种优化器的目的和发明它们的初衷其实就是能让用户选择一种适合自己场景的优化器。优化器的最主要的衡量指标就是优化曲线的平稳度,最好的优化器就是每一轮样本数据的优化都让权重参数匀速的接近目标值,而不是忽上忽下的跳跃的变化。因此损失值的平稳下降对于一个深度学习模型来说是一个非常重要的衡量指标。
pytorch的优化器都放在torch.optim
包中。常见的优化器有:
SGD, Adam, Adadelta, Adagrad, Adamax等。这几种优化器足够现实世界中使用了,如果需要定制特殊的优化器,pytorch也提供了定制化的手段,不过这里我们就不去深究了,毕竟预留的优化器已经足够强大了。
在本节中就说说几种常见的优化器的用法。
SGD指stochastic gradient descent, 即随机梯度下降,随机的意思是随机选取部分数据集参与计算,是梯度下降的batch版本。SGD支持动量参数,支持学习衰减率。SGD优化器也是最常见的一种优化器,实现简单,容易理解。
用法:
optimizer = optim.SGD(model.parameters(),lr = 0.01, momentum = 0.9) #这里lr表示leaning rate
参数
对于训练数据集,我们首先将其分成n个batch,每个batch包含m个样本。我们每次更新都利用一个batch的数据,而非整个训练集,即:
x t + 1 = x t + Δ x t x_{t+1} = x_t +\Delta x_t xt+1=xt+Δxt
Δ x t = − η g t \Delta x_t =-\eta g_t Δxt=−ηgt
其中, η \eta η为学习率, g t g_t gt为x在t时刻的梯度。
这么做的好处在于:
当训练数据太多时,利用整个数据集更新往往时间上不现实。batch的方法可以减少机器的压力,并且可以更快地收敛。
当训练集有很多冗余时(类似的样本出现多次), batch方法收敛更快。以一个极端情况为例,若训练集前一半和后一半梯度相同,那么如果前一半作为一个batch,后一半作为另一个batch,那么在一次遍历训练集时,batch的方法向最优解前进两个step,而整体的方法只前进一个step。
RMSProp全称Root Mean Square Prop,RMSProp通过引入一个衰减系数,让r每回合都衰减一定比例,类似于Momentum中的做法,该优化器通常是面对递归神经网络时的一个良好的选择。
具体实现:
需要:全局学习速率 ϵ \epsilon ϵ, 初始参数 θ \theta θ, 数值稳定量 δ \delta δ,衰减速率 ρ \rho ρ.
中间变量:梯度累积量r(初始化为0)
每步迭代过程:
(1) 从训练集中随机抽取一批容量为m的样本 x 1 , . . . , x m {x_1,...,x_m} x1,...,xm以及相关的输出 y i y_i yi。
keras.optimizers.RMSprop(lr=0.001, alpha=0.9, eps=1e-06)
参数
AdaGrad可以自动变更学习速率,只是需要设定一个全局的学习速率 ϵ \epsilon ϵ, 但是这并非是实际的学习速率,实际的速率是与以往参数的模之和的开方成反比的。也许说起来有点绕口,不过用公式来表示就直白的多:
其中 δ \delta δ是一个很小的常量,大概在 1 0 − 7 10^{-7} 10−7, 防止出现除以0的情况。
具体实现:
需要:全局学习速率 ϵ \epsilon ϵ,初始参数 θ \theta θ, 数值稳定量 δ \delta δ。
中间变量:梯度累积量r(初始化为0)。
每步迭代过程:
优点:
能够实现学习速率的自动更改。如果这次梯度大,那么学习速率衰减的就快一些;如果这次梯度小,那么学习速率衰减的就慢一些。
缺点:
仍然要设置一个变量 ϵ \epsilon ϵ。
经验表明,在普通算法中也许效果不错,但在深度学习中,当深度过深时,会造成训练提前结束。
用法:
torch.optim.optimizers.Adagrad(lr=0.01, epsilon=1e-06)
参数:
Adagrad 算法存在三个问题:
学习速率是单调递减的,训练后期学习率非常小。
需要手工设置一个全局的初始学习率。
更新 x t x_t xt时,左右两边的单位不统一。
Adadelta针对上述的三个问题提出了比较漂亮的解决方案。
首先,针对第一个问题,我们可以只使用adagrad的分母中的累计项(离当前时间点比较近的项),如下式:
这里的 ρ \rho ρ是衰减系数,通过这个衰减系数,我们令每一个时刻的 g t g_t gt随时间按照 ρ \rho ρ指数衰减, 这样就相当于我们仅使用离当前时刻比较近的 g t g_t gt信息,从而使得很长时间后,参数仍然可以得到更新。
针对第三个问题,其实SGD跟momentum系列的方法也有单位不统一的问题。sgd、momentum系列方法中:
类似的,adagrad中,用于更新 Δ x \Delta x Δx的单位也不是x的单位,而是1.
而对于牛顿迭代法:
其中H为Hessian矩阵,由于其计算量巨大,因而实际中不常使用。其单位为:
注意:这里f无单位。因而,牛顿迭代法的单位是正确的。所以,我们可以模拟牛顿迭代法来得到正确的单位。注意到:
这里,在解决学习率单调递减的问题的方案中,分母已经是 ∂ f ∂ x \partial f \over \partial x ∂x∂f的一个近似了。这里我们可以构造 Δ x \Delta x Δx的近似,来模拟得到H-1的近似,从而得到近似的牛顿迭代法。具体做法如下:
可以看到,如此以来Adagrad中分子部分需要人工设置的初始学习率也消失了,从而顺带解决了上述的第二个问题。
用法:
keras.optimizer.Adadelta(lr=1.0,rho=0.95,epsilon=1e-06)
Adam是一种基于一阶梯度来优化随机目标函数的算法。
Adam这个名字来源于 adaptive moment estimation, 自适应矩估计。概率论中矩的含义是:如果一个随机变量X服从某个分布,X的一阶矩是 E ( X ) E(X) E(X),也就是样本平均值,X的二阶距就是 E ( X 2 ) E(X^2) E(X2),也就是样本平方的平均值。Adam算法根据损失函数对每个参数的梯度的一阶矩估计和二阶距估计动态调整对于每个参数的学习速率。Adam也是基于梯度下降的方法,但是每次迭代参数的学习步长都有一个确定的范围,不会因为很大的梯度而导致较大的学习步长,参数的值也比较稳定。
Adam(Adaptive Moment Estimation)本质上是带有动量项的RMSprop,它利用梯度的一阶矩估计和二阶距估计动态调整每个参数的学习率。Adam的有点主要在于经过偏置校正后,每一次迭代学习率都有一个确定的范围,使得参数比较平稳。
具体实现:
需要:步进值 ϵ \epsilon ϵ,初始参数 θ \theta θ,数值稳定量 δ \delta δ,一阶动量衰减系数 ρ 1 \rho 1 ρ1, 二阶动量衰减系数 ρ 2 \rho 2 ρ2。
其中几个取值一般为: δ = 1 0 8 , ρ 1 = 0.9 , ρ 2 = 0.999 \delta=10^8,\rho 1=0.9,\rho 2=0.999 δ=108,ρ1=0.9,ρ2=0.999 。
中间变量:一阶动量s,二阶动量r,都初始化为0。
每步迭代过程:
keras.optimizers.Adam(lr=0.001,beta_1=0.9,beta_2=0.999,epsilon=1e-08)
参数
keras.optimizers.Adamax(lr=0.002,beta_1 = 0.9, beta_2 = 0.999, epsilong=1e-08)
Adamax 优化器来自于Adam的论文的Section7,该方法是基于无穷范数的Adam方法的变体。
默认参数由论文提供。
参数
本文是作者在学习书籍《Pytorch深度学习实战》一书时做的笔记,才疏学浅,如有错误还望指正。