feat(phi3-small): implement blocksparse attention - #582
Closed
inureyes wants to merge 1 commit into
Closed
Conversation
Replace the dense-attention fallback on phi3small's non-dense layers with the trained blocksparse pattern. Each block_sparse layer attends to the local window of blocksparse_num_local_blocks blocks of size blocksparse_block_size ending at the current query block, plus earlier blocks selected by blocksparse_vert_stride, while the periodic dense_attention_every_n_layers layers keep dense attention. The per-layer block_sparse flag is threaded into the attention path, and the L==1 decode path gathers the selected key blocks instead of building a full sparse mask each step, so short context reduces to the dense fallback while long context follows the trained sparsity.
16 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replace the dense-attention fallback on Phi-3-small's non-dense layers with the real blocksparse pattern (local block window + per-head vertical stride), while keeping the periodic fully-dense layers on the plain causal path. This makes long-context output follow the trained sparsity instead of diverging toward dense.
What changed
src/models/phi3small.rsbuild_blocksparse_mask(...): builds the additive[1, n_heads, q_len, kv_len]mask on-device (broadcasting ops only, nothing of sizeq_len * kv_lenmaterialized on the host). Faithful port ofmlx_lm/models/phi3small.py(Attention._block_sparse_mask+_block_sparse_attention), including the reference's right-aligned query-block assignment and the per-head vertical stride(kb + head + 1) % vert_stride == 0. Token-level causality is folded into the same mask so it reproduces the referencemask + dense_maskcombination exactly.dense_attention(unchanged causal path, used by the periodic dense layers) andblocksparse_attention(non-dense layers), threading the already-computed per-layerblock_sparseflag into the attention path.kv_len <= num_local_blocks * block_size) the pattern is exactly causal, so the dense path is reused. This gives byte-identical short-context output and, for in-windowL == 1decode, allocates no per-step mask (the maskless single-query fast path selects the whole cache).blocksparse_block_size/_num_local_blocks/_vert_strideonAttention.src/models/phi3small_tests.rs(new): config parsing/defaults,block_sparseflag pattern, device-mask vs host-reference agreement (bulk + explicit key-block set), short-context mask==causal and RMS parity against the dense fallback, long-context sparser-than-causal + runtime divergence, and a decode single-row mask check.Decode (
L == 1) noteThe issue asks to prefer gather-based KV selection over a full per-step mask. In-window decode does exactly that (no mask; trailing-cache selection via the maskless fast path). Beyond the window, the union of attended blocks across all heads spans the full causal range for Phi-3-small's head count (
vert_stridedivides the head set), so a per-head gather cannot shrink the fused-SDPA work and would require a ragged per-head kernel; we build a single[1, n_heads, 1, kv_len]additive mask (one row) and let the fused kernel consume it.Test plan
cargo test --release phi3small --features metal,accelerate(mask pattern, short-context dense parity, long-context sparsity, decode row)cargo clippy --lib --tests --features metal,accelerate -- -D warningscargo fmt --all -- --checkValidation scope (honest)
Validated: unit tests above, including short-context RMS parity with the dense fallback and mask-pattern agreement with the mlx-lm reference formula on constructed cases, run on Apple Silicon Metal. NOT run: generation on a real Phi-3-small checkpoint (no Phi-3-small checkpoint available in this environment; Phi-3-small is a ~7B model and a multi-GB download was out of scope here). Long-context behavior is validated at the mask/selection and SDPA-output level, not via a real-model long-context generation.
Closes #511