Intuition What this page is for
The parent note gave you the two formulas. Here we do the drill : we list every kind of gradient you could ever be handed — safe ones, exploding ones, a zero gradient, a single-number gradient, a gradient sitting exactly on the leash, a real training spike — and we clip each one carefully. If you finish this page, no clipping problem on an exam or in a codebase can surprise you.
Before anything, let us re-anchor the two tools in plain words so every symbol below is earned.
Definition The two clip rules, in words
g = the gradient vector : a list of numbers, one per parameter. Think of it as an arrow pointing in the direction the loss climbs fastest.
∥ g ∥ = the L2 norm = the length of that arrow = g 1 2 + g 2 2 + … . It answers "how far would one raw step throw us?"
c = the norm threshold : the longest arrow we allow.
v = the value threshold : the biggest single component we allow.
α = the scale factor : the single positive number we multiply the whole gradient by. For clip-by-norm we define α = min ( 1 , ∥ g ∥ c ) .
Clip-by-norm: g ^ = α g = g ⋅ min ( 1 , ∥ g ∥ c ) — same arrow, maybe shorter.
Clip-by-value: g ^ i = clip ( g i , − v , v ) = max ( − v , min ( g i , v )) — cap each number on its own.
Clipping produces the safe gradient g ^ ; whatever the optimizer does with it afterwards is a separate step we don't need here.
Every clipping problem is one of these cells. The examples below each carry a tag like (A2) .
#
Cell class
What makes it special
Covered by
A1
Norm, safe gradient
∥ g ∥ ≤ c → no change
Ex 1
A2
Norm, exploding gradient
∥ g ∥ > c → shrink
Ex 2
A3
Norm, exactly on the leash
∥ g ∥ = c (boundary)
Ex 3
A4
Norm, negative components
signs must survive scaling
Ex 4
B1
Value clip, mixed signs
each coord clamped to [ − v , v ]
Ex 5
B2
Value vs norm on same g
direction distortion shown
Ex 6
C1
Zero / degenerate gradient
∥ g ∥ = 0 , division danger
Ex 7
C2
Scalar (1-D) gradient
norm = absolute value
Ex 7
D1
Real-world word problem
RNN loss spike, pick behaviour
Ex 8
D2
Exam twist
solve for the threshold c
Ex 9
g = ( 0.6 , 0.8 ) , threshold c = 2 . Clip by norm.
Forecast: Guess first — will this arrow get trimmed at all? Look at how short ( 0.6 , 0.8 ) feels versus a budget of 2 .
Compute the length ∥ g ∥ = 0. 6 2 + 0. 8 2 = 0.36 + 0.64 = 1 = 1 .
Why this step? We must know the arrow's length before we can compare it to the leash c .
Compare to c : 1 ≤ 2 , so the arrow is already inside budget.
Why this step? The rule splits into two cases on exactly this comparison.
Apply the factor α = min ( 1 , 2/1 ) = min ( 1 , 2 ) = 1 , so g ^ = 1 ⋅ ( 0.6 , 0.8 ) = ( 0.6 , 0.8 ) .
Why this step? When c /∥ g ∥ ≥ 1 the min picks 1 — the whole point of the min is to leave good gradients untouched.
Verify: g ^ = g , length still 1 ≤ 2 . Nothing was distorted. ✓
g = ( 3 , 4 ) , c = 2 .
Forecast: The length is 5 but the budget is 2 . Predict the final vector and its length before reading on.
∥ g ∥ = 9 + 16 = 5 . Why? Establish we exceed c .
5 > 2 → we are in the shrink case. Why? Determines which branch of the min fires.
α = min ( 1 , 2/5 ) = 0.4 . Why? c /∥ g ∥ is the exact factor that pulls the length down to c .
g ^ = 0.4 ⋅ ( 3 , 4 ) = ( 1.2 , 1.6 ) . Why? One scalar multiplies both coordinates → direction preserved.
Verify: ∥ g ^ ∥ = 1. 2 2 + 1. 6 2 = 1.44 + 2.56 = 4 = 2 = c . Sits exactly on the leash. ✓ The ratio 1.2 : 1.6 = 3 : 4 is untouched — same arrow, shorter.
Look at the figure: the black arrow is the raw g of length 5 . The red arrow is g ^ — it lands exactly on the dashed circle of radius c = 2 , lying along the same ray. The circle is the "leash": any raw arrow poking outside it gets pulled back onto its rim.
g = ( 2 , 0 ) , c = 2 . This is the boundary case — does the min pick 1 or shrink?
Forecast: When ∥ g ∥ equals c exactly , which branch wins?
∥ g ∥ = 2 2 + 0 2 = 2 . Why? We are testing the equality edge.
c /∥ g ∥ = 2/2 = 1 , so α = min ( 1 , 1 ) = 1 . Why? At equality both arguments of min tie; the result is 1 , so no scaling.
g ^ = 1 ⋅ ( 2 , 0 ) = ( 2 , 0 ) . Why? Multiplying by 1 is identity.
Verify: unchanged, length still exactly 2 . The boundary is treated as safe (the condition is ∥ g ∥ > c to shrink, strict). ✓ No danger of dividing by trouble here.
g = ( − 6 , 8 ) , c = 5 .
Forecast: Will the negative sign flip when we scale? Guess the signs of g ^ first.
∥ g ∥ = ( − 6 ) 2 + 8 2 = 36 + 64 = 100 = 10 . Why? Squaring kills the sign, so length is always positive — that's why norm doesn't care about direction, only size.
10 > 5 → shrink. α = min ( 1 , 5/10 ) = 0.5 . Why? Standard Case 2.
g ^ = 0.5 ⋅ ( − 6 , 8 ) = ( − 3 , 4 ) . Why? A positive scalar 0.5 multiplies each coord — signs are preserved because 0.5 > 0 .
Verify: ∥ g ^ ∥ = ( − 3 ) 2 + 4 2 = 9 + 16 = 5 = c . ✓ The negative component stayed negative — clip-by-norm never flips signs, because α > 0 always.
g = ( 100 , − 3 , 0.5 ) , value threshold v = 10 . Clip by value.
Forecast: Which of the three numbers actually get touched? Guess before computing.
Coord 1: clip ( 100 , − 10 , 10 ) = min ( 100 , 10 ) = 10 . Why? 100 exceeds the upper cap, so it's pinned to + v .
Coord 2: clip ( − 3 , − 10 , 10 ) = − 3 (already inside [ − 10 , 10 ] ). Why? − 3 is between the bounds — untouched.
Coord 3: clip ( 0.5 , − 10 , 10 ) = 0.5 . Why? Well inside → untouched.
g ^ = ( 10 , − 3 , 0.5 ) . Why? Each coordinate is decided independently — that's the definition of value clipping.
Verify: Every entry now lies in [ − 10 , 10 ] . ✓ But notice: the ratio of coord 1 to coord 2 went from 100 : ( − 3 ) to 10 : ( − 3 ) — the direction changed . Value clipping guarantees per-coordinate bounds, not direction.
g = ( 6 , 8 ) , with c = v = 5 . Do it both ways and compare.
Forecast: One method keeps the arrow pointing at "3:4"; the other tilts it. Predict which — and predict whether the value-clipped result even fits inside the norm budget.
By norm: ∥ g ∥ = 36 + 64 = 10 , α = 5/10 = 0.5 , g ^ norm = ( 3 , 4 ) . Why? Scalar scaling → direction 6 : 8 = 3 : 4 preserved.
Length check: 3 2 + 4 2 = 9 + 16 = 5 = c . Why this step? We must confirm the norm-clipped vector actually lands on the leash (length exactly c ) — this is the guarantee that separates it from value clipping, so we check it before comparing.
By value: g ^ val = ( min ( 6 , 5 ) , min ( 8 , 5 )) = ( 5 , 5 ) . Why? Both coords exceed 5 , both pinned to 5 .
Its length: 25 + 25 = 50 ≈ 7.07 . Why compute it? To expose a trap.
Verify: The value-clipped vector has length ≈ 7.07 > 5 — it still overshoots the norm budget and its direction is now 1 : 1 instead of 3 : 4 . Clip-by-norm respects the geometry; clip-by-value does not. ✓
In the figure the black arrow is g = ( 6 , 8 ) . The red arrow is the norm-clipped result sitting on the ray at length 5 ; the grey arrow is the value-clipped ( 5 , 5 ) — visibly rotated away from the original ray. Same start, different destinations.
Two edge inputs, each solved on its own numbered track.
(a) g = ( 0 , 0 , 0 ) with c = 2 . (b) a single scalar gradient g = − 7 with c = 4 .
Forecast: In (a) the formula has c /∥ g ∥ = 2/0 . Does clipping blow up? In (b), what even is the norm of one number?
Track (a) — the zero gradient:
∥ g ∥ = 0 2 + 0 2 + 0 2 = 0 = 0 . Naively c /∥ g ∥ = 2/0 is undefined. Why does this matter? A raw division would crash.
Test the shrink condition: is ∥ g ∥ > c ? Here 0 > 2 is false , so we take the safe branch and never divide. Why this step? The rule only reaches the division when ∥ g ∥ > c ; guarding on this comparison is exactly how real code (clip_grad_norm_) avoids the 2/0 .
g ^ = ( 0 , 0 , 0 ) , unchanged. Why? A zero gradient means "no update," and clipping leaves it that way.
Track (b) — the scalar gradient:
∥ g ∥ = ( − 7 ) 2 = 7 = ∣ − 7 ∣ . Why? With a single component, the L2 norm collapses to absolute value.
Test the shrink condition: 7 > 4 is true → shrink. Why this step? Same comparison as always, applied to a 1-D vector.
α = min ( 1 , 4/7 ) = 4/7 , and g ^ = − 7 ⋅ 7 4 = − 4 . Why? Scale to length c = 4 ; the sign stays because α > 0 .
Verify: (a) output is all zeros, no NaN. ✓ (b) ∣ g ^ ∣ = ∣ − 4∣ = 4 = c , sign preserved. ✓
You are training an RNN with BPTT . Normal gradient norms hover around 0.8 . On step 4021 the norm suddenly reads 540 and the loss is about to go NaN. You have clip_grad_norm_ set to c = 5 . By what factor does this step shrink, and does learning direction survive?
Forecast: Guess the shrink factor's order of magnitude before computing.
Is it a spike? 540 ≫ 0.8 typical → yes, this is an exploding gradient off a cliff . Why? We only want to clip the rare spike, not the ordinary steps.
∥ g ∥ = 540 > 5 = c → shrink. α = 5/540 = 108 1 ≈ 0.009259 . Why? Same scalar formula, applied to the whole flattened parameter vector (global norm).
After clipping ∥ g ^ ∥ = 5 instead of 540 , so a giant leap becomes a sane step in the same direction. Why global norm? Scaling every layer by one factor α keeps their relative sizes intact.
Verify: α ⋅ 540 = 540 5 ⋅ 540 = 5 = c . ✓ The direction is untouched (one positive scalar), the magnitude is safe, NaN averted. This is exactly why clipping is near-mandatory for RNNs/Transformers.
A gradient g = ( 0 , 5 , 12 ) is clipped by norm and you observe the clipped vector has length 6.5 . What threshold c produced this, and what is g ^ ?
Forecast: The clipped length equals... c itself, whenever clipping actually fires. So what is c ?
∥ g ∥ = 0 2 + 5 2 + 1 2 2 = 0 + 25 + 144 = 169 = 13 . Why? Need the raw length to know if clipping happened.
Since the output length 6.5 < 13 , clipping did fire, which means the output length equals c . So c = 6.5 . Why? When Case 2 fires, ∥ g ^ ∥ = α ∥ g ∥ = ∥ g ∥ c ∥ g ∥ = c exactly.
α = c /∥ g ∥ = 6.5/13 = 0.5 . Why? Recover the scale factor now that c is known.
g ^ = 0.5 ⋅ ( 0 , 5 , 12 ) = ( 0 , 2.5 , 6 ) . Why? Apply the factor to each coordinate.
Verify: ∥ g ^ ∥ = 0 + 2. 5 2 + 6 2 = 6.25 + 36 = 42.25 = 6.5 = c . ✓ Self-consistent.
Recall Rapid self-test (predict, then reveal)
Do these in your head using "same arrow, shorter arrow."
g = ( 9 , 12 ) , c = 3 : shrink factor and result? ::: ∥ g ∥ = 15 , α = 3/15 = 0.2 , g ^ = ( 1.8 , 2.4 ) , length 3 .
g = ( 0 , 0 ) , c = 1 , clip-by-norm: result? ::: ( 0 , 0 ) — safe branch, no division, no NaN.
g = ( 4 , − 3 ) value-clipped at v = 3 : result and did direction change? ::: ( 3 , − 3 ) ; direction 4 : − 3 → 1 : − 1 , yes it changed.
Clip-by-norm output length always equals what when clipping fires? ::: The threshold c exactly.
Norm clips the arrow; value clips the numbers. If the clipped length comes out equal to c , clipping fired; if it comes out unchanged, the gradient was already safe.