Sam Babichenko

Reading notes / NanoGPT speedrun

Muon

Jordan et al., 2024; Bernstein and Newhouse, 2024; Bernstein, 2025; Amsel et al., 2025

Context. In 2024 the optimizers that beat AdamW per step, such as Shampoo and SOAP, lost on wall-clock because their matrix inverse roots are expensive and need float32. Muon (Jordan et al., 2024) changed this in the NanoGPT speedrun, where only time counts. Bernstein and Newhouse (2024) and Bernstein's Deriving Muon (2025) derive it as steepest descent under a norm, and the Polar Express (Amsel et al., 2025) makes its polynomial iteration optimal. For a hidden weight matrix, Muon keeps the singular vectors of the momentum and discards its singular values, so the update UV⊤UV^\top moves every direction by the same amount. That is steepest descent under a rescaled spectral norm, and five matmul-only polynomial steps in bfloat16 get close enough to UV⊤UV^\top for under 1% extra FLOPs.

What Muon does. For each 2-D hidden parameter with stochastic gradient GtG_t, Muon runs momentum and orthogonalizes the buffer: Bt=μBt−1+Gt,Ot=NS5(Bt),Wt=Wt−1−η Ot,B_t=\mu B_{t-1}+G_t,\qquad O_t=\mathrm{NS}_5(B_t),\qquad W_t=W_{t-1}-\eta\,O_t, where NS5\mathrm{NS}_5 is five Newton-Schulz steps approximating Ortho(B)=UV⊤\mathrm{Ortho}(B)=UV^\top, the Frobenius-nearest semi-orthogonal matrix to B=USV⊤B=USV^\top. The reference code uses Nesterov momentum with μ=0.95\mu=0.95 and multiplies OtO_t by max⁡(1,rows/cols)\sqrt{\max(1,\text{rows}/\text{cols})}; the scale of the buffer is irrelevant because Ortho(cB)=Ortho(B)\mathrm{Ortho}(cB)=\mathrm{Ortho}(B). Transformer updates are nearly low rank, so a raw step is almost entirely along a few top singular directions; orthogonalizing raises the directions with small singular values to the same scale. The order matters: Orthogonal-SGDM, which orthogonalizes each gradient and then averages, lost to tuned SGD-momentum, and the post finds averaging first better. Which parameters get Muon is part of the method. Scalars and vectors go to AdamW, and so do the embedding and the output head although they are 2-D, the embedding for a reason given below, the head on empirical grounds only. Q, K and V work better orthogonalized separately than as one fused matrix.

Why orthogonalize. Optimizers as steepest descent under a norm. Steepest descent under a norm splits into a direction, the dual map arg⁡max⁡∥t∥=1g⊤t\arg\max_{\|t\|=1}g^\top t, which depends only on the norm, and a length. With the EMAs off, known optimizers become such methods. Adam with β1=β2=0\beta_1=\beta_2=0 is sign descent, the ℓ∞\ell_\infty case: the unit ball is a cube, its vertex most aligned with gg is sign⁡(g)\operatorname{sign}(g), and the dual norm is ∥g∥1\|g\|_1. Shampoo with accumulation off is (GG⊤)−1/4G(G⊤G)−1/4=UV⊤(GG^\top)^{-1/4}G(G^\top G)^{-1/4}=UV^\top, the spectral-norm case, by von Neumann's trace bound ⟨A,G⟩≤∑iσi=tr⁡Σwhenever ∥A∥ℓ2→ℓ2≤1,\langle A,G\rangle\le\sum_i\sigma_i=\operatorname{tr}\Sigma\qquad\text{whenever }\|A\|_{\ell_2\to\ell_2}\le1, with equality at A=UV⊤A=UV^\top: the dual of the spectral norm is the nuclear norm, and UV⊤UV^\top attains it. So Muon is momentum followed by accumulation-free Shampoo, at Newton-Schulz cost. It is the constrained form, minimizing ⟨G,ΔW⟩\langle G,\Delta W\rangle over a spectral ball of radius η\eta, which gives the fixed-length step −ηUV⊤-\eta UV^\top; the penalized form would scale each step by the nuclear norms of the gradients (our comparison of the two sources). For a linear predictor with square loss averaged over outputs and inputs of norm din\sqrt{d_{in}}, the spectral norm is also what bounds the loss: the second-order term is at most 12dindout∥ΔW∥ℓ2→ℓ22\frac12\frac{d_{in}}{d_{out}}\|\Delta W\|_{\ell_2\to\ell_2}^2, because the bound must hold for every input direction.

