PythiloLesson 14 of 18 · progress kept in this browser

Checkpoints and early stopping

The model to keep is the one from the epoch with the lowest validation loss, not the last one. Early stopping watches that loss, remembers the best weights, and stops once patience epochs in a row have not beaten it.

Remembering needs a real copy. state_dict() returns the live parameter tensors, which the next optimizer step changes in place:

import copy
import torch
from torch import nn

model = nn.Linear(2, 1)
alias = model.state_dict()
best = copy.deepcopy(model.state_dict())
with torch.no_grad():
    model.weight.fill_(5.0)
print(alias["weight"])  # 5s: it moved
print(best["weight"])  # the old values
model.load_state_dict(best)

To resume training later, save a checkpoint: one dictionary with the model's state, the optimizer's state, which for Adam holds running averages a restart would lose, and the epoch number.

import torch
from torch import nn

model = nn.Linear(2, 1)
opt = torch.optim.Adam(model.parameters())
torch.save({"model": model.state_dict(),
            "optimizer": opt.state_dict(),
            "epoch": 7}, "checkpoint.pt")
saved = torch.load("checkpoint.pt")
opt.load_state_dict(saved["optimizer"])
print(saved["epoch"])
Your task

Write early_stopping(model, step, val_loss, patience, max_epochs=100): each epoch call step() then val_loss(), stop after patience epochs in a row without a new lowest loss, load the best epoch's weights back into model, and return that epoch's number, counting from 0. Write save_checkpoint(path, model, optimizer, epoch) and load_checkpoint(path, model, optimizer), which restores both states and returns the epoch.

This lesson uses torch, which Python in this browser does not include. Read it here, and run and check it in the Pythilo app on iPhone or iPad.

Next: Convolutions