Concepts / Saving and Loading Model Checkpoints

Saving and Loading Model Checkpoints

Fine-tuning a saved GPT model starts by restoring two pieces of state: the model and the optimizer, both stored in one checkpoint file.

  • Programming

Why Training Gets Resumed

Training a large language model is a long process, and a training run does not always finish in one sitting. Training a GPT model is expensive, so you rarely want to throw away the work already done. Instead of treating every training session as a fresh start, the progress made so far can be stored and then picked up again later. This picking up is called fine-tuning a saved model: you continue training for more passes over the data, starting from a saved point rather than from scratch.

The source describes the whole job in one sentence: load the model and the optimizer that were saved in the main chapter. This article unpacks what that sentence requires, one piece at a time, and explains why the order of the steps matters. The central question is simple. When you stop training and come back later, what exactly has to survive the break, and what has to be restored before training can carry on from where it left off?

Following the Weights Through a Break

Saving is the act of writing the current weights to storage. Saving model weights stores the learned values of a model so that they can be used later. Loading is the reverse: reading previously saved weights back in, so the model starts from that stored state rather than from scratch. The source gives both operations the same purpose, which is to continue training an LLM.

The two operations work best when you think of them as a pair. A save without a later load stores the progress but never puts it back to work. A load is only meaningful when there is a saved set of weights to restore. The diagram below traces the weights through one full break in training, from their random starting values to one extra epoch after they have been restored.

Random initial valuesstarting point of a newmodelTrained weights atsave timelearned values afterearlier trainingSaved checkpointweights written to storageFreshly built modelstructure exists, valuesnot yet restoredRestored weightssaved values loaded intothe modelWeights after onemore epochtraining continued fromrestored statetrainingsavebuild modelload_state_dicttrain_simple_function
What is the weight state at save time, what is it after loading into a freshly built model, and how does it differ from a randomly initialized model?

The important comparison is between the restored weights and a randomly initialized model. A randomly initialized model starts with arbitrary values and has learned nothing yet. The restored model carries the values that were learned before the break. When training resumes from the restored state, it continues from the point where the saved weights left off rather than from those random initial values.

The Two Parts Inside One Checkpoint

A saved checkpoint holds two separate pieces of state, both stored together in one checkpoint file. The first is the state of the GPT model, which is its learned parameters. The second is the state of the optimizer, which in this workflow is torch.optim.AdamW. The optimizer keeps its own internal state alongside the model. Restoring only the model would leave the optimizer behaving as though it had never run, so the optimizer's saved state has to come back too.

The loading code reads the checkpoint into a single object using torch.load(). That object is a dictionary, and you pull two entries out of it by key. The key model_state_dict belongs to the model, and the key optimizer_state_dict belongs to the optimizer. These two keys are the whole contract between saving and loading. If something goes wrong when you resume, they are the first place to look.

Definition

Model state: the learned parameters of the GPT model, stored under the key model_state_dict. Optimizer state: the internal state of the AdamW optimizer, stored under the key optimizer_state_dict. Checkpoint: the single file that holds both of these together.

Matching Checkpoint Entries to Load Calls

Each entry must reach a specific destination, and one call cannot serve both. The entry model_state_dict feeds model.load_state_dict(), which fills the model. The entry optimizer_state_dict feeds optimizer.load_state_dict(), which fills the optimizer. The mapping is one entry to one call, and it is the wiring you need to hold in your head before reading any resume code.

model_state_dictlearned parameters of theGPT modelmodel.load_state_dict()fills the rebuilt modeloptimizer_state_dictinternal state of AdamWoptimizer.load_state_dict()fills the rebuilt optimizerfeedsfeeds
Which entry in the checkpoint file feeds which load call, and where would a key mismatch surface?

A mismatch shows up at the loading call that receives the wrong entry. If a key is wrong, or the entry does not match the object it is loaded into, the failure appears where that load call runs, not earlier in the script. That is why the two keys and the two load calls are the places to check first.

What do you think happens?

Which checkpoint entry should be passed to optimizer.load_state_dict()?

  • model_state_dict

  • optimizer_state_dict

  • Either entry works

Reveal answer
Answer:

optimizer_state_dict

The model entry belongs to the model and the optimizer entry belongs to the optimizer. Each entry must reach its own destination, so one call cannot serve both.

Rebuilding the Model and Optimizer First

The saved state is a set of values, not a running model. Something has to exist to receive those values. The loading sequence therefore creates a fresh GPTModel using the configuration named GPT_CONFIG_124M, and only then calls model.load_state_dict() with the model_state_dict entry. Creating the object first gives the loading call a structure to fill in.

The optimizer follows the same pattern. It is constructed first, as torch.optim.AdamW applied to the parameters of the freshly loaded model, with a learning rate of 5e-4 and a weight decay of 0.1. Only after that is optimizer.load_state_dict() called with the optimizer_state_dict entry. The order matters because the optimizer is built from the model's parameters, so the model must already exist at that point.

python
Notes on the code
  • torch.load() reads the whole checkpoint into one dictionary
  • The model is constructed before its saved values are loaded into it
  • The optimizer is built from the restored model's parameters, then given its saved state
  • Training resumes from the restored state for one more epoch
