-
Notifications
You must be signed in to change notification settings - Fork 101
Expand file tree
/
Copy pathmla.py
More file actions
193 lines (167 loc) · 5.96 KB
/
Copy pathmla.py
File metadata and controls
193 lines (167 loc) · 5.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# Copyright (c) 2025 BAAI. All rights reserved.
# Adapted from https://github.com/vllm-project/vllm/blob/v0.11.0/vllm/v1/attention/backends/mla/flashattn_mla.py
# Below is the original copyright:
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
from typing import Optional, Union
import torch
from vllm.v1.attention.backend import (
AttentionLayer,
AttentionType,
)
from vllm.utils.torch_utils import is_quantized_kv_cache
# from vllm.attention.ops.triton_decode_attention import decode_attention_fwd
# from vllm.attention.ops.triton_flash_attention import triton_attention
from vllm.logger import init_logger
from vllm.model_executor.layers.attention.mla_attention import (
MLACommonBackend,
MLACommonImpl,
MLACommonMetadata,
)
from flag_gems import flash_attn_varlen_func, flash_mla
logger = init_logger(__name__)
class MLAFLBackend(MLACommonBackend):
@staticmethod
def get_name() -> str:
return "MLAFL"
@staticmethod
def get_impl_cls() -> type["MLAFLImpl"]:
return MLAFLImpl
class MLAFLImpl(MLACommonImpl[MLACommonMetadata]):
can_return_lse_for_decode: bool = True
def __init__(
self,
num_heads: int,
head_size: int,
scale: float,
num_kv_heads: int,
alibi_slopes: Optional[list[float]],
sliding_window: Optional[int],
kv_cache_dtype: str,
logits_soft_cap: Optional[float],
attn_type: str,
kv_sharing_target_layer_name: Optional[str],
# MLA Specific Arguments
**mla_args,
) -> None:
super().__init__(
num_heads,
head_size,
scale,
num_kv_heads,
alibi_slopes,
sliding_window,
kv_cache_dtype,
logits_soft_cap,
attn_type,
kv_sharing_target_layer_name,
**mla_args,
)
unsupported_features = [alibi_slopes, sliding_window, logits_soft_cap]
if any(unsupported_features):
raise NotImplementedError(
"TritonMLAImpl does not support one of the following: "
"alibi_slopes, sliding_window, logits_soft_cap"
)
if attn_type != AttentionType.DECODER:
raise NotImplementedError(
"Encoder self-attention and "
"encoder/decoder cross-attention "
"are not implemented for "
"TritonMLAImpl"
)
if is_quantized_kv_cache(self.kv_cache_dtype):
raise NotImplementedError(
"TritonMLA V1 with FP8 KV cache not yet supported"
)
def _flash_attn_varlen_diff_headdims(
self, q, k, v, return_softmax_lse=False, softmax_scale=None, **kwargs
):
maybe_padded_v = v
if self._pad_v:
maybe_padded_v = torch.nn.functional.pad(
v, [0, q.shape[-1] - v.shape[-1]], value=0
)
kwargs["return_softmax_lse"] = return_softmax_lse
attn_out = flash_attn_varlen_func(
q=q,
k=k,
v=maybe_padded_v,
softmax_scale=softmax_scale,
**kwargs,
)
# Unpack the output if there is multiple results
lse = None
if isinstance(attn_out, tuple):
attn_out, lse = attn_out[0], attn_out[1]
# Remain consistent with old `flash_attn_varlen_func` where there
# is only one output tensor if `return_softmax_lse` is False.
if return_softmax_lse:
return attn_out, lse
return attn_out
def forward_mqa(
self,
q: Union[torch.Tensor, tuple[torch.Tensor, torch.Tensor]],
kv_c_and_k_pe_cache: torch.Tensor,
attn_metadata: MLACommonMetadata,
layer: AttentionLayer,
) -> tuple[torch.Tensor, Optional[torch.Tensor]]:
assert kv_c_and_k_pe_cache.numel() > 0
assert attn_metadata.decode is not None
if self.kv_cache_dtype.startswith("fp8"):
raise NotImplementedError("FP8 MLA FL not yet supported")
head_dim_v = 0
if type(q) is tuple:
### q_nope & q_pe
head_dim_v = q[0][-1]
q = torch.cat(q, dim=-1)
assert isinstance(q, torch.Tensor)
B = q.shape[0]
q_num_heads = q.shape[1]
head_dim = q[-1]
# o = torch.zeros(B,
# q_num_heads,
# self.kv_lora_rank,
# dtype=q.dtype,
# device=q.device)
lse = torch.zeros(B, q_num_heads, dtype=q.dtype, device=q.device)
# num_kv_splits = 4 # TODO: heuristic
# TODO(lucas) Allocate ahead of time
# attn_logits = torch.empty(
# (
# B,
# q_num_heads,
# num_kv_splits,
# # NOTE(lucas) idk why the +1 is here but sglang has it so we
# # just mirror that
# self.kv_lora_rank + 1,
# ),
# dtype=torch.float32,
# device=q.device,
# )
# Add a head dim of 1
kv_c_and_k_pe_cache = kv_c_and_k_pe_cache.unsqueeze(2)
# kv_c_cache = kv_c_and_k_pe_cache[..., : self.kv_lora_rank]
PAGE_SIZE = kv_c_and_k_pe_cache.size(1)
# # Run MQA
# decode_attention_fwd(q, kv_c_and_k_pe_cache, kv_c_cache, o, lse,
# attn_metadata.decode.block_table,
# attn_metadata.decode.seq_lens, attn_logits,
# num_kv_splits, self.scale, PAGE_SIZE)
### NOTE(lms): check correctness
o = flash_mla(
q,
attn_metadata.decode.block_table,
kv_c_and_k_pe_cache,
None,
PAGE_SIZE,
B,
1,
attn_metadata.decode.seq_lens,
q_num_heads,
None,
head_dim,
head_dim_v,
True,
)
return o, lse