Keras深度学习——学习率对神经网络性能的影响

954 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情

学习率对网络性能的影响

原始神经网络以及之后的一些改进中,我们一直使用 Adam 优化器,默认学习率为 0.0001。在本节中,手动将学习率设置为更高的数值,并查看更改学习率对模型准确率的影响,使用与先前示例相同的 MNIST 数据集。

《神经网络基础》中,我们也同时了解了学习率可以用于更新权重,权重的变化与减少的损失成正比。且权重值的变化等于损失的减少量乘以学习率。因此,学习率越低,权重值的变化越小,反之亦然。

本质上,可以将权重值视为一个连续的空间状态,其中权重是随机初始化的。当权重值的变化很大时,并不能充分的搜索到空间中的大量权重值。但是,当权重值的变化很小时,权重可能会达到全局最小值,因为可以考虑更多可能的权重值:

权重更新

基础示例

为了进一步理解这一点,我们拟合简单函数 y=2xy = 2x,其中初始权重值为 1.477,初始偏置值为 0。前向和后向传播过程与《神经网络基础》中的相同:

def feed_forward(inputs, outputs, weights):
    hidden = np.dot(inputs, weights[0])
    out = hidden + weights[1]
    squared_error = (np.square(out - outputs))
    return squared_error

def update_weights(inputs, outputs, weights, epochs, lr):
    for epoch in range(epochs):
        org_loss = feed_forward(inputs, outputs, weights)
        wts_tmp = deepcopy(weights)
        wts_tmp2 = deepcopy(weights)
        for ix, wt in enumerate(weights):
            # print(ix, wt)
            wts_tmp[ix] += 0.0001
            loss = feed_forward(inputs, outputs, wts_tmp)
            del_loss = np.sum(org_loss - loss) / (0.0001 * len(inputs))
            wts_tmp2[ix] += del_loss * lr
            wts_tmp = deepcopy(weights)
        weights = deepcopy(wts_tmp2)
    return wts_tmp2

与在《神经网络基础》中的反向传播函数相比,唯一的变化是我们将学习率( learning rate, lr )作为参数传递给它,统计在不同 epoch 内学习率为 0.01 时的权重值的变化:

x = np.array([[1], [2], [3], [4]])
y = np.array([[2], [4], [6], [8]])
w = np.array([[[1.477]], [[0]]])
w_val = []
b_val = []
for k in range(1000):
    w_new, b_new = update_weights(x, y, w, (k+1), 0.5)
    w_val.append(w_new[0])
    b_val.append(b_new[0])

可以使用以下代码绘制不同 epoch 的权重变化情况:

plt.plot(w_val)
plt.title('Weight value over different epochs when learning rate is 0.01')
plt.xlabel('epochs')
plt.ylabel('weight value')
plt.show()

绘制结果输出如下:

学习率为0.01时权重变化

以类似的方式,绘制当学习率为 0.1 时,在不同 epoch 上的权重值如下:

学习率为0.1时权重变化

下图显示了学习率为 0.5 时不同 epoch 的权重值:

学习率为0.5时权重变化

观察以上情况,可以看到权重值最初都发生了巨大变化,并且学习率为 0.1 时模型仍可以收敛,而学习率为 0.5 时没有收敛到最优解,其陷入了局部最小值,因此无法达到最佳值 2

MNIST 数据集上不同学习率对性能的影响

我们已经了解了学习率对模型的影响,接下来我们来看一下学习率对 MNIST 数据集上训练的模型影响,在该模型中,我们使用与之前相同的模型架构,仅更改学习率参数。

  1. 通过指定优化器来改变模型的学习率:
from keras import optimizers
# 以学习速率 `0.01` 初始化 `Adam` 优化器
adam = optimizers.Adam(lr=0.01)
  1. 按照以下方式构建,编译和拟合模型:
model = Sequential()
model.add(Dense(1000, input_dim=num_pixels, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer=adam, metrics=['acc'])

history = model.fit(x_train, y_train,
                    validation_data=(x_test, y_test),
                    epochs=50,
                    batch_size=64,
                    verbose=1)

在 50 个 epoch 结束时,网络的准确性约为 91%,观察损失值和准确率在不同 epoch 之间如何变化:

损失值和准确率的变化情况

当学习率较高时,损失的下降较不平稳,低学习率模型会缓慢更新权重,从而导致平滑的减少损失值并获得较高的准确率。或者也可以说,当学习率较高时,损失值的跳跃变化是由于损失值陷入局部最小值导致的。较低的学习率可以更好地达到最佳权重值,因为权重在正确的方向上缓慢但稳定地变化。

我们可以以类似的方式探索学习率高达 0.1 时的网络准确率:

from keras import optimizers
adam=optimizers.Adam(lr=0.1)

model = Sequential()
model.add(Dense(1000, input_dim=784, activation='relu'))
model.add(Dense(10,  activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer=adam, metrics=['accuracy'])
history = model.fit(x_train, y_train,
                    validation_data=(x_test, y_test),
                    epochs=50,
                    batch_size=64,
                    verbose=1)

由于学习率高,损失值无法进一步降低,权重可能停留在局部最小值中:

损失值和准确率的变化情况

因此,一般而言,将学习速率设置为较低的值并让网络在大量时间内进行训练是一种常用策略。

相关链接

Keras深度学习——训练原始神经网络