advanced28 min studyLesson 549 in Engineering

Equivalence tests: compare the update state, not only the loss

Build canonical small-step references for gradients, parameters, moments, clipping, masks, and precision-dependent drift across replicated and sharded execution.

On this page

What you’ll understand

  • Design a deterministic separable reference objective and canonical state mapping.
  • Compare several optimizer boundaries, including nonzero restored state.
  • Distinguish expected floating-point variation from incorrect scaling or ownership.

A distributed training change can preserve the printed loss while moving one optimizer moment to the wrong parameter or applying weight decay twice. Equivalence testing should therefore compare the mathematical update and its hidden state at defined boundaries. We use pinned PyTorch 2.9 DDP, FSDP, optimizer, and mixed-precision contracts, with small explicit reference calculations. Numerical agreement under a selected fixture is valuable evidence, but it does not prove that every graph, dtype, or failure path behaves equivalently.

Make the reference objective and state mapping unambiguous

Start with a tiny deterministic model and a known global example or token multiset. Use a separable objective so that splitting inputs does not change model semantics; rank-local batch normalization, randomness, and stateful layers need separate intended contracts. Compute a high-precision unsharded reference and preserve masks, reduction mode, eligible counts, parameter identities, and optimizer hyperparameter groups. Reconstruct sharded tensors in canonical logical order before comparison. Equal norms cannot detect a permutation that attaches correct numerical moments to the wrong coordinates.

Compare at several boundaries: local loss-sum accounting, normalized aggregate gradients, post-clipping gradients, updated parameters, and optimizer state after the step. Include zero gradients, unequal token counts, uneven parameter shapes, and a final partial accumulation window. A reference that repeats the implementation’s mistaken denominator will agree for the wrong reason, so derive expected values independently for at least a few scalar fixtures. Record which differences are algorithmic changes and which are supposed to preserve the same update.

∥xtest−xref∥∞≤atol+rtol∥xref∥∞\|x_{\rm test}-x_{\rm ref}\|_\infty\le a_{\rm tol}+r_{\rm tol}\|x_{\rm ref}\|_\infty
This illustrative comparison rule uses arrays with the same canonical shape, absolute tolerance a in x units, and dimensionless relative tolerance r, both nonnegative. A passing tolerance is a chosen numerical criterion, not an algorithmic equivalence theorem.↔ Scroll wide equations horizontally.

Multiple steps expose missing state and boundary errors

The first optimizer step can hide a lost momentum or adaptive-moment checkpoint because the initial buffers are often zero. Test multiple steps and restore a fixture with known nonzero state. Check the step counter, schedule position, weight-decay mode, and parameter-group settings as well as tensor values. Advancing an optimizer or scheduler once per microbatch instead of once per accumulation window can change every later step even if the initial gradient matches. A state-sharding test must verify each owner’s identity and state, not just that the final model contains finite numbers.

Mixed precision needs explicit expected ordering: accumulate under a consistent scale, synchronize according to the wrapper’s contract, unscale at the proper boundary, and clip the intended global gradient. Overflow and skipped-step behavior must leave ranks compatible. Floating-point reductions are not associative, so a different legal collective or bucket order may introduce small drift without an objective error. Choose tolerances based on dtype and the operation, then investigate structured discrepancies such as an exact world-size factor, a swapped parameter block, or a step counter that differs by the accumulation count.

vt=βvt−1+gt,θt+1=θt−ηvtv_t=\beta v_{t-1}+g_t,\qquad\theta_{t+1}=\theta_t-\eta v_t
This deliberately simple momentum recurrence uses 0≤β<1, η≥0, no dampening, no weight decay, no Nesterov term, and explicitly supplied gradients. It is a test fixture, not a formula for every optimizer or mixed-precision implementation.↔ Scroll wide equations horizontally.

Use metamorphic cases with independent expected outcomes

Change the number of workers while preserving the intended global batch and objective, or repartition the same canonical gradient among owners, then compare the next state. Such transformations should preserve the stated mathematics only when their assumptions remain true. A local-batch-dependent model or changed sample duplication invalidates that expectation. Also test a save-and-resume boundary against uninterrupted execution, including optimizer and input progress state. Keep the result scoped to the evaluated implementation and configurations, and retain a failing fixture rather than weakening tolerance until every difference disappears.

