Concepts / Introduction to the AdamW Optimizer

Introduction to the AdamW Optimizer

Adaptive optimizers such as AdamW store additional parameters for each model weight, and that data is separate from the weights themselves.

  • Programming

The Belief That Weights Are Enough

When people first save a trained model, they often treat it as a single object: the numbers that make up the weights. The reasoning goes that if those numbers are written to disk and read back later, training can pick up exactly where it stopped. This belief feels natural, because the weights are what the model learned. It is also incomplete, and the gap matters most when the optimizer is an adaptive one such as AdamW.

This article is built around that belief. You will first see what goes wrong when the optimizer is left out of a checkpoint, then follow the code that saves and restores both pieces, and finally use the same reasoning to find the point where a resumed run stops matching the original.

What AdamW Keeps Beyond the Weights

Adaptive optimizers such as AdamW do not treat every update the same way with a fixed rule. They use historical data to adjust the learning rate for each model parameter dynamically. To make that possible, AdamW stores additional parameters for each model weight. Those parameters belong to the optimizer, not to the model's weights, and that separation is exactly why saving the model alone is not enough.

weight tensor Wmodel parameteroptimizer state for Wper-weight valuesbias tensor bmodel parameteroptimizer state for bper-weight valuesbelongs tobelongs to
For each weight tensor in the model, which optimizer values belong to it, and where do those values live?

The diagram shows the key idea. Each weight tensor has its own companion values held by the optimizer. The weights and those companion values are separate objects, so the model's state dictionary does not contain them. Read the diagram as two columns that are linked weight by weight: the left column is what the model learned, and the right column is what the optimizer has accumulated about how each weight has been changing.

What a Reset Optimizer Does to Training

The source is direct about the consequence. If the optimizer state is not saved, the optimizer resets on restart. The model may then learn suboptimally, or even fail to converge properly. The source describes that failure in strong terms, noting that the model may lose the ability to generate coherent text.

The misconception this article targets is the assumption that a reset optimizer is harmless because the weights were preserved. The weights tell the resumed run where the model stands. The optimizer's saved history tells the run how it has been moving. A fresh optimizer starts with no such history, so the answer to the prediction question is no: the new optimizer does not behave as though it has seen the earlier training. Its updates are built from nothing, even though the model is already partway through learning.

Saving Both States into One File

PyTorch lets you save the model and the optimizer together. The model contributes its state_dict, and the optimizer contributes its own state_dict. Both are placed in one dictionary under two keys, and that dictionary is written to a single file with torch.save. The keys are names you choose; what matters is that the restore step later uses the same names.

python
Notes on the code
  • The optimizer is built from model.parameters(), so the model must exist first
  • Two state dictionaries are placed under two keys in one dictionary
  • torch.save writes that single dictionary to one file named checkpoint.pt

Notice what this does and does not do. It does not save the training loop, the data loader, or the code that defines the model. It saves the two state dictionaries, and only those, into the file named in the call. Restoring a run later depends entirely on what this one file contains.

model state dictweightscheckpoint dictionarytwo keyscheckpoint.ptsingle filecheckpoint dictionaryread back by torch.loadnew modelreceives weightsoptimizer statedictper-weight valuesnew AdamW optimizerreceives optimizer statekey model_statekey optimizer_statetorch.savetorch.loadmodel_stateoptimizer_state
How do the model's weights and the optimizer's state flow into one saved file, and how are they separated again on load?

Restoring in the Correct Order

Restoring is a two-stage operation. First the saved file is read back into memory with torch.load. Then the pieces are applied to freshly created objects with load_state_dict. The file itself does not reconnect to any live model or optimizer. That connection is made by you, in code, and the order of the steps matters.

python
Notes on the code
  • torch.load reads the file into memory as a dictionary
  • The model is created before the optimizer, because the optimizer needs model.parameters()
  • Each load_state_dict call is applied only after the matching object exists
  • The optimizer restore is the step a resumed run most easily loses
