[ROCm][Triton] Migrating MiniMax-M3 kernels from make_block_ptr to tensor descriptors (#59285)
Signed-off-by: jpvillam <juan.villamizar@amd.com> Signed-off-by: Daniel <danichan@amd.com> Co-authored-by: jpvillam <juan.villamizar@amd.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Rohan Potdar <rohan.potdar@amd.com> Co-authored-by: Daniel <danichan@amd.com>
This commit is contained in:
co-authored by
jpvillam
Claude Opus 5.5
Rohan Potdar
Daniel
parent
240ee8de9e
commit
d64a18832b
@@ -229,15 +229,16 @@ def _index_block_score_kernel(
|
||||
if BLOCK_SIZE_Q * pid_q >= q_len:
|
||||
return
|
||||
|
||||
q_ptrs = tl.make_block_ptr(
|
||||
q_desc = tl.make_tensor_descriptor(
|
||||
base=q_ptr + seq_start * stride_q_n + pid_h * stride_q_h,
|
||||
shape=(q_len, head_dim),
|
||||
strides=(stride_q_n, stride_q_d),
|
||||
offsets=(pid_q * BLOCK_SIZE_Q, 0),
|
||||
block_shape=(BLOCK_SIZE_Q, head_dim),
|
||||
order=(1, 0),
|
||||
shape=[q_len, head_dim],
|
||||
strides=[stride_q_n, stride_q_d],
|
||||
block_shape=[BLOCK_SIZE_Q, head_dim],
|
||||
padding_option="zero",
|
||||
)
|
||||
q = tl.load(q_ptrs, boundary_check=(0,), padding_option="zero")
|
||||
|
||||
# 2. Perform the load by providing the multi-dimensional offset directly
|
||||
q = q_desc.load([pid_q * BLOCK_SIZE_Q, 0])
|
||||
q_start = prefix_len + pid_q * BLOCK_SIZE_Q
|
||||
|
||||
off_q = tl.arange(0, BLOCK_SIZE_Q) + pid_q * BLOCK_SIZE_Q + prefix_len
|
||||
|
||||
@@ -139,15 +139,15 @@ def _gqa_sparse_fwd_kernel(
|
||||
off_t = tl.arange(0, BLOCK_SIZE_T)
|
||||
topk_idx = tl.load(t_ptr_j + off_t * stride_tk, mask=off_t < max_topk, other=-1)
|
||||
real_topk = tl.sum((topk_idx >= 0).to(tl.int32), axis=0)
|
||||
q_ptrs = tl.make_block_ptr(
|
||||
q_desc = tl.make_tensor_descriptor(
|
||||
base=q_ptr + q_start * stride_qn + pid_h * stride_qh,
|
||||
shape=(q_len, gqa_group_size, head_dim),
|
||||
strides=(stride_qn, stride_qh, stride_qd),
|
||||
offsets=(pid_q_j * BLOCK_SIZE_Q, 0, 0),
|
||||
block_shape=(BLOCK_SIZE_Q, BLOCK_SIZE_H, BLOCK_SIZE_D),
|
||||
order=(2, 1, 0),
|
||||
shape=[q_len, gqa_group_size, head_dim],
|
||||
strides=[stride_qn, stride_qh, stride_qd],
|
||||
block_shape=[BLOCK_SIZE_Q, BLOCK_SIZE_H, BLOCK_SIZE_D],
|
||||
padding_option="zero",
|
||||
)
|
||||
q = tl.load(q_ptrs, boundary_check=(0, 1, 2), padding_option="zero")
|
||||
|
||||
q = q_desc.load([pid_q_j * BLOCK_SIZE_Q, 0, 0])
|
||||
m_i = tl.full((BLOCK_SIZE_QH,), float("-inf"), dtype=tl.float32)
|
||||
lse_i = tl.full((BLOCK_SIZE_QH,), float("-inf"), dtype=tl.float32)
|
||||
acc_o = tl.zeros((BLOCK_SIZE_QH, BLOCK_SIZE_D), dtype=tl.float32)
|
||||
@@ -228,15 +228,17 @@ def _gqa_sparse_fwd_kernel(
|
||||
lse_i = m_ij + tl.log2(tl.exp2(lse_i - m_ij) + l_ij)
|
||||
acc_o = acc_o * tl.exp2(m_i - lse_i)[:, None]
|
||||
acc_o = tl.reshape(acc_o, BLOCK_SIZE_Q, BLOCK_SIZE_H, BLOCK_SIZE_D)
|
||||
o_ptrs = tl.make_block_ptr(
|
||||
o_desc = tl.make_tensor_descriptor(
|
||||
base=o_ptr + q_start * stride_on + pid_h * stride_oh,
|
||||
shape=(q_len, gqa_group_size, head_dim),
|
||||
strides=(stride_on, stride_oh, stride_od),
|
||||
offsets=(pid_q_j * BLOCK_SIZE_Q, 0, 0),
|
||||
block_shape=(BLOCK_SIZE_Q, BLOCK_SIZE_H, BLOCK_SIZE_D),
|
||||
order=(2, 1, 0),
|
||||
shape=[q_len, gqa_group_size, head_dim],
|
||||
strides=[stride_on, stride_oh, stride_od],
|
||||
block_shape=[BLOCK_SIZE_Q, BLOCK_SIZE_H, BLOCK_SIZE_D],
|
||||
)
|
||||
|
||||
o_desc.store(
|
||||
offsets=[pid_q_j * BLOCK_SIZE_Q, 0, 0],
|
||||
value=acc_o.to(o_ptr.dtype.element_ty),
|
||||
)
|
||||
tl.store(o_ptrs, acc_o.to(o_ptr.dtype.element_ty), boundary_check=(0, 1, 2))
|
||||
|
||||
|
||||
@torch.no_grad()
|
||||
|
||||
@@ -110,7 +110,9 @@ def _gqa_sparse_fwd_kernel(
|
||||
bt_row = block_table_ptr + pid_b * stride_bt_b
|
||||
off_n = tl.arange(0, BLOCK_SIZE_K)
|
||||
off_d = tl.arange(0, BLOCK_SIZE_D)
|
||||
off_h = tl.arange(0, BLOCK_SIZE_H)
|
||||
d_mask = off_d < head_dim
|
||||
h_mask = off_h < gqa_group_size
|
||||
for j in range(real_q_loop):
|
||||
pid_q_j = pid_q * num_q_loop + j
|
||||
t_ptr_j = t_ptr + (q_block_start + pid_q_j) * stride_tn + pid_kh * stride_th
|
||||
@@ -118,15 +120,20 @@ def _gqa_sparse_fwd_kernel(
|
||||
q_abs = prefix_len + pid_q_j * BLOCK_SIZE_Q
|
||||
valid_blocks = (q_abs + BLOCK_SIZE_K) // BLOCK_SIZE_K
|
||||
real_topk = tl.minimum(max_topk, valid_blocks)
|
||||
q_ptrs = tl.make_block_ptr(
|
||||
base=q_ptr + q_start * stride_qn + pid_h * stride_qh,
|
||||
shape=(q_len, gqa_group_size, head_dim),
|
||||
strides=(stride_qn, stride_qh, stride_qd),
|
||||
offsets=(pid_q_j * BLOCK_SIZE_Q, 0, 0),
|
||||
block_shape=(BLOCK_SIZE_Q, BLOCK_SIZE_H, BLOCK_SIZE_D),
|
||||
order=(2, 1, 0),
|
||||
off_qi = pid_q_j * BLOCK_SIZE_Q + tl.arange(0, BLOCK_SIZE_Q)
|
||||
qo_mask = (
|
||||
(off_qi < q_len)[:, None, None]
|
||||
& h_mask[None, :, None]
|
||||
& d_mask[None, None, :]
|
||||
)
|
||||
q = tl.load(
|
||||
q_ptr
|
||||
+ (q_start + off_qi)[:, None, None] * stride_qn
|
||||
+ (pid_h + off_h)[None, :, None] * stride_qh
|
||||
+ off_d[None, None, :] * stride_qd,
|
||||
mask=qo_mask,
|
||||
other=0.0,
|
||||
)
|
||||
q = tl.load(q_ptrs, boundary_check=(0, 1, 2), padding_option="zero")
|
||||
off_q = (
|
||||
tl.arange(0, BLOCK_SIZE_Q)[:, None]
|
||||
+ pid_q_j * BLOCK_SIZE_Q
|
||||
@@ -203,15 +210,14 @@ def _gqa_sparse_fwd_kernel(
|
||||
lse_i = m_ij + tl.log2(tl.exp2(lse_i - m_ij) + l_ij)
|
||||
acc_o = acc_o * tl.exp2(m_i - lse_i)[:, None]
|
||||
acc_o = tl.reshape(acc_o, BLOCK_SIZE_Q, BLOCK_SIZE_H, BLOCK_SIZE_D)
|
||||
o_ptrs = tl.make_block_ptr(
|
||||
base=o_ptr + q_start * stride_on + pid_h * stride_oh,
|
||||
shape=(q_len, gqa_group_size, head_dim),
|
||||
strides=(stride_on, stride_oh, stride_od),
|
||||
offsets=(pid_q_j * BLOCK_SIZE_Q, 0, 0),
|
||||
block_shape=(BLOCK_SIZE_Q, BLOCK_SIZE_H, BLOCK_SIZE_D),
|
||||
order=(2, 1, 0),
|
||||
tl.store(
|
||||
o_ptr
|
||||
+ (q_start + off_qi)[:, None, None] * stride_on
|
||||
+ (pid_h + off_h)[None, :, None] * stride_oh
|
||||
+ off_d[None, None, :] * stride_od,
|
||||
acc_o.to(o_ptr.dtype.element_ty),
|
||||
mask=qo_mask,
|
||||
)
|
||||
tl.store(o_ptrs, acc_o.to(o_ptr.dtype.element_ty), boundary_check=(0, 1, 2))
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -306,21 +312,23 @@ def _gqa_sparse_decode_kernel(
|
||||
|
||||
off_n = tl.arange(0, BLOCK_SIZE_K)
|
||||
off_d = tl.arange(0, BLOCK_SIZE_D)
|
||||
off_h = tl.arange(0, BLOCK_SIZE_H)
|
||||
d_mask = off_d < head_dim
|
||||
h_mask = off_h < gqa_group_size
|
||||
hd_mask = h_mask[:, None] & d_mask[None, :]
|
||||
bt_row = block_table_ptr + req_id * stride_bt_b
|
||||
|
||||
m_i = tl.full((BLOCK_SIZE_H,), float("-inf"), dtype=tl.float32)
|
||||
lse_i = tl.full((BLOCK_SIZE_H,), float("-inf"), dtype=tl.float32)
|
||||
acc_o = tl.zeros((BLOCK_SIZE_H, BLOCK_SIZE_D), dtype=tl.float32)
|
||||
q_ptrs = tl.make_block_ptr(
|
||||
base=q_ptr + pid_b * stride_qn + pid_h * stride_qh,
|
||||
shape=(gqa_group_size, head_dim),
|
||||
strides=(stride_qh, stride_qd),
|
||||
offsets=(0, 0),
|
||||
block_shape=(BLOCK_SIZE_H, BLOCK_SIZE_D),
|
||||
order=(1, 0),
|
||||
q = tl.load(
|
||||
q_ptr
|
||||
+ pid_b * stride_qn
|
||||
+ (pid_h + off_h)[:, None] * stride_qh
|
||||
+ off_d[None, :] * stride_qd,
|
||||
mask=hd_mask,
|
||||
other=0.0,
|
||||
)
|
||||
q = tl.load(q_ptrs, boundary_check=(0, 1), padding_option="zero")
|
||||
|
||||
cur_idx_ptr = idx_base + chunk_start_topk * stride_tk
|
||||
for _ in tl.range(chunk_start_topk, chunk_end_topk):
|
||||
@@ -392,24 +400,23 @@ def _gqa_sparse_decode_kernel(
|
||||
# can hit 0 * NaN. All-empty padded rows may still produce NaNs in merge.
|
||||
scale = tl.where(lse_i > float("-inf"), tl.exp2(m_i - lse_i), tl.zeros_like(lse_i))
|
||||
acc_o = acc_o * scale[:, None]
|
||||
o_ptrs = tl.make_block_ptr(
|
||||
base=o_ptr + pid_c * stride_o_c + pid_b * stride_o_b + pid_h * stride_o_h,
|
||||
shape=(gqa_group_size, head_dim),
|
||||
strides=(stride_o_h, stride_o_d),
|
||||
offsets=(0, 0),
|
||||
block_shape=(BLOCK_SIZE_H, BLOCK_SIZE_D),
|
||||
order=(1, 0),
|
||||
tl.store(
|
||||
o_ptr
|
||||
+ pid_c * stride_o_c
|
||||
+ pid_b * stride_o_b
|
||||
+ (pid_h + off_h)[:, None] * stride_o_h
|
||||
+ off_d[None, :] * stride_o_d,
|
||||
acc_o.to(o_ptr.dtype.element_ty),
|
||||
mask=hd_mask,
|
||||
)
|
||||
tl.store(o_ptrs, acc_o.to(o_ptr.dtype.element_ty), boundary_check=(0, 1))
|
||||
lse_ptrs = tl.make_block_ptr(
|
||||
base=lse_ptr + pid_c * stride_l_c + pid_b * stride_l_b + pid_h * stride_l_h,
|
||||
shape=(gqa_group_size,),
|
||||
strides=(stride_l_h,),
|
||||
offsets=(0,),
|
||||
block_shape=(BLOCK_SIZE_H,),
|
||||
order=(0,),
|
||||
tl.store(
|
||||
lse_ptr
|
||||
+ pid_c * stride_l_c
|
||||
+ pid_b * stride_l_b
|
||||
+ (pid_h + off_h) * stride_l_h,
|
||||
lse_i.to(lse_ptr.dtype.element_ty),
|
||||
mask=h_mask,
|
||||
)
|
||||
tl.store(lse_ptrs, lse_i.to(lse_ptr.dtype.element_ty), boundary_check=(0,))
|
||||
|
||||
|
||||
@triton.heuristics(
|
||||
@@ -444,16 +451,16 @@ def _merge_topk_attn_out_kernel(
|
||||
|
||||
off_c = tl.arange(0, NUM_TOPK_CHUNKS)
|
||||
off_d = tl.arange(0, BLOCK_SIZE_D)
|
||||
o_ptrs = tl.make_block_ptr(
|
||||
base=o_ptr + pid_b * stride_o_b + pid_h * stride_o_h,
|
||||
shape=(NUM_TOPK_CHUNKS, head_dim),
|
||||
strides=(stride_o_c, stride_o_d),
|
||||
offsets=(0, 0),
|
||||
block_shape=(NUM_TOPK_CHUNKS, BLOCK_SIZE_D),
|
||||
order=(1, 0),
|
||||
d_mask = off_d < head_dim
|
||||
o_ptrs = (
|
||||
o_ptr
|
||||
+ pid_b * stride_o_b
|
||||
+ pid_h * stride_o_h
|
||||
+ off_c[:, None] * stride_o_c
|
||||
+ off_d[None, :] * stride_o_d
|
||||
)
|
||||
lse_ptrs = lse_ptr + pid_b * stride_l_b + pid_h * stride_l_h + off_c * stride_l_c
|
||||
o = tl.load(o_ptrs, boundary_check=(0, 1), padding_option="zero")
|
||||
o = tl.load(o_ptrs, mask=d_mask[None, :], other=0.0)
|
||||
lse = tl.load(lse_ptrs) # empty chunks contribute -inf -> weight 0
|
||||
lse_max = tl.max(lse, axis=0)
|
||||
weights = tl.exp2(lse - lse_max)
|
||||
@@ -462,7 +469,7 @@ def _merge_topk_attn_out_kernel(
|
||||
out_ptrs = (
|
||||
out_ptr + pid_b * stride_out_n + pid_h * stride_out_h + off_d * stride_out_d
|
||||
)
|
||||
tl.store(out_ptrs, o_merged.to(out_ptr.dtype.element_ty), mask=off_d < head_dim)
|
||||
tl.store(out_ptrs, o_merged.to(out_ptr.dtype.element_ty), mask=d_mask)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user