Decoder Architecture › The Causal Masking Requirement
Language AI HandbookAll chapters Decoder Architecture › The Causal Masking RequirementOne section · Sections in this chapter4 / 16 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
To understand why causal masking is essential, consider what happens without it. In standard self-attention, every position can attend to every other position. When processing the word "cat" in "The cat sat on the mat," the model can look at "sat," "on," "the," and "mat" to help represent "cat." This bidirectional view is powerful for understanding, but it creates a fundamental problem for generation.
During generation, when we're about to predict "sat," the words "on," "the," and "mat" don't exist yet. If the model learned to rely on future context during training, it would fail at inference time. Even worse, during training on complete sequences, the model could "cheat" by peeking at the answer. Position 3 could look at position 4 to see what word should come next, trivially solving the prediction task without learning meaningful patterns.
Causal masking restricts each position to attend only to itself and previous positions. This enforces a left-to-right information flow that matches the autoregressive generation process, where tokens are produced one at a time and future tokens don't exist.
The solution is to enforce a strict temporal ordering: position can only attend to positions . This constraint, called causal masking or autoregressive masking, ensures the model learns to predict using only past context.
From Intuition to Formulation
How do we mathematically enforce "only attend to the past"? We need to modify the attention mechanism so that certain query-key pairs produce zero attention weight. The key insight is that attention weights come from a softmax over scores. If we can make certain scores extremely negative before the softmax, they'll become negligible in the final weights.
Standard scaled dot-product attention computes:
The term produces an matrix of scores, where entry measures how much query should attend to key . To block future positions, we add a mask matrix to these scores before the softmax:
where:
- : query matrix containing query vectors, each of dimension
- : key matrix containing key vectors, each of dimension
- : value matrix containing value vectors, each of dimension
- : the raw attention score matrix, where entry measures similarity between query and key
- : scaling factor that prevents dot products from growing too large as dimension increases
- : the causal mask matrix that blocks future positions
Designing the Mask
The mask must satisfy a simple requirement: add 0 to scores we want to keep, and add a very large negative number to scores we want to block. Formally:
where:
- : the query position (row index), representing the token doing the attending
- : the key position (column index), representing the token being attended to
- : the mask value added to the attention score at position
The condition captures "key is at or before query," which means the token at position is in the past (or present) relative to position . When this holds, we add 0, leaving the score unchanged. When , the key is in the future, so we add to block that attention path.
This creates a characteristic triangular pattern:
- Row 0 (first token): only column 0 is allowed (the token can only see itself)
- Row 1 (second token): columns 0 and 1 are allowed (can see itself and the first token)
- Row (last token): all columns 0 through are allowed (can see the entire sequence)
Why Creates Zero Attention
The mathematical trick is elegant. After adding the mask, we apply softmax to convert scores to attention weights. For a masked position:
As the mask value approaches , the numerator approaches 0. The denominator remains positive because unmasked positions contribute finite, positive exponentials. The result:
Those positions receive exactly zero attention weight. The token at position effectively cannot see any token at positions . In practice, we use a large finite value like instead of true infinity, which achieves the same effect with standard floating-point arithmetic.
Implementation
Let's implement causal masking and visualize the resulting attention pattern. The mask is simply an upper triangular matrix of negative infinities:
import numpy as np
def create_causal_mask(seq_len):
"""
Create a causal attention mask.
Returns a matrix where:
- 0 for positions that CAN be attended (j <= i)
- -inf for positions that CANNOT be attended (j > i)
"""
# Upper triangular matrix with -inf above the diagonal
mask = np.triu(np.ones((seq_len, seq_len)) * float("-inf"), k=1)
return mask
# Example: 5-token sequence
mask = create_causal_mask(5)Causal Mask (5 tokens): Rows = query position, Columns = key position 0 = can attend, -inf = blocked Position 0: [ 0 -inf -inf -inf -inf ] Position 1: [ 0 0 -inf -inf -inf ] Position 2: [ 0 0 0 -inf -inf ] Position 3: [ 0 0 0 0 -inf ] Position 4: [ 0 0 0 0 0 ]
Position 0 can only attend to itself. Position 1 can attend to positions 0 and 1. Position 4 can attend to all five positions. The triangular structure ensures strictly left-to-right information flow.
