Keras에게 손실 값을 기반으로 훈련을 중지하도록 알리는 방법은 무엇입니까?


82

현재 다음 코드를 사용합니다.

callbacks = [
    EarlyStopping(monitor='val_loss', patience=2, verbose=0),
    ModelCheckpoint(kfold_weights_path, monitor='val_loss', save_best_only=True, verbose=0),
]
model.fit(X_train.astype('float32'), Y_train, batch_size=batch_size, nb_epoch=nb_epoch,
      shuffle=True, verbose=1, validation_data=(X_valid, Y_valid),
      callbacks=callbacks)

2 Epoch 동안 손실이 개선되지 않으면 Keras에게 훈련을 중단하라고 지시합니다. 그러나 손실이 일정한 "THR"보다 작아지면 훈련을 중단하고 싶습니다.

if val_loss < THR:
    break

나는 문서에서 자신의 콜백을 만들 가능성이 있음을 보았다 : http://keras.io/callbacks/ 그러나 훈련 과정을 멈추는 방법을 찾지 못했습니다. 조언이 필요합니다.

답변:


85

답을 찾았습니다. Keras 소스를 살펴보고 EarlyStopping에 대한 코드를 찾았습니다. 나는 그것을 기반으로 내 자신의 콜백을 만들었습니다.

class EarlyStoppingByLossVal(Callback):
    def __init__(self, monitor='val_loss', value=0.00001, verbose=0):
        super(Callback, self).__init__()
        self.monitor = monitor
        self.value = value
        self.verbose = verbose

    def on_epoch_end(self, epoch, logs={}):
        current = logs.get(self.monitor)
        if current is None:
            warnings.warn("Early stopping requires %s available!" % self.monitor, RuntimeWarning)

        if current < self.value:
            if self.verbose > 0:
                print("Epoch %05d: early stopping THR" % epoch)
            self.model.stop_training = True

그리고 사용법 :

callbacks = [
    EarlyStoppingByLossVal(monitor='val_loss', value=0.00001, verbose=1),
    # EarlyStopping(monitor='val_loss', patience=2, verbose=0),
    ModelCheckpoint(kfold_weights_path, monitor='val_loss', save_best_only=True, verbose=0),
]
model.fit(X_train.astype('float32'), Y_train, batch_size=batch_size, nb_epoch=nb_epoch,
      shuffle=True, verbose=1, validation_data=(X_valid, Y_valid),
      callbacks=callbacks)

1
누군가에게 유용 할 경우-제 경우에는 monitor = 'loss'를 사용했는데 잘 작동했습니다.
QtRoS

15
Keras가 업데이트 된 것 같습니다. EarlyStopping의 콜백 함수는 지금에 내장 min_delta 있습니다. 더 이상 소스 코드를 해킹 할 필요가 없습니다. stackoverflow.com/a/41459368/3345375
jkdev

3
질문과 답변을 다시 읽으면 스스로 수정해야합니다. min_delta는 "에포크 당 (또는 여러 에포크 당) 개선이 충분하지 않으면 일찍 중지"를 의미합니다. 그러나 OP는 "손실이 일정 수준 이하로 내려 가면 조기 중단"하는 방법을 물었다.
jkdev

NameError : name 'Callback'is not defined ... 어떻게 수정하나요?
alyssaeliyah

2
Eliyah 시도 : from keras.callbacks import Callback
ZFTurbo

26

keras.callbacks.EarlyStopping 콜백에는 min_delta 인수가 있습니다. Keras 문서에서 :

min_delta : 개선으로 인정하기 위해 모니터링 된 수량의 최소 변경, 즉 min_delta 미만의 절대 변경은 개선되지 않은 것으로 간주됩니다.


3
참고로 다음은 min_delta 인수가 아직 포함되지 않은 Keras (1.1.0)의 이전 버전에 대한 문서입니다. faroit.github.io/keras-docs/1.1.0/callbacks/#earlystopping
jkdev

min_delta여러 시대에 걸쳐 지속될 때까지 어떻게 멈추지 않을 수 있습니까?
zyxue

EarlyStopping에는 인내라는 또 다른 매개 변수가 있습니다. 개선되지 않은 에포크의 수는 훈련이 중단됩니다.
devin

13

한 가지 해결책은 model.fit(nb_epoch=1, ...)for 루프 내부 를 호출 하는 것입니다. 그러면 for 루프 내부에 break 문을 넣고 원하는 다른 사용자 정의 제어 흐름을 수행 할 수 있습니다.


그렇게 할 수있는 단일 함수를받는 콜백을 만들면 좋을 것입니다.
Honesty

7

사용자 지정 콜백을 사용하여 동일한 문제를 해결했습니다.

다음 사용자 지정 콜백 코드에서 훈련을 중지하려는 값으로 THR을 할당하고 모델에 콜백을 추가합니다.

from keras.callbacks import Callback

class stopAtLossValue(Callback):

        def on_batch_end(self, batch, logs={}):
            THR = 0.03 #Assign THR with the value at which you want to stop training.
            if logs.get('loss') <= THR:
                 self.model.stop_training = True

2

실제로 TensorFlow를 전문화 하는 동안 매우 우아한 기술을 배웠습니다. 수락 된 답변에서 약간 수정되었습니다.

우리가 가장 좋아하는 MNIST 데이터로 예제를 설정해 보겠습니다.

import tensorflow as tf

class new_callback(tf.keras.callbacks.Callback):
    def epoch_end(self, epoch, logs={}): 
        if(logs.get('accuracy')> 0.90): # select the accuracy
            print("\n !!! 90% accuracy, no further training !!!")
            self.model.stop_training = True

mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0 #normalize

callbacks = new_callback()

# model = tf.keras.models.Sequential([# define your model here])

