`RNN`
Attention Weights
Zero-Padding
Sequence Masking
Machine Learning

Should `RNN` attention weights over variable length sequences be re-normalized to mask the effects of zero-padding?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Yes, padded positions should be masked out of the attention distribution so they receive zero probability mass. In practice, that means you either mask the logits before softmax or zero out padded weights and re-normalize afterward, with the first option being the standard and numerically cleaner approach.

Why Padding Breaks Attention if Left Unmasked

Attention weights are usually computed by taking scores over all timestep positions and then applying softmax. If padded positions remain in that softmax, they compete with real tokens for probability mass.

That means the model can end up assigning some attention to pure padding, which dilutes the weight assigned to actual sequence content.

For variable-length batches, that is incorrect behavior. Padding exists only to align tensor shapes, not because those positions carry meaning.

The Correct Mental Model

Suppose a sequence of true length 3 is padded to length 5.

Real positions:

  • token 1
  • token 2
  • token 3

Padding positions:

  • pad
  • pad

The attention distribution should sum to 1 only across the three real positions. The padded positions should have weight 0.

So yes, in effect the weights must be re-normalized over valid tokens only.

Best Practice: Mask Before Softmax

The usual implementation is to add a very negative number to padded logits before softmax.

python
1import tensorflow as tf
2
3scores = tf.constant([[1.2, 0.8, 2.0, -0.3, 0.1]], dtype=tf.float32)
4mask = tf.constant([[1, 1, 1, 0, 0]], dtype=tf.float32)
5
6large_negative = -1e9
7masked_scores = scores + (1.0 - mask) * large_negative
8weights = tf.nn.softmax(masked_scores, axis=-1)
9
10print(weights.numpy())

This produces weights that sum to 1 over the valid positions and effectively 0 over padding.

Masking before softmax is preferred because it preserves the probabilistic interpretation cleanly.

Re-Normalizing After Softmax Also Works

If you already have attention weights and need to fix them afterward, you can zero out padding weights and then divide by the remaining total.

python
1import numpy as np
2
3weights = np.array([0.20, 0.15, 0.25, 0.20, 0.20])
4mask = np.array([1, 1, 1, 0, 0])
5
6masked = weights * mask
7renormalized = masked / masked.sum()
8print(renormalized)

This gives the right result mathematically, but it is usually less convenient and less stable than masking the logits first.

Why This Matters for Context Vectors

The attention weights determine how hidden states are combined into the context vector.

python
1import tensorflow as tf
2
3hidden_states = tf.constant([
4    [1.0, 0.0],
5    [0.0, 1.0],
6    [1.0, 1.0],
7    [9.0, 9.0],
8    [9.0, 9.0],
9], dtype=tf.float32)
10
11weights = tf.constant([0.2, 0.3, 0.5, 0.0, 0.0], dtype=tf.float32)
12context = tf.reduce_sum(hidden_states * tf.expand_dims(weights, -1), axis=0)
13print(context.numpy())

If padded positions were allowed to carry nonzero weight, the context vector would be contaminated by states that represent padding artifacts rather than real sequence content.

That is why masking is not optional bookkeeping. It changes the actual representation the network uses downstream.

RNNs, Packed Sequences, and Framework Support

Many frameworks already offer sequence masking mechanisms. For example:

  • TensorFlow and Keras propagate masks through compatible layers
  • PyTorch often uses sequence lengths or packed sequences for recurrent parts, while attention masking is still handled explicitly in the attention layer

The important point is that recurrent processing and attention masking are related but separate concerns. Even if the RNN itself handled variable lengths efficiently, attention still needs to know which positions are valid.

What About Learned Attention to Padding?

Sometimes people ask whether the model might learn to ignore padding automatically. It might partially do so, but that is not a reason to leave the problem in the optimization path.

Padding positions are known invalid inputs. Since you already know they should receive zero attention, it is better to encode that constraint directly than to hope the model learns it from data.

This usually improves stability and makes the attention distribution easier to interpret.

Common Pitfalls

A common mistake is masking hidden states but not masking attention logits. Those are different operations, and the latter is still necessary.

Another issue is zeroing weights after softmax without re-normalizing. That leaves the total attention mass below 1 and changes the scale of the context vector.

Developers also sometimes use the wrong mask shape when batching multi-head or decoder-query attention, which silently masks the wrong positions.

Finally, do not assume zero-valued padding embeddings are harmless. The problem is not only the padded value; it is the probability mass assigned to invalid positions.

Summary

  • Padding positions should receive zero attention weight.
  • The standard solution is to mask logits before softmax.
  • Zeroing weights after softmax requires re-normalization to stay correct.
  • Unmasked padding corrupts the context vector and weakens interpretability.
  • Attention masking is necessary even when the recurrent layer already handles variable lengths.

Course illustration
Course illustration

All Rights Reserved.