Long PyTorch training runs need more than final model weights when a job stops before the next epoch completes. A training checkpoint captures the model tensors, optimizer buffers, epoch position, and recent loss so training can continue from the saved state instead of restarting from random initialization.
PyTorch stores model and optimizer state through state_dict dictionaries, and torch.save serializes those dictionaries into one checkpoint file. Restoring requires new model and optimizer objects with the same structure before load_state_dict applies the saved tensors.
Use weights_only=True when loading a checkpoint that contains tensors, primitive values, and dictionaries from a trusted training run. Set map_location to the device that should receive the tensors during restore, then switch the restored model back to training mode before the next optimizer step.
Related: How to save and load a PyTorch model
Related: How to run a training loop in PyTorch
Steps to save and restore a PyTorch training checkpoint:
- Create a smoke script that trains once, saves a checkpoint, restores new objects, and resumes training.
- checkpoint_resume.py
import torch from torch import nn torch.manual_seed(7) checkpoint_path = "training-checkpoint.tar" def build_model(): return nn.Sequential( nn.Linear(3, 4), nn.ReLU(), nn.Linear(4, 1), ) x = torch.tensor( [ [0.1, 0.2, 0.3], [0.4, 0.5, 0.6], ], dtype=torch.float32, ) y = torch.tensor( [ [0.6], [1.5], ], dtype=torch.float32, ) loss_fn = nn.MSELoss() def train_step(model, optimizer): model.train() optimizer.zero_grad() loss = loss_fn(model(x), y) loss.backward() optimizer.step() return loss.item() model = build_model() optimizer = torch.optim.Adam(model.parameters(), lr=0.01) loss_before_save = train_step(model, optimizer) torch.save( { "epoch": 1, "model_state_dict": model.state_dict(), "optimizer_state_dict": optimizer.state_dict(), "loss": loss_before_save, }, checkpoint_path, ) print(f"saved epoch=1 loss={loss_before_save:.4f}") restored_model = build_model() restored_optimizer = torch.optim.Adam(restored_model.parameters(), lr=0.01) checkpoint = torch.load(checkpoint_path, map_location="cpu", weights_only=True) restored_model.load_state_dict(checkpoint["model_state_dict"]) restored_optimizer.load_state_dict(checkpoint["optimizer_state_dict"]) restored_model.train() state_match = all( torch.equal(model.state_dict()[name], restored_model.state_dict()[name]) for name in model.state_dict() ) optimizer_state_entries = len(restored_optimizer.state_dict()["state"]) next_epoch = checkpoint["epoch"] + 1 resumed_loss = train_step(restored_model, restored_optimizer) print(f"loaded keys={', '.join(checkpoint.keys())}") print(f"state_match={state_match}") print(f"optimizer_state_entries={optimizer_state_entries}") print(f"resume_epoch={next_epoch} previous_loss={checkpoint['loss']:.4f}") print(f"resumed_loss={resumed_loss:.4f}")
Build the restored model and optimizer with the same architecture and optimizer class that created the checkpoint. load_state_dict loads values into existing objects; it does not recreate the model class.
- Run the checkpoint smoke script.
$ python checkpoint_resume.py saved epoch=1 loss=0.7571 loaded keys=epoch, model_state_dict, optimizer_state_dict, loss state_match=True optimizer_state_entries=4 resume_epoch=2 previous_loss=0.7571 resumed_loss=0.7287
state_match=True confirms that the model tensors loaded into the new model object. optimizer_state_entries=4 confirms that the Adam buffers were restored before the resumed step.
- Save the same checkpoint fields after a completed training epoch in the real training loop.
torch.save( { "epoch": epoch, "model_state_dict": model.state_dict(), "optimizer_state_dict": optimizer.state_dict(), "loss": float(loss.item()), }, "training-checkpoint.tar", )
Store enough metadata to choose the next epoch and compare resumed training logs with the interrupted run.
- Restore the checkpoint before the next training loop starts.
model = build_model() optimizer = torch.optim.Adam(model.parameters(), lr=0.01) checkpoint = torch.load( "training-checkpoint.tar", map_location="cpu", weights_only=True, ) model.load_state_dict(checkpoint["model_state_dict"]) optimizer.load_state_dict(checkpoint["optimizer_state_dict"]) start_epoch = checkpoint["epoch"] + 1 model.train()
Load only checkpoint files from a trusted source. torch.load deserializes saved data; weights_only=True restricts loading to tensors, primitive values, dictionaries, and allowlisted safe globals.
- Remove the smoke-test files when the checkpoint pattern has been verified.
$ rm checkpoint_resume.py training-checkpoint.tar
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.