Home / Deep Learning

Optimizers in Neural Networks

By Updated

Visualize how different optimization algorithms navigate the "Loss Landscape" to find the global minimum. Run multiple in parallel to observe realistic relative speeds!

Overview

What each one adds

  • SGDθ ← θ − ηg. No memory at all. Each step depends only on the current gradient.
  • Momentumv ← βv + g, then θ ← θ − ηv with β around 0.9. Builds up velocity in consistent directions and cancels out oscillation.
  • RMSprop — divides each parameter's step by a running root-mean-square of its recent gradients, so every parameter gets a step size suited to its own scale.
  • Adam — momentum and RMSprop together, plus a correction for the fact that both averages start at zero.
0.1x

Optimization State

Target Minimum is at (0, 0)

Optimizers in Neural Networks: A Practical Guide

Every optimiser here computes the same gradient. They differ entirely in how much they remember about the gradients that came before.

Why plain SGD zig-zags

Picture a long narrow valley where the gradient across the valley is 10 and along it is 0.1. With η = 0.01, SGD steps 0.1 across and 0.001 along — a hundred to one. It bounces off the steep walls while creeping toward the actual minimum.

Momentum fixes this by accumulation: the across-valley components alternate sign and cancel, while the along-valley components all point the same way and add up. RMSprop fixes it differently, by normalising both directions to roughly equal step sizes.

Momentum, precisely

Plain SGD steps in the direction of the current gradient and forgets everything before it. Momentum keeps a running average of past gradients and steps along that instead:

v ← βv + (1 − β)∇L    w ← w − ηv

With the usual β = 0.9 the velocity is an average over roughly the last ten gradients. Consistent directions accumulate and speed up; directions that flip sign each step cancel out. That is exactly the fix for a narrow valley, where the gradient across the valley alternates while the gradient along it stays constant — the oscillation cancels and the useful direction survives.

What Adam actually stores

Adam keeps two running averages per parameter: the mean of the gradients (momentum, as above) and the mean of their squares. It divides the step by the square root of that second average:

w ← w − η · m̂ / (√v̂ + ε)

The effect is a per-parameter learning rate. A parameter that has consistently seen large gradients gets a smaller effective step; one that has seen small or infrequent gradients gets a larger one. That is what makes Adam so effective on sparse data, where rare features would otherwise learn thousands of times more slowly than common ones.

The cost is memory: two extra values per parameter, so optimiser state is three times the size of the model. On a large model that is a real constraint, and it is why plain SGD with momentum is still used where memory is tight.

Which optimiser to reach for

  • AdamW — the default for almost everything now, and the correct choice whenever weight decay is used, because plain Adam’s L2 term gets rescaled by the adaptive step and stops behaving like decay.
  • SGD with momentum — still the best final accuracy on large vision models, given a good learning-rate schedule. It needs more tuning and generalises slightly better.
  • Adam — fine when there is no weight decay; otherwise prefer AdamW.
  • Adagrad / RMSprop — largely superseded by Adam, which combines their ideas with momentum.

A practical note: the optimiser is not a substitute for the learning rate. Adam’s default of 0.001 is a reasonable starting point rather than a universal answer, and a badly chosen rate will defeat any optimiser on this list.

From one global step size to per-parameter steps

Plain gradient descent applies one learning rate to every parameter. That is a poor fit for a real network, where some parameters sit on steep slopes and others on nearly flat ones.

Optimisers are the successive fixes for that, and they build on each other:

OptimiserIdea added
SGDStep against the gradient
SGD + momentumAccumulate a velocity across steps
NesterovLook ahead before stepping
AdaGradDivide by accumulated squared gradients — per-parameter rates
RMSPropSame, but with a decaying average so it does not stall
AdamRMSProp plus momentum, with bias correction
AdamWAdam with weight decay applied correctly

Momentum is the first and biggest win. Averaging recent gradients builds speed in consistent directions and cancels oscillation across a narrow valley.

AdaGrad introduced per-parameter scaling, but its accumulator only grows, so the effective learning rate decays to zero and training stalls. RMSProp replaced the running sum with an exponential moving average, which fixed it.

Adam combines the two: a moving average of gradients (momentum) and of squared gradients (scaling), each bias-corrected for the first few steps when the averages start at zero.

What Adam actually computes

m ← β₁m + (1−β₁)g    v ← β₂v + (1−β₂)g²

w ← w − η · m̂ / (√v̂ + ε)

m is the smoothed gradient, v the smoothed squared gradient. Dividing by √v means a parameter with consistently large gradients takes smaller steps and one with tiny gradients takes larger ones — the per-parameter adaptation.

The defaults are unusually robust: β₁ = 0.9, β₂ = 0.999, ε = 1e-8. Those are almost never worth changing. β₂ = 0.999 corresponds to a memory of roughly a thousand steps, which is why Adam is stable but slow to react to a genuine change in the loss landscape.

AdamW is the version to use. Plain Adam applies weight decay by adding it to the gradient, which then gets divided by √v — so parameters with small gradients are penalised more, which was never the intent. AdamW applies the decay directly to the weights, decoupled from the adaptive scaling. The difference is measurable, and it is why every transformer recipe specifies AdamW.

