Long Keras training runs need a checkpoint file before the final epoch finishes. ModelCheckpoint saves a model or weight file during model.fit(), which protects progress and preserves the best validation result from a run that may take minutes, hours, or longer.

The callback watches a metric from the training logs, such as val_loss or val_accuracy. With save_best_only=True, it overwrites the target checkpoint only when the monitored metric improves, so the path keeps the strongest model seen so far instead of the last epoch by default.

A whole-model checkpoint in native .keras format stores the architecture, weights, compile information, and optimizer state that Keras can reload with keras.models.load_model(). Use the weights-only mode only when the architecture will be recreated separately and the checkpoint filename ends in .weights.h5.

Steps to save the best Keras model checkpoint:

  1. Create checkpoint_best_model.py with a ModelCheckpoint callback.
    checkpoint_best_model.py
    import keras
    import numpy as np
     
     
    keras.utils.set_random_seed(42)
     
    x_train = np.linspace(-1.0, 1.0, 160, dtype="float32").reshape(80, 2)
    y_train = (0.75 * x_train[:, :1]) - (0.25 * x_train[:, 1:2])
    x_val = np.linspace(-0.8, 0.8, 40, dtype="float32").reshape(20, 2)
    y_val = (0.75 * x_val[:, :1]) - (0.25 * x_val[:, 1:2])
     
    model = keras.Sequential(
        [
            keras.layers.Input(shape=(2,)),
            keras.layers.Dense(8, activation="relu"),
            keras.layers.Dense(1),
        ]
    )
    model.compile(
        optimizer=keras.optimizers.Adam(learning_rate=0.05),
        loss="mse",
        metrics=["mae"],
    )
     
    checkpoint_path = "checkpoints/best.keras"
    checkpoint = keras.callbacks.ModelCheckpoint(
        filepath=checkpoint_path,
        monitor="val_loss",
        mode="min",
        save_best_only=True,
        verbose=1,
    )
     
    history = model.fit(
        x_train,
        y_train,
        validation_data=(x_val, y_val),
        epochs=4,
        batch_size=16,
        callbacks=[checkpoint],
        verbose=0,
    )
     
    loaded = keras.models.load_model(checkpoint_path)
    loaded_loss, loaded_mae = loaded.evaluate(x_val, y_val, verbose=0)
     
    print(f"Saved checkpoint: {checkpoint_path}")
    print(f"Best val_loss: {min(history.history['val_loss']):.4f}")
    print(f"Loaded val_loss: {loaded_loss:.4f}")
    print(f"Loaded val_mae: {loaded_mae:.4f}")

    Use a .keras suffix for a full-model checkpoint. Use .weights.h5 only with save_weights_only=True, and compile the model before loading weights when optimizer state needs to be restored.

  2. Run the training script in the Python environment where Keras is installed.
    $ python checkpoint_best_model.py
    Epoch 1: val_loss improved from None to 0.05945, saving model to checkpoints/best.keras
    ##### snipped #####
    Saved checkpoint: checkpoints/best.keras
    Best val_loss: 0.0006
    Loaded val_loss: 0.0006
    Loaded val_mae: 0.0218

    Loaded val_loss appears only after keras.models.load_model() opens the saved .keras checkpoint and evaluates it on the validation data.

  3. Remove the demo script and checkpoint directory when the run was only a callback test.
    $ rm -rf checkpoint_best_model.py checkpoints

    Do not remove a real training checkpoint directory until the checkpoint has been copied, promoted, or replaced by a newer saved model.