Masks#
Mask functions define which query-key pairs can attend to each other. Each function returns a mask_mod — a callable with signature (b, h, q_idx, kv_idx) -> bool — that can be passed to create_block_mask to produce a BlockMask. See Concepts for details on how masks and block sparsity work together.
Causal#
Standard lower-triangular causal mask. Each position attends only to itself and earlier positions.
from attn_gym.masks import causal_mask
block_mask = create_block_mask(causal_mask, B, H, S, S, device=device)
attn_gym.masks.causal.causal_mask(b, h, q_idx, kv_idx)
#
attn_gym.masks.causal.create_causal_block_mask_fast(batch_size, num_heads, q_seq_len, kv_seq_len, device, block_size=128, separate_full_blocks=True)
#
Create a causal block mask efficiently without materializing the full mask.
This function generates the block mask data structure directly for causal attention, avoiding the need to create and process a full dense mask. This is much more efficient for long sequences.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
q_seq_len
|
int
|
Query sequence length |
required |
kv_seq_len
|
int
|
Key/value sequence length |
required |
device
|
device
|
Device to create tensors on |
required |
batch_size
|
int | None
|
Batch size (defaults to 1 if None) |
required |
num_heads
|
int | None
|
Number of attention heads (defaults to 1 if None) |
required |
block_size
|
int
|
Block size for the block mask (both Q and KV use same size) |
128
|
separate_full_blocks
|
bool
|
Whether to separate full blocks from partial blocks |
True
|
Returns:
| Name | Type | Description |
|---|---|---|
BlockMask |
BlockMask
|
Block mask object for causal attention |
Sliding Window#
Each position attends to a fixed-size window of preceding tokens (combined with causal masking).
from attn_gym.masks import generate_sliding_window
mask_mod = generate_sliding_window(window_size=1024)
block_mask = create_block_mask(mask_mod, B, H, S, S, device=device)
attn_gym.masks.sliding_window.generate_sliding_window(window_size)
#
Generates a sliding window attention mask with a given window size. Args: window_size: The size of the sliding window.
Note
We assume that the window size represents the lookback size and we mask out all future tokens similar to causal masking.
Dilated Sliding Window#
Sliding window with dilation — attends to every dilation-th token within the window.
attn_gym.masks.dilated_sliding_window.generate_dilated_sliding_window(window_size, dilation)
#
Generates a dilated sliding window attention mask. Args: window_size: The size of the sliding window. dilation: The dilation factor for the sliding window.
Note
Query at position i can only attend to keys within a window of size window_size
centered around i, where the keys are at positions j such that:
* abs(i - j) <= window_size
* abs(i - j) % dilation == 0
Global + Sliding Window#
Longformer-style attention (paper): a bidirectional sliding window plus designated global tokens (e.g. CLS) that attend to and are attended by every position.
import torch
from attn_gym.masks import generate_global_sliding_window
is_global = torch.zeros(S, dtype=torch.bool, device=device)
is_global[0] = True # CLS token
mask_mod = generate_global_sliding_window(window_size=512, is_global=is_global)
block_mask = create_block_mask(mask_mod, B, H, S, S, device=device)
attn_gym.masks.global_sliding_window.generate_global_sliding_window(window_size, is_global)
#
Generates a Longformer-style global + sliding window attention mask.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
window_size
|
int
|
The symmetric sliding window radius; position i attends to positions j with abs(i - j) <= window_size. |
required |
is_global
|
Tensor
|
Boolean tensor of shape [SEQ_LEN] marking global tokens (e.g. CLS or task tokens). Global tokens attend to all positions and all positions attend to them. |
required |
Note
Following the Longformer paper, attention is bidirectional: local
attention is a window centered on each position, and global attention is
symmetric. Compose with a causal mask via and_masks for decoder use.
Prefix LM#
Bidirectional attention over a prefix, causal attention over the rest.
from attn_gym.masks import generate_prefix_lm_mask
mask_mod = generate_prefix_lm_mask(prefix_length=512)
attn_gym.masks.prefix_lm.generate_prefix_lm_mask(prefix_length)
#
Generates a prefix LM causal attention mask.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prefix_length
|
int
|
The length of the prefix. |
required |
Note
This mask allows full attention within the prefix (first PREFIX_LENGTH tokens) and causal attention for the rest of the sequence.
Block Diffusion#
Hybrid attention mask for Block Diffusion language models (BD3-LM, paper). Training attends over a concatenated [x_t; x_0] sequence of length 2 * S: noised tokens attend bidirectionally within their block and to clean tokens in previous blocks, while clean tokens attend block-causally to other clean tokens. The mask is highly block-sparse, so FlexAttention can achieve large speedups over dense SDPA.
from attn_gym.masks import generate_block_diffusion_mask
mask_mod = generate_block_diffusion_mask(seq_len=S, block_size=16)
block_mask = create_block_mask(mask_mod, B, H, 2 * S, 2 * S, device=device)
attn_gym.masks.block_diffusion.generate_block_diffusion_mask(seq_len, block_size)
#
Generates the Block Diffusion training mask from BD3-LM section 3.1.
Training runs attention over a length 2 * seq_len sequence: the noised
tokens x_t occupy positions [0, seq_len) and the clean tokens x_0
occupy positions [seq_len, 2 * seq_len). The mask is the union of three
pieces:
- Block Diagonal: noised tokens attend bidirectionally within their own block.
- Offset Block Causal: noised tokens attend to clean tokens in strictly previous blocks.
- Block Causal: clean tokens attend to clean tokens in their own and previous blocks.
Clean tokens never attend to noised tokens.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seq_len
|
int
|
Length of the clean sequence |
required |
block_size
|
int
|
Diffusion block size |
required |
JetSpec Tree Attention#
Tree-verification attention for JetSpec: each tree
query attends to cached prefix keys and to flattened tree keys only when they are ancestors
of that query node, including self. The example below uses the Figure 3 candidate-tree
order: return, a, -, +, B, b, sum.
from attn_gym.masks import build_tree_ancestor_matrix, generate_jetspec_tree_causal_mask_mod
parent_indices = [-1, 0, 1, 1, 3, 3, 0]
ancestor = build_tree_ancestor_matrix(parent_indices, device="cuda")
mask_mod = generate_jetspec_tree_causal_mask_mod(prefix_length=1024, ancestor_matrix=ancestor)
block_mask = create_block_mask(
mask_mod,
B,
H,
ancestor.shape[0],
1024 + ancestor.shape[0],
device="cuda",
)
attn_gym.masks.jetspec.build_tree_ancestor_matrix(parent_indices, device='cuda')
#
Build the ancestor matrix for the paper's tree-causal mask.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
parent_indices
|
Sequence[int]
|
Parent index for each flattened tree node in parent-before-child order.
The root entry is ignored and is conventionally |
required |
device
|
str | device
|
Output device. |
'cuda'
|
Returns:
| Type | Description |
|---|---|
Tensor
|
A boolean tensor where |
Tensor
|
|
attn_gym.masks.jetspec.generate_jetspec_tree_causal_mask_mod(prefix_length, ancestor_matrix)
#
Generate the paper's tree-causal mask for parallel tree drafting/verification.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prefix_length
|
int
|
Number of prefix keys before the flattened tree keys. |
required |
ancestor_matrix
|
Tensor
|
Boolean |
required |
Returns:
| Type | Description |
|---|---|
_mask_mod_signature
|
A |
_mask_mod_signature
|
|
JetSpec's draft-head training path uses a different multi-block causal mask: sampled-block queries attend to all verified prefix keys and causally within their own sampled block.
from attn_gym.masks import generate_jetspec_training_mask_mod
prefix_length = 4096
block_size = 16
num_blocks = 3
mask_mod = generate_jetspec_training_mask_mod(prefix_length, block_size)
block_mask = create_block_mask(
mask_mod,
B,
H,
num_blocks * block_size,
prefix_length + num_blocks * block_size,
device="cuda",
)
attn_gym.masks.jetspec.generate_jetspec_training_mask_mod(prefix_length, block_size)
#
Generate the paper's multi-block causal draft-head training mask.
Query rows are sampled-block tokens. KV columns are prefix followed by one or more
sampled blocks, each laid out as [anchor, future_1, ..., future_N]. Each query can
attend to the full verified prefix and to the anchor plus earlier positions in its own
block, but not to future positions or other sampled blocks.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prefix_length
|
int
|
Number of verified prefix keys before sampled training blocks. |
required |
block_size
|
int
|
Number of tokens in each sampled block, including the anchor. |
required |
Returns:
| Type | Description |
|---|---|
_mask_mod_signature
|
A |
_mask_mod_signature
|
|
Document Mask#
For packed sequences: restrict attention to within document boundaries by wrapping a base mask with document offsets.
from attn_gym.masks import causal_mask, generate_doc_mask_mod
from attn_gym.masks.document_mask import length_to_offsets
lengths = [3, 2, 5]
offsets = length_to_offsets(lengths, device="cuda")
mask_mod = generate_doc_mask_mod(causal_mask, offsets)
attn_gym.masks.document_mask.generate_doc_mask_mod(mask_mod, offsets)
#
Generates mask mods that apply to inputs to flex attention in the sequence stacked format.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mask_mod
|
_mask_mod_signature
|
The mask mod to apply to the documents |
required |
offsets
|
Tensor
|
This tensor should be of shape(num_documents + 1) this should contain the cumulative counts of document tokens. e.g. if you have 3 documents of length 2, 4, 3 then offsets = [0, 2, 6, 9] |
required |
Note
What is the sequence stacked format? When assembling batches of inputs, we take multiple sequences and stack them together to form 1 large sequence. We then use masking to ensure that the attention scores are only applied to tokens within the same document.
For causal packed sequences where every batch element shares the same document layout, use the
causal-only offset form. It is equivalent to wrapping causal_mask, but exposes each query row as
one contiguous KV interval.
from attn_gym.masks import generate_packed_causal_doc_mask_mod
from attn_gym.masks.document_mask import length_to_offsets
lengths = [3, 2, 5]
offsets = length_to_offsets(lengths, device="cuda")
mask_mod = generate_packed_causal_doc_mask_mod(offsets)
attn_gym.masks.document_mask.generate_packed_causal_doc_mask_mod(offsets)
#
Generates a causal document mask for packed sequences sharing one offset layout.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
offsets
|
Tensor
|
Cumulative document token counts with shape |
required |
Note
This is equivalent to generate_doc_mask_mod(causal_mask, offsets) for packed
causal attention, but expresses each query row as one contiguous KV interval.
Neighborhood Attention (NATTEN)#
Multi-dimensional neighborhood attention patterns.
attn_gym.masks.natten.generate_natten(canvas_w, canvas_h, kernel_w, kernel_h)
#
Generates a NATTEN attention mask with a given kernel size. Args: canvas_w: The width of the canvas. canvas_h: The height of the canvas. kernel_w: The width of the kernel. kernel_h: The height of the kernel.
attn_gym.masks.natten.generate_tiled_natten(W, H, K_W, K_H, T_W, T_H)
#
Generates a NATTEN attention mask with a given kernel size and static tiling. Args: W: The width of the canvas. H: The height of the canvas. K_W: The width of the kernel. K_H: The height of the kernel. T_W: The width of the tile. T_H: The height of the tile.
attn_gym.masks.natten.generate_morton_natten(canvas_w, canvas_h, kernel_w, kernel_h)
#
Generates a NATTEN attention mask with a given kernel size under morton curve layout. Args: canvas_w: The width of the canvas. canvas_h: The height of the canvas. kernel_w: The width of the kernel. kernel_h: The height of the kernel.
STA (Sparse Temporal Attention)#
attn_gym.masks.sta.generate_sta_mask_mod_2d(canvas_hw, kernel_hw, tile_hw, text_seq_len=0)
#
Generates a 2D STA mask with a given kernel size.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_hw
|
Tuple[int, int]
|
The shape of the canvas (height, width). |
required |
kernel_hw
|
Tuple[int, int]
|
The shape of the kernel (height, width). |
required |
tile_hw
|
Tuple[int, int]
|
The shape of the tile (height, width). |
required |
text_seq_len
|
int
|
The length of the text sequence for masking. |
0
|
attn_gym.masks.sta.generate_sta_mask_mod_3d(canvas_twh, kernel_twh, tile_twh, text_seq_len=0)
#
Generates a 3D STA mask with a given kernel size.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_twh
|
Tuple[int, int, int]
|
The shape of the canvas (time, height, width). |
required |
kernel_twh
|
Tuple[int, int, int]
|
The shape of the kernel (time, height, width). |
required |
tile_twh
|
Tuple[int, int, int]
|
The shape of the tile (time, height, width). |
required |
text_seq_len
|
int
|
The length of the text sequence for masking. |
0
|
VSA (Video Sparse Attention)#
VSA's fine sparse pass can be represented by precomputing each query tile's top-k KV
tiles and turning those tile ids into a BlockMask. Use create_vsa_block_mask for
the direct Triton construction path; deriving the same mask with generic
create_block_mask is intended only for visualization or small correctness checks.
For current Flex FLASH all-full tile paths, use create_vsa_flash_block_mask. The
coarse top-k selection and FastVideo-style additive coarse/fine output combine run
outside the FlexAttention kernel.
from attn_gym.masks import compute_vsa_coarse_attention, create_vsa_block_mask
coarse = compute_vsa_coarse_attention(q, k, v, tile_numel=64, top_k=78)
block_mask = create_vsa_block_mask(
coarse.topk_indices,
tile_numel=64,
num_kv_tiles=k.shape[-2] // 64,
)
out = flex_attention(q, k, v, block_mask=block_mask)
attn_gym.masks.vsa.compute_vsa_coarse_attention(query, key, value, tile_numel, top_k, scale=None, sort_indices=True, include_self=False, q_variable_block_sizes=None, kv_variable_block_sizes=None)
#
Run VSA's coarse attention pass and extract fine-pass top-k tiles.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
Tensor
|
Query tensor with shape |
required |
key
|
Tensor
|
Key tensor with shape |
required |
value
|
Tensor
|
Value tensor with shape |
required |
tile_numel
|
int
|
Number of fine tokens in one VSA tile. |
required |
top_k
|
int
|
Number of KV tiles selected for each query tile. |
required |
scale
|
float | None
|
Optional scale applied to the coarse dot products. Defaults to
|
None
|
sort_indices
|
bool
|
Whether to sort selected KV tile ids ascending before returning. |
True
|
include_self
|
bool
|
Whether to force each query tile to include the same-id KV tile. |
False
|
q_variable_block_sizes
|
Tensor | None
|
Optional real-token counts for padded query tiles. |
None
|
kv_variable_block_sizes
|
Tensor | None
|
Optional real-token counts for padded KV tiles. |
None
|
Returns:
| Type | Description |
|---|---|
VSACoarseResult
|
|
VSACoarseResult
|
coarse log-sum-exp. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If value shape is incompatible or |
attn_gym.masks.vsa.create_vsa_block_mask(topk_indices, tile_numel, num_kv_tiles, variable_block_sizes=None)
#
Build the runtime FlexAttention BlockMask for VSA's fine sparse pass.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
topk_indices
|
Tensor
|
Selected KV tile ids with shape |
required |
tile_numel
|
int
|
Number of fine tokens in one VSA tile. |
required |
num_kv_tiles
|
int
|
Total number of KV tiles before top-k pruning. |
required |
variable_block_sizes
|
Tensor | None
|
Optional real-token counts for each padded KV tile. |
None
|
Returns:
| Type | Description |
|---|---|
BlockMask
|
A directly constructed block-sparse mask. Full selected tiles use |
BlockMask
|
|
BlockMask
|
predicate. The top-k membership itself is encoded by block metadata. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If rank or static shape arguments are invalid. |
attn_gym.masks.vsa.create_vsa_flash_block_mask(topk_indices, tile_numel, num_kv_tiles, kv_block_size=128, variable_block_sizes=None)
#
Build the VSA block representation required by Flex FLASH.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
topk_indices
|
Tensor
|
Selected KV tile ids with shape |
required |
tile_numel
|
int
|
Number of fine tokens in one VSA tile. |
required |
num_kv_tiles
|
int
|
Total number of KV tiles before top-k pruning. |
required |
kv_block_size
|
int
|
KV block size of the returned mask. FA4 requires this to
equal its KV tile size ( |
128
|
variable_block_sizes
|
Tensor | None
|
Optional real-token counts for each padded KV tile.
Fully valid FA4 KV subblocks are emitted as |
None
|
Returns:
| Type | Description |
|---|---|
BlockMask
|
A |
Raises:
| Type | Description |
|---|---|
ValueError
|
If rank or static shape arguments are invalid. |
attn_gym.masks.vsa.generate_vsa_mask_mod(topk_indices, tile_numel, variable_block_sizes=None)
#
Create a VSA mask_mod from precomputed top-k tile indices.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
topk_indices
|
Tensor
|
Selected KV tile ids with shape |
required |
tile_numel
|
int
|
Number of fine tokens in one VSA tile. |
required |
variable_block_sizes
|
Tensor | None
|
Optional real-token counts for each padded KV tile. |
None
|
Returns:
| Type | Description |
|---|---|
_mask_mod_signature
|
A |
_mask_mod_signature
|
appears in that query tile's top-k list and, if provided, excludes padded KV |
_mask_mod_signature
|
positions in edge tiles. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Batchify#
Groups tokens into batches where attention is only allowed within the same group.
attn_gym.masks.batchify.batchify_mask_mod(mask_mod, batchify_size)
#
Given arbirary mask_mod, batchify it to only allow attention within the same batch.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mask_mod
|
_mask_mod_signature
|
The mask mod to apply within each batch. |
required |
batchify_size
|
int
|
The number of tokens in each batch. |
required |
Flamingo Cross-Attention#
Cross-attention mask for Flamingo-style vision-language models.
attn_gym.masks.flamingo.generate_vision_cross_attention_mask_mod(intervals, image_token_length)
#
Generates a mask mod for VisionCrossAttention.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
intervals
|
Tensor
|
Tensor of shape (num_images, 2) containing the start and end indices for each image. |
required |
image_token_length
|
int
|
Number of tokens per image. |
required |
Sparse VideoGen#
Spatial and temporal attention masks following the Sparse VideoGen paper.
attn_gym.masks.svg.generate_spatial_head_mask_mod(prompt_length=226, num_frames=13, token_per_frame=1350, width=2, attn_sink=False, round_width=128)
#
Generates a spatial head mask as specified in SVG. The same mask can also be used for
temporal attention mask after applying the layout transformation by setting attn_sink to False.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prompt_length
|
int
|
The length of the prompt. |
226
|
num_frames
|
int
|
The number of frames in the video. |
13
|
token_per_frame
|
int
|
The number of tokens per frame. |
1350
|
width
|
int
|
The width of the spatial head mask, determine the number of frames that can be attended. |
2
|
attn_sink
|
bool
|
Whether to use the attention sink for the first column. |
False
|
round_width
|
int
|
The number to round to for better hardware utilization, usually set to 128. |
128
|
attn_gym.masks.svg.generate_temporal_head_mask_mod(prompt_length=226, num_frames=13, token_per_frame=1350, width=2)
#
Generates a temporal head mask as specified in SVG.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prompt_length
|
int
|
The length of the prompt. |
226
|
num_frames
|
int
|
The number of frames in the video. |
13
|
token_per_frame
|
int
|
The number of tokens per frame. |
1350
|
width
|
int
|
The width of the temporal head mask, determine the number of frames that can be attended. |
2
|