損失値に基づいて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エポックの間損失が改善されなかったときにトレーニングを停止するように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 2017

15
Kerasが更新されたようです。EarlyStoppingのコールバック関数は今それに組み込まれてmin_deltaを持っています。もうソースコードをハックする必要はありません。stackoverflow.com/a/41459368/3345375
jkdev 2017年

3
質問と回答を読み直したら、自分で修正する必要があります。min_deltaは、「エポックごと(または複数のエポックごと)に十分な改善がない場合は、早期に停止する」という意味です。しかし、OPは「損失が一定のレベルを下回ったときに早期に停止する」方法を尋ねました。
jkdev 2017年

NameError:name'Callback 'is not defined ...どうすれば修正できますか?
alyssaeliyah

2
エリヤはこれを試してみてください: from keras.callbacks import Callback
ZFTurbo 2018年

26

keras.callbacks.EarlyStoppingコールバックにはmin_delta引数があります。Kerasのドキュメントから:

min_delta:改善と見なされる監視対象量の最小変化、つまりmin_delta未満の絶対変化は、改善なしとしてカウントされます。


3
参考までに、min_delta引数がまだ含まれていない以前のバージョンのKeras(1.1.0)のドキュメントを次に示します。faroit.github.io
docs

min_delta複数のエポックにわたって持続するまで停止しないようにするにはどうすればよいですか?
zyxue

EarlyStoppingには、忍耐と呼ばれる別のパラメーターがあります。それは、トレーニングが停止されるまで改善されていないエポックの数です。
devin 2018

13

1つの解決策はmodel.fit(nb_epoch=1, ...)、forループ内で呼び出すことです。次に、forループ内にbreakステートメントを配置して、他のカスタム制御フローを実行できます。


彼らがそれを行うことができる単一の関数を受け取るコールバックを作ったらいいのにと思います。
正直2016

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.