94057c3d3e
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
263 lines
9.1 KiB
Python
263 lines
9.1 KiB
Python
# Adapted from https://github.com/fla-org/flash-linear-attention/blob/main/fla/ops/gated_delta_rule/chunk.py
|
|
# -*- coding: utf-8 -*-
|
|
# Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
|
|
|
|
from typing import Optional
|
|
|
|
import torch
|
|
from einops import rearrange
|
|
|
|
from sglang.srt.layers.attention.fla.chunk_delta_h import chunk_gated_delta_rule_fwd_h
|
|
from sglang.srt.layers.attention.fla.chunk_fwd import chunk_gated_delta_rule_fwd_intra
|
|
from sglang.srt.layers.attention.fla.chunk_o import chunk_fwd_o
|
|
from sglang.srt.layers.attention.fla.cumsum import chunk_local_cumsum
|
|
from sglang.srt.layers.attention.fla.index import (
|
|
prepare_chunk_indices,
|
|
)
|
|
from sglang.srt.layers.attention.fla.l2norm import l2norm_fwd
|
|
from sglang.srt.layers.attention.fla.utils import (
|
|
SUPPRESS_LEVEL,
|
|
autocast_custom_fwd,
|
|
input_guard,
|
|
is_intel,
|
|
)
|
|
|
|
if is_intel:
|
|
from sglang.srt.hardware_backend.xpu.kernels.fla.chunk_delta_h import (
|
|
chunk_gated_delta_rule_fwd_h,
|
|
)
|
|
from sglang.srt.hardware_backend.xpu.kernels.fla.chunk_fwd import (
|
|
chunk_gated_delta_rule_fwd_intra,
|
|
)
|
|
|
|
CHUNK_SIZE = 64
|
|
|
|
|
|
def chunk_gated_delta_rule_fwd(
|
|
q: torch.Tensor,
|
|
k: torch.Tensor,
|
|
v: torch.Tensor,
|
|
g: torch.Tensor,
|
|
beta: torch.Tensor,
|
|
scale: float,
|
|
initial_state: torch.Tensor,
|
|
initial_state_indices: torch.Tensor,
|
|
cu_seqlens: Optional[torch.LongTensor] = None,
|
|
chunk_indices: torch.LongTensor | None = None,
|
|
):
|
|
g = chunk_local_cumsum(
|
|
g, chunk_size=CHUNK_SIZE, cu_seqlens=cu_seqlens, chunk_indices=chunk_indices
|
|
)
|
|
|
|
# fused kkt + solve_tril + recompute_w_u
|
|
w, u, A = chunk_gated_delta_rule_fwd_intra(
|
|
k=k,
|
|
v=v,
|
|
g=g,
|
|
beta=beta,
|
|
cu_seqlens=cu_seqlens,
|
|
chunk_indices=chunk_indices,
|
|
)
|
|
|
|
h, v_new = chunk_gated_delta_rule_fwd_h(
|
|
k=k,
|
|
w=w,
|
|
u=u,
|
|
g=g,
|
|
initial_state=initial_state,
|
|
initial_state_indices=initial_state_indices,
|
|
cu_seqlens=cu_seqlens,
|
|
chunk_indices=chunk_indices,
|
|
)
|
|
o = chunk_fwd_o(
|
|
q=q,
|
|
k=k,
|
|
v=v_new,
|
|
h=h,
|
|
g=g,
|
|
scale=scale,
|
|
cu_seqlens=cu_seqlens,
|
|
)
|
|
if SUPPRESS_LEVEL < 3:
|
|
return g, o, A, None, h, None
|
|
elif SUPPRESS_LEVEL >= 3:
|
|
return g, o, A, w, h, v_new
|
|
|
|
|
|
class ChunkGatedDeltaRuleFunction(torch.autograd.Function):
|
|
|
|
@staticmethod
|
|
@input_guard
|
|
@autocast_custom_fwd
|
|
def forward(
|
|
ctx,
|
|
q: torch.Tensor,
|
|
k: torch.Tensor,
|
|
v: torch.Tensor,
|
|
g: torch.Tensor,
|
|
beta: torch.Tensor,
|
|
scale: float,
|
|
initial_state: torch.Tensor,
|
|
initial_state_indices: torch.Tensor,
|
|
cu_seqlens: Optional[torch.LongTensor] = None,
|
|
use_qk_l2norm_in_kernel: bool = False,
|
|
):
|
|
q_orig = q
|
|
k_orig = k
|
|
|
|
if use_qk_l2norm_in_kernel:
|
|
q = l2norm_fwd(q)
|
|
k = l2norm_fwd(k)
|
|
|
|
chunk_indices = (
|
|
prepare_chunk_indices(cu_seqlens, CHUNK_SIZE)
|
|
if cu_seqlens is not None
|
|
else None
|
|
)
|
|
g, o, A, w, h, v_new = chunk_gated_delta_rule_fwd(
|
|
q=q,
|
|
k=k,
|
|
v=v,
|
|
g=g,
|
|
beta=beta,
|
|
scale=scale,
|
|
initial_state=initial_state,
|
|
initial_state_indices=initial_state_indices,
|
|
cu_seqlens=cu_seqlens,
|
|
chunk_indices=chunk_indices,
|
|
)
|
|
return o.to(q.dtype), h
|
|
|
|
|
|
@torch.compiler.disable
|
|
def chunk_gated_delta_rule(
|
|
q: torch.Tensor,
|
|
k: torch.Tensor,
|
|
v: torch.Tensor,
|
|
g: torch.Tensor,
|
|
beta: torch.Tensor,
|
|
scale: float = None,
|
|
initial_state: torch.Tensor = None,
|
|
initial_state_indices: torch.Tensor = None,
|
|
cu_seqlens: Optional[torch.LongTensor] = None,
|
|
head_first: bool = False,
|
|
use_qk_l2norm_in_kernel: bool = False,
|
|
):
|
|
r"""
|
|
Args:
|
|
q (torch.Tensor):
|
|
queries of shape `[B, T, H, K]` if `head_first=False` else `[B, H, T, K]`.
|
|
k (torch.Tensor):
|
|
keys of shape `[B, T, H, K]` if `head_first=False` else `[B, H, T, K]`.
|
|
v (torch.Tensor):
|
|
values of shape `[B, T, H, V]` if `head_first=False` else `[B, H, T, V]`.
|
|
g (torch.Tensor):
|
|
(forget) gating tensor (in log space!) of shape `[B, T, H]` if `head_first=False` else `[B, H, T]`.
|
|
beta (torch.Tensor):
|
|
betas of shape `[B, T, H]` if `head_first=False` else `[B, H, T]`.
|
|
scale (Optional[int]):
|
|
Scale factor for the RetNet attention scores.
|
|
If not provided, it will default to `1 / sqrt(K)`. Default: `None`.
|
|
initial_state (Optional[torch.Tensor]):
|
|
Initial state of shape `[N, H, V, K]` for `N` input sequences.
|
|
For equal-length input sequences, `N` equals the batch size `B`.
|
|
Default: `None`.
|
|
output_final_state (Optional[bool]):
|
|
Whether to output the final state of shape `[N, H, V, K]`. Default: `False`.
|
|
cu_seqlens (torch.LongTensor):
|
|
Cumulative sequence lengths of shape `[N+1]` used for variable-length training,
|
|
consistent with the FlashAttention API.
|
|
head_first (Optional[bool]):
|
|
Whether the inputs are in the head-first format, which is not supported for variable-length inputs.
|
|
Default: `False`.
|
|
|
|
Returns:
|
|
o (torch.Tensor):
|
|
Outputs of shape `[B, T, H, V]` if `head_first=False` else `[B, H, T, V]`.
|
|
final_state (torch.Tensor):
|
|
Final state of shape `[N, H, V, K]` if `output_final_state=True` else `None`.
|
|
|
|
Examples::
|
|
>>> import torch
|
|
>>> import torch.nn.functional as F
|
|
>>> from einops import rearrange
|
|
>>> from fla.ops.gated_delta_rule import chunk_gated_delta_rule
|
|
# inputs with equal lengths
|
|
>>> B, T, H, K, V = 4, 2048, 4, 512, 512
|
|
>>> q = torch.randn(B, T, H, K, dtype=torch.bfloat16, device='cuda')
|
|
>>> k = F.normalize(torch.randn(B, T, H, K, dtype=torch.bfloat16, device='cuda'), p=2, dim=-1)
|
|
>>> v = torch.randn(B, T, H, V, dtype=torch.bfloat16, device='cuda')
|
|
>>> beta = torch.rand(B, T, H, dtype=torch.bfloat16, device='cuda').sigmoid()
|
|
>>> g = F.logsigmoid(torch.rand(B, T, H, dtype=torch.bfloat16, device='cuda'))
|
|
>>> h0 = torch.randn(B, H, K, V, dtype=torch.bfloat16, device='cuda')
|
|
>>> o, ht = chunk_gated_delta_rule(
|
|
q, k, v, g, beta,
|
|
initial_state=h0,
|
|
output_final_state=True
|
|
)
|
|
# for variable-length inputs, the batch size `B` is expected to be 1 and `cu_seqlens` is required
|
|
>>> q, k, v, beta, g = map(lambda x: rearrange(x, 'b t ... -> 1 (b t) ...'), (q, k, v, beta, g))
|
|
# for a batch with 4 sequences, `cu_seqlens` with 5 start/end positions are expected
|
|
>>> cu_seqlens = q.new_tensor([0, 2048, 4096, 6144, 8192], dtype=torch.long)
|
|
>>> o_var, ht_var = chunk_gated_delta_rule(
|
|
q, k, v, g, beta,
|
|
initial_state=h0,
|
|
output_final_state=True,
|
|
cu_seqlens=cu_seqlens
|
|
)
|
|
"""
|
|
assert q.dtype == k.dtype == v.dtype
|
|
assert (
|
|
q.dtype != torch.float32
|
|
), "ChunkGatedDeltaRuleFunction does not support float32. Please use bfloat16."
|
|
assert (
|
|
len(beta.shape) == 3
|
|
), "beta must be of shape [B, T, H] if head_first=False, or [B, H, T] otherwise."
|
|
|
|
if head_first:
|
|
raise DeprecationWarning(
|
|
"head_first is deprecated and will be removed in a future version. "
|
|
"Please use head_first=False for now instead."
|
|
)
|
|
q, k, v, beta, g = map(
|
|
lambda x: rearrange(x, "b h t ... -> b t h ..."), (q, k, v, beta, g)
|
|
)
|
|
# if not head_first and q.shape[1] < q.shape[2]:
|
|
# warnings.warn(
|
|
# f"Input tensor shape suggests potential format mismatch: seq_len ({q.shape[1]}) < num_heads ({q.shape[2]}). "
|
|
# "This may indicate the inputs were passed in head-first format [B, H, T, ...] "
|
|
# "when head_first=False was specified. "
|
|
# "Please verify your input tensor format matches the expected shape [B, T, H, ...]."
|
|
# )
|
|
if cu_seqlens is not None:
|
|
if q.shape[0] != 1:
|
|
raise ValueError(
|
|
f"The batch size is expected to be 1 rather than {q.shape[0]} when using `cu_seqlens`."
|
|
f"Please flatten variable-length inputs before processing."
|
|
)
|
|
if (
|
|
initial_state_indices is not None
|
|
and initial_state_indices.shape[0] != len(cu_seqlens) - 1
|
|
):
|
|
raise ValueError(
|
|
f"The number of initial states is expected to be equal to the number of input sequences, "
|
|
f"i.e., {len(cu_seqlens) - 1} rather than {initial_state_indices.shape[0]}."
|
|
)
|
|
if scale is None:
|
|
scale = k.shape[-1] ** -0.5
|
|
o, h = ChunkGatedDeltaRuleFunction.apply(
|
|
q,
|
|
k,
|
|
v,
|
|
g,
|
|
beta,
|
|
scale,
|
|
initial_state,
|
|
initial_state_indices,
|
|
cu_seqlens,
|
|
use_qk_l2norm_in_kernel,
|
|
)
|
|
if head_first:
|
|
o = rearrange(o, "b t h ... -> b h t ...")
|
|
return o, None, h
|