畅游人工智能之海--Keras教程之优化器(二)

畅游人工智能之海--Keras教程之优化器(二)

各位读者朋友大家好,昨天我们已经了解了什么是优化器以及优化器的作用,今天我们就来看看其中的SGD和RMSprop优化器。

SGD类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
tf.keras.optimizers.SGD(
learning_rate=0.01, #学习率。默认为0.01
momentum=0.0, #float >= 0. 参数,用于加速 SGD 在相关方向上前进,并抑制震荡。默认为0
nesterov=False, #boolean. 是否使用 Nesterov 动量
name="SGD", #应用梯度时创建的操作的可选名称前缀。默认为“SGD”
**kwargs #关键字参数。允许是“clipnorm”或“clipvalue”之一clipnorm“(float)按范数剪裁梯度;“clipvalue”(float)按值剪裁梯度
)
'''
当momentum等于0时参数w根据梯度g的更新规则如下:
w = w - learning_rate * g

当momentum大于0时的更新规则为:
velocity = momentum * velocity - learning_rate * g
w = w * velocity

当nesterov为False时更新规则如下:
velocity = momentum * velocity - learning_rate * g
w = w + momentum * velocity - learning_rate * g
'''

随机梯度下降(Stochastic gradient descent)算法每次从训练集中随机选择一个样本来进行学习,公式如下。

1192699-20180310214057443-2087742064

批量梯度下降算法(BGD)每次都会使用全部训练样本,因此这些计算是冗余的,因为每次都使用完全相同的样本集。而随机梯度下降算法每次只随机选择一个样本来更新模型参数,因此每次的学习是非常快速的,并且可以进行在线更新。

随机梯度下降代码如下

1
2
3
4
5
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

随机梯度下降最大的缺点在于每次更新可能并不会按照正确的方向进行,因此可以带来优化波动(扰动),如下图:

1192699-20180310214248005-2068714250

随机梯度下降是通过每个样本来迭代更新一次,如果样本量很大的情况,那么可能只用其中部分的样本,就已经将theta迭代到最优解了。缺点是SGD的噪音较BGD要多,使得SGD并不是每次迭代都向着整体最优化方向所以虽然训练速度快,但是准确度下降,并不是全局最优虽然包含一定的随机性,但是从期望上来看,它是等于正确的导数的。

不过从另一个方面来看,随机梯度下降所带来的波动有个好处就是,对于类似盆地区域(即很多局部极小值点)那么这个波动的特点可能会使得优化的方向从当前的局部极小值点跳到另一个更好的局部极小值点,这样便可能对于非凸函数,最终收敛于一个较好的局部极值点,甚至全局极值点。

例子:

1
2
3
4
5
6
7
>>> opt = tf.keras.optimizers.SGD(learning_rate=0.1)
>>> var = tf.Variable(1.0)
>>> loss = lambda: (var ** 2)/2.0 # d(loss)/d(var1) = var1
>>> step_count = opt.minimize(loss, [var]).numpy()
>>> # Step is `- learning_rate * grad`
>>> var.numpy()
0.9

RMSprop类

1
2
3
4
5
6
7
8
9
tf.keras.optimizers.RMSprop(
learning_rate=0.001, #学习率。默认为0.01
rho=0.9, #历史或未来梯度的dicounting因子,默认为0.9
momentum=0.0, #标量或标量张量。默认为0
epsilon=1e-07, #数值稳定性的一个小常数。默认为1e-7
centered=False, #布尔值。如果为真,则通过梯度的估计方差对梯度进行规范化;如果为假,则通过未居中的第二时刻对梯度进行规范化。设置为True可能有助于训练,但在计算和内存方面代价更大一些。默认为False
name="RMSprop", #应用梯度时创建的操作的可选名称前缀。默认为“RMSprop”
**kwargs #关键字参数。允许是“clipnorm”或“clipvalue”之一clipnorm“(float)按范数剪裁梯度;“clipvalue”(float)按值剪裁梯度
)

建议使用优化器的默认参数 (除了学习率 lr,它可以被自由调节)

这个优化器通常是训练循环神经网络RNN的不错选择。

RMSProp算法的全称叫 Root Mean Square Prop,是Geoffrey E. Hinton在Coursera课程中提出的一种优化算法。所谓的摆动幅度就是在优化中经过更新之后参数的变化范围,如下图所示,绿色的为RMSProp优化算法所走的路线。

20170923134334368

为了进一步优化损失函数在更新中存在摆动幅度过大的问题,并且进一步加快函数的收敛速度,RMSProp算法对权重 W 和偏置 bb的梯度使用了微分平方加权平均数。 其中,假设在第 t 轮迭代过程中,各个公式如下所示:

捕获

算法的主要思想就用上面的公式表达完毕了。在上面的公式中sdw和sdb分别是损失函数在前t−1轮迭代过程中累积的梯度梯度动量,ββ 是梯度累积的一个指数。所不同的是,RMSProp算法对梯度计算了微分平方加权平均数。这种做法有利于消除了摆动幅度大的方向,用来修正摆动幅度,使得各个维度的摆动幅度都较小。另一方面也使得网络函数收敛更快。(比如当 dW或者 db中有一个值比较大的时候,那么我们在更新权重或者偏置的时候除以它之前累积的梯度的平方根,这样就可以使得更新幅度变小)。为了防止分母为零,使用了一个很小的数值 ϵ来进行平滑,一般取值为10−8。

例子:

1
2
3
4
5
6
>>> opt = tf.keras.optimizers.RMSprop(learning_rate=0.1)
>>> var1 = tf.Variable(10.0)
>>> loss = lambda: (var1 ** 2) / 2.0 # d(loss) / d(var1) = var1
>>> step_count = opt.minimize(loss, [var1]).numpy()
>>> var1.numpy()
9.683772

今天我们学习了优化器中的SGD和RMSprop类,优化器对于神经网络来说非常重要,不同的优化方式有不同的效果,应该针对样本进行选择,以实现更好的优化效果,下周我们将继续介绍剩下的优化器,希望大家在学习之余也多多查阅相关资料,更加牢固地掌握这一知识。谢谢大家的阅读。