0Training is navigation
Training a neural network is an exercise in navigation. You are dropped into a massive, foggy landscape with millions of valleys and ridges, and your only goal is to find the lowest point, the absolute minimum loss. How you choose to take your steps matters just as much as where you are trying to go.
To appreciate why modern networks train successfully at all, we have to look closely at the mathematical memory that drives them: the optimizer state.
1Why vanilla SGD fails
In the early days of deep learning, models relied on vanilla stochastic gradient descent (SGD). It is a purely reactive algorithm. It looks at the slope right under its feet, takes a step down that slope, and immediately forgets everything else.
The formula is entirely memoryless:
Where θ represents the model weights, η is the learning rate, and ∇t is the gradient, the current slope.
The ravine problem
Imagine a landscape that looks like a long, narrow canyon. The floor slopes very gently toward the exit (the true minimum), but the walls of the canyon are incredibly steep. Drop a vanilla SGD optimizer into this canyon and here is what happens:
- It calculates the gradient. The slope pointing down the steep canyon walls is massive compared to the gentle slope leading toward the exit.
- SGD takes a massive step based on that steep slope. It violently hurtles across the canyon floor and smashes into the opposite wall.
- On the next step, it sees a massive slope pointing back the other way. It bounds across the floor again.
Because SGD has no memory of its past trajectory, it spends all its energy oscillating wildly between the canyon walls. It makes almost zero progress down the length of the canyon toward the exit. In complex modern AI models, this exact behavior causes training to stall out completely.1
LessonA memoryless optimizer pays for every oscillation twice: once in wasted motion across the canyon, once in progress never made along it.
2AdamW: the optimizer with history
To solve this lack of awareness, modern training relies on AdamW, Adam with decoupled weight decay. AdamW succeeds because it keeps records. For every single parameter in your model, the optimizer state tracks historical statistics and creates a custom, adaptive update using two historical metrics: the first momentum and the second momentum.2
| Record | Job | Precision | Bytes |
|---|---|---|---|
| Weights θ | what gets updated | bf16 / fp16 | 2 |
| First moment mt | smoothed direction | fp32 | 4 |
| Second moment vt | smoothed volatility | fp32 | 4 |
| Master weight copy | full-precision target for tiny updates | fp32 | 4 |
3The mechanics of first and second momentum
The core of the optimizer state consists of two vectors that act as filters for the noisy gradients generated during training.
The first momentum (mt): the direction manager
The first momentum tracks the directional trend of the gradients over time. It functions exactly like physical momentum:
- The work: it acts as an exponential moving average. If the gradient points in the same direction for several steps, the optimizer speeds up. If the gradient starts oscillating back and forth (like bouncing off canyon walls), the opposing signs cancel each other out in the running average.
- The result: it flattens noisy, erratic bounces and keeps the model pushing steadily along the true path.
The second momentum (vt): the scale manager
The second momentum tracks the volatility, or the sheer variance, of the gradients for each parameter:
- The work: by squaring the gradient, the optimizer strips away the directional sign and focuses purely on magnitude.
- The result: it acts as an automatic speed regulator. The final update divides the step by √vt. A wildly volatile parameter with massive gradients gets divided by a large √vt, shrinking its step to keep it safe. A parameter with tiny, rare gradients gets divided by a tiny √vt, boosting its step so it does not get left behind. This is what makes the learning rate adaptive.
4Bias correction and the full update
Because mt and vt are initialized at zero, the early estimates are artificially pulled toward zero. Bias correction compensates:
As t grows large, β1t → 0 and β2t → 0, so the corrections fade and the estimates converge to their true values. In the early steps, however, they provide an essential rescaling that prevents the optimizer from taking negligibly small steps at the start of training.3
The full update rule
Combine the direction manager and the scale manager and you get the unified mathematical step that updates the weights:
- η is your global learning rate.
- m̂t/(√v̂t + ε) is the bias-corrected adaptive step: the smoothed direction divided by the smoothed volatility scale. The tiny constant ε prevents division by zero.
- ηλθt is the decoupled weight decay term, the W in AdamW. Crucially, it is applied as a separate subtraction, not folded inside the adaptive fraction. In vanilla Adam, L2 regularization is mixed into the gradient before the adaptive scaling, which makes the effective decay rate vary per parameter. AdamW decouples it entirely, so every weight decays at a uniform, predictable rate regardless of its gradient history.
opt = torch.optim.AdamW(model.parameters(), lr=1e-3,
betas=(0.9, 0.999), weight_decay=0.01) # defaults
LessonAn optimizer is a tiny database with an update policy. What it remembers (direction, volatility) decides how it moves; make sure you know which memories your training run is paying for.
5FP32 master weights in mixed precision
When scaling up large language models, storing everything in 32-bit floating-point numbers (FP32) consumes too much GPU memory. Mixed-precision training runs the active forward and backward passes in 16-bit brain floats (BF16) or half-precision floats (FP16).
This introduces a massive problem called underflow. Because 16-bit floats have limited precision, they cannot represent incredibly small numbers. During an update, the step size is often a tiny fraction. Subtracting a tiny 16-bit fraction from a 16-bit weight rounds that fraction down to absolute zero. The weight never changes, and the model stops learning.4
The solution: the FP32 master weight copy
To bypass underflow, the optimizer state holds a hidden, full-precision FP32 copy of all the model weights:
- The model does its fast calculations in 16-bit to save memory.
- The gradients are computed and passed to the optimizer.
- The optimizer calculates the first and second moments.
- The resulting tiny update step is applied directly to the FP32 master weights. Full 32-bit precision preserves the tiny numbers instead of rounding them to zero.
- The freshly updated FP32 weights are cast back down to 16-bit for the next round of training.
LessonPrecision is a budget. Spend 16-bit where the math is bulk, keep 32-bit where tiny increments land. Without the FP32 master copy, low-precision training of modern architectures would be mathematically impossible.
6References
- torch.optim.AdamW documentation: defaults for lr, betas, and weight decay.
- Fixing Weight Decay Regularization in Adam (Loshchilov and Hutter, 2017): the decoupled decay argument behind AdamW.
- Adam: A Method for Stochastic Optimization (Kingma and Ba, 2014): original bias correction derivation.
- Mixed Precision Training (Micikevicius et al., 2017): FP16 compute with FP32 master weights.
- Local source:
bin/blogs/optimizer-state.md, the original markdown note this page was rewritten from.