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 tt could trivially attend to token tt 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 tt can never depend on tokens t+1,t+2,…t+1, t+2, \dots. 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.

Key takeaways
  • 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 −∞-\infty 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 O(n2d)O(n^2 d) per layer — identical to unmasked attention; the mask itself costs only O(n2)O(n^2) 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.
The core insight

Masked self-attention adds a triangular mask to attention scores before the softmax so that position tt can only see positions ≤t\le t, 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 Q,K,V∈Rn×dQ, K, V \in \mathbb{R}^{n \times d},

Attention(Q,K,V)=softmax ⁣(QK⊤d)V.\text{Attention}(Q,K,V) = \text{softmax}\!\left(\frac{QK^\top}{\sqrt{d}}\right) V .

Here nn is the sequence length and dd the (per-head) hidden dimension. The matrix QK⊤/d∈Rn×nQK^\top / \sqrt{d} \in \mathbb{R}^{n \times n} contains a raw compatibility score between every pair of positions (i,j)(i, j): row ii says "how much should position ii attend to position jj." 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 ii from attending to any position j>ij > i. Formally, define a mask matrix M∈{0,−∞}n×nM \in \{0, -\infty\}^{n \times n} with

Mij={0j≤i−∞j>iM_{ij} = \begin{cases} 0 & j \le i \\ -\infty & j > i \end{cases}

and compute

MaskedAttention(Q,K,V)=softmax ⁣(QK⊤d+M)V.\text{MaskedAttention}(Q,K,V) = \text{softmax}\!\left(\frac{QK^\top}{\sqrt{d}} + M\right) V .

Adding −∞-\infty to a score before the softmax sends its exponential to 00, so after normalization the attention weight assigned to any "future" position is exactly zero. Row ii of the resulting attention-weight matrix is a proper probability distribution supported only on {1,…,i}\{1, \dots, i\} — 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 Q,K,VQ, K, V, scaling by d\sqrt{d}, applying softmax, multiplying by VV — 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 n2n^2 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 ii 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 t+1t+1, only tokens 1,…,t1, \dots, t 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 −∞-\infty is realized as a very large negative finite number (e.g. −109-10^9) to avoid `NaN` values arising from −∞−(−∞)-\infty - (-\infty) during numerically-stabilized softmax computation.

Figure
Causal attention mask: each row can only look left, including itself
Attention weight matrix (rows = query position, cols = key position) k1 k2 k3 k4 k5 q1 q2 q3 q4 q5 allowed (j ≤ i) masked, weight = 0 Row q_i is nonzero only in columns 1..i — a lower-triangular pattern. Query q3 sees keys k1, k2, k3 but never k4 or k5 (the future). Mask is added as −∞ to scores before softmax; softmax renormalizes each row.

Complexity & correctness

Time complexity. Computing QK⊤QK^\top costs O(n2d)O(n^2 d) scalar multiply-adds (an n×dn \times d matrix times a d×nd \times n matrix). Applying the mask is an elementwise operation on an n×nn \times n matrix, costing O(n2)O(n^2) — asymptotically dominated by the score computation. The softmax is likewise O(n2)O(n^2), and the final multiplication weights⋅V\text{weights} \cdot V costs another O(n2d)O(n^2 d). So the total time complexity per masked self-attention layer is

O(n2d),O(n^2 d),

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 n×nn \times n 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 Θ(n2d)\Theta(n^2 d).)

