python - 使用最佳学习率导致随机猜测的准确性

我正在学习 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 发送列表-取消订

css - 关键帧动画问题

python - 如何一次对每一行进行不同的 tensorflow 张量切片?

json - 使用 JSON Body on Rule 调用 REST API Business C

firebase - 如何在 flutter 中捕获 StorageException

authentication - 如何在 ReactJS 中实现登录亚马逊?