@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 9f0247cfa4
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 13, 10:45 UTC

`VLLM_USE_TRITON_FLASH_ATTN` V0 variable deprecation (#27611)

Signed-off-by: Andreas Karatzas <akaratza@amd.com> Signed-off-by: Andreas Karatzas <Andreas.Karatzas@amd.com>

Andreas Karatzas committed Nov 11, 2025 at 20:34 UTC 9f0247cfa40a52356aa7860c163c062eb086d266
15 files changed +11 -1587
.buildkite/scripts/hardware_ci/run-amd-test.sh
+2 -6
@@ -78,17 +78,13 @@ HF_MOUNT="/root/.cache/huggingface"
78 commands=$@
79 echo "Commands:$commands"
80
81 -if [[ $commands == *"pytest -v -s basic_correctness/test_basic_correctness.py"* ]]; then
82 - commands=${commands//"pytest -v -s basic_correctness/test_basic_correctness.py"/"VLLM_USE_TRITON_FLASH_ATTN=0 pytest -v -s basic_correctness/test_basic_correctness.py"}
83 -fi
81 +commands=${commands//"pytest -v -s basic_correctness/test_basic_correctness.py"/"pytest -v -s basic_correctness/test_basic_correctness.py"}
82
83 if [[ $commands == *"pytest -v -s models/test_registry.py"* ]]; then
84 commands=${commands//"pytest -v -s models/test_registry.py"/"pytest -v -s models/test_registry.py -k 'not BambaForCausalLM and not GritLM and not Mamba2ForCausalLM and not Zamba2ForCausalLM'"}
85 fi
86
89 -if [[ $commands == *"pytest -v -s compile/test_basic_correctness.py"* ]]; then
90 - commands=${commands//"pytest -v -s compile/test_basic_correctness.py"/"VLLM_USE_TRITON_FLASH_ATTN=0 pytest -v -s compile/test_basic_correctness.py"}
91 -fi
87 +commands=${commands//"pytest -v -s compile/test_basic_correctness.py"/"pytest -v -s compile/test_basic_correctness.py"}
88
89 if [[ $commands == *"pytest -v -s lora"* ]]; then
90 commands=${commands//"pytest -v -s lora"/"VLLM_ROCM_CUSTOM_PAGED_ATTN=0 pytest -v -s lora"}
tests/kernels/test_triton_flash_attention.py deleted
-516
@@ -1,516 +0,0 @@
1 -# SPDX-License-Identifier: Apache-2.0
2 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -"""Tests for the triton_flash_attention kernel
4 -
5 -Run `pytest tests/kernels/test_triton_flash_attention.py`.
6 -"""
7 -
8 -import pytest
9 -import torch
10 -
11 -from vllm.attention.ops.triton_flash_attention import (
12 - SUPPORTED_LAYOUTS,
13 - MetaData,
14 - compute_alibi_tensor,
15 - scale_fp8,
16 - triton_attention_rocm,
17 -)
18 -from vllm.platforms import current_platform
19 -
20 -
21 -class ReferenceAttention:
22 - def __init__(
23 - self, Z, HQ, HK, N_CTX_Q, N_CTX_K, D_HEAD, use_alibi, dtype, input_metadata
24 - ):
25 - self.Z = Z
26 - self.HQ = HQ
27 - self.HK = HK
28 - self.N_CTX_Q = N_CTX_Q
29 - self.N_CTX_K = N_CTX_K
30 - self.D_HEAD = D_HEAD
31 - self.use_alibi = use_alibi
32 - self.dtype = dtype
33 - self.input_metadata = input_metadata
34 -
35 - def fwd(self, q, k, v):
36 - scores = (
37 - torch.einsum("bhqd,bhkd->bhqk", q, k).float() * self.input_metadata.sm_scale
38 - )
39 - if self.input_metadata.causal:
40 - mask = torch.tril(
41 - torch.ones(self.N_CTX_Q, self.N_CTX_K, device="cuda"),
42 - diagonal=self.N_CTX_K - self.N_CTX_Q,
43 - )
44 - scores[:, :, mask == 0] = float("-inf")
45 -
46 - if self.input_metadata.bias is not None:
47 - scores += self.input_metadata.bias
48 -
49 - if self.use_alibi:
50 - scores += compute_alibi_tensor(
51 - self.input_metadata.alibi_slopes, self.N_CTX_Q, self.N_CTX_K
52 - )
53 -
54 - p = torch.softmax(scores, dim=-1)
55 - if self.input_metadata.causal:
56 - # If N_CTX_Q > N_CTX_K, there's at least one row of all -infs going
57 - # into softmax. This creates a row of NaNs as -inf - -inf == NaN.
58 - # So we fix this by converting the NaNs to 0s, which is what they
59 - # should be out of the softmax.
60 - nan_mask = torch.isnan(p)
61 - p[nan_mask == 1] = 0
62 - ref_out = torch.einsum("bhqk,bhkd->bhqd", p.to(self.dtype), v)
63 - # compare
64 - if self.input_metadata.layout == "bshd":
65 - ref_out = ref_out.transpose(1, 2).clone()
66 - return ref_out
67 -
68 - def fwd_fp8(self, q_quantized, k_quantized, v_quantized):
69 - q = (q_quantized.to(torch.float16) * self.input_metadata.q_descale).to(
70 - self.dtype
71 - )
72 - k = (k_quantized.to(torch.float16) * self.input_metadata.k_descale).to(
73 - self.dtype
74 - )
75 - v = (v_quantized.to(torch.float16) * self.input_metadata.v_descale).to(
76 - self.dtype
77 - )
78 - result = self.fwd(q, k, v)
79 - if self.input_metadata.o_scale is not None:
80 - result, _ = scale_fp8(result, self.input_metadata.o_scale)
81 - return result
82 -
83 - def fwd_fp8_kv(self, q, k_quantized, v_quantized):
84 - k_descale, v_descale = (
85 - self.input_metadata.k_descale,
86 - self.input_metadata.v_descale,
87 - )
88 - k_dequantized = (
89 - k_quantized.to(torch.float32) * k_descale.to(torch.float32)
90 - ).to(self.dtype)
91 - v_dequantized = (
92 - v_quantized.to(torch.float32) * v_descale.to(torch.float32)
93 - ).to(self.dtype)
94 - return self.fwd(q, k_dequantized, v_dequantized)
95 -
96 - def varlen_fwd(self, q, k, v, is_mqa=False):
97 - ref_out = torch.empty_like(q)
98 - if is_mqa:
99 - # Make KV look like HQ/HK "groups" of HK. Later, we will reshape so
100 - # the size aligns with Q.
101 - k_ref = k.view(k.shape[0], k.shape[1], 1, k.shape[2]).expand(
102 - -1, -1, self.HQ // self.HK, -1
103 - )
104 - v_ref = v.view(v.shape[0], v.shape[1], 1, v.shape[2]).expand(
105 - -1, -1, self.HQ // self.HK, -1
106 - )
107 - else:
108 - k_ref = k
109 - v_ref = v
110 -
111 - for i in range(0, self.input_metadata.num_contexts):
112 - start_q, start_k = (
113 - self.input_metadata.cu_seqlens_q[i],
114 - self.input_metadata.cu_seqlens_k[i],
115 - )
116 - end_q, end_k = (
117 - self.input_metadata.cu_seqlens_q[i + 1],
118 - self.input_metadata.cu_seqlens_k[i + 1],
119 - )
120 - k_curr = k_ref[start_k:end_k]
121 - v_curr = v_ref[start_k:end_k]
122 - if is_mqa:
123 - k_curr = k_curr.reshape(k_curr.shape[0], -1, k_curr.shape[3])
124 - v_curr = v_curr.reshape(v_curr.shape[0], -1, v_curr.shape[3])
125 - scores = torch.einsum("qhd,khd->qhk", q[start_q:end_q], k_curr).float()
126 - p = torch.softmax(scores * self.input_metadata.sm_scale, dim=-1).half()
127 - ref_out[start_q:end_q] = torch.einsum("qhk,khd->qhd", p, v_curr)
128 - return ref_out
129 -
130 -
131 -def quantize_input(q, k, v, fp8_kv=False, use_o_scale=False):
132 - q_descale = None
133 - if not fp8_kv:
134 - q, q_descale = scale_fp8(q)
135 - k, k_descale = scale_fp8(k)
136 - v, v_descale = scale_fp8(v)
137 -
138 - # In real world use case, the p scale would be a parameter trained by the
139 - # model.
140 - p_scale = None
141 -
142 - o_scale = torch.rand(1, device="cuda", requires_grad=False) if use_o_scale else None
143 -
144 - return q, k, v, q_descale, k_descale, v_descale, p_scale, o_scale
145 -
146 -
147 -def input_helper(
148 - Z,
149 - HQ,
150 - HK,
151 - N_CTX_Q,
152 - N_CTX_K,
153 - D_HEAD,
154 - dtype,
155 - layout=None,
156 - use_alibi=None,
157 - causal=None,
158 - is_fp8=False,
159 - fp8_kv=False,
160 - use_o_scale=False,
161 - use_bias=False,
162 -):
163 - assert layout in SUPPORTED_LAYOUTS, "Got unsupported layout."
164 -
165 - current_platform.seed_everything(0)
166 -
167 - # Initialize q, k, v
168 - if layout == "bhsd":
169 - q_tensor_shape = (Z, HQ, N_CTX_Q, D_HEAD)
170 - k_tensor_shape = (Z, HK, N_CTX_K, D_HEAD)
171 - elif layout == "bshd":
172 - q_tensor_shape = (Z, N_CTX_Q, HQ, D_HEAD)
173 - k_tensor_shape = (Z, N_CTX_K, HK, D_HEAD)
174 -
175 - if use_alibi:
176 - # for n heads the set of slopes is the geometric sequence that starts
177 - # 2^(-8/n)
178 - alibi_slopes = torch.tensor(
179 - [2 ** (-8 / HQ * i) for i in range(1, HQ + 1)],
180 - dtype=torch.float32,
181 - device="cuda",
182 - ).repeat(Z, 1)
183 - else:
184 - alibi_slopes = None
185 -
186 - if use_bias:
187 - bias = torch.randn(
188 - (1, HQ, N_CTX_Q, N_CTX_K), dtype=dtype, device="cuda", requires_grad=False
189 - )
190 - else:
191 - bias = None
192 -
193 - q = torch.randn(q_tensor_shape, dtype=dtype, device="cuda", requires_grad=False)
194 - k = torch.randn(k_tensor_shape, dtype=dtype, device="cuda", requires_grad=False)
195 - v = torch.randn(k_tensor_shape, dtype=dtype, device="cuda", requires_grad=False)
196 -
197 - if is_fp8:
198 - (q, k, v, q_descale, k_descale, v_descale, p_scale, o_scale) = quantize_input(
199 - q, k, v, use_o_scale=use_o_scale, fp8_kv=fp8_kv
200 - )
201 - else:
202 - q_descale = k_descale = v_descale = p_scale = o_scale = None
203 -
204 - input_metadata = MetaData(
205 - sm_scale=D_HEAD**-0.5,
206 - max_seqlens_q=N_CTX_Q,
207 - max_seqlens_k=N_CTX_K,
208 - layout=layout,
209 - alibi_slopes=alibi_slopes,
210 - alibi_batch=Z,
211 - alibi_nheads=HQ,
212 - q_descale=q_descale,
213 - k_descale=k_descale,
214 - v_descale=v_descale,
215 - p_scale=p_scale,
216 - o_scale=o_scale,
217 - bias=bias,
218 - seqlen_q=N_CTX_Q,
219 - seqlen_k=N_CTX_K,
220 - )
221 - return q, k, v, input_metadata
222 -
223 -
224 -def varlen_input_helper(
225 - Z, HQ, HK, N_CTX_Q, N_CTX_K, D_HEAD, dtype, equal_seqlens=False
226 -):
227 - current_platform.seed_everything(0)
228 -
229 - # Random sequence lengths. Using N_CTX as kind of max of sum of individual
230 - # seqs
231 - if not equal_seqlens:
232 - max_seqlens_q = N_CTX_Q // Z
233 - max_seqlens_k = N_CTX_K // Z
234 - seqlens_q = torch.randint(1, max_seqlens_q + 1, (Z,), dtype=torch.int32)
235 - seqlens_k = torch.randint(1, max_seqlens_k + 1, (Z,), dtype=torch.int32)
236 - else:
237 - seqlens_q = torch.full((Z,), N_CTX_Q // Z)
238 - seqlens_k = torch.full((Z,), N_CTX_K // Z)
239 -
240 - # Calculate cumulative sequence lengths
241 - cu_seqlens_q = torch.cat(
242 - [
243 - torch.tensor([0], dtype=torch.int32),
244 - seqlens_q.cumsum(dim=0, dtype=torch.int32),
245 - ]
246 - )
247 - cu_seqlens_k = torch.cat(
248 - [
249 - torch.tensor([0], dtype=torch.int32),
250 - seqlens_k.cumsum(dim=0, dtype=torch.int32),
251 - ]
252 - )
253 - cu_seqlens_q = cu_seqlens_q.to(device="cuda")
254 - cu_seqlens_k = cu_seqlens_k.to(device="cuda")
255 -
256 - # Initialize q, k, v with variable lengths
257 - total_q = cu_seqlens_q[-1].item()
258 - total_k = cu_seqlens_k[-1].item()
259 - q = (
260 - torch.randn((total_q, HQ, D_HEAD), dtype=dtype, device="cuda")
261 - .normal_(mean=0.0, std=0.5)
262 - .requires_grad_()
263 - )
264 - k = (
265 - torch.randn((total_k, HK, D_HEAD), dtype=dtype, device="cuda")
266 - .normal_(mean=0.0, std=0.5)
267 - .requires_grad_()
268 - )
269 - v = (
270 - torch.randn((total_k, HK, D_HEAD), dtype=dtype, device="cuda")
271 - .normal_(mean=0.0, std=0.5)
272 - .requires_grad_()
273 - )
274 - sm_scale = D_HEAD**-0.5
275 - input_metadata = MetaData(sm_scale=sm_scale)
276 - input_metadata.set_varlen_params(cu_seqlens_q, cu_seqlens_k)
277 - return q, k, v, input_metadata
278 -
279 -
280 -@pytest.mark.parametrize(
281 - "Z, HQ, HK, N_CTX_Q, N_CTX_K, D_HEAD",
282 - [
283 - (1, 48, 12, 1, 1, 64),
284 - (4, 4, 4, 128, 128, 65),
285 - (16, 48, 48, 1, 1, 128),
286 - (64, 48, 24, 3, 3, 128),
287 - (4, 4, 4, 113, 123, 1),
288 - ],
289 -)
290 -@pytest.mark.parametrize("causal", [True, False])
291 -@pytest.mark.parametrize("use_alibi", [True, False])
292 -@pytest.mark.parametrize("layout", ["bshd"])
293 -def test_op_fwd(
294 - Z, HQ, HK, N_CTX_Q, N_CTX_K, D_HEAD, causal, use_alibi, layout, dtype=torch.float16
295 -):
296 - current_platform.seed_everything(0)
297 - q, k, v, input_metadata = input_helper(
298 - Z, HQ, HK, N_CTX_Q, N_CTX_K, D_HEAD, dtype, layout, use_alibi, causal
299 - )
300 -
301 - o = torch.empty_like(q)
302 -
303 - # triton implementation
304 - tri_out, _ = triton_attention_rocm(q, k, v, o, input_metadata)
305 -
306 - # Transpose here if layout is bshd so we have same reference code for all
307 - # layouts
308 - if layout == "bshd":
309 - q = q.transpose(1, 2).clone()
310 - k = k.transpose(1, 2).clone()
311 - v = v.transpose(1, 2).clone()
312 - # Replicate K and V if using MQA/GQA
313 - if HQ != HK:
314 - k = (
315 - k.view(k.shape[0], k.shape[1], -1, k.shape[2], k.shape[3])
316 - .expand(-1, -1, HQ // HK, -1, -1)
317 - .reshape(k.shape[0], -1, k.shape[2], k.shape[3])
318 - )
319 - v = (
320 - v.view(v.shape[0], v.shape[1], -1, v.shape[2], v.shape[3])
321 - .expand(-1, -1, HQ // HK, -1, -1)
322 - .reshape(v.shape[0], -1, v.shape[2], v.shape[3])
323 - )
324 -
325 - ref_impl = ReferenceAttention(
326 - Z, HQ, HK, N_CTX_Q, N_CTX_K, D_HEAD, use_alibi, dtype, input_metadata
327 - )
328 - ref_out = ref_impl.fwd(q, k, v)
329 -
330 - torch.testing.assert_close(ref_out, tri_out, atol=2e-2, rtol=2e-2)
331 -
332 -
333 -@pytest.mark.parametrize(
334 - "Z, H, N_CTX_Q, N_CTX_K, D_HEAD",
335 - [
336 - (4, 48, 1, 1, 64),
337 - (4, 48, 1, 1, 128),
338 - (4, 48, 3, 3, 128),
339 - (4, 4, 128, 128, 65),
340 - ],
341 -)
342 -@pytest.mark.parametrize("causal", [True, False])
343 -@pytest.mark.parametrize("layout", ["bhsd"])
344 -@pytest.mark.parametrize("use_o_scale", [True, False])
345 -@pytest.mark.skipif(
346 - torch.cuda.get_device_capability() < (9, 0),
347 - reason="Triton FP8 requires CUDA 9.0 or higher",
348 -)
349 -def test_op_fwd_fp8(
350 - Z, H, N_CTX_Q, N_CTX_K, D_HEAD, causal, layout, use_o_scale, dtype=torch.float32
351 -):
352 - current_platform.seed_everything(0)
353 -
354 - # Disable grad to save memory it won't run into OOM on CI machine.
355 - # q, k, v, input_metadata = input_helper(Z, H, H, N_CTX_Q, N_CTX_K, D_HEAD,
356 - # dtype, layout)
357 -
358 - q_quantized, k_quantized, v_quantized, input_metadata = input_helper(
359 - Z,
360 - H,
361 - H,
362 - N_CTX_Q,
363 - N_CTX_K,
364 - D_HEAD,
365 - dtype,
366 - causal=causal,
367 - layout=layout,
368 - is_fp8=True,
369 - use_o_scale=use_o_scale,
370 - )
371 -
372 - o = torch.empty_like(q_quantized) if use_o_scale else None
373 -
374 - tri_out, _ = triton_attention_rocm(
375 - q_quantized, k_quantized, v_quantized, o, input_metadata
376 - )
377 -
378 - ref_impl = ReferenceAttention(
379 - Z, H, H, N_CTX_Q, N_CTX_K, D_HEAD, False, dtype, input_metadata
380 - )
381 - ref_out = ref_impl.fwd_fp8(q_quantized, k_quantized, v_quantized)
382 -
383 - # compare
384 - torch.testing.assert_close(
385 - ref_out.to(torch.float32), tri_out.to(torch.float32), atol=7e-2, rtol=2e-1
386 - )
387 -
388 -
389 -@pytest.mark.parametrize(
390 - "Z, H, N_CTX_Q, N_CTX_K, D_HEAD",
391 - [
392 - (4, 48, 1, 1, 64),
393 - (4, 48, 1, 1, 128),
394 - (4, 48, 3, 3, 128),
395 - (4, 4, 128, 128, 65),
396 - (4, 4, 113, 123, 1),
397 - ],
398 -)
399 -@pytest.mark.parametrize("causal", [True, False])
400 -@pytest.mark.parametrize("layout", ["bhsd"])
401 -def test_op_fwd_fp8_kv(
402 - Z, H, N_CTX_Q, N_CTX_K, D_HEAD, causal, layout, dtype=torch.float32
403 -):
404 - current_platform.seed_everything(0)
405 -
406 - q, k_quantized, v_quantized, input_metadata = input_helper(
407 - Z,
408 - H,
409 - H,
410 - N_CTX_Q,
411 - N_CTX_K,
412 - D_HEAD,
413 - dtype,
414 - causal=causal,
415 - layout=layout,
416 - is_fp8=True,
417 - fp8_kv=True,
418 - )
419 -
420 - o = torch.empty_like(q)
421 -
422 - tri_out, _ = triton_attention_rocm(q, k_quantized, v_quantized, o, input_metadata)
423 -
424 - ref_impl = ReferenceAttention(
425 - Z, H, H, N_CTX_Q, N_CTX_K, D_HEAD, False, dtype, input_metadata
426 - )
427 - ref_out = ref_impl.fwd_fp8_kv(q, k_quantized, v_quantized)
428 -
429 - torch.testing.assert_close(ref_out, tri_out, atol=3e-2, rtol=8e-1)
430 -
431 -
432 -@pytest.mark.parametrize(
433 - "Z, H, N_CTX_Q, N_CTX_K, D_HEAD",
434 - [
435 - (4, 48, 1, 1, 64),
436 - (4, 48, 1, 1, 128),
437 - (4, 48, 3, 3, 128),
438 - (4, 4, 128, 128, 65),
439 - ],
440 -)
441 -@pytest.mark.parametrize("causal", [True, False])
442 -@pytest.mark.parametrize("use_bias", [True])
443 -@pytest.mark.parametrize("dtype", [torch.bfloat16])
444 -def test_op_fwd_bias(Z, H, N_CTX_Q, N_CTX_K, D_HEAD, causal, use_bias, dtype):
445 - current_platform.seed_everything(0)
446 - q, k, v, input_metadata = input_helper(
447 - Z,
448 - H,
449 - H,
450 - N_CTX_Q,
451 - N_CTX_K,
452 - D_HEAD,
453 - dtype,
454 - layout="bhsd",
455 - causal=causal,
456 - use_bias=use_bias,
457 - )
458 - o = torch.empty_like(q)
459 -
460 - # triton implementation
461 - tri_out, _ = triton_attention_rocm(q, k, v, o, input_metadata)
462 -
463 - ref_impl = ReferenceAttention(
464 - Z, H, H, N_CTX_Q, N_CTX_K, D_HEAD, False, dtype, input_metadata
465 - )
466 - ref_out = ref_impl.fwd(q, k, v)
467 -
468 - # compare
469 - torch.testing.assert_close(ref_out, tri_out, atol=2e-2, rtol=2e-2)
470 -
471 -
472 -# NOTE: Uses thd layout, so also tests thd.
473 -@pytest.mark.parametrize(
474 - "Z, H, N_CTX, D_HEAD",
475 - [(1, 48, 256, 64), (4, 48, 512, 64), (16, 48, 512, 64), (64, 48, 128, 128)],
476 -)
477 -@pytest.mark.parametrize("causal", [True, False])
478 -def test_op_varlen_fwd(Z, H, N_CTX, D_HEAD, causal, dtype=torch.float16):
479 - q, k, v, input_metadata = varlen_input_helper(Z, H, H, N_CTX, N_CTX, D_HEAD, dtype)
480 -
481 - tri_out = torch.empty_like(q)
482 - triton_attention_rocm(q, k, v, tri_out, input_metadata)
483 -
484 - ref_impl = ReferenceAttention(
485 - Z, H, H, N_CTX, N_CTX, D_HEAD, False, dtype, input_metadata
486 - )
487 - ref_out = ref_impl.varlen_fwd(q, k, v, is_mqa=False)
488 -
489 - torch.testing.assert_close(ref_out, tri_out, atol=2e-2, rtol=2e-2)
490 -
491 -
492 -# NOTE: Uses thd layout, so also tests thd.
493 -@pytest.mark.parametrize(
494 - "Z, HQ, HK, N_CTX, D_HEAD",
495 - [
496 - (2, 48, 24, 128, 64),
497 - (4, 48, 12, 256, 64),
498 - (4, 48, 4, 512, 64),
499 - (4, 64, 16, 128, 128),
500 - ],
501 -)
502 -@pytest.mark.parametrize("causal", [False])
503 -def test_op_varlen_mqa_fwd(Z, HQ, HK, N_CTX, D_HEAD, causal, dtype=torch.float16):
504 - q, k, v, input_metadata = varlen_input_helper(
505 - Z, HQ, HK, N_CTX, N_CTX, D_HEAD, dtype
506 - )
507 -
508 - tri_out = torch.empty_like(q)
509 - triton_attention_rocm(q, k, v, tri_out, input_metadata)
510 -
511 - ref_impl = ReferenceAttention(
512 - Z, HQ, HK, N_CTX, N_CTX, D_HEAD, False, dtype, input_metadata
513 - )
514 - ref_out = ref_impl.varlen_fwd(q, k, v, is_mqa=True)
515 -
516 - torch.testing.assert_close(ref_out, tri_out, atol=2e-2, rtol=2e-2)
tests/models/language/pooling/test_classification.py
-6
@@ -27,13 +27,7 @@ def test_models(
27 example_prompts,
28 model: str,
29 dtype: str,
30 - monkeypatch,
30 ) -> None:
32 - if current_platform.is_rocm():
33 - # ROCm Triton FA does not currently support sliding window attention
34 - # switch to use ROCm CK FA backend
35 - monkeypatch.setenv("VLLM_USE_TRITON_FLASH_ATTN", "False")
36 -
31 with vllm_runner(model, max_model_len=512, dtype=dtype) as vllm_model:
32 vllm_outputs = vllm_model.classify(example_prompts)
33
tests/models/language/pooling/test_embedding.py
-7
@@ -4,7 +4,6 @@
4 import pytest
5
6 from vllm.config import PoolerConfig
7 -from vllm.platforms import current_platform
7
8 from ...utils import check_embeddings_close
9
@@ -51,13 +50,7 @@ def test_models(
50 vllm_runner,
51 example_prompts,
52 model,
54 - monkeypatch,
53 ) -> None:
56 - if model == "BAAI/bge-multilingual-gemma2" and current_platform.is_rocm():
57 - # ROCm Triton FA does not currently support sliding window attention
58 - # switch to use ROCm CK FA backend
59 - monkeypatch.setenv("VLLM_USE_TRITON_FLASH_ATTN", "False")
60 -
54 vllm_extra_kwargs = {}
55 if model == "ssmits/Qwen2-7B-Instruct-embed-base":
56 vllm_extra_kwargs["pooler_config"] = PoolerConfig(
tests/models/language/pooling/test_mm_classifier_conversion.py
-13
@@ -2,18 +2,11 @@
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 from vllm.config.pooler import PoolerConfig
5 -from vllm.platforms import current_platform
5
6
7 def test_idefics_multimodal(
8 vllm_runner,
10 - monkeypatch,
9 ) -> None:
12 - if current_platform.is_rocm():
13 - # ROCm Triton FA does not currently support sliding window attention
14 - # switch to use ROCm CK FA backend
15 - monkeypatch.setenv("VLLM_USE_TRITON_FLASH_ATTN", "False")
16 -
10 prompts = [
11 "Hello, my name is",
12 "The president of the United States is",
@@ -59,13 +52,7 @@ def update_config(config):
52
53 def test_gemma_multimodal(
54 vllm_runner,
62 - monkeypatch,
55 ) -> None:
64 - if current_platform.is_rocm():
65 - # ROCm Triton FA does not currently support sliding window attention
66 - # switch to use ROCm CK FA backend
67 - monkeypatch.setenv("VLLM_USE_TRITON_FLASH_ATTN", "False")
68 -
56 messages = [
57 {
58 "role": "system",
tests/models/language/pooling/test_reward.py
-6
@@ -76,7 +76,6 @@ def test_prm_models(
76 math_step_prompts,
77 model: str,
78 dtype: str,
79 - monkeypatch,
79 ) -> None:
80 check_transformers_version(
81 "Qwen/Qwen2.5-Math-PRM-7B", max_transformers_version="4.53.2"
@@ -85,11 +84,6 @@ def test_prm_models(
84 if current_platform.is_cpu():
85 pytest.skip("CPU only supports V1")
86
88 - if current_platform.is_rocm():
89 - # ROCm Triton FA does not currently support sliding window attention
90 - # switch to use ROCm CK FA backend
91 - monkeypatch.setenv("VLLM_USE_TRITON_FLASH_ATTN", "False")
92 -
87 with vllm_runner(model, max_model_len=1024, dtype=dtype) as vllm_model:
88 vllm_outputs = vllm_model.reward(math_step_prompts)
89
tests/models/multimodal/generation/test_common.py
-8
@@ -5,7 +5,6 @@ image, embedding, and video support for different VLMs in vLLM.
5 """
6
7 import math
8 -import os
8 from collections import defaultdict
9 from pathlib import PosixPath
10
@@ -38,13 +37,6 @@ from .vlm_utils.types import (
37 VLMTestType,
38 )
39
41 -# This hack is needed for phi3v & paligemma models
42 -# ROCm Triton FA can run into shared memory issues with these models,
43 -# use other backends in the meantime
44 -# FIXME (mattwong, gshtrasb, hongxiayan)
45 -if current_platform.is_rocm():
46 - os.environ["VLLM_USE_TRITON_FLASH_ATTN"] = "0"
47 -
40 COMMON_BROADCAST_SETTINGS = {
41 "test_type": VLMTestType.IMAGE,
42 "dtype": "half",
tests/models/multimodal/generation/test_phi4_multimodal.py
-7
@@ -11,7 +11,6 @@ from huggingface_hub import snapshot_download
11 from vllm.assets.image import ImageAsset
12 from vllm.lora.request import LoRARequest
13 from vllm.multimodal.image import rescale_image_size
14 -from vllm.platforms import current_platform
14
15 from ....conftest import (
16 IMAGE_ASSETS,
@@ -46,12 +45,6 @@ models = [model_path]
45
46 target_dtype = "half"
47
49 -# ROCm Triton FA can run into shared memory issues with these models,
50 -# use other backends in the meantime
51 -# FIXME (mattwong, gshtrasb, hongxiayan)
52 -if current_platform.is_rocm():
53 - os.environ["VLLM_USE_TRITON_FLASH_ATTN"] = "0"
54 -
48
49 def run_test(
50 hf_runner: type[HfRunner],
tests/models/multimodal/generation/test_phi4mm.py
-7
@@ -14,7 +14,6 @@ from vllm.assets.image import ImageAsset
14 from vllm.logprobs import SampleLogprobs
15 from vllm.lora.request import LoRARequest
16 from vllm.multimodal.image import convert_image_mode, rescale_image_size
17 -from vllm.platforms import current_platform
17
18 from ....conftest import (
19 IMAGE_ASSETS,
@@ -68,12 +67,6 @@ def vllm_to_hf_output(
67
68 target_dtype = "half"
69
71 -# ROCm Triton FA can run into shared memory issues with these models,
72 -# use other backends in the meantime
73 -# FIXME (mattwong, gshtrasb, hongxiayan)
74 -if current_platform.is_rocm():
75 - os.environ["VLLM_USE_TRITON_FLASH_ATTN"] = "0"
76 -
70
71 def run_test(
72 hf_runner: type[HfRunner],
tests/quantization/test_quark.py
-5
@@ -8,7 +8,6 @@ See also `tests/kernels/moe/test_ocp_mx_moe.py`.
8 """
9
10 import importlib.metadata
11 -import os
11 from dataclasses import dataclass
12 from importlib.util import find_spec
13
@@ -246,8 +245,6 @@ def test_mxfp4_gsm8k_correctness(config: AccuracyTestConfig):
245 task = "gsm8k"
246 rtol = 0.03
247
249 - os.environ["VLLM_USE_TRITON_FLASH_ATTN"] = "0"
250 -
248 results = lm_eval.simple_evaluate(
249 model="vllm",
250 model_args=config.get_model_args(tp_size=8, model_max_len=38768),
@@ -263,8 +260,6 @@ def test_mxfp4_gsm8k_correctness(config: AccuracyTestConfig):
260 and measured_value + rtol > EXPECTED_VALUE
261 ), f"Expected: {EXPECTED_VALUE} | Measured: {measured_value}"
262
266 - del os.environ["VLLM_USE_TRITON_FLASH_ATTN"]
267 -
263
264 @pytest.mark.skipif(not QUARK_MXFP4_AVAILABLE, reason="amd-quark>=0.9 is not available")
265 @pytest.mark.parametrize("float_dtype", [torch.bfloat16, torch.float16])
vllm/attention/ops/triton_flash_attention.py deleted
-932
@@ -1,932 +0,0 @@
1 -#!/usr/bin/env python
2 -# SPDX-License-Identifier: Apache-2.0
3 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
4 -"""
5 -Fused Attention
6 -===============
7 -
8 -This is a Triton implementation of the Flash Attention v2 algorithm from Tri Dao
9 -(https://tridao.me/publications/flash2/flash2.pdf)
10 -Credits: OpenAI kernel team, AMD ML Frameworks Triton team
11 -
12 -Features supported:
13 -
14 -1) Fwd with causal masking
15 -2) Any sequence lengths without padding (currently fwd kernel only)
16 -3) Support for different sequence lengths for q and k
17 -4) Nested tensor API currently does not support dropout or bias.
18 -
19 -Not currently supported:
20 -
21 -1) Non power of two head dims
22 -
23 -"""
24 -
25 -import torch
26 -
27 -from vllm.platforms import current_platform
28 -from vllm.triton_utils import tl, triton
29 -
30 -# Avoid misleading ROCm warning.
31 -if current_platform.is_rocm():
32 - from vllm.platforms.rocm import on_gfx1x
33 -else:
34 - on_gfx1x = lambda *args, **kwargs: False
35 -
36 -torch_dtype: tl.constexpr = torch.float16
37 -
38 -
39 -@triton.jit
40 -def cdiv_fn(x, y):
41 - return (x + y - 1) // y
42 -
43 -
44 -@triton.jit
45 -def max_fn(x, y):
46 - return tl.math.max(x, y)
47 -
48 -
49 -@triton.jit
50 -def dropout_offsets(philox_seed, philox_offset, dropout_p, m, n, stride):
51 - ms = tl.arange(0, m)
52 - ns = tl.arange(0, n)
53 - return philox_offset + ms[:, None] * stride + ns[None, :]
54 -
55 -
56 -@triton.jit
57 -def dropout_rng(philox_seed, philox_offset, dropout_p, m, n, stride):
58 - rng_offsets = dropout_offsets(
59 - philox_seed, philox_offset, dropout_p, m, n, stride
60 - ).to(tl.uint32)
61 - # TODO: use tl.randint for better performance
62 - return tl.rand(philox_seed, rng_offsets)
63 -
64 -
65 -@triton.jit
66 -def dropout_mask(philox_seed, philox_offset, dropout_p, m, n, stride):
67 - rng_output = dropout_rng(philox_seed, philox_offset, dropout_p, m, n, stride)
68 - rng_keep = rng_output > dropout_p
69 - return rng_keep
70 -
71 -
72 -@triton.jit
73 -def load_fn(block_ptr, first, second, pad):
74 - if first and second:
75 - tensor = tl.load(block_ptr, boundary_check=(0, 1), padding_option=pad)
76 - elif first:
77 - tensor = tl.load(block_ptr, boundary_check=(0,), padding_option=pad)
78 - elif second:
79 - tensor = tl.load(block_ptr, boundary_check=(1,), padding_option=pad)
80 - else:
81 - tensor = tl.load(block_ptr)
82 - return tensor
83 -
84 -
85 -@triton.jit
86 -def _attn_fwd_inner(
87 - acc,
88 - l_i,
89 - m_i,
90 - q,
91 - K_block_ptr,
92 - V_block_ptr,
93 - start_m,
94 - actual_seqlen_k,
95 - dropout_p,
96 - philox_seed,
97 - batch_philox_offset,
98 - encoded_softmax_block_ptr,
99 - block_min,
100 - block_max,
101 - offs_n_causal,
102 - masked_blocks,
103 - n_extra_tokens,
104 - bias_ptr,
105 - IS_CAUSAL: tl.constexpr,
106 - BLOCK_M: tl.constexpr,
107 - BLOCK_DMODEL: tl.constexpr,
108 - BLOCK_N: tl.constexpr,
109 - OFFS_M: tl.constexpr,
110 - OFFS_N: tl.constexpr,
111 - PRE_LOAD_V: tl.constexpr,
112 - MASK_STEPS: tl.constexpr,
113 - ENABLE_DROPOUT: tl.constexpr,
114 - RETURN_ENCODED_SOFTMAX: tl.constexpr,
115 - PADDED_HEAD: tl.constexpr,
116 - USE_FP8: tl.constexpr,
117 - qk_scale,
118 - p_descale,
119 -):
120 - # loop over k, v, and update accumulator
121 - for start_n in range(block_min, block_max, BLOCK_N):
122 - # For padded blocks, we will overrun the tensor size if
123 - # we load all BLOCK_N. For others, the blocks are all within range.
124 - k = load_fn(
125 - K_block_ptr,
126 - PADDED_HEAD,
127 - MASK_STEPS and (n_extra_tokens != 0),
128 - "zero",
129 - )
130 - if PRE_LOAD_V:
131 - v = load_fn(
132 - V_block_ptr,
133 - MASK_STEPS and (n_extra_tokens != 0),
134 - PADDED_HEAD,
135 - "zero",
136 - )
137 - qk = tl.zeros([BLOCK_M, BLOCK_N], dtype=tl.float32)
138 - # We start from end of seqlen_k so only the first iteration would need
139 - # to be checked for padding if it is not a multiple of block_n
140 - # TODO: This can be optimized to only be true for the padded block.
141 - if MASK_STEPS: # noqa: SIM102
142 - # If this is the last block / iteration, we want to
143 - # mask if the sequence length is not a multiple of block size
144 - # a solution is to always do BLOCK_M // BLOCK_N + 1 steps
145 - # if not is_modulo_mn. last step might get wasted but that is okay.
146 - # check if this masking works for that case.
147 - if (start_n + BLOCK_N == block_max) and (n_extra_tokens != 0):
148 - boundary_m = tl.full([BLOCK_M], actual_seqlen_k, dtype=tl.int32)
149 - size_n = start_n + OFFS_N[None, :]
150 - mask = size_n < boundary_m[:, None]
151 - qk = tl.where(mask, qk, float("-inf"))
152 - if IS_CAUSAL:
153 - causal_boundary = start_n + offs_n_causal
154 - causal_mask = OFFS_M[:, None] >= causal_boundary[None, :]
155 - qk = tl.where(causal_mask, qk, float("-inf"))
156 - # -- compute qk ----
157 - qk += tl.dot(q, k)
158 - if USE_FP8:
159 - qk *= qk_scale
160 - if bias_ptr is not None:
161 - bias = load_fn(
162 - bias_ptr, False, MASK_STEPS and (n_extra_tokens != 0), "zero"
163 - )
164 - # While bias is added after multiplying qk with sm_scale, our
165 - # optimization to use 2^x instead of e^x results in an additional
166 - # scale factor of log2(e) which we must also multiply the bias with.
167 - qk += bias * 1.44269504089
168 - m_ij = tl.maximum(m_i, tl.max(qk, 1))
169 - qk = qk - m_ij[:, None]
170 - p = tl.math.exp2(qk)
171 -
172 - # CAVEAT: Must update l_ij before applying dropout
173 - l_ij = tl.sum(p, 1)
174 - if ENABLE_DROPOUT:
175 - philox_offset = (
176 - batch_philox_offset
177 - + start_m * BLOCK_M * actual_seqlen_k
178 - + start_n
179 - - BLOCK_N
180 - )
181 - keep = dropout_mask(
182 - philox_seed,
183 - philox_offset,
184 - dropout_p,
185 - BLOCK_M,
186 - BLOCK_N,
187 - actual_seqlen_k,
188 - )
189 - if RETURN_ENCODED_SOFTMAX:
190 - tl.store(
191 - encoded_softmax_block_ptr,
192 - tl.where(keep, p, -p).to(encoded_softmax_block_ptr.type.element_ty),
193 - )
194 - p = tl.where(keep, p, 0.0)
195 - elif RETURN_ENCODED_SOFTMAX:
196 - tl.store(
197 - encoded_softmax_block_ptr,
198 - p.to(encoded_softmax_block_ptr.type.element_ty),
199 - )
200 - # -- update output accumulator --
201 - alpha = tl.math.exp2(m_i - m_ij)
202 - acc = acc * alpha[:, None]
203 - if not PRE_LOAD_V:
204 - v = load_fn(
205 - V_block_ptr,
206 - MASK_STEPS and (n_extra_tokens != 0),
207 - PADDED_HEAD,
208 - "zero",
209 - )
210 - # -- update m_i and l_i
211 - l_i = l_i * alpha + l_ij
212 - # update m_i and l_i
213 - m_i = m_ij
214 -
215 - if USE_FP8:
216 - p *= p_descale
217 -
218 - acc += tl.dot(p.to(V_block_ptr.type.element_ty), v)
219 -
220 - V_block_ptr = tl.advance(V_block_ptr, (BLOCK_N, 0))
221 - K_block_ptr = tl.advance(K_block_ptr, (0, BLOCK_N))
222 - if bias_ptr is not None:
223 - bias_ptr = tl.advance(bias_ptr, (0, BLOCK_N))
224 - if RETURN_ENCODED_SOFTMAX:
225 - encoded_softmax_block_ptr = tl.advance(
226 - encoded_softmax_block_ptr, (0, BLOCK_N)
227 - )
228 - return acc, l_i, m_i
229 -
230 -
231 -def get_cdna_autotune_configs():
232 - return [
233 - triton.Config(
234 - {"BLOCK_M": 256, "BLOCK_N": 64, "waves_per_eu": 2, "PRE_LOAD_V": False},
235 - num_stages=1,
236 - num_warps=8,
237 - ),
238 - triton.Config(
239 - {"BLOCK_M": 128, "BLOCK_N": 128, "waves_per_eu": 2, "PRE_LOAD_V": False},
240 - num_stages=1,
241 - num_warps=4,
242 - ),
243 - triton.Config(
244 - {"BLOCK_M": 256, "BLOCK_N": 128, "waves_per_eu": 2, "PRE_LOAD_V": False},
245 - num_stages=1,
246 - num_warps=8,
247 - ),
248 - triton.Config(
249 - {"BLOCK_M": 128, "BLOCK_N": 64, "waves_per_eu": 1, "PRE_LOAD_V": False},
250 - num_stages=1,
251 - num_warps=4,
252 - ),
253 - triton.Config(
254 - {"BLOCK_M": 128, "BLOCK_N": 64, "waves_per_eu": 3, "PRE_LOAD_V": True},
255 - num_stages=1,
256 - num_warps=4,
257 - ),
258 - triton.Config(
259 - {"BLOCK_M": 128, "BLOCK_N": 64, "waves_per_eu": 3, "PRE_LOAD_V": False},
260 - num_stages=1,
261 - num_warps=4,
262 - ),
263 - triton.Config(
264 - {"BLOCK_M": 64, "BLOCK_N": 64, "waves_per_eu": 4, "PRE_LOAD_V": False},
265 - num_stages=1,
266 - num_warps=8,
267 - ),
268 - triton.Config(
269 - {"BLOCK_M": 32, "BLOCK_N": 32, "waves_per_eu": 4, "PRE_LOAD_V": False},
270 - num_stages=1,
271 - num_warps=8,
272 - ),
273 - # TODO: This config fails with head_size not pow2 with data mismatches.
274 - # triton.Config({'BLOCK_M': 32, 'BLOCK_N': 16, 'waves_per_eu': 1,
275 - # 'PRE_LOAD_V': False}, num_stages=1, num_warps=4),
276 - # Fails in AccelerateAMDMatmul (Triton) assert when using FP8:
277 - # triton.Config(
278 - # {
279 - # "BLOCK_M": 16,
280 - # "BLOCK_N": 16,
281 - # "waves_per_eu": 1,
282 - # "PRE_LOAD_V": False,
283 - # },
284 - # num_stages=1,
285 - # num_warps=4,
286 - # ),
287 - ], ["IS_CAUSAL", "dropout_p", "BLOCK_DMODEL", "USE_FP8"]
288 -
289 -
290 -def get_rdna_autotune_configs():
291 - return [
292 - triton.Config(
293 - {"BLOCK_M": 32, "BLOCK_N": 32, "waves_per_eu": 4, "PRE_LOAD_V": False},
294 - num_stages=1,
295 - num_warps=2,
296 - ),
297 - triton.Config(
298 - {"BLOCK_M": 32, "BLOCK_N": 32, "waves_per_eu": 2, "PRE_LOAD_V": False},
299 - num_stages=1,
300 - num_warps=2,
301 - ),
302 - triton.Config(
303 - {"BLOCK_M": 32, "BLOCK_N": 16, "waves_per_eu": 4, "PRE_LOAD_V": False},
304 - num_stages=1,
305 - num_warps=2,
306 - ),
307 - triton.Config(
308 - {"BLOCK_M": 32, "BLOCK_N": 16, "waves_per_eu": 2, "PRE_LOAD_V": False},
309 - num_stages=1,
310 - num_warps=2,
311 - ),
312 - # Fails in AccelerateAMDMatmul (Triton) assert when using FP8:
313 - # triton.Config(
314 - # {
315 - # 'BLOCK_M': 16,
316 - # 'BLOCK_N': 16,
317 - # 'waves_per_eu': 4,
318 - # 'PRE_LOAD_V': False
319 - # },
320 - # num_stages=1,
321 - # num_warps=2),
322 - # triton.Config(
323 - # {
324 - # 'BLOCK_M': 16,
325 - # 'BLOCK_N': 16,
326 - # 'waves_per_eu': 2,
327 - # 'PRE_LOAD_V': False
328 - # },
329 - # num_stages=1,
330 - # num_warps=2),
331 - # # Fall-back config.
332 - # triton.Config(
333 - # {
334 - # 'BLOCK_M': 16,
335 - # 'BLOCK_N': 16,
336 - # 'waves_per_eu': 1,
337 - # 'PRE_LOAD_V': False
338 - # },
339 - # num_stages=1,
340 - # num_warps=2),
341 - ], ["IS_CAUSAL", "dropout_p", "BLOCK_DMODEL", "USE_FP8"]
342 -
343 -
344 -def get_autotune_configs():
345 - if on_gfx1x():
346 - return get_rdna_autotune_configs()
347 - else:
348 - return get_cdna_autotune_configs()
349 -
350 -
351 -autotune_configs, autotune_keys = get_autotune_configs()
352 -
353 -float8_info = torch.finfo(current_platform.fp8_dtype())
354 -
355 -
356 -@triton.autotune(
357 - configs=autotune_configs,
358 - key=autotune_keys,
359 -)
360 -@triton.jit
361 -def attn_fwd(
362 - Q,
363 - K,
364 - V,
365 - bias,
366 - sm_scale,
367 - q_scale,
368 - k_scale,
369 - v_scale,
370 - p_scale,
371 - p_descale,
372 - o_descale,
373 - L,
374 - Out,
375 - stride_qz: tl.int64,
376 - stride_qh: tl.int64,
377 - stride_qm: tl.int64,
378 - stride_qk: tl.int64,
379 - stride_kz: tl.int64,
380 - stride_kh: tl.int64,
381 - stride_kn: tl.int64,
382 - stride_kk: tl.int64,
383 - stride_vz: tl.int64,
384 - stride_vh: tl.int64,
385 - stride_vk: tl.int64,
386 - stride_vn: tl.int64,
387 - stride_oz: tl.int64,
388 - stride_oh: tl.int64,
389 - stride_om: tl.int64,
390 - stride_on: tl.int64,
391 - stride_bz: tl.int64,
392 - stride_bh: tl.int64,
393 - stride_bm: tl.int64,
394 - stride_bn: tl.int64,
395 - cu_seqlens_q,
396 - cu_seqlens_k,
397 - dropout_p,
398 - philox_seed,
399 - philox_offset_base,
400 - encoded_softmax,
401 - HQ: tl.constexpr,
402 - HK: tl.constexpr,
403 - ACTUAL_BLOCK_DMODEL: tl.constexpr,
404 - MAX_SEQLENS_Q: tl.constexpr,
405 - MAX_SEQLENS_K: tl.constexpr,
406 - VARLEN: tl.constexpr,
407 - IS_CAUSAL: tl.constexpr,
408 - BLOCK_M: tl.constexpr,
409 - BLOCK_DMODEL: tl.constexpr,
410 - USE_FP8: tl.constexpr,
411 - USE_FP8_OUT: tl.constexpr,
412 - BLOCK_N: tl.constexpr,
413 - PRE_LOAD_V: tl.constexpr,
414 - BIAS_TYPE: tl.constexpr,
415 - ENABLE_DROPOUT: tl.constexpr,
416 - RETURN_ENCODED_SOFTMAX: tl.constexpr,
417 - FP8_MIN: tl.constexpr = float8_info.min,
418 - FP8_MAX: tl.constexpr = float8_info.max,
419 -):
420 - start_m = tl.program_id(0)
421 - off_h_q = tl.program_id(1)
422 - off_z = tl.program_id(2)
423 - offs_m = start_m * BLOCK_M + tl.arange(0, BLOCK_M)
424 - offs_n = tl.arange(0, BLOCK_N)
425 - if VARLEN:
426 - cu_seqlens_q_start = tl.load(cu_seqlens_q + off_z)
427 - cu_seqlens_q_end = tl.load(cu_seqlens_q + off_z + 1)
428 - seqlen_q = cu_seqlens_q_end - cu_seqlens_q_start
429 - # We have a one-size-fits-all grid in id(0). Some seqlens might be too
430 - # small for all start_m so for those we return early.
431 - if start_m * BLOCK_M > seqlen_q:
432 - return
433 - cu_seqlens_k_start = tl.load(cu_seqlens_k + off_z)
434 - cu_seqlens_k_end = tl.load(cu_seqlens_k + off_z + 1)
435 - seqlen_k = cu_seqlens_k_end - cu_seqlens_k_start
436 - else:
437 - cu_seqlens_q_start = 0
438 - cu_seqlens_k_start = 0
439 - seqlen_q = MAX_SEQLENS_Q
440 - seqlen_k = MAX_SEQLENS_K
441 -
442 - # Now we compute whether we need to exit early due to causal masking.
443 - # This is because for seqlen_q > seqlen_k, M rows of the attn scores
444 - # are completely masked, resulting in 0s written to the output, and
445 - # inf written to LSE. We don't need to do any GEMMs in this case.
446 - # This block of code determines what N is, and if this WG is operating
447 - # on those M rows.
448 - n_blocks = cdiv_fn(seqlen_k, BLOCK_N)
449 - if IS_CAUSAL:
450 - # If seqlen_q == seqlen_k, the attn scores are a square matrix.
451 - # If seqlen_q != seqlen_k, attn scores are rectangular which means
452 - # the causal mask boundary is bottom right aligned, and ends at either
453 - # the top edge (seqlen_q < seqlen_k) or left edge.
454 - # This captures the decrease in n_blocks if we have a rectangular attn
455 - # matrix
456 - n_blocks_seqlen = cdiv_fn(
457 - (start_m + 1) * BLOCK_M + seqlen_k - seqlen_q, BLOCK_N
458 - )
459 - # This is what adjusts the block_max for the current WG, only
460 - # if IS_CAUSAL. Otherwise we want to always iterate through all n_blocks
461 - n_blocks = min(n_blocks, n_blocks_seqlen)
462 - # If we have no blocks after adjusting for seqlen deltas, this WG is
463 - # part of the blocks that are all 0. We exit early.
464 - if n_blocks <= 0:
465 - o_offset = (
466 - off_z * stride_oz + cu_seqlens_q_start * stride_om + off_h_q * stride_oh
467 - )
468 - O_block_ptr = tl.make_block_ptr(
469 - base=Out + o_offset,
470 - shape=(seqlen_q, BLOCK_DMODEL),
471 - strides=(stride_om, stride_on),
472 - offsets=(start_m * BLOCK_M, 0),
473 - block_shape=(BLOCK_M, BLOCK_DMODEL),
474 - order=(1, 0),
475 - )
476 - acc = tl.zeros([BLOCK_M, BLOCK_DMODEL], dtype=Out.type.element_ty)
477 - # We still need to write 0s to the result
478 - # tl.store(O_block_ptr,
479 - # acc.to(Out.type.element_ty), boundary_check=(0,1))
480 - # l_ptrs = L + off_z * HQ * MAX_SEQLENS_Q + off_h_q * MAX_SEQLENS_Q
481 - # + offs_m
482 - # We store inf to LSE, not -inf because in the bwd pass,
483 - # we subtract this
484 - # from qk which makes it -inf, such that exp(qk - inf) = 0
485 - # for these masked blocks.
486 - # l = tl.full([BLOCK_M], value=float("inf"), dtype=tl.float32)
487 - # tl.store(l_ptrs, l)
488 - # TODO: Should dropout and return encoded softmax be handled here?
489 - return
490 -
491 - # If MQA / GQA, set the K and V head offsets appropriately.
492 - GROUP_SIZE: tl.constexpr = HQ // HK
493 - off_h_k = off_h_q // GROUP_SIZE if GROUP_SIZE != 1 else off_h_q
494 -
495 - n_extra_tokens = 0
496 - if seqlen_k < BLOCK_N:
497 - n_extra_tokens = BLOCK_N - seqlen_k
498 - elif seqlen_k % BLOCK_N:
499 - n_extra_tokens = seqlen_k % BLOCK_N
500 - padded_head = ACTUAL_BLOCK_DMODEL != BLOCK_DMODEL
501 -
502 - # Compute pointers for all the tensors used in this kernel.
503 - q_offset = off_z * stride_qz + off_h_q * stride_qh + cu_seqlens_q_start * stride_qm
504 - Q_block_ptr = tl.make_block_ptr(
505 - base=Q + q_offset,
506 - shape=(seqlen_q, ACTUAL_BLOCK_DMODEL),
507 - strides=(stride_qm, stride_qk),
508 - offsets=(start_m * BLOCK_M, 0),
509 - block_shape=(BLOCK_M, BLOCK_DMODEL),
510 - order=(1, 0),
511 - )
512 - k_offset = off_z * stride_kz + off_h_k * stride_kh + cu_seqlens_k_start * stride_kn
513 - K_block_ptr = tl.make_block_ptr(
514 - base=K + k_offset,
515 - shape=(ACTUAL_BLOCK_DMODEL, seqlen_k),
516 - strides=(stride_kk, stride_kn),
517 - offsets=(0, 0),
518 - block_shape=(BLOCK_DMODEL, BLOCK_N),
519 - order=(0, 1),
520 - )
521 - v_offset = off_z * stride_vz + off_h_k * stride_vh + cu_seqlens_k_start * stride_vk
522 - V_block_ptr = tl.make_block_ptr(
523 - base=V + v_offset,
524 - shape=(seqlen_k, ACTUAL_BLOCK_DMODEL),
525 - strides=(stride_vk, stride_vn),
526 - offsets=(0, 0),
527 - block_shape=(BLOCK_N, BLOCK_DMODEL),
528 - order=(1, 0),
529 - )
530 - if BIAS_TYPE != 0:
531 - bias_ptr = tl.make_block_ptr(
532 - base=bias + off_h_q * stride_bh,
533 - shape=(seqlen_q, seqlen_k),
534 - strides=(stride_bm, stride_bn),
535 - offsets=(start_m * BLOCK_M, 0),
536 - block_shape=(BLOCK_M, BLOCK_N),
537 - order=(1, 0),
538 - )
539 - else:
540 - bias_ptr = None
541 - if ENABLE_DROPOUT:
542 - batch_philox_offset = (
543 - philox_offset_base + (off_z * HQ + off_h_q) * seqlen_q * seqlen_k
544 - )
545 - else:
546 - batch_philox_offset = 0
547 - # We can ask to return the dropout mask without actually doing any dropout.
548 - # In this case, we return an invalid pointer so indicate the mask is not i
549 - # valid.
550 - # TODO: Fix encoded softmax. It currently uses just h_q in the base offset.
551 - if RETURN_ENCODED_SOFTMAX:
552 - encoded_softmax_block_ptr = tl.make_block_ptr(
553 - base=encoded_softmax + off_h_q * seqlen_q * seqlen_k,
554 - shape=(seqlen_q, seqlen_k),
555 - strides=(seqlen_k, 1),
556 - offsets=(start_m * BLOCK_M, 0),
557 - block_shape=(BLOCK_M, BLOCK_N),
558 - order=(1, 0),
559 - )
560 - else:
561 - encoded_softmax_block_ptr = 0
562 - # initialize pointer to m and l
563 - m_i = tl.full([BLOCK_M], float("-inf"), dtype=tl.float32)
564 - l_i = tl.full([BLOCK_M], 1.0, dtype=tl.float32)
565 - acc = tl.zeros([BLOCK_M, BLOCK_DMODEL], dtype=tl.float32)
566 - # scale sm_scale by log_2(e) and use 2^x in the loop as we do not
567 - # have native e^x support in HW.
568 - qk_scale = sm_scale * 1.44269504089
569 - # Q is loaded once at the beginning and shared by all N blocks.
570 - q = load_fn(Q_block_ptr, True, padded_head, "zero")
571 - if not USE_FP8:
572 - q = (q * qk_scale).to(Q_block_ptr.type.element_ty)
573 - acc_scale = 1.0
574 - else:
575 - qk_scale *= q_scale * k_scale
576 - acc_scale = p_scale * v_scale
577 -
578 - # Here we compute how many full and masked blocks we have.
579 - padded_block_k = n_extra_tokens != 0
580 - is_modulo_mn = not padded_block_k and (seqlen_q % BLOCK_M == 0)
581 - if IS_CAUSAL:
582 - # There are always at least BLOCK_M // BLOCK_N masked blocks.
583 - # Additionally there might be one more due to dissimilar seqlens.
584 - masked_blocks = BLOCK_M // BLOCK_N + (not is_modulo_mn)
585 - else:
586 - # Padding on Q does not need to be masked in the FA loop.
587 - masked_blocks = padded_block_k
588 - # if IS_CAUSAL, not is_modulo_mn does not always result in an additional
589 - # block. In this case we might exceed n_blocks so pick the min.
590 - masked_blocks = min(masked_blocks, n_blocks)
591 - n_full_blocks = n_blocks - masked_blocks
592 - block_min = 0
593 - block_max = n_blocks * BLOCK_N
594 - # Compute for full blocks. Here we set causal to false regardless of its
595 - # value because there is no masking. Similarly we do not need padding.
596 - if n_full_blocks > 0:
597 - block_max = (n_blocks - masked_blocks) * BLOCK_N
598 - acc, l_i, m_i = _attn_fwd_inner(
599 - acc,
600 - l_i,
601 - m_i,
602 - q,
603 - K_block_ptr,
604 - V_block_ptr,
605 - start_m,
606 - seqlen_k,
607 - dropout_p,
608 - philox_seed,
609 - batch_philox_offset,
610 - encoded_softmax_block_ptr,
611 - # _, _, offs_n_causal, masked_blocks, n_extra_tokens, _
612 - block_min,
613 - block_max,
614 - 0,
615 - 0,
616 - 0,
617 - bias_ptr,
618 - # IS_CAUSAL, ....
619 - False,
620 - BLOCK_M,
621 - BLOCK_DMODEL,
622 - BLOCK_N,
623 - offs_m,
624 - offs_n,
625 - # _, MASK_STEPS, ...
626 - PRE_LOAD_V,
627 - False,
628 - ENABLE_DROPOUT,
629 - RETURN_ENCODED_SOFTMAX,
630 - padded_head,
631 - USE_FP8,
632 - qk_scale,
633 - p_descale,
634 - )
635 - block_min = block_max
636 - block_max = n_blocks * BLOCK_N
637 -
638 - tl.debug_barrier()
639 - # Remaining blocks, if any, are full / not masked.
640 - if masked_blocks > 0:
641 - offs_n_causal = offs_n + (seqlen_q - seqlen_k) if IS_CAUSAL else 0
642 - K_block_ptr = tl.advance(K_block_ptr, (0, n_full_blocks * BLOCK_N))
643 - V_block_ptr = tl.advance(V_block_ptr, (n_full_blocks * BLOCK_N, 0))
644 - if bias_ptr is not None:
645 - bias_ptr = tl.advance(bias_ptr, (0, n_full_blocks * BLOCK_N))
646 - if RETURN_ENCODED_SOFTMAX:
647 - encoded_softmax_block_ptr = tl.advance(
648 - encoded_softmax_block_ptr, (0, n_full_blocks)
649 - )
650 - acc, l_i, m_i = _attn_fwd_inner(
651 - acc,
652 - l_i,
653 - m_i,
654 - q,
655 - K_block_ptr,
656 - V_block_ptr,
657 - start_m,
658 - seqlen_k,
659 - dropout_p,
660 - philox_seed,
661 - batch_philox_offset,
662 - encoded_softmax_block_ptr,
663 - block_min,
664 - block_max,
665 - offs_n_causal,
666 - masked_blocks,
667 - n_extra_tokens,
668 - bias_ptr,
669 - IS_CAUSAL,
670 - BLOCK_M,
671 - BLOCK_DMODEL,
672 - BLOCK_N,
673 - offs_m,
674 - offs_n,
675 - # _, MASK_STEPS, ...
676 - PRE_LOAD_V,
677 - True,
678 - ENABLE_DROPOUT,
679 - RETURN_ENCODED_SOFTMAX,
680 - padded_head,
681 - USE_FP8,
682 - qk_scale,
683 - p_descale,
684 - )
685 - # epilogue
686 -
687 - if USE_FP8:
688 - acc *= acc_scale
689 - acc = acc / l_i[:, None]
690 - if ENABLE_DROPOUT:
691 - acc = acc / (1 - dropout_p)
692 - # If seqlen_q > seqlen_k but the delta is not a multiple of BLOCK_M,
693 - # then we have one block with a row of all NaNs which come from computing
694 - # softmax over a row of all -infs (-inf - inf = NaN). We check for that here
695 - # and store 0s where there are NaNs as these rows should've been zeroed out.
696 - end_m_idx = (start_m + 1) * BLOCK_M
697 - start_m_idx = start_m * BLOCK_M
698 - causal_start_idx = seqlen_q - seqlen_k
699 - if USE_FP8_OUT:
700 - acc *= o_descale
701 - acc = tl.clamp(acc, FP8_MIN, FP8_MAX)
702 - acc = acc.to(Out.type.element_ty)
703 - if IS_CAUSAL: # noqa: SIM102
704 - if causal_start_idx > start_m_idx and causal_start_idx < end_m_idx:
705 - out_mask_boundary = tl.full(
706 - (BLOCK_DMODEL,), causal_start_idx, dtype=tl.int32
707 - )
708 - mask_m_offsets = start_m_idx + tl.arange(0, BLOCK_M)
709 - out_ptrs_mask = mask_m_offsets[:, None] >= out_mask_boundary[None, :]
710 - z = tl.zeros((1,), tl.float32)
711 - acc = tl.where(out_ptrs_mask, acc, z.to(acc.type.element_ty))
712 - # write back LSE
713 - # l_ptrs = L + off_z * HQ * MAX_SEQLENS_Q + off_h_q * MAX_SEQLENS_Q + offs_m
714 - # If seqlen_q not multiple of BLOCK_M, we need to mask out the last
715 - # few rows. This is only true for the last M block. For others,
716 - # overflow_size will be -ve
717 - # overflow_size = end_m_idx - seqlen_q
718 - # if overflow_size > 0:
719 - # boundary = tl.full((BLOCK_M,), BLOCK_M - overflow_size, dtype=tl.int32)
720 - # # This is a > check because mask being 0 blocks the store.
721 - # l_ptrs_mask = boundary > tl.arange(0, BLOCK_M)
722 - # tl.store(l_ptrs, m_i + tl.math.log2(l_i), mask=l_ptrs_mask)
723 - # else:
724 - # tl.store(l_ptrs, m_i + tl.math.log2(l_i))
725 -
726 - # write back O
727 - o_offset = off_z * stride_oz + cu_seqlens_q_start * stride_om + off_h_q * stride_oh
728 - O_block_ptr = tl.make_block_ptr(
729 - base=Out + o_offset,
730 - shape=(seqlen_q, ACTUAL_BLOCK_DMODEL),
731 - strides=(stride_om, stride_on),
732 - offsets=(start_m * BLOCK_M, 0),
733 - block_shape=(BLOCK_M, BLOCK_DMODEL),
734 - order=(1, 0),
735 - )
736 - # Need boundary check on this to make sure the padding from the
737 - # Q and KV tensors in both dims are not part of what we store back.
738 - # TODO: Do the boundary check optionally.
739 - tl.store(O_block_ptr, acc, boundary_check=(0, 1))
740 -
741 -
742 -def check_args(
743 - q,
744 - k,
745 - v,
746 - o,
747 - varlen=True,
748 - max_seqlens=None,
749 - cu_seqlens_q=None,
750 - cu_seqlens_k=None,
751 -):
752 - assert q.dim() == k.dim() and q.dim() == v.dim()
753 - if varlen:
754 - assert q.dim() == 3
755 - total_q, nheads_q, head_size = q.shape
756 - total_k, nheads_k, _ = k.shape
757 - assert cu_seqlens_q is not None
758 - assert cu_seqlens_k is not None
759 - assert len(cu_seqlens_q) == len(cu_seqlens_k)
760 - else:
761 - assert q.dim() == 4
762 - batch, nheads_q, seqlen_q, head_size = q.shape
763 - _, nheads_k, seqlen_k, _ = k.shape
764 - assert max_seqlens > 0
765 - assert k.shape == v.shape
766 - assert q.shape[-1] == k.shape[-1] and q.shape[-1] == v.shape[-1]
767 - # TODO: Change assert if we support qkl f8 and v f16
768 - assert q.dtype == k.dtype and q.dtype == v.dtype
769 - assert head_size <= 256
770 - assert o.shape == q.shape
771 - assert (nheads_q % nheads_k) == 0
772 -
773 -
774 -class _attention(torch.autograd.Function):
775 - @staticmethod
776 - def forward(
777 - ctx,
778 - q,
779 - k,
780 - v,
781 - o,
782 - cu_seqlens_q,
783 - cu_seqlens_k,
784 - max_seqlens_q,
785 - max_seqlens_k,
786 - causal=False,
787 - sm_scale=1.0,
788 - bias=None,
789 - fp8_scales=None,
790 - fp8_out_scale=None,
791 - ):
792 - if fp8_scales is not None:
793 - use_fp8 = True
794 - (q_scale, k_scale, v_scale, p_scale) = fp8_scales
795 - float8 = current_platform.fp8_dtype()
796 -
797 - def check_and_convert(t, scale):
798 - if t.dtype != float8:
799 - descale = 1.0 / scale
800 - ts = (t * descale).clamp(min=float8_info.min, max=float8_info.max)
801 - return ts.to(float8)
802 - else:
803 - return t
804 -
805 - q = check_and_convert(q, q_scale)
806 - k = check_and_convert(k, k_scale)
807 - v = check_and_convert(v, v_scale)
808 - else:
809 - use_fp8 = False
810 - q_scale = k_scale = v_scale = p_scale = 1.0
811 -
812 - if o is None:
813 - o = torch.empty_like(q, dtype=v.dtype)
814 -
815 - check_args(
816 - q,
817 - k,
818 - v,
819 - o,
820 - varlen=True,
821 - cu_seqlens_q=cu_seqlens_q,
822 - cu_seqlens_k=cu_seqlens_k,
823 - )
824 - if True: # varlen
825 - total_q, nheads_q, head_size = q.shape
826 - total_k, nheads_k, _ = k.shape
827 - batch = len(cu_seqlens_q) - 1
828 - q_strides = (0, q.stride(1), q.stride(0), q.stride(2))
829 - k_strides = (0, k.stride(1), k.stride(0), k.stride(2))
830 - v_strides = (0, v.stride(1), v.stride(0), v.stride(2))
831 - o_strides = (0, o.stride(1), o.stride(0), o.stride(2))
832 - else:
833 - batch, seqlen_q, nheads_q, head_size = q.shape
834 - _, seqlen_k, nheads_k, _ = k.shape
835 - q_strides = (q.stride(0), q.stride(2), q.stride(1), q.stride(3))
836 - k_strides = (k.stride(0), k.stride(2), k.stride(1), k.stride(3))
837 - v_strides = (v.stride(0), v.stride(2), v.stride(1), v.stride(3))
838 - o_strides = (o.stride(0), o.stride(2), o.stride(1), o.stride(3))
839 -
840 - # Get closest power of 2 over or equal to 32.
841 - unpadded_head_dims = {32, 64, 128, 256}
842 - if head_size not in unpadded_head_dims:
843 - padded_d_model = None
844 - for i in unpadded_head_dims:
845 - if i > head_size:
846 - padded_d_model = i
847 - break
848 - assert padded_d_model is not None
849 - else:
850 - padded_d_model = head_size
851 -
852 - grid = lambda META: (
853 - triton.cdiv(max_seqlens_q, META["BLOCK_M"]),
854 - nheads_q,
855 - batch,
856 - )
857 -
858 - encoded_softmax = None
859 -
860 - # Seed the RNG so we get reproducible results for testing.
861 - philox_seed = 0x1BF52
862 - philox_offset = 0x1D4B42
863 -
864 - if bias is not None:
865 - bias_strides = (
866 - bias.stride(0),
867 - bias.stride(1),
868 - bias.stride(2),
869 - bias.stride(3),
870 - )
871 - else:
872 - bias_strides = (0, 0, 0, 0)
873 -
874 - p_descale = 1.0 / p_scale
875 - o_descale = 1.0 / fp8_out_scale.item() if fp8_out_scale is not None else 1.0
876 -
877 - arg_max_seqlens_q = 0 if on_gfx1x() else max_seqlens_q
878 - arg_max_seqlens_k = 0 if on_gfx1x() else max_seqlens_k
879 -
880 - attn_fwd[grid](
881 - q,
882 - k,
883 - v,
884 - bias,
885 - sm_scale,
886 - q_scale,
887 - k_scale,
888 - v_scale,
889 - p_scale,
890 - p_descale,
891 - o_descale,
892 - None,
893 - o,
894 - *q_strides,
895 - *k_strides,
896 - *v_strides,
897 - *o_strides,
898 - *bias_strides,
899 - cu_seqlens_q,
900 - cu_seqlens_k,
901 - dropout_p=0.0,
902 - philox_seed=philox_seed,
903 - philox_offset_base=philox_offset,
904 - encoded_softmax=encoded_softmax,
905 - HQ=nheads_q,
906 - HK=nheads_k,
907 - ACTUAL_BLOCK_DMODEL=head_size,
908 - MAX_SEQLENS_Q=arg_max_seqlens_q,
909 - MAX_SEQLENS_K=arg_max_seqlens_k,
910 - IS_CAUSAL=causal,
911 - VARLEN=True,
912 - BLOCK_DMODEL=padded_d_model,
913 - BIAS_TYPE=0 if bias is None else 1,
914 - ENABLE_DROPOUT=False,
915 - RETURN_ENCODED_SOFTMAX=False,
916 - USE_FP8=use_fp8,
917 - USE_FP8_OUT=fp8_out_scale is not None,
918 - )
919 -
920 - ctx.grid = grid
921 - ctx.sm_scale = sm_scale
922 - ctx.BLOCK_DMODEL = head_size
923 - ctx.causal = causal
924 - ctx.dropout_p = 0.0
925 - ctx.philox_seed = philox_seed
926 - ctx.philox_offset = philox_offset
927 - ctx.encoded_softmax = encoded_softmax
928 - ctx.return_encoded_softmax = False
929 - return o, encoded_softmax
930 -
931 -
932 -triton_attention = _attention.apply
vllm/envs.py
-6
@@ -18,7 +18,6 @@ if TYPE_CHECKING:
18 VLLM_RINGBUFFER_WARNING_INTERVAL: int = 60
19 VLLM_NCCL_SO_PATH: str | None = None
20 LD_LIBRARY_PATH: str | None = None
21 - VLLM_USE_TRITON_FLASH_ATTN: bool = True
21 VLLM_V1_USE_PREFILL_DECODE_ATTENTION: bool = False
22 VLLM_FLASH_ATTN_VERSION: int | None = None
23 LOCAL_RANK: int = 0
@@ -521,10 +520,6 @@ environment_variables: dict[str, Callable[[], Any]] = {
520 # when `VLLM_NCCL_SO_PATH` is not set, vllm will try to find the nccl
521 # library file in the locations specified by `LD_LIBRARY_PATH`
522 "LD_LIBRARY_PATH": lambda: os.environ.get("LD_LIBRARY_PATH", None),
524 - # flag to control if vllm should use triton flash attention
525 - "VLLM_USE_TRITON_FLASH_ATTN": lambda: (
526 - os.environ.get("VLLM_USE_TRITON_FLASH_ATTN", "True").lower() in ("true", "1")
527 - ),
523 # Use separate prefill and decode kernels for V1 attention instead of
524 # the unified triton kernel.
525 "VLLM_V1_USE_PREFILL_DECODE_ATTENTION": lambda: (
@@ -1554,7 +1549,6 @@ def compute_hash() -> str:
1549 "VLLM_PP_LAYER_PARTITION",
1550 "VLLM_MLA_DISABLE",
1551 "VLLM_FLASH_ATTN_MAX_NUM_SPLITS_FOR_CUDA_GRAPH",
1557 - "VLLM_USE_TRITON_FLASH_ATTN",
1552 "VLLM_USE_TRITON_AWQ",
1553 "VLLM_DP_RANK",
1554 "VLLM_DP_SIZE",
vllm/platforms/rocm.py
+2 -19
@@ -49,25 +49,8 @@ _ROCM_UNSUPPORTED_MODELS: list[str] = []
49
50 # Models partially supported by ROCm.
51 # Architecture -> Reason.
52 -_ROCM_SWA_REASON = (
53 - "Sliding window attention (SWA) is not yet supported in "
54 - "Triton flash attention. For half-precision SWA support, "
55 - "please use CK flash attention by setting "
56 - "`VLLM_USE_TRITON_FLASH_ATTN=0`"
57 -)
58 -_ROCM_PARTIALLY_SUPPORTED_MODELS: dict[str, str] = {
59 - "Qwen2ForCausalLM": _ROCM_SWA_REASON,
60 - "MistralForCausalLM": _ROCM_SWA_REASON,
61 - "MixtralForCausalLM": _ROCM_SWA_REASON,
62 - "PaliGemmaForConditionalGeneration": (
63 - "ROCm flash attention does not yet fully support 32-bit precision on PaliGemma"
64 - ),
65 - "Phi3VForCausalLM": (
66 - "ROCm Triton flash attention may run into compilation errors due to "
67 - "excessive use of shared memory. If this happens, disable Triton FA "
68 - "by setting `VLLM_USE_TRITON_FLASH_ATTN=0`"
69 - ),
70 -}
52 +_ROCM_SWA_REASON = ()
53 +_ROCM_PARTIALLY_SUPPORTED_MODELS: dict[str, str] = {}
54 _ROCM_DEVICE_ID_NAME_MAP: dict[str, str] = {
55 "0x74a0": "AMD_Instinct_MI300A",
56 "0x74a1": "AMD_Instinct_MI300X",
vllm/usage/usage_lib.py
-1
@@ -37,7 +37,6 @@ _GLOBAL_RUNTIME_DATA = dict[str, str | int | bool]()
37
38 _USAGE_ENV_VARS_TO_COLLECT = [
39 "VLLM_USE_MODELSCOPE",
40 - "VLLM_USE_TRITON_FLASH_ATTN",
40 "VLLM_ATTENTION_BACKEND",
41 "VLLM_USE_FLASHINFER_SAMPLER",
42 "VLLM_PP_LAYER_PARTITION",
vllm/v1/attention/backends/mla/triton_mla.py
+7 -48
@@ -5,22 +5,18 @@ from typing import ClassVar
5
6 import torch
7
8 -from vllm import envs
8 from vllm.attention.backends.abstract import (
9 AttentionLayer,
10 AttentionType,
11 is_quantized_kv_cache,
12 )
13 from vllm.attention.ops.triton_decode_attention import decode_attention_fwd
15 -from vllm.attention.ops.triton_flash_attention import triton_attention
14 from vllm.config.cache import CacheDType
15 from vllm.logger import init_logger
16 from vllm.model_executor.layers.batch_invariant import (
17 vllm_is_batch_invariant,
18 )
21 -from vllm.platforms import current_platform
19 from vllm.platforms.interface import DeviceCapability
23 -from vllm.triton_utils import HAS_TRITON
20 from vllm.v1.attention.backends.mla.common import (
21 MLACommonBackend,
22 MLACommonImpl,
@@ -99,55 +95,18 @@ class TritonMLAImpl(MLACommonImpl[MLACommonMetadata]):
95 "TritonMLA V1 with FP8 KV cache not yet supported"
96 )
97
102 - self.use_triton_flash_attn = envs.VLLM_USE_TRITON_FLASH_ATTN
103 - self.triton_fa_func = triton_attention if HAS_TRITON else None
104 -
105 - def _flash_attn_varlen_diff_headdims_rocm(
106 - self, q, k, v, softmax_scale=None, **kwargs
98 + def _flash_attn_varlen_diff_headdims(
99 + self, q, k, v, return_softmax_lse=False, softmax_scale=None, **kwargs
100 ):
108 - assert self.triton_fa_func is not None
109 -
110 - # Triton Attention requires a padded V
111 - padded_v = torch.nn.functional.pad(v, [0, q.shape[-1] - v.shape[-1]], value=0)
112 - # The output of triton_attention is a tuple of
113 - # [output_tensor, encoded_softmax] where encoded_softmax is always None
114 - output_tensor, _ = self.triton_fa_func(
101 + return super()._flash_attn_varlen_diff_headdims(
102 q,
103 k,
117 - padded_v,
118 - None, # output
119 - kwargs["cu_seqlens_q"],
120 - kwargs["cu_seqlens_k"],
121 - kwargs["max_seqlen_q"],
122 - kwargs["max_seqlen_k"],
123 - kwargs["causal"],
124 - softmax_scale,
125 - None, # bias
104 + v,
105 + return_softmax_lse=return_softmax_lse,
106 + softmax_scale=softmax_scale,
107 + **kwargs,
108 )
109
128 - return output_tensor
129 -
130 - def _flash_attn_varlen_diff_headdims(
131 - self, q, k, v, return_softmax_lse=False, softmax_scale=None, **kwargs
132 - ):
133 - if (
134 - current_platform.is_rocm()
135 - and self.use_triton_flash_attn
136 - and not return_softmax_lse
137 - ):
138 - return self._flash_attn_varlen_diff_headdims_rocm(
139 - q, k, v, softmax_scale=softmax_scale, **kwargs
140 - )
141 - else:
142 - return super()._flash_attn_varlen_diff_headdims(
143 - q,
144 - k,
145 - v,
146 - return_softmax_lse=return_softmax_lse,
147 - softmax_scale=softmax_scale,
148 - **kwargs,
149 - )
150 -
110 def _forward_decode(
111 self,
112 q: torch.Tensor | tuple[torch.Tensor, torch.Tensor],