Which spectral norm: RMS to RMS, and the width factor. Deriving Muon measures a weight change of a dense layer y=Wxy=Wx by how far it can move the output. With ∥v∥RMS=∥v∥2/d\|v\|_{RMS}=\|v\|_2/\sqrt d on both sides, ∥ΔWx∥RMS≤∥ΔW∥RMS→RMS ∥x∥RMS,∥W∥RMS→RMS=dindout  ∥W∥ℓ2→ℓ2,\|\Delta Wx\|_{RMS}\le\|\Delta W\|_{RMS\to RMS}\,\|x\|_{RMS},\qquad\|W\|_{RMS\to RMS}=\sqrt{\frac{d_{in}}{d_{out}}}\;\|W\|_{\ell_2\to\ell_2}, so an RMS-to-RMS ball of radius η\eta is a spectral ball of radius ηdout/din\eta\sqrt{d_{out}/d_{in}}, and the dualized update is ΔW=−ηdout/din UV⊤\Delta W=-\eta\sqrt{d_{out}/d_{in}}\,UV^\top. When din≤doutd_{in}\le d_{out} and the gradient has full rank, UV⊤UV^\top is an isometry, so every unit-RMS input has its output moved by exactly η\eta whatever the width: a fixed learning rate transfers across width, which is what μ\muP (the maximal-update parametrization) achieves, here derived from a norm. The reference factor max⁡(1,rows/cols)\sqrt{\max(1,\text{rows}/\text{cols})} agrees on a 4d×d4d\times d up-projection (both give 2) and differs on the d×4dd\times4d down-projection (12\tfrac12 against 1); which scales better is not shown. The same logic explains the embedding: it maps one-hot vectors to dense ones and gets the ℓ1→RMS\ell_1\to RMS norm, whose dual step normalizes each token's column separately (our derivation), whereas orthogonalization couples the tokens through shared singular vectors.

Why five polynomial steps suffice. An odd matrix polynomial changes only the singular values. One step X↦aX+b(XX⊤)X+c(XX⊤)2XX\mapsto aX+b(XX^\top)X+c(XX^\top)^2X sends USV⊤USV^\top to Uφ(S)V⊤U\varphi(S)V^\top with φ(x)=ax+bx3+cx5\varphi(x)=ax+bx^3+cx^5, so the singular vectors are kept exactly and NN steps apply φN\varphi^N to each singular value. Dividing by ∥G∥F≥∥G∥2\|G\|_F\ge\|G\|_2 puts the singular values in [0,1][0,1] but leaves many of them small. A small singular value grows by about φ′(0)=a\varphi'(0)=a per step, so Jordan's coefficients maximize aa subject to the iterates ending within about 0.3 of 1, an error that does not hurt the loss curve. The routine in plain PyTorch:
def newton_schulz5(G, steps=5):
    a, b, c = 3.4445, -4.7750, 2.0315
    X = G.bfloat16() / (G.norm() + 1e-7)   # all singular values now at most 1
    if G.size(0) > G.size(1):
        X = X.T                            # use the smaller Gram matrix X X^T
    for _ in range(steps):
        A = X @ X.T
        B = b * A + c * A @ A
        X = a * X + B @ X                  # each singular value s becomes a s + b s^3 + c s^5
    if G.size(0) > G.size(1):
        X = X.T
    return X
After five steps every σ≥0.01\sigma\ge0.01 lies in about [0.68,1.13][0.68,1.13], where Kovarik's classical cubic 32x−12x3\tfrac32x-\tfrac12x^3 needs σ≥0.10\sigma\ge0.10 just to reach 0.68 (our numpy check). Newton-Schulz, unlike Shampoo's coupled Newton iteration, is stable in bfloat16.

The optimal coefficients (Polar Express), and why practical Muon is a spectral method. The worst-case spectral error over matrices with singular values in [ℓ,u][\ell,u] is the scalar error max⁡[ℓ,u]∣1−p∣\max_{[\ell,u]}|1-p| of the composed polynomial. Rescaling the input preserves odd polynomials, so the only state of the iteration is the ratio ℓt/ut\ell_t/u_t of the current interval, and choosing each step greedily as the minimax polynomial on that interval (a small Remez solve, done once offline) is worst-case optimal. Each optimal step maps [ℓ,u][\ell,u] onto a narrower [p(ℓ),2−p(ℓ)][p(\ell),2-p(\ell)]; Jordan's fixed quintic cannot shrink its own output interval and stalls at an error of about 0.3. With u=1u=1 and ℓ=10−3\ell=10^{-3}, near bfloat16 precision, five steps map every singular value in [10−3,1][10^{-3},1] into about [0.85,1.12][0.85,1.12], against [0.47,1.20][0.47,1.20] for Jordan's five steps, and the bfloat16 safety fixes cost about 0.04 of worst-case error relative to pure greedy (our re-implementation). More precision does not help: in the paper's ablations an exact SVD trains no better than five or six steps, and flipping or zeroing the update on singular directions below 10−4σmax⁡10^{-4}\sigma_{\max} changes nothing (below 10−3σmax⁡10^{-3}\sigma_{\max}, very little). So practical Muon is a spectral method. It keeps the singular vectors exactly and moves the singular values that matter into a band around 1, and the ablations show that this is enough.

