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 14, 05:30 UTC
Remove V0 attention backends (#25351)
Signed-off-by: Woosuk Kwon <woosuk.kwon@berkeley.edu>
Woosuk Kwon committed
Sep 21, 2025 at 16:03 UTC
bc6e542d9fc400d7002853b3878c81b14fbdc998
28 files changed
+142
-7375
examples/offline_inference/qwen_1m.py
-1
@@ -5,7 +5,6 @@ from urllib.request import urlopen
5
6
from vllm import LLM, SamplingParams
7
8
-os.environ["VLLM_ATTENTION_BACKEND"] = "DUAL_CHUNK_FLASH_ATTN"
8
os.environ["VLLM_ALLOW_LONG_MAX_MODEL_LEN"] = "1"
9
10
tests/compile/test_fusion_attn.py
+3
-2
@@ -334,8 +334,9 @@ else:
334
[7, 256, 533] if current_platform.is_cuda() else [8])
335
@pytest.mark.parametrize("dtype", [torch.bfloat16, torch.float16])
336
@pytest.mark.parametrize("model_name, model_class", MODELS)
337
-@pytest.mark.parametrize("backend", [_Backend.FLASHINFER] if
338
- current_platform.is_cuda() else [_Backend.ROCM_FLASH])
337
+@pytest.mark.parametrize("backend",
338
+ [_Backend.FLASHINFER] if current_platform.is_cuda()
339
+ else [_Backend.TRITON_ATTN_VLLM_V1])
340
@pytest.mark.parametrize(
341
"split_attention",
342
[False, True] if current_platform.is_rocm() else [False])
tests/kernels/attention/test_attention.py
+3
-3
@@ -18,7 +18,7 @@ if not current_platform.is_rocm():
18
from xformers import ops as xops
19
from xformers.ops.fmha.attn_bias import BlockDiagonalCausalMask
20
21
- from vllm.attention.backends.xformers import _make_alibi_bias
21
+ from tests.kernels.utils import make_alibi_bias
22
23
FLOAT32_BYTES = torch.finfo(torch.float).bits // 8
24
# This will change depending on the compute capability.
@@ -429,8 +429,8 @@ def test_multi_query_kv_attention(
429
alibi_bias = None
430
if use_alibi:
431
alibi_slopes = torch.randn(num_query_heads, dtype=torch.float)
432
- attn_bias = _make_alibi_bias(alibi_slopes, num_kv_heads, dtype,
433
- seq_lens)
432
+ attn_bias = make_alibi_bias(alibi_slopes, num_kv_heads, dtype,
433
+ seq_lens)
434
output = torch.empty_like(query)
435
start = 0
436
# Dynamic sequence length not supported with custom attn_bias.
tests/kernels/attention/test_attention_selector.py
+1
@@ -67,6 +67,7 @@ def generate_params():
67
return params
68
69
70
+@pytest.mark.skip(reason="Skipped for now. Should be revisited.")
71
@pytest.mark.parametrize("device, name, use_mla, block_size",
72
generate_params())
73
def test_env(
tests/kernels/attention/test_prefix_prefill.py
+3
-3
@@ -11,7 +11,7 @@ import torch
11
from xformers import ops as xops
12
from xformers.ops.fmha.attn_bias import BlockDiagonalCausalFromBottomRightMask
13
14
-from vllm.attention.backends.xformers import _make_alibi_bias
14
+from tests.kernels.utils import make_alibi_bias
15
from vllm.attention.ops.chunked_prefill_paged_decode import (
16
chunked_prefill_paged_decode)
17
from vllm.attention.ops.prefix_prefill import context_attention_fwd
@@ -470,7 +470,7 @@ def test_contexted_kv_attention_alibi(
470
key = key.unsqueeze(0)
471
value = value.unsqueeze(0)
472
473
- attn_bias = _make_alibi_bias(alibi_slopes, num_kv_heads, dtype, seq_lens)
473
+ attn_bias = make_alibi_bias(alibi_slopes, num_kv_heads, dtype, seq_lens)
474
output_ref = torch.empty_like(output)
475
seq_start = 0
476
query_start = 0
@@ -479,7 +479,7 @@ def test_contexted_kv_attention_alibi(
479
# FIXME(DefTruth): Because xformers does not support dynamic sequence
480
# lengths with custom attention bias, we process each prompt one by
481
# one. This is inefficient, especially when we have many short prompts.
482
- # modified from: vllm/attention/backends/xformers.py#L343
482
+ # modified from: vllm/v1/attention/backends/xformers.py#L343
483
for i, (query_len, seq_len) in enumerate(zip(query_lens, seq_lens)):
484
seq_end = seq_start + seq_len
485
query_end = query_start + query_len
tests/kernels/attention/test_rocm_attention_selector.py
+1
@@ -16,6 +16,7 @@ def clear_cache():
16
_cached_get_attn_backend.cache_clear()
17
18
19
+@pytest.mark.skip(reason="Skipped for now. Should be revisited.")
20
def test_selector(monkeypatch: pytest.MonkeyPatch):
21
with monkeypatch.context() as m:
22
m.setenv(STR_BACKEND_ENV_VAR, "ROCM_FLASH")
tests/kernels/utils.py
+56
-10
@@ -513,10 +513,6 @@ def make_backend(backend_name: str) -> AttentionBackend:
513
Construct the backend instance determined by the backend_name string
514
argument.
515
516
- "XFORMERS" -> construct xformers backend
517
-
518
- TODO: other backends
519
-
516
Note: at time of writing the Attention wrapper automatically selects
517
its own backend for Attention.forward(); so the backend instance which
518
you generate with this function is not meant to be used for *running*
@@ -528,18 +524,68 @@ def make_backend(backend_name: str) -> AttentionBackend:
524
525
* Backend instance
526
'''
531
- if backend_name == STR_XFORMERS_ATTN_VAL:
532
- # NOTE: xFormers backend cannot be imported for CPU and AMD GPUs.
533
- from vllm.attention.backends.xformers import XFormersBackend
534
- return XFormersBackend()
535
- elif backend_name == STR_FLASH_ATTN_VAL:
536
- from vllm.attention.backends.flash_attn import FlashAttentionBackend
527
+ if backend_name in (STR_XFORMERS_ATTN_VAL, "XFORMERS_VLLM_V1"):
528
+ from vllm.v1.attention.backends.xformers import (
529
+ XFormersAttentionBackend)
530
+ return XFormersAttentionBackend()
531
+ if backend_name in (STR_FLASH_ATTN_VAL, "FLASH_ATTN_VLLM_V1"):
532
+ from vllm.v1.attention.backends.flash_attn import FlashAttentionBackend
533
return FlashAttentionBackend()
534
+ if backend_name == "TRITON_ATTN_VLLM_V1":
535
+ from vllm.v1.attention.backends.triton_attn import (
536
+ TritonAttentionBackend)
537
+ return TritonAttentionBackend()
538
+ if backend_name == "FLEX_ATTENTION":
539
+ from vllm.v1.attention.backends.flex_attention import (
540
+ FlexAttentionBackend)
541
+ return FlexAttentionBackend()
542
+ if backend_name in ("TORCH_SDPA", "TORCH_SDPA_VLLM_V1"):
543
+ from vllm.v1.attention.backends.cpu_attn import TorchSDPABackend
544
+ return TorchSDPABackend()
545
+ if backend_name == "FLASHINFER":
546
+ from vllm.v1.attention.backends.flashinfer import FlashInferBackend
547
+ return FlashInferBackend()
548
549
raise AssertionError(
550
f"Unrecognized backend_name {backend_name} for unit test")
551
552
553
+def make_alibi_bias(
554
+ alibi_slopes: torch.Tensor,
555
+ num_kv_heads: int,
556
+ dtype: torch.dtype,
557
+ seq_lens: list[int],
558
+) -> list[Any]:
559
+ """Create ALiBi biases compatible with xFormers attention tests."""
560
+ from xformers.ops.fmha.attn_bias import LowerTriangularMaskWithTensorBias
561
+
562
+ if alibi_slopes is None:
563
+ return [None for _ in seq_lens]
564
+
565
+ attn_biases: list[Any] = []
566
+ num_heads = alibi_slopes.shape[0]
567
+ assert num_heads >= num_kv_heads, (
568
+ "ALiBi slopes expect at least as many heads as KV heads")
569
+
570
+ for seq_len in seq_lens:
571
+ bias = torch.arange(seq_len, dtype=dtype, device=alibi_slopes.device)
572
+ bias = bias[None, :] - bias[:, None]
573
+
574
+ padded_len = (seq_len + 7) // 8 * 8
575
+ bias_tensor = torch.empty(
576
+ 1,
577
+ num_heads,
578
+ seq_len,
579
+ padded_len,
580
+ device=alibi_slopes.device,
581
+ dtype=dtype,
582
+ )[:, :, :, :seq_len].copy_(bias)
583
+ bias_tensor.mul_(alibi_slopes[:, None, None])
584
+ attn_biases.append(LowerTriangularMaskWithTensorBias(bias_tensor))
585
+
586
+ return attn_biases
587
+
588
+
589
def _make_metadata_tensors(
590
seq_lens: Optional[list[int]],
591
context_lens: Optional[list[int]],
tests/models/test_initialization.py
+2
-3
@@ -78,9 +78,8 @@ def can_initialize(model_arch: str, monkeypatch: pytest.MonkeyPatch,
78
return
79
80
if model_arch in ("Phi4FlashForCausalLM", "MotifForCausalLM"):
81
- # Phi4FlashForCausalLM and MotifForCausalLM
82
- # only supports DIFFERENTIAL_FLASH_ATTN backend
83
- m.setenv("VLLM_ATTENTION_BACKEND", "DIFFERENTIAL_FLASH_ATTN")
81
+ pytest.skip(
82
+ "Differential Flash Attention backend has been removed.")
83
if model_arch == "GptOssForCausalLM":
84
# FIXME: A hack to bypass FA3 assertion because our CI's L4 GPU
85
# has cc==8.9 which hasn't supported FA3 yet. Remove this hack when
vllm/attention/backends/differential_flash_attn.py
deleted
-931
@@ -1,931 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-"""" An implementation of https://arxiv.org/pdf/2410.05258 """
4
-from collections import defaultdict
5
-from dataclasses import dataclass
6
-from itertools import accumulate
7
-from typing import Any, Dict, List, Optional, Tuple, Type
8
-
9
-import torch
10
-from einops import rearrange
11
-
12
-from vllm import _custom_ops as ops
13
-# yapf conflicts with isort for this block
14
-# yapf: disable
15
-from vllm.attention.backends.abstract import (AttentionBackend, AttentionImpl,
16
- AttentionLayer,
17
- AttentionMetadata,
18
- AttentionMetadataBuilder,
19
- AttentionType,
20
- is_quantized_kv_cache)
21
-from vllm.attention.backends.flash_attn import FlashAttentionBackend
22
-# yapf: enable
23
-from vllm.attention.backends.utils import (PAD_SLOT_ID, CommonAttentionState,
24
- compute_slot_mapping,
25
- compute_slot_mapping_start_idx,
26
- is_all_cross_attn_metadata_set,
27
- is_all_encoder_attn_metadata_set,
28
- is_block_tables_empty)
29
-from vllm.attention.utils.fa_utils import (flash_attn_supports_fp8,
30
- get_flash_attn_version)
31
-from vllm.logger import init_logger
32
-from vllm.multimodal import MultiModalPlaceholderMap
33
-from vllm.utils import async_tensor_h2d, make_tensor_with_pad
34
-from vllm.vllm_flash_attn import (flash_attn_varlen_func,
35
- flash_attn_with_kvcache)
36
-
37
-logger = init_logger(__name__)
38
-
39
-
40
-class DifferentialFlashAttentionBackend(AttentionBackend):
41
- accept_output_buffer = False
42
-
43
- @staticmethod
44
- def get_supported_head_sizes() -> List[int]:
45
- return [32, 64, 96, 128, 160, 192, 224, 256]
46
-
47
- @staticmethod
48
- def get_kv_cache_shape(
49
- num_blocks: int,
50
- block_size: int,
51
- num_kv_heads: int,
52
- head_size: int,
53
- ) -> Tuple[int, ...]:
54
- if block_size % 16 != 0:
55
- raise ValueError("Block size must be a multiple of 16.")
56
- assert num_kv_heads % 2 == 0, "num_kv_heads must be divisible by 2"
57
- return (2, 2, num_blocks, block_size, num_kv_heads // 2, head_size)
58
-
59
- @staticmethod
60
- def get_name() -> str:
61
- return "DIFFERENTIAL_FLASH_ATTN"
62
-
63
- @staticmethod
64
- def get_impl_cls() -> Type["DifferentialFlashAttentionImpl"]:
65
- return DifferentialFlashAttentionImpl
66
-
67
- @staticmethod
68
- def get_metadata_cls() -> Type["DifferentialFlashAttentionMetadata"]:
69
- return DifferentialFlashAttentionMetadata
70
-
71
- @staticmethod
72
- def get_builder_cls() -> Type["DifferentialFlashAttentionMetadataBuilder"]:
73
- return DifferentialFlashAttentionMetadataBuilder
74
-
75
- @staticmethod
76
- def get_state_cls() -> Type["CommonAttentionState"]:
77
- return CommonAttentionState
78
-
79
- @staticmethod
80
- def swap_blocks(
81
- src_kv_cache: torch.Tensor,
82
- dst_kv_cache: torch.Tensor,
83
- src_to_dst: torch.Tensor,
84
- ) -> None:
85
- src_key_cache = src_kv_cache[0]
86
- dst_key_cache = dst_kv_cache[0]
87
- ops.swap_blocks(src_key_cache, dst_key_cache, src_to_dst)
88
- src_value_cache = src_kv_cache[1]
89
- dst_value_cache = dst_kv_cache[1]
90
- ops.swap_blocks(src_value_cache, dst_value_cache, src_to_dst)
91
-
92
- @staticmethod
93
- def copy_blocks(
94
- kv_caches: List[torch.Tensor],
95
- src_to_dists: torch.Tensor,
96
- ) -> None:
97
- key_caches = [kv_cache[0] for kv_cache in kv_caches]
98
- value_caches = [kv_cache[1] for kv_cache in kv_caches]
99
-
100
- ops.copy_blocks(key_caches, value_caches, src_to_dists)
101
-
102
-
103
-@dataclass
104
-class DifferentialFlashAttentionMetadata(AttentionMetadata):
105
- """Metadata for FlashAttentionBackend.
106
-
107
- NOTE: Any python object stored here is not updated when it is
108
- cuda-graph replayed. If you have values that need to be changed
109
- dynamically, it should be stored in tensor. The tensor has to be
110
- updated from `CUDAGraphRunner.forward` API.
111
- """
112
- # (batch_size,). The sequence length per sequence. Sequence length means
113
- # the computed tokens + new tokens None if it is a decoding.
114
- seq_lens: Optional[List[int]]
115
- # seq_lens stored as a tensor.
116
- seq_lens_tensor: Optional[torch.Tensor]
117
-
118
- # NOTE(sang): Definition of context_len, query_len, and seq_len.
119
- # |---------- N-1 iteration --------|
120
- # |---------------- N iteration ---------------------|
121
- # |- tokenA -|......................|-- newTokens ---|
122
- # |---------- context_len ----------|
123
- # |-------------------- seq_len ---------------------|
124
- # |-- query_len ---|
125
-
126
- # Maximum sequence length among prefill batch. 0 if there are decoding
127
- # requests only.
128
- max_prefill_seq_len: int
129
- # Maximum sequence length among decode batch. 0 if there are prefill
130
- # requests only.
131
- max_decode_seq_len: int
132
- # (batch_size,) A tensor of context lengths (tokens that are computed
133
- # so far).
134
- context_lens_tensor: Optional[torch.Tensor]
135
-
136
- # (batch_size, max_blocks_per_seq).
137
- # Block addresses per sequence. (Seq id -> list of physical block)
138
- # E.g., [0, 1, 2] means tokens are stored in 0th, 1st, and 2nd blocks
139
- # in the kv cache. Each block can contain up to block_size tokens.
140
- # 2nd dimensions are padded up to max_blocks_per_seq if it is cuda-graph
141
- # captured.
142
- block_tables: Optional[torch.Tensor]
143
-
144
- # Whether or not if cuda graph is enabled.
145
- # Cuda-graph is currently enabled for decoding only.
146
- # TODO(woosuk): Move `use_cuda_graph` out since it's unrelated to attention.
147
-
148
- use_cuda_graph: bool
149
-
150
- # Maximum query length in the batch.
151
- max_query_len: Optional[int] = None
152
-
153
- # Max number of query tokens among request in the batch.
154
- max_decode_query_len: Optional[int] = None
155
-
156
- # (batch_size + 1,). The cumulative subquery lengths of the sequences in
157
- # the batch, used to index into subquery. E.g., if the subquery length
158
- # is [4, 6], it is [0, 4, 10].
159
- query_start_loc: Optional[torch.Tensor] = None
160
- # (batch_size + 1,). The cumulative sequence lengths of the sequences in
161
- # the batch, used to index into sequence. E.g., if the sequence length is
162
- # [4, 6], it is [0, 4, 10].
163
- seq_start_loc: Optional[torch.Tensor] = None
164
-
165
- _cached_prefill_metadata: Optional[
166
- "DifferentialFlashAttentionMetadata"] = None
167
- _cached_decode_metadata: Optional[
168
- "DifferentialFlashAttentionMetadata"] = None
169
-
170
- # Begin encoder attn & enc/dec cross-attn fields...
171
-
172
- # Encoder sequence lengths representation
173
- encoder_seq_lens: Optional[List[int]] = None
174
- encoder_seq_lens_tensor: Optional[torch.Tensor] = None
175
- # (batch_size + 1,). The cumulative sequence lengths of the sequences in
176
- # the batch, used to index into sequence. E.g., if the sequence length is
177
- # [4, 6], it is [0, 4, 10].
178
- encoder_seq_start_loc: Optional[torch.Tensor] = None
179
- # Maximum sequence length among encoder sequences
180
- max_encoder_seq_len: Optional[int] = None
181
- # Number of tokens input to encoder
182
- num_encoder_tokens: Optional[int] = None
183
-
184
- # Cross-attention memory-mapping data structures: slot mapping
185
- # and block tables
186
- cross_slot_mapping: Optional[torch.Tensor] = None
187
- cross_block_tables: Optional[torch.Tensor] = None
188
-
189
- # Cross-layer shared attention block tables
190
- cross_layer_shared_block_tables: Optional[torch.Tensor] = None
191
-
192
- @property
193
- def is_all_encoder_attn_metadata_set(self):
194
- '''
195
- All attention metadata required for encoder attention is set.
196
- '''
197
- return is_all_encoder_attn_metadata_set(self)
198
-
199
- @property
200
- def is_all_cross_attn_metadata_set(self):
201
- '''
202
- All attention metadata required for enc/dec cross-attention is set.
203
-
204
- Superset of encoder attention required metadata.
205
- '''
206
- return is_all_cross_attn_metadata_set(self)
207
-
208
- @property
209
- def prefill_metadata(
210
- self) -> Optional["DifferentialFlashAttentionMetadata"]:
211
- if self.num_prefills == 0:
212
- return None
213
-
214
- if self._cached_prefill_metadata is not None:
215
- return self._cached_prefill_metadata
216
-
217
- assert ((self.seq_lens is not None)
218
- or (self.encoder_seq_lens is not None))
219
- assert ((self.seq_lens_tensor is not None)
220
- or (self.encoder_seq_lens_tensor is not None))
221
-
222
- # Compute some attn_metadata fields which default to None
223
- query_start_loc = (None if self.query_start_loc is None else
224
- self.query_start_loc[:self.num_prefills + 1])
225
- slot_mapping = (None if self.slot_mapping is None else
226
- self.slot_mapping[:self.num_prefill_tokens])
227
- seq_lens = (None if self.seq_lens is None else
228
- self.seq_lens[:self.num_prefills])
229
- seq_lens_tensor = (None if self.seq_lens_tensor is None else
230
- self.seq_lens_tensor[:self.num_prefills])
231
- seq_start_loc = (None if self.seq_start_loc is None else
232
- self.seq_start_loc[:self.num_prefills + 1])
233
- context_lens_tensor = (None if self.context_lens_tensor is None else
234
- self.context_lens_tensor[:self.num_prefills])
235
- block_tables = (None if self.block_tables is None else
236
- self.block_tables[:self.num_prefills])
237
- cross_layer_shared_block_tables = (
238
- None if self.cross_layer_shared_block_tables is None else
239
- self.cross_layer_shared_block_tables[:self.num_prefills])
240
-
241
- self._cached_prefill_metadata = DifferentialFlashAttentionMetadata(
242
- num_prefills=self.num_prefills,
243
- num_prefill_tokens=self.num_prefill_tokens,
244
- num_decode_tokens=0,
245
- slot_mapping=slot_mapping,
246
- multi_modal_placeholder_index_maps=self.
247
- multi_modal_placeholder_index_maps,
248
- enable_kv_scales_calculation=self.enable_kv_scales_calculation,
249
- seq_lens=seq_lens,
250
- seq_lens_tensor=seq_lens_tensor,
251
- max_query_len=self.max_query_len,
252
- max_prefill_seq_len=self.max_prefill_seq_len,
253
- max_decode_query_len=0,
254
- max_decode_seq_len=0,
255
- query_start_loc=query_start_loc,
256
- seq_start_loc=seq_start_loc,
257
- context_lens_tensor=context_lens_tensor,
258
- block_tables=block_tables,
259
- cross_layer_shared_block_tables=cross_layer_shared_block_tables,
260
- use_cuda_graph=False,
261
- # Begin encoder & cross attn fields below...
262
- encoder_seq_lens=self.encoder_seq_lens,
263
- encoder_seq_lens_tensor=self.encoder_seq_lens_tensor,
264
- encoder_seq_start_loc=self.encoder_seq_start_loc,
265
- max_encoder_seq_len=self.max_encoder_seq_len,
266
- cross_slot_mapping=self.cross_slot_mapping,
267
- cross_block_tables=self.cross_block_tables)
268
- return self._cached_prefill_metadata
269
-
270
- @property
271
- def decode_metadata(
272
- self) -> Optional["DifferentialFlashAttentionMetadata"]:
273
- if self.num_decode_tokens == 0:
274
- return None
275
-
276
- if self._cached_decode_metadata is not None:
277
- return self._cached_decode_metadata
278
- assert ((self.seq_lens_tensor is not None)
279
- or (self.encoder_seq_lens_tensor is not None))
280
-
281
- # Compute some attn_metadata fields which default to None
282
- slot_mapping = (None if self.slot_mapping is None else
283
- self.slot_mapping[self.num_prefill_tokens:])
284
- seq_lens_tensor = (None if self.seq_lens_tensor is None else
285
- self.seq_lens_tensor[self.num_prefills:])
286
- block_tables = (None if self.block_tables is None else
287
- self.block_tables[self.num_prefills:])
288
- cross_layer_shared_block_tables = (
289
- None if self.cross_layer_shared_block_tables is None else
290
- self.cross_layer_shared_block_tables[self.num_prefills:])
291
- self._cached_decode_metadata = DifferentialFlashAttentionMetadata(
292
- num_prefills=0,
293
- num_prefill_tokens=0,
294
- num_decode_tokens=self.num_decode_tokens,
295
- slot_mapping=slot_mapping,
296
- multi_modal_placeholder_index_maps=None,
297
- enable_kv_scales_calculation=True,
298
- seq_lens=None,
299
- seq_lens_tensor=seq_lens_tensor,
300
- max_decode_query_len=self.max_decode_query_len,
301
- max_query_len=self.max_query_len,
302
- max_prefill_seq_len=0,
303
- max_decode_seq_len=self.max_decode_seq_len,
304
- # Batch may be composed of prefill|decodes, adjust query start
305
- # indices to refer to the start of decodes. E.g.
306
- # in tokens:[3 prefills|6 decodes], query_start_loc=[3,9] => [0,6].
307
- query_start_loc=(self.query_start_loc[self.num_prefills:] -
308
- self.query_start_loc[self.num_prefills])
309
- if self.query_start_loc is not None else None,
310
- seq_start_loc=self.seq_start_loc[self.num_prefills:]
311
- if self.seq_start_loc is not None else None,
312
- context_lens_tensor=None,
313
- block_tables=block_tables,
314
- cross_layer_shared_block_tables=cross_layer_shared_block_tables,
315
- use_cuda_graph=self.use_cuda_graph,
316
- # Begin encoder & cross attn fields below...
317
- encoder_seq_lens=self.encoder_seq_lens,
318
- encoder_seq_lens_tensor=self.encoder_seq_lens_tensor,
319
- encoder_seq_start_loc=self.encoder_seq_start_loc,
320
- max_encoder_seq_len=self.max_encoder_seq_len,
321
- cross_slot_mapping=self.cross_slot_mapping,
322
- cross_block_tables=self.cross_block_tables)
323
- return self._cached_decode_metadata
324
-
325
-
326
-class DifferentialFlashAttentionMetadataBuilder(
327
- AttentionMetadataBuilder[DifferentialFlashAttentionMetadata]):
328
-
329
- def __init__(self, input_builder):
330
- self.input_builder = input_builder
331
- self.runner = input_builder.runner
332
- self.sliding_window = input_builder.sliding_window
333
- self.block_size = input_builder.block_size
334
-
335
- def prepare(self):
336
- self.slot_mapping: List[int] = []
337
- self.prefill_seq_lens: List[int] = []
338
- self.context_lens: List[int] = []
339
- self.block_tables: List[List[int]] = []
340
- self.cross_layer_shared_block_tables: List[List[int]] = []
341
- self.curr_seq_lens: List[int] = []
342
- self.multimodal_placeholder_maps: Dict[
343
- str,
344
- MultiModalPlaceholderMap] = defaultdict(MultiModalPlaceholderMap)
345
- self.num_prefills = 0
346
- self.num_prefill_tokens = 0
347
- self.num_decode_tokens = 0
348
- self.has_prefix_cache_hit = False
349
-
350
- def _add_seq_group(self, inter_data, chunked_prefill_enabled: bool,
351
- prefix_cache_hit: bool):
352
- """Add a sequence group to the metadata. Specifically update/append
353
- 1. context length.
354
- 2. block table.
355
- 3. slot mapping.
356
- """
357
- # TODO: add support for chunked prefill and prefix caching.
358
- assert not chunked_prefill_enabled, \
359
- "chunked prefill is not supported for now"
360
- assert not prefix_cache_hit, "prefix caching is not supported for now"
361
-
362
- is_prompt = inter_data.is_prompt
363
- block_tables = inter_data.block_tables
364
-
365
- for (seq_id, token_len, seq_len, curr_seq_len, query_len, context_len,
366
- curr_sliding_window_block) in zip(
367
- inter_data.seq_ids, [len(t) for t in inter_data.input_tokens],
368
- inter_data.orig_seq_lens, inter_data.seq_lens,
369
- inter_data.query_lens, inter_data.context_lens,
370
- inter_data.curr_sliding_window_blocks):
371
- self.context_lens.append(context_len)
372
-
373
- if is_prompt:
374
- mm_maps = inter_data.multi_modal_placeholder_maps
375
- if mm_maps:
376
- for modality, placeholders in mm_maps.items():
377
- self.multimodal_placeholder_maps[modality].extend(
378
- placeholders)
379
-
380
- self.num_prefills += 1
381
- self.num_prefill_tokens += token_len
382
- self.prefill_seq_lens.append(seq_len)
383
- else:
384
- self.num_decode_tokens += query_len
385
- self.curr_seq_lens.append(curr_seq_len)
386
-
387
- # Compute block table.
388
- # TODO(sang): Combine chunked prefill and prefix caching by
389
- # only allowing multiple of block_size chunk size.
390
- # NOTE: This only works for oooooooxxx style attention.
391
- block_table = []
392
- if prefix_cache_hit:
393
- # NOTE(woosuk): For flash-attn, the block table should
394
- # include the entries for the incoming prefill tokens.
395
- block_table = block_tables[seq_id]
396
- elif ((chunked_prefill_enabled or not is_prompt)
397
- and block_tables is not None):
398
- if curr_sliding_window_block == 0:
399
- block_table = block_tables[seq_id]
400
- else:
401
- block_table = block_tables[seq_id][
402
- -curr_sliding_window_block:]
403
- self.block_tables.append(block_table)
404
-
405
- cross_layer_shared_block_table = []
406
- if prefix_cache_hit:
407
- cross_layer_shared_block_table = block_tables[seq_id]
408
- elif block_tables is not None:
409
- if curr_sliding_window_block == 0:
410
- cross_layer_shared_block_table = block_tables[seq_id]
411
- else:
412
- cross_layer_shared_block_table = block_tables[seq_id][
413
- -curr_sliding_window_block:]
414
- self.cross_layer_shared_block_tables.append(
415
- cross_layer_shared_block_table)
416
-
417
- # Compute slot mapping.
418
- is_profile_run = is_block_tables_empty(block_tables)
419
- start_idx = compute_slot_mapping_start_idx(is_prompt, query_len,
420
- context_len,
421
- self.sliding_window)
422
- compute_slot_mapping(is_profile_run, self.slot_mapping, seq_id,
423
- seq_len, context_len, start_idx,
424
- self.block_size, inter_data.block_tables)
425
-
426
- def _get_graph_runner_block_tables(self, num_seqs: int,
427
- block_tables: List[List[int]],
428
- graph_block_tables) -> torch.Tensor:
429
- # The shape of graph_block_tables is
430
- # [max batch size, max context len // block size].
431
- # max_batch_size, max_blocks = self.runner.graph_block_tables.shape
432
- max_batch_size, max_blocks = graph_block_tables.shape
433
- assert max_batch_size >= num_seqs
434
-
435
- # graph_block_tables = self.runner.graph_block_tables[:num_seqs]
436
- graph_block_tables = graph_block_tables[:num_seqs]
437
- for i, block_table in enumerate(block_tables):
438
- if block_table:
439
- num_blocks = len(block_table)
440
- if num_blocks <= max_blocks:
441
- graph_block_tables[i, :num_blocks] = block_table
442
- else:
443
- # It may be possible to have more blocks allocated due
444
- # to lookahead slots of multi-step, however, they are
445
- # not used anyway, so can be safely ignored.
446
- graph_block_tables[
447
- i, :max_blocks] = block_table[:max_blocks]
448
-
449
- return torch.from_numpy(graph_block_tables).to(
450
- device=self.runner.device, non_blocking=True)
451
-
452
- def build(self, seq_lens: List[int], query_lens: List[int],
453
- cuda_graph_pad_size: int, batch_size: int):
454
- """Build attention metadata with on-device tensors.
455
-
456
- Args:
457
- seq_lens: The maybe padded sequence lengths of the input sequences.
458
- query_lens: The query lengths of the input sequences.
459
- cuda_graph_pad_size: The padding size for cuda graph.
460
- -1 if cuda graph is not used.
461
- batch_size: The maybe padded batch size.
462
- """
463
- prefix_cache_hit = any([
464
- inter_data.prefix_cache_hit
465
- for inter_data in self.input_builder.inter_data_list
466
- ])
467
- for inter_data in self.input_builder.inter_data_list:
468
- self._add_seq_group(inter_data,
469
- self.input_builder.chunked_prefill_enabled,
470
- prefix_cache_hit)
471
-
472
- device = self.runner.device
473
- use_captured_graph = cuda_graph_pad_size != -1
474
-
475
- max_query_len = max(query_lens)
476
- decode_query_lens = query_lens[self.num_prefills:]
477
- if len(decode_query_lens) > 0:
478
- max_decode_query_len = max(decode_query_lens)
479
- else:
480
- max_decode_query_len = 1
481
- max_prefill_seq_len = max(self.prefill_seq_lens, default=0)
482
- max_decode_seq_len = max(self.curr_seq_lens, default=0)
483
- num_decode_tokens = self.num_decode_tokens
484
- query_start_loc = list(accumulate(query_lens, initial=0))
485
- seq_start_loc = list(accumulate(seq_lens, initial=0))
486
-
487
- num_seqs = len(seq_lens)
488
- if use_captured_graph:
489
- self.slot_mapping.extend([PAD_SLOT_ID] * cuda_graph_pad_size)
490
- self.block_tables.extend([] * cuda_graph_pad_size)
491
-
492
- self.cross_layer_shared_block_tables.extend([] *
493
- cuda_graph_pad_size)
494
-
495
- num_decode_tokens = batch_size - self.num_prefill_tokens
496
- block_tables = self._get_graph_runner_block_tables(
497
- num_seqs, self.block_tables, self.runner.graph_block_tables)
498
- cross_layer_shared_block_tables = \
499
- self._get_graph_runner_block_tables(
500
- num_seqs, self.cross_layer_shared_block_tables,
501
- self.runner.cross_layer_shared_graph_block_tables)
502
- else:
503
- block_tables = make_tensor_with_pad(
504
- self.block_tables,
505
- pad=0,
506
- dtype=torch.int,
507
- device=device,
508
- )
509
- cross_layer_shared_block_tables = make_tensor_with_pad(
510
- self.cross_layer_shared_block_tables,
511
- pad=0,
512
- dtype=torch.int,
513
- device=device,
514
- )
515
- assert max_query_len > 0, ("query_lens: {}".format(query_lens))
516
-
517
- assert device is not None
518
- context_lens_tensor = async_tensor_h2d(self.context_lens, torch.int,
519
- device, self.runner.pin_memory)
520
- seq_lens_tensor = async_tensor_h2d(seq_lens, torch.int, device,
521
- self.runner.pin_memory)
522
- slot_mapping_tensor = async_tensor_h2d(self.slot_mapping, torch.long,
523
- device, self.runner.pin_memory)
524
- query_start_loc_tensor = async_tensor_h2d(query_start_loc, torch.int32,
525
- device,
526
- self.runner.pin_memory)
527
- seq_start_loc_tensor = async_tensor_h2d(seq_start_loc, torch.int32,
528
- device, self.runner.pin_memory)
529
- placeholder_index_maps = {
530
- modality: placeholder_map.index_map()
531
- for modality, placeholder_map in
532
- self.multimodal_placeholder_maps.items()
533
- }
534
-
535
- return DifferentialFlashAttentionMetadata(
536
- num_prefills=self.num_prefills,
537
- slot_mapping=slot_mapping_tensor,
538
- num_prefill_tokens=self.num_prefill_tokens,
539
- num_decode_tokens=num_decode_tokens,
540
- seq_lens=seq_lens,
541
- multi_modal_placeholder_index_maps=placeholder_index_maps,
542
- enable_kv_scales_calculation=True,
543
- seq_lens_tensor=seq_lens_tensor,
544
- max_query_len=max_query_len,
545
- max_decode_query_len=max_decode_query_len,
546
- max_prefill_seq_len=max_prefill_seq_len,
547
- max_decode_seq_len=max_decode_seq_len,
548
- query_start_loc=query_start_loc_tensor,
549
- seq_start_loc=seq_start_loc_tensor,
550
- context_lens_tensor=context_lens_tensor,
551
- block_tables=block_tables,
552
- cross_layer_shared_block_tables=cross_layer_shared_block_tables,
553
- use_cuda_graph=use_captured_graph,
554
- )
555
-
556
-
557
-class DifferentialFlashAttentionImpl(AttentionImpl):
558
- """
559
- If the input tensors contain prompt tokens, the layout is as follows:
560
- |<--------------- num_prefill_tokens ----------------->|
561
- |<--prefill_0-->|<--prefill_1-->|...|<--prefill_N-1--->|
562
-
563
- Otherwise, the layout is as follows:
564
- |<----------------- num_decode_tokens ------------------>|
565
- |<--decode_0-->|..........|<--decode_M-1-->|<--padding-->|
566
-
567
- Generation tokens can contain padding when cuda-graph is used.
568
- Currently, prompt tokens don't contain any padding.
569
-
570
- The prompts might have different lengths, while the generation tokens
571
- always have length 1.
572
-
573
- If chunked prefill is enabled, prefill tokens and decode tokens can be
574
- batched together in a flattened 1D query.
575
-
576
- |<----- num_prefill_tokens ---->|<------- num_decode_tokens --------->|
577
- |<-prefill_0->|...|<-prefill_N-1->|<--decode_0-->|...|<--decode_M-1-->|
578
-
579
- Currently, cuda graph is disabled for chunked prefill, meaning there's no
580
- padding between prefill and decode tokens.
581
- """
582
-
583
- def __init__(
584
- self,
585
- num_heads: int,
586
- head_size: int,
587
- scale: float,
588
- num_kv_heads: int,
589
- alibi_slopes: Optional[List[float]],
590
- sliding_window: Optional[int],
591
- kv_cache_dtype: str,
592
- logits_soft_cap: Optional[float] = None,
593
- attn_type: str = AttentionType.DECODER,
594
- kv_sharing_target_layer_name: Optional[str] = None,
595
- use_irope: bool = False,
596
- differential_flash_attention_config: Optional[Dict[str, Any]] = None,
597
- ) -> None:
598
- if differential_flash_attention_config is None:
599
- differential_flash_attention_config = {}
600
- self.differential_flash_attention_config = \
601
- differential_flash_attention_config
602
- self.used_shared_kv_cache = kv_sharing_target_layer_name is not None
603
- self.kv_sharing_target_layer_name = kv_sharing_target_layer_name
604
- if use_irope:
605
- logger.warning(
606
- "Using irope in V0 is not supported yet, it will fall back "
607
- "to global attention for long context.")
608
- self.num_heads = num_heads
609
- self.head_size = head_size
610
- self.scale = float(scale)
611
- self.num_kv_heads = num_kv_heads
612
- if alibi_slopes is not None:
613
- alibi_slopes = torch.tensor(alibi_slopes, dtype=torch.float32)
614
- self.alibi_slopes = alibi_slopes
615
- self.sliding_window = ((sliding_window - 1,
616
- 0) if sliding_window is not None else (-1, -1))
617
- self.kv_cache_dtype = kv_cache_dtype
618
- self.vllm_flash_attn_version = get_flash_attn_version(
619
- requires_alibi=self.alibi_slopes is not None)
620
- if is_quantized_kv_cache(self.kv_cache_dtype) and (
621
- not self.kv_cache_dtype.startswith("fp8")
622
- or not flash_attn_supports_fp8()):
623
- raise NotImplementedError(
624
- f"FlashAttention does not support {self.kv_cache_dtype} "
625
- "kv-cache on this device "
626
- f"(FA supports fp8 = {flash_attn_supports_fp8()}).")
627
- if logits_soft_cap is None:
628
- # In flash-attn, setting logits_soft_cap as 0 means no soft cap.
629
- logits_soft_cap = 0
630
- self.logits_soft_cap = logits_soft_cap
631
-
632
- assert self.num_heads % self.num_kv_heads == 0
633
- self.num_queries_per_kv = self.num_heads // self.num_kv_heads
634
-
635
- support_head_sizes = FlashAttentionBackend.get_supported_head_sizes()
636
- if head_size not in support_head_sizes:
637
- raise ValueError(
638
- f"Head size {head_size} is not supported by FlashAttention. "
639
- f"Supported head sizes are: {support_head_sizes}.")
640
- self.attn_type = attn_type
641
-
642
- self.lambda_full = None
643
- self.subln = self.differential_flash_attention_config["subln"]
644
-
645
- def split_heads(self, x):
646
- # split by num_heads, the stripe pattern is friendly to tensor parallel.
647
- x = rearrange(x, "... (H two) D -> ... H two D", two=2)
648
- x1 = x[..., 0, :]
649
- x2 = x[..., 1, :]
650
- return x1.contiguous(), x2.contiguous()
651
-
652
- def split_kv_cache(self, x):
653
- # split by num_heads, the stripe pattern is friendly to tensor parallel.
654
- if x.numel() == 0:
655
- return torch.empty(0), torch.empty(0)
656
-
657
- x1, x2 = x[0], x[1]
658
- return x1, x2
659
-
660
- def populate_kv_cache(self, layer: AttentionLayer, key: torch.Tensor,
661
- value: torch.Tensor, kv_cache: torch.Tensor,
662
- attn_metadata: DifferentialFlashAttentionMetadata):
663
- if kv_cache.numel() > 0 and key is not None and value is not None:
664
- updated_slot_mapping = attn_metadata.slot_mapping
665
- torch.ops._C_cache_ops.reshape_and_cache_flash(
666
- key,
667
- value,
668
- kv_cache[0],
669
- kv_cache[1],
670
- updated_slot_mapping.flatten(),
671
- self.kv_cache_dtype,
672
- layer._k_scale,
673
- layer._v_scale,
674
- )
675
-
676
- def forward_generate_kv_cache(
677
- self, query: torch.Tensor, key: Optional[torch.Tensor],
678
- value: Optional[torch.Tensor], k_cache: torch.Tensor,
679
- v_cache: torch.Tensor,
680
- attn_metadata: DifferentialFlashAttentionMetadata) -> torch.Tensor:
681
-
682
- head_size = self.head_size
683
- num_heads = self.num_heads // 2
684
- num_kv_heads = self.num_kv_heads // 2
685
-
686
- query = query.view(-1, num_heads, head_size)
687
- if key is not None:
688
- assert value is not None
689
- key = key.view(-1, num_kv_heads, head_size)
690
- value = value.view(-1, num_kv_heads, head_size)
691
- else:
692
- assert value is None
693
-
694
- num_prefill_tokens = attn_metadata.num_prefill_tokens
695
- num_decode_tokens = attn_metadata.num_decode_tokens
696
- assert key.shape[
697
- 0] == num_prefill_tokens + num_decode_tokens, "key shape mismatch"
698
- assert value.shape[
699
- 0] == num_prefill_tokens + num_decode_tokens, "value shape mismatch"
700
-
701
- output = torch.empty_like(query)
702
- # Query for decode. KV is not needed because it is already cached.
703
- decode_query = query[num_prefill_tokens:]
704
- # QKV for prefill.
705
- query = query[:num_prefill_tokens]
706
- if key is not None and value is not None:
707
- key = key[:num_prefill_tokens]
708
- value = value[:num_prefill_tokens]
709
-
710
- assert query.shape[0] == num_prefill_tokens, "query shape mismatch"
711
- assert decode_query.shape[
712
- 0] == num_decode_tokens, "decode query shape mismatch"
713
-
714
- if prefill_meta := attn_metadata.prefill_metadata:
715
- # Prompt run.
716
- if k_cache.numel() == 0 \
717
- or prefill_meta.block_tables is None \
718
- or prefill_meta.block_tables.numel() == 0:
719
- # normal attention
720
- prefill_output = flash_attn_varlen_func(
721
- q=query,
722
- k=key,
723
- v=value,
724
- cu_seqlens_q=prefill_meta.seq_start_loc,
725
- cu_seqlens_k=prefill_meta.seq_start_loc,
726
- max_seqlen_q=prefill_meta.max_prefill_seq_len,
727
- max_seqlen_k=prefill_meta.max_prefill_seq_len,
728
- softmax_scale=self.scale,
729
- causal=True,
730
- window_size=self.sliding_window,
731
- alibi_slopes=self.alibi_slopes,
732
- softcap=self.logits_soft_cap,
733
- fa_version=self.vllm_flash_attn_version,
734
- )
735
- assert prefill_output.shape == output[:
736
- num_prefill_tokens].shape
737
- output[:num_prefill_tokens] = prefill_output
738
- else:
739
- raise Exception("prefix caching not supported")
740
-
741
- if decode_meta := attn_metadata.decode_metadata:
742
- block_tables_arg = decode_meta.block_tables
743
- try:
744
- output[num_prefill_tokens:] = flash_attn_with_kvcache(
745
- q=decode_query.unsqueeze(1),
746
- k_cache=k_cache,
747
- v_cache=v_cache,
748
- block_table=block_tables_arg,
749
- cache_seqlens=decode_meta.seq_lens_tensor,
750
- softmax_scale=self.scale,
751
- causal=True,
752
- window_size=self.sliding_window,
753
- alibi_slopes=self.alibi_slopes,
754
- softcap=self.logits_soft_cap,
755
- fa_version=self.vllm_flash_attn_version,
756
- ).squeeze(1)
757
- except Exception as e:
758
- logger.error("Error in PagedAttention.forward_decode: %s",
759
- str(e))
760
- raise e
761
-
762
- # Reshape the output tensor.
763
- return output.view(-1, num_heads, head_size)
764
-
765
- def forward_with_kv_cache_only(
766
- self,
767
- query: torch.Tensor,
768
- k_cache: torch.Tensor,
769
- v_cache: torch.Tensor,
770
- attn_metadata: DifferentialFlashAttentionMetadata,
771
- ):
772
- if not attn_metadata.decode_metadata:
773
- block_tables_arg = attn_metadata.cross_layer_shared_block_tables
774
- else:
775
- block_tables_arg = attn_metadata.block_tables
776
-
777
- output = flash_attn_with_kvcache(
778
- q=query.unsqueeze(1),
779
- k_cache=k_cache,
780
- v_cache=v_cache,
781
- block_table=block_tables_arg,
782
- cache_seqlens=attn_metadata.seq_lens_tensor,
783
- softmax_scale=self.scale,
784
- causal=True,
785
- window_size=self.sliding_window,
786
- alibi_slopes=self.alibi_slopes,
787
- softcap=self.logits_soft_cap,
788
- fa_version=self.vllm_flash_attn_version,
789
- ).squeeze(1)
790
- return output
791
-
792
- def forward(
793
- self,
794
- layer: AttentionLayer,
795
- q: torch.Tensor,
796
- k: torch.Tensor,
797
- v: torch.Tensor,
798
- kv_cache: torch.Tensor,
799
- attn_metadata: DifferentialFlashAttentionMetadata,
800
- output: Optional[torch.Tensor] = None,
801
- output_scale: Optional[torch.Tensor] = None,
802
- output_block_scale: Optional[torch.Tensor] = None,
803
- ) -> torch.Tensor:
804
- """Forward pass with FlashAttention.
805
-
806
- Args:
807
- layer: Attention layer instance.
808
- q: Query tensor with shape = [num_tokens, num_heads, head_size]
809
- k: Key tensor with shape = [num_tokens, num_kv_heads, head_size]
810
- v: Value tensor with shape = [num_tokens, num_kv_heads, head_size]
811
- kv_cache: KV cache tensor with shape
812
- [2, num_blocks, block_size, num_kv_heads, head_size].
813
- NOTE: kv_cache will be an empty tensor with shape [0]
814
- for profiling run.
815
- attn_metadata: Metadata for attention.
816
- output: Output tensor with shape [num_tokens, num_heads, head_size]
817
- output_scale: Optional output scale tensor.
818
- output_block_scale: Optional output block scale tensor.
819
- NOTE: It in-place updates the output tensor.
820
- NOTE: FP8 quantization, flash-attn expect the size of
821
- {q,k,v}_descale to be (num_sequences, num_kv_heads).
822
- We use torch's .expand() to avoid duplicating values
823
- """
824
- if output_scale is not None or output_block_scale is not None:
825
- raise NotImplementedError(
826
- "fused output quantization is not yet supported"
827
- " for DifferentialFlashAttentionImpl")
828
-
829
- if self.lambda_full is None:
830
- self.lambda_init = self.differential_flash_attention_config[
831
- "lambda_init"]
832
- lambda_q1 = self.differential_flash_attention_config["lambda_q1"]
833
- lambda_k1 = self.differential_flash_attention_config["lambda_k1"]
834
- lambda_q2 = self.differential_flash_attention_config["lambda_q2"]
835
- lambda_k2 = self.differential_flash_attention_config["lambda_k2"]
836
- lambda_1 = torch.exp(
837
- torch.sum(lambda_q1 * lambda_k1, dim=-1).float()).type_as(q)
838
- lambda_2 = torch.exp(
839
- torch.sum(lambda_q2 * lambda_k2, dim=-1).float()).type_as(q)
840
- self.lambda_full = lambda_1 - lambda_2 + self.lambda_init
841
-
842
- if not self.used_shared_kv_cache: # need to generate kv-cache
843
- q = q.view(-1, self.num_heads, self.head_size)
844
- k = k.view(-1, self.num_kv_heads, self.head_size)
845
- v = v.view(-1, self.num_kv_heads, self.head_size)
846
-
847
- q1, q2 = self.split_heads(q)
848
- k1, k2 = self.split_heads(k)
849
- v1, v2 = self.split_heads(v)
850
-
851
- # kv_cache shape is (2, 2, num_blocks, block_size, num_kv_heads // 2, head_size) # noqa: E501
852
- # Split by half along the first dimension.
853
- kv_cache1, kv_cache2 = self.split_kv_cache(kv_cache)
854
- assert kv_cache1.is_contiguous(), "kv_cache1 is not contiguous"
855
- assert kv_cache2.is_contiguous(), "kv_cache2 is not contiguous"
856
-
857
- if kv_cache1.numel() != 0:
858
- self.populate_kv_cache(layer, k1, v1, kv_cache1, attn_metadata)
859
- self.populate_kv_cache(layer, k2, v2, kv_cache2, attn_metadata)
860
-
861
- key_cache1, value_cache1 = self.split_kv_cache(kv_cache1)
862
- key_cache2, value_cache2 = self.split_kv_cache(kv_cache2)
863
- else:
864
- key_cache1, value_cache1 = torch.empty(0), torch.empty(0)
865
- key_cache2, value_cache2 = torch.empty(0), torch.empty(0)
866
- attn11 = self.forward_generate_kv_cache(q1, k1, v1, key_cache1,
867
- value_cache1,
868
- attn_metadata)
869
- attn12 = self.forward_generate_kv_cache(q1, k1, v2, key_cache1,
870
- value_cache2,
871
- attn_metadata)
872
- attn11 = attn11.view(q1.shape)
873
- attn12 = attn12.view(q1.shape)
874
- attn1 = torch.cat([attn11, attn12], dim=-1)
875
-
876
- attn21 = self.forward_generate_kv_cache(q2, k2, v1, key_cache2,
877
- value_cache1,
878
- attn_metadata)
879
- attn22 = self.forward_generate_kv_cache(q2, k2, v2, key_cache2,
880
- value_cache2,
881
- attn_metadata)
882
- attn21 = attn21.view(q2.shape)
883
- attn22 = attn22.view(q2.shape)
884
- attn2 = torch.cat([attn21, attn22], dim=-1)
885
-
886
- attn = attn1 - self.lambda_full * attn2
887
- # attn shape (-1, self.num_heads // 2, 2 * self.head_dim)
888
- attn = self.subln(attn)
889
- attn = attn * (1 - self.lambda_init)
890
- # reshape back to 2 * num_head
891
- attn_output = rearrange(attn,
892
- "... H (two D) -> ... (H two) D",
893
- two=2)
894
-
895
- else: # reuse the kv cache, full attention
896
- q = q.view(-1, self.num_heads, self.head_size)
897
- q1, q2 = self.split_heads(q)
898
- # kv_cache shape is (2, num_blocks, block_size, num_kv_heads, head_size) # noqa: E501
899
- kv_cache1, kv_cache2 = self.split_kv_cache(kv_cache)
900
- key_cache1, value_cache1 = kv_cache1[0], kv_cache1[1]
901
- key_cache2, value_cache2 = kv_cache2[0], kv_cache2[1]
902
-
903
- attn11 = self.forward_with_kv_cache_only(q1, key_cache1,
904
- value_cache1,
905
- attn_metadata)
906
- attn12 = self.forward_with_kv_cache_only(q1, key_cache1,
907
- value_cache2,
908
- attn_metadata)
909
- attn11 = attn11.view(q1.shape)
910
- attn12 = attn12.view(q1.shape)
911
- attn1 = torch.cat([attn11, attn12], dim=-1)
912
-
913
- attn21 = self.forward_with_kv_cache_only(q2, key_cache2,
914
- value_cache1,
915
- attn_metadata)
916
- attn22 = self.forward_with_kv_cache_only(q2, key_cache2,
917
- value_cache2,
918
- attn_metadata)
919
- attn21 = attn21.view(q2.shape)
920
- attn22 = attn22.view(q2.shape)
921
- attn2 = torch.cat([attn21, attn22], dim=-1)
922
-
923
- attn = attn1 - self.lambda_full * attn2
924
- attn = self.subln(attn)
925
- attn = attn * (1 - self.lambda_init)
926
- # reshape back to 2 * num_head
927
- attn_output = rearrange(attn,
928
- "... H (two D) -> ... (H two) D",
929
- two=2)
930
- attn_output = attn_output.view(-1, self.num_heads * self.head_size)
931
- return attn_output
vllm/attention/backends/dual_chunk_flash_attn.py
deleted
-1495
@@ -1,1495 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-"""Attention layer with Dual chunk flash attention and sparse attention.
4
-"""
5
-import math
6
-from dataclasses import dataclass
7
-from typing import Any, Dict, List, Optional, Tuple, Type
8
-
9
-import torch
10
-import torch.distributed
11
-import torch.nn.functional as F
12
-
13
-from vllm import _custom_ops as ops
14
-from vllm.attention.backends.abstract import AttentionLayer, AttentionType
15
-from vllm.attention.backends.flash_attn import (FlashAttentionBackend,
16
- FlashAttentionImpl,
17
- FlashAttentionMetadata,
18
- FlashAttentionMetadataBuilder)
19
-from vllm.distributed.parallel_state import get_tensor_model_parallel_rank
20
-from vllm.logger import init_logger
21
-from vllm.utils import async_tensor_h2d
22
-from vllm.vllm_flash_attn import (flash_attn_varlen_func,
23
- flash_attn_with_kvcache, sparse_attn_func)
24
-
25
-logger = init_logger(__name__)
26
-
27
-
28
-class DualChunkFlashAttentionBackend(FlashAttentionBackend):
29
-
30
- accept_output_buffer: bool = False
31
-
32
- @staticmethod
33
- def get_name() -> str:
34
- return "DUAL_CHUNK_FLASH_ATTN"
35
-
36
- @staticmethod
37
- def get_impl_cls() -> Type["DualChunkFlashAttentionImpl"]:
38
- return DualChunkFlashAttentionImpl
39
-
40
- @staticmethod
41
- def get_metadata_cls() -> Type["DualChunkFlashAttentionMetadata"]:
42
- return DualChunkFlashAttentionMetadata
43
-
44
- @staticmethod
45
- def get_builder_cls() -> Type["DualChunkFlashAttentionMetadataBuilder"]:
46
- return DualChunkFlashAttentionMetadataBuilder
47
-
48
-
49
-@dataclass
50
-class DualChunkFlashAttentionMetadata(FlashAttentionMetadata):
51
- # Block size of the paged kv cache.
52
- block_size: int = 16
53
-
54
- # Original max position embeddings.
55
- original_max_position_embeddings: int = 0
56
-
57
- # Chunk size
58
- chunk_size: int = 8192
59
-
60
- # Local size
61
- local_size: int = 1024
62
-
63
- # (batch_size,). The orig sequence length per sequence.
64
- orig_seq_lens: Optional[List[int]] = None
65
-
66
- # orig_seq_lens stored as a tensor.
67
- orig_seq_lens_tensor: Optional[torch.Tensor] = None
68
-
69
- # Length scaling factor
70
- scaling_factor: Optional[torch.Tensor] = None
71
-
72
- # (batch_size,). Sequence lengths for intra attention.
73
- seq_lens_intra: Optional[torch.Tensor] = None
74
-
75
- # Max sequence length for intra attention.
76
- max_seq_len_intra: Optional[int] = None
77
-
78
- # (batch_size, num_blocks). Block table for intra attention.
79
- block_tables_intra: Optional[torch.Tensor] = None
80
-
81
- # (batch_size,). Sequence lengths for succ attention.
82
- seq_lens_succ: Optional[torch.Tensor] = None
83
-
84
- # Max sequence length for succ attention.
85
- max_seq_len_succ: Optional[int] = None
86
-
87
- # (batch_size, num_blocks). Block table for succ attention.
88
- block_tables_succ: Optional[torch.Tensor] = None
89
-
90
- # (batch_size,). Sequence lengths for inter attention.
91
- seq_lens_inter: Optional[torch.Tensor] = None
92
-
93
- # Max sequence length for inter attention.
94
- max_seq_len_inter: Optional[int] = None
95
-
96
- _cached_prefill_metadata: Optional[
97
- "DualChunkFlashAttentionMetadata"] = None
98
- _cached_decode_metadata: Optional["DualChunkFlashAttentionMetadata"] = None
99
-
100
- @property
101
- def prefill_metadata(self) -> Optional["DualChunkFlashAttentionMetadata"]:
102
- if self.num_prefills == 0:
103
- return None
104
-
105
- if self._cached_prefill_metadata is not None:
106
- return self._cached_prefill_metadata
107
-
108
- prefill_metadata = super().prefill_metadata
109
- if prefill_metadata is None:
110
- return None
111
-
112
- prefill_metadata = DualChunkFlashAttentionMetadata(
113
- **prefill_metadata.asdict_zerocopy())
114
-
115
- prefill_metadata.orig_seq_lens = (
116
- None if self.orig_seq_lens is None else
117
- self.orig_seq_lens[:self.num_prefills])
118
- prefill_metadata.orig_seq_lens_tensor = (
119
- None if self.orig_seq_lens_tensor is None else
120
- self.orig_seq_lens_tensor[:self.num_prefills])
121
-
122
- if self.original_max_position_embeddings > 0:
123
- assert prefill_metadata.orig_seq_lens_tensor is not None
124
- prefill_metadata.scaling_factor = (
125
- 0.1 * torch.log(prefill_metadata.orig_seq_lens_tensor /
126
- self.original_max_position_embeddings) +
127
- 1.0).clip(min=1)
128
-
129
- self._cached_prefill_metadata = prefill_metadata
130
- return prefill_metadata
131
-
132
- @property
133
- def decode_metadata(self) -> Optional["DualChunkFlashAttentionMetadata"]:
134
- if self.num_decode_tokens == 0:
135
- return None
136
-
137
- if self._cached_decode_metadata is not None:
138
- return self._cached_decode_metadata
139
-
140
- decode_metadata = super().decode_metadata
141
- if decode_metadata is None:
142
- return None
143
-
144
- decode_metadata = DualChunkFlashAttentionMetadata(
145
- **decode_metadata.asdict_zerocopy())
146
-
147
- decode_metadata.orig_seq_lens_tensor = (
148
- None if self.orig_seq_lens_tensor is None else
149
- self.orig_seq_lens_tensor[self.num_prefills:])
150
-
151
- assert decode_metadata.orig_seq_lens_tensor is not None
152
- assert decode_metadata.block_tables is not None
153
-
154
- cache_seq_lens = decode_metadata.orig_seq_lens_tensor
155
- chunk_len = self.chunk_size - self.local_size
156
- chunk_num_curr = (cache_seq_lens - 1) // chunk_len
157
- batch_size = decode_metadata.num_decode_tokens
158
-
159
- if self.original_max_position_embeddings > 0:
160
- decode_metadata.scaling_factor = (0.1 * torch.log(
161
- cache_seq_lens / self.original_max_position_embeddings) +
162
- 1.0).clip(min=1)
163
-
164
- seq_lens_intra = cache_seq_lens - chunk_num_curr * chunk_len
165
- max_seq_len_intra = seq_lens_intra.max().item()
166
- decode_metadata.seq_lens_intra = seq_lens_intra
167
- decode_metadata.max_seq_len_intra = max_seq_len_intra
168
-
169
- block_tables_intra = torch.zeros(
170
- batch_size,
171
- (max_seq_len_intra - 1) // self.block_size + 1,
172
- dtype=decode_metadata.block_tables.dtype,
173
- device=decode_metadata.block_tables.device,
174
- )
175
- for i in range(batch_size):
176
- st = chunk_num_curr[i] * chunk_len // self.block_size
177
- ed = min(
178
- st + (max_seq_len_intra - 1) // self.block_size + 1,
179
- (cache_seq_lens[i] - 1) // self.block_size + 1,
180
- )
181
- block_tables_intra[i, :ed -
182
- st] = decode_metadata.block_tables[i, st:ed]
183
- decode_metadata.block_tables_intra = block_tables_intra
184
-
185
- seq_lens_succ = (chunk_num_curr -
186
- (chunk_num_curr - 1).clip(min=0)) * chunk_len
187
- max_seq_len_succ = seq_lens_succ.max().item()
188
- decode_metadata.seq_lens_succ = seq_lens_succ
189
- decode_metadata.max_seq_len_succ = max_seq_len_succ
190
- if max_seq_len_succ:
191
- block_tables_succ = torch.zeros(
192
- batch_size,
193
- (max_seq_len_succ - 1) // self.block_size + 1,
194
- dtype=decode_metadata.block_tables.dtype,
195
- device=decode_metadata.block_tables.device,
196
- )
197
- for i in range(batch_size):
198
- start = ((chunk_num_curr[i] - 1).clip(min=0) * chunk_len //
199
- self.block_size)
200
- end = min(
201
- start + (max_seq_len_succ - 1) // self.block_size + 1,
202
- (cache_seq_lens[i] - 1) // self.block_size + 1,
203
- )
204
- block_tables_succ[
205
- i, :end - start] = decode_metadata.block_tables[i,
206
- start:end]
207
- decode_metadata.block_tables_succ = block_tables_succ
208
-
209
- seq_lens_inter = (chunk_num_curr - 1).clip(min=0) * chunk_len
210
- max_seq_len_inter = seq_lens_inter.max().item()
211
- decode_metadata.seq_lens_inter = seq_lens_inter
212
- decode_metadata.max_seq_len_inter = max_seq_len_inter
213
-
214
- self._cached_decode_metadata = decode_metadata
215
- return decode_metadata
216
-
217
-
218
-class DualChunkFlashAttentionMetadataBuilder(FlashAttentionMetadataBuilder):
219
-
220
- def prepare(self):
221
- super().prepare()
222
- self.orig_seq_lens: List[int] = []
223
-
224
- def _add_seq_group(self, inter_data, chunked_prefill_enabled: bool,
225
- prefix_cache_hit: bool):
226
- super()._add_seq_group(inter_data, chunked_prefill_enabled,
227
- prefix_cache_hit)
228
- for prompt_len, seq_len in zip(inter_data.prompt_lens,
229
- inter_data.seq_lens):
230
- self.orig_seq_lens.append(max(prompt_len, seq_len))
231
-
232
- def build(self, seq_lens: List[int], query_lens: List[int],
233
- cuda_graph_pad_size: int, batch_size: int):
234
- attn_metadata = super().build(seq_lens, query_lens,
235
- cuda_graph_pad_size, batch_size)
236
- attn_metadata = DualChunkFlashAttentionMetadata(
237
- **attn_metadata.asdict_zerocopy())
238
-
239
- device = self.runner.device
240
- attn_metadata.orig_seq_lens = self.orig_seq_lens
241
- attn_metadata.orig_seq_lens_tensor = async_tensor_h2d(
242
- self.orig_seq_lens, torch.int, device, self.runner.pin_memory)
243
-
244
- attn_metadata.block_size = self.runner.block_size
245
- dual_chunk_attn_config = getattr(self.runner.model_config.hf_config,
246
- "dual_chunk_attention_config", {})
247
- attn_metadata.original_max_position_embeddings = \
248
- dual_chunk_attn_config.get("original_max_position_embeddings", 0)
249
- attn_metadata.chunk_size = dual_chunk_attn_config.get(
250
- "chunk_size", 8192)
251
- attn_metadata.local_size = dual_chunk_attn_config.get(
252
- "local_size", 1024)
253
-
254
- return attn_metadata
255
-
256
-
257
-class DualChunkFlashAttentionImpl(FlashAttentionImpl):
258
- """
259
- If the input tensors contain prompt tokens, the layout is as follows:
260
- |<--------------- num_prefill_tokens ----------------->|
261
- |<--prefill_0-->|<--prefill_1-->|...|<--prefill_N-1--->|
262
- Otherwise, the layout is as follows:
263
- |<----------------- num_decode_tokens ------------------>|
264
- |<--decode_0-->|..........|<--decode_M-1-->|<--padding-->|
265
- Generation tokens can contain padding when cuda-graph is used.
266
- Currently, prompt tokens don't contain any padding.
267
- The prompts might have different lengths, while the generation tokens
268
- always have length 1.
269
- If chunked prefill is enabled, prefill tokens and decode tokens can be
270
- batched together in a flattened 1D query.
271
- |<----- num_prefill_tokens ---->|<------- num_decode_tokens --------->|
272
- |<-prefill_0->|...|<-prefill_N-1->|<--decode_0-->|...|<--decode_M-1-->|
273
- Currently, cuda graph is disabled for chunked prefill, meaning there's no
274
- padding between prefill and decode tokens.
275
- """
276
-
277
- def __init__(
278
- self,
279
- num_heads: int,
280
- head_size: int,
281
- scale: float,
282
- num_kv_heads: int,
283
- alibi_slopes: Optional[List[float]],
284
- sliding_window: Optional[int],
285
- kv_cache_dtype: str,
286
- logits_soft_cap: Optional[float] = None,
287
- attn_type: str = AttentionType.DECODER,
288
- kv_sharing_target_layer_name: Optional[str] = None,
289
- layer_idx: int = -1,
290
- dual_chunk_attention_config: Optional[Dict[str, Any]] = None,
291
- ) -> None:
292
- if kv_sharing_target_layer_name is not None:
293
- raise NotImplementedError("KV sharing is not supported in V0 "
294
- "DUAL_CHUNK_FLASH_ATTN backend.")
295
- self.num_heads = num_heads
296
- self.head_size = head_size
297
- self.scale = float(scale)
298
- self.num_kv_heads = num_kv_heads
299
- if alibi_slopes is not None:
300
- alibi_slopes = torch.tensor(alibi_slopes, dtype=torch.float32)
301
- self.alibi_slopes = alibi_slopes
302
- self.sliding_window = ((sliding_window, sliding_window)
303
- if sliding_window is not None else (-1, -1))
304
- self.kv_cache_dtype = kv_cache_dtype
305
-
306
- self.num_queries_per_kv = self.num_heads // self.num_kv_heads
307
- if sliding_window is not None:
308
- # NOTE(woosuk): flash-attn's sliding window does not work with
309
- # paged KV cache.
310
- raise ValueError(
311
- "Sliding window is not supported in FlashAttention.")
312
-
313
- support_head_sizes = (
314
- DualChunkFlashAttentionBackend.get_supported_head_sizes())
315
-
316
- if head_size not in support_head_sizes:
317
- raise ValueError(
318
- f"Head size {head_size} is not supported by FlashAttention. "
319
- f"Supported head sizes are: {support_head_sizes}.")
320
-
321
- assert dual_chunk_attention_config is not None
322
- self.chunk_size = dual_chunk_attention_config.get("chunk_size", 8192)
323
- self.local_size = dual_chunk_attention_config.get("local_size", 1024)
324
- self.original_max_position_embeddings = dual_chunk_attention_config.get(
325
- "original_max_position_embeddings", 0)
326
- self.sparse_attention_config = dual_chunk_attention_config.get(
327
- "sparse_attention_config", None)
328
- if not self.sparse_attention_config:
329
- logger.warning_once("Sparse attention will not be enabled as "
330
- "sparse attention config is not provided.")
331
- self.sparse_attention_enabled = dual_chunk_attention_config.get(
332
- "sparse_attention_enabled", self.sparse_attention_config
333
- is not None)
334
- self.sparse_attention_threshold = dual_chunk_attention_config.get(
335
- "sparse_attention_threshold", 32768)
336
- self.sparse_attention_last_q = dual_chunk_attention_config.get(
337
- "sparse_attention_last_q", 64)
338
- self.layer_idx = layer_idx
339
- self.dual_chunk_attention_config = dual_chunk_attention_config
340
-
341
- if self.sparse_attention_config:
342
- self.sparse_attention_config = {
343
- int(i): j
344
- for i, j in self.sparse_attention_config[
345
- self.layer_idx].items()
346
- }
347
- start_head = self.num_heads * get_tensor_model_parallel_rank()
348
- end_head = start_head + self.num_heads
349
- self.sparse_attention_config = [
350
- self.sparse_attention_config[i]
351
- for i in range(start_head, end_head)
352
- ]
353
-
354
- if self.sparse_attention_enabled:
355
- self.arange = torch.arange(self.sparse_attention_last_q,
356
- device="cuda")
357
- self.last_q_mask = (self.arange[None, None, :, None]
358
- >= self.arange[None, None, None, :])
359
-
360
- def forward( # type: ignore
361
- self,
362
- layer: AttentionLayer,
363
- query: torch.Tensor,
364
- key: torch.Tensor,
365
- value: torch.Tensor,
366
- kv_cache: torch.Tensor,
367
- attn_metadata: DualChunkFlashAttentionMetadata,
368
- output: Optional[torch.Tensor] = None,
369
- output_scale: Optional[torch.Tensor] = None,
370
- output_block_scale: Optional[torch.Tensor] = None,
371
- ) -> torch.Tensor:
372
- """Forward pass with DualChunkFlashAttention.
373
- Args:
374
- query: shape = [num_tokens, num_heads * head_size]
375
- query_succ: shape = [num_tokens, num_heads * head_size]
376
- query_inter: shape = [num_tokens, num_heads * head_size]
377
- key: shape = [num_tokens, num_kv_heads * head_size]
378
- value: shape = [num_tokens, num_kv_heads * head_size]
379
- kv_cache = [2, num_blocks, block_size, num_kv_heads * head_size]
380
- attn_metadata: Metadata for attention.
381
- Returns:
382
- shape = [num_tokens, num_heads * head_size]
383
- """
384
- assert output is None, "Output tensor not supported for DualChunk"
385
-
386
- if output_scale is not None or output_block_scale is not None:
387
- raise NotImplementedError(
388
- "fused output quantization is not yet supported"
389
- " for FlashAttentionImpl")
390
-
391
- (
392
- query,
393
- query_succ,
394
- query_inter,
395
- query_succ_critical,
396
- query_inter_critical,
397
- ) = torch.split(query, query.shape[-1] // 5, dim=-1)
398
-
399
- assert (
400
- query_succ is not None and query_inter is not None
401
- ), "query_succ and query_inter are required in Dual Chunk Attention."
402
-
403
- num_tokens, hidden_size = query.shape
404
-
405
- # Reshape the query, key, and value tensors.
406
- query = query.view(-1, self.num_heads, self.head_size)
407
- query_succ = query_succ.view(-1, self.num_heads, self.head_size)
408
- query_inter = query_inter.view(-1, self.num_heads, self.head_size)
409
- query_succ_critical = query_succ_critical.view(-1, self.num_heads,
410
- self.head_size)
411
- query_inter_critical = query_inter_critical.view(
412
- -1, self.num_heads, self.head_size)
413
- key = key.view(-1, self.num_kv_heads, self.head_size)
414
- value = value.view(-1, self.num_kv_heads, self.head_size)
415
-
416
- if self.original_max_position_embeddings > 0:
417
- if prefill_meta := attn_metadata.prefill_metadata:
418
- assert prefill_meta.scaling_factor is not None
419
- assert prefill_meta.query_start_loc is not None
420
- assert prefill_meta.orig_seq_lens is not None
421
- current_start = 0
422
- query_start_loc_cpu = prefill_meta.query_start_loc.cpu()
423
- for i in range(len(prefill_meta.orig_seq_lens)):
424
- current_end = (current_start +
425
- (query_start_loc_cpu[i + 1] -
426
- query_start_loc_cpu[i]).item())
427
- key[current_start:current_end].mul_(
428
- prefill_meta.scaling_factor[i])
429
- current_start = current_end
430
- assert current_end <= attn_metadata.num_prefill_tokens
431
- if decode_meta := attn_metadata.decode_metadata:
432
- assert decode_meta.scaling_factor is not None
433
- scaling_factor = decode_meta.scaling_factor
434
- key[attn_metadata.num_prefill_tokens:].mul_(
435
- scaling_factor.unsqueeze(-1).unsqueeze(-1))
436
-
437
- if kv_cache is not None and kv_cache.numel() > 0:
438
- key_cache = kv_cache[0]
439
- value_cache = kv_cache[1]
440
-
441
- # Reshape the input keys and values and store them in the cache.
442
- # If kv_cache is not provided, the new key and value tensors are
443
- # not cached. This happens during the initial memory profiling run.
444
- ops.reshape_and_cache_flash(
445
- key,
446
- value,
447
- key_cache,
448
- value_cache,
449
- attn_metadata.slot_mapping.flatten(),
450
- self.kv_cache_dtype,
451
- layer._k_scale,
452
- layer._v_scale,
453
- )
454
-
455
- num_prefill_tokens = attn_metadata.num_prefill_tokens
456
- num_decode_tokens = attn_metadata.num_decode_tokens
457
- assert key.shape[0] == num_prefill_tokens + num_decode_tokens
458
- assert value.shape[0] == num_prefill_tokens + num_decode_tokens
459
- output = torch.empty_like(query)
460
-
461
- # Query for decode. KV is not needed because it is already cached.
462
- decode_query = query[num_prefill_tokens:]
463
- decode_query_succ = query_succ[num_prefill_tokens:]
464
- decode_query_inter = query_inter[num_prefill_tokens:]
465
-
466
- # QKV for prefill.
467
- query = query[:num_prefill_tokens]
468
- query_succ = query_succ[:num_prefill_tokens]
469
- query_inter = query_inter[:num_prefill_tokens]
470
- query_succ_critical = query_succ_critical[:num_prefill_tokens]
471
- query_inter_critical = query_inter_critical[:num_prefill_tokens]
472
- key = key[:num_prefill_tokens]
473
- value = value[:num_prefill_tokens]
474
- assert query.shape[0] == num_prefill_tokens
475
- assert decode_query.shape[0] == num_decode_tokens
476
-
477
- if prefill_meta := attn_metadata.prefill_metadata:
478
- # Prompt run.
479
- if (kv_cache is None or prefill_meta.block_tables is None
480
- or prefill_meta.block_tables.numel() == 0):
481
- # normal attention, called during the profiling run.
482
- out = flash_attn_varlen_func(
483
- q=query,
484
- k=key,
485
- v=value,
486
- cu_seqlens_q=prefill_meta.seq_start_loc,
487
- cu_seqlens_k=prefill_meta.seq_start_loc,
488
- max_seqlen_q=prefill_meta.max_prefill_seq_len,
489
- max_seqlen_k=prefill_meta.max_prefill_seq_len,
490
- softmax_scale=self.scale,
491
- causal=True,
492
- window_size=self.sliding_window,
493
- alibi_slopes=self.alibi_slopes,
494
- )
495
- assert output[:num_prefill_tokens].shape == out.shape
496
- output[:num_prefill_tokens] = out
497
- else:
498
- # prefix-enabled attention
499
- assert prefill_meta.seq_lens is not None
500
- assert prefill_meta.orig_seq_lens is not None
501
- output[:num_prefill_tokens] = (
502
- self._dual_chunk_flash_attn_prefill(
503
- q=query,
504
- q_succ=query_succ,
505
- q_inter=query_inter,
506
- q_succ_critical=query_succ_critical,
507
- q_inter_critical=query_inter_critical,
508
- k=key_cache,
509
- v=value_cache,
510
- cu_seqlens_q=prefill_meta.query_start_loc,
511
- cu_seqlens_k=prefill_meta.seq_start_loc,
512
- orig_seq_lens=prefill_meta.orig_seq_lens,
513
- scaling_factor=prefill_meta.scaling_factor,
514
- softmax_scale=self.scale,
515
- causal=True,
516
- window_size=(-1, -1),
517
- alibi_slopes=self.alibi_slopes,
518
- block_table=prefill_meta.block_tables,
519
- chunk_size=self.chunk_size,
520
- local_size=self.local_size,
521
- ))
522
-
523
- if decode_meta := attn_metadata.decode_metadata:
524
- # Decoding run.
525
- output[num_prefill_tokens:] = (
526
- self._dual_chunk_flash_attn_decoding(
527
- decode_query.unsqueeze(1),
528
- decode_query_succ.unsqueeze(1),
529
- decode_query_inter.unsqueeze(1),
530
- key_cache,
531
- value_cache,
532
- block_table=decode_meta.block_tables,
533
- cache_seqlens=decode_meta.seq_lens_tensor,
534
- softmax_scale=self.scale,
535
- causal=True,
536
- alibi_slopes=self.alibi_slopes,
537
- chunk_size=self.chunk_size,
538
- local_size=self.local_size,
539
- original_max_position_embeddings=self.
540
- original_max_position_embeddings,
541
- decode_meta=decode_meta,
542
- ).squeeze(1))
543
- # Reshape the output tensor.
544
- return output.view(num_tokens, hidden_size)
545
-
546
- def _dual_chunk_flash_attn_prefill(
547
- self,
548
- q,
549
- q_succ,
550
- q_inter,
551
- q_succ_critical,
552
- q_inter_critical,
553
- k,
554
- v,
555
- cu_seqlens_q,
556
- cu_seqlens_k,
557
- orig_seq_lens: List[int],
558
- scaling_factor: torch.Tensor,
559
- softmax_scale: float,
560
- causal: Optional[bool] = True,
561
- window_size: Tuple[int, int] = (-1, -1),
562
- alibi_slopes: Optional[torch.Tensor] = None,
563
- block_table: Optional[torch.Tensor] = None,
564
- chunk_size: int = 8192,
565
- local_size: int = 1024,
566
- ):
567
- if alibi_slopes is not None:
568
- raise ValueError(
569
- "Dual Chunk Attention does not support alibi_slopes")
570
- if not causal:
571
- raise ValueError(
572
- "Dual Chunk Attention does not support causal=False")
573
- if window_size != (-1, -1):
574
- raise ValueError(
575
- "Dual Chunk Attention does not support window_size")
576
-
577
- cu_seqlens_q_cpu = cu_seqlens_q.cpu().tolist()
578
- cu_seqlens_k_cpu = cu_seqlens_k.cpu().tolist()
579
- all_outputs = []
580
-
581
- for i in range(0, len(cu_seqlens_q_cpu) - 1):
582
- qs = cu_seqlens_q_cpu[i]
583
- qe = cu_seqlens_q_cpu[i:i + 2][-1]
584
- ks = cu_seqlens_k_cpu[i]
585
- ke = cu_seqlens_k_cpu[i:i + 2][-1]
586
-
587
- current_q = q[qs:qe]
588
- current_q_succ = q_succ[qs:qe]
589
- current_q_inter = q_inter[qs:qe]
590
- current_q_succ_critical = q_succ_critical[qs:qe]
591
- current_q_inter_critical = q_inter_critical[qs:qe]
592
-
593
- if block_table is None:
594
- current_k = k[ks:ke]
595
- current_v = v[ks:ke]
596
- current_block_table = None
597
- current_orig_seq_len = orig_seq_lens[i]
598
- else:
599
- current_block_table = block_table[i]
600
- current_orig_seq_len = orig_seq_lens[i]
601
- current_k = k
602
- current_v = v
603
- sparse_attn_enabled = (self.sparse_attention_enabled
604
- and current_orig_seq_len
605
- > self.sparse_attention_threshold)
606
-
607
- if current_q.shape[0] == 0:
608
- continue
609
-
610
- if current_k.shape[0] == 0:
611
- all_outputs.append(
612
- torch.zeros(
613
- (current_q.shape[0], current_q.shape[1], v.shape[2]),
614
- device=q.device,
615
- dtype=q.dtype,
616
- ))
617
- continue
618
-
619
- current_output = torch.empty_like(current_q)
620
- group_size = int(current_q.size(-2) / current_k.size(-2))
621
-
622
- if sparse_attn_enabled:
623
- num_device_q_heads = current_q.size(-2)
624
- heads_vertical_size = torch.empty(size=(num_device_q_heads, ),
625
- dtype=torch.int32)
626
- heads_slash_size = torch.empty(size=(num_device_q_heads, ),
627
- dtype=torch.int32)
628
- for head_id in range(current_q.size(-2)):
629
- (
630
- ty,
631
- vertical_size,
632
- slash_size,
633
- _,
634
- ) = self.sparse_attention_config[head_id]
635
- assert ty == "vertical_and_slash", "only support slash mode"
636
-
637
- if vertical_size == 30:
638
- vertical_size += 100
639
- heads_vertical_size[head_id] = vertical_size
640
- heads_slash_size[head_id] = slash_size
641
-
642
- current_output = self._dual_chunk_flash_attn_prefill_func(
643
- current_q, # allheads
644
- current_q_succ,
645
- current_q_inter,
646
- current_q_succ_critical,
647
- current_q_inter_critical,
648
- current_k,
649
- current_v,
650
- current_block_table,
651
- softmax_scale,
652
- chunk_size,
653
- local_size,
654
- scaling_factor[i].item(),
655
- ke - ks,
656
- sparse_attn_enabled=sparse_attn_enabled,
657
- heads_vertical_size=heads_vertical_size,
658
- heads_slash_size=heads_slash_size,
659
- group_size=group_size)
660
- else:
661
- for head_id in range(current_q.size(-2)):
662
- # (seq_len, num_heads, head_size)
663
- current_q_head = current_q[:, head_id, :].unsqueeze(1)
664
- current_q_succ_head = \
665
- current_q_succ[:, head_id, :].unsqueeze(1)
666
- current_q_inter_head = \
667
- current_q_inter[:, head_id, :].unsqueeze(1)
668
- current_q_succ_head_critical = \
669
- current_q_succ_critical[:, head_id, :].unsqueeze(1)
670
- current_q_inter_head_critical = \
671
- current_q_inter_critical[:, head_id, :].unsqueeze(1)
672
- if block_table is not None:
673
- current_k_head = current_k[..., head_id //
674
- group_size, :].unsqueeze(2)
675
- current_v_head = current_v[..., head_id //
676
- group_size, :].unsqueeze(2)
677
-
678
- else:
679
- current_k_head = current_k[:, head_id, :].unsqueeze(1)
680
- current_v_head = current_v[:, head_id, :].unsqueeze(1)
681
-
682
- current_out = self._dual_chunk_flash_attn_prefill_func(
683
- current_q_head,
684
- current_q_succ_head,
685
- current_q_inter_head,
686
- current_q_succ_head_critical,
687
- current_q_inter_head_critical,
688
- current_k_head,
689
- current_v_head,
690
- current_block_table,
691
- softmax_scale,
692
- chunk_size,
693
- local_size,
694
- scaling_factor[i].item(),
695
- ke - ks,
696
- sparse_attn_enabled=sparse_attn_enabled,
697
- )
698
- current_output[:, head_id:head_id + 1, :] = current_out
699
- all_outputs.append(current_output)
700
- return torch.cat(all_outputs, dim=0)
701
-
702
- def _dual_chunk_flash_attn_prefill_func(
703
- self,
704
- q,
705
- q_succ,
706
- q_inter,
707
- q_succ_critical,
708
- q_inter_critical,
709
- k,
710
- v,
711
- block_table,
712
- softmax_scale: float,
713
- chunk_size: int,
714
- local_size: int,
715
- scaling_factor: float,
716
- k_length: int,
717
- sparse_attn_enabled: Optional[bool] = True,
718
- heads_vertical_size=None,
719
- heads_slash_size=None,
720
- group_size=None,
721
- ):
722
- flash_results = []
723
- chunk_len = chunk_size - local_size
724
-
725
- if block_table is not None:
726
- block_size = v.shape[1]
727
- if chunk_len % block_size != 0:
728
- raise ValueError("chunk_len must be divisible by block_size.")
729
- else:
730
- block_size = 1
731
-
732
- if self.original_max_position_embeddings > 0:
733
- softmax_scale = softmax_scale * scaling_factor
734
-
735
- begin = k_length - q.shape[0]
736
- while begin < k_length:
737
- flash_per_chunk = []
738
-
739
- prev_chunk_end_pos = (begin // chunk_len) * chunk_len
740
- next_chunk_end_pos = prev_chunk_end_pos + chunk_len
741
- end = min(next_chunk_end_pos, k_length)
742
- qbegin = begin - (k_length - q.shape[0])
743
- qend = end - (k_length - q.shape[0])
744
-
745
- qk_chunks = []
746
- q_states_intra = q[qbegin:qend]
747
- # choose critical token
748
- if block_table is not None:
749
- block_tables_intra = _get_block(block_table, block_size,
750
- prev_chunk_end_pos, end)
751
- k_states_intra = k[block_tables_intra].view(
752
- -1, *k.shape[-2:])[:(end - prev_chunk_end_pos)]
753
- v_states_intra = v[block_tables_intra].view(
754
- -1, *v.shape[-2:])[:(end - prev_chunk_end_pos)]
755
- else:
756
- block_tables_intra = None
757
- k_states_intra = k[prev_chunk_end_pos:end]
758
- v_states_intra = v[prev_chunk_end_pos:end]
759
-
760
- if sparse_attn_enabled:
761
- last_q_size = min(qend - qbegin, self.sparse_attention_last_q)
762
- _, num_device_k_heads, head_dim = k_states_intra.shape
763
- k_states_intra = (k_states_intra.unsqueeze(2).repeat(
764
- 1, 1, group_size,
765
- 1).reshape(-1, num_device_k_heads * group_size, head_dim))
766
- v_states_intra = (v_states_intra.unsqueeze(2).repeat(
767
- 1, 1, group_size,
768
- 1).reshape(-1, num_device_k_heads * group_size, head_dim))
769
- qk_chunks.append(
770
- (q_states_intra.transpose(0, 1)[:, -last_q_size:] *
771
- softmax_scale) @ k_states_intra.permute(1, 2, 0))
772
-
773
- if prev_chunk_end_pos - chunk_len >= 0:
774
- q_states_succ = q_succ[qbegin:qend]
775
- q_states_succ_critical = q_succ_critical[qbegin:qend]
776
- if block_table is not None:
777
- block_tables_succ = _get_block(
778
- block_table, block_size,
779
- prev_chunk_end_pos - chunk_len, prev_chunk_end_pos)
780
- k_states_succ = k[block_tables_succ].view(
781
- -1, *k.shape[-2:])[:chunk_len]
782
- v_states_succ = v[block_tables_succ].view(
783
- -1, *v.shape[-2:])[:chunk_len]
784
- else:
785
- k_states_succ = k[prev_chunk_end_pos -
786
- chunk_len:prev_chunk_end_pos]
787
- v_states_succ = v[prev_chunk_end_pos -
788
- chunk_len:prev_chunk_end_pos]
789
-
790
- if sparse_attn_enabled:
791
- k_states_succ = (k_states_succ.unsqueeze(2).repeat(
792
- 1, 1, group_size,
793
- 1).reshape(-1, num_device_k_heads * group_size,
794
- head_dim))
795
- v_states_succ = (v_states_succ.unsqueeze(2).repeat(
796
- 1, 1, group_size,
797
- 1).reshape(-1, num_device_k_heads * group_size,
798
- head_dim))
799
- qk_chunks.append((q_states_succ_critical.transpose(
800
- 0, 1)[:, -last_q_size:] * softmax_scale)
801
- @ k_states_succ.permute(1, 2, 0))
802
-
803
- if prev_chunk_end_pos - chunk_len * 2 >= 0:
804
- q_states_inter = q_inter[qbegin:qend]
805
- q_states_inter_critical = q_inter_critical[qbegin:qend]
806
- if block_table is not None:
807
- block_tables_inter = _get_block(
808
- block_table, block_size, 0,
809
- prev_chunk_end_pos - chunk_len)
810
- k_states_inter = k[block_tables_inter].view(
811
- -1, *k.shape[-2:])[:(prev_chunk_end_pos - chunk_len)]
812
- v_states_inter = v[block_tables_inter].view(
813
- -1, *v.shape[-2:])[:(prev_chunk_end_pos - chunk_len)]
814
- else:
815
- k_states_inter = k[:prev_chunk_end_pos - chunk_len]
816
- v_states_inter = v[:prev_chunk_end_pos - chunk_len]
817
-
818
- if sparse_attn_enabled:
819
- k_states_inter = (k_states_inter.unsqueeze(2).repeat(
820
- 1, 1, group_size,
821
- 1).reshape(-1, num_device_k_heads * group_size,
822
- head_dim))
823
- v_states_inter = (v_states_inter.unsqueeze(2).repeat(
824
- 1, 1, group_size,
825
- 1).reshape(-1, num_device_k_heads * group_size,
826
- head_dim))
827
- qk_chunks.append((q_states_inter_critical.transpose(
828
- 0, 1)[:, -last_q_size:] * softmax_scale)
829
- @ k_states_inter.permute(1, 2, 0))
830
-
831
- if sparse_attn_enabled:
832
- reversed_qk = qk_chunks[::-1]
833
- qk = torch.cat(reversed_qk, dim=-1)
834
-
835
- qk[:, :, -last_q_size:] = torch.where(
836
- self.last_q_mask[..., -last_q_size:,
837
- -last_q_size:].to(qk.device),
838
- qk[:, :, -last_q_size:], -torch.inf)
839
- qk = F.softmax(qk, dim=-1, dtype=torch.float32)
840
-
841
- vertical = qk.sum(-2, keepdim=True)
842
- vertical[..., :30] = torch.inf
843
-
844
- # Avoid sorting by using the min/max ints to fill the indexer
845
- # buffers.
846
- int32_max = torch.iinfo(torch.int32).max
847
- int32_min = torch.iinfo(torch.int32).min
848
- n_heads = qk.size()[0]
849
- max_slash_topk = torch.max(heads_slash_size).item()
850
- max_vertical_topk = torch.max(heads_vertical_size).item()
851
- # store each head's slash topk, vertical topk
852
- vertical = vertical.reshape((n_heads, -1))
853
- # prevent out of range when prompt size < max_vertical_topk
854
- max_vertical_topk = min(vertical.shape[-1], max_vertical_topk)
855
- vertical_topk_buffer = torch.topk(vertical, max_vertical_topk,
856
- -1).indices
857
- slash_topk_buffer = torch.empty(size=(n_heads, max_slash_topk),
858
- dtype=torch.int64,
859
- device=qk.device)
860
- for head_i in range(n_heads):
861
- # (nqheads=1, lastq, k_len)
862
- head_score = qk[head_i:head_i + 1, :, :]
863
- slash_scores = _sum_all_diagonal_matrix(head_score)
864
- if head_score.size(1) != 1:
865
- # drop right up corner
866
- slash_scores = slash_scores[..., :-last_q_size + 1]
867
- slash_scores[..., -100:] = torch.inf
868
-
869
- head_slash_size = heads_slash_size[head_i]
870
- head_slash_size = min(head_slash_size, vertical.size(-1))
871
- slash_topk = torch.topk(slash_scores, head_slash_size,
872
- -1).indices
873
- #(nheads, max_topk)
874
- slash_topk_buffer[head_i, :head_slash_size] = slash_topk
875
-
876
- # reset heads topk
877
- heads_slash_size[head_i] = head_slash_size
878
- heads_vertical_size[head_i] = min(
879
- heads_vertical_size[head_i], max_vertical_topk)
880
-
881
- # store
882
- vertical_buffer = torch.full((n_heads, max_vertical_topk),
883
- int32_max,
884
- dtype=torch.int64,
885
- device=q.device)
886
- slash_buffer = torch.full((n_heads, max_slash_topk),
887
- int32_min,
888
- dtype=torch.int64,
889
- device=q.device)
890
- succ_vertical_buffer = torch.full((n_heads, max_vertical_topk),
891
- int32_max,
892
- dtype=torch.int64,
893
- device=q.device)
894
- succ_slash_buffer = torch.full((n_heads, max_slash_topk),
895
- int32_min,
896
- dtype=torch.int64,
897
- device=q.device)
898
- inter_vertical_buffer = torch.full(
899
- (n_heads, max_vertical_topk),
900
- int32_max,
901
- dtype=torch.int64,
902
- device=q.device)
903
- inter_slash_buffer = torch.full((n_heads, max_slash_topk),
904
- int32_min,
905
- dtype=torch.int64,
906
- device=q.device)
907
-
908
- vertical_size_buffer = torch.empty(size=(n_heads, ),
909
- dtype=torch.int32,
910
- device=q.device)
911
- slash_sizes_buffer = torch.empty(size=(n_heads, ),
912
- dtype=torch.int32,
913
- device=q.device)
914
- succ_vertical_size_buffer = torch.empty(size=(n_heads, ),
915
- dtype=torch.int32,
916
- device=q.device)
917
- succ_slash_sizes_buffer = torch.empty(size=(n_heads, ),
918
- dtype=torch.int32,
919
- device=q.device)
920
- inter_vertical_size_buffer = torch.empty(size=(n_heads, ),
921
- dtype=torch.int32,
922
- device=q.device)
923
- inter_slash_sizes_buffer = torch.empty(size=(n_heads, ),
924
- dtype=torch.int32,
925
- device=q.device)
926
-
927
- for head_i in range(n_heads):
928
- vertical_topk = vertical_topk_buffer[
929
- head_i, :heads_vertical_size[head_i]]
930
- # intra
931
- intra_vertical_indices = vertical_topk[
932
- vertical_topk >=
933
- prev_chunk_end_pos] - prev_chunk_end_pos
934
- if intra_vertical_indices.nelement() == 0:
935
- intra_vertical_indices = torch.cat([
936
- intra_vertical_indices,
937
- torch.arange(0,
938
- k_states_intra.size(0),
939
- max(1,
940
- k_states_intra.size(0) / 5),
941
- dtype=torch.int32,
942
- device=intra_vertical_indices.device)
943
- ])
944
- slash_topk = slash_topk_buffer[
945
- head_i, :heads_slash_size[head_i]]
946
- intra_slash_indices = (
947
- (qk.size(-1) - 1) -
948
- slash_topk[slash_topk >= prev_chunk_end_pos])
949
- # fill buffer
950
- v_count = intra_vertical_indices.nelement()
951
- s_count = intra_slash_indices.nelement()
952
- vertical_size_buffer[head_i] = v_count
953
- slash_sizes_buffer[head_i] = s_count
954
- vertical_buffer[head_i, :v_count].copy_(
955
- intra_vertical_indices)
956
- slash_buffer[head_i, :s_count].copy_(intra_slash_indices)
957
- # succ
958
- if prev_chunk_end_pos - chunk_len >= 0:
959
- succ_vertical_indices = vertical_topk[
960
- (vertical_topk < prev_chunk_end_pos)
961
- & (vertical_topk >= prev_chunk_end_pos -
962
- chunk_len)] - (prev_chunk_end_pos - chunk_len)
963
- # TODO: support no vertical
964
- if succ_vertical_indices.nelement() == 0:
965
- succ_vertical_indices = torch.cat([
966
- succ_vertical_indices,
967
- torch.arange(
968
- 0,
969
- k_states_succ.size(0),
970
- max(1,
971
- k_states_succ.size(0) / 5),
972
- dtype=torch.int32,
973
- device=intra_vertical_indices.device)
974
- ])
975
- succ_slash_indices = (
976
- (prev_chunk_end_pos + (qend - qbegin) - 1) -
977
- slash_topk[((slash_topk >=
978
- (prev_chunk_end_pos - chunk_len)) &
979
- (slash_topk < (prev_chunk_end_pos +
980
- (qend - qbegin))))])
981
- if succ_slash_indices.nelement() == 0:
982
- succ_slash_indices = torch.cat([
983
- succ_slash_indices,
984
- torch.arange(
985
- 0,
986
- k_states_succ.size(0),
987
- max(1,
988
- k_states_succ.size(0) / 5),
989
- dtype=torch.int32,
990
- device=intra_vertical_indices.device)
991
- ])
992
- # fill buffer
993
- v_count = succ_vertical_indices.nelement()
994
- s_count = succ_slash_indices.nelement()
995
- succ_vertical_size_buffer[head_i] = v_count
996
- succ_slash_sizes_buffer[head_i] = s_count
997
- succ_vertical_buffer[head_i, :v_count].copy_(
998
- succ_vertical_indices)
999
- succ_slash_buffer[head_i, :s_count].copy_(
1000
- succ_slash_indices)
1001
-
1002
- if prev_chunk_end_pos - 2 * chunk_len >= 0:
1003
- inter_vertical_indices = vertical_topk[
1004
- vertical_topk < prev_chunk_end_pos - chunk_len]
1005
-
1006
- if inter_vertical_indices.nelement() == 0:
1007
- inter_vertical_indices = torch.cat([
1008
- inter_vertical_indices,
1009
- torch.arange(
1010
- 0,
1011
- k_states_inter.size(0),
1012
- max(1,
1013
- k_states_inter.size(0) / 5),
1014
- dtype=torch.int32,
1015
- device=intra_vertical_indices.device)
1016
- ])
1017
- inter_slash_indices = (
1018
- (prev_chunk_end_pos - chunk_len +
1019
- (qend - qbegin) - 1) -
1020
- slash_topk[slash_topk < (prev_chunk_end_pos -
1021
- chunk_len +
1022
- (qend - qbegin))])
1023
- if inter_slash_indices.nelement() == 0:
1024
- inter_slash_indices = torch.cat([
1025
- inter_slash_indices,
1026
- torch.arange(
1027
- 0,
1028
- k_states_inter.size(0),
1029
- max(1,
1030
- k_states_inter.size(0) / 5),
1031
- dtype=torch.int32,
1032
- device=intra_vertical_indices.device)
1033
- ])
1034
- # fill buffer
1035
- v_count = inter_vertical_indices.nelement()
1036
- s_count = inter_slash_indices.nelement()
1037
- inter_vertical_size_buffer[head_i] = v_count
1038
- inter_slash_sizes_buffer[head_i] = s_count
1039
- inter_vertical_buffer[head_i, :v_count].copy_(
1040
- inter_vertical_indices)
1041
- inter_slash_buffer[head_i, :s_count].copy_(
1042
- inter_slash_indices)
1043
- else:
1044
- intra_vertical_indices, intra_slash_indices = None, None
1045
- succ_vertical_indices, succ_slash_indices = None, None
1046
- inter_vertical_indices, inter_slash_indices = None, None
1047
-
1048
- if sparse_attn_enabled:
1049
- flash_result = self._do_flash_attn(
1050
- q_states_intra,
1051
- k_states_intra,
1052
- v_states_intra,
1053
- softmax_scale=softmax_scale,
1054
- causal=True,
1055
- stage="intra",
1056
- vertical_indices=vertical_buffer,
1057
- slash_indices=slash_buffer,
1058
- vertical_indices_count=vertical_size_buffer,
1059
- slash_indices_count=slash_sizes_buffer,
1060
- mergehead_softmax_scale=softmax_scale,
1061
- sparse_attn_enabled=sparse_attn_enabled)
1062
- else:
1063
- flash_result = self._do_flash_attn(
1064
- q_states_intra,
1065
- k_states_intra,
1066
- v_states_intra,
1067
- softmax_scale=softmax_scale,
1068
- causal=True,
1069
- stage="intra",
1070
- vertical_indices=intra_vertical_indices,
1071
- slash_indices=intra_slash_indices,
1072
- sparse_attn_enabled=sparse_attn_enabled)
1073
- flash_per_chunk.append(flash_result)
1074
-
1075
- if prev_chunk_end_pos - chunk_len >= 0:
1076
- if sparse_attn_enabled:
1077
- flash_result = self._do_flash_attn(
1078
- q_states_succ,
1079
- k_states_succ,
1080
- v_states_succ,
1081
- softmax_scale=softmax_scale,
1082
- causal=False,
1083
- stage="succ",
1084
- vertical_indices=succ_vertical_buffer,
1085
- slash_indices=succ_slash_buffer,
1086
- vertical_indices_count=succ_vertical_size_buffer,
1087
- slash_indices_count=succ_slash_sizes_buffer,
1088
- mergehead_softmax_scale=softmax_scale,
1089
- sparse_attn_enabled=sparse_attn_enabled)
1090
- else:
1091
- flash_result = self._do_flash_attn(
1092
- q_states_succ,
1093
- k_states_succ,
1094
- v_states_succ,
1095
- softmax_scale=softmax_scale,
1096
- causal=False,
1097
- stage="succ",
1098
- vertical_indices=succ_vertical_indices,
1099
- slash_indices=succ_slash_indices,
1100
- sparse_attn_enabled=sparse_attn_enabled)
1101
- flash_per_chunk.append(flash_result)
1102
-
1103
- if prev_chunk_end_pos - chunk_len * 2 >= 0:
1104
- if sparse_attn_enabled:
1105
- flash_result = self._do_flash_attn(
1106
- q_states_inter,
1107
- k_states_inter,
1108
- v_states_inter,
1109
- softmax_scale=softmax_scale,
1110
- causal=False,
1111
- stage="inter",
1112
- vertical_indices=inter_vertical_buffer,
1113
- slash_indices=inter_slash_buffer,
1114
- vertical_indices_count=inter_vertical_size_buffer,
1115
- slash_indices_count=inter_slash_sizes_buffer,
1116
- mergehead_softmax_scale=softmax_scale,
1117
- sparse_attn_enabled=sparse_attn_enabled)
1118
- else:
1119
- flash_result = self._do_flash_attn(
1120
- q_states_inter,
1121
- k_states_inter,
1122
- v_states_inter,
1123
- softmax_scale=softmax_scale,
1124
- causal=False,
1125
- stage="inter",
1126
- vertical_indices=inter_vertical_indices,
1127
- slash_indices=inter_slash_indices,
1128
- sparse_attn_enabled=sparse_attn_enabled)
1129
- flash_per_chunk.append(flash_result)
1130
-
1131
- flash_results.append(flash_per_chunk)
1132
- begin = end
1133
-
1134
- attn_output = self._merge_attn_outputs(flash_results)
1135
- del flash_results
1136
- return attn_output
1137
-
1138
- def _do_flash_attn(
1139
- self,
1140
- query_states: torch.Tensor,
1141
- key_states: torch.Tensor,
1142
- value_states: torch.Tensor,
1143
- softmax_scale: float,
1144
- causal: bool = True,
1145
- max_seqlen_k: Optional[int] = None,
1146
- stage: str = "intra",
1147
- vertical_indices: Optional[torch.Tensor] = None,
1148
- slash_indices: Optional[torch.Tensor] = None,
1149
- vertical_indices_count: Optional[torch.Tensor] = None,
1150
- slash_indices_count: Optional[torch.Tensor] = None,
1151
- mergehead_softmax_scale: Optional[float] = None,
1152
- sparse_attn_enabled: Optional[bool] = False,
1153
- ):
1154
- if max_seqlen_k is None:
1155
- max_seqlen_k = key_states.shape[0]
1156
-
1157
- q_len = query_states.shape[0]
1158
- q_heads = query_states.shape[1]
1159
- h_dim = query_states.shape[-1]
1160
-
1161
- if sparse_attn_enabled:
1162
- assert slash_indices is not None
1163
- if stage == "intra":
1164
- assert causal
1165
- else:
1166
- assert not causal
1167
-
1168
- query_states = query_states.unsqueeze(0).transpose(1, 2)
1169
- key_states = key_states.unsqueeze(0).transpose(1, 2)
1170
- value_states = value_states.unsqueeze(0).transpose(1, 2)
1171
-
1172
- q = query_states
1173
- k = key_states
1174
- v = value_states
1175
-
1176
- if (vertical_indices_count is not None and \
1177
- slash_indices_count is not None):
1178
- assert mergehead_softmax_scale is not None
1179
-
1180
- res, s_lse = _vertical_slash_sparse_attention(
1181
- q,
1182
- k,
1183
- v,
1184
- vertical_indices,
1185
- slash_indices,
1186
- mergehead_softmax_scale,
1187
- causal=causal,
1188
- stage=stage,
1189
- vertical_indices_count=vertical_indices_count,
1190
- slash_indices_count=slash_indices_count)
1191
- res = res.view(q_heads, q_len,
1192
- h_dim).transpose(0, 1) # (qlen,nhead,h_dim)
1193
- s_lse = s_lse.view(
1194
- q_heads, q_len,
1195
- 1).squeeze(-1).unsqueeze(0).float() # (1, nhead,qlen)
1196
- else:
1197
- res, s_lse = _vertical_slash_sparse_attention(q,
1198
- k,
1199
- v,
1200
- vertical_indices,
1201
- slash_indices,
1202
- softmax_scale,
1203
- causal=causal,
1204
- stage=stage)
1205
- res = res.view(q_len, q_heads, h_dim)
1206
- s_lse = s_lse.view(q_len, q_heads, 1).transpose(0, 2).float()
1207
- return res, s_lse
1208
-
1209
- output, softmax_lse = flash_attn_varlen_func(
1210
- q=query_states,
1211
- k=key_states,
1212
- v=value_states,
1213
- softmax_scale=softmax_scale,
1214
- cu_seqlens_q=torch.tensor([0, query_states.shape[0]],
1215
- dtype=torch.int32,
1216
- device=query_states.device),
1217
- max_seqlen_q=query_states.shape[0],
1218
- cu_seqlens_k=torch.tensor([0, max_seqlen_k],
1219
- dtype=torch.int32,
1220
- device=query_states.device),
1221
- max_seqlen_k=max_seqlen_k,
1222
- causal=causal,
1223
- return_softmax_lse=True,
1224
- )
1225
- softmax_lse = softmax_lse.view(q_len, q_heads, 1).transpose(0,
1226
- 2).float()
1227
- return output, softmax_lse
1228
-
1229
- def _merge_attn_outputs(
1230
- self,
1231
- flash_results: List[List[Tuple[torch.Tensor, torch.Tensor]]],
1232
- return_lse: Optional[bool] = False,
1233
- ) -> torch.Tensor:
1234
- attn_outputs_all = []
1235
- logits_all = []
1236
-
1237
- for flash_per_chunk in flash_results:
1238
- if len(flash_per_chunk) == 1:
1239
- attn_outputs_all.append(flash_per_chunk[0][0])
1240
- if return_lse:
1241
- logits_all.append(flash_per_chunk[0][1])
1242
- continue
1243
-
1244
- attn_outputs = torch.stack([
1245
- flash_attn_output[0] for flash_attn_output in flash_per_chunk
1246
- ])
1247
- logits = torch.stack([
1248
- flash_attn_output[1] for flash_attn_output in flash_per_chunk
1249
- ])
1250
- logits = logits.to(torch.float32)
1251
-
1252
- if return_lse:
1253
- max_val = torch.max(logits, dim=0).values
1254
- diff = torch.abs(logits[0] - logits[1])
1255
- log_sum_exp = max_val + torch.log1p(torch.exp(-diff))
1256
- logits_all.append(log_sum_exp)
1257
-
1258
- max_logits = torch.max(logits, dim=0).values
1259
- stable_logits = logits - max_logits.unsqueeze(0)
1260
- lse_s = torch.exp(stable_logits).detach()
1261
- lse_sum = torch.sum(lse_s, dim=0)
1262
- lse_s /= lse_sum
1263
- attn_outputs *= lse_s.unsqueeze(-1).transpose(2, 3).squeeze(1)
1264
- attn_outputs_all.append(attn_outputs.sum(dim=0))
1265
-
1266
- if return_lse:
1267
- return (torch.cat(attn_outputs_all,
1268
- dim=0), torch.cat(logits_all, dim=-1))
1269
- else:
1270
- return torch.cat(attn_outputs_all, dim=0)
1271
-
1272
- def _dual_chunk_flash_attn_decoding(
1273
- self,
1274
- query: torch.Tensor,
1275
- query_succ: torch.Tensor,
1276
- query_inter: torch.Tensor,
1277
- key_cache: torch.Tensor,
1278
- value_cache: torch.Tensor,
1279
- block_table: torch.Tensor,
1280
- cache_seqlens: torch.Tensor,
1281
- softmax_scale: float,
1282
- causal: bool,
1283
- alibi_slopes: Optional[torch.Tensor],
1284
- chunk_size: int,
1285
- local_size: int,
1286
- original_max_position_embeddings: int,
1287
- decode_meta: DualChunkFlashAttentionMetadata,
1288
- ):
1289
- if not causal:
1290
- raise ValueError(
1291
- "Dual Chunk Attention does not support causal=False")
1292
-
1293
- block_size = value_cache.shape[1]
1294
- chunk_len = chunk_size - local_size
1295
- if chunk_len % block_size != 0:
1296
- raise ValueError("chunk_len must be divisible by block_size.")
1297
- if original_max_position_embeddings > 0:
1298
- assert decode_meta.scaling_factor is not None
1299
- scaling_factor = decode_meta.scaling_factor
1300
- query = (query * scaling_factor.view(-1, 1, 1, 1)).to(
1301
- query.dtype
1302
- ) # possible for numerical issue, need to fused in the kernel
1303
- query_succ = (query_succ * scaling_factor.view(-1, 1, 1, 1)).to(
1304
- query.dtype)
1305
- query_inter = (query_inter * scaling_factor.view(-1, 1, 1, 1)).to(
1306
- query.dtype)
1307
- outputs_list = []
1308
- softmax_lses_list = []
1309
-
1310
- # intra-attention
1311
- intra_output, intra_softmax_lse = (
1312
- self._dual_chunk_flash_attn_decoding_with_exp_sums(
1313
- query,
1314
- key_cache,
1315
- value_cache,
1316
- decode_meta.block_tables_intra,
1317
- decode_meta.seq_lens_intra,
1318
- softmax_scale,
1319
- alibi_slopes,
1320
- causal=False,
1321
- ))
1322
- outputs_list.append(intra_output)
1323
- softmax_lses_list.append(intra_softmax_lse)
1324
-
1325
- # succ-attention
1326
- if decode_meta.max_seq_len_succ:
1327
- succ_output, succ_softmax_lse = (
1328
- self._dual_chunk_flash_attn_decoding_with_exp_sums(
1329
- query_succ,
1330
- key_cache,
1331
- value_cache,
1332
- decode_meta.block_tables_succ,
1333
- decode_meta.seq_lens_succ,
1334
- softmax_scale,
1335
- alibi_slopes,
1336
- causal=False,
1337
- ))
1338
- outputs_list.append(succ_output)
1339
- softmax_lses_list.append(succ_softmax_lse)
1340
-
1341
- # inter-attention
1342
- if decode_meta.max_seq_len_inter:
1343
- inter_output, inter_softmax_lse = (
1344
- self._dual_chunk_flash_attn_decoding_with_exp_sums(
1345
- query_inter,
1346
- key_cache,
1347
- value_cache,
1348
- block_table[:, :decode_meta.max_seq_len_inter],
1349
- decode_meta.seq_lens_inter,
1350
- softmax_scale,
1351
- alibi_slopes,
1352
- causal=False,
1353
- ))
1354
- outputs_list.append(inter_output)
1355
- softmax_lses_list.append(inter_softmax_lse)
1356
- outputs = torch.stack(outputs_list, dim=0)
1357
- del outputs_list
1358
- softmax_lses = torch.stack(softmax_lses_list, dim=0).to(torch.float32)
1359
- del softmax_lses_list
1360
- max_logits = torch.max(softmax_lses, dim=0).values
1361
- stable_logits = softmax_lses - max_logits.unsqueeze(0)
1362
- lse_s = torch.exp(stable_logits).detach()
1363
- lse_sum = torch.sum(lse_s, dim=0)
1364
- lse_s /= lse_sum
1365
- outputs *= lse_s.unsqueeze(-1).transpose(2, 3)
1366
- return outputs.sum(0)
1367
-
1368
- def _dual_chunk_flash_attn_decoding_with_exp_sums(
1369
- self,
1370
- query: torch.Tensor,
1371
- key_cache: torch.Tensor,
1372
- value_cache: torch.Tensor,
1373
- block_table: torch.Tensor,
1374
- cache_seqlens: torch.Tensor,
1375
- softmax_scale: float,
1376
- alibi_slopes: Optional[torch.Tensor],
1377
- causal: bool,
1378
- ):
1379
- out, softmax_lse = flash_attn_with_kvcache(
1380
- q=query,
1381
- k_cache=key_cache,
1382
- v_cache=value_cache,
1383
- block_table=block_table,
1384
- cache_seqlens=cache_seqlens,
1385
- softmax_scale=softmax_scale,
1386
- alibi_slopes=alibi_slopes,
1387
- causal=causal,
1388
- return_softmax_lse=True,
1389
- )
1390
- mask = (cache_seqlens == 0)
1391
- out[mask] = 0
1392
- softmax_lse[mask] = -float("inf")
1393
- return out, softmax_lse
1394
-
1395
-
1396
-def _vertical_slash_sparse_attention(
1397
- query: torch.Tensor, # [BATCH, N_HEADS, N_CTX, D_HEAD]
1398
- key: torch.Tensor, # [BATCH, N_HEADS, N_KV_CTX, D_HEAD]
1399
- value: torch.Tensor, # [BATCH, N_HEADS, N_KV_CTX, D_HEAD]
1400
- v_idx: torch.Tensor, # [BATCH, N_HEADS, NNZ_V]
1401
- s_idx: torch.Tensor, # [BATCH, N_HEADS, NNZ_S]
1402
- softmax_scale: float,
1403
- causal: bool = True,
1404
- stage: str = "intra",
1405
- block_size_M: int = 64,
1406
- block_size_N: int = 64,
1407
- vertical_indices_count: torch.Tensor = None, # [N_HEADS,]
1408
- slash_indices_count: torch.Tensor = None,
1409
-):
1410
- if stage == "intra":
1411
- assert causal
1412
- else:
1413
- assert not causal
1414
-
1415
- batch_size, num_heads, context_size, head_dim = query.shape
1416
- _, _, kv_seq_len, _ = key.shape
1417
-
1418
- if head_dim not in [16, 32, 64, 128, 256, 512]:
1419
- target_dim = 2**math.ceil(math.log2(head_dim)) - head_dim
1420
- query = F.pad(query, [0, target_dim, 0, 0, 0, 0, 0, 0])
1421
- key = F.pad(key, [0, target_dim, 0, 0, 0, 0, 0, 0])
1422
- value = F.pad(value, [0, target_dim, 0, 0, 0, 0, 0, 0])
1423
-
1424
- v_idx = v_idx.to(torch.int32).reshape(
1425
- (batch_size, num_heads, -1)).sort(dim=-1, descending=False)[0]
1426
- s_idx = s_idx.to(torch.int32).reshape(
1427
- (batch_size, num_heads, -1)).sort(dim=-1, descending=True)[0]
1428
- q_seqlens = torch.tensor([context_size],
1429
- dtype=torch.int32,
1430
- device=query.device)
1431
- kv_seqlens = torch.tensor([kv_seq_len],
1432
- dtype=torch.int32,
1433
- device=query.device)
1434
-
1435
- if vertical_indices_count is not None and slash_indices_count is not None:
1436
- (
1437
- block_count,
1438
- block_offset,
1439
- column_count,
1440
- column_index,
1441
- ) = ops.convert_vertical_slash_indexes_mergehead(
1442
- q_seqlens, kv_seqlens, v_idx, s_idx, vertical_indices_count,
1443
- slash_indices_count, context_size, block_size_M, block_size_N,
1444
- causal)
1445
- else:
1446
- (
1447
- block_count,
1448
- block_offset,
1449
- column_count,
1450
- column_index,
1451
- ) = ops.convert_vertical_slash_indexes(q_seqlens, kv_seqlens, v_idx,
1452
- s_idx, context_size,
1453
- block_size_M, block_size_N,
1454
- causal)
1455
-
1456
- q = query.transpose(1, 2).contiguous()
1457
- k = key.transpose(1, 2).contiguous()
1458
- v = value.transpose(1, 2).contiguous()
1459
- out, lse = sparse_attn_func(
1460
- q,
1461
- k,
1462
- v,
1463
- block_count,
1464
- block_offset,
1465
- column_count,
1466
- column_index,
1467
- causal=causal,
1468
- softmax_scale=softmax_scale,
1469
- return_softmax_lse=True,
1470
- )
1471
- out = out.transpose(1, 2).contiguous()
1472
- softmax_lse = lse.reshape(*lse.shape, 1)
1473
- return (out[..., :context_size, :head_dim],
1474
- softmax_lse[..., :context_size, :])
1475
-
1476
-
1477
-def _sum_all_diagonal_matrix(mat: torch.tensor):
1478
- h, n, m = mat.shape
1479
- # Zero matrix used for padding
1480
- zero_mat = torch.zeros((h, n, n), device=mat.device)
1481
- # pads the matrix on left and right
1482
- mat_padded = torch.cat((zero_mat, mat, zero_mat), -1)
1483
- # Change the strides
1484
- mat_strided = mat_padded.as_strided((1, n, n + m),
1485
- (n * (2 * n + m), 2 * n + m + 1, 1))
1486
- # Sums the resulting matrix's columns
1487
- sum_diags = torch.sum(mat_strided, 1)
1488
- return sum_diags[:, 1:] # drop left bottom corner
1489
-
1490
-
1491
-def _get_block(block_table: torch.Tensor, block_size: int, begin: int,
1492
- end: int):
1493
- begin_block = begin // block_size
1494
- end_block = (end - 1) // block_size + 1
1495
- return block_table[begin_block:end_block]
vllm/attention/backends/flash_attn.py
deleted
-929
@@ -1,929 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-"""Attention layer with FlashAttention."""
4
-from collections import defaultdict
5
-from dataclasses import dataclass
6
-from itertools import accumulate
7
-from typing import Dict, List, Optional, Tuple, Type
8
-
9
-import torch
10
-
11
-from vllm import _custom_ops as ops
12
-# yapf conflicts with isort for this block
13
-# yapf: disable
14
-from vllm.attention.backends.abstract import (AttentionBackend, AttentionImpl,
15
- AttentionLayer,
16
- AttentionMetadata,
17
- AttentionMetadataBuilder,
18
- AttentionType,
19
- is_quantized_kv_cache)
20
-# yapf: enable
21
-from vllm.attention.backends.utils import (
22
- PAD_SLOT_ID, CommonAttentionState, compute_slot_mapping,
23
- compute_slot_mapping_start_idx, get_num_prefill_decode_query_kv_tokens,
24
- get_seq_len_block_table_args, is_all_cross_attn_metadata_set,
25
- is_all_encoder_attn_metadata_set, is_block_tables_empty)
26
-from vllm.attention.utils.fa_utils import (flash_attn_supports_fp8,
27
- get_flash_attn_version)
28
-from vllm.logger import init_logger
29
-from vllm.multimodal import MultiModalPlaceholderMap
30
-from vllm.utils import async_tensor_h2d, make_tensor_with_pad
31
-from vllm.vllm_flash_attn import (flash_attn_varlen_func,
32
- flash_attn_with_kvcache)
33
-
34
-logger = init_logger(__name__)
35
-
36
-
37
-class FlashAttentionBackend(AttentionBackend):
38
-
39
- accept_output_buffer: bool = True
40
-
41
- @staticmethod
42
- def get_supported_head_sizes() -> List[int]:
43
- return [32, 64, 96, 128, 160, 192, 224, 256]
44
-
45
- @staticmethod
46
- def get_name() -> str:
47
- return "FLASH_ATTN"
48
-
49
- @staticmethod
50
- def get_impl_cls() -> Type["FlashAttentionImpl"]:
51
- return FlashAttentionImpl
52
-
53
- @staticmethod
54
- def get_metadata_cls() -> Type["AttentionMetadata"]:
55
- return FlashAttentionMetadata
56
-
57
- @staticmethod
58
- def get_builder_cls() -> Type["FlashAttentionMetadataBuilder"]:
59
- return FlashAttentionMetadataBuilder
60
-
61
- @staticmethod
62
- def get_state_cls() -> Type["CommonAttentionState"]:
63
- return CommonAttentionState
64
-
65
- @staticmethod
66
- def get_kv_cache_shape(
67
- num_blocks: int,
68
- block_size: int,
69
- num_kv_heads: int,
70
- head_size: int,
71
- ) -> Tuple[int, ...]:
72
- if block_size % 16 != 0:
73
- raise ValueError("Block size must be a multiple of 16.")
74
- return (2, num_blocks, block_size, num_kv_heads, head_size)
75
-
76
- @staticmethod
77
- def swap_blocks(
78
- src_kv_cache: torch.Tensor,
79
- dst_kv_cache: torch.Tensor,
80
- src_to_dst: torch.Tensor,
81
- ) -> None:
82
- src_key_cache = src_kv_cache[0]
83
- dst_key_cache = dst_kv_cache[0]
84
- ops.swap_blocks(src_key_cache, dst_key_cache, src_to_dst)
85
- src_value_cache = src_kv_cache[1]
86
- dst_value_cache = dst_kv_cache[1]
87
- ops.swap_blocks(src_value_cache, dst_value_cache, src_to_dst)
88
-
89
- @staticmethod
90
- def copy_blocks(
91
- kv_caches: List[torch.Tensor],
92
- src_to_dists: torch.Tensor,
93
- ) -> None:
94
- key_caches = [kv_cache[0] for kv_cache in kv_caches]
95
- value_caches = [kv_cache[1] for kv_cache in kv_caches]
96
-
97
- ops.copy_blocks(key_caches, value_caches, src_to_dists)
98
-
99
-
100
-@dataclass
101
-class FlashAttentionMetadata(AttentionMetadata):
102
- """Metadata for FlashAttentionBackend.
103
-
104
- NOTE: Any python object stored here is not updated when it is
105
- cuda-graph replayed. If you have values that need to be changed
106
- dynamically, it should be stored in tensor. The tensor has to be
107
- updated from `CUDAGraphRunner.forward` API.
108
- """
109
- # (batch_size,). The sequence length per sequence. Sequence length means
110
- # the computed tokens + new tokens None if it is a decoding.
111
- seq_lens: Optional[List[int]]
112
- # seq_lens stored as a tensor.
113
- seq_lens_tensor: Optional[torch.Tensor]
114
-
115
- # NOTE(sang): Definition of context_len, query_len, and seq_len.
116
- # |---------- N-1 iteration --------|
117
- # |---------------- N iteration ---------------------|
118
- # |- tokenA -|......................|-- newTokens ---|
119
- # |---------- context_len ----------|
120
- # |-------------------- seq_len ---------------------|
121
- # |-- query_len ---|
122
-
123
- # Maximum sequence length among prefill batch. 0 if there are decoding
124
- # requests only.
125
- max_prefill_seq_len: int
126
- # Maximum sequence length among decode batch. 0 if there are prefill
127
- # requests only.
128
- max_decode_seq_len: int
129
- # (batch_size,) A tensor of context lengths (tokens that are computed
130
- # so far).
131
- context_lens_tensor: Optional[torch.Tensor]
132
-
133
- # (batch_size, max_blocks_per_seq).
134
- # Block addresses per sequence. (Seq id -> list of physical block)
135
- # E.g., [0, 1, 2] means tokens are stored in 0th, 1st, and 2nd blocks
136
- # in the kv cache. Each block can contain up to block_size tokens.
137
- # 2nd dimensions are padded up to max_blocks_per_seq if it is cuda-graph
138
- # captured.
139
- block_tables: Optional[torch.Tensor]
140
-
141
- # Whether or not if cuda graph is enabled.
142
- # Cuda-graph is currently enabled for decoding only.
143
- # TODO(woosuk): Move `use_cuda_graph` out since it's unrelated to attention.
144
-
145
- use_cuda_graph: bool
146
-
147
- # Maximum query length in the batch.
148
- max_query_len: Optional[int] = None
149
-
150
- # Max number of query tokens among request in the batch.
151
- max_decode_query_len: Optional[int] = None
152
-
153
- # (batch_size + 1,). The cumulative subquery lengths of the sequences in
154
- # the batch, used to index into subquery. E.g., if the subquery length
155
- # is [4, 6], it is [0, 4, 10].
156
- query_start_loc: Optional[torch.Tensor] = None
157
- # (batch_size + 1,). The cumulative sequence lengths of the sequences in
158
- # the batch, used to index into sequence. E.g., if the sequence length is
159
- # [4, 6], it is [0, 4, 10].
160
- seq_start_loc: Optional[torch.Tensor] = None
161
-
162
- _cached_prefill_metadata: Optional["FlashAttentionMetadata"] = None
163
- _cached_decode_metadata: Optional["FlashAttentionMetadata"] = None
164
-
165
- # Begin encoder attn & enc/dec cross-attn fields...
166
-
167
- # Encoder sequence lengths representation
168
- encoder_seq_lens: Optional[List[int]] = None
169
- encoder_seq_lens_tensor: Optional[torch.Tensor] = None
170
- # (batch_size + 1,). The cumulative sequence lengths of the sequences in
171
- # the batch, used to index into sequence. E.g., if the sequence length is
172
- # [4, 6], it is [0, 4, 10].
173
- encoder_seq_start_loc: Optional[torch.Tensor] = None
174
- # Maximum sequence length among encoder sequences
175
- max_encoder_seq_len: Optional[int] = None
176
- # Number of tokens input to encoder
177
- num_encoder_tokens: Optional[int] = None
178
-
179
- # Cross-attention memory-mapping data structures: slot mapping
180
- # and block tables
181
- cross_slot_mapping: Optional[torch.Tensor] = None
182
- cross_block_tables: Optional[torch.Tensor] = None
183
-
184
- @property
185
- def is_all_encoder_attn_metadata_set(self):
186
- '''
187
- All attention metadata required for encoder attention is set.
188
- '''
189
- return is_all_encoder_attn_metadata_set(self)
190
-
191
- @property
192
- def is_all_cross_attn_metadata_set(self):
193
- '''
194
- All attention metadata required for enc/dec cross-attention is set.
195
-
196
- Superset of encoder attention required metadata.
197
- '''
198
- return is_all_cross_attn_metadata_set(self)
199
-
200
- @property
201
- def prefill_metadata(self) -> Optional["FlashAttentionMetadata"]:
202
- if self.num_prefills == 0:
203
- return None
204
-
205
- if self._cached_prefill_metadata is not None:
206
- return self._cached_prefill_metadata
207
-
208
- assert ((self.seq_lens is not None)
209
- or (self.encoder_seq_lens is not None))
210
- assert ((self.seq_lens_tensor is not None)
211
- or (self.encoder_seq_lens_tensor is not None))
212
-
213
- # Compute some attn_metadata fields which default to None
214
- query_start_loc = (None if self.query_start_loc is None else
215
- self.query_start_loc[:self.num_prefills + 1])
216
- slot_mapping = (None if self.slot_mapping is None else
217
- self.slot_mapping[:self.num_prefill_tokens])
218
- seq_lens = (None if self.seq_lens is None else
219
- self.seq_lens[:self.num_prefills])
220
- seq_lens_tensor = (None if self.seq_lens_tensor is None else
221
- self.seq_lens_tensor[:self.num_prefills])
222
- seq_start_loc = (None if self.seq_start_loc is None else
223
- self.seq_start_loc[:self.num_prefills + 1])
224
- context_lens_tensor = (None if self.context_lens_tensor is None else
225
- self.context_lens_tensor[:self.num_prefills])
226
- block_tables = (None if self.block_tables is None else
227
- self.block_tables[:self.num_prefills])
228
-
229
- self._cached_prefill_metadata = FlashAttentionMetadata(
230
- num_prefills=self.num_prefills,
231
- num_prefill_tokens=self.num_prefill_tokens,
232
- num_decode_tokens=0,
233
- slot_mapping=slot_mapping,
234
- multi_modal_placeholder_index_maps=self.
235
- multi_modal_placeholder_index_maps,
236
- enable_kv_scales_calculation=self.enable_kv_scales_calculation,
237
- seq_lens=seq_lens,
238
- seq_lens_tensor=seq_lens_tensor,
239
- max_query_len=self.max_query_len,
240
- max_prefill_seq_len=self.max_prefill_seq_len,
241
- max_decode_query_len=0,
242
- max_decode_seq_len=0,
243
- query_start_loc=query_start_loc,
244
- seq_start_loc=seq_start_loc,
245
- context_lens_tensor=context_lens_tensor,
246
- block_tables=block_tables,
247
- use_cuda_graph=False,
248
- # Begin encoder & cross attn fields below...
249
- encoder_seq_lens=self.encoder_seq_lens,
250
- encoder_seq_lens_tensor=self.encoder_seq_lens_tensor,
251
- encoder_seq_start_loc=self.encoder_seq_start_loc,
252
- max_encoder_seq_len=self.max_encoder_seq_len,
253
- cross_slot_mapping=self.cross_slot_mapping,
254
- cross_block_tables=self.cross_block_tables)
255
- return self._cached_prefill_metadata
256
-
257
- @property
258
- def decode_metadata(self) -> Optional["FlashAttentionMetadata"]:
259
- if self.num_decode_tokens == 0:
260
- return None
261
-
262
- if self._cached_decode_metadata is not None:
263
- return self._cached_decode_metadata
264
- assert ((self.seq_lens_tensor is not None)
265
- or (self.encoder_seq_lens_tensor is not None))
266
-
267
- # Compute some attn_metadata fields which default to None
268
- slot_mapping = (None if self.slot_mapping is None else
269
- self.slot_mapping[self.num_prefill_tokens:])
270
- seq_lens_tensor = (None if self.seq_lens_tensor is None else
271
- self.seq_lens_tensor[self.num_prefills:])
272
- block_tables = (None if self.block_tables is None else
273
- self.block_tables[self.num_prefills:])
274
-
275
- self._cached_decode_metadata = FlashAttentionMetadata(
276
- num_prefills=0,
277
- num_prefill_tokens=0,
278
- num_decode_tokens=self.num_decode_tokens,
279
- slot_mapping=slot_mapping,
280
- multi_modal_placeholder_index_maps=None,
281
- enable_kv_scales_calculation=True,
282
- seq_lens=None,
283
- seq_lens_tensor=seq_lens_tensor,
284
- max_decode_query_len=self.max_decode_query_len,
285
- max_query_len=self.max_query_len,
286
- max_prefill_seq_len=0,
287
- max_decode_seq_len=self.max_decode_seq_len,
288
- # Batch may be composed of prefill|decodes, adjust query start
289
- # indices to refer to the start of decodes. E.g.
290
- # in tokens:[3 prefills|6 decodes], query_start_loc=[3,9] => [0,6].
291
- query_start_loc=(self.query_start_loc[self.num_prefills:] -
292
- self.query_start_loc[self.num_prefills])
293
- if self.query_start_loc is not None else None,
294
- seq_start_loc=self.seq_start_loc[self.num_prefills:]
295
- if self.seq_start_loc is not None else None,
296
- context_lens_tensor=None,
297
- block_tables=block_tables,
298
- use_cuda_graph=self.use_cuda_graph,
299
- # Begin encoder & cross attn fields below...
300
- encoder_seq_lens=self.encoder_seq_lens,
301
- encoder_seq_lens_tensor=self.encoder_seq_lens_tensor,
302
- encoder_seq_start_loc=self.encoder_seq_start_loc,
303
- max_encoder_seq_len=self.max_encoder_seq_len,
304
- cross_slot_mapping=self.cross_slot_mapping,
305
- cross_block_tables=self.cross_block_tables)
306
- return self._cached_decode_metadata
307
-
308
-
309
-class FlashAttentionMetadataBuilder(
310
- AttentionMetadataBuilder[FlashAttentionMetadata]):
311
-
312
- def __init__(self, input_builder):
313
- self.input_builder = input_builder
314
- self.runner = input_builder.runner
315
- self.sliding_window = input_builder.sliding_window
316
- self.block_size = input_builder.block_size
317
-
318
- def prepare(self):
319
- self.slot_mapping: List[int] = []
320
- self.prefill_seq_lens: List[int] = []
321
- self.context_lens: List[int] = []
322
- self.block_tables: List[List[int]] = []
323
- self.curr_seq_lens: List[int] = []
324
- self.multimodal_placeholder_maps: Dict[
325
- str,
326
- MultiModalPlaceholderMap] = defaultdict(MultiModalPlaceholderMap)
327
- self.num_prefills = 0
328
- self.num_prefill_tokens = 0
329
- self.num_decode_tokens = 0
330
- self.has_prefix_cache_hit = False
331
-
332
- def _add_seq_group(self, inter_data, chunked_prefill_enabled: bool,
333
- prefix_cache_hit: bool):
334
- """Add a sequence group to the metadata. Specifically update/append
335
- 1. context length.
336
- 2. block table.
337
- 3. slot mapping.
338
- """
339
- is_prompt = inter_data.is_prompt
340
- block_tables = inter_data.block_tables
341
-
342
- for (seq_id, token_len, seq_len, curr_seq_len, query_len, context_len,
343
- curr_sliding_window_block) in zip(
344
- inter_data.seq_ids, [len(t) for t in inter_data.input_tokens],
345
- inter_data.orig_seq_lens, inter_data.seq_lens,
346
- inter_data.query_lens, inter_data.context_lens,
347
- inter_data.curr_sliding_window_blocks):
348
- self.context_lens.append(context_len)
349
-
350
- if is_prompt:
351
- mm_maps = inter_data.multi_modal_placeholder_maps
352
- if mm_maps:
353
- for modality, placeholders in mm_maps.items():
354
- self.multimodal_placeholder_maps[modality].extend(
355
- placeholders)
356
-
357
- self.num_prefills += 1
358
- self.num_prefill_tokens += token_len
359
- self.prefill_seq_lens.append(seq_len)
360
- else:
361
- self.num_decode_tokens += query_len
362
- self.curr_seq_lens.append(curr_seq_len)
363
-
364
- # Compute block table.
365
- # TODO(sang): Combine chunked prefill and prefix caching by
366
- # only allowing multiple of block_size chunk size.
367
- # NOTE: This only works for oooooooxxx style attention.
368
- block_table = []
369
- if prefix_cache_hit:
370
- # NOTE(woosuk): For flash-attn, the block table should
371
- # include the entries for the incoming prefill tokens.
372
- block_table = block_tables[seq_id]
373
- elif ((chunked_prefill_enabled or not is_prompt)
374
- and block_tables is not None):
375
- if curr_sliding_window_block == 0:
376
- block_table = block_tables[seq_id]
377
- else:
378
- block_table = block_tables[seq_id][
379
- -curr_sliding_window_block:]
380
- self.block_tables.append(block_table)
381
-
382
- # Compute slot mapping.
383
- is_profile_run = is_block_tables_empty(block_tables)
384
- start_idx = compute_slot_mapping_start_idx(is_prompt, query_len,
385
- context_len,
386
- self.sliding_window)
387
- compute_slot_mapping(is_profile_run, self.slot_mapping, seq_id,
388
- seq_len, context_len, start_idx,
389
- self.block_size, inter_data.block_tables)
390
-
391
- def _get_graph_runner_block_tables(
392
- self, num_seqs: int,
393
- block_tables: List[List[int]]) -> torch.Tensor:
394
- # The shape of graph_block_tables is
395
- # [max batch size, max context len // block size].
396
- max_batch_size, max_blocks = self.runner.graph_block_tables.shape
397
- assert max_batch_size >= num_seqs
398
-
399
- graph_block_tables = self.runner.graph_block_tables[:num_seqs]
400
- for i, block_table in enumerate(block_tables):
401
- if block_table:
402
- num_blocks = len(block_table)
403
- if num_blocks <= max_blocks:
404
- graph_block_tables[i, :num_blocks] = block_table
405
- else:
406
- # It may be possible to have more blocks allocated due
407
- # to lookahead slots of multi-step, however, they are
408
- # not used anyway, so can be safely ignored.
409
- graph_block_tables[
410
- i, :max_blocks] = block_table[:max_blocks]
411
-
412
- return torch.from_numpy(graph_block_tables).to(
413
- device=self.runner.device, non_blocking=True)
414
-
415
- def build(self, seq_lens: List[int], query_lens: List[int],
416
- cuda_graph_pad_size: int, batch_size: int):
417
- """Build attention metadata with on-device tensors.
418
-
419
- Args:
420
- seq_lens: The maybe padded sequence lengths of the input sequences.
421
- query_lens: The query lengths of the input sequences.
422
- cuda_graph_pad_size: The padding size for cuda graph.
423
- -1 if cuda graph is not used.
424
- batch_size: The maybe padded batch size.
425
- """
426
- prefix_cache_hit = any([
427
- inter_data.prefix_cache_hit
428
- for inter_data in self.input_builder.inter_data_list
429
- ])
430
- for inter_data in self.input_builder.inter_data_list:
431
- self._add_seq_group(inter_data,
432
- self.input_builder.chunked_prefill_enabled,
433
- prefix_cache_hit)
434
-
435
- device = self.runner.device
436
- use_captured_graph = cuda_graph_pad_size != -1
437
-
438
- max_query_len = max(query_lens)
439
- decode_query_lens = query_lens[self.num_prefills:]
440
- if len(decode_query_lens) > 0:
441
- max_decode_query_len = max(decode_query_lens)
442
- else:
443
- max_decode_query_len = 1
444
- max_prefill_seq_len = max(self.prefill_seq_lens, default=0)
445
- max_decode_seq_len = max(self.curr_seq_lens, default=0)
446
- num_decode_tokens = self.num_decode_tokens
447
- query_start_loc = list(accumulate(query_lens, initial=0))
448
- seq_start_loc = list(accumulate(seq_lens, initial=0))
449
-
450
- num_seqs = len(seq_lens)
451
- if use_captured_graph:
452
- self.slot_mapping.extend([PAD_SLOT_ID] * cuda_graph_pad_size)
453
- self.block_tables.extend([] * cuda_graph_pad_size)
454
- num_decode_tokens = batch_size - self.num_prefill_tokens
455
- block_tables = self._get_graph_runner_block_tables(
456
- num_seqs, self.block_tables)
457
- else:
458
- block_tables = make_tensor_with_pad(
459
- self.block_tables,
460
- pad=0,
461
- dtype=torch.int,
462
- device=device,
463
- )
464
- assert max_query_len > 0, ("query_lens: {}".format(query_lens))
465
-
466
- assert device is not None
467
- context_lens_tensor = async_tensor_h2d(self.context_lens, torch.int,
468
- device, self.runner.pin_memory)
469
- seq_lens_tensor = async_tensor_h2d(seq_lens, torch.int, device,
470
- self.runner.pin_memory)
471
- slot_mapping_tensor = async_tensor_h2d(self.slot_mapping, torch.long,
472
- device, self.runner.pin_memory)
473
- query_start_loc_tensor = async_tensor_h2d(query_start_loc, torch.int32,
474
- device,
475
- self.runner.pin_memory)
476
- seq_start_loc_tensor = async_tensor_h2d(seq_start_loc, torch.int32,
477
- device, self.runner.pin_memory)
478
- placeholder_index_maps = {
479
- modality: placeholder_map.index_map()
480
- for modality, placeholder_map in
481
- self.multimodal_placeholder_maps.items()
482
- }
483
-
484
- return FlashAttentionMetadata(
485
- num_prefills=self.num_prefills,
486
- slot_mapping=slot_mapping_tensor,
487
- num_prefill_tokens=self.num_prefill_tokens,
488
- num_decode_tokens=num_decode_tokens,
489
- seq_lens=seq_lens,
490
- multi_modal_placeholder_index_maps=placeholder_index_maps,
491
- enable_kv_scales_calculation=True,
492
- seq_lens_tensor=seq_lens_tensor,
493
- max_query_len=max_query_len,
494
- max_decode_query_len=max_decode_query_len,
495
- max_prefill_seq_len=max_prefill_seq_len,
496
- max_decode_seq_len=max_decode_seq_len,
497
- query_start_loc=query_start_loc_tensor,
498
- seq_start_loc=seq_start_loc_tensor,
499
- context_lens_tensor=context_lens_tensor,
500
- block_tables=block_tables,
501
- use_cuda_graph=use_captured_graph,
502
- )
503
-
504
-
505
-class FlashAttentionImpl(AttentionImpl):
506
- """
507
- If the input tensors contain prompt tokens, the layout is as follows:
508
- |<--------------- num_prefill_tokens ----------------->|
509
- |<--prefill_0-->|<--prefill_1-->|...|<--prefill_N-1--->|
510
-
511
- Otherwise, the layout is as follows:
512
- |<----------------- num_decode_tokens ------------------>|
513
- |<--decode_0-->|..........|<--decode_M-1-->|<--padding-->|
514
-
515
- Generation tokens can contain padding when cuda-graph is used.
516
- Currently, prompt tokens don't contain any padding.
517
-
518
- The prompts might have different lengths, while the generation tokens
519
- always have length 1.
520
-
521
- If chunked prefill is enabled, prefill tokens and decode tokens can be
522
- batched together in a flattened 1D query.
523
-
524
- |<----- num_prefill_tokens ---->|<------- num_decode_tokens --------->|
525
- |<-prefill_0->|...|<-prefill_N-1->|<--decode_0-->|...|<--decode_M-1-->|
526
-
527
- Currently, cuda graph is disabled for chunked prefill, meaning there's no
528
- padding between prefill and decode tokens.
529
- """
530
-
531
- def __init__(
532
- self,
533
- num_heads: int,
534
- head_size: int,
535
- scale: float,
536
- num_kv_heads: int,
537
- alibi_slopes: Optional[List[float]],
538
- sliding_window: Optional[int],
539
- kv_cache_dtype: str,
540
- logits_soft_cap: Optional[float] = None,
541
- attn_type: str = AttentionType.DECODER,
542
- kv_sharing_target_layer_name: Optional[str] = None,
543
- use_irope: bool = False,
544
- ) -> None:
545
- if kv_sharing_target_layer_name is not None:
546
- raise NotImplementedError("KV sharing is not supported in V0 "
547
- "FLASH_ATTN backend.")
548
- if use_irope:
549
- logger.warning(
550
- "Using irope in V0 is not supported yet, it will fall back "
551
- "to global attention for long context.")
552
- self.num_heads = num_heads
553
- self.head_size = head_size
554
- self.scale = float(scale)
555
- self.num_kv_heads = num_kv_heads
556
- if alibi_slopes is not None:
557
- alibi_slopes = torch.tensor(alibi_slopes, dtype=torch.float32)
558
- self.alibi_slopes = alibi_slopes
559
- self.sliding_window = ((sliding_window - 1,
560
- 0) if sliding_window is not None else (-1, -1))
561
- self.kv_cache_dtype = kv_cache_dtype
562
- self.vllm_flash_attn_version = get_flash_attn_version(
563
- requires_alibi=self.alibi_slopes is not None)
564
- if is_quantized_kv_cache(self.kv_cache_dtype) and (
565
- not self.kv_cache_dtype.startswith("fp8")
566
- or not flash_attn_supports_fp8()):
567
- raise NotImplementedError(
568
- f"FlashAttention does not support {self.kv_cache_dtype} "
569
- "kv-cache on this device "
570
- f"(FA supports fp8 = {flash_attn_supports_fp8()}).")
571
- if logits_soft_cap is None:
572
- # In flash-attn, setting logits_soft_cap as 0 means no soft cap.
573
- logits_soft_cap = 0
574
- self.logits_soft_cap = logits_soft_cap
575
-
576
- self.num_queries_per_kv = self.num_heads // self.num_kv_heads
577
-
578
- support_head_sizes = FlashAttentionBackend.get_supported_head_sizes()
579
- if head_size not in support_head_sizes:
580
- raise ValueError(
581
- f"Head size {head_size} is not supported by FlashAttention. "
582
- f"Supported head sizes are: {support_head_sizes}.")
583
- self.attn_type = attn_type
584
-
585
- def forward(
586
- self,
587
- layer: AttentionLayer,
588
- query: torch.Tensor,
589
- key: torch.Tensor,
590
- value: torch.Tensor,
591
- kv_cache: torch.Tensor,
592
- attn_metadata: FlashAttentionMetadata,
593
- output: Optional[torch.Tensor] = None,
594
- output_scale: Optional[torch.Tensor] = None,
595
- output_block_scale: Optional[torch.Tensor] = None,
596
- ) -> torch.Tensor:
597
- """Forward pass with FlashAttention.
598
-
599
- Args:
600
- query: shape = [num_tokens, num_heads, head_size]
601
- key: shape = [num_tokens, num_kv_heads, head_size]
602
- value: shape = [num_tokens, num_kv_heads, head_size]
603
- output: shape = [num_tokens, num_heads, head_size]
604
- kv_cache: KV cache tensor with shape
605
- [2, num_blocks, block_size, num_kv_heads, head_size].
606
- NOTE: kv_cache will be an empty tensor with shape [0]
607
- for profiling run.
608
- attn_metadata: Metadata for attention.
609
- NOTE: It in-place updates the output tensor.
610
- NOTE: FP8 quantization, flash-attn expect the size of
611
- {q,k,v}_descale to be (num_sequences, num_kv_heads).
612
- We use torch's .expand() to avoid duplicating values
613
- """
614
- assert output is not None, "Output tensor must be provided."
615
-
616
- if output_scale is not None or output_block_scale is not None:
617
- raise NotImplementedError(
618
- "fused output quantization is not yet supported"
619
- " for FlashAttentionImpl")
620
-
621
- # NOTE(woosuk): FlashAttention2 does not support FP8 KV cache.
622
- if not flash_attn_supports_fp8() or output.dtype != torch.bfloat16:
623
- assert (
624
- layer._k_scale_float == 1.0 and layer._v_scale_float == 1.0), (
625
- "key/v_scale is only supported in FlashAttention 3 with "
626
- "base dtype bfloat16")
627
-
628
- attn_type = self.attn_type
629
- if (attn_type == AttentionType.ENCODER
630
- and (not attn_metadata.is_all_encoder_attn_metadata_set)):
631
- raise AttributeError("Encoder attention requires setting "
632
- "encoder metadata attributes.")
633
- elif (attn_type == AttentionType.ENCODER_DECODER
634
- and (not attn_metadata.is_all_cross_attn_metadata_set)):
635
- raise AttributeError("Encoder/decoder cross-attention "
636
- "requires setting cross-attention "
637
- "metadata attributes.")
638
-
639
- kv_cache_dtype: str = self.kv_cache_dtype
640
- softmax_scale: float = self.scale
641
- window_size = self.sliding_window
642
- alibi_slopes: Optional[torch.Tensor] = self.alibi_slopes
643
- logits_soft_cap: Optional[float] = self.logits_soft_cap
644
- fp8_attention = kv_cache_dtype.startswith("fp8")
645
-
646
- if fp8_attention and not flash_attn_supports_fp8():
647
- raise NotImplementedError(
648
- "FlashAttention does not support FP8 kv-cache on this device.")
649
-
650
- if kv_cache.numel() > 0:
651
- key_cache = kv_cache[0]
652
- value_cache = kv_cache[1]
653
- # We skip updating the KV cache under two conditions:
654
- # a. When the Attention Type is ENCODER. In this phase, we compute
655
- # only the encoder attention without updating the cache.
656
- # b. When both Key and Value are None. This occurs during
657
- # cross-attention computation in the decoding phase, where the
658
- # KV cache is already populated with the cross-attention
659
- # tensor. Thus, we skip cache updates during this time.
660
- if (attn_type != AttentionType.ENCODER) and (key is not None) and (
661
- value is not None):
662
- if attn_type == AttentionType.ENCODER_DECODER:
663
- # Update cross-attention KV cache (prefill-only)
664
- updated_slot_mapping = attn_metadata.cross_slot_mapping
665
- else:
666
- # Update self-attention KV cache (prefill/decode)
667
- updated_slot_mapping = attn_metadata.slot_mapping
668
-
669
- # Reshape the input keys and values and store them in the cache.
670
- # If kv_cache is not provided, the new key and value tensors are
671
- # not cached. This happens during the initial memory
672
- # profiling run.
673
- torch.ops._C_cache_ops.reshape_and_cache_flash(
674
- key,
675
- value,
676
- kv_cache[0],
677
- kv_cache[1],
678
- updated_slot_mapping.flatten(), # type: ignore[union-attr]
679
- kv_cache_dtype,
680
- layer._k_scale,
681
- layer._v_scale,
682
- )
683
-
684
- if fp8_attention:
685
- kv_cache = kv_cache.view(torch.float8_e4m3fn)
686
- key_cache = key_cache.view(torch.float8_e4m3fn)
687
- value_cache = value_cache.view(torch.float8_e4m3fn)
688
-
689
- if fp8_attention:
690
- num_tokens, num_heads, head_size = query.shape
691
- query, _ = ops.scaled_fp8_quant(
692
- query.reshape(
693
- (num_tokens, num_heads * head_size)).contiguous(),
694
- layer._q_scale)
695
- query = query.reshape((num_tokens, num_heads, head_size))
696
-
697
- (num_prefill_query_tokens, num_prefill_kv_tokens,
698
- num_decode_query_tokens) = \
699
- get_num_prefill_decode_query_kv_tokens(attn_metadata, attn_type)
700
- decode_query = query[num_prefill_query_tokens:]
701
- decode_output = output[num_prefill_query_tokens:]
702
- # QKV for prefill.
703
- query = query[:num_prefill_query_tokens]
704
- prefill_output = output[:num_prefill_query_tokens]
705
- assert query.shape[0] == num_prefill_query_tokens
706
- assert decode_query.shape[0] == num_decode_query_tokens
707
-
708
- if prefill_meta := attn_metadata.prefill_metadata:
709
- # Prompt run.
710
- if (kv_cache.numel() == 0 or prefill_meta.block_tables is None
711
- or prefill_meta.block_tables.numel() == 0):
712
- # normal attention
713
- # When block_tables are not filled, it means q and k are the
714
- # prompt, and they have the same length.
715
- q_seq_start_loc, q_seq_len, k_seq_start_loc, k_seq_len = \
716
- _get_query_key_seq_metadata(prefill_meta, True, attn_type)
717
-
718
- key = key[:num_prefill_kv_tokens]
719
- value = value[:num_prefill_kv_tokens]
720
-
721
- if fp8_attention:
722
- num_kv_tokens, num_kv_heads, head_size = key.shape
723
-
724
- key, _ = ops.scaled_fp8_quant(
725
- key.reshape((num_kv_tokens,
726
- num_kv_heads * head_size)).contiguous(),
727
- layer._k_scale)
728
- key = key.reshape((num_kv_tokens, num_kv_heads, head_size))
729
-
730
- value, _ = ops.scaled_fp8_quant(
731
- value.reshape((num_kv_tokens,
732
- num_kv_heads * head_size)).contiguous(),
733
- layer._v_scale)
734
- value = value.reshape(
735
- (num_kv_tokens, num_kv_heads, head_size))
736
-
737
- descale_shape = (q_seq_start_loc.shape[0] - 1, key.shape[1])
738
- flash_attn_varlen_func(
739
- q=query,
740
- k=key,
741
- v=value,
742
- cu_seqlens_q=q_seq_start_loc,
743
- cu_seqlens_k=k_seq_start_loc,
744
- max_seqlen_q=q_seq_len,
745
- max_seqlen_k=k_seq_len,
746
- softmax_scale=softmax_scale,
747
- causal=_get_causal_option(attn_type),
748
- window_size=window_size,
749
- alibi_slopes=alibi_slopes,
750
- softcap=logits_soft_cap,
751
- out=prefill_output,
752
- fa_version=self.vllm_flash_attn_version,
753
- q_descale=layer._q_scale.expand(descale_shape),
754
- k_descale=layer._k_scale.expand(descale_shape),
755
- v_descale=layer._v_scale.expand(descale_shape),
756
- )
757
- else:
758
- # prefix-enabled attention
759
- assert attn_type == AttentionType.DECODER, (
760
- "Only decoder-only models support prefix caching")
761
- assert prefill_meta.seq_lens is not None
762
- assert prefill_meta.query_start_loc is not None
763
- max_seq_len = max(prefill_meta.seq_lens)
764
- descale_shape = (prefill_meta.query_start_loc.shape[0] - 1,
765
- key.shape[1])
766
- flash_attn_varlen_func( # noqa
767
- q=query,
768
- k=key_cache,
769
- v=value_cache,
770
- cu_seqlens_q=prefill_meta.query_start_loc,
771
- max_seqlen_q=prefill_meta.max_query_len,
772
- seqused_k=prefill_meta.seq_lens_tensor,
773
- max_seqlen_k=max_seq_len,
774
- softmax_scale=softmax_scale,
775
- causal=True,
776
- window_size=window_size,
777
- alibi_slopes=alibi_slopes,
778
- block_table=prefill_meta.block_tables,
779
- softcap=logits_soft_cap,
780
- out=prefill_output,
781
- fa_version=self.vllm_flash_attn_version,
782
- q_descale=layer._q_scale.expand(descale_shape),
783
- k_descale=layer._k_scale.expand(descale_shape),
784
- v_descale=layer._v_scale.expand(descale_shape),
785
- )
786
-
787
- if decode_meta := attn_metadata.decode_metadata:
788
- # Decoding run.
789
- # Use flash_attn_varlen_func kernel for speculative decoding
790
- # because different queries might have different lengths.
791
-
792
- assert decode_meta.max_decode_query_len is not None
793
- # use only for actual varlen decoding
794
- if decode_meta.max_decode_query_len > 1:
795
- assert attn_type == AttentionType.DECODER, (
796
- "Only decoder-only models support max_decode_query_len > 1"
797
- )
798
- assert decode_meta.query_start_loc is not None
799
- descale_shape = (decode_meta.query_start_loc.shape[0] - 1,
800
- key.shape[1])
801
- flash_attn_varlen_func(
802
- q=decode_query,
803
- k=key_cache,
804
- v=value_cache,
805
- cu_seqlens_q=decode_meta.query_start_loc,
806
- max_seqlen_q=decode_meta.max_decode_query_len,
807
- seqused_k=decode_meta.seq_lens_tensor,
808
- max_seqlen_k=decode_meta.max_decode_seq_len,
809
- softmax_scale=softmax_scale,
810
- causal=True,
811
- window_size=window_size,
812
- alibi_slopes=alibi_slopes,
813
- softcap=logits_soft_cap,
814
- block_table=decode_meta.block_tables,
815
- out=decode_output,
816
- fa_version=self.vllm_flash_attn_version,
817
- q_descale=layer._q_scale.expand(descale_shape),
818
- k_descale=layer._k_scale.expand(descale_shape),
819
- v_descale=layer._v_scale.expand(descale_shape),
820
- )
821
- else:
822
- # Use flash_attn_with_kvcache for normal decoding.
823
- (
824
- seq_lens_arg,
825
- _,
826
- block_tables_arg,
827
- ) = get_seq_len_block_table_args(decode_meta, False, attn_type)
828
- descale_shape = (seq_lens_arg.shape[0], key_cache.shape[-2])
829
- flash_attn_with_kvcache(
830
- q=decode_query.unsqueeze(1),
831
- k_cache=key_cache,
832
- v_cache=value_cache,
833
- block_table=block_tables_arg,
834
- cache_seqlens=seq_lens_arg,
835
- softmax_scale=softmax_scale,
836
- causal=True,
837
- window_size=window_size,
838
- alibi_slopes=alibi_slopes,
839
- softcap=logits_soft_cap,
840
- out=decode_output.unsqueeze(1),
841
- fa_version=self.vllm_flash_attn_version,
842
- q_descale=layer._q_scale.expand(descale_shape),
843
- k_descale=layer._k_scale.expand(descale_shape),
844
- v_descale=layer._v_scale.expand(descale_shape),
845
- )
846
- return output
847
-
848
-
849
-def _get_query_key_seq_metadata(
850
- attn_metadata: FlashAttentionMetadata,
851
- is_prompt: bool,
852
- attn_type: str,
853
-) -> tuple:
854
- """
855
- Returns sequence metadata for key and query based on the specified
856
- attention type and whether input is a prompt.
857
-
858
- This function computes the starting locations and maximum sequence lengths
859
- for key and query sequences for different attention types.
860
-
861
- Args:
862
- attn_metadata: The attention metadata object
863
- is_prompt (bool): A flag indicating if the input is a prompt
864
- attn_type (AttentionType): The type of attention being used.
865
-
866
- Returns:
867
- tuple: A tuple containing four integers:
868
- - Starting location for the query sequence.
869
- - Maximum sequence length for the query sequence.
870
- - Starting location for the key sequence.
871
- - Maximum sequence length for the key sequence.
872
-
873
- Raises:
874
- AttributeError: If an invalid attention type is provided.
875
- """
876
- if attn_type == AttentionType.DECODER:
877
- # Decoder self-attention
878
- # Choose max_seq_len based on whether we are in prompt_run
879
- if is_prompt:
880
- max_seq_len = attn_metadata.max_prefill_seq_len
881
- else:
882
- max_seq_len = attn_metadata.max_decode_seq_len
883
- return (attn_metadata.seq_start_loc, max_seq_len,
884
- attn_metadata.seq_start_loc, max_seq_len)
885
-
886
- elif attn_type == AttentionType.ENCODER_DECODER:
887
- # This is cross attention between the where the key
888
- # is the precomputed encoder attention and query
889
- # is the input sequence.
890
- # Choose query max length based on whether it is prompt
891
- # or not.
892
- if is_prompt:
893
- max_seq_len = attn_metadata.max_prefill_seq_len
894
- else:
895
- max_seq_len = attn_metadata.max_decode_seq_len
896
- return (attn_metadata.seq_start_loc, max_seq_len,
897
- attn_metadata.encoder_seq_start_loc,
898
- attn_metadata.max_encoder_seq_len)
899
- elif attn_type == AttentionType.ENCODER:
900
- # For encoder attention both the query and the key are same i.e. the
901
- # encoder sequence.
902
- return (attn_metadata.encoder_seq_start_loc,
903
- attn_metadata.max_encoder_seq_len,
904
- attn_metadata.encoder_seq_start_loc,
905
- attn_metadata.max_encoder_seq_len)
906
- elif attn_type == AttentionType.ENCODER_ONLY:
907
- assert is_prompt, "Should not have decode for encoder only model."
908
- return (attn_metadata.seq_start_loc, attn_metadata.max_prefill_seq_len,
909
- attn_metadata.seq_start_loc, attn_metadata.max_prefill_seq_len)
910
- else:
911
- raise AttributeError(f"Invalid attention type {str(attn_type)}")
912
-
913
-
914
-def _get_causal_option(attn_type: str) -> bool:
915
- """
916
- Determine whether the given attention type is suitable for causal
917
- attention mechanisms.
918
-
919
- Args:
920
- attn_type (AttentionType): The type of attention being evaluated
921
-
922
- Returns:
923
- bool: Returns `True` if the attention type is suitable for causal
924
- attention (i.e., not encoder, encoder-only, or encoder-decoder),
925
- otherwise returns `False`.
926
- """
927
- return not (attn_type == AttentionType.ENCODER
928
- or attn_type == AttentionType.ENCODER_ONLY
929
- or attn_type == AttentionType.ENCODER_DECODER)
vllm/attention/backends/flashmla.py
deleted
-227
@@ -1,227 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-
4
-from contextlib import contextmanager
5
-from dataclasses import dataclass
6
-from typing import List, Optional, Tuple, Type
7
-
8
-import torch
9
-
10
-from vllm.attention.backends.abstract import (AttentionType,
11
- is_quantized_kv_cache)
12
-from vllm.attention.backends.mla.common import (MLACommonBackend,
13
- MLACommonImpl,
14
- MLACommonMetadata,
15
- MLACommonMetadataBuilder,
16
- MLACommonState)
17
-from vllm.attention.ops.flashmla import (flash_mla_with_kvcache,
18
- get_mla_metadata,
19
- is_flashmla_supported)
20
-
21
-
22
-class FlashMLABackend(MLACommonBackend):
23
-
24
- @staticmethod
25
- def get_name() -> str:
26
- return "FLASHMLA"
27
-
28
- @staticmethod
29
- def get_impl_cls() -> Type["FlashMLAImpl"]:
30
- return FlashMLAImpl
31
-
32
- @staticmethod
33
- def get_metadata_cls() -> Type["FlashMLAMetadata"]:
34
- return FlashMLAMetadata
35
-
36
- @staticmethod
37
- def get_builder_cls() -> Type["FlashMLAMetadataBuilder"]:
38
- return FlashMLAMetadataBuilder
39
-
40
- @staticmethod
41
- def get_state_cls() -> Type["FlashMLAState"]:
42
- return FlashMLAState
43
-
44
-
45
-@dataclass
46
-class FlashMLAMetadata(MLACommonMetadata):
47
- decode_tile_scheduler_metadata: Optional[Tuple[torch.Tensor,
48
- torch.Tensor]] = None
49
- decode_num_splits: Optional[torch.Tensor] = None
50
-
51
- @property
52
- def decode_metadata(self):
53
- decode_metadata = super().decode_metadata
54
- # TODO: cache assignment?
55
- if decode_metadata is not None:
56
- decode_metadata.decode_tile_scheduler_metadata=\
57
- self.decode_tile_scheduler_metadata
58
- decode_metadata.decode_num_splits=\
59
- self.decode_num_splits
60
- return decode_metadata
61
-
62
-
63
-class FlashMLAMetadataBuilder(MLACommonMetadataBuilder[FlashMLAMetadata]):
64
-
65
- def __init__(self, *args, **kwargs):
66
- super().__init__(*args, **kwargs)
67
-
68
- self.num_q_heads = self.runner.model_config.get_num_attention_heads(
69
- self.runner.parallel_config)
70
-
71
- def build(self, seq_lens: List[int], query_lens: List[int],
72
- cuda_graph_pad_size: int, batch_size: int):
73
- m = super().build(seq_lens, query_lens, cuda_graph_pad_size,
74
- batch_size)
75
-
76
- if m.num_decode_tokens > 0:
77
- m.decode_tile_scheduler_metadata, m.decode_num_splits = \
78
- get_mla_metadata(
79
- m.seq_lens_tensor[m.num_prefills:],
80
- self.num_q_heads,
81
- 1, # MQA for the decode path
82
- )
83
-
84
- return m
85
-
86
-
87
-class FlashMLAState(MLACommonState[FlashMLAMetadata]):
88
-
89
- def __init__(self, *args, **kwds):
90
- super().__init__(*args, **kwds)
91
-
92
- self.num_q_heads = self.runner.model_config.get_num_attention_heads(
93
- self.runner.parallel_config)
94
-
95
- @contextmanager
96
- def graph_capture(self, max_batch_size: int):
97
- # Run a dummy `get_mla_metadata` so we can get the right shapes
98
- self._graph_decoder_tile_scheduler_metadata, \
99
- self._graph_decode_num_splits = get_mla_metadata(
100
- torch.ones(
101
- max_batch_size, dtype=torch.int32, device=self.runner.device),
102
- self.num_q_heads,
103
- 1, # MQA for the decode path
104
- )
105
-
106
- with super().graph_capture(max_batch_size):
107
- yield
108
-
109
- del self._graph_decoder_tile_scheduler_metadata
110
- del self._graph_decode_num_splits
111
-
112
- def graph_capture_get_metadata_for_batch(
113
- self, batch_size: int, is_encoder_decoder_model: bool = False):
114
- metadata = super().graph_capture_get_metadata_for_batch(
115
- batch_size, is_encoder_decoder_model)
116
- assert metadata.num_decode_tokens > 0
117
-
118
- decoder_tile_scheduler_metadata, decode_num_splits = get_mla_metadata(
119
- self._graph_seq_lens[:batch_size],
120
- self.num_q_heads,
121
- 1, # MQA for the decode path
122
- )
123
-
124
- self._graph_decoder_tile_scheduler_metadata.copy_(
125
- decoder_tile_scheduler_metadata)
126
- self._graph_decode_num_splits[:batch_size + 1].copy_(decode_num_splits)
127
-
128
- metadata.decode_tile_scheduler_metadata=\
129
- self._graph_decoder_tile_scheduler_metadata
130
- metadata.decode_num_splits=\
131
- self._graph_decode_num_splits[:batch_size + 1]
132
-
133
- return metadata
134
-
135
- def get_graph_input_buffers(self,
136
- attn_metadata,
137
- is_encoder_decoder_model: bool = False):
138
- input_buffers = super().get_graph_input_buffers(
139
- attn_metadata, is_encoder_decoder_model)
140
- input_buffers["decode_tile_scheduler_metadata"] = \
141
- attn_metadata.decode_metadata.decode_tile_scheduler_metadata
142
- input_buffers["decode_num_splits"] = \
143
- attn_metadata.decode_metadata.decode_num_splits
144
-
145
- return input_buffers
146
-
147
- def prepare_graph_input_buffers(self,
148
- input_buffers,
149
- attn_metadata,
150
- is_encoder_decoder_model: bool = False):
151
- super().prepare_graph_input_buffers(input_buffers, attn_metadata,
152
- is_encoder_decoder_model)
153
-
154
- input_buffers["decode_tile_scheduler_metadata"].copy_(
155
- attn_metadata.decode_metadata.decode_tile_scheduler_metadata)
156
- input_buffers["decode_num_splits"].copy_(
157
- attn_metadata.decode_metadata.decode_num_splits)
158
-
159
-
160
-class FlashMLAImpl(MLACommonImpl[FlashMLAMetadata]):
161
-
162
- def __init__(
163
- self,
164
- num_heads: int,
165
- head_size: int,
166
- scale: float,
167
- num_kv_heads: int,
168
- alibi_slopes: Optional[List[float]],
169
- sliding_window: Optional[int],
170
- kv_cache_dtype: str,
171
- logits_soft_cap: Optional[float],
172
- attn_type: str,
173
- kv_sharing_target_layer_name: Optional[str] = None,
174
- # MLA Specific Arguments
175
- **mla_args) -> None:
176
- super().__init__(num_heads, head_size, scale, num_kv_heads,
177
- alibi_slopes, sliding_window, kv_cache_dtype,
178
- logits_soft_cap, attn_type,
179
- kv_sharing_target_layer_name, **mla_args)
180
-
181
- is_supported, reason = is_flashmla_supported()
182
- assert is_supported, reason
183
-
184
- unsupported_features = [alibi_slopes, sliding_window, logits_soft_cap]
185
- if any(unsupported_features):
186
- raise NotImplementedError(
187
- "FlashMLAImpl does not support one of the following: "
188
- "alibi_slopes, sliding_window, logits_soft_cap")
189
-
190
- if attn_type != AttentionType.DECODER:
191
- raise NotImplementedError("Encoder self-attention and "
192
- "encoder/decoder cross-attention "
193
- "are not implemented for "
194
- "FlashMLAImpl")
195
-
196
- if is_quantized_kv_cache(self.kv_cache_dtype):
197
- raise NotImplementedError(
198
- "FlashMLA with FP8 KV cache not yet supported")
199
-
200
- def _forward_decode(
201
- self,
202
- q_nope: torch.Tensor,
203
- q_pe: torch.Tensor,
204
- kv_c_and_k_pe_cache: torch.Tensor,
205
- attn_metadata: FlashMLAMetadata,
206
- ) -> torch.Tensor:
207
- assert kv_c_and_k_pe_cache.numel() > 0
208
-
209
- decode_meta = attn_metadata.decode_metadata
210
- assert decode_meta is not None
211
-
212
- q = torch.cat([q_nope, q_pe], dim=-1)\
213
- .unsqueeze(1) # Add seqlen dim of 1 (decode)
214
-
215
- o, _ = flash_mla_with_kvcache(
216
- q=q,
217
- k_cache=kv_c_and_k_pe_cache.unsqueeze(-2), # Add head dim of 1
218
- block_table=decode_meta.block_tables,
219
- cache_seqlens=decode_meta.seq_lens_tensor,
220
- head_dim_v=self.kv_lora_rank,
221
- tile_scheduler_metadata=decode_meta.decode_tile_scheduler_metadata,
222
- num_splits=decode_meta.decode_num_splits,
223
- softmax_scale=self.scale,
224
- causal=True,
225
- )
226
-
227
- return self._v_up_proj(o)
vllm/attention/backends/mla/__init__.py
vllm/attention/backends/mla/common.py
deleted
-1305
@@ -1,1305 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-"""
4
-# MLA Common Components
5
-
6
-This file implements common components for MLA implementations.
7
-
8
-First we define:
9
-
10
-Sq as Q sequence length
11
-Skv as KV sequence length
12
-
13
-MLA has two possible ways of computing, a data-movement friendly approach and a
14
-compute friendly approach, we generally want to use the compute friendly
15
-approach for "prefill" (i.e. the ratio Sq / Skv is "small", is near 1)
16
-and the data-movement friendly approach for "decode" (i.e. the ratio
17
-Sq / Skv is "large").
18
-
19
-NOTE what we deem small and large is currently determined by if its labelled
20
-prefill or decode by the scheduler, but this is something we should probably
21
-tune.
22
-
23
-Main reference: DeepseekV2 paper, and FlashInfer Implementation
24
-(https://arxiv.org/abs/2405.04434 and https://github.com/flashinfer-ai/flashinfer/pull/551).
25
-
26
-Deepseek's MLA attention works the following way:
27
-* Use a single latent vector to represent the per-token entry of the KV cache.
28
-* For decode (i.e. the memory friendly approach) the attention "simulates" a
29
-multi-head attention, while the compute is similar to multi-query attention.
30
-
31
-Below is example of both paths assuming batchsize = 1
32
-
33
-## More Extent Definitions:
34
-
35
-C Context length, `Skv - Sq`
36
-H hidden size
37
-N number of attention heads
38
-Lq latent dimension for Q 1536 in DSV3
39
-Lkv latent dimension for K/V 512 in DSV3
40
-P nope dimension, no rope. 128 in DSV3
41
-R rope dimension, goes through rope. 64 in DSV3
42
-V V head dim. 128 in DSV3
43
-
44
-## Vector/Matrix Definitions
45
-
46
-h_t hidden states (input to attention) shape [Sq, H]
47
-q_c latent/compressed Q shape [Sq, Lq]
48
-q_nope uncompressed Q (no-rope) shape [Sq, N, P]
49
-q_pe uncompressed Q (rope) shape [Sq, N, R]
50
-kv_c latent/compressed KV shape [Skv, Lkv]
51
-k_pe decoupled k position embeddings shape [Skv, R]
52
-new_kv_c new kv_c from current iter shape [Sq, Lkv]
53
-new_k_pe new k_pe from current iter shape [Sq, R]
54
-cache_kv_c cached k_c from previous iters shape [C, Lkv]
55
-cache_k_pe cached k_pe from previous iters shape [C, R]
56
-W_DQ project h_t to q_c shape [H, Lq]
57
-W_UQ project q_c to q_nope shape [Lq, N * P]
58
-W_QR project q_c to q_pe shape [Lq, N * R]
59
-W_DKV project h_t to kv_c shape [H, Lkv]
60
-W_UK project kv_c to k_nope shape [Lkv, N, P]
61
-W_KR project h_t to k_pe shape [H, R]
62
-W_UV project kv_c to v shape [Lkv, N, V]
63
-W_O project v to h_t shape [N * V, H]
64
-
65
-
66
-## Compute Friendly Approach (i.e. "_forward_prefill"):
67
-
68
-q_c = h_t @ W_DQ
69
-q_nope = (q_c @ W_UQ).view(Sq, N, P)
70
-q_pe = RoPE(q_c @ W_QR).view(Sq, N, R)
71
-new_kv_c = h_t @ W_DKV
72
-new_k_pe = RoPE(h_t @ W_KR)
73
-kv_c = torch.cat([new_kv_c, cache_kv_c], dim=0)
74
-k_pe = torch.cat([new_k_pe, cache_k_pe], dim=0)
75
-k_nope = (kv_c @ W_UK.view(Lkv, N * P)).view(Skv, N, P)
76
-v = (kv_c @ W_UV.view(Lkv, N * V)).view(Skv, N, V)
77
-
78
-// MHA with QK headdim = P + R
79
-// V headdim = V
80
-// spda_o shape [Sq, N, V]
81
-spda_o = scaled_dot_product_attention(
82
- torch.cat([q_nope, q_pe], dim=-1),
83
- torch.cat([k_nope, k_pe.unsqueeze(1).expand(-1, N, -1)], dim=-1),
84
- v
85
-)
86
-return spda_o @ W_O
87
-
88
-NOTE: in the actual code,
89
- `kv_b_proj` is [W_UK; W_UV] concatenated per head
90
- `q_b_proj` is [W_UQ; W_QR] concatenated per head
91
- `out_proj` is W_O
92
-
93
-
94
-## Data-Movement Friendly Approach (i.e. "_forward_decode"):
95
-
96
-Runtime
97
-q_c = h_t @ W_DQ
98
-q_nope = (q_c @ W_UQ).view(-1, N, P)
99
-ql_nope = einsum("snh,lnh->snl", q, W_UK)
100
-q_pe = RoPE(q_c @ W_QR).view(Sq, N, R)
101
-new_kv_c = h_t @ W_DKV
102
-new_k_pe = RoPE(h_t @ W_KR)
103
-kv_c = torch.cat([new_kv_c, cache_kv_c], dim=0)
104
-k_pe = torch.cat([new_k_pe, cache_k_pe], dim=0)
105
-
106
-// MQA with QK headdim = Lkv + R
107
-// V headdim = Lkv
108
-// spda_o shape [Sq, N, Lkv]
109
-// NOTE: this is less compute-friendly since Lkv > P
110
-// but is more data-movement friendly since its MQA vs MHA
111
-spda_o = scaled_dot_product_attention(
112
- torch.cat([ql_nope, q_pe], dim=-1),
113
- torch.cat([kv_c, k_pe], dim=-1),
114
- kv_c
115
-)
116
-
117
-o = einsum("snl,lnv->snv", spda_o.reshape(-1, N, Lkv), W_UV)
118
-return o.view(-1, N * V) @ self.num_heads @ W_O
119
-
120
-
121
-## Chunked Prefill
122
-
123
-For chunked prefill we want to use the compute friendly algorithm. We are
124
-assuming sufficiently large Sq / Skv ratio, in the future may want to switch to
125
-the data-movement friendly approach if the chunk (i.e. `Sq`) is small.
126
-
127
-However, the compute-friendly approach can potentially run out of memory if Skv
128
-is large due to: `k_nope = (kv_c @ W_UK).view(Skv, N, P)`
129
-
130
-To mitigate this, we chunk the computation of attention with respect to the
131
-current context (i.e. `cache_kv_c` and `cache_k_pe`) so that we can used a
132
-fixed workspace size.
133
-
134
-The chunked prefill approach is as follows:
135
-
136
-MCC Max chunk of context to process per iter, computed dynamically,
137
- used to bound the memory usage
138
-
139
-q_c = h_t @ W_DQ
140
-q_nope = (q_c @ W_UQ).view(Sq, N, P)
141
-q_pe = RoPE(q_c @ W_QR).view(Sq, N, R)
142
-new_kv_c = h_t @ W_DKV
143
-new_k_pe = RoPE(h_t @ W_KR)
144
-new_k_nope = (new_kv_c @ W_UK.view(Lkv, N * P)).view(Sq, N, P)
145
-new_v = (new_kv_c @ W_UV.view(Lkv, N * V)).view(Sq, N, V)
146
-
147
-// MHA between queries and new KV
148
-// with QK headdim = P + R
149
-// V headdim = V
150
-// curr_o shape [Sq, N, V]
151
-// curr_lse shape [N, Sq], this is just order FA returns
152
-curr_o, curr_lse = scaled_dot_product_attention(
153
- torch.cat([q_nope, q_pe], dim=-1),
154
- torch.cat([new_k_nope, new_k_pe.unsqueeze(1).expand(-1, N, -1)], dim=-1),
155
- new_v,
156
- casual=True,
157
- return_softmax_lse=True
158
-)
159
-
160
-// Compute attention with the already existing context
161
-for chunk_idx in range(cdiv(C, MCC)):
162
- chunk_start = chunk_idx * MCC
163
- chunk_end = min(chunk_start + MCC, C)
164
- Sc = chunk_end - chunk_start
165
- cache_kv_c_chunk = cache_kv_c[chunk_start:chunk_end]
166
- cache_k_pe_chunk = cache_k_pe[chunk_start:chunk_end]
167
- cache_k_nope_chunk = (cache_kv_c_chunk @ W_UK).view(-1, N, P)
168
- cache_v_chunk = (cache_kv_c_chunk @ W_UV).view(-1, N, V)
169
-
170
- chunk_o, chunk_lse = scaled_dot_product_attention(
171
- torch.cat([q_nope, q_pe], dim=-1),
172
- torch.cat([cache_k_nope_chunk,
173
- cache_k_pe_chunk.unsqueeze(1).expand(-1, N, -1)],
174
- dim=-1),
175
- cache_v_chunk,
176
- casual=False,
177
- return_softmax_lse=True
178
- )
179
-
180
- curr_o, curr_lse = merge_attn_states(
181
- suffix_output=curr_o,
182
- suffix_lse=curr_lse,
183
- prefix_output=chunk_o,
184
- prefix_lse=chunk_lse,
185
- )
186
-
187
-return curr_o @ W_O
188
-"""
189
-
190
-import functools
191
-from abc import abstractmethod
192
-from collections import defaultdict
193
-from contextlib import contextmanager
194
-from dataclasses import dataclass
195
-from itertools import accumulate
196
-from typing import Any, Dict, Generic, List, Optional, Tuple, Type, TypeVar
197
-
198
-import torch
199
-
200
-from vllm import _custom_ops as ops
201
-from vllm import envs
202
-from vllm.attention.backends.abstract import (AttentionBackend, AttentionLayer,
203
- AttentionMetadata,
204
- AttentionMetadataBuilder,
205
- AttentionState, MLAAttentionImpl)
206
-from vllm.attention.backends.utils import (PAD_SLOT_ID, compute_slot_mapping,
207
- compute_slot_mapping_start_idx,
208
- is_block_tables_empty)
209
-from vllm.attention.ops.merge_attn_states import merge_attn_states
210
-from vllm.attention.utils.fa_utils import get_flash_attn_version
211
-from vllm.model_executor.layers.linear import (ColumnParallelLinear,
212
- LinearBase,
213
- UnquantizedLinearMethod)
214
-from vllm.multimodal import MultiModalPlaceholderMap
215
-from vllm.platforms import current_platform
216
-from vllm.triton_utils import HAS_TRITON
217
-from vllm.utils import async_tensor_h2d, cdiv, make_tensor_with_pad, round_down
218
-
219
-if HAS_TRITON:
220
- from vllm.attention.ops.triton_flash_attention import triton_attention
221
-else:
222
- triton_attention = None
223
-
224
-try:
225
- from vllm.vllm_flash_attn import flash_attn_varlen_func
226
- is_vllm_fa = True
227
-except ImportError:
228
- is_vllm_fa = False
229
- try:
230
- # For rocm use upstream flash attention
231
- from flash_attn import flash_attn_varlen_func
232
- except ImportError:
233
- flash_attn_varlen_func = None
234
-
235
-is_hip = current_platform.is_rocm()
236
-
237
-
238
-class MLACommonBackend(AttentionBackend):
239
-
240
- @staticmethod
241
- def get_name() -> str:
242
- return "TRITON_MLA"
243
-
244
- @staticmethod
245
- def get_metadata_cls() -> Type["AttentionMetadata"]:
246
- return MLACommonMetadata
247
-
248
- @staticmethod
249
- def get_builder_cls() -> Type["MLACommonMetadataBuilder"]:
250
- return MLACommonMetadataBuilder
251
-
252
- @staticmethod
253
- def get_state_cls() -> Type["MLACommonState"]:
254
- return MLACommonState
255
-
256
- @staticmethod
257
- def get_kv_cache_shape(
258
- num_blocks: int,
259
- block_size: int,
260
- num_kv_heads: int, # assumed to be 1 for MLA
261
- head_size: int,
262
- ) -> Tuple[int, ...]:
263
- return (num_blocks, block_size, head_size)
264
-
265
- @staticmethod
266
- def swap_blocks(
267
- src_kv_cache: torch.Tensor,
268
- dst_kv_cache: torch.Tensor,
269
- src_to_dst: torch.Tensor,
270
- ) -> None:
271
- ops.swap_blocks(src_kv_cache, dst_kv_cache, src_to_dst)
272
-
273
- @staticmethod
274
- def copy_blocks(
275
- kv_caches: List[torch.Tensor],
276
- src_to_dists: torch.Tensor,
277
- ) -> None:
278
- ops.copy_blocks_mla(kv_caches, src_to_dists)
279
-
280
- @staticmethod
281
- def get_supported_head_sizes() -> List[int]:
282
- return [576]
283
-
284
-
285
-T = TypeVar("T", bound="MLACommonMetadata")
286
-
287
-
288
-class MLACommonState(AttentionState, Generic[T]):
289
-
290
- def __init__(self, runner):
291
- self.runner = runner
292
- self._is_graph_capturing = False
293
-
294
- scheduler_config = runner.scheduler_config
295
- self.model_config = runner.model_config
296
- cache_config = runner.cache_config
297
-
298
- self.chunked_prefill_enabled = scheduler_config.chunked_prefill_enabled
299
- self.enable_prefix_caching = cache_config.enable_prefix_caching
300
-
301
- if self.chunked_prefill_enabled or self.enable_prefix_caching:
302
- self.context_chunk_workspace_size = min(
303
- # Max sure there is enough for 8 full length request or at least
304
- # 4 pages of cache per request
305
- max(
306
- 8 * self.model_config.max_model_len, 4 *
307
- scheduler_config.max_num_seqs * cache_config.block_size),
308
- # For long-context models try not to over-allocate limiting
309
- # kv-cache space, limiting it to 64k tokens,
310
- # which would result in the workspace being:
311
- # 2*(576)*(64*1024) = 144mb
312
- # (assuming 576 MLA head dim, and fp16)
313
- # which would result in up-projected context being
314
- # 2*(192*128)*(64*1024) = 3gb
315
- # (assuming 192 QK head dim, 128 heads, and fp16)
316
- 128 * 1024)
317
- assert self.context_chunk_workspace_size >= \
318
- scheduler_config.max_num_seqs * cache_config.block_size
319
-
320
- @contextmanager
321
- def graph_capture(self, max_batch_size: int):
322
- self._is_graph_capturing = True
323
-
324
- self._graph_slot_mapping = torch.full((max_batch_size, ),
325
- PAD_SLOT_ID,
326
- dtype=torch.long,
327
- device=self.runner.device)
328
- self._graph_seq_lens = torch.ones(max_batch_size,
329
- dtype=torch.int32,
330
- device=self.runner.device)
331
- self._graph_block_tables = torch.from_numpy(
332
- self.runner.graph_block_tables).to(device=self.runner.device)
333
-
334
- self._positions = torch.zeros((max_batch_size, ),
335
- dtype=torch.long,
336
- device=self.runner.device)
337
-
338
- yield
339
-
340
- self._is_graph_capturing = False
341
- del self._graph_slot_mapping
342
- del self._graph_seq_lens
343
- del self._graph_block_tables
344
- del self._positions
345
-
346
- def graph_clone(self, batch_size: int):
347
- assert self._is_graph_capturing
348
- return self.__class__(self.runner)
349
-
350
- def graph_capture_get_metadata_for_batch(
351
- self,
352
- batch_size: int,
353
- is_encoder_decoder_model: bool = False) -> T:
354
- assert self._is_graph_capturing
355
-
356
- attn_metadata = self.runner.attn_backend.make_metadata(
357
- multi_modal_placeholder_index_maps=None,
358
- enable_kv_scales_calculation=False,
359
- use_cuda_graph=True,
360
- num_prefills=0,
361
- num_prefill_tokens=0,
362
- num_decode_tokens=batch_size,
363
- slot_mapping=self._graph_slot_mapping[:batch_size],
364
- seq_lens=None,
365
- seq_lens_tensor=self._graph_seq_lens[:batch_size],
366
- max_query_len=1,
367
- max_decode_query_len=1,
368
- max_prefill_seq_len=0,
369
- max_decode_seq_len=self.runner.max_seq_len_to_capture,
370
- query_start_loc=None,
371
- seq_start_loc=None,
372
- context_lens_tensor=None,
373
- block_tables=self._graph_block_tables[:batch_size],
374
- head_dim=self.runner.model_config.get_head_size())
375
-
376
- if is_encoder_decoder_model:
377
- raise NotImplementedError(
378
- "MLACommonState does not support encoder/decoder yet")
379
-
380
- return attn_metadata
381
-
382
- def get_graph_input_buffers(self,
383
- attn_metadata,
384
- is_encoder_decoder_model: bool = False):
385
- input_buffers = {
386
- "slot_mapping": attn_metadata.slot_mapping,
387
- "seq_lens_tensor": attn_metadata.decode_metadata.seq_lens_tensor,
388
- "block_tables": attn_metadata.decode_metadata.block_tables,
389
- }
390
- if is_encoder_decoder_model:
391
- raise NotImplementedError(
392
- "MLACommonState does not support encoder/decoder yet")
393
-
394
- return input_buffers
395
-
396
- def prepare_graph_input_buffers(self,
397
- input_buffers,
398
- attn_metadata,
399
- is_encoder_decoder_model: bool = False):
400
- input_buffers["seq_lens_tensor"].copy_(
401
- attn_metadata.decode_metadata.seq_lens_tensor, non_blocking=True)
402
- input_buffers["block_tables"].copy_(
403
- attn_metadata.decode_metadata.block_tables, non_blocking=True)
404
- if is_encoder_decoder_model:
405
- raise NotImplementedError(
406
- "TritonMLAState does not support encoder/decoder yet")
407
-
408
- def begin_forward(self, model_input):
409
- if self.chunked_prefill_enabled or self.enable_prefix_caching:
410
- if not hasattr(self, "context_chunk_workspace"):
411
- # not self.runner.device does not return the correct device
412
- # for this process, (init_device sets the correct device but
413
- # only on the Worker). The only way Ive figured out to get the
414
- # correct device is to allocate the workspace on the first call
415
- # to begin_forward and use the device of the input tokens
416
- assert model_input.input_tokens is not None
417
- self.context_chunk_workspace = torch.empty(
418
- (self.context_chunk_workspace_size,
419
- self.model_config.get_head_size()),
420
- dtype=self.model_config.dtype,
421
- device=model_input.input_tokens.device,
422
- )
423
-
424
- model_input.attn_metadata.context_chunk_workspace = \
425
- self.context_chunk_workspace
426
-
427
-
428
-@dataclass
429
-class MLACommonMetadata(AttentionMetadata):
430
- """Metadata for MLACommon.
431
-
432
- NOTE: Please read the comment at the top of the file before trying to
433
- understand this class
434
-
435
- NOTE: Any python object stored here is not updated when it is
436
- cuda-graph replayed. If you have values that need to be changed
437
- dynamically, it should be stored in tensor. The tensor has to be
438
- updated from `CUDAGraphRunner.forward` API.
439
- """
440
- # Whether or not if cuda graph is enabled.
441
- # Cuda-graph is currently enabled for decoding only.
442
- # TODO(woosuk): Move `use_cuda_graph` out since it's unrelated to attention.
443
- use_cuda_graph: bool
444
-
445
- # NOTE(sang): Definition of context_len, query_len, and seq_len.
446
- # |---------- N-1 iteration --------|
447
- # |---------------- N iteration ---------------------|
448
- # |- tokenA -|......................|-- newTokens ---|
449
- # |---------- context_len ----------|
450
- # |-------------------- seq_len ---------------------|
451
- # |-- query_len ---|
452
-
453
- # (batch_size,). The sequence length per sequence. Sequence length means
454
- # the computed tokens + new tokens None if it is a decoding.
455
- seq_lens: Optional[List[int]]
456
- # seq_lens stored as a tensor.
457
- seq_lens_tensor: Optional[torch.Tensor]
458
-
459
- # Maximum sequence length among prefill batch. 0 if there are decoding
460
- # requests only.
461
- max_prefill_seq_len: int
462
- # Maximum sequence length among decode batch. 0 if there are prefill
463
- # requests only.
464
- max_decode_seq_len: int
465
- # (batch_size,) A tensor of context lengths (tokens that are computed
466
- # so far).
467
- context_lens_tensor: Optional[torch.Tensor]
468
-
469
- # (batch_size, max_blocks_per_seq).
470
- # Block addresses per sequence. (Seq id -> list of physical block)
471
- # E.g., [0, 1, 2] means tokens are stored in 0th, 1st, and 2nd blocks
472
- # in the kv cache. Each block can contain up to block_size tokens.
473
- # 2nd dimensions are padded up to max_blocks_per_seq if it is cuda-graph
474
- # captured.
475
- block_tables: Optional[torch.Tensor]
476
-
477
- # Maximum query length in the batch.
478
- max_query_len: Optional[int] = None
479
-
480
- # Max number of query tokens among request in the batch.
481
- max_decode_query_len: Optional[int] = None
482
-
483
- # (batch_size + 1,). The cumulative subquery lengths of the sequences in
484
- # the batch, used to index into subquery. E.g., if the subquery length
485
- # is [4, 6], it is [0, 4, 10].
486
- query_start_loc: Optional[torch.Tensor] = None
487
- # (batch_size + 1,). The cumulative sequence lengths of the sequences in
488
- # the batch, used to index into sequence. E.g., if the sequence length is
489
- # [4, 6], it is [0, 4, 10].
490
- seq_start_loc: Optional[torch.Tensor] = None
491
-
492
- _cached_prefill_metadata: Optional[Any] = None
493
- _cached_decode_metadata: Optional[Any] = None
494
-
495
- num_prefill_tokens: int
496
-
497
- # The dimension of the attention heads
498
- head_dim: Optional[int] = None
499
-
500
- # Used when chunked prefill is enabled to simulate worst case workspace
501
- # allocations, hopefully to avoid going OOM
502
- is_profile_run: bool = False
503
-
504
- # New for MLA (compared to FlashAttention)
505
- # For chunked prefill
506
- context_chunk_cu_seq_lens: Optional[torch.Tensor] = None
507
- context_chunk_starts: Optional[torch.Tensor] = None
508
- context_chunk_seq_tot: Optional[List[int]] = None
509
- context_chunk_max_seq_lens: Optional[List[int]] = None
510
- # Set by MLAAttentionState in `begin_forward` so it doesn't get broadcasted
511
- context_chunk_workspace: Optional[torch.Tensor] = None
512
-
513
- def __post_init__(self):
514
- supported_head_sizes = MLACommonBackend.get_supported_head_sizes()
515
- if self.head_dim is not None and self.head_dim \
516
- not in supported_head_sizes:
517
- raise ValueError(
518
- f"Only {supported_head_sizes} are supported for head_dim,",
519
- f" received {self.head_dim}.")
520
-
521
- @property
522
- def prefill_metadata(self):
523
- if self.num_prefills == 0:
524
- return None
525
-
526
- if self._cached_prefill_metadata is not None:
527
- return self._cached_prefill_metadata
528
-
529
- assert self.seq_lens is not None
530
- assert self.seq_lens_tensor is not None
531
-
532
- # Compute some attn_metadata fields which default to None
533
- query_start_loc = (None if self.query_start_loc is None else
534
- self.query_start_loc[:self.num_prefills + 1])
535
- slot_mapping = (None if self.slot_mapping is None else
536
- self.slot_mapping[:self.num_prefill_tokens])
537
- seq_lens = (None if self.seq_lens is None else
538
- self.seq_lens[:self.num_prefills])
539
- seq_lens_tensor = (None if self.seq_lens_tensor is None else
540
- self.seq_lens_tensor[:self.num_prefills])
541
- seq_start_loc = (None if self.seq_start_loc is None else
542
- self.seq_start_loc[:self.num_prefills + 1])
543
- context_lens_tensor = (None if self.context_lens_tensor is None else
544
- self.context_lens_tensor[:self.num_prefills])
545
- block_tables = (None if self.block_tables is None else
546
- self.block_tables[:self.num_prefills])
547
-
548
- self._cached_prefill_metadata = self.__class__(
549
- # Required by ModelRunner
550
- use_cuda_graph=False, # Not Attention Related
551
- # Required by Attention Metadata
552
- num_prefills=self.num_prefills,
553
- num_prefill_tokens=self.num_prefill_tokens,
554
- num_decode_tokens=0,
555
- slot_mapping=slot_mapping,
556
- # Required by Attention Metadata (not used)
557
- multi_modal_placeholder_index_maps=None,
558
- enable_kv_scales_calculation=False,
559
- # MLACommonMetadata
560
- seq_lens=seq_lens,
561
- seq_lens_tensor=seq_lens_tensor,
562
- max_query_len=self.max_query_len,
563
- max_prefill_seq_len=self.max_prefill_seq_len,
564
- max_decode_query_len=0,
565
- max_decode_seq_len=0,
566
- query_start_loc=query_start_loc,
567
- seq_start_loc=seq_start_loc,
568
- context_lens_tensor=context_lens_tensor,
569
- block_tables=block_tables,
570
- head_dim=self.head_dim,
571
- is_profile_run=self.is_profile_run,
572
- # MLACommonMetadata Chunk prefill specific
573
- context_chunk_cu_seq_lens=self.context_chunk_cu_seq_lens,
574
- context_chunk_starts=self.context_chunk_starts,
575
- context_chunk_seq_tot=self.context_chunk_seq_tot,
576
- context_chunk_max_seq_lens=self.context_chunk_max_seq_lens,
577
- )
578
- return self._cached_prefill_metadata
579
-
580
- @property
581
- def decode_metadata(self):
582
- if self.num_decode_tokens == 0:
583
- return None
584
-
585
- if self._cached_decode_metadata is not None:
586
- return self._cached_decode_metadata
587
- assert self.seq_lens_tensor is not None
588
-
589
- # Compute some attn_metadata fields which default to None
590
- slot_mapping = (None if self.slot_mapping is None else
591
- self.slot_mapping[self.num_prefill_tokens:])
592
- seq_lens_tensor = (None if self.seq_lens_tensor is None else
593
- self.seq_lens_tensor[self.num_prefills:])
594
- block_tables = (None if self.block_tables is None else
595
- self.block_tables[self.num_prefills:])
596
-
597
- self._cached_decode_metadata = self.__class__(
598
- # Required by ModelRunner
599
- use_cuda_graph=self.use_cuda_graph, # Not Attention Related
600
- # Required by Attention Metadata
601
- num_prefills=0,
602
- num_prefill_tokens=0,
603
- num_decode_tokens=self.num_decode_tokens,
604
- slot_mapping=slot_mapping,
605
- # Required by Attention Metadata (not used)
606
- multi_modal_placeholder_index_maps=None,
607
- enable_kv_scales_calculation=False,
608
- # MLACommonMetadata
609
- seq_lens=None,
610
- seq_lens_tensor=seq_lens_tensor,
611
- max_decode_query_len=self.max_decode_query_len,
612
- max_query_len=self.max_query_len,
613
- max_prefill_seq_len=0,
614
- max_decode_seq_len=self.max_decode_seq_len,
615
- # Batch may be composed of prefill|decodes, adjust query start
616
- # indices to refer to the start of decodes. E.g.
617
- # in tokens:[3 prefills|6 decodes], query_start_loc=[3,9] => [0,6].
618
- query_start_loc=(self.query_start_loc[self.num_prefills:] -
619
- self.query_start_loc[self.num_prefills])
620
- if self.query_start_loc is not None else None,
621
- seq_start_loc=self.seq_start_loc[self.num_prefills:]
622
- if self.seq_start_loc is not None else None,
623
- context_lens_tensor=None,
624
- block_tables=block_tables,
625
- head_dim=self.head_dim,
626
- is_profile_run=self.is_profile_run)
627
- return self._cached_decode_metadata
628
-
629
-
630
-class MLACommonMetadataBuilder(AttentionMetadataBuilder[T], Generic[T]):
631
- """
632
- NOTE: Please read the comment at the top of the file before trying to
633
- understand this class
634
- """
635
- BLOCK_TABLE_EXTENDER: list[list[int]] = []
636
-
637
- def __init__(self, input_builder):
638
- self.input_builder = input_builder
639
- self.runner = input_builder.runner
640
- self.sliding_window = input_builder.sliding_window
641
- self.block_size = input_builder.block_size
642
- self.chunked_prefill_enabled = \
643
- self.runner.scheduler_config.chunked_prefill_enabled
644
- self.enable_prefix_caching = \
645
- self.runner.cache_config.enable_prefix_caching
646
-
647
- if self.chunked_prefill_enabled or self.enable_prefix_caching:
648
- attn_state = self.input_builder.runner.attn_state
649
- self.context_chunk_workspace_size = \
650
- attn_state.context_chunk_workspace_size
651
- self.page_size = self.runner.block_size
652
-
653
- def prepare(self):
654
- self.slot_mapping: List[int] = []
655
- self.prefill_seq_lens: List[int] = []
656
- self.context_lens: List[int] = []
657
- self.block_tables: List[List[int]] = []
658
- self.curr_seq_lens: List[int] = []
659
- self.multimodal_placeholder_maps: Dict[
660
- str,
661
- MultiModalPlaceholderMap] = defaultdict(MultiModalPlaceholderMap)
662
- self.num_prefills = 0
663
- self.num_prefill_tokens = 0
664
- self.num_decode_tokens = 0
665
- self.has_prefix_cache_hit = False
666
-
667
- def _add_seq_group(self, inter_data, chunked_prefill_enabled: bool,
668
- prefix_cache_hit: bool):
669
- """Add a sequence group to the metadata. Specifically update/append
670
- 1. context length.
671
- 2. block table.
672
- 3. slot mapping.
673
- """
674
- is_prompt = inter_data.is_prompt
675
- block_tables = inter_data.block_tables
676
-
677
- for (seq_id, token_len, seq_len, curr_seq_len, query_len, context_len,
678
- curr_sliding_window_block) in zip(
679
- inter_data.seq_ids, [len(t) for t in inter_data.input_tokens],
680
- inter_data.orig_seq_lens, inter_data.seq_lens,
681
- inter_data.query_lens, inter_data.context_lens,
682
- inter_data.curr_sliding_window_blocks):
683
- self.context_lens.append(context_len)
684
- if is_prompt:
685
- self.num_prefills += 1
686
- self.num_prefill_tokens += token_len
687
- self.prefill_seq_lens.append(seq_len)
688
- else:
689
- self.num_decode_tokens += query_len
690
- self.curr_seq_lens.append(curr_seq_len)
691
-
692
- # Compute block table.
693
- # TODO(sang): Combine chunked prefill and prefix caching by
694
- # only allowing multiple of block_size chunk size.
695
- # NOTE: This only works for oooooooxxx style attention.
696
- block_table = []
697
- if prefix_cache_hit:
698
- # NOTE(woosuk): For flash-attn, the block table should
699
- # include the entries for the incoming prefill tokens.
700
- block_table = block_tables[seq_id]
701
- elif ((chunked_prefill_enabled or not is_prompt)
702
- and block_tables is not None):
703
- if curr_sliding_window_block == 0:
704
- block_table = block_tables[seq_id]
705
- else:
706
- block_table = block_tables[seq_id][
707
- -curr_sliding_window_block:]
708
- self.block_tables.append(block_table)
709
-
710
- # Compute slot mapping.
711
- is_profile_run = is_block_tables_empty(block_tables)
712
- start_idx = compute_slot_mapping_start_idx(is_prompt, query_len,
713
- context_len,
714
- self.sliding_window)
715
- compute_slot_mapping(is_profile_run, self.slot_mapping, seq_id,
716
- seq_len, context_len, start_idx,
717
- self.block_size, inter_data.block_tables)
718
-
719
- def _get_graph_runner_block_tables(
720
- self, num_seqs: int,
721
- block_tables: List[List[int]]) -> torch.Tensor:
722
- # The shape of graph_block_tables is
723
- # [max batch size, max context len // block size].
724
- max_batch_size, max_blocks = self.runner.graph_block_tables.shape
725
- assert max_batch_size >= num_seqs
726
-
727
- graph_block_tables = self.runner.graph_block_tables[:num_seqs]
728
- for i, block_table in enumerate(block_tables):
729
- if block_table:
730
- num_blocks = len(block_table)
731
- if num_blocks <= max_blocks:
732
- graph_block_tables[i, :num_blocks] = block_table
733
- else:
734
- # It may be possible to have more blocks allocated due
735
- # to lookahead slots of multi-step, however, they are
736
- # not used anyway, so can be safely ignored.
737
- graph_block_tables[
738
- i, :max_blocks] = block_table[:max_blocks]
739
-
740
- return torch.from_numpy(graph_block_tables).to(
741
- device=self.runner.device, non_blocking=True)
742
-
743
- def build(self, seq_lens: List[int], query_lens: List[int],
744
- cuda_graph_pad_size: int, batch_size: int):
745
- """Build attention metadata with on-device tensors.
746
-
747
- Args:
748
- seq_lens: The maybe padded sequence lengths of the input sequences.
749
- query_lens: The query lengths of the input sequences.
750
- cuda_graph_pad_size: The padding size for cuda graph.
751
- -1 if cuda graph is not used.
752
- batch_size: The maybe padded batch size.
753
- """
754
- prefix_cache_hit = any([
755
- inter_data.prefix_cache_hit
756
- for inter_data in self.input_builder.inter_data_list
757
- ])
758
-
759
- for inter_data in self.input_builder.inter_data_list:
760
- self._add_seq_group(inter_data,
761
- self.input_builder.chunked_prefill_enabled,
762
- prefix_cache_hit)
763
-
764
- device = self.runner.device
765
- use_captured_graph = cuda_graph_pad_size != -1
766
-
767
- max_query_len = max(query_lens)
768
- decode_query_lens = query_lens[self.num_prefills:]
769
- if len(decode_query_lens) > 0:
770
- max_decode_query_len = max(decode_query_lens)
771
- else:
772
- max_decode_query_len = 1
773
- max_prefill_seq_len = max(self.prefill_seq_lens, default=0)
774
- max_decode_seq_len = max(self.curr_seq_lens, default=0)
775
- num_decode_tokens = self.num_decode_tokens
776
- query_start_loc = list(accumulate(query_lens, initial=0))
777
- seq_start_loc = list(accumulate(seq_lens, initial=0))
778
-
779
- num_seqs = len(seq_lens)
780
- if use_captured_graph:
781
- self.slot_mapping.extend([PAD_SLOT_ID] * cuda_graph_pad_size)
782
- self.block_tables.extend(self.__class__.BLOCK_TABLE_EXTENDER *
783
- cuda_graph_pad_size)
784
- num_decode_tokens = batch_size - self.num_prefill_tokens
785
-
786
- block_tables = self._get_graph_runner_block_tables(
787
- num_seqs, self.block_tables)
788
- else:
789
- block_tables = make_tensor_with_pad(
790
- self.block_tables,
791
- pad=0,
792
- dtype=torch.int,
793
- device=device,
794
- )
795
- assert max_query_len > 0, ("query_lens: {}".format(query_lens))
796
-
797
- assert device is not None
798
- context_lens_tensor = async_tensor_h2d(self.context_lens, torch.int,
799
- device, self.runner.pin_memory)
800
- seq_lens_tensor = async_tensor_h2d(seq_lens, torch.int, device,
801
- self.runner.pin_memory)
802
- slot_mapping_tensor = async_tensor_h2d(self.slot_mapping, torch.long,
803
- device, self.runner.pin_memory)
804
- query_start_loc_tensor = async_tensor_h2d(query_start_loc, torch.int32,
805
- device,
806
- self.runner.pin_memory)
807
- seq_start_loc_tensor = async_tensor_h2d(seq_start_loc, torch.int32,
808
- device, self.runner.pin_memory)
809
-
810
- context_chunk_cu_seq_lens = None
811
- context_chunk_starts = None
812
- context_chunk_seq_tot = None
813
- context_chunk_max_seq_lens = None
814
-
815
- if (self.chunked_prefill_enabled or self.enable_prefix_caching) \
816
- and self.num_prefills > 0 \
817
- and context_lens_tensor is not None \
818
- and context_lens_tensor[:self.num_prefills].max() > 0:
819
-
820
- # NOTE: it is recommended you read the `Chunked Prefill` section in
821
- # the comment at the top of the file before trying to understand
822
- # the following code
823
-
824
- num_prefills_with_context = \
825
- (context_lens_tensor[:self.num_prefills] > 0).sum().item()
826
-
827
- # currently we allocate an equal amount of workspace for each
828
- # prefill in the batch, we could probably use a more advanced
829
- # algorithm here and allocate more workspace to prefills with
830
- # longer context lengths
831
- max_context_chunk = \
832
- self.context_chunk_workspace_size // num_prefills_with_context
833
-
834
- # align max_context_chunk to page_size by rounding down,
835
- # currently the `gather_and_maybe_dequant_cache` kernel cannot
836
- # handle `context_chunk_starts` that are not aligned to page_size
837
- max_context_chunk = round_down(max_context_chunk, self.page_size)
838
- assert max_context_chunk > 0
839
- num_chunks = cdiv(context_lens_tensor.max(), max_context_chunk)
840
-
841
- # if `max_context_chunk = 256`, `num_chunks = 3`, and
842
- # `num_prefills_with_context = 4`, create a tensor that looks like
843
- # [[0, 0, 0, 0], [256, 256, 256, 256], [512, 512, 512, 512]]
844
- context_chunk_starts = \
845
- torch.arange(num_chunks, device=device, dtype=torch.int32)\
846
- .unsqueeze(1).expand(-1, self.num_prefills)\
847
- * max_context_chunk
848
- chunk_ends = torch.min(context_lens_tensor[:self.num_prefills]\
849
- .unsqueeze(0), context_chunk_starts + max_context_chunk)
850
- chunk_seq_lens = (chunk_ends - context_chunk_starts).clamp(min=0)
851
- _context_chunk_cu_seq_lens = chunk_seq_lens.cumsum(dim=1).to(
852
- torch.int32)
853
- zero = torch.zeros(num_chunks, dtype=torch.int32, device=device)\
854
- .unsqueeze(-1)
855
- context_chunk_cu_seq_lens = \
856
- torch.cat([zero, _context_chunk_cu_seq_lens], dim=1)
857
- context_chunk_max_seq_lens = \
858
- chunk_seq_lens.max(dim=1).values.tolist()
859
- context_chunk_seq_tot = chunk_seq_lens.sum(dim=1).tolist()
860
- assert max(context_chunk_seq_tot) <= \
861
- self.context_chunk_workspace_size
862
-
863
- return self.runner.attn_backend.make_metadata(
864
- # Required by ModelRunner
865
- use_cuda_graph=use_captured_graph, # Not Attention Related
866
- # Required by Attention Metadata
867
- num_prefills=self.num_prefills,
868
- slot_mapping=slot_mapping_tensor,
869
- num_prefill_tokens=self.num_prefill_tokens,
870
- num_decode_tokens=num_decode_tokens,
871
- # Required by Attention Metadata (not used)
872
- multi_modal_placeholder_index_maps=None, # Not Attention Related
873
- enable_kv_scales_calculation=False,
874
- # MLACommonMetadata
875
- seq_lens=seq_lens,
876
- seq_lens_tensor=seq_lens_tensor,
877
- max_query_len=max_query_len,
878
- max_decode_query_len=max_decode_query_len,
879
- max_prefill_seq_len=max_prefill_seq_len,
880
- max_decode_seq_len=max_decode_seq_len,
881
- query_start_loc=query_start_loc_tensor,
882
- seq_start_loc=seq_start_loc_tensor,
883
- context_lens_tensor=context_lens_tensor,
884
- block_tables=block_tables,
885
- head_dim=self.runner.model_config.get_head_size(),
886
- is_profile_run=self.runner.in_profile_run,
887
- # MLACommonMetadata Chunk prefill specific
888
- context_chunk_cu_seq_lens=context_chunk_cu_seq_lens,
889
- context_chunk_starts=context_chunk_starts,
890
- context_chunk_seq_tot=context_chunk_seq_tot,
891
- context_chunk_max_seq_lens=context_chunk_max_seq_lens,
892
- )
893
-
894
-
895
-class MLACommonImpl(MLAAttentionImpl[T], Generic[T]):
896
- """
897
- NOTE: Please read the comment at the top of the file before trying to
898
- understand this class
899
- """
900
-
901
- def __init__(
902
- self,
903
- num_heads: int,
904
- head_size: int,
905
- scale: float,
906
- num_kv_heads: int,
907
- alibi_slopes: Optional[List[float]],
908
- sliding_window: Optional[int],
909
- kv_cache_dtype: str,
910
- logits_soft_cap: Optional[float],
911
- attn_type: str,
912
- kv_sharing_target_layer_name: Optional[str],
913
- # MLA Specific Arguments
914
- q_lora_rank: Optional[int],
915
- kv_lora_rank: int,
916
- qk_nope_head_dim: int,
917
- qk_rope_head_dim: int,
918
- qk_head_dim: int,
919
- v_head_dim: int,
920
- kv_b_proj: ColumnParallelLinear,
921
- ) -> None:
922
- if kv_sharing_target_layer_name is not None:
923
- raise NotImplementedError("KV sharing not supported in V0.")
924
- self.num_heads = num_heads
925
- self.head_size = head_size
926
- self.scale = float(scale)
927
- self.num_kv_heads = num_kv_heads
928
- self.kv_cache_dtype = kv_cache_dtype
929
-
930
- self.q_lora_rank = q_lora_rank
931
- self.kv_lora_rank = kv_lora_rank
932
- self.qk_nope_head_dim = qk_nope_head_dim
933
- self.qk_rope_head_dim = qk_rope_head_dim
934
- self.qk_head_dim = qk_head_dim
935
- self.v_head_dim = v_head_dim
936
- self.kv_b_proj = kv_b_proj
937
-
938
- self.triton_fa_func = triton_attention
939
- # Handle the differences between the flash_attn_varlen from flash_attn
940
- # and the one from vllm_flash_attn. The former is used on RoCM and the
941
- # latter has an additional parameter to control FA2 vs FA3
942
- self.flash_attn_varlen_func = flash_attn_varlen_func
943
- self.vllm_flash_attn_version = get_flash_attn_version()
944
- if self.vllm_flash_attn_version is not None:
945
- self.flash_attn_varlen_func = \
946
- functools.partial(flash_attn_varlen_func,
947
- fa_version=self.vllm_flash_attn_version)
948
-
949
- # For MLA the v head dim is smaller than qk head dim so we pad out
950
- # v with 0s to match the qk head dim for attention backends that do
951
- # not support different headdims
952
- # We don't need to pad V if we are on a hopper system with FA3
953
- self._pad_v = self.vllm_flash_attn_version is None or not (
954
- self.vllm_flash_attn_version == 3
955
- and current_platform.get_device_capability()[0] == 9)
956
-
957
- def _flash_attn_varlen_diff_headdims(self, q, k, v, softmax_scale,
958
- return_softmax_lse, **kwargs):
959
- maybe_padded_v = v
960
- if self._pad_v:
961
- maybe_padded_v = torch.nn.functional.pad(
962
- v, [0, q.shape[-1] - v.shape[-1]], value=0)
963
-
964
- if is_hip and envs.VLLM_USE_TRITON_FLASH_ATTN \
965
- and not return_softmax_lse:
966
- attn_out = self.triton_fa_func(
967
- q,
968
- k,
969
- maybe_padded_v,
970
- None, # output
971
- kwargs["cu_seqlens_q"],
972
- kwargs["cu_seqlens_k"],
973
- kwargs["max_seqlen_q"],
974
- kwargs["max_seqlen_k"],
975
- kwargs["causal"],
976
- softmax_scale,
977
- None, # bias
978
- )
979
- elif is_vllm_fa:
980
- attn_out = self.flash_attn_varlen_func(
981
- q=q,
982
- k=k,
983
- v=maybe_padded_v,
984
- return_softmax_lse=return_softmax_lse,
985
- softmax_scale=softmax_scale,
986
- **kwargs,
987
- )
988
- else:
989
- # Use return_attn_probs instead of return_softmax_lse for RoCM
990
- attn_out = self.flash_attn_varlen_func(
991
- q=q,
992
- k=k,
993
- v=maybe_padded_v,
994
- return_attn_probs=return_softmax_lse,
995
- softmax_scale=softmax_scale,
996
- **kwargs,
997
- )
998
-
999
- # Unpack the output if there is multiple results,
1000
- # triton always returns (output, softmax_lse),
1001
- # vllm_flash_attn returns (output, softmax_lse) when
1002
- # `return_softmax_lse = True`
1003
- # flash_attn (RoCM) returns (output, softmax_lse, ...) when
1004
- # `return_attn_probs = True`
1005
- rest = None
1006
- if isinstance(attn_out, tuple):
1007
- attn_out, *rest = attn_out
1008
-
1009
- # Remain consistent with old `flash_attn_varlen_func` where there
1010
- # is only one output tensor if `return_softmax_lse` is False.
1011
- if return_softmax_lse:
1012
- assert rest is not None
1013
- return attn_out, rest[0]
1014
- return attn_out
1015
-
1016
- def _v_up_proj(self, x):
1017
- # Convert from (B, N, L) to (N, B, L)
1018
- x = x.view(-1, self.num_heads, self.kv_lora_rank).transpose(0, 1)
1019
- # Multiply (N, B, L) x (N, L, V) -> (N, B, V)
1020
- x = torch.bmm(x, self.W_UV)
1021
- # Convert from (N, B, V) to (B, N * V)
1022
- return x.transpose(0, 1).reshape(-1, self.num_heads * self.v_head_dim)
1023
-
1024
- def process_weights_after_loading(self, act_dtype: torch.dtype):
1025
-
1026
- def get_layer_weight(layer):
1027
- WEIGHT_NAMES = ("weight", "qweight", "weight_packed")
1028
- for attr in WEIGHT_NAMES:
1029
- if hasattr(layer, attr):
1030
- return getattr(layer, attr)
1031
- raise AttributeError(
1032
- f"Layer '{layer}' has no recognized weight attribute:"
1033
- f" {WEIGHT_NAMES}.")
1034
-
1035
- def get_and_maybe_dequant_weights(layer: LinearBase):
1036
- if not isinstance(layer.quant_method, UnquantizedLinearMethod):
1037
- # NOTE: This should only be used offline, since it's O(N^3)
1038
- eye = torch.eye(layer.input_size_per_partition,
1039
- dtype=act_dtype,
1040
- device=get_layer_weight(layer).device)
1041
- dequant_weights = layer.quant_method.apply(layer,
1042
- eye,
1043
- bias=None)
1044
- del eye
1045
- # standardize to (output, input)
1046
- return dequant_weights.T
1047
- return layer.weight
1048
-
1049
- # we currently do not have quantized bmm's which are needed for
1050
- # `W_UV` and `W_UK_T`, we just store fp16/bf16 copies and perform
1051
- # the bmm's in 16-bit, the extra memory overhead of this is fairly low
1052
- kv_b_proj_weight = get_and_maybe_dequant_weights(self.kv_b_proj).T
1053
- assert kv_b_proj_weight.shape == (
1054
- self.kv_lora_rank,
1055
- self.num_heads * (self.qk_nope_head_dim + self.v_head_dim)), (
1056
- f"{kv_b_proj_weight.shape=}, "
1057
- f"{self.kv_lora_rank=}, "
1058
- f"{self.num_heads=}, "
1059
- f"{self.qk_nope_head_dim=}, "
1060
- f"{self.v_head_dim=}")
1061
- kv_b_proj_weight = kv_b_proj_weight.view(
1062
- self.kv_lora_rank,
1063
- self.num_heads,
1064
- self.qk_nope_head_dim + self.v_head_dim,
1065
- )
1066
-
1067
- W_UK, W_UV = kv_b_proj_weight.split(
1068
- [self.qk_nope_head_dim, self.v_head_dim], dim=-1)
1069
-
1070
- # Convert from (L, N, V) to (N, L, V)
1071
- self.W_UV = W_UV.transpose(0, 1)
1072
- # Convert from (L, N, P) to (N, P, L)
1073
- self.W_UK_T = W_UK.permute(1, 2, 0)
1074
-
1075
- def _compute_prefill_context(
1076
- self,
1077
- q: torch.Tensor,
1078
- kv_c_and_k_pe_cache: torch.Tensor,
1079
- attn_metadata: MLACommonMetadata,
1080
- k_scale: torch.Tensor,
1081
- ):
1082
- prefill_metadata = attn_metadata.prefill_metadata
1083
- assert prefill_metadata is not None
1084
- assert prefill_metadata.context_chunk_seq_tot is not None
1085
- assert prefill_metadata.context_chunk_cu_seq_lens is not None
1086
- assert prefill_metadata.context_chunk_starts is not None
1087
- assert prefill_metadata.context_chunk_max_seq_lens is not None
1088
- assert prefill_metadata.context_lens_tensor is not None
1089
-
1090
- output = None
1091
- iters = len(prefill_metadata.context_chunk_seq_tot)
1092
-
1093
- # Fetch from attn_metadata directly, since it late bound by
1094
- # MLAAttentionState, grabbing it directly `attn_metadata` can avoid
1095
- # any weirdness around prefill_metadata caching
1096
- assert attn_metadata.context_chunk_workspace is not None
1097
- workspace = attn_metadata.context_chunk_workspace
1098
-
1099
- for i in range(iters):
1100
- toks = prefill_metadata.context_chunk_seq_tot[i]
1101
-
1102
- ops.gather_and_maybe_dequant_cache(
1103
- src_cache=kv_c_and_k_pe_cache,
1104
- dst=workspace,
1105
- block_table=prefill_metadata.block_tables,
1106
- cu_seq_lens=prefill_metadata.context_chunk_cu_seq_lens[i],
1107
- batch_size=prefill_metadata.num_prefills,
1108
- kv_cache_dtype=self.kv_cache_dtype,
1109
- scale=k_scale,
1110
- seq_starts=prefill_metadata.context_chunk_starts[i],
1111
- )
1112
-
1113
- kv_c_normed = workspace[:toks]\
1114
- [..., :self.kv_lora_rank]
1115
- k_pe = workspace[:toks]\
1116
- [..., self.kv_lora_rank:].unsqueeze(1)
1117
-
1118
- kv_nope = self.kv_b_proj(kv_c_normed)[0].view( \
1119
- -1, self.num_heads, self.qk_nope_head_dim + self.v_head_dim)
1120
- k_nope, v = kv_nope\
1121
- .split([self.qk_nope_head_dim, self.v_head_dim], dim=-1)
1122
-
1123
- k = torch.cat((k_nope, k_pe.expand((*k_nope.shape[:-1], -1))),
1124
- dim=-1)
1125
-
1126
- attn_output, attn_softmax_lse = \
1127
- self._flash_attn_varlen_diff_headdims(
1128
- q=q,
1129
- k=k,
1130
- v=v,
1131
- cu_seqlens_q=prefill_metadata.query_start_loc,
1132
- cu_seqlens_k=prefill_metadata.context_chunk_cu_seq_lens[i],
1133
- max_seqlen_q=prefill_metadata.max_query_len,
1134
- max_seqlen_k=prefill_metadata.context_chunk_max_seq_lens[i],
1135
- softmax_scale=self.scale,
1136
- causal=False, # Context is unmasked
1137
- return_softmax_lse=True,
1138
- )
1139
-
1140
- if output is None:
1141
- output = attn_output
1142
- output_lse = attn_softmax_lse
1143
- else:
1144
- output_tmp = torch.empty_like(output)
1145
- output_lse_tmp = torch.empty_like(output_lse)
1146
- merge_attn_states(
1147
- output=output_tmp,
1148
- output_lse=output_lse_tmp,
1149
- prefix_output=output,
1150
- prefix_lse=output_lse,
1151
- suffix_output=attn_output,
1152
- suffix_lse=attn_softmax_lse,
1153
- )
1154
- output = output_tmp
1155
- output_lse = output_lse_tmp
1156
-
1157
- return output, output_lse
1158
-
1159
- def _forward_prefill(
1160
- self,
1161
- q: torch.Tensor,
1162
- kv_c_normed: torch.Tensor,
1163
- k_pe: torch.Tensor,
1164
- kv_c_and_k_pe_cache: torch.Tensor,
1165
- attn_metadata: MLACommonMetadata,
1166
- k_scale: torch.Tensor,
1167
- ) -> torch.Tensor:
1168
-
1169
- prefill_metadata = attn_metadata.prefill_metadata
1170
- assert prefill_metadata is not None
1171
-
1172
- has_context = prefill_metadata.context_lens_tensor is not None \
1173
- and prefill_metadata.context_lens_tensor.max() > 0
1174
-
1175
- kv_nope = self.kv_b_proj(kv_c_normed)[0].view(\
1176
- -1, self.num_heads, self.qk_nope_head_dim + self.v_head_dim)
1177
- k_nope, v = kv_nope\
1178
- .split([self.qk_nope_head_dim, self.v_head_dim], dim=-1)
1179
-
1180
- k = torch.cat((k_nope, k_pe.expand((*k_nope.shape[:-1], -1))), dim=-1)
1181
-
1182
- output = self._flash_attn_varlen_diff_headdims(
1183
- q=q,
1184
- k=k,
1185
- v=v,
1186
- cu_seqlens_q=prefill_metadata.query_start_loc,
1187
- cu_seqlens_k=prefill_metadata.query_start_loc,
1188
- max_seqlen_q=prefill_metadata.max_prefill_seq_len,
1189
- max_seqlen_k=prefill_metadata.max_prefill_seq_len,
1190
- softmax_scale=self.scale,
1191
- causal=True,
1192
- return_softmax_lse=has_context,
1193
- )
1194
-
1195
- if has_context:
1196
- # ROCm flash_attn_varlen_func will return 3 objects instead of 2
1197
- suffix_output, suffix_lse = output
1198
- context_output, context_lse = self._compute_prefill_context( \
1199
- q, kv_c_and_k_pe_cache, attn_metadata, k_scale)
1200
-
1201
- output = torch.empty_like(suffix_output)
1202
- merge_attn_states(
1203
- output=output,
1204
- prefix_output=context_output,
1205
- prefix_lse=context_lse,
1206
- suffix_output=suffix_output,
1207
- suffix_lse=suffix_lse,
1208
- )
1209
-
1210
- # unpad if necessary
1211
- if self._pad_v:
1212
- output = output[..., :v.shape[-1]]
1213
-
1214
- return output.flatten(start_dim=-2)
1215
-
1216
- @abstractmethod
1217
- def _forward_decode(
1218
- self,
1219
- ql_nope: torch.Tensor,
1220
- q_pe: torch.Tensor,
1221
- kv_c_and_k_pe_cache: torch.Tensor,
1222
- attn_metadata: T,
1223
- ) -> torch.Tensor:
1224
- raise NotImplementedError
1225
-
1226
- def forward(
1227
- self,
1228
- layer: AttentionLayer,
1229
- q: torch.Tensor, # query in unified attn
1230
- k_c_normed: torch.Tensor, # key in unified attn
1231
- k_pe: torch.Tensor, # value in unified attn
1232
- kv_cache: torch.Tensor,
1233
- attn_metadata: T,
1234
- output: Optional[torch.Tensor] = None,
1235
- output_scale: Optional[torch.Tensor] = None,
1236
- output_block_scale: Optional[torch.Tensor] = None,
1237
- ) -> torch.Tensor:
1238
- if output is not None:
1239
- raise NotImplementedError(
1240
- "output is not yet supported for MLAImplBase")
1241
-
1242
- if output_scale is not None or output_block_scale is not None:
1243
- raise NotImplementedError(
1244
- "fused output quantization is not yet supported"
1245
- " for MLAImplBase")
1246
-
1247
- if attn_metadata.is_profile_run and \
1248
- attn_metadata.context_chunk_workspace is not None:
1249
- # During the profile run try to simulate to worse case output size
1250
- # for `self.kv_b_proj(kv_c_normed)` in `_compute_prefill_context`
1251
- # since this can be large
1252
- _ = torch.empty(
1253
- (attn_metadata.context_chunk_workspace.shape[0],
1254
- self.num_heads, self.qk_nope_head_dim + self.v_head_dim),
1255
- device=k_c_normed.device,
1256
- dtype=k_c_normed.dtype,
1257
- )
1258
-
1259
- has_decode = attn_metadata.decode_metadata is not None
1260
- has_prefill = attn_metadata.prefill_metadata is not None
1261
-
1262
- num_prefill_tokens: int = attn_metadata.num_prefill_tokens
1263
- q = q.view(-1, self.num_heads, self.qk_head_dim)
1264
-
1265
- decode_q = q[num_prefill_tokens:]
1266
-
1267
- prefill_q = q[:num_prefill_tokens]
1268
- prefill_k_pe = k_pe[:num_prefill_tokens]
1269
- prefill_k_c_normed = k_c_normed[:num_prefill_tokens]
1270
-
1271
- # write the latent and rope to kv cache
1272
- if kv_cache.numel() > 0:
1273
- ops.concat_and_cache_mla(
1274
- k_c_normed,
1275
- k_pe.squeeze(1),
1276
- kv_cache,
1277
- attn_metadata.slot_mapping.flatten(),
1278
- kv_cache_dtype=self.kv_cache_dtype,
1279
- scale=layer._k_scale,
1280
- )
1281
-
1282
- output = torch.empty(attn_metadata.num_prefill_tokens +
1283
- attn_metadata.num_decode_tokens,
1284
- self.v_head_dim * self.num_heads,
1285
- device=q.device,
1286
- dtype=q.dtype)
1287
- if has_prefill:
1288
- output[:num_prefill_tokens] = self._forward_prefill(
1289
- prefill_q, prefill_k_c_normed, prefill_k_pe, kv_cache,
1290
- attn_metadata, layer._k_scale)
1291
-
1292
- if has_decode:
1293
- decode_q_nope, decode_q_pe = decode_q.split(
1294
- [self.qk_nope_head_dim, self.qk_rope_head_dim], dim=-1)
1295
- # Convert from (B, N, P) to (N, B, P)
1296
- decode_q_nope = decode_q_nope.transpose(0, 1)
1297
- # Multiply (N, B, P) x (N, P, L) -> (N, B, L)
1298
- decode_ql_nope = torch.bmm(decode_q_nope, self.W_UK_T)
1299
- # Convert from (N, B, L) to (B, N, L)
1300
- decode_ql_nope = decode_ql_nope.transpose(0, 1)
1301
-
1302
- output[num_prefill_tokens:] = self._forward_decode(
1303
- decode_ql_nope, decode_q_pe, kv_cache, attn_metadata)
1304
-
1305
- return output
vllm/attention/backends/rocm_aiter_mla.py
deleted
-407
@@ -1,407 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-
4
-from contextlib import contextmanager
5
-from dataclasses import dataclass
6
-from typing import Optional, Type, Union
7
-
8
-import torch
9
-
10
-import vllm.envs as envs
11
-from vllm.attention.backends.mla.common import (MLACommonBackend,
12
- MLACommonImpl,
13
- MLACommonMetadata,
14
- MLACommonMetadataBuilder,
15
- MLACommonState)
16
-from vllm.attention.backends.utils import (compute_slot_mapping,
17
- compute_slot_mapping_start_idx,
18
- is_block_tables_empty)
19
-from vllm.attention.ops.rocm_aiter_mla import (aiter_mla_decode_fwd,
20
- get_aiter_mla_metadata)
21
-
22
-
23
-def is_aiter_mla_enabled() -> bool:
24
- return envs.VLLM_ROCM_USE_AITER \
25
- and envs.VLLM_ROCM_USE_AITER_MLA
26
-
27
-
28
-class AiterMLABackend(MLACommonBackend):
29
-
30
- @staticmethod
31
- def get_name() -> str:
32
- return "ROCM_AITER_MLA"
33
-
34
- @staticmethod
35
- def get_impl_cls() -> Type["AiterMLAImpl"]:
36
- return AiterMLAImpl
37
-
38
- @staticmethod
39
- def get_metadata_cls() -> Type["AiterMLAMetadata"]:
40
- return AiterMLAMetadata
41
-
42
- @staticmethod
43
- def get_builder_cls() -> Type["AiterMLAMetadataBuilder"]:
44
- return AiterMLAMetadataBuilder
45
-
46
- @staticmethod
47
- def get_state_cls() -> Type["AiterMLAState"]:
48
- return AiterMLAState
49
-
50
-
51
-@dataclass
52
-class AiterMLAMetadata(MLACommonMetadata):
53
- # The following 5 tensors are for current version of AITER MLA
54
- block_table_bound: Optional[torch.Tensor] = None
55
- # The indptr of the paged kv cache, shape: [batch_size + 1]
56
- paged_kv_indptr: Optional[torch.Tensor] = None
57
- # The page indices of the paged kv cache
58
- paged_kv_indices: Optional[torch.Tensor] = None
59
- # The number of entries in the last page of each request in
60
- # the paged kv cache, shape: [batch_size]
61
- paged_kv_last_page_lens: Optional[torch.Tensor] = None
62
-
63
- # This is just to make new AITER MLA API work
64
- # -- MTP support is not added yet.
65
- qo_indptr: Optional[torch.Tensor] = None
66
-
67
- @property
68
- def prefill_metadata(self):
69
- prefill_metadata = super().prefill_metadata
70
- self._cached_prefill_metadata = prefill_metadata
71
-
72
- if prefill_metadata is not None:
73
- prefill_metadata.paged_kv_indptr = self.paged_kv_indptr
74
- prefill_metadata.paged_kv_indices = self.paged_kv_indices
75
- prefill_metadata\
76
- .paged_kv_last_page_lens = self.paged_kv_last_page_lens
77
- prefill_metadata.block_table_bound = self.block_table_bound
78
- prefill_metadata.qo_indptr = self.qo_indptr
79
-
80
- # update the cache
81
- self._cached_prefill_metadata = self.__class__(
82
- **prefill_metadata.__dict__)
83
-
84
- return self._cached_prefill_metadata
85
-
86
- @property
87
- def decode_metadata(self):
88
- decode_metadata = super().decode_metadata
89
-
90
- self._cached_decode_metadata = decode_metadata
91
-
92
- if decode_metadata is not None:
93
- decode_metadata.paged_kv_indptr = self.paged_kv_indptr
94
- decode_metadata.paged_kv_indices = self.paged_kv_indices
95
- decode_metadata\
96
- .paged_kv_last_page_lens = self.paged_kv_last_page_lens
97
- decode_metadata.block_table_bound = self.block_table_bound
98
- decode_metadata.qo_indptr = self.qo_indptr
99
-
100
- # update the cache
101
- self._cached_decode_metadata = self.__class__(
102
- **decode_metadata.__dict__)
103
-
104
- return self._cached_decode_metadata
105
-
106
-
107
-class AiterMLAMetadataBuilder(MLACommonMetadataBuilder[AiterMLAMetadata]):
108
- BLOCK_TABLE_EXTENDER: list[list[int]] = [[]]
109
-
110
- def __init__(self, input_builder):
111
- super().__init__(input_builder)
112
- assert self.block_size == 1, "AITER MLA requires only block size 1."
113
-
114
- def prepare(self):
115
- super().prepare()
116
- self.paged_kv_indices: list[int] = []
117
- self.paged_kv_indptr: list[int] = [0]
118
- self.paged_kv_last_page_lens: list[int] = []
119
- self.total_blocks = 0
120
- self.qo_indptr: list[int] = [0]
121
-
122
- def _add_seq_group(self, inter_data, chunked_prefill_enabled: bool,
123
- prefix_cache_hit: bool):
124
- """Add a sequence group to the metadata. Specifically update/append
125
- 1. context length.
126
- 2. block table.
127
- 3. slot mapping.
128
- """
129
- is_prompt = inter_data.is_prompt
130
- block_tables = inter_data.block_tables
131
-
132
- for (seq_id, token_len, seq_len, curr_seq_len, query_len, context_len,
133
- curr_sliding_window_block) in zip(
134
- inter_data.seq_ids, [len(t) for t in inter_data.input_tokens],
135
- inter_data.orig_seq_lens, inter_data.seq_lens,
136
- inter_data.query_lens, inter_data.context_lens,
137
- inter_data.curr_sliding_window_blocks):
138
- self.context_lens.append(context_len)
139
- if is_prompt:
140
- self.num_prefills += 1
141
- self.num_prefill_tokens += token_len
142
- self.prefill_seq_lens.append(seq_len)
143
- else:
144
- self.num_decode_tokens += query_len
145
- self.curr_seq_lens.append(curr_seq_len)
146
-
147
- # Compute block table.
148
- # TODO(sang): Combine chunked prefill and prefix caching by
149
- # only allowing multiple of block_size chunk size.
150
- # NOTE: This only works for oooooooxxx style attention.
151
- block_table = []
152
- if prefix_cache_hit:
153
- # NOTE(woosuk): For flash-attn, the block table should
154
- # include the entries for the incoming prefill tokens.
155
- block_table = block_tables[seq_id]
156
- elif ((chunked_prefill_enabled or not is_prompt)
157
- and block_tables is not None):
158
- if curr_sliding_window_block == 0:
159
- block_table = block_tables[seq_id]
160
- else:
161
- block_table = block_tables[seq_id][
162
- -curr_sliding_window_block:]
163
- self.block_tables.append(block_table)
164
-
165
- # Compute slot mapping.
166
- is_profile_run = is_block_tables_empty(block_tables)
167
- start_idx = compute_slot_mapping_start_idx(is_prompt, query_len,
168
- context_len,
169
- self.sliding_window)
170
- compute_slot_mapping(is_profile_run, self.slot_mapping, seq_id,
171
- seq_len, context_len, start_idx,
172
- self.block_size, inter_data.block_tables)
173
- if is_profile_run:
174
- return
175
-
176
- # Update paged_kv_* tensors only for non-profile run
177
- block_table = block_tables[seq_id]
178
- self._update_paged_kv_tensors(block_table, seq_len)
179
-
180
- def _update_paged_kv_tensors(self, block_table: list[int], seq_len: int):
181
- # Get the number of valid blocks based on sequence length.
182
- # If seq_len = 16, block_size = 16,
183
- # block_table_bound is 1 with 1 valid block.
184
- # If seq_len = 15, block_size = 16,
185
- # block_table_bound is 0 + 1 with 1 valid block.
186
- self.total_blocks += len(block_table)
187
- block_table_bound = seq_len // self.block_size + 1 \
188
- if seq_len % self.block_size != 0 \
189
- else seq_len // self.block_size
190
- self.paged_kv_indices.extend(block_table[:block_table_bound])
191
- self.paged_kv_indptr.append(self.paged_kv_indptr[-1] +
192
- block_table_bound)
193
- self.qo_indptr.append(self.qo_indptr[-1] + 1)
194
-
195
- last_page_len = seq_len % self.block_size
196
- if last_page_len == 0:
197
- last_page_len = self.block_size
198
- self.paged_kv_last_page_lens.append(last_page_len)
199
-
200
- def build(self, seq_lens: list[int], query_lens: list[int],
201
- cuda_graph_pad_size: int, batch_size: int) -> AiterMLAMetadata:
202
- metadata = super().build(seq_lens, query_lens, cuda_graph_pad_size,
203
- batch_size)
204
- device = self.runner.device
205
- use_captured_graph = cuda_graph_pad_size != -1
206
-
207
- if use_captured_graph:
208
- last_paged_kv_indptr = self.paged_kv_indptr[-1]
209
- self.paged_kv_indptr.extend([last_paged_kv_indptr] *
210
- cuda_graph_pad_size)
211
- self.paged_kv_last_page_lens.extend([0] * cuda_graph_pad_size)
212
- last_qo_indptr = self.qo_indptr[-1]
213
- self.qo_indptr.extend([last_qo_indptr] * cuda_graph_pad_size)
214
-
215
- # For current version of AITER MLA
216
- if len(self.paged_kv_indptr) > 0:
217
- # extend to the maximum number of blocks as returned by the
218
- # scheduler
219
- self.paged_kv_indices.extend(
220
- [0] * (self.total_blocks - len(self.paged_kv_indices)))
221
- paged_kv_indices_tensor = torch.tensor(self.paged_kv_indices,
222
- device=device,
223
- dtype=torch.int)
224
- paged_kv_indptr_tensor = torch.tensor(self.paged_kv_indptr,
225
- device=device,
226
- dtype=torch.int)
227
- paged_kv_last_page_lens_tensor = torch.tensor(
228
- self.paged_kv_last_page_lens, device=device, dtype=torch.int)
229
- block_table_bound_tensor = torch.zeros(len(self.paged_kv_indptr) -
230
- 1,
231
- device=device,
232
- dtype=torch.int)
233
-
234
- qo_indptr = torch.tensor(self.qo_indptr,
235
- device=device,
236
- dtype=torch.int)
237
- else:
238
- paged_kv_indices_tensor = None
239
- paged_kv_indptr_tensor = None
240
- paged_kv_last_page_lens_tensor = None
241
- block_table_bound_tensor = None
242
- qo_indptr = None
243
-
244
- metadata.paged_kv_indptr = paged_kv_indptr_tensor
245
- metadata.paged_kv_indices = paged_kv_indices_tensor
246
- metadata.paged_kv_last_page_lens = paged_kv_last_page_lens_tensor
247
- metadata.block_table_bound = block_table_bound_tensor
248
- metadata.qo_indptr = qo_indptr
249
-
250
- return metadata
251
-
252
-
253
-class AiterMLAState(MLACommonState[AiterMLAMetadata]):
254
-
255
- @contextmanager
256
- def graph_capture(self, max_batch_size: int):
257
- kv_indices, kv_indptr, last_page_lens, qo_indptr = \
258
- get_aiter_mla_metadata(
259
- max_batch_size=max_batch_size,
260
- block_size=self.runner.block_size,
261
- max_block_per_batch=\
262
- self.runner.get_max_block_per_batch(),
263
- device=self.runner.device)
264
- self._paged_kv_indices_tensor = kv_indices
265
- self._paged_kv_indptr_tensor = kv_indptr
266
- self._paged_kv_last_page_lens_tensor = last_page_lens
267
- self._qo_indptr_tensor = qo_indptr
268
-
269
- with super().graph_capture(max_batch_size):
270
- yield
271
-
272
- del self._paged_kv_indices_tensor
273
- del self._paged_kv_indptr_tensor
274
- del self._paged_kv_last_page_lens_tensor
275
- del self._qo_indptr_tensor
276
-
277
- def graph_capture_get_metadata_for_batch(
278
- self,
279
- batch_size: int,
280
- is_encoder_decoder_model: bool = False) -> AiterMLAMetadata:
281
-
282
- metadata = super().graph_capture_get_metadata_for_batch(
283
- batch_size, is_encoder_decoder_model)
284
-
285
- paged_kv_indptr = self._paged_kv_indptr_tensor[:batch_size + 1]
286
- paged_kv_indices = self._paged_kv_indices_tensor
287
- paged_kv_last_page_lens = self._paged_kv_last_page_lens_tensor[:
288
- batch_size]
289
- qo_indptr = self._qo_indptr_tensor[:batch_size + 1]
290
-
291
- metadata.paged_kv_indptr = paged_kv_indptr
292
- metadata.paged_kv_indices = paged_kv_indices
293
- metadata.paged_kv_last_page_lens = paged_kv_last_page_lens
294
- metadata.qo_indptr = qo_indptr
295
-
296
- return metadata
297
-
298
- def get_graph_input_buffers(self,
299
- attn_metadata: AiterMLAMetadata,
300
- is_encoder_decoder_model: bool = False):
301
- input_buffers = super().get_graph_input_buffers(
302
- attn_metadata, is_encoder_decoder_model)
303
- input_buffers[
304
- 'paged_kv_indptr'] = attn_metadata.decode_metadata.paged_kv_indptr
305
- input_buffers[
306
- "paged_kv_indices"] = attn_metadata.\
307
- decode_metadata.paged_kv_indices
308
- input_buffers[
309
- "paged_kv_last_page_lens"] = attn_metadata.\
310
- decode_metadata.paged_kv_last_page_lens
311
- input_buffers['qo_indptr'] = attn_metadata.qo_indptr
312
-
313
- return input_buffers
314
-
315
- def prepare_graph_input_buffers(self,
316
- input_buffers,
317
- attn_metadata: AiterMLAMetadata,
318
- is_encoder_decoder_model: bool = False):
319
- super().prepare_graph_input_buffers(input_buffers, attn_metadata,
320
- is_encoder_decoder_model)
321
-
322
- num_total_blocks = attn_metadata.decode_metadata.paged_kv_indices.shape[
323
- 0]
324
- input_buffers["paged_kv_indptr"].copy_(
325
- attn_metadata.decode_metadata.paged_kv_indptr, non_blocking=True)
326
- input_buffers["paged_kv_indices"][:num_total_blocks].copy_(
327
- attn_metadata.decode_metadata.paged_kv_indices, non_blocking=True)
328
- input_buffers["paged_kv_last_page_lens"].copy_(
329
- attn_metadata.decode_metadata.paged_kv_last_page_lens,
330
- non_blocking=True)
331
- input_buffers["qo_indptr"].copy_(
332
- attn_metadata.decode_metadata.qo_indptr, non_blocking=True)
333
-
334
-
335
-class AiterMLAImpl(MLACommonImpl[AiterMLAMetadata]):
336
-
337
- def __init__(
338
- self,
339
- num_heads: int,
340
- head_size: int,
341
- scale: float,
342
- num_kv_heads: int,
343
- alibi_slopes: Optional[list[float]],
344
- sliding_window: Optional[int],
345
- kv_cache_dtype: str,
346
- logits_soft_cap: Optional[float],
347
- attn_type: str,
348
- kv_sharing_target_layer_name: Optional[str],
349
- # MLA Specific Arguments
350
- **mla_args) -> None:
351
- super().__init__(num_heads, head_size, scale, num_kv_heads,
352
- alibi_slopes, sliding_window, kv_cache_dtype,
353
- logits_soft_cap, attn_type,
354
- kv_sharing_target_layer_name, **mla_args)
355
-
356
- unsupported_features = [alibi_slopes, sliding_window, logits_soft_cap]
357
- if any(unsupported_features):
358
- raise NotImplementedError(
359
- "Aiter MLA does not support one of the following: "
360
- "alibi_slopes, sliding_window, logits_soft_cap")
361
-
362
- from aiter import flash_attn_varlen_func
363
- self.flash_attn_varlen_func = flash_attn_varlen_func
364
-
365
- def _flash_attn_varlen_diff_headdims(
366
- self, q: torch.Tensor, k: torch.Tensor, v: torch.Tensor,
367
- softmax_scale: float, return_softmax_lse: bool,
368
- **kwargs) -> Union[tuple[torch.Tensor, ...], torch.Tensor]:
369
- output = self.flash_attn_varlen_func(
370
- q,
371
- k,
372
- v,
373
- **kwargs,
374
- )
375
-
376
- return output
377
-
378
- def _forward_decode(
379
- self,
380
- q_nope: torch.Tensor,
381
- q_pe: torch.Tensor,
382
- kv_c_and_k_pe_cache: torch.Tensor,
383
- attn_metadata: AiterMLAMetadata,
384
- ) -> torch.Tensor:
385
- assert kv_c_and_k_pe_cache.numel() > 0
386
-
387
- decode_meta = attn_metadata.decode_metadata
388
- assert decode_meta is not None
389
- B = q_nope.shape[0]
390
-
391
- q = torch.cat([q_nope, q_pe], dim=-1)
392
- o = torch.empty(B,
393
- self.num_heads,
394
- self.kv_lora_rank,
395
- dtype=q.dtype,
396
- device=q.device)
397
-
398
- kv_buffer = kv_c_and_k_pe_cache.unsqueeze(2)
399
-
400
- aiter_mla_decode_fwd(q, kv_buffer, o, self.scale,
401
- attn_metadata.qo_indptr,
402
- attn_metadata.max_query_len,
403
- attn_metadata.paged_kv_indptr,
404
- attn_metadata.paged_kv_indices,
405
- attn_metadata.paged_kv_last_page_lens)
406
-
407
- return self._v_up_proj(o)
vllm/attention/backends/rocm_flash_attn.py
deleted
-953
@@ -1,953 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-"""Attention layer ROCm GPUs."""
4
-import itertools
5
-from dataclasses import dataclass
6
-from functools import cache
7
-from typing import List, Optional, Tuple, Type
8
-
9
-import torch
10
-
11
-import vllm.envs as envs
12
-from vllm import _custom_ops as ops
13
-from vllm.attention.backends.abstract import (AttentionBackend, AttentionImpl,
14
- AttentionLayer,
15
- AttentionMetadata, AttentionType)
16
-from vllm.attention.backends.utils import (CommonAttentionState,
17
- CommonMetadataBuilder)
18
-from vllm.attention.ops.paged_attn import (PagedAttention,
19
- PagedAttentionMetadata)
20
-from vllm.config import get_current_vllm_config
21
-from vllm.logger import init_logger
22
-from vllm.model_executor.layers.quantization.utils.quant_utils import (
23
- QuantKey, kFp8StaticTensorSym)
24
-from vllm.platforms import current_platform
25
-
26
-logger = init_logger(__name__)
27
-_PARTITION_SIZE_ROCM = 256
28
-
29
-
30
-@cache
31
-def is_rocm_aiter_paged_attn_enabled() -> bool:
32
- return envs.VLLM_ROCM_USE_AITER_PAGED_ATTN \
33
- and envs.VLLM_ROCM_USE_AITER \
34
-
35
-
36
-@cache
37
-def _get_paged_attn_module() -> PagedAttention:
38
- """
39
- Initializes the appropriate PagedAttention module from `attention/ops`,
40
- which is used as helper function
41
- by `ROCmFlashAttentionImpl` and `ROCmFlashAttentionBackend`.
42
-
43
- The choice of attention module depends on whether
44
- AITER paged attention is enabled:
45
- - If enabled, `ROCmFlashAttentionImpl` uses `AITERPagedAttention`.
46
- - Otherwise, it defaults to using the original `PagedAttention`.
47
- """
48
- if is_rocm_aiter_paged_attn_enabled():
49
- # Import AITERPagedAttention only when the flag is enabled
50
- from vllm.attention.ops.rocm_aiter_paged_attn import (
51
- AITERPagedAttention)
52
- return AITERPagedAttention()
53
- return PagedAttention()
54
-
55
-
56
-class ROCmFlashAttentionBackend(AttentionBackend):
57
- accept_output_buffer: bool = True
58
-
59
- @staticmethod
60
- def get_name() -> str:
61
- return "ROCM_FLASH"
62
-
63
- @staticmethod
64
- def get_impl_cls() -> Type["ROCmFlashAttentionImpl"]:
65
- return ROCmFlashAttentionImpl
66
-
67
- @staticmethod
68
- def get_metadata_cls() -> Type["AttentionMetadata"]:
69
- return ROCmFlashAttentionMetadata
70
-
71
- @staticmethod
72
- def get_builder_cls() -> Type["ROCmFlashAttentionMetadataBuilder"]:
73
- return ROCmFlashAttentionMetadataBuilder
74
-
75
- @staticmethod
76
- def get_state_cls() -> Type["CommonAttentionState"]:
77
- return CommonAttentionState
78
-
79
- @staticmethod
80
- def get_kv_cache_shape(
81
- num_blocks: int,
82
- block_size: int,
83
- num_kv_heads: int,
84
- head_size: int,
85
- ) -> Tuple[int, ...]:
86
- paged_attn = _get_paged_attn_module()
87
- return paged_attn.get_kv_cache_shape(num_blocks, block_size,
88
- num_kv_heads, head_size)
89
-
90
- @staticmethod
91
- def swap_blocks(
92
- src_kv_cache: torch.Tensor,
93
- dst_kv_cache: torch.Tensor,
94
- src_to_dst: torch.Tensor,
95
- ) -> None:
96
- paged_attn = _get_paged_attn_module()
97
- paged_attn.swap_blocks(src_kv_cache, dst_kv_cache, src_to_dst)
98
-
99
- @staticmethod
100
- def copy_blocks(
101
- kv_caches: List[torch.Tensor],
102
- src_to_dists: torch.Tensor,
103
- ) -> None:
104
- paged_attn = _get_paged_attn_module()
105
- paged_attn.copy_blocks(kv_caches, src_to_dists)
106
-
107
-
108
-@dataclass
109
-class ROCmFlashAttentionMetadata(AttentionMetadata, PagedAttentionMetadata):
110
- """Metadata for FlashAttentionBackend.
111
-
112
- NOTE: Any python object stored here is not updated when it is
113
- cuda-graph replayed. If you have values that need to be changed
114
- dynamically, it should be stored in tensor. The tensor has to be
115
- updated from `CUDAGraphRunner.forward` API.
116
- """
117
- # (batch_size,). The sequence length per sequence. Sequence length means
118
- # the computed tokens + new tokens None if it is a decoding.
119
- seq_lens: Optional[List[int]]
120
- # seq_lens stored as a tensor.
121
- seq_lens_tensor: Optional[torch.Tensor]
122
- # Maximum sequence length among prefill batch. 0 if there are decoding
123
- # requests only.
124
- max_prefill_seq_len: int
125
- # Maximum sequence length among decode batch. 0 if there are prefill
126
- # requests only.
127
- max_decode_seq_len: int
128
-
129
- # Whether or not if cuda graph is enabled.
130
- # Cuda-graph is currently enabled for decoding only.
131
- # TODO(woosuk): Move `use_cuda_graph` out since it's unrelated to attention.
132
- use_cuda_graph: bool
133
-
134
- # NOTE(sang): Definition of context_len, query_len, and seq_len.
135
- # |---------- N-1 iteration --------|
136
- # |---------------- N iteration ---------------------|
137
- # |- tokenA -|......................|-- newTokens ---|
138
- # |---------- context_len ----------|
139
- # |-------------------- seq_len ----------------------|
140
- # |-- query_len ---|
141
-
142
- # Maximum query length in the batch. None for decoding.
143
- max_query_len: Optional[int] = None
144
- # (batch_size + 1,). The cumulative subquery lengths of the sequences in
145
- # the batch, used to index into subquery. E.g., if the subquery length
146
- # is [4, 6], it is [0, 4, 10].
147
- query_start_loc: Optional[torch.Tensor] = None
148
- # (batch_size + 1,). The cumulative sequence lengths of the sequences in
149
- # the batch, used to index into sequence. E.g., if the sequence length is
150
- # [4, 6], it is [0, 4, 10].
151
- seq_start_loc: Optional[torch.Tensor] = None
152
- # (batch_size,) A tensor of context lengths (tokens that are computed
153
- # so far).
154
- context_lens_tensor: Optional[torch.Tensor] = None
155
-
156
- # Max number of query tokens among request in the batch.
157
- max_decode_query_len: Optional[int] = None
158
-
159
- _cached_prefill_metadata: Optional["ROCmFlashAttentionMetadata"] = None
160
- _cached_decode_metadata: Optional["ROCmFlashAttentionMetadata"] = None
161
-
162
- # Begin encoder attn & enc/dec cross-attn fields...
163
-
164
- # Encoder sequence lengths representation
165
- encoder_seq_lens: Optional[List[int]] = None
166
- encoder_seq_lens_tensor: Optional[torch.Tensor] = None
167
-
168
- # Maximum sequence length among encoder sequences
169
- max_encoder_seq_len: Optional[int] = None
170
-
171
- # Number of tokens input to encoder
172
- num_encoder_tokens: Optional[int] = None
173
-
174
- # Cross-attention memory-mapping data structures: slot mapping
175
- # and block tables
176
- cross_slot_mapping: Optional[torch.Tensor] = None
177
- cross_block_tables: Optional[torch.Tensor] = None
178
-
179
- @property
180
- def prefill_metadata(self) -> Optional["ROCmFlashAttentionMetadata"]:
181
- if self.num_prefills == 0:
182
- return None
183
-
184
- if self._cached_prefill_metadata is not None:
185
- return self._cached_prefill_metadata
186
-
187
- assert self.seq_lens is not None
188
- assert self.seq_lens_tensor is not None
189
- assert self.block_tables is not None
190
-
191
- self._cached_prefill_metadata = ROCmFlashAttentionMetadata(
192
- num_prefills=self.num_prefills,
193
- num_prefill_tokens=self.num_prefill_tokens,
194
- num_decode_tokens=0,
195
- slot_mapping=self.slot_mapping[:self.num_prefill_tokens],
196
- multi_modal_placeholder_index_maps=self.
197
- multi_modal_placeholder_index_maps,
198
- enable_kv_scales_calculation=self.enable_kv_scales_calculation,
199
- seq_lens=self.seq_lens[:self.num_prefills],
200
- seq_lens_tensor=self.seq_lens_tensor[:self.num_prefills],
201
- max_query_len=self.max_query_len,
202
- max_prefill_seq_len=self.max_prefill_seq_len,
203
- max_decode_seq_len=0,
204
- query_start_loc=None if self.query_start_loc is None else
205
- self.query_start_loc[:self.num_prefills + 1],
206
- seq_start_loc=None if self.seq_start_loc is None else
207
- self.seq_start_loc[:self.num_prefills + 1],
208
- context_lens_tensor=None if self.context_lens_tensor is None else
209
- self.context_lens_tensor[:self.num_prefills],
210
- block_tables=self.block_tables[:self.num_prefills],
211
- use_cuda_graph=False,
212
- # Begin encoder & cross attn fields below...
213
- encoder_seq_lens=self.encoder_seq_lens,
214
- encoder_seq_lens_tensor=self.encoder_seq_lens_tensor,
215
- max_encoder_seq_len=self.max_encoder_seq_len,
216
- cross_slot_mapping=self.cross_slot_mapping,
217
- cross_block_tables=self.cross_block_tables)
218
- return self._cached_prefill_metadata
219
-
220
- @property
221
- def decode_metadata(self) -> Optional["ROCmFlashAttentionMetadata"]:
222
- if self.num_decode_tokens == 0:
223
- return None
224
-
225
- if self._cached_decode_metadata is not None:
226
- return self._cached_decode_metadata
227
- assert self.block_tables is not None
228
- assert self.seq_lens_tensor is not None
229
-
230
- self._cached_decode_metadata = ROCmFlashAttentionMetadata(
231
- num_prefills=0,
232
- num_prefill_tokens=0,
233
- num_decode_tokens=self.num_decode_tokens,
234
- slot_mapping=self.slot_mapping[self.num_prefill_tokens:],
235
- multi_modal_placeholder_index_maps=None,
236
- enable_kv_scales_calculation=True,
237
- seq_lens=None,
238
- seq_lens_tensor=self.seq_lens_tensor[self.num_prefills:],
239
- max_query_len=None,
240
- max_prefill_seq_len=0,
241
- max_decode_seq_len=self.max_decode_seq_len,
242
- query_start_loc=None,
243
- seq_start_loc=None,
244
- context_lens_tensor=None,
245
- block_tables=self.block_tables[self.num_prefills:],
246
- use_cuda_graph=self.use_cuda_graph,
247
- # Begin encoder & cross attn fields below...
248
- encoder_seq_lens=self.encoder_seq_lens,
249
- encoder_seq_lens_tensor=self.encoder_seq_lens_tensor,
250
- max_encoder_seq_len=self.max_encoder_seq_len,
251
- cross_slot_mapping=self.cross_slot_mapping,
252
- cross_block_tables=self.cross_block_tables)
253
- # Batch may be composed of prefill|decodes, adjust query start indices
254
- # to refer to the start of decodes when the two are split apart.
255
- # E.g. in tokens:[3 prefills|6 decodes], query_start_loc=[3,9] => [0,6].
256
- if self._cached_decode_metadata.query_start_loc is not None:
257
- qs = self._cached_decode_metadata.query_start_loc
258
- self._cached_decode_metadata.query_start_loc = qs - qs[0]
259
- return self._cached_decode_metadata
260
-
261
-
262
-class ROCmFlashAttentionMetadataBuilder(
263
- CommonMetadataBuilder[ROCmFlashAttentionMetadata]):
264
-
265
- _metadata_cls = ROCmFlashAttentionMetadata
266
-
267
-
268
-def _make_alibi_bias(alibi_slopes: torch.Tensor,
269
- dtype: torch.dtype,
270
- seq_lens: Optional[List[int]],
271
- make_attn_mask: bool = True) -> List[torch.Tensor]:
272
- attn_biases = []
273
- if seq_lens:
274
- for seq_len in seq_lens:
275
- bias = torch.arange(seq_len, dtype=dtype)
276
- # NOTE(zhuohan): HF uses
277
- # `bias = bias[None, :].repeat(seq_len, 1)`
278
- # here. We find that both biases give the same results, but
279
- # the bias below more accurately follows the original ALiBi
280
- # paper.
281
- bias = bias[None, :] - bias[:, None]
282
-
283
- num_heads = alibi_slopes.shape[0]
284
- bias = bias[None, :].repeat(
285
- (num_heads, 1, 1)).to(alibi_slopes.device)
286
- bias.mul_(alibi_slopes[:, None, None])
287
- if make_attn_mask:
288
- inf_mask = torch.empty(
289
- (1, seq_len, seq_len),
290
- dtype=bias.dtype).fill_(-torch.inf).triu_(diagonal=1).to(
291
- alibi_slopes.device)
292
- attn_biases.append((bias + inf_mask).to(dtype))
293
- else:
294
- attn_biases.append(bias.to(dtype))
295
-
296
- return attn_biases
297
-
298
-
299
-def _get_seq_len_block_table_args(
300
- attn_metadata: ROCmFlashAttentionMetadata,
301
- attn_type: str,
302
-) -> tuple:
303
- '''
304
- The particular choice of sequence-length
305
- attributes which should be extracted from attn_metadata is dependent
306
- on the type of attention operation.
307
-
308
- Decoder attn -> select entirely decoder self-attention-related fields
309
- Encoder/decoder cross-attn -> select encoder sequence lengths
310
- Encoder attn -> select encoder sequence lengths fields
311
- Encoder-only attn -> select prefill sequence lengths with
312
- bidirectional attention
313
-
314
- Arguments:
315
-
316
- * attn_metadata: Attention metadata structure associated with attention op
317
- * attn_type: encoder attention, decoder self-attention,
318
- encoder/decoder cross-attention, encoder-only
319
-
320
- Returns:
321
-
322
- * Appropriate sequence-lengths tensors for query and key
323
- * Appropriate max sequence-length scalar
324
- * Causal masking flag
325
- '''
326
-
327
- if attn_type == AttentionType.ENCODER:
328
- assert attn_metadata.encoder_seq_lens is not None
329
- assert attn_metadata.encoder_seq_lens_tensor is not None
330
- query_seq_start_loc = torch.tensor(
331
- list(itertools.accumulate([0] + attn_metadata.encoder_seq_lens)),
332
- device=attn_metadata.encoder_seq_lens_tensor.device,
333
- dtype=attn_metadata.encoder_seq_lens_tensor.dtype)
334
- causal_mask = False
335
-
336
- # No block tables associated with encoder attention
337
- return (query_seq_start_loc, attn_metadata.max_encoder_seq_len,
338
- query_seq_start_loc, attn_metadata.max_encoder_seq_len,
339
- attn_metadata.encoder_seq_lens, causal_mask)
340
-
341
- elif attn_type == AttentionType.ENCODER_ONLY:
342
- # For encoder-only models, we use the prefill sequence lengths
343
- assert attn_metadata.seq_lens is not None
344
- assert attn_metadata.seq_lens_tensor is not None
345
- query_seq_start_loc = torch.tensor(
346
- list(itertools.accumulate([0] + attn_metadata.seq_lens)),
347
- device=attn_metadata.seq_lens_tensor.device,
348
- dtype=attn_metadata.seq_lens_tensor.dtype)
349
- max_seq_len = attn_metadata.max_prefill_seq_len
350
- # Encoder-only models typically use bidirectional attention
351
- causal_mask = False
352
-
353
- return (query_seq_start_loc, max_seq_len, query_seq_start_loc,
354
- max_seq_len, attn_metadata.seq_lens, causal_mask)
355
-
356
- elif attn_type == AttentionType.DECODER:
357
- # Decoder self-attention
358
- # Choose max_seq_len based on whether we are in prompt_run
359
- assert attn_metadata.seq_lens is not None
360
- assert attn_metadata.seq_lens_tensor is not None
361
- query_seq_start_loc = torch.tensor(
362
- list(itertools.accumulate([0] + attn_metadata.seq_lens)),
363
- device=attn_metadata.seq_lens_tensor.device,
364
- dtype=attn_metadata.seq_lens_tensor.dtype)
365
- max_seq_len = attn_metadata.max_prefill_seq_len
366
- causal_mask = True
367
-
368
- return (query_seq_start_loc, max_seq_len, query_seq_start_loc,
369
- max_seq_len, attn_metadata.seq_lens, causal_mask)
370
- elif attn_type == AttentionType.ENCODER_DECODER:
371
- assert attn_metadata.seq_lens is not None
372
- assert attn_metadata.encoder_seq_lens_tensor is not None
373
- query_start_loc = torch.tensor(
374
- list(itertools.accumulate([0] + attn_metadata.seq_lens)),
375
- device=attn_metadata.encoder_seq_lens_tensor.device,
376
- dtype=attn_metadata.encoder_seq_lens_tensor.dtype)
377
-
378
- assert attn_metadata.encoder_seq_lens is not None
379
- assert attn_metadata.seq_lens_tensor is not None
380
- key_seq_start_loc = torch.tensor(
381
- list(itertools.accumulate([0] + attn_metadata.encoder_seq_lens)),
382
- device=attn_metadata.seq_lens_tensor.device,
383
- dtype=attn_metadata.seq_lens_tensor.dtype)
384
- causal_mask = False
385
-
386
- # Enc/dec cross-attention KVs match encoder sequence length;
387
- # cross-attention utilizes special "cross" block tables
388
- return (query_start_loc, attn_metadata.max_prefill_seq_len,
389
- key_seq_start_loc, attn_metadata.max_encoder_seq_len,
390
- attn_metadata.seq_lens, causal_mask)
391
- else:
392
- raise AttributeError(f"Invalid attention type {str(attn_type)}")
393
-
394
-
395
-class ROCmFlashAttentionImpl(AttentionImpl):
396
- """
397
- If the input tensors contain prompt tokens, the layout is as follows:
398
- |<--------------- num_prompt_tokens -------------->|
399
- |<--prompt_0-->|<--prompt_1-->|...|<--prompt_N-1-->|
400
-
401
- Otherwise, the layout is as follows:
402
- |<------------------ num_generation_tokens (M) ----------------->|
403
- |<--generation_0-->|..........|<--generation_M-1-->|<--padding-->|
404
-
405
- Generation tokens can contain padding when cuda-graph is used.
406
- Currently, prompt tokens don't contain any padding.
407
-
408
- The prompts might have different lengths, while the generation tokens
409
- always have length 1.
410
-
411
- If chunked prefill is enabled, prefill tokens and decode tokens can be
412
- batched together in a flattened 1D query.
413
-
414
- |<----- num_prefill_tokens ---->|<------- num_decode_tokens ----------->|
415
- |<-prompt_0->|...|<-prompt_N-1->|<-generation_0->|...|<-generation_M-1->|
416
-
417
- Currently, cuda graph is disabled for chunked prefill, meaning there's no
418
- padding between prefill and decode tokens.
419
- """
420
-
421
- def __init__(
422
- self,
423
- num_heads: int,
424
- head_size: int,
425
- scale: float,
426
- num_kv_heads: int,
427
- alibi_slopes: Optional[List[float]],
428
- sliding_window: Optional[int],
429
- kv_cache_dtype: str,
430
- logits_soft_cap: Optional[float] = None,
431
- attn_type: str = AttentionType.DECODER,
432
- kv_sharing_target_layer_name: Optional[str] = None,
433
- use_irope: bool = False,
434
- ) -> None:
435
- if kv_sharing_target_layer_name is not None:
436
- raise NotImplementedError("KV sharing is not supported in V0 "
437
- "ROCM_FLASH backend.")
438
- if use_irope:
439
- logger.warning_once(
440
- "Using irope in ROCm Flash Attention is not supported yet, it "
441
- "will fail back to global attention for long context.")
442
- if use_irope:
443
- logger.warning(
444
- "Using irope in V0 is not supported yet, it will fall back "
445
- "to global attention for long context.")
446
- if logits_soft_cap is None:
447
- # In flash-attn, setting logits_soft_cap as 0 means no soft cap.
448
- self.logits_soft_cap = 0.0
449
- else:
450
- self.logits_soft_cap = logits_soft_cap
451
- self.attn_type = attn_type
452
- self.num_heads = num_heads
453
- self.head_size = head_size
454
- self.scale = float(scale)
455
- self.num_kv_heads = num_kv_heads
456
- if alibi_slopes is not None:
457
- alibi_slopes = torch.tensor(alibi_slopes, dtype=torch.float32)
458
- self.alibi_slopes = alibi_slopes
459
- self.sliding_window = ((sliding_window, sliding_window)
460
- if sliding_window is not None else (-1, -1))
461
- self.kv_cache_dtype = kv_cache_dtype
462
-
463
- self.num_queries_per_kv = self.num_heads // self.num_kv_heads
464
-
465
- self.paged_attn_module = _get_paged_attn_module()
466
- supported_head_sizes = self.paged_attn_module.get_supported_head_sizes(
467
- )
468
-
469
- if head_size not in supported_head_sizes:
470
- raise ValueError(
471
- f"Head size {head_size} is not supported by PagedAttention. "
472
- f"Supported head sizes are: {supported_head_sizes}.")
473
-
474
- self.use_naive_attn = False
475
- # NOTE: Allow for switching between Triton and CK. Defaulting to triton.
476
- self.use_triton_flash_attn = envs.VLLM_USE_TRITON_FLASH_ATTN
477
- if self.use_triton_flash_attn:
478
- if logits_soft_cap is not None:
479
- raise ValueError(
480
- "ROCm Triton FlashAttention does not support attention"
481
- " logits soft capping."
482
- " please try using the ROCm CK "
483
- "FA backend instead by setting the env var "
484
- "`VLLM_USE_TRITON_FLASH_ATTN=0`")
485
-
486
- from vllm.attention.ops.triton_flash_attention import ( # noqa: F401
487
- triton_attention)
488
- self.triton_attn_func = triton_attention
489
- logger.debug("Using Triton FA in ROCmBackend")
490
- if self.sliding_window != (-1, -1):
491
- logger.warning("ROCm Triton FA does not currently support "
492
- "sliding window attention. If using half "
493
- "precision, please try using the ROCm CK "
494
- "FA backend instead by setting the env var "
495
- "`VLLM_USE_TRITON_FLASH_ATTN=0`")
496
- else:
497
- # if not using triton, navi3x/navi21/navi10 do not use flash-attn
498
- # either
499
- if not current_platform.has_device_capability(90):
500
- self.use_naive_attn = True
501
- else:
502
- try:
503
- from flash_attn import flash_attn_varlen_func # noqa: F401
504
- self.fa_attn_func = flash_attn_varlen_func
505
- logger.debug("Using CK FA in ROCmBackend")
506
- except ModuleNotFoundError:
507
- self.use_naive_attn = True
508
-
509
- if self.use_naive_attn:
510
- if logits_soft_cap is not None:
511
- raise ValueError(
512
- "ROCm Naive FlashAttention does not support "
513
- "attention logits soft capping.")
514
-
515
- self.sdpa_attn_func = _sdpa_attention
516
- logger.debug("Using naive (SDPA) attention in ROCmBackend")
517
-
518
- self.aiter_kv_scales_initialized = False
519
- self.force_fp8_attention = (
520
- get_current_vllm_config() is not None
521
- and get_current_vllm_config().model_config.override_attention_dtype
522
- == "fp8")
523
-
524
- def repeat_kv(self, x: torch.Tensor, n_rep: int) -> torch.Tensor:
525
- """torch.repeat_interleave(x, dim=1, repeats=n_rep)"""
526
- tokens, n_kv_heads, head_dim = x.shape
527
- return (x[:, :,
528
- None, :].expand(tokens, n_kv_heads, n_rep,
529
- head_dim).reshape(tokens, n_kv_heads * n_rep,
530
- head_dim))
531
-
532
- def fused_output_quant_supported(self, quant_key: QuantKey):
533
- if self.use_triton_flash_attn:
534
- return quant_key == kFp8StaticTensorSym
535
-
536
- # Only supported in the Triton backend
537
- return False
538
-
539
- def forward(
540
- self,
541
- layer: AttentionLayer,
542
- query: torch.Tensor,
543
- key: torch.Tensor,
544
- value: torch.Tensor,
545
- kv_cache: torch.Tensor,
546
- attn_metadata: ROCmFlashAttentionMetadata,
547
- output: Optional[torch.Tensor] = None,
548
- output_scale: Optional[torch.Tensor] = None,
549
- output_block_scale: Optional[torch.Tensor] = None,
550
- ) -> torch.Tensor:
551
- """Forward pass with FlashAttention and PagedAttention.
552
-
553
- For decoder-only models: query, key and value must be non-None.
554
-
555
- For encoder/decoder models:
556
- * ROCmFlashAttentionImpl.forward() may be invoked for both self- and
557
- cross-attention layers.
558
- * For self-attention: query, key and value must be non-None.
559
- * For cross-attention:
560
- * Query must be non-None
561
- * During prefill, key and value must be non-None; key and value
562
- get cached for use during decode.
563
- * During decode, key and value may be None, since:
564
- (1) key and value tensors were cached during prefill, and
565
- (2) cross-attention key and value tensors do not grow during
566
- decode
567
-
568
- A note on how the attn_type (attention type enum) argument impacts
569
- attention forward() behavior:
570
-
571
- * DECODER: normal decoder-only behavior;
572
- use decoder self-attention block table
573
- * ENCODER: no KV caching; pass encoder sequence
574
- attributes (encoder_seq_lens/encoder_seq_lens_tensor/
575
- max_encoder_seq_len) to kernel, in lieu of decoder
576
- sequence attributes (seq_lens/seq_lens_tensor/max_seq_len)
577
- * ENCODER_DECODER: cross-attention behavior;
578
- use cross-attention block table for caching KVs derived
579
- from encoder hidden states; since KV sequence lengths
580
- will match encoder sequence lengths, pass encoder sequence
581
- attributes to kernel (encoder_seq_lens/encoder_seq_lens_tensor/
582
- max_encoder_seq_len)
583
- * ENCODER_ONLY: bidirectional attention with no KV caching;
584
- use prefill sequence attributes
585
-
586
- Args:
587
- layer: Attention layer instance.
588
- query: shape = [num_tokens, num_heads * head_size]
589
- key: shape = [num_tokens, num_kv_heads * head_size]
590
- value: shape = [num_tokens, num_kv_heads * head_size]
591
- kv_cache: KV cache tensor with shape
592
- [2, num_blocks, block_size * num_kv_heads * head_size].
593
- NOTE: kv_cache will be an empty tensor with shape [0]
594
- for profiling run.
595
- attn_metadata: Metadata for attention.
596
- output: Optional output tensor.
597
- output_scale: Optional output scale tensor.
598
- output_block_scale: Optional output block scale tensor.
599
- Returns:
600
- shape = [num_tokens, num_heads * head_size]
601
- """
602
- assert output is not None, "Output tensor must be provided."
603
-
604
- if output_scale is not None and not self.use_triton_flash_attn:
605
- raise NotImplementedError(
606
- "fused output quantization only supported for Triton"
607
- " implementation in ROCMFlashAttentionImpl for now")
608
-
609
- if output_block_scale is not None:
610
- raise NotImplementedError(
611
- "fused nvfp4 output quantization is not supported"
612
- " for ROCMFlashAttentionImpl")
613
-
614
- query = query.view(-1, self.num_heads, self.head_size)
615
- if key is not None:
616
- assert value is not None
617
- key = key.view(-1, self.num_kv_heads, self.head_size)
618
- value = value.view(-1, self.num_kv_heads, self.head_size)
619
- else:
620
- assert value is None
621
-
622
- paged_attn = self.paged_attn_module
623
-
624
- # Reshaping kv tensors is required for AITER paged attention kernel
625
- # because it works on a different tensor shape,
626
- # when the size of one element is one byte (int8/fp8 dtypes).
627
- # This reshaping is only required on the first forward call
628
- # and the kv cache must not be empty.
629
- if (is_rocm_aiter_paged_attn_enabled() and kv_cache.dtype.itemsize == 1
630
- and not self.aiter_kv_scales_initialized
631
- and kv_cache.shape != torch.Size([0])):
632
- num_blocks = kv_cache.shape[1]
633
- block_size = kv_cache.shape[2] // (self.num_kv_heads *
634
- self.head_size)
635
- k_scale = torch.empty((self.num_kv_heads, num_blocks * block_size),
636
- dtype=torch.float32,
637
- device=kv_cache.device)
638
- v_scale = torch.empty((self.num_kv_heads, num_blocks * block_size),
639
- dtype=torch.float32,
640
- device=kv_cache.device)
641
- self.aiter_kv_scales_initialized = True
642
- k_scale.fill_(layer._k_scale.item())
643
- v_scale.fill_(layer._v_scale.item())
644
- layer._k_scale = k_scale
645
- layer._v_scale = v_scale
646
-
647
- # Only update KV cache for decoder self-attention
648
- # and encoder-decoder cross-attention
649
- if self.attn_type not in [
650
- AttentionType.ENCODER, AttentionType.ENCODER_ONLY
651
- ] and kv_cache.numel() > 0:
652
- key_cache, value_cache = paged_attn.split_kv_cache(
653
- kv_cache, self.num_kv_heads, self.head_size)
654
-
655
- if key is not None and value is not None:
656
- # Reshape the input keys and values and store them in the
657
- # cache. If kv_cache is not provided, the new key and value
658
- # tensors are not cached. This happens during the initial
659
- # memory profiling run.
660
- paged_attn.write_to_paged_cache(
661
- key,
662
- value,
663
- key_cache,
664
- value_cache,
665
- attn_metadata.slot_mapping
666
- if self.attn_type != AttentionType.ENCODER_DECODER else
667
- attn_metadata.cross_slot_mapping,
668
- self.kv_cache_dtype,
669
- layer._k_scale,
670
- layer._v_scale,
671
- )
672
-
673
- if self.attn_type != AttentionType.ENCODER:
674
- num_prefill_tokens = attn_metadata.num_prefill_tokens
675
- elif self.attn_type == AttentionType.ENCODER_ONLY:
676
- # For encoder-only models, all tokens are processed in one go
677
- num_prefill_tokens = query.shape[0]
678
- else:
679
- assert attn_metadata.num_encoder_tokens is not None
680
- num_prefill_tokens = attn_metadata.num_encoder_tokens
681
-
682
- # Query for decode. KV is not needed because it is already cached.
683
- decode_query = query[num_prefill_tokens:]
684
- # QKV for prefill.
685
- query = query[:num_prefill_tokens]
686
-
687
- # For encoder-only and encoder models,
688
- # we process all tokens at once
689
- # For decoder and encoder-decoder,
690
- # we may need to limit key/value to prefill tokens
691
- if key is not None and value is not None \
692
- and self.attn_type not in [AttentionType.ENCODER_DECODER,
693
- AttentionType.ENCODER_ONLY]:
694
- key = key[:num_prefill_tokens]
695
- value = value[:num_prefill_tokens]
696
-
697
- if prefill_meta := attn_metadata.prefill_metadata:
698
- # Prompt run.
699
- # normal attention and DECODER
700
- if self.attn_type == AttentionType.DECODER and (
701
- kv_cache.numel() == 0 or prefill_meta.block_tables is None
702
- or prefill_meta.block_tables.numel() == 0):
703
- (query_seq_start_loc, query_max_seq_len, key_seq_start_loc,
704
- key_max_seq_len, seq_lens,
705
- causal_mask) = (prefill_meta.seq_start_loc,
706
- prefill_meta.max_prefill_seq_len,
707
- prefill_meta.seq_start_loc,
708
- prefill_meta.max_prefill_seq_len,
709
- attn_metadata.seq_lens, True)
710
- # prefix-enabled attention and ENCODER/ENCODER_DECODER
711
- else:
712
- (query_seq_start_loc, query_max_seq_len, key_seq_start_loc,
713
- key_max_seq_len, seq_lens,
714
- causal_mask) = _get_seq_len_block_table_args(
715
- prefill_meta, self.attn_type)
716
- # Prompt run.
717
- if kv_cache.numel() == 0 or prefill_meta.block_tables.numel() == 0:
718
- # triton attention
719
- # When block_tables are not filled, it means q and k are the
720
- # prompt, and they have the same length.
721
- attn_masks = None
722
- if self.use_triton_flash_attn:
723
- if self.alibi_slopes is not None:
724
- attn_masks = _make_alibi_bias(
725
- self.alibi_slopes,
726
- query.dtype,
727
- seq_lens,
728
- make_attn_mask=causal_mask) # type: ignore
729
-
730
- use_fp8_scales = (layer._q_scale and layer._k_scale
731
- and layer._v_scale and layer._prob_scale
732
- and (self.kv_cache_dtype == "fp8"
733
- or self.force_fp8_attention))
734
-
735
- full_scales = (
736
- layer._q_scale.item(), layer._k_scale.item(),
737
- layer._v_scale.item(),
738
- layer._prob_scale.item()) if use_fp8_scales else None
739
- self.triton_attn_func(
740
- query,
741
- key,
742
- value,
743
- output[:num_prefill_tokens],
744
- query_seq_start_loc,
745
- key_seq_start_loc,
746
- query_max_seq_len,
747
- key_max_seq_len,
748
- causal_mask,
749
- self.scale,
750
- attn_masks[0][None]
751
- if attn_masks is not None else None,
752
- full_scales,
753
- output_scale,
754
- )
755
- elif self.use_naive_attn:
756
- if self.num_kv_heads != self.num_heads:
757
- # Interleave for MQA workaround.
758
- key = self.repeat_kv(key, self.num_queries_per_kv)
759
- value = self.repeat_kv(value, self.num_queries_per_kv)
760
- if self.alibi_slopes is not None:
761
- attn_masks = _make_alibi_bias(
762
- self.alibi_slopes,
763
- query.dtype,
764
- attn_metadata.seq_lens,
765
- make_attn_mask=causal_mask) # type: ignore
766
- query = query.movedim(0, query.dim() - 2)
767
- key = key.movedim(0, key.dim() - 2)
768
- value = value.movedim(0, value.dim() - 2)
769
- # sdpa math backend attention
770
- self.sdpa_attn_func(
771
- query,
772
- key,
773
- value,
774
- output[:num_prefill_tokens],
775
- query_seq_start_loc,
776
- num_prefill_tokens,
777
- self.num_heads,
778
- self.head_size,
779
- self.scale,
780
- attn_masks,
781
- )
782
- else:
783
- # upstream FA does not support an output arg, copy
784
- output[:num_prefill_tokens] = self.fa_attn_func(
785
- q=query,
786
- k=key,
787
- v=value,
788
- cu_seqlens_q=query_seq_start_loc,
789
- cu_seqlens_k=key_seq_start_loc,
790
- max_seqlen_q=prefill_meta.max_prefill_seq_len,
791
- max_seqlen_k=key_max_seq_len,
792
- softmax_scale=self.scale,
793
- causal=causal_mask,
794
- window_size=self.sliding_window,
795
- alibi_slopes=self.alibi_slopes,
796
- softcap=self.logits_soft_cap,
797
- )
798
-
799
- else:
800
- # prefix-enabled attention -
801
- # not applicable for encoder-only models
802
- if self.attn_type != AttentionType.ENCODER_ONLY:
803
- output[:num_prefill_tokens] = paged_attn.forward_prefix(
804
- query,
805
- key,
806
- value,
807
- self.kv_cache_dtype,
808
- key_cache,
809
- value_cache,
810
- prefill_meta.block_tables,
811
- prefill_meta.query_start_loc,
812
- prefill_meta.seq_lens_tensor,
813
- prefill_meta.max_query_len,
814
- self.alibi_slopes,
815
- self.sliding_window[0],
816
- layer._k_scale,
817
- layer._v_scale,
818
- )
819
- # Skip decode phase for encoder-only models
820
- if (decode_meta := attn_metadata.decode_metadata) and (
821
- self.attn_type != AttentionType.ENCODER_ONLY):
822
- # Decoding run.
823
- # Whether to use rocm custom paged attention or not
824
- num_seqs, num_heads, head_size = decode_query.shape
825
- block_size = value_cache.shape[3]
826
- gqa_ratio = num_heads // self.num_kv_heads
827
- from vllm.platforms.rocm import use_rocm_custom_paged_attention
828
- use_custom = use_rocm_custom_paged_attention(
829
- decode_query.dtype, head_size, block_size, gqa_ratio,
830
- decode_meta.max_decode_seq_len, self.sliding_window,
831
- self.kv_cache_dtype, self.alibi_slopes)
832
-
833
- if use_custom:
834
- max_seq_len = (decode_meta.max_decode_seq_len if self.attn_type
835
- != AttentionType.ENCODER_DECODER else
836
- decode_meta.max_encoder_seq_len)
837
- assert max_seq_len is not None
838
- max_num_partitions = (
839
- (max_seq_len + _PARTITION_SIZE_ROCM - 1) //
840
- _PARTITION_SIZE_ROCM)
841
- assert _PARTITION_SIZE_ROCM % block_size == 0
842
- tmp_output = torch.empty(
843
- size=(num_seqs, num_heads, max_num_partitions, head_size),
844
- dtype=query.dtype,
845
- device=output.device,
846
- )
847
- exp_sums = torch.empty(
848
- size=(num_seqs, num_heads, max_num_partitions),
849
- dtype=torch.float32,
850
- device=output.device,
851
- )
852
- max_logits = torch.empty_like(exp_sums)
853
-
854
- query_start_loc = None
855
- ops.paged_attention_rocm(
856
- output[num_prefill_tokens:],
857
- exp_sums,
858
- max_logits,
859
- tmp_output,
860
- decode_query,
861
- key_cache,
862
- value_cache,
863
- self.num_kv_heads,
864
- self.scale,
865
- decode_meta.block_tables
866
- if self.attn_type != AttentionType.ENCODER_DECODER else
867
- decode_meta.cross_block_tables,
868
- decode_meta.seq_lens_tensor
869
- if self.attn_type != AttentionType.ENCODER_DECODER else
870
- decode_meta.encoder_seq_lens_tensor,
871
- query_start_loc,
872
- block_size,
873
- max_seq_len,
874
- self.alibi_slopes,
875
- self.kv_cache_dtype,
876
- layer._k_scale,
877
- layer._v_scale,
878
- output_scale,
879
- )
880
- else:
881
- # PagedAttention does not support fused quant, manually quantize
882
- if output_scale is None:
883
- out_pa = output[num_prefill_tokens:]
884
- else:
885
- out_pa = torch.empty_like(output[num_prefill_tokens:],
886
- dtype=query.dtype)
887
-
888
- out_pa[:] = paged_attn.forward_decode(
889
- decode_query,
890
- key_cache,
891
- value_cache,
892
- decode_meta.block_tables
893
- if self.attn_type != AttentionType.ENCODER_DECODER else
894
- decode_meta.cross_block_tables,
895
- decode_meta.seq_lens_tensor
896
- if self.attn_type != AttentionType.ENCODER_DECODER else
897
- decode_meta.encoder_seq_lens_tensor,
898
- decode_meta.max_decode_seq_len
899
- if self.attn_type != AttentionType.ENCODER_DECODER else
900
- decode_meta.max_encoder_seq_len,
901
- self.kv_cache_dtype,
902
- self.num_kv_heads,
903
- self.scale,
904
- self.alibi_slopes,
905
- layer._k_scale,
906
- layer._v_scale,
907
- )
908
-
909
- # Manually perform quantization
910
- if output_scale is not None:
911
- out_uq = out_pa.view(-1, self.num_heads * self.head_size)
912
- out_q = output.view(-1, self.num_heads * self.head_size)
913
- ops.scaled_fp8_quant(out_uq,
914
- output_scale,
915
- output=out_q[num_prefill_tokens:])
916
-
917
- # Reshape the output tensor.
918
- return output.view(-1, self.num_heads * self.head_size)
919
-
920
-
921
-def _sdpa_attention(
922
- query: torch.Tensor,
923
- key: torch.Tensor,
924
- value: torch.Tensor,
925
- output: torch.Tensor,
926
- seq_lens: torch.Tensor,
927
- num_tokens: int,
928
- num_heads: int,
929
- head_size: int,
930
- scale: float,
931
- attn_masks: Optional[List[torch.Tensor]] = None,
932
-) -> torch.Tensor:
933
- start = 0
934
- assert output.shape == (num_tokens, num_heads, head_size)
935
- assert output.dtype == query.dtype
936
- assert output.device == query.device
937
-
938
- for i, seq_len in enumerate(seq_lens):
939
- end = start + seq_len
940
- with torch.nn.attention.sdpa_kernel(
941
- torch.nn.attention.SDPBackend.MATH):
942
- sub_out = torch.nn.functional.scaled_dot_product_attention(
943
- query[:, start:end, :],
944
- key[:, start:end, :],
945
- value[:, start:end, :],
946
- dropout_p=0.0,
947
- is_causal=attn_masks is None,
948
- attn_mask=attn_masks[i] if attn_masks else None,
949
- scale=scale).movedim(query.dim() - 2, 0)
950
- output[start:end, :, :] = sub_out
951
- start = end
952
-
953
- return output
vllm/attention/backends/triton_mla.py
deleted
-111
@@ -1,111 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-
4
-from typing import List, Optional, Type
5
-
6
-import torch
7
-
8
-from vllm.attention.backends.abstract import (AttentionType,
9
- is_quantized_kv_cache)
10
-from vllm.attention.backends.mla.common import (MLACommonBackend,
11
- MLACommonImpl,
12
- MLACommonMetadata)
13
-from vllm.attention.ops.triton_decode_attention import decode_attention_fwd
14
-
15
-
16
-class TritonMLABackend(MLACommonBackend):
17
-
18
- @staticmethod
19
- def get_name() -> str:
20
- return "TRITON_MLA"
21
-
22
- @staticmethod
23
- def get_impl_cls() -> Type["TritonMLAImpl"]:
24
- return TritonMLAImpl
25
-
26
-
27
-class TritonMLAImpl(MLACommonImpl[MLACommonMetadata]):
28
-
29
- def __init__(
30
- self,
31
- num_heads: int,
32
- head_size: int,
33
- scale: float,
34
- num_kv_heads: int,
35
- alibi_slopes: Optional[List[float]],
36
- sliding_window: Optional[int],
37
- kv_cache_dtype: str,
38
- logits_soft_cap: Optional[float],
39
- attn_type: str,
40
- kv_sharing_target_layer_name: Optional[str],
41
- # MLA Specific Arguments
42
- **mla_args) -> None:
43
- super().__init__(num_heads, head_size, scale, num_kv_heads,
44
- alibi_slopes, sliding_window, kv_cache_dtype,
45
- logits_soft_cap, attn_type,
46
- kv_sharing_target_layer_name, **mla_args)
47
-
48
- unsupported_features = [alibi_slopes, sliding_window, logits_soft_cap]
49
- if any(unsupported_features):
50
- raise NotImplementedError(
51
- "TritonMLAImpl does not support one of the following: "
52
- "alibi_slopes, sliding_window, logits_soft_cap")
53
-
54
- if attn_type != AttentionType.DECODER:
55
- raise NotImplementedError("Encoder self-attention and "
56
- "encoder/decoder cross-attention "
57
- "are not implemented for "
58
- "TritonMLAImpl")
59
-
60
- if is_quantized_kv_cache(self.kv_cache_dtype):
61
- raise NotImplementedError(
62
- "TritonMLA with FP8 KV cache not yet supported")
63
-
64
- def _forward_decode(
65
- self,
66
- q_nope: torch.Tensor,
67
- q_pe: torch.Tensor,
68
- kv_c_and_k_pe_cache: torch.Tensor,
69
- attn_metadata: MLACommonMetadata,
70
- ) -> torch.Tensor:
71
- assert kv_c_and_k_pe_cache.numel() > 0
72
-
73
- decode_meta = attn_metadata.decode_metadata
74
- assert decode_meta is not None
75
- B = q_nope.shape[0]
76
-
77
- q = torch.cat([q_nope, q_pe], dim=-1)
78
- o = torch.zeros(B,
79
- self.num_heads,
80
- self.kv_lora_rank,
81
- dtype=q.dtype,
82
- device=q.device)
83
-
84
- num_kv_splits = 4 # TODO: heuristic
85
-
86
- # TODO(lucas) Allocate ahead of time
87
- attn_logits = torch.empty(
88
- (
89
- B,
90
- self.num_heads,
91
- num_kv_splits,
92
- # NOTE(lucas) idk why the +1 is here but sglang has it so we
93
- # just mirror that
94
- self.kv_lora_rank + 1,
95
- ),
96
- dtype=torch.float32,
97
- device=q.device,
98
- )
99
-
100
- # Add a head dim of 1
101
- kv_c_and_k_pe_cache = kv_c_and_k_pe_cache.unsqueeze(2)
102
- kv_c_cache = kv_c_and_k_pe_cache[..., :self.kv_lora_rank]
103
- PAGE_SIZE = kv_c_and_k_pe_cache.size(1)
104
-
105
- # Run MQA
106
- decode_attention_fwd(q, kv_c_and_k_pe_cache, kv_c_cache, o,
107
- decode_meta.block_tables,
108
- decode_meta.seq_lens_tensor, attn_logits,
109
- num_kv_splits, self.scale, PAGE_SIZE)
110
-
111
- return self._v_up_proj(o)
vllm/attention/backends/utils.py
+6
-8
@@ -338,10 +338,9 @@ class CommonAttentionState(AttentionState):
338
# The encoder decoder model works only with XFormers and
339
# Flash Attention backend. Assert the same.
340
assert self.runner.attn_backend.get_name() in \
341
- ["XFORMERS", "FLASH_ATTN", "ROCM_FLASH"], \
342
- f"Expected attn_backend name to be either 'XFORMERS'," \
343
- f"'ROCM_FLASH', or 'FLASH_ATTN', but " \
344
- f"got '{self.runner.attn_backend.get_name()}'"
341
+ ["XFORMERS", "FLASH_ATTN"], \
342
+ f"Expected attn_backend name to be either 'XFORMERS' or " \
343
+ f"'FLASH_ATTN', but got '{self.runner.attn_backend.get_name()}'"
344
self._update_captured_metadata_for_enc_dec_model(
345
batch_size=batch_size, attn_metadata=attn_metadata)
346
@@ -360,10 +359,9 @@ class CommonAttentionState(AttentionState):
359
# The encoder decoder model works only with XFormers and
360
# Flash Attention backend. Assert the same.
361
assert self.runner.attn_backend.get_name() in \
363
- ["XFORMERS", "FLASH_ATTN", "ROCM_FLASH"], \
364
- f"Expected attn_backend name to be either 'XFORMERS'," \
365
- f"'ROCM_FLASH', or 'FLASH_ATTN', but " \
366
- f"got '{self.runner.attn_backend.get_name()}'"
362
+ ["XFORMERS", "FLASH_ATTN"], \
363
+ f"Expected attn_backend name to be either 'XFORMERS' or " \
364
+ f"'FLASH_ATTN', but got '{self.runner.attn_backend.get_name()}'"
365
self._add_additional_input_buffers_for_enc_dec_model(
366
attn_metadata=attn_metadata, input_buffers=input_buffers)
367
return input_buffers
vllm/attention/backends/xformers.py
deleted
-805
@@ -1,805 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-"""Attention layer with xFormers and PagedAttention."""
4
-from dataclasses import dataclass
5
-from typing import Dict, List, Optional, Tuple, Type
6
-
7
-import torch
8
-from xformers import ops as xops
9
-from xformers.ops.fmha.attn_bias import (AttentionBias,
10
- BlockDiagonalCausalMask,
11
- BlockDiagonalMask,
12
- LowerTriangularMaskWithTensorBias)
13
-
14
-from vllm.attention.backends.abstract import (AttentionBackend, AttentionImpl,
15
- AttentionLayer,
16
- AttentionMetadata, AttentionType)
17
-from vllm.attention.backends.utils import (
18
- CommonAttentionState, CommonMetadataBuilder,
19
- get_num_prefill_decode_query_kv_tokens, get_seq_len_block_table_args,
20
- is_all_cross_attn_metadata_set, is_all_encoder_attn_metadata_set)
21
-from vllm.attention.ops.paged_attn import (PagedAttention,
22
- PagedAttentionMetadata)
23
-from vllm.logger import init_logger
24
-
25
-logger = init_logger(__name__)
26
-
27
-
28
-class XFormersBackend(AttentionBackend):
29
-
30
- @staticmethod
31
- def get_name() -> str:
32
- return "XFORMERS"
33
-
34
- @staticmethod
35
- def get_impl_cls() -> Type["XFormersImpl"]:
36
- return XFormersImpl
37
-
38
- @staticmethod
39
- def get_metadata_cls() -> Type["AttentionMetadata"]:
40
- return XFormersMetadata
41
-
42
- @staticmethod
43
- def get_builder_cls() -> Type["XFormersMetadataBuilder"]:
44
- return XFormersMetadataBuilder
45
-
46
- @staticmethod
47
- def get_state_cls() -> Type["CommonAttentionState"]:
48
- return CommonAttentionState
49
-
50
- @staticmethod
51
- def get_kv_cache_shape(
52
- num_blocks: int,
53
- block_size: int,
54
- num_kv_heads: int,
55
- head_size: int,
56
- ) -> Tuple[int, ...]:
57
- return PagedAttention.get_kv_cache_shape(num_blocks, block_size,
58
- num_kv_heads, head_size)
59
-
60
- @staticmethod
61
- def swap_blocks(
62
- src_kv_cache: torch.Tensor,
63
- dst_kv_cache: torch.Tensor,
64
- src_to_dst: Dict[int, int],
65
- ) -> None:
66
- PagedAttention.swap_blocks(src_kv_cache, dst_kv_cache, src_to_dst)
67
-
68
- @staticmethod
69
- def copy_blocks(
70
- kv_caches: List[torch.Tensor],
71
- src_to_dists: torch.Tensor,
72
- ) -> None:
73
- PagedAttention.copy_blocks(kv_caches, src_to_dists)
74
-
75
-
76
-@dataclass
77
-class XFormersMetadata(AttentionMetadata, PagedAttentionMetadata):
78
- """Metadata for XFormersbackend.
79
-
80
- NOTE: Any python object stored here is not updated when it is
81
- cuda-graph replayed. If you have values that need to be changed
82
- dynamically, it should be stored in tensor. The tensor has to be
83
- updated from `CUDAGraphRunner.forward` API.
84
- """
85
-
86
- # |---------- N-1 iteration --------|
87
- # |---------------- N iteration ---------------------|
88
- # |- tokenA -|......................|-- newTokens ---|
89
- # |---------- context_len ----------|
90
- # |-------------------- seq_len ----------------------|
91
- # |-- query_len ---|
92
-
93
- # seq_lens stored as a tensor.
94
- seq_lens_tensor: Optional[torch.Tensor]
95
-
96
- # FIXME: It is for flash attn.
97
- # Maximum sequence length among prefill batch. 0 if there are decoding
98
- # requests only.
99
- max_prefill_seq_len: int
100
- # Maximum sequence length among decode batch. 0 if there are prefill
101
- # requests only.
102
- max_decode_seq_len: int
103
-
104
- # Whether or not if cuda graph is enabled.
105
- # Cuda-graph is currently enabled for decoding only.
106
- # TODO(woosuk): Move `use_cuda_graph` out since it's unrelated to attention.
107
- use_cuda_graph: bool
108
-
109
- # (batch_size,). The sequence length per sequence. Sequence length means
110
- # the computed tokens + new tokens None if it is a decoding.
111
- seq_lens: Optional[List[int]] = None
112
-
113
- # FIXME: It is for flash attn.
114
- # (batch_size + 1,). The cumulative sequence lengths of the sequences in
115
- # the batch, used to index into sequence. E.g., if the sequence length is
116
- # [4, 6], it is [0, 4, 10].
117
- seq_start_loc: Optional[torch.Tensor] = None
118
-
119
- # (batch_size,) A tensor of context lengths (tokens that are computed
120
- # so far).
121
- context_lens_tensor: Optional[torch.Tensor] = None
122
-
123
- # Maximum query length in the batch. None for decoding.
124
- max_query_len: Optional[int] = None
125
-
126
- # Max number of query tokens among request in the batch.
127
- max_decode_query_len: Optional[int] = None
128
-
129
- # (batch_size + 1,). The cumulative subquery lengths of the sequences in
130
- # the batch, used to index into subquery. E.g., if the subquery length
131
- # is [4, 6], it is [0, 4, 10].
132
- query_start_loc: Optional[torch.Tensor] = None
133
-
134
- # Self-attention prefill/decode metadata cache
135
- _cached_prefill_metadata: Optional["XFormersMetadata"] = None
136
- _cached_decode_metadata: Optional["XFormersMetadata"] = None
137
-
138
- # Begin encoder attn & enc/dec cross-attn fields...
139
-
140
- # Encoder sequence lengths representation
141
- encoder_seq_lens: Optional[List[int]] = None
142
- encoder_seq_lens_tensor: Optional[torch.Tensor] = None
143
- # FIXME: It is for flash attn.
144
- # (batch_size + 1,). The cumulative sequence lengths of the sequences in
145
- # the batch, used to index into sequence. E.g., if the sequence length is
146
- # [4, 6], it is [0, 4, 10].
147
- encoder_seq_start_loc: Optional[torch.Tensor] = None
148
-
149
- # Maximum sequence length among encoder sequences
150
- max_encoder_seq_len: Optional[int] = None
151
-
152
- # Number of tokens input to encoder
153
- num_encoder_tokens: Optional[int] = None
154
-
155
- # Cross-attention memory-mapping data structures: slot mapping
156
- # and block tables
157
- cross_slot_mapping: Optional[torch.Tensor] = None
158
- cross_block_tables: Optional[torch.Tensor] = None
159
-
160
- def __post_init__(self):
161
- # Set during the execution of the first attention op.
162
- # It is a list because it is needed to set per prompt
163
- # when alibi slopes is used. It is because of the limitation
164
- # from xformer API.
165
- # will not appear in the __repr__ and __init__
166
- self.attn_bias: Optional[List[AttentionBias]] = None
167
- self.encoder_attn_bias: Optional[List[AttentionBias]] = None
168
- self.cross_attn_bias: Optional[List[AttentionBias]] = None
169
-
170
- @property
171
- def is_all_encoder_attn_metadata_set(self):
172
- '''
173
- All attention metadata required for encoder attention is set.
174
- '''
175
- return is_all_encoder_attn_metadata_set(self)
176
-
177
- @property
178
- def is_all_cross_attn_metadata_set(self):
179
- '''
180
- All attention metadata required for enc/dec cross-attention is set.
181
-
182
- Superset of encoder attention required metadata.
183
- '''
184
- return is_all_cross_attn_metadata_set(self)
185
-
186
- @property
187
- def prefill_metadata(self) -> Optional["XFormersMetadata"]:
188
- if self.num_prefills == 0:
189
- return None
190
-
191
- if self._cached_prefill_metadata is not None:
192
- # Recover cached prefill-phase attention
193
- # metadata structure
194
- return self._cached_prefill_metadata
195
-
196
- assert ((self.seq_lens is not None)
197
- or (self.encoder_seq_lens is not None))
198
- assert ((self.seq_lens_tensor is not None)
199
- or (self.encoder_seq_lens_tensor is not None))
200
-
201
- # Compute some attn_metadata fields which default to None
202
- query_start_loc = (None if self.query_start_loc is None else
203
- self.query_start_loc[:self.num_prefills + 1])
204
- seq_start_loc = (None if self.seq_start_loc is None else
205
- self.seq_start_loc[:self.num_prefills + 1])
206
- slot_mapping = (None if self.slot_mapping is None else
207
- self.slot_mapping[:self.num_prefill_tokens])
208
- seq_lens = (None if self.seq_lens is None else
209
- self.seq_lens[:self.num_prefills])
210
- seq_lens_tensor = (None if self.seq_lens_tensor is None else
211
- self.seq_lens_tensor[:self.num_prefills])
212
- context_lens_tensor = (None if self.context_lens_tensor is None else
213
- self.context_lens_tensor[:self.num_prefills])
214
- block_tables = (None if self.block_tables is None else
215
- self.block_tables[:self.num_prefills])
216
-
217
- # Construct & cache prefill-phase attention metadata structure
218
- self._cached_prefill_metadata = XFormersMetadata(
219
- num_prefills=self.num_prefills,
220
- num_prefill_tokens=self.num_prefill_tokens,
221
- num_decode_tokens=0,
222
- slot_mapping=slot_mapping,
223
- multi_modal_placeholder_index_maps=self.
224
- multi_modal_placeholder_index_maps,
225
- enable_kv_scales_calculation=self.enable_kv_scales_calculation,
226
- seq_lens=seq_lens,
227
- seq_lens_tensor=seq_lens_tensor,
228
- max_query_len=self.max_query_len,
229
- max_prefill_seq_len=self.max_prefill_seq_len,
230
- max_decode_seq_len=0,
231
- query_start_loc=query_start_loc,
232
- seq_start_loc=seq_start_loc,
233
- context_lens_tensor=context_lens_tensor,
234
- block_tables=block_tables,
235
- use_cuda_graph=False,
236
- # Begin encoder & cross attn fields below...
237
- encoder_seq_lens=self.encoder_seq_lens,
238
- encoder_seq_lens_tensor=self.encoder_seq_lens_tensor,
239
- max_encoder_seq_len=self.max_encoder_seq_len,
240
- cross_slot_mapping=self.cross_slot_mapping,
241
- cross_block_tables=self.cross_block_tables)
242
- return self._cached_prefill_metadata
243
-
244
- @property
245
- def decode_metadata(self) -> Optional["XFormersMetadata"]:
246
- if self.num_decode_tokens == 0:
247
- return None
248
-
249
- if self._cached_decode_metadata is not None:
250
- # Recover cached decode-phase attention
251
- # metadata structure
252
- return self._cached_decode_metadata
253
- assert ((self.seq_lens_tensor is not None)
254
- or (self.encoder_seq_lens_tensor is not None))
255
-
256
- # Compute some attn_metadata fields which default to None
257
- slot_mapping = (None if self.slot_mapping is None else
258
- self.slot_mapping[self.num_prefill_tokens:])
259
- seq_lens_tensor = (None if self.seq_lens_tensor is None else
260
- self.seq_lens_tensor[self.num_prefills:])
261
- block_tables = (None if self.block_tables is None else
262
- self.block_tables[self.num_prefills:])
263
-
264
- # Construct & cache decode-phase attention metadata structure
265
- self._cached_decode_metadata = XFormersMetadata(
266
- num_prefills=0,
267
- num_prefill_tokens=0,
268
- num_decode_tokens=self.num_decode_tokens,
269
- slot_mapping=slot_mapping,
270
- multi_modal_placeholder_index_maps=None,
271
- enable_kv_scales_calculation=True,
272
- seq_lens_tensor=seq_lens_tensor,
273
- max_prefill_seq_len=0,
274
- max_decode_seq_len=self.max_decode_seq_len,
275
- block_tables=block_tables,
276
- use_cuda_graph=self.use_cuda_graph,
277
- # Begin encoder & cross attn fields below...
278
- encoder_seq_lens=self.encoder_seq_lens,
279
- encoder_seq_lens_tensor=self.encoder_seq_lens_tensor,
280
- max_encoder_seq_len=self.max_encoder_seq_len,
281
- cross_slot_mapping=self.cross_slot_mapping,
282
- cross_block_tables=self.cross_block_tables)
283
-
284
- # Batch may be composed of prefill|decodes, adjust query start indices
285
- # to refer to the start of decodes when the two are split apart.
286
- # E.g. in tokens:[3 prefills|6 decodes], query_start_loc=[3,9] => [0,6].
287
- if self._cached_decode_metadata.query_start_loc is not None:
288
- qs = self._cached_decode_metadata.query_start_loc
289
- self._cached_decode_metadata.query_start_loc = qs - qs[0]
290
- return self._cached_decode_metadata
291
-
292
-
293
-def _get_attn_bias(
294
- attn_metadata: XFormersMetadata,
295
- attn_type: str,
296
-) -> Optional[AttentionBias]:
297
- '''
298
- Extract appropriate attention bias from attention metadata
299
- according to attention type.
300
-
301
- Arguments:
302
-
303
- * attn_metadata: Attention metadata structure associated with attention
304
- * attn_type: encoder attention, decoder self-attention,
305
- encoder/decoder cross-attention
306
-
307
- Returns:
308
- * Appropriate attention bias value given the attention type
309
- '''
310
-
311
- if (attn_type == AttentionType.DECODER
312
- or attn_type == AttentionType.ENCODER_ONLY):
313
- return attn_metadata.attn_bias
314
- elif attn_type == AttentionType.ENCODER:
315
- return attn_metadata.encoder_attn_bias
316
- elif attn_type == AttentionType.ENCODER_DECODER:
317
- return attn_metadata.cross_attn_bias
318
- else:
319
- raise AttributeError(f"Invalid attention type {str(attn_type)}")
320
-
321
-
322
-def _set_attn_bias(
323
- attn_metadata: XFormersMetadata,
324
- attn_bias: List[Optional[AttentionBias]],
325
- attn_type: str,
326
-) -> None:
327
- '''
328
- Update appropriate attention bias field of attention metadata,
329
- according to attention type.
330
-
331
- Arguments:
332
-
333
- * attn_metadata: Attention metadata structure associated with attention
334
- * attn_bias: The desired attention bias value
335
- * attn_type: encoder attention, decoder self-attention,
336
- encoder/decoder cross-attention
337
- '''
338
-
339
- if (attn_type == AttentionType.DECODER
340
- or attn_type == AttentionType.ENCODER_ONLY):
341
- attn_metadata.attn_bias = attn_bias
342
- elif attn_type == AttentionType.ENCODER:
343
- attn_metadata.encoder_attn_bias = attn_bias
344
- elif attn_type == AttentionType.ENCODER_DECODER:
345
- attn_metadata.cross_attn_bias = attn_bias
346
- else:
347
- raise AttributeError(f"Invalid attention type {str(attn_type)}")
348
-
349
-
350
-class XFormersMetadataBuilder(CommonMetadataBuilder[XFormersMetadata]):
351
-
352
- _metadata_cls = XFormersMetadata
353
-
354
-
355
-class XFormersImpl(AttentionImpl[XFormersMetadata]):
356
- """
357
- If the input tensors contain prompt tokens, the layout is as follows:
358
- |<--------------- num_prefill_tokens ----------------->|
359
- |<--prefill_0-->|<--prefill_1-->|...|<--prefill_N-1--->|
360
-
361
- Otherwise, the layout is as follows:
362
- |<----------------- num_decode_tokens ------------------>|
363
- |<--decode_0-->|..........|<--decode_M-1-->|<--padding-->|
364
-
365
- Generation tokens can contain padding when cuda-graph is used.
366
- Currently, prompt tokens don't contain any padding.
367
-
368
- The prompts might have different lengths, while the generation tokens
369
- always have length 1.
370
-
371
- If chunked prefill is enabled, prefill tokens and decode tokens can be
372
- batched together in a flattened 1D query.
373
-
374
- |<----- num_prefill_tokens ---->|<------- num_decode_tokens --------->|
375
- |<-prefill_0->|...|<-prefill_N-1->|<--decode_0-->|...|<--decode_M-1-->|
376
-
377
- Currently, cuda graph is disabled for chunked prefill, meaning there's no
378
- padding between prefill and decode tokens.
379
- """
380
-
381
- def __init__(
382
- self,
383
- num_heads: int,
384
- head_size: int,
385
- scale: float,
386
- num_kv_heads: int,
387
- alibi_slopes: Optional[List[float]],
388
- sliding_window: Optional[int],
389
- kv_cache_dtype: str,
390
- logits_soft_cap: Optional[float] = None,
391
- attn_type: str = AttentionType.DECODER,
392
- kv_sharing_target_layer_name: Optional[str] = None,
393
- use_irope: bool = False,
394
- ) -> None:
395
- if kv_sharing_target_layer_name is not None:
396
- raise NotImplementedError("KV sharing is not supported in V0 "
397
- "XFORMERS backend.")
398
- if logits_soft_cap is not None:
399
- logger.warning_once("XFormers does not support logits soft cap. "
400
- "Outputs may be slightly off.")
401
- if use_irope:
402
- logger.warning_once(
403
- "Using irope in XFormers is not supported yet, it will fall"
404
- " back to global attention for long context.")
405
- self.num_heads = num_heads
406
- self.head_size = head_size
407
- self.scale = float(scale)
408
- self.num_kv_heads = num_kv_heads
409
- if alibi_slopes is not None:
410
- alibi_slopes = torch.tensor(alibi_slopes, dtype=torch.float32)
411
- self.alibi_slopes = alibi_slopes
412
- self.sliding_window = sliding_window
413
- self.kv_cache_dtype = kv_cache_dtype
414
-
415
- self.num_queries_per_kv = self.num_heads // self.num_kv_heads
416
-
417
- supported_head_sizes = PagedAttention.get_supported_head_sizes()
418
- if head_size not in supported_head_sizes:
419
- raise ValueError(
420
- f"Head size {head_size} is not supported by PagedAttention. "
421
- f"Supported head sizes are: {supported_head_sizes}.")
422
-
423
- self.attn_type = attn_type
424
-
425
- def forward(
426
- self,
427
- layer: AttentionLayer,
428
- query: torch.Tensor,
429
- key: Optional[torch.Tensor],
430
- value: Optional[torch.Tensor],
431
- kv_cache: torch.Tensor,
432
- attn_metadata: "XFormersMetadata",
433
- output: Optional[torch.Tensor] = None,
434
- output_scale: Optional[torch.Tensor] = None,
435
- output_block_scale: Optional[torch.Tensor] = None,
436
- ) -> torch.Tensor:
437
- """Forward pass with xFormers and PagedAttention.
438
-
439
- For decoder-only models: query, key and value must be non-None.
440
-
441
- For encoder/decoder models:
442
- * XFormersImpl.forward() may be invoked for both self- and cross-
443
- attention layers.
444
- * For self-attention: query, key and value must be non-None.
445
- * For cross-attention:
446
- * Query must be non-None
447
- * During prefill, key and value must be non-None; key and value
448
- get cached for use during decode.
449
- * During decode, key and value may be None, since:
450
- (1) key and value tensors were cached during prefill, and
451
- (2) cross-attention key and value tensors do not grow during
452
- decode
453
-
454
- A note on how the attn_type (attention type enum) argument impacts
455
- attention forward() behavior:
456
-
457
- * DECODER: normal decoder-only behavior;
458
- use decoder self-attention block table
459
- * ENCODER: no KV caching; pass encoder sequence
460
- attributes (encoder_seq_lens/encoder_seq_lens_tensor/
461
- max_encoder_seq_len) to kernel, in lieu of decoder
462
- sequence attributes (seq_lens/seq_lens_tensor/max_seq_len).
463
- Used for encoder branch of encoder-decoder models.
464
- * ENCODER_ONLY: no kv_caching, uses the normal attention
465
- attributes (seq_lens/seq_lens_tensor/max_seq_len).
466
- * ENCODER_DECODER: cross-attention behavior;
467
- use cross-attention block table for caching KVs derived
468
- from encoder hidden states; since KV sequence lengths
469
- will match encoder sequence lengths, pass encoder sequence
470
- attributes to kernel (encoder_seq_lens/encoder_seq_lens_tensor/
471
- max_encoder_seq_len)
472
-
473
- Args:
474
- layer: Attention layer instance.
475
- query: shape = [num_tokens, num_heads * head_size]
476
- key: shape = [num_tokens, num_kv_heads * head_size]
477
- value: shape = [num_tokens, num_kv_heads * head_size]
478
- kv_cache: KV cache tensor with shape
479
- [2, num_blocks, block_size * num_kv_heads * head_size].
480
- NOTE: kv_cache will be an empty tensor with shape [0]
481
- for profiling run.
482
- attn_metadata: Metadata for attention.
483
- output: Optional output tensor.
484
- output_scale: Optional output scale tensor.
485
- output_block_scale: Optional output block scale tensor.
486
- Returns:
487
- shape = [num_tokens, num_heads * head_size]
488
- """
489
- if output_scale is not None or output_block_scale is not None:
490
- raise NotImplementedError(
491
- "fused output quantization is not yet supported"
492
- " for XFormersImpl")
493
-
494
- attn_type = self.attn_type
495
- # Check that appropriate attention metadata attributes are
496
- # selected for the desired attention type
497
- if (attn_type == AttentionType.ENCODER
498
- and (not attn_metadata.is_all_encoder_attn_metadata_set)):
499
- raise AttributeError("Encoder attention requires setting "
500
- "encoder metadata attributes.")
501
-
502
- elif (attn_type == AttentionType.ENCODER_DECODER
503
- and (not attn_metadata.is_all_cross_attn_metadata_set)):
504
- raise AttributeError("Encoder/decoder cross-attention "
505
- "requires setting cross-attention "
506
- "metadata attributes.")
507
-
508
- query = query.view(-1, self.num_heads, self.head_size)
509
- if key is not None:
510
- assert value is not None
511
- key = key.view(-1, self.num_kv_heads, self.head_size)
512
- value = value.view(-1, self.num_kv_heads, self.head_size)
513
- else:
514
- assert value is None
515
-
516
- # Self-attention vs. cross-attention will impact
517
- # which KV cache memory-mapping & which
518
- # seqlen datastructures we utilize
519
-
520
- if (attn_type != AttentionType.ENCODER and kv_cache.numel() > 0):
521
- # KV-cache during decoder-self- or
522
- # encoder-decoder-cross-attention, but not
523
- # during encoder attention.
524
- #
525
- # Even if there are no new key/value pairs to cache,
526
- # we still need to break out key_cache and value_cache
527
- # i.e. for later use by paged attention
528
- key_cache, value_cache = PagedAttention.split_kv_cache(
529
- kv_cache, self.num_kv_heads, self.head_size)
530
-
531
- if (key is not None) and (value is not None):
532
-
533
- if attn_type == AttentionType.ENCODER_DECODER:
534
- # Update cross-attention KV cache (prefill-only)
535
- # During cross-attention decode, key & value will be None,
536
- # preventing this IF-statement branch from running
537
- updated_slot_mapping = attn_metadata.cross_slot_mapping
538
- else:
539
- # Update self-attention KV cache (prefill/decode)
540
- updated_slot_mapping = attn_metadata.slot_mapping
541
-
542
- # Reshape the input keys and values and store them in the cache.
543
- # If kv_cache is not provided, the new key and value tensors are
544
- # not cached. This happens during the initial memory
545
- # profiling run.
546
- PagedAttention.write_to_paged_cache(
547
- key, value, key_cache, value_cache, updated_slot_mapping,
548
- self.kv_cache_dtype, layer._k_scale, layer._v_scale)
549
- (num_prefill_query_tokens, num_prefill_kv_tokens,
550
- num_decode_query_tokens) = \
551
- get_num_prefill_decode_query_kv_tokens(attn_metadata, attn_type)
552
-
553
- output = torch.empty_like(query)
554
- # Query for decode. KV is not needed because it is already cached.
555
- decode_query = query[num_prefill_query_tokens:]
556
- # QKV for prefill.
557
- query = query[:num_prefill_query_tokens]
558
- if key is not None and value is not None:
559
- key = key[:num_prefill_kv_tokens]
560
- value = value[:num_prefill_kv_tokens]
561
-
562
- assert query.shape[0] == num_prefill_query_tokens
563
- assert decode_query.shape[0] == num_decode_query_tokens
564
-
565
- if prefill_meta := attn_metadata.prefill_metadata:
566
- # Prompt run.
567
- if kv_cache.numel() == 0 or prefill_meta.block_tables.numel() == 0:
568
- # normal attention.
569
- # block tables are empty if the prompt does not have a cached
570
- # prefix.
571
- out = self._run_memory_efficient_xformers_forward(
572
- query, key, value, prefill_meta, attn_type=attn_type)
573
- assert out.shape == output[:num_prefill_query_tokens].shape
574
- output[:num_prefill_query_tokens] = out
575
- else:
576
- assert attn_type != AttentionType.ENCODER_ONLY, (
577
- "Encoder-only models should not have prefix attention.")
578
-
579
- assert prefill_meta.query_start_loc is not None
580
- assert prefill_meta.max_query_len is not None
581
-
582
- # prefix-enabled attention
583
- # TODO(Hai) this triton kernel has regression issue (broke) to
584
- # deal with different data types between KV and FP8 KV cache,
585
- # to be addressed separately.
586
- out = PagedAttention.forward_prefix(
587
- query,
588
- key,
589
- value,
590
- self.kv_cache_dtype,
591
- key_cache,
592
- value_cache,
593
- prefill_meta.block_tables,
594
- prefill_meta.query_start_loc,
595
- prefill_meta.seq_lens_tensor,
596
- prefill_meta.max_query_len,
597
- self.alibi_slopes,
598
- self.sliding_window,
599
- layer._k_scale,
600
- layer._v_scale,
601
- )
602
- assert output[:num_prefill_query_tokens].shape == out.shape
603
- output[:num_prefill_query_tokens] = out
604
-
605
- if decode_meta := attn_metadata.decode_metadata:
606
- assert attn_type != AttentionType.ENCODER_ONLY, (
607
- "Encoder-only models should not have decode metadata.")
608
-
609
- (
610
- seq_lens_arg,
611
- max_seq_len_arg,
612
- block_tables_arg,
613
- ) = get_seq_len_block_table_args(decode_meta, False, attn_type)
614
-
615
- output[num_prefill_query_tokens:] = PagedAttention.forward_decode(
616
- decode_query,
617
- key_cache,
618
- value_cache,
619
- block_tables_arg,
620
- seq_lens_arg,
621
- max_seq_len_arg,
622
- self.kv_cache_dtype,
623
- self.num_kv_heads,
624
- self.scale,
625
- self.alibi_slopes,
626
- layer._k_scale,
627
- layer._v_scale,
628
- )
629
-
630
- # Reshape the output tensor.
631
- return output.view(-1, self.num_heads * self.head_size)
632
-
633
- def _run_memory_efficient_xformers_forward(
634
- self,
635
- query: torch.Tensor,
636
- key: torch.Tensor,
637
- value: torch.Tensor,
638
- attn_metadata: XFormersMetadata,
639
- attn_type: str = AttentionType.DECODER,
640
- ) -> torch.Tensor:
641
- """Attention for 1D query of multiple prompts. Multiple prompt
642
- tokens are flattened in to `query` input.
643
-
644
- See https://facebookresearch.github.io/xformers/components/ops.html
645
- for API spec.
646
-
647
- Args:
648
- query: shape = [num_prefill_tokens, num_heads, head_size]
649
- key: shape = [num_prefill_tokens, num_kv_heads, head_size]
650
- value: shape = [num_prefill_tokens, num_kv_heads, head_size]
651
- attn_metadata: Metadata for attention.
652
- attn_type: Select attention type, between encoder attention,
653
- decoder self-attention, or encoder/decoder cross-
654
- attention. Defaults to decoder self-attention,
655
- which is the vLLM default generally
656
- """
657
-
658
- original_query = query
659
- if self.num_kv_heads != self.num_heads:
660
- # GQA/MQA requires the shape [B, M, G, H, K].
661
- # Note that the output also has the same shape (which is different
662
- # from a spec from the doc).
663
- query = query.view(query.shape[0], self.num_kv_heads,
664
- self.num_queries_per_kv, query.shape[-1])
665
- key = key[:, :,
666
- None, :].expand(key.shape[0], self.num_kv_heads,
667
- self.num_queries_per_kv, key.shape[-1])
668
- value = value[:, :,
669
- None, :].expand(value.shape[0], self.num_kv_heads,
670
- self.num_queries_per_kv,
671
- value.shape[-1])
672
-
673
- # Set attention bias if not provided. This typically happens at
674
- # the very attention layer of every iteration.
675
- # FIXME(woosuk): This is a hack.
676
- attn_bias = _get_attn_bias(attn_metadata, attn_type)
677
- if attn_bias is None:
678
- if self.alibi_slopes is None:
679
-
680
- # Cross attention block of decoder branch of encoder-decoder
681
- # model uses seq_lens for dec / encoder_seq_lens for enc
682
- if (attn_type == AttentionType.ENCODER_DECODER):
683
- assert attn_metadata.seq_lens is not None
684
- assert attn_metadata.encoder_seq_lens is not None
685
-
686
- # Cross-attention mask is non-causal
687
- attn_bias = BlockDiagonalMask.from_seqlens(
688
- attn_metadata.seq_lens,
689
- attn_metadata.encoder_seq_lens,
690
- device=query.device)
691
-
692
- # Encoder branch of encoder-decoder model uses
693
- # attn_metadata.encoder_seq_lens
694
- elif attn_type == AttentionType.ENCODER:
695
-
696
- assert attn_metadata.encoder_seq_lens is not None
697
-
698
- # Encoder self-attention mask is non-causal
699
- attn_bias = BlockDiagonalMask.from_seqlens(
700
- attn_metadata.encoder_seq_lens, device=query.device)
701
-
702
- # Self-attention block of encoder-only model just
703
- # uses the seq_lens directly.
704
- elif attn_type == AttentionType.ENCODER_ONLY:
705
- assert attn_metadata.seq_lens is not None
706
-
707
- # Encoder self-attention mask is non-causal
708
- attn_bias = BlockDiagonalMask.from_seqlens(
709
- attn_metadata.seq_lens, device=query.device)
710
-
711
- # Self-attention block of decoder branch just
712
- # uses the seq_lens directly
713
- elif attn_type == AttentionType.DECODER:
714
- assert attn_metadata.seq_lens is not None
715
-
716
- # Decoder self-attention mask is causal
717
- attn_bias = BlockDiagonalCausalMask.from_seqlens(
718
- attn_metadata.seq_lens, device=query.device)
719
- else:
720
- raise ValueError("Unknown AttentionType: %s", attn_type)
721
-
722
- if self.sliding_window is not None:
723
- attn_bias = attn_bias.make_local_attention(
724
- self.sliding_window)
725
- attn_bias = [attn_bias]
726
- else:
727
- assert attn_type == AttentionType.DECODER
728
- assert attn_metadata.seq_lens is not None
729
- attn_bias = _make_alibi_bias(self.alibi_slopes,
730
- self.num_kv_heads, query.dtype,
731
- attn_metadata.seq_lens)
732
-
733
- _set_attn_bias(attn_metadata, attn_bias, attn_type)
734
-
735
- # No alibi slopes.
736
- # TODO(woosuk): Too many view operations. Let's try to reduce
737
- # them in the future for code readability.
738
- if self.alibi_slopes is None:
739
- # Add the batch dimension.
740
- query = query.unsqueeze(0)
741
- key = key.unsqueeze(0)
742
- value = value.unsqueeze(0)
743
- out = xops.memory_efficient_attention_forward(
744
- query,
745
- key,
746
- value,
747
- attn_bias=attn_bias[0],
748
- p=0.0,
749
- scale=self.scale)
750
- return out.view_as(original_query)
751
-
752
- # Attention with alibi slopes.
753
- # FIXME(woosuk): Because xformers does not support dynamic sequence
754
- # lengths with custom attention bias, we process each prompt one by
755
- # one. This is inefficient, especially when we have many short prompts.
756
- assert attn_metadata.seq_lens is not None
757
- output = torch.empty_like(original_query)
758
- start = 0
759
- for i, seq_len in enumerate(attn_metadata.seq_lens):
760
- end = start + seq_len
761
- out = xops.memory_efficient_attention_forward(
762
- query[None, start:end],
763
- key[None, start:end],
764
- value[None, start:end],
765
- attn_bias=attn_bias[i],
766
- p=0.0,
767
- scale=self.scale)
768
- # TODO(woosuk): Unnecessary copy. Optimize.
769
- output[start:end].copy_(out.view_as(original_query[start:end]))
770
- start += seq_len
771
- return output
772
-
773
-
774
-def _make_alibi_bias(
775
- alibi_slopes: torch.Tensor,
776
- num_kv_heads: int,
777
- dtype: torch.dtype,
778
- seq_lens: List[int],
779
-) -> List[AttentionBias]:
780
- attn_biases: List[AttentionBias] = []
781
- for seq_len in seq_lens:
782
- bias = torch.arange(seq_len, dtype=dtype)
783
- # NOTE(zhuohan): HF uses
784
- # `bias = bias[None, :].repeat(seq_len, 1)`
785
- # here. We find that both biases give the same results, but
786
- # the bias below more accurately follows the original ALiBi
787
- # paper.
788
- # Calculate a matrix where each element represents ith element- jth
789
- # element.
790
- bias = bias[None, :] - bias[:, None]
791
-
792
- padded_len = (seq_len + 7) // 8 * 8
793
- num_heads = alibi_slopes.shape[0]
794
- bias = torch.empty(
795
- 1, # batch size
796
- num_heads,
797
- seq_len,
798
- padded_len,
799
- device=alibi_slopes.device,
800
- dtype=dtype,
801
- )[:, :, :, :seq_len].copy_(bias)
802
- bias.mul_(alibi_slopes[:, None, None])
803
- attn_biases.append(LowerTriangularMaskWithTensorBias(bias))
804
-
805
- return attn_biases
vllm/config/model.py
+1
-6
@@ -32,8 +32,7 @@ from vllm.transformers_utils.config import (
32
from vllm.transformers_utils.runai_utils import (ObjectStorageModel,
33
is_runai_obj_uri)
34
from vllm.transformers_utils.utils import maybe_model_redirect
35
-from vllm.utils import (STR_DUAL_CHUNK_FLASH_ATTN_VAL, LayerBlockType,
36
- LazyLoader, common_broadcastable_dtype)
35
+from vllm.utils import LayerBlockType, LazyLoader, common_broadcastable_dtype
36
37
if TYPE_CHECKING:
38
from transformers import PretrainedConfig
@@ -1103,10 +1102,6 @@ class ModelConfig:
1102
self.hf_config.dual_chunk_attention_config[
1103
"sparse_attention_enabled"] = True
1104
1106
- if envs.VLLM_ATTENTION_BACKEND != STR_DUAL_CHUNK_FLASH_ATTN_VAL:
1107
- raise ValueError("please set VLLM_ATTENTION_BACKEND to "
1108
- f"{STR_DUAL_CHUNK_FLASH_ATTN_VAL}")
1109
-
1105
def verify_with_parallel_config(
1106
self,
1107
parallel_config: ParallelConfig,
vllm/distributed/kv_transfer/kv_connector/utils.py
+1
-1
@@ -44,7 +44,7 @@ class model_aware_kv_ops_helper:
44
# When VLLM_MLA_DISABLE=1, standard FA is used instead, leading
45
# to a kv_cache shape of [2, num_blks, blk_size,
46
# num_key_value_heads / tp, qk_nope_head_dim + qk_rope_head_dim].
47
- # For more details, see vllm/attention/backends/mla/common.py.
47
+ # For more details, see vllm/v1/attention/backends/mla/common.py.
48
if self.is_deepseek_mla and self.use_mla_opt:
49
head_size = model_config.kv_lora_rank + \
50
model_config.qk_rope_head_dim
vllm/engine/arg_utils.py
+2
-13
@@ -44,8 +44,8 @@ from vllm.test_utils import MODEL_WEIGHTS_S3_BUCKET, MODELS_ON_S3
44
from vllm.transformers_utils.config import (get_model_path, is_interleaved,
45
maybe_override_with_speculators)
46
from vllm.transformers_utils.utils import check_gguf_file
47
-from vllm.utils import (STR_DUAL_CHUNK_FLASH_ATTN_VAL, FlexibleArgumentParser,
48
- GiB_bytes, get_ip, is_in_ray_actor)
47
+from vllm.utils import (FlexibleArgumentParser, GiB_bytes, get_ip,
48
+ is_in_ray_actor)
49
from vllm.v1.sample.logits_processor import LogitsProcessor
50
51
# yapf: enable
@@ -1163,17 +1163,6 @@ class EngineArgs:
1163
self._set_default_args_v0(model_config)
1164
assert self.enable_chunked_prefill is not None
1165
1166
- if envs.VLLM_ATTENTION_BACKEND in [STR_DUAL_CHUNK_FLASH_ATTN_VAL]:
1167
- assert self.enforce_eager, (
1168
- "Cuda graph is not supported with DualChunkFlashAttention. "
1169
- "To run the model in eager mode, set 'enforce_eager=True' "
1170
- "or use '--enforce-eager' in the CLI.")
1171
- assert current_platform.is_cuda(), (
1172
- "DualChunkFlashAttention is only supported on CUDA platform.")
1173
- assert not use_v1, (
1174
- "DualChunkFlashAttention is not supported on V1 engine. "
1175
- "To run the model in V0 engine, try set 'VLLM_USE_V1=0'")
1176
-
1166
sliding_window: Optional[int] = None
1167
if not is_interleaved(model_config.hf_text_config):
1168
# Only set CacheConfig.sliding_window if the model is all sliding
vllm/envs.py
-1
@@ -529,7 +529,6 @@ environment_variables: dict[str, Callable[[], Any]] = {
529
# - "TORCH_SDPA": use torch.nn.MultiheadAttention
530
# - "FLASH_ATTN": use FlashAttention
531
# - "XFORMERS": use XFormers
532
- # - "ROCM_FLASH": use ROCmFlashAttention
532
# - "FLASHINFER": use flashinfer
533
# - "FLASHMLA": use FlashMLA
534
# - "FLASH_ATTN_MLA": use FlashAttention for MLA
vllm/model_executor/layers/mamba/mamba2_metadata.py
+12
-7
@@ -53,13 +53,18 @@ class Mamba2Metadata:
53
def get_platform_metadata_classes() -> tuple[type[AttentionMetadata], ...]:
54
"""Returns the appropriate metadata classes for the current platform."""
55
if current_platform.is_rocm():
56
- from vllm.attention.backends.rocm_flash_attn import (
57
- ROCmFlashAttentionMetadata)
58
- return (ROCmFlashAttentionMetadata, PlaceholderAttentionMetadata)
59
- elif current_platform.is_cuda():
60
- from vllm.attention.backends.flash_attn import FlashAttentionMetadata
61
- from vllm.attention.backends.xformers import XFormersMetadata
62
- return (FlashAttentionMetadata, XFormersMetadata,
56
+ from vllm.v1.attention.backends.rocm_aiter_fa import (
57
+ AiterFlashAttentionMetadata)
58
+ from vllm.v1.attention.backends.triton_attn import (
59
+ TritonAttentionMetadata)
60
+ return (AiterFlashAttentionMetadata, TritonAttentionMetadata,
61
+ PlaceholderAttentionMetadata)
62
+ if current_platform.is_cuda():
63
+ from vllm.v1.attention.backends.flash_attn import (
64
+ FlashAttentionMetadata)
65
+ from vllm.v1.attention.backends.xformers import (
66
+ XFormersAttentionMetadata)
67
+ return (FlashAttentionMetadata, XFormersAttentionMetadata,
68
PlaceholderAttentionMetadata)
69
raise ValueError(
70
f"Unsupported platform for Mamba2: {current_platform.device_type}")
vllm/model_executor/models/deepseek_v2.py
+2
-1
@@ -478,7 +478,8 @@ class DeepseekV2MLAAttention(nn.Module):
478
Main reference: DeepseekV2 paper, and FlashInfer Implementation
479
(https://arxiv.org/abs/2405.04434 and https://github.com/flashinfer-ai/flashinfer/pull/551).
480
481
- For more info see MLACommonImpl in: vllm/attention/backends/mla/utils.py
481
+ For more info see MLACommonImpl in:
482
+ vllm/v1/attention/backends/mla/utils.py
483
"""
484
485
def __init__(
vllm/platforms/cuda.py
+26
-113
@@ -226,8 +226,10 @@ class CudaPlatformBase(Platform):
226
kv_cache_dtype, block_size, use_v1, use_mla,
227
has_sink) -> str:
228
if use_mla:
229
- # TODO(lucas): refactor to be more concise
230
- # we should probably consider factoring out V1 here
229
+ if not use_v1:
230
+ raise RuntimeError(
231
+ "MLA attention backends require the V1 engine. "
232
+ "Set VLLM_USE_V1=1 to enable them.")
233
234
from vllm.attention.ops.flashmla import is_flashmla_supported
235
from vllm.attention.utils.fa_utils import flash_attn_supports_mla
@@ -246,35 +248,17 @@ class CudaPlatformBase(Platform):
248
use_triton = selected_backend == _Backend.TRITON_MLA or (
249
selected_backend is None)
250
249
- def _get_version(name, import_suffix) -> str:
250
- if use_v1:
251
- logger.info_once(f"Using {name} backend on V1 engine.")
252
- return f"vllm.v1.attention.backends.mla.{import_suffix}"
253
- else:
254
- logger.info_once(f"Using {name} backend.")
255
- return f"vllm.attention.backends.{import_suffix}"
256
-
251
if use_cutlassmla:
258
- if use_v1:
259
- logger.info_once("Using Cutlass MLA backend on V1 engine.")
260
- return ("vllm.v1.attention.backends.mla."
261
- "cutlass_mla.CutlassMLABackend")
262
- else:
263
- logger.warning(
264
- "Cutlass MLA backend is only supported on V1 engine")
252
+ logger.info_once("Using Cutlass MLA backend on V1 engine.")
253
+ return ("vllm.v1.attention.backends.mla."
254
+ "cutlass_mla.CutlassMLABackend")
255
if use_flashinfermla:
266
- if use_v1:
267
- from vllm.v1.attention.backends.utils import (
268
- set_kv_cache_layout)
269
- set_kv_cache_layout("HND")
270
- logger.info_once(
271
- "Using FlashInfer MLA backend on V1 engine.")
272
- return ("vllm.v1.attention.backends.mla."
273
- "flashinfer_mla.FlashInferMLABackend")
274
- else:
275
- logger.warning(
276
- "FlashInfer MLA backend is only supported on V1 engine"
277
- )
256
+ from vllm.v1.attention.backends.utils import (
257
+ set_kv_cache_layout)
258
+ set_kv_cache_layout("HND")
259
+ logger.info_once("Using FlashInfer MLA backend on V1 engine.")
260
+ return ("vllm.v1.attention.backends.mla."
261
+ "flashinfer_mla.FlashInferMLABackend")
262
if use_flashmla:
263
if block_size != 64:
264
logger.warning(
@@ -282,20 +266,18 @@ class CudaPlatformBase(Platform):
266
" (currently only supports block size 64).",
267
block_size)
268
else:
285
- return _get_version("FlashMLA", "flashmla.FlashMLABackend")
286
- if use_flashattn:
287
- if use_v1:
288
- logger.info_once(
289
- "Using FlashAttention MLA backend on V1 engine.")
269
+ logger.info_once("Using FlashMLA backend on V1 engine.")
270
return ("vllm.v1.attention.backends.mla."
291
- "flashattn_mla.FlashAttnMLABackend")
292
- else:
293
- logger.warning(
294
- "FlashAttention MLA backend is only supported on V1 "
295
- "engine.")
271
+ "flashmla.FlashMLABackend")
272
+ if use_flashattn:
273
+ logger.info_once(
274
+ "Using FlashAttention MLA backend on V1 engine.")
275
+ return ("vllm.v1.attention.backends.mla."
276
+ "flashattn_mla.FlashAttnMLABackend")
277
if use_triton:
297
- return _get_version("Triton MLA",
298
- "triton_mla.TritonMLABackend")
278
+ logger.info_once("Using Triton MLA backend on V1 engine.")
279
+ return ("vllm.v1.attention.backends.mla."
280
+ "triton_mla.TritonMLABackend")
281
if use_v1:
282
FLASHINFER_V1 = "vllm.v1.attention.backends.flashinfer.FlashInferBackend" # noqa: E501
283
FLEX_ATTENTION_V1 = "vllm.v1.attention.backends.flex_attention.FlexAttentionBackend" # noqa: E501
@@ -382,78 +364,9 @@ class CudaPlatformBase(Platform):
364
)
365
return FLEX_ATTENTION_V1
366
385
- # Backends for V0 engine
386
- if selected_backend == _Backend.XFORMERS:
387
- logger.info("Using XFormers backend.")
388
- return "vllm.attention.backends.xformers.XFormersBackend"
389
- elif selected_backend == _Backend.DUAL_CHUNK_FLASH_ATTN:
390
- logger.info("Using DualChunkFlashAttention backend.")
391
- return ("vllm.attention.backends.dual_chunk_flash_attn."
392
- "DualChunkFlashAttentionBackend")
393
- elif selected_backend == _Backend.DIFFERENTIAL_FLASH_ATTN:
394
- logger.info("Using DifferentialFlashAttention backend.")
395
- return ("vllm.attention.backends.differential_flash_attn."
396
- "DifferentialFlashAttentionBackend")
397
- elif selected_backend == _Backend.FLASH_ATTN:
398
- pass
399
- elif selected_backend:
400
- raise ValueError(
401
- f"Invalid attention backend for {cls.device_name}, "
402
- f"with use_v1: {use_v1} use_mla: {use_mla}")
403
-
404
- target_backend = _Backend.FLASH_ATTN
405
- if not cls.has_device_capability(80):
406
- # Volta and Turing NVIDIA GPUs.
407
- logger.info(
408
- "Cannot use FlashAttention-2 backend for Volta and Turing "
409
- "GPUs.")
410
- target_backend = _Backend.XFORMERS
411
- elif dtype not in (torch.float16, torch.bfloat16):
412
- logger.info(
413
- "Cannot use FlashAttention-2 backend for dtype other than "
414
- "torch.float16 or torch.bfloat16.")
415
- target_backend = _Backend.XFORMERS
416
- elif block_size % 16 != 0:
417
- logger.info(
418
- "Cannot use FlashAttention-2 backend for block size not "
419
- "divisible by 16.")
420
- target_backend = _Backend.XFORMERS
421
-
422
- # FlashAttn is valid for the model, checking if the package is
423
- # installed.
424
- if target_backend == _Backend.FLASH_ATTN:
425
- try:
426
- import vllm.vllm_flash_attn # noqa: F401
427
- from vllm.attention.backends.flash_attn import ( # noqa: F401
428
- FlashAttentionBackend, flash_attn_supports_fp8)
429
-
430
- supported_sizes = \
431
- FlashAttentionBackend.get_supported_head_sizes()
432
- if head_size not in supported_sizes:
433
- logger.info(
434
- "Cannot use FlashAttention-2 backend for head size %d.",
435
- head_size)
436
- target_backend = _Backend.XFORMERS
437
- fp8_kv_cache = (kv_cache_dtype is not None
438
- and kv_cache_dtype.startswith("fp8"))
439
- if (fp8_kv_cache and not flash_attn_supports_fp8()):
440
- logger.info(
441
- "Cannot use FlashAttention backend for FP8 KV cache.")
442
- target_backend = _Backend.XFORMERS
443
- except ImportError:
444
- logger.info(
445
- "Cannot use FlashAttention-2 backend because the "
446
- "vllm.vllm_flash_attn package is not found. "
447
- "Make sure that vllm_flash_attn was built and installed "
448
- "(on by default).")
449
- target_backend = _Backend.XFORMERS
450
-
451
- if target_backend == _Backend.XFORMERS:
452
- logger.info("Using XFormers backend.")
453
- return "vllm.attention.backends.xformers.XFormersBackend"
454
-
455
- logger.info("Using Flash Attention backend.")
456
- return "vllm.attention.backends.flash_attn.FlashAttentionBackend"
367
+ raise RuntimeError(
368
+ "V0 attention backends have been removed. Set VLLM_USE_V1=1 "
369
+ "to select a supported backend.")
370
371
@classmethod
372
def get_punica_wrapper(cls) -> str:
vllm/platforms/rocm.py
+23
-38
@@ -191,6 +191,11 @@ class RocmPlatform(Platform):
191
kv_cache_dtype, block_size, use_v1, use_mla,
192
has_sink) -> str:
193
if use_mla:
194
+ if not use_v1:
195
+ raise RuntimeError(
196
+ "MLA attention backends require the V1 engine. "
197
+ "Set VLLM_USE_V1=1 to enable them.")
198
+
199
from vllm.v1.attention.backends.mla.rocm_aiter_mla import (
200
is_aiter_mla_enabled)
201
@@ -201,39 +206,24 @@ class RocmPlatform(Platform):
206
207
if selected_backend == _Backend.TRITON_MLA:
208
if block_size != 1:
204
- if use_v1:
205
- logger.info_once(
206
- "Using Triton MLA backend on V1 engine.")
207
- return ("vllm.v1.attention.backends.mla."
208
- "triton_mla.TritonMLABackend")
209
- else:
210
- logger.info("Using Triton MLA backend.")
211
- return "vllm.attention.backends.triton_mla.TritonMLABackend" # noqa: E501
212
- else:
213
- raise ValueError(
214
- f" The selected backend, {selected_backend.name},"
215
- f"does not support block size {block_size}.")
216
- elif selected_backend == _Backend.ROCM_AITER_MLA \
217
- or selected_backend == _Backend.ROCM_AITER_MLA_VLLM_V1:
209
+ logger.info_once("Using Triton MLA backend on V1 engine.")
210
+ return ("vllm.v1.attention.backends.mla."
211
+ "triton_mla.TritonMLABackend")
212
+ raise ValueError(
213
+ f" The selected backend, {selected_backend.name},"
214
+ f"does not support block size {block_size}.")
215
+ if selected_backend in (_Backend.ROCM_AITER_MLA,
216
+ _Backend.ROCM_AITER_MLA_VLLM_V1):
217
if block_size == 1:
219
- if use_v1:
220
- logger.info("Using AITER MLA backend on V1 engine.")
221
- return "vllm.v1.attention.backends.mla.rocm_aiter_mla.AiterMLABackend" # noqa: E501
222
- else:
223
- logger.info("Using AITER MLA backend")
224
- return "vllm.attention.backends.rocm_aiter_mla.AiterMLABackend" # noqa: E501
225
- else:
226
- raise ValueError(
227
- f" The selected backend, {selected_backend.name},"
228
- f"does not support block size {block_size}."
229
- "(currently only supports block size 1)")
230
- else:
218
+ logger.info("Using AITER MLA backend on V1 engine.")
219
+ return "vllm.v1.attention.backends.mla.rocm_aiter_mla.AiterMLABackend" # noqa: E501
220
raise ValueError(
221
f" The selected backend, {selected_backend.name},"
233
- f"is not MLA type while requested for MLA backend.")
234
-
235
- if selected_backend is None or selected_backend == _Backend.FLASH_ATTN:
236
- selected_backend = _Backend.ROCM_FLASH
222
+ f"does not support block size {block_size}."
223
+ "(currently only supports block size 1)")
224
+ raise ValueError(
225
+ f" The selected backend, {selected_backend.name},"
226
+ f"is not MLA type while requested for MLA backend.")
227
228
if envs.VLLM_USE_V1:
229
if envs.VLLM_ROCM_USE_AITER and envs.VLLM_ROCM_USE_AITER_MHA \
@@ -245,14 +235,9 @@ class RocmPlatform(Platform):
235
logger.info("Using Triton Attention backend on V1 engine.")
236
return ("vllm.v1.attention.backends."
237
"triton_attn.TritonAttentionBackend")
248
- if selected_backend == _Backend.ROCM_FLASH:
249
- if not cls.has_device_capability(90):
250
- # not Instinct series GPUs.
251
- logger.info("flash_attn is not supported on NAVI GPUs.")
252
- else:
253
- logger.info("%s is not supported in AMD GPUs.", selected_backend)
254
- logger.info("Using ROCmFlashAttention backend.")
255
- return "vllm.attention.backends.rocm_flash_attn.ROCmFlashAttentionBackend" # noqa: E501
238
+ raise RuntimeError(
239
+ "V0 attention backends have been removed. Set VLLM_USE_V1=1 "
240
+ "to select a supported backend.")
241
242
@classmethod
243
def set_device(cls, device: torch.device) -> None:
vllm/utils/__init__.py
-2
@@ -157,10 +157,8 @@ STR_BACKEND_ENV_VAR: str = "VLLM_ATTENTION_BACKEND"
157
# register, corresponding to possible backends
158
STR_FLASHINFER_ATTN_VAL: str = "FLASHINFER"
159
STR_TORCH_SDPA_ATTN_VAL: str = "TORCH_SDPA"
160
-STR_ROCM_FLASH_ATTN_VAL: str = "ROCM_FLASH"
160
STR_XFORMERS_ATTN_VAL: str = "XFORMERS"
161
STR_FLASH_ATTN_VAL: str = "FLASH_ATTN"
163
-STR_DUAL_CHUNK_FLASH_ATTN_VAL: str = "DUAL_CHUNK_FLASH_ATTN"
162
STR_INVALID_VAL: str = "INVALID"
163
164
MB_bytes = 1_000_000