Реальная функция, которую вы реализуете, - это не экспоненциальный спад (как вы упоминаете в заголовке), а лестничная функция .
Кроме того, вы упоминаете, что ваша скорость обучения не меняется внутри вашей петли. Это правда, потому что вы устанавливаете model.fit(..., epochs=1,...)
и ваш epochs_drop = 2.0
одновременно. Я не уверен, что это ваш желаемый случай или нет. Вы приводите игрушечный пример, и в этом случае не ясно.
Я хотел бы добавить более распространенный случай , когда вы не смешиваете цикл for с fit()
и просто предоставляете другой параметр epochs
в вашей функции fit()
. В этом случае у вас есть следующие опции:
Прежде всего keras
предоставляет саму разлагающуюся функциональность с предопределенными оптимизаторами. Например, в вашем случае Adam()
фактический код равен :
lr = lr * (1. / (1. + self.decay * K.cast (self.iterations, K.dtype (self.decay))))
, который также не является точно экспоненциальным и чем-то отличается от tenorflow's one . Кроме того, он используется только тогда, когда decay > 0.0
, как это очевидно.
Чтобы следовать принципу тензорного потока экспоненциального затухания, вы должны реализовать:
decayed_learning_rate = learning_rate * ^ (global_step / decay_steps)
В зависимости от ваших потребностей, вы можете выбрать реализацию подкласса Callback
и определить в нем функцию (см. 3-й пункт ниже) или использовать LearningRateScheduler
, что на самом деле , с некоторой проверкой : a 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
Наконец, добавьте фактическую функцию внутри класса:
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
.