keras optimizers的源码实现
基类Optimizer包含两个公共参数,用于控制梯度裁剪
- clipnorm: float >= 0. Gradients will be clipped when their L2 norm exceeds this value.
- clipvalue: float >= 0. Gradients will be clipped when their absolute value exceeds this value.
1. 梯度下降
梯度下降是一种优化算法,通过迭代的方式寻找的模型的最优参数;
- 当目标函数是凸函数时,梯度下降的解是全局最优解,但在一般情况下,梯度下降无法保证全局最优。
梯度是函数增长最快的方向,因此神经网络中使用负梯度来表示函数下降最快的方向
- 梯度实际是损失函数对网络中每个参数的偏导组成的向量
- 梯度仅仅指示了每个参数各自增长最快的方向,因此,梯度无法保证全局方向就是函数为了达到最小值应该前进的方向
负梯度中的每一项可认为传递了两个信息
- 正负号告诉输入向量应该调大还是调小(正调大,负调小)
- 每一项的相对大小表面每个参数对函数值达到最值的影响程度
1.1 三种梯度下降方法
批梯度下降
- 使用所有训练样本的平均损失来更新参数
- 当训练样本的数量很大时,需要消耗大量计算资源
随机梯度下降
- 每次使用单个样本的损失来近似平均损失
小批量梯度下降
- 为了降低随机梯度的方差,使模型迭代更加稳定,使用一批随机数据来近似平均损失
- 可以利用高度优化的矩阵运算以及并行计算框架
批大小的影响
- 较大的批能够得到精确的梯度估计,但回报是小于线性的
- 较小的批能带来更好的泛化误差,泛化误差通常在批大小为 1 时最好。
- 原因可能是由于小批量在学习过程中带来了噪声,使产生了一些正则化效果 (Wilson and Martinez, 2003)
- 但是,因为梯度估计的高方差,小批量训练需要较小的学习率以保持稳定性,这意味着更长的训练时间。
- 当批的大小为 2 的幂时能充分利用矩阵运算操作,所以批的大小一般取 32、64、128、256 等。
1.2 SGD存在的问题
- SGD放弃了梯度的准确性,仅采用一部分样本来估计当前的梯度;因此 SGD 对梯度的估计常常出现偏差,造成目标函数收敛不稳定,甚至不收敛的情况。
- 无论是GD还是SGD, 都可能陷入局部极值点;除此之外,SGD 还可能遇到“峡谷”和“鞍点”两种情况
以上内容参考至:C-专题-优化算法
2. 基本算法
基本算法包括SGD, momentum, Nesterove momentum三种,keras中的SGD类包含了普通SGD, momentum, nesterove momentum三种实现1
keras.optimizers.SGD(lr=0.01,momentum=0.0,decay=0.0,nesterov=False)
2.1 SGD
现在的SGD用法一般指,按照数据生成分布抽取m 个小批 量(独立同分布的)样本,通过计算它们梯度均值,我们可以得到梯度的无偏估计,然后对参数进行更新。
SGD中的关键参数是学习率。在实践中有必要随着时间的推移逐渐降低学习率,这是因为这是因为SGD中梯度估计引入的噪声源(m 个训练样本的随机采样)并不会
在极小点处消失。相比之下,当我们使用批量梯度下降到达极小点时,整个代价函
数的真实梯度会变得很小,之后为0,因此批量梯度下降可以使用固定的学习。
实践中,可以通过线性衰减学习率直到第T次迭代:
其中 α = k/T, 在T步迭代之后一般使ϵ 保持常数。
2.2 动量
动量方法旨在加速学习。动量算法积累了之前梯度指数级衰减的移动平均,并继续沿该方向移动。其效果如图所示。
动量的主要目的是解决两个问题:
- Hessian矩阵的病态条件
- 随机梯度的方差
如图所示,红色为SGD+Momentum。黑色为SGD。可以看到黑色为典型Hessian矩阵病态的情况,相当于大幅度的徘徊着向最低点前进。
而由于动量积攒了历史的梯度,如点P前一刻的梯度与当前的梯度方向几乎相反。因此原本在P点原本要大幅徘徊的梯度,主要受到前一时刻的影响,而导致在当前时刻的梯度幅度减小。
直观上讲就是,要是当前时刻的梯度与历史时刻梯度方向相似,这种趋势在当前时刻则会加强;要是不同,则当前时刻的梯度方向减弱。
从形式上看,,动量算法引入了变量v 充当速度角色——它代表参数在参数空间移动的方向和速率,速度被设置为负梯度的指数衰减平均。超参数α决定了之前梯度的贡献衰减得有多快。
之前,步长只是梯度范数乘以学习率。现在,步长取决于梯度序列的大小和排
列。当许多连续的梯度指向相同的方向时,步长最大。如果动量算法总是观测到梯
度g,那么它会在方向-g 上不停加速,直到达到最终速度,其中步长大小为:
因此将动量的超参数视为1/(1-α)有助于理解。例如,α = 0.9 对应着最大速度10倍
于梯度下降算法。
在实践中,α的一般取值为0.5,0.9 和0.99。和学习率一样,α也会随着时间
不断调整。一般初始值是一个较小的值,随后会慢慢变大。随着时间推移调整α没
有收缩ϵ重要。
2.3 Nesterov动量
Nesterov动量与标准动量的区别体现在梯度计算的方法上:
- Nesterov 动量中,Nesterov先用当前的速度v更新一遍参数,再用更新的临时参数计算梯度
- Nesterov 动量可以解释为往标准动量方法中添加了一个校正因子
在凸批量情况下,Nesterov将误差收敛从O(1/k),改进到O(1/k^2), 然而在SGD下,Nesterov并没有任何改进。
3. 自适应学习率算法
3.1 AdaGrad
AdaGrad算法, 独立地适应所有模型参数的学习率
- 缩放每个参数反比于其所有梯度历史平方值总和的平方根
- 具有损失最大偏导的参数相应地有一个快速下降的学习率,而具有小偏导的参数在学习率上
有相对较小的下降 - 效果是在参数空间中更为平缓的倾斜方向会取得更大的进步
缺点:
- 从训练开始时积累梯度平方会导致有效学习率过早和过量的减小。
3.2 RMSProp
AdaGrad 旨在应用于凸问题时快速收敛,RMSProp算法修改AdaGrad以在非凸设定下效果更好,改变梯度积累为指数加权的移动平均。
相比于AdaGrad,RMSProp使用指数衰减平均以丢弃遥远过去的历史,引入了一个新的超参数ρ,用来控制移动平均的长度范围
结合Nesterov动量的RMSProp:RMSProp改变了学习率,Nesterov引入动量改变了梯度,从两方面改进更新方式。
3.3 Adam
adaptive moments
- Adam算法可以看做是修正后的Momentum+RMSProp算法
- 动量直接并入梯度一阶矩估计中(指数加权)
- Adam通常被认为对超参数的选择相当鲁棒
- 学习率建议为0.001
参考:花书Deep learning