3.3.7 · D2Deep Learning Frameworks

Visual walkthrough — Saving and loading models (checkpoints)

1,907 words9 min readBack to topic

Everything below is drawn on a chalkboard. Follow the coloured arrows — the pictures carry the argument; the words just point at them.


Step 1 — What a "parameter" and a "gradient" even are

WHAT. A neural network is just a big pile of numbers we can tune. Call any one of those tunable numbers (the Greek letter "theta" — read it as "the knob"). There are millions of them, but to see the idea we track just one.

Attached to the network is a loss — a single number that says "how wrong are you right now?" Big = very wrong. Our whole job is to turn the knob until is small.

WHY a gradient? We need to know which way to turn the knob. The tool that answers "if I nudge up a tiny bit, does the loss go up or down, and how steeply?" is the derivative, written

  • (the "nabla" symbol with a little ) means slope of the loss as this one knob changes.
  • is just a shorter name for that slope, the gradient.
  • If is positive, loss rises when rises → so we should decrease .
  • If is negative, we should increase .

We pick the derivative and not, say, the raw loss value, because the loss alone tells us "how bad" but never "which direction fixes it." Only slope encodes direction.

PICTURE. The board shows a valley (the loss curve). A ball sits on the slope; the arrow shows the downhill direction the gradient points to.

Figure — Saving and loading models (checkpoints)

Step 2 — Plain gradient descent, and its weakness

WHAT. Repeat the rule from Step 1 over and over:

  • is the step counter (step 1, 2, 3, …).
  • is the knob's old value; is the new value.
  • is the slope measured right now, at this step.
  • is the size and direction of the nudge.

WHY look closer? In a nice round bowl this works fine. But real loss surfaces are long narrow valleys — steep across, nearly flat along the bottom. Plain descent zig-zags: it bounces off the two steep walls and crawls along the useful direction. Each step's direction is decided only by the current slope, with no memory of where we were heading.

PICTURE. A narrow valley seen from above. The plain-descent path (pink) bounces wall to wall, making painfully slow progress toward the goal.

Figure — Saving and loading models (checkpoints)

Step 3 — Momentum: giving the ball memory

WHAT. Instead of stepping along the current slope, we step along a running average of past slopes. We invent a new quantity , the velocity, and update it each step:

Term by term:

  • — the velocity we already had (accumulated history).
  • (beta, the momentum coefficient, usually ) — how much of the old velocity we keep. Close to 1 = long memory.
  • — how much of the fresh slope we mix in. With that's only of the new gradient each step.
  • Second line: we now step along (the smoothed direction), not the raw .

WHY this tool? A running average cancels the sideways bouncing (those flips average to near zero) while adding up the consistent downhill direction (same sign every step → grows). It's exactly a ball with inertia rolling down: it ignores jitter and builds speed along the true slope.

PICTURE. Same narrow valley. The momentum path (blue) barely bounces — it flows smoothly down the trough, reaching the goal in far fewer steps than the pink zig-zag.

Figure — Saving and loading models (checkpoints)

Step 4 — The moment of the crash: what a "fresh optimizer" throws away

WHAT. You save a checkpoint but store only . Training crashes. You reload , but the optimizer is brand new, so its velocity resets:

The very next update, with , collapses back to plain gradient descent:

Notice the step is now only as long — for that's a tiny step, in the raw jittery direction, with no inherited momentum.

WHY it hurts. The ball was cruising fast down the valley; you froze its position but set its speed to zero. It has to laboriously build speed again from a standstill — and while it does, it re-enters the sideways zig-zag it had already escaped.

PICTURE. The blue momentum path is cruising; a red "X" marks the crash. On reload the ball restarts from rest (dashed red) — slow, hesitant, bouncing again, before it eventually rebuilds the smooth blue flow.

Figure — Saving and loading models (checkpoints)

Step 5 — Exactly how many steps you lose

WHAT. After reset, velocity is rebuilt by the recursion in Step 3. Unrolling it, the velocity is a weighted sum of the last many gradients with weights . The effective memory length — how many past steps meaningfully contribute — is

  • For : steps.
  • For : steps.

WHY this formula? The old contributions decay like . The velocity reaches a fixed fraction (about , i.e. ) of its full value after roughly steps — this is the momentum "warm-up time." Those are the steps you waste re-accelerating every time you resume without saved state.

PICTURE. A bar chart of how much each past gradient counts: tall bar for the newest, shrinking by each step back. The shaded region up to step holds the bulk of the weight — that's the memory you erased.

Figure — Saving and loading models (checkpoints)

Step 6 — Edge cases: when does the reset not hurt?

Cover every scenario so you never hit a surprise:

Case A — (no momentum at all). Then ; there is no history to lose. . Saving weights alone is perfectly fine. Plain SGD, plain safety.

Case B — Adam / RMSProp. These carry two running averages: (mean of gradients) and (mean of squared gradients, used to scale each knob's step). Losing is worse than losing plain momentum — the per-parameter step sizes are wrong until it rebuilds, and Adam's bias-correction counter resets too. Always save optimizer.state_dict() for Adam.

Case C — You've reached the valley floor already (). Then has already decayed toward zero on its own. Resetting it costs almost nothing — this is why inference-only exports (Example 2 in the parent) safely drop the optimizer: training is done, there's no motion left to preserve.

Case D — Fine-tuning / changing the learning-rate schedule. If you're deliberately restarting the schedule (see Learning Rate Schedules) or doing Transfer Learning on a new task, you sometimes want a fresh optimizer. Resetting is a choice, not an accident.

PICTURE. A 2×2 board: top-left "β=0 → safe", top-right "Adam → save both m and v", bottom-left "at minimum → harmless", bottom-right "new task → reset on purpose". A check or cross on each.

Figure — Saving and loading models (checkpoints)

The one-picture summary

Everything on one board: position vs. motion. Save both, and the ball resumes cruising. Save only position, and it restarts from rest, costing you warm-up steps.

Figure — Saving and loading models (checkpoints)
Recall Feynman retelling — say it out loud in plain words

Training is a ball rolling down a bumpy valley toward the lowest point. The ball's position is the model's weights . Plain gradient descent looks only at the slope right under its feet, so in a narrow valley it bounces uselessly off the walls. Momentum fixes this by giving the ball memory: it keeps a running average of recent slopes, called velocity , so the random side-to-side wobbles cancel out and the steady downhill direction adds up — the ball flows smoothly and fast.

Now the catch. A checkpoint that saves only the weights saves where the ball is but forgets that it was moving. When you reload, velocity resets to zero — the ball, which was cruising, suddenly starts from a dead stop. It has to spend about steps (ten steps for the usual ) rebuilding speed, bouncing off the walls again while it does. That's wasted training. The fix is one line: also save optimizer.state_dict(), which stores for every knob, so the ball resumes exactly at cruising speed. Exceptions: plain SGD () has nothing to lose, a finished model at the valley floor has already stopped, and sometimes for a new task you want to reset.

Practice recall:

Why isn't saving only the weights enough to resume training smoothly?
The weights are the ball's position, but the optimizer's velocity is its motion; dropping it restarts the ball from rest and wastes momentum warm-up.
For , how many steps to rebuild lost momentum?
About steps.
Which optimizer state does Adam carry that plain momentum doesn't?
Two running averages — the mean and the mean-of-squares (plus its bias-correction step counter).
When is resetting the optimizer actually harmless or desirable?
When (no memory), when training is finished at the valley floor (inference export), or when deliberately starting a new schedule / Transfer Learning task.