Basics of Optimizers
Training a model means choosing its parameters so that its predictions incur a small loss. If all trainable parameters are collected in a vector \(\theta\in\mathbb R^d\), the problem is
\[\boxed{\text{find }\theta\text{ that makes }L(\theta)\text{ as small as possible}.}\]For a neural network, \(d\) may be billions and \(L(\theta)\) is a deeply nested nonlinear function. We cannot list every possible \(\theta\), evaluate the loss at each one, and select the best. Nor can we usually rearrange the equation \(\nabla L(\theta)=0\) and solve directly for \(\theta\). Training must therefore be iterative: start from some \(\theta_0\), make a small informed change, inspect the new local information, and repeat.
An optimizer answers the decision made at every such iteration:
Given what we know at the current parameters, which update \(\Delta\theta_t\) should we apply next?
This wording also separates two algorithms that are often conflated. Backpropagation computes how sensitive the current loss is to each parameter—the gradient. The optimizer consumes that gradient, combines it with its state and hyperparameters, and produces the actual parameter update. Backprop provides local evidence; the optimizer decides how to act on it.
Road map. The article now follows five focused parts. Section 1 builds gradient descent from derivatives, Taylor approximation, and the learning rate. Section 2 replaces the full gradient by a mini-batch estimate, states plain SGD, and then introduces momentum as SGD’s memory across steps. Section 3 explains why coordinates need different scales, uses AdaGrad and RMSProp as stepping stones, and assembles the complete Adam update. Section 4 separates weight decay to obtain AdamW. Section 5 develops Muon as a matrix-aware alternative to coordinate-wise adaptation.
Throughout, \(L(\theta)\) is the objective, \(g_t\) is the gradient available at step \(t\), \(\Delta\theta_t=\theta_{t+1}-\theta_t\) is the chosen update, and \(\eta_t>0\) is the learning rate.
1. Gradient Descent Fundamentals
For supervised learning, the objective is usually an average of per-example losses:
\[\min_\theta L(\theta), \qquad L(\theta)=\mathbb E_{\xi\sim\mathcal D}[\ell(\theta;\xi)].\]Here \(\xi\) is one example drawn from a data distribution \(\mathcal D\), \(\ell(\theta;\xi)\) measures how badly the current model handles that example, and \(L\) is the average behavior we actually care about. In a finite dataset, the expectation can simply be read as an average over its examples.
Notice the mismatch between the question and the information available. The question is global—which parameters have the smallest loss?—but at step \(t\) we stand at only one point \(\theta_t\). A forward pass tells us \(L(\theta_t)\). Backpropagation tells us the local slope
\[g_t=\nabla_\theta L(\theta_t)\]for a full batch, or an estimate of it for a mini-batch. The symbol \(\nabla_\theta\) collects one partial derivative per parameter,
\[g_t=\left(\frac{\partial L}{\partial\theta_1},\ldots, \frac{\partial L}{\partial\theta_d}\right)_{\theta=\theta_t}.\]Math foundation: derivative, partial derivative, and gradient (Click to expand)
Start with a loss that depends on one scalar parameter \(u\). Change the parameter by a small amount \(h\) and measure
\[\frac{L(u+h)-L(u)}{h}.\]This quotient is the loss change per unit parameter change across that interval. Letting the interval shrink toward zero defines the derivative
\[\frac{dL}{du}(u) =\lim_{h\to0}\frac{L(u+h)-L(u)}{h}.\]It is the slope of the tangent line at \(u\). If it equals \(4\), then a sufficiently small increase \(h\) predicts a loss change of approximately \(4h\). The derivative is not a step size; it describes local sensitivity.
A model has many parameters, so write \(\theta=(\theta_1,\ldots,\theta_d)\). The partial derivative
\[\frac{\partial L}{\partial\theta_i}\]asks the same slope question for coordinate \(i\) while holding all other coordinates fixed. The round symbol \(\partial\) reminds us that \(L\) has several inputs. Putting all partial derivatives into one vector gives the gradient
\[\nabla_\theta L(\theta) =\left(\frac{\partial L}{\partial\theta_1},\ldots, \frac{\partial L}{\partial\theta_d}\right).\]Where did the \(\theta\) in the objective go? It did not disappear; standard derivative notation suppresses arguments that would otherwise be repeated. The original objective
\[\min_\theta L(\theta)\]says that \(\theta\) is the variable we are allowed to change. Training cannot search all values at once, so at step \(t\) it holds one candidate \(\theta_t\). Backpropagation differentiates that same function \(L(\theta)\) with respect to its variable \(\theta\) and then evaluates the result at the current candidate:
\[\boxed{ g_t=\nabla_\theta L(\theta_t) =\left( \left.\frac{\partial L(\theta)}{\partial\theta_1}\right|_{\theta=\theta_t}, \ldots, \left.\frac{\partial L(\theta)}{\partial\theta_d}\right|_{\theta=\theta_t} \right).}\]The shorter expression \((\partial L/\partial\theta_1,\ldots)\) means exactly the same thing; the argument was omitted for readability. Each component can be traced all the way back to the per-example objective:
\[\begin{aligned} g_{t,i} &=\left.\frac{\partial L(\theta)}{\partial\theta_i}\right|_{\theta=\theta_t}\\ &=\left.\frac{\partial}{\partial\theta_i} \mathbb E_{\xi\sim\mathcal D}[\ell(\theta;\xi)] \right|_{\theta=\theta_t}\\ &=\mathbb E_{\xi\sim\mathcal D}\!\left[ \left.\frac{\partial\ell(\theta;\xi)}{\partial\theta_i} \right|_{\theta=\theta_t}\right], \end{aligned}\]Here \(\left.\cdot\right\rvert_{\theta=\theta_t}\) is an evaluation bar: first differentiate while \(\theta\) remains symbolic, then substitute the current parameter vector \(\theta_t\). For example, \(\left.2u\right\rvert_{u=3}=6\). The subscript distinguishes this use from absolute value or conditional probability.
The last equality assumes the loss is differentiable and sufficiently well behaved that differentiation and averaging can be exchanged. Conceptually, it says: keep the sampled data \(\xi\) fixed, ask how its loss changes with parameter \(\theta_i\), and then average that sensitivity over data. A mini-batch estimates this final expectation.
What role does the argument \(\theta\) play here? It specifies the position at which the gradient is evaluated. It helps to separate two objects:
\[\underbrace{\theta}_{\text{current position in parameter space}}, \qquad \underbrace{\nabla_\theta L(\theta)}_{\text{local slope vector attached to that position}}.\]Imagine the loss as terrain. The parameter vector \(\theta\) gives a location on the map; \(L(\theta)\) gives its altitude; and \(\nabla L(\theta)\) is an arrow placed there, pointing toward the steepest local ascent. Moving to another position generally changes the arrow.
The arrow depends on the position, but it does not necessarily identify that position. For \(L(u)=u^2\), the derivative \(L'(u)=2u\) differs between \(u=1\) and \(u=3\). But for \(L(u)=3u\), the derivative is \(3\) everywhere, so seeing the derivative alone cannot reveal whether \(u=1\) or \(u=100\). The complete local description keeps the position and its measurements together:
\[\bigl(\theta,\;L(\theta),\;\nabla L(\theta)\bigr).\]Many calculus books call the independent variable \(x\) and write \(\nabla_x f(x)\). In this article, \(\theta\) plays that mathematical role because the optimizer changes model parameters. A training example may also be named \(x\), as in \(\ell(\theta;x,y)\), but that \(x\) is data held fixed while backpropagation computes \(\nabla_\theta\ell(\theta;x,y)\).
Two subscripts serve different roles in this article:
- \(i\) identifies a parameter coordinate;
- \(t\) identifies a training step, so \(\theta_t\) is the entire parameter vector currently held at step \(t\).
Therefore, because \(\theta_t\) is a vector here, writing \(\partial L/\partial\theta_t\) can be misleading. The precise notation is
\[\nabla_\theta L(\theta_t)\]for the whole gradient evaluated at the current vector, or
\[\left.\frac{\partial L}{\partial\theta_i}\right|_{\theta=\theta_t}\]for the derivative of one coordinate evaluated at that point. Backpropagation computes all these coordinate derivatives efficiently in one backward pass.
Thus \(g_{t,i}\) answers a deliberately local question: if only \(\theta_i\) increased by a tiny amount, at what rate would the loss change? Neither the loss value nor this vector tells us the loss everywhere else. The optimizer must use this limited local information to choose \(\Delta\theta_t\).
1.1 Why Does Taylor Expansion Appear?
Suppose we are considering many possible updates. Evaluating the full network and loss after every candidate would be prohibitively expensive. We instead want a cheap local model that answers:
If I move by a small \(\Delta\theta\), approximately how will the loss change?
Math foundation: what is a Taylor expansion? (Click to expand)
A derivative gives a local slope. Taylor expansion uses that slope—and, if desired, higher derivatives—to build a simple local approximation to a complicated function.
For a one-variable function,
\[L(u+h) =L(u)+L'(u)h+\frac12L''(u)h^2+\cdots.\]The terms have a natural order:
- \(L(u)\) is the known value at the current point;
- \(L'(u)h\) predicts change using the local slope;
- \(\frac12L''(u)h^2\) corrects for curvature;
- later terms describe still finer local shape.
For example, take \(L(u)=u^2\) at \(u=3\) and propose \(h=-0.1\). The first-order prediction is
\[L(3-0.1)\approx L(3)+L'(3)(-0.1) =9+6(-0.1)=8.4.\]The exact value is \(2.9^2=8.41\). The missing \(0.01\) is exactly the second-order term \(h^2\) in this quadratic example. A small move makes that quadratic correction much smaller than the linear change.
With many parameters, the corresponding expansion is
\[L(\theta+\Delta\theta) =L(\theta) +\underbrace{\sum_i\frac{\partial L}{\partial\theta_i}\Delta\theta_i}_{\nabla L(\theta)^\top\Delta\theta} +\frac12\Delta\theta^\top H\Delta\theta+\cdots,\]where \(H\) is the matrix of second derivatives. Keeping only the constant and linear terms gives the first-order Taylor approximation used below. The approximation is local: “small” means small enough that curvature and later terms do not dominate. It is not a claim that the entire neural-network loss is a straight line.
The derivative is defined precisely to answer how a function changes under a small displacement. Collecting the derivatives for all parameter coordinates gives the first-order Taylor expansion
\[L(\theta_t+\Delta\theta) \approx L(\theta_t)+g_t^\top\Delta\theta.\]The first term is the loss we already know. The dot product in the second term is the predicted change:
\[g_t^\top\Delta\theta=\sum_{i=1}^d g_{t,i}\Delta\theta_i.\]Every parameter’s slope is multiplied by how far we propose to move that parameter, and the contributions are added. For example, a positive component of \(g_t\) says that increasing that parameter alone would locally increase the loss; a negative component says the reverse.
Why keep only the first-order term? Higher-order terms contain curvature and can make the prediction more accurate, but constructing and solving with them is far more expensive at neural-network scale. When \(\Delta\theta\) is small, their contribution also shrinks faster than the linear term. Taylor expansion is therefore not an arbitrary proof trick: it is the simplest affordable model of the nearby loss surface.
Before optimizing the expression, separate what is known from what is being chosen:
| Quantity | Role at step \(t\) |
|---|---|
| \(g_t\) | already computed by backpropagation; fixed during this decision |
| \(\Delta\theta\) | the candidate update whose direction and length we are choosing |
| \(g_t^\top\Delta\theta\) | one scalar: the Taylor model’s predicted loss change |
Thus \(\Delta\theta\) is the update direction being chosen. The known vector \(g_t\) tells us how each possible direction would score. To compare directions fairly, first give every candidate the same length \(\lVert\Delta\theta\rVert_2=r\). We then ask which direction makes \(g_t^\top\Delta\theta\) as negative as possible. Cauchy–Schwarz gives
\[g_t^\top\Delta\theta\ge-\lVert g_t\rVert_2\lVert\Delta\theta\rVert_2=-r\lVert g_t\rVert_2,\]and the lower bound is attained only when \(\Delta\theta\) points exactly opposite \(g_t\). Therefore the best fixed-length candidate is
\[\boxed{\Delta\theta^*=-r\frac{g_t}{\lVert g_t\rVert_2}}.\]This answers the direction question: \(g_t\) points toward steepest local increase, while \(-g_t\) points toward steepest local decrease. Plain gradient descent does not usually choose a fixed radius \(r\) explicitly. It introduces a positive learning rate \(\eta_t\) and sets
\[\Delta\theta=-\eta_t g_t.\]The negative sign chooses the direction; \(\eta_t\) scales the distance. In fact,
\[\lVert\Delta\theta\rVert_2=\eta_t\lVert g_t\rVert_2,\]so a fixed radius \(r\) would correspond to \(\eta_t=r/\lVert g_t\rVert_2\). Substitution into the Taylor prediction gives
\[g_t^\top\Delta\theta=-\eta_t\lVert g_t\rVert_2^2\le0.\]For example, if \(g_t=(3,4)\) and we allow radius \(r=1\), then \(\lVert g_t\rVert_2=5\) and
\[\Delta\theta^*=(-3/5,-4/5).\]Its predicted change is \((3,4)^\top(-3/5,-4/5)=-5\), the smallest possible among all unit-length updates. If instead \(g_t=0\), the first-order model predicts no change in any direction, so it cannot choose a descent direction from gradient information alone.
Math foundation: Euclidean length and the Cauchy–Schwarz inequality (Click to expand)
For a vector \(a=(a_1,\ldots,a_d)\), its Euclidean or \(L_2\) length is
\[\lVert a\rVert_2=\sqrt{a_1^2+\cdots+a_d^2}.\]This is the ordinary straight-line distance formula extended to \(d\) dimensions. The dot product satisfies
\[a^\top b=\lVert a\rVert_2\lVert b\rVert_2\cos\phi,\]where \(\phi\) is the angle between the vectors. It is largest when they point the same way \((\cos\phi=1)\), zero when they are perpendicular, and smallest when they point in exactly opposite directions \((\cos\phi=-1)\). Because \(-1\le\cos\phi\le1\),
\[-\lVert a\rVert_2\lVert b\rVert_2 \le a^\top b \le\lVert a\rVert_2\lVert b\rVert_2.\]This bound is the Cauchy–Schwarz inequality. It can also be derived algebraically from the fact that a squared length can never be negative. For \(b\ne0\),
\[0\le\left\lVert a-\frac{a^\top b}{\lVert b\rVert_2^2}b \right\rVert_2^2 =\lVert a\rVert_2^2- \frac{(a^\top b)^2}{\lVert b\rVert_2^2},\]which rearranges to \((a^\top b)^2\le\lVert a\rVert_2^2\lVert b\rVert_2^2\).
Apply the angle picture with \(a=g_t\) and \(b=\Delta\theta\). If every candidate update has length \(r\), then the most negative possible predicted change is
\[g_t^\top\Delta\theta=-r\lVert g_t\rVert_2,\]achieved by \(\Delta\theta=-r\,g_t/\lVert g_t\rVert_2\). Gradient descent writes the same opposite direction as \(\Delta\theta=-\eta_tg_t\); its corresponding radius is \(r=\eta_t\lVert g_t\rVert_2\). Thus the inequality is the mathematical reason “opposite the gradient” solves the fixed-length local choice.
Thus the negative gradient is not merely a downhill direction: under the ordinary Euclidean notion of a fixed-size move, it gives the largest decrease predicted by the local linear model. Gradient descent applies exactly this update:
\[\boxed{\theta_{t+1}=\theta_t-\eta_t g_t}.\]This conclusion has two qualifications. It is about the local approximation, not the entire landscape, so it does not promise the global minimum. And it determines a direction but not a safe travel distance. An arbitrarily large step can leave the neighborhood where the Taylor model is accurate and increase the real loss. That remaining decision is the learning rate.
1.2 From a Direction to a Distance: the Learning Rate
The learning rate converts the gradient direction into a displacement. Too small wastes iterations; too large makes the local prediction unreliable and can overshoot. A quadratic is a degree-two function; it is the simplest function with nonzero curvature. A one-dimensional quadratic lets us see this tradeoff without any neural-network detail:
\[L(\theta)=\frac12a\theta^2, \qquad g=a\theta, \qquad a>0.\]Gradient descent becomes
\[\theta_{t+1}=(1-\eta a)\theta_t.\]This one equation shows three regimes:
- if \(0<\eta a<1\), the parameter approaches zero without changing sign;
- if \(1<\eta a<2\), it crosses zero on every step but the oscillation shrinks;
- if \(\eta a>2\), the magnitude grows and training diverges.
Here \(a\) measures curvature: large \(a\) means the loss bends upward sharply. The three regimes show that “the gradient points downhill” is not enough. The step must be small relative to the distance over which the surface bends. In many dimensions, different directions have different curvatures, so the next difficulty is that one global learning rate must somehow serve all of them.
Loss scale and learning rate are coupled. Replacing \(L\) by \(cL\) multiplies every gradient by \(c\). Plain SGD with learning rate \(\eta\) then behaves like the original loss with learning rate \(c\eta\). For a batch of \(b\) examples, “mean reduction” uses \(b^{-1}\sum_i\ell_i\) while “sum reduction” uses \(\sum_i\ell_i\); the latter is \(b\) times larger on the same batch. Switching between them can therefore require a corresponding learning-rate change.
2. Stochastic Gradient Descent
The update derived above is the cleanest possible baseline, but it quietly assumes two conveniences. First, \(g_t\) faithfully describes the objective we care about. Second, measuring every parameter coordinate with the same Euclidean ruler is sensible. Neural-network training violates both assumptions: the gradient is estimated from sampled data, and the loss bends at very different rates in different directions. We will introduce these difficulties separately so that each later modification has a clear job.
2.1 Mini-Batches Turn the Gradient into an Estimate
The population objective averages over every possible data example, so its exact gradient is itself an expectation. The true data distribution is unknown, and even averaging over every example in a large stored dataset before every update would be expensive. A mini-batch makes one update affordable: for a sampled set \(B_t\) of size \(b\), we use
\[g_t=\frac1b\sum_{i\in B_t}\nabla_\theta\ell(\theta_t;\xi_i).\]Why is this a reasonable substitute? Under ordinary independent uniform sampling, each example has the correct chance to appear. Averaging over all possible choices of the mini-batch therefore recovers the full dataset gradient:
\[\mathbb E[g_t\mid\theta_t]=\nabla L(\theta_t).\]Here \(\mid\theta_t\) means that \(\theta_t\) is held fixed while the expectation averages only over the random choice of mini-batch.
Here \(L\) denotes the finite-dataset average. This equality does not say that the dataset gradient equals the unknown population gradient; the dataset itself is only a sample from the world. There are therefore two sampling gaps: a mini-batch approximates the dataset, and the dataset approximates the population.
The word unbiased describes the first gap—an average over hypothetical mini-batches. It does not say that the particular batch in front of us equals the full gradient. One batch may contain unusually easy examples, another unusually hard ones, so their gradients can differ even at the same \(\theta_t\). Increasing batch size usually lowers this sampling variation, but costs more computation per update.
The tradeoff is now visible. A full-batch gradient obtains a more stable direction but waits longer before moving. A mini-batch gradient is cheap and frequent, but every estimate is uncertain. Combining this estimate with the gradient-descent update produces SGD, whose complete update appears below in this section. Momentum will then use history to distinguish persistent signal from batch-to-batch fluctuation.
2.2 Why Plain SGD Needs More Context
Even with an exact full-batch gradient, one global learning rate can be inefficient. Section 1 used only the first-order Taylor term to choose a direction. To understand how long that direction remains trustworthy, we must look at the next term:
\[L(\theta_t+\Delta\theta)\approx L(\theta_t)+g_t^\top\Delta\theta +\frac12\Delta\theta^\top H_t\Delta\theta.\]The Hessian \(H_t\) is the matrix of second derivatives. It records curvature: how the gradient itself changes as we move. Near a smooth local minimum \(\theta^*\), the gradient is approximately zero, leaving the familiar quadratic model
\[L(\theta)\approx L(\theta^*)+ \frac12(\theta-\theta^*)^\top H(\theta-\theta^*).\]An eigenvector of \(H\) is a direction in which this quadratic does not mix with the other directions; its eigenvalue \(\lambda_i\) is the curvature along that direction. Gradient descent there behaves exactly like the one-dimensional example with \(a=\lambda_i\). Stability is limited by the largest curvature, while progress in a flat direction is controlled by the smallest.
The objective in Figure 1 makes this concrete:
\[L(x,y)=\frac12(x^2+12y^2), \qquad \nabla L(x,y)=(x,12y).\]The same displacement in \(y\) changes the loss twelve times as sharply as in \(x\). Stability in the \(y\) direction requires \(\eta<2/12=1/6\). But after respecting that limit, the update along the flatter \(x\) direction is necessarily modest. The path therefore tends to bounce across the narrow valley while advancing slowly along it. More generally, a large condition number
\[\kappa=\frac{\lambda_{\max}}{\lambda_{\min}}\]creates exactly this separation of scales.
Linear-algebra foundation: Hessian, eigenvectors, and condition number (Click to expand)
The gradient contains first derivatives. Differentiating again produces the Hessian matrix
\[H_{ij}=\frac{\partial^2L}{\partial\theta_i\partial\theta_j}.\]A diagonal entry \(H_{ii}\) measures how the slope in coordinate \(i\) changes as that same coordinate moves. An off-diagonal entry \(H_{ij}\) measures interaction: moving \(\theta_j\) changes the slope seen by \(\theta_i\). For an ordinary twice-smooth loss, \(H\) is symmetric, meaning \(H_{ij}=H_{ji}\).
An eigenvector \(v\) of \(H\) is a direction whose orientation is preserved by the matrix:
\[Hv=\lambda v.\]The scalar \(\lambda\) is its eigenvalue. Near a point where the gradient is zero, moving a distance \(a\) along a unit eigenvector changes the quadratic model by
\[L(\theta^*+av)-L(\theta^*)\approx\frac12\lambda a^2.\]Thus \(\lambda>0\) bends upward, a small \(\lambda>0\) is flat, and \(\lambda<0\) reveals a direction that bends downward. A local minimum is no worse than all sufficiently nearby points; a global minimum is no worse than every point in the entire domain. Neural-network losses can also contain saddle points with both positive and negative curvature.
When the curvatures under discussion are positive, the condition number
\[\kappa=\lambda_{\max}/\lambda_{\min}\]compares the steepest and flattest eigen-directions. \(\kappa\approx1\) describes a locally round bowl; \(\kappa\gg1\) describes an elongated one. If \(\lambda_{\min}=0\), the ratio is infinite; if negative eigenvalues are present, this positive-bowl condition number is not an adequate summary of the local geometry.
We have now exposed two different losses of information. A current mini-batch gradient does not tell us which components will persist on the next batch, and its raw values do not tell us whether a large component comes from a useful direction or merely from a differently scaled, highly curved direction.
Here a coordinate means one scalar position in the parameter vector. If
\[\theta=(\theta_1,\ldots,\theta_d), \qquad g_t=(g_{t,1},\ldots,g_{t,d}),\]then \(g_{t,i}=\partial L/\partial\theta_i\) is the gradient component associated with parameter \(\theta_i\). “Across coordinates” means comparing these components and their histories. For example, suppose several successive gradients look like
\[g_1=(100,0.01),\qquad g_2=(80,-0.02),\qquad g_3=(120,0.01).\]The first coordinate repeatedly has magnitude near \(100\), whereas the second is near \(0.01\). Plain SGD multiplies both by the same learning rate, so its first-coordinate update will be thousands of times larger. But a persistently large gradient does not by itself prove that this parameter should move much farther: the difference can also come from parameter units, network parameterization, or curvature. An optimizer may therefore accumulate two kinds of context:
- across steps: has a gradient component kept the same direction, or has its sign fluctuated over time?
- across coordinates: do different parameters’ gradients persistently live on different magnitude scales, so their update scales should be adjusted separately?
Momentum uses the first kind of history. RMSProp records a typical squared-gradient magnitude separately for every coordinate and uses the second. Adam uses both.
2.3 An Optimizer Is a State-Update Rule
A stateless rule sees only the current \(g_t\). It cannot distinguish a component that has pointed the same way for twenty steps from one that alternates sign on every step; nor can it know whether a large coordinate is consistently large. To make those distinctions, the optimizer must carry information from earlier steps. We can write such an optimizer abstractly as
\[s_t=F(s_{t-1},g_t,t), \qquad \theta_{t+1}=\theta_t+U(s_t,g_t,\eta_t),\]where \(s_t\) is optimizer state: a compact summary of the gradient history. The function \(F\) updates that memory; \(U\) turns the memory and current gradient into a parameter change. SGD without momentum has no persistent per-parameter state. Momentum stores one moving average. Adam stores two. These buffers survive across training steps and must be checkpointed if training is to resume with identical dynamics. Their memory cost is discussed separately in LLM Optimization Basics: Memory.
2.4 The Plain SGD Algorithm
We now have the two ingredients needed to define the standard baseline. Gradient descent says how to update from a gradient; mini-batching says how to obtain an affordable estimate of that gradient. Stochastic gradient descent (SGD) combines them:
\[\boxed{ g_t=\frac1b\sum_{i\in B_t}\nabla_\theta\ell(\theta_t;\xi_i), \qquad \theta_{t+1}=\theta_t-\eta_tg_t.}\]One SGD step has a concrete order:
- sample a mini-batch \(B_t\);
- run the model and average its per-example losses on that batch;
- use backpropagation to compute the mini-batch gradient \(g_t\);
- multiply it by \(-\eta_t\) and update the parameters.
The word stochastic refers to step 1: because the batch is random, \(g_t\) and the resulting update are random. Once \(B_t\), \(\theta_t\), and \(\eta_t\) are fixed, the plain SGD rule itself is deterministic. When the mini-batch estimator is unbiased and the learning rate is fixed during the conditional expectation,
\[\mathbb E[\Delta\theta_t\mid\theta_t] =-\eta_t\mathbb E[g_t\mid\theta_t] =-\eta_t\nabla L(\theta_t).\]Thus one update need not lower the full objective, but its expected local direction matches full-batch gradient descent. The computational advantage is that one step processes \(b\) examples rather than the entire dataset. The price is sampling noise.
Plain SGD stores no moving average or per-coordinate scale: apart from the parameters themselves and an external step counter or schedule, the next update uses only the current batch gradient. This makes it a low-memory, transparent baseline. It also leaves both difficulties identified above unresolved: batch fluctuations pass directly into the update, and one global learning rate still serves every coordinate.
An optimizer step and an epoch are different units. One step consumes one effective batch and updates parameters once; one epoch processes roughly one dataset’s worth of examples. With gradient accumulation, parameters stay fixed while \(K\) microbatch gradients are combined, typically as \(g_t=K^{-1}\sum_{k=1}^K g_t^{(k)}\), before one optimizer update. It enlarges the effective batch without storing all examples’ activations at once; it does not create \(K\) optimizer steps.
Terminology warning. Libraries sometimes use “SGD” as the class name for both plain SGD and SGD with momentum. In this article, plain SGD means the update above with no momentum buffer; “SGD + momentum” explicitly means the stateful method introduced next.
2.5 SGD with Momentum: Consistency across Steps
Write a mini-batch gradient informally as “persistent direction + sampling fluctuation.” We do not know either term separately, but repeated observations help: a component that keeps the same sign is more credible evidence of a persistent direction, while rapidly alternating components tend to cancel when averaged.
A simple average of every past gradient would eventually react very slowly because ancient gradients—computed at quite different parameters—would retain the same weight as recent ones. Momentum instead uses an exponential moving average (EMA), which gives the newest gradient weight \(1-\beta\) and discounts the existing history by \(\beta\):
\[m_t=\beta m_{t-1}+(1-\beta)g_t,\] \[\boxed{\theta_{t+1}=\theta_t-\eta_t m_t}, \qquad 0\le\beta<1.\]The first equation updates the memory; the second uses that smoothed direction in place of the raw current gradient. Expanding the recurrence shows the exact weights:
\[m_t=(1-\beta)\sum_{k=1}^{t}\beta^{t-k}g_k\]when \(m_0=0\). Within the current buffer \(m_t\), a more recent gradient has a larger direct coefficient: the coefficient on a gradient \(j\) steps old is \((1-\beta)\beta^j\). The characteristic averaging window is on the order of \(1/(1-\beta)\) steps: about \(10\) for \(\beta=0.9\) and \(100\) for \(\beta=0.99\). This is a scale, not a hard cutoff; older gradients never disappear abruptly.
This statement does not say that the newest data always has the greatest influence on the entire training trajectory. At the first step,
\[m_1=(1-\beta)g_1,\]so \(g_1\) is the only observed direction and therefore determines the direction completely; the factor \(1-\beta\) only shrinks the buffer magnitude under this convention. That first update then changes \(\theta_1\), which changes every gradient computed afterward. Early gradients can therefore have a lasting indirect effect through the parameters, even after their direct coefficients inside a later buffer \(m_t\) have decayed. The expansion above describes the latter only.
The name “momentum” comes from the qualitative analogy with velocity: the update carries some previous direction forward instead of responding only to the force-like current gradient. The formula is an optimization rule, not a literal simulation of physical mechanics.
Math foundation: how does an exponential moving average remember history? (Click to expand)
An arithmetic average gives equal weight to all observations. An exponential moving average instead repeats the rule
\[m_t=\beta m_{t-1}+(1-\beta)g_t.\]For example,
\[m_3=(1-\beta)g_3 +(1-\beta)\beta g_2 +(1-\beta)\beta^2g_1 +\beta^3m_0.\]Each additional step multiplies an old weight by \(\beta\), so weights decay exponentially with age—hence the name. With \(m_0=0\), the observed-gradient weights sum to the geometric series
\[(1-\beta)(1+\beta+\cdots+\beta^{t-1})=1-\beta^t.\]At early steps this is below one because some weight still belongs to the zero initialization. This fact will motivate Adam’s bias correction.
The heuristic window \(1/(1-\beta)\) describes the number of recent observations carrying most of the influence. Another useful measure is the half-life \(\log(1/2)/\log\beta\): after that many steps, a gradient’s weight has halved. Setting \(\beta=0\) keeps only the current gradient; moving \(\beta\) toward one gives smoother but slower-changing memory.
Why does this help in a narrow valley? Across the steep direction, successive gradients often alternate signs, so they cancel in the moving average. Along the shallow direction, their signs remain consistent, so they survive the averaging. Momentum therefore damps side-to-side oscillation while preserving motion along the valley. With the normalized EMA convention used here, any additional acceleration depends on the learning rate and the dynamics—not on the buffer’s raw magnitude growing without bound.
Momentum formulas use different conventions. Some libraries store \(v_t=\beta v_{t-1}+g_t\) without the factor \(1-\beta\) and then update with \(v_t\). This rescales the buffer and therefore changes which numerical learning rate is equivalent. Compare complete update equations, not just the name “momentum.”
What changes in Nesterov momentum? (Click to expand)
Ordinary momentum computes the gradient at the current point and then follows its accumulated direction. Nesterov’s idea is to evaluate the gradient after looking ahead in the momentum direction. In one common convention,
\[g_t=\nabla L(\theta_t-\eta\beta v_{t-1}),\] \[v_t=\beta v_{t-1}+g_t, \qquad \theta_{t+1}=\theta_t-\eta v_t.\]The look-ahead gradient can correct the trajectory before momentum carries it too far. Library implementations often use algebraically rearranged forms, so exact state definitions again matter.
3. Adam
3.1 Coordinate-wise Scaling
Momentum addresses when gradient evidence is consistent, but it still measures every coordinate in raw gradient units. Return to the narrow valley: the steep coordinate may be numerically large even when we are already close to the valley floor, while a smaller gradient along the flat coordinate may be the direction in which substantial progress remains.
Does this contradict the claim that \(-g_t\) is the best direction? No. Section 1 proved a narrower statement: using only the linear Taylor model, among updates with the same Euclidean length, \(-g_t\) gives the largest immediate predicted decrease. The gradient’s magnitude is a slope—loss change per unit parameter change—not a measurement of the distance to the minimum or of how long that slope will remain valid.
A one-dimensional quadratic makes the missing information explicit:
\[L(\theta)=\frac12a\theta^2, \qquad g=a\theta, \qquad \theta^*=0.\]The same observed gradient \(g=1\) could mean \(\theta=1\) when \(a=1\), but only \(\theta=0.01\) when \(a=100\). The gradient has the same sign and magnitude in both cases, yet the distances to the minimum differ by a factor of one hundred. We need the curvature \(a\) to recover the appropriate quadratic step:
\[\Delta\theta^*=-\theta=-\frac{g}{a}.\]In several dimensions, the analogous quadratic step is \(-H^{-1}g\) when the Hessian \(H\) is positive definite; it is generally not parallel to \(-g\). Thus coordinate-wise scaling does not repair a gradient that “forgot” its magnitude. It uses additional scale information to reinterpret how far each gradient component should move. Adaptive optimizers do not know the exact Hessian: their historical squared-gradient statistics provide a practical diagonal scaling heuristic.
Here global multiplier means the one scalar learning rate shared by all coordinates, not an optimizer that can find a global optimum. In plain gradient descent,
\[\Delta\theta_i=-\eta g_i,\]so \(\Delta\theta_i/g_i=-\eta\) for every \(i\). Changing \(\eta\) expands or contracts the whole update, but it cannot make the steep coordinate cautious relative to its gradient while making the flat coordinate aggressive. For example, consider
\[L(x,y)=\frac12(100x^2+y^2).\]At \((x,y)=(0.1,1)\), the gradient is \((10,1)\) even though the remaining distances to the minimum \((0,0)\) are only \(0.1\) in \(x\) and \(1\) in \(y\). The shared multiplier produces
\[\Delta(x,y)=(-10\eta,-\eta).\]Every choice of \(\eta\) preserves this \(10:1\) update ratio. The steep \(x\) direction forces \(\eta\) to remain small for stability; that same small number then makes progress along the flat \(y\) direction slow. Momentum may smooth sign changes over time, but its update \(-\eta m_t\) still applies one scalar to all components of the raw-unit vector \(m_t\). Distinguishing coordinate scales requires a vector of effective learning rates—or, equivalently, a separate scale estimate for every coordinate.
Adaptive methods therefore build a separate recent scale for every coordinate and divide by it. To estimate magnitude without positive and negative gradients cancelling, they accumulate \(g_t^2\) rather than \(g_t\). Taking a square root converts the squared quantity back to gradient units, so those units cancel in “gradient divided by typical gradient magnitude.” The ratio is dimensionless—it has no remaining physical unit—before the global learning rate is applied.
AdaGrad: Accumulate Squared Gradients
The most direct version is AdaGrad. Beginning from \(v_0=0\), it adds every squared gradient observed so far:
\[v_t=v_{t-1}+g_t\odot g_t,\]where \(\odot\) denotes element-wise multiplication, not a dot product or matrix multiplication. If
\[g_t=(g_{t,1},\ldots,g_{t,d}),\]then
\[g_t\odot g_t=(g_{t,1}^2,\ldots,g_{t,d}^2).\]Thus \(v_t\) has the same shape as \(g_t\), and coordinate \(v_{t,i}\) accumulates only the squared gradients previously observed for parameter \(\theta_i\). AdaGrad then updates
\[\theta_{t+1}=\theta_t-\eta\frac{g_t}{\sqrt{v_t}+\epsilon}.\]The square root, addition, and division in this update are also element-wise. Written for one coordinate,
\[\theta_{t+1,i}=\theta_{t,i} -\frac{\eta}{\sqrt{v_{t,i}}+\epsilon}g_{t,i}.\]Thus coordinate \(i\) has effective learning rate \(\eta/(\sqrt{v_{t,i}}+\epsilon)\). A coordinate that repeatedly receives large gradients builds a large denominator and takes smaller future steps. A rare feature—one active in only a small fraction of examples—produces zero gradient on most steps and retains a relatively large effective step, which makes AdaGrad attractive for sparse data. The small positive \(\epsilon\) prevents division by zero before a coordinate has accumulated any scale.
Its weakness is visible in the recurrence: \(v_t\) only increases. Effective learning rates continually shrink and can become too small during long nonstationary neural-network training.
RMSProp: Forget Stale Squared Gradients
AdaGrad treats a gradient from the first training step as permanently relevant. But the model and its loss geometry change throughout training, so an old scale estimate can become stale. RMSProp makes one surgical change: replace the never-forgetting sum with an exponential moving average,
\[v_t=\beta_2v_{t-1}+(1-\beta_2)g_t\odot g_t,\] \[\boxed{\theta_{t+1}=\theta_t-\eta_t\frac{g_t}{\sqrt{v_t}+\epsilon}}.\]Statistics foundation: mean square, RMS, second moment, and variance (Click to expand)
Given scalar observations \(q_1,\ldots,q_n\), their mean, mean square, and root mean square are
\[\operatorname{mean}(q)=\frac1n\sum_jq_j,\] \[\operatorname{MS}(q)=\frac1n\sum_jq_j^2, \qquad \operatorname{RMS}(q)=\sqrt{\operatorname{MS}(q)}.\]Squaring prevents signs from cancelling. For observations \(+3\) and \(-3\), the mean is zero but the RMS is three, correctly recording their typical magnitude. RMSProp applies this idea separately to each gradient coordinate and replaces the equal-weight mean by an exponential moving average, so \(v_{t,i}\) is a recent mean square and \(\sqrt{v_{t,i}}\) is its recent RMS.
In probability notation, \(\mathbb E[g_i^2]\) is the raw or uncentered second moment. The variance instead measures deviations from the mean \(\mu_i=\mathbb E[g_i]\):
\[\operatorname{Var}(g_i) =\mathbb E[(g_i-\mu_i)^2] =\mathbb E[g_i^2]-\mu_i^2.\]RMSProp wants a magnitude scale, not dispersion around the mean, so it uses the uncentered quantity. The square root restores the original gradient units. The small \(\epsilon>0\) prevents division by zero and sets a floor below which normalization stops becoming stronger.
The denominator estimates each coordinate’s recent root-mean-square gradient. Dividing by it reduces persistent scale differences: after enough steps, multiplying one coordinate’s gradients by a positive constant approximately multiplies both numerator and denominator by that constant, leaving the normalized update similar. The equivalence is only approximate because of initialization, \(\epsilon\), momentum, clipping, and nonstationarity.
The quantity \(v_t\) is called an uncentered second moment because a moment is an average of a power: the first raw moment averages \(g\), and the second averages \(g^2\). It is not the statistical variance; variance would be \(\mathbb E[g^2]-\mathbb E[g]^2\).
3.2 Combining Momentum and Coordinate-wise Scaling
Momentum and RMSProp changed two independent parts of plain SGD. Momentum replaced the noisy numerator by a smoothed direction. RMSProp kept the current numerator but divided it by a recent coordinate-wise scale. Adam applies both ideas at once: smooth the direction in the numerator and normalize it by the smoothed magnitude in the denominator.
It therefore maintains two buffers:
\[m_t=\beta_1m_{t-1}+(1-\beta_1)g_t,\] \[v_t=\beta_2v_{t-1}+(1-\beta_2)g_t\odot g_t.\]The names “first moment” and “second moment” refer here to averages of the observed gradient stream: \(m_t\) averages \(g_t\), whereas \(v_t\) averages \(g_t^2\). They are not moments of the training-data distribution or of the model’s predictions.
Both buffers start at zero. During the first few steps, part of their notional averaging window is therefore filled with zeros rather than observations, which pulls them toward zero. Adam corrects this initialization bias:
\[\hat m_t=\frac{m_t}{1-\beta_1^t}, \qquad \hat v_t=\frac{v_t}{1-\beta_2^t}.\]The update is
\[\boxed{\theta_{t+1}=\theta_t-\eta_t \frac{\hat m_t}{\sqrt{\hat v_t}+\epsilon}}.\]Every part now has a distinct role:
| Quantity | Meaning | Main effect |
|---|---|---|
| \(g_t\) | current stochastic gradient | newest local information |
| \(m_t\) | EMA of gradients | smooths direction over time |
| \(v_t\) | EMA of squared gradients | estimates coordinate-wise scale |
| \(\hat m_t,\hat v_t\) | bias-corrected moments | removes zero-initialization shrinkage |
| \(\eta_t\) | global learning rate | sets overall step scale |
| \(\epsilon\) | numerical floor | prevents division by zero and caps amplification of tiny scales |
Does \(v_t\) affect the update direction? For one scalar coordinate, its nonnegative denominator cannot change the sign set by \(m_t\); it changes only that coordinate’s magnitude. For the full parameter vector, however, different entries of \(v_t\) rescale coordinates by different amounts and therefore generally rotate the update. Ignoring \(\epsilon\), for example,
\[\hat m=(1,1),\quad \hat v=(1,100) \quad\Longrightarrow\quad -\frac{\hat m}{\sqrt{\hat v}}=(-1,-0.1),\]which is not parallel to \(-\hat m=(-1,-1)\). The numerator supplies each coordinate’s sign; the denominator changes the coordinates’ relative magnitudes.
The following pseudocode puts one complete Adam step in execution order. Hover a highlighted symbol—or focus it with the keyboard—to inspect what it stores and why it is needed.
θ ← initial_parameters()
m ← zeros_like(θ)
v ← zeros_like(θ)
t ← 0
repeat until the stopping condition:
t ← t + 1
B ← sample_minibatch()
g ← minibatch_gradient(θ, B)
m ← β₁·m + (1−β₁)·g
v ← β₂·v + (1−β₂)·(g ⊙ g)
m̂ ← m / (1−β₁^t)
v̂ ← v / (1−β₂^t)
θ ← θ − ηₜ·m̂ / (sqrt(v̂) + ε)
return θ 3.3 Why Is Bias Correction Necessary?
Suppose the gradient is the same vector \(g\) for the first several steps. Starting from zero,
\[m_t=(1-\beta_1^t)g, \qquad v_t=(1-\beta_2^t)g^2.\]Statistics foundation: what does “bias” mean in bias correction? (Click to expand)
Statistical bias is systematic error in an estimator’s average. If \(\widehat\mu\) estimates a target \(\mu\), then
\[\operatorname{Bias}(\widehat\mu)=\mathbb E[\widehat\mu]-\mu.\]Suppose, for intuition, that gradients come from a stationary process—one whose relevant statistics do not change over steps—with \(\mathbb E[g_t]=\mu\) and \(m_0=0\). Expanding the EMA gives
\[\mathbb E[m_t]=(1-\beta_1^t)\mu,\]which is pulled toward zero by the factor \(1-\beta_1^t\). Dividing by that factor gives \(\mathbb E[\hat m_t]=\mu\) in this simplified setting. The same reasoning applies to \(v_t\) with target \(\mathbb E[g_t^2]\).
This use of “bias” is unrelated to a neural layer’s trainable bias parameter. It also does not claim that corrected moments are noiseless or perfectly unbiased during nonstationary training, where \(\theta_t\) and the gradient distribution keep changing. It corrects the specific, known shrinkage caused by initializing the EMA buffers at zero.
Why do those denominators have exactly this form? The EMA weights accumulated through step \(t\) sum to \(1-\beta^t\), not one. Dividing by that sum renormalizes the observed weights. Equivalently, in the constant-gradient example, division by \(1-\beta_1^t\) and \(1-\beta_2^t\) recovers \(g\) and \(g^2\). The correction approaches one as the history fills, so it matters most near the start of training.
An instructive consequence appears on the first step. Ignoring \(\epsilon\),
\[\frac{\hat m_1}{\sqrt{\hat v_1}} =\frac{g_1}{|g_1|} =\operatorname{sign}(g_1)\]coordinate-wise. Adam’s first update depends mainly on the signs of nonzero gradient coordinates, not their raw magnitudes. This is one reason an Adam learning rate is not numerically interchangeable with an SGD learning rate.
Here \(\operatorname{sign}(a)\) is \(+1\) when \(a>0\), \(-1\) when \(a<0\), and \(0\) when \(a=0\). The statement is an approximation for nonzero coordinates because the actual \(\epsilon\) prevents exact cancellation.
3.4 What Problem Does Adam Solve—and Not Solve?
Adam is helpful when gradients are noisy, sparse, or very differently scaled across coordinates. It often reaches a useful training regime with less tuning than plain SGD. But its denominator rescales coordinates independently; it cannot rotate the update to undo off-diagonal interactions between parameters, infer how far the local approximation remains valid, or guarantee a better minimum. A small recent \(v_{t,i}\) can also amplify coordinate \(i\). The floor \(\epsilon\) limits that amplification; learning-rate warmup begins with deliberately small steps; gradient clipping caps unusually large gradient norms; and sufficient numerical precision keeps these small statistics representable.
The usual defaults \(\beta_1=0.9\), \(\beta_2=0.999\), and a small \(\epsilon\) are starting points, not laws. The much larger \(\beta_2\) gives the scale estimate a longer, steadier window than the direction estimate. Changing batch size, loss normalization, model scale, or precision can change the appropriate learning rate and sometimes the moment constants.
4. AdamW
So far every modification has tried to use the data gradient more effectively. Weight decay asks a separate question: besides fitting the training objective, do we want to prefer parameter vectors with smaller norms? Such a preference can act as regularization or norm control, though its effect depends on the architecture. It is easy to conflate with the optimizer because it is applied during the same update.
The traditional way to express this preference is to add an \(L_2\) penalty to the loss. This gives
\[L_{\mathrm{reg}}(\theta)=L(\theta)+\frac\lambda2\lVert\theta\rVert_2^2, \qquad \lambda\ge0,\]and gradient
\[\nabla L_{\mathrm{reg}}(\theta)=g+\lambda\theta.\]Math foundation: $$L_2$$ regularization and weight decay (Click to expand)
The squared \(L_2\) norm is
\[\lVert\theta\rVert_2^2=\sum_i\theta_i^2.\]Adding it to the data loss means that two parameter vectors with similar data fit need not have the same objective: the one with the larger norm pays a larger penalty. The coefficient \(\lambda\) controls the tradeoff; \(\lambda=0\) removes the preference, while a larger \(\lambda\) emphasizes it more strongly.
The factor \(1/2\) is included only to simplify differentiation:
\[\frac{\partial}{\partial\theta_i} \left(\frac\lambda2\sum_j\theta_j^2\right) =\lambda\theta_i.\]Collecting all coordinates gives gradient \(\lambda\theta\), which always points away from the origin. Subtracting it therefore moves parameters toward zero. Regularization is any preference added to fitting the observed training data, commonly with the goal of improving behavior on held-out data. Smaller norm is a useful inductive preference in many settings, not a universal guarantee of better generalization.
“\(L_2\) regularization” names the penalty added to the objective. “Weight decay” names the direct parameter operation \(\theta\leftarrow(1-\eta\lambda)\theta\). They coincide for plain SGD, as the next algebra shows, but not automatically for an adaptive optimizer.
For plain SGD, substituting this gradient into the update and collecting the two terms gives
\[\theta_{t+1} =\theta_t-\eta(g_t+\lambda\theta_t) =(1-\eta\lambda)\theta_t-\eta g_t.\]The factor \(1-\eta\lambda\) literally shrinks every selected parameter by the same proportion on that step. This is why \(L_2\) regularization and weight decay are equivalent for plain SGD.
For Adam, however, inserting \(\lambda\theta\) into the gradient sends the penalty through the first- and second-moment normalization. A coordinate’s penalty is then divided by a history-dependent scale, so different coordinates experience different effective shrinkage. Coupled \(L_2\) regularization is no longer the same operation as uniform weight decay.
AdamW keeps the loss gradient and decay separate:
\[\boxed{\theta_{t+1} =(1-\eta_t\lambda)\theta_t -\eta_t\frac{\hat m_t}{\sqrt{\hat v_t}+\epsilon}}.\]The moments are computed from the data gradient \(g_t\), not from \(g_t+\lambda\theta_t\). This is the meaning of decoupled weight decay.
“No decay on bias and normalization parameters” is a modeling convention, not part of AdamW’s definition. It is common in Transformer training because those parameters play special scale and offset roles, but the correct parameter groups are architecture- and experiment-dependent. They must be recorded explicitly.
Here is a minimal array-level implementation. A production model stores parameters in a parameter tree, a nested collection of named arrays. Distributed training also reduces gradients by combining contributions from multiple devices. The example omits those structures, mixed precision, and fused kernels so the update equation remains visible.
import jax.numpy as jnp
def adamw_step(params, grads, state, lr,
beta1=0.9, beta2=0.999,
eps=1e-8, weight_decay=0.01):
t = state["t"] + 1
m = beta1 * state["m"] + (1.0 - beta1) * grads
v = beta2 * state["v"] + (1.0 - beta2) * jnp.square(grads)
m_hat = m / (1.0 - beta1 ** t)
v_hat = v / (1.0 - beta2 ** t)
params = ((1.0 - lr * weight_decay) * params
- lr * m_hat / (jnp.sqrt(v_hat) + eps))
return params, {"t": t, "m": m, "v": v}
The code assumes \(t\) counts optimizer updates beginning at zero and that \(m,v\) have the same shape as the parameter array. Production libraries may place \(\epsilon\) differently, use AMSGrad, apply capturable step counters, or fuse decay and updates. Here, placing \(\epsilon\) differently means choosing \(\sqrt{\hat v}+\epsilon\) versus \(\sqrt{\hat v+\epsilon}\); AMSGrad replaces the current second-moment denominator by a running maximum; a capturable counter stores \(t\) where a compiled accelerator graph can access it; and a fused kernel performs several array operations together to reduce memory traffic. These choices preserve the central idea but can matter for exact numerical reproduction.
5. Muon
Adam’s scale estimate is coordinate-wise: it would work the same way if a weight matrix were flattened into a long vector. But a matrix in a linear layer is not merely stored in two dimensions by accident. If \(W\) maps an activation \(h\) to \(Wh\), its rows and columns jointly describe input and output directions. A matrix update can be strong along one pair of directions and weak along another. Treating each entry independently discards this structure.
Muon starts from the same temporal question as momentum and then changes the geometry of the resulting matrix update. For a weight \(W\in\mathbb R^{m\times n}\), its gradient \(G_t\) and momentum \(M_t\) have the same shape. First form the momentum matrix
\[M_t=\beta M_{t-1}+(1-\beta)G_t.\]To see the next operation, recall what a singular value decomposition says. Any matrix can be written
\[M_t=U\Sigma V^\top.\]The columns of \(V\) identify orthogonal input directions, the columns of \(U\) identify the corresponding output directions, and the nonnegative diagonal entries of \(\Sigma\)—the singular values—say how strongly the update acts along each paired direction. If one singular value is much larger than the others, that mode dominates the matrix update.
Ideal orthogonalization keeps the two sets of directions but replaces every nonzero singular value by one:
\[\operatorname{Ortho}(M_t)=UV^\top.\]Matrix foundation: orthogonality, SVD, and Newton–Schulz iteration (Click to expand)
A matrix \(W\in\mathbb R^{m\times n}\) maps an \(n\)-dimensional input to an \(m\)-dimensional output. Two unit vectors are orthogonal when their dot product is zero. A square matrix \(Q\) is orthogonal when
\[Q^\top Q=QQ^\top=I,\]which means it preserves lengths and right angles. A rectangular matrix cannot satisfy both identities, but it may have orthonormal columns \((Q^\top Q=I)\) or orthonormal rows \((QQ^\top=I)\); this is the semi-orthogonal case.
The SVD
\[M=U\Sigma V^\top\]describes the action mode by mode. For the \(k\)th right singular vector \(v_k\),
\[Mv_k=\sigma_k u_k.\]Thus the input direction \(v_k\) is sent to output direction \(u_k\) and scaled by singular value \(\sigma_k\). Replacing every nonzero \(\sigma_k\) by one produces \(UV^\top\): keep the paired directions, remove their unequal magnitudes.
How can this be approximated without computing an SVD? For a tall matrix whose singular values have first been scaled into a suitable range, the classical Newton–Schulz polar iteration is
\[X_{k+1}=\frac12X_k\left(3I-X_k^\top X_k\right).\]If \(X_k\) has singular value \(s\), the next one follows the scalar map \(s\mapsto\tfrac12s(3-s^2)\). One is a fixed point, meaning the map leaves \(s=1\) unchanged. Repeating the matrix formula therefore pushes suitable singular values toward one using only matrix multiplications. For a wide matrix, the dimensionally appropriate form multiplies \(\tfrac12(3I-X_kX_k^\top)X_k\) instead. Practical Muon implementations often use higher-order polynomial coefficients and a fixed small number of iterations rather than this textbook cubic formula.
The starting matrix is normalized because the iteration converges only over a suitable singular-value range. One possible scale is the Frobenius norm
\[\lVert X\rVert_F=\sqrt{\sum_{i,j}X_{ij}^2}.\]After orthogonalization, the Frobenius norm depends on matrix rank—the number of nonzero singular values—and shape because every retained singular value is one. This is why a practical recipe adds a dimension-dependent scale before applying its global learning rate.
For a rectangular matrix the result is more precisely semi-orthogonal, but the important statement is the same: its nonzero singular modes now have equal strength. This is a matrix-level analogue of normalization. It does not assert that the true loss has identical curvature in every singular direction; it chooses a better-balanced candidate update from the information in \(M_t\).
Computing a full SVD for every eligible weight on every step would be expensive. Muon instead normalizes the starting matrix and applies a short Newton–Schulz-style polynomial iteration. Each iteration uses matrix multiplications and moves the singular values toward one, thereby approximating \(UV^\top\) without explicitly constructing \(U\), \(\Sigma\), and \(V\). The implementation then applies its prescribed dimension-dependent scale and learning rate. Thus a practical Muon configuration includes more than the symbol \(UV^\top\): one must specify the momentum convention, orthogonalization approximation, scaling, decay, and parameter grouping.
This is a different kind of adaptivity from Adam:
- Adam rescales individual scalar coordinates using their historical squared gradients;
- Muon reshapes an entire matrix update using its singular directions.
Why not apply this to every parameter? A bias or normalization gain is a scalar or vector and has no two-dimensional input–output structure to orthogonalize. An embedding table maps discrete token identities to vectors, while an output head maps hidden states to output scores; these matrices play special boundary roles for which the same scaling rule need not be appropriate. Muon is therefore normally used for eligible two-dimensional hidden-layer weights, while embeddings, output heads, normalization gains, biases, and other vector or scalar parameters are handled by AdamW.
Muon is included here because it makes the design space clearer, not because it universally dominates AdamW. Orthogonalization adds matrix multiplications. If a matrix is split across devices, those multiplications may also require communication, so operation count alone does not determine wall-clock cost. A fair comparison should match compute or training time, number of processed tokens, learning-rate schedules, and the amount of hyperparameter tuning given to each method.
The shortest mental model: SGD follows the current gradient. Momentum averages gradient directions over time. RMSProp divides by recent coordinate-wise gradient scale. Adam combines these two memories. AdamW keeps weight shrinkage outside the moment estimates. Muon uses the geometry of a matrix update rather than treating every entry independently.
1. Gradient Descent 基础
References
- Polyak, B. T. (1964). Some Methods of Speeding Up the Convergence of Iteration Methods. USSR Computational Mathematics and Mathematical Physics, 4(5), 1–17.
- Duchi, J., Hazan, E., & Singer, Y. (2011). Adaptive Subgradient Methods for Online Learning and Stochastic Optimization. JMLR, 12, 2121–2159.
- Tieleman, T. & Hinton, G. (2012). RMSProp, Lecture 6.5 of Neural Networks for Machine Learning.
- Kingma, D. P. & Ba, J. (2015). Adam: A Method for Stochastic Optimization. ICLR.
- Loshchilov, I. & Hutter, F. (2019). Decoupled Weight Decay Regularization. ICLR.
- Jordan, K. (2024). Muon: An Optimizer for Hidden Layers in Neural Networks.
- Liu, J. et al. (2025). Muon is Scalable for LLM Training.