Space complexity. The dense attention-weight matrix requires O(n2)O(n^2) memory per head (plus O(nd)O(nd) for Q,K,VQ, K, V 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 O(td)O(td) keys and values generated so far at step tt, 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 t+1t+1 depends only on tokens 1,…,t1, \dots, t, matching exactly what is available at generation time. Consider the computational dependency graph of the masked attention layer. Row ii of the output, OiO_i, is a function only of {Qi}\{Q_i\} and {Kj,Vj:j≤i}\{K_j, V_j : j \le i\}, because weightsij=0\text{weights}_{ij} = 0 for all j>ij > i by construction (softmax of −∞-\infty is exactly 00, not merely small). Since Qi,Kj,VjQ_i, K_j, V_j are themselves computed from Xi,XjX_i, X_j respectively via the same linear projections applied position-wise, output OiO_i is a function only of X1,…,XiX_1, \dots, X_i. Stacking LL such masked layers preserves this property by induction on depth: if every layer's output at position ii depends only on inputs at positions ≤i\le i, then layer ℓ+1\ell+1's output at position ii — being a function of layer ℓ\ell's outputs at positions ≤i\le i — also depends only on inputs at positions ≤i\le i. (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 ii, and hence its predicted next-token distribution P(xi+1∣x1,…,xi)P(x_{i+1} \mid x_1, \dots, x_i), 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,

P(x1,…,xn)=∏i=1nP(xi∣x1,…,xi−1),P(x_1, \dots, x_n) = \prod_{i=1}^n P(x_i \mid x_1, \dots, x_{i-1}),

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 O(n2)O(n^2) 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 dk=2d_k = 2 for simplicity. Suppose the (already projected) query and key vectors are:

PositionTokenQuery qiq_iKey kik_i
1the(1,0)(1, 0)(1,0)(1, 0)
2cat(0,1)(0, 1)(0,1)(0, 1)
3sat(1,1)(1, 1)(1,0)(1, 0)
4down(0,0)(0, 0)(1,1)(1, 1)

Raw dot products qi⋅kjq_i \cdot k_j (before scaling by dk=2≈1.414\sqrt{d_k} = \sqrt{2} \approx 1.414), for the row i=3i=3 ("sat") against all four keys:

q3⋅k1=(1,1)⋅(1,0)=1,q3⋅k2=(1,1)⋅(0,1)=1,q3⋅k3=(1,1)⋅(1,0)=1,q3⋅k4=(1,1)⋅(1,1)=2.q_3 \cdot k_1 = (1,1)\cdot(1,0) = 1, \quad q_3 \cdot k_2 = (1,1)\cdot(0,1) = 1, \quad q_3 \cdot k_3 = (1,1)\cdot(1,0) = 1, \quad q_3 \cdot k_4 = (1,1)\cdot(1,1) = 2.

Scaled: 1/1.414≈0.7071/1.414 \approx 0.707 for j=1,2,3j=1,2,3 and 2/1.414≈1.4142/1.414 \approx 1.414 for j=4j = 4.

Without masking, row 3's softmax input is (0.707,0.707,0.707,1.414)(0.707, 0.707, 0.707, 1.414). Computing softmax:

e0.707≈2.03,e0.707≈2.03,e0.707≈2.03,e1.414≈4.11.e^{0.707} \approx 2.03,\quad e^{0.707} \approx 2.03,\quad e^{0.707}\approx 2.03,\quad e^{1.414}\approx 4.11.

Sum ≈2.03+2.03+2.03+4.11=10.2\approx 2.03+2.03+2.03+4.11 = 10.2, giving weights approximately (0.199,0.199,0.199,0.403)(0.199, 0.199, 0.199, 0.403) — note that "sat" would attend most strongly (weight 0.4030.403) to "down", a word that comes after it. That is precisely the information leak we must prevent.

With the causal mask, position j=4j=4 is forbidden for query i=3i = 3, since 4>34 > 3. The mask sets that score to −∞-\infty:

masked scores3,⋅=(0.707, 0.707, 0.707, −∞).\text{masked scores}_{3,\cdot} = (0.707,\ 0.707,\ 0.707,\ -\infty).

Softmax now only normalizes over j=1,2,3j = 1, 2, 3:

e0.707≈2.03 (three times),e−∞=0.e^{0.707} \approx 2.03 \text{ (three times)}, \quad e^{-\infty} = 0.

Sum =2.03×3=6.09= 2.03 \times 3 = 6.09, giving weights

(0.333, 0.333, 0.333, 0.0).(0.333,\ 0.333,\ 0.333,\ 0.0).

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 rowMasked columnsSoftmax support
i=1i=1 ("the")j=2,3,4j = 2,3,4{1}\{1\} only
i=2i=2 ("cat")j=3,4j = 3,4{1,2}\{1,2\}
i=3i=3 ("sat")j=4j = 4{1,2,3}\{1,2,3\}
i=4i=4 ("down")none{1,2,3,4}\{1,2,3,4\}

This table exhibits the triangular support pattern directly: row ii's softmax is supported exactly on {1,…,i}\{1, \dots, i\}, matching the earlier correctness argument concretely rather than abstractly.

Common pitfalls & traps

PitfallWhy it happensConsequence
Mask built with wrong inequality (`j >= i` instead of `j > i`)Off-by-one in triangle constructionPosition ii 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 maskBatches contain variable-length sequences padded to a common lengthModel 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. −100-100With large score magnitudes, masked entries leak nonzero probability, causing subtle future-information leakage
Mismatched mask shape when using multi-head attention or KV-cachingReusing a single 2D mask incorrectly across a batch or across cached vs. new tokensShape broadcasting errors or (worse) silent misalignment where wrong positions get masked
Assuming masking reduces asymptotic computeIntuition that "we only need half the matrix" automatically speeds things upNaive implementations still compute and store the full O(n2)O(n^2) 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
AV
Ashish Vaswani
b. 1980s (contemporary) · Lead author of "Attention Is All You Need" (2017), which introduced the Transformer architecture including the masked decoder self-attention mechanism

History
1990
— recurrent neural network language models establish the sequential, left-to-right autoregressive paradigm for text generation.
2014
— sequence-to-sequence models with attention allow decoders to align with encoder outputs, foreshadowing full self-attention.
2017
— the Transformer architecture introduces masked (causal) self-attention in its decoder, alongside bidirectional encoder self-attention.
2018
— GPT demonstrates that a decoder-only stack of masked self-attention layers, pretrained on raw text, transfers to diverse downstream tasks.
2019
onward — GPT-2, GPT-3, and successors scale decoder-only masked self-attention to billions of parameters, cementing it as the default architecture for generative language models.

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 ii's output could depend on token i+1i+1 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 (i,j)(i, j) 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 −∞-\infty, or a large negative number, wherever attention should be forbidden) correctly forbids attention to both future positions and padding positions simultaneously, since −∞+anything finite-\infty + \text{anything finite} remains effectively −∞-\infty after the softmax.

Does masked self-attention prevent the model from ever learning bidirectional context?

Within a single masked self-attention layer, yes — position ii genuinely cannot see position j>ij > i'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 j=ij = i 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 −∞-\infty (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., −109-10^9) 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 O(n2d)O(n^2 d)-per-step generation into O(nd)O(nd)-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 (j>ij > i), 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 QQ and KK 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.

Before this

Where this leads