The useful part, up front

What you’ll take away

  • A zero-valued gradient and an absent gradient have different participation semantics in the cited optimizer.
  • Retained momentum and separate weight decay can change a parameter even when its new gradient is zero.
  • Skipping a parameter update preserves its existing optimizer history rather than resetting it.
  • In the ordinary AdamW path examined here, zero learning rate can preserve the weight while moments and update count advance.
  • Three equal weights in the original example become 9.507, about 9.531329 and 9.607 after the same next gradient because their histories differ.
  • A continuation record needs matching parameter values, optimizer state, settings and parameter identity.
01

A pause needs a more precise description

Suppose a model weight has stopped changing during part of a training run. Has its learning process really paused? The answer depends on what happened to the optimizer, the procedure that uses gradients and its own stored information to choose updates. Keeping a weight still for one step does not necessarily keep that stored information still.

A gradient describes how the current loss changes with a small change in a weight. A zero gradient is a numerical result. An absent gradient means there is no gradient object for that parameter at this step. PyTorch documents different optimizer behavior for these cases: a present zero can still take part in an update, while an absent gradient skips the parameter's step [2].

We will compare those cases with setting the learning rate to zero and with starting fresh optimizer history. The examples use invented scalar values and the documented ordinary AdamW equations [1]. They are calculations, not a model-training experiment. Their purpose is to explain why two copies of the same visible weight can take different next steps.

One first update creates the common checkpoint. Original scalar example: initial weight 10, gradient 3, learning rate 0.2, decay 0.1, β₁=0.5, β₂=0.8 and ε=1. Values are chosen for teaching, not recommended training settings.
Original scalar example: initial weight 10, gradient 3, learning rate 0.2, decay 0.1, β₁=0.5, β₂=0.8 and ε=1. Values are chosen for teaching, not recommended training settings. · Ameer Journal — original explanatory diagramOriginal editorial illustration; no third-party artwork reused.
02

The optimizer remembers more than the last weight

AdamW keeps two running summaries for each participating parameter. One follows the signed gradients, so recent positive and negative values can partly cancel. The other follows squared gradients, so their sign disappears. The algorithm also uses an update count when correcting these summaries for their zero starting values [1]. These are separate pieces of information from the weight itself.

This history explains why a new zero gradient need not produce a zero adjustment. A running summary can remain positive after a new contribution of zero. AdamW also applies weight decay through a separate part of its update [1]. In our positive-weight example, the chosen decay factor reduces the weight even if the new gradient supplies no adjustment.

Think of a saved optimizer record as containing the information needed to interpret the next gradient. PyTorch's optimizer state dictionary stores state per parameter and stores parameter-group settings, including learning rate and weight decay; it does not itself store the parameter values [4]. Both the values and the matching history matter when describing a continuation.

03

Build one checkpoint with transparent numbers

Start with one weight equal to 10 and no previous optimizer history. Choose learning rate 0.2, weight-decay coefficient 0.1, first-summary factor 0.5, second-summary factor 0.8 and the denominator's extra constant equal to 1. These are deliberately simple teaching values. In particular, the extra constant is much larger than the documented default; this is not a suggested training configuration [1].

Supply a first gradient of 3. The running summaries become 1.5 and 1.8. After the algorithm corrects their zero-start effect, the values used in the adjustment are 3 and 9. The square root of 9 is 3, and the extra constant makes the denominator 4. The gradient-based subtraction is therefore 0.2 times 3 divided by 4, or 0.15.

Separately, the decay multiplier is one minus 0.2 times 0.1: 0.98. It changes 10 to 9.8 before the subtraction of 0.15. Our checkpoint is weight 9.65, signed summary 1.5, squared summary 1.8 and update count one. Every comparison below starts from this same checkpoint unless a fresh history is explicitly specified.

04

A present zero gradient still changes this weight

First, give the checkpoint a gradient value of zero and keep the ordinary learning rate. The signed summary halves from 1.5 to 0.75. The squared summary becomes 0.8 times 1.8, or 1.44. Both have changed, but neither has become zero. This is the second update, so the corrections must use count two rather than count one.

The corrected summaries are now 1 and 4. Taking the square root of 4 and adding the extra constant gives 3, so the gradient-based subtraction is 0.2 divided by 3: one fifteenth. Decay separately changes 9.65 to 9.457. Subtracting one fifteenth leaves approximately 9.390333, below the original checkpoint weight.

The new gradient was zero throughout that calculation. The change came from retained history and decay, which are part of the documented update [1]. A zero gradient therefore does not establish that this optimizer leaves the parameter unchanged. It also does not establish that training has found a globally best model; it only describes the supplied derivative value for this step.

Separate history-driven movement from decay. Original comparisons from weight 9.65. History: m=1.5, v=1.8, count=1. Fresh state resets those three values to zero. Decimals are rounded.
Original comparisons from weight 9.65. History: m=1.5, v=1.8, count=1. Fresh state resets those three values to zero. Decimals are rounded. · Ameer Journal — original explanatory diagramOriginal editorial illustration; no third-party artwork reused.
05

