Skip to content
AI.info

Training and optimization

AdamW, Weight Decay, and Parameter Groups

Learn why L2 penalties and weight decay differ under adaptive optimization, which parameters are commonly excluded, and how decay interacts with schedules.

By the end you can

Example

Two implementations called “regularization” can produce different paths

Two procedures answer to the word regularization. Somebody put them head to head on named architectures at a named learning rate and measured the gap instead of assuming it.

  • An L2 penalty enters the objective, so its gradient is divided by Adam’s coordinate-wise denominator. Decoupled weight decay applies the shrinkage as a separate parameter update. Loshchilov and Hutter treated the difference as an empirical question rather than a definitional one.
  • Their answer, in 2019: “In a comprehensive analysis, we show that Adam generalizes substantially better with decoupled weight decay than with L2 regularization, achieving 15% relative improvement in test error (see Figures 2 and 3)”.
  • That 15% was at Adam’s default learning rate of 0.001. The models were 26 2x64d and 26 2x96d ResNets on CIFAR-10 — 11.6M and 25.6M parameters, batch size 128 — and again on ImageNet32x32.
  • It was not one lucky configuration. The result held across training budgets from 100 to 1800 epochs, and across fixed, step-drop and cosine-annealing schedules.
  • An outside group got the same direction on its own runs. Gugger and Howard’s CIFAR-10 experiments at fast.ai had Adam with an L2 penalty at 93.96% accuracy on average in 30 epochs, against 94% to 94.25% with decoupled decay.

L2 regularization and decay are concepts with different implementations

An L2 penalty changes the objective by adding a norm term, so its gradient enters the optimizer transformation. Decoupled decay shrinks parameters separately from the adaptive gradient step.

The boundary was drawn precisely in 2019. The two are “equivalent for standard stochastic gradient descent (when rescaled by the learning rate)”, Loshchilov and Hutter wrote, but not for adaptive gradient algorithms — and the abstract names Adam. Their fix was “a simple modification to recover the original formulation of weight decay regularization by decoupling the weight decay from the optimization steps taken w.r.t. the loss function”.

The distinction is visible in the printed algorithms, not only in the prose. PyTorch 2.13’s torch.optim.Adam folds the coefficient into the gradient ahead of the moment updates: if λ ≠ 0, g_t ← g_t + λθ_{t−1}. It documents the argument as “weight decay (L2 penalty) (default: 0)”. torch.optim.AdamW, on the same documentation set, applies θ_t ← θ_{t−1} − γλθ_{t−1} instead. The page describes that algorithm as one “where weight decay does not accumulate in the momentum nor variance”, and points the reader to the 2019 paper for the details. The name on the argument is identical in both.

The configuration name is not enough: one keyword prints two different lines of algorithm.

Visual

A decoupled AdamW step

This conceptual sequence separates data-gradient adaptation from parameter shrinkage. The shrinkage line is exactly where implementations diverge.

PyTorch 2.13’s AdamW prints θ_t ← θ_{t−1} − γλθ_{t−1}, so the current learning rate γ multiplies the decay at every step. The original paper does not put the base step size α there at all. Its Algorithm 2 sets ηt ← SetScheduleMultiplier(t) and lets the decay enter as −ηtλθ_{t−1}; the authors “introduce a scaling factor ηt delivered by a user-defined procedure SetScheduleMultiplier(t)”. Read the sequence and you know which of the two quantities is scaling the shrinkage in your own run.

FigureProcess · 5 steps
  1. 1

    Estimate moments

    Update first and second moments from the current data gradient.

  2. 2

    Build adaptive direction

    Normalize the bias-corrected first moment by recent magnitude.

  3. 3

    Apply learning-rate scale

    Convert the adaptive direction into a parameter change.

  4. 4

    Apply decoupled decay

    Shrink selected parameters without passing decay through moment normalization.

  5. 5

    Advance scheduler state

    Update the rate and any group-specific schedule for the next step.

Visual

Audit a decay recipe before a large sweep

Make the policy explicit, then test its consequences. Step 1 is not busywork. The same keyword on the same optimizer name compiles to two different update rules in two mainstream libraries.