The speedrun evidence and the cost. Muon's introduction (record #3) and first improvements (#4) took the speedrun from 31.4 to 22.3 minutes; the post credits it with a 1.35x speedup, and at 1.5B parameters Muon matched tuned AdamW's final loss with 25% fewer tokens. The benchmark makes this credible: Muon costs more per step, so if AdamW could be tuned to Muon's per-token efficiency, putting it back would set a record, and Muon had survived 12 further records by 7 researchers when the post was written. For an n×mn\times m matrix with m≤nm\le n, TT Newton-Schulz steps cost at most 6Tnm26Tnm^2 FLOPs against 6nmB6nmB for the layer's forward and backward pass on BB tokens, so the overhead is at most Tm/BTm/B: the orthogonalization cost is fixed by the shape while the training cost grows with the batch. That is 0.7% at the speedrun's m=768m=768, B=524,288B=524{,}288 and 0.5% at Llama-405B's sizes; the state is one momentum buffer, half of Adam's. Polar Express replaced Newton-Schulz in record #38 (2.483 to 2.476 minutes); the README states about 1 s from 10 fewer steps, with a safety factor of 1.02 and a higher Muon learning rate, and says its author could not reproduce gains as large as the paper's (0.05 to 0.06 in GPT-2 validation loss over Jordan's coefficients at 1B tokens, under 0.01 at 10B).

Consequences and limits. Muon splits optimizer design for hidden matrices into a geometric choice, the norm whose dual map is orthogonalization, and a numerical one, an odd polynomial, which Polar Express makes minimax-optimal with one parameter, the assumed smallest singular value ℓ\ell. The norm equivalences hold with the EMAs off, so why momentum must come first is left to the next note; the second-order loss bound covers one linear layer; and the speedups are single-setup measurements on small language models.

Terms

Ortho(G)=UV⊤\mathrm{Ortho}(G)=UV^\top
nearest semi-orthogonal matrix to G=USV⊤G=USV^\top in Frobenius norm
Muon step
Bt=μBt−1+GtB_t=\mu B_{t-1}+G_t, Wt=Wt−1−η NS5(Bt)W_t=W_{t-1}-\eta\,\mathrm{NS}_5(B_t); Nesterov, μ=0.95\mu=0.95
Newton-Schulz step
A=XX⊤A=XX^\top, X←aX+(bA+cA2)XX\leftarrow aX+(bA+cA^2)X, which maps USV⊤USV^\top to Uφ(S)V⊤U\varphi(S)V^\top
φ(x)=ax+bx3+cx5\varphi(x)=ax+bx^3+cx^5
odd polynomial applied to singular values; φ′(0)=a\varphi'(0)=a sets how fast small ones grow
Dual norm ∥g∥†\|g\|^\dagger
max⁡∥t∥=1g⊤t\max_{\|t\|=1}g^\top t; ℓ∞↔ℓ1\ell_\infty\leftrightarrow\ell_1, spectral ↔\leftrightarrow nuclear tr⁡Σ\operatorname{tr}\Sigma
Accumulation-free Shampoo
(GG⊤)−1/4G(G⊤G)−1/4=UV⊤(GG^\top)^{-1/4}G(G^\top G)^{-1/4}=UV^\top: Muon without momentum
∥W∥RMS→RMS\|W\|_{RMS\to RMS}
din/dout ∥W∥ℓ2→ℓ2\sqrt{d_{in}/d_{out}}\,\|W\|_{\ell_2\to\ell_2}; bounds the RMS change of a layer's output
Dualized Muon step
ΔW=−ηdout/din UV⊤\Delta W=-\eta\sqrt{d_{out}/d_{in}}\,UV^\top: RMS output change η\eta, independent of width
ℓt/ut\ell_t/u_t
the only state of the iteration; greedy steps maximize it
Overhead ≤Tm/B\le Tm/B
Newton-Schulz FLOPs over training FLOPs for a layer; 0.7% at the speedrun's sizes

Quiz

  1. At fixed width, a run halves its batch size in tokens. What happens to Muon's FLOP overhead bound Tm/BTm/B?
  2. The post keeps both the embedding and the output head on AdamW. What distinguishes the two cases?
  3. Muon with an exact SVD polar factor trains no better than with five or six Polar Express steps, which do not converge fully. What explains this, per the ablations?
  4. Polar Express improves on Jordan's fixed quintic most in which respect?

Sources