Checkpoint fileholds both saved entriesResume scriptruns the loading sequenceGPT modelbuilt from GPT_CONFIG_124MAdamW optimizerbuilt from model parameterstorch.load() reads checkpointconstruct GPTModelload_state_dict(model_state_dict)construct AdamWload_state_dict(optimizer_state_dict)train_simple_function(num_epochs=1)
In what order do the objects get constructed and populated, and why must the model and optimizer exist before their saved states are loaded into them?

Resuming a Run Step by Step

Worked example

Resuming Fine-Tuning from a Saved Checkpoint

A training run saved a checkpoint file holding model_state_dict and optimizer_state_dict. Describe the steps needed to continue training for one more epoch from that saved point.

  1. 1
    Read the checkpoint

    Call torch.load() to read the file into a single dictionary. Nothing is trained yet at this point.

  2. 2
    Rebuild the model

    Create a fresh GPTModel using GPT_CONFIG_124M. This gives the saved values a structure to fill.

  3. 3
    Restore the model

    Call model.load_state_dict() with the model_state_dict entry. The model now holds the learned parameters from the save.

  4. 4
    Rebuild the optimizer

    Create torch.optim.AdamW from the restored model's parameters, with learning rate 5e-4 and weight decay 0.1.

  5. 5
    Restore the optimizer

    Call optimizer.load_state_dict() with the optimizer_state_dict entry, so the optimizer keeps its internal state.

  6. 6
    Continue training

    Call train_simple_function with num_epochs=1. Training starts from the restored state, not from random initial values.

Result

The model and the optimizer both begin from their saved states, so one additional epoch of training picks up where the earlier run stopped.

Training One More Epoch

Once the model and optimizer are restored, the final step is to continue training. The source calls for train_simple_function with num_epochs=1. That single call trains the model for another epoch, starting from the restored state. Over that one epoch, the weights are updated from their starting values, which are the restored values, toward whatever values the continued training produces at its end.

Mistakes That Make a Resumed Run Start Over

  • Common mistake

    Restoring only the model and skipping the optimizer

    What it looks like

    The script calls model.load_state_dict() with model_state_dict but never calls optimizer.load_state_dict().

    Why it fails

    The optimizer keeps its own internal state alongside the model. Without its saved state, the optimizer behaves as though it had never run.

    Do this instead

    Restore both entries: model_state_dict into the model and optimizer_state_dict into the optimizer.

  • Common mistake

    Loading a state into an object that has not been built yet

    What it looks like

    The script tries to load the saved values before creating the GPTModel or the optimizer.

    Why it fails

    The saved state is a set of values, not a running model, so nothing exists yet to receive them.

    Do this instead

    Construct the GPTModel from GPT_CONFIG_124M first, then load model_state_dict, then construct the optimizer and load optimizer_state_dict.

  • Common mistake

    Building the optimizer before the model exists

    Why it fails

    The optimizer is created from the parameters of the freshly loaded model, so the model must already exist.

    Do this instead

    Build the model first, load its state, and only then create torch.optim.AdamW from model.parameters().

  • Common mistake

    Swapping the two checkpoint entries

    What it looks like
    Passing optimizer_state_dict to model.load_state_dict() and model_state_dict to optimizer.load_state_dict().
    Why it fails

    Each entry must reach its own destination, and one call cannot serve both.

    Do this instead
    Map model_state_dict to model.load_state_dict() and optimizer_state_dict to optimizer.load_state_dict().
  • Common mistake

    Saving the weights without ever loading them back, so the stored progress is never put to work

AspectCorrectly resumed runRun with weights or optimizer not restored
Model weightsStart from the saved learned valuesStart from fresh or random initial values
OptimizerKeeps its saved internal stateBehaves as though it had never run
Training behaviorContinues from the point where the earlier run stoppedBehaves as if training started over
Load orderModel and optimizer are built before their states are loadedA state is loaded before its object exists, or a piece is skipped

What differs between a correctly resumed run and one where state was not restored

Practice Resuming Fine-Tuning

MEDIUM

A colleague saved a checkpoint with model_state_dict and optimizer_state_dict. Write the resume sequence that rebuilds the GPT model from GPT_CONFIG_124M, restores the model, builds the AdamW optimizer with learning rate 5e-4 and weight decay 0.1, restores the optimizer, and then trains for one additional epoch. Say which checkpoint entry feeds each load call.

Hints
  • Start with torch.load() to read the checkpoint into one dictionary.
  • Construct the GPT model before calling load_state_dict on it.
  • Build the AdamW optimizer from the restored model's parameters before loading its state.
  • The training call uses num_epochs=1.

Key Takeaways

  • A checkpoint holds two pieces of state, the model and the optimizer, and both must be restored before training continues.
  • The checkpoint is read with torch.load(). The model_state_dict entry feeds model.load_state_dict(), and the optimizer_state_dict entry feeds optimizer.load_state_dict().
  • The model is rebuilt from GPT_CONFIG_124M and the AdamW optimizer is built from its parameters before their saved states are loaded, because a saved state is a set of values that needs an object to fill.
  • Saving stores learned weights and loading reads them back, and the two work as a pair. Training then continues with train_simple_function and num_epochs=1 from the restored state.

Related concepts

More concepts starting with S