Skip to content
Merged
Show file tree
Hide file tree
Changes from 85 commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
0f6f8ce
Add GDN2
yzhangcs Jul 4, 2025
3720f19
Keep gate in fp32
yzhangcs Jul 6, 2025
0307e92
Keep l2norm k in fp32
yzhangcs Jul 6, 2025
6927239
[Norm] Unify eps behaviors across kernels
yzhangcs Jul 6, 2025
5e8e1df
[GDN2] Add naive chunk impls
yzhangcs Jul 8, 2025
aea459d
Add naive impls
yzhangcs Jul 8, 2025
418694c
Minor fix
yzhangcs Jul 8, 2025
ca72ca6
Add tests for naive
yzhangcs Jul 8, 2025
8010348
[GDN2] fwd done
yzhangcs Jul 8, 2025
3637c18
Merge branch 'main' into gdn2
yzhangcs Jul 8, 2025
52049ae
Fix inplace mod
yzhangcs Jul 9, 2025
f2417a8
Update tests
yzhangcs Jul 9, 2025
56397fd
[GDN2] dv/dh done
yzhangcs Jul 9, 2025
6ab853d
[GDN2] dq done
yzhangcs Jul 9, 2025
dcc683f
[GDN2] dk/dg/db done
yzhangcs Jul 10, 2025
2ace7b8
Merge branch 'main' into gdn2
yzhangcs Jul 10, 2025
45d6354
Merge branch 'main' into gdn2
yzhangcs Jul 10, 2025
31be5cb
[GDN2] Compute qg/kg first
yzhangcs Jul 10, 2025
40b36f9
Save Aqk
yzhangcs Jul 10, 2025
7b71555
Merge branch 'main' into gdn2
yzhangcs Jul 11, 2025
99838ac
Merge branch 'main' into gdn2
yzhangcs Jul 11, 2025
98a2cd8
Merge remote-tracking branch 'origin/main' into gdn2
yzhangcs Jul 11, 2025
3ead289
Fix dk overflows
yzhangcs Jul 11, 2025
dcc8e89
Merge remote-tracking branch 'origin/main' into gdn2
yzhangcs Jul 14, 2025
941e39b
Separated qk l2norm
yzhangcs Jul 14, 2025
5248b29
Merge remote-tracking branch 'origin/main' into gdn2
yzhangcs Jul 23, 2025
4fd1e57
Merge branch 'main' into gdn2
zhiyuan1i Jul 25, 2025
5deb9e3
Merge branch 'main' into gdn2
zhiyuan1i Jul 27, 2025
2c50777
Merge remote-tracking branch 'origin/main' into gdn2
yzhangcs Jul 30, 2025
7de5dca
Merge remote-tracking branch 'origin/main' into gdn2
Jul 30, 2025
7404ac1
Update GDN2 gate
yzhangcs Aug 5, 2025
9495501
Merge remote-tracking branch 'origin/main' into gdn2
yzhangcs Aug 14, 2025
b928910
Merge branch 'main' into gdn2
zhiyuan1i Aug 20, 2025
bc6a1b7
Merge branch 'main' into gdn2
zhiyuan1i Aug 20, 2025
6b54742
Merge remote-tracking branch 'origin/main' into gdn2
yzhangcs Aug 26, 2025
80696e4
Merge remote-tracking branch 'origin/main' into gdn2
yzhangcs Aug 28, 2025
ae38cd8
Merge remote-tracking branch 'origin/main' into gdn2
yzhangcs Aug 28, 2025
4342647
Merge remote-tracking branch 'origin/main' into gdn2
yzhangcs Aug 31, 2025
1c482b7
Merge remote-tracking branch 'origin/main' into gdn2
yzhangcs Sep 2, 2025
c541794
Avoid potential overflows
yzhangcs Sep 2, 2025
671a7ea
Merge remote-tracking branch 'origin/main' into gdn2
yzhangcs Sep 4, 2025
973266b
Merge remote-tracking branch 'origin/main' into gdn2
yzhangcs Sep 4, 2025
224f9de
Merge remote-tracking branch 'origin/main' into gdn2
yzhangcs Sep 5, 2025
2236817
Merge remote-tracking branch 'origin/main' into gdn2
yzhangcs Sep 6, 2025
3314a79
[GDN2] Update layer impls & Add tests
yzhangcs Sep 6, 2025
4485c0e
Delete unused fns
yzhangcs Sep 6, 2025
11ab983
[GDN] Deal with init on meta device
yzhangcs Sep 7, 2025
71c9051
[README] Add Qwen3-Next news
yzhangcs Sep 9, 2025
003cf3e
[Deps] Upgrade to transformers 4.56.x (#587)
zhiyuan1i Sep 9, 2025
7287fce
[Build] Split package distribution[skip test] (#588)
zhiyuan1i Sep 10, 2025
e23db7a
[Build] Do not import all names
yzhangcs Sep 10, 2025
07ea966
Bump fla to `v0.3.2`
yzhangcs Sep 10, 2025
0bfa136
fetch to main branch
zhiyuan1i Sep 11, 2025
10fba32
[GDN2] Add comprehensive TMA support to chunk kernels
zhiyuan1i Sep 11, 2025
2a97b66
Merge branch 'main' into gdn2
zhiyuan1i Sep 12, 2025
d98eebd
[GDN2] Use fused_gdn2_gate function for gate computation
zhiyuan1i Sep 13, 2025
be68f24
Fetch to main branch
zhiyuan1i Sep 13, 2025
e9b6eee
revert! [GDN2] Add comprehensive TMA support to chunk kernels
zhiyuan1i Sep 13, 2025
800d20c
[GDN2] Fix naive impl bugs
yzhangcs Sep 16, 2025
ba7971b
Merge branch 'main' into HEAD
zhiyuan1i Sep 20, 2025
0550e59
add cache for triton>=3.4.0
zhiyuan1i Sep 20, 2025
f96d22a
fixup! Merge branch 'main' into HEAD
zhiyuan1i Sep 22, 2025
6989914
fix potential boundary in conv
zhiyuan1i Sep 23, 2025
dea5c64
fix [CUDA]: invalid argument
zhiyuan1i Sep 23, 2025
ddaa1c4
support new a shape
zhiyuan1i Sep 24, 2025
bb54da0
support bias
zhiyuan1i Sep 25, 2025
ecb6554
force output to fp32
zhiyuan1i Sep 26, 2025
ce6da61
Merge branch 'main' into gdn2
zhiyuan1i Oct 15, 2025
37f454f
clean
zhiyuan1i Oct 17, 2025
65004ee
fix deltarule
zhiyuan1i Oct 17, 2025
b58a7dc
fix tma
zhiyuan1i Oct 20, 2025
ff7bb72
Merge remote-tracking branch 'origin/main' into gdn2
yzhangcs Oct 20, 2025
8bf7d25
fixup! fix tma
zhiyuan1i Oct 20, 2025
aa8bb0c
Merge remote-tracking branch 'origin/main' into gdn2
yzhangcs Oct 20, 2025
11dca3a
Merge remote-tracking branch 'origin/main' into gdn2
yzhangcs Oct 20, 2025
6215fd2
Update benchmark_gdn2.py
yzhangcs Oct 21, 2025
9064809
Refactor GDN2 impls
yzhangcs Oct 22, 2025
7c3c8f3
Merge remote-tracking branch 'origin/main' into gdn2-optim
yzhangcs Oct 24, 2025
0b45606
Minor fix
yzhangcs Oct 24, 2025
0da4bb0
Merge remote-tracking branch 'origin/main' into gdn2-optim
yzhangcs Oct 24, 2025
0b11984
rename
yzhangcs Oct 24, 2025
669ce78
Merge remote-tracking branch 'origin/main' into gdn2-optim
yzhangcs Oct 24, 2025
5774ff8
Update GDN
yzhangcs Oct 24, 2025
2b65e00
Minor fix
yzhangcs Oct 24, 2025
26fe007
Use o gate by default
yzhangcs Oct 24, 2025
00b1783
enhance bmk
zhiyuan1i Oct 27, 2025
082d92b
update doc strings
zhiyuan1i Oct 27, 2025
eccea7e
fix lint
zhiyuan1i Oct 27, 2025
5b8ed72
fix type string
zhiyuan1i Oct 27, 2025
0511a50
KimiDeltaAttention
zhiyuan1i Oct 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions benchmarks/ops/benchmark_kda.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# -*- coding: utf-8 -*-

import os

import torch
import triton
from flash_attn import flash_attn_func
from torch.nn import functional as F

from fla.ops.comba import chunk_comba
from fla.ops.gated_delta_rule import chunk_gated_delta_rule
from fla.ops.generalized_delta_rule import chunk_dplr_delta_rule
from fla.ops.kda import chunk_kda


@triton.testing.perf_report(
triton.testing.Benchmark(
# argument names to use as an x-axis for the plot
x_names=['T'],
# different possible values for `x_name`
x_vals=[256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536],
# argument name whose value corresponds to a different line in the plot
line_arg='provider',
# possible values for `line_arg``
line_vals=['gdn', 'comba', 'kda', 'dplr'],
# label name for the lines
line_names=['gdn', 'comba', 'kda', 'dplr'],
# line styles
styles=[('blue', '-'), ('red', '-.'), ('green', '-'), ('orange', '-.'),
('purple', '-'), ('brown', '-.'), ('pink', '-'), ('gray', '-.')],
ylabel="Execution Time (ms)", # label name for the y-axis
# name for the plot. Used also as a file name for saving the plot.
plot_name="Performance",
args={},
)
)
def benchmark(T, provider):
from fla.utils import device
dtype = torch.bfloat16
B, H, D = 1, 16, 128

# Set TMA environment variable based on provider
original_tma_env = os.environ.get('FLA_USE_TMA', '0')

if provider.endswith('_no_tma'):
os.environ['FLA_USE_TMA'] = '0'
provider_base = provider.replace('_no_tma', '')
else:
os.environ['FLA_USE_TMA'] = '1'
provider_base = provider
Comment on lines +42 to +50

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Wrap environment variable restoration in try-finally to ensure cleanup.

The TMA environment variable restoration at line 142 won't execute if an exception occurs during benchmarking. This could leave the environment in an inconsistent state for subsequent runs.

Apply this diff to ensure proper cleanup:

     quantiles = [0.5, 0.2, 0.8]
     results = 0, 0, 0
 
-    do = torch.randn(B, T, H, D, dtype=dtype, device=device)
-    if provider_base == 'gdn':
+    try:
+        do = torch.randn(B, T, H, D, dtype=dtype, device=device)
+        if provider_base == 'gdn':
+            ...
+        elif provider_base == 'dplr':
+            ...
+    finally:
+        # Restore original TMA environment variable
+        os.environ['FLA_USE_TMA'] = original_tma_env
+    
-    # Restore original TMA environment variable
-    os.environ['FLA_USE_TMA'] = original_tma_env
     return results

Also applies to: 141-142

🤖 Prompt for AI Agents
In benchmarks/ops/benchmark_kda.py around lines 42 to 50, the code sets
FLA_USE_TMA based on the provider but does not guarantee restoration if an
exception occurs during benchmarking; wrap the benchmarking logic that follows
these lines in a try...finally block and move the restoration of
os.environ['FLA_USE_TMA'] (using the saved original_tma_env) into the finally so
the environment variable is always reset regardless of errors.


quantiles = [0.5, 0.2, 0.8]
results = 0, 0, 0

do = torch.randn(B, T, H, D, dtype=dtype, device=device)
if provider_base == 'gdn':
q = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
k = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
v = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
g = F.logsigmoid(torch.randn(B, T, H, dtype=dtype, device=device)).requires_grad_(True)
beta = torch.randn(B, T, H, dtype=dtype, device=device).sigmoid().requires_grad_(True)
results = triton.testing.do_bench(
lambda: chunk_gated_delta_rule(
q=q,
k=k,
v=v,
g=g,
beta=beta,
use_qk_l2norm_in_kernel=True,
)[0].backward(do),
quantiles=quantiles
)

elif provider_base == 'attn':
q = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
k = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
v = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
results = triton.testing.do_bench(
lambda: flash_attn_func(
q=q,
k=k,
v=v,
).backward(do),
quantiles=quantiles
)
if provider_base == 'comba':
q = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
k = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
p = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
v = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
g = F.logsigmoid(torch.randn(B, T, H, dtype=torch.float, device=device)).requires_grad_(True)
Comment thread
zhiyuan1i marked this conversation as resolved.
beta = torch.randn(B, T, H, dtype=dtype, device=device).sigmoid().requires_grad_(True)
results = triton.testing.do_bench(
lambda: chunk_comba(
q=q,
k=k,
p=p,
v=v,
g=g,
beta=beta,
use_qk_l2norm_in_kernel=True,
)[0].backward(do),
quantiles=quantiles
)
if provider_base == 'kda':
q = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
k = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
p = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
Comment thread
zhiyuan1i marked this conversation as resolved.
Outdated
v = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
g = F.logsigmoid(torch.randn(B, T, H, D, dtype=dtype, device=device)).requires_grad_(True)
beta = torch.randn(B, T, H, dtype=dtype, device=device).sigmoid().requires_grad_(True)
results = triton.testing.do_bench(
lambda: chunk_kda(
q=q,
k=k,
v=v,
g=g,
beta=beta,
use_qk_l2norm_in_kernel=True,
)[0].backward(do),
quantiles=quantiles
)
Comment on lines +104 to +120

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix critical shape mismatch for g tensor in KDA provider.

Line 108 creates g with shape [B, T, H, D], but chunk_kda expects g to have shape [B, T, H] according to its signature. This mismatch will cause runtime errors or incorrect computation.

Apply this diff to fix the shape:

-        g = F.logsigmoid(torch.randn(B, T, H, D, dtype=dtype, device=device)).requires_grad_(True)
+        g = F.logsigmoid(torch.randn(B, T, H, dtype=dtype, device=device)).requires_grad_(True)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
elif provider_base == 'kda':
q = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
k = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
v = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
g = F.logsigmoid(torch.randn(B, T, H, D, dtype=dtype, device=device)).requires_grad_(True)
beta = torch.randn(B, T, H, dtype=dtype, device=device).sigmoid().requires_grad_(True)
results = triton.testing.do_bench(
lambda: chunk_kda(
q=q,
k=k,
v=v,
g=g,
beta=beta,
use_qk_l2norm_in_kernel=True,
)[0].backward(do),
quantiles=quantiles
)
elif provider_base == 'kda':
q = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
k = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
v = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
g = F.logsigmoid(torch.randn(B, T, H, dtype=dtype, device=device)).requires_grad_(True)
beta = torch.randn(B, T, H, dtype=dtype, device=device).sigmoid().requires_grad_(True)
results = triton.testing.do_bench(
lambda: chunk_kda(
q=q,
k=k,
v=v,
g=g,
beta=beta,
use_qk_l2norm_in_kernel=True,
)[0].backward(do),
quantiles=quantiles
)
🤖 Prompt for AI Agents
In benchmarks/ops/benchmark_kda.py around lines 104 to 120, the tensor g is
created with shape [B, T, H, D] but chunk_kda expects g of shape [B, T, H];
change the g initializer to create a tensor of shape [B, T, H] (preserving
dtype, device and requires_grad_) and then apply F.logsigmoid to that tensor so
g has the correct shape and gradient behavior; no other changes to the
surrounding benchmark call are needed.

elif provider_base == 'dplr':
q = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
k = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
a = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
b = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
v = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
g = F.logsigmoid(torch.randn(B, T, H, D, dtype=dtype, device=device)).requires_grad_(True)
beta = torch.randn(B, T, H, dtype=dtype, device=device).sigmoid().requires_grad_(True)
results = triton.testing.do_bench(
lambda: chunk_dplr_delta_rule(
q=q,
k=k,
v=v,
a=a,
b=b,
gk=g,
)[0].backward(do),
quantiles=quantiles
)
Comment thread
zhiyuan1i marked this conversation as resolved.
Comment on lines +121 to +139

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Remove unused beta variable in DPLR provider.

Line 128 creates a beta tensor that is never used in the chunk_dplr_delta_rule call. The function signature doesn't accept a beta parameter, making this unnecessary computation that wastes resources during benchmarking.

Apply this diff to remove the unused variable:

         v = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
         g = F.logsigmoid(torch.randn(B, T, H, D, dtype=dtype, device=device)).requires_grad_(True)
-        beta = torch.randn(B, T, H, dtype=dtype, device=device).sigmoid().requires_grad_(True)
         results = triton.testing.do_bench(
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
elif provider_base == 'dplr':
q = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
k = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
a = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
b = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
v = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
g = F.logsigmoid(torch.randn(B, T, H, D, dtype=dtype, device=device)).requires_grad_(True)
beta = torch.randn(B, T, H, dtype=dtype, device=device).sigmoid().requires_grad_(True)
results = triton.testing.do_bench(
lambda: chunk_dplr_delta_rule(
q=q,
k=k,
v=v,
a=a,
b=b,
gk=g,
)[0].backward(do),
quantiles=quantiles
)
elif provider_base == 'dplr':
q = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
k = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
a = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
b = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
v = torch.randn(B, T, H, D, dtype=dtype, device=device).requires_grad_(True)
g = F.logsigmoid(torch.randn(B, T, H, D, dtype=dtype, device=device)).requires_grad_(True)
results = triton.testing.do_bench(
lambda: chunk_dplr_delta_rule(
q=q,
k=k,
v=v,
a=a,
b=b,
gk=g,
)[0].backward(do),
quantiles=quantiles
)
🤖 Prompt for AI Agents
In benchmarks/ops/benchmark_kda.py around lines 121 to 139, the DPLR branch
creates an unused tensor `beta` at line 128 which is not passed to
chunk_dplr_delta_rule and wastes compute during benchmarks; remove the creation
of `beta` (and any associated .requires_grad_(True) call) and ensure the call to
chunk_dplr_delta_rule remains unchanged, then run tests/benchmarks to confirm no
references to `beta` remain.


# Restore original TMA environment variable
os.environ['FLA_USE_TMA'] = original_tma_env
return results


if __name__ == '__main__':
benchmark.run(print_data=True)
2 changes: 2 additions & 0 deletions fla/layers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from .gsa import GatedSlotAttention
from .hgrn import HGRNAttention
from .hgrn2 import HGRN2Attention
from .kda import KDA
from .lightnet import LightNetAttention
from .linear_attn import LinearAttention
from .log_linear_mamba2 import LogLinearMamba2
Expand Down Expand Up @@ -45,6 +46,7 @@
'GatedSlotAttention',
'HGRNAttention',
'HGRN2Attention',
'KDA',
'LightNetAttention',
'LinearAttention',
'LogLinearMamba2',
Expand Down
4 changes: 2 additions & 2 deletions fla/layers/gated_deltanet.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ def forward(
initial_state=recurrent_state,
output_final_state=use_cache,
cu_seqlens=cu_seqlens,
use_qk_l2norm_in_kernel=True
use_qk_l2norm_in_kernel=True,
)
elif mode == 'fused_recurrent':
o, recurrent_state = fused_recurrent_gated_delta_rule(
Expand All @@ -293,7 +293,7 @@ def forward(
initial_state=recurrent_state,
output_final_state=use_cache,
cu_seqlens=cu_seqlens,
use_qk_l2norm_in_kernel=True
use_qk_l2norm_in_kernel=True,
)
else:
raise NotImplementedError(f"Not supported mode `{mode}`.")
Expand Down
Loading
Loading