【发布时间】:2020-09-03 17:26:40
【问题描述】:
我正在通过 Aurélien Géron 的 使用 Scikit-Learn、Keras 和 TensorFlow 进行机器学习实践,我正在尝试在解决练习时弄清我做错了什么.这是第 11 章中的练习 8。我要做的是在 CIFAR10 数据集上训练一个有 20 个隐藏层,每个 100 个神经元的神经网络,使用激活函数 ELU 和权重初始化器 He Normal(我知道 100 个神经元的 20 个隐藏层是很多,但这就是练习的重点,所以请耐心等待)。我必须使用 Early Stopping 和 Nadam 优化器。
我的问题是我不知道要使用什么学习率。在解决方案笔记本中,作者列出了一堆他尝试并使用了他找到的最好的学习率。我对此并不满意,我决定自己尝试找到最佳学习率。所以我使用了书中推荐的一种技术:将网络训练一个 epoch,在每次迭代中成倍增加学习率。然后将损失绘制为学习率的函数,查看损失达到最小值的位置,然后选择稍小的学习率(因为这是上限)。
这是我模型中的代码:
model = keras.models.Sequential()
model.add(keras.layers.Flatten(input_shape=[32, 32, 3]))
for _ in range(20):
model.add(keras.layers.Dense(100,
activation="elu",
kernel_initializer="he_normal"))
model.add(keras.layers.Dense(10, activation="softmax"))
optimizer = keras.optimizers.Nadam(lr=1e-5)
model.compile(loss="sparse_categorical_crossentropy",
optimizer=optimizer,
metrics=["accuracy"])
(忽略学习率的值,这没关系,因为我正在尝试找到正确的。)
这里是用于找到最佳学习率的代码:
class ExponentialLearningRate(keras.callbacks.Callback):
def __init__(self, factor):
self.factor = factor
self.rates = []
self.losses = []
def on_batch_end(self, batch, logs):
self.rates.append(keras.backend.get_value(self.model.optimizer.lr))
self.losses.append(logs["loss"])
keras.backend.set_value(self.model.optimizer.lr, self.model.optimizer.lr * self.factor)
def find_learning_rate(model, X, y, epochs=1, batch_size=32, min_rate=10**-5, max_rate=10):
init_weights = model.get_weights()
init_lr = keras.backend.get_value(model.optimizer.lr)
iterations = len(X) // batch_size * epochs
factor = np.exp(np.log(max_rate / min_rate) / iterations)
keras.backend.set_value(model.optimizer.lr, min_rate)
exp_lr = ExponentialLearningRate(factor)
history = model.fit(X, y, epochs = epochs, batch_size = batch_size, callbacks = [exp_lr])
keras.backend.set_value(model.optimizer.lr, init_lr)
model.set_weights(init_weights)
return exp_lr.rates, exp_lr.losses
def plot_lr_vs_losses(rates, losses):
plt.figure(figsize=(10, 5))
plt.plot(rates, losses)
plt.gca().set_xscale("log")
plt.hlines(min(losses), min(rates), max(rates))
plt.axis([min(rates), max(rates), min(losses), losses[0] + min(losses) / 2])
plt.xlabel("Learning rate")
plt.ylabel("Loss")
find_learning_rate() 函数在每次迭代中以指数方式提高学习率,从最小学习率 10^(-5) 到最大学习率 10。之后,我使用 function plot_lr_vs_losses() 绘制了曲线这就是我得到的:
看起来使用 1e-2 的学习率会很棒,对吧?但是当我重新编译模型时,以1e-2 的学习率,模型在训练集和验证集上的准确率都在 10% 左右,这就像随机选择一样,因为我们有 10 个类。我使用了提前停止,所以我不能说我让模型训练了太多 epoch(我用了 100 个)。但即使在训练期间,模型也没有学到任何东西,训练集和验证集的准确率始终在 10% 左右。
当我使用更小的学习率(作者在解决方案笔记本中使用的那个)时,整个问题就消失了。当我使用5e-5 的学习率时,模型正在学习并在验证集上达到大约 50% 的准确度(这是练习所期望的,与作者得到的准确度相同)。但是,使用图中指示的学习率怎么会这么糟糕呢?我在网上看了一点,这种成倍增加学习率的方法似乎被很多人使用,所以我真的不明白我做错了什么。
【问题讨论】:
标签: python machine-learning keras deep-learning neural-network