Skip to content

[SSE] Add SSE integration - #882

Open
Pan-Yuqi wants to merge 2 commits into
fla-org:mainfrom
Pan-Yuqi:sse_dev
Open

[SSE] Add SSE integration#882
Pan-Yuqi wants to merge 2 commits into
fla-org:mainfrom
Pan-Yuqi:sse_dev

Conversation

@Pan-Yuqi

@Pan-Yuqi Pan-Yuqi commented May 9, 2026

Copy link
Copy Markdown
Contributor

Description

This PR adds SSE integration, where SSE refers to Scaling Linear Attention with Sparse State Expansion.

The implementation introduces the SSE model/layer/operator components into the repository and wires them into the existing module structure so that SSE can be used consistently with other supported architectures.

Changes

  • Add SSE layer implementation under fla/layers/
  • Add SSE model configuration and modeling files under fla/models/sse/
  • Add SSE operator utilities under fla/ops/sse/
  • Register SSE modules in package-level __init__.py files

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request introduces the SSE (Scaling Linear Attention with Sparse State Expansion) architecture, implementing SSEGLA and SSEGDN layers, optimized Triton kernels, and the SSEForCausalLM model. Feedback identifies a typo in the all export list and a critical indexing bug in the Triton kernels where query strides are incorrectly applied to gate tensors. Additionally, recommendations were made to remove performance-degrading host-device synchronizations during state handling and to synchronize default parameter values between the configuration and layer classes for better consistency.

Comment thread fla/__init__.py Outdated
Comment thread fla/ops/sse/mask.py

p_q = q + i_b * stride_k_b + i_t * stride_k_l + i_h * stride_k_h + offsets_k
p_k = k + i_b * stride_k_b + i_t * stride_k_l + i_h * stride_k_h + offsets_k
p_g = g + i_b * stride_k_b + i_t * stride_k_l + i_h * stride_k_h + offsets_k

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.

high

The _fused_mask_fwd_kernel uses stride_k_* to access the g tensor. This is incorrect when g has different strides than k, which happens in SSEGDN.sse_linear_attention_mask where v (with head dimension V) is passed as the g argument. Since v has a different head dimension and different strides than k, this leads to incorrect memory indexing. The kernel should accept stride_g_* or the caller should ensure strides match.

Comment thread fla/ops/sse/mask.py
p_k = k + i_b * stride_k_b + i_t * stride_k_l + i_h * stride_k_h + offsets_k
p_dq = dq + i_b * stride_k_b + i_t * stride_k_l + i_h * stride_k_h + offsets_k
p_dk = dk + i_b * stride_k_b + i_t * stride_k_l + i_h * stride_k_h + offsets_k
p_dg = dg + i_b * stride_k_b + i_t * stride_k_l + i_h * stride_k_h + offsets_k

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.

high

Similar to the forward kernel, _fused_mask_bwd_kernel uses stride_k_* for dg. This will cause incorrect gradient updates when dg has different strides than k (e.g., in SSEGDN).

Comment thread fla/layers/sse.py

recurrent_state_rec = None
if use_cache:
state_id = torch.nonzero(state_sizes.flatten(), as_tuple=True)[0].cpu()

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.

medium

Calling .cpu() on state_id triggers a host-device synchronization, which can be a significant performance bottleneck during inference. Since recurrent_state2 is on the GPU, you should keep state_id on the GPU as well for indexing.

Suggested change
state_id = torch.nonzero(state_sizes.flatten(), as_tuple=True)[0].cpu()
state_id = torch.nonzero(state_sizes.flatten(), as_tuple=True)[0]

Comment thread fla/layers/sse.py

recurrent_state_rec = None
if use_cache:
state_id = torch.nonzero(state_sizes.flatten(), as_tuple=True)[0].cpu()

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.

medium

Similar to the SSEGLA implementation, avoid moving state_id to the CPU to prevent unnecessary synchronization overhead.

Suggested change
state_id = torch.nonzero(state_sizes.flatten(), as_tuple=True)[0].cpu()
state_id = torch.nonzero(state_sizes.flatten(), as_tuple=True)[0]

Comment on lines +30 to +31
num_writer: int = 2,
num_reader: int = 2,

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.

medium

The default values for num_writer and num_reader in SSEConfig (2) do not match the defaults in the SSEGLA and SSEGDN layers (1). It is recommended to synchronize these defaults to avoid confusion.

Suggested change
num_writer: int = 2,
num_reader: int = 2,
num_writer: int = 1,
num_reader: int = 1,

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant