Adam and Its Variants
Imagine training a deep network with varied parameters. Some — like the embedding row for a rare word — receive a gradient signal once every few thousand steps. Others — like a bias term in the first layer — are updated on every single batch. A single global learning rate is a bad compromise for both. This is the concrete problem Adam was built to solve. How do you pick a step size, automatically and per-parameter? This must work when the loss landscape has wildly different curvature and sparsity. That variation spans its millions of dimensions. Adam (Adaptive Moment Estimation) has become the default optimizer for a huge share of deep learning practice. It is used from fine-tuning transformers to training convolutional vision backbones. Its dominance is not an accident. It merges two ideas that each solved half the problem. These are Momentum and Nesterov Accelerated Gradient for smoothing noisy gradients, and AdaGrad and RMSProp for adapting the step size per coordinate. It also adds a bias-correction trick. This trick makes the whole thing well-behaved from step one. This article gives Adam a precise, from-scratch derivation. It covers what quantities it tracks, and why bias correction is mathematically necessary (not just a heuristic patch). It also shows how the update rule falls out of estimating the first and second moments of the gradient. It also covers the most consequential variant, AdamW. This variant fixes a subtle but important interaction. That interaction is between adaptive scaling and weight decay, which plain Adam gets wrong. By the end you will be able to write Adam's update loop from memory. You will be able to explain exactly why bias correction is needed at small . You will be able to diagnose the specific failure mode that motivated AdamW. You will also be able to reason about when Adam is the right choice. You will also know when it is not, compared to plain SGD with momentum.
- Adam maintains exponential moving averages of the gradient (first moment, "momentum") and the squared gradient (second moment, "adaptive scale").
- Both moving averages are biased toward zero at early steps; Adam corrects this with an explicit division by .
- The update divides a momentum-smoothed gradient by the square root of a smoothed second-moment estimate, giving each parameter its own effective learning rate.
- Per-step cost is time and extra memory for parameters — two extra buffers, same asymptotic cost as SGD.
- Plain Adam's penalty gets rescaled by the adaptive term, which is not true weight decay; AdamW decouples the two and fixes this.
- Adam converges fast and robustly in practice but can generalize worse than tuned SGD+momentum on some vision tasks, motivating hybrid schedules and AdamW as the safer default.
Adam is SGD with momentum whose step size for each parameter is automatically rescaled by a bias-corrected running estimate of that parameter's gradient variance.
The idea
Adam tracks two exponential moving averages (EMAs) of the gradient at each step : the first moment , an estimate of , and the second raw moment , an estimate of (elementwise, per parameter). The first moment plays the role of classical momentum — it smooths out noise and lets consistent gradient directions accumulate speed. The second moment plays the role of AdaGrad/RMSProp scaling — it estimates how large and how noisy the gradient has typically been for each coordinate, so that parameters with large or erratic gradients get a smaller effective step and parameters with small, consistent gradients get a relatively larger one. The subtlety that distinguishes Adam from a naive combination of momentum and RMSProp is bias correction. Because and are initialized at zero and updated with a decay factor (for ) and (for ) close to 1, the raw EMAs are systematically biased toward zero, especially in the first few steps when there is little history to average over. Adam divides by and respectively to produce bias-corrected estimates and that are unbiased in expectation under a stationary-gradient assumption. Skipping this correction (as an early, naive combination of momentum + RMSProp effectively does) causes the first steps of training to take abnormally tiny steps, because starts near zero and the ratio behaves erratically. The final update rule divides the bias-corrected momentum by the square root of the bias-corrected second moment, plus a small constant for numerical stability:
This single line encodes both ideas at once: the numerator is a momentum-smoothed gradient direction, and the denominator is a per-coordinate adaptive learning rate that shrinks steps in directions of historically large or noisy gradient magnitude.
How it works
Adam is a first-order, stochastic optimizer: at every step it only needs the current mini-batch gradient , plus the two running-average buffers carried over from the previous step. There is no need to store or invert any curvature matrix — the "adaptive scaling" is purely diagonal and elementwise, which is what keeps it cheap enough for models with billions of parameters.
Step-by-step mechanism: 1. Initialize parameters , and set , , . 2. At each step, sample a mini-batch and compute the gradient . 3. Update the first moment (momentum): . 4. Update the second moment (uncentered variance): (elementwise square). 5. Bias-correct both: , . 6. Update parameters: . 7. Repeat until convergence or a fixed number of steps. Typical defaults, from the original paper and confirmed as robust defaults across countless later architectures, are , , , . ``` function ADAM(params θ, loss_fn, α=0.001, β1=0.9, β2=0.999, ε=1e-8, weight_decay λ=0): m ← zeros_like(θ) # first moment buffer v ← zeros_like(θ) # second moment buffer t ← 0 while not converged: t ← t + 1 batch ← sample_minibatch() g ← gradient(loss_fn, θ, batch) # ∇θ L(θ) on this batch if λ > 0 and variant == "Adam-L2": g ← g + λ θ # L2 penalty folded into gradient (plain Adam) m ← β1 m + (1 - β1) g # elementwise v ← β2 v + (1 - β2) (g ⊙ g) # elementwise square m_hat ← m / (1 - β1^t) # bias correction v_hat ← v / (1 - β2^t) if variant == "AdamW": θ ← θ - α ( m_hat / (sqrt(v_hat) + ε) + λ θ ) # decoupled decay else: θ ← θ - α m_hat / (sqrt(v_hat) + ε) # plain Adam step return θ ``` Every operation above — the moving averages, the elementwise square root, the division — is applied per parameter, independently. There is no cross-parameter coupling, which is exactly what makes the whole computation per step for parameters and trivially parallelizable across a parameter tensor on a GPU.
Complexity & correctness
Time complexity. Each step performs a constant number of elementwise operations (multiply, add, square, square root, divide) over vectors of size , the total parameter count. This is per step, identical in order to plain SGD; the constant factor is larger (roughly 4–5x the elementwise arithmetic of vanilla SGD) but this is dwarfed in practice by the cost of the forward/backward pass through the network, which is typically or much more for convolutional and attention layers. Over steps, total optimizer overhead is .
Space complexity. Adam must store and alongside , i.e. two extra copies of the parameter vector, giving extra memory — a real practical cost (3x the parameter memory instead of 1x for SGD, or 2x for SGD with momentum) that matters at billion-parameter scale, motivating memory-efficient variants such as Adafactor.
Why bias correction is exactly right, not just a heuristic. Assume the true gradient at each step is drawn i.i.d. (or at least stationarily) with . Unrolling the EMA recursion,
Taking expectations under stationarity,
So unless : the raw moving average systematically underestimates the true mean by a factor of , which is severe when is small (e.g. at , , the factor is only — a 10x understatement). Dividing by exactly cancels this factor, giving : an unbiased estimator under the stationarity assumption. The identical argument applies to and . This is the precise mathematical justification for the correction — it is not an ad hoc rescaling but the unique factor that removes the geometric-series bias.
Why the adaptive denominator helps. estimates the root-mean-square magnitude of recent gradients for that coordinate. Dividing by it approximately normalizes the step so that every coordinate takes a step of comparable scale regardless of how large or small its raw gradients are — this is exactly the AdaGrad/RMSProp insight, inherited by Adam. Coordinates with sparse, rare, but informative gradients (e.g. an embedding row hit once every 10,000 steps) do not get drowned out by coordinates with dense, large gradients (e.g. shared bias terms); their smaller produces a relatively larger effective step size when they do fire.
Convergence. Adam's original convergence proof (in the online convex optimization setting) was later shown to contain a subtle flaw: a fixed can, in adversarial sequences, prevent the regret bound from holding, because can decrease even as gradients grow, letting the effective learning rate increase at the wrong time. The fix used by the follow-up variant AMSGrad is to keep a running maximum of so the denominator is monotonically non-decreasing, restoring a clean regret bound. In practice, plain Adam with standard hyperparameters converges reliably on essentially all standard deep learning benchmarks, and the pathological non-convergent sequences are rarely encountered; AMSGrad is used selectively rather than as a universal replacement.
Tradeoff, honestly stated. Adam's adaptivity buys robustness to learning-rate misspecification and fast early progress, especially valuable for the noisy, non-convex, highly heterogeneous-curvature landscape of deep networks. The cost is (a) 2x-3x optimizer memory versus SGD, and (b) empirically worse generalization than well-tuned SGD+momentum on some large-scale image classification tasks, an effect attributed partly to the -vs-weight-decay coupling problem that AdamW addresses below.
Worked example
Trace two steps of Adam on a single scalar parameter, to make the bias-correction arithmetic concrete. Suppose , , , , , and the observed gradients are , (consistently positive, as if the loss is -like locally).
Step :
| quantity | value |
|---|---|
| step | |
Notice the bias correction recovers exactly and : with only one sample, the corrected estimate should simply equal that sample, and it does — a sanity check that the correction formula is exact at (since trivially when ).
Step :
| quantity | value |
|---|---|
| step | |
Compare to what plain SGD with would have done: , a much larger, more volatile step. Adam's adaptive denominator (near here, since gradients are consistently around –) keeps the effective step close to in magnitude regardless of the raw gradient scale — this is the adaptive-scaling behavior working exactly as designed: it normalizes step size to be comparable to , not proportional to the raw gradient magnitude.
AdamW contrast. Suppose we add weight decay . Plain "Adam-L2" folds into before the moment estimates are computed, so the decay term itself gets divided by — coordinates with large historical gradients have their weight decay shrunk, which is backwards (large-gradient parameters usually need more, not less, regularization pressure). AdamW instead applies as a separate, undivided term added directly to the parameter update, so every parameter decays toward zero at the same rate regardless of its gradient history — matching the original intent of weight decay in Weight Decay and L2 Regularization.
Common pitfalls & traps
| Pitfall | Why it happens | Fix |
|---|---|---|
| Forgetting bias correction | start at 0, so early steps take erratically tiny or huge steps | Always divide by , ; recompute correctly (starts at 1, not 0) |
| Using plain Adam's term as if it were weight decay | The penalty gets rescaled by , so large-gradient params are under-regularized | Use AdamW's decoupled decay term instead |
| too large relative to gradient scale | Swamps the adaptive term, making Adam behave like plain SGD with a tiny learning rate | Use the standard (or – for fp16 mixed precision) and tune only if diverging |
| Reusing the same counter across restarted training runs / mismatched checkpoints | Resuming with re-triggers strong bias correction on a "warm" buffer, causing a spike | Checkpoint and restore , , together with |
| Assuming Adam always generalizes as well as SGD+momentum | Adaptive scaling can converge to sharper minima on some vision benchmarks | Consider SGD+momentum with a tuned schedule, or AdamW with proper weight decay, as an ablation |
| Setting too low for very noisy/sparse gradients | Short effective averaging window for makes the denominator jumpy, destabilizing steps | Raise toward – for very sparse-gradient regimes (e.g. large embedding tables) |
Pioneers & history
Adam was introduced by Diederik P. Kingma and Jimmy Ba as a synthesis of ideas that had been developed separately over the preceding years: Momentum and Nesterov Accelerated Gradient provided the notion of accumulating a velocity vector, while AdaGrad and RMSProp provided the idea of a per-coordinate adaptive learning rate driven by accumulated squared gradients. Adam's specific contribution was combining both moving averages with an explicit, mathematically motivated bias-correction step, which proved decisive for stable behavior at the start of training and for robustness across a very wide range of problems with minimal hyperparameter tuning.
Origins · 1 minDiederik P. Kingma and how this was discovered
Kingma co-authored Adam during his PhD at the University of Amsterdam, alongside foundational work on variational autoencoders. His research broadly bridges probabilistic modeling and practical, scalable optimization, and Adam itself grew out of the same push to make gradient-based training of deep probabilistic models tractable at scale.
Where this matters
Adam and AdamW are the default optimizers behind the majority of modern deep learning training runs: transformer language models (including large-scale pretraining pipelines), vision transformers, diffusion models, and most fine-tuning workflows use AdamW as the standard choice, typically paired with a warmup-then-decay learning rate schedule. Recommendation systems and NLP models with huge, sparse embedding tables particularly benefit from Adam's per-coordinate adaptivity, since most embedding rows are touched rarely and need individualized step sizes. Frameworks such as PyTorch, TensorFlow, and JAX ship Adam and AdamW as built-in, heavily optimized primitives (including fused CUDA kernels), reflecting how central this optimizer has become to the practical deep learning stack. Understanding its mechanics is also the natural gateway to Hyperparameter Tuning, since , , , and the weight-decay coefficient are among the most consequential knobs in any training recipe.
Ask the tutor: Can you walk me through why Adam's adaptive denominator can sometimes lead to worse generalization than SGD, and how gradient noise interacts with near a sharp minimum?
Why does Adam need two separate moving averages instead of one?
The first moment tracks the direction the gradient tends to point in, smoothing out mini-batch noise the same way classical momentum does — this speeds convergence along consistent downhill directions. The second moment tracks the typical magnitude of the gradient (squared), independent of sign, which is used purely to rescale the step size per coordinate. These are conceptually different quantities: one is about direction and speed, the other about scale and normalization. Using only one of them recovers either plain momentum (no adaptivity) or plain RMSProp/AdaGrad (no smoothing of direction) — Adam's contribution is combining both, plus the bias correction that makes the combination well-behaved from the very first step.
Is Adam always a better choice than SGD with momentum?
No. Adam typically converges faster and is more robust to learning-rate misspecification, which is extremely valuable during early experimentation and for architectures like transformers where the loss landscape is poorly understood. However, several empirical studies on image classification with convolutional networks found that well-tuned SGD with momentum and a hand-crafted learning-rate schedule can reach better final test accuracy, sometimes attributed to Adam's adaptive scaling biasing optimization toward sharper minima with worse generalization. In practice, many production transformer-training pipelines still prefer AdamW, while some vision pipelines prefer SGD+momentum; the right choice depends on architecture, data regime, and how much tuning budget is available.
What does the epsilon term in the denominator actually do?
prevents division by zero when is extremely small, which can happen early in training or for parameters that have received almost no gradient signal yet. But its effect is not merely a numerical safeguard: if is set too large relative to typical values, it dominates the denominator and effectively suppresses the adaptive scaling, making Adam behave like plain SGD with a small, fixed learning rate. Conversely, too small an can cause instability when is near zero, producing huge steps. The default works well in float32; in float16/mixed-precision training a larger value like or is often used to avoid underflow-related instability.
How does AdamW change the actual parameter update compared to Adam?
In plain Adam with an penalty, the term is added directly to the gradient before computing and , so the penalty gets absorbed into, and rescaled by, the adaptive denominator . In AdamW, the gradient used for and excludes the decay term entirely; instead, is subtracted directly from the parameter update as a separate term. The result is that every parameter decays toward zero at a uniform rate proportional to , regardless of its gradient history — matching what weight decay is supposed to do, and empirically improving generalization and making the decay coefficient easier to tune independently of the learning rate.
Why is Adam's memory overhead sometimes a real practical concern?
Adam stores and as full copies of the parameter tensor shape, so training requires roughly three times the parameter memory (parameters, , ), compared to roughly one time for plain SGD or two times for SGD with momentum. For a model with billions of parameters, this tripling can be the difference between fitting on available GPU/TPU memory and needing to shard optimizer state across multiple devices. This overhead motivated memory-efficient alternatives such as Adafactor, which factorizes the second-moment estimate to avoid storing a full-size buffer, at some cost in adaptivity precision, particularly relevant for very large-scale model training.
Does Adam guarantee convergence to a minimum?
For general non-convex deep learning losses, no optimizer has a guarantee of finding a global minimum; Adam, like SGD, is only guaranteed (under suitable assumptions) to converge to a stationary point or to have bounded regret in convex online-learning settings. The original Adam paper's convex convergence proof was later shown to have a gap, since a fixed can allow to decrease at a bad moment, which is what motivated AMSGrad's fix of taking a running maximum of . In practice, across standard deep learning benchmarks, plain Adam with default hyperparameters converges reliably, and the theoretical counterexamples are rarely encountered outside adversarially constructed sequences.