Deep learning
Gradient clipping and accumulation
Clipping caps rare gradient spikes. Accumulation simulates a larger batch when memory is tight. Get the loss averaging right or the effective learning rate silently changes.
Two practical tools show up in almost every transformer training loop. Gradient clipping stops a rare spike from destroying the run. Gradient accumulation fakes a larger batch when the GPU cannot hold one.
Concept
Clipping bounds the global L2 norm of gradients before the optimizer step. If the pre-clip norm was 100 and max_norm=1, every grad is scaled by 0.01.
The big idea
import torch
from torch import nn
p = nn.Parameter(torch.tensor([3.0, 4.0])) # grad we will set to this vector
p.grad = torch.tensor([3.0, 4.0]) # L2 norm = 5
torch.nn.utils.clip_grad_norm_([p], max_norm=1.0)
print(p.grad.tolist())Output:
[0.6, 0.8]The vector (3, 4) had norm 5, so it was scaled by 1/5. Typical steps barely change. Rare spikes get crushed. Log the pre-clip norm. A sudden climb warns of instability. max_norm=1.0 is a common default in RNN and transformer training.
Walking through accumulation
Accumulation simulates a larger batch when memory is tight:
for micro in microbatches:
loss = compute(micro) / N
loss.backward() # grads accumulate
optimizer.step(); optimizer.zero_grad()Effective batch size = micro_batch × N × num_gpus. Keep the loss averaging correct so the effective learning-rate meaning stays stable. If you forget to divide by N, you have scaled the gradient — and the step — by N.
BatchNorm statistics see only the micro-batch. That is another reason transformers prefer LayerNorm. See normalization layers.
A picture: clipping is a speed limiter on a downhill road. Accumulation is taking the same trip in several cars and averaging the directions before you turn the wheel. The picture breaks if the cars (micro-batches) are so small that BatchNorm's "class average" is noise.
Warmup plus cosine (or a known step schedule) still beats a constant LR for long runs. See conditioning and schedules. Mismatching "scheduler step per batch" versus "per epoch" is how you accidentally use 100× fewer decay steps than you intended.
Common mistakes
- Forgetting to divide the micro-batch loss by
N. The effective LR jumps byN. - Clipping after the optimizer step. The spike already landed.
- Using BatchNorm with tiny micro-batches and blaming Adam. The batch statistic is the noise.
Check yourself
- Pre-clip grad norm is 100,
max_norm=1. What happens to each gradient? Answer: Every grad is scaled by 0.01. - You accumulate 8 micro-batches and do not divide the loss by 8. What did you just do to the step size? Answer: You scaled the gradient, and the update, by 8.
Key takeaways
- Clipping caps the global grad norm and saves runs from rare spikes.
- Log the pre-clip norm. A sudden climb is an instability warning.
- Accumulation fakes a larger batch. Divide the loss by the number of micro-batches.
- BatchNorm still sees the micro-batch. LayerNorm does not care.
Further learning
Next: neural-net regularization.
Related
Training neural networks well
Optimizers, schedules, initialization, normalization, regularization and a practical recipe for debugging loss curves.
Mini-batch SGD and batch size
Estimating the gradient from a random mini-batch is cheap and noisy, and that noise is useful. Batch size trades gradient quality, hardware efficiency and generalization.
BatchNorm, LayerNorm and RMSNorm
Normalization rescales activations so each layer sees well-scaled inputs. BatchNorm uses the batch, LayerNorm uses one example's features, and RMSNorm drops the mean.