How to save and load Keras model weights

Saving only weights keeps the learned parameters without serializing the complete Keras model definition. This is useful when the architecture is recreated by code, when a checkpoint feeds transfer learning, or when only compatible layer weights should move between models.

In Keras 3, model.save_weights() writes an HDF5 weights file whose name should end in .weights.h5. The receiving model must have a compatible architecture and built variables before load_weights() can restore the parameters.

Use full-model .keras saving when the next process should reload the architecture, compile information, and optimizer state automatically. Use weights-only saving when that extra model metadata is not needed or the architecture is intentionally rebuilt.

Steps to save and load Keras model weights:

  1. Install Keras and the backend package.
    $ python -m pip install --upgrade keras jax
  2. Create save_load_weights.py.
    save_load_weights.py
    import os
    from pathlib import Path
     
    os.environ["KERAS_BACKEND"] = "jax"
     
    import keras
    import numpy as np
     
     
    def build_model(compile_model=True):
        model = keras.Sequential(
            [
                keras.Input(shape=(4,), name="features"),
                keras.layers.Dense(8, activation="relu", name="hidden"),
                keras.layers.Dense(1, activation="sigmoid", name="score"),
            ]
        )
        if compile_model:
            model.compile(
                optimizer=keras.optimizers.Adam(learning_rate=0.04),
                loss=keras.losses.BinaryCrossentropy(),
            )
        return model
     
     
    keras.utils.set_random_seed(29)
    weights_path = Path("risk-score.weights.h5")
    if weights_path.exists():
        weights_path.unlink()
     
    x_train = np.linspace(0.0, 1.0, 64, dtype="float32").reshape(16, 4)
    y_train = ((x_train[:, 1] + x_train[:, 3]) > 0.9).astype("float32")
    sample = np.array([[0.2, 0.7, 0.4, 0.8]], dtype="float32")
     
    model = build_model()
    model.fit(x_train, y_train, epochs=10, batch_size=4, verbose=0)
    before = model.predict(sample, verbose=0)
    model.save_weights(weights_path)
     
    clone = build_model(compile_model=False)
    clone(np.zeros((1, 4), dtype="float32"))
    clone.load_weights(weights_path)
    after = clone.predict(sample, verbose=0)
     
    print(f"backend: {keras.backend.backend()}")
    print(f"weights file: {weights_path}")
    print(f"weights file exists: {weights_path.exists()}")
    print(f"prediction before save: {before[0, 0]:.6f}")
    print(f"prediction after load: {after[0, 0]:.6f}")
    print(f"predictions match: {np.allclose(before, after, atol=1e-6)}")

    The clone is built once before loading weights so all layer variables exist. The architecture must stay compatible with the saved weights file.

  3. Run the script.
    $ python save_load_weights.py
    backend: jax
    weights file: risk-score.weights.h5
    weights file exists: True
    prediction before save: 0.655520
    prediction after load: 0.655520
    predictions match: True

    Confirm predictions match: True before using the weights file in another script or training job.

  4. Use the native .keras format instead when the architecture should travel with the weights.
    model.save("risk-score.keras")
    loaded_model = keras.models.load_model("risk-score.keras")