[ROCm][Deepseek] dsv3.2 further optimization (#41217)

Signed-off-by: ganyi <[email protected]>
Signed-off-by: Matthew Wong <[email protected]>
Co-authored-by: Matthew Wong <[email protected]>
This commit is contained in:
Pleaplusone
2026-05-01 23:06:00 +09:00
committed by GitHub
co-authored by Matthew Wong
parent c3e64696cd
commit bc635fad23
6 changed files with 291 additions and 71 deletions
+1 -1
View File
@@ -216,7 +216,7 @@ configuration.
| `FLASHMLA_SPARSE` | bf16 | `auto`, `bfloat16`, `fp8_ds_mla` | 64 | 512, 576 | ❌ | ✅ | ❌ | ❌ | Decoder | 9.x-10.x |
| `FLASH_ATTN_MLA` | fp16, bf16 | `auto`, `float16`, `bfloat16` | %16 | Any | ❌ | ❌ | ❌ | ✅ | Decoder | 9.x |
| `ROCM_AITER_MLA` | fp16, bf16 | `auto`, `float16`, `bfloat16`, `fp8`, `fp8_e4m3`, `fp8_e5m2` | %1 | Any | ❌ | ❌ | ❌ | ❌ | Decoder | N/A |
| `ROCM_AITER_MLA_SPARSE` | fp16, bf16 | `auto`, `float16`, `bfloat16` | 1 | Any | ❌ | ✅ | ❌ | ❌ | Decoder | N/A |
| `ROCM_AITER_MLA_SPARSE` | fp16, bf16 | `auto`, `float16`, `bfloat16`, `fp8`, `fp8_e4m3` | 1, 64 | Any | ❌ | ✅ | ❌ | ❌ | Decoder | N/A |
| `ROCM_AITER_TRITON_MLA` | fp16, bf16 | `auto` | Any | Any | ❌ | ❌ | ❌ | ❌ | Decoder | N/A |
| `TRITON_MLA` | fp16, bf16 | `auto`, `float16`, `bfloat16`, `fp8`, `fp8_e4m3` | %16 | Any | ❌ | ❌ | ❌ | ✅ | Decoder | Any |
| `XPU_MLA_SPARSE` | fp16, bf16 | `auto`, `float16`, `bfloat16` | Any | 576 | ❌ | ✅ | ❌ | ❌ | Decoder | Any |
+36 -21
View File
@@ -674,30 +674,45 @@ class Indexer(nn.Module):
) -> torch.Tensor:
q, _ = self.wq_b(qr)
q = q.view(-1, self.n_head, self.head_dim)
q_pe, q_nope = torch.split(
q, [self.rope_dim, self.head_dim - self.rope_dim], dim=-1
)
# Fused wk + weights_proj: one GEMM, then split
kw, _ = self.wk_weights_proj(hidden_states)
k = kw[:, : self.head_dim]
weights = kw[:, self.head_dim :]
k = self.k_norm(k)
k_pe, k_nope = torch.split(
k, [self.rope_dim, self.head_dim - self.rope_dim], dim=-1
)
if current_platform.is_rocm():
# This path should works on all platform, will remove extra
# branches in the future
# Fused wk + weights_proj: one GEMM, then split
kw, _ = self.wk_weights_proj(hidden_states)
k = kw[:, : self.head_dim]
weights = kw[:, self.head_dim :]
q_pe, k_pe = rotary_emb(positions, q_pe, k_pe.unsqueeze(1))
# Note: RoPE (NeoX) can introduce extra leading dimensions during compilation
# so we need to reshape back to token-flattened shapes
q_pe = q_pe.reshape(-1, self.n_head, self.rope_dim)
k_pe = k_pe.reshape(-1, 1, self.rope_dim)
k = self.k_norm(k)
# `rotary_emb` is shape-preserving; `q_pe` is already
# [num_tokens, n_head, rope_dim].
q = torch.cat([q_pe, q_nope], dim=-1)
# `k_pe` is [num_tokens, 1, rope_dim] (MQA).
k = torch.cat([k_pe.squeeze(-2), k_nope], dim=-1)
rotary_emb(
positions, q[..., : self.rope_dim], k[..., : self.rope_dim].unsqueeze(1)
)
else:
q_pe, q_nope = torch.split(
q, [self.rope_dim, self.head_dim - self.rope_dim], dim=-1
)
# Fused wk + weights_proj: one GEMM, then split
kw, _ = self.wk_weights_proj(hidden_states)
k = kw[:, : self.head_dim]
weights = kw[:, self.head_dim :]
k = self.k_norm(k)
k_pe, k_nope = torch.split(
k, [self.rope_dim, self.head_dim - self.rope_dim], dim=-1
)
q_pe, k_pe = rotary_emb(positions, q_pe, k_pe.unsqueeze(1))
# Note: RoPE (NeoX) can introduce extra leading dimensions during
# compilation so we need to reshape back to token-flattened shapes
q_pe = q_pe.reshape(-1, self.n_head, self.rope_dim)
k_pe = k_pe.reshape(-1, 1, self.rope_dim)
# `rotary_emb` is shape-preserving; `q_pe` is already
# [num_tokens, n_head, rope_dim].
q = torch.cat([q_pe, q_nope], dim=-1)
# `k_pe` is [num_tokens, 1, rope_dim] (MQA).
k = torch.cat([k_pe.squeeze(-2), k_nope], dim=-1)
# we only quant q here since k quant is fused with cache insertion
q = q.view(-1, self.head_dim)
+1 -1
View File
@@ -122,7 +122,7 @@ class DeepseekV32IndexerBackend(AttentionBackend):
@staticmethod
def get_supported_kernel_block_sizes() -> list[int | MultipleOf]:
return [1 if current_platform.is_rocm() else 64]
return [1, 64] if current_platform.is_rocm() else [64]
@classmethod
def get_supported_head_sizes(cls) -> list[int]:
@@ -396,6 +396,7 @@ class AiterMLAHelper:
"""
_AITER_MIN_MLA_HEADS: Final = 16
_AITER_UNSUPPORTED_HEADS = [32]
@staticmethod
def check_num_heads_validity(num_heads: int):
@@ -419,6 +420,9 @@ class AiterMLAHelper:
@staticmethod
def get_mla_padded_q(num_heads: int, q: torch.Tensor) -> torch.Tensor:
assert num_heads not in AiterMLAHelper._AITER_UNSUPPORTED_HEADS, (
f"unsupported head_num: {num_heads}"
)
return (
q
if num_heads >= AiterMLAHelper._AITER_MIN_MLA_HEADS
@@ -7,6 +7,7 @@ from typing import TYPE_CHECKING, ClassVar
import numpy as np
import torch
from vllm import _custom_ops as ops
from vllm._aiter_ops import rocm_aiter_ops
from vllm.config import VllmConfig
from vllm.config.cache import CacheDType
@@ -14,6 +15,7 @@ from vllm.logger import init_logger
from vllm.model_executor.layers.attention.mla_attention import (
get_mla_dims,
)
from vllm.platforms import current_platform
from vllm.triton_utils import tl, triton
from vllm.v1.attention.backend import (
AttentionBackend,
@@ -25,9 +27,6 @@ from vllm.v1.attention.backend import (
MultipleOf,
SparseMLAAttentionImpl,
)
from vllm.v1.attention.backends.mla.flashmla_sparse import (
triton_convert_req_index_to_global_index,
)
from vllm.v1.attention.backends.mla.rocm_aiter_mla import (
AiterMLAHelper,
)
@@ -38,6 +37,188 @@ if TYPE_CHECKING:
logger = init_logger(__name__)
@triton.jit
def _convert_req_index_to_global_index_kernel(
req_id_ptr, # int32 [num_tokens]
block_table_ptr, # int32 [num_requests, max_num_blocks_per_req]
token_indices_ptr, # int32 [num_tokens, NUM_TOPK_TOKENS]
cu_seqlens_ptr, # int32 [num_tokens + 1]
out_ptr, # int32 [num_tokens, NUM_TOPK_TOKENS]
# shapes (compile-time where possible)
max_num_blocks_per_req: tl.constexpr,
BLOCK_SIZE: tl.constexpr,
BLOCK_N: tl.constexpr, # tile width along columns
# strides (in elements)
bt_stride0,
bt_stride1,
ti_stride0,
ti_stride1,
):
# program_id(0) -> token_id (row)
# program_id(1) -> tile index along columns
token_id = tl.program_id(0)
tile_id = tl.program_id(1)
# Each program covers BLOCK_N consecutive columns
indice_id = tile_id * BLOCK_N + tl.arange(0, BLOCK_N)
# Load request id for this token (no mask: grid is exact)
req = tl.load(req_id_ptr + token_id)
# Load cumulative sequence lengths to get starting index of this request
seq_start = tl.load(cu_seqlens_ptr + token_id)
seq_end = tl.load(cu_seqlens_ptr + token_id + 1)
if tile_id * BLOCK_N + seq_start >= seq_end:
return
# Load token indices for this tile
ti_ptr = token_indices_ptr + token_id * ti_stride0 + indice_id * ti_stride1
tok = tl.load(ti_ptr) # int32
# Only token == -1 should propagate as -1
is_invalid_tok = tok < 0
# Compute block id and in-block offset
block_id = tok // BLOCK_SIZE
inblock_off = tok % BLOCK_SIZE
# Guard block_table access
valid_block = (block_id < max_num_blocks_per_req) & (block_id >= 0)
bt_ptr = block_table_ptr + req * bt_stride0 + block_id * bt_stride1
base = tl.load(bt_ptr, mask=valid_block, other=0)
# # If token == -1 OR block_id OOB, output 0; else base * BLOCK_SIZE + offset
out_val = tl.where(
is_invalid_tok | (~valid_block), 0, base * BLOCK_SIZE + inblock_off
)
out_ptr_ij = out_ptr + seq_start + indice_id
out_ptr_ij_mask = (seq_start + indice_id) < seq_end
# store the results with mask
tl.store(out_ptr_ij, out_val, mask=out_ptr_ij_mask)
def triton_convert_req_index_to_global_index(
req_id: torch.Tensor, # int32 [num_tokens]
block_table: torch.Tensor, # int32 [num_requests, max_num_blocks_per_req]
token_indices: torch.Tensor, # int32 [num_tokens, NUM_TOPK_TOKENS]
cu_seqlens: torch.Tensor, # int32 [num_tokens + 1]
paged_kv_indices: torch.Tensor, # int32 [num_tokens * topk] out_buffer
BLOCK_SIZE: int = 64,
NUM_TOPK_TOKENS: int = 2048,
BLOCK_N: int = 128, # tile width along columns
):
"""
out[token_id, indice_id] =
block_table[req_id[token_id],
token_indices[token_id, indice_id] // BLOCK_SIZE] * BLOCK_SIZE
+ token_indices[token_id, indice_id] % BLOCK_SIZE
Only when token_indices[token_id, indice_id] == -1 do we output -1.
For safety, we also output -1 if the derived block_id would be
out-of-bounds.
"""
assert req_id.dtype == torch.int32
assert block_table.dtype == torch.int32
assert token_indices.dtype == torch.int32
assert token_indices.shape[1] == NUM_TOPK_TOKENS
assert NUM_TOPK_TOKENS % BLOCK_N == 0, (
f"NUM_TOPK_TOKENS ({NUM_TOPK_TOKENS}) must be divisible byBLOCK_N ({BLOCK_N})"
)
# print("req_id: ", req_id, flush=True)
num_tokens = req_id.shape[0]
_, max_num_blocks_per_req = block_table.shape
tiles_per_row = NUM_TOPK_TOKENS // BLOCK_N
# Ensure contiguous tensors on the same device
req_id_c = req_id.contiguous()
block_table_c = block_table.contiguous()
token_indices_c = token_indices.contiguous()
# Strides in elements
bt_stride0, bt_stride1 = block_table_c.stride()
ti_stride0, ti_stride1 = token_indices_c.stride()
# Exact 2D grid: tokens × column tiles
grid = (num_tokens, tiles_per_row)
_convert_req_index_to_global_index_kernel[grid](
req_id_c,
block_table_c,
token_indices_c,
cu_seqlens,
paged_kv_indices,
# shapes / constexprs
max_num_blocks_per_req,
BLOCK_SIZE,
BLOCK_N,
# strides
bt_stride0,
bt_stride1,
ti_stride0,
ti_stride1,
)
return
@triton.jit
def generate_sparse_seqlen_kernel(
seq_len_ptr, # [num_seq]
cu_query_lens_ptr, # [num_seq]
out_ptr, # [num_query_tokens]
topk_token: tl.constexpr,
BLOCK_SIZE: tl.constexpr,
):
seq_id = tl.program_id(0)
query_offset = tl.program_id(1) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
query_start = tl.load(cu_query_lens_ptr + seq_id)
query_end = tl.load(cu_query_lens_ptr + seq_id + 1)
if query_start + tl.program_id(1) * BLOCK_SIZE > query_end:
return
query_len = query_end - query_start
query_mask = query_offset + query_start < query_end
seq_len = tl.load(seq_len_ptr + seq_id)
# Just return since the out_ptr is zero initialized.
if seq_len == 0:
return
context_start_point = seq_len - query_len
sparse_seqlen = context_start_point + query_offset
sparse_seqlen_masked = tl.where(
sparse_seqlen + 1 < topk_token, sparse_seqlen + 1, topk_token
)
tl.store(
out_ptr + query_start + query_offset, sparse_seqlen_masked, mask=query_mask
)
def generate_sparse_seqlen_triton(
query_lens: torch.Tensor,
seq_lens: torch.Tensor,
cu_query_lens: torch.Tensor,
topk_token: int,
num_tokens: int,
max_query_len: int,
):
num_seqs = query_lens.size(0)
# zero initialize the tensor to make sure invalid positions will be zero
out = torch.zeros([num_tokens], dtype=torch.int32, device=query_lens.device)
block_size = 64
num_block_per_row = triton.cdiv(max_query_len, block_size)
grid = (
num_seqs,
num_block_per_row,
)
generate_sparse_seqlen_kernel[grid](
seq_lens,
cu_query_lens,
out,
topk_token,
block_size,
)
return out
@triton.jit
def fetch_id_to_ragged_kernel(
in_tensor_ptr, # [num_seq, topk]
@@ -86,11 +267,13 @@ class ROCMAiterMLASparseBackend(AttentionBackend):
"auto",
"float16",
"bfloat16",
"fp8",
"fp8_e4m3",
]
@staticmethod
def get_supported_kernel_block_sizes() -> list[int | MultipleOf]:
return [1]
return [1, 64]
@staticmethod
def get_name() -> str:
@@ -144,7 +327,7 @@ class ROCMAiterMLASparseMetadata(AttentionMetadata):
paged_kv_last_page_len: torch.Tensor
paged_kv_indices: torch.Tensor
paged_kv_indptr: torch.Tensor
paged_kv_indptr_rest: torch.Tensor
attn_out_dtype: torch.dtype
block_size: int = 1
topk_tokens: int = 2048
@@ -167,6 +350,7 @@ class ROCMAiterMLASparseMetadataBuilder(
):
self.kv_cache_spec = kv_cache_spec
self.model_config = vllm_config.model_config
self.model_dtype = vllm_config.model_config.dtype
parallel_config = vllm_config.parallel_config
self.device = device
max_num_batched_tokens = vllm_config.scheduler_config.max_num_batched_tokens
@@ -174,9 +358,6 @@ class ROCMAiterMLASparseMetadataBuilder(
self.num_heads = self.model_config.get_num_attention_heads(parallel_config)
self.mla_dims = get_mla_dims(self.model_config)
self.topk_tokens = vllm_config.model_config.hf_config.index_topk
self.topk_tokens_tensor = torch.tensor(
[self.topk_tokens], device=device, dtype=torch.int32
)
self.max_model_len_tensor = torch.tensor(
[self.model_config.max_model_len], device=device, dtype=torch.int32
)
@@ -222,18 +403,33 @@ class ROCMAiterMLASparseMetadataBuilder(
)
# Zero-fill for cudagraphs
self.req_id_per_token_buffer.fill_(0)
self.paged_kv_indices.fill_(0)
self.paged_kv_indptr.fill_(0)
self.req_id_per_token_buffer[: req_id_per_token.shape[0]].copy_(
torch.from_numpy(req_id_per_token), non_blocking=True
)
self.paged_kv_indices.fill_(0)
self.paged_kv_indptr.fill_(0)
query_lens = (
common_attn_metadata.query_start_loc[1:]
- common_attn_metadata.query_start_loc[:-1]
)
seq_lens = common_attn_metadata.seq_lens
sparse_seqlen = generate_sparse_seqlen_triton(
query_lens,
seq_lens,
common_attn_metadata.query_start_loc,
self.topk_tokens,
num_tokens,
common_attn_metadata.max_query_len,
)
torch.cumsum(sparse_seqlen, dim=0, out=self.paged_kv_indptr[1 : num_tokens + 1])
self.paged_kv_indptr[num_tokens + 1 :].fill_(self.paged_kv_indptr[num_tokens])
req_id_per_token = self.req_id_per_token_buffer[:num_tokens]
qo_indptr = self.qo_indptr[: num_tokens + 1]
paged_kv_last_page_len = self.paged_kv_last_page_len[:num_tokens]
paged_kv_indices = self.paged_kv_indices[: num_tokens * self.topk_tokens]
paged_kv_indptr = self.paged_kv_indptr[: num_tokens + 1]
paged_kv_indptr_rest = self.paged_kv_indptr[num_tokens + 1 :]
paged_kv_indices = self.paged_kv_indices[: num_tokens * self.topk_tokens]
metadata = ROCMAiterMLASparseMetadata(
num_reqs=common_attn_metadata.num_reqs,
@@ -245,12 +441,12 @@ class ROCMAiterMLASparseMetadataBuilder(
block_table=common_attn_metadata.block_table_tensor,
req_id_per_token=req_id_per_token,
block_size=self.kv_cache_spec.block_size,
attn_out_dtype=self.model_dtype,
topk_tokens=self.topk_tokens,
qo_indptr=qo_indptr,
paged_kv_last_page_len=paged_kv_last_page_len,
paged_kv_indices=paged_kv_indices,
paged_kv_indptr=paged_kv_indptr,
paged_kv_indptr_rest=paged_kv_indptr_rest,
)
return metadata
@@ -314,29 +510,20 @@ class ROCMAiterMLASparseImpl(SparseMLAAttentionImpl[ROCMAiterMLASparseMetadata])
assert indexer is not None
self.topk_indices_buffer: torch.Tensor | None = indexer.topk_indices_buffer
def _forward_bf16_kv(
def _forward_mla(
self,
layer: AttentionLayer,
q: torch.Tensor, # [sq, heads, d_qk]
kv_c_and_k_pe_cache: torch.Tensor, # [blocks, heads, d_qk]
topk_indices: torch.Tensor, # [sq, topk]
attn_metadata: ROCMAiterMLASparseMetadata,
) -> torch.Tensor:
num_tokens = q.shape[0]
mla_num_heads = AiterMLAHelper.get_actual_mla_num_heads(self.num_heads)
output = torch.empty(
[num_tokens, mla_num_heads, self.kv_lora_rank],
dtype=q.dtype,
dtype=attn_metadata.attn_out_dtype,
device=q.device,
)
seq_len = (topk_indices != -1).sum(dim=-1)
torch.cumsum(seq_len, dim=0, out=attn_metadata.paged_kv_indptr[1:])
attn_metadata.paged_kv_indptr_rest.fill_(attn_metadata.paged_kv_indptr[-1])
fetch_id_to_ragged_triton(
topk_indices,
attn_metadata.paged_kv_indptr,
attn_metadata.paged_kv_indices,
attn_metadata.topk_tokens,
)
rocm_aiter_ops.mla_decode_fwd(
q,
@@ -348,6 +535,8 @@ class ROCMAiterMLASparseImpl(SparseMLAAttentionImpl[ROCMAiterMLASparseMetadata])
attn_metadata.paged_kv_indptr,
attn_metadata.paged_kv_indices,
attn_metadata.paged_kv_last_page_len,
q_scale=layer._q_scale,
kv_scale=layer._k_scale,
)
return AiterMLAHelper.get_mla_unpadded_o(self.num_heads, output)
@@ -366,23 +555,32 @@ class ROCMAiterMLASparseImpl(SparseMLAAttentionImpl[ROCMAiterMLASparseMetadata])
if isinstance(q, tuple):
q = torch.cat(q, dim=-1)
num_actual_toks = q.shape[0]
num_actual_toks = attn_metadata.num_actual_tokens
# Get topk indices
assert self.topk_indices_buffer is not None
topk_indices = self.topk_indices_buffer[:num_actual_toks]
topk_indices_global = triton_convert_req_index_to_global_index(
triton_convert_req_index_to_global_index(
attn_metadata.req_id_per_token,
attn_metadata.block_table,
topk_indices,
attn_metadata.paged_kv_indptr,
attn_metadata.paged_kv_indices,
BLOCK_SIZE=attn_metadata.block_size,
NUM_TOPK_TOKENS=attn_metadata.topk_tokens,
)
# write the latent and rope to kv cache
fp8_attention = self.kv_cache_dtype.startswith("fp8")
if fp8_attention:
original_q_shape = q.shape
kv_c_and_k_pe_cache = kv_c_and_k_pe_cache.view(current_platform.fp8_dtype())
q, _ = ops.scaled_fp8_quant(q.view(q.shape[0], -1), layer._q_scale)
q = q.view(original_q_shape)
mla_padded_q = AiterMLAHelper.get_mla_padded_q(self.num_heads, q)
attn_out = self._forward_bf16_kv(
mla_padded_q, kv_c_and_k_pe_cache, topk_indices_global, attn_metadata
attn_out = self._forward_mla(
layer, mla_padded_q, kv_c_and_k_pe_cache, attn_metadata
)
return attn_out, None
+22 -19
View File
@@ -13,9 +13,6 @@ from vllm.utils.torch_utils import LayerNameType
from vllm.v1.attention.backends.mla.indexer import DeepseekV32IndexerMetadata
from vllm.v1.attention.ops.common import pack_seq_triton, unpack_seq_triton
if current_platform.is_cuda_alike():
from vllm import _custom_ops as ops
@triton.jit
def _indexer_k_quant_and_cache_kernel(
@@ -97,7 +94,8 @@ def indexer_k_quant_and_cache_triton(
# In real layout, we store the first portion as kv cache value
# and second portion as kv cache scale
kv_cache = kv_cache.view(num_blocks, -1)
kv_cache_value = kv_cache[:, : block_size * head_dim]
fp8_dtype = current_platform.fp8_dtype()
kv_cache_value = kv_cache[:, : block_size * head_dim].view(fp8_dtype)
kv_cache_scale = kv_cache[:, block_size * head_dim :].view(torch.float32)
head_tile_size = head_tile_size // kv_cache.element_size()
grid = (num_tokens,)
@@ -111,7 +109,7 @@ def indexer_k_quant_and_cache_triton(
block_size,
num_tokens,
head_dim,
"NHD",
"SHUFFLE",
block_tile_size,
head_tile_size,
IS_FNUZ=current_platform.fp8_dtype() == torch.float8_e4m3fnuz,
@@ -212,7 +210,7 @@ def cp_gather_indexer_k_quant_cache_triton(
block_table_stride,
k_cache_value.stride(0),
k_cache_scale.stride(0),
"NHD",
"SHUFFLE",
head_dim,
block_tile_size,
head_tile_size,
@@ -325,33 +323,38 @@ def rocm_fp8_paged_mqa_logits(
from vllm._aiter_ops import rocm_aiter_ops
aiter_paged_mqa_logits_module = None
# if rocm_aiter_ops.is_enabled():
batch_size, next_n, heads, head_dim = q_fp8.shape
num_blocks, block_size, _, _ = kv_cache_fp8.shape
if rocm_aiter_ops.is_enabled():
aiter_paged_mqa_logits_module = paged_mqa_logits_module()
if aiter_paged_mqa_logits_module is not None:
deepgemm_fp8_paged_mqa_logits_stage1 = (
aiter_paged_mqa_logits_module.deepgemm_fp8_paged_mqa_logits_stage1
deepgemm_fp8_paged_mqa_logits = (
aiter_paged_mqa_logits_module.deepgemm_fp8_paged_mqa_logits
)
batch_size, next_n, heads, _ = q_fp8.shape
out_qk = torch.full(
(heads, batch_size * next_n, max_model_len),
out_logits = torch.full(
[batch_size * next_n, max_model_len],
float("-inf"),
device="cuda",
dtype=torch.float32,
)
# TODO: 1. Replace _stage1 and out_qk.sum with another fused variant;
# 2. Remove ChunkQ when AITER PR #2891 merged
deepgemm_fp8_paged_mqa_logits_stage1(
deepgemm_fp8_paged_mqa_logits(
q_fp8,
kv_cache_fp8,
weights,
out_qk,
out_logits,
context_lens,
block_tables,
max_model_len,
ChunkQ=heads,
ChunkK=256,
Preshuffle=block_size == 64,
KVBlockSize=block_size,
WavePerEU=2,
)
return out_qk.sum(dim=0)
return out_logits
else:
return fp8_paged_mqa_logits_torch(
q_fp8, kv_cache_fp8, weights, context_lens, block_tables, max_model_len
@@ -540,7 +543,7 @@ def rocm_aiter_sparse_attn_indexer(
num_tokens = slot_mapping.shape[0]
k = k[:num_tokens]
ops.indexer_k_quant_and_cache(
indexer_k_quant_and_cache_triton(
k,
kv_cache,
slot_mapping,
@@ -563,13 +566,13 @@ def rocm_aiter_sparse_attn_indexer(
device=k.device,
dtype=torch.uint8,
)
ops.cp_gather_indexer_k_quant_cache(
cp_gather_indexer_k_quant_cache_triton(
kv_cache,
k_fp8,
k_scale,
chunk.block_table,
chunk.cu_seq_lens,
chunk.token_to_seq,
)
logits = rocm_fp8_mqa_logits(