Spot the masking bug in this packed-sequence training setup
Same topic, related formats. Practice these next.
Same topic, related formats. Practice these next.
Click any words you think contain an error. Click again to unmark.
A plain causal mask lets each example attend backward into earlier packed examples, leaking signal. Layer a block-diagonal document mask on top, or use FlashAttention-2's cu_seqlens API.
Imagine printing five different children's stories on the same long roll of paper, end to end, to save paper. You then hand the roll to a student and ask them to predict the next word at any point, only looking to the left of where they are. Without any marks separating the stories, the student happily looks left and gets to read the end of story 4 as 'context' for the beginning of story 5, which is completely the wrong context. The fix is to draw a thick vertical line between every story so the student knows they can only look left as far as the most recent line. Packed-sequence attention works the same way: the lines between examples must be enforced, not just inferred.
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 the causal-only mask's blind spot at example boundaries, motivate the document mask as a block-diagonal overlay, show how the masks compose via elementwise AND, walk through FlashAttention-2's cu_seqlens implementation, and close with the production checklist for packed-sequence training.
import torch
from flash_attn import flash_attn_varlen_func
# Three examples packed into one sequence of length 17 + 25 + 47 = 89.
example_lengths = [17, 25, 47]
cu_seqlens = torch.tensor(
[0] + list(torch.tensor(example_lengths).cumsum(0).tolist()),
dtype=torch.int32,
) # [0, 17, 42, 89]
# Q, K, V are packed: shape (total_tokens, n_heads, d_head)
total_tokens = sum(example_lengths) # 89
n_heads, d_head = 8, 64
Q = torch.randn(total_tokens, n_heads, d_head, dtype=torch.float16, device='cuda')
K = torch.randn(total_tokens, n_heads, d_head, dtype=torch.float16, device='cuda')
V = torch.randn(total_tokens, n_heads, d_head, dtype=torch.float16, device='cuda')
# FlashAttention-2 applies causal + block-diagonal (per cu_seqlens) masking.
output = flash_attn_varlen_func(
Q, K, V,
cu_seqlens_q=cu_seqlens, cu_seqlens_k=cu_seqlens,
max_seqlen_q=max(example_lengths), max_seqlen_k=max(example_lengths),
causal=True,
)
# output has shape (total_tokens, n_heads, d_head)
# Each example's tokens attend only to earlier tokens in the same example.Real products, models, and research that use this idea.
What an interviewer would ask next. Try answering before peeking at the approach.
Red flags and common mistakes that signal junior thinking. Click to expand.
Assuming the causal mask alone is sufficient because pad tokens are gone. The boundary between concatenated examples is exactly the leak point a causal mask cannot see.
The night-before-the-interview bullets. Scan these on the way to the call.
Primary sources. Skim if you want the original framing.