深度学习中常用的优化算法(SGD, Nesterov,Adagrad,RMSProp,Adam)总结
1. 引言
在深度学习中我们定义了损失函数以后,会采取各种各样的方法来降低损失函数的数值,从而使模型参数不断的逼近于真实数据的表达。不过损失函数的数值只是我们用来优化模型中参数的一个参考量,我们是通过优化损失函数来间接地优化模型参数,并提高模型的度量指标。而优化算法的作用就是加快模型的收敛,取得最优值。
优化算法可以分为两大类,一类是基于 Momentum 的优化算法, 另一类是自适应的优化算法。
基于 Momentum 的优化算法
- SGD
- SGD + Mementum
- Nesterov
自适应的优化算法
- Adagrad
- RMSProp
- Adam
2. Momentum Based
2.1 SGD
SGD (stochastic gradient descent) 随机梯度下降。随机梯度下降系列可以分为
- SGD
- full-batch SGD
- mini-batch SGD
- mini-batch SGD + Momentum
值得注意的是,通常我们在说随机梯度下降算法的时候, 实际上都是说的 mini-batch SGD + Momentum, 因为它运用的最多。
SGD 是每次随机选择一个数据,喂给模型,然后更新参数。显然这种方式的缺点是由于每次喂入的数据量太少,模型学不到什么东西。
显然 full-batch SGD 是另一个极端, 上面的 SGD 是一条数据一条数据的喂,而 full-batch SGD 则是每一次迭代都将所有数据都喂进去,显然这将是非常大的计算量。所以现实中常常采用的是 mini-batch SGD, 其从训练集中少量采样一些数据拿来计算。这里有一个问题是为什么可以用 mini-batch 来替代 full-batch?
- 第一,n个样本的均值的标准差是 σ n \frac{\sigma} {\sqrt{n}} nσ ,其中 σ \sigma σ 是样本值真实的标准差。分母 n \sqrt{n} n 说明样本数量的贡献是低于线性的,可以算一下,我们用100个样本和用10000个样本来计算均值标准差,多用了100倍的数据,却只降低了10倍的标准差。如果能够迅速求出估计值,而不是缓慢计算准确值,会加快算法的收敛速度。
- 第二,训练集中经常会存在冗余的情况,完全有可能出现相同数据,如果重复了 m m m 次,那么用小批量算法就可以少花 m m m 倍的时间。
mini-batch SGD 的过程大致如下:
mini-batch SGD |
---|
输入:学习率 ϵ k \epsilon_k ϵk ,初始参数 θ \theta θ |
while 未满足停止条件 do |
从训练集中采集包含 m m m 个样本 { x ( 1 ) , x ( 2 ) , . . . , x ( m ) } \{x^{(1)},x^{(2)},...,x^{(m)}\} { x(1),x(2),...,x(m)} 的小批量,其中数据 x i {x^{i}} xi 和对应目标 y ( i ) y^{(i)} y(i) |
计算梯度估计: ∇ θ k − 1 J ( θ k − 1 ) ← 1 m ∇ θ k − 1 L ( f ( x ( i ) , θ k − 1 ) , y ( i ) ) \nabla_{\theta_{k-1}} J(\theta_{k-1}) \leftarrow\frac{1}{m}\nabla_{\theta_{k-1}} L(f(x^{(i)}, \theta_{k-1}),y^{(i)}) ∇θk−1J(θk−1)←m1∇θk−1L(f(x(i),θk−1),y(i)) |
更新参数: θ k ← θ k − 1 − ϵ k ∇ θ k − 1 J ( θ k − 1 ) \theta_k \leftarrow\theta_{k-1}-\epsilon_k\nabla_{\theta_{k-1}} J(\theta_{k-1}) θk←θk−1−ϵk∇θk−1J(θk−1) |
end while |
上面的学习率 ϵ \epsilon ϵ 是需要学习的超参数。因为仅仅用一个 case 或者一个小的 batch 的 case 来计算梯度,所以仅仅是对训练数据集梯度的一个估计。
总的来说上面的三种 SGD 算法所面临的问题是
- Zigzag
- 容易陷入 local optimize
针对上面问题,SGD + Momentum 被提了出来,SGD + Momentum 主要有了以下提升:
- 缓解 Zigzag
- 比 SGD, 对于局部最优有改善
首先对比下单纯的 SGD 和 SGD + Momentum 的更新方式的区别。
名字 | 更新方式 |
---|---|
单纯 SGD: | θ ← θ − ϵ ∇ θ J ( θ ) \theta \leftarrow\theta-\epsilon \nabla_\theta J(\theta) θ←θ−ϵ∇θJ(θ) |
SGD + Momentum: | v t ← α v t − 1 − ϵ ∇ θ J ( θ ) v_t \leftarrow\alpha v_{t-1}-\epsilon \nabla_\theta J(\theta) vt←αvt−1−ϵ∇θJ(θ); θ ← θ + v t \theta \leftarrow\theta+v_t θ←θ+vt |
上面的 v v v 我们称为速度, α \alpha α 是动量参数, ∇ θ J ( θ ) \nabla_\theta J(\theta) ∇θJ(θ) 是当前轮次计算得到的梯度。
从公式可以看出, v v v 会记录上一次的梯度信息,通过动量参数 α \alpha α 来控制上一次的更新量对本次更新量的影响,注意它是一个非负项,所以它起到了“惯性”的作用。
- 下降初期时,引入上一次参数更新,使得下降方向趋近于上次的方向,乘上较大的 α \alpha α 能够进行很好的加速
- 下降中后期时,在局部最小值来回震荡的时候,也就是 ∇ θ J ( θ ) → 0 \nabla_\theta J(\theta)\rightarrow0 ∇θJ(θ)→0, α \alpha α 使得更新幅度增大,跳出局部最优
- 在梯度改变方向的时候,momentum 能够减少更新,从而缓解 Zigzag 问题。
SGD + Momentum |
---|
输入:学习率 ϵ k \epsilon_k ϵk ,初始参数 θ \theta θ,动量参数 α \alpha α ,初始速度 v v v |
while 未满足停止条件 do |
从训练集中采集包含 m m m 个样本 { x ( 1 ) , x ( 2 ) , . . . , x ( m ) } \{x^{(1)},x^{(2)},...,x^{(m)}\} { x(1),x(2),...,x(m)} 的小批量,其中数据 x i {x^{i}} xi 和对应目标 y ( i ) y^{(i)} y(i) |
计算梯度估计: ∇ θ k − 1 J ( θ k − 1 ) ← 1 m ∇ θ k − 1 L ( f ( x ( i ) , θ k − 1 ) , y ( i ) ) \nabla_{\theta_{k-1}} J(\theta_{k-1}) \leftarrow\frac{1}{m}\nabla_{\theta_{k-1}} L(f(x^{(i)}, \theta_{k-1}),y^{(i)}) ∇θk−1J(θk−1)←m1∇θk−1L(f(x(i),θk−1),y(i)) |
更新速度: v k ← α v k − 1 − ϵ k ∇ θ k − 1 J ( θ k − 1 ) v_k \leftarrow \alpha v_{k-1}-\epsilon_k\nabla_{\theta_{k-1}} J(\theta_{k-1}) vk←αvk−1−ϵk∇θk−1J(θk−1) |
更新参数: θ k ← θ k − 1 + v k \theta_k \leftarrow\theta_{k-1} + v_k θk←θk−1+vk |
end while |
其中:
v k = α v k − 1 − ϵ k ( 1 − α ) ∇ θ k − 1 J ( θ k − 1 ) = α v k − 1 − ϵ k ∇ θ k − 1 J ( θ k − 1 ) v_k = \alpha v_{k-1}-\epsilon_k(1-\alpha)\nabla_{\theta_{k-1}} J(\theta_{k-1}) = \alpha v_{k-1}-\epsilon_k\nabla_{\theta_{k-1}} J(\theta_{k-1}) vk<