Remove one cause at a time

To see the two causes clearly, repeat the zero-gradient calculation from the original checkpoint while switching off weight decay. Keep the history. The one-fifteenth subtraction remains, so the weight becomes about 9.583333. The weight still moves because the optimizer still remembers the earlier positive gradient.

Now try a separate branch with the same weight, 9.65, but fresh zero summaries and count zero. Keep weight decay and supply a zero gradient. The summaries remain zero, so the gradient-based subtraction is zero. Decay alone changes the weight to 9.457. This branch deliberately removes history; it is not what an ordinary missing-gradient step does.

These branches identify two independent explanations for movement in our original example. With fresh zero summaries and repeated zero gradients, the chosen decay factor would multiply the weight by 0.98 on each participating update. The number of such updates therefore matters. Skipping a parameter's update does not apply the same repeated multiplication, even if the surrounding training loop continues running.

06

An absent gradient skips the parameter without erasing its past

Return to the original checkpoint. This time the parameter's gradient is absent, represented by None in PyTorch. The cited zero_grad documentation distinguishes that state from a tensor filled with zeroes [2]. In the inspected AdamW implementation, only parameters with an existing gradient are added to the update's parameter and state lists [6][7].

Under that ordinary update path, our parameter stays at 9.65. Its summaries stay at 1.5 and 1.8, and its update count stays at one. No decay is applied to this skipped parameter. Other eligible parameters can still be processed during the same optimizer call; the statement concerns the parameter we are following.

The old history has been preserved, not forgotten. If a later step supplies another gradient, the optimizer can continue from that history. This is why a skipped update and a fresh optimizer are different choices even when both leave the current weight at 9.65. The next gradient provides a way to make their difference visible.

07

A zero learning rate can preserve the weight while changing the history

There is another way to keep the weight still in our example. Give the parameter a present gradient of zero, but use learning rate zero for that update. Both the decay change and the gradient-based change to the weight are multiplied by the learning rate, so the weight remains 9.65.

The stored summaries do not use the learning rate in their own recurrences [1]. They still become 0.75 and 1.44, and the count advances to two in the ordinary implementation path [7]. The visible weight now matches the skipped-gradient branch, but the optimizer history does not. Looking only at saved weights would miss that difference.

Restore the ordinary learning rate later and that changed history can affect the next adjustment. Setting the learning rate to zero is therefore a precise intervention with a particular effect, rather than a complete description of pausing all learning-related state. This example does not extend that claim to every optimizer implementation, every numerical mode or an update containing nonfinite values.

An unchanged weight can hide changed optimizer state. Both hypothetical pause branches leave the weight at 9.65. A missing gradient skips this parameter; a present zero gradient with learning rate zero still advances its ordinary moment state.
Both hypothetical pause branches leave the weight at 9.65. A missing gradient skips this parameter; a present zero gradient with learning rate zero still advances its ordinary moment state. · Ameer Journal — original explanatory diagramOriginal editorial illustration; no third-party artwork reused.
08

The same next gradient exposes three different histories

Take three branches that all now have weight 9.65. One skipped the pause update and kept its earlier history. Another took the zero-gradient update with learning rate zero. The third starts fresh history at the same weight. Restore the ordinary learning rate of 0.2 and give every branch the same next gradient: minus 3.

The skipped branch reaches 9.507. The zero-learning-rate branch reaches about 9.531329. The fresh-history branch reaches 9.607. Their starting weight, current gradient and current settings are equal; their past optimizer states differ. The negative gradient creates an upward adaptive adjustment here, but the size depends on that retained history as well as the current input.

This comparison is why checking that a supposedly paused weight stayed still can be necessary without answering the whole question. It establishes what happened to the parameter during the pause, but it does not establish how the parameter will resume. A clear experiment records whether history was preserved, advanced or deliberately reset, rather than treating all three outcomes as the same kind of freeze.

09

The zero-gradient issue also appears in ordinary momentum

AdamW's details are useful, but stored history is not unique to it. PyTorch's ordinary stochastic gradient descent optimizer can use a momentum buffer that carries part of a previous update forward [3]. A simpler example makes the same zero-versus-absent distinction without AdamW's two summaries or bias corrections.

Start a separate weight at 10, choose learning rate 0.1 and momentum factor 0.8, and use no weight decay or dampening. A first gradient of 2 creates a buffer of 2 and moves the weight to 9.8. With a present zero gradient next, the buffer becomes 0.8 times 2, or 1.6. Subtracting 0.1 times 1.6 moves the weight again, to 9.64.

If that second gradient is absent, the ordinary parameter update is skipped and the weight stays 9.8 [2]. With momentum switched off in a separate comparison, a present zero gradient also leaves the weight at 9.8. Those equal weights arise for different reasons. Name the optimizer and its state rule before interpreting a zero-gradient observation.

