muon

muon is the Muon optimizer (Jordan et al., 2024) with a grouped Newton-Schulz kernel, loadable through kernels. Muon orthogonalizes the momentum of every 2D parameter with a Newton-Schulz iteration before each step, and the cost of the optimizer is that iteration: five steps of three matrix products per matrix. Run one matrix at a time, those products are too small to fill a large GPU, so the device sits idle between launches. This kernel runs the iteration for a whole shape-bucket of parameters in a single batched tensor-core call (bf16 operands, fp32 accumulate), and rounds the bf16 write-back stochastically so bf16 parameters train with no fp32 master copy.

Usage

import torch
from kernels import get_kernel

muon = get_kernel("phanerozoic/muon", version=1, trust_remote_code=True)

# hidden 2D weights use Muon; embeddings, the LM head, and 1D params use AdamW
hidden = [p for n, p in model.named_parameters() if p.ndim == 2 and "embed" not in n and "lm_head" not in n]
rest   = [p for n, p in model.named_parameters() if p not in set(hidden)]
opt = muon.Muon([
    {"params": hidden, "use_muon": True,  "lr": 0.02, "weight_decay": 0.01},
    {"params": rest,   "use_muon": False, "adamw_lr": 3e-4},
])

for batch in loader:
    opt.zero_grad(); loss(model(batch)).backward(); opt.step()

version selects the release branch; trust_remote_code is required by kernels for publishers without the trusted-publisher mark. bf16 parameters in a Muon group are written back with stochastic rounding, so no fp32 master copy is needed. The orthogonalization is also exposed directly:

O = muon.orthogonalize(G, steps=5)          # single matrix [R, C] -> bf16
Ob = muon.orthogonalize(G_stack)            # [G, R, C] -> all orthogonalized in one call

API

Symbol Purpose
Muon(params, lr, momentum, nesterov, ns_steps, weight_decay, seed, adamw_*) Muon optimizer; groups with use_muon=False take AdamW
orthogonalize(G, steps, eps) / newton_schulz Newton-Schulz factor of a matrix or a stack, bf16
ops.muon_orthogonalize(Xb, steps, eps) batched Newton-Schulz over [G, R, C]
ops.muon_sr_update(param, O, lr, scale, wd, seed, step, base_index) fused scaled update, decoupled decay, stochastic-rounding bf16 write-back

How it works

For a matrix G, Muon computes NS(G), an approximate orthogonal factor, with the quintic iteration X <- a X + (b A + c A^2) X, A = X X^T, coefficients (3.4445, -4.7750, 2.0315), five steps, after scaling X to unit Frobenius norm and transposing so the contracted dimension is the larger one. The singular values are pulled toward one, loosely by design.

The optimizer buckets its 2D parameters by shape and stacks each bucket into one [G, R, C] tensor. Every Newton-Schulz step is then three batched GEMMs (cublasGemmStridedBatchedEx) over the whole bucket rather than G separate launches, with the two bf16-elementwise combines fused. The scaled update and decoupled weight decay are a single kernel; for a bf16 parameter the write-back is rounded with counter-based stochastic rounding keyed by the element's global index, so the expected value is exact and sub-ULP updates accumulate. 1D parameters (biases, norm gains) and any group marked use_muon=False (embeddings, the LM head) take a standard decoupled-weight-decay AdamW path.

Measured

Time for the Newton-Schulz iteration over a set of parameter matrices, grouped kernel against the same iteration run per matrix in eager PyTorch and under torch.compile (max-autotune), median of repeated executions. Each cell is speedup over eager / speedup over compile; above 1 is faster.

matrices L4 (sm_89) H200 (sm_90) RTX PRO 6000 (sm_120)
256x256 x256 13.8 / 12.3 104.7 / 63.5 39.0 / 24.2
512x512 x128 3.1 / 3.0 25.2 / 20.4 5.5 / 5.2
768x768 x48 0.86 / 0.85 9.6 / 10.3 3.6 / 3.5
1024x2816 x64 0.84 / 0.71 2.5 / 11.0 1.2 / 1.2
GPT2-medium set (48) 0.82 / 0.70 2.3 / 6.0 1.4 / 1.4

