Obecnie używam następującego kodu:
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)
Mówi Kerasowi, aby przestał trenować, jeśli straty nie poprawiły się przez 2 epoki. Ale chcę przestać trenować po tym, jak strata stała się mniejsza niż jakieś stałe „THR”:
if val_loss < THR:
break
Widziałem w dokumentacji, że istnieje możliwość wykonania własnego oddzwonienia: http://keras.io/callbacks/ Ale nic nie znalazło sposobu na zatrzymanie procesu szkolenia. Potrzebuję rady.
from keras.callbacks import Callback
Callback keras.callbacks.EarlyStopping ma argument min_delta. Z dokumentacji Keras:
źródło
min_delta
nie będzie trwało przez wiele epok?Jednym z rozwiązań jest wywołanie
model.fit(nb_epoch=1, ...)
wewnątrz pętli for, a następnie umieszczenie instrukcji break wewnątrz pętli for i wykonanie dowolnego innego niestandardowego przepływu sterowania.źródło
Rozwiązałem ten sam problem, używając niestandardowego wywołania zwrotnego.
W poniższym niestandardowym kodzie wywołania zwrotnego przypisz THR wartość, przy której chcesz zatrzymać uczenie i dodać wywołanie zwrotne do swojego modelu.
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
źródło
Chociaż byłem biorąc TensorFlow specjalizacji w praktyce , nauczyłem się bardzo elegancką technikę. Niewiele zmodyfikowano w stosunku do zaakceptowanej odpowiedzi.
Dajmy przykład naszym ulubionym danym 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])
Więc tutaj ustawiam
metrics=['accuracy']
, a więc w klasie wywołania zwrotnego warunek jest ustawiony na'accuracy'> 0.90
.Możesz wybrać dowolną metrykę i monitorować szkolenie, tak jak w tym przykładzie. Co najważniejsze, możesz ustawić różne warunki dla różnych danych i używać ich jednocześnie.
Mam nadzieję, że to pomoże!
źródło
Dla mnie model przestałby trenować tylko wtedy, gdybym dodał instrukcję return po ustawieniu parametru stop_training na True, ponieważ dzwoniłem po self.model.evaluate. Więc upewnij się, że na końcu funkcji umieścisz stop_training = True lub dodaj instrukcję 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
źródło
Jeśli używasz niestandardowej pętli treningowej, możesz użyć
collections.deque
listy „toczącej się”, którą można dołączyć, a pozycje po lewej stronie zostaną wyskakujące, gdy lista jest dłuższa niżmaxlen
. Oto linia: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
Oto pełny przykład:
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.
źródło