Tensor Flow 📂 Data Pipelines and Good Training · 6 of 6 28 min read

tf.train.Checkpoint: Save and Resume Training in TensorFlow

Save your model, optimizer and step counter with tf.train.Checkpoint, and keep the last few saves with CheckpointManager. Simulate a crash, rebuild everything and restore to continue from the same step. Look inside a checkpoint and learn when to use a SavedModel. Then crash and resume training in the live simulator.

Section 01

The Story — Save Points in a Video Game

Never Lose Five Hours of Progress
You have played a hard game level for five hours. Then the power goes off. If the game had no save points, you start again from zero. Good games save often, keep the last few saves in case one is broken, and let you continue exactly where you stopped — same level, same score, same items.

Training on a cloud machine is the same. Machines get restarted, notebooks time out, jobs get pre-empted. tf.train.Checkpoint is your save point. It stores the model's weights, the optimizer's memory, and your step counter, so training continues as if nothing happened.

Section 02

What Goes Into a Checkpoint?

A checkpoint saves every tf.Variable reachable from the objects you give it. That is why it works with anything built on tf.Module.

🧠
Model
weights, biases
Everything the model has learned so far.
🏃
Optimizer
momentum, Adam m and v, step
Without these, resuming "forgets" its momentum and Adam restarts its bias correction.
🔢
Counters
step, epoch
So logs, schedules and file names continue from the right number.
import tensorflow as tf
import numpy as np, os, shutil
shutil.rmtree("/tmp/ckpt", ignore_errors=True)

rng = np.random.default_rng(0)
X = rng.normal(size=(256, 3)).astype("float32")
y = (X @ np.array([[2.0], [-1.0], [0.5]], dtype="float32") + 0.1 * rng.normal(size=(256, 1))).astype("float32")

def build():
    tf.random.set_seed(0)
    model = tf.keras.Sequential([tf.keras.Input((3,)), tf.keras.layers.Dense(1)])
    opt = tf.keras.optimizers.SGD(0.05, momentum=0.9)
    step = tf.Variable(0, dtype=tf.int64, name="step")
    return model, opt, step

model, opt, step = build()
ckpt = tf.train.Checkpoint(model=model, optimizer=opt, step=step)
manager = tf.train.CheckpointManager(ckpt, directory="/tmp/ckpt", max_to_keep=3)

@tf.function
def train_step():
    with tf.GradientTape() as tape:
        loss = tf.reduce_mean((model(X) - y) ** 2)
    grads = tape.gradient(loss, model.trainable_variables)
    opt.apply_gradients(zip(grads, model.trainable_variables))
    step.assign_add(1)
    return loss

for _ in range(50):
    loss = train_step()
    if int(step) % 10 == 0:
        path = manager.save(checkpoint_number=step)
        print(f"step {int(step):3d}  loss {float(loss):.4f}  saved {os.path.basename(path)}")

print("kept:", [os.path.basename(p) for p in manager.checkpoints])
print("files:", sorted(os.listdir("/tmp/ckpt")))
OUTPUT
step 10 loss 2.8872 saved ckpt-10 step 20 loss 0.9170 saved ckpt-20 step 30 loss 0.2726 saved ckpt-30 step 40 loss 0.0786 saved ckpt-40 step 50 loss 0.0252 saved ckpt-50 kept: ['ckpt-30', 'ckpt-40', 'ckpt-50'] files: ['checkpoint', 'ckpt-30.data-00000-of-00001', 'ckpt-30.index', 'ckpt-40.data-00000-of-00001', 'ckpt-40.index', 'ckpt-50.data-00000-of-00001', 'ckpt-50.index']
📁
Three Kinds of Files

ckpt-N.index says which variable is where. ckpt-N.data-00000-of-00001 holds the actual numbers. The small checkpoint text file remembers which one is the latest. With max_to_keep=3, older saves are deleted automatically.


Section 03

The Crash — and the Resume

We pretend the machine restarted: we throw away every Python object and build a brand-new model and optimizer. Then we restore.

del model, opt, step, ckpt, manager                         # "the machine restarted"

model, opt, step = build()                                   # fresh, random objects
ckpt = tf.train.Checkpoint(model=model, optimizer=opt, step=step)
manager = tf.train.CheckpointManager(ckpt, "/tmp/ckpt", max_to_keep=3)

print("latest:", os.path.basename(manager.latest_checkpoint))
status = ckpt.restore(manager.latest_checkpoint)
print("step after restore:", int(step))

@tf.function
def train_step():
    with tf.GradientTape() as tape:
        loss = tf.reduce_mean((model(X) - y) ** 2)
    grads = tape.gradient(loss, model.trainable_variables)
    opt.apply_gradients(zip(grads, model.trainable_variables))
    step.assign_add(1)
    return loss

for _ in range(10):
    loss = train_step()
status.assert_consumed()                                     # every saved value found a home
print(f"continued to step {int(step)}, loss {float(loss):.5f}")
print("weights:", model.layers[0].kernel.numpy().ravel().round(3))
OUTPUT
latest: ckpt-50 step after restore: 50 continued to step 60, loss 0.01189 weights: [ 1.964 -1.003 0.441]
✅
Exactly Where We Left Off

The step counter continued from 50, and the loss is still tiny, so the learned weights came back. The optimizer's momentum was restored too. assert_consumed() checks that every saved value was matched to a variable. Use expect_partial() instead when you deliberately restore only part of a checkpoint (for example, just the model for inference).


Section 04

Look Inside a Checkpoint

for name, shape in tf.train.list_variables(manager.latest_checkpoint):
    if not name.startswith("_CHECKPOINTABLE") and "OBJECT_CONFIG" not in name:
        print(f"{name:70s} {shape}")
OUTPUT
optimizer/_iterations/.ATTRIBUTES/VARIABLE_VALUE [] optimizer/_learning_rate/.ATTRIBUTES/VARIABLE_VALUE [] optimizer/_trainable_variables/0/.ATTRIBUTES/VARIABLE_VALUE [3, 1] optimizer/_trainable_variables/1/.ATTRIBUTES/VARIABLE_VALUE [1] optimizer/_variables/2/.ATTRIBUTES/VARIABLE_VALUE [3, 1] optimizer/_variables/3/.ATTRIBUTES/VARIABLE_VALUE [1] save_counter/.ATTRIBUTES/VARIABLE_VALUE [] step/.ATTRIBUTES/VARIABLE_VALUE []

The names are paths through your objects. Each variable is stored once, under the first path TensorFlow finds. Here the Dense kernel [3, 1] and bias [1] show up as optimizer/_trainable_variables/0 and /1, because the optimizer also points to them. _variables/2 and /3 are the momentum slots, and step is our counter. Restore matches values to variables by this object structure, not by Python variable names.

The Standard Pattern: Restore If Possible

ckpt = tf.train.Checkpoint(model=model, optimizer=opt, step=step)
manager = tf.train.CheckpointManager(ckpt, "ckpts/run1", max_to_keep=5)

ckpt.restore(manager.latest_checkpoint)          # does nothing if there is none yet
print("starting at step", int(step))

while int(step) < total_steps:
    train_step()
    if int(step) % 500 == 0:
        manager.save(checkpoint_number=step)

Section 05

Try It — Crash and Resume Simulator

💾 Save Often, Keep Some, Survive Crashes Interactive

Set how often to save and how many checkpoints to keep, then press Train. Press ⚡ Crash! at any moment. You lose the work since the last save. Press Resume to restore the latest checkpoint and continue.

/ckpts on disk

log


Section 06

Checkpoint or SavedModel?

tf.train.Checkpointtf.saved_model.save / model.export
StoresVariable values onlyVariables and the computation graph (tf.functions)
Needs your Python code to load?Yes — rebuild the objects, then restoreNo — works in C++, TF Serving, LiteRT
Keeps optimizer stateYes (if you include it)Usually not needed
Best forResuming training, keeping the best epochDeploying the finished model
🏆
Combine With Early Stopping

Keep a second manager in a "best" folder with max_to_keep=1. Save to it only when validation loss improves. At the end, restore it — that is "restore best weights" that also survives a crash.


Section 07

Golden Rules

💾 Checkpoints — Rules to Remember
1
Put model, optimizer and a step counter in the Checkpoint. Leaving out the optimizer changes training after a resume.
2
Use CheckpointManager with max_to_keep so the disk does not fill up.
3
At start-up, always restore(manager.latest_checkpoint). It is safe when no checkpoint exists.
4
Rebuild objects with the same structure before restoring; names are object paths.
5
Checkpoints are for training. Export a SavedModel for deployment.
You have completed Data Pipelines and Good Training. View all sections →