Vibe Engines is free, interactive AI engineering & system design — runs in your browser. Pick a learning path →
Adam,
explained.
If you have ever trained a neural network, you almost certainly used Adam. It is the closest thing deep learning has to a default — the optimizer you reach for before thinking. Its secret is combining two older ideas, momentum and per-parameter scaling, and adding one small correction most explanations skip. Here is the whole thing, built up from scratch and made runnable.
Contents 15 sections
The delta Why one learning rate isn't enough Momentum: the first moment RMSProp: the second moment Adam, and the correction everyone forgets How it works The math The evidence Since then Solve it yourself The full rule and its famous defaults Why it became the default — and where it goes next Questions Check yourself Where this sitsWhat changes against batch norm: every parameter gets its own step
Rung 2 improves conditioning by changing the network — rescaling activations so the surface the optimiser walks is better behaved. Adam leaves the network alone and changes the walk. Plain SGD applies one global learning rate to every parameter, which assumes every parameter wants a step of roughly the same size. In a deep network they demonstrably do not: a rarely-activated embedding row and a hot attention projection have gradients that differ by orders of magnitude.
The change is to keep two running averages per parameter and divide one by the other. The first moment is an exponential average of the gradient — momentum, which carries you through flat regions and damps oscillation. The second moment is an exponential average of the squared gradient — the RMSProp term, which measures how large this parameter's gradients have recently been. Dividing the first by the root of the second gives a step whose size is roughly scale-free: a parameter with consistently tiny gradients still moves.
Stated in the ladder's units: rung 2 added two parameters per feature and bought a bigger learning rate. Adam adds two optimiser states per parameter — so an Adam run holds roughly three times the model's weights in memory, which is the single largest reason training a model costs more memory than serving it — and buys a per-parameter effective learning rate. It also introduces the correction that most reimplementations get wrong: both averages start at zero, so early in training both are biased toward zero, and the bias correction divides each by 1−β^t to undo it. Skip it and the first few hundred steps take wildly wrong-sized steps. The famous defaults — β₁ 0.9, β₂ 0.999, ε 1e−8 — are from this paper and are still the usual starting point, although large-language-model training commonly lowers β₂ to roughly 0.95–0.98 and adds learning-rate warmup.
Why one learning rate isn't enough
Plain gradient descent has one knob — the learning rate — applied identically to every parameter. That is a problem, because parameters are not alike. Some receive large, frequent gradients; others receive tiny, rare ones. A step size big enough to move the sluggish parameters will make the sensitive ones explode; a step size safe for the sensitive ones leaves the sluggish ones barely moving. And the loss landscape makes it worse: real objectives have ravines — steep in one direction, nearly flat in another — where a single learning rate either bounces across the walls or crawls along the floor.
Two fixes had been invented separately. Momentum smooths and accelerates by averaging gradients over time. RMSProp gives each parameter its own effective learning rate, scaled by how big its gradients have recently been. Adam's contribution was to combine them cleanly — and to fix a subtle bias that both introduce at the start.
Adam keeps a running memory of each parameter's recent gradients (direction) and their recent sizes (scale), and uses both to take a well-sized step for every parameter independently.
Momentum: the first moment
Instead of stepping along the raw gradient g, which is noisy and can zig-zag, momentum steps along an exponentially weighted average of recent gradients. Call it m — the first moment, an estimate of the gradient's mean. Each step nudges the old average a little toward the new gradient:
With β₁ = 0.9, roughly the last ten gradients dominate the average. The effect is a heavy ball rolling downhill: consistent directions accumulate and speed up, while noisy back-and-forth components cancel out. Ravines that make raw descent oscillate get smoothed into a steady roll along the valley floor.
RMSProp: the second moment
Momentum fixes direction; it does nothing about scale. RMSProp adds a second running average — this time of the squared gradients. Call it v, the second moment, an estimate of each parameter's gradient variance:
Then it divides the step by √v. A parameter with consistently large gradients gets a large v and so a smaller effective step; a parameter with tiny gradients gets a small v and a larger effective step. Every parameter ends up with its own adaptive learning rate, automatically. With β₂ = 0.999, this variance is averaged over a much longer window than the momentum — it changes slowly and stably.
Put the two together — step in the direction of m, scaled by 1/√v — and you almost have Adam. Almost, because both averages start life at zero, and that creates a bias worth fixing.
Adam, and the correction everyone forgets
Both moments are initialized at m = 0, v = 0. So on step 1, with a gradient g, the first moment is m = (1 − β₁)·g = 0.1·g — ten times too small. The estimate is biased toward zero, badly, for the first several steps. Adam cancels this exactly by dividing each moment by 1 − β^t, where t is the step number:
m̂t = mt / (1 − β₁^t) v̂t = vt / (1 − β₂^t) θt = θt−1 − α · m̂t / (√v̂t + ε)
At t=1 the divisor 1−β₁ turns m = 0.1·g back into m̂ = g, undoing the bias precisely; as t grows, β^t → 0 and the correction fades to 1. The final line is the whole optimizer: move each parameter by the (corrected) average gradient, divided by the square root of its (corrected) average squared gradient.
One elegant property falls out of that division: Adam is roughly scale-invariant. Multiply every gradient by a constant and m̂ scales by that constant while √v̂ scales by the same amount — they cancel, and the step size barely changes. The update is governed by the direction and consistency of the gradients, not their raw magnitude, which is a big reason the default learning rate works across so many different problems.
What Adam's update guarantees, and where it comes from
Kingma and Ba present Adam as a first-order method for stochastic objectives with many parameters, where the noise can come from mini-batch sampling or from dropout and the objective may drift over time. Beyond the moment updates written out on this page, the paper specifies:
- Initialization. Choose α and β₁, β₂ in [0, 1); set m₀ = v₀ = 0 and t = 0. All operations are elementwise, so the optimizer state is two numbers per parameter.
- A cheaper ordering of the same step. Fold both bias corrections into one scalar, αt = α·√(1 − β₂^t)/(1 − β₁^t), then update θt = θt−1 − αt·mt/(√vt + ε̂). This avoids building m̂ and v̂ as separate vectors.
- α as a trust region. Ignoring ε, the effective step is Δt = α·m̂t/√v̂t, and its size is approximately bounded by α (the exact bounds are written out with the equations). The authors suggest choosing α from how far the optimum plausibly sits from the starting point, since α caps how far one step can travel.
- Automatic annealing. The paper calls m̂/√v̂ a signal-to-noise ratio. When successive gradients disagree in sign, the average m̂ shrinks while √v̂ does not, so the effective step falls toward zero, as it typically does near an optimum.
- Analysis in the online convex setting. The regret bound assumes convex losses, bounded gradients and iterates, a step size decaying as α/√t, a first-moment coefficient decaying as β₁λ^t−1 with λ just below 1, and β₁²/√β₂ < 1, and gives regret growing as √T. In practice Adam is run with constant β₁, and the proof was later shown to contain an error.
Where it sits among adaptive methods
AdaGrad divides each step by the root of the sum of all past squared gradients. The paper shows Adam reduces to it with β₁ = 0, β₂ infinitesimally close to 1 and a step α/√t, but only with bias correction: without it, β₂ → 1 would give infinite bias and infinite steps. RMSProp with momentum is the closest relative, but it applies momentum to the already-rescaled gradient instead of averaging the raw gradient, and it has no bias correction, which matters most when β₂ is near 1, the setting sparse gradients need. The authors also point out that v̂ approximates the diagonal of the Fisher information, so Adam behaves like a conservative form of natural-gradient descent that preconditions with the square root of that diagonal.
AdaMax and parameter averaging
Replacing the L2 norm in the denominator with an Lp norm becomes numerically unstable for large p, but the limit p → ∞ is simple and stable: track an exponentially weighted infinity norm ut = max(β₂·ut−1, |gt|), which needs no bias correction, and step by α/(1 − β₁^t) times mt/ut. Its suggested defaults are α = 0.002, β₁ = 0.9 and β₂ = 0.999. The paper also proposes keeping an exponential moving average of the parameters themselves, bias-corrected the same way, because the last iterate of a stochastic method is noisy.
The effective step bound and the AdaMax update
Δt— the change applied to one parameter at step t, with ε ignored.(1 − β₁)/√(1 − β₂)— the worst case, which the paper says occurs only under the most severe sparsity: a gradient that was zero at every earlier step and is nonzero now. With the defaults it is 0.1/√0.001 ≈ 3.16, reached once the bias corrections have faded.|m̂/√v̂| ≤ 1— the common case, since |E[g]|/√E[g²] ≤ 1; steps are close to α when gradients agree in sign and smaller when they do not.ut— an exponentially decaying maximum of past |g|, the limit of the Lp version as p → ∞. It starts at 0 but jumps to |g₁| immediately, so unlike v it is not biased toward zero and needs no correction; the paper gives AdaMax the simpler bound |Δt| ≤ α.
At the extremes: with (1 − β₁) = √(1 − β₂), |m̂/√v̂| stays below 1 and no step exceeds α. With β₁ = 0, β₂ → 1 and a step size of α/√t, the update becomes AdaGrad's α·gt/√(Σi≤t gi²), the method Adam was designed to generalize.
What the Adam experiments compared
Each comparison used the same model for every optimizer, with hyperparameters such as the learning rate and momentum chosen by a dense grid search and the best setting reported. The results are training-cost curves rather than accuracy tables, so the findings below are the authors' readings of those curves.
| Experiment | Setup | Compared with | Finding |
|---|---|---|---|
| Logistic regression, MNIST | L2-regularized, 784 inputs, mini-batch 128, step α/√t | SGD with Nesterov momentum, AdaGrad | Adam matched SGD with Nesterov; both beat AdaGrad |
| Logistic regression, IMDB reviews | 10,000-word sparse bag of words, with and without 50% dropout noise | SGD with Nesterov momentum, AdaGrad | Adam as fast as AdaGrad; both well ahead of SGD |
| Fully connected net, MNIST | two hidden layers of 1,000 ReLUs, mini-batch 128 | SFO quasi-Newton; first-order methods with dropout | faster than SFO in iterations and wall-clock; best with dropout, where SFO failed to converge |
| CNN, CIFAR-10 | c64-c64-c128-1000, whitened inputs, dropout, mini-batch 128 | AdaGrad, SGD with Nesterov momentum | Adam and SGD both much faster than AdaGrad; Adam only marginally ahead of SGD |
| Bias-correction ablation | VAE, 500 softplus units, 50-d latent; β₁ in [0, 0.9], β₂ in {0.99, 0.999, 0.9999} | the same update without correction, which is RMSProp with momentum | without correction, β₂ near 1 was unstable, worst in the first epochs |
Two findings cut against the simplest story. On the CNN, the second-moment estimate v̂ fell to nearly zero within a few epochs and was dominated by ε, so the authors conclude it described the cost surface poorly there and that most of the speed-up came from the first moment. What Adam still offered was a separate effective step size per layer, without hand-picking a smaller rate for the convolutional layers as is common with SGD. SFO, the quasi-Newton competitor, was 5 to 10 times slower per iteration and needed memory growing with the number of mini-batches. In the bias-correction ablation the best results combined a slow second-moment decay with the correction, and across the whole grid Adam did as well as or better than the uncorrected version.
What the authors admit, and what happened next
The paper offers a convergence argument for convex objectives, and that argument turned out to be wrong. Reddi and colleagues exhibited a simple convex problem in 2018 on which Adam does not converge to the optimum, because the exponential average of squared gradients can forget a rare but informative large gradient; their AMSGrad variant keeps a running maximum instead. This is the clearest case on the ladder of a method that is overwhelmingly useful and whose original proof does not hold.
A second defect is not admitted because it was not noticed: the paper folds L2 regularisation into the gradient, which means the penalty is then divided by the second-moment term along with everything else, so parameters with large gradients are effectively regularised less. Loshchilov and Hutter separated the two — decoupling weight decay from the adaptive scaling — and AdamW, not Adam, is what actually trains modern models.
How it held up: as the default, almost completely. Essentially every transformer on this site was trained with Adam or AdamW. Two things remain genuinely contested. The first is generalisation: on image classification, well-tuned SGD with momentum often matches or beats Adam on held-out accuracy, and the reason is not settled. The second is whether the per-parameter scalar is the right object at all — rung 7 of the scaling ladder is the first serious challenger to get traction, and it treats a weight matrix rather than each weight separately.
Adam, in twelve lines
Here is the entire optimizer, plus a loop that runs it. Three things the math promised, made concrete: at step 1 the raw first moment is 0.1×g (ten times too small) and bias correction restores it to exactly g; the step for a gradient of 2 and a gradient of 20 come out identical (scale invariance); and Adam drives an ill-conditioned bowl — 100× steeper in x than y — to the origin, handling both directions at once where a single learning rate would struggle. Change the bowl or the betas and watch it adapt.
Write the body of minimize. Everything else in the file is
already written; this is the function the paper is about. Press ▶ Run to check it against
the 5 assertions below — they start red.
- Bias correction at step 1 recovers the gradient
- The uncorrected 1st moment is 10x too small at step 1
- The step is scale-invariant (10x the gradient, same step)
- Adam minimizes an ill-conditioned bowl to ~0
- The bias correction shrinks toward 1 as t grows
The full rule and its famous defaults
The whole algorithm, per step t, per parameter: update m and v, bias-correct both, then step. Four hyperparameters govern it, and the paper's defaults are so robust they are rarely touched:
| Symbol | Default | What it controls |
|---|---|---|
| α (learning rate) | 0.001 | Overall step size. The one people actually tune. |
| β₁ | 0.9 | Decay of the first moment — how much momentum is retained (~last 10 gradients). |
| β₂ | 0.999 | Decay of the second moment — the window for gradient-variance (~last 1000). |
| ε | 1e-8 | Guards the denominator against divide-by-zero when v̂ is tiny. |
The reason those numbers travel so well is the scale invariance from section 04: because the update normalizes by the gradient's own size, the same α = 0.001 is a reasonable starting step whether gradients are large or small, though it is not a good value for giant transformers, where the peak rate is usually far smaller and warmed up. That "just works out of the box" quality is exactly why Adam displaced hand-tuned SGD schedules for most practitioners.
Why it became the default — and where it goes next
Adam won because it removed a chore. Before it, getting a network to train meant babysitting a learning-rate schedule and often a per-layer tuning ritual. Adam's per-parameter adaptation absorbed most of that, converging fast and reliably on a huge range of architectures with the stock settings. For research velocity — try an idea, see if it trains, today — that mattered enormously.
It is not the end of the story. Plain Adam mishandles weight decay: folding L2 regularization into the gradient lets the adaptive 1/√v̂ scaling rescale the decay unevenly across parameters. AdamW fixes this by decoupling weight decay — applying it straight to the weights, outside the adaptive step — and is now the standard for training large models. Newer optimizers (LAMB for huge batches, Lion, Adafactor for memory) refine the idea further, though not all of them keep the recipe: LAMB is Adam with a per-layer trust ratio, while Adafactor factors the second moment and Lion tracks only a momentum and takes a sign.
Adam keeps two extra numbers (m and v) per parameter — so its optimizer state is twice the model's size in memory. For a 7-billion-parameter model that is tens of gigabytes of optimizer state alone, which is why memory-efficient variants and sharding (ZeRO) exist.
Questions people ask about Adam
How does AdaMax differ from Adam?
AdaMax, introduced in the same paper, replaces the square root of the averaged squared gradient with an exponentially weighted infinity norm: u is the larger of beta2 times its previous value and the absolute value of the current gradient. That norm starts at zero but jumps to the first gradient's size immediately, so it needs no bias correction; only the first moment is corrected. The suggested defaults are a learning rate of 0.002 with beta1 = 0.9 and beta2 = 0.999, and the paper bounds each step by the learning rate. It is available in common libraries, for example as torch.optim.Adamax in PyTorch, but Adam and AdamW remain far more widely used.
Why does Adam need a learning-rate warmup if it already has bias correction?
Bias correction removes the systematic pull of the zero initialization, but it cannot make the first estimates reliable. Early on, the second moment is averaged over only a handful of gradients, so its value, and the step size divided by it, is noisy, and a parameter whose first few gradients happen to be small can take a very large step. Liu and colleagues, in the RAdam paper (2020), argued this variance of the adaptive learning rate is what warmup fixes. The Adam paper itself used no warmup, and its experiments were small. Large transformer recipes use one: the original Transformer warmed up over 4,000 steps, and LLaMA over 2,000.
Why do large language models train Adam with beta2 = 0.95 instead of 0.999?
Beta2 sets how long the second moment remembers: roughly 1/(1 − beta2) steps, so about 1,000 at 0.999 and 20 at 0.95. With a long memory, if gradient magnitudes jump during training, v lags behind, the denominator stays too small and updates come out too large, which is a commonly cited source of instability in large-scale runs. A shorter memory tracks the gradient scale more closely, at the price of a noisier denominator. GPT-3 used beta1 = 0.9 and beta2 = 0.95, LLaMA the same with AdamW, and the original Transformer used beta2 = 0.98. The 0.999 default came from the Adam paper's much smaller experiments.
How is Adam related to AdaGrad and RMSProp?
Adam was designed to combine AdaGrad's strength with sparse gradients and RMSProp's with non-stationary objectives. The paper shows that Adam with beta1 = 0, beta2 infinitesimally close to 1 and a step size decaying as alpha divided by the square root of t is exactly AdaGrad, dividing by the root of the sum of all past squared gradients, but only because of bias correction. RMSProp with momentum is the closest relative: it applies momentum to the already-rescaled gradient rather than averaging the raw gradient, and has no bias correction, which the authors show causes very large early steps and sometimes divergence when beta2 is close to 1. Removing Adam's correction terms gives RMSProp with momentum.
How large can a single Adam update be?
Ignoring epsilon, the step for each parameter is the learning rate times the corrected first moment divided by the root of the corrected second moment. The paper bounds it. When 1 − beta1 exceeds the square root of 1 − beta2, as with the defaults, the worst case is alpha times (1 − beta1) divided by the square root of (1 − beta2), about 3.16 alpha, reached only when a parameter's gradient was zero at every earlier step and suddenly is not. Otherwise the bound is alpha. In typical training the ratio is at most about 1 in size, so steps are around alpha or smaller, which is why the authors describe alpha as setting a trust region around the current parameters.
5 questions to test what you just read
Work each one out before you open it — a number, a prediction or a reason, not a definition. Producing the answer is what makes it stick. Your progress is kept on this device.
With Adam's defaults and α = 0.001, how large can the worst-case step be, and when can it occur?
Show answer
(1 − β₁)/√(1 − β₂) = 0.1/√0.001 ≈ 3.16, so |Δ| ≤ about 0.0032. It applies because 1 − β₁ exceeds √(1 − β₂) with the defaults, and it is reached only when a parameter's gradient was zero at every earlier step and is nonzero now.
Run AdaMax for one step with g₁ = −0.5, starting from m₀ = u₀ = 0 with its defaults. How far and in which direction does θ move?
Show answer
m₁ = 0.1 × (−0.5) = −0.05 and u₁ = max(0, 0.5) = 0.5. The step is (0.002/(1 − 0.9)) × (−0.05/0.5) = 0.02 × (−0.1) = −0.002, and θ ← θ − (−0.002), so θ rises by 0.002: exactly α, against the gradient.
Without bias correction, how large is Adam's tenth step relative to α for a constant gradient, with the defaults?
Show answer
Uncorrected, m10 = (1 − 0.9^10)g ≈ 0.651g and v10 = (1 − 0.999^10)g² ≈ 0.00995g², so m/√v ≈ 0.651/0.0998 ≈ 6.5. The step is about 6.5α instead of α, because the zero-initialized second moment lags far behind.
Approximately how many recent gradients does v average over with β₂ = 0.999 versus 0.95, and what does that predict about reacting to a sudden jump in gradient size?
Show answer
About 1/(1 − β₂): 1,000 steps versus 20. After a jump, the 0.999 average takes hundreds of steps to catch up, so √v̂ stays too small and the steps run large; at 0.95 the denominator catches up within a few dozen steps, which is the usual argument for the lower value at scale.
Which AdaGrad update does Adam reproduce with β₁ = 0, β₂ → 1 and a step size of α/√t, and why does this only work with bias correction?
Show answer
θ ← θ − α·gt/√(Σi≤t gi²). With β₂ → 1 the corrected v̂t tends to the plain average of the squared gradients, and α/√t cancels the 1/t inside the root. Uncorrected, vt carries a factor (1 − β₂) that goes to zero, so the steps would become infinite.
Making deep nets train
Seven papers that turned "deeper is better in theory" into a network that actually converges. Every later architecture paper assumes all of them.
Explore the topic
See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.
More Paper Breakdowns
- Attention Is All You NeedThe paper that introduced the Transformer — the architecture underneath GPT, BERT, Claude, and Gemini. Self-attention, Query/Key/Value, multi-head attention, positional encoding, and the real BLEU results, explained in depth with analogies and animated visuals, not just equations.Read →
- Word2VecHow words became math. Dense word vectors learned from the company a word keeps, so king − man + woman lands near queen. Skip-gram, CBOW, the distributional hypothesis, and the origin of every embedding model powering search and RAG.Read →
- ResNetThe skip connection that made deep learning deep. Why stacking layers made networks worse, and how residual learning let them reach 150+ layers and win ImageNet — the identity shortcut every Transformer still uses inside every block.Read →
- Vision Transformer (ViT)When an image became 16×16 words. Cut a picture into patches, treat each patch as a token, and feed them to a plain Transformer — no convolutions. Patch embeddings, the class token, and why data scale lets attention beat the CNNs that ruled computer vision for a decade.Read →
- Latent DiffusionThe paper behind Stable Diffusion. Compress an image into a small latent space with a VAE, run the diffusion denoising there instead of on pixels for a tens-of-times efficiency win, and steer it with text via cross-attention. The architecture that put text-to-image generation on consumer GPUs.Read →
- DDPMThe original denoising diffusion math — the paper that made diffusion work. A fixed forward process adds Gaussian noise over many steps; a U-Net learns the reverse. The masterstroke: train the network to simply predict the added noise with a plain MSE loss. The foundation under every modern image generator.Read →