Masked Self-Attention
Imagine training a language model to predict the next word in a sentence. But during training it can secretly peek at the answer sitting a few tokens ahead. The model would ace training and then fail completely at real generation. This happens because at generation time the future does not exist yet. This mismatch between training and deployment is exactly the problem that masked self-attention solves. It is the single mechanism that turns a bidirectional Scaled Dot-Product Attention block into a valid engine for autoregressive sequence generation. Masked self-attention — also called causal self-attention — restricts each position in a sequence. It may attend only to itself and to positions that came before it. This one constraint allows the same parallel, matrix-multiplication-based attention machinery used in encoders to be repurposed for generation. In generation, tokens must be produced one at a time, left to right. Each token is conditioned only on what has already been produced. Without this mask, a Transformer trained to predict token could trivially attend to token itself. It could also attend to later tokens through the unmasked self-attention computation. This would make the "prediction" task vacuous. This idea matters enormously in practice. It is the structural backbone of every autoregressive large language model. This includes GPT-style architectures, decoder-only Transformers, and the decoder half of encoder-decoder models. An example is the original Transformer for machine translation. Every time you see a language model generate fluent, contextually appropriate text one token at a time, causal masking is silently enforcing a rule. The model's beliefs about token can never depend on tokens . It is a small addition to the attention formula — one masking matrix. But it is what makes large-scale self-supervised language modeling on raw, unlabeled text both trainable. It also keeps the model consistent with how it will actually be used at inference time. This article gives a precise definition of masked self-attention. It walks through the algorithm step by step with pseudocode. It explains why the mask preserves both correctness and full training parallelism. It traces a worked numerical example, and surveys the common bugs that break causal masking in practice. It closes with the historical context that led to this design. It also covers its role in the broader Transformer decoder stack.
- Masked self-attention restricts each position to attend only to itself and earlier positions, enforcing left-to-right causality.
- It is implemented by adding a mask (usually in "forbidden" entries) to attention scores before the softmax, zeroing out disallowed weights.
- It enables parallel training on entire sequences while still guaranteeing the same conditional independence structure needed for sequential generation.
- Time complexity is per layer — identical to unmasked attention; the mask itself costs only to apply.
- The mask is the defining feature that turns a Transformer encoder block into the core of a Transformer decoder, and is essential to GPT-style autoregressive language modeling.
- Common bugs include wrong mask orientation, forgetting to mask padding tokens jointly with causality, and applying the mask after softmax instead of before.
Masked self-attention adds a triangular mask to attention scores before the softmax so that position can only see positions , making parallel training and sequential, left-to-right generation mathematically consistent.
The idea
Recall that standard Scaled Dot-Product Attention computes, for query, key, and value matrices ,
Here is the sequence length and the (per-head) hidden dimension. The matrix contains a raw compatibility score between every pair of positions : row says "how much should position attend to position ." In an unmasked (bidirectional) self-attention layer, this is fine — every position may look at every other position, which is exactly what you want for tasks like masked language modeling (BERT-style) or general sequence encoding, where the whole input is visible at once.
Causal masking modifies this computation by forbidding position from attending to any position . Formally, define a mask matrix with
and compute
Adding to a score before the softmax sends its exponential to , so after normalization the attention weight assigned to any "future" position is exactly zero. Row of the resulting attention-weight matrix is a proper probability distribution supported only on — a lower-triangular structure. This is why the mask is often visualized and implemented as a lower-triangular boolean matrix. The terminology worth fixing precisely: a mask that only depends on relative position (like this triangular one) is a structural mask, distinct from a padding mask, which blocks attention to padding tokens inserted to make sequences in a batch equal length. In practice, both are combined by addition (or logical OR of "forbidden" flags) before the softmax. The causal mask alone is what defines autoregressive or decoder-style self-attention, as opposed to the bidirectional self-attention used in encoders.
How it works
The mechanism sits inside the same attention computation you already know, with one extra step: build the mask, then add it to the scaled scores before the softmax. Everything else — projecting inputs to , scaling by , applying softmax, multiplying by — is unchanged from ordinary scaled dot-product attention. There are two regimes worth understanding separately, because they explain why this design is both efficient to train and correct to deploy: 1. Training-time (teacher forcing), full-sequence, parallel form. The entire target sequence (or the entire input sequence in a decoder-only model) is available at once. We compute all pairwise scores in one matrix multiplication, then mask out the upper triangle in a single elementwise operation, then run one softmax. This is fully parallel across all positions — no sequential loop over is needed at training time, which is the key efficiency win over classical recurrent (RNN) autoregressive models. 2. Inference-time, incremental (autoregressive decoding) form. At generation time, tokens are produced one at a time. When generating token , only tokens exist. The causal mask is trivially satisfied because there simply are no future keys/values yet to attend to — but the training-time mask must have matched this exact conditional structure, otherwise the model would have learned to rely on information that will not exist at generation time. This is precisely the training/inference consistency argument for why the mask must be triangular and not, say, banded or random. ```
# Masked (causal) self-attention — full parallel form (training / prefill) #
# Inputs:
# X : (n, d_model) -- input sequence embeddings (n tokens)
# W_Q, W_K, W_V : (d_model, d_k) -- learned projection matrices
# Output:
# O : (n, d_k) -- context-aware output representations function MaskedSelfAttention(X, W_Q, W_K, W_V): n = number_of_rows(X) d_k = number_of_columns(W_K) Q = X @ W_Q # (n, d_k) K = X @ W_K # (n, d_k) V = X @ W_V # (n, d_k) scores = (Q @ transpose(K)) / sqrt(d_k) # (n, n) raw compatibility
# Build causal mask: forbid j > i (attending to the future) for i in 1..n: for j in 1..n: if j > i: scores[i][j] = -infinity
# else: leave scores[i][j] unchanged (j <= i is allowed) weights = row_wise_softmax(scores) # (n, n), each row sums to 1
# row i has zero weight for j > i O = weights @ V # (n, d_k) return O ``` ```
# Incremental (autoregressive) decoding form — used at generation time #
# Maintains a growing cache of keys/values; each new token only ever
# computes attention over already-generated tokens (mask is automatic). function IncrementalMaskedAttention(x_new, W_Q, W_K, W_V, K_cache, V_cache): q = x_new @ W_Q # (1, d_k), the new token's query k = x_new @ W_K # (1, d_k) v = x_new @ W_V # (1, d_k) K_cache = append(K_cache, k) # grows by one row each step V_cache = append(V_cache, v) scores = (q @ transpose(K_cache)) / sqrt(d_k) # (1, t) — t = current length
# No masking loop needed: K_cache contains only positions 1..t (t = current position) weights = softmax(scores) # (1, t) o = weights @ V_cache # (1, d_k) return o, K_cache, V_cache ``` Two implementation notes that matter in real systems. First, in a real Transformer, this whole block is run once per attention head, and results from multiple heads are concatenated and linearly projected — the mask is identical across heads and is usually computed once per layer (or once per forward pass, since it does not depend on the data, only on sequence length). Second, in practice is realized as a very large negative finite number (e.g. ) to avoid `NaN` values arising from during numerically-stabilized softmax computation.
Complexity & correctness
Time complexity. Computing costs scalar multiply-adds (an matrix times a matrix). Applying the mask is an elementwise operation on an matrix, costing — asymptotically dominated by the score computation. The softmax is likewise , and the final multiplication costs another . So the total time complexity per masked self-attention layer is
identical to unmasked self-attention — masking adds no asymptotic overhead; it only zeroes out entries that were already going to be computed. This is an important honesty point: causal masking does not save compute relative to bidirectional attention in the naive dense implementation, since we still materialize the full score matrix and simply discard (mask) half of it. (Specialized implementations can skip computing the strictly-upper-triangular half, roughly halving the constant factor, but the asymptotic order remains .)
Space complexity. The dense attention-weight matrix requires memory per head (plus for and outputs). This is the well-known quadratic memory bottleneck of Transformer self-attention, and it applies to masked attention exactly as it does to unmasked attention — masking changes values inside the matrix, not its shape. During incremental generation, however, a key-value cache stores only the keys and values generated so far at step , avoiding recomputation of earlier positions' representations; this is a major practical optimization enabled precisely by the causal structure (past keys/values never need to be revisited or recomputed because future tokens cannot influence them).
Correctness argument. The claim to verify is: training with the causal mask produces a model whose predicted distribution for token depends only on tokens , matching exactly what is available at generation time. Consider the computational dependency graph of the masked attention layer. Row of the output, , is a function only of and , because for all by construction (softmax of is exactly , not merely small). Since are themselves computed from respectively via the same linear projections applied position-wise, output is a function only of . Stacking such masked layers preserves this property by induction on depth: if every layer's output at position depends only on inputs at positions , then layer 's output at position — being a function of layer 's outputs at positions — also depends only on inputs at positions . (Feedforward sublayers and layer normalization are applied position-wise and do not break this invariant.) This gives an exact conditional-independence guarantee: the model's final hidden state at position , and hence its predicted next-token distribution , is a genuine function of only the causal prefix. This is exactly the factorization used in the chain rule of probability for autoregressive language modeling,
so training a masked Transformer with cross-entropy loss on next-token prediction is a consistent way to fit this factorization — the model literally cannot cheat by looking ahead, because the mask makes the forward computation graph itself acyclic and causally ordered.
Tradeoffs. Masking is cheap to implement and adds no fundamentally new complexity class, but it does not reduce the memory and compute footprint of full self-attention — for long sequences this remains the dominant bottleneck, motivating sparse, linear, or blockwise-recurrent attention variants (a separate topic from masking itself). Masked attention also gives up the bidirectional context that helps encoder-style models (like those used for classification or masked-language-modeling pretraining); this is a genuine representational tradeoff, not a bug — it is the price paid for making the model usable for open-ended generation.
Worked example
Consider a toy sequence of 4 tokens: `"the cat sat down"`, with for simplicity. Suppose the (already projected) query and key vectors are:
| Position | Token | Query | Key |
|---|---|---|---|
| 1 | the | ||
| 2 | cat | ||
| 3 | sat | ||
| 4 | down |
Raw dot products (before scaling by ), for the row ("sat") against all four keys:
Scaled: for and for .
Without masking, row 3's softmax input is . Computing softmax:
Sum , giving weights approximately — note that "sat" would attend most strongly (weight ) to "down", a word that comes after it. That is precisely the information leak we must prevent.
With the causal mask, position is forbidden for query , since . The mask sets that score to :
Softmax now only normalizes over :
Sum , giving weights
Position 3 ("sat") now attends equally to "the", "cat", and itself, and exactly zero weight to "down" — the future token is fully excluded, not merely down-weighted. This row is precisely what will be available when the model must, at generation time, predict what comes after "the cat sat" without yet knowing the word "down" exists.
| Query row | Masked columns | Softmax support |
|---|---|---|
| ("the") | only | |
| ("cat") | ||
| ("sat") | ||
| ("down") | none |
This table exhibits the triangular support pattern directly: row 's softmax is supported exactly on , matching the earlier correctness argument concretely rather than abstractly.
Common pitfalls & traps
| Pitfall | Why it happens | Consequence |
|---|---|---|
| Mask built with wrong inequality (`j >= i` instead of `j > i`) | Off-by-one in triangle construction | Position cannot even attend to itself, breaking the model (it can never see its own current token's representation) |
| Applying mask after softmax (zeroing weights post-hoc) | Confusing "additive mask before softmax" with "multiplicative mask after" | Rows no longer sum to 1 after zeroing; unnormalized attention silently degrades quality |
| Forgetting to combine causal mask with padding mask | Batches contain variable-length sequences padded to a common length | Model attends to meaningless padding tokens, corrupting learned representations |
| Using finite but too-small negative number for "masked" | Trying to avoid `-inf`/NaN issues, but choosing e.g. | With large score magnitudes, masked entries leak nonzero probability, causing subtle future-information leakage |
| Mismatched mask shape when using multi-head attention or KV-caching | Reusing a single 2D mask incorrectly across a batch or across cached vs. new tokens | Shape broadcasting errors or (worse) silent misalignment where wrong positions get masked |
| Assuming masking reduces asymptotic compute | Intuition that "we only need half the matrix" automatically speeds things up | Naive implementations still compute and store the full score matrix; real speed gains require specialized fused kernels |
Pioneers & history
Masked self-attention was introduced as part of the original Transformer architecture, designed to replace recurrent and convolutional sequence models with a fully attention-based design. The insight that a single triangular mask could convert a bidirectional attention mechanism into an autoregressive one — while preserving full parallelism across the sequence during training — was central to making self-attention practical for sequence generation tasks like machine translation, and later the foundation for large-scale generative language modeling.
Origins · 1 minAshish Vaswani and how this was discovered
Where this matters
Masked self-attention is the computational core of every GPT-family model and, more broadly, every decoder-only large language model used for open-ended text generation, chat assistants, and code completion. It is also used inside the decoder half of encoder-decoder ("sequence-to-sequence") Transformer models used for machine translation and summarization, where the decoder must generate output tokens autoregressively while separately attending to the (unmasked) encoder output. Production inference systems build entire serving stacks — key-value caching, speculative decoding, continuous batching — around the specific dependency structure that causal masking guarantees: that past keys and values are frozen and reusable once computed, since no future token can ever alter them. Any system claiming to do streaming or incremental text generation with a Transformer — search engine query completion, code autocompletion, real-time chat — relies on this exact guarantee at its core. Understanding masked self-attention is the direct prerequisite for understanding the full Transformer Decoder Stack and how it powers GPT & Autoregressive Language Modeling.
Ask the tutor: How does causal masking interact with multi-head attention and key-value caching when generating text one token at a time?
Why can't we just train with unmasked attention and only mask at inference time?
Because training uses teacher forcing: the whole target sequence is fed to the model at once so all positions can be trained in parallel. If the mask were absent during training, position 's output could depend on token and beyond (via unmasked attention), so the model would learn to partly "read off" the answer it is supposed to predict. At inference time those future tokens do not exist, so the model's learned dependence on them would be useless or actively wrong. The mask must be present during training precisely so the training-time computation graph matches the inference-time information constraints — this is what makes the learned conditional distributions valid for actual sequential generation.
Is masked self-attention the same thing as the decoder in a Transformer?
Not quite — masked self-attention is one sublayer inside a decoder block, not the whole decoder. A full Transformer decoder layer typically also contains a second, unmasked "cross-attention" sublayer (in encoder-decoder models) that attends over the encoder's output, plus a position-wise feedforward network, residual connections, and layer normalization. In decoder-only architectures like GPT, there is no separate cross-attention sublayer — every layer is simply a masked self-attention sublayer followed by a feedforward sublayer, repeated many times. So masked self-attention is the defining ingredient of a decoder, but the decoder as a whole includes additional components.
How is the mask combined with padding masks in a real batched implementation?
Both are represented as additive score-space masks and simply summed (or combined with logical OR before conversion to additive form) before the softmax. The causal mask depends only on the pair of positions and is the same for every sequence in the batch. The padding mask depends on which specific tokens in that particular sequence are real versus padding, and therefore varies per example in the batch. Adding both masks together (each contributing , or a large negative number, wherever attention should be forbidden) correctly forbids attention to both future positions and padding positions simultaneously, since remains effectively after the softmax.
Does masked self-attention prevent the model from ever learning bidirectional context?
Within a single masked self-attention layer, yes — position genuinely cannot see position 's representation at that layer. But this is a deliberate design choice for autoregressive generation tasks, not a general limitation of Transformers. Encoder-style pretraining objectives such as masked language modeling (as in BERT) deliberately use unmasked, bidirectional self-attention instead, because their goal is representation learning over a fully visible input rather than left-to-right generation. The choice between masked and unmasked self-attention is essentially a choice of pretraining objective and downstream use case, not a strictly better-or-worse tradeoff.
What happens numerically if -infinity is implemented as a literal floating-point negative infinity?
Most deep learning frameworks handle this safely if implemented carefully: `exp(-inf)` correctly evaluates to `0.0`, and as long as at least one entry in each row is finite (which is guaranteed, since is always allowed), the softmax denominator is finite and positive, avoiding division by zero. The danger arises in numerically-stabilized softmax implementations that subtract the row maximum before exponentiating — if an entire row were somehow all (which should never happen under correct causal masking, since the diagonal is always unmasked), the max-subtraction step could produce `NaN`. In practice, most production implementations use a large finite negative constant (e.g., ) specifically to sidestep any such edge cases in mixed-precision arithmetic.
How does causal masking relate to key-value caching during text generation?
Causal masking guarantees that once a token's key and value vectors are computed at a given layer, they are never affected by tokens generated afterward, since future tokens cannot feed back into past ones. This licenses key-value caching: during autoregressive generation, instead of recomputing attention over the entire sequence-so-far at every generation step, a system can cache the keys and values computed for all previous tokens and simply append the new token's key and value at each step. This turns naive -per-step generation into -per-step generation (amortized over the whole sequence), a major practical efficiency gain that only works because of the causal structure guaranteed by masking.
Can masked self-attention be combined with relative or rotary position encodings?
Yes, and in modern large language models it typically is. The causal mask operates purely on the attention-score matrix based on token index comparisons (), and is entirely independent of how positional information is injected into the queries and keys. Rotary position embeddings (RoPE), relative position biases, and other schemes modify how and encode position before the dot product is taken, while the causal mask is applied afterward, additively, to the resulting score matrix. The two mechanisms are complementary layers of the same attention computation and are combined routinely in state-of-the-art decoder-only architectures.