Gradient clipping
Read these first if they are new to you
- Gradient descent Intermediate
- Reading Python Basic
The idea in one paragraph
Gradient clipping puts a cap on how long the gradient may be before a training step uses it. Measure the length of the whole gradient. If it is longer than a chosen maximum, scale it down to exactly that maximum, keeping its direction. Ordinary steps pass through unchanged. A rare, huge gradient, such as one caused by a single unusual batch of examples, can then no longer throw the weights far off course.
One huge gradient can undo many good steps
In gradient descent, each step moves the weights by the learning rate times the gradient. Most steps are small. Now and then, one batch of examples produces a gradient a hundred times larger than usual: an odd example, a steep cliff in the loss, or a numerical accident. The step is then a hundred times larger too. The weights land somewhere far away, the loss jumps up, and training may take thousands of steps to recover, or never recover.
Clipping shrinks a long gradient to a fixed length, keeping its direction
Think of the gradient as one long vector, with an entry for every weight in the model. Its length, called its norm, is the square root of the sum of the squares of all entries. That is the distance formula, with as many coordinates as the model has weights.
Choose a maximum length c. Then, before each step:
- if the norm is c or less, leave the gradient as it is;
- if the norm is larger, multiply every entry by c / norm.
Multiplying every entry by the same number keeps the direction and changes only the length. The clipped length is exactly c.
- Norm: √(32 + 42) = √25 = 5.
- 5 is more than c = 1, so scale by 1 / 5 = 0.2.
- Clipped gradient: (0.6, 0.8). Its length is √(0.36 + 0.64) = 1, and it points the same way.
Your turn. Clip (6, 8) with c = 5.
Answer
The norm is 10, so scale by 5 / 10 = 0.5. The result is (3, 4).
Try it. The figure clips a gradient to length c = 1, shown as the circle. Predict first: what is the clipped length when the gradient's length is 2.5? Then move the slider and find the length at which the two arrows stop matching.
Answer
The clipped length is 1, as it is for any gradient longer than 1. The arrows match up to length 1 and separate beyond it.
The norm covers all the weights together
The usual method, clipping by the global norm, computes one norm over every weight in the model and scales all gradients by the same factor. Suppose one layer's gradient is (1, 2) and another's is (2). The global norm is √(1 + 4 + 4) = 3. With c = 1.5, every entry is halved.
A cruder method, clipping by value, caps each entry on its own. It changes the direction: capping (3, 4) at 1 gives (1, 1), which points somewhere else.
In PyTorch, clip after loss.backward() has filled the gradients and before
optimizer.step() uses them. The function returns the norm from before clipping. That number is worth
printing or logging: a norm that keeps rising warns that training is going wrong.
clip_torch.py
import torch
a = torch.zeros(2, requires_grad=True) # weights of one layer
b = torch.zeros(1, requires_grad=True) # weights of another
a.grad = torch.tensor([1.0, 2.0])
b.grad = torch.tensor([2.0])
total = torch.nn.utils.clip_grad_norm_([a, b], max_norm=1.5)
print(total) # length before clipping: sqrt(1 + 4 + 4) = 3
print(a.grad, b.grad) # every entry scaled by 1.5 / 3 = 0.5
tensor(3.)
tensor([0.5000, 1.0000]) tensor([1.0000])
In a training loop, the three lines go in this order (an excerpt, not a whole program):
loss.backward()
# model.parameters() lists all the model's weights, like [a, b] above.
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
optimizer.step()
PyTorch scales by c / (norm + 0.000001), so the clipped length is a hair under c. A maximum of 1.0 is a common starting value, but it is a setting to tune. Clipping is used with AdamW too. AdamW already limits each step's size, but one huge gradient still inflates its running average of squared gradients, which then shrinks the steps for hundreds of steps afterwards.
Check yourself
-
Clip the gradient (0.3, 0.4) with c = 1.
Answer
Its norm is 0.5, which is below 1, so it stays (0.3, 0.4).
-
Clip the gradient (2, 0, 0, 1, 2) with c = 2.
Answer
The norm is √(4 + 0 + 0 + 1 + 4) = 3. Scale by 2 / 3 to get (4/3, 0, 0, 2/3, 4/3), about (1.33, 0, 0, 0.67, 1.33).
-
Why is clipping by the global norm usually preferred to clipping each entry by value?
Answer
It keeps the gradient's direction, so the step still goes downhill in the same way, only shorter. Clipping by value can change the direction.
-
Someone calls
clip_grad_norm_afteroptimizer.step(). What goes wrong?Answer
The step has already used the unclipped gradient, so the large step happens anyway. Clipping must come between
backward()andstep().
Go further
Optional background, for readers who want more than this page.
-
A short derivation of why clipping bounds the step, with a from-scratch implementation.
-
The function's arguments, including other kinds of norm, and what it returns.
-
On the difficulty of training recurrent neural networks Pascanu, Mikolov and Bengio, 2013 Paper Advanced
The paper that made norm clipping standard, with a picture of a loss cliff that throws a step far away.
Where this shows up
Units that build on this one
- The training loop Intermediate