This visualizes one fixed attention head reading selected sparse KV blocks. The selected sparse pattern is the same in both layouts, but the memory address pattern is very different.
Simplified setup: B=1, H=4, N=12 KV blocks. Each cell represents one KV block vector/tile for one head. In a real kernel, each KV block contains many tokens and the full head dimension.
Memory is grouped by head first. For a fixed head, sequence blocks are compact.
Memory is grouped by token/block first. Heads are interleaved inside each sequence block.
SpargeAttn uses a LUT-driven sparse stream. The logical selected blocks are identical, but the physical address stride is larger under raw NHD.
Address model: addr = h * N + n. For one fixed head, moving from selected block n to n+1 is one block step.
Address model: addr = n * H + h. For one fixed head, moving from block n to n+1 jumps over the other heads.
For target head h, selected KV blocks are compact per-head chunks. Sparse jumps come only from the LUT pattern.
For target head h, same-head sequence blocks are separated by all other heads. Sparse jumps combine with head interleaving.
HND [B,H,N,D] because each selected K/V tile for one head is compact and easier to load with cp.async. If input is NHD [B,N,H,D], many implementations rearrange it to HND before the optimized sparse kernel.