如何在Python中使用Keras的深度学习模型的学习率安排

147 阅读7分钟

训练一个神经网络或大型深度学习模型是一项困难的优化任务。

训练神经网络的经典算法被称为随机梯度下降。已经证实,通过使用在训练过程中改变的学习率,你可以在一些问题上实现更高的性能和更快的训练。

在这篇文章中,你将发现如何在Python中使用Keras深度学习库为你的神经网络模型使用不同的学习率计划。

读完这篇文章后,你会知道。

  • 如何配置和评估一个基于时间的学习率计划。
  • 如何配置和评估基于下降的学习率计划。

训练模型的学习率计划

为你的随机梯度下降优化程序调整学习率可以提高性能并减少训练时间。

有时这被称为学习率退火或自适应学习率。在这里,我们将这种方法称为学习率时间表,默认的时间表是使用一个恒定的学习率来更新每个训练纪元的网络权重。

在训练过程中,最简单的,也许是最常用的适应学习率的技术是随着时间的推移降低学习率。这些技术的好处是,在训练程序开始时使用较大的学习率值,并降低学习率,以便在训练程序后期对权重进行较小的学习率,从而进行较小的训练更新。

这样做的效果是在早期快速学习好的权重,并在后期对其进行微调。

两个流行的、易于使用的学习率计划如下。

  • 根据epoch逐渐降低学习率。
  • 在特定的历时中使用点状的大幅下降来降低学习率。

接下来,我们将看看你如何在Keras中依次使用这些学习率计划。

基于时间的学习率表

Keras内置了一个基于时间的学习率计划。

在SGD类中的随机梯度下降优化算法的实现有一个参数叫做衰减。这个参数在基于时间的学习率衰减表方程中使用,如下所示。

LearningRate = LearningRate * 1/(1 + decay * epoch)

当衰减参数为零时(默认),这对学习率没有影响。

LearningRate = 0.1 * 1/(1 + 0.0 * 1)
LearningRate = 0.1

当衰变参数被指定时,它将以给定的固定量减少前一个历时的学习率。

例如,如果我们使用初始学习率值0.1和衰减值0.001,前5个历时将适应如下的学习率。

Epoch	Learning Rate
1	0.1
2	0.0999000999
3	0.0997006985
4	0.09940249103
5	0.09900646517

将此扩展到100个历时,将产生以下的学习率(y轴)与历时(x轴)的关系图。

Time-Based Learning Rate Schedule

基于时间的学习率计划

你可以通过设置衰减值来创建一个漂亮的默认时间表,如下所示。

Decay = LearningRate / Epochs
Decay = 0.1 / 100
Decay = 0.001

下面的例子演示了在Keras中使用基于时间的学习率适应计划。

电离层数据集很适合用来练习神经网络,因为所有的输入值都是相同尺度的小数值。

一个小型的神经网络模型是由一个具有34个神经元的单一隐藏层构建的,并使用整流器激活函数。输出层有一个神经元,使用sigmoid激活函数,以输出类似概率的数值。

随机梯度下降的学习率被设定为较高的0.1值。该模型被训练了50个历时,衰减参数被设置为0.002,计算为0.1/50。此外,在使用自适应学习率时,使用动量可能是个好主意。在这种情况下,我们使用的动量值为0.8。

完整的例子列在下面。

# Time Based Learning Rate Decay
from pandas import read_csv
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.optimizers import SGD
from sklearn.preprocessing import LabelEncoder
# load dataset
dataframe = read_csv("ionosphere.csv", header=None)
dataset = dataframe.values
# split into input (X) and output (Y) variables
X = dataset[:,0:34].astype(float)
Y = dataset[:,34]
# encode class values as integers
encoder = LabelEncoder()
encoder.fit(Y)
Y = encoder.transform(Y)
# create model
model = Sequential()
model.add(Dense(34, input_shape=(34,), activation='relu'))
model.add(Dense(1, activation='sigmoid'))
# Compile model
epochs = 50
learning_rate = 0.1
decay_rate = learning_rate / epochs
momentum = 0.8
sgd = SGD(learning_rate=learning_rate, momentum=momentum, decay=decay_rate, nesterov=False)
model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=['accuracy'])
# Fit the model
model.fit(X, Y, validation_split=0.33, epochs=epochs, batch_size=28, verbose=2)

注意:鉴于算法或评估程序的随机性,或数字精度的差异,你的结果可能会有所不同。考虑把这个例子运行几次,比较一下平均结果。

该模型是在67%的数据集上训练的,并使用33%的验证数据集进行评估。

运行这个例子显示分类精度为99.14%。这比没有学习率衰减或动力的基线95.69%要高。

...
Epoch 45/50
0s - loss: 0.0622 - acc: 0.9830 - val_loss: 0.0929 - val_acc: 0.9914
Epoch 46/50
0s - loss: 0.0695 - acc: 0.9830 - val_loss: 0.0693 - val_acc: 0.9828
Epoch 47/50
0s - loss: 0.0669 - acc: 0.9872 - val_loss: 0.0616 - val_acc: 0.9828
Epoch 48/50
0s - loss: 0.0632 - acc: 0.9830 - val_loss: 0.0824 - val_acc: 0.9914
Epoch 49/50
0s - loss: 0.0590 - acc: 0.9830 - val_loss: 0.0772 - val_acc: 0.9828
Epoch 50/50
0s - loss: 0.0592 - acc: 0.9872 - val_loss: 0.0639 - val_acc: 0.9828

