nemo_automodel.components.models.minimax_m3_vl.msa
nemo_automodel.components.models.minimax_m3_vl.msa
Packed-document MSA sparse attention for MiniMax M3 on SM100.
One MSAMicrobatch per microbatch holds everything MSA shares across the attention layers and the
pipeline virtual stages: the canonical document map, the packed document layout, the lazily planned
block scorer and the padding mask (ADR 0010). sparse_attention runs the official flat forward
and the model-private backward on compact tokens; require_msa_support is the construction-time
gate. Everything here is BSHD in and BSHD out; the compact [tokens, ...] layout lives between
pack and unpack.
Module Contents
Classes
Functions
Data
API
One packed microbatch’s MSA state, built once and shared by every attention layer and stage.
The scorer plan of this microbatch, built on the first block selection.
The first plan of a process also compiles every scorer variant production can reach: the
from_pretrained path skips initialize_weights, so this is the one model-owned point both
load paths pass through before the first scoring pass (ADR 0010).
Return this microbatch’s state, building it once per batch tensor.
Every virtual pipeline stage is a deep-copied model that receives the same _packed_seq_ids
tensor, so its identity plus _version keys the memo; the entry lives as long as the batch,
which is why the state keeps no reference to the tensor. Without _packed_seq_ids the state is
rebuilt on every call.
Parameters:
[batch, sequence, hidden] hidden states; only the shape and device are read.
The loader’s [batch, sequence] document map, or None.
A 2-D document map or bool mask, a bool 4-D block-causal mask, or None.
bool [batch, sequence] padding mask, or None.
The forward’s backend keyword arguments, checked for unsupported runtime features.
(init_blocks, local_blocks) of the model’s indexer.
Raises:
NotImplementedError: For non-BSHD input, caches, non-causal or windowed attention, or CUDA graph capture.ValueError: If no source yields a well-formed document map.
Derive the packed layout of doc_ids with exactly one device-to-host synchronization.
Parameters:
Integer [batch, sequence] document map: 0 marks padding, each positive id one
contiguous run of tokens within its row.
(init_blocks, local_blocks) of the model’s indexer.
Raises:
ValueError: If the map is empty, holds negative ids, no real token, an interrupted document, or coordinates past int32.
Gather external[batch, sequence, ...] to [tokens, ...] in document order; may alias the input.
Choose each query’s key blocks within its own document for one layer.
Selection is a hard top-k over unnormalized QK maxima, so it is not differentiable: call it
under torch.no_grad.
Parameters:
bf16 [tokens, 4, 128] index queries, post norm and RoPE.
bf16 [tokens, 1, 128] shared index key, post norm and RoPE.
Returns: torch.Tensor
int32 [4, tokens, 16] document-local block ids, padded with -1: the canonical support.
Scatter packed[tokens, ...] back to [batch, sequence, ...] with zero padding; may alias the input.
The layer-invariant half of block selection: the FMHA plan, the score shape and each query’s geometry.
Pinned to split_prefill_decode=False and num_kv_splits=1: the first splits a batch whose
first document is short into two sub-plans (2.9x on the score pass plus two host syncs per call),
the second lets the planner pick a variant from an SM-count estimate.
Plan the scorer for msa and derive its [tokens, blocks] candidate and forced masks.
Score bf16 index_q[tokens, 4, 128] against index_k[tokens, 1, 128] -> int32 [4, tokens, 16] block ids.
Bases: Function
The official flat forward, its saved schedule, and the backward-only aligned K/V workspace.
Map bf16 grad_out[tokens, 64, 128] to dq[tokens, 64, 128], dk/dv[tokens, 4, 128] and two None slots.
Run bf16 q[tokens, 64, 128], k/v[tokens, 4, 128], int32 q2k[4, tokens, 16] -> bf16 out[tokens, 64, 128].
Scatter compact[tokens, H, D] to rows positions[tokens] of a zero-filled [workspace_size, H, D].
Decode the document map of the dense mask a packed loader builds for a single-document pack.
Kept until PR #3831 lets consumes_packed_seq_ids request the compact map for every pack; delete
this decoder once that merges.
Parameters:
bool [batch, 1, sequence, sequence]; query row i keeps key j where true.
The expected (batch, sequence).
Returns: torch.Tensor
int64 [batch, sequence] document ids, 0 for padding.
Raises:
ValueError: If the mask is not standard block-causal (every real query keeps exactly the causal keys of its own contiguous document, padding rows all false), checked with one host synchronization.
Check that every document is one contiguous run of tokens.
Parameters:
int64 [batch * sequence] flat document map.
int64 [batch * sequence] batch row of each flat token.
bool [batch * sequence]; True where ids > 0.
Returns: torch.Tensor
(valid, first_bad_row) 0-d tensors: whether no run is interrupted, and the first flat row
Recover the int64 canonical document map [batch, sequence] (0 = padding) of one microbatch.
Only the shape and device of hidden [batch, sequence, hidden] are read. Sources, in priority
order: the packed loader’s _packed_seq_ids, a 2-D attention_mask holding document ids or a bool
4-D block-causal attention_mask (decoded by _block_causal_documents), a bool padding_mask
(one document per row), else one document per row.
Reject cache/THD/window/cross-attention/capture; tensor kwargs are checked only for presence.
Return the process-wide score buffer of device, grown to shape.
The scorer stores rather than accumulates and every tile the selection rule reads is written by the
same call, so one buffer serves every layer and microbatch; scoring passes never overlap because MSA
is single-stream and rejects CUDA-graph capture. max_k_tiles is rounded up to 128 tiles whatever
the documents are, so per-plan buffers would cost 224 MiB where this one costs 11.28 MiB.
Compile every reachable scorer variant once per process and device, ~44 s each on a cold cache.
Warming runs the production path over synthetic one-document microbatches, so the variant compiled here is the variant production reaches by construction.
Reject, at construction, an attention layer or backend the MSA kernels are not built for.
Parameters:
The sparse attention layer: num_heads, num_kv_heads, head_dim and an
indexer with num_index_heads, block_size, topk_blocks, index_head_dim
and score_type.
The model’s backend selection.
Raises:
ValueError: If the topology is not the 64-query/4-KV-head, 128-channel, top-16 one, or the block score is not themaxreduction.NotImplementedError: If the backend asks for FP8 projections or fused RoPE.
Run MSA sparse attention on compact tokens.
Parameters:
bf16 [tokens, 64, 128] queries after RoPE.
bf16 [tokens, 4, 128] keys after RoPE.
bf16 [tokens, 4, 128] values.
int32 [4, tokens, 16] canonical support from msa.select_blocks.
The microbatch the tokens were packed by.
Returns: torch.Tensor
bf16 [tokens, 64, 128] attention output; q, k and v receive gradients.
Raises:
NotImplementedError: Undertorch.use_deterministic_algorithms: the backward accumulates dK/dV with FP32 atomics and dQ with packed bf16 atomics, so it is not bitwise deterministic.ValueError: Ifq,korvis not bf16.