1. 优化器(Optimizer)用法
优化器是Keras模型Compile()方法所需的参数之一,其决定采用何种方法来训练模型。
优化器两种用法:
- 实例化优化器对象,然后传入model.compile()。实例化的优化器对象可以指定参数
from kears import optimizers
model = Sequential()
model.add(Dense(64, kernel_initializer='uniform', input_shape=(10,)))
model.add(Activation('softmax')) # 激活层单独设置激活函数
#实例化优化器
sgd = optimizers.SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='mean_squared_error', optimizer=sgd)
- 在model.compile()中通过名称调用优化器,此时优化器采用默认的参数
model.compile(loss='mean_squared_error', optimizer='sgd')
2. Keras 优化器的公共参数
用于控制梯度消失与梯度爆炸的梯度裁剪参数:
- clipnorm
- clipvalue
from keras import optimizers
# 所有参数梯度将被裁剪,让其 l2 范数最大为 1:g * 1 / max(1, l2_norm)
sgd = optimizers.SGD(lr=0.01, clipnorm=1.)
from keras import optimizers
# 所有参数 d 梯度将被裁剪到数值范围内:
# 最大值 0.5
# 最小值 -0.5
sgd = optimizers.SGD(lr=0.01, clipvalue=0.5)
3. Keras常见的优化器
Keras内置实现了如下几种常见的优化器:
- SGD 随机梯度下降优化器
- RMSprop优化器
- Adagrad优化器
- Adadelta优化器
- Adam优化器
- Adamax优化器
- Nadam优化器
下面一一介绍这几种优化器的原理、参数配置、以及适用情况
虽然Keras仅提供了随机梯度下降优化器,但是我们还是对梯度下降的三种变形都有所了解比较好。
3.1 Batch Gradient Descent (BGD)
更新规则:BGD 采用整个训练集的数据来计算 cost function 对参数的梯度:
代码示例
for i in range(nb_epochs):
params_grad = evaluate_gradient(loss_function, data, params)
params = params - learning_rate * params_grad
我们会事先定义一个迭代次数 epoch,首先计算梯度向量 params_grad,然后沿着梯度的方向更新参数 params,learning rate 决定了我们每一步迈多大。
优点
Batch gradient descent 对于凸函数可以收敛到全局极小值,对于非凸函数可以收敛到局部极小值。
缺点
由于这种方法是在一次更新中,就对整个数据集计算梯度,所以计算起来非常慢,遇到很大量的数据集也会非常棘手,而且不能投入新数据实时更新模型。
超参数
该算法涉及到的超参数是学习速率
3.2 Mini-Batch Gradient Descent(MBGD)
更新规则
MBGD 每一次利用一小批样本,即 n 个样本进行计算,这样它可以降低参数更新时的方差,收敛更稳定,另一方面可以充分地利用深度学习库中高度优化的矩阵操作来进行更有效的梯度计算。
代码示例
for i in range(nb_epochs):
np.random.shuffle(data)
for batch in get_batches(data, batch_size=50):
params_grad = evaluate_gradient(loss_function, batch, params)
params = params - learning_rate * params_grad
优点
可以降低参数更新时的方差,收敛更稳定,另一方面可以充分地利用深度学习库中高度优化的矩阵操作来进行更有效的梯度计算。即训练速度相对于BGD快,训练稳定性相对于SGD高
缺点
Mini-batch gradient descent 不能保证很好的收敛性,learning rate 如果选择的太小,收敛速度会很慢,如果太大,loss function 就会在极小值处不停地震荡甚至偏离。(有一种措施是先设定大一点的学习率,当两次迭代之间的变化低于某个阈值后,就减小 learning rate,不过这个阈值的设定需要提前写好,这样的话就不能够适应数据集的特点。)
超参数
该方法涉及到的超参数包括学习速率和mini-batch大小,一般mini-batch的大小设置为2的n次幂,32-256之间
3.3 Stochastic Gradient Descent (SGD)
更新规则
和 BGD 的一次用所有数据计算梯度相比,SGD 每次更新时对每个样本进行梯度更新
代码示例
for i in range(nb_epochs):
np.random.shuffle(data)
for example in data:
params_grad = evaluate_gradient(loss_function, example, params)
params = params - learning_rate * params_grad
优点
收敛速度快
缺点
SGD 因为更新比较频繁,会造成 cost function 有严重的震荡。
BGD 可以收敛到局部极小值,当然 SGD 的震荡可能会跳到更好的局部极小值处。
当我们稍微减小 learning rate,SGD 和 BGD 的收敛性是一样的。
超参数
学习速率
Keras中的SGD使用
keras.optimizers.SGD(learning_rate=0.01, momentum=0.0, nesterov=False)
- Learning_rate:float>=0, 学习速率
- momentum: float >= 0. 参数,用于加速 SGD 在相关方向上前进,并抑制震荡。
- nesterov: boolean. 是否使用 Nesterov 动量。
Momentum 动量
SGD方法的一个缺点是,其更新方向完全依赖于当前的batch,因而其更新十分不稳定。解决这一问题的一个简单的做法便是引入momentum。
momentum即动量,它模拟的是物体运动时的惯性,即更新的时候在一定程度上保留之前更新的方向,同时利用当前batch的梯度微调最终的更新方向。这样一来,可以在一定程度上增加稳定性,从而学习地更快,并且还有一定摆脱局部最优的能力:
其更新规则为:
Nesterov Momentum
用 θ−γv_t−1 来近似当做参数下一步会变成的值,则在计算梯度时,不是在当前位置,而是未来的位置上
3.4 Adagrad (Adaptive gradient algorithm)
上面提到的方法对于所有参数都使用了同一个更新速率。但是同一个更新速率不一定适合所有参数。比如有的参数可能已经到了仅需要微调的阶段,但又有些参数由于对应样本少等原因,还需要较大幅度的调动。
Adagrad就是针对这一问题提出的,自适应地为各个参数分配不同学习率的算法。参数接收的更新越多(对应的梯度越大),更新越小(对应的学习速率越小)。
更新规则
优点
减少学习速率的手动调节
缺点
分母会不断累加,这样学习速率就会收缩并最终变得非常小,其需要手工设置一个全局的初始学习率
keras中Adagrad的使用
keras.optimizers.Adagrad(learning_rate=0.01)
3.5 Adadelta
这个算法是对 Adagrad 的改进,和 Adagrad 相比,就是分母的 G 换成了过去的梯度平方的衰减平均值,指数衰减平均值
优点
- 无需设置初始学习速率
- 解决了Adagrad的学习速率衰减问题
缺点
虽然Adagrad和Adadelta不需要调参,稳定性较好,但是精调的sgd和momentum系列方法无论是收敛速度还是precision都比adagrad要好一些
keras中Adadelta的使用
Adadelta 是 Adagrad 的一个具有更强鲁棒性的的扩展版本,它不是累积所有过去的梯度,而是根据渐变更新的移动窗口调整学习速率。 这样,即使进行了许多更新,Adadelta 仍在继续学习。 与 Adagrad 相比,在 Adadelta 的原始版本中,您无需设置初始学习率。 在此版本中,与大多数其他 Keras 优化器一样,可以设置初始学习速率和衰减因子。
keras.optimizers.Adadelta(learning_rate=1, rho=0.95)
- learning_rate: float >= 0. 初始学习率,默认为 1。建议保留默认值。
- rho: float >= 0. Adadelta 梯度平方移动均值的衰减率。
3.6 RMSprop
RMSProp优化算法是AdaGrad算法的一种改进。RMSProp算法不是像AdaGrad算法那样暴力直接的累加平方梯度,而是加了一个衰减系数来控制历史信息的获取多少。鉴于神经网络都是非凸条件下的,RMSProp在非凸条件下结果更好,改变梯度累积为指数衰减的移动平均以丢弃遥远的过去历史。
直观理解作用
简单来讲,设置全局学习率之后,每次通过,全局学习率逐参数的除以经过衰减系数控制的历史梯度平方和的平方根,使得每个参数的学习率不同
那么它起到的作用是什么呢?
起到的效果是在参数空间更为平缓的方向,会取得更大的进步(因为平缓,所以历史梯度平方和较小,对应学习下降的幅度较小),并且能够使得陡峭的方向变得平缓,从而加快训练速度。
Keras中RMSprop的使用
keras.optimizers.RMSprop(learning_rate=0.001, rho=0.9)
这个优化器通常是训练循环神经网络 RNN 的不错选择。
- learning_rate: float >= 0. 学习率。
- rho: float >= 0. RMSProp 梯度平方的移动均值的衰减率。
3.7 Adam: Adaptive Moment Estimation
这个算法是另一种计算每个参数的自适应学习率的方法。相当于 RMSprop + Momentum
除了像 Adadelta 和 RMSprop 一样存储了过去梯度的平方 vt 的指数衰减平均值 ,也像 momentum 一样保持了过去梯度 mt 的指数衰减平均值:
如果 mt 和 vt 被初始化为 0 向量,那它们就会向 0 偏置,所以做了偏差校正,通过计算偏差校正后的 mt 和 vt 来抵消这些偏差:
实践表明,Adam 比其他适应性学习方法效果要好。
keras中Adam的使用
keras.optimizers.Adam(learning_rate=0.001, beta_1=0.9, beta_2=0.999, amsgrad=False)
- learning_rate: float >= 0. 学习率
- beta_1: float, 0 < beta < 1. 通常接近于 1。
- beta_2: float, 0 < beta < 1. 通常接近于 1。
- amsgrad: boolean. 是否应用此算法的 AMSGrad 变种,来自论文 “On the Convergence of Adam and Beyond”。
4. 如何选择优化器
如果数据是稀疏的,就用自适用方法,即 Adagrad, Adadelta, RMSprop, Adam。
RMSprop, Adadelta, Adam 在很多情况下的效果是相似的。
Adam 就是在 RMSprop 的基础上加了 bias-correction 和 momentum,
随着梯度变的稀疏,Adam 比 RMSprop 效果会好。
整体来讲,Adam 是最好的选择。
很多论文里都会用 SGD,没有 momentum 等。SGD 虽然能达到极小值,但是比其它算法用的时间长,而且可能会被困在鞍点。
如果需要更快的收敛,或者是训练更深更复杂的神经网络,需要用一种自适应的算法。