基于下降的学习率计划

另一个用于深度学习模型的流行的学习率计划是在训练期间的特定时间系统地降低学习率。

通常这种方法是通过每隔固定数量的epochs将学习率下降一半来实现的。例如,我们可能有一个0.1的初始学习率,然后每10个历时下降0.5。训练的前10个历时将使用0.1的值,在接下来的10个历时,将使用0.05的学习率,以此类推。

如果我们把这个例子的学习率绘制到100个历时中,你会得到下面的图表,显示学习率(Y轴)与历时(X轴)的关系。

Drop Based Learning Rate Schedule

基于下降的学习率计划

我们可以在拟合模型时,在Keras中使用LearningRateScheduler回调来实现这一点。

LearningRateScheduler回调允许我们定义一个函数来调用,该函数将历时数作为参数,并返回用于随机梯度下降的学习率。当使用时,随机梯度下降指定的学习率被忽略了。

在下面的代码中,我们使用了之前在Ionosphere数据集上的一个单隐层网络的例子。定义了一个新的step_decay()函数,实现了该公式。

LearningRate = InitialLearningRate * DropRate^floor(Epoch / EpochDrop)

其中InitialLearningRate是初始学习率,如0.1,DropRate是每次改变学习率的量,如0.5,Epoch是当前的epoch数,EpochDrop是改变学习率的频率,如10。

注意,我们把SGD类中的学习率设置为0,以明确表示不使用它。尽管如此,如果你想用这个学习率时间表使用动量,你可以在SGD中设置一个动量项。

# Drop-Based Learning Rate Decay
from pandas import read_csv
import math
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.optimizers import SGD
from sklearn.preprocessing import LabelEncoder
from tensorflow.keras.callbacks import LearningRateScheduler

# learning rate schedule
def step_decay(epoch):
	initial_lrate = 0.1
	drop = 0.5
	epochs_drop = 10.0
	lrate = initial_lrate * math.pow(drop, math.floor((1+epoch)/epochs_drop))
	return lrate

# load dataset
dataframe = read_csv("ionosphere.csv", header=None)
dataset = dataframe.values
# split into input (X) and output (Y) variables
X = dataset[:,0:34].astype(float)
Y = dataset[:,34]
# encode class values as integers
encoder = LabelEncoder()
encoder.fit(Y)
Y = encoder.transform(Y)
# create model
model = Sequential()
model.add(Dense(34, input_shape=(34,), activation='relu'))
model.add(Dense(1, activation='sigmoid'))
# Compile model
sgd = SGD(learning_rate=0.0, momentum=0.9)
model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=['accuracy'])
# learning schedule callback
lrate = LearningRateScheduler(step_decay)
callbacks_list = [lrate]
# Fit the model
model.fit(X, Y, validation_split=0.33, epochs=50, batch_size=28, callbacks=callbacks_list, verbose=2)

注意:鉴于算法或评估程序的随机性,或数字精度的差异,你的结果可能会有所不同。考虑多运行几次这个例子,比较一下平均结果。

运行这个例子的结果是,在验证数据集上的分类准确率为99.14%,同样比该问题上的模型基线有所提高。

...
Epoch 45/50
0s - loss: 0.0546 - acc: 0.9830 - val_loss: 0.0634 - val_acc: 0.9914
Epoch 46/50
0s - loss: 0.0544 - acc: 0.9872 - val_loss: 0.0638 - val_acc: 0.9914
Epoch 47/50
0s - loss: 0.0553 - acc: 0.9872 - val_loss: 0.0696 - val_acc: 0.9914
Epoch 48/50
0s - loss: 0.0537 - acc: 0.9872 - val_loss: 0.0675 - val_acc: 0.9914
Epoch 49/50
0s - loss: 0.0537 - acc: 0.9872 - val_loss: 0.0636 - val_acc: 0.9914
Epoch 50/50
0s - loss: 0.0534 - acc: 0.9872 - val_loss: 0.0679 - val_acc: 0.9914

使用学习率计划的技巧

本节列出了在使用神经网络的学习率计划时需要考虑的一些技巧和窍门。

  • 增加初始学习率:因为学习率很可能会下降,所以要从一个较大的值开始下降。较大的学习率将导致权重的较大变化,至少在开始时是这样的,从而使你能够从以后的微调中获益。
  • 使用一个大的动量:使用较大的动量值将有助于优化算法在你的学习率缩减到小值时继续向正确方向更新。
  • 用不同的时间表进行实验:使用哪种学习率时间表并不清楚,所以要尝试一些不同的配置选项,看看什么对你的问题最有效。也可以尝试以指数形式变化的时间表,甚至可以尝试对你的模型在训练或测试数据集上的准确性做出反应的时间表。

总结

在这篇文章中,你发现了用于训练神经网络模型的学习率计划。