MediumOptimization

Gradient Clipping (Global Norm)

Optimization · Neural Networks

Medium

Problem

Clip an entire gradient array by its global L2 norm:

\lVert g \rVert_2 = \sqrt{\sum_i g_i^2}

g_{\mathrm{clipped}} = \begin{cases} g, & \lVert g \rVert_2 \le m \\ g\dfrac{m}{\lVert g \rVert_2}, & \lVert g \rVert_2 > m \end{cases}

Here, g is the gradient array and m is max_norm. Return a NumPy array with the same shape as $$.

Theory

Training a neural network means computing gradients through backpropagation. The chain rule tells us to multiply the local derivatives at each layer together:

\frac{\partial L}{\partial w_1} = \frac{\partial L}{\partial h_n} \cdot \frac{\partial h_n}{\partial h_{n-1}} \cdot \frac{\partial h_{n-1}}{\partial h_{n-2}} \cdots \frac{\partial h_2}{\partial h_1} \cdot \frac{\partial h_1}{\partial w_1}

Each factor in that chain is a derivative from one layer. When many of these factors are greater than 1, the product grows exponentially. A network with 50 layers where each derivative is around 1.1 gives 1.1^{50} \approx 117. If each is around 2, you get $ \approx 10^{15}$.

This is the exploding gradient problem. It shows up most often in:

When gradients explode, the parameter update becomes enormous. A single training step can push the weights so far that the loss jumps to a huge value or becomes NaN. Training effectively crashes.


What Gradient Clipping Does

The idea is simple: if the gradient is too big, shrink it before using it to update the weights.

You pick a threshold (called the max norm). Before every parameter update, you check the size of the gradient. If it is within the threshold, you leave it alone. If it exceeds the threshold, you scale it down so its size equals exactly the threshold.

The key property: clipping only changes the magnitude, never the direction. The gradient still points in the same direction (toward decreasing loss), it just takes a smaller step. Think of it like a speed limit. You can still drive in whatever direction you want, but your speed is capped.


The L2 Norm (Global Norm)

To measure "how big" a gradient is, we use the L2 norm. This is the same as the Euclidean distance from the origin.

For a 1D gradient vector g = [g_1, g_2, \ldots, g_n]:

\|g\| = \sqrt{g_1^2 + g_2^2 + \cdots + g_n^2}

A few examples to build intuition:

For multi-dimensional arrays (like a 2D weight matrix), the "global" norm treats the entire array as one long flattened vector and computes the norm over all elements. A 2 \times 2 gradient [[2, 2], [2, 2]] has norm = \sqrt{4 + 4 + 4 + 4} = \sqrt{16} = 4.

The word "global" means we compute a single norm across all gradient values, not separate norms per row or per layer. This gives one number that captures the overall gradient magnitude.


The Clipping Rule

Once you have the norm, the rule is:

The scaling factor is:

\text{scale} = \frac{\text{max\_norm}}{\|g\|}

And the clipped gradient is:

g_{\text{clipped}} = g \cdot \text{scale}

Example: gradient g = [6, 8], max norm = 5

  1. Compute the norm: \|g\| = \sqrt{36 + 64} = \sqrt{100} = 10
  2. Since 10 > 5, clipping is needed
  3. Scale factor: \frac{5}{10} = 0.5
  4. Clipped gradient: [6 \times 0.5, \; 8 \times 0.5] = [3.0, 4.0]
  5. Verify: \|g_{\text{clipped}}\| = \sqrt{9 + 16} = 5.0 (exactly the max norm)

Example: gradient g = [0.1, 0.2, 0.2], max norm = 1.0

  1. Compute the norm: \|g\| = \sqrt{0.01 + 0.04 + 0.04} = \sqrt{0.09} = 0.3
  2. Since 0.3 \leq 1.0, no clipping needed
  3. Return the gradient unchanged: [0.1, 0.2, 0.2]

Why Direction Matters

A common alternative is element-wise clipping, where each individual gradient value is capped independently (e.g., clamp every value to [-1, 1]). The problem with this approach is that it changes the direction of the gradient vector.

Consider g = [0.5, 10.0] with element-wise clipping at 1.0:

Preserving direction matters because the gradient direction tells you which way loss decreases fastest. Changing the direction means you are no longer following the steepest descent path. Global norm clipping respects the geometry of the optimization landscape.


Choosing the Max Norm

The max norm is a hyperparameter you set before training. Common choices:

How to think about it:

A practical approach is to monitor the gradient norm during training and set the threshold just above the typical range.


Where Gradient Clipping Shows Up

Examples

Example 1

Input
g = [0.1, 0.2, 0.2], max_norm = 1.0
Output
[0.1, 0.2, 0.2]
Explanation
The global norm is 0.3, so the gradient remains unchanged.

Example 2

Input
g = [6, 8], max_norm = 5.0
Output
[3.0, 4.0]

Example 3

Input
g = [[2, 2], [2, 2]], max_norm = 2.0
Output
[[1.0, 1.0], [1.0, 1.0]]

Hints

  1. Use np.linalg.norm(g) to compute the global L2 norm.
  2. When clipping is needed, multiply by max_norm / norm.

Requirements

Constraints

Starter Code

import numpy as np

def clip_gradients(g: list, max_norm: float) -> np.ndarray:
    """
    Returns a NumPy array with the same shape as g.
    """
    # Write code here
    pass

Test Cases

CaseMatches
No clippingpublic
Clipping neededExample 2public
2D array clippingExample 3public