PyTorch 2.13 ships the choice as an argument on plain Adam: “decoupled_weight_decay (bool, optional) – if True, this optimizer is equivalent to AdamW and the algorithm will not accumulate weight decay in the momentum nor variance. (default: False)”. The default there is the coupled penalty, folded into the gradient. Keras 3 made the opposite choice for everything it ships. Its keras.optimizers.Adam carries a weight_decay argument of its own, and Keras 3.15.1 applies it in the base class as variable.assign(variable - variable * wd * lr), before each optimizer’s own update step runs. Decoupled, scaled by the learning rate, for every optimizer in the library.

Steps 2 through 5 only mean something once step 1 has said which of those two rules you are running.

FigureProcess · 5 steps
  1. 1. Inspect the formula

    Confirm whether the library uses coupled L2, decoupled decay, or another rule.

  2. 2. List parameter groups

    Record every inclusion, exclusion, rate, and decay coefficient.

  3. 3. Track parameter norms

    Observe growth, shrinkage, and scale-invariant layers separately.

  4. 4. Match the schedule

    Compare decay under the same number of steps and learning-rate path.

  5. 5. Validate downstream behavior

    Check calibration, robustness, and task metrics rather than norm alone.

Decay per step interacts with learning rate and step count

In common AdamW implementations the shrinkage applied each step is scaled by the current learning rate. Schedule, batch size and total steps therefore all change the cumulative decay.

The authors state that horizon dependence in the paper and supply a correction for it. Different weight decay factors are optimal for different computational budgets, measured in batch passes. So an appendix on normalized weight decay replaces λ with λ = λ_norm · sqrt(b / (BT)). Here b is the batch size, B the total number of training points, T the total number of epochs. λ_norm is the decay that would apply if only one batch pass were allowed. That is what let a constant setting be reused across short and long runs in AdamWR — 7 settings of normalized weight decay for AdamW, against 12 settings of L2 for Adam, over 1800-epoch runs.

A second group reached the same joint dependence from the other side. Kosson and colleagues, in 2024, give AdamW’s equilibrium weight norm as sqrt(ηC/2λ), set by the learning rate and the decay together. Under a cosine decay schedule they observe that “the weights fall back out of equilibrium as the weights can not decay fast enough to keep up with the shifting equilibrium norm (which decreases with the learning rate schedule)”.

PaLM took the coupling to its conclusion in 2023 and used no constant at all. Its training setup applied a dynamic weight decay of lr^2.0, where lr is the current learning rate.

The authors themselves rescale λ by sqrt(b/(BT)): the number does not travel without its batch size, dataset size and epoch count.

Case

The same decay number shrinking weights by different amounts

One keyword, three defaults. PyTorch 2.13’s torch.optim.AdamW documents “weight_decay (float, optional) – weight decay coefficient (default: 1e-2)” and applies it as θ_t ← θ_{t−1} − γλθ_{t−1}, so a cosine schedule tapers the shrinkage along with the step size. Keras 3’s keras.optimizers.AdamW ships weight_decay=0.004 beside learning_rate=0.001. Hugging Face’s TrainingArguments is the entry point most fine-tuning runs pass through, with optim defaulting to 'adamw_torch_fused'; it lists weight_decay as “float, optional, defaults to 0”. Carry a recipe between the three without restating the number and you train with 2.5x less decay, or with none at all.

The number survives a change of recipe no better than it survives a change of library. GPT-3 used a single coefficient for the whole family: “All models use weight decay of 0.1 to provide a small amount of regularization”, cited in that sentence to Loshchilov and Hutter. The Falcon team tried to inherit PaLM’s dynamic schedule instead. It did not take: “We attempted to reproduce the weight decay schedule from Chowdhery et al. (2022), but failed to obtain an improvement–we suspect this is due to differences in initialization.” They shipped a fixed weight decay of 0.1 with AdamW for Falcon-7B, 40B and 180B.

Their own numbers show why the constant is not the lesson. Turning weight decay on moved zero-shot main accuracy from 50.3 to 51.7 on The Pile, and from 52.1 to 52.0 on RefinedWeb.

Analogy

Two forces acting through different mechanisms

Steering turns a boat. Drag slows it. Both change the path, but applying the drag through the steering mechanism would distort its direction.

Decay is separated from adaptive gradient normalization for that reason. Which parts of the model should feel it at all is a further question, and the shipped trainers have already answered it on your behalf. Hugging Face’s Trainer builds exactly two parameter groups, and every bias and normalization parameter goes into the one carrying weight_decay=0.0.

