main
py 817 lines 22.6 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 # Adapted from
5 # https://github.com/sgl-project/sglang/blob/9f635ea50de920aa507f486daafba26a5b837574/python/sglang/srt/layers/attention/triton_ops/decode_attention.py
6 # which was originally adapted from
7 # https://github.com/ModelTC/lightllm/blob/96353e868a840db4d103138caf15ed9dbea8c186/lightllm/models/deepseek2/triton_kernel/gqa_flash_decoding_stage1.py
8 # https://github.com/ModelTC/lightllm/blob/96353e868a840db4d103138caf15ed9dbea8c186/lightllm/models/deepseek2/triton_kernel/gqa_flash_decoding_stage2.py
9
10 # Changes:
11 # - Add support for page size >= 1.
12
13 # Copyright 2025 vLLM Team
14 # Copyright 2023-2024 SGLang Team
15 # Licensed under the Apache License, Version 2.0 (the "License");
16 # you may not use this file except in compliance with the License.
17 # You may obtain a copy of the License at
18 #
19 # http://www.apache.org/licenses/LICENSE-2.0
20 #
21 # Unless required by applicable law or agreed to in writing, software
22 # distributed under the License is distributed on an "AS IS" BASIS,
23 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24 # See the License for the specific language governing permissions and
25 # limitations under the License.
26 # ==============================================================================
27 """Memory-efficient attention for decoding.
28 It supports page size >= 1.
29 """
30
31 import logging
32
33 import torch
34 from packaging import version
35
36 from vllm.platforms import current_platform
37 from vllm.triton_utils import tl, triton
38
39 is_hip_ = current_platform.is_rocm()
40
41 logger = logging.getLogger(__name__)
42
43 # Only print the following warnings when triton version < 3.2.0.
44 # The issue won't affect performance or accuracy.
45 if version.parse(triton.__version__) < version.parse("3.2.0"):
46 logger.warning(
47 "The following error message 'operation scheduled before its operands' "
48 "can be ignored."
49 )
50
51
52 @triton.jit
53 def tanh(x):
54 # Tanh is just a scaled sigmoid
55 return 2 * tl.sigmoid(2 * x) - 1
56
57
58 def _page_stride(buf, page_size):
59 # Stride between pages. 4D buffers have a page dim; 3D buffers pack pages
60 # along the token dim, so split it out first. Read the real stride (a
61 # cross-layer view has gaps), don't assume PAGE_SIZE * token stride.
62 if buf.ndim == 3:
63 buf = buf.unflatten(-3, (-1, page_size))
64 return buf.stride(-4)
65
66
67 @triton.jit
68 def _fwd_kernel_stage1(
69 Q,
70 K_Buffer,
71 V_Buffer,
72 sm_scale,
73 Req_to_tokens,
74 B_Seqlen,
75 Att_Out,
76 stride_req_to_tokens_b,
77 stride_qbs,
78 stride_qh,
79 stride_buf_kpbs,
80 stride_buf_kbs,
81 stride_buf_kh,
82 stride_buf_vpbs,
83 stride_buf_vbs,
84 stride_buf_vh,
85 stride_mid_ob,
86 stride_mid_oh,
87 stride_mid_os,
88 k_scale,
89 v_scale,
90 kv_group_num: tl.constexpr,
91 BLOCK_DMODEL: tl.constexpr,
92 BLOCK_DV: tl.constexpr,
93 BLOCK_N: tl.constexpr,
94 NUM_KV_SPLITS: tl.constexpr,
95 PAGE_SIZE: tl.constexpr,
96 logit_cap: tl.constexpr,
97 Lk: tl.constexpr,
98 Lv: tl.constexpr,
99 ):
100 cur_batch = tl.program_id(0)
101 cur_head = tl.program_id(1)
102 split_kv_id = tl.program_id(2)
103
104 cur_kv_head = cur_head // kv_group_num
105
106 offs_d = tl.arange(0, BLOCK_DMODEL)
107 offs_dv = tl.arange(0, BLOCK_DV)
108 mask_d = offs_d < Lk
109 mask_dv = offs_dv < Lv
110 cur_batch_seq_len = tl.load(B_Seqlen + cur_batch)
111 cur_batch_req_idx = cur_batch
112
113 off_q = cur_batch * stride_qbs + cur_head * stride_qh + offs_d
114 q = tl.load(Q + off_q, mask=mask_d, other=0.0)
115
116 kv_len_per_split = tl.cdiv(cur_batch_seq_len, NUM_KV_SPLITS)
117 split_kv_start = kv_len_per_split * split_kv_id
118 split_kv_end = tl.minimum(split_kv_start + kv_len_per_split, cur_batch_seq_len)
119
120 e_max = -float("inf")
121 e_sum = 0.0
122 acc = tl.zeros([BLOCK_DV], dtype=tl.float32)
123
124 if split_kv_end > split_kv_start:
125 ks = tl.load(k_scale)
126 vs = tl.load(v_scale)
127 for start_n in range(split_kv_start, split_kv_end, BLOCK_N):
128 offs_n = start_n + tl.arange(0, BLOCK_N)
129 kv_page_number = tl.load(
130 Req_to_tokens
131 + stride_req_to_tokens_b * cur_batch_req_idx
132 + offs_n // PAGE_SIZE,
133 mask=offs_n < split_kv_end,
134 other=0,
135 ).to(tl.int64) # page_number * page stride overflows int32
136 kv_in_page = offs_n % PAGE_SIZE
137 offs_buf_k = (
138 (kv_page_number * stride_buf_kpbs + kv_in_page * stride_buf_kbs)[
139 :, None
140 ]
141 + cur_kv_head * stride_buf_kh
142 + offs_d[None, :]
143 )
144 k = tl.load(
145 K_Buffer + offs_buf_k,
146 mask=(offs_n[:, None] < split_kv_end) & (mask_d[None, :]),
147 other=0.0,
148 )
149 if k.dtype.is_fp8():
150 k = (k.to(tl.float32) * ks).to(q.dtype)
151 qk = tl.sum(q[None, :] * k, 1)
152 qk *= sm_scale
153
154 if logit_cap > 0:
155 qk = logit_cap * tanh(qk / logit_cap)
156
157 qk = tl.where(offs_n < split_kv_end, qk, float("-inf"))
158
159 offs_buf_v = (
160 (kv_page_number * stride_buf_vpbs + kv_in_page * stride_buf_vbs)[
161 :, None
162 ]
163 + cur_kv_head * stride_buf_vh
164 + offs_dv[None, :]
165 )
166 v = tl.load(
167 V_Buffer + offs_buf_v,
168 mask=(offs_n[:, None] < split_kv_end) & (mask_dv[None, :]),
169 other=0.0,
170 )
171 if v.dtype.is_fp8():
172 v = (v.to(tl.float32) * vs).to(q.dtype)
173
174 n_e_max = tl.maximum(tl.max(qk, 0), e_max)
175 re_scale = tl.exp(e_max - n_e_max)
176 p = tl.exp(qk - n_e_max)
177 acc *= re_scale
178 acc += tl.sum(p[:, None] * v, 0)
179
180 e_sum = e_sum * re_scale + tl.sum(p, 0)
181 e_max = n_e_max
182
183 offs_mid_o = (
184 cur_batch * stride_mid_ob
185 + cur_head * stride_mid_oh
186 + split_kv_id * stride_mid_os
187 + offs_dv
188 )
189
190 tl.store(
191 Att_Out + offs_mid_o,
192 acc / e_sum,
193 mask=(mask_dv),
194 )
195
196 offs_mid_o_1 = (
197 cur_batch * stride_mid_ob
198 + cur_head * stride_mid_oh
199 + split_kv_id * stride_mid_os
200 + Lv
201 )
202
203 tl.store(
204 Att_Out + offs_mid_o_1,
205 e_max + tl.log(e_sum),
206 )
207
208
209 def _decode_att_m_fwd(
210 q,
211 k_buffer,
212 v_buffer,
213 att_out,
214 Req_to_tokens,
215 B_Seqlen,
216 num_kv_splits,
217 sm_scale,
218 page_size,
219 logit_cap,
220 k_scale,
221 v_scale,
222 ):
223 BLOCK = 64 if not is_hip_ else 8
224
225 NUM_KV_SPLITS = num_kv_splits
226 Lk = k_buffer.shape[-1]
227 Lv = v_buffer.shape[-1]
228
229 batch, head_num = q.shape[0], q.shape[1]
230
231 grid = (batch, head_num, NUM_KV_SPLITS)
232 kv_group_num = q.shape[1] // k_buffer.shape[-2]
233
234 num_warps = 4
235 if kv_group_num != 1:
236 num_warps = 1 if is_hip_ else 2
237
238 BLOCK_DMODEL = triton.next_power_of_2(Lk)
239 BLOCK_DV = triton.next_power_of_2(Lv)
240
241 _fwd_kernel_stage1[grid](
242 q,
243 k_buffer,
244 v_buffer,
245 sm_scale,
246 Req_to_tokens,
247 B_Seqlen,
248 att_out,
249 Req_to_tokens.stride(0),
250 q.stride(0),
251 q.stride(1),
252 _page_stride(k_buffer, page_size),
253 k_buffer.stride(-3), # Assume (..., PAGE_SIZE, NUM_HEADS, HEAD_DIM)
254 k_buffer.stride(-2), # Assume (..., PAGE_SIZE, NUM_HEADS, HEAD_DIM)
255 _page_stride(v_buffer, page_size),
256 v_buffer.stride(-3), # Assume (..., PAGE_SIZE, NUM_HEADS, HEAD_DIM)
257 v_buffer.stride(-2), # Assume (..., PAGE_SIZE, NUM_HEADS, HEAD_DIM)
258 att_out.stride(0),
259 att_out.stride(1),
260 att_out.stride(2),
261 k_scale,
262 v_scale,
263 kv_group_num=kv_group_num,
264 BLOCK_DMODEL=BLOCK_DMODEL,
265 BLOCK_DV=BLOCK_DV,
266 BLOCK_N=BLOCK,
267 NUM_KV_SPLITS=NUM_KV_SPLITS,
268 PAGE_SIZE=page_size,
269 logit_cap=logit_cap,
270 num_warps=num_warps,
271 num_stages=2,
272 Lk=Lk,
273 Lv=Lv,
274 )
275
276
277 @triton.jit
278 def _fwd_grouped_kernel_stage1(
279 Q,
280 K_Buffer,
281 V_Buffer,
282 sm_scale,
283 Req_to_tokens,
284 B_Seqlen,
285 Att_Out,
286 stride_req_to_tokens_b,
287 stride_qbs,
288 stride_qh,
289 stride_buf_kpbs,
290 stride_buf_kbs,
291 stride_buf_kh,
292 stride_buf_vpbs,
293 stride_buf_vbs,
294 stride_buf_vh,
295 stride_mid_ob,
296 stride_mid_oh,
297 stride_mid_os,
298 k_scale,
299 v_scale,
300 kv_group_num: tl.constexpr,
301 q_head_num: tl.constexpr,
302 BLOCK_DMODEL: tl.constexpr,
303 BLOCK_DPE: tl.constexpr,
304 BLOCK_DV: tl.constexpr,
305 BLOCK_N: tl.constexpr,
306 BLOCK_H: tl.constexpr,
307 NUM_KV_SPLITS: tl.constexpr,
308 PAGE_SIZE: tl.constexpr,
309 logit_cap: tl.constexpr,
310 Lk: tl.constexpr,
311 Lv: tl.constexpr,
312 IS_MLA: tl.constexpr = False,
313 ):
314 cur_batch = tl.program_id(0)
315 cur_head_id = tl.program_id(1)
316 cur_kv_head = cur_head_id // tl.cdiv(kv_group_num, BLOCK_H)
317 split_kv_id = tl.program_id(2)
318
319 VALID_BLOCK_H: tl.constexpr = BLOCK_H if kv_group_num > BLOCK_H else kv_group_num
320 cur_head = cur_head_id * VALID_BLOCK_H + tl.arange(0, BLOCK_H)
321 mask_h = cur_head < (cur_head_id + 1) * VALID_BLOCK_H
322 mask_h = mask_h & (cur_head < q_head_num)
323
324 offs_d = tl.arange(0, BLOCK_DMODEL)
325 offs_dv = tl.arange(0, BLOCK_DV)
326 mask_d = offs_d < Lk
327 mask_dv = offs_dv < Lv
328 cur_batch_seq_len = tl.load(B_Seqlen + cur_batch)
329 cur_batch_req_idx = cur_batch
330
331 offs_q = cur_batch * stride_qbs + cur_head[:, None] * stride_qh + offs_d[None, :]
332 q = tl.load(
333 Q + offs_q,
334 mask=(mask_h[:, None]) & (mask_d[None, :]),
335 other=0.0,
336 cache_modifier=".ca",
337 )
338
339 if BLOCK_DPE > 0:
340 offs_dpe = BLOCK_DMODEL + tl.arange(0, BLOCK_DPE)
341 mask_dpe = offs_dpe < Lk
342 off_qpe = (
343 cur_batch * stride_qbs + cur_head[:, None] * stride_qh + offs_dpe[None, :]
344 )
345 qpe = tl.load(
346 Q + off_qpe,
347 mask=(mask_h[:, None]) & (mask_dpe[None, :]),
348 other=0.0,
349 cache_modifier=".ca",
350 )
351
352 kv_len_per_split = tl.cdiv(cur_batch_seq_len, NUM_KV_SPLITS)
353 split_kv_start = kv_len_per_split * split_kv_id
354 split_kv_end = tl.minimum(split_kv_start + kv_len_per_split, cur_batch_seq_len)
355
356 e_max = tl.zeros([BLOCK_H], dtype=tl.float32) - float("inf")
357 e_sum = tl.zeros([BLOCK_H], dtype=tl.float32)
358 acc = tl.zeros([BLOCK_H, BLOCK_DV], dtype=tl.float32)
359
360 if split_kv_end > split_kv_start:
361 base_offs_k = cur_kv_head * stride_buf_kh + offs_d[:, None]
362 base_offs_v = cur_kv_head * stride_buf_vh + offs_dv[None, :]
363 if BLOCK_DPE > 0:
364 base_offs_kpe = cur_kv_head * stride_buf_kh + offs_dpe[:, None]
365
366 ks = tl.load(k_scale)
367 vs = tl.load(v_scale)
368 for start_n in tl.range(split_kv_start, split_kv_end, BLOCK_N):
369 offs_n = start_n + tl.arange(0, BLOCK_N)
370 kv_page_number = tl.load(
371 Req_to_tokens
372 + stride_req_to_tokens_b * cur_batch_req_idx
373 + offs_n // PAGE_SIZE,
374 mask=offs_n < split_kv_end,
375 other=0,
376 cache_modifier=".ca",
377 ).to(tl.int64) # page_number * page stride overflows int32
378 kv_off_k = (
379 kv_page_number * stride_buf_kpbs + (offs_n % PAGE_SIZE) * stride_buf_kbs
380 )
381
382 # explicitly facilitate overlapping load/compute
383 offs_buf_k = kv_off_k[None, :] + base_offs_k
384 k = tl.load(
385 K_Buffer + offs_buf_k,
386 mask=(offs_n[None, :] < split_kv_end) & (mask_d[:, None]),
387 other=0.0,
388 cache_modifier=".cg",
389 )
390
391 if k.dtype.is_fp8():
392 k = (k.to(tl.float32) * ks).to(q.dtype)
393 qk = tl.dot(q, k.to(q.dtype))
394 if BLOCK_DPE > 0:
395 offs_buf_kpe = kv_off_k[None, :] + base_offs_kpe
396 kpe = tl.load(
397 K_Buffer + offs_buf_kpe,
398 mask=(offs_n[None, :] < split_kv_end) & (mask_dpe[:, None]),
399 other=0.0,
400 cache_modifier=".cg",
401 )
402 if kpe.dtype.is_fp8():
403 kpe = (kpe.to(tl.float32) * ks).to(qpe.dtype)
404 qk += tl.dot(qpe, kpe.to(qpe.dtype))
405 qk *= sm_scale
406
407 if logit_cap > 0:
408 qk = logit_cap * tanh(qk / logit_cap)
409
410 qk = tl.where(
411 mask_h[:, None] & (offs_n[None, :] < split_kv_end), qk, float("-inf")
412 )
413
414 if not IS_MLA:
415 kv_off_v = (
416 kv_page_number * stride_buf_vpbs
417 + (offs_n % PAGE_SIZE) * stride_buf_vbs
418 )
419 offs_buf_v = kv_off_v[:, None] + base_offs_v
420 v = tl.load(
421 V_Buffer + offs_buf_v,
422 mask=(offs_n[:, None] < split_kv_end) & (mask_dv[None, :]),
423 other=0.0,
424 )
425 if v.dtype.is_fp8():
426 v = (v.to(tl.float32) * vs).to(q.dtype)
427 else:
428 # MLA uses a single c_kv.
429 # loading the same c_kv to interpret it as v is not necessary.
430 # transpose the existing c_kv (aka k) for the dot product.
431 v = tl.trans(k)
432
433 n_e_max = tl.maximum(tl.max(qk, 1), e_max)
434 re_scale = tl.exp(e_max - n_e_max)
435 p = tl.exp(qk - n_e_max[:, None])
436 acc *= re_scale[:, None]
437 acc += tl.dot(p.to(v.dtype), v)
438
439 e_sum = e_sum * re_scale + tl.sum(p, 1)
440 e_max = n_e_max
441
442 offs_mid_o = (
443 cur_batch * stride_mid_ob
444 + cur_head[:, None] * stride_mid_oh
445 + split_kv_id * stride_mid_os
446 + offs_dv[None, :]
447 )
448
449 tl.store(
450 Att_Out + offs_mid_o,
451 acc / e_sum[:, None],
452 mask=(mask_h[:, None]) & (mask_dv[None, :]),
453 )
454
455 offs_mid_o_1 = (
456 cur_batch * stride_mid_ob
457 + cur_head * stride_mid_oh
458 + split_kv_id * stride_mid_os
459 + Lv
460 )
461
462 tl.store(
463 Att_Out + offs_mid_o_1,
464 e_max + tl.log(e_sum),
465 mask=mask_h,
466 )
467
468
469 def _decode_grouped_att_m_fwd(
470 q,
471 k_buffer,
472 v_buffer,
473 att_out,
474 Req_to_tokens,
475 B_Seqlen,
476 num_kv_splits,
477 sm_scale,
478 page_size,
479 logit_cap,
480 k_scale,
481 v_scale,
482 is_mla=False,
483 ):
484 # with is_mla there is only a single c_kv in smem.
485 # could increase BLOCK or num_stages.
486 Lk = k_buffer.shape[-1]
487 Lv = v_buffer.shape[-1]
488
489 # Align tile dimensions with latent rank for MLA to avoid shape mismatch.
490 if is_mla:
491 if not is_hip_ and Lk == 576:
492 BLOCK_DMODEL = 512
493 BLOCK_DPE = 64
494 elif not is_hip_ and Lk == 288:
495 BLOCK_DMODEL = 256
496 BLOCK_DPE = 32
497 else:
498 BLOCK_DMODEL = triton.next_power_of_2(Lv)
499 BLOCK_DPE = triton.next_power_of_2(Lk - Lv) if Lk > Lv else 0
500 else:
501 BLOCK_DMODEL = triton.next_power_of_2(Lk)
502 BLOCK_DPE = 0
503 BLOCK_DV = triton.next_power_of_2(Lv)
504
505 BLOCK = 32
506 if is_hip_:
507 BLOCK = 16
508
509 batch, head_num = q.shape[0], q.shape[1]
510 kv_group_num = q.shape[1] // k_buffer.shape[-2]
511
512 BLOCK_H = 16
513 NUM_KV_SPLITS = num_kv_splits
514 grid = (
515 batch,
516 triton.cdiv(head_num, min(BLOCK_H, kv_group_num)),
517 NUM_KV_SPLITS,
518 )
519
520 extra_kargs = {}
521 num_stages = 2
522 if is_hip_:
523 # https://rocm.docs.amd.com/en/latest/how-to/rocm-for-ai/inference-optimization/workload.html#mi300x-triton-kernel-performance-optimization
524 # https://github.com/triton-lang/triton/blob/main/third_party/amd/backend/compiler.py
525 extra_kargs = {"waves_per_eu": 1, "matrix_instr_nonkdim": 16, "kpack": 2}
526 num_stages = 1
527 elif not is_hip_ and BLOCK_DMODEL >= 1024:
528 # Avoid shared memory overflow on NVIDIA when BLOCK_DMODEL is large
529 # like non-MLA D_QK=576, BLOCK_DMODEL=1024, BLOCK_H=16
530 # exceeds 101376 bytes limit
531 num_stages = 1
532
533 _fwd_grouped_kernel_stage1[grid](
534 q,
535 k_buffer,
536 v_buffer,
537 sm_scale,
538 Req_to_tokens,
539 B_Seqlen,
540 att_out,
541 Req_to_tokens.stride(0),
542 q.stride(0),
543 q.stride(1),
544 _page_stride(k_buffer, page_size),
545 k_buffer.stride(-3), # Assume (..., PAGE_SIZE, NUM_HEADS, HEAD_DIM)
546 k_buffer.stride(-2), # Assume (..., PAGE_SIZE, NUM_HEADS, HEAD_DIM)
547 _page_stride(v_buffer, page_size),
548 v_buffer.stride(-3), # Assume (..., PAGE_SIZE, NUM_HEADS, HEAD_DIM)
549 v_buffer.stride(-2), # Assume (..., PAGE_SIZE, NUM_HEADS, HEAD_DIM)
550 att_out.stride(0),
551 att_out.stride(1),
552 att_out.stride(2),
553 k_scale,
554 v_scale,
555 kv_group_num=kv_group_num,
556 q_head_num=head_num,
557 BLOCK_DMODEL=BLOCK_DMODEL,
558 BLOCK_DPE=BLOCK_DPE,
559 BLOCK_DV=BLOCK_DV,
560 BLOCK_N=BLOCK,
561 BLOCK_H=BLOCK_H,
562 NUM_KV_SPLITS=NUM_KV_SPLITS,
563 PAGE_SIZE=page_size,
564 logit_cap=logit_cap,
565 num_warps=4,
566 num_stages=num_stages,
567 Lk=Lk,
568 Lv=Lv,
569 IS_MLA=is_mla,
570 **extra_kargs,
571 )
572
573
574 @triton.jit
575 def _fwd_kernel_stage2(
576 Mid_O,
577 o,
578 lse,
579 B_Seqlen,
580 stride_mid_ob,
581 stride_mid_oh,
582 stride_mid_os,
583 stride_obs,
584 stride_oh,
585 stride_lse_bs,
586 NUM_KV_SPLITS: tl.constexpr,
587 BLOCK_DV: tl.constexpr,
588 Lv: tl.constexpr,
589 OUTPUT_FP16: tl.constexpr = 0,
590 ):
591 cur_batch = tl.program_id(0)
592 cur_head = tl.program_id(1)
593
594 cur_batch_seq_len = tl.load(B_Seqlen + cur_batch)
595
596 offs_d = tl.arange(0, BLOCK_DV)
597 mask_d = offs_d < Lv
598
599 e_sum = 0.0
600 e_max = -float("inf")
601 acc = tl.zeros([BLOCK_DV], dtype=tl.float32)
602
603 offs_v = cur_batch * stride_mid_ob + cur_head * stride_mid_oh + offs_d
604 offs_logic = cur_batch * stride_mid_ob + cur_head * stride_mid_oh + Lv
605
606 for split_kv_id in range(0, NUM_KV_SPLITS):
607 kv_len_per_split = tl.cdiv(cur_batch_seq_len, NUM_KV_SPLITS)
608 split_kv_start = kv_len_per_split * split_kv_id
609 split_kv_end = tl.minimum(split_kv_start + kv_len_per_split, cur_batch_seq_len)
610
611 if split_kv_end > split_kv_start:
612 tv = tl.load(
613 Mid_O + offs_v + split_kv_id * stride_mid_os, mask=mask_d, other=0.0
614 )
615 tlogic = tl.load(Mid_O + offs_logic + split_kv_id * stride_mid_os)
616 n_e_max = tl.maximum(tlogic, e_max)
617
618 old_scale = tl.exp(e_max - n_e_max)
619 acc *= old_scale
620 exp_logic = tl.exp(tlogic - n_e_max)
621 acc += exp_logic * tv
622
623 e_sum = e_sum * old_scale + exp_logic
624 e_max = n_e_max
625
626 result = acc / e_sum
627 if OUTPUT_FP16:
628 result = result.to(tl.float16)
629 tl.store(
630 o + cur_batch * stride_obs + cur_head * stride_oh + offs_d,
631 result,
632 mask=mask_d,
633 )
634 lse_val = e_max + tl.log(e_sum)
635 tl.store(
636 lse + cur_batch * stride_lse_bs + cur_head,
637 lse_val,
638 )
639
640
641 def _decode_softmax_reducev_fwd(
642 logits,
643 q,
644 o,
645 lse,
646 v_buffer,
647 b_seq_len,
648 num_kv_splits,
649 ):
650 batch, head_num = q.shape[0], q.shape[1]
651 Lv = v_buffer.shape[-1]
652 BLOCK_DV = triton.next_power_of_2(Lv)
653
654 NUM_KV_SPLITS = num_kv_splits
655
656 extra_kargs = {}
657 if is_hip_:
658 # https://rocm.docs.amd.com/en/docs-6.2.0/how-to/llm-fine-tuning-optimization/optimizing-triton-kernel.html
659 # https://github.com/triton-lang/triton/blob/main/third_party/amd/backend/compiler.py
660 extra_kargs = {"waves_per_eu": 4, "matrix_instr_nonkdim": 16, "kpack": 2}
661
662 grid = (batch, head_num)
663 _fwd_kernel_stage2[grid](
664 logits,
665 o,
666 lse,
667 b_seq_len,
668 logits.stride(0),
669 logits.stride(1),
670 logits.stride(2),
671 o.stride(0),
672 o.stride(1),
673 lse.stride(0),
674 NUM_KV_SPLITS=NUM_KV_SPLITS,
675 BLOCK_DV=BLOCK_DV,
676 Lv=Lv,
677 num_warps=4,
678 num_stages=2,
679 **extra_kargs,
680 )
681
682
683 def decode_attention_fwd_normal(
684 q,
685 k_buffer,
686 v_buffer,
687 o,
688 lse,
689 req_to_token,
690 b_seq_len,
691 attn_logits,
692 num_kv_splits,
693 sm_scale,
694 page_size,
695 logit_cap=0.0,
696 k_scale=None,
697 v_scale=None,
698 ):
699 _decode_att_m_fwd(
700 q,
701 k_buffer,
702 v_buffer,
703 attn_logits,
704 req_to_token,
705 b_seq_len,
706 num_kv_splits,
707 sm_scale,
708 page_size,
709 logit_cap,
710 k_scale,
711 v_scale,
712 )
713 _decode_softmax_reducev_fwd(
714 attn_logits, q, o, lse, v_buffer, b_seq_len, num_kv_splits
715 )
716
717
718 def decode_attention_fwd_grouped(
719 q,
720 k_buffer,
721 v_buffer,
722 o,
723 lse,
724 req_to_token,
725 b_seq_len,
726 attn_logits,
727 num_kv_splits,
728 sm_scale,
729 page_size,
730 logit_cap=0.0,
731 k_scale=None,
732 v_scale=None,
733 is_mla=False,
734 ):
735 _decode_grouped_att_m_fwd(
736 q,
737 k_buffer,
738 v_buffer,
739 attn_logits,
740 req_to_token,
741 b_seq_len,
742 num_kv_splits,
743 sm_scale,
744 page_size,
745 logit_cap,
746 k_scale,
747 v_scale,
748 is_mla=is_mla,
749 )
750 _decode_softmax_reducev_fwd(
751 attn_logits, q, o, lse, v_buffer, b_seq_len, num_kv_splits
752 )
753
754
755 def decode_attention_fwd(
756 q,
757 k_buffer,
758 v_buffer,
759 o,
760 lse,
761 req_to_token,
762 b_seq_len,
763 attn_logits,
764 num_kv_splits,
765 sm_scale,
766 page_size=1,
767 logit_cap=0.0,
768 k_scale=None,
769 v_scale=None,
770 is_mla=False,
771 ):
772 assert num_kv_splits == attn_logits.shape[2]
773
774 if k_scale is None:
775 k_scale = torch.tensor(1.0, dtype=torch.float32, device=q.device)
776 if v_scale is None:
777 v_scale = torch.tensor(1.0, dtype=torch.float32, device=q.device)
778
779 kv_group_num = q.shape[1] // v_buffer.shape[-2]
780
781 if kv_group_num == 1:
782 # MHA
783 decode_attention_fwd_normal(
784 q,
785 k_buffer,
786 v_buffer,
787 o,
788 lse,
789 req_to_token,
790 b_seq_len,
791 attn_logits,
792 num_kv_splits,
793 sm_scale,
794 page_size,
795 logit_cap,
796 k_scale,
797 v_scale,
798 )
799 else:
800 # GQA/MQA/MLA
801 decode_attention_fwd_grouped(
802 q,
803 k_buffer,
804 v_buffer,
805 o,
806 lse,
807 req_to_token,
808 b_seq_len,
809 attn_logits,
810 num_kv_splits,
811 sm_scale,
812 page_size,
813 logit_cap,
814 k_scale,
815 v_scale,
816 is_mla=is_mla,
817 )