Try this above

  1. Select All (Compare) and run. Watch SGD (red) oscillate while Adam (green) takes a far more direct route.
  2. Raise Learning Rate gradually. There is a value where SGD diverges outright but the adaptive methods still converge.
  3. Now drop the learning rate very low and run again. SGD's path becomes clean — it was never the algorithm's fault, it was the step size.
  4. Use Sim Speed to slow it right down and watch Momentum overshoot the minimum and come back.

What usually goes wrong

Carrying a learning rate between optimisers. A good SGD learning rate is often 0.01–0.1; Adam's usual default is 0.001. Swapping optimiser while keeping η is one of the most common reasons a switch to Adam appears to make things worse.Assuming Adam always wins. It usually converges fastest, but well-tuned SGD with momentum frequently generalises better on vision tasks, and a good deal of published work still uses it for exactly that reason. Fast to a worse minimum is not a win.

In one line

Same downhill direction, different memory — and memory is what stops you bouncing off the walls.

Choosing one, and the schedule that goes with it

SituationOptimiserStarting learning rate
Transformers, language modelsAdamW1e-4 to 3e-4, with warm-up
Vision, from scratchSGD + momentum 0.9, or AdamW0.1 (SGD) / 1e-3 (AdamW)
Fine-tuning a pretrained modelAdamW1e-5 to 1e-4
Tabular data, small networksAdamW1e-3
Sparse features, embeddingsAdam or Adagrad1e-3

The honest summary of a long-running debate: AdamW converges faster and needs less tuning; well-tuned SGD with momentum sometimes generalises slightly better on vision tasks. If you have limited time, use AdamW.

The schedule matters as much as the optimiser. Two components are standard:

Warm-up — ramp the learning rate from near zero over the first few hundred or few thousand steps. Adam's variance estimate is unreliable early on, and a large first step can damage the initialisation. Essential for transformers.

Cosine decay — smoothly reduce the rate to near zero over training. Reliably beats a constant rate, and beats step decay in most comparisons.

import torch

opt = torch.optim.AdamW(model.parameters(), lr=3e-4, weight_decay=0.01)
sched = torch.optim.lr_scheduler.OneCycleLR(
    opt, max_lr=3e-4, total_steps=epochs * len(loader), pct_start=0.1)

for batch in loader:
    loss = criterion(model(batch.x), batch.y)
    opt.zero_grad()
    loss.backward()
    torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
    opt.step()
    sched.step()          # per batch for OneCycle, not per epoch

Memory, and the newer options

Adam stores two extra values per parameter, so its optimiser state is twice the model size. For a 7-billion-parameter model in 32-bit that is 56GB of optimiser state alone, which is why large-model training uses 8-bit optimisers, sharding across devices (ZeRO), or memory-efficient variants such as Adafactor and Lion.

Lion keeps only momentum and uses the sign of the update, halving the state. Sophia and other second-order-flavoured methods use curvature estimates. These matter at scale; for ordinary work AdamW remains the right default.

Four optimisers on one badly-scaled bowl

A surface 1000x steeper in one direction than the other -- the normal situation in a real network. Plain SGD cannot solve it, and watching why explains every optimiser invented since.

example_01.pyNumPy
Output

Questions people ask

Should I ever use plain SGD? With momentum, yes — it is still competitive on vision with a good schedule. Without momentum, essentially never.

Do I need to tune β₁ and β₂? Almost never. β₂ = 0.95 is sometimes used for very large models where the default is too slow to adapt.

Why does my loss spike after a while with Adam? Often the learning rate is too high for the later, sharper part of the landscape. A decaying schedule fixes it.

What weight decay should I use? 0.01 to 0.1 with AdamW is typical. Note that it applies to weights, and biases and normalisation parameters are usually excluded.

Is Adam bad for generalisation? The old claim is overstated. AdamW closed most of the gap, and with a proper schedule the difference is small.

Can I change optimiser mid-training? You can, and the state is lost, so expect a temporary disruption. Sometimes done deliberately: Adam early, SGD late.

Recap in one screen

  • Momentum accumulates a velocity; adaptive methods give each parameter its own effective step size.
  • Adam combines both with bias correction; AdamW fixes how weight decay interacts with the scaling.
  • Defaults (β₁ = 0.9, β₂ = 0.999) are robust and rarely need changing.
  • Warm-up plus cosine decay is the modern schedule, and matters as much as the optimiser choice.
  • Adam's state doubles memory use, which is why large-scale training uses sharded or 8-bit variants.

Recall check

0 of 3

Say the answer out loud before you reveal it — recalling it is what makes it stick, and rereading it is not.

  1. Without scrolling back — what is the one-line takeaway from this module?

  2. What does this module say about “What each one adds”?

  3. What does this module say about “Why plain SGD zig-zags”?

Cheat sheet

Optimizers in Neural Networks

Visualize how different optimization algorithms navigate the "Loss Landscape" to find the global minimum. Run multiple in parallel to observe realistic relative speeds!

DEEP LEARNING · vizlearn.in/deep_learning/optimizers_in_neural_networks.html

Further reading

About the author

Ashish Jangra builds and maintains VizLearn. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.