Как реализовать экспоненциальную скорость обучения в Керасе, выполнив глобальные шаги - PullRequest
0 голосов
/ 11 сентября 2018

Посмотрите на следующий пример

# 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 вообще не меняет скорость обучения, потому что на каждой итерации ep, epoch=1.Таким образом, скорость обучения просто постоянна (1,0, согласно step_decay).На самом деле, вместо установки epoch> 1 напрямую, я должен сделать внешний цикл, как показано в примере, и в каждом цикле я просто запускаю 1 эпоху.(Это тот случай, когда я применяю глубокое подкрепляющее обучение вместо контролируемого обучения).

Мой вопрос заключается в том, как установить экспоненциальную скорость обучения с затуханием в моем примере и как получить скорость обучения на каждой итерации ep.

Ответы [ 2 ]

0 голосов
/ 08 мая 2019

Реальная функция, которую вы реализуете, - это не экспоненциальный спад (как вы упоминаете в заголовке), а лестничная функция .

Кроме того, вы упоминаете, что ваша скорость обучения не меняется внутри вашей петли. Это правда, потому что вы устанавливаете model.fit(..., epochs=1,...) и ваш epochs_drop = 2.0 одновременно. Я не уверен, что это ваш желаемый случай или нет. Вы приводите игрушечный пример, и в этом случае не ясно.

Я хотел бы добавить более распространенный случай , когда вы не смешиваете цикл for с fit() и просто предоставляете другой параметр epochs в вашей функции fit(). В этом случае у вас есть следующие опции:

  1. Прежде всего keras предоставляет саму разлагающуюся функциональность с предопределенными оптимизаторами. Например, в вашем случае Adam() фактический код равен :

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

, который также не является точно экспоненциальным и чем-то отличается от tenorflow's one . Кроме того, он используется только тогда, когда decay > 0.0, как это очевидно.

  1. Чтобы следовать принципу тензорного потока экспоненциального затухания, вы должны реализовать:

    decayed_learning_rate = learning_rate * ^ (global_step / decay_steps)

В зависимости от ваших потребностей, вы можете выбрать реализацию подкласса Callback и определить в нем функцию (см. 3-й пункт ниже) или использовать LearningRateScheduler, что на самом деле , с некоторой проверкой : a Callback подкласс, который обновляет скорость обучения на каждый конец эпохи .

  1. Если вы хотите более тонкую обработку вашей политики скорости обучения (например, для каждой партии), вам придется реализовать свой подкласс, поскольку, насколько я знаю, для этой задачи не существует реализованного подкласса. Хорошая часть в том, что это супер просто:

Создать подкласс

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

Наконец, добавьте фактическую функцию внутри класса:

def on_batch_begin(self, batch, logs=None):
    actual_lr = float(K.get_value(self.model.optimizer.lr))
    decayed_learning_rate = actual_lr * self.decay_rate ^ (self.global_step / self.decay_steps)
    K.set_value(self.model.optimizer.lr, decayed_learning_rate)
    self.global_step += 1

Действительно классная часть - это если вы хотите, чтобы вышеуказанный подкласс обновлял каждую эпоху, которую вы могли бы использовать on_epoch_begin(self, epoch, logs=None), которая приятно имеет эпоху в качестве параметра своей подписи. Этот случай еще проще, поскольку вы можете вообще пропустить глобальный шаг (не нужно отслеживать его сейчас, если вы не хотите более изощренный способ применить ваш распад) и использовать вместо него epoch.

0 голосов
/ 12 сентября 2018

Вы можете передать два аргумента в LearningRateScheduler.В соответствии с документацией Keras , планировщиком является

функция, которая принимает индекс эпохи в качестве входных данных (целое число, индексированное от 0) и текущая скорость обучения ивозвращает новую скорость обучения в виде выходных данных (float).

Итак, просто замените ваш 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
...