model.compile(optimizer=tf.optimizers.Adam(),
          loss='sparse_categorical_crossentropy',
          metrics=['accuracy'])
model.fit(x_train, y_train, epochs=10, callbacks=[callbacks])

그래서 여기에서를 설정 metrics=['accuracy']했으므로 콜백 클래스에서 조건이로 설정됩니다 'accuracy'> 0.90.

이 예제와 같이 모든 지표를 선택하고 훈련을 모니터링 할 수 있습니다. 가장 중요한 것은 서로 다른 메트릭에 대해 서로 다른 조건을 설정하고 동시에 사용할 수 있다는 것입니다.

도움이 되었기를 바랍니다.


함수 이름은 on_epoch_end
xarion

0

나를 위해 self.model.evaluate를 호출했기 때문에 stop_training 매개 변수를 True로 설정 한 후 return 문을 추가하면 모델이 훈련을 중지합니다. 따라서 함수 끝에 stop_training = True를 입력하거나 return 문을 추가하십시오.

def on_epoch_end(self, batch, logs):
        self.epoch += 1
        self.stoppingCounter += 1
        print('\nstopping counter \n',self.stoppingCounter)

        #Stop training if there hasn't been any improvement in 'Patience' epochs
        if self.stoppingCounter >= self.patience:
            self.model.stop_training = True
            return

        # Test on additional set if there is one
        if self.testingOnAdditionalSet:
            evaluation = self.model.evaluate(self.val2X, self.val2Y, verbose=0)
            self.validationLoss2.append(evaluation[0])
            self.validationAcc2.append(evaluation[1])enter code here

0

사용자 지정 학습 루프를 사용하는 collections.deque경우 추가 할 수있는 "롤링"목록 인을 사용할 수 있으며 목록이보다 길면 왼쪽 항목이 팝업됩니다 maxlen. 다음은 라인입니다.

loss_history = deque(maxlen=early_stopping + 1)

for epoch in range(epochs):
    fit(epoch)
    loss_history.append(test_loss.result().numpy())
    if len(loss_history) > early_stopping and loss_history.popleft() < min(loss_history)
            break

다음은 전체 예입니다.

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
import tensorflow_datasets as tfds
import tensorflow as tf
from tensorflow.keras.layers import Dense
from collections import deque

data, info = tfds.load('iris', split='train', as_supervised=True, with_info=True)

data = data.map(lambda x, y: (tf.cast(x, tf.int32), y))

train_dataset = data.take(120).batch(4)
test_dataset = data.skip(120).take(30).batch(4)

model = tf.keras.models.Sequential([
    Dense(8, activation='relu'),
    Dense(16, activation='relu'),
    Dense(info.features['label'].num_classes)])

loss_object = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)

train_loss = tf.keras.metrics.Mean()
test_loss = tf.keras.metrics.Mean()

train_acc = tf.keras.metrics.SparseCategoricalAccuracy()
test_acc = tf.keras.metrics.SparseCategoricalAccuracy()

opt = tf.keras.optimizers.Adam(learning_rate=1e-3)


@tf.function
def train_step(inputs, labels):
    with tf.GradientTape() as tape:
        logits = model(inputs, training=True)
        loss = loss_object(labels, logits)

    gradients = tape.gradient(loss, model.trainable_variables)
    opt.apply_gradients(zip(gradients, model.trainable_variables))
    train_loss(loss)
    train_acc(labels, logits)


@tf.function
def test_step(inputs, labels):
    logits = model(inputs, training=False)
    loss = loss_object(labels, logits)
    test_loss(loss)
    test_acc(labels, logits)


def fit(epoch):
    template = 'Epoch {:>2} Train Loss {:.3f} Test Loss {:.3f} ' \
               'Train Acc {:.2f} Test Acc {:.2f}'

    train_loss.reset_states()
    test_loss.reset_states()
    train_acc.reset_states()
    test_acc.reset_states()

    for X_train, y_train in train_dataset:
        train_step(X_train, y_train)

    for X_test, y_test in test_dataset:
        test_step(X_test, y_test)

    print(template.format(
        epoch + 1,
        train_loss.result(),
        test_loss.result(),
        train_acc.result(),
        test_acc.result()
    ))


def main(epochs=50, early_stopping=10):
    loss_history = deque(maxlen=early_stopping + 1)

    for epoch in range(epochs):
        fit(epoch)
        loss_history.append(test_loss.result().numpy())
        if len(loss_history) > early_stopping and loss_history.popleft() < min(loss_history):
            print(f'\nEarly stopping. No validation loss '
                  f'improvement in {early_stopping} epochs.')
            break

if __name__ == '__main__':
    main(epochs=250, early_stopping=10)
Epoch  1 Train Loss 1.730 Test Loss 1.449 Train Acc 0.33 Test Acc 0.33
Epoch  2 Train Loss 1.405 Test Loss 1.220 Train Acc 0.33 Test Acc 0.33
Epoch  3 Train Loss 1.173 Test Loss 1.054 Train Acc 0.33 Test Acc 0.33
Epoch  4 Train Loss 1.006 Test Loss 0.935 Train Acc 0.33 Test Acc 0.33
Epoch  5 Train Loss 0.885 Test Loss 0.846 Train Acc 0.33 Test Acc 0.33
...
Epoch 89 Train Loss 0.196 Test Loss 0.240 Train Acc 0.89 Test Acc 0.87
Epoch 90 Train Loss 0.195 Test Loss 0.239 Train Acc 0.89 Test Acc 0.87
Epoch 91 Train Loss 0.195 Test Loss 0.239 Train Acc 0.89 Test Acc 0.87
Epoch 92 Train Loss 0.194 Test Loss 0.239 Train Acc 0.90 Test Acc 0.87

Early stopping. No validation loss improvement in 10 epochs.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.