main
cuh 504 lines 11.8 KB
Raw
1 /*
2 * Adapted from
3 * https://github.com/NVIDIA/FasterTransformer/blob/release/v5.3_tag/src/fastertransformer/kernels/decoder_masked_multihead_attention/decoder_masked_multihead_attention_template.hpp
4 * and
5 * https://github.com/NVIDIA/FasterTransformer/blob/release/v5.3_tag/src/fastertransformer/kernels/decoder_masked_multihead_attention_utils.h
6 * Copyright (c) 2023, The vLLM team.
7 * Copyright (c) 2020-2023, NVIDIA CORPORATION. All rights reserved.
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21 #pragma once
22
23 #include "attention_generic.cuh"
24 #include "dtype_float32.cuh"
25
26 #ifdef USE_ROCM
27 #include <hip/hip_fp16.h>
28 #endif
29
30 #include <stdint.h>
31
32 namespace vllm {
33
34 // FP16 vector types for Q, K, V.
35 template <>
36 struct Vec<uint16_t, 1> {
37 using Type = uint16_t;
38 };
39 template <>
40 struct Vec<uint16_t, 2> {
41 using Type = uint32_t;
42 };
43 template <>
44 struct Vec<uint16_t, 4> {
45 using Type = uint2;
46 };
47 template <>
48 struct Vec<uint16_t, 8> {
49 using Type = uint4;
50 };
51
52 // FP32 accumulator vector types corresponding to Vec.
53 template <>
54 struct FloatVec<uint16_t> {
55 using Type = float;
56 };
57 template <>
58 struct FloatVec<uint32_t> {
59 using Type = float2;
60 };
61 template <>
62 struct FloatVec<uint2> {
63 using Type = Float4_;
64 };
65 template <>
66 struct FloatVec<uint4> {
67 using Type = Float8_;
68 };
69
70 // Utility functions for type conversions.
71 inline __device__ uint32_t h0_h0(uint16_t a) {
72 #ifndef USE_ROCM
73 uint32_t b;
74 asm volatile("mov.b32 %0, {%1, %1};" : "=r"(b) : "h"(a));
75 return b;
76 #else
77 union {
78 uint32_t u32;
79 uint16_t u16[2];
80 } tmp;
81 tmp.u16[0] = a;
82 tmp.u16[1] = a;
83 return tmp.u32;
84 #endif
85 }
86
87 inline __device__ float half_to_float(uint16_t h) {
88 float f;
89 #ifndef USE_ROCM
90 asm volatile("cvt.f32.f16 %0, %1;\n" : "=f"(f) : "h"(h));
91 #else
92 asm volatile("v_cvt_f32_f16 %0, %1;" : "=v"(f) : "v"(h));
93 #endif
94 return f;
95 }
96
97 inline __device__ float2 half2_to_float2(uint32_t v) {
98 #ifndef USE_ROCM
99 uint16_t lo, hi;
100 asm volatile("mov.b32 {%0, %1}, %2;\n" : "=h"(lo), "=h"(hi) : "r"(v));
101 return make_float2(half_to_float(lo), half_to_float(hi));
102 #else
103 union {
104 uint32_t u32;
105 uint16_t u16[2];
106 } tmp;
107 tmp.u32 = v;
108 float2 ret;
109 ret.x = half_to_float(tmp.u16[0]);
110 ret.y = half_to_float(tmp.u16[1]);
111 return ret;
112 #endif
113 }
114
115 inline __device__ uint16_t float_to_half(float f) {
116 union {
117 uint32_t u32;
118 uint16_t u16[2];
119 } tmp;
120 #ifndef USE_ROCM
121 asm volatile("cvt.rn.f16.f32 %0, %1;\n" : "=h"(tmp.u16[0]) : "f"(f));
122 #else
123 asm volatile("v_cvt_f16_f32 %0, %1;\n" : "=v"(tmp.u32) : "v"(f));
124 #endif
125 return tmp.u16[0];
126 }
127
128 inline __device__ uint32_t float2_to_half2(float2 f) {
129 union {
130 uint32_t u32;
131 uint16_t u16[2];
132 } tmp;
133 #ifndef USE_ROCM
134 #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800
135 asm volatile("cvt.rn.f16x2.f32 %0, %1, %2;\n"
136 : "=r"(tmp.u32)
137 : "f"(f.y), "f"(f.x));
138 #else
139 asm volatile("cvt.rn.f16.f32 %0, %1;\n" : "=h"(tmp.u16[0]) : "f"(f.x));
140 asm volatile("cvt.rn.f16.f32 %0, %1;\n" : "=h"(tmp.u16[1]) : "f"(f.y));
141 #endif
142 #else
143 tmp.u16[0] = float_to_half(f.x);
144 tmp.u16[1] = float_to_half(f.y);
145 #endif
146 return tmp.u32;
147 }
148
149 // Vector addition.
150 inline __device__ uint16_t add(uint16_t a, uint16_t b) {
151 uint16_t c;
152 #ifndef USE_ROCM
153 asm volatile("add.f16 %0, %1, %2;\n" : "=h"(c) : "h"(a), "h"(b));
154 #else
155 asm volatile("v_add_f16 %0, %1, %2;\n" : "=v"(c) : "v"(a), "v"(b));
156 #endif
157 return c;
158 }
159
160 inline __device__ uint32_t add(uint32_t a, uint32_t b) {
161 uint32_t c;
162 #ifndef USE_ROCM
163 asm volatile("add.f16x2 %0, %1, %2;\n" : "=r"(c) : "r"(a), "r"(b));
164 #else
165 asm volatile("v_pk_add_f16 %0, %1, %2;\n" : "=v"(c) : "v"(a), "v"(b));
166 #endif
167 return c;
168 }
169
170 inline __device__ uint2 add(uint2 a, uint2 b) {
171 uint2 c;
172 c.x = add(a.x, b.x);
173 c.y = add(a.y, b.y);
174 return c;
175 }
176
177 inline __device__ uint4 add(uint4 a, uint4 b) {
178 uint4 c;
179 c.x = add(a.x, b.x);
180 c.y = add(a.y, b.y);
181 c.z = add(a.z, b.z);
182 c.w = add(a.w, b.w);
183 return c;
184 }
185
186 inline __device__ float2 add(uint32_t a, float2 fb) {
187 float2 fa = half2_to_float2(a);
188 return add(fa, fb);
189 }
190
191 inline __device__ Float4_ add(uint2 a, Float4_ fb) {
192 Float4_ fc;
193 fc.x = add(a.x, fb.x);
194 fc.y = add(a.y, fb.y);
195 return fc;
196 }
197
198 inline __device__ Float8_ add(uint4 a, Float8_ fb) {
199 Float8_ fc;
200 fc.x = add(a.x, fb.x);
201 fc.y = add(a.y, fb.y);
202 fc.z = add(a.z, fb.z);
203 fc.w = add(a.w, fb.w);
204 return fc;
205 }
206
207 // Vector multiplication.
208 template <>
209 inline __device__ uint16_t mul(uint16_t a, uint16_t b) {
210 uint16_t c;
211 #ifndef USE_ROCM
212 asm volatile("mul.f16 %0, %1, %2;\n" : "=h"(c) : "h"(a), "h"(b));
213 #else
214 asm volatile("v_mul_f16 %0, %1, %2;\n" : "=v"(c) : "v"(a), "v"(b));
215 #endif
216 return c;
217 }
218
219 template <>
220 inline __device__ uint32_t mul(uint32_t a, uint32_t b) {
221 uint32_t c;
222 #ifndef USE_ROCM
223 asm volatile("mul.f16x2 %0, %1, %2;\n" : "=r"(c) : "r"(a), "r"(b));
224 #else
225 asm volatile("v_pk_mul_f16 %0, %1, %2;\n" : "=v"(c) : "v"(a), "v"(b));
226 #endif
227 return c;
228 }
229
230 template <>
231 inline __device__ uint32_t mul(uint16_t a, uint32_t b) {
232 return mul<uint32_t, uint32_t, uint32_t>(h0_h0(a), b);
233 }
234
235 template <>
236 inline __device__ uint2 mul(uint2 a, uint2 b) {
237 uint2 c;
238 c.x = mul<uint32_t, uint32_t, uint32_t>(a.x, b.x);
239 c.y = mul<uint32_t, uint32_t, uint32_t>(a.y, b.y);
240 return c;
241 }
242
243 template <>
244 inline __device__ uint2 mul(uint16_t a, uint2 b) {
245 uint32_t s = h0_h0(a);
246 uint2 c;
247 c.x = mul<uint32_t, uint32_t, uint32_t>(s, b.x);
248 c.y = mul<uint32_t, uint32_t, uint32_t>(s, b.y);
249 return c;
250 }
251
252 template <>
253 inline __device__ uint4 mul(uint4 a, uint4 b) {
254 uint4 c;
255 c.x = mul<uint32_t, uint32_t, uint32_t>(a.x, b.x);
256 c.y = mul<uint32_t, uint32_t, uint32_t>(a.y, b.y);
257 c.z = mul<uint32_t, uint32_t, uint32_t>(a.z, b.z);
258 c.w = mul<uint32_t, uint32_t, uint32_t>(a.w, b.w);
259 return c;
260 }
261
262 template <>
263 inline __device__ uint4 mul(uint16_t a, uint4 b) {
264 uint32_t s = h0_h0(a);
265 uint4 c;
266 c.x = mul<uint32_t, uint32_t, uint32_t>(s, b.x);
267 c.y = mul<uint32_t, uint32_t, uint32_t>(s, b.y);
268 c.z = mul<uint32_t, uint32_t, uint32_t>(s, b.z);
269 c.w = mul<uint32_t, uint32_t, uint32_t>(s, b.w);
270 return c;
271 }
272
273 template <>
274 inline __device__ float mul(uint16_t a, uint16_t b) {
275 float fa = half_to_float(a);
276 float fb = half_to_float(b);
277 return fa * fb;
278 }
279
280 template <>
281 inline __device__ float2 mul(uint32_t a, uint32_t b) {
282 float2 fa = half2_to_float2(a);
283 float2 fb = half2_to_float2(b);
284 return mul<float2, float2, float2>(fa, fb);
285 }
286
287 template <>
288 inline __device__ float2 mul(uint16_t a, uint32_t b) {
289 return mul<float2, uint32_t, uint32_t>(h0_h0(a), b);
290 }
291
292 template <>
293 inline __device__ Float4_ mul(uint2 a, uint2 b) {
294 Float4_ fc;
295 fc.x = mul<float2, uint32_t, uint32_t>(a.x, b.x);
296 fc.y = mul<float2, uint32_t, uint32_t>(a.y, b.y);
297 return fc;
298 }
299
300 template <>
301 inline __device__ Float4_ mul(uint16_t a, uint2 b) {
302 uint32_t s = h0_h0(a);
303 Float4_ fc;
304 fc.x = mul<float2, uint32_t, uint32_t>(s, b.x);
305 fc.y = mul<float2, uint32_t, uint32_t>(s, b.y);
306 return fc;
307 }
308
309 template <>
310 inline __device__ Float8_ mul(uint4 a, uint4 b) {
311 Float8_ fc;
312 fc.x = mul<float2, uint32_t, uint32_t>(a.x, b.x);
313 fc.y = mul<float2, uint32_t, uint32_t>(a.y, b.y);
314 fc.z = mul<float2, uint32_t, uint32_t>(a.z, b.z);
315 fc.w = mul<float2, uint32_t, uint32_t>(a.w, b.w);
316 return fc;
317 }
318
319 template <>
320 inline __device__ Float8_ mul(uint16_t a, uint4 b) {
321 uint32_t s = h0_h0(a);
322 Float8_ fc;
323 fc.x = mul<float2, uint32_t, uint32_t>(s, b.x);
324 fc.y = mul<float2, uint32_t, uint32_t>(s, b.y);
325 fc.z = mul<float2, uint32_t, uint32_t>(s, b.z);
326 fc.w = mul<float2, uint32_t, uint32_t>(s, b.w);
327 return fc;
328 }
329
330 // Vector fused multiply-add.
331 inline __device__ uint32_t fma(uint32_t a, uint32_t b, uint32_t c) {
332 uint32_t d;
333 #ifndef USE_ROCM
334 asm volatile("fma.rn.f16x2 %0, %1, %2, %3;\n"
335 : "=r"(d)
336 : "r"(a), "r"(b), "r"(c));
337 #else
338 asm volatile("v_pk_fma_f16 %0, %1, %2, %3;\n"
339 : "=v"(d)
340 : "v"(a), "v"(b), "v"(c));
341 #endif
342 return d;
343 }
344
345 inline __device__ uint32_t fma(uint16_t a, uint32_t b, uint32_t c) {
346 return fma(h0_h0(a), b, c);
347 }
348
349 inline __device__ uint2 fma(uint2 a, uint2 b, uint2 c) {
350 uint2 d;
351 d.x = fma(a.x, b.x, c.x);
352 d.y = fma(a.y, b.y, c.y);
353 return d;
354 }
355
356 inline __device__ uint2 fma(uint16_t a, uint2 b, uint2 c) {
357 uint32_t s = h0_h0(a);
358 uint2 d;
359 d.x = fma(s, b.x, c.x);
360 d.y = fma(s, b.y, c.y);
361 return d;
362 }
363
364 inline __device__ uint4 fma(uint4 a, uint4 b, uint4 c) {
365 uint4 d;
366 d.x = fma(a.x, b.x, c.x);
367 d.y = fma(a.y, b.y, c.y);
368 d.z = fma(a.z, b.z, c.z);
369 d.w = fma(a.w, b.w, c.w);
370 return d;
371 }
372
373 inline __device__ uint4 fma(uint16_t a, uint4 b, uint4 c) {
374 uint32_t s = h0_h0(a);
375 uint4 d;
376 d.x = fma(s, b.x, c.x);
377 d.y = fma(s, b.y, c.y);
378 d.z = fma(s, b.z, c.z);
379 d.w = fma(s, b.w, c.w);
380 return d;
381 }
382
383 inline __device__ float fma(uint16_t a, uint16_t b, float fc) {
384 float fa = half_to_float(a);
385 float fb = half_to_float(b);
386 return fa * fb + fc;
387 }
388
389 inline __device__ float2 fma(uint32_t a, uint32_t b, float2 fc) {
390 float2 fa = half2_to_float2(a);
391 float2 fb = half2_to_float2(b);
392 return fma(fa, fb, fc);
393 }
394
395 inline __device__ float2 fma(uint16_t a, uint32_t b, float2 fc) {
396 return fma(h0_h0(a), b, fc);
397 }
398
399 inline __device__ Float4_ fma(uint2 a, uint2 b, Float4_ fc) {
400 Float4_ fd;
401 fd.x = fma(a.x, b.x, fc.x);
402 fd.y = fma(a.y, b.y, fc.y);
403 return fd;
404 }
405
406 inline __device__ Float4_ fma(uint16_t a, uint2 b, Float4_ fc) {
407 uint32_t s = h0_h0(a);
408 Float4_ fd;
409 fd.x = fma(s, b.x, fc.x);
410 fd.y = fma(s, b.y, fc.y);
411 return fd;
412 }
413
414 inline __device__ Float8_ fma(uint4 a, uint4 b, Float8_ fc) {
415 Float8_ fd;
416 fd.x = fma(a.x, b.x, fc.x);
417 fd.y = fma(a.y, b.y, fc.y);
418 fd.z = fma(a.z, b.z, fc.z);
419 fd.w = fma(a.w, b.w, fc.w);
420 return fd;
421 }
422
423 inline __device__ Float8_ fma(uint16_t a, uint4 b, Float8_ fc) {
424 uint32_t s = h0_h0(a);
425 Float8_ fd;
426 fd.x = fma(s, b.x, fc.x);
427 fd.y = fma(s, b.y, fc.y);
428 fd.z = fma(s, b.z, fc.z);
429 fd.w = fma(s, b.w, fc.w);
430 return fd;
431 }
432
433 // Vector sum.
434 template <>
435 inline __device__ float sum(uint16_t v) {
436 return half_to_float(v);
437 }
438
439 template <>
440 inline __device__ float sum(uint32_t v) {
441 float2 tmp = half2_to_float2(v);
442 return tmp.x + tmp.y;
443 }
444
445 template <>
446 inline __device__ float sum(uint2 v) {
447 uint32_t c = add(v.x, v.y);
448 return sum(c);
449 }
450
451 template <>
452 inline __device__ float sum(uint4 v) {
453 uint32_t c = add(v.x, v.y);
454 c = add(c, v.z);
455 c = add(c, v.w);
456 return sum(c);
457 }
458
459 // From float32 to float16.
460 inline __device__ void from_float(uint16_t& dst, float src) {
461 dst = float_to_half(src);
462 }
463
464 inline __device__ void from_float(uint32_t& dst, float2 src) {
465 dst = float2_to_half2(src);
466 }
467
468 inline __device__ void from_float(uint2& dst, Float4_ src) {
469 dst.x = float2_to_half2(src.x);
470 dst.y = float2_to_half2(src.y);
471 }
472
473 inline __device__ void from_float(uint4& dst, Float8_ src) {
474 dst.x = float2_to_half2(src.x);
475 dst.y = float2_to_half2(src.y);
476 dst.z = float2_to_half2(src.z);
477 dst.w = float2_to_half2(src.w);
478 }
479
480 // From float16 to float32.
481 inline __device__ float to_float(uint16_t u) { return half_to_float(u); }
482
483 inline __device__ float2 to_float(uint32_t u) { return half2_to_float2(u); }
484
485 inline __device__ Float4_ to_float(uint2 u) {
486 Float4_ tmp;
487 tmp.x = half2_to_float2(u.x);
488 tmp.y = half2_to_float2(u.y);
489 return tmp;
490 }
491
492 inline __device__ Float8_ to_float(uint4 u) {
493 Float8_ tmp;
494 tmp.x = half2_to_float2(u.x);
495 tmp.y = half2_to_float2(u.y);
496 tmp.z = half2_to_float2(u.z);
497 tmp.w = half2_to_float2(u.w);
498 return tmp;
499 }
500
501 // Zero-out a variable.
502 inline __device__ void zero(uint16_t& dst) { dst = uint16_t(0); }
503
504 } // namespace vllm