{
  "@context": "https://schema.org",
  "@id": "https://aggr.aymericbeaumet.com/items/qwen-ai/2026-04-28-flashqla-cp-bwd-friendly-fused-linear-attention-kernels-for/#webpage",
  "@type": [
    "WebPage",
    "ArchiveComponent"
  ],
  "articleBody": "![](https://qianwen-res.oss-cn-beijing.aliyuncs.com/flashqla/flashqla.png)\n\n## Introduction\n\nFollowing the release of [Qwen3-Next](https://qwen.ai/blog?id=qwen3-next), Gated Delta Network (GDN) has become the workhorse attention layer across the Qwen family — from Qwen3-Next-80B-A3B all the way to the subsequent [Qwen3.5](https://qwen.ai/blog?id=qwen3.5) / [Qwen3.6](https://qwen.ai/blog?id=qwen3.6) series. As models scale to **397A17B / 122A10B / 35B / 27B** and context windows stretch beyond 256K, the overhead of the GDN block in end-to-end training and inference has become non-negligible.\n\nToday we officially open-source **FlashQLA**: a high-performance linear attention kernel library built on [TileLang](https://github.com/tile-ai/tilelang). FlashQLA applies **reasonable operator fusion and performance optimization** to the forward and backward passes of GDN Chunked Prefill, achieving **2-3× forward speedup** and **2× backward speedup** over the FLA Triton kernel across multiple scenarios on NVIDIA Hopper. The efficiency gains are particularly pronounced in pretraining scenarios and edge-side agentic inference.\n\nKey highlights of this release:\n\n1. **Gate-driven automatic intra-card context parallelism**. By exploiting the exponential decay property of the GDN gate, FlashQLA automatically enables intra-card CP under TP, long-sequence, and small-head-count settings, improving GPU SM utilization.\n\n2. **Hardware-friendly algebraic reformulation**. We reformulate the forward and backward flows of GDN Chunked Prefill to a certain extent, effectively reducing Tensor Core, CUDA Core, and SFU overhead without sacrificing numerical precision.\n\n3. **TileLang fused warp-specialized kernels**. Rather than following the step-by-step decomposition into independent kernels, nor fusing the entire computation flow into a single kernel, we take CP and backward requirements into account, use TileLang to build several key fused kernels, and manually implement warpgroup specialization to overlap data movement, Tensor Core computation, and CUDA Core computation.\n\nFlashQLA code and benchmarks are open-sourced at [github.com/QwenLM/FlashQLA](https://github.com/QwenLM/FlashQLA).\n\n## Key Problems in FLA GDN Chunked Prefill\n\nLet us first review the forward computation flow of GDN Chunked Prefill, taking chunk index $i$ as an example:\n\n1. $A\\_i \\\\gets \\\\left(I+\\\\mathrm{StrictLower}\\\\left( \\\\mathrm{diag}(\\\\beta\\_i)(\\\\Gamma\\_i \\\\odot K\\_iK\\_i^\\\\intercal) \\\\right)\\\\right)^{-1}$\n2. $\\\\left\\\\{\\\\begin{aligned} W\\_i &\\\\gets A\\_i\\\\mathrm{diag}(\\\\beta\\_i)\\\\mathrm{diag}(\\\\gamma\\_i)K\\_i \\\\\\\\ U\\_i &\\\\gets A\\_i\\\\mathrm{diag}(\\\\beta\\_i)V\\_i \\\\end{aligned}\\\\right.$\n3. $\\\\left\\\\{\\\\begin{aligned} V\\_i’ &\\\\gets U\\_i-W\\_iS\\_i \\\\\\\\ S\\_{i+1} &\\\\gets \\\\gamma\\_{i,C-1}S\\_i + K\\_i^\\\\intercal\\\\mathrm{diag}\\\\left(\\\\frac{\\\\gamma\\_{i,C-1}}{\\\\gamma\\_i}\\\\right)V\\_i’ \\\\end{aligned}\\\\right.$\n4. $O\\_i \\\\gets \\\\mathrm{diag}({\\\\gamma})Q\\_iS\\_i + \\\\left(\\\\mathrm{Lower}(\\\\Gamma\\_i) \\\\odot Q\\_iK\\_i^\\\\intercal\\\\right)V\\_i'$\n\nIgnoring gate preprocessing and CP, each step of this flow corresponds to one kernel [in FLA](https://github.com/fla-org/flash-linear-attention/blob/v0.5.0/fla/ops/gated_delta_rule/chunk.py). This flow has two main efficiency problems:\n\n1. Most of the above are **memory-bound kernels**. The flow repeatedly reads $K$, $V$ and other data, while $W$, $U$, $S$ as intermediate variables must be written to HBM and then read by the next kernel, incurring significant memory access overhead.\n2. The recurrent nature of the SSM state means that the corresponding third step `chunk_gated_delta_rule_fwd_kernel` can only launch `batch_size * num_heads` thread blocks simultaneously, resulting in **low GPU utilization** in small-model, small-batch, or TP scenarios.\n\nThe solutions to these two problems are contradictory. For the first problem, the most intuitive solution is to write a [fully-fused kernel](https://github.com/flashinfer-ai/flashinfer/pull/2276), where all data is accessed only once and all intermediate variables are kept on-chip. When `batch_size * num_heads` is large enough, this is certainly optimal. However, such a solution obviously runs into the second problem: for edge-side inference with small models and `batch_size=1`, or for large-model online deployments with TP where long-sequence inputs from coding agents etc. cannot launch a large enough batch for chunked prefill, the speedup of a fully-fused kernel over the original FLA implementation is limited.\n\nThe earliest solution to the second problem comes from [how DeltaNet does context parallelism](https://yywangcs.notion.site/DeltaNet-2a9fc9f5d8058013a498f34e0b25bd52), which splits a long sequence into multiple sub-sequences, uses $S\\_0=0$ to parallelize the recurrence, and then computes an additional $M$ matrix to correct the recurrent results. This scheme was later optimized to insert a step before the recurrence kernel to compute the $S\\_0$ of each sub-sequence, and has now been [merged into the FLA repository](https://github.com/fla-org/flash-linear-attention/blob/main/fla/ops/cp/README.md). For CP rank $j$, the specific preprocessing flow is:\n\n1. $\\\\left\\\\{\\\\begin{aligned} S^\\\\ast\\_{j,i+1} &\\\\gets \\\\gamma\\_{j,i,C-1}S^\\\\ast\\_{j,i} + K\\_{j,i}^\\\\intercal \\\\mathrm{diag}\\\\left(\\\\frac{\\\\gamma\\_{j,i,C-1}}{\\\\gamma\\_{j,i}}\\\\right) V’\\_{j,i} \\\\\\\\ M\\_{j,i+1} &\\\\gets \\\\left( \\\\gamma\\_{j,i,C-1} I -K\\_{j,i}^\\\\intercal \\\\mathrm{diag}\\\\left(\\\\frac{\\\\gamma\\_{j,i,C-1}}{\\\\gamma\\_{j,i}}\\\\right) W\\_{j,i} \\\\right) M\\_{j,i} \\\\end{aligned}\\\\right.$\n2. $S\\_{j,0} \\\\gets S^\\\\ast\\_{j,0} + M\\_{j,0}S\\_{j-1,0}$\n\nHowever, this CP scheme also has its drawbacks: first, it introduces significant extra computation, with the time complexity of recurrently computing the $M$ matrix even exceeding that of the $S$ matrix; second, it does not work well with fully-fused kernels, because matrix inversion and other steps must be performed before the $S\\_0$ of each sub-sequence can be computed.\n\n## A Balanced Solution: Fusing Kernels While Enabling Intra-Card CP\n\nBased on the two problems above, a compromise solution can be derived: split the GDN Chunked Prefill forward computation into two fused kernels, inserting CP-related preprocessing steps between them. After some transformations and simplifications, the following computation flow is obtained:\n\n1. $A\\_i \\\\gets \\\\left(I+\\\\mathrm{StrictLower}\\\\left( \\\\mathrm{diag}(\\\\beta\\_i)K\\_iK\\_i^\\\\intercal\\\\right)\\\\right)^{-1}$\n2. CP Preprocess\n   - 2.1. $\\\\left\\\\{\\\\begin{aligned} X\\_{j,i} &\\\\gets -\\\\beta\\_{j,i} A\\_{j,i}’^\\\\intercal K\\_{j,i} \\\\\\\\ Y\\_{j,i} &\\\\gets \\\\gamma\\_{j,i,C-1} K\\_{j,i} S^\\\\ast\\_{j,i} - \\\\mathrm{diag}\\\\left(\\\\frac{\\\\gamma\\_{j,i,C-1}}{\\\\gamma\\_{j,i}}\\\\right) V\\_{j,i} \\\\\\\\ Z\\_{j,i} &\\\\gets K\\_{j,i} M\\_{j,i} \\\\\\\\ S^\\\\ast\\_{j,i+1} &\\\\gets \\\\gamma\\_{j,i,C-1}S^\\\\ast\\_{j,i} + X\\_{j,i}^\\\\intercal Y\\_{j,i} \\\\\\\\ M\\_{j,i+1} &\\\\gets \\\\gamma\\_{j,i,C-1} \\\\left( M\\_{j,i} + X\\_{j,i}^\\\\intercal Z\\_{j,i} \\\\right) \\\\end{aligned}\\\\right.$\n   - 2.2. $S\\_{j,0} \\\\gets S^\\\\ast\\_{j,0} + M\\_{j,0}S\\_{j-1,0}$\n3. $\\\\left\\\\{\\\\begin{aligned} V\\_i^\\\\Delta &\\\\gets V\\_i - \\\\mathrm{diag}(\\\\gamma\\_i)K\\_iS\\_i \\\\\\\\ V\\_i’ &\\\\gets \\\\left(\\\\Gamma\\_i \\\\odot A\\_i\\\\right)\\\\mathrm{diag}(\\\\beta\\_i)V\\_i^\\\\Delta \\\\\\\\ S\\_{i+1} &\\\\gets \\\\gamma\\_{i,C-1}S\\_i + K\\_i^\\\\intercal\\\\mathrm{diag}\\\\left(\\\\frac{\\\\gamma\\_{i,C-1}}{\\\\gamma\\_i}\\\\right)V\\_i’ \\\\\\\\ O\\_i &\\\\gets \\\\mathrm{diag}({\\\\gamma\\_i})Q\\_iS\\_i + \\\\left(\\\\mathrm{Lower}(\\\\Gamma\\_i) \\\\odot Q\\_iK\\_i^\\\\intercal\\\\right)V\\_i’ \\\\end{aligned}\\\\right.$\n\nWe also designed a simple mathematical model to automatically determine the degree of parallelism. Let $N$ be the number of chunks in a sequence and $L$ be the number of chunks per CP rank. It is easy to see that the runtime of steps 2.1 and 3 is proportional to $L$, while the runtime of step 2.2 is proportional to $\\\\frac NL$; therefore we can choose $L=\\\\lambda \\\\sqrt N$ to minimize total time, where $\\\\lambda$ is a coefficient composed of `batch_size`, `num_heads`, and other hyperparameters.\n\nIn production, intra-card CP is not always needed. Following the original FLA implementation, step 3 can also increase parallelism by 2-4× via splitting `v_head_dim`, at the cost of redundant memory access to Q and K. Based on measured data, we enable CP only when `batch_size * num_heads <= 40` or `batch_size * num_heads <= 56 && seq_len >= 8192`.\n\n## Further Optimization via Gate Decay\n\nRevisiting the GDN recurrence:\n\n$$S\\_{i+1} = \\\\alpha\\_iS\\_i(I-\\\\beta\\_ik\\_ik\\_i^\\\\intercal)+\\\\beta\\_iv\\_ik\\_i^\\\\intercal$$\n\nFor $\\\\alpha\\_i\\\\in(0,1)$, the influence of each $S\\_i$ on subsequent states decays exponentially, giving it a sliding-window property. For a sufficiently long window size of $W$, starting computation from $S\\_{i-W}=0$ can obtain the accurate $S\\_i$, without the need to start from $S\\_0$. We refer to this process as warmup. On real data, we find that $\\\\alpha\\_i$ is not constantly 1 on 60–80% of linear attention heads, and **6–8 chunks of warmup** are sufficient to drive the $S\\_i$ error below the noise floor.\n\nTherefore, for linear attention heads with the sliding-window property, we can design a lighter CP preprocessing flow that discards the computation of the correction term $M$ and directly obtains an equally accurate sub-sequence $S\\_0$ through warmup:\n\n|    | C0 | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 | C9 | C10 | C11 | C12 |\n| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | --- | --- | --- |\n| R1 | O  | O  | O  | O  | O  |    |    |    |    |    |     |     |     |\n| R2 |    |    |    | X  | X  | O  | O  | O  | O  |    |     |     |     |\n| R3 |    |    |    |    |    |    |    | X  | X  | O  | O   | O   | O   |\n\n`X` denotes warming up with a zero initial state until the gate has decayed sufficiently, then writing out the $S\\_0$ of that CP rank; `O` denotes subsequent normal recurrent computation. The warmup length for each rank is determined by an independent kernel that collects gate statistics, and the cost of this step is negligible.\n\n## TileLang Warp-Specialized Kernel\n\nWe implement FlashQLA in [TileLang](https://github.com/tile-ai/tilelang) using a warpgroup-specialization pattern: one producer warpgroup and three consumer warpgroups reside in the same SM, exchange data through shared memory, and synchronize via mbarriers.\n\n### Forward\n\nIn the forward pass, the three consumer warp groups compute $V’$, $S$, and $O$ respectively, overlapping computation and memory traffic through a ping-pong structure.\n\n|           | WG3       | WG2                                         | WG1                                  | WG0                                           |                                                                                                        |                                  |\n| --------- | --------- | ------------------------------------------- | ------------------------------------ | --------------------------------------------- | ------------------------------------------------------------------------------------------------------ | -------------------------------- |\n| **BAR 0** | **LD**$Q$ | **LD**$\\\\gamma$                             | **ST**$O$                            | $\\\\gamma, \\\\gamma\\_{C-1}\\\\gamma^{-1}$         | **TC**$P = Q K^\\\\intercal$                                                                             |                                  |\n| **BAR 1** | **LD**$K$ | **LD**$\\\\beta$                              | **ST**$S\\_i$                         | **TC**$U = K S\\_i$                            | $\\\\Gamma = L(\\\\gamma I \\\\gamma^{-1})$ $A\\_\\\\gamma = \\\\Gamma \\\\odot A$ $P\\_\\\\gamma = s\\\\Gamma \\\\odot P$ | $S\\_{i+1} = \\\\gamma\\_{C-1} S\\_i$ |\n| **BAR 2** | **LD**$V$ |                                             | $W = \\\\beta (V - \\\\gamma U)$         | **TC**$O = Q S\\_i$                            |                                                                                                        |                                  |\n| **BAR 3** | **LD**$A$ |                                             | **TC**$V^\\\\Delta = A\\_\\\\gamma W$     | $O = s\\\\gamma O$                              |                                                                                                        |                                  |\n| **BAR 4** |           | $V’ = \\\\gamma\\_{C-1}\\\\gamma^{-1} V^\\\\Delta$ | **TC**$O = O + P\\_\\\\gamma V^\\\\Delta$ |                                               |                                                                                                        |                                  |\n| **BAR 5** |           |                                             |                                      | **TC**$S\\_{i+1} = S\\_{i+1} + K^\\\\intercal V'$ |                                                                                                        |                                  |\n\nNotes:\n\n- $S$ output per chunk is for debugging only; normally only $O$ and the last chunk’s $S$ are output.\n\n### CP Preprocessing\n\nAs mentioned earlier, the CP preprocessing splits into two cases: the original approach (computing both $M$ and $S$) and the sliding-window approach (computing only $S$). We designed a single fused kernel that handles both:\n\n|           | WG3       | WG2                                                      | WG1                                                      | WG0                                                                       |                                              |                                  |\n| --------- | --------- | -------------------------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------- | -------------------------------------------- | -------------------------------- |\n| **BAR 0** | **LD**$K$ | **LD**$\\\\gamma$                                          |                                                          | $\\\\gamma\\_{C-1}\\\\gamma^{-1}$                                              | **TC**$X = A^\\\\intercal K$                   |                                  |\n| **BAR 1** | **LD**$V$ | **LD**$\\\\beta$                                           | **ST**$S\\_i$                                             | **TC**$U = K S\\_i$ $Y = -\\\\gamma\\_{C-1}\\\\gamma^{-1} V + \\\\gamma\\_{C-1} U$ | $X = -\\\\beta X$                              | $S\\_{i+1} = \\\\gamma\\_{C-1} S\\_i$ |\n| **BAR 2** | **LD**$A$ |                                                          | $\\\\gamma^\\\\pi = \\\\gamma^\\\\pi \\\\gamma\\_{C-1}$             | $\\\\gamma^\\\\pi = \\\\gamma^\\\\pi \\\\gamma\\_{C-1}$                              | **TC**$S\\_{i+1} = S\\_{i+1} + X^\\\\intercal Y$ |                                  |\n| **BAR 3** |           | **TC**$Z^L = K M^L$ **TC**$M^L = M^L + X^\\\\intercal Z^L$ | **TC**$Z^R = K M^R$ **TC**$M^R = M^R + X^\\\\intercal Z^R$ |                                                                           |                                              |                                  |\n\nNotes:\n\n- The last two steps of WG1 and WG2 correspond to the $M$ matrix computation and are triggered only when required.\n- $S$ is output per chunk only during backward recomputation.\n\n### Backward\n\nIn the backward pass, we reuse the CP preprocessing kernel from the previous section to recompute the $S$ matrix, then fuse `bwd_dv`, `bwd_dhu`, `bwd_dqkwg`, `bwd_wy` into a single kernel with corresponding algebraic optimizations. Because of on-chip resource constraints, the backward kernel does not use multi-stage pipelining; instead it relies on the long compute chain to hide memory traffic. The full schedule is available in the [FlashQLA repo](https://github.com/QwenLM/FlashQLA).\n\n|            | WG3        | WG2                                                                                                      | WG1                                                                       | WG0                                                                                                                                                                                              |                                                   |\n| ---------- | ---------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------- |\n| **BAR 00** | **ST**$dK$ |                                                                                                          |                                                                           | **TC** $P=QK^\\\\intercal$                                                                                                                                                                         | $\\\\gamma, \\\\gamma\\_{C-1}\\\\gamma^{-1}$             |\n| **BAR 01** |            | **TC** $dV’=KdS\\_{i+1}$ $dV’=\\\\gamma\\_{C-1}\\\\gamma^{-1}dV'$                                              | $\\\\Gamma=\\\\gamma I \\\\gamma^{-1}$ $P\\_\\\\gamma=sL(\\\\Gamma)\\\\odot P$         | $dS\\_i = \\\\gamma\\_{C-1} dS\\_{i+1}$                                                                                                                                                               |                                                   |\n| **BAR 02** |            | **TC** $dV’=dV’+P\\_\\\\gamma^\\\\intercal dO$                                                                | $A\\_\\\\beta = A \\\\beta$ $A\\_\\\\gamma = \\\\Gamma \\\\odot A\\_\\\\beta$            |                                                                                                                                                                                                  |                                                   |\n| **BAR 03** |            |                                                                                                          | **TC**$U=KS\\_i$                                                           |                                                                                                                                                                                                  |                                                   |\n| **BAR 04** |            | **TC** $dV=A\\_\\\\gamma^\\\\intercal dV’$                                                                    | $W=V-\\\\gamma U$                                                           | $d\\\\gamma\\_{C-1}=\\\\sum S\\_i \\\\odot dS\\_{i+1}$                                                                                                                                                    |                                                   |\n| **BAR 05** | **ST**$dV$ | **LD**$V$                                                                                                | $dV\\_\\\\gamma = -\\\\gamma dV$ $d\\\\gamma = \\\\sum\\_i dV\\_\\\\gamma \\\\odot U$    | **TC** $dA\\_\\\\gamma = dV’W^T$ **TC** $V’=A\\_\\\\gamma W$                                                                                                                                           |                                                   |\n| **BAR 06** |            |                                                                                                          | **TC** $dP\\_\\\\gamma = dO V’^\\\\intercal$                                   |                                                                                                                                                                                                  |                                                   |\n| **BAR 07** |            | **LD**$K$                                                                                                | **TC** $dK=V’dS\\_{i+1}^\\\\intercal$                                        | $dA\\_\\\\beta = \\\\Gamma \\\\odot dA\\_\\\\gamma$ $d\\\\gamma = d\\\\gamma + \\\\sum\\_i dP\\_\\\\gamma \\\\odot L(P)$ $d\\\\gamma = d\\\\gamma - \\\\sum\\_j dP\\_\\\\gamma \\\\odot L(P)$ $dP = sL(\\\\Gamma)\\\\odot dP\\_\\\\gamma$ |                                                   |\n| **BAR 08** |            | $dK=\\\\gamma\\_{C-1}\\\\gamma^{-1}dK$ $d\\\\gamma\\_{C-1}=\\\\sum K \\\\odot dK$ $d\\\\gamma = -\\\\sum\\_i K \\\\odot dK$ | **TC** $dQ=dOS\\_i^T$                                                      |                                                                                                                                                                                                  |                                                   |\n| **BAR 09** |            | **LD**$Q$                                                                                                | **TC** $dK=dK+dV\\_\\\\gamma S\\_i^\\\\intercal$                                | $dQ=s\\\\gamma dQ$ $d\\\\gamma = \\\\sum Q \\\\odot dQ$                                                                                                                                                  |                                                   |\n| **BAR 10** |            | **LD**$S$                                                                                                |                                                                           | **TC** $dQ=dQ+dPK$                                                                                                                                                                               |                                                   |\n| **BAR 11** | **ST**$dQ$ |                                                                                                          |                                                                           | $d\\\\gamma = d\\\\gamma + \\\\sum\\_i dA\\_\\\\beta \\\\odot A \\\\beta$ $d\\\\gamma = d\\\\gamma - \\\\sum\\_j dA\\_\\\\beta \\\\odot A \\\\beta$ $d\\\\beta = \\\\sum\\_j dA\\_\\\\beta \\\\odot A$ $dA=dA\\_\\\\beta \\\\beta$          | **TC** $dS\\_i = dS\\_i + K^\\\\intercal dV\\_\\\\gamma$ |\n| **BAR 12** |            | **TC** $dK=dK+dP^\\\\intercal Q$                                                                           |                                                                           |                                                                                                                                                                                                  |                                                   |\n| **BAR 13** |            |                                                                                                          | **TC** $dA = -A^\\\\intercal dA A^\\\\intercal$ **TC** $A\\_T = KK^\\\\intercal$ | $dO\\_\\\\gamma=s\\\\gamma dO$                                                                                                                                                                        |                                                   |\n| **BAR 14** |            | **LD**$dO$ **LD**$A$                                                                                     |                                                                           | $d\\\\beta = d\\\\beta + \\\\sum\\_i dA \\\\odot A\\_T$ $dA\\_T = \\\\beta dA$ $dA\\_S = dA\\_T + dA\\_T^\\\\intercal$                                                                                             | **TC** $dS\\_0 = dS\\_0 + Q^\\\\intercal dO\\_\\\\gamma$ |\n| **BAR 15** |            | **TC** $dK=dK+dA\\_S K$                                                                                   |                                                                           |                                                                                                                                                                                                  |                                                   |\n\n## Benchmark\n\nWe benchmarked FlashQLA against the FLA Triton and FlashInfer baseline (FLA 0.5.0, Triton 3.5.1, FlashInfer 0.6.9, TileLang 0.1.8) on the head configurations used by the Qwen3.5 / Qwen3.6 family — $h\\_v \\\\in {64, 48, 32, 24, 16, 8}$, corresponding to TP1 through TP8.\n\n![FlashQLA vs FLA and FlashInfer on H200](https://qianwen-res.oss-cn-beijing.aliyuncs.com/flashqla/fwd_bwd_latency_comparison.png)\n\nSpecifically, the forward (FWD) benchmarks measure single-kernel latency for different models and TP settings under varying batch lengths, while the backward (BWD) benchmarks examine the relationship between total token count within a batch and latency during a single update step.\n\nSelected H200 single-layer forward results:\n\n| Model / TP    | Seqlen     | $h\\_{qk}$ | $h\\_v$ | FlashQLA | FlashInfer | FLA     | vs FLA | vs FI |\n| ------------- | ---------- | --------- | ------ | -------- | ---------- | ------- | ------ | ----- |\n| 397B/122B TP8 | 1x32768    | 2         | 8      | 0.310ms  | 1.653ms    | 0.913ms | 2.95×  | 5.33× |\n| 397B/122B TP8 | 1x16384    | 2         | 8      | 0.184ms  | 0.833ms    | 0.465ms | 2.53×  | 4.53× |\n| 397B/122B TP8 | 24576+8192 | 2         | 8      | 0.302ms  | 1.242ms    | 0.767ms | 2.54×  | 4.11× |\n| 397B/122B TP4 | 1x32768    | 4         | 16     | 0.486ms  | 1.654ms    | 1.250ms | 2.57×  | 3.40× |\n| 397B/122B TP4 | 1x16384    | 4         | 16     | 0.292ms  | 0.832ms    | 0.623ms | 2.13×  | 2.85× |\n| 27B TP2       | 1x32768    | 8         | 24     | 0.659ms  | 1.616ms    | 1.564ms | 2.37×  | 2.45× |\n| 2B/0.8B TP1   | 1x32768    | 16        | 16     | 0.493ms  | 1.640ms    | 1.285ms | 2.60×  | 3.33× |\n| Sym h32       | 1x32768    | 32        | 32     | 0.877ms  | 1.554ms    | 1.952ms | 2.23×  | 1.77× |\n\nThe speedup grows with TP degree because FlashQLA improves SM utilization via intra-card AutoCP in the exact regimes — TP sharding and small head number — where the baseline leaves SMs idle.\n\n## Usage\n\nFlashQLA exposes both a high-level API matching FLA’s signature and low-level fwd/bwd entry points:\n\n```python\nimport torch\nfrom qla import chunk_gated_delta_rule\n\no, final_state = chunk_gated_delta_rule(\n    q=q,                            # [B, T, H_q, K]\n    k=k,                            # [B, T, H_q, K]\n    v=v,                            # [B, T, H_v, V]\n    g=g,                            # [B, T, H_v]\n    beta=beta,                      # [B, T, H_v]\n    scale=scale,\n    initial_state=initial_state,    # optional, [B, H_v, K, V]\n    output_final_state=True,\n    cu_seqlens=cu_seqlens,          # optional, varlen support\n)\n```\n\nRequirements: SM90, CUDA 12.8+, PyTorch 2.8+. Install:\n\n```bash\ngit clone https://github.com/QwenLM/FlashQLA.git\ncd FlashQLA && pip install -v .\n```\n\n## Acknowledgments\n\nFlashQLA is inspired by [Flash Linear Attention](https://github.com/fla-org/flash-linear-attention), [FlashInfer](https://github.com/flashinfer-ai/flashinfer) and [TileLang](https://github.com/tile-ai/tilelang). We thank these communities for the reference implementations.\n\n## Citation\n\nIf FlashQLA is useful for your research, please cite:\n\n```bibtex\n@misc{flashqla2026,\n    title  = {FlashQLA: Flash Qwen Linear Attention},\n    author = {Zhang, Chengruidong and Lin, Xi and Jiang, Huiqiang and Wang, Zekun and\n              Li, Xiao and Cao, Yizhong and Zhuang, Bohan and Men, Rui and Zhang, Jianwei and\n              Zheng, Bo and Lin, Junyang and Liu, Dayiheng and Zhou, Jingren},\n    year   = {2026},\n    publisher = {GitHub},\n    howpublished = {\\url{https://github.com/QwenLM/FlashQLA}}\n}\n```\n",
  "authors": [
    "QwenTeam"
  ],
  "captured_at": "2026-10-19T01:26:53.998049939+00:00",
  "category": "ai",
  "content_html": "<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://qianwen-res.oss-cn-beijing.aliyuncs.com/flashqla/flashqla.png\" alt=\"\" loading=\"eager\" decoding=\"async\" fetchpriority=\"high\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<h2>Introduction</h2>\n<p>Following the release of <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://qwen.ai/blog?id=qwen3-next\">Qwen3-Next</a>, Gated Delta Network (GDN) has become the workhorse attention layer across the Qwen family — from Qwen3-Next-80B-A3B all the way to the subsequent <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://qwen.ai/blog?id=qwen3.5\">Qwen3.5</a> / <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://qwen.ai/blog?id=qwen3.6\">Qwen3.6</a> series. As models scale to <strong>397A17B / 122A10B / 35B / 27B</strong> and context windows stretch beyond 256K, the overhead of the GDN block in end-to-end training and inference has become non-negligible.</p>\n<p>Today we officially open-source <strong>FlashQLA</strong>: a high-performance linear attention kernel library built on <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/tile-ai/tilelang\">TileLang</a>. FlashQLA applies <strong>reasonable operator fusion and performance optimization</strong> to the forward and backward passes of GDN Chunked Prefill, achieving <strong>2-3× forward speedup</strong> and <strong>2× backward speedup</strong> over the FLA Triton kernel across multiple scenarios on NVIDIA Hopper. The efficiency gains are particularly pronounced in pretraining scenarios and edge-side agentic inference.</p>\n<p>Key highlights of this release:</p>\n<ol>\n<li>\n<p><strong>Gate-driven automatic intra-card context parallelism</strong>. By exploiting the exponential decay property of the GDN gate, FlashQLA automatically enables intra-card CP under TP, long-sequence, and small-head-count settings, improving GPU SM utilization.</p>\n</li>\n<li>\n<p><strong>Hardware-friendly algebraic reformulation</strong>. We reformulate the forward and backward flows of GDN Chunked Prefill to a certain extent, effectively reducing Tensor Core, CUDA Core, and SFU overhead without sacrificing numerical precision.</p>\n</li>\n<li>\n<p><strong>TileLang fused warp-specialized kernels</strong>. Rather than following the step-by-step decomposition into independent kernels, nor fusing the entire computation flow into a single kernel, we take CP and backward requirements into account, use TileLang to build several key fused kernels, and manually implement warpgroup specialization to overlap data movement, Tensor Core computation, and CUDA Core computation.</p>\n</li>\n</ol>\n<p>FlashQLA code and benchmarks are open-sourced at <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/QwenLM/FlashQLA\">github.com/QwenLM/FlashQLA</a>.</p>\n<h2>Key Problems in FLA GDN Chunked Prefill</h2>\n<p>Let us first review the forward computation flow of GDN Chunked Prefill, taking chunk index <span class=\"math\">i</span> as an example:</p>\n<ol>\n<li><span class=\"math\">Aᵢ ← (I+StrictLower( diag(βᵢ)(Γᵢ ⊙ KᵢKᵢ^ᵀ) ))⁻¹</span></li>\n<li><span class=\"math\">{Wᵢ ← Aᵢdiag(βᵢ)diag(γᵢ)Kᵢ; Uᵢ ← Aᵢdiag(βᵢ)Vᵢ</span></li>\n<li><span class=\"math\">{Vᵢ’ ← Uᵢ−WᵢSᵢ; Sᵢ₊₁ ← γ_(i,C−1)Sᵢ + Kᵢ^ᵀdiag((γ_(i,C−1))/γᵢ)Vᵢ’</span></li>\n<li><span class=\"math\">Oᵢ ← diag(γ)QᵢSᵢ + (Lower(Γᵢ) ⊙ QᵢKᵢ^ᵀ)Vᵢ′</span></li>\n</ol>\n<p>Ignoring gate preprocessing and CP, each step of this flow corresponds to one kernel <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/fla-org/flash-linear-attention/blob/v0.5.0/fla/ops/gated_delta_rule/chunk.py\">in FLA</a>. This flow has two main efficiency problems:</p>\n<ol>\n<li>Most of the above are <strong>memory-bound kernels</strong>. The flow repeatedly reads <span class=\"math\">K</span>, <span class=\"math\">V</span> and other data, while <span class=\"math\">W</span>, <span class=\"math\">U</span>, <span class=\"math\">S</span> as intermediate variables must be written to HBM and then read by the next kernel, incurring significant memory access overhead.</li>\n<li>The recurrent nature of the SSM state means that the corresponding third step <code>chunk_gated_delta_rule_fwd_kernel</code> can only launch <code>batch_size * num_heads</code> thread blocks simultaneously, resulting in <strong>low GPU utilization</strong> in small-model, small-batch, or TP scenarios.</li>\n</ol>\n<p>The solutions to these two problems are contradictory. For the first problem, the most intuitive solution is to write a <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/flashinfer-ai/flashinfer/pull/2276\">fully-fused kernel</a>, where all data is accessed only once and all intermediate variables are kept on-chip. When <code>batch_size * num_heads</code> is large enough, this is certainly optimal. However, such a solution obviously runs into the second problem: for edge-side inference with small models and <code>batch_size=1</code>, or for large-model online deployments with TP where long-sequence inputs from coding agents etc. cannot launch a large enough batch for chunked prefill, the speedup of a fully-fused kernel over the original FLA implementation is limited.</p>\n<p>The earliest solution to the second problem comes from <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://yywangcs.notion.site/DeltaNet-2a9fc9f5d8058013a498f34e0b25bd52\">how DeltaNet does context parallelism</a>, which splits a long sequence into multiple sub-sequences, uses <span class=\"math\">S₀=0</span> to parallelize the recurrence, and then computes an additional <span class=\"math\">M</span> matrix to correct the recurrent results. This scheme was later optimized to insert a step before the recurrence kernel to compute the <span class=\"math\">S₀</span> of each sub-sequence, and has now been <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/fla-org/flash-linear-attention/blob/main/fla/ops/cp/README.md\">merged into the FLA repository</a>. For CP rank <span class=\"math\">j</span>, the specific preprocessing flow is:</p>\n<ol>\n<li><span class=\"math\">{S^∗_(j,i+1) ← γ_(j,i,C−1)S^∗_(j,i) + K_(j,i)^ᵀ diag((γ_(j,i,C−1))/γ_(j,i)) V’_(j,i); M_(j,i+1) ← ( γ_(j,i,C−1) I −K_(j,i)^ᵀ diag((γ_(j,i,C−1))/γ_(j,i)) W_(j,i) ) M_(j,i)</span></li>\n<li><span class=\"math\">S_(j,0) ← S^∗_(j,0) + M_(j,0)S_(j−1,0)</span></li>\n</ol>\n<p>However, this CP scheme also has its drawbacks: first, it introduces significant extra computation, with the time complexity of recurrently computing the <span class=\"math\">M</span> matrix even exceeding that of the <span class=\"math\">S</span> matrix; second, it does not work well with fully-fused kernels, because matrix inversion and other steps must be performed before the <span class=\"math\">S₀</span> of each sub-sequence can be computed.</p>\n<h2>A Balanced Solution: Fusing Kernels While Enabling Intra-Card CP</h2>\n<p>Based on the two problems above, a compromise solution can be derived: split the GDN Chunked Prefill forward computation into two fused kernels, inserting CP-related preprocessing steps between them. After some transformations and simplifications, the following computation flow is obtained:</p>\n<ol>\n<li><span class=\"math\">Aᵢ ← (I+StrictLower( diag(βᵢ)KᵢKᵢ^ᵀ))⁻¹</span></li>\n<li>CP Preprocess\n<ul>\n<li>2.1. <span class=\"math\">{X_(j,i) ← −β_(j,i) A_(j,i)’^ᵀ K_(j,i); Y_(j,i) ← γ_(j,i,C−1) K_(j,i) S^∗_(j,i) − diag((γ_(j,i,C−1))/γ_(j,i)) V_(j,i); Z_(j,i) ← K_(j,i) M_(j,i); S^∗_(j,i+1) ← γ_(j,i,C−1)S^∗_(j,i) + X_(j,i)^ᵀ Y_(j,i); M_(j,i+1) ← γ_(j,i,C−1) ( M_(j,i) + X_(j,i)^ᵀ Z_(j,i) )</span></li>\n<li>2.2. <span class=\"math\">S_(j,0) ← S^∗_(j,0) + M_(j,0)S_(j−1,0)</span></li>\n</ul>\n</li>\n<li><span class=\"math\">{Vᵢ^Δ ← Vᵢ − diag(γᵢ)KᵢSᵢ; Vᵢ’ ← (Γᵢ ⊙ Aᵢ)diag(βᵢ)Vᵢ^Δ; Sᵢ₊₁ ← γ_(i,C−1)Sᵢ + Kᵢ^ᵀdiag((γ_(i,C−1))/γᵢ)Vᵢ’; Oᵢ ← diag(γᵢ)QᵢSᵢ + (Lower(Γᵢ) ⊙ QᵢKᵢ^ᵀ)Vᵢ’</span></li>\n</ol>\n<p>We also designed a simple mathematical model to automatically determine the degree of parallelism. Let <span class=\"math\">N</span> be the number of chunks in a sequence and <span class=\"math\">L</span> be the number of chunks per CP rank. It is easy to see that the runtime of steps 2.1 and 3 is proportional to <span class=\"math\">L</span>, while the runtime of step 2.2 is proportional to <span class=\"math\">N/L</span>; therefore we can choose <span class=\"math\">L=λ √N</span> to minimize total time, where <span class=\"math\">λ</span> is a coefficient composed of <code>batch_size</code>, <code>num_heads</code>, and other hyperparameters.</p>\n<p>In production, intra-card CP is not always needed. Following the original FLA implementation, step 3 can also increase parallelism by 2-4× via splitting <code>v_head_dim</code>, at the cost of redundant memory access to Q and K. Based on measured data, we enable CP only when <code>batch_size * num_heads &lt;= 40</code> or <code>batch_size * num_heads &lt;= 56 &amp;&amp; seq_len &gt;= 8192</code>.</p>\n<h2>Further Optimization via Gate Decay</h2>\n<p>Revisiting the GDN recurrence:</p>\n<p><span class=\"math math-display\">Sᵢ₊₁ = αᵢSᵢ(I−βᵢkᵢkᵢ^ᵀ)+βᵢvᵢkᵢ^ᵀ</span></p>\n<p>For <span class=\"math\">αᵢ∈(0,1)</span>, the influence of each <span class=\"math\">Sᵢ</span> on subsequent states decays exponentially, giving it a sliding-window property. For a sufficiently long window size of <span class=\"math\">W</span>, starting computation from <span class=\"math\">S_(i−W)=0</span> can obtain the accurate <span class=\"math\">Sᵢ</span>, without the need to start from <span class=\"math\">S₀</span>. We refer to this process as warmup. On real data, we find that <span class=\"math\">αᵢ</span> is not constantly 1 on 60–80% of linear attention heads, and <strong>6–8 chunks of warmup</strong> are sufficient to drive the <span class=\"math\">Sᵢ</span> error below the noise floor.</p>\n<p>Therefore, for linear attention heads with the sliding-window property, we can design a lighter CP preprocessing flow that discards the computation of the correction term <span class=\"math\">M</span> and directly obtains an equally accurate sub-sequence <span class=\"math\">S₀</span> through warmup:</p>\n<table>\n<thead>\n<tr>\n<th></th>\n<th>C0</th>\n<th>C1</th>\n<th>C2</th>\n<th>C3</th>\n<th>C4</th>\n<th>C5</th>\n<th>C6</th>\n<th>C7</th>\n<th>C8</th>\n<th>C9</th>\n<th>C10</th>\n<th>C11</th>\n<th>C12</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>R1</td>\n<td>O</td>\n<td>O</td>\n<td>O</td>\n<td>O</td>\n<td>O</td>\n<td></td>\n<td></td>\n<td></td>\n<td></td>\n<td></td>\n<td></td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>R2</td>\n<td></td>\n<td></td>\n<td></td>\n<td>X</td>\n<td>X</td>\n<td>O</td>\n<td>O</td>\n<td>O</td>\n<td>O</td>\n<td></td>\n<td></td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>R3</td>\n<td></td>\n<td></td>\n<td></td>\n<td></td>\n<td></td>\n<td></td>\n<td></td>\n<td>X</td>\n<td>X</td>\n<td>O</td>\n<td>O</td>\n<td>O</td>\n<td>O</td>\n</tr>\n</tbody>\n</table>\n<p><code>X</code> denotes warming up with a zero initial state until the gate has decayed sufficiently, then writing out the <span class=\"math\">S₀</span> of that CP rank; <code>O</code> denotes subsequent normal recurrent computation. The warmup length for each rank is determined by an independent kernel that collects gate statistics, and the cost of this step is negligible.</p>\n<h2>TileLang Warp-Specialized Kernel</h2>\n<p>We implement FlashQLA in <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/tile-ai/tilelang\">TileLang</a> using a warpgroup-specialization pattern: one producer warpgroup and three consumer warpgroups reside in the same SM, exchange data through shared memory, and synchronize via mbarriers.</p>\n<h3>Forward</h3>\n<p>In the forward pass, the three consumer warp groups compute <span class=\"math\">V’</span>, <span class=\"math\">S</span>, and <span class=\"math\">O</span> respectively, overlapping computation and memory traffic through a ping-pong structure.</p>\n<table>\n<thead>\n<tr>\n<th></th>\n<th>WG3</th>\n<th>WG2</th>\n<th>WG1</th>\n<th>WG0</th>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>BAR 0</strong></td>\n<td><strong>LD</strong><span class=\"math\">Q</span></td>\n<td><strong>LD</strong><span class=\"math\">γ</span></td>\n<td><strong>ST</strong><span class=\"math\">O</span></td>\n<td><span class=\"math\">γ, γ_(C−1)γ⁻¹</span></td>\n<td><strong>TC</strong><span class=\"math\">P = Q K^ᵀ</span></td>\n<td></td>\n</tr>\n<tr>\n<td><strong>BAR 1</strong></td>\n<td><strong>LD</strong><span class=\"math\">K</span></td>\n<td><strong>LD</strong><span class=\"math\">β</span></td>\n<td><strong>ST</strong><span class=\"math\">Sᵢ</span></td>\n<td><strong>TC</strong><span class=\"math\">U = K Sᵢ</span></td>\n<td><span class=\"math\">Γ = L(γ I γ⁻¹)</span> <span class=\"math\">A_γ = Γ ⊙ A</span> <span class=\"math\">P_γ = sΓ ⊙ P</span></td>\n<td><span class=\"math\">Sᵢ₊₁ = γ_(C−1) Sᵢ</span></td>\n</tr>\n<tr>\n<td><strong>BAR 2</strong></td>\n<td><strong>LD</strong><span class=\"math\">V</span></td>\n<td></td>\n<td><span class=\"math\">W = β (V − γ U)</span></td>\n<td><strong>TC</strong><span class=\"math\">O = Q Sᵢ</span></td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td><strong>BAR 3</strong></td>\n<td><strong>LD</strong><span class=\"math\">A</span></td>\n<td></td>\n<td><strong>TC</strong><span class=\"math\">V^Δ = A_γ W</span></td>\n<td><span class=\"math\">O = sγ O</span></td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td><strong>BAR 4</strong></td>\n<td></td>\n<td><span class=\"math\">V’ = γ_(C−1)γ⁻¹ V^Δ</span></td>\n<td><strong>TC</strong><span class=\"math\">O = O + P_γ V^Δ</span></td>\n<td></td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td><strong>BAR 5</strong></td>\n<td></td>\n<td></td>\n<td></td>\n<td><strong>TC</strong><span class=\"math\">Sᵢ₊₁ = Sᵢ₊₁ + K^ᵀ V′</span></td>\n<td></td>\n<td></td>\n</tr>\n</tbody>\n</table>\n<p>Notes:</p>\n<ul>\n<li><span class=\"math\">S</span> output per chunk is for debugging only; normally only <span class=\"math\">O</span> and the last chunk’s <span class=\"math\">S</span> are output.</li>\n</ul>\n<h3>CP Preprocessing</h3>\n<p>As mentioned earlier, the CP preprocessing splits into two cases: the original approach (computing both <span class=\"math\">M</span> and <span class=\"math\">S</span>) and the sliding-window approach (computing only <span class=\"math\">S</span>). We designed a single fused kernel that handles both:</p>\n<table>\n<thead>\n<tr>\n<th></th>\n<th>WG3</th>\n<th>WG2</th>\n<th>WG1</th>\n<th>WG0</th>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>BAR 0</strong></td>\n<td><strong>LD</strong><span class=\"math\">K</span></td>\n<td><strong>LD</strong><span class=\"math\">γ</span></td>\n<td></td>\n<td><span class=\"math\">γ_(C−1)γ⁻¹</span></td>\n<td><strong>TC</strong><span class=\"math\">X = A^ᵀ K</span></td>\n<td></td>\n</tr>\n<tr>\n<td><strong>BAR 1</strong></td>\n<td><strong>LD</strong><span class=\"math\">V</span></td>\n<td><strong>LD</strong><span class=\"math\">β</span></td>\n<td><strong>ST</strong><span class=\"math\">Sᵢ</span></td>\n<td><strong>TC</strong><span class=\"math\">U = K Sᵢ</span> <span class=\"math\">Y = −γ_(C−1)γ⁻¹ V + γ_(C−1) U</span></td>\n<td><span class=\"math\">X = −β X</span></td>\n<td><span class=\"math\">Sᵢ₊₁ = γ_(C−1) Sᵢ</span></td>\n</tr>\n<tr>\n<td><strong>BAR 2</strong></td>\n<td><strong>LD</strong><span class=\"math\">A</span></td>\n<td></td>\n<td><span class=\"math\">γ^π = γ^π γ_(C−1)</span></td>\n<td><span class=\"math\">γ^π = γ^π γ_(C−1)</span></td>\n<td><strong>TC</strong><span class=\"math\">Sᵢ₊₁ = Sᵢ₊₁ + X^ᵀ Y</span></td>\n<td></td>\n</tr>\n<tr>\n<td><strong>BAR 3</strong></td>\n<td></td>\n<td><strong>TC</strong><span class=\"math\">Z^L = K M^L</span> <strong>TC</strong><span class=\"math\">M^L = M^L + X^ᵀ Z^L</span></td>\n<td><strong>TC</strong><span class=\"math\">Z^R = K M^R</span> <strong>TC</strong><span class=\"math\">M^R = M^R + X^ᵀ Z^R</span></td>\n<td></td>\n<td></td>\n<td></td>\n</tr>\n</tbody>\n</table>\n<p>Notes:</p>\n<ul>\n<li>The last two steps of WG1 and WG2 correspond to the <span class=\"math\">M</span> matrix computation and are triggered only when required.</li>\n<li><span class=\"math\">S</span> is output per chunk only during backward recomputation.</li>\n</ul>\n<h3>Backward</h3>\n<p>In the backward pass, we reuse the CP preprocessing kernel from the previous section to recompute the <span class=\"math\">S</span> matrix, then fuse <code>bwd_dv</code>, <code>bwd_dhu</code>, <code>bwd_dqkwg</code>, <code>bwd_wy</code> into a single kernel with corresponding algebraic optimizations. Because of on-chip resource constraints, the backward kernel does not use multi-stage pipelining; instead it relies on the long compute chain to hide memory traffic. The full schedule is available in the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/QwenLM/FlashQLA\">FlashQLA repo</a>.</p>\n<table>\n<thead>\n<tr>\n<th></th>\n<th>WG3</th>\n<th>WG2</th>\n<th>WG1</th>\n<th>WG0</th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>BAR 00</strong></td>\n<td><strong>ST</strong>$dK$</td>\n<td></td>\n<td></td>\n<td><strong>TC</strong> <span class=\"math\">P=QK^ᵀ</span></td>\n<td><span class=\"math\">γ, γ_(C−1)γ⁻¹</span></td>\n</tr>\n<tr>\n<td><strong>BAR 01</strong></td>\n<td></td>\n<td><strong>TC</strong> <span class=\"math\">dV’=KdSᵢ₊₁</span> <span class=\"math\">dV’=γ_(C−1)γ⁻¹dV′</span></td>\n<td><span class=\"math\">Γ=γ I γ⁻¹</span> <span class=\"math\">P_γ=sL(Γ)⊙ P</span></td>\n<td><span class=\"math\">dSᵢ = γ_(C−1) dSᵢ₊₁</span></td>\n<td></td>\n</tr>\n<tr>\n<td><strong>BAR 02</strong></td>\n<td></td>\n<td><strong>TC</strong> <span class=\"math\">dV’=dV’+P_γ^ᵀ dO</span></td>\n<td><span class=\"math\">A_β = A β</span> <span class=\"math\">A_γ = Γ ⊙ A_β</span></td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td><strong>BAR 03</strong></td>\n<td></td>\n<td></td>\n<td><strong>TC</strong><span class=\"math\">U=KSᵢ</span></td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td><strong>BAR 04</strong></td>\n<td></td>\n<td><strong>TC</strong> <span class=\"math\">dV=A_γ^ᵀ dV’</span></td>\n<td><span class=\"math\">W=V−γ U</span></td>\n<td><span class=\"math\">dγ_(C−1)=∑ Sᵢ ⊙ dSᵢ₊₁</span></td>\n<td></td>\n</tr>\n<tr>\n<td><strong>BAR 05</strong></td>\n<td><strong>ST</strong>$dV$</td>\n<td><strong>LD</strong><span class=\"math\">V</span></td>\n<td><span class=\"math\">dV_γ = −γ dV</span> <span class=\"math\">dγ = ∑ᵢ dV_γ ⊙ U</span></td>\n<td><strong>TC</strong> <span class=\"math\">dA_γ = dV’Wᵀ</span> <strong>TC</strong> <span class=\"math\">V’=A_γ W</span></td>\n<td></td>\n</tr>\n<tr>\n<td><strong>BAR 06</strong></td>\n<td></td>\n<td></td>\n<td><strong>TC</strong> <span class=\"math\">dP_γ = dO V’^ᵀ</span></td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td><strong>BAR 07</strong></td>\n<td></td>\n<td><strong>LD</strong><span class=\"math\">K</span></td>\n<td><strong>TC</strong> <span class=\"math\">dK=V’dSᵢ₊₁^ᵀ</span></td>\n<td><span class=\"math\">dA_β = Γ ⊙ dA_γ</span> <span class=\"math\">dγ = dγ + ∑ᵢ dP_γ ⊙ L(P)</span> <span class=\"math\">dγ = dγ − ∑ⱼ dP_γ ⊙ L(P)</span> <span class=\"math\">dP = sL(Γ)⊙ dP_γ</span></td>\n<td></td>\n</tr>\n<tr>\n<td><strong>BAR 08</strong></td>\n<td></td>\n<td><span class=\"math\">dK=γ_(C−1)γ⁻¹dK</span> <span class=\"math\">dγ_(C−1)=∑ K ⊙ dK</span> <span class=\"math\">dγ = −∑ᵢ K ⊙ dK</span></td>\n<td><strong>TC</strong> <span class=\"math\">dQ=dOSᵢᵀ</span></td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td><strong>BAR 09</strong></td>\n<td></td>\n<td><strong>LD</strong><span class=\"math\">Q</span></td>\n<td><strong>TC</strong> <span class=\"math\">dK=dK+dV_γ Sᵢ^ᵀ</span></td>\n<td><span class=\"math\">dQ=sγ dQ</span> <span class=\"math\">dγ = ∑ Q ⊙ dQ</span></td>\n<td></td>\n</tr>\n<tr>\n<td><strong>BAR 10</strong></td>\n<td></td>\n<td><strong>LD</strong><span class=\"math\">S</span></td>\n<td></td>\n<td><strong>TC</strong> <span class=\"math\">dQ=dQ+dPK</span></td>\n<td></td>\n</tr>\n<tr>\n<td><strong>BAR 11</strong></td>\n<td><strong>ST</strong>$dQ$</td>\n<td></td>\n<td></td>\n<td><span class=\"math\">dγ = dγ + ∑ᵢ dA_β ⊙ A β</span> <span class=\"math\">dγ = dγ − ∑ⱼ dA_β ⊙ A β</span> <span class=\"math\">dβ = ∑ⱼ dA_β ⊙ A</span> <span class=\"math\">dA=dA_β β</span></td>\n<td><strong>TC</strong> <span class=\"math\">dSᵢ = dSᵢ + K^ᵀ dV_γ</span></td>\n</tr>\n<tr>\n<td><strong>BAR 12</strong></td>\n<td></td>\n<td><strong>TC</strong> <span class=\"math\">dK=dK+dP^ᵀ Q</span></td>\n<td></td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td><strong>BAR 13</strong></td>\n<td></td>\n<td></td>\n<td><strong>TC</strong> <span class=\"math\">dA = −A^ᵀ dA A^ᵀ</span> <strong>TC</strong> <span class=\"math\">A_T = KK^ᵀ</span></td>\n<td><span class=\"math\">dO_γ=sγ dO</span></td>\n<td></td>\n</tr>\n<tr>\n<td><strong>BAR 14</strong></td>\n<td></td>\n<td><strong>LD</strong>$dO$ <strong>LD</strong><span class=\"math\">A</span></td>\n<td></td>\n<td><span class=\"math\">dβ = dβ + ∑ᵢ dA ⊙ A_T</span> <span class=\"math\">dA_T = β dA</span> <span class=\"math\">dA_S = dA_T + dA_T^ᵀ</span></td>\n<td><strong>TC</strong> <span class=\"math\">dS₀ = dS₀ + Q^ᵀ dO_γ</span></td>\n</tr>\n<tr>\n<td><strong>BAR 15</strong></td>\n<td></td>\n<td><strong>TC</strong> <span class=\"math\">dK=dK+dA_S K</span></td>\n<td></td>\n<td></td>\n<td></td>\n</tr>\n</tbody>\n</table>\n<h2>Benchmark</h2>\n<p>We benchmarked FlashQLA against the FLA Triton and FlashInfer baseline (FLA 0.5.0, Triton 3.5.1, FlashInfer 0.6.9, TileLang 0.1.8) on the head configurations used by the Qwen3.5 / Qwen3.6 family — <span class=\"math\">hᵥ ∈ 64, 48, 32, 24, 16, 8</span>, corresponding to TP1 through TP8.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://qianwen-res.oss-cn-beijing.aliyuncs.com/flashqla/fwd_bwd_latency_comparison.png\" alt=\"FlashQLA vs FLA and FlashInfer on H200\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Specifically, the forward (FWD) benchmarks measure single-kernel latency for different models and TP settings under varying batch lengths, while the backward (BWD) benchmarks examine the relationship between total token count within a batch and latency during a single update step.</p>\n<p>Selected H200 single-layer forward results:</p>\n<table>\n<thead>\n<tr>\n<th>Model / TP</th>\n<th>Seqlen</th>\n<th><span class=\"math\">h_(qk)</span></th>\n<th><span class=\"math\">hᵥ</span></th>\n<th>FlashQLA</th>\n<th>FlashInfer</th>\n<th>FLA</th>\n<th>vs FLA</th>\n<th>vs FI</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>397B/122B TP8</td>\n<td>1x32768</td>\n<td>2</td>\n<td>8</td>\n<td>0.310ms</td>\n<td>1.653ms</td>\n<td>0.913ms</td>\n<td>2.95×</td>\n<td>5.33×</td>\n</tr>\n<tr>\n<td>397B/122B TP8</td>\n<td>1x16384</td>\n<td>2</td>\n<td>8</td>\n<td>0.184ms</td>\n<td>0.833ms</td>\n<td>0.465ms</td>\n<td>2.53×</td>\n<td>4.53×</td>\n</tr>\n<tr>\n<td>397B/122B TP8</td>\n<td>24576+8192</td>\n<td>2</td>\n<td>8</td>\n<td>0.302ms</td>\n<td>1.242ms</td>\n<td>0.767ms</td>\n<td>2.54×</td>\n<td>4.11×</td>\n</tr>\n<tr>\n<td>397B/122B TP4</td>\n<td>1x32768</td>\n<td>4</td>\n<td>16</td>\n<td>0.486ms</td>\n<td>1.654ms</td>\n<td>1.250ms</td>\n<td>2.57×</td>\n<td>3.40×</td>\n</tr>\n<tr>\n<td>397B/122B TP4</td>\n<td>1x16384</td>\n<td>4</td>\n<td>16</td>\n<td>0.292ms</td>\n<td>0.832ms</td>\n<td>0.623ms</td>\n<td>2.13×</td>\n<td>2.85×</td>\n</tr>\n<tr>\n<td>27B TP2</td>\n<td>1x32768</td>\n<td>8</td>\n<td>24</td>\n<td>0.659ms</td>\n<td>1.616ms</td>\n<td>1.564ms</td>\n<td>2.37×</td>\n<td>2.45×</td>\n</tr>\n<tr>\n<td>2B/0.8B TP1</td>\n<td>1x32768</td>\n<td>16</td>\n<td>16</td>\n<td>0.493ms</td>\n<td>1.640ms</td>\n<td>1.285ms</td>\n<td>2.60×</td>\n<td>3.33×</td>\n</tr>\n<tr>\n<td>Sym h32</td>\n<td>1x32768</td>\n<td>32</td>\n<td>32</td>\n<td>0.877ms</td>\n<td>1.554ms</td>\n<td>1.952ms</td>\n<td>2.23×</td>\n<td>1.77×</td>\n</tr>\n</tbody>\n</table>\n<p>The speedup grows with TP degree because FlashQLA improves SM utilization via intra-card AutoCP in the exact regimes — TP sharding and small head number — where the baseline leaves SMs idle.</p>\n<h2>Usage</h2>\n<p>FlashQLA exposes both a high-level API matching FLA’s signature and low-level fwd/bwd entry points:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">torch</span></span></span>\n<span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-from syntax-python\">from</span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-meta syntax-import-source syntax-python\"> <span class=\"syntax-meta syntax-import-path syntax-python\"><span class=\"syntax-meta syntax-import-name syntax-python\">qla</span></span> <span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span></span></span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"> <span class=\"syntax-meta syntax-generic-name syntax-python\">chunk_gated_delta_rule</span></span>\n\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">o</span></span>, <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">final_state</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">chunk_gated_delta_rule</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\">\n    <span class=\"syntax-variable syntax-parameter syntax-python\">q</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">q</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>                            <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> [B, T, H_q, K]\n</span>    <span class=\"syntax-variable syntax-parameter syntax-python\">k</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">k</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>                            <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> [B, T, H_q, K]\n</span>    <span class=\"syntax-variable syntax-parameter syntax-python\">v</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">v</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>                            <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> [B, T, H_v, V]\n</span>    <span class=\"syntax-variable syntax-parameter syntax-python\">g</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">g</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>                            <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> [B, T, H_v]\n</span>    <span class=\"syntax-variable syntax-parameter syntax-python\">beta</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">beta</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>                      <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> [B, T, H_v]\n</span>    <span class=\"syntax-variable syntax-parameter syntax-python\">scale</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">scale</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n    <span class=\"syntax-variable syntax-parameter syntax-python\">initial_state</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">initial_state</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>    <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> optional, [B, H_v, K, V]\n</span>    <span class=\"syntax-variable syntax-parameter syntax-python\">output_final_state</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-constant syntax-language syntax-python\">True</span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n    <span class=\"syntax-variable syntax-parameter syntax-python\">cu_seqlens</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">cu_seqlens</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>          <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> optional, varlen support\n</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>Requirements: SM90, CUDA 12.8+, PyTorch 2.8+. Install:</p>\n<pre><code class=\"language-bash\"><span class=\"code-snippet\" data-language=\"Shell\"><span class=\"syntax-source syntax-shell syntax-bash\"><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">git</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> clone https://github.com/QwenLM/FlashQLA.git</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-support syntax-function syntax-cd syntax-shell\">cd</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> FlashQLA</span> <span class=\"syntax-keyword syntax-operator syntax-logical syntax-and syntax-shell\">&amp;&amp;</span> <span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">pip</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> install<span class=\"syntax-variable syntax-parameter syntax-option syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-parameter syntax-shell\"> -</span>v</span> .</span>\n</span></span></code></pre>\n<h2>Acknowledgments</h2>\n<p>FlashQLA is inspired by <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/fla-org/flash-linear-attention\">Flash Linear Attention</a>, <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/flashinfer-ai/flashinfer\">FlashInfer</a> and <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/tile-ai/tilelang\">TileLang</a>. We thank these communities for the reference implementations.</p>\n<h2>Citation</h2>\n<p>If FlashQLA is useful for your research, please cite:</p>\n<pre><code class=\"language-bibtex\"><span class=\"code-snippet\" data-language=\"Bibtex\"><span class=\"syntax-text syntax-bibtex\"><span class=\"syntax-meta syntax-entry syntax-braces syntax-bibtex\"><span class=\"syntax-keyword syntax-other syntax-entry-type syntax-bibtex\"><span class=\"syntax-punctuation syntax-definition syntax-keyword syntax-bibtex\">@</span>misc</span><span class=\"syntax-punctuation syntax-section syntax-entry syntax-begin syntax-bibtex\">{</span><span class=\"syntax-entity syntax-name syntax-type syntax-entry-key syntax-bibtex\">flashqla2026</span>,\n    <span class=\"syntax-meta syntax-key-assignment syntax-bibtex\"><span class=\"syntax-string syntax-unquoted syntax-key syntax-bibtex\">title</span>  <span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-bibtex\">=</span> <span class=\"syntax-string syntax-quoted syntax-other syntax-braces syntax-bibtex\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-bibtex\">{</span>FlashQLA: Flash Qwen Linear Attention<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-bibtex\">}</span></span></span>,\n    <span class=\"syntax-meta syntax-key-assignment syntax-bibtex\"><span class=\"syntax-string syntax-unquoted syntax-key syntax-bibtex\">author</span> <span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-bibtex\">=</span> <span class=\"syntax-string syntax-quoted syntax-other syntax-braces syntax-bibtex\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-bibtex\">{</span>Zhang, Chengruidong and Lin, Xi and Jiang, Huiqiang and Wang, Zekun and\n              Li, Xiao and Cao, Yizhong and Zhuang, Bohan and Men, Rui and Zhang, Jianwei and\n              Zheng, Bo and Lin, Junyang and Liu, Dayiheng and Zhou, Jingren<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-bibtex\">}</span></span></span>,\n    <span class=\"syntax-meta syntax-key-assignment syntax-bibtex\"><span class=\"syntax-string syntax-unquoted syntax-key syntax-bibtex\">year</span>   <span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-bibtex\">=</span> <span class=\"syntax-string syntax-quoted syntax-other syntax-braces syntax-bibtex\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-bibtex\">{</span>2026<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-bibtex\">}</span></span></span>,\n    <span class=\"syntax-meta syntax-key-assignment syntax-bibtex\"><span class=\"syntax-string syntax-unquoted syntax-key syntax-bibtex\">publisher</span> <span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-bibtex\">=</span> <span class=\"syntax-string syntax-quoted syntax-other syntax-braces syntax-bibtex\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-bibtex\">{</span>GitHub<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-bibtex\">}</span></span></span>,\n    <span class=\"syntax-meta syntax-key-assignment syntax-bibtex\"><span class=\"syntax-string syntax-unquoted syntax-key syntax-bibtex\">howpublished</span> <span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-bibtex\">=</span> <span class=\"syntax-string syntax-quoted syntax-other syntax-braces syntax-bibtex\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-bibtex\">{</span>\\url<span class=\"syntax-punctuation syntax-definition syntax-group syntax-begin syntax-bibtex\">{</span>https://github.com/QwenLM/FlashQLA<span class=\"syntax-punctuation syntax-definition syntax-group syntax-end syntax-bibtex\">}</span><span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-bibtex\">}</span></span>\n</span><span class=\"syntax-punctuation syntax-section syntax-entry syntax-end syntax-bibtex\">}</span></span>\n</span></span></code></pre>\n",
  "content_markdown": "![](https://qianwen-res.oss-cn-beijing.aliyuncs.com/flashqla/flashqla.png)\n\n## Introduction\n\nFollowing the release of [Qwen3-Next](https://qwen.ai/blog?id=qwen3-next), Gated Delta Network (GDN) has become the workhorse attention layer across the Qwen family — from Qwen3-Next-80B-A3B all the way to the subsequent [Qwen3.5](https://qwen.ai/blog?id=qwen3.5) / [Qwen3.6](https://qwen.ai/blog?id=qwen3.6) series. As models scale to **397A17B / 122A10B / 35B / 27B** and context windows stretch beyond 256K, the overhead of the GDN block in end-to-end training and inference has become non-negligible.\n\nToday we officially open-source **FlashQLA**: a high-performance linear attention kernel library built on [TileLang](https://github.com/tile-ai/tilelang). FlashQLA applies **reasonable operator fusion and performance optimization** to the forward and backward passes of GDN Chunked Prefill, achieving **2-3× forward speedup** and **2× backward speedup** over the FLA Triton kernel across multiple scenarios on NVIDIA Hopper. The efficiency gains are particularly pronounced in pretraining scenarios and edge-side agentic inference.\n\nKey highlights of this release:\n\n1. **Gate-driven automatic intra-card context parallelism**. By exploiting the exponential decay property of the GDN gate, FlashQLA automatically enables intra-card CP under TP, long-sequence, and small-head-count settings, improving GPU SM utilization.\n\n2. **Hardware-friendly algebraic reformulation**. We reformulate the forward and backward flows of GDN Chunked Prefill to a certain extent, effectively reducing Tensor Core, CUDA Core, and SFU overhead without sacrificing numerical precision.\n\n3. **TileLang fused warp-specialized kernels**. Rather than following the step-by-step decomposition into independent kernels, nor fusing the entire computation flow into a single kernel, we take CP and backward requirements into account, use TileLang to build several key fused kernels, and manually implement warpgroup specialization to overlap data movement, Tensor Core computation, and CUDA Core computation.\n\nFlashQLA code and benchmarks are open-sourced at [github.com/QwenLM/FlashQLA](https://github.com/QwenLM/FlashQLA).\n\n## Key Problems in FLA GDN Chunked Prefill\n\nLet us first review the forward computation flow of GDN Chunked Prefill, taking chunk index $i$ as an example:\n\n1. $A\\_i \\\\gets \\\\left(I+\\\\mathrm{StrictLower}\\\\left( \\\\mathrm{diag}(\\\\beta\\_i)(\\\\Gamma\\_i \\\\odot K\\_iK\\_i^\\\\intercal) \\\\right)\\\\right)^{-1}$\n2. $\\\\left\\\\{\\\\begin{aligned} W\\_i &\\\\gets A\\_i\\\\mathrm{diag}(\\\\beta\\_i)\\\\mathrm{diag}(\\\\gamma\\_i)K\\_i \\\\\\\\ U\\_i &\\\\gets A\\_i\\\\mathrm{diag}(\\\\beta\\_i)V\\_i \\\\end{aligned}\\\\right.$\n3. $\\\\left\\\\{\\\\begin{aligned} V\\_i’ &\\\\gets U\\_i-W\\_iS\\_i \\\\\\\\ S\\_{i+1} &\\\\gets \\\\gamma\\_{i,C-1}S\\_i + K\\_i^\\\\intercal\\\\mathrm{diag}\\\\left(\\\\frac{\\\\gamma\\_{i,C-1}}{\\\\gamma\\_i}\\\\right)V\\_i’ \\\\end{aligned}\\\\right.$\n4. $O\\_i \\\\gets \\\\mathrm{diag}({\\\\gamma})Q\\_iS\\_i + \\\\left(\\\\mathrm{Lower}(\\\\Gamma\\_i) \\\\odot Q\\_iK\\_i^\\\\intercal\\\\right)V\\_i'$\n\nIgnoring gate preprocessing and CP, each step of this flow corresponds to one kernel [in FLA](https://github.com/fla-org/flash-linear-attention/blob/v0.5.0/fla/ops/gated_delta_rule/chunk.py). This flow has two main efficiency problems:\n\n1. Most of the above are **memory-bound kernels**. The flow repeatedly reads $K$, $V$ and other data, while $W$, $U$, $S$ as intermediate variables must be written to HBM and then read by the next kernel, incurring significant memory access overhead.\n2. The recurrent nature of the SSM state means that the corresponding third step `chunk_gated_delta_rule_fwd_kernel` can only launch `batch_size * num_heads` thread blocks simultaneously, resulting in **low GPU utilization** in small-model, small-batch, or TP scenarios.\n\nThe solutions to these two problems are contradictory. For the first problem, the most intuitive solution is to write a [fully-fused kernel](https://github.com/flashinfer-ai/flashinfer/pull/2276), where all data is accessed only once and all intermediate variables are kept on-chip. When `batch_size * num_heads` is large enough, this is certainly optimal. However, such a solution obviously runs into the second problem: for edge-side inference with small models and `batch_size=1`, or for large-model online deployments with TP where long-sequence inputs from coding agents etc. cannot launch a large enough batch for chunked prefill, the speedup of a fully-fused kernel over the original FLA implementation is limited.\n\nThe earliest solution to the second problem comes from [how DeltaNet does context parallelism](https://yywangcs.notion.site/DeltaNet-2a9fc9f5d8058013a498f34e0b25bd52), which splits a long sequence into multiple sub-sequences, uses $S\\_0=0$ to parallelize the recurrence, and then computes an additional $M$ matrix to correct the recurrent results. This scheme was later optimized to insert a step before the recurrence kernel to compute the $S\\_0$ of each sub-sequence, and has now been [merged into the FLA repository](https://github.com/fla-org/flash-linear-attention/blob/main/fla/ops/cp/README.md). For CP rank $j$, the specific preprocessing flow is:\n\n1. $\\\\left\\\\{\\\\begin{aligned} S^\\\\ast\\_{j,i+1} &\\\\gets \\\\gamma\\_{j,i,C-1}S^\\\\ast\\_{j,i} + K\\_{j,i}^\\\\intercal \\\\mathrm{diag}\\\\left(\\\\frac{\\\\gamma\\_{j,i,C-1}}{\\\\gamma\\_{j,i}}\\\\right) V’\\_{j,i} \\\\\\\\ M\\_{j,i+1} &\\\\gets \\\\left( \\\\gamma\\_{j,i,C-1} I -K\\_{j,i}^\\\\intercal \\\\mathrm{diag}\\\\left(\\\\frac{\\\\gamma\\_{j,i,C-1}}{\\\\gamma\\_{j,i}}\\\\right) W\\_{j,i} \\\\right) M\\_{j,i} \\\\end{aligned}\\\\right.$\n2. $S\\_{j,0} \\\\gets S^\\\\ast\\_{j,0} + M\\_{j,0}S\\_{j-1,0}$\n\nHowever, this CP scheme also has its drawbacks: first, it introduces significant extra computation, with the time complexity of recurrently computing the $M$ matrix even exceeding that of the $S$ matrix; second, it does not work well with fully-fused kernels, because matrix inversion and other steps must be performed before the $S\\_0$ of each sub-sequence can be computed.\n\n## A Balanced Solution: Fusing Kernels While Enabling Intra-Card CP\n\nBased on the two problems above, a compromise solution can be derived: split the GDN Chunked Prefill forward computation into two fused kernels, inserting CP-related preprocessing steps between them. After some transformations and simplifications, the following computation flow is obtained:\n\n1. $A\\_i \\\\gets \\\\left(I+\\\\mathrm{StrictLower}\\\\left( \\\\mathrm{diag}(\\\\beta\\_i)K\\_iK\\_i^\\\\intercal\\\\right)\\\\right)^{-1}$\n2. CP Preprocess\n   - 2.1. $\\\\left\\\\{\\\\begin{aligned} X\\_{j,i} &\\\\gets -\\\\beta\\_{j,i} A\\_{j,i}’^\\\\intercal K\\_{j,i} \\\\\\\\ Y\\_{j,i} &\\\\gets \\\\gamma\\_{j,i,C-1} K\\_{j,i} S^\\\\ast\\_{j,i} - \\\\mathrm{diag}\\\\left(\\\\frac{\\\\gamma\\_{j,i,C-1}}{\\\\gamma\\_{j,i}}\\\\right) V\\_{j,i} \\\\\\\\ Z\\_{j,i} &\\\\gets K\\_{j,i} M\\_{j,i} \\\\\\\\ S^\\\\ast\\_{j,i+1} &\\\\gets \\\\gamma\\_{j,i,C-1}S^\\\\ast\\_{j,i} + X\\_{j,i}^\\\\intercal Y\\_{j,i} \\\\\\\\ M\\_{j,i+1} &\\\\gets \\\\gamma\\_{j,i,C-1} \\\\left( M\\_{j,i} + X\\_{j,i}^\\\\intercal Z\\_{j,i} \\\\right) \\\\end{aligned}\\\\right.$\n   - 2.2. $S\\_{j,0} \\\\gets S^\\\\ast\\_{j,0} + M\\_{j,0}S\\_{j-1,0}$\n3. $\\\\left\\\\{\\\\begin{aligned} V\\_i^\\\\Delta &\\\\gets V\\_i - \\\\mathrm{diag}(\\\\gamma\\_i)K\\_iS\\_i \\\\\\\\ V\\_i’ &\\\\gets \\\\left(\\\\Gamma\\_i \\\\odot A\\_i\\\\right)\\\\mathrm{diag}(\\\\beta\\_i)V\\_i^\\\\Delta \\\\\\\\ S\\_{i+1} &\\\\gets \\\\gamma\\_{i,C-1}S\\_i + K\\_i^\\\\intercal\\\\mathrm{diag}\\\\left(\\\\frac{\\\\gamma\\_{i,C-1}}{\\\\gamma\\_i}\\\\right)V\\_i’ \\\\\\\\ O\\_i &\\\\gets \\\\mathrm{diag}({\\\\gamma\\_i})Q\\_iS\\_i + \\\\left(\\\\mathrm{Lower}(\\\\Gamma\\_i) \\\\odot Q\\_iK\\_i^\\\\intercal\\\\right)V\\_i’ \\\\end{aligned}\\\\right.$\n\nWe also designed a simple mathematical model to automatically determine the degree of parallelism. Let $N$ be the number of chunks in a sequence and $L$ be the number of chunks per CP rank. It is easy to see that the runtime of steps 2.1 and 3 is proportional to $L$, while the runtime of step 2.2 is proportional to $\\\\frac NL$; therefore we can choose $L=\\\\lambda \\\\sqrt N$ to minimize total time, where $\\\\lambda$ is a coefficient composed of `batch_size`, `num_heads`, and other hyperparameters.\n\nIn production, intra-card CP is not always needed. Following the original FLA implementation, step 3 can also increase parallelism by 2-4× via splitting `v_head_dim`, at the cost of redundant memory access to Q and K. Based on measured data, we enable CP only when `batch_size * num_heads <= 40` or `batch_size * num_heads <= 56 && seq_len >= 8192`.\n\n## Further Optimization via Gate Decay\n\nRevisiting the GDN recurrence:\n\n$$S\\_{i+1} = \\\\alpha\\_iS\\_i(I-\\\\beta\\_ik\\_ik\\_i^\\\\intercal)+\\\\beta\\_iv\\_ik\\_i^\\\\intercal$$\n\nFor $\\\\alpha\\_i\\\\in(0,1)$, the influence of each $S\\_i$ on subsequent states decays exponentially, giving it a sliding-window property. For a sufficiently long window size of $W$, starting computation from $S\\_{i-W}=0$ can obtain the accurate $S\\_i$, without the need to start from $S\\_0$. We refer to this process as warmup. On real data, we find that $\\\\alpha\\_i$ is not constantly 1 on 60–80% of linear attention heads, and **6–8 chunks of warmup** are sufficient to drive the $S\\_i$ error below the noise floor.\n\nTherefore, for linear attention heads with the sliding-window property, we can design a lighter CP preprocessing flow that discards the computation of the correction term $M$ and directly obtains an equally accurate sub-sequence $S\\_0$ through warmup:\n\n|    | C0 | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 | C9 | C10 | C11 | C12 |\n| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | --- | --- | --- |\n| R1 | O  | O  | O  | O  | O  |    |    |    |    |    |     |     |     |\n| R2 |    |    |    | X  | X  | O  | O  | O  | O  |    |     |     |     |\n| R3 |    |    |    |    |    |    |    | X  | X  | O  | O   | O   | O   |\n\n`X` denotes warming up with a zero initial state until the gate has decayed sufficiently, then writing out the $S\\_0$ of that CP rank; `O` denotes subsequent normal recurrent computation. The warmup length for each rank is determined by an independent kernel that collects gate statistics, and the cost of this step is negligible.\n\n## TileLang Warp-Specialized Kernel\n\nWe implement FlashQLA in [TileLang](https://github.com/tile-ai/tilelang) using a warpgroup-specialization pattern: one producer warpgroup and three consumer warpgroups reside in the same SM, exchange data through shared memory, and synchronize via mbarriers.\n\n### Forward\n\nIn the forward pass, the three consumer warp groups compute $V’$, $S$, and $O$ respectively, overlapping computation and memory traffic through a ping-pong structure.\n\n|           | WG3       | WG2                                         | WG1                                  | WG0                                           |                                                                                                        |                                  |\n| --------- | --------- | ------------------------------------------- | ------------------------------------ | --------------------------------------------- | ------------------------------------------------------------------------------------------------------ | -------------------------------- |\n| **BAR 0** | **LD**$Q$ | **LD**$\\\\gamma$                             | **ST**$O$                            | $\\\\gamma, \\\\gamma\\_{C-1}\\\\gamma^{-1}$         | **TC**$P = Q K^\\\\intercal$                                                                             |                                  |\n| **BAR 1** | **LD**$K$ | **LD**$\\\\beta$                              | **ST**$S\\_i$                         | **TC**$U = K S\\_i$                            | $\\\\Gamma = L(\\\\gamma I \\\\gamma^{-1})$ $A\\_\\\\gamma = \\\\Gamma \\\\odot A$ $P\\_\\\\gamma = s\\\\Gamma \\\\odot P$ | $S\\_{i+1} = \\\\gamma\\_{C-1} S\\_i$ |\n| **BAR 2** | **LD**$V$ |                                             | $W = \\\\beta (V - \\\\gamma U)$         | **TC**$O = Q S\\_i$                            |                                                                                                        |                                  |\n| **BAR 3** | **LD**$A$ |                                             | **TC**$V^\\\\Delta = A\\_\\\\gamma W$     | $O = s\\\\gamma O$                              |                                                                                                        |                                  |\n| **BAR 4** |           | $V’ = \\\\gamma\\_{C-1}\\\\gamma^{-1} V^\\\\Delta$ | **TC**$O = O + P\\_\\\\gamma V^\\\\Delta$ |                                               |                                                                                                        |                                  |\n| **BAR 5** |           |                                             |                                      | **TC**$S\\_{i+1} = S\\_{i+1} + K^\\\\intercal V'$ |                                                                                                        |                                  |\n\nNotes:\n\n- $S$ output per chunk is for debugging only; normally only $O$ and the last chunk’s $S$ are output.\n\n### CP Preprocessing\n\nAs mentioned earlier, the CP preprocessing splits into two cases: the original approach (computing both $M$ and $S$) and the sliding-window approach (computing only $S$). We designed a single fused kernel that handles both:\n\n|           | WG3       | WG2                                                      | WG1                                                      | WG0                                                                       |                                              |                                  |\n| --------- | --------- | -------------------------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------- | -------------------------------------------- | -------------------------------- |\n| **BAR 0** | **LD**$K$ | **LD**$\\\\gamma$                                          |                                                          | $\\\\gamma\\_{C-1}\\\\gamma^{-1}$                                              | **TC**$X = A^\\\\intercal K$                   |                                  |\n| **BAR 1** | **LD**$V$ | **LD**$\\\\beta$                                           | **ST**$S\\_i$                                             | **TC**$U = K S\\_i$ $Y = -\\\\gamma\\_{C-1}\\\\gamma^{-1} V + \\\\gamma\\_{C-1} U$ | $X = -\\\\beta X$                              | $S\\_{i+1} = \\\\gamma\\_{C-1} S\\_i$ |\n| **BAR 2** | **LD**$A$ |                                                          | $\\\\gamma^\\\\pi = \\\\gamma^\\\\pi \\\\gamma\\_{C-1}$             | $\\\\gamma^\\\\pi = \\\\gamma^\\\\pi \\\\gamma\\_{C-1}$                              | **TC**$S\\_{i+1} = S\\_{i+1} + X^\\\\intercal Y$ |                                  |\n| **BAR 3** |           | **TC**$Z^L = K M^L$ **TC**$M^L = M^L + X^\\\\intercal Z^L$ | **TC**$Z^R = K M^R$ **TC**$M^R = M^R + X^\\\\intercal Z^R$ |                                                                           |                                              |                                  |\n\nNotes:\n\n- The last two steps of WG1 and WG2 correspond to the $M$ matrix computation and are triggered only when required.\n- $S$ is output per chunk only during backward recomputation.\n\n### Backward\n\nIn the backward pass, we reuse the CP preprocessing kernel from the previous section to recompute the $S$ matrix, then fuse `bwd_dv`, `bwd_dhu`, `bwd_dqkwg`, `bwd_wy` into a single kernel with corresponding algebraic optimizations. Because of on-chip resource constraints, the backward kernel does not use multi-stage pipelining; instead it relies on the long compute chain to hide memory traffic. The full schedule is available in the [FlashQLA repo](https://github.com/QwenLM/FlashQLA).\n\n|            | WG3        | WG2                                                                                                      | WG1                                                                       | WG0                                                                                                                                                                                              |                                                   |\n| ---------- | ---------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------- |\n| **BAR 00** | **ST**$dK$ |                                                                                                          |                                                                           | **TC** $P=QK^\\\\intercal$                                                                                                                                                                         | $\\\\gamma, \\\\gamma\\_{C-1}\\\\gamma^{-1}$             |\n| **BAR 01** |            | **TC** $dV’=KdS\\_{i+1}$ $dV’=\\\\gamma\\_{C-1}\\\\gamma^{-1}dV'$                                              | $\\\\Gamma=\\\\gamma I \\\\gamma^{-1}$ $P\\_\\\\gamma=sL(\\\\Gamma)\\\\odot P$         | $dS\\_i = \\\\gamma\\_{C-1} dS\\_{i+1}$                                                                                                                                                               |                                                   |\n| **BAR 02** |            | **TC** $dV’=dV’+P\\_\\\\gamma^\\\\intercal dO$                                                                | $A\\_\\\\beta = A \\\\beta$ $A\\_\\\\gamma = \\\\Gamma \\\\odot A\\_\\\\beta$            |                                                                                                                                                                                                  |                                                   |\n| **BAR 03** |            |                                                                                                          | **TC**$U=KS\\_i$                                                           |                                                                                                                                                                                                  |                                                   |\n| **BAR 04** |            | **TC** $dV=A\\_\\\\gamma^\\\\intercal dV’$                                                                    | $W=V-\\\\gamma U$                                                           | $d\\\\gamma\\_{C-1}=\\\\sum S\\_i \\\\odot dS\\_{i+1}$                                                                                                                                                    |                                                   |\n| **BAR 05** | **ST**$dV$ | **LD**$V$                                                                                                | $dV\\_\\\\gamma = -\\\\gamma dV$ $d\\\\gamma = \\\\sum\\_i dV\\_\\\\gamma \\\\odot U$    | **TC** $dA\\_\\\\gamma = dV’W^T$ **TC** $V’=A\\_\\\\gamma W$                                                                                                                                           |                                                   |\n| **BAR 06** |            |                                                                                                          | **TC** $dP\\_\\\\gamma = dO V’^\\\\intercal$                                   |                                                                                                                                                                                                  |                                                   |\n| **BAR 07** |            | **LD**$K$                                                                                                | **TC** $dK=V’dS\\_{i+1}^\\\\intercal$                                        | $dA\\_\\\\beta = \\\\Gamma \\\\odot dA\\_\\\\gamma$ $d\\\\gamma = d\\\\gamma + \\\\sum\\_i dP\\_\\\\gamma \\\\odot L(P)$ $d\\\\gamma = d\\\\gamma - \\\\sum\\_j dP\\_\\\\gamma \\\\odot L(P)$ $dP = sL(\\\\Gamma)\\\\odot dP\\_\\\\gamma$ |                                                   |\n| **BAR 08** |            | $dK=\\\\gamma\\_{C-1}\\\\gamma^{-1}dK$ $d\\\\gamma\\_{C-1}=\\\\sum K \\\\odot dK$ $d\\\\gamma = -\\\\sum\\_i K \\\\odot dK$ | **TC** $dQ=dOS\\_i^T$                                                      |                                                                                                                                                                                                  |                                                   |\n| **BAR 09** |            | **LD**$Q$                                                                                                | **TC** $dK=dK+dV\\_\\\\gamma S\\_i^\\\\intercal$                                | $dQ=s\\\\gamma dQ$ $d\\\\gamma = \\\\sum Q \\\\odot dQ$                                                                                                                                                  |                                                   |\n| **BAR 10** |            | **LD**$S$                                                                                                |                                                                           | **TC** $dQ=dQ+dPK$                                                                                                                                                                               |                                                   |\n| **BAR 11** | **ST**$dQ$ |                                                                                                          |                                                                           | $d\\\\gamma = d\\\\gamma + \\\\sum\\_i dA\\_\\\\beta \\\\odot A \\\\beta$ $d\\\\gamma = d\\\\gamma - \\\\sum\\_j dA\\_\\\\beta \\\\odot A \\\\beta$ $d\\\\beta = \\\\sum\\_j dA\\_\\\\beta \\\\odot A$ $dA=dA\\_\\\\beta \\\\beta$          | **TC** $dS\\_i = dS\\_i + K^\\\\intercal dV\\_\\\\gamma$ |\n| **BAR 12** |            | **TC** $dK=dK+dP^\\\\intercal Q$                                                                           |                                                                           |                                                                                                                                                                                                  |                                                   |\n| **BAR 13** |            |                                                                                                          | **TC** $dA = -A^\\\\intercal dA A^\\\\intercal$ **TC** $A\\_T = KK^\\\\intercal$ | $dO\\_\\\\gamma=s\\\\gamma dO$                                                                                                                                                                        |                                                   |\n| **BAR 14** |            | **LD**$dO$ **LD**$A$                                                                                     |                                                                           | $d\\\\beta = d\\\\beta + \\\\sum\\_i dA \\\\odot A\\_T$ $dA\\_T = \\\\beta dA$ $dA\\_S = dA\\_T + dA\\_T^\\\\intercal$                                                                                             | **TC** $dS\\_0 = dS\\_0 + Q^\\\\intercal dO\\_\\\\gamma$ |\n| **BAR 15** |            | **TC** $dK=dK+dA\\_S K$                                                                                   |                                                                           |                                                                                                                                                                                                  |                                                   |\n\n## Benchmark\n\nWe benchmarked FlashQLA against the FLA Triton and FlashInfer baseline (FLA 0.5.0, Triton 3.5.1, FlashInfer 0.6.9, TileLang 0.1.8) on the head configurations used by the Qwen3.5 / Qwen3.6 family — $h\\_v \\\\in {64, 48, 32, 24, 16, 8}$, corresponding to TP1 through TP8.\n\n![FlashQLA vs FLA and FlashInfer on H200](https://qianwen-res.oss-cn-beijing.aliyuncs.com/flashqla/fwd_bwd_latency_comparison.png)\n\nSpecifically, the forward (FWD) benchmarks measure single-kernel latency for different models and TP settings under varying batch lengths, while the backward (BWD) benchmarks examine the relationship between total token count within a batch and latency during a single update step.\n\nSelected H200 single-layer forward results:\n\n| Model / TP    | Seqlen     | $h\\_{qk}$ | $h\\_v$ | FlashQLA | FlashInfer | FLA     | vs FLA | vs FI |\n| ------------- | ---------- | --------- | ------ | -------- | ---------- | ------- | ------ | ----- |\n| 397B/122B TP8 | 1x32768    | 2         | 8      | 0.310ms  | 1.653ms    | 0.913ms | 2.95×  | 5.33× |\n| 397B/122B TP8 | 1x16384    | 2         | 8      | 0.184ms  | 0.833ms    | 0.465ms | 2.53×  | 4.53× |\n| 397B/122B TP8 | 24576+8192 | 2         | 8      | 0.302ms  | 1.242ms    | 0.767ms | 2.54×  | 4.11× |\n| 397B/122B TP4 | 1x32768    | 4         | 16     | 0.486ms  | 1.654ms    | 1.250ms | 2.57×  | 3.40× |\n| 397B/122B TP4 | 1x16384    | 4         | 16     | 0.292ms  | 0.832ms    | 0.623ms | 2.13×  | 2.85× |\n| 27B TP2       | 1x32768    | 8         | 24     | 0.659ms  | 1.616ms    | 1.564ms | 2.37×  | 2.45× |\n| 2B/0.8B TP1   | 1x32768    | 16        | 16     | 0.493ms  | 1.640ms    | 1.285ms | 2.60×  | 3.33× |\n| Sym h32       | 1x32768    | 32        | 32     | 0.877ms  | 1.554ms    | 1.952ms | 2.23×  | 1.77× |\n\nThe speedup grows with TP degree because FlashQLA improves SM utilization via intra-card AutoCP in the exact regimes — TP sharding and small head number — where the baseline leaves SMs idle.\n\n## Usage\n\nFlashQLA exposes both a high-level API matching FLA’s signature and low-level fwd/bwd entry points:\n\n```python\nimport torch\nfrom qla import chunk_gated_delta_rule\n\no, final_state = chunk_gated_delta_rule(\n    q=q,                            # [B, T, H_q, K]\n    k=k,                            # [B, T, H_q, K]\n    v=v,                            # [B, T, H_v, V]\n    g=g,                            # [B, T, H_v]\n    beta=beta,                      # [B, T, H_v]\n    scale=scale,\n    initial_state=initial_state,    # optional, [B, H_v, K, V]\n    output_final_state=True,\n    cu_seqlens=cu_seqlens,          # optional, varlen support\n)\n```\n\nRequirements: SM90, CUDA 12.8+, PyTorch 2.8+. Install:\n\n```bash\ngit clone https://github.com/QwenLM/FlashQLA.git\ncd FlashQLA && pip install -v .\n```\n\n## Acknowledgments\n\nFlashQLA is inspired by [Flash Linear Attention](https://github.com/fla-org/flash-linear-attention), [FlashInfer](https://github.com/flashinfer-ai/flashinfer) and [TileLang](https://github.com/tile-ai/tilelang). We thank these communities for the reference implementations.\n\n## Citation\n\nIf FlashQLA is useful for your research, please cite:\n\n```bibtex\n@misc{flashqla2026,\n    title  = {FlashQLA: Flash Qwen Linear Attention},\n    author = {Zhang, Chengruidong and Lin, Xi and Jiang, Huiqiang and Wang, Zekun and\n              Li, Xiao and Cao, Yizhong and Zhuang, Bohan and Men, Rui and Zhang, Jianwei and\n              Zheng, Bo and Lin, Junyang and Liu, Dayiheng and Zhou, Jingren},\n    year   = {2026},\n    publisher = {GitHub},\n    howpublished = {\\url{https://github.com/QwenLM/FlashQLA}}\n}\n```\n",
  "dateCreated": "2026-10-19T01:26:53.998049939+00:00",
  "date_created": "2026-04-28T02:00:00+00:00",
  "date_modified": null,
  "date_published": "2026-04-28T02:00:00+00:00",
  "description": "Introduction Following the release of Qwen3-Next, Gated Delta Network (GDN) has become the workhorse attention layer across the Qwen family — from Qwen3-Next-80B-A3B all the way to the subsequent Qwen3.5 / Qwen3.6 series. As models scale…",
  "external_url": "https://qwen.ai/blog?id=flashqla",
  "git": {
    "commit": "ebb0941c5c06a2ab2377342d607535262a3e969e",
    "path": "items/qwen-ai/2026/04/2026-04-28-flashqla-cp-bwd-friendly-fused-linear-attention-kernels-for.md",
    "permalink": "https://github.com/aymericbeaumet/aggr-instance/blob/ebb0941c5c06a2ab2377342d607535262a3e969e/items/qwen-ai/2026/04/2026-04-28-flashqla-cp-bwd-friendly-fused-linear-attention-kernels-for.md"
  },
  "id": "urn:aggr:item:ec3446ada7c39c8eaeca9a50472afbae8596466a",
  "isBasedOn": {
    "@id": "https://qwen.ai/blog?id=flashqla"
  },
  "mainEntity": {
    "@id": "https://qwen.ai/blog?id=flashqla",
    "@type": "CreativeWork",
    "archivedAt": {
      "@id": "https://aggr.aymericbeaumet.com/items/qwen-ai/2026-04-28-flashqla-cp-bwd-friendly-fused-linear-attention-kernels-for/#webpage"
    },
    "author": [
      {
        "@type": "Person",
        "name": "QwenTeam"
      }
    ],
    "datePublished": "2026-04-28T02:00:00+00:00",
    "headline": "FlashQLA: CP-/Bwd-Friendly Fused Linear Attention Kernels for GDN",
    "image": {
      "@type": "ImageObject",
      "caption": null,
      "height": 90,
      "url": "https://img.alicdn.com/imgextra/i2/O1CN01IUOCqg1RG48rlBwP7_!!6000000002083-2-tps-1590-954.png",
      "width": 160
    },
    "timeRequired": "PT11M",
    "url": "https://qwen.ai/blog?id=flashqla",
    "wordCount": 2398
  },
  "name": "Archived snapshot: FlashQLA: CP-/Bwd-Friendly Fused Linear Attention Kernels for GDN",
  "preview": {
    "alt": null,
    "color": null,
    "height": 90,
    "placeholder": {
      "data_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=",
      "hash": ""
    },
    "url": "https://img.alicdn.com/imgextra/i2/O1CN01IUOCqg1RG48rlBwP7_!!6000000002083-2-tps-1590-954.png",
    "width": 160
  },
  "reading_minutes": 11,
  "replicated_at": null,
  "source": "qwen-ai",
  "source_name": "Qwen",
  "summary": null,
  "tags": [
    "open-source"
  ],
  "temporalCoverage": "2026-10-19T01:26:53.998049939+00:00",
  "title": "FlashQLA: CP-/Bwd-Friendly Fused Linear Attention Kernels for GDN",
  "url": "https://aggr.aymericbeaumet.com/items/qwen-ai/2026-04-28-flashqla-cp-bwd-friendly-fused-linear-attention-kernels-for/",
  "word_count": 2398
}