The advantage grows with the GPU, because batching is what keeps a large device fed: on the H200 and the RTX PRO 6000 the grouped iteration is faster at every size measured, including the large matrices where per-matrix GEMMs are compute bound. torch.compile fuses the per-matrix iteration but does not batch across distinct parameters, so the grouped call is faster than the compiled per-matrix loop as well. The L4 has few SMs, so a matrix of 768 or larger already fills it and grouping is at parity there; the gain on that class of GPU is in the many-small-matrix regimes (adapters, small models, mixture-of-experts).

Correctness

Equivalence to reference Muon is established at three levels, measured on H200 and RTX PRO 6000 through get_kernel. The kernel's grouped and single-matrix paths are bitwise identical (torch.equal), so the shape-bucket is not an approximation of the per-matrix result.

  • The grouped iteration is the reference iteration. Run in fp64, grouped and per-matrix Newton-Schulz agree to 5.8e-15, the fp64 rounding floor, so batching a shape-bucket does not change the computation.
  • The kernel is at least as accurate as the reference. Against an fp64 ground-truth Newton-Schulz over 49 cases (seven shapes by seven conditionings: Gaussian, ill-conditioned to 1e-6, low-rank, heavy-tailed, scaled by 1e+-3, near-orthogonal), the kernel's bf16 error is 0.65x the reference bf16 error in the median and never above 0.80x; its singular values are closer to the truth than the reference's (0.17 vs 0.22 worst) and the output direction matches the reference to a cosine above 0.978. Any kernel-versus-reference difference is bf16 rounding, and it favors the kernel.
  • It holds dynamically. A 20M-parameter six-layer transformer trained 600 steps with kernel-Muon and with a reference-Muon differing only in the Newton-Schulz implementation keeps a loss relative gap under 1.2e-3 at every step; the two descend together while the parameters decorrelate only at the bf16 rate expected of two low-precision runs of one optimizer.

The stochastic-rounding write-back is unbiased (a sub-ULP update across 200k bf16 elements averages to the true value, where round-to-nearest leaves it unchanged) and bitwise reproducible for a fixed (seed, step). Results are deterministic.

Requirements and limits

  • NVIDIA GPU with compute capability 8.0+ and torch with bf16 tensor cores.
  • Muon is for the 2D hidden weights; keep embeddings, the LM head, and 1D parameters in an AdamW group, as in the standard recipe.
  • Optimizer state for a Muon matrix parameter is one fp32 momentum buffer, and the parameter may stay bf16 with no fp32 master, so a bf16 matrix parameter costs 4 bytes per element less than the bf16-master recipe.
  • base_index sets the global-index offset for sharded updates so a parameter updated whole or across shards rounds identically.

References

Jordan et al., "Muon: An optimizer for the hidden layers of neural networks" (2024); Bernstein and Newhouse, "Old Optimizer, New Norm" and the modular-duality view of Muon as steepest descent under the spectral norm (2024); Liu et al., "Muon is Scalable for LLM Training" (Moonshot, 2025); Amsel et al., "The Polar Express: Optimal Matrix Sign Methods" (2025).

License

Apache-2.0.

