https://blog.csdn.net/u010899985/article/details/81836299
https://www.jianshu.com/p/ee39eca29117
- 梯度下降算法(Gradient Descent Optimization)
根据计算目标函数J(θ)采用数据量的大小,梯度下降算法又可以分为批量梯度下降算法(Batch Gradient Descent),随机梯度下降算法(Stochastic GradientDescent)和小批量梯度下降算法(Mini-batch Gradient Descent)。
批量梯度下降算法:
针对的是整个数据集,通过对所有的样本的计算来求解梯度的方向。
优点:全局最优解;易于并行实现;
缺点:当样本数据很多时,计算量开销大,计算速度慢随机梯度下降算法:只通过一个随机选取的数据(xn,yn) 来获取“梯度”,以此对w进行更新。这种优化方法叫做随机梯度下降。其收敛速度会快一些,但是有可能出现目标函数值震荡现象,因为高频率的参数更新导致了高方差。
每个数据都计算算一下损失函数,然后求梯度更新参数。
优点:计算速度快
缺点:收敛性能不好小批量梯度下降算法(通常选用该方案),是折中方案,J(θ)选取训练集中一个小批量样本计算,这样可以保证训练过程更稳定,而且采用批量训练方法也可以利用矩阵计算的优势。这是目前最常用的梯度下降算法。
常见问题:
- 选择合适的learning rate比较困难,如果对所有的参数更新使用同样的learning rate。对于稀疏数据或者特征,有时我们可能想对不经常出现的特征更新快一些,对于常出现的特征更新慢一些,这时候SGD就不太能满足要求了。
- SGD容易收敛到局部最优,并且在某些情况下可能被困在鞍点,容易产生局部最优,而不能达到全局最优。
- Momentum(动量)
https://zhuanlan.zhihu.com/p/21475880
SGD更新方向完全依赖于当前的batch,因而其更新十分不稳定,每次迭代计算的梯度含有比较大的噪音。
- 滑板问题:
下图为函数,可知最小值位于(0,0)点,从(150,75)这个点开始下降。
# 梯度函数,返回x,y方向上的导数。
def g(x):
return np.array([2 * x[0], 100 * x[1]])
def momentum(x_start, step, g, discount = 0.7):
x = np.array(x_start, dtype='float64')
pre_grad = np.zeros_like(x)
for i in range(50):
grad = g(x)
pre_grad = pre_grad * discount + grad * step
# 部分(discount)保留之前的惯性pre_grad
x -= pre_grad
print '[ Epoch {0} ] grad = {1}, x = {2}'.format(i, grad, x)
if abs(sum(grad)) < 1e-6:
break;
return x
当使用了动量后,实际上沿-y和+y方向的两个力可以相互抵消,而-x方向的力则会一直加强,这样滑板少年会在y方向打转,但是y方向的力量会越来越小,但是他在-x方向的速度会比之前快不少。但还是在y轴方向浪费了不少时间,产生了强烈的震荡抖动。
- Nesterov Accelerated Gradient(2012年)
该优化器相对于Momentum,唯一不同的是计算反向梯度的时机。Momentum计算的是当前位置的反向梯度,Nesterov Momentum 计算的是按照上次更新方向走一小步后的反向梯度。
def g(x):
return np.array([2 * x[0], 100 * x[1]])
def momentum(x_start, step, g, discount = 0.7):
x = np.array(x_start, dtype='float64')
pre_grad = np.zeros_like(x)
for i in range(50):
grad = g(x+pre_grad*discount)
# 提前跨一步,但是是用于提取它的梯度
pre_grad = pre_grad * discount + grad * step
# 部分(discount)保留之前的惯性pre_grad
x -= pre_grad
print '[ Epoch {0} ] grad = {1}, x = {2}'.format(i, grad, x)
if abs(sum(grad)) < 1e-6:
break;
return x
因为momentum的值更小,所以可以减弱震荡,避免跨过头太多导致剧烈的震荡。
- AdaGrad算法(2011年)
增加了一个学习率递减系数。在训练迭代过程,初期步长大后期步长小。由于比较陡的方向梯度比较大,其学习速率将衰减得更快,这有利于参数沿着更接近坡底的方向移动,从而加速收敛。
注: 通常为,是为了防止分母的为 0,为步长(学习率)
注:如果第t次训练有m个样本,则取
- 特点:
(1)适合处理稀疏梯度。 - 缺点:
(1)由公式可以看出,仍依赖于人工设置一个全局学习率。
(2)分母上梯度平方的累加将会越来越大,会造成训练提前结束。
(3)深度学习中,深度过深时会造成训练提前结束。
- RMSProp算法
衰减系数累积了所有更新步骤中的梯度,我们可能更希望考察最近几步中的梯度来决定衰减系数。所以我们添加了一个衰减系数,使距离远的更新影响更弱,距离近的更新影响大。这就是RMSProp。
衰减系数ρ
步长ε
第t轮迭代的梯度g^t
- 自适应矩估计(adaptive moment estimation):
https://blog.csdn.net/qq_41747565/article/details/86100697
https://blog.csdn.net/fengchao03/article/details/78208414
- 偏置修正:因为初始化为0,为了能快点进入工作状态,给每个都除以校正初始化偏差。
t从0开始,m0,n0初始化为0,和是对和的无偏估计, gt指Θt在该处目标函数的梯度值,u一般取0.9, v一般取0.999, ε一般取。是步长。
各种算法的选择:
https://blog.csdn.net/weixin_40170902/article/details/80092628
- 对于稀疏数据,优先选择学习速率自适应的算法如RMSprop和Adam算法,而且最好采用默认值,大部分情况下其效果是较好的
SGD通常训练时间更长,容易陷入鞍点,但是在好的初始化和学习率调度方案的情况下,结果更可靠。 - 如果要求更快的收敛,并且较深较复杂的网络时,推荐使用学习率自适应的优化方法。例如对于RNN之类的网络结构,Adam速度快,效果好,而对于CNN之类的网络结构,SGD +momentum 的更新方法要更好(常见国际顶尖期刊常见优化方法).
- Adadelta,RMSprop,Adam是比较相近的算法,在相似的情况下表现差不多。
- 在想使用带动量的RMSprop,或者Adam的地方,大多可以使用Nadam取得更好的效果。
- 特别注意学习速率的问题。学习速率设置得非常大,那么训练可能不会收敛,就直接发散了;如果设置的比较小,虽然可以收敛,但是训练时间可能无法接受。理想的学习速率是:刚开始设置较大,有很快的收敛速度,然后慢慢衰减,保证稳定到达最优
- 其实还有很多方面会影响梯度下降算法,如梯度的消失与爆炸,梯度下降算法目前无法保证全局收敛还将是一个持续性的数学难题。
- RMSprop适合处理非平稳目标 - 对于RNN效果很好
Momentum还有NAG这种动量算法容易在梯度翻转的时候因为惯性作用偏离目标航线,但是一但找到了正确的行驶方向就能跑得 比自适应的快很多。自适应相对比较稳妥