Decoupling makes shrinkage easier to reason about, not automatically optimal.

Comparison

Parameters that often receive different decay policies

These conventions are not starting hypotheses. In the mainstream trainers they are hard-coded defaults that you inherit unless you override them.

Hugging Face’s Trainer builds exactly two groups. In Transformers 5.16.1, get_decay_parameter_names sets forbidden_name_patterns = [r"bias", r"layernorm", r"rmsnorm", r"(?:^|\.)norm(?:$|\.)", r"_norm(?:$|\.)"]. create_optimizer then splits the model into a weight_decay group and a weight_decay=0.0 group, and that second group also absorbs every parameter of an nn.LayerNorm module. The documentation states the same thing in one line: “The weight decay to apply (if not zero) to all layers except all bias and LayerNorm weights.” Keras 3 exposes the intent as a public API, exclude_from_weight_decay(var_list=None, var_names=None) on its base optimizer. PyTorch supports the pattern by accepting an “iterable of parameters or named_parameters to optimize or iterable of dicts defining parameter groups”, and its state_dict example carries per-group entries with 'weight_decay': 0 and 'weight_decay': 0.5.

The reason the normalization-adjacent parameters get a different policy is mechanical. A weight sitting in front of a normalization layer is not regularized by an L2 penalty at all. Van Laarhoven put it in his 2017 abstract: “However, we show that L2 regularization has no regularizing effect when combined with normalization. Instead, regularization has an influence on the scale of weights, and thereby on the effective learning rate.” Hoffer and colleagues made the consequence visible in 2018, on VGG11 and CIFAR-10: “We show empirically that the accuracy gained by using WD can be achieved without it, only by adjusting the learning rate.” The whole accuracy gain attributed to weight decay came back with no weight decay at all, purely by correcting the learning rate for the growing weight norm.

Matrix and convolution weights remain the usual decay targets. Embeddings and other special tensors have no comparable published rule quoted here, so that policy stays a decision to record and to test.

FigureComparison · 3 columns

Matrix and convolution weights

Large learned transformations are common decay targets.

  • Goal: limit unconstrained norm growth
  • Default: often decayed
  • Check: scale-invariant parameterization
  • Evidence: validation and norm trends

Biases and normalization scales

Small affine parameters often use zero or reduced decay.

  • Goal: avoid unhelpful shrinkage
  • Default: commonly excluded
  • Check: framework recipe
  • Evidence: ablation when material

Embeddings and special tensors

Behavior depends on task, frequency, and parameterization.

  • Goal: control representation norms
  • Default: recipe-dependent
  • Check: sparse update support
  • Evidence: retrieval or downstream quality

Shrinking weights is not a complete theory of generalization

Weight decay can improve validation behavior. But the mechanism the groups who went looking actually found is not the one the name suggests. With batch normalization, Hoffer and colleagues report, decay “improves optimization only”, by holding the weight norm in a small range.

A 2024 paper generalizes that, and its abstract does not hedge: “Overall, we present a unifying perspective from ResNets on vision tasks to LLMs: weight decay is never useful as an explicit regularizer but instead changes the training dynamics in a desirable way.” D’Angelo and colleagues reproduced AdamW’s entire loss curve on GPT-2-124M and OpenWebText, context length 1024, by matching only its effective learning rate η_t/‖w_t‖ with a non-standard schedule. At learning rate 0.001, all three random seeds trained with weight decay 0 diverged late in bfloat16 training. λ=0.1 and λ=0.3 stayed stable and reached lower final training loss. In one-pass pretraining, that is what the coefficient is buying.

An independent derivation lands in the same place. Kosson and colleagues show decay balancing “the average rotation—a proxy for the effective learning rate”, with AdamW’s equilibrium norm derived as sqrt(ηC/2λ). Their conclusion: “we hypothesize that balanced equilibrium rotation is the main benefit of AdamW over Adam+ℓ2”. Treat decay as one instrument whose value must be demonstrated under the intended training system. Treat a smaller norm as evidence about the trajectory, not about the learned function.

In the LLM regime the decay coefficient is a knob on the effective learning rate and on low-precision stability, not a penalty on function complexity.

Key takeaways