Downloads last month
-
apache-2.0
Supported hardwares new
CUDA
8.08.68.99.010.012.0
GPU
B300
288GB
NVIDIA SXM
B200
192GB
NVIDIA SXM
H200
141GB
NVIDIA SXM
H100
80GB
GPU
H800
80GB
GPU
H20
96GB
GPU
L40s
48GB
GPU
L40
48GB
GPU
L20
48GB
GPU
L4
24GB
DGX Spark
GB10
128GB
GPU
RTX PRO 6000 WS
96GB
GPU
RTX PRO 6000 Max-Q
96GB
GPU
RTX PRO 5000
48GB
GPU
RTX PRO 4500 WS
32GB
GPU
RTX PRO 4000
24GB
GPU
RTX PRO 4000 SFF
24GB
GPU
RTX PRO 2000
16GB
GPU
RTX 6000 Ada
48GB
GPU
RTX 5880 Ada
48GB
RTX
RTX 5000 Ada
32GB
GPU
RTX 4500 Ada
24GB
RTX
RTX 4000 Ada
20GB
RTX
RTX 4000 SFF Ada
20GB
GPU
RTX 3500 Ada Mobile
12GB
GPU
RTX 2000 Ada
16GB
GPU
RTX A6000
48GB
GPU
RTX A5000
8GB
GPU
RTX A5000 Max-Q
16GB
GPU
RTX A5000 Mobile
16GB
GPU
RTX A4000
16GB
GPU
RTX A4000 Max-Q
8GB
GPU
RTX A4000 Mobile
8GB
GPU
RTX A3000 Mobile
6GB
GPU
RTX A2000
6GB
GPU
RTX A2000 Embedded
4GB
GPU
RTX A2000 Max-Q
4GB
GPU
RTX A2000 Mobile
4GB
GPU
A800
40GB
GPU
A100
80GB
GPU
A40
48GB
GPU
A30
24GB
GPU
A10
24GB
GPU
A2
16GB
RTX
RTX 5090
32GB
RTX
RTX 5090 D
32GB
RTX
RTX 5090 Mobile
24GB
RTX
RTX 5080
16GB
RTX
RTX 5080 Mobile
16GB
RTX
RTX 5070
12GB
RTX
RTX 5070 Mobile
8GB
RTX
RTX 5070 Ti
16GB
RTX
RTX 5070 Ti Mobile
12GB
RTX
RTX 5060 Ti
16GB
RTX
RTX 5060
8GB
RTX
RTX 5060 Mobile
8GB
RTX
RTX 5050
8GB
RTX
RTX 5050 Mobile
8GB
RTX
RTX 4090
24GB
RTX
RTX 4090D
24GB
RTX
RTX 4090 Mobile
16GB
RTX
RTX 4080 SUPER
16GB
RTX
RTX 4080
16GB
RTX
RTX 4080 Mobile
12GB
RTX
RTX 4070
12GB
RTX
RTX 4070 Mobile
8GB
RTX
RTX 4070 Ti
12GB
RTX
RTX 4070 Super
12GB
RTX
RTX 4070 Ti Super
16GB
RTX
RTX 4060
8GB
RTX
RTX 4060 Ti
8GB
RTX
RTX 4090 Laptop
16GB
RTX
RTX 4080 Laptop
12GB
RTX
RTX 4070 Laptop
8GB
RTX
RTX 4060 Laptop
8GB
RTX
RTX 4050 Laptop
6GB
RTX
RTX 3090
24GB
RTX
RTX 3090 Ti
24GB
RTX
RTX 3080
12GB
RTX
RTX 3080 Ti
12GB
RTX
RTX 3080 Mobile
16GB
RTX
RTX 3070
8GB
RTX
RTX 3070 Ti
8GB
RTX
RTX 3070 Ti Mobile
8GB
RTX
RTX 3060 Ti
8GB
RTX
RTX 3060
12GB
RTX
RTX 3060 Mobile
6GB
RTX
RTX 3050 Mobile
4GB
GPU
RTX 2050 Mobile
4GB
Jetson
Jetson AGX Orin 64GB
64GB
Jetson
Jetson AGX Orin 32GB
32GB
Jetson
Jetson Orin NX 16GB
16GB
Jetson
Jetson Orin NX 8GB
8GB
Jetson
Jetson Orin Nano 8GB
8GB
Jetson
Jetson Orin Nano 4GB
4GB
OS
linux
Arch
x86_64
Kernel Builder
570dcf4