Concepts / Saving a PyTorch Model

Saving a PyTorch Model

torch.save(model.state_dict(), file_name) writes a model's state dictionary to a .pth file, so the fine-tuned model can be reused later.

  • Programming

Why Learned Values Need a File

After fine-tuning, a model's learned values exist only while the program is running. Once the program ends, those values are gone unless they were written to a file. Saving is the final step of the fine-tuning workflow: the fine-tuned model is written to disk so it can be reused in future projects, and loaded back into a program later.

This article follows one save and one load from start to finish. As you read, trace each line and notice which value it produces before the next line uses it. Most save and load errors come from a step that used a value the previous step did not produce in the form expected.

Tracing the Save Line by Line

The saving work happens in one call: torch.save(model.state_dict(), file_name). The first argument, model.state_dict(), gives the model's state dictionary. The second argument, file_name, is a string that names the file on disk. The model is saved as a .pth file. The file name is computed on the line before the save, so the name is already fixed before torch.save runs.

model in memorymodel.state_dict()state dictionarytorch.savegpt2-medium355M-sft.pthfile on diskfile_namestring computed earliermodel objectremains in memorytake state dictunchangedfirst argumentsecond argumentwrites to
What moves from the model in memory to the .pth file on disk, and what stays behind?

The diagram shows that the state dictionary is taken from the model, handed to torch.save, and written to the file named by file_name. The model object itself is not what gets written; the save operates on the state dictionary. The file name is the only thing that determines where the output goes, so a wrong file name produces a file with the wrong name rather than a missing save.

Building the File Name from a Model Name

The file name is not typed by hand. It is generated from the chosen model name. The code takes CHOOSE_MODEL, removes every space, opening parenthesis, and closing parenthesis using re.sub with the pattern [ ()], and then appends the suffix -sft.pth. The result for the course model is gpt2-medium355M-sft.pth.

python
Output (expected)
gpt2-medium355M-sft.pth
Notes on the code
  • re.sub replaces every character matched by the pattern [ ()] with an empty string
  • The pattern matches a space, an opening parenthesis, or a closing parenthesis
  • The suffix -sft.pth is appended after the cleaned model name
Worked example

Tracing the name from CHOOSE_MODEL

CHOOSE_MODEL is "gpt2-medium (355M)". What string does file_name hold before torch.save runs?

  1. 1
    Start with the model name

    The raw string is gpt2-medium (355M), which contains a hyphen, a space, an opening parenthesis, and a closing parenthesis.

  2. 2
    Remove spaces and parentheses

    The space before the parenthesis is removed, along with both parentheses. The hyphen is not in the pattern, so it stays. The result is gpt2-medium355M.

  3. 3
    Append the suffix

    The string -sft.pth is added to the end, giving gpt2-medium355M-sft.pth.

Result

file_name holds gpt2-medium355M-sft.pth, and torch.save writes the state dictionary to a file with that name.

The State Dictionary as a Key-Value Mapping

A state dictionary is a mapping. Each entry pairs a name with a value, so you can look up a stored value by its name. When torch.save writes the state dictionary, the names and the values are both written to the file. When the file is read back, load_state_dict uses those names to decide which saved value belongs to which place in the model.

state dictweightnametensor of valuesstored numbersbiasnametensor of valuesstored numberscontains keycontains keymaps tomaps to
How does a state dict map each parameter name to its tensor, and why do names have to match between the saved file and the model?

The example keys weight and bias are illustrative. The important point is structural: every name in the saved mapping must correspond to a place in the model that receives a value. If the names in the file do not match the names expected by the model, the saved values cannot be placed correctly. This is why the same model structure has to be used on both sides of the save and load.

Model Object Versus State Dictionary

The call saves model.state_dict(), not the model object. These are different things, and the difference determines what the .pth file contains and what you must have ready when you load it.

