What does a padding mask zero out, and why is it needed when batching variable-length sequences?
A padding mask zeros out attention to pad tokens added during batching. It adds -inf to pre-softmax scores at pad columns so e^(-inf) = 0 contributes nothing after normalization.
Picture a teacher running a group quiz where every team must turn in an answer sheet with exactly 100 boxes filled. Some teams only have 30 real answers, so they fill the remaining 70 boxes with the word 'BLANK' to make the sheet look the same size as everyone else's. When the teacher grades by averaging answers, they need to know to skip every box marked BLANK; otherwise the average of every team is dragged toward 'BLANK' and nothing means anything. The padding mask is exactly the rule 'skip BLANK boxes'. Without it, attention happily averages in the pad tokens and the model's output becomes garbage.
Detailed answer & concept explanation~7 min readEverything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example.
Everything important, quickly.
Explain why padding exists, walk through the additive -inf trick at the score matrix, show the softmax converting -inf to 0, distinguish padding from causal masks, and close with the FlashAttention-2 cu_seqlens replacement and continuous-batching alternative at inference.
import torch
import torch.nn.functional as F
B, T, n_heads, d_head = 2, 8, 4, 16
# Sequence 0 has 5 real tokens, sequence 1 has 8 real tokens.
real_lengths = torch.tensor([5, 8])
Q = torch.randn(B, n_heads, T, d_head)
K = torch.randn(B, n_heads, T, d_head)
V = torch.randn(B, n_heads, T, d_head)
# Build padding mask: True at real positions, False at pad.
idx = torch.arange(T)[None, :] # (1, T)
is_real = idx < real_lengths[:, None] # (B, T)
# Convert to additive: 0 at real, -inf at pad.
additive = torch.where(is_real, 0.0, float('-inf')) # (B, T)
additive = additive[:, None, None, :] # (B, 1, 1, T) -- broadcast over heads and queries
scores = Q @ K.transpose(-2, -1) / (d_head ** 0.5) # (B, n_heads, T, T)
scores = scores + additive # pad columns become -inf
weights = F.softmax(scores, dim=-1) # pad columns now exactly 0
output = weights @ V # (B, n_heads, T, d_head), no contribution from pad keysReal products, models, and research that use this idea.
- PyTorch's torch.nn.MultiheadAttention takes a key_padding_mask of shape (B, T) where True means 'this is padding'.
- Hugging Face Transformers uses attention_mask of shape (B, T) where 1 means 'real token' (opposite polarity).
- FlashAttention-2's cu_seqlens API replaces explicit padding masks with cumulative example lengths, avoiding (B, T, T) mask materialization.
- vLLM's continuous batching avoids padding entirely at inference by dynamically composing batches at every decode step.
- Llama 4 Maverick, Mistral, and Qwen 3.5 pretraining stacks use packed sequences with cu_seqlens rather than padding.
What an interviewer would ask next. Try answering before peeking at the approach.
QWhy the additive -inf trick instead of multiplying the weights by zero after softmax?
QHow does the padding mask interact with the causal mask in causal-LM training?
Don't say thisRed flags and common mistakes that signal junior thinking. Click to expand.
Red flags and common mistakes that signal junior thinking. Click to expand.
Confusing padding mask with causal mask. Padding hides fake batching tokens; causal hides real future tokens. Both can coexist in the same attention call.
The night-before-the-interview bullets. Scan these on the way to the call.
Primary sources. Skim if you want the original framing.
Same topic, related formats. Practice these next.