Пропустить веса одной эпохи в Tensorflow Keras

#python #tensorflow #keras

#python #tensorflow #keras

Вопрос:

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

Я написал небольшую функцию обратного вызова, как в этом примере

 from keras.callbacks import Callback

class skip_bad_epoch(Callback):
    """Skip epoch when the loss significantly higher than the previous epoch.
  Arguments:
      factor: Factor by which the loss has to be higher than the previous   """

    def __init__(self, factor=2):
        super(skip_bad_epoch, self).__init__()
        self.factor = factor
        # best_weights to store the weights at which the minimum loss occurs.
        self.last_weights = None

    def on_train_begin(self, logs=None):
        # Initialize the last as infinity.
        self.last = np.Inf

    def on_epoch_end(self, epoch, logs=None):
        current = logs.get("loss") # Use train loss here because that really freaks out
        if (current/self.last)<self.factor: # If the current loss is not significantly higher than the previous
            self.last = current
            # Record the best weights if current results is better (less loss).
            self.last_weights = self.model.get_weights()
        else:
            print(f"Restoring model weights from the previous epoch. Last loss: {self.last} this loss {current}")
            self.model.set_weights(self.last_weights)
  

И вызвал его во время обучения следующим образом:

 callbacks_list = [skip_bad_epoch(factor=1.5)]
model.fit(
    x, y,
    validation_split=0.1,
    callbacks=callbacks_list
    )
  

Результаты:
В этом примере эпоха # 10 была плохой, и обратный вызов пытается пропустить ее. Однако потери в предстоящей эпохе (здесь: 11 ) всегда значительно хуже, чем те, которые были до пропущенной. Итак, похоже, что веса все еще корректируются, и
их сброса self.model.set_weights(self.last_weights) недостаточно? Может быть, это не включает в себя смещения?

 Epoch 00007: val_loss did not improve from 0.02599
50/50 [==============================] - 6s 117ms/step - loss: 0.0258 - val_loss: 0.0262

Epoch 00008: val_loss improved from 0.02599 to 0.02570, saving model
50/50 [==============================] - 6s 121ms/step - loss: 0.0260 - val_loss: 0.0257

Epoch 00009: val_loss did not improve from 0.02570
50/50 [==============================] - 6s 120ms/step - loss: 0.0259 - val_loss: 0.0475

Epoch 00010: val_loss did not improve from 0.02570
Restoring model weights from the previous epoch. Last loss: 0.0259 this loss 0.0444
50/50 [==============================] - 6s 119ms/step - loss: 0.0444 - val_loss: 0.0331

Epoch 00011: val_loss did not improve from 0.02570
50/50 [==============================] - 6s 121ms/step - loss: 0.0292 - val_loss: 0.0264

Epoch 00012: val_loss did not improve from 0.02570
50/50 [==============================] - 6s 129ms/step - loss: 0.0261 - val_loss: 0.0259
  

введите описание изображения здесь

Используя:
Tensorflow 2.3.1
Keras 2.4.3
Python 3.8.6

Ответ №1:

Я создал обратный вызов, который делает именно то, что вы хотите сделать, кроме того, он также регулирует обучение. Сначала он регулирует скорость обучения, отслеживая точность обучения. Как только точность обучения достигает порогового уровня, скажем .95, тогда обратный вызов корректирует скорость обучения на основе потери проверки. Данные проверки при низкой точности обучения практически не имеют значения. Как и вы, я подумал, что если вы получите значительное снижение производительности отслеживаемого количества в конце эпохи, вам следует сделать две вещи, одна из которых — наверняка снизить скорость обучения. Другой способ — восстановить веса из предыдущей эпохи. Загрузка и сохранение весов, кстати, включает загрузку и сохранение смещений. Логика заключается в том, что отслеживаемая метрика представляет собой поверхность в N пространстве, где N — количество обучаемых параметров. Если вы получаете снижение производительности, вы переместились в местоположение в пространстве N, которое не так хорошо, как то, в котором вы были в предыдущую эпоху. Зачем оставаться там. Итак, загрузите веса из предыдущей эпохи и снова начните обучение с этого лучшего места, но с уменьшенной скоростью обучения. Я думаю, что вы увидели увеличение потерь в эпоху 11 из-за того, что ваша скорость обучения была слишком высокой, что, вероятно, также вызвало значительное увеличение в эпоху 10. Когда я уменьшаю lr, я умножаю lr на фиксированный коэффициент, например .5, затем я дополнительно умножаю его на отношение наименьших потерь v_loss / v_loss текущей эпохи. У меня есть параметр с именем dwell, для которого я могу установить значение True или False, чтобы включить или отключить перезагрузку весов. Я заметил некоторое улучшение в более быстрой сходимости моделей (не сильно) при использовании идеи dwell, но я не так много экспериментировал. Одна из опасностей, которую я вижу, заключается в том, что использование этого жилья может быстро привести к тому, что вы застряли в локальном минимуме в том смысле, что вы не так сильно «исследуете» пространство N. Итак, попробуйте идею снижения lr и посмотрите, работает ли она лучше. Вы можете получить текущую скорость обучения и установить новое обучение с помощью кода, показанного ниже:

 current_lr=float(tf.keras.backend.get_value(self.model.optimizer.lr))
new_lr= whatever calculation you want to use
tf.keras.backend.set_value(self.model.optimizer.lr, new_lr)