Derivative checks provide targeted evidence, not an oracle
Choose directional finite-difference scales, test adjoint consistency with shaped seeds, and separate smoothness, rounding, stochastic replay, and mutually wrong derivative rules.
On this page
The question for today
What you’ll understand
- Compare a JVP with a central directional finite difference at a valid smooth point.
- Use an adjoint dot-product identity with compatible real shapes.
- Explain why kinks, rounding, shared bugs, and uncontrolled state limit a passing check.
Automatic differentiation can faithfully compose an incorrect custom rule, so an independent check matters. Numerical perturbations and adjoint identities catch different mistakes. Neither is a universal proof: finite differences balance approximation and rounding, while two mutually wrong linear maps can satisfy the same dot identity. Build small checks whose mathematical target, runtime state, scale, and expected limitations are explicit before trusting a large model's plausible gradient norms.
A finite-difference step has two competing errors
For a smooth map at a valid input, the central directional difference [f(x+hv)−f(x−hv)]/(2h) approximates J_f(x)v. Its truncation error is typically second order in h under sufficient local smoothness and a fixed direction. Floating-point subtraction and function-evaluation error can grow in relative importance as h shrinks, so making h arbitrarily tiny is not a universal improvement. Scale perturbations to the input and direction, compare several h values, and examine both absolute and relative error where appropriate.
The familiar error sketch Ch²+Dε/h explains a possible U-shaped behavior, not an exact error law or universal optimal step. Constants depend on derivatives, evaluation scale, conditioning, and the numeric format. A symmetric quadratic can have zero central-difference truncation error in exact arithmetic, while a cubic has a visible h² term. Discontinuous branches, nonsmooth boundaries, invalid domains, or stochastic evaluations can violate the smooth deterministic assumptions entirely. Distinguish a checker failing its assumptions from a derivative implementation failing the intended contract.
An adjoint check verifies a different algebraic relationship
At fixed real input, compatible forward and reverse derivative products satisfy uᵀ(Jv)=vᵀ(Jᵀu). This is useful for large operators whose full Jacobian is impractical to form. Choose nontrivial seeds and verify dimensions before evaluating the scalar products. A transpose mistake, missing accumulation path, or incorrectly shaped reduction often breaks the identity. However, implementing JVP and VJP from the same wrong matrix can pass it exactly. Combine adjoint consistency with independent primal perturbations and hand-derived cases rather than treating two matching numbers as a proof of the true derivative.
For a scalar loss, compare directional differences with the gradient dot v instead of perturbing every coordinate if that matches the test target. Sparse layouts, aliases, custom rules, and higher-order paths need their own supported checks. PyTorch 2.9's gradcheck documentation describes assumptions and limitations, including numerical differences near nondifferentiable points. Use a suitable precision and tolerance, restore RNG and mutable state between evaluations, and avoid an optimizer update during the check. A stochastic output mismatch can otherwise dominate the derivative signal even when the rule is correct.
Report what the check actually covers
Choose inputs inside each valid branch and test boundary conventions separately. Include zero and scaled seeds, repeated indices, shared subexpressions, several shapes, and supported higher-order compositions. Preserve minimized failing examples and record framework version, dtype, device, state, and perturbation scale. A passing random-direction test can miss errors orthogonal to that direction; multiple directions improve evidence without proving every input. Explain whether the checker validates a true derivative, a declared surrogate, or a runtime convention, since a finite-difference mismatch can be expected for the latter two.
The quadratic lab shows why one numerical example can be unusually easy. Reset, explicitly set BOTH a=1 and x=1, predict analytic slope two, then Play or Step. Compute the central quotient for this quadratic on paper: its exact-arithmetic value is two for every nonzero h. Reset and re-set BOTH a=2 and x=1; the value is four. Edits retain t; playback traces an analytic curve and does not simulate rounding, change h, or run gradcheck. Use the cubic worked example to see nonzero truncation rather than concluding from the quadratic that step size never matters.
Work it through
A cubic exposes the central difference's h² term
For f(x)=x³ at x=2 with direction one, compare central differences using h=0.1 and h=0.01 in exact arithmetic. Then check the adjoint identity for the earlier 3×2 Jacobian with v=(1,−1), u=(1,2,−1).
The true derivative is 12. Expanding [(2+h)³−(2−h)³]/(2h) gives 12+h², so h=0.1 yields 12.01 and h=0.01 yields 12.0001 before rounding.
For J=[[4,0],[3,2],[0,6]], Jv=(4,1,−6) and Jᵀu=(10,−2). The shapes match the three-output and two-input spaces.
Both dot products equal twelve: u·Jv=4+2+6=12 and v·Jᵀu=10+2=12. This confirms this pair's adjoint consistency, while the independent cubic calculation illustrates a different numerical-error question.
Smaller h reduces this cubic's exact truncation error, while the dot check verifies a compatible transpose relationship. Neither example proves arbitrary derivative code correct.
The living notebook
Explore the model
Interactive lab · function
An easy quadratic can hide step-size limitations
For EACH run Reset, set BOTH a and x, predict, then Play or Step. Compare (1,1), slope two, with (2,1), slope four. Their central quotients are exact in ideal arithmetic for nonzero h. Edits retain t. The instrument has no perturbation control, floating-point error simulation, AD engine, or numerical derivative checker.
- y at chosen x
- 0.608
- Tangent slope · 2ax
- 1.35
- Signed area · ax³/3
- 0.182
This lab uses only y = ax². Playback traces the curve within the fixed integration interval from 0 to x; it does not estimate numerical error or change the chosen point. 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 forCheck assumptions and use several mechanisms: one analytic family or a passing adjoint identity cannot certify a general derivative implementation.
Pause & reason
Check your understanding
Your turn
Try it yourself
At the kink of |x| at zero, a central difference with symmetric nonzero h returns zero. Does that establish an ordinary derivative zero? Explain alongside the function's one-sided slopes.
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Compare the two directional limits; a symmetric quotient can cancel despite a missing derivative.
Compare with the solution
No. The left slope is minus one and the right slope plus one, so |x| has no ordinary derivative at zero. The symmetric quotient cancels to zero because |h|=|−h|; it does not override the mismatch or validate every framework's chosen subgradient convention.
Keep the idea
Take it with you
- Finite differences require a valid smooth deterministic target and a scale-aware step.
- Adjoint dot checks verify consistency without proving primal agreement.
- Passing evidence must name its inputs, shapes, conventions, runtime state, and limits.
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.