For a simple update-boundary check, Reset the optimization lab, explicitly set step size 0.1 and initial position two, predict two iterates, then Step twice. Compare a fresh Reset with both step size 0.2 and initial position two set before one Step. Results are 1.8 then 1.62 versus 1.6. The fixed quadratic is a small independent arithmetic oracle, not a momentum, Adam, DDP, or sharding implementation. It demonstrates why distinct update schedules should not be labeled equivalent merely because their total nominal step sizes match.

A missing momentum buffer appears on the second update

Use the stated momentum fixture with initial parameter one, v₀=0, β=0.9, and learning rate 0.1. The first supplied gradient is two and the second is one. Compare correct state retention with resetting the momentum buffer before the second update.

  1. For the first update, momentum becomes 0.9×0+2=2 and the parameter becomes 1−0.1×2=0.8. A mistaken implementation that starts from zero can still match this first result.

  2. Retaining state, the next momentum is 0.9×2+1=2.8 and the next parameter is 0.8−0.1×2.8=0.52. Both the parameter and the momentum are expected reference outputs.

  3. Resetting momentum before the second update gives v=1 and parameter 0.7 instead. The parameter difference is 0.18, with a state difference of 1.8; inspecting only the first update or the supplied gradient would miss the bug.

The result

The correct two-update parameter is 0.52 with momentum 2.8. A nonzero-state fixture distinguishes restoration from coincidental first-step agreement.

Explore the model

Interactive lab

Interactive lab · optimization

One independent scalar schedule can expose a boundary mismatch

Use separate Reset → set BOTH controls → predict → Step runs. With η=.1,x₀=2, two Steps give 1.8 and 1.62; with η=.2,x₀=2, one Step gives 1.6. The lab models only fixed quadratic gradient descent, with no momentum state or distributed execution.

One independent scalar schedule can expose a boundary mismatchGradient descent on f(x) = x²/2: xₙ = (1 − η)ⁿx₀. Playback advances two discrete iterations per second. Values outside |x| ≤ 4 are explicitly reported. Current readings: Position x0: 2; Objective x²/2: 2; Iteration behavior: Stable step. All parameters are adjustable with the labeled controls below.−4−202402.174.356.528.7Parameter xf(x) = x²/2n = 0
ObjectiveDiscrete iterate
Position x0
2
Objective x²/2
2
Iteration behavior
Stable step
n = 0 · t = 0 s

Gradient descent on f(x) = x²/2: xₙ = (1 − η)ⁿx₀. Playback advances two discrete iterations per second. Values outside |x| ≤ 4 are explicitly reported. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.

Look forChoose an oracle whose expected state can be derived independently, and compare at the intended optimizer boundaries.

Check your understanding

A sharded optimizer matches the first parameter update from zero-initialized moments. Which additional test most directly checks state restoration?

Try it yourself

For the same momentum fixture, use β=0.5, learning rate 0.2, initial parameter two, and initial momentum zero. Supply gradients four and two on consecutive updates. Calculate the two momentum values and final parameter. What if momentum is reset before the second update?

Take a moment to make a prediction or work it out on paper. Open a hint when you need one.

Give me a hint

Apply the recurrence at each optimizer boundary and retain the first state as an input to the second.

Compare with the solution

The first momentum is four and the parameter becomes 2−0.2×4=1.2. The second momentum is 0.5×4+2=4, so the correct final parameter is 0.4. Resetting before the second update instead gives momentum two and parameter 0.8. Compare both state and parameters against these values, using an appropriate floating-point tolerance. This deliberately simple fixture isolates state retention; it does not validate a different optimizer’s adaptive moments, loss-scaling, or distributed clipping without additional cases.

Take it with you

  • Derive the global objective and canonical parameter identity independently.
  • Compare gradients, parameters, and hidden optimizer state across multiple boundaries.
  • Scope tolerance-based evidence and investigate structured discrepancies.

Read further

Original sources and deeper explanations to follow at your own pace.

Optional progress, saved in this browser when available. Revisit any lesson at any time.

Lesson not marked complete.