Long-running Keras training can keep updating weights after validation performance has stopped improving. EarlyStopping watches an epoch-level metric from model.fit() and ends the run once the configured wait for improvement is exhausted.
The callback can monitor val_loss when model.fit() receives validation data. mode=“min” treats a lower value as better, while min_delta sets the smallest decrease that resets the patience counter.
The demonstration uses patience=2 and restore_best_weights=True. Training should stop before the requested 20 epochs, and evaluating the restored model should reproduce the best validation loss recorded in the training history.
Related: How to use ModelCheckpoint in Keras
Related: How to create a custom callback in Keras
Related: How to resume Keras training from a checkpoint
Related: How to set the Keras backend
Steps to stop Keras training early with EarlyStopping:
- Create early_stopping_demo.py with the imports and regression data.
- early_stopping_demo.py
import keras import numpy as np keras.utils.set_random_seed(42) x_train = np.linspace(-1.0, 1.0, 120, dtype="float32").reshape(-1, 1) y_train = (2.0 * x_train) + 0.5 x_val = np.linspace(-0.8, 0.8, 40, dtype="float32").reshape(-1, 1) y_val = (2.0 * x_val) + 0.5
- Append the model definition and compilation settings to early_stopping_demo.py.
model = keras.Sequential( [ keras.layers.Input(shape=(1,)), keras.layers.Dense(8, activation="relu"), keras.layers.Dense(1), ] ) model.compile( optimizer=keras.optimizers.SGD(learning_rate=0.35), loss="mse", metrics=["mae"], )
- Append the validation-loss callback configuration to early_stopping_demo.py.
early_stop = keras.callbacks.EarlyStopping( monitor="val_loss", mode="min", min_delta=0.0001, patience=2, restore_best_weights=True, verbose=1, )
mode=“max” suits a monitored metric that should increase, such as val_accuracy. start_from_epoch delays monitoring while the model completes warm-up epochs.
- Append the training call to early_stopping_demo.py.
history = model.fit( x_train, y_train, validation_data=(x_val, y_val), epochs=20, batch_size=16, callbacks=[early_stop], verbose=0, )
The callbacks argument accepts a list, so EarlyStopping can run beside logging or checkpoint callbacks.
- Append the restored-weight checks to early_stopping_demo.py.
best_epoch = int(np.argmin(history.history["val_loss"])) + 1 best_val_loss = min(history.history["val_loss"]) restored_val_loss, _ = model.evaluate(x_val, y_val, verbose=0) epochs_run = len(history.history["loss"]) if epochs_run >= 20: raise RuntimeError("EarlyStopping did not stop training before epoch 20") if not np.isclose(restored_val_loss, best_val_loss, rtol=1e-5, atol=1e-7): raise RuntimeError("restored weights do not match the best validation loss") print("epochs requested: 20") print(f"epochs run: {epochs_run}") print(f"best epoch: {best_epoch}") print(f"best val_loss: {best_val_loss:.4f}") print(f"restored val_loss: {restored_val_loss:.4f}") print(f"history keys: {sorted(history.history.keys())}")
history.history must contain the monitored key. If val_loss is absent, pass validation data to model.fit() or monitor an epoch metric already present in the training logs.
- Run the completed demonstration script.
$ python3 early_stopping_demo.py Epoch 3: early stopping Restoring model weights from the end of the best epoch: 1. epochs requested: 20 epochs run: 3 best epoch: 1 best val_loss: 0.0474 restored val_loss: 0.0474 history keys: ['loss', 'mae', 'val_loss', 'val_mae']
The exact loss values can vary by backend and hardware.
- Confirm epochs run is below 20 in the script output.
This observation shows the callback ended training after the patience window instead of consuming the full epoch budget.
- Confirm restored val_loss matches best val_loss in the script output.
This observation shows restore_best_weights=True returned the model to the best monitored epoch.
- Rerun the retained early_stopping_demo.py program to verify its EarlyStopping checks still pass.
$ python3 early_stopping_demo.py Epoch 3: early stopping Restoring model weights from the end of the best epoch: 1. epochs requested: 20 epochs run: 3 best epoch: 1 best val_loss: 0.0474 restored val_loss: 0.0474 history keys: ['loss', 'mae', 'val_loss', 'val_mae']
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.