具有“staircase=True”的 ExponentialDecay 学习率计划甚至在训练行为生效之前就改变了它

a_g*_*est 5 python machine-learning keras tensorflow

当向我的优化器添加ExponentialDecay学习率计划时Adam,它甚至在训练行为生效之前就改变了它。我对时间表使用了以下定义:

lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(
    1e-3, decay_steps=25, decay_rate=0.95, staircase=True)
Run Code Online (Sandbox Code Playgroud)

由于我使用的是staircase=True,因此与使用相同值的静态学习率相比,前 25 个时期应该没有差异。因此,以下两个优化器应该在前 25 个时期产生相同的训练结果:

optimizer = tf.keras.optimizers.Adam(learning_rate=1e-3)
optimizer = tf.keras.optimizers.Adam(learning_rate=lr_schedule)
Run Code Online (Sandbox Code Playgroud)

然而我观察到行为之前已经有所不同:

损失曲线示例

这是我使用的测试代码:

import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import Dense, Dropout

np.random.seed(0)

x_data = 2*np.random.random(size=(1000, 1))
y_data = np.random.normal(loc=x_data**2, scale=0.05)

lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(
    1e-3, decay_steps=25, decay_rate=0.95, staircase=True)

histories = []
learning_rates = [1e-3, lr_schedule]
for lr in learning_rates:
    tf.random.set_seed(0)

    model = tf.keras.models.Sequential([
        Dense(10, activation='tanh', input_dim=1), Dropout(0.2),
        Dense(10, activation='tanh'), Dropout(0.2),
        Dense(1)
    ])
    optimizer = tf.keras.optimizers.Adam(learning_rate=lr)
    model.compile(optimizer=optimizer, loss='mse')
    history = model.fit(x_data, y_data, epochs=50)
    histories.append(history.history['loss'])

fig, ax = plt.subplots()
ax.set(xlabel='Epoch', ylabel='Loss')
ax.plot(histories[0], label='Static learning rate')
ax.plot(histories[1], label='Learning rate schedule')
ax.legend()
plt.show()
Run Code Online (Sandbox Code Playgroud)

我正在使用 Python 3.7.9 和以下 Tensorflow 安装:

$ conda list | grep tensorflow
tensorflow                2.1.0           mkl_py37h80a91df_0  
tensorflow-base           2.1.0           mkl_py37h6d63fb7_0  
tensorflow-estimator      2.1.0              pyhd54b08b_0
Run Code Online (Sandbox Code Playgroud)

the*_*fee 7

当使用 时ExponentialDecay,你基本上所做的就是使学习率衰减,例如:

def decayed_learning_rate(step):
  return initial_learning_rate * decay_rate ^ (step / decay_steps)
Run Code Online (Sandbox Code Playgroud)

当您设置 时staircase=True,会发生step / decay_steps整数除法并且速率遵循阶梯函数。现在,我们来看看源代码:

# ...setup for step function...
global_step_recomp = math_ops.cast(step, dtype) # step is the current step count
p = global_step_recomp / decay_steps
if self.staircase:
  p = math_ops.floor(p)
return math_ops.multiply(initial_learning_rate, math_ops.pow(decay_rate, p), name=name)
Run Code Online (Sandbox Code Playgroud)

我们可以看到,我们有一个变量p在 的每倍数处更新decay_steps,因此在第 25、50、75 步等处......基本上,学习率每 25 个步骤都是恒定的,而不是纪元 - 这就是它更新的原因在前 25 个 epoch 之前。关于差异的一个很好的解释可以阅读TensorFlow 中步骤和时期之间的区别是什么?