Kernels
attention
flash-attention
flash-attn-4
sm120
sm121
blackwell
rtx5090
rtx-pro-6000
dgx-spark
cute-dsl
Instructions to use SecondNatureComputing/flash-attn-4-sm120 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Kernels
How to use SecondNatureComputing/flash-attn-4-sm120 with Kernels:
# !pip install kernels from kernels import get_kernel kernel = get_kernel("SecondNatureComputing/flash-attn-4-sm120") - Notebooks
- Google Colab
- Kaggle
| library_name: kernels | |
| license: bsd-3-clause | |
| tags: | |
| - attention | |
| - flash-attention | |
| - flash-attn-4 | |
| - sm120 | |
| - sm121 | |
| - blackwell | |
| - rtx5090 | |
| - rtx-pro-6000 | |
| - dgx-spark | |
| - cute-dsl | |
| # flash-attn-4-sm120 | |
| **Flash Attention 4 (CuTe DSL) for SM120 / SM121 consumer Blackwell GPUs.** | |
| This is a downstream distribution of [Dao-AILab/flash-attention](https://github.com/Dao-AILab/flash-attention) that bundles **six open upstream PRs** targeting consumer Blackwell hardware (RTX 5090, RTX PRO 6000, DGX Spark GB10, SM121a). Once these PRs merge upstream, prefer the upstream `flash-attn` package; this bundle exists so SM120 users can use the improvements today. | |
| ## Why this exists | |
| `flash-attn-4`'s CuTe DSL kernels work great on Hopper (SM90) and datacenter Blackwell (SM100). But SM120 (consumer Blackwell) is genuinely different hardware: | |
| - No `tcgen05` / TMEM (so FA4's primary speed path doesn't apply) | |
| - No WGMMA (so the SM90 epilogue path doesn't apply) | |
| - 99 KB shared memory capacity (vs 163 KB on SM80) | |
| - Has TMA, but only single-CTA flavor | |
| - Same SM80-era `mma.sync.aligned.m16n8k16` for FP16/BF16 MMA | |
| The PRs bundled here adapt FA4's kernels to these constraints β runtime-correct dispatch, SMEM-budget-aware tiling, paged KV that fits in 99 KB, TMA-with-warp-spec for the loaded path, and a couple of crash fixes that block dispatch entirely. | |
| ## Bundled PRs | |
| | PR | Title | | |
| |---|---| | |
| | [#2336](https://github.com/Dao-AILab/flash-attention/pull/2336) | SM120 split-KV (FlashDecoding) with FP32 partial outputs | | |
| | [#2348](https://github.com/Dao-AILab/flash-attention/pull/2348) | SM120 kernel-level paged KV cache support | | |
| | [#2349](https://github.com/Dao-AILab/flash-attention/pull/2349) | SM120 TMA forward kernel with warp specialization | | |
| | [#2389](https://github.com/Dao-AILab/flash-attention/pull/2389) | SM80 / SM120 block-sparse forward attention support | | |
| | [#2439](https://github.com/Dao-AILab/flash-attention/pull/2439) | FA4 dropout (Philox, per-element, all arches) | | |
| | [#2484](https://github.com/Dao-AILab/flash-attention/pull/2484) | SM120 init-time runtime fix + GQA `pack_gqa` workaround | | |
| ## Setup | |
| ### Hardware | |
| - NVIDIA SM120 / SM121 / SM121a (RTX 5090, RTX PRO 6000 Blackwell, DGX Spark GB10) | |
| - Should also work on SM80 / SM90 / SM100 since the bundle inherits from upstream `flash-attn-4`, but those paths are not the primary target | |
| ### Software | |
| - CUDA Toolkit **12.8 or newer** (FA4 baseline requirement) | |
| - PyTorch with CUDA support | |
| - `nvidia-cutlass-dsl >= 4.4.1` (auto-installed by `kernels`) | |
| - `einops`, `apache-tvm-ffi` (auto-installed) | |
| ### Installation via the `kernels` library (recommended) | |
| ```bash | |
| pip install -U kernels | |
| ``` | |
| ```python | |
| from kernels import get_kernel | |
| flash_attn_4 = get_kernel("SecondNatureComputing/flash-attn-4-sm120") | |
| ``` | |
| `kernels` will download this repository, resolve dependencies, and make the package importable without any manual build step. | |
| ### Direct use (alternative) | |
| If you prefer not to use the `kernels` library, you can clone the repo and import the package directly: | |
| ```bash | |
| git clone https://huggingface.co/SecondNatureComputing/flash-attn-4-sm120 | |
| ``` | |
| ```python | |
| import sys | |
| sys.path.insert(0, "flash-attn-4-sm120/build/torch-cuda") | |
| import importlib | |
| flash_attn_4 = importlib.import_module("flash_attn_4_sm120") # or whatever you alias the dir to | |
| ``` | |
| The `kernels.get_kernel(...)` path is recommended since it handles caching and dependency resolution automatically. | |
| ## Usage | |
| ### Basic β non-causal MHA | |
| ```python | |
| import torch | |
| from kernels import get_kernel | |
| flash_attn_4 = get_kernel("SecondNatureComputing/flash-attn-4-sm120") | |
| B, S, H, D = 1, 1024, 16, 128 | |
| q = torch.randn(B, S, H, D, device="cuda", dtype=torch.bfloat16) | |
| k = torch.randn(B, S, H, D, device="cuda", dtype=torch.bfloat16) | |
| v = torch.randn(B, S, H, D, device="cuda", dtype=torch.bfloat16) | |
| out, _ = flash_attn_4.flash_attn_func(q, k, v, causal=False) | |
| ``` | |
| ### Causal GQA β Qwen / LLaMA family models | |
| ```python | |
| B, S, Hq, Hkv, D = 1, 2048, 16, 8, 128 # Qwen3-style GQA: Hq=16, Hkv=8 | |
| q = torch.randn(B, S, Hq, D, device="cuda", dtype=torch.bfloat16) | |
| k = torch.randn(B, S, Hkv, D, device="cuda", dtype=torch.bfloat16) | |
| v = torch.randn(B, S, Hkv, D, device="cuda", dtype=torch.bfloat16) | |
| out, _ = flash_attn_4.flash_attn_func(q, k, v, causal=True) | |
| ``` | |
| ### Variable-length (production batched serving) | |
| ```python | |
| # Pack a batch of sequences with different lengths into a single flat tensor | |
| seq_lens = [128, 256, 512] | |
| total = sum(seq_lens) | |
| cu_seqlens = torch.tensor([0] + list(__import__('itertools').accumulate(seq_lens)), | |
| dtype=torch.int32, device="cuda") | |
| q = torch.randn(total, Hq, D, device="cuda", dtype=torch.bfloat16) | |
| k = torch.randn(total, Hkv, D, device="cuda", dtype=torch.bfloat16) | |
| v = torch.randn(total, Hkv, D, device="cuda", dtype=torch.bfloat16) | |
| out, _ = flash_attn_4.flash_attn_varlen_func( | |
| q, k, v, | |
| cu_seqlens_q=cu_seqlens, | |
| cu_seqlens_k=cu_seqlens, | |
| max_seqlen_q=max(seq_lens), | |
| max_seqlen_k=max(seq_lens), | |
| causal=True, | |
| ) | |
| ``` | |
| ### Paged KV (vLLM / SGLang serving pattern) | |
| ```python | |
| out, _ = flash_attn_4.flash_attn_func( | |
| q, k_paged, v_paged, | |
| page_table=page_table, | |
| seqused_k=actual_seq_lens, | |
| max_seqlen_k=max_kv_len, | |
| causal=True, | |
| ) | |
| ``` | |
| ## API | |
| Two entry points exposed at the package root: | |
| - `flash_attn_func(q, k, v, ...)` β standard attention, fixed-length within a batch | |
| - `flash_attn_varlen_func(q, k, v, cu_seqlens_q, cu_seqlens_k, ...)` β variable-length | |
| Parameters supported beyond upstream main: | |
| | Parameter | What it enables | PR | | |
| |---|---|---| | |
| | `page_table=...` | Paged KV cache | #2348 | | |
| | `num_splits=...` | Split-KV / FlashDecoding | #2336 | | |
| | `block_sparse_tensors=...` | Block-sparse attention | #2389 | | |
| | `dropout_p=..., dropout_seed=...` | Per-element dropout | #2439 | | |
| | (automatic) | TMA forward dispatch when viable | #2349 | | |
| Tensor layout: `(batch, seqlen, num_heads, head_dim)`, last dim contiguous, 16-byte aligned. | |
| ## Validation | |
| End-to-end on SM121a (DGX Spark GB10), bf16 + fp16, causal + non-causal, dense + varlen: | |
| | Shape category | Configurations | | |
| |---|---| | |
| | MHA (`Hq = Hkv`) | `D β {64, 128}`, `S β {128, 256, 512, 1024}` | | |
| | GQA Qwen3-style | `Hq=16, Hkv=8, D=128` | | |
| | GQA LLaMA3-style | `Hq=32, Hkv=8, D=128` | | |
| | MQA | `Hq=4, Hkv=1, D=128` | | |
| | Batched | `B = 2` | | |
| - **Forward**: 64 / 64 configurations pass β max diff β€ 0.0156 vs PyTorch f32 reference | |
| - **Backward**: 40 / 40 configurations pass (dq, dk, dv all within 0.05 vs PyTorch f32 reference) | |
| - **Standalone install**: validated via `kernels.get_kernel(...)` from a clean Python venv with only `kernels`, `torch`, `nvidia-cutlass-dsl`, `apache-tvm-ffi`, `einops`, `quack-kernels` installed β no `flash-attn` dependency required. | |
| ## Performance | |
| Patched HF FA4 vs vLLM's FA2 baseline on SM121a (DGX Spark), bf16, causal, Qwen3-style GQA `Hq=16, Hkv=8, D=128`, median of 30 iters after 5 warmups: | |
| | Shape (B, S, Hq, Hkv, D) | HF FA4 (ms) | vLLM FA2 (ms) | FA4 / FA2 | | |
| | --- | --- | --- | --- | | |
| | (1, 128, 16, 8, 128) | 0.036 | 0.021 | 1.71x | | |
| | (1, 512, 16, 8, 128) | 0.053 | 0.049 | 1.07x | | |
| | (1, 1024, 16, 8, 128) | 0.106 | 0.102 | 1.04x | | |
| | (1, 2048, 16, 8, 128) | 0.289 | 0.278 | 1.04x | | |
| | (1, 4096, 16, 8, 128) | 0.976 | 0.886 | 1.10x | | |
| | (2, 512, 16, 8, 128) | 0.075 | 0.069 | 1.09x | | |
| | (4, 256, 16, 8, 128) | 0.059 | 0.049 | 1.19x | | |
| | (8, 256, 16, 8, 128) | 0.109 | 0.104 | 1.05x | | |
| At very short sequences (S = 128) FA4's dispatch overhead dominates (~70% slower than FA2). At realistic Qwen 3 prefill lengths (S = 512 to 4096) FA4 is **within 4 to 10 percent of FA2**. This is consistent with the SM120 hardware: no `tcgen05` / TMEM means FA4's primary speed path doesn't apply, so it compiles down to roughly the same SM80 era `mma.sync` compute as FA2 with a small dispatch overhead. Use this kernel for the FA4 only features (paged KV, score_mod, block sparse, dropout); use FA2 if pure attention throughput is the only goal. | |
| ## Known limitations | |
| - **GQA dispatches through the non-packed path on SM120** (PR #2484 workaround). Functionally correct on every GQA / MQA shape we tested. Throughput is within roughly 10% of fmha_v2 on the GQA shapes measured. Tracked upstream. | |
| - **`head_dim > 128` is not supported on SM120** β the 99 KB SMEM budget cannot hold the Q tile. This affects models like Qwen3.5-9B (D=256) and Qwen3-Coder-Next (D=256). vLLM's existing `fa_utils.py` gate already routes `head_size > 128` to FA2 on Blackwell; this kernel maintains that boundary. | |
| - **Split-KV not supported on SM120 in this kernel variant.** PR #2336 implements it but the bundle's `interface.py` clamps `num_splits` to 1 on SM12x. Decode workloads use a single split, which is consistent with how vLLM and SGLang configure SM120 today. | |
| - **Dropout** runs but spills registers at `tile_m=128, tile_n=128` non-causal; the bundle's `interface.py` falls back to `tile_m=128, tile_n=64` (or `tile_m=64, tile_n=64` for `D > 64`) when `dropout_p > 0`, which fixes the spill at a small throughput cost. | |
| ## Hardware support outside SM120 | |
| The bundle inherits from upstream `flash-attn-4`'s SM80 / SM90 / SM100 dispatch paths. Those should work the same as upstream main; the bundled PRs target SM120 specifically. We do not test SM80 / SM90 / SM100 β please open an issue if you find regressions. | |
| ## License | |
| BSD-3-Clause, inherited from [Dao-AILab/flash-attention](https://github.com/Dao-AILab/flash-attention). | |
| ## Credits | |
| - **Upstream**: [Dao-AILab/flash-attention](https://github.com/Dao-AILab/flash-attention) β Tri Dao, Jay Shah, Ganesh Bikshandi, Ying Zhang, Vijay Thakkar, Pradeep Ramani, and contributors | |
| - **SM120 PRs and bundle packaging**: Blake Ledden, [Second Nature Computing](https://joinsecondnature.com) | |
| - **Hub packaging template**: [kernels-community/flash-attn4](https://huggingface.co/kernels-community/flash-attn4) | |
| ## Issues | |
| For bundle-specific issues (the dispatch logic, validation gaps, packaging), open an issue on this HF repo. For kernel-level issues that exist upstream, file against [Dao-AILab/flash-attention](https://github.com/Dao-AILab/flash-attention) directly. | |
| ## See also | |
| - [`CONFLICTS_LOG.md`](https://huggingface.co/SecondNatureComputing/flash-attn-4-sm120/blob/main/CONFLICTS_LOG.md) β detailed log of every conflict encountered while stacking the six PRs, with resolution and per-PR backport guidance | |