restore scriptyour codecheckpoint.ptsaved filenew modelcreated firstnew AdamW optimizerneeds model parameters1. torch.load reads dictionary2. create model3. create optimizer from model.parameters()4. model.load_state_dict(model_state)5. optimizer.load_state_dict(optimizer_state)
In what order must the file, the model, and the optimizer be touched during a restore, and which step is the first place a resumed run can stop matching the original?

Read the sequence as a chain of dependencies. The file can be read at any point, but the two load_state_dict calls cannot run until the objects they apply to exist. The optimizer is created after the model's parameters exist, because its constructor needs model.parameters(). Its saved state is applied only after the optimizer itself has been built. Each step depends on a matching object already being in place.

Finding Where a Resumed Run Diverges

To locate a divergence, walk the restore sequence one step at a time and ask what the resumed run now holds that the original run also held. The first step where the resumed state stops matching the original is the place to look. In the sequence above, the weights are restored at step 4, but if step 5 is missing, the run has correct weights and a fresh optimizer. That mismatch is the divergence, and it appears before any training step runs.

A useful tool for this is inspecting what the checkpoint actually holds. The keys below are the ones used in the save example, so the check confirms whether the optimizer entry is really in the file before you blame the restore code.

python
Notes on the code
  • Lists the top-level keys stored in the file
  • Confirms the model entry exists
  • Confirms the optimizer entry exists, which is the entry a resumed run most often ignores
  • Common mistake

    Saving only the model's state_dict

    What it looks like
    torch.save(model.state_dict(), 'checkpoint.pt')
    Why it fails

    The file then holds the weights but none of the optimizer's per-weight history, so the resumed optimizer starts from nothing.

    Do this instead

    Save a dictionary that holds both the model state dictionary and the optimizer state dictionary under two keys.

  • Common mistake

    Restoring the model and assuming the run has resumed

    What it looks like
    model.load_state_dict(checkpoint['model_state'])  with no optimizer load afterwards
    Why it fails

    A clean load does not show that the optimizer was restored. The source says a reset optimizer can leave the model learning suboptimally or failing to converge.

    Do this instead

    Apply the optimizer's saved state with optimizer.load_state_dict after the optimizer has been created.

  • Common mistake

    Trying to apply optimizer state before the optimizer exists

    Why it fails

    Each load_state_dict call depends on a matching object already being in place, and the optimizer is created from model.parameters().

    Do this instead

    Create the model, then create the optimizer from its parameters, then apply both saved states.

  • Common mistake

    Changing key names between save and restore

    Why it fails

    The restore code reads entries by key. If the names do not match, the lookup fails or the wrong entry is used.

    Do this instead

    Use the same key names in the save and restore code, and check them with a keys inspection when a restore misbehaves.

Diagnosing a Resume Script

python
Notes on the code
  • The file is read first
  • The model and optimizer are created in dependency order
  • Only the model's saved state is applied in this script
MEDIUM

A resumed run produces noticeably different updates from the original run, even though the model weights loaded without error. Using the order of operations from the restore example, identify the single line most likely responsible for this script's behavior. Explain your reasoning in terms of what the optimizer is missing.

Hints
  • Compare this script with the restore sequence: which of the five numbered steps is not present here?
  • Ask what the new AdamW optimizer holds at the moment training continues, and where that history was saved in the checkpoint.
  • A successful model load confirms only the weights; it does not restore the optimizer entry.

Key Takeaways

  • AdamW keeps additional per-weight parameters that belong to the optimizer and are separate from the model's weights, so saving the model alone does not capture the training history.
  • If the optimizer state is not saved, the optimizer resets on restart, which the source says can leave the model learning suboptimally or failing to converge.
  • torch.save can write the model's state_dict and the optimizer's state_dict into one dictionary under two keys, saved to a single file.
  • A restore reads the file with torch.load, creates the model and then the optimizer, and applies each saved state with load_state_dict in that order.
  • To find a divergence, walk the restore sequence step by step; the first step where the resumed state stops matching the original is the point to fix.

Related concepts

More concepts starting with I