ajh-code commited on
Commit
ee3ab6f
·
verified ·
1 Parent(s): c88a064

Add runtime/spas_sage_attn/quant_per_warp_cuda.py

Browse files
runtime/spas_sage_attn/quant_per_warp_cuda.py ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Copyright (c) 2025 by SpargeAttn team.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ """
16
+
17
+ import torch
18
+ from typing import Any, List, Literal, Optional, Tuple, Union
19
+
20
+ from . import _fused
21
+
22
+ def per_block_int8(
23
+ q: torch.Tensor,
24
+ k: torch.Tensor,
25
+ km: Optional[torch.Tensor] = None,
26
+ BLKQ: int =128,
27
+ BLKK: int =64,
28
+ sm_scale: Optional[float] = None,
29
+ tensor_layout: str ="HND"
30
+ ):
31
+ """
32
+ Quantize the query tensor `q` and the key tensor `k` with per block quantization.
33
+
34
+ Parameters
35
+ ----------
36
+ q : torch.Tensor
37
+ The query tensor. Shape:
38
+ - If `tensor_layout` is "HND": ``[batch_size, num_qo_heads, qo_len, head_dim]``.
39
+ - If `tensor_layout` is "NHD": ``[batch_size, qo_len, num_qo_heads, head_dim]``.
40
+
41
+ k : torch.Tensor
42
+ The key tensor. Shape:
43
+ - If `tensor_layout` is "HND": ``[batch_size, num_kv_heads, kv_len, head_dim]``.
44
+ - If `tensor_layout` is "NHD": ``[batch_size, kv_len, num_kv_heads, head_dim]``.
45
+
46
+ km : Optional[torch.Tensor]
47
+ The mean tensor of `k` along the sequence length dimension. Shape: ``[batch_size, num_kv_heads, head_dim]``.
48
+ Should be of the same dtype as `k` if provided. Default is None.
49
+
50
+ sm_scale : Optional[float]
51
+ The scale factor for the softmax operation. Default is ``head_dim**-0.5``.
52
+ It will be multiplied by ``1.44269504`` to work together with the triton attention kernel.
53
+
54
+ tensor_layout : str
55
+ The tensor layout, either "HND" or "NHD".
56
+ Default: "HND".
57
+
58
+ Returns
59
+ -------
60
+ Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]
61
+ A tuple containing:
62
+ - The quantized query tensor. Shape: Same as `q` but with `int8` dtype.
63
+ - The scale tensor of the query tensor. Shape: ``[batch_size, num_qo_heads, (qo_len + BLKQ - 1) // BLKQ]`` with `float32` dtype.
64
+ - The quantized key tensor. Shape: Same as `k` but with `int8` dtype.
65
+ - The scale tensor of the key tensor. Shape: ``[batch_size, num_kv_heads, (kv_len + BLKK - 1) // BLKK]`` with `float32` dtype.
66
+
67
+ Note
68
+ ----
69
+ - The tensors `q` and `k` must have the dtype ``torch.float16`` or ``torch.bfloat16``
70
+ """
71
+
72
+ q_int8 = torch.empty(q.shape, dtype=torch.int8, device=q.device)
73
+ k_int8 = torch.empty(k.shape, dtype=torch.int8, device=k.device)
74
+
75
+ if tensor_layout == "HND":
76
+ b, h_qo, qo_len, head_dim = q.shape
77
+ _, h_kv, kv_len, _ = k.shape
78
+
79
+ elif tensor_layout == "NHD":
80
+ b, qo_len, h_qo, head_dim = q.shape
81
+ _, kv_len, h_kv, _ = k.shape
82
+
83
+ else:
84
+ raise ValueError(f"Unknown tensor layout: {tensor_layout}")
85
+
86
+ _tensor_layout = 0 if tensor_layout == "NHD" else 1
87
+
88
+ q_scale = torch.empty((b, h_qo, (qo_len + BLKQ - 1) // BLKQ), device=q.device, dtype=torch.float32)
89
+ k_scale = torch.empty((b, h_kv, (kv_len + BLKK - 1) // BLKK), device=q.device, dtype=torch.float32)
90
+
91
+ if sm_scale is None:
92
+ sm_scale = head_dim**-0.5
93
+
94
+ sm_scale *= 1.44269504
95
+
96
+ _fused.quant_per_block_int8_cuda(q, q_int8, q_scale, sm_scale, BLKQ, _tensor_layout)
97
+ if km is not None:
98
+ km = km.squeeze(1) if _tensor_layout == 0 else km.squeeze(2)
99
+ _fused.quant_per_block_int8_fuse_sub_mean_cuda(k, km, k_int8, k_scale, BLKK, _tensor_layout)
100
+ else:
101
+ _fused.quant_per_block_int8_cuda(k, k_int8, k_scale, BLKK, _tensor_layout)
102
+
103
+ return q_int8, q_scale, k_int8, k_scale
104
+
105
+ def per_warp_int8(
106
+ q: torch.Tensor,
107
+ k: torch.Tensor,
108
+ km: Optional[torch.Tensor] = None,
109
+ tensor_layout: str ="HND"
110
+ ):
111
+ """
112
+ Quantize the query tensor `q` with per warp quantization and the key tensor `k` with per block quantization.
113
+ Warp size of quantizing `q` is 32, with a block size of 128.
114
+ Block size of quantizing `k` is 64.
115
+
116
+ Parameters
117
+ ----------
118
+ q : torch.Tensor
119
+ The query tensor. Shape:
120
+ - If `tensor_layout` is "HND": ``[batch_size, num_qo_heads, qo_len, head_dim]``.
121
+ - If `tensor_layout` is "NHD": ``[batch_size, qo_len, num_qo_heads, head_dim]``.
122
+
123
+ k : torch.Tensor
124
+ The key tensor. Shape:
125
+ - If `tensor_layout` is "HND": ``[batch_size, num_kv_heads, kv_len, head_dim]``.
126
+ - If `tensor_layout` is "NHD": ``[batch_size, kv_len, num_kv_heads, head_dim]``.
127
+
128
+ km : Optional[torch.Tensor]
129
+ The mean tensor of `k` along the sequence length dimension. Shape: ``[batch_size, num_kv_heads, head_dim]``.
130
+ Should be of the same dtype as `k` if provided. Default is None.
131
+
132
+ tensor_layout : str
133
+ The tensor layout, either "HND" or "NHD".
134
+ Default: "HND".
135
+
136
+ Returns
137
+ -------
138
+ Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]
139
+ A tuple containing:
140
+ - The quantized query tensor. Shape: Same as `q` but with `int8` dtype.
141
+ - The scale tensor of the query tensor. Shape: ``[batch_size, num_qo_heads, (qo_len + BLKQ - 1) // 128 * 4]`` with `float32` dtype.
142
+ - The quantized key tensor. Shape: Same as `k` but with `int8` dtype.
143
+ - The scale tensor of the key tensor. Shape: ``[batch_size, num_kv_heads, (kv_len + BLKK - 1) // 64]`` with `float32` dtype.
144
+
145
+ Note
146
+ ----
147
+ - The tensors `q` and `k` must have the dtype ``torch.float16`` or ``torch.bfloat16``
148
+ """
149
+
150
+ q_int8 = torch.empty(q.shape, dtype=torch.int8, device=q.device)
151
+ k_int8 = torch.empty(k.shape, dtype=torch.int8, device=k.device)
152
+
153
+ if tensor_layout == "HND":
154
+ b, h_qo, qo_len, head_dim = q.shape
155
+ _, h_kv, kv_len, _ = k.shape
156
+
157
+ elif tensor_layout == "NHD":
158
+ b, qo_len, h_qo, head_dim = q.shape
159
+ _, kv_len, h_kv, _ = k.shape
160
+
161
+ else:
162
+ raise ValueError(f"Unknown tensor layout: {tensor_layout}")
163
+
164
+ _tensor_layout = 0 if tensor_layout == "NHD" else 1
165
+
166
+ q_scale = torch.empty((b, h_qo, ((qo_len + 127) // 128) * (128 // 32)), device=q.device, dtype=torch.float32)
167
+ k_scale = torch.empty((b, h_kv, (kv_len + 63) // 64), device=q.device, dtype=torch.float32)
168
+
169
+ _fused.quant_per_warp_int8_cuda(q, q_int8, q_scale, _tensor_layout)
170
+
171
+ if km is not None:
172
+ km = km.squeeze(1) if _tensor_layout == 0 else km.squeeze(2)
173
+ _fused.quant_per_block_int8_fuse_sub_mean_cuda(k, km, k_int8, k_scale, 64, _tensor_layout)
174
+ else:
175
+ _fused.quant_per_block_int8_cuda(k, k_int8, k_scale, 64, _tensor_layout)
176
+
177
+ return q_int8, q_scale, k_int8, k_scale
178
+
179
+