我正在学习 Aurélien Géron 的 Hands-on Machine Learning with Scikit-Learn, Keras, and TensorFlow 并且我试图弄清楚我在解决练习时做错了什么.这是第 11 章的练习 8。我要做的是在 CIFAR10 数据集上训练一个具有 20 个隐藏层、每个 100 个神经元、激活函数 ELU 和权重初始化器 He Normal 的神经网络(我知道 100 个神经元的 20 个隐藏层是很多,但这就是练习的重点,所以请耐心等待)。我必须使用 Early Stopping 和 Nadam 优化器。
我遇到的问题是我不知道使用什么学习率。在解决方案笔记本中,作者列出了一堆他尝试过的学习率,并使用了他找到的最好的一个。我对此并不满意,我决定自己尝试找到最佳学习率。所以我使用了书中推荐的一种技术:训练网络一个时期,在每次迭代中以指数方式提高学习率。然后将损失绘制为学习率的函数,查看损失达到最小值的位置,然后选择稍微小一点的学习率(因为这是上限)。
这是我模型中的代码:
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节课。我用了early stopping,所以我不能说我让模型训练了太多的epochs(我用了100个)。但即使在训练期间,模型也没有学到任何东西,训练集和验证集的准确率始终在 10% 左右。
当我使用更小的学习率(作者在解决方案笔记本中使用的那个)时,整个问题就消失了。当我使用 5e-5
的学习率时,模型正在学习并在验证集上达到大约 50% 的准确度(这是练习所期望的,这与作者获得的准确度相同)。但是怎么用plot指示的学习率就这么差呢?我在网上看了一点,这种学习率呈指数级增长的方法好像很多人都在用,所以我真的不明白我做错了什么。
最佳答案
您正在对未知探索空间使用启发式搜索方法。如果没有关于模型/数据特征的更多信息,很难说出了什么问题。
我首先担心的是损失突然上升到有效无穷大;你在 yoru 探索空间中有一个边缘不平滑,这表明更大的空间(包括许多训练时期)有一个高度干扰的边界。任何接近 epoch-=1 边界的学习率都有可能在后面的 epoch 中跌跌撞撞地跨过悬崖,留下随机分类。
您使用的启发式方法基于几个假设。
启发式训练仅在一个时期;在不同的学习率下收敛模型需要多少个 epoch?如果学习率太大,模型可能会非常缓慢地完成最后的收敛,因为它围绕着最佳点。也有可能您从未以过大的速率接近该点。
如果不针对那个 epoch-1 测试映射收敛空间,我们就无法正确分析问题。但是,您可以尝试相关实验:从 10^-4 开始,全面训练您的模型(检测收敛并停止)。重复,每次将 LR 乘以 3。当您在 .0081 附近进入非收敛状态时,您会感觉到您不再收敛的位置。
现在按照您认为合适的方式分割该范围 [.0027, .0081]。一旦找到确实收敛的上端点,您就可以使用它来指导最终搜索最佳学习率。
https://stackoverflow.com/questions/63728790/
相关文章:
tensorflow - 如何将 tf.data.Dataset 与 kedro 一起使用?
android - 如何处理 In-App Billing Library 中的多个用户? (最佳实
node.js - 在 node.js 中将字符串转换为 64 位 float
ios - iPhone 上的 Safari 是否支持为 <input type =“file
python-3.x - SendGrid 无法向 Yahoo 和 Outlook 发送列表-取消订
python - 如何一次对每一行进行不同的 tensorflow 张量切片?
json - 使用 JSON Body on Rule 调用 REST API Business C