Concepts / Saving a GPT Model and Optimizer Checkpoint

Saving a GPT Model and Optimizer Checkpoint

Loading a GPT model and optimizer from a checkpoint is a two-part act: the program constructs live objects first, then attaches saved entries to them by key.

  • Programming

Why Save a Training State

Training a language model produces state that is worth keeping. The model's learned values change as training runs, and the optimizer's bookkeeping changes with them. A practical workflow therefore saves both to a file and reads them back later, instead of retraining from nothing each time.

This article starts from that saved file. The task is to rebuild a GPT model and its optimizer from a checkpoint, and then to compute loss values on the training data and on the validation data. The approach is code first: you read the loading steps as a trace, predict what each step produces, and then check your prediction against the explanation.

What do you think happens?

Before reading further, predict: if you could only load one thing from the checkpoint, which would you need to restore a model that can keep training, and why?

  • The model weights only

  • The optimizer state only

  • Both the model entries and the optimizer entries

Reveal answer
Answer:

Both the model entries and the optimizer entries

The source saves the model's learned values and the optimizer's bookkeeping together, because both change as training runs. Restoring only one of them leaves the other part of the training state missing.

Reading the Checkpoint File

The loading procedure uses five statements, and each one either reads from the checkpoint, builds an object, or attaches saved values to an object. Knowing which of the three a line does is the key to finding where a run goes wrong. Here is the sequence in order.

  1. 1
    Read the checkpoint file named model_and_optimizer.pth. This is a read step: the file on disk becomes a Python object.
  2. 2
    Construct a GPT model from the configuration called GPT_CONFIG_124M. This is a build step: a live model object now exists.
  3. 3
    Load saved values into that model. This is an attach step: entries from the checkpoint are poured into the model object.
  4. 4
    Construct an AdamW optimizer over the model's parameters. This is a build step: a live optimizer object now exists.
  5. 5
    Load saved values into the optimizer. This is an attach step: entries from the checkpoint are poured into the optimizer object.

The source describes the loading code as a flow of values. A file on disk is read into a Python object. That object holds saved entries under named keys. Two of those entries are then used to fill in two live objects, the model and the optimizer. The checkpoint is not the model, and the model is not the optimizer. The file is a container of named entries; the live objects are what the program builds and then fills.

Mapping Keys to Live Objects

The saved object holds two entries that matter for this procedure. The entry under model_state_dict feeds the GPT model, and the entry under optimizer_state_dict feeds the AdamW optimizer. Each key selects one saved group of values, and each group goes into exactly one live object.

model_and_optimizer.pthcheckpoint read into aPython objectmodel_state_dictsaved model entriesGPT modelbuilt from GPT_CONFIG_124Moptimizer_state_dictsaved optimizer entriesAdamW optimizerbuilt overmodel.parameters()keykeyloaded intoloaded into
Which saved key holds the model weights and which holds the optimizer state, and which live object gets each one?

Read the diagram from top to bottom. The file is the single source. Two keys pull two different groups out of it. Each group lands in a different live object. Nothing in the diagram crosses over: the model entries never go to the optimizer, and the optimizer entries never go to the model.

Why Build Before Loading

Loading is a two-part act. First, the program constructs a live object. Second, a saved entry is poured into that object. The order matters. The source calls load_state_dict on an object that already exists, so the object has to be built before any saved state can be attached to it.

Read checkpointmodel_and_optimizer.pthBuild GPT modelGPT_CONFIG_124MLoad model statemodel_state_dictBuild AdamW optimizerover model.parameters()Load optimizer stateoptimizer_state_dictthenthenthenthen
Why must the model and AdamW optimizer be created first, and what breaks if the saved state is loaded before they exist?

Notice that the optimizer is built over model.parameters(), so the model must already exist before the optimizer can be constructed from it. The optimizer's saved state is then loaded last, after the optimizer object is in place.

Computing Train and Validation Loss

Once the model is restored, the source calculates two loss values for the GPT model: one for the training set and one for the validation set. Both are computed with a custom function named calc_loss_loader. The function is called twice, with the same model and the same device. Only the data loader changes between the two calls.

