SGD/Momentum/Nesterov

今天看pytorch的SGD发现了关于SGD的三种扩展,分别是SGD, Momentum, Nesterov
下面整理一下三个的原理和区别:

SGD

Stochastic Gradient Descent

param -= lr * gradient

Momentum

由于采用SGD时,使用mini-batch会使得计算的梯度有较大波动. Momentum的引入可以缓解这个问题,并且加速收敛过程。具体形式如下:

u = mu * u - lr * g
param += u

u = mu * u + g
param -= lr * u

其中每次用于更新参数的u都会有历史梯度的贡献, mu是动量。当前梯度g与历史梯度u方向相同时,起到累积梯度的作用;当前梯度g与历史梯度u方向相反时,会抵消不确定性。
更详细的理解参考 https://zhuanlan.zhihu.com/p/21486826
对于 z = x^2 + 50 * y^2 , 使用SGD的优化路线如下图(等高线图):
SGD/Momentum/Nesterov_第1张图片
当增加学习率时,优化路线在y方向具有更大的波动性
SGD/Momentum/Nesterov_第2张图片
而引入momentum之后,可以抵消y方向梯度的波动,并使x方向的梯度累积增加,提高收敛速度。
SGD/Momentum/Nesterov_第3张图片

Nestrerov Method

是Momentum的进一步变形,基本假设时,在历史梯度的前提下,提前看一步梯度,用该前瞻梯度来做Momentum优化。具体形式如下:

u = mu * u - lr * g(param + mu * u)
param += u

所以param_ahead = param + mu * u
我们假设将优化算法用于param_ahead,即保存的参数是根据历史梯度更新过的,
而我们保存的是param的历史梯度u
那么优化形式可以写成:

param_ahead += u_ahead
u_ahead = mu * u_ahead - lr * g(param_ahead)

由于我们存储的u对应param而不是param_head,所以从u->u_ahead需要多跳一步

u_ahead = mu * u - lr * g(param_ahead)

综合以上三式,可以得到:

param_ahead += mu * (mu * u - lr * g(param_ahead)) - lr * g(param_ahead)
= - mu * u + (1 + mu) * (mu * u - lr * g(pamra_ahead)
将其中param_ahead替换成param
同时使u_prev = u, u = mu * u - lr * g(param_ahead),得到
param = -mu * u_prev + (1 + mu) * u

经过有些博客分析,Nestrerov方法其实是在更新时加入了二阶导信息,因此更加准确和有效。
参见:
https://zhuanlan.zhihu.com/p/21486826
http://cs231n.github.io/neural-networks-3/
https://stats.stackexchange.com/questions/179915/whats-the-difference-between-momentum-based-gradient-descent-and-nesterovs-ac

你可能感兴趣的:(deep,leaning,basic)