Difference between tf.clip_by_value and tf.clip_by_global_norm for RNN's and how to decide max value to clip on?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Gradient clipping prevents exploding gradients during RNN training. TensorFlow provides two main approaches: tf.clip_by_value clips each gradient element independently to a fixed range, while tf.clip_by_global_norm scales all gradients proportionally so their combined norm stays below a threshold. Global norm clipping is preferred for RNNs because it preserves the relative direction of gradients across layers, whereas value clipping can distort the gradient direction and harm training.
tf.clip_by_value: Element-Wise Clipping
tf.clip_by_value clamps every individual gradient value to a [min, max] range:
Each element is clipped independently. The value 100.0 becomes 1.0 and -10.0 becomes -1.0, but 0.5 and -0.1 are untouched.
Usage in Training
tf.clip_by_global_norm: Proportional Scaling
tf.clip_by_global_norm computes the global L2 norm across ALL gradients and scales them down proportionally if the norm exceeds the threshold:
The scaling factor is min(1, clip_norm / global_norm). When the global norm is within the threshold, gradients are unchanged. When it exceeds the threshold, all gradients are multiplied by the same factor, preserving their relative magnitudes and directions.
Usage in Training
Why Global Norm Is Better for RNNs
RNNs unroll across many timesteps, creating deep computation graphs where gradients flow through repeated matrix multiplications. This makes them prone to exploding gradients where some gradient components become enormous while others stay small.
Value clipping distorts the gradient direction — the tiny component (0.001) is left unchanged while the large component (1000.0) is crushed to 1.0. The gradient now points in a fundamentally different direction.
Global norm clipping preserves the direction by scaling everything proportionally. The relative relationship between components is maintained, leading to more stable training.
Choosing the Clip Value
For tf.clip_by_global_norm (recommended starting values)
| Task | Typical clip_norm |
| LSTM/GRU language models | 1.0 - 5.0 |
| Sequence-to-sequence | 5.0 - 10.0 |
| Vanilla RNN | 1.0 |
| Transformer models | 1.0 |
For tf.clip_by_value
A common choice is [-1.0, 1.0] or [-5.0, 5.0]. These are less principled than global norm thresholds because the appropriate range depends on every layer's gradient scale.
Keras Built-In Clipnorm
Keras optimizers support gradient clipping directly:
clipnorm uses global norm clipping internally. clipvalue uses value clipping.
Side-by-Side Comparison
| Property | tf.clip_by_value | tf.clip_by_global_norm |
| Clips | Each element independently | All gradients proportionally |
| Preserves direction | No | Yes |
| Parameters | min, max values | Single norm threshold |
| Best for | Simple feedforward networks | RNNs, LSTMs, Transformers |
| Keras shortcut | clipvalue=0.5 | clipnorm=1.0 |
Common Pitfalls
- Using clip_by_value for RNNs: Value clipping distorts gradient direction, causing training instability. Always prefer global norm clipping for recurrent architectures.
- Setting clip_norm too low: Aggressively clipping (e.g.,
clip_norm=0.1) effectively reduces the learning rate to near zero, causing extremely slow training. Monitor gradient norms first. - Setting clip_norm too high: A threshold that never triggers (e.g.,
clip_norm=1000) provides no protection against exploding gradients. The threshold should be near the typical gradient norm. - Clipping before vs after optimizer state updates: When using Adam or RMSProp, the optimizer uses raw gradients for its moment estimates. Clipping before
apply_gradientsmeans the optimizer sees clipped gradients, which is the standard approach. Clipping inside a custom training step at the wrong point can corrupt optimizer state. - Forgetting None gradients:
tape.gradient()returnsNonefor variables not connected to the loss. PassingNonetotf.clip_by_global_normraises an error. Filter them out:[(g, v) for g, v in zip(grads, vars) if g is not None].
Summary
tf.clip_by_valueclips each gradient element to a fixed range — simple but distorts directiontf.clip_by_global_normscales all gradients proportionally to keep the global norm below a threshold — preserves direction- Use global norm clipping for RNNs, LSTMs, GRUs, and Transformers
- Start with
clip_norm=1.0to5.0and monitor gradient norms to tune - Use
clipnormin Keras optimizers for the simplest integration

