【问题标题】:How to change a learning rate for Adam in TF2?如何在 TF2 中更改 Adam 的学习率?
【发布时间】:2019-12-09 14:51:08
【问题描述】:

如何在 TF2 进行学习的同时改变 Adam 优化器的学习率? 有一些答案浮动,但适用于 TF1,例如使用 feed_dict。

【问题讨论】:

    标签: tensorflow tensorflow2.0


    【解决方案1】:

    您可以通过callback 读取和分配学习率。所以你可以使用这样的东西:

    class LearningRateReducerCb(tf.keras.callbacks.Callback):
    
      def on_epoch_end(self, epoch, logs={}):
        old_lr = self.model.optimizer.lr.read_value()
        new_lr = old_lr * 0.99
        print("\nEpoch: {}. Reducing Learning Rate from {} to {}".format(epoch, old_lr, new_lr))
        self.model.optimizer.lr.assign(new_lr)
    

    例如,使用MNIST demo 可以这样应用:

    mnist = tf.keras.datasets.mnist
    
    (x_train, y_train), (x_test, y_test) = mnist.load_data()
    x_train, x_test = x_train / 255.0, x_test / 255.0
    
    model = tf.keras.models.Sequential([
      tf.keras.layers.Flatten(input_shape=(28, 28)),
      tf.keras.layers.Dense(128, activation='relu'),
      tf.keras.layers.Dropout(0.2),
      tf.keras.layers.Dense(10, activation='softmax')
    ])
    
    model.compile(optimizer='adam',
                  loss='sparse_categorical_crossentropy',
                  metrics=['accuracy'])
    
    model.fit(x_train, y_train, callbacks=[LearningRateReducerCb()], epochs=5)
    
    model.evaluate(x_test, y_test)
    

    给出这样的输出:

    Train on 60000 samples
    Epoch 1/5
    59744/60000 [============================>.] - ETA: 0s - loss: 0.2969 - accuracy: 0.9151
    Epoch: 0. Reducing Learning Rate from 0.0010000000474974513 to 0.0009900000877678394
    60000/60000 [==============================] - 6s 92us/sample - loss: 0.2965 - accuracy: 0.9152
    Epoch 2/5
    59488/60000 [============================>.] - ETA: 0s - loss: 0.1421 - accuracy: 0.9585
    Epoch: 1. Reducing Learning Rate from 0.0009900000877678394 to 0.000980100128799677
    60000/60000 [==============================] - 5s 91us/sample - loss: 0.1420 - accuracy: 0.9586
    Epoch 3/5
    59968/60000 [============================>.] - ETA: 0s - loss: 0.1056 - accuracy: 0.9684
    Epoch: 2. Reducing Learning Rate from 0.000980100128799677 to 0.0009702991228550673
    60000/60000 [==============================] - 5s 91us/sample - loss: 0.1056 - accuracy: 0.9684
    Epoch 4/5
    59520/60000 [============================>.] - ETA: 0s - loss: 0.0856 - accuracy: 0.9734
    Epoch: 3. Reducing Learning Rate from 0.0009702991228550673 to 0.0009605961386114359
    60000/60000 [==============================] - 5s 89us/sample - loss: 0.0857 - accuracy: 0.9733
    Epoch 5/5
    59712/60000 [============================>.] - ETA: 0s - loss: 0.0734 - accuracy: 0.9772
    Epoch: 4. Reducing Learning Rate from 0.0009605961386114359 to 0.0009509901865385473
    60000/60000 [==============================] - 5s 87us/sample - loss: 0.0733 - accuracy: 0.9772
    10000/10000 [==============================] - 0s 43us/sample - loss: 0.0768 - accuracy: 0.9762
    [0.07680597708942369, 0.9762]
    

    【讨论】:

    • 谢谢。看来我什至不需要回调,我只需要执行 optimizer.lr.assign(new_value)
    • 我的荣幸。很高兴它有帮助。如果我的回答对您有帮助,那么您可以随时投票和/或接受.. :-)
    【解决方案2】:

    如果您使用自定义训练循环(而不是 keras.fit()),您可以简单地这样做:

    new_learning_rate = 0.01 
    my_optimizer.lr.assign(new_learning_rate)
    

    【讨论】:

    【解决方案3】:

    如果您想使用低级控制而不是 fit 回调功能,请查看 tf.optimizers.schedules。下面是一些示例代码:

    train_steps = 25000
    lr_fn = tf.optimizers.schedules.PolynomialDecay(1e-3, train_steps, 1e-5, 2)
    opt = tf.optimizers.Adam(lr_fn)
    

    这将使学习率从 1e-3 衰减到 1e-5,超过 25000 步,并以 2 次幂多项式衰减。

    注意:

    • 这并没有像其他答案那样真正“存储”学习率,而是学习率现在是一个函数,每次需要计算当前学习率时都会调用它。
    • Optimizer 实例有一个内部计步器,每次调用apply_gradients 时都会加一(据我所知......)。这允许此过程在低级上下文(通常使用tf.GradientTape)中使用时正常工作
    • 不幸的是,这个特性没有很好的文档记录(文档只是说学习率参数必须是浮点数或张量......)但它确实有效。您还可以编写自己的衰减时间表。我认为它们只需要是接受优化器的一些当前“状态”(可能是训练步骤数)并返回一个浮点数以用作学习率的函数。

    【讨论】:

    • 这真的很难找到,但是在循环期间分配它的最优雅的解决方案非常难看
    【解决方案4】:

    您有 3 个解决方案:

    这是来自this tutorial的示例:

    class CustomSchedule(tf.keras.optimizers.schedules.LearningRateSchedule):
        def __init__(self, d_model, warmup_steps=4000):
            super(CustomSchedule, self).__init__()
    
            self.d_model = d_model
            self.d_model = tf.cast(self.d_model, tf.float32)
    
            self.warmup_steps = warmup_steps
    
        def __call__(self, step):
            arg1 = tf.math.rsqrt(step)
            arg2 = step * (self.warmup_steps ** -1.5)
    
            return tf.math.rsqrt(self.d_model) * tf.math.minimum(arg1, arg2)
    
    

    然后你将它传递给你的优化器:

    learning_rate = CustomSchedule(d_model)
    
    optimizer = tf.keras.optimizers.Adam(learning_rate, beta_1=0.9, beta_2=0.98, 
                                         epsilon=1e-9)
    
    

    这样,CustomSchedule 将成为您图表的一部分,它会在您的模型训练时更新学习率。

    【讨论】:

    • 什么是d_model
    • @Nerxis 你设置的模型是优化器
    • 谢谢,我刚刚在示例中找到了这个,我认为将它直接添加到您的答案中是值得的。您只是复制了示例的内容,但没有完整的上下文就不清楚了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 2019-09-30
    • 1970-01-01
    • 1970-01-01
    • 2018-05-09
    • 2021-09-25
    相关资源
    最近更新 更多