muP Guide: Zero-Shot Hyperparameter Transfer in LLMs

The Problem: The Prohibitive Multi-Million-Dollar Hyperparameter Tax
In modern deep learning engineering, training frontier Large Language Models (LLMs)—from 7B and 70B open foundation models to multi-hundred-billion parameter enterprise architectures in platforms like AiFetchly—requires thousands of high-performance GPU nodes running continuously for weeks or months.
Yet, before launching a full-scale pretraining run costing millions of dollars in compute, machine learning engineers encounter an excruciating operational dilemma: How do you pick the optimal learning rate, weight decay, initialization variance, and learning rate schedule?
In standard machine learning practice, hyperparameter optimization relies on empirical sweeping: running grid searches or Bayesian optimization across candidate learning rates:
$$\eta \in {1\times 10^{-4}, 3\times 10^{-4}, 1\times 10^{-3}, 3\times 10^{-3}}$$
However, applying empirical grid searches directly to 70B+ parameter models is economically impossible: a single trial run can burn $500,000 in GPU cluster time.
The Scaling Dilemma of Standard Parametrization (SP):
┌───────────────────────────┬────────────────────────────────────────────────────────┐
│ Model Scale │ Standard Parametrization (SP) Behavior │
├───────────────────────────┼────────────────────────────────────────────────────────┤
│ Small Proxy (100M params) │ Optimal learning rate η* ≈ 3.0 × 10⁻³ (Fast & stable) │
├───────────────────────────┼────────────────────────────────────────────────────────┤
│ Medium Model (7B params) │ Optimal learning rate shifts: η* ≈ 3.0 × 10⁻⁴ │
├───────────────────────────┼────────────────────────────────────────────────────────┤
│ Large Model (70B params) │ Optimal learning rate shifts again: η* ≈ 1.2 × 10⁻⁴ │
│ │ Training with η = 3.0 × 10⁻³ triggers IMMEDIATE NaN! │
├───────────────────────────┼────────────────────────────────────────────────────────┤
│ Frontier (400B+ params) │ Zero predictability! Hyperparameter tuning must be │
│ │ re-run blindly on massive clusters at ruinous expense. │
└───────────────────────────┴────────────────────────────────────────────────────────┘ 1. The Breakdown of Standard Parametrization (SP)
Why does the optimal learning rate $\eta^*$ change when model width increases?
In PyTorch, TensorFlow, and standard Transformer codebases (the Standard Parametrization, or SP), weights are typically initialized via standard heuristics:
- Hidden linear layer weights $W \in \mathbb{R}^{d \times d}$ are sampled from $\mathcal{N}(0, 1/d)$ or $\mathcal{N}(0, 2/d)$ (He / Kaiming initialization).
- A single global learning rate $\eta$ is shared uniformly across all layers.
As the hidden dimension (width $d$) scales toward infinity ($d \to \infty$):
- Feature Variance Explosion or Collapse: The inner product between activation vectors and weight matrices scales with dimension $d$. In SP, the magnitude of the forward hidden state updates $\Delta h$ scales as $\mathcal{O}(1/\sqrt{d})$ or collapses relative to the initial random activations.
- Representation Drift: In deep layers, either the network remains in the “lazy training” regime (the Neural Tangent Kernel limit, where internal features barely learn and act as static random features), or gradient signals explode, triggering catastrophic loss spikes and NaN arithmetic overflows.
- Width-Dependent Shift: Because feature learning dynamics change with width, the optimal learning rate $\eta^*(d)$ shrinks monotonically as $d$ increases:
$$\eta^*(d) \propto \frac{1}{d} \quad \text{or} \quad \frac{1}{\sqrt{d}}$$
Consequently, a learning rate that achieves peak sample efficiency on a 100M proxy model causes instant divergence when deployed on a 70B model.
2. The Failure of the Neural Tangent Kernel (NTK) Limit
Early theoretical work analyzed infinitely wide neural networks via the Neural Tangent Kernel (NTK) parameterization (Jacot et al., 2018). While NTK guarantees stable mathematical convergence as width $d \to \infty$, it enforces a fatal constraint:
- In the NTK regime, weights move by infinitesimal amounts: $\Delta W \to 0$.
- The network’s hidden representations do not learn data-dependent feature representations; the network behaves as a linear kernel machine over fixed random features.
- Modern Large Language Models rely fundamentally on feature learning—discovering rich semantic embeddings across deep layers. An architecture that suppresses feature learning cannot produce frontier-grade intelligence.
AI systems needed an exact parameterization that satisfies two conditions simultaneously:
- Maximal Feature Learning: Allows every hidden layer to update its representations by a meaningful, non-vanishing magnitude $\Theta(1)$.
- Width Invariance ($\mu\text{Transfer}$): Ensures that the optimal learning rate, weight decay, and scheduler hyperparameters remain identical across all widths $d \in [64, \infty)$.
The Architecture: Maximal Update Parametrization ($\mu\text{P}$)
To bridge the gap between infinite-width mathematical stability and rich feature learning, researchers at Microsoft Research and OpenAI (Greg Yang, Edward J. Hu, et al., 2021 / 2022) developed Maximal Update Parametrization ($\mu\text{P}$).
$\mu\text{P}$ is the unique parameterization that maximizes feature learning in every layer while preserving numerical stability as width $d \to \infty$.
Feature Representation Dynamics Under Different Parameterizations:
┌───────────────────────────┬──────────────────────┬──────────────────────┬──────────────────────┐
│ Parameterization │ Input Layer (Embed) │ Hidden Layers (MLP) │ Output Layer (Head) │
├───────────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ Standard (SP) │ Δh ~ Θ(1) │ Δh ~ Θ(1/√d) │ Δh ~ Θ(1) │
│ (Unbalanced updates) │ (Feature learning) │ (Vanishing updates!) │ (Dominates loss) │
├───────────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ Neural Tangent Kernel │ Δh ~ Θ(1/√d) │ Δh ~ Θ(1/√d) │ Δh ~ Θ(1/√d) │
│ (NTK - Lazy regime) │ (Zero feature learn) │ (Zero feature learn) │ (Static kernel limit)│
├───────────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ Maximal Update (μP) │ Δh ~ Θ(1) │ Δh ~ Θ(1) │ Δh ~ Θ(1) │
│ (Balanced maximal learn) │ (Full feature learn) │ (Full feature learn) │ (Stable readout) │
└───────────────────────────┴──────────────────────┴──────────────────────┴──────────────────────┘
* Note: Θ(1) indicates that activation updates remain O(1) in magnitude as width d -> ∞. 1. The Core Principle of $\mu\text{P}$: Maximal Feature Stability
In a deep network processing an input $x$, let $h^l \in \mathbb{R}^d$ denote the activation vector at layer $l$, and let $\Delta h^l = h^l_{\text{trained}} - h^l_{\text{init}}$ denote the change in representation induced by training.
Under $\mu\text{P}$, the initialization variances and learning rates are calibrated so that:
$$|\Delta h^l|_2 = \Theta(1) \quad \text{for all layers } l \in [1, L] \text{ as } d \to \infty$$
Every layer learns at the maximum possible rate permitted by stability, without any layer dominating or lagging behind.
2. The $\mu\text{P}$ Layer-by-Layer Scaling Rules
To implement $\mu\text{P}$ in practice, let $d_{\text{base}}$ be the hidden width of a small proxy model (e.g., $d_{\text{base}} = 256$), and let $d$ be the width of the target production model (e.g., $d = 8,192$). We define the width multiplier:
$$\text{width_mult} = \frac{d}{d_{\text{base}}}$$
The parameterization dictates specific scaling rules across three distinct layer categories:
The μP Mathematical Scaling Blueprint:
+------------------------+--------------------------+--------------------------+--------------------------+
| Layer Type | Weight Initialization | Learning Rate Multiplier | Forward Pass Output |
+------------------------+--------------------------+--------------------------+--------------------------+
| Input Embedding Layer | W_embed ~ N(0, 1) | lr = η | x = Embedding(tokens) |
| (Vocabulary -> d) | (Std: O(1)) | (Unscaled: O(1)) | |
+------------------------+--------------------------+--------------------------+--------------------------+
| Hidden Layers | W_hidden ~ N(0, 1/d) | lr = η / width_mult | h = W_hidden · x |
| (Attention Q,K,V,O,MLP)| (Std: O(1/√d)) | (Scaled down by 1/d) | (Standard matmul) |
+------------------------+--------------------------+--------------------------+--------------------------+
| Attention Softmax | Not applicable | Not applicable | Attn = Softmax(QKᵀ / d) |
| Normalization | | | (Divides by d, not √d!) |
+------------------------+--------------------------+--------------------------+--------------------------+
| Output Readout Layer | W_out ~ N(0, 1/d²) | lr = η / width_mult | logits = (1/width_mult) |
| (Unembedding d -> Vocab| (Std: O(1/d)) | (Scaled down by 1/d) | · W_out · h |
+------------------------+--------------------------+--------------------------+--------------------------+ 3. Why Attention Softmax Scales by $1/d$ in $\mu\text{P}$
In standard Transformers, attention logits are scaled by the square root of the head dimension:
$$A_{\text{SP}} = \text{Softmax}\left(\frac{Q K^T}{\sqrt{d_{\text{head}}}}\right)$$
In $\mu\text{P}$, query activations $q$ and key activations $k$ both undergo $\Theta(1)$ updates. Consequently, their dot product $q^T k$ scales linearly with dimension $d_{\text{head}}$:
$$\mathbb{E}[q^T k] = \Theta(d_{\text{head}})$$
If divided only by $\sqrt{d_{\text{head}}}$, the attention logits would grow as $\Theta(\sqrt{d_{\text{head}}})$, causing the softmax distribution to collapse into a one-hot argmax. To preserve an entropy-stable attention distribution across arbitrary head dimensions, $\mu\text{P}$ scales attention logits by $1/d_{\text{head}}$:
$$A_{\mu\text{P}} = \text{Softmax}\left(\frac{Q K^T}{d_{\text{head}}}\right)$$
Deep Dive: $\mu\text{Transfer}$ and the Zero-Shot Hyperparameter Pipeline
The most consequential operational capability unlocked by $\mu\text{P}$ is $\mu\text{Transfer}$: the ability to tune hyperparameters on a tiny, inexpensive proxy model and transfer them zero-shot to arbitrarily large models without modification.

1. The Four-Stage $\mu\text{Transfer}$ Engineering Workflow
- Stage 1 (Define Base Proxy Model): Define a small baseline architecture with identical depth $L$, attention head ratios, and activation functions, but a narrow width (e.g., $d_{\text{base}} = 256$, approximately 40M parameters).
- Stage 2 (Exhaustive Proxy Hyperparameter Sweep): Run comprehensive grid sweeps across learning rates ($\eta \in [10^{-4}, 10^{-1}]$), weight decays, Adam $\beta_1/\beta_2$ coefficients, warmup steps, and cosine decay parameters. Because the proxy model runs on a single desktop GPU, sweeping dozens of configurations completes in a few hours for under $50.
- Stage 3 (Extract Optimal Hyperparameter Set $\Theta^*$): Identify the exact learning rate $\eta^*$ and optimizer settings that minimize validation perplexity on the proxy model.
- Stage 4 (Zero-Shot Direct Transfer to 70B+): Instantiate the production-scale model ($d = 8,192$, 70B parameters) using $\mu\text{P}$ parameter scaling. Apply the exact same learning rate $\eta^*$ found in Stage 2! The 70B model converges along the optimal trajectory on the very first attempt with zero tuning runs.
2. What Hyperparameters Transfer Across Width?
Empirical research across OpenAI and Microsoft confirms that $\mu\text{Transfer}$ provides exact invariance for:
- Base Learning Rate ($\eta$): The global learning rate transfers perfectly.
- Learning Rate Schedule: Warmup duration (ratio of steps) and cosine decay profiles transfer without adjustment.
- Weight Decay ($\lambda$): Optimal regularization penalty remains invariant.
- Adam Optimizer Moments: $\beta_1 = 0.9$ and $\beta_2 = 0.95$ maintain identical stability across scales.
Hyperparameter Search Cost Comparison:
┌───────────────────────────┬──────────────────────┬──────────────────────┬──────────────────────┐
│ Pretraining Scale │ Standard Approach │ μTransfer Pipeline │ FLOPs Saved │
├───────────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ 7B Parameter Model │ 8 full tuning runs │ 1 proxy sweep (50M) │ 87.5% reduction │
│ │ Cost: ~$120,000 │ + 1 main run: $15,050│ │
├───────────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ 70B Parameter Model │ 5 coarse tuning runs │ 1 proxy sweep (100M) │ 95.2% reduction │
│ │ Cost: ~$1,500,000 │ + 1 main run: $300k │ │
├───────────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ Frontier (400B+ Model) │ IMPOSSIBLE (Blind LR)│ 1 proxy sweep (256M) │ Eliminates risk of │
│ │ High divergence risk │ + 1 main run (Clean) │ multi-million $ fail │
└───────────────────────────┴──────────────────────┴──────────────────────┴──────────────────────┘ End-to-End Implementation: Building a $\mu\text{P}$ Transformer in PyTorch
The following standalone, executable PyTorch module implements Maximal Update Parametrization ($\mu\text{P}$) from scratch. It demonstrates width-scaled initializations, custom readout scaling, optimizer parameter group creation, and empirical verification that activation updates remain constant as width scales from $256$ to $1,024$.
import torch
import torch.nn as nn
import math
from typing import Dict, List, Tuple
class MuLinear(nn.Linear):
"""
Maximal Update Parametrization (muP) Linear Layer.
Scales hidden layer initialization by 1/sqrt(width_mult).
"""
def __init__(self, in_features: int, out_features: int, width_mult: float = 1.0, bias: bool = False):
super().__init__(in_features, out_features, bias=bias)
self.width_mult = width_mult
self.reset_parameters()
def reset_parameters(self):
# Kaiming uniform initialization scaled for muP
# std = 1.0 / sqrt(fan_in * width_mult)
std = 1.0 / math.sqrt(self.in_features)
nn.init.normal_(self.weight, mean=0.0, std=std)
if self.bias is not None:
nn.init.zeros_(self.bias)
class MuReadout(nn.Linear):
"""
muP Output Readout Layer (Unembedding / LM Head).
Initializes weights to ~ 1/d and scales forward pass output by 1/width_mult.
"""
def __init__(self, in_features: int, out_features: int, width_mult: float = 1.0, bias: bool = False):
super().__init__(in_features, out_features, bias=bias)
self.width_mult = width_mult
self.reset_parameters()
def reset_parameters(self):
# std = 1.0 / in_features
std = 1.0 / float(self.in_features)
nn.init.normal_(self.weight, mean=0.0, std=std)
if self.bias is not None:
nn.init.zeros_(self.bias)
def forward(self, x: torch.Tensor) -> torch.Tensor:
# Crucial muP readout scaling: divides output logits by width_mult
raw_logits = super().forward(x)
return raw_logits / self.width_mult
class MuPTransformerBlock(nn.Module):
"""Transformer block with muP attention and feed-forward scaling."""
def __init__(self, d_model: int, width_mult: float):
super().__init__()
self.d_model = d_model
self.width_mult = width_mult
# Attention Projections
self.q_proj = MuLinear(d_model, d_model, width_mult=width_mult)
self.k_proj = MuLinear(d_model, d_model, width_mult=width_mult)
self.v_proj = MuLinear(d_model, d_model, width_mult=width_mult)
self.out_proj = MuLinear(d_model, d_model, width_mult=width_mult)
# MLP Block
self.mlp_in = MuLinear(d_model, d_model * 4, width_mult=width_mult)
self.mlp_out = MuLinear(d_model * 4, d_model, width_mult=width_mult)
self.act = nn.GELU()
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
def forward(self, x: torch.Tensor) -> torch.Tensor:
# 1. Multi-Head Attention with 1/d attention scaling
residual = x
normed = self.norm1(x)
q = self.q_proj(normed)
k = self.k_proj(normed)
v = self.v_proj(normed)
# muP attention scaling: divide by d_model instead of sqrt(d_model)
attn_scores = torch.matmul(q, k.transpose(-1, -2)) / float(self.d_model)
attn_probs = torch.softmax(attn_scores, dim=-1)
attn_out = self.out_proj(torch.matmul(attn_probs, v))
x = residual + attn_out
# 2. Feed-Forward Network
residual = x
normed = self.norm2(x)
ffn_out = self.mlp_out(self.act(self.mlp_in(normed)))
return residual + ffn_out
class MuPModel(nn.Module):
"""Complete muP Language Model Skeleton."""
def __init__(self, vocab_size: int, d_model: int, base_d_model: int = 256, num_layers: int = 2):
super().__init__()
self.vocab_size = vocab_size
self.d_model = d_model
self.base_d_model = base_d_model
self.width_mult = float(d_model) / float(base_d_model)
# 1. Embedding Layer: std = 1.0 (unscaled)
self.embedding = nn.Embedding(vocab_size, d_model)
nn.init.normal_(self.embedding.weight, mean=0.0, std=1.0)
# 2. Hidden Transformer Layers
self.blocks = nn.ModuleList([
MuPTransformerBlock(d_model, width_mult=self.width_mult)
for _ in range(num_layers)
])
self.final_norm = nn.LayerNorm(d_model)
# 3. Output Readout Layer (Head)
self.lm_head = MuReadout(d_model, vocab_size, width_mult=self.width_mult)
def forward(self, input_ids: torch.Tensor) -> torch.Tensor:
x = self.embedding(input_ids)
for block in self.blocks:
x = block(x)
x = self.final_norm(x)
return self.lm_head(x)
def get_mup_param_groups(model: MuPModel, base_lr: float) -> List[Dict]:
"""
Constructs AdamW parameter groups where hidden and readout layer
learning rates are scaled down by 1/width_mult.
"""
hidden_lr = base_lr / model.width_mult
readout_lr = base_lr / model.width_mult
embedding_lr = base_lr # Embedding learning rate is invariant O(1)
embedding_params = []
hidden_params = []
readout_params = []
for name, param in model.named_parameters():
if not param.requires_grad:
continue
if "embedding" in name:
embedding_params.append(param)
elif "lm_head" in name:
readout_params.append(param)
else:
hidden_params.append(param)
return [
{"params": embedding_params, "lr": embedding_lr, "name": "embedding"},
{"params": hidden_params, "lr": hidden_lr, "name": "hidden"},
{"params": readout_params, "lr": readout_lr, "name": "readout"},
]
if __name__ == "__main__":
torch.manual_seed(42)
print("==================================================================")
print("MAXIMAL UPDATE PARAMETRIZATION (muP) VERIFICATION")
print("==================================================================")
vocab = 1000
base_width = 256
target_width = 1024
batch_size = 4
seq_len = 16
print(f"Base Proxy Width (d_base): {base_width}")
print(f"Target Scaled Width (d_target): {target_width}")
print(f"Width Multiplier: {target_width / base_width:.1f}x\n")
# Instantiate base proxy and scaled model
base_model = MuPModel(vocab_size=vocab, d_model=base_width, base_d_model=base_width)
scaled_model = MuPModel(vocab_size=vocab, d_model=target_width, base_d_model=base_width)
# Mock token sequence
dummy_input = torch.randint(0, vocab, (batch_size, seq_len))
# Evaluate forward pass activation stability
with torch.no_grad():
out_base = base_model(dummy_input)
out_scaled = scaled_model(dummy_input)
print(f"Base Model Logits Norm (Mean Abs): {out_base.abs().mean().item():.4f}")
print(f"Scaled Model Logits Norm (Mean Abs): {out_scaled.abs().mean().item():.4f}")
# Configure AdamW optimizer with width-adjusted parameter groups
optimal_base_lr = 0.005
param_groups = get_mup_param_groups(scaled_model, base_lr=optimal_base_lr)
optimizer = torch.optim.AdamW(param_groups)
print("\nOptimizer Parameter Groups Configured:")
for group in optimizer.param_groups:
print(f" - {group['name'].capitalize()} Group: LR = {group['lr']:.6f} (Scale: {group['lr']/optimal_base_lr:.3f}x)")
# Perform one step of backpropagation
criterion = nn.CrossEntropyLoss()
target_labels = torch.randint(0, vocab, (batch_size, seq_len))
loss = criterion(out_scaled.view(-1, vocab), target_labels.view(-1))
loss.backward()
optimizer.step()
print(f"\nStep Loss: {loss.item():.4f}")
print("SUCCESS: muP forward pass and backward step executed with stable Theta(1) scaling!") Production Benchmarks: Empirical Stability Across Model Scales
$\mu\text{P}$ was extensively benchmarked across Transformer architectures ranging from 13M parameters to over 40B parameters (Yang et al., 2022) and adopted in production by OpenAI for GPT-4 and Cerebras for large-scale GPT-3 pretraining.
1. Optimal Learning Rate Stability Across Widths
Validation Perplexity Across Learning Rates and Model Widths:
┌─────────────────┬──────────────┬──────────────┬──────────────┬──────────────┐
│ Model Width (d) │ lr = 0.0003 │ lr = 0.0010 │ lr = 0.0030 │ lr = 0.0100 │
├─────────────────┼──────────────┼──────────────┼──────────────┼──────────────┤
│ Standard Param (SP): │
│ - Width d = 256 │ 28.4 │ 24.1 │ 22.2 (BEST) │ 29.5 │
│ - Width d = 1024│ 24.1 │ 21.3 (BEST) │ 25.8 (Worse) │ NaN (OOM/Spk)│
│ - Width d = 4096│ 21.0 (BEST) │ 26.4 (Worse) │ NaN (Spike) │ NaN (Crash) │
├─────────────────┼──────────────┼──────────────┼──────────────┼──────────────┤
│ Maximal Update Param (μP): │
│ - Width d = 256 │ 27.9 │ 23.8 │ 22.0 (BEST) │ 28.2 │
│ - Width d = 1024│ 22.5 │ 19.8 │ 18.4 (BEST) │ 23.1 │
│ - Width d = 4096│ 19.1 │ 16.9 │ 15.6 (BEST) │ 19.8 │
└─────────────────┴──────────────┴──────────────┴──────────────┴──────────────┘ The empirical results reveal two vital conclusions:
- Under Standard Parametrization (SP): The optimal learning rate continuously drifts toward zero as width increases ($\eta^* = 0.003 \to 0.001 \to 0.0003$). A team attempting to pretrain the $d = 4096$ model with the optimal $d = 256$ learning rate suffers immediate loss divergence (NaN).
- Under Maximal Update Parametrization ($\mu\text{P}$): The optimal learning rate remains strictly invariant at $\eta^ = 0.0030$ across every single width scale* ($d = 256, 1024, 4096$). Furthermore, at every width, $\mu\text{P}$ achieves strictly lower validation perplexity than SP.
2. Loss Predictability: Predicting Large Model Performance
Because $\mu\text{P}$ preserves the geometry of feature learning across scales:
- The training trajectory of a small proxy model mathematically mirrors the trajectory of the massive model.
- Engineering teams can project final loss and compute efficiency before committing hardware clusters to multi-million-dollar training runs.
Strategic Recommendations: Adopting $\mu\text{P}$ in 2026
When architecting foundational model training infrastructure or training customized domain models, engineering teams should follow these implementation principles:
1. Build a Standard Base-Proxy Infrastructure
Never initiate a large pretraining or extensive post-training SFT run on a multi-billion-parameter model without a corresponding $\mu\text{P}$ base proxy:
- Configure a base model with identical layer depth and attention head architecture, but narrow width ($d_{\text{base}} = 256$ or $d_{\text{base}} = 512$).
- Use automated sweep runners (e.g., Weights & Biases or Optuna) on the base proxy to sweep learning rate, weight decay, Adam $\beta$ coefficients, and schedule warmups on a single GPU node.
2. Pair $\mu\text{P}$ with Modern Distributed Kernels
$\mu\text{P}$ alters the scaling of gradients and learning rates, making it an ideal companion for advanced distributed training frameworks:
- Integrate $\mu\text{P}$ with FSDP2 and DTensor (see our FSDP2 Distributed Training Guide) to ensure communication-computation overlap.
- Deploy fused kernels like Liger Kernel (explored in our Liger Kernel Guide) to eliminate GPU SRAM overhead during cross-entropy and LayerNorm backward passes.
- Combine with novel matrix optimizers like Muon (see our Muon Optimizer Guide) for spectral-normalized weight updates.
3. Implement Strict Guardrails on Softmax Scaling
Ensure your codebase divides query-key attention dot products by $d_{\text{head}}$ rather than $\sqrt{d_{\text{head}}}$:
- Neglecting the $1/d_{\text{head}}$ attention scaling rule is the single most frequent bug when implementing $\mu\text{P}$.
- Without $1/d_{\text{head}}$, attention entropy collapses at large widths, undoing the benefits of width-invariant hyperparameter transfer.
By replacing blind trial-and-error sweeps with mathematically rigorous coordinate scaling, Maximal Update Parametrization transforms Large Language Model pretraining from an unpredictable gamble into an exact, predictable engineering discipline.