TensorFlow Saving and Loading Models

Training a model takes time, data, and computing power. Once training finishes, you need to save the model so you can reuse it later for predictions, share it with teammates, or deploy it to a production server. TensorFlow provides multiple formats for saving models, each suited to different use cases. This topic explains every format, when to use each, and how to reload a saved model correctly.

What Needs to Be Saved

A complete model save includes:

1. Architecture  — the layer structure and connections
2. Weights       — all the learned numbers (kernel and bias values)
3. Optimizer state — learning rate and momentum values (for resuming training)
4. Compile config — loss, optimizer name, metrics (for further training)

Format 1 — Keras Native Format (.keras)

The .keras format is the modern recommended format for saving and loading Keras models. It stores everything in a single file: architecture, weights, optimizer state, and compile config.

import tensorflow as tf

# Save
model.save('my_model.keras')

# Load
loaded_model = tf.keras.models.load_model('my_model.keras')

# Verify the loaded model works
results = loaded_model.evaluate(x_test, y_test)
print("Loaded model accuracy:", results[1])

Format 2 — SavedModel Format

SavedModel is TensorFlow's universal format. It saves not just the Keras model but the full TensorFlow computation graph, making it compatible with TensorFlow Serving, TFLite conversion, TensorFlow.js export, and multi-language deployment.

# Save as SavedModel directory
model.save('saved_model_dir/')
# Creates: saved_model_dir/
#   ├── saved_model.pb      (graph definition)
#   └── variables/
#       ├── variables.index
#       └── variables.data-00000-of-00001

# Load
loaded_model = tf.keras.models.load_model('saved_model_dir/')

Format 3 — HDF5 Format (.h5)

The HDF5 format (legacy) saves architecture and weights in a single .h5 file. It works for most models but does not support custom objects as well as the .keras format. New projects should prefer .keras.

# Save
model.save('my_model.h5')

# Load
loaded_model = tf.keras.models.load_model('my_model.h5')

Saving Only the Weights

Sometimes you want to save just the learned weights without the architecture, for example when you plan to rebuild the same model in code and just restore the parameters.

# Save weights only
model.save_weights('weights_only.weights.h5')

# Load weights into a model with the same architecture
new_model = build_model()   # Create the same architecture
new_model.load_weights('weights_only.weights.h5')

Checkpointing During Training

A checkpoint saves the model's weights at specific points during training. This protects against crashes and lets you restore the best-performing model rather than the final one.

import tensorflow as tf

# Save checkpoint at the end of every epoch
checkpoint_cb = tf.keras.callbacks.ModelCheckpoint(
    filepath='checkpoints/model_epoch_{epoch:02d}.keras',
    save_weights_only=False,
    save_freq='epoch',
    verbose=1
)

model.fit(x_train, y_train, epochs=20, callbacks=[checkpoint_cb])

Save Only the Best Model

best_model_cb = tf.keras.callbacks.ModelCheckpoint(
    filepath='best_model.keras',
    monitor='val_accuracy',   # Watch this metric
    save_best_only=True,      # Only overwrite if this metric improves
    mode='max',               # Higher val_accuracy is better
    verbose=1
)

model.fit(x_train, y_train,
          epochs=50,
          validation_data=(x_val, y_val),
          callbacks=[best_model_cb])

# After training, load the best model (not necessarily the last epoch)
best_model = tf.keras.models.load_model('best_model.keras')

TensorFlow Checkpoints (Low-Level)

For custom training loops that do not use model.fit(), use TensorFlow's low-level checkpoint system:

import tensorflow as tf

optimizer = tf.keras.optimizers.Adam()
checkpoint = tf.train.Checkpoint(model=model, optimizer=optimizer)
manager = tf.train.CheckpointManager(checkpoint,
                                      directory='./tf_checkpoints',
                                      max_to_keep=3)

# Save
save_path = manager.save()
print(f"Saved checkpoint: {save_path}")

# Restore latest checkpoint
checkpoint.restore(manager.latest_checkpoint)
print("Restored from:", manager.latest_checkpoint)

Saving and Loading Custom Models

If your model uses custom layers, custom loss functions, or custom metrics, you must pass a custom_objects dictionary when loading:

# Custom activation function
def my_activation(x):
    return x * tf.nn.sigmoid(x)  # Swish

# Save works normally
model.save('custom_model.keras')

# Load requires custom_objects
loaded = tf.keras.models.load_model(
    'custom_model.keras',
    custom_objects={'my_activation': my_activation}
)

Format Comparison

Format          Extension   Architecture  Weights  Optimizer  Deployment
──────────────────────────────────────────────────────────────────────────
Keras native    .keras      Yes           Yes      Yes        Keras only
SavedModel      directory   Yes           Yes      Yes        Universal
HDF5 (legacy)   .h5         Yes           Yes      Yes        Keras only
Weights only    .weights.h5 No            Yes      No         Keras only
TF Checkpoint   directory   No            Yes      Yes        TF only
──────────────────────────────────────────────────────────────────────────
Use .keras for most projects. Use SavedModel when deploying to TF Serving or
converting to TFLite. Use Weights only when sharing parameters across experiments.

Converting SavedModel for Deployment

# Convert SavedModel to TFLite for mobile
converter = tf.lite.TFLiteConverter.from_saved_model('saved_model_dir/')
tflite_model = converter.convert()
with open('model.tflite', 'wb') as f:
    f.write(tflite_model)

# Convert SavedModel to TensorFlow.js for browser
# (requires tensorflowjs package)
# tensorflowjs_converter --input_format=tf_saved_model saved_model_dir/ tfjs_dir/

Loading for Inference Only (No Training)

# Load model and run predictions — no need to recompile
loaded_model = tf.keras.models.load_model('my_model.keras')

# Single prediction
sample = x_test[0:1]   # Keep batch dimension: shape (1, features)
prediction = loaded_model.predict(sample)
print("Prediction:", prediction)

# Batch prediction
all_predictions = loaded_model.predict(x_test, batch_size=64)

Verifying a Loaded Model

# Always verify the loaded model matches the original
original_results = model.evaluate(x_test, y_test, verbose=0)
loaded_results   = loaded_model.evaluate(x_test, y_test, verbose=0)

print(f"Original accuracy: {original_results[1]:.4f}")
print(f"Loaded accuracy:   {loaded_results[1]:.4f}")
# These should be identical

Saving and loading models correctly is an essential production skill. A missing custom_objects argument, a wrong file format for deployment, or failing to save the best checkpoint rather than the last one are common mistakes that waste hours of training time. The next topic moves into data handling — how to build efficient data pipelines that feed models without bottlenecking on slow disk reads.

Leave a Comment

Your email address will not be published. Required fields are marked *