Support flash-attention2 for Ascend NPU

#1
build/torch-universal/FlashAttention/__init__.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ from .flash_attn_2 import flash_attn_func, flash_attn_varlen_func
2
+ from .attention_utils import pad_input, unpad_input
3
+
4
+ __all__ = [
5
+ "flash_attn_func",
6
+ "flash_attn_varlen_func",
7
+ "pad_input",
8
+ "unpad_input",
9
+ ]
build/torch-universal/FlashAttention/attention_utils.py ADDED
File without changes
build/torch-universal/FlashAttention/flash_attn_2.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Licensed under the Apache License, Version 2.0 (the "License");
2
+ # you may not use this file except in compliance with the License.
3
+ # You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+
14
+ import math
15
+ import os
16
+
17
+ import torch
18
+ import torch_npu
19
+ from torch_npu import npu_fusion_attention
20
+
21
+
22
+ # FlashAttention2 is supported on Ascend NPU with down-right aligned causal mask by default.
23
+ # Set environment variable `NPU_FA2_SPARSE_MODE` to 2 when using top-left aligned causal mask.
24
+ TOP_LEFT_ALIGNED_CAUSAL_MASK_MODE = 2
25
+ DOWN_RIGHT_ALIGNED_CAUSAL_MASK_MODE = 3
26
+
27
+ SPARSE_MODE = int(os.getenv("NPU_FA2_SPARSE_MODE", default=DOWN_RIGHT_ALIGNED_CAUSAL_MASK_MODE))
28
+ if SPARSE_MODE not in [TOP_LEFT_ALIGNED_CAUSAL_MASK_MODE, DOWN_RIGHT_ALIGNED_CAUSAL_MASK_MODE]:
29
+ raise ValueError(
30
+ "Environment variable `NPU_FA2_SPARSE_MODE` can only be set as 2 (top-left aligned causal mask) "
31
+ "or 3 (down-right aligned causal mask)."
32
+ )
33
+
34
+ ATTN_MASK_NPU_CACHE = {}
35
+
36
+
37
+ def get_attn_mask_npu(device):
38
+ """Get or create attention mask for the specified device."""
39
+ if device not in ATTN_MASK_NPU_CACHE:
40
+ ATTN_MASK_NPU_CACHE[device] = torch.triu(torch.ones([2048, 2048], device=device), diagonal=1).bool()
41
+ return ATTN_MASK_NPU_CACHE[device]
42
+
43
+
44
+ def npu_flash_attn_func(
45
+ q,
46
+ k,
47
+ v,
48
+ dropout_p=0.0,
49
+ softmax_scale=None,
50
+ causal=False,
51
+ **kwargs,
52
+ ):
53
+ keep_prob = 1.0 - dropout_p
54
+
55
+ if softmax_scale is None:
56
+ softmax_scale = 1.0 / math.sqrt(q.shape[-1])
57
+
58
+ if not causal:
59
+ head_num = q.shape[2]
60
+ output = npu_fusion_attention(q, k, v, head_num, "BSND", keep_prob=keep_prob, scale=softmax_scale)[0]
61
+ else:
62
+ attn_mask_npu = get_attn_mask_npu(q.device)
63
+ head_num = q.shape[2]
64
+ output = npu_fusion_attention(
65
+ q,
66
+ k,
67
+ v,
68
+ head_num,
69
+ "BSND",
70
+ keep_prob=keep_prob,
71
+ scale=softmax_scale,
72
+ atten_mask=attn_mask_npu,
73
+ sparse_mode=SPARSE_MODE,
74
+ )[0]
75
+
76
+ return output
77
+
78
+
79
+ def npu_flash_attn_varlen_func(
80
+ q,
81
+ k,
82
+ v,
83
+ cu_seqlens_q,
84
+ cu_seqlens_k,
85
+ max_seqlen_q=None, # defined for aligning params order with corresponding function in `flash-attn`
86
+ max_seqlen_k=None, # defined for aligning params order with corresponding function in `flash-attn`
87
+ dropout_p=0.0,
88
+ softmax_scale=None,
89
+ causal=False,
90
+ **kwargs,
91
+ ):
92
+ keep_prob = 1.0 - dropout_p
93
+
94
+ if softmax_scale is None:
95
+ softmax_scale = 1.0 / math.sqrt(q.shape[-1])
96
+
97
+ if not causal:
98
+ head_num = q.shape[1]
99
+ output = npu_fusion_attention(
100
+ q,
101
+ k,
102
+ v,
103
+ head_num,
104
+ pse=None,
105
+ atten_mask=None,
106
+ scale=softmax_scale,
107
+ keep_prob=keep_prob,
108
+ input_layout="TND",
109
+ actual_seq_qlen=tuple(cu_seqlens_q[1:].cpu().numpy().tolist()),
110
+ actual_seq_kvlen=tuple(cu_seqlens_k[1:].cpu().numpy().tolist()),
111
+ )[0]
112
+ else:
113
+ attn_mask_npu = get_attn_mask_npu(q.device)
114
+ head_num = q.shape[1]
115
+ output = npu_fusion_attention(
116
+ q,
117
+ k,
118
+ v,
119
+ head_num,
120
+ pse=None,
121
+ padding_mask=None,
122
+ atten_mask=attn_mask_npu,
123
+ scale=softmax_scale,
124
+ keep_prob=keep_prob,
125
+ input_layout="TND",
126
+ actual_seq_qlen=tuple(cu_seqlens_q[1:].cpu().numpy().tolist()),
127
+ actual_seq_kvlen=tuple(cu_seqlens_k[1:].cpu().numpy().tolist()),
128
+ sparse_mode=SPARSE_MODE,
129
+ )[0]
130
+
131
+ return output