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
408 lines
12 KiB
Python
408 lines
12 KiB
Python
from __future__ import annotations
|
|
|
|
import torch
|
|
import triton
|
|
import triton.language as tl
|
|
|
|
# =============================================================================
|
|
# Fused kernel — reads INTERLEAVED input format
|
|
# Used by Qwen3-Next whose checkpoint stores fused in_proj_qkvz weights
|
|
# in per-head-group interleaved layout:
|
|
# [g0_q, g0_k, g0_v, g0_z, g1_q, g1_k, g1_v, g1_z, ...]
|
|
# =============================================================================
|
|
|
|
|
|
@triton.jit
|
|
def fused_qkvzba_split_reshape_cat_kernel(
|
|
mixed_qkv,
|
|
z,
|
|
b,
|
|
a,
|
|
mixed_qkvz,
|
|
mixed_ba,
|
|
NUM_HEADS_QK: tl.constexpr,
|
|
NUM_HEADS_V: tl.constexpr,
|
|
HEAD_QK: tl.constexpr,
|
|
HEAD_V: tl.constexpr,
|
|
):
|
|
i_bs, i_qk = tl.program_id(0), tl.program_id(1)
|
|
QKVZ_DIM_T: tl.constexpr = HEAD_QK * 2 + NUM_HEADS_V // NUM_HEADS_QK * HEAD_V * 2
|
|
BA_DIM_T: tl.constexpr = NUM_HEADS_V // NUM_HEADS_QK * 2
|
|
QKV_DIM_T: tl.constexpr = HEAD_QK * 2 + NUM_HEADS_V // NUM_HEADS_QK * HEAD_V
|
|
q_end: tl.constexpr = HEAD_QK
|
|
blk_q_ptr = (
|
|
mixed_qkvz
|
|
+ i_bs * NUM_HEADS_QK * QKVZ_DIM_T
|
|
+ i_qk * QKVZ_DIM_T
|
|
+ tl.arange(0, q_end)
|
|
)
|
|
k_end: tl.constexpr = q_end + HEAD_QK
|
|
blk_k_ptr = (
|
|
mixed_qkvz
|
|
+ i_bs * NUM_HEADS_QK * QKVZ_DIM_T
|
|
+ i_qk * QKVZ_DIM_T
|
|
+ tl.arange(q_end, k_end)
|
|
)
|
|
v_end: tl.constexpr = k_end + NUM_HEADS_V // NUM_HEADS_QK * HEAD_V
|
|
blk_v_ptr = (
|
|
mixed_qkvz
|
|
+ i_bs * NUM_HEADS_QK * QKVZ_DIM_T
|
|
+ i_qk * QKVZ_DIM_T
|
|
+ tl.arange(k_end, v_end)
|
|
)
|
|
z_end: tl.constexpr = v_end + NUM_HEADS_V // NUM_HEADS_QK * HEAD_V
|
|
blk_z_ptr = (
|
|
mixed_qkvz
|
|
+ i_bs * NUM_HEADS_QK * QKVZ_DIM_T
|
|
+ i_qk * QKVZ_DIM_T
|
|
+ tl.arange(v_end, z_end)
|
|
)
|
|
blk_q_st_ptr = (
|
|
mixed_qkv
|
|
+ i_bs * NUM_HEADS_QK * QKV_DIM_T
|
|
+ i_qk * HEAD_QK
|
|
+ tl.arange(0, HEAD_QK)
|
|
)
|
|
blk_k_st_ptr = (
|
|
mixed_qkv
|
|
+ i_bs * NUM_HEADS_QK * QKV_DIM_T
|
|
+ NUM_HEADS_QK * HEAD_QK
|
|
+ i_qk * HEAD_QK
|
|
+ tl.arange(0, HEAD_QK)
|
|
)
|
|
blk_v_st_ptr = (
|
|
mixed_qkv
|
|
+ i_bs * NUM_HEADS_QK * QKV_DIM_T
|
|
+ NUM_HEADS_QK * HEAD_QK * 2
|
|
+ i_qk * HEAD_V * NUM_HEADS_V // NUM_HEADS_QK
|
|
+ tl.arange(0, HEAD_V * NUM_HEADS_V // NUM_HEADS_QK)
|
|
)
|
|
blk_z_st_ptr = (
|
|
z
|
|
+ i_bs * NUM_HEADS_V * HEAD_V
|
|
+ i_qk * HEAD_V * NUM_HEADS_V // NUM_HEADS_QK
|
|
+ tl.arange(0, HEAD_V * NUM_HEADS_V // NUM_HEADS_QK)
|
|
)
|
|
tl.store(blk_q_st_ptr, tl.load(blk_q_ptr))
|
|
tl.store(blk_k_st_ptr, tl.load(blk_k_ptr))
|
|
tl.store(blk_v_st_ptr, tl.load(blk_v_ptr))
|
|
tl.store(blk_z_st_ptr, tl.load(blk_z_ptr))
|
|
b_end: tl.constexpr = NUM_HEADS_V // NUM_HEADS_QK
|
|
a_end: tl.constexpr = b_end + NUM_HEADS_V // NUM_HEADS_QK
|
|
for i in tl.static_range(b_end):
|
|
blk_b_ptr = mixed_ba + i_bs * NUM_HEADS_QK * BA_DIM_T + i_qk * BA_DIM_T + i
|
|
blk_b_st_ptr = b + i_bs * NUM_HEADS_V + i_qk * NUM_HEADS_V // NUM_HEADS_QK + i
|
|
tl.store(blk_b_st_ptr, tl.load(blk_b_ptr))
|
|
for i in tl.static_range(b_end, a_end):
|
|
blk_a_ptr = mixed_ba + i_bs * NUM_HEADS_QK * BA_DIM_T + i_qk * BA_DIM_T + i
|
|
blk_a_st_ptr = (
|
|
a + i_bs * NUM_HEADS_V + i_qk * NUM_HEADS_V // NUM_HEADS_QK + (i - b_end)
|
|
)
|
|
tl.store(blk_a_st_ptr, tl.load(blk_a_ptr))
|
|
|
|
|
|
def fused_qkvzba_split_reshape_cat(
|
|
mixed_qkvz,
|
|
mixed_ba,
|
|
num_heads_qk,
|
|
num_heads_v,
|
|
head_qk,
|
|
head_v,
|
|
):
|
|
batch, seq_len = mixed_qkvz.shape[0], 1
|
|
qkv_dim_t = num_heads_qk * head_qk * 2 + num_heads_v * head_v
|
|
mixed_qkv = torch.empty(
|
|
[batch * seq_len, qkv_dim_t],
|
|
dtype=mixed_qkvz.dtype,
|
|
device=mixed_qkvz.device,
|
|
)
|
|
z = torch.empty(
|
|
[batch * seq_len, num_heads_v, head_v],
|
|
dtype=mixed_qkvz.dtype,
|
|
device=mixed_qkvz.device,
|
|
)
|
|
b = torch.empty(
|
|
[batch * seq_len, num_heads_v],
|
|
dtype=mixed_ba.dtype,
|
|
device=mixed_ba.device,
|
|
)
|
|
a = torch.empty_like(b)
|
|
grid = (batch * seq_len, num_heads_qk)
|
|
fused_qkvzba_split_reshape_cat_kernel[grid](
|
|
mixed_qkv,
|
|
z,
|
|
b,
|
|
a,
|
|
mixed_qkvz,
|
|
mixed_ba,
|
|
num_heads_qk,
|
|
num_heads_v,
|
|
head_qk,
|
|
head_v,
|
|
num_warps=1,
|
|
num_stages=3,
|
|
)
|
|
return mixed_qkv, z, b, a
|
|
|
|
|
|
# =============================================================================
|
|
# Fused kernel — reads CONTIGUOUS input format
|
|
# Used by Qwen3.5 whose checkpoint stores in_proj_qkv and in_proj_z separately.
|
|
# After MergedColumnParallelLinear loads them, the matmul output is contiguous:
|
|
# mixed_qkvz: [all_q | all_k | all_v | all_z]
|
|
# mixed_ba: [all_b | all_a]
|
|
#
|
|
# Output format is identical to the interleaved kernel (same downstream consumer).
|
|
# =============================================================================
|
|
|
|
|
|
@triton.jit
|
|
def fused_qkvzba_split_reshape_cat_contiguous_kernel(
|
|
mixed_qkv,
|
|
z,
|
|
b,
|
|
a,
|
|
mixed_qkvz,
|
|
mixed_ba,
|
|
NUM_HEADS_QK: tl.constexpr,
|
|
NUM_HEADS_V: tl.constexpr,
|
|
HEAD_QK: tl.constexpr,
|
|
HEAD_V: tl.constexpr,
|
|
):
|
|
i_bs, i_qk = tl.program_id(0), tl.program_id(1)
|
|
|
|
V_PER_GROUP: tl.constexpr = NUM_HEADS_V // NUM_HEADS_QK
|
|
|
|
# ── Input dimensions (contiguous layout) ──
|
|
TOTAL_Q: tl.constexpr = NUM_HEADS_QK * HEAD_QK
|
|
TOTAL_K: tl.constexpr = NUM_HEADS_QK * HEAD_QK
|
|
TOTAL_V: tl.constexpr = NUM_HEADS_V * HEAD_V
|
|
TOTAL_QKVZ: tl.constexpr = TOTAL_Q + TOTAL_K + TOTAL_V + TOTAL_V
|
|
TOTAL_BA: tl.constexpr = NUM_HEADS_V * 2
|
|
|
|
# ── Output dimensions ──
|
|
QKV_DIM_T: tl.constexpr = TOTAL_Q + TOTAL_K + TOTAL_V
|
|
|
|
# ── Read from contiguous input ──
|
|
# q for head group i_qk: in the all_q region, offset i_qk * HEAD_QK
|
|
blk_q_ptr = mixed_qkvz + i_bs * TOTAL_QKVZ + i_qk * HEAD_QK + tl.arange(0, HEAD_QK)
|
|
# k for head group i_qk: in the all_k region
|
|
blk_k_ptr = (
|
|
mixed_qkvz
|
|
+ i_bs * TOTAL_QKVZ
|
|
+ TOTAL_Q
|
|
+ i_qk * HEAD_QK
|
|
+ tl.arange(0, HEAD_QK)
|
|
)
|
|
# v for head group i_qk: in the all_v region
|
|
blk_v_ptr = (
|
|
mixed_qkvz
|
|
+ i_bs * TOTAL_QKVZ
|
|
+ TOTAL_Q
|
|
+ TOTAL_K
|
|
+ i_qk * V_PER_GROUP * HEAD_V
|
|
+ tl.arange(0, V_PER_GROUP * HEAD_V)
|
|
)
|
|
# z for head group i_qk: in the all_z region
|
|
blk_z_ptr = (
|
|
mixed_qkvz
|
|
+ i_bs * TOTAL_QKVZ
|
|
+ TOTAL_Q
|
|
+ TOTAL_K
|
|
+ TOTAL_V
|
|
+ i_qk * V_PER_GROUP * HEAD_V
|
|
+ tl.arange(0, V_PER_GROUP * HEAD_V)
|
|
)
|
|
|
|
# ── Write to output (identical layout to the interleaved kernel) ──
|
|
blk_q_st_ptr = mixed_qkv + i_bs * QKV_DIM_T + i_qk * HEAD_QK + tl.arange(0, HEAD_QK)
|
|
blk_k_st_ptr = (
|
|
mixed_qkv
|
|
+ i_bs * QKV_DIM_T
|
|
+ NUM_HEADS_QK * HEAD_QK
|
|
+ i_qk * HEAD_QK
|
|
+ tl.arange(0, HEAD_QK)
|
|
)
|
|
blk_v_st_ptr = (
|
|
mixed_qkv
|
|
+ i_bs * QKV_DIM_T
|
|
+ NUM_HEADS_QK * HEAD_QK * 2
|
|
+ i_qk * V_PER_GROUP * HEAD_V
|
|
+ tl.arange(0, V_PER_GROUP * HEAD_V)
|
|
)
|
|
blk_z_st_ptr = (
|
|
z
|
|
+ i_bs * NUM_HEADS_V * HEAD_V
|
|
+ i_qk * V_PER_GROUP * HEAD_V
|
|
+ tl.arange(0, V_PER_GROUP * HEAD_V)
|
|
)
|
|
|
|
tl.store(blk_q_st_ptr, tl.load(blk_q_ptr))
|
|
tl.store(blk_k_st_ptr, tl.load(blk_k_ptr))
|
|
tl.store(blk_v_st_ptr, tl.load(blk_v_ptr))
|
|
tl.store(blk_z_st_ptr, tl.load(blk_z_ptr))
|
|
|
|
# ── b and a from contiguous [all_b | all_a] ──
|
|
for i in tl.static_range(V_PER_GROUP):
|
|
blk_b_ptr = mixed_ba + i_bs * TOTAL_BA + i_qk * V_PER_GROUP + i
|
|
blk_b_st_ptr = b + i_bs * NUM_HEADS_V + i_qk * V_PER_GROUP + i
|
|
tl.store(blk_b_st_ptr, tl.load(blk_b_ptr))
|
|
|
|
for i in tl.static_range(V_PER_GROUP):
|
|
blk_a_ptr = mixed_ba + i_bs * TOTAL_BA + NUM_HEADS_V + i_qk * V_PER_GROUP + i
|
|
blk_a_st_ptr = a + i_bs * NUM_HEADS_V + i_qk * V_PER_GROUP + i
|
|
tl.store(blk_a_st_ptr, tl.load(blk_a_ptr))
|
|
|
|
|
|
def fused_qkvzba_split_reshape_cat_contiguous(
|
|
mixed_qkvz,
|
|
mixed_ba,
|
|
num_heads_qk,
|
|
num_heads_v,
|
|
head_qk,
|
|
head_v,
|
|
):
|
|
"""Fused split/reshape/cat for CONTIGUOUS input format (Qwen3.5).
|
|
|
|
Input layout:
|
|
mixed_qkvz: [all_q | all_k | all_v | all_z]
|
|
mixed_ba: [all_b | all_a]
|
|
|
|
Output layout (same as fused_qkvzba_split_reshape_cat):
|
|
mixed_qkv: [all_q | all_k | all_v] (z stripped)
|
|
z: [num_v_heads, head_v]
|
|
b: [num_v_heads]
|
|
a: [num_v_heads]
|
|
"""
|
|
batch, seq_len = mixed_qkvz.shape[0], 1
|
|
qkv_dim_t = num_heads_qk * head_qk * 2 + num_heads_v * head_v
|
|
mixed_qkv = torch.empty(
|
|
[batch * seq_len, qkv_dim_t],
|
|
dtype=mixed_qkvz.dtype,
|
|
device=mixed_qkvz.device,
|
|
)
|
|
z = torch.empty(
|
|
[batch * seq_len, num_heads_v, head_v],
|
|
dtype=mixed_qkvz.dtype,
|
|
device=mixed_qkvz.device,
|
|
)
|
|
b = torch.empty(
|
|
[batch * seq_len, num_heads_v],
|
|
dtype=mixed_ba.dtype,
|
|
device=mixed_ba.device,
|
|
)
|
|
a = torch.empty_like(b)
|
|
grid = (batch * seq_len, num_heads_qk)
|
|
fused_qkvzba_split_reshape_cat_contiguous_kernel[grid](
|
|
mixed_qkv,
|
|
z,
|
|
b,
|
|
a,
|
|
mixed_qkvz,
|
|
mixed_ba,
|
|
num_heads_qk,
|
|
num_heads_v,
|
|
head_qk,
|
|
head_v,
|
|
num_warps=1,
|
|
num_stages=3,
|
|
)
|
|
return mixed_qkv, z, b, a
|
|
|
|
|
|
@triton.jit
|
|
def fused_qkv_split_gdn_prefill_kernel(
|
|
q,
|
|
k,
|
|
v,
|
|
mixed_qkv,
|
|
MIXED_QKV_STRIDE_T: tl.constexpr,
|
|
MIXED_QKV_STRIDE_D: tl.constexpr,
|
|
NUM_Q_HEADS: tl.constexpr,
|
|
NUM_K_HEADS: tl.constexpr,
|
|
NUM_V_HEADS: tl.constexpr,
|
|
HEAD_Q: tl.constexpr,
|
|
HEAD_K: tl.constexpr,
|
|
HEAD_V: tl.constexpr,
|
|
BLOCK_SIZE: tl.constexpr,
|
|
):
|
|
i_t = tl.program_id(0)
|
|
offsets = tl.arange(0, BLOCK_SIZE)
|
|
|
|
q_dim: tl.constexpr = NUM_Q_HEADS * HEAD_Q
|
|
k_dim: tl.constexpr = NUM_K_HEADS * HEAD_K
|
|
v_dim: tl.constexpr = NUM_V_HEADS * HEAD_V
|
|
qk_dim: tl.constexpr = q_dim + k_dim
|
|
qkv_dim: tl.constexpr = qk_dim + v_dim
|
|
|
|
mask = offsets < qkv_dim
|
|
values = tl.load(
|
|
mixed_qkv + i_t * MIXED_QKV_STRIDE_T + offsets * MIXED_QKV_STRIDE_D,
|
|
mask=mask,
|
|
)
|
|
|
|
q_mask = offsets < q_dim
|
|
tl.store(q + i_t * q_dim + offsets, values, mask=q_mask)
|
|
|
|
k_offsets = offsets - q_dim
|
|
k_mask = (offsets >= q_dim) & (offsets < qk_dim)
|
|
tl.store(k + i_t * k_dim + k_offsets, values, mask=k_mask)
|
|
|
|
v_offsets = offsets - qk_dim
|
|
v_mask = (offsets >= qk_dim) & (offsets < qkv_dim)
|
|
tl.store(v + i_t * v_dim + v_offsets, values, mask=v_mask)
|
|
|
|
|
|
def fused_qkv_split_gdn_prefill(
|
|
mixed_qkv: torch.Tensor,
|
|
num_q_heads: int,
|
|
num_k_heads: int,
|
|
num_v_heads: int,
|
|
head_q: int,
|
|
head_k: int,
|
|
head_v: int,
|
|
):
|
|
"""Split packed post-conv GDN QKV into contiguous FLA prefill tensors.
|
|
|
|
`mixed_qkv` is laid out per token as `[all_q | all_k | all_v]`. The FLA
|
|
chunk kernels consume separate contiguous `[1, T, H, D]` tensors, so this
|
|
fused split replaces three independent `aten::copy_` kernels from the
|
|
generic FLA input guard. `mixed_qkv` may be a strided `[T, qkv_dim]` view.
|
|
"""
|
|
seq_len = mixed_qkv.shape[0]
|
|
q = torch.empty(
|
|
(1, seq_len, num_q_heads, head_q),
|
|
dtype=mixed_qkv.dtype,
|
|
device=mixed_qkv.device,
|
|
)
|
|
k = torch.empty(
|
|
(1, seq_len, num_k_heads, head_k),
|
|
dtype=mixed_qkv.dtype,
|
|
device=mixed_qkv.device,
|
|
)
|
|
v = torch.empty(
|
|
(1, seq_len, num_v_heads, head_v),
|
|
dtype=mixed_qkv.dtype,
|
|
device=mixed_qkv.device,
|
|
)
|
|
|
|
qkv_dim = num_q_heads * head_q + num_k_heads * head_k + num_v_heads * head_v
|
|
fused_qkv_split_gdn_prefill_kernel[(seq_len,)](
|
|
q,
|
|
k,
|
|
v,
|
|
mixed_qkv,
|
|
mixed_qkv.stride(0),
|
|
mixed_qkv.stride(1),
|
|
num_q_heads,
|
|
num_k_heads,
|
|
num_v_heads,
|
|
head_q,
|
|
head_k,
|
|
head_v,
|
|
BLOCK_SIZE=triton.next_power_of_2(qkv_dim),
|
|
num_warps=8,
|
|
num_stages=3,
|
|
)
|
|
return q, k, v
|