AspectModel objectState dictionary
What it isThe live model in the running programA mapping from names to learned values
Written by torch.save hereNoYes, via model.state_dict()
Needed to receive loaded valuesYes, load_state_dict is called on itProduced by torch.load and passed in
Survives program endNo, unless written to a fileYes, once saved to the .pth file

Comparing the live model with the state dictionary that this save writes

Loading Values Back into a Model

Loading runs in the opposite direction to saving. The file is read by torch.load, the resulting state dictionary is passed to load_state_dict, and the model receives the saved values. The saved model can be loaded later with the following call, which uses the same file name that the save produced.

python
Notes on the code
  • torch.load reads the file and returns the saved state dictionary
  • load_state_dict is called on the model object and receives that dictionary
  • The string must match the file name produced by the save step
saved .pth filetorch.loadstate dictload_state_dictmodel1. read file2. returns state dict3. passed as argument4. copies saved values in
What is the order of steps from the .pth file to the populated model, and what does each step produce?

Read the sequence in order. The file produces nothing until torch.load reads it. Its output is a state dictionary, and that dictionary is what load_state_dict receives. Only at the final step does the model's own storage change. If you reverse any two of these steps, the program is describing a different operation than the one the source intends.

Where Save and Load Go Wrong

When a save or load fails, trace the file name first. Both steps must use the same generated string, so a mismatch is the most common cause of a broken load. Work through the checks below in order.

  • Common mistake

    Loading with a file name that was typed by hand and does not match the generated name

    What it looks like

    The save wrote gpt2-medium355M-sft.pth, but the load asks for gpt2-medium-355M-sft.pth

    Why it fails

    The two steps must agree on the same string, and a different spelling points at a file that does not exist

    Do this instead

    Print file_name right before the save and copy that exact string into the load step, or reuse the variable

  • Common mistake

    Passing the model object where the state dictionary is expected, or the reverse

    What it looks like
    model.load_state_dict(model) instead of model.load_state_dict(torch.load(...))
    Why it fails

    load_state_dict expects a state dictionary as its argument, not a model

    Do this instead

    Pass the result of torch.load as the argument to load_state_dict, which is called on the model

  • Common mistake

    Calling load_state_dict on the file path or on torch.load

    What it looks like
    torch.load("gpt2-medium355M-sft.pth").load_state_dict(model)
    Why it fails

    load_state_dict is a method of the model object; the loaded result is a dictionary, not a model

    Do this instead

    Call model.load_state_dict(...) with the loaded dictionary as its argument

  • Common mistake

    Assuming a wrong file name causes a missing save

    What it looks like

    The program runs without error, but the file on disk has an unexpected name

    Why it fails

    The file name alone decides where the output goes, so a wrong name still produces a file, just under the wrong name

    Do this instead

    List the directory after saving and check that the expected .pth file appears

Predict the File Name

What do you think happens?

CHOOSE_MODEL is "Llama 2 (7B)". What file name does the generation step produce?

Reveal answer
Answer:

Llama27B-sft.pth

The space and both parentheses are removed by the pattern [ ()], which leaves Llama27B. The suffix -sft.pth is then appended.

EASY

Take the model name "my model (v2)" and work out the file name step by step. Then write the matching torch.load call for a model object named model. Check that your string is the same in both the save step and the load step.

Hints
  • Remove the spaces and both parentheses first
  • The hyphen, if present, is not in the removal pattern
  • The load call must use the exact string produced by the save

Key Takeaways

  • torch.save(model.state_dict(), file_name) writes a model's state dictionary to a .pth file, so learned values survive after the program ends
  • The file name is generated from CHOOSE_MODEL by removing spaces and parentheses and appending -sft.pth, producing names such as gpt2-medium355M-sft.pth
  • A state dictionary maps names to values, and load_state_dict uses those names to place saved values into the model
  • Loading reverses the flow: torch.load reads the file, and model.load_state_dict applies the returned values to the model
  • When a save or load fails, trace the file name first, because both steps must use the same generated string

Related concepts

More concepts starting with S