如何通过遵循全局步骤在Keras中实现指数衰减学习率

时间:2018-09-11 13:24:54

标签: neural-network keras deep-learning reinforcement-learning

看下面的例子

# encoding: utf-8
import numpy as np
import pandas as pd
import random
import math
from keras import Sequential
from keras.layers import Dense, Activation
from keras.optimizers import Adam, RMSprop
from keras.callbacks import LearningRateScheduler

X = [i*0.05 for i in range(100)]

def step_decay(epoch):
    initial_lrate = 1.0
    drop = 0.5
    epochs_drop = 2.0
    lrate = initial_lrate * math.pow(drop, 
    math.floor((1+epoch)/epochs_drop))
    return lrate

def build_model():
    model = Sequential()
    model.add(Dense(32, input_shape=(1,), activation='relu'))
    model.add(Dense(1, activation='linear'))
    adam = Adam(lr=0.5)
    model.compile(loss='mse', optimizer=adam)
    return model

model = build_model()
lrate = LearningRateScheduler(step_decay)
callback_list = [lrate]

for ep in range(20):
    X_train = np.array(random.sample(X, 10))
    y_train = np.sin(X_train)
    X_train = np.reshape(X_train, (-1,1))
    y_train = np.reshape(y_train, (-1,1))
    model.fit(X_train, y_train, batch_size=2, callbacks=callback_list, 
              epochs=1, verbose=2)

在此示例中,LearningRateSchedule根本不改变学习率,因为在epepoch=1的每次迭代中。因此,学习率仅为const(根据step_decay为1.0)。实际上,不必像示例中那样直接设置epoch> 1,而是必须执行外部循环,如示例所示,并且在每个循环内部,我只运行了1个时期。 (当我实施深度强化学习而不是监督学习时就是这种情况。)

我的问题是在示例中如何设置指数衰减的学习率,以及如何在ep的每次迭代中获得学习率。

2 个答案:

答案 0 :(得分:2)

您实际上可以将两个参数传递给LearningRateScheduler。 根据{{​​3}},调度程序是

  

以纪元索引作为输入的函数(整数,从   0)和当前学习率,并返回新的学习率作为输出   (浮动)。

因此,基本上,只需将initial_lr替换为一个函数参数,就像这样:

def step_decay(epoch, lr):
    # initial_lrate = 1.0 # no longer needed
    drop = 0.5
    epochs_drop = 2.0
    lrate = lr * math.pow(drop, 
    math.floor((1+epoch)/epochs_drop))
    return lrate

答案 1 :(得分:0)

您实现的实际功能不是指数衰减(如您在标题中所述),而是楼梯功能

此外,您提到您的学习率在循环内不会改变。的确如此,因为您同时设置了model.fit(..., epochs=1,...)epochs_drop = 2.0。我不确定这是否是您想要的情况。您提供的是一个玩具示例,在这种情况下还不清楚。

我想添加一个更常见的情况,在这种情况下,您不要将for循环与fit()混合使用,而只是在{{1 }}函数。在这种情况下,您可以使用以下选项:

  1. 首先epochs本身提供了带有预定义优化器的衰减功能。例如,对于您的情况fit() actual code is

    lr = lr *(1. /(1. + self.decay * K.cast(self.iterations,K.dtype(self.decay))))

也不完全是指数,它与tensorflow's one有所不同。而且,仅当keras很明显时才使用它。

  1. 要遵循指数衰减的张量流约定,您应该实现:

    decayed_learning_rate = learning_rate * ^(全局步数/衰减步数)

根据您的需要,您可以选择实现Adam()子类并在其中定义一个函数(请参见下面的第3个项目符号),也可以使用actually exactly this with some checkingdecay > 0.0:{{1 }}子类,可在每个时期结束时更新学习率。

  1. 如果您想更好地处理学习率策略(例如,每批),则必须实现您的子类,因为据我所知,该任务没有实现的子类。好处是它非常容易:

创建一个子类

Callback

并添加LearningRateScheduler函数,该函数将使用所有需要的参数初始化实例,并创建一个Callback变量以跟踪迭代(批次):

class LearningRateExponentialDecay(Callback):

最后,在类中添加实际功能:

__init__()

最酷的部分是,如果您希望上述子类更新每个纪元,则可以使用global_step,它很好地将纪元作为其签名的参数。这种情况甚至更容易,因为您可以完全跳过全局步骤(除非您想要一种更简单的方法来应用衰减,否则无需立即跟踪它)并在该位置使用 def __init__(self, init_learining_rate, decay_rate, decay_steps): self.init_learining_rate = init_learining_rate self.decay_rate = decay_rate self.decay_steps = decay_steps self.global_step = 0