Ordinary SGD momentum can also survive a zero gradient. Separate original SGD example: after gradient 2, weight=9.8 and momentum buffer=2. Learning rate 0.1, momentum 0.8, no decay or dampening. Compare the next update; no library execution is claimed.
Separate original SGD example: after gradient 2, weight=9.8 and momentum buffer=2. Learning rate 0.1, momentum 0.8, no decay or dampening. Compare the next update; no library execution is claimed. · Ameer Journal — original explanatory diagramOriginal editorial illustration; no third-party artwork reused.
10

Keep the decay rule and its coefficient convention together

Weight decay and a penalty added to the loss are related ideas, but their implementation matters. The original AdamW paper explains why adding a squared-weight penalty into an adaptive gradient calculation is generally different from applying decay separately [5]. A penalty added to the gradient can also enter the optimizer's historical summaries.

Our calculations use the PyTorch AdamW rule, where the decay multiplier is one minus learning rate times weight-decay coefficient [1]. With our chosen settings, that is 0.98. This is why reducing the learning rate to zero removes the decay change for the particular update we studied.

Be careful when comparing equations across sources. The paper's opening weight-decay equation uses a coefficient that directly represents the fraction removed per step [5]. Its symbol is not automatically the same numerical setting as the PyTorch argument. Here the direct fraction is 0.02, while the PyTorch weight-decay coefficient is 0.1. Keeping the complete formula prevents a matching name from hiding different quantities.

11

Check the parameter that actually reaches the optimizer

The example follows one complete scalar parameter. In a real model, a parameter may contain many values. A gradient tensor can exist while some of its entries are zero. That is different from having no gradient object for the entire parameter. The inspected optimizer checks whether the parameter's gradient exists before admitting it to the update [7].

This also makes the timing of a change important. Saying that a parameter should receive no new gradient does not describe an older gradient object that may already be present. PyTorch's zero_grad documentation explains the effect of setting gradients to None before a backward pass [2]. A clear record distinguishes the gradient object actually supplied from the intention to stop computing new derivatives.

Choose an observable question. Are the parameter values unchanged? Are the optimizer's summaries and count unchanged? Does resuming produce the same update? These require different comparisons. The present article addresses optimizer state; model training modes and other mutable buffers are separate controls. An observation about one of these objects cannot establish that every part of the model has paused.

12

A reproducible continuation pairs values with the matching state

A useful continuation record pairs the parameter values with their matching optimizer state and settings. For our example that means the weight, both summaries, the update count, the learning rate, the two averaging factors, decay and the denominator's extra constant. It also records which pause was applied, so the next result can be explained.

Restoring state requires the right association with the current parameters. PyTorch documents that saved optimizer identifiers are matched to current parameter groups in order, without an additional verification of that match [4]. Its loading notes also explain that saved parameter names do not by themselves control the loading process [1]. A file containing history is not enough if that history is attached to the wrong parameter.

The worked result remains specific and useful: zero gradients can preserve momentum-derived movement, missing gradients can preserve old history without advancing it, and zero learning rate can keep weights still while history advances. Equal saved weights therefore do not guarantee equal next updates. Recording the complete transition makes a pause understandable without pretending that its arithmetic proves model quality or a successful training outcome.

A continuation record must connect state to the right parameter. Conceptual record for the article’s scalar optimizer example. A model-value snapshot and optimizer state serve different purposes; saved state must be associated with the intended current parameter.
Conceptual record for the article’s scalar optimizer example. A model-value snapshot and optimizer state serve different purposes; saved state must be associated with the intended current parameter. · Ameer Journal — original explanatory diagramOriginal editorial illustration; no third-party artwork reused.
Follow the evidence

Sources & further reading

Explore the references behind this guide. External pages may change after our review.

  1. AdamW — PyTorch 2.15 documentation
    PyTorch · Accessed 7 Nov 2026
  2. torch.optim.Optimizer.zero_grad — PyTorch 2.15 documentation
    PyTorch · Accessed 7 Nov 2026
  3. SGD — PyTorch 2.15 documentation
    PyTorch · Accessed 7 Nov 2026
  4. torch.optim.Optimizer.state_dict — PyTorch 2.15 documentation
    PyTorch · Accessed 7 Nov 2026
  5. Decoupled Weight Decay Regularization
    Loshchilov and Hutter / University of Freiburg / arXiv · Accessed 7 Nov 2026
  6. pytorch/torch/optim/adamw.py at v2.15.0 · pytorch/pytorch · GitHub
    PyTorch · Accessed 7 Nov 2026
  7. pytorch/torch/optim/adam.py at v2.15.0 · pytorch/pytorch · GitHub
    PyTorch · Accessed 7 Nov 2026

Article updated 7 Nov 2026.

Found something we should revisit?

Good explanations get better with thoughtful feedback.

Suggest a correction