Shared model anddeviceheld fixed across bothcallstrain loadertraining datacalc_loss_loader call1train_lossval loadervalidation datacalc_loss_loader call2val_lossmodel and devicemodel and deviceloader argumentloader argumentreturnsreturns
How does one loss function receive two different data loaders and produce two separate loss values?

Because the model and device are held fixed, any difference between train_loss and val_loss comes from the data each call was given, not from a different model or a different device. The two values are separate results of the same function applied to two different inputs.

Worked example

Tracing the two loss calls

Given a restored model, a device, a training loader, and a validation loader, show how the two loss values are produced.

  1. 1
    Fix the shared inputs

    The model and device are passed to both calls unchanged. Nothing about them differs between the two calls.

  2. 2
    Call with the training loader

    The first call to calc_loss_loader receives the training loader. Its result is the training loss.

  3. 3
    Call with the validation loader

    The second call receives the validation loader. Its result is the validation loss.

  4. 4
    Attach each result to its label

    The first returned value is labeled train_loss and the second is labeled val_loss. The labels depend only on which loader each call received.

Result

Two loss values, train_loss and val_loss, that differ only because the loader argument differs.

Finding Where a Run Goes Wrong

A run can fail in the loading path or in the loss-calculation path. The source points to specific checks that narrow the search. Work through the lines in order and ask, for each one, whether it reads, builds, or attaches.

  • Common mistake

    Swapping the two loader arguments

    What it looks like

    Passing the validation loader to the first calc_loss_loader call and the training loader to the second.

    Why it fails

    The code still runs without complaint, but the two results end up attached to the wrong label.

    Do this instead

    Check the loader argument of each call first. Confirm that the training loss comes from the training loader and the validation loss from the validation loader.

  • Common mistake

    Loading saved state before the object exists

    What it looks like

    Calling the optimizer load step before the AdamW optimizer has been constructed over the model's parameters.

    Why it fails

    load_state_dict is called on an existing object. Before construction there is no optimizer object to receive the saved entries.

    Do this instead

    Keep the build-then-attach order: construct the model, load its state, construct the optimizer, then load the optimizer state.

  • Common mistake

    Treating the checkpoint as the model

    What it looks like

    Assuming that reading model_and_optimizer.pth has already produced a working GPT model.

    Why it fails

    The file is a container of named entries. The live model is a separate object built by the program.

    Do this instead

    Remember that a live object is constructed first and a saved entry is then poured into it.

  • Common mistake

    Changing the model or device between the two loss calls

    What it looks like

    Restoring a different model for the validation call than for the training call.

    Why it fails

    The source holds the model and device fixed, so a difference in results would no longer be attributable to the data alone.

    Do this instead

    Use the same model and device in both calls and vary only the loader.

Practice Tracing the Restore

MEDIUM

A colleague's restore run completes the file read and the GPT model build, then fails on the attach step for the optimizer. Using the five-step order, name the step that most likely went wrong first, and explain what the correct order would have required before that step could succeed.

Hints
  • Count the steps in order: read, build model, load model, build optimizer, load optimizer.
  • Ask which object the failing step is trying to attach saved entries to, and whether that object was built yet.
EASY

Two loss values come back from a run, and they are the same number. List the inputs you would check first, and state which of them could explain the result without any change to the model or device.

Hints
  • Recall that the model and device are fixed across both calls.
  • Check which loader was passed to each call.

Key Takeaways

  • A checkpoint is a file read into a Python object that holds saved entries under named keys, not the model or optimizer itself.
  • The GPT model is built from GPT_CONFIG_124M and loaded from model_state_dict, while the AdamW optimizer is built over model.parameters() and loaded from optimizer_state_dict.
  • Loading is a two-part act: construct the live object first, then attach saved entries to it, because load_state_dict is called on an existing object.
  • Training and validation losses come from two calls to calc_loss_loader that share the same model and device and differ only in the loader passed, so a swapped loader is the most common silent error.

Related concepts

More concepts starting with S