Qwen3.8-27B Model Support (#34859)

Co-authored-by: Jimmy Shong <69131491+Jiminator@users.noreply.github.com>
Co-authored-by: Brayden Zhong <brayden.zhong@radixark.ai>
Co-authored-by: BBuf <1182563586@qq.com>
Co-authored-by: Zijie Xia <zijie.xia@radixark.ai>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Qiaolin Yu <liin1211@outlook.com>
This commit is contained in:
Yuhao Yang
2026-08-19 16:31:43 +08:00
committed by GitHub
co-authored by Jimmy Shong Brayden Zhong BBuf Zijie Xia Claude Fable 5 Qiaolin Yu
parent ebec85f606
commit 8a1e6e4e46
18 changed files with 836 additions and 55 deletions
@@ -0,0 +1,91 @@
import unittest
import torch
from sglang.kernels.ops.attention.triton_gdn_fused_proj import (
fused_qkvzba_split_reshape_cat_contiguous,
)
from sglang.test.ci.ci_register import register_cuda_ci
register_cuda_ci(est_time=3, stage="base-b", runner_config="1-gpu-large")
def _reference_split(mixed_qkvz, mixed_ba, num_heads_qk, num_heads_v, head_qk, head_v):
"""Plain-slicing reference for the contiguous [Q|K|V|Z] / [B|A] layouts."""
batch = mixed_qkvz.shape[0]
total_q = num_heads_qk * head_qk
total_v = num_heads_v * head_v
q = mixed_qkvz[:, :total_q]
k = mixed_qkvz[:, total_q : 2 * total_q]
v = mixed_qkvz[:, 2 * total_q : 2 * total_q + total_v]
z = mixed_qkvz[:, 2 * total_q + total_v :]
mixed_qkv = torch.cat((q, k, v), dim=-1).contiguous()
b = mixed_ba[:, :num_heads_v].contiguous()
a = mixed_ba[:, num_heads_v:].contiguous()
return (
mixed_qkv,
z.reshape(batch, num_heads_v, head_v).contiguous(),
b,
a,
)
@unittest.skipIf(not torch.cuda.is_available(), "Test requires CUDA")
class TestGdnFusedSplitHeadRatios(unittest.TestCase):
"""The fused contiguous split must be exact for every supported v/k head
ratio, including the non-power-of-two ratio 3 of the dense 27B hybrids
(served by the per-head walk instead of one wide vector access)."""
HEAD_QK = 128
HEAD_V = 128
NUM_HEADS_QK = 16
def _run_ratio(self, ratio: int, batch: int = 33) -> None:
torch.manual_seed(ratio)
num_heads_v = self.NUM_HEADS_QK * ratio
total_qkvz = (
2 * self.NUM_HEADS_QK * self.HEAD_QK + 2 * num_heads_v * self.HEAD_V
)
mixed_qkvz = torch.randn(batch, total_qkvz, dtype=torch.bfloat16, device="cuda")
mixed_ba = torch.randn(
batch, 2 * num_heads_v, dtype=torch.bfloat16, device="cuda"
)
got_qkv, got_z, got_b, got_a = fused_qkvzba_split_reshape_cat_contiguous(
mixed_qkvz,
mixed_ba,
self.NUM_HEADS_QK,
num_heads_v,
self.HEAD_QK,
self.HEAD_V,
)
ref_qkv, ref_z, ref_b, ref_a = _reference_split(
mixed_qkvz,
mixed_ba,
self.NUM_HEADS_QK,
num_heads_v,
self.HEAD_QK,
self.HEAD_V,
)
# A pure data-movement kernel must be bitwise exact.
torch.testing.assert_close(got_qkv.view(-1), ref_qkv.view(-1), rtol=0, atol=0)
torch.testing.assert_close(got_z.reshape(-1), ref_z.reshape(-1), rtol=0, atol=0)
torch.testing.assert_close(got_b.view(-1), ref_b.view(-1), rtol=0, atol=0)
torch.testing.assert_close(got_a.view(-1), ref_a.view(-1), rtol=0, atol=0)
def test_ratio_1(self):
self._run_ratio(1)
def test_ratio_2(self):
self._run_ratio(2)
def test_ratio_3(self):
self._run_ratio(3)
def test_ratio_4(self):
self._run_ratio(4)
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,68 @@
"""
Tests the Hopper single-token bf16 GEMV JIT kernel against torch (cuBLAS +
fp32 reference) on the dispatch domains where the backend enables it.
"""
import unittest
import torch
from sglang.test.ci.ci_register import register_cuda_ci
register_cuda_ci(est_time=6, stage="base-b", runner_config="1-gpu-large")
def _is_sm90() -> bool:
return torch.cuda.is_available() and torch.cuda.get_device_capability()[0] == 9
@unittest.skipIf(not _is_sm90(), "Hopper bf16 GEMV requires an SM90 GPU")
class TestHopperBf16Gemv(unittest.TestCase):
def _run_case(self, n, k, seed=0):
from sglang.kernels.ops.gemm.hopper_bf16_gemv import hopper_bf16_gemv
torch.manual_seed(seed)
x = torch.randn(1, k, dtype=torch.bfloat16, device="cuda")
w = torch.randn(n, k, dtype=torch.bfloat16, device="cuda") * 0.05
out = hopper_bf16_gemv(x, w)
ref = x.float() @ w.float().t()
cub = (x @ w.t()).float()
err = (out.float() - ref).abs().max().item()
err_cub = (cub - ref).abs().max().item()
# fp32 accumulation + single warp-tree reduction: at least as tight as
# cuBLAS (which split-K reduces) against the fp32 reference.
self.assertLessEqual(err, max(err_cub * 2.0, 1e-2), (n, k, err, err_cub))
self.assertFalse(torch.isnan(out).any().item(), (n, k))
def test_dispatch_domain_shapes(self):
# Representative dense-decode shapes (Qwen3.6-27B): out_proj/attn_o,
# attn_qkv, mlp_down, mlp_gate_up, in_proj_ba.
for n, k in [
(5120, 6144),
(8192, 5120),
(5120, 17408),
(34816, 5120),
(96, 5120),
]:
self._run_case(n, k)
def test_tail_rows(self):
# N not divisible by rows_per_block exercises the guarded tail path.
for n in [104, 5128, 8200]:
self._run_case(n, 5120)
def test_predicate(self):
from sglang.kernels.ops.gemm.hopper_bf16_gemv import use_hopper_bf16_gemv
self.assertTrue(use_hopper_bf16_gemv(1, 5120, 6144))
self.assertTrue(use_hopper_bf16_gemv(1, 34816, 5120))
# batched decode, odd K, huge N (lm_head), and the near-optimal-cuBLAS
# mid-N band must all fall back.
self.assertFalse(use_hopper_bf16_gemv(2, 5120, 6144))
self.assertFalse(use_hopper_bf16_gemv(1, 5120, 6000))
self.assertFalse(use_hopper_bf16_gemv(1, 248320, 5120))
self.assertFalse(use_hopper_bf16_gemv(1, 16384, 5120))
if __name__ == "__main__":
unittest.main()