ZhengyangZhang commited on
Commit
6e8e00b
·
verified ·
1 Parent(s): 4e9dd55

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. lib/python3.12/site-packages/deepspeed/inference/v2/__pycache__/engine_factory.cpython-312.pyc +0 -0
  2. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/__init__.py +6 -0
  3. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/__pycache__/__init__.cpython-312.pyc +0 -0
  4. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/__pycache__/ds_kernel.cpython-312.pyc +0 -0
  5. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/__init__.py +11 -0
  6. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/__pycache__/__init__.cpython-312.pyc +0 -0
  7. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/__init__.py +6 -0
  8. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/__pycache__/__init__.cpython-312.pyc +0 -0
  9. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/__pycache__/bias_activation.cpython-312.pyc +0 -0
  10. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/bias_activation.cpp +68 -0
  11. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/bias_activation.h +22 -0
  12. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/bias_activation.py +62 -0
  13. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/bias_activation_cuda.cu +140 -0
  14. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/blas_kernels/__init__.py +6 -0
  15. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/blas_kernels/__pycache__/__init__.cpython-312.pyc +0 -0
  16. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/blas_kernels/__pycache__/blas_linear.cpython-312.pyc +0 -0
  17. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/blas_kernels/blas.h +138 -0
  18. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/blas_kernels/blas_linear.py +55 -0
  19. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/blas_kernels/blas_utils.h +299 -0
  20. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/core_ops.cpp +42 -0
  21. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/__init__.py +8 -0
  22. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/__pycache__/__init__.cpython-312.pyc +0 -0
  23. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/__pycache__/cuda_fp_ln_base.cpython-312.pyc +0 -0
  24. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/__pycache__/cuda_ln.cpython-312.pyc +0 -0
  25. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/__pycache__/cuda_post_ln.cpython-312.pyc +0 -0
  26. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/__pycache__/cuda_pre_ln.cpython-312.pyc +0 -0
  27. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/cuda_fp_ln_base.py +37 -0
  28. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/cuda_ln.py +30 -0
  29. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/cuda_post_ln.py +34 -0
  30. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/cuda_pre_ln.py +39 -0
  31. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/layer_norm.cpp +102 -0
  32. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/layer_norm.h +67 -0
  33. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/layer_norm_cuda.cu +489 -0
  34. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/__init__.py +6 -0
  35. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/__pycache__/__init__.cpython-312.pyc +0 -0
  36. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/__pycache__/cuda_linear.cpython-312.pyc +0 -0
  37. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/cuda_linear.py +207 -0
  38. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/configs.h +96 -0
  39. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/kernel_matmul.cuh +272 -0
  40. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/kernel_reduction.cuh +43 -0
  41. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/ptx_cp.async.cuh +75 -0
  42. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/ptx_mma.cuh +139 -0
  43. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/utils_core.cuh +246 -0
  44. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/utils_gmem.cuh +86 -0
  45. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/utils_paralleldequant.cuh +127 -0
  46. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/weight_prepacking.h +209 -0
  47. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/linear_kernels.cpp +224 -0
  48. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/linear_kernels.h +28 -0
  49. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/linear_kernels_cuda.cu +318 -0
  50. lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/linear_kernels_cuda.h +51 -0
lib/python3.12/site-packages/deepspeed/inference/v2/__pycache__/engine_factory.cpython-312.pyc ADDED
Binary file (6.14 kB). View file
 
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/__init__.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # Copyright (c) Microsoft Corporation.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ # DeepSpeed Team
5
+
6
+ from .ds_kernel import DSKernelBase
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (260 Bytes). View file
 
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/__pycache__/ds_kernel.cpython-312.pyc ADDED
Binary file (1.42 kB). View file
 
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/__init__.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Microsoft Corporation.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ # DeepSpeed Team
5
+
6
+ from .bias_activations import *
7
+ from .blas_kernels import *
8
+ from .cuda_layer_norm import *
9
+ from .cuda_rms_norm import *
10
+ from .gated_activations import *
11
+ from .cuda_linear import *
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (401 Bytes). View file
 
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/__init__.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # Copyright (c) Microsoft Corporation.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ # DeepSpeed Team
5
+
6
+ from .bias_activation import *
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (274 Bytes). View file
 
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/__pycache__/bias_activation.cpython-312.pyc ADDED
Binary file (3.44 kB). View file
 
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/bias_activation.cpp ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ #include "bias_activation.h"
7
+ #include <c10/cuda/CUDAStream.h>
8
+ #include "ds_kernel_utils.h"
9
+
10
+ #ifdef BF16_AVAILABLE
11
+ #define DTYPE_SWITCH(DTYPE, ...) \
12
+ [&] { \
13
+ if (DTYPE == torch::kFloat16) { \
14
+ using scalar_t = __half; \
15
+ return __VA_ARGS__(); \
16
+ } else if (DTYPE == torch::kBFloat16) { \
17
+ using scalar_t = __nv_bfloat16; \
18
+ return __VA_ARGS__(); \
19
+ } else { \
20
+ TORCH_CHECK(false, "Unsupported dtype for BiasActivation"); \
21
+ } \
22
+ }()
23
+ #else
24
+ #define DTYPE_SWITCH(DTYPE, ...) \
25
+ [&] { \
26
+ if (DTYPE == torch::kFloat16) { \
27
+ using scalar_t = __half; \
28
+ return __VA_ARGS__(); \
29
+ } else { \
30
+ TORCH_CHECK(false, "Unsupported dtype for BiasActivation"); \
31
+ } \
32
+ }()
33
+ #endif
34
+
35
+ /*
36
+ In-place bias and activation fusion kernel.
37
+ */
38
+ void bias_activation(torch::Tensor& activation,
39
+ c10::optional<torch::Tensor>& bias,
40
+ const int32_t act_type)
41
+ {
42
+ const ActivationType atype = static_cast<ActivationType>(act_type);
43
+ const int32_t rows = activation.size(0);
44
+ const int32_t cols = activation.size(1);
45
+
46
+ TORCH_CHECK(atype == ActivationType::GELU || atype == ActivationType::RELU ||
47
+ atype == ActivationType::SILU || atype == ActivationType::IDENTITY,
48
+ "Unsupported activation type for BiasActivation");
49
+ TORCH_CHECK(activation.dim() == 2, "BiasActivation only supports 2D activation tensors");
50
+
51
+ DTYPE_SWITCH(activation.scalar_type(), [&] {
52
+ scalar_t* activation_ptr = reinterpret_cast<scalar_t*>(activation.data_ptr());
53
+
54
+ const scalar_t* bias_ptr;
55
+ if (bias.has_value()) {
56
+ TORCH_CHECK(activation.scalar_type() == bias.value().scalar_type(),
57
+ "BiasActivation activation and bias must have same dtype");
58
+ bias_ptr = reinterpret_cast<const scalar_t*>(bias.value().data_ptr());
59
+ } else {
60
+ bias_ptr = nullptr;
61
+ }
62
+
63
+ if (atype == ActivationType::IDENTITY && bias_ptr == nullptr) { return; }
64
+
65
+ launch_bias_activation<scalar_t>(
66
+ activation_ptr, bias_ptr, rows, cols, atype, c10::cuda::getCurrentCUDAStream());
67
+ });
68
+ }
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/bias_activation.h ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ #pragma once
7
+
8
+ #include <c10/cuda/CUDAStream.h>
9
+ #include <torch/extension.h>
10
+ #include "activation_type.h"
11
+
12
+ template <typename T>
13
+ void launch_bias_activation(T* activation,
14
+ const T* bias,
15
+ const int32_t n_rows,
16
+ const int32_t n_cols,
17
+ const ActivationType activation_type,
18
+ cudaStream_t stream);
19
+
20
+ void bias_activation(torch::Tensor& activation,
21
+ c10::optional<torch::Tensor>& bias,
22
+ const int32_t activation_type);
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/bias_activation.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Microsoft Corporation.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ # DeepSpeed Team
5
+
6
+ from typing import Optional
7
+
8
+ import torch
9
+
10
+ from ....inference_utils import ActivationType, DtypeEnum
11
+ from deepspeed.ops.op_builder import InferenceCoreBuilder
12
+ from ... import DSKernelBase
13
+
14
+
15
+ class CUDABiasActivation(DSKernelBase):
16
+ """
17
+ CUDA implementation of bias activation kernel. This kernel should be deprecated once
18
+ we are fusing the bias activation into the linear kernel in all scenarios.
19
+ """
20
+
21
+ supported_dtypes = [DtypeEnum.fp16, DtypeEnum.bf16]
22
+ supported_act_fns = [ActivationType.IDENTITY, ActivationType.GELU, ActivationType.RELU, ActivationType.SILU]
23
+
24
+ def __init__(self, channels: int, dtype: DtypeEnum, act_fn: ActivationType) -> None:
25
+ """
26
+ Compile and validate for the fused bias-activation kernel.
27
+
28
+ Parameters:
29
+ channels (int): Number of channels to expect in the activation.
30
+ dtype (torch.dtype): Data type for the input/output. Supported values
31
+ are DtypeEnum.fp16 and DtypeEnum.bf16.
32
+ act_fn (ActivationType): Activation function to use. Only IDENTITY, GELU, RELU, and SILU are supported.
33
+ """
34
+
35
+ if channels % 8 != 0:
36
+ raise ValueError("channels must be divisible by 8")
37
+
38
+ if DtypeEnum(dtype) not in CUDABiasActivation.supported_dtypes:
39
+ raise ValueError("Unsupported data type: {}, supported_dtypes are {}".format(
40
+ dtype, CUDABiasActivation.supported_dtypes))
41
+
42
+ act_fn = ActivationType(act_fn)
43
+ if act_fn not in CUDABiasActivation.supported_act_fns:
44
+ raise ValueError("Unsupported activation function: {}, supported_act_fns are {}".format(
45
+ act_fn, CUDABiasActivation.supported_act_fns))
46
+
47
+ inf_module = InferenceCoreBuilder().load()
48
+ self.kernel = inf_module.bias_activation
49
+ self.act_fn = act_fn
50
+
51
+ def __call__(self, activation: torch.Tensor, bias: Optional[torch.Tensor] = None) -> torch.Tensor:
52
+ """
53
+ Add an optional bias and perform the non-linear activation function.
54
+
55
+ Parameters:
56
+ activation (torch.Tensor): Input tensor of shape [tokens, channels]
57
+ bias (torch.Tensor): Optional bias tensor of shape [channels]
58
+
59
+ Returns:
60
+ activation that has been updated in-place
61
+ """
62
+ self.kernel(activation, bias, self.act_fn.value)
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/bias_activation_cuda.cu ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ #include <cassert>
7
+ #include "activation_type.h"
8
+ #include "conversion_utils.h"
9
+ #include "ds_kernel_utils.h"
10
+ #include "memory_access_utils.h"
11
+
12
+ // Default activation function will error out
13
+ template <ActivationType ActType>
14
+ DS_D_INLINE float act_fn(float val);
15
+
16
+ template <>
17
+ DS_D_INLINE float act_fn<ActivationType::IDENTITY>(float val)
18
+ {
19
+ return val;
20
+ }
21
+
22
+ template <>
23
+ DS_D_INLINE float act_fn<ActivationType::RELU>(float val)
24
+ {
25
+ return val > 0.0f ? val : 0.0f;
26
+ }
27
+
28
+ template <>
29
+ DS_D_INLINE float act_fn<ActivationType::GELU>(float val)
30
+ {
31
+ constexpr float sqrt_param = 0.79788456080286535587989211986876f;
32
+ constexpr float mul_param = 0.044715f;
33
+ return val * 0.5f * (1.0f + tanhf(sqrt_param * (val + mul_param * val * val * val)));
34
+ }
35
+
36
+ template <>
37
+ DS_D_INLINE float act_fn<ActivationType::SILU>(float val)
38
+ {
39
+ return val / (1.0f + expf(-val));
40
+ }
41
+
42
+ namespace bias_act {
43
+
44
+ constexpr int access_size = 16;
45
+ constexpr int threads = 512;
46
+ constexpr int unroll = 4;
47
+
48
+ } // namespace bias_act
49
+
50
+ template <typename T, ActivationType ActType>
51
+ __global__ void bias_activation_kernel(T* activation,
52
+ const T* bias,
53
+ const int32_t rows,
54
+ const int32_t cols)
55
+ {
56
+ constexpr int vector_T = bias_act::access_size / sizeof(T);
57
+
58
+ const int32_t thread_offset = threadIdx.x * vector_T;
59
+ const int32_t block_offset = blockIdx.x * vector_T * bias_act::unroll * bias_act::threads;
60
+ const int32_t base_offset = block_offset + thread_offset;
61
+
62
+ const int32_t thread_stride = bias_act::threads * vector_T;
63
+
64
+ #pragma unroll
65
+ for (int i = 0; i < bias_act::unroll; i++) {
66
+ const int32_t iter_offset = base_offset + i * thread_stride;
67
+
68
+ const int32_t row = iter_offset / cols;
69
+
70
+ T buffer[vector_T];
71
+ T bias_buffer[vector_T];
72
+
73
+ if (row < rows) {
74
+ const int32_t col = iter_offset % cols;
75
+
76
+ mem_access::load_global<bias_act::access_size>(buffer, activation + iter_offset);
77
+ mem_access::load_global<bias_act::access_size>(
78
+ bias_buffer, bias + col, bias != nullptr);
79
+
80
+ #pragma unroll
81
+ for (int j = 0; j < vector_T; j++) {
82
+ float val =
83
+ conversion::to<float>(buffer[j]) + conversion::to<float>(bias_buffer[j]);
84
+ buffer[j] = conversion::to<T>(act_fn<ActType>(val));
85
+ }
86
+
87
+ mem_access::store_global<bias_act::access_size>(activation + iter_offset, buffer);
88
+ }
89
+ }
90
+ }
91
+
92
+ #define ACT_TYPE_SWITCH(ACT_TYPE, ...) \
93
+ if (ACT_TYPE == ActivationType::IDENTITY) { \
94
+ constexpr ActivationType act_fn_t = ActivationType::IDENTITY; \
95
+ return __VA_ARGS__(); \
96
+ } else if (ACT_TYPE == ActivationType::RELU) { \
97
+ constexpr ActivationType act_fn_t = ActivationType::RELU; \
98
+ return __VA_ARGS__(); \
99
+ } else if (ACT_TYPE == ActivationType::GELU) { \
100
+ constexpr ActivationType act_fn_t = ActivationType::GELU; \
101
+ return __VA_ARGS__(); \
102
+ } else if (ACT_TYPE == ActivationType::SILU) { \
103
+ constexpr ActivationType act_fn_t = ActivationType::SILU; \
104
+ return __VA_ARGS__(); \
105
+ } else { \
106
+ assert(false); \
107
+ }
108
+
109
+ template <typename T>
110
+ void launch_bias_activation(T* activation,
111
+ const T* bias,
112
+ const int32_t n_rows,
113
+ const int32_t n_cols,
114
+ const ActivationType activation_type,
115
+ cudaStream_t stream)
116
+ {
117
+ constexpr int32_t elems_per_block =
118
+ bias_act::threads * bias_act::unroll * bias_act::access_size / sizeof(T);
119
+ const int32_t total_elems = n_rows * n_cols;
120
+
121
+ const int32_t blocks = (total_elems + elems_per_block - 1) / elems_per_block;
122
+
123
+ const dim3 grid(blocks);
124
+ const dim3 block(bias_act::threads);
125
+
126
+ ACT_TYPE_SWITCH(activation_type, [&] {
127
+ bias_activation_kernel<T, act_fn_t>
128
+ <<<grid, block, 0, stream>>>(activation, bias, n_rows, n_cols);
129
+ });
130
+ }
131
+
132
+ #define INSTANTIATE_FOR_T(T) \
133
+ template void launch_bias_activation<T>( \
134
+ T*, const T*, const int32_t, const int32_t, const ActivationType, cudaStream_t);
135
+
136
+ INSTANTIATE_FOR_T(__half);
137
+
138
+ #ifdef BF16_AVAILABLE
139
+ INSTANTIATE_FOR_T(__nv_bfloat16);
140
+ #endif
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/blas_kernels/__init__.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # Copyright (c) Microsoft Corporation.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ # DeepSpeed Team
5
+
6
+ from .blas_linear import *
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/blas_kernels/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (266 Bytes). View file
 
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/blas_kernels/__pycache__/blas_linear.cpython-312.pyc ADDED
Binary file (2.89 kB). View file
 
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/blas_kernels/blas.h ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ #pragma once
7
+
8
+ #include <c10/cuda/CUDAStream.h>
9
+ #include <torch/extension.h>
10
+ #include <cstdio>
11
+ #include "blas_utils.h"
12
+
13
+ #define DISPATCH_BLAS_MATMUL(T_TYPE, C_TYPE) \
14
+ if (output.options().dtype() == torch::T_TYPE) { \
15
+ blas_gemm_ex(output.data_ptr(), \
16
+ (const void*)weights.data_ptr(), \
17
+ (const void*)hidden_states.data_ptr(), \
18
+ m, \
19
+ n, \
20
+ k, \
21
+ lda, \
22
+ ldb, \
23
+ ldc, \
24
+ trans_a, \
25
+ trans_b, \
26
+ &alpha, \
27
+ &beta, \
28
+ C_TYPE); \
29
+ }
30
+
31
+ void blas_linear(at::Tensor& output, at::Tensor& hidden_states, at::Tensor& weights)
32
+ {
33
+ /*
34
+ Expected shape: output([total_tokens_across_dims], out_neurons)
35
+ hidden_states([total_tokens_across_dims], in_neurons)
36
+ weights(out_neurons, in_neurons)
37
+
38
+ We are going to assume contiguous for the above shapes.
39
+
40
+ The shapes are going to get messed with a little internally to handle column-major
41
+ GEMMs.
42
+ */
43
+
44
+ // Number of tokens is N (since the GEMM output is column-major but our Tensor
45
+ // is row-major, we need to transpose the shapes)
46
+ const int n = output.numel() / output.size(-1);
47
+ const int k = weights.size(1);
48
+ const int m = weights.size(0);
49
+
50
+ // A strides
51
+ const bool trans_a = weights.stride(1) == 1;
52
+ const int lda = (trans_a) ? weights.stride(0) : weights.stride(1);
53
+
54
+ // B strides
55
+ const bool trans_b = hidden_states.stride(-1) != 1;
56
+ const int ldb = (trans_b) ? hidden_states.stride(-1) : hidden_states.stride(-2);
57
+
58
+ // C strides
59
+ const int ldc = output.stride(-2);
60
+
61
+ const float alpha = 1.0f;
62
+ const float beta = 0.0f;
63
+
64
+ TORCH_CHECK(output.scalar_type() == hidden_states.scalar_type(),
65
+ "Output and hidden states must have the same scalar type");
66
+ TORCH_CHECK(output.scalar_type() == weights.scalar_type(),
67
+ "Output and weights must have the same scalar type");
68
+
69
+ // Dispatch the datatypes
70
+ DISPATCH_BLAS_MATMUL(kFloat, BlasType::FP32);
71
+ DISPATCH_BLAS_MATMUL(kHalf, BlasType::FP16);
72
+ #ifdef BF16_AVAILABLE
73
+ DISPATCH_BLAS_MATMUL(kBFloat16, BlasType::BF16);
74
+ #endif
75
+ }
76
+
77
+ #define DISPATCH_4D_BLAS(T_TYPE, C_TYPE) \
78
+ if (C.options().dtype() == torch::T_TYPE) { \
79
+ blas_strided_batched_gemm(C.data_ptr(), \
80
+ (const void*)A.data_ptr(), \
81
+ (const void*)B.data_ptr(), \
82
+ m, \
83
+ n, \
84
+ k, \
85
+ lda, \
86
+ ldb, \
87
+ ldc, \
88
+ trans_a, \
89
+ trans_b, \
90
+ &alpha, \
91
+ &beta, \
92
+ stride_a, \
93
+ stride_b, \
94
+ stride_c, \
95
+ batch, \
96
+ C_TYPE); \
97
+ }
98
+
99
+ void blas_4d_matmul(at::Tensor& C, at::Tensor& B, at::Tensor& A)
100
+ {
101
+ /*
102
+ C shape: (batch_size, N, M)
103
+ A shape: (batch_size, N, K)
104
+ B shape: (batch_size, K, M)
105
+ */
106
+
107
+ const int n = C.size(-2);
108
+ const int k = C.size(-1);
109
+ const int m = B.size(-1);
110
+
111
+ // A strides
112
+ const bool trans_a = A.stride(-1) == 1;
113
+ const int lda = (trans_a) ? A.stride(-2) : A.stride(-1);
114
+ const int stride_a = A.stride(-3);
115
+
116
+ // B strides
117
+ const bool trans_b = B.stride(-1) != 1;
118
+ const int ldb = (trans_b) ? B.stride(-1) : B.stride(-2);
119
+ const int stride_b = B.stride(-3);
120
+
121
+ // C strides
122
+ const int ldc = C.stride(-2);
123
+ const int stride_c = C.stride(-3);
124
+
125
+ const float alpha = 1.0f;
126
+ const float beta = 0.0f;
127
+
128
+ const int batch = C.numel() / (n * m);
129
+
130
+ // Dispatch the datatypes
131
+ DISPATCH_4D_BLAS(kFloat, BlasType::FP32);
132
+ DISPATCH_4D_BLAS(kHalf, BlasType::FP16);
133
+ #ifdef BF16_AVAILABLE
134
+ DISPATCH_4D_BLAS(kBFloat16, BlasType::BF16);
135
+ #endif
136
+ }
137
+
138
+ void create_handle() { BlasContext::getInstance().get_handle(); }
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/blas_kernels/blas_linear.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Microsoft Corporation.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ # DeepSpeed Team
5
+
6
+ import torch
7
+
8
+ from ....inference_utils import DtypeEnum
9
+ from deepspeed.ops.op_builder import InferenceCoreBuilder
10
+ from ... import DSKernelBase
11
+
12
+
13
+ class BlasLibLinear(DSKernelBase):
14
+ """
15
+ Wrapper around the BLAS matmul kernel for FP16/BF16/FP32 for CUDA/RoCM.
16
+
17
+ Performs z = x @ y
18
+ """
19
+
20
+ supported_dtypes = [DtypeEnum.fp16, DtypeEnum.bf16, DtypeEnum.fp32]
21
+
22
+ def __init__(self, fp_dtype: DtypeEnum):
23
+ """
24
+ Parameters:
25
+ fp_dtype (torch.dtype): Data type for the input/output. Supported values
26
+ are torch.float16, torch.bfloat16, and torch.float32.
27
+ """
28
+ fp_dtype = DtypeEnum(fp_dtype)
29
+ if fp_dtype not in BlasLibLinear.supported_dtypes:
30
+ raise ValueError("Unsupported data type: {}, supported_dtypes are {}".format(
31
+ fp_dtype, BlasLibLinear.supported_dtypes))
32
+
33
+ self.inf_module = InferenceCoreBuilder().load()
34
+ self.inf_module.create_handle()
35
+ self.kernel = self.inf_module.blas_linear
36
+
37
+ def __call__(self, output: torch.Tensor, hidden_states: torch.Tensor, weights: torch.Tensor) -> torch.Tensor:
38
+ """
39
+ Matmul kernel as implemented by platform BLAS library. The input must be 2D or larger. If
40
+ n-dimensional, the leading dimensions are folded into each other:
41
+ 2D: m = x.size(0)
42
+ 3D: m = x.size(0) * x.size(1)
43
+ 4D: m = x.size(0) * x.size(1) * x.size(2) (etc...)
44
+ All inputs should be contiguous.
45
+
46
+ Parameters:
47
+ output (torch.Tensor): Output tensor. Shape is of [*, out_features]
48
+ hidden_states (torch.Tensor): Input tensor. Shape is of [*, in_features]
49
+ weights (torch.Tensor): Input tensor. Shape is of [out_features, in_features]
50
+
51
+ Returns:
52
+ z (torch.Tensor): Output tensor. Shape is of [m, n]
53
+ """
54
+ self.kernel(output, hidden_states, weights)
55
+ return output
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/blas_kernels/blas_utils.h ADDED
@@ -0,0 +1,299 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ #pragma once
7
+
8
+ #include <assert.h>
9
+ #include <cublas_v2.h>
10
+ #include <cuda.h>
11
+ #ifdef BF16_AVAILABLE
12
+ #include <cuda_bf16.h>
13
+ #endif
14
+ #include <cuda_fp16.h>
15
+ #include <cuda_runtime.h>
16
+ #ifndef __HIP_PLATFORM_AMD__
17
+ #include <mma.h>
18
+ #endif
19
+ #include <stdio.h>
20
+ #include <iostream>
21
+ #include <stdexcept>
22
+
23
+ class BlasContext {
24
+ /*
25
+ Slim wrapper for managing the lifetime of the platform's BLAS handle. This should
26
+ be hipified for ROCm.
27
+ */
28
+ public:
29
+ BlasContext()
30
+ {
31
+ if (cublasCreate(&_handle) != CUBLAS_STATUS_SUCCESS) {
32
+ auto message = std::string("Fail to create cublas handle.");
33
+ std::cerr << message << std::endl;
34
+ throw std::runtime_error(message);
35
+ }
36
+ #ifndef __HIP_PLATFORM_AMD__
37
+ cublasSetMathMode(_handle, CUBLAS_TENSOR_OP_MATH);
38
+ #endif
39
+ }
40
+
41
+ virtual ~BlasContext() { cublasDestroy(_handle); }
42
+
43
+ static BlasContext& getInstance()
44
+ {
45
+ // Should always access the singleton through this function.
46
+ static BlasContext _instance;
47
+ return _instance;
48
+ }
49
+
50
+ cublasHandle_t get_handle() const { return _handle; }
51
+
52
+ private:
53
+ cublasHandle_t _handle;
54
+ };
55
+
56
+ enum class BlasType { FP32, FP16, BF16 };
57
+
58
+ // TODO HIP: Remove backward compatibility for torch<=2.0 in future
59
+ #if defined(__HIP_PLATFORM_AMD__) && \
60
+ ((TORCH_VERSION_MAJOR < 2) || (TORCH_VERSION_MAJOR == 2 && TORCH_VERSION_MINOR == 0))
61
+ rocblas_operation get_trans_op(bool do_trans)
62
+ {
63
+ return (do_trans) ? rocblas_operation_transpose : rocblas_operation_none;
64
+ }
65
+
66
+ rocblas_datatype get_datatype(BlasType type)
67
+ {
68
+ switch (type) {
69
+ case BlasType::FP32: return rocblas_datatype_f32_r;
70
+ case BlasType::FP16: return rocblas_datatype_f16_r;
71
+ case BlasType::BF16: return rocblas_datatype_bf16_r;
72
+ default: throw std::runtime_error("Unsupported BlasType");
73
+ }
74
+ }
75
+ #else
76
+ cublasOperation_t get_trans_op(bool do_trans) { return (do_trans) ? CUBLAS_OP_T : CUBLAS_OP_N; }
77
+
78
+ cublasDataType_t get_datatype(BlasType type)
79
+ {
80
+ switch (type) {
81
+ #ifdef __HIP_PLATFORM_AMD__
82
+ case BlasType::FP32: return HIPBLAS_R_32F;
83
+ case BlasType::FP16: return HIPBLAS_R_16F;
84
+ case BlasType::BF16: return HIPBLAS_R_16B;
85
+ #else
86
+ case BlasType::FP32: return CUDA_R_32F;
87
+ case BlasType::FP16: return CUDA_R_16F;
88
+ case BlasType::BF16: return CUDA_R_16BF;
89
+ #endif
90
+ default: throw std::runtime_error("Unsupported BlasType");
91
+ }
92
+ }
93
+ #endif
94
+
95
+ int blas_gemm_ex(void* C,
96
+ const void* A,
97
+ const void* B,
98
+ int m,
99
+ int n,
100
+ int k,
101
+ int lda,
102
+ int ldb,
103
+ int ldc,
104
+ bool transa,
105
+ bool transb,
106
+ const float* alpha,
107
+ const float* beta,
108
+ BlasType type)
109
+ {
110
+ #if defined(__HIP_PLATFORM_AMD__) && \
111
+ ((TORCH_VERSION_MAJOR < 2) || (TORCH_VERSION_MAJOR == 2 && TORCH_VERSION_MINOR == 0))
112
+ rocblas_operation_t transa_op = get_trans_op(transa);
113
+ rocblas_operation_t transb_op = get_trans_op(transb);
114
+
115
+ rocblas_datatype_t abc_type = get_datatype(type);
116
+
117
+ rocblas_status status = rocblas_gemm_ex(BlasContext::getInstance().get_handle(),
118
+ transa_op,
119
+ transb_op,
120
+ m,
121
+ n,
122
+ k,
123
+ (const void*)alpha,
124
+ A,
125
+ abc_type,
126
+ lda,
127
+ B,
128
+ abc_type,
129
+ ldb,
130
+ (const void*)beta,
131
+ C,
132
+ abc_type,
133
+ ldc,
134
+ C,
135
+ abc_type,
136
+ ldc,
137
+ rocblas_datatype_f32_r,
138
+ rocblas_gemm_algo_standard,
139
+ 0,
140
+ 0);
141
+ #else
142
+ cublasOperation_t transa_op = get_trans_op(transa);
143
+ cublasOperation_t transb_op = get_trans_op(transb);
144
+
145
+ cublasDataType_t abc_type = get_datatype(type);
146
+ cublasStatus_t status = cublasGemmEx(BlasContext::getInstance().get_handle(),
147
+ transa_op,
148
+ transb_op,
149
+ m,
150
+ n,
151
+ k,
152
+ (const void*)alpha,
153
+ A,
154
+ abc_type,
155
+ lda,
156
+ B,
157
+ abc_type,
158
+ ldb,
159
+ (const void*)beta,
160
+ C,
161
+ abc_type,
162
+ ldc,
163
+ #if defined(__HIP_PLATFORM_AMD__) && defined(HIPBLAS_V2)
164
+ HIPBLAS_COMPUTE_32F,
165
+ #elif defined(__HIP_PLATFORM_AMD__)
166
+ HIPBLAS_R_32F,
167
+ #else
168
+ CUDA_R_32F,
169
+ #endif
170
+ CUBLAS_GEMM_DEFAULT_TENSOR_OP);
171
+ #endif
172
+
173
+ #if defined(__HIP_PLATFORM_AMD__) && \
174
+ ((TORCH_VERSION_MAJOR < 2) || (TORCH_VERSION_MAJOR == 2 && TORCH_VERSION_MINOR == 0))
175
+ if (status != rocblas_status_success) {
176
+ #else
177
+ if (status != CUBLAS_STATUS_SUCCESS) {
178
+ #endif
179
+ fprintf(stderr,
180
+ "!!!! kernel execution error. (m: %d, n: %d, k: %d, error: %d) \n",
181
+ m,
182
+ n,
183
+ k,
184
+ (int)status);
185
+ return EXIT_FAILURE;
186
+ }
187
+ return 0;
188
+ }
189
+
190
+ int blas_strided_batched_gemm(void* C,
191
+ const void* A,
192
+ const void* B,
193
+ int m,
194
+ int n,
195
+ int k,
196
+ int lda,
197
+ int ldb,
198
+ int ldc,
199
+ bool transa,
200
+ bool transb,
201
+ const float* alpha,
202
+ const float* beta,
203
+ int stride_A,
204
+ int stride_B,
205
+ int stride_C,
206
+ int batch,
207
+ BlasType type)
208
+ {
209
+ #if defined(__HIP_PLATFORM_AMD__) && \
210
+ ((TORCH_VERSION_MAJOR < 2) || (TORCH_VERSION_MAJOR == 2 && TORCH_VERSION_MINOR == 0))
211
+ rocblas_operation_t transa_op = get_trans_op(transa);
212
+ rocblas_operation_t transb_op = get_trans_op(transb);
213
+
214
+ rocblas_datatype_t abc_type = get_datatype(type);
215
+
216
+ rocblas_status status =
217
+ rocblas_gemm_strided_batched_ex(BlasContext::getInstance()::get_handle(),
218
+ transa_op,
219
+ transb_op,
220
+ m,
221
+ n,
222
+ k,
223
+ (const void*)alpha,
224
+ A,
225
+ abc_type,
226
+ lda,
227
+ stride_A,
228
+ B,
229
+ abc_type,
230
+ ldb,
231
+ stride_B,
232
+ (const void*)beta,
233
+ C,
234
+ abc_type,
235
+ ldc,
236
+ stride_C,
237
+ C,
238
+ abc_type,
239
+ ldc,
240
+ stride_C,
241
+ batch,
242
+ rocblas_datatype_f32_r,
243
+ rocblas_gemm_algo_standard,
244
+ 0,
245
+ 0);
246
+ #else
247
+ cublasOperation_t transa_op = get_trans_op(transa);
248
+ cublasOperation_t transb_op = get_trans_op(transb);
249
+
250
+ cublasDataType_t abc_type = get_datatype(type);
251
+
252
+ cublasStatus_t status = cublasGemmStridedBatchedEx(BlasContext::getInstance().get_handle(),
253
+ transa_op,
254
+ transb_op,
255
+ m,
256
+ n,
257
+ k,
258
+ (const void*)alpha,
259
+ A,
260
+ abc_type,
261
+ lda,
262
+ stride_A,
263
+ B,
264
+ abc_type,
265
+ ldb,
266
+ stride_B,
267
+ (const void*)beta,
268
+ C,
269
+ abc_type,
270
+ ldc,
271
+ stride_C,
272
+ batch,
273
+ #if defined(__HIP_PLATFORM_AMD__) && defined(HIPBLAS_V2)
274
+ HIPBLAS_COMPUTE_32F,
275
+ #elif defined(__HIP_PLATFORM_AMD__)
276
+ HIPBLAS_R_32F,
277
+ #else
278
+ CUDA_R_32F,
279
+ #endif
280
+ CUBLAS_GEMM_DEFAULT_TENSOR_OP);
281
+ #endif
282
+
283
+ #if defined(__HIP_PLATFORM_AMD__) && \
284
+ ((TORCH_VERSION_MAJOR < 2) || (TORCH_VERSION_MAJOR == 2 && TORCH_VERSION_MINOR == 0))
285
+ if (status != rocblas_status_success) {
286
+ #else
287
+ if (status != CUBLAS_STATUS_SUCCESS) {
288
+ #endif
289
+ fprintf(stderr,
290
+ "!!!! kernel execution error. (batch: %d, m: %d, n: %d, k: %d, error: %d) \n",
291
+ batch,
292
+ m,
293
+ n,
294
+ k,
295
+ (int)status);
296
+ return EXIT_FAILURE;
297
+ }
298
+ return 0;
299
+ }
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/core_ops.cpp ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ #include <c10/cuda/CUDAStream.h>
7
+ #include <torch/extension.h>
8
+
9
+ #include "bias_activation.h"
10
+ #include "blas.h"
11
+ #include "gated_activation_kernels.h"
12
+ #include "layer_norm.h"
13
+ #include "linear_kernels.h"
14
+ #include "rms_norm.h"
15
+
16
+ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m)
17
+ {
18
+ // bias_activation.h
19
+ m.def("bias_activation", &bias_activation, "DeepSpeed bias activation in CUDA");
20
+
21
+ // layer_norm.h
22
+ m.def("layer_norm", &ds_layer_norm, "DeepSpeed layer norm in CUDA");
23
+ m.def("pre_layer_norm", &ds_pre_layer_norm, "DeepSpeed pre layer norm in CUDA");
24
+ m.def("post_layer_norm", &ds_post_layer_norm, "DeepSpeed pre layer norm in CUDA");
25
+
26
+ // blas.h
27
+ m.def("blas_linear", &blas_linear, "Linear implemented by vendor BLAS");
28
+ m.def("blas_4d_matmul", &blas_4d_matmul, "4D matmul implemented by vendor BLAS");
29
+ m.def("create_handle", &create_handle, "Create a handle for vendor BLAS");
30
+
31
+ // gated_activation_kernels.h
32
+ m.def("gated_activation", &ds_gated_activation, "DeepSpeed gated activation in CUDA");
33
+
34
+ // rms_norm.h
35
+ m.def("rms_norm", &rms_norm, "DeepSpeed rms norm in CUDA");
36
+ m.def("rms_pre_norm", &rms_pre_norm, "DeepSpeed rms pre norm in CUDA");
37
+
38
+ // linear_kernels.h
39
+ m.def("cuda_wf6af16_linear", &cuda_wf6af16_linear, "DeepSpeed Wf6Af16 linear in CUDA");
40
+ m.def(
41
+ "preprocess_weight", &preprocess_weight, "preprocess the FP16 weight to be 2bit and 4 bit");
42
+ }
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/__init__.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Microsoft Corporation.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ # DeepSpeed Team
5
+
6
+ from .cuda_ln import *
7
+ from .cuda_post_ln import *
8
+ from .cuda_pre_ln import *
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (318 Bytes). View file
 
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/__pycache__/cuda_fp_ln_base.cpython-312.pyc ADDED
Binary file (2 kB). View file
 
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/__pycache__/cuda_ln.cpython-312.pyc ADDED
Binary file (1.43 kB). View file
 
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/__pycache__/cuda_post_ln.cpython-312.pyc ADDED
Binary file (1.6 kB). View file
 
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/__pycache__/cuda_pre_ln.cpython-312.pyc ADDED
Binary file (1.91 kB). View file
 
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/cuda_fp_ln_base.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Microsoft Corporation.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ # DeepSpeed Team
5
+
6
+ import torch
7
+
8
+ from ... import DSKernelBase
9
+ from ....inference_utils import elem_size
10
+ from deepspeed.ops.op_builder import InferenceCoreBuilder
11
+
12
+
13
+ class CUDAFPLNBase(DSKernelBase):
14
+ """
15
+ Base class for CUDA LN kernels. They all same the same validation logic,
16
+ so we can share it here.
17
+ """
18
+
19
+ supported_dtypes = [torch.float16, torch.bfloat16, torch.float32]
20
+
21
+ def __init__(self, channels: int, fp_dtype: torch.dtype, epsilon: float = 1e-5):
22
+ """
23
+ Parameters:
24
+ channels (int): Number of channels in the input tensor. Must be divisible to align
25
+ to 16 bytes.
26
+ fp_dtype (torch.dtype): Data type for the input/output/gamma. Supported values
27
+ are torch.float16, torch.bfloat16, and torch.float32.
28
+ """
29
+ if fp_dtype not in CUDAFPLNBase.supported_dtypes:
30
+ raise ValueError("Unsupported data type: {}, supported_dtypes are {}".format(
31
+ fp_dtype, CUDAFPLNBase.supported_dtypes))
32
+
33
+ if elem_size(fp_dtype) * channels % 16 != 0:
34
+ raise ValueError("channels must be divisible by 16 bytes")
35
+
36
+ self.inf_module = InferenceCoreBuilder().load()
37
+ self.epsilon = epsilon
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/cuda_ln.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Microsoft Corporation.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ # DeepSpeed Team
5
+
6
+ import torch
7
+
8
+ from .cuda_fp_ln_base import CUDAFPLNBase
9
+
10
+
11
+ class CUDAFPLN(CUDAFPLNBase):
12
+ """
13
+ Floating point layer norm kernel for CUDA/RoCM.
14
+
15
+ Performs: z = ln(x)
16
+ """
17
+
18
+ def __call__(self, output_z: torch.Tensor, input_x: torch.Tensor, gamma: torch.Tensor,
19
+ beta: torch.Tensor) -> torch.Tensor:
20
+ """
21
+ output_z may alias input_x directly. All Tensors should have the same shape.
22
+
23
+ Parameters:
24
+ output_z (torch.Tensor): Output tensor.
25
+ input_x (torch.Tensor): Input tensor.
26
+ gamma (torch.Tensor): Gamma tensor.
27
+ beta (torch.Tensor): Beta tensor.
28
+ """
29
+ self.inf_module.layer_norm(output_z, input_x, gamma, beta, self.epsilon)
30
+ return output_z
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/cuda_post_ln.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Microsoft Corporation.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ # DeepSpeed Team
5
+
6
+ import torch
7
+
8
+ from .cuda_fp_ln_base import CUDAFPLNBase
9
+
10
+
11
+ class CUDAFPPostLN(CUDAFPLNBase):
12
+ """
13
+ Floating point post-LayerNorm kernel for CUDA/RoCM.
14
+
15
+ Performs: z = ln(x + y)
16
+ """
17
+
18
+ def __call__(self, output_z: torch.Tensor, input_x: torch.Tensor, input_y: torch.Tensor, gamma: torch.Tensor,
19
+ beta: torch.Tensor) -> torch.Tensor:
20
+ """
21
+ Either input_x or input_y can alias output_z.
22
+
23
+ Parameters:
24
+ output_z (torch.Tensor): Output tensor.
25
+ input_x (torch.Tensor): Input tensor.
26
+ input_y (torch.Tensor): Input tensor.
27
+ gamma (torch.Tensor): Gamma tensor.
28
+ beta (torch.Tensor): Beta tensor.
29
+
30
+ Returns:
31
+ output (torch.Tensor): Output tensor.
32
+ """
33
+ self.inf_module.post_layer_norm(output_z, input_x, input_y, gamma, beta, self.epsilon)
34
+ return output_z
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/cuda_pre_ln.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Microsoft Corporation.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ # DeepSpeed Team
5
+
6
+ from typing import Tuple
7
+
8
+ import torch
9
+
10
+ from .cuda_fp_ln_base import CUDAFPLNBase
11
+
12
+
13
+ class CUDAFPPreLN(CUDAFPLNBase):
14
+ """
15
+ Floating point pre-LayerNorm kernel for CUDA/RoCM.
16
+
17
+ Performs: z_res = x_res + y_hid
18
+ z_hid = ln(z_hid)
19
+ """
20
+
21
+ def __call__(self, z_res: torch.Tensor, z_hid: torch.Tensor, x_res: torch.Tensor, y_hid: torch.Tensor,
22
+ gamma: torch.Tensor, beta: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
23
+ """
24
+ z_res can alias x_res. All non-parameter input/output tensors
25
+ must have the same shape. z_hid can alias y_hid.
26
+
27
+ Parameters:
28
+ z_res (torch.Tensor): Output residual.
29
+ z_hid (torch.Tensor): Output hidden states.
30
+ x_res (torch.Tensor): Input residual.
31
+ y_hid (torch.Tensor): Input hidden states.
32
+ gamma (torch.Tensor): Gamma tensor.
33
+ beta (torch.Tensor): Beta tensor.
34
+
35
+ Returns:
36
+ output (torch.Tensor): Output tensor.
37
+ """
38
+ self.inf_module.pre_layer_norm(z_res, z_hid, x_res, y_hid, gamma, beta, self.epsilon)
39
+ return z_res, z_hid
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/layer_norm.cpp ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ #include "layer_norm.h"
7
+
8
+ #define DISPATCH_LAYER_NORM(T_TYPE, C_TYPE) \
9
+ if (input.options().dtype() == torch::T_TYPE) { \
10
+ launch_fused_ln((C_TYPE*)output.data_ptr(), \
11
+ (const C_TYPE*)input.data_ptr(), \
12
+ (const C_TYPE*)gamma.data_ptr(), \
13
+ (const C_TYPE*)beta.data_ptr(), \
14
+ epsilon, \
15
+ rows, \
16
+ elems_per_row, \
17
+ at::cuda::getCurrentCUDAStream()); \
18
+ }
19
+
20
+ void ds_layer_norm(at::Tensor& output,
21
+ at::Tensor& input,
22
+ at::Tensor& gamma,
23
+ at::Tensor& beta,
24
+ float epsilon)
25
+ {
26
+ bool ragged_input = input.dim() == 2;
27
+
28
+ const int rows = ragged_input ? input.size(0) : input.size(0) * input.size(1);
29
+ const int elems_per_row = ragged_input ? input.size(1) : input.size(2);
30
+
31
+ DISPATCH_LAYER_NORM(kFloat, float);
32
+ DISPATCH_LAYER_NORM(kHalf, __half);
33
+ #ifdef BF16_AVAILABLE
34
+ DISPATCH_LAYER_NORM(kBFloat16, __nv_bfloat16);
35
+ #endif
36
+ }
37
+
38
+ #define DISPATCH_LAYER_NORM_RESIDUAL(T_TYPE, C_TYPE) \
39
+ if (input.options().dtype() == torch::T_TYPE) { \
40
+ launch_fused_post_ln((C_TYPE*)output.data_ptr(), \
41
+ (const C_TYPE*)input.data_ptr(), \
42
+ (const C_TYPE*)residual.data_ptr(), \
43
+ (const C_TYPE*)gamma.data_ptr(), \
44
+ (const C_TYPE*)beta.data_ptr(), \
45
+ epsilon, \
46
+ rows, \
47
+ elems_per_row, \
48
+ at::cuda::getCurrentCUDAStream()); \
49
+ }
50
+
51
+ void ds_post_layer_norm(at::Tensor& output,
52
+ at::Tensor& input,
53
+ at::Tensor& residual,
54
+ at::Tensor& gamma,
55
+ at::Tensor& beta,
56
+ float epsilon)
57
+ {
58
+ bool ragged_input = input.dim() == 2;
59
+
60
+ const int rows = ragged_input ? input.size(0) : input.size(0) * input.size(1);
61
+ const int elems_per_row = ragged_input ? input.size(1) : input.size(2);
62
+
63
+ DISPATCH_LAYER_NORM_RESIDUAL(kFloat, float);
64
+ DISPATCH_LAYER_NORM_RESIDUAL(kHalf, __half);
65
+ #ifdef BF16_AVAILABLE
66
+ DISPATCH_LAYER_NORM_RESIDUAL(kBFloat16, __nv_bfloat16);
67
+ #endif
68
+ }
69
+
70
+ #define DISPATCH_PRE_LAYER_NORM_RESIDUAL(T_TYPE, C_TYPE) \
71
+ if (input.options().dtype() == torch::T_TYPE) { \
72
+ launch_fused_pre_ln((C_TYPE*)norm_output.data_ptr(), \
73
+ (C_TYPE*)res_output.data_ptr(), \
74
+ (const C_TYPE*)input.data_ptr(), \
75
+ (const C_TYPE*)residual.data_ptr(), \
76
+ (const C_TYPE*)gamma.data_ptr(), \
77
+ (const C_TYPE*)beta.data_ptr(), \
78
+ epsilon, \
79
+ rows, \
80
+ elems_per_row, \
81
+ at::cuda::getCurrentCUDAStream()); \
82
+ }
83
+
84
+ void ds_pre_layer_norm(at::Tensor& res_output,
85
+ at::Tensor& norm_output,
86
+ at::Tensor& input,
87
+ at::Tensor& residual,
88
+ at::Tensor& gamma,
89
+ at::Tensor& beta,
90
+ float epsilon)
91
+ {
92
+ bool ragged_input = input.dim() == 2;
93
+
94
+ const int rows = ragged_input ? input.size(0) : input.size(0) * input.size(1);
95
+ const int elems_per_row = ragged_input ? input.size(1) : input.size(2);
96
+
97
+ DISPATCH_PRE_LAYER_NORM_RESIDUAL(kFloat, float);
98
+ DISPATCH_PRE_LAYER_NORM_RESIDUAL(kHalf, __half);
99
+ #ifdef BF16_AVAILABLE
100
+ DISPATCH_PRE_LAYER_NORM_RESIDUAL(kBFloat16, __nv_bfloat16);
101
+ #endif
102
+ }
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/layer_norm.h ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ #pragma once
7
+
8
+ #include <c10/cuda/CUDAStream.h>
9
+ #include <torch/extension.h>
10
+ #include "ds_kernel_utils.h"
11
+
12
+ /*
13
+ Kernel launch methods for layer norm variants.
14
+ */
15
+
16
+ template <typename T>
17
+ void launch_fused_ln(T* output,
18
+ const T* vals,
19
+ const T* gamma,
20
+ const T* beta,
21
+ float epsilon,
22
+ int rows,
23
+ int elems_per_row,
24
+ cudaStream_t stream);
25
+
26
+ template <typename T>
27
+ void launch_fused_post_ln(T* output,
28
+ const T* vals,
29
+ const T* residual,
30
+ const T* gamma,
31
+ const T* beta,
32
+ float epsilon,
33
+ int rows,
34
+ int elems_per_row,
35
+ cudaStream_t stream);
36
+ template <typename T>
37
+ void launch_fused_pre_ln(T* norm_output,
38
+ T* res_output,
39
+ const T* vals,
40
+ const T* residual,
41
+ const T* gamma,
42
+ const T* beta,
43
+ float epsilon,
44
+ int rows,
45
+ int elems_per_row,
46
+ cudaStream_t stream);
47
+
48
+ void ds_layer_norm(at::Tensor& output,
49
+ at::Tensor& input,
50
+ at::Tensor& gamma,
51
+ at::Tensor& beta,
52
+ float epsilon);
53
+
54
+ void ds_post_layer_norm(at::Tensor& output,
55
+ at::Tensor& input,
56
+ at::Tensor& residual,
57
+ at::Tensor& gamma,
58
+ at::Tensor& beta,
59
+ float epsilon);
60
+
61
+ void ds_pre_layer_norm(at::Tensor& res_output,
62
+ at::Tensor& norm_output,
63
+ at::Tensor& input,
64
+ at::Tensor& residual,
65
+ at::Tensor& gamma,
66
+ at::Tensor& beta,
67
+ float epsilon);
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/layer_norm_cuda.cu ADDED
@@ -0,0 +1,489 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ #include "conversion_utils.h"
7
+ #include "ds_kernel_utils.h"
8
+ #include "memory_access_utils.h"
9
+ #include "reduction_utils.h"
10
+
11
+ namespace cg = cooperative_groups;
12
+ using rop = reduce::ROpType;
13
+
14
+ namespace ln {
15
+ constexpr int granularity = 16;
16
+ } // namespace ln
17
+
18
+ /*
19
+ Regular layer norm implementation. Assumes elems_per_row % 8
20
+ is equal to 0.
21
+
22
+ Args:
23
+ output: buffer for output data
24
+ vals: buffer for input data
25
+ gamma: gain for normalization
26
+ beta: bias for normalization
27
+ epsilon: numeric stability
28
+ elems_per_row: number of elements each block will normalize
29
+ */
30
+ template <typename T, int unRoll, int threadsPerGroup, int maxThreads>
31
+ __global__ void fused_ln(T* output,
32
+ const T* vals,
33
+ const T* gamma,
34
+ const T* beta,
35
+ float epsilon,
36
+ int elems_per_row)
37
+ {
38
+ constexpr int T_per_load = ln::granularity / sizeof(T);
39
+
40
+ cg::thread_block tb = cg::this_thread_block();
41
+ cg::thread_block_tile<hw_warp_size> warp = cg::tiled_partition<hw_warp_size>(tb);
42
+
43
+ // X-dimension of the block
44
+ const int block_offset = (tb.group_index().x * (maxThreads / threadsPerGroup) * elems_per_row) +
45
+ (tb.thread_index().y * elems_per_row);
46
+ const int thread_offset = tb.thread_index().x * T_per_load;
47
+ const int base_offset = block_offset + thread_offset;
48
+ const int stride = blockDim.x * T_per_load;
49
+
50
+ float sum = reduce::init<rop::Add, float>();
51
+
52
+ const T* input_base = vals + base_offset;
53
+
54
+ T local_buffer[unRoll * T_per_load];
55
+
56
+ #pragma unRoll
57
+ for (int i = 0; i < unRoll; i++) {
58
+ T* iteration_buffer = local_buffer + i * T_per_load;
59
+
60
+ mem_access::load_global<ln::granularity>(
61
+ iteration_buffer, input_base + i * stride, thread_offset + i * stride < elems_per_row);
62
+
63
+ #pragma unRoll
64
+ for (int j = 0; j < T_per_load; j++) {
65
+ float vals_up_cast = conversion::to<float>(iteration_buffer[j]);
66
+ sum = reduce::element<rop::Add>(sum, vals_up_cast);
67
+ }
68
+ }
69
+
70
+ reduce::partitioned_block<rop::Add, threadsPerGroup>(tb, warp, sum);
71
+ const float mean = sum / elems_per_row;
72
+
73
+ float mean_diff = reduce::init<rop::Add, float>();
74
+
75
+ #pragma unRoll
76
+ for (int i = 0; i < unRoll; i++) {
77
+ #pragma unRoll
78
+ for (int j = 0; j < T_per_load; j++) {
79
+ // Using a 0 value here skews the variance, have to if-guard
80
+ if (thread_offset + i * stride < elems_per_row) {
81
+ float diff = (conversion::to<float>(local_buffer[i * T_per_load + j]) - mean);
82
+ mean_diff = reduce::element<rop::Add>(mean_diff, diff * diff);
83
+ }
84
+ }
85
+ }
86
+
87
+ reduce::partitioned_block<rop::Add, threadsPerGroup>(tb, warp, mean_diff);
88
+ const float variance = mean_diff / elems_per_row;
89
+ const float denom = __frsqrt_rn(variance + epsilon);
90
+
91
+ T* block_output = output + block_offset;
92
+
93
+ #pragma unRoll
94
+ for (int i = 0; i < unRoll; i++) {
95
+ T* iteration_buffer = local_buffer + i * T_per_load;
96
+ const int iter_idx = i * stride + thread_offset;
97
+ const bool do_loads = iter_idx < elems_per_row;
98
+
99
+ T gamma_local[T_per_load], beta_local[T_per_load];
100
+
101
+ mem_access::load_global<ln::granularity>(gamma_local, gamma + iter_idx, do_loads);
102
+ mem_access::load_global<ln::granularity>(beta_local, beta + iter_idx, do_loads);
103
+
104
+ #pragma unRoll
105
+ for (int j = 0; j < T_per_load; j++) {
106
+ float val = conversion::to<float>(iteration_buffer[j]);
107
+ val = (val - mean) * denom;
108
+ val =
109
+ val * conversion::to<float>(gamma_local[j]) + conversion::to<float>(beta_local[j]);
110
+ iteration_buffer[j] = conversion::to<T>(val);
111
+ }
112
+
113
+ if (do_loads) {
114
+ mem_access::store_global<ln::granularity>(block_output + iter_idx, iteration_buffer);
115
+ }
116
+ }
117
+ }
118
+
119
+ #define LAUNCH_FUSED_LN(unRollFactor, threadsPerGroup, maxThreads) \
120
+ fused_ln<T, unRollFactor, threadsPerGroup, maxThreads> \
121
+ <<<grid, block, 0, stream>>>(output, vals, gamma, beta, epsilon, elems_per_row);
122
+
123
+ template <typename T>
124
+ void launch_fused_ln(T* output,
125
+ const T* vals,
126
+ const T* gamma,
127
+ const T* beta,
128
+ float epsilon,
129
+ int rows,
130
+ int elems_per_row,
131
+ cudaStream_t stream)
132
+ {
133
+ // 8 for __half, 4 for float
134
+ constexpr int T_per_load = ln::granularity / sizeof(T);
135
+
136
+ constexpr int maxThreads = 256;
137
+
138
+ // For Flaoat, unRoll 4, for __half, unRoll 2
139
+ constexpr int internal_unRoll = sizeof(T) == 4 ? 4 : 2;
140
+
141
+ const bool is_subblock_schedule = (elems_per_row <= 128) ? true : false;
142
+ const int h_per_step = is_subblock_schedule ? T_per_load : T_per_load * internal_unRoll;
143
+
144
+ // Scheduling concern: may be slightly faster for some inputs to assign multiple stages of
145
+ // warp-sized blocks rather than stepping up to 64/96 threads
146
+ const int one_step_threads = next_pow2((elems_per_row + h_per_step - 1) / h_per_step);
147
+ const int threadsPerGroup = (one_step_threads < maxThreads) ? one_step_threads : maxThreads;
148
+
149
+ const int groups_per_block_max =
150
+ is_subblock_schedule ? (maxThreads + threadsPerGroup - 1) / threadsPerGroup : 1;
151
+ const int groups_per_block = (rows < groups_per_block_max) ? rows : groups_per_block_max;
152
+ const int groups_launch = (groups_per_block + rows - 1) / groups_per_block;
153
+
154
+ dim3 block(threadsPerGroup, groups_per_block);
155
+ dim3 grid(groups_launch);
156
+
157
+ const int elems_per_step = threadsPerGroup * h_per_step;
158
+ const int external_unRoll = (elems_per_row + elems_per_step - 1) / elems_per_step;
159
+
160
+ if (is_subblock_schedule) {
161
+ // <=128
162
+ if (threadsPerGroup == 1) {
163
+ LAUNCH_FUSED_LN(1, 1, maxThreads);
164
+ } else if (threadsPerGroup == 2) {
165
+ LAUNCH_FUSED_LN(1, 2, maxThreads);
166
+ } else if (threadsPerGroup == 4) {
167
+ LAUNCH_FUSED_LN(1, 4, maxThreads);
168
+ } else if (threadsPerGroup == 8) {
169
+ LAUNCH_FUSED_LN(1, 8, maxThreads);
170
+ } else if (threadsPerGroup == 16) {
171
+ LAUNCH_FUSED_LN(1, 16, maxThreads);
172
+ }
173
+ } else if (external_unRoll == 1) {
174
+ // 129 - 4096 elems
175
+ // (this can launch with 1-7 warps as well)
176
+ LAUNCH_FUSED_LN(1 * internal_unRoll, maxThreads, maxThreads);
177
+ } else if (external_unRoll == 2) {
178
+ // 4097 - 8192 elems
179
+ LAUNCH_FUSED_LN(2 * internal_unRoll, maxThreads, maxThreads);
180
+ } else if (external_unRoll == 3) {
181
+ // 8193 - 12288 elems
182
+ LAUNCH_FUSED_LN(3 * internal_unRoll, maxThreads, maxThreads);
183
+ } else if (external_unRoll == 4) {
184
+ // 12289 - 16384 elems
185
+ LAUNCH_FUSED_LN(4 * internal_unRoll, maxThreads, maxThreads);
186
+ }
187
+ }
188
+
189
+ #define INSTANTIATE_FUSED_LN(T) \
190
+ template void launch_fused_ln(T*, const T*, const T*, const T*, float, int, int, cudaStream_t);
191
+
192
+ INSTANTIATE_FUSED_LN(__half);
193
+ #ifdef BF16_AVAILABLE
194
+ INSTANTIATE_FUSED_LN(__nv_bfloat16);
195
+ #endif
196
+ INSTANTIATE_FUSED_LN(float);
197
+
198
+ /*
199
+ Fused resiual + bias + layer norm implementation. Assumes elems_per_row % 8
200
+ is equal to 0.
201
+
202
+ TODO(cmikeh2): Goal is to deprecate this implementation. The bias + residual
203
+ need to be fused into compute-bound producer operations.
204
+
205
+ Args:
206
+ output: buffer for output data
207
+ res_output: output of residual addition
208
+ vals: buffer for input data
209
+ residual: residual data
210
+ bias: bias of of input data
211
+ gamma: gain for normalization
212
+ beta: bias for normalization
213
+ epsilon: numeric stability
214
+ elems_per_row: number of elements each block will normalize
215
+ Template arg:
216
+ StoreResidual: controls whether the residual calculation is stored
217
+ or not. When set to false, the input `res_output` is unused.
218
+ */
219
+ template <typename T, int unRoll, int threadsPerGroup, int maxThreads, bool preLnResidual>
220
+ __global__ void fused_residual_ln(T* output,
221
+ T* res_output,
222
+ const T* vals,
223
+ const T* residual,
224
+ const T* gamma,
225
+ const T* beta,
226
+ float epsilon,
227
+ int elems_per_row)
228
+ {
229
+ constexpr int T_per_load = ln::granularity / sizeof(T);
230
+
231
+ cg::thread_block tb = cg::this_thread_block();
232
+ cg::thread_block_tile<hw_warp_size> warp = cg::tiled_partition<hw_warp_size>(tb);
233
+
234
+ // X-dimension of the block
235
+ const int block_offset = (tb.group_index().x * (maxThreads / threadsPerGroup) * elems_per_row) +
236
+ (tb.thread_index().y * elems_per_row);
237
+ const int thread_offset = tb.thread_index().x * T_per_load;
238
+ const int base_offset = block_offset + thread_offset;
239
+ const int stride = tb.size() * T_per_load;
240
+
241
+ float sum = reduce::init<rop::Add, float>();
242
+
243
+ const T* input_base = vals + base_offset;
244
+ const T* residual_base = residual + base_offset;
245
+
246
+ T local_buffer[unRoll * T_per_load];
247
+
248
+ // Unlike a vanilla layernorm, since we're fusing the two adds as well
249
+ // an inner unRoll seems to be less valuable. If anything, a double unRoll
250
+ // makes the most sense if we find we are having performance issues.
251
+ #pragma unRoll
252
+ for (int i = 0; i < unRoll; i++) {
253
+ T* iteration_buffer = local_buffer + i * T_per_load;
254
+ T residual_buffer[T_per_load];
255
+
256
+ mem_access::load_global<ln::granularity>(
257
+ iteration_buffer, input_base + i * stride, thread_offset + i * stride < elems_per_row);
258
+ mem_access::load_global<ln::granularity>(residual_buffer,
259
+ residual_base + i * stride,
260
+ thread_offset + i * stride < elems_per_row);
261
+
262
+ #pragma unRoll
263
+ for (int j = 0; j < T_per_load; j++) {
264
+ float vals_up_cast = conversion::to<float>(iteration_buffer[j]);
265
+ float res_up_cast = conversion::to<float>(residual_buffer[j]);
266
+ vals_up_cast += res_up_cast;
267
+ sum = reduce::element<rop::Add>(sum, vals_up_cast);
268
+ iteration_buffer[j] = conversion::to<T>(vals_up_cast);
269
+ }
270
+
271
+ if (preLnResidual && (thread_offset + i * stride < elems_per_row)) {
272
+ mem_access::store_global<ln::granularity>(res_output + base_offset + i * stride,
273
+ iteration_buffer);
274
+ }
275
+ }
276
+
277
+ reduce::partitioned_block<rop::Add, threadsPerGroup>(tb, warp, sum);
278
+ const float mean = sum / elems_per_row;
279
+
280
+ float mean_diff = reduce::init<rop::Add, float>();
281
+ #pragma unRoll
282
+ for (int i = 0; i < unRoll; i++) {
283
+ #pragma unRoll
284
+ for (int j = 0; j < T_per_load; j++) {
285
+ // Using a 0 value here skews the variance, have to if-guard
286
+ if (thread_offset + i * stride < elems_per_row) {
287
+ float diff = (conversion::to<float>(local_buffer[i * T_per_load + j]) - mean);
288
+ mean_diff = reduce::element<rop::Add>(mean_diff, diff * diff);
289
+ }
290
+ }
291
+ }
292
+
293
+ reduce::partitioned_block<rop::Add, threadsPerGroup>(tb, warp, mean_diff);
294
+ const float variance = mean_diff / elems_per_row;
295
+ const float denom = __frsqrt_rn(variance + epsilon);
296
+
297
+ T* block_output = output + block_offset;
298
+
299
+ #pragma unRoll
300
+ for (int i = 0; i < unRoll; i++) {
301
+ T* iteration_buffer = local_buffer + i * T_per_load;
302
+ const int iter_idx = i * stride + thread_offset;
303
+ const bool do_loads = iter_idx < elems_per_row;
304
+
305
+ T gamma_local[T_per_load], beta_local[T_per_load];
306
+
307
+ mem_access::load_global<ln::granularity>(gamma_local, gamma + iter_idx, do_loads);
308
+ mem_access::load_global<ln::granularity>(beta_local, beta + iter_idx, do_loads);
309
+
310
+ #pragma unRoll
311
+ for (int j = 0; j < T_per_load; j++) {
312
+ float val = conversion::to<float>(iteration_buffer[j]);
313
+ val = (val - mean) * denom;
314
+ val =
315
+ val * conversion::to<float>(gamma_local[j]) + conversion::to<float>(beta_local[j]);
316
+ iteration_buffer[j] = conversion::to<T>(val);
317
+ }
318
+
319
+ if (do_loads) {
320
+ mem_access::store_global<ln::granularity>(block_output + iter_idx, iteration_buffer);
321
+ }
322
+ }
323
+ }
324
+
325
+ // TODO(cmikeh2): There's a bunch of redundancy here that needs to be removed/simplified.
326
+ #define LAUNCH_FUSED_RES_LN(unRollFactor, threadsPerGroup, maxThreads) \
327
+ fused_residual_ln<T, unRollFactor, threadsPerGroup, maxThreads, false> \
328
+ <<<grid, block, 0, stream>>>( \
329
+ output, nullptr, vals, residual, gamma, beta, epsilon, elems_per_row);
330
+
331
+ template <typename T>
332
+ void launch_fused_post_ln(T* output,
333
+ const T* vals,
334
+ const T* residual,
335
+ const T* gamma,
336
+ const T* beta,
337
+ float epsilon,
338
+ int rows,
339
+ int elems_per_row,
340
+ cudaStream_t stream)
341
+ {
342
+ // 8 for __half, 4 for float
343
+ constexpr int T_per_load = ln::granularity / sizeof(T);
344
+
345
+ constexpr int maxThreads = 256;
346
+
347
+ // For Flaoat, unRoll 4, for __half, unRoll 2
348
+ constexpr int internal_unRoll = sizeof(T) == 4 ? 4 : 2;
349
+
350
+ const bool is_subblock_schedule = (elems_per_row <= 128) ? true : false;
351
+ const int h_per_step = is_subblock_schedule ? T_per_load : T_per_load * internal_unRoll;
352
+
353
+ // Scheduling concern: may be slightly faster for some inputs to assign multiple stages of
354
+ // warp-sized blocks rather than stepping up to 64/96 threads
355
+ const int one_step_threads = next_pow2((elems_per_row + h_per_step - 1) / h_per_step);
356
+ const int threadsPerGroup = (one_step_threads < maxThreads) ? one_step_threads : maxThreads;
357
+
358
+ const int groups_per_block_max =
359
+ is_subblock_schedule ? (maxThreads + threadsPerGroup - 1) / threadsPerGroup : 1;
360
+ const int groups_per_block = (rows < groups_per_block_max) ? rows : groups_per_block_max;
361
+ const int groups_launch = (groups_per_block + rows - 1) / groups_per_block;
362
+
363
+ dim3 block(threadsPerGroup, groups_per_block);
364
+ dim3 grid(groups_launch);
365
+
366
+ const int elems_per_step = threadsPerGroup * h_per_step;
367
+ const int external_unRoll = (elems_per_row + elems_per_step - 1) / elems_per_step;
368
+
369
+ if (is_subblock_schedule) {
370
+ // <=128
371
+ if (threadsPerGroup == 1) {
372
+ LAUNCH_FUSED_RES_LN(1, 1, maxThreads);
373
+ } else if (threadsPerGroup == 2) {
374
+ LAUNCH_FUSED_RES_LN(1, 2, maxThreads);
375
+ } else if (threadsPerGroup == 4) {
376
+ LAUNCH_FUSED_RES_LN(1, 4, maxThreads);
377
+ } else if (threadsPerGroup == 8) {
378
+ LAUNCH_FUSED_RES_LN(1, 8, maxThreads);
379
+ } else if (threadsPerGroup == 16) {
380
+ LAUNCH_FUSED_RES_LN(1, 16, maxThreads);
381
+ }
382
+ } else if (external_unRoll == 1) {
383
+ // 129 - 4096 elems
384
+ // (this can launch with 1-7 warps as well)
385
+ LAUNCH_FUSED_RES_LN(1 * internal_unRoll, maxThreads, maxThreads);
386
+ } else if (external_unRoll == 2) {
387
+ // 4097 - 8192 elems
388
+ LAUNCH_FUSED_RES_LN(2 * internal_unRoll, maxThreads, maxThreads);
389
+ } else if (external_unRoll == 3) {
390
+ // 8193 - 12288 elems
391
+ LAUNCH_FUSED_RES_LN(3 * internal_unRoll, maxThreads, maxThreads);
392
+ } else if (external_unRoll == 4) {
393
+ // 12289 - 16384 elems
394
+ LAUNCH_FUSED_RES_LN(4 * internal_unRoll, maxThreads, maxThreads);
395
+ }
396
+ }
397
+
398
+ #define LAUNCH_FUSED_RES_LN_STORE_PRE_LN_RES(unRollFactor, threadsPerGroup, maxThreads) \
399
+ fused_residual_ln<T, unRollFactor, threadsPerGroup, maxThreads, true> \
400
+ <<<grid, block, 0, stream>>>( \
401
+ norm_output, res_output, vals, residual, gamma, beta, epsilon, elems_per_row);
402
+
403
+ template <typename T>
404
+ void launch_fused_pre_ln(T* norm_output,
405
+ T* res_output,
406
+ const T* vals,
407
+ const T* residual,
408
+ const T* gamma,
409
+ const T* beta,
410
+ float epsilon,
411
+ int rows,
412
+ int elems_per_row,
413
+ cudaStream_t stream)
414
+ {
415
+ // 8 for __half, 4 for float
416
+ constexpr int T_per_load = ln::granularity / sizeof(T);
417
+
418
+ constexpr int maxThreads = 256;
419
+
420
+ // For Flaoat, unRoll 4, for __half, unRoll 2
421
+ constexpr int internal_unRoll = sizeof(T) == 4 ? 4 : 2;
422
+
423
+ const bool is_subblock_schedule = (elems_per_row <= 128) ? true : false;
424
+ const int h_per_step = is_subblock_schedule ? T_per_load : T_per_load * internal_unRoll;
425
+
426
+ // Scheduling concern: may be slightly faster for some inputs to assign multiple stages of
427
+ // warp-sized blocks rather than stepping up to 64/96 threads
428
+ const int one_step_threads = next_pow2((elems_per_row + h_per_step - 1) / h_per_step);
429
+ const int threadsPerGroup = (one_step_threads < maxThreads) ? one_step_threads : maxThreads;
430
+
431
+ const int groups_per_block_max =
432
+ is_subblock_schedule ? (maxThreads + threadsPerGroup - 1) / threadsPerGroup : 1;
433
+ const int groups_per_block = (rows < groups_per_block_max) ? rows : groups_per_block_max;
434
+ const int groups_launch = (groups_per_block + rows - 1) / groups_per_block;
435
+
436
+ dim3 block(threadsPerGroup, groups_per_block);
437
+ dim3 grid(groups_launch);
438
+
439
+ const int elems_per_step = threadsPerGroup * h_per_step;
440
+ const int external_unRoll = (elems_per_row + elems_per_step - 1) / elems_per_step;
441
+
442
+ if (is_subblock_schedule) {
443
+ // <=128
444
+ if (threadsPerGroup == 1) {
445
+ LAUNCH_FUSED_RES_LN_STORE_PRE_LN_RES(1, 1, maxThreads);
446
+ } else if (threadsPerGroup == 2) {
447
+ LAUNCH_FUSED_RES_LN_STORE_PRE_LN_RES(1, 2, maxThreads);
448
+ } else if (threadsPerGroup == 4) {
449
+ LAUNCH_FUSED_RES_LN_STORE_PRE_LN_RES(1, 4, maxThreads);
450
+ } else if (threadsPerGroup == 8) {
451
+ LAUNCH_FUSED_RES_LN_STORE_PRE_LN_RES(1, 8, maxThreads);
452
+ } else if (threadsPerGroup == 16) {
453
+ LAUNCH_FUSED_RES_LN_STORE_PRE_LN_RES(1, 16, maxThreads);
454
+ }
455
+ } else if (external_unRoll == 1) {
456
+ // 129 - 4096 elems
457
+ // (this can launch with 1-7 warps as well)
458
+ LAUNCH_FUSED_RES_LN_STORE_PRE_LN_RES(1 * internal_unRoll, maxThreads, maxThreads);
459
+ } else if (external_unRoll == 2) {
460
+ // 4097 - 8192 elems
461
+ LAUNCH_FUSED_RES_LN_STORE_PRE_LN_RES(2 * internal_unRoll, maxThreads, maxThreads);
462
+ } else if (external_unRoll == 3) {
463
+ // 8193 - 12288 elems
464
+ LAUNCH_FUSED_RES_LN_STORE_PRE_LN_RES(3 * internal_unRoll, maxThreads, maxThreads);
465
+ } else if (external_unRoll == 4) {
466
+ // 12289 - 16384 elems
467
+ LAUNCH_FUSED_RES_LN_STORE_PRE_LN_RES(4 * internal_unRoll, maxThreads, maxThreads);
468
+ }
469
+ }
470
+
471
+ #define INSTANTIATE_RES_LN(T) \
472
+ template void launch_fused_post_ln<T>( \
473
+ T*, const T*, const T*, const T*, const T*, float, int, int, cudaStream_t);
474
+
475
+ #define INSTANTIATE_PRE_LN_RES(T) \
476
+ template void launch_fused_pre_ln<T>( \
477
+ T*, T*, const T*, const T*, const T*, const T*, float, int, int, cudaStream_t);
478
+
479
+ INSTANTIATE_RES_LN(__half);
480
+ INSTANTIATE_RES_LN(float);
481
+ #ifdef BF16_AVAILABLE
482
+ INSTANTIATE_RES_LN(__nv_bfloat16);
483
+ #endif
484
+
485
+ INSTANTIATE_PRE_LN_RES(__half);
486
+ INSTANTIATE_PRE_LN_RES(float);
487
+ #ifdef BF16_AVAILABLE
488
+ INSTANTIATE_PRE_LN_RES(__nv_bfloat16);
489
+ #endif
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/__init__.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # Copyright (c) Microsoft Corporation.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ # DeepSpeed Team
5
+
6
+ from .cuda_linear import *
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (265 Bytes). View file
 
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/__pycache__/cuda_linear.cpython-312.pyc ADDED
Binary file (4.91 kB). View file
 
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/cuda_linear.py ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Microsoft Corporation.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ # DeepSpeed Team
5
+
6
+ import torch
7
+
8
+ from ....inference_utils import DtypeEnum
9
+ from ....logging import inference_logger
10
+ from deepspeed.ops.op_builder import InferenceCoreBuilder
11
+ from ... import DSKernelBase
12
+
13
+
14
+ class CUDAWf6Af16Linear(DSKernelBase):
15
+ """
16
+ Wrapper around the CUDA kernel of Wf6Af16 quantized linear.
17
+
18
+ Performs z = x @ y
19
+ """
20
+ supported_dtypes = [DtypeEnum.fp16]
21
+
22
+ def __init__(self):
23
+ self.inf_module = InferenceCoreBuilder().load()
24
+ self.inf_module.create_handle()
25
+ self.kernel = self.inf_module.cuda_wf6af16_linear
26
+ # The split_k_map is profiled on A100-80G GPU for some common shapes.
27
+ # It is an array of dictionaries, where the array index is the tokens chunk id.
28
+ # The dictionary is the mapping from the output channel to the split-K size.
29
+ self.split_k_map = [
30
+ { # tokens: [1, 64]
31
+ 3072: 18,
32
+ 4096: 13,
33
+ 5120: 10,
34
+ 6144: 9,
35
+ 8192: 6,
36
+ 10240: 5,
37
+ 14336: 7,
38
+ 28672: 7,
39
+ 57344: 7
40
+ },
41
+ { # tokens: [65:128]
42
+ 3072: 9,
43
+ 4096: 6,
44
+ 5120: 5,
45
+ 6144: 9,
46
+ 8192: 3,
47
+ 10240: 5,
48
+ 14336: 7,
49
+ 28672: 7,
50
+ 57344: 6
51
+ },
52
+ { # tokens: [129:192]
53
+ 3072: 6,
54
+ 4096: 4,
55
+ 5120: 7,
56
+ 6144: 3,
57
+ 8192: 2,
58
+ 10240: 5,
59
+ 14336: 5,
60
+ 28672: 5,
61
+ 57344: 4
62
+ },
63
+ { # tokens: [193:256]
64
+ 3072: 9,
65
+ 4096: 3,
66
+ 5120: 5,
67
+ 6144: 2,
68
+ 8192: 5,
69
+ 10240: 4,
70
+ 14336: 8,
71
+ 28672: 6,
72
+ 57344: 4
73
+ },
74
+ { # tokens: [257:320]
75
+ 3072: 7,
76
+ 4096: 5,
77
+ 5120: 2,
78
+ 6144: 5,
79
+ 8192: 4,
80
+ 10240: 1,
81
+ 14336: 3,
82
+ 28672: 3,
83
+ 57344: 4
84
+ },
85
+ { # tokens: [321:384]
86
+ 3072: 3,
87
+ 4096: 2,
88
+ 5120: 5,
89
+ 6144: 3,
90
+ 8192: 1,
91
+ 10240: 8,
92
+ 14336: 3,
93
+ 28672: 4,
94
+ 57344: 3
95
+ },
96
+ { # tokens: [385:448]
97
+ 3072: 5,
98
+ 4096: 7,
99
+ 5120: 3,
100
+ 6144: 5,
101
+ 8192: 7,
102
+ 10240: 3,
103
+ 14336: 1,
104
+ 28672: 1,
105
+ 57344: 3
106
+ },
107
+ { # tokens: [449:512]
108
+ 3072: 2,
109
+ 4096: 5,
110
+ 5120: 4,
111
+ 6144: 1,
112
+ 8192: 5,
113
+ 10240: 2,
114
+ 14336: 6,
115
+ 28672: 4,
116
+ 57344: 1
117
+ },
118
+ { # tokens: [513:576]
119
+ 3072: 2,
120
+ 4096: 3,
121
+ 5120: 1,
122
+ 6144: 1,
123
+ 8192: 3,
124
+ 10240: 3,
125
+ 14336: 3,
126
+ 28672: 1,
127
+ 57344: 1
128
+ },
129
+ { # tokens: [577:640]
130
+ 3072: 5,
131
+ 4096: 4,
132
+ 5120: 1,
133
+ 6144: 4,
134
+ 8192: 2,
135
+ 10240: 1,
136
+ 14336: 1,
137
+ 28672: 1,
138
+ 57344: 1
139
+ },
140
+ { # tokens: [641:704]
141
+ 3072: 3,
142
+ 4096: 1,
143
+ 5120: 2,
144
+ 6144: 2,
145
+ 8192: 1,
146
+ 10240: 2,
147
+ 14336: 1,
148
+ 28672: 1,
149
+ 57344: 1
150
+ },
151
+ { # tokens: [705:768]
152
+ 3072: 3,
153
+ 4096: 1,
154
+ 5120: 3,
155
+ 6144: 2,
156
+ 8192: 1,
157
+ 10240: 1,
158
+ 14336: 1,
159
+ 28672: 1,
160
+ 57344: 1
161
+ }
162
+ ]
163
+
164
+ def __call__(self, output: torch.Tensor, hidden_states: torch.Tensor, weights_2bit: torch.Tensor,
165
+ weights_4bit: torch.Tensor, scale: torch.Tensor, out_channels, tokens, in_channels) -> torch.Tensor:
166
+ """
167
+ Matmul kernel of FP6 weight-only quantized linear. All inputs should be contiguous.
168
+ It does not support batched-matmul.
169
+
170
+ Parameters:
171
+ output (torch.Tensor): Output tensor. Shape is of [token_number, out_features]
172
+ hidden_states (torch.Tensor): Input tensor. Shape is of [token_number, in_features]
173
+ weights_2bit (torch.Tensor): Input tensor of the 2-bit slice. Shape is of [out_features*2/8, in_features]
174
+ weights_4bit (torch.Tensor): Input tensor of the 4-bit slice. Shape is of [out_features*4/8, in_features]
175
+ scale (torch.Tensor): Input tensor. Shape is of [out_features], since the scale is per output channel
176
+ out_channels (int): The number of output channels
177
+ tokens (int): The number of tokens
178
+ in_channels (int): The number of input channels
179
+ """
180
+
181
+ if out_channels % 256 != 0 or in_channels % 64 != 0:
182
+ raise ValueError("The out and in channel should be multiple of 256 and 64 respectively.")
183
+
184
+ # TODO: add a more general heuristic to determine the split-K.
185
+ split_k = -1 # not initialized
186
+ if tokens <= 768:
187
+ # Try to find the split-K from the pre-profiled map.
188
+ tokens_chunk_id = (tokens - 1) // 64
189
+ split_k = self.split_k_map[tokens_chunk_id].get(out_channels, -1)
190
+ if split_k == -1:
191
+ split_k = 1
192
+ inference_logger().warning(
193
+ f"The split-K setting may be suboptimal for shape {tokens}x{in_channels}x{out_channels}...")
194
+
195
+ workspace = self.get_workspace(out_channels, tokens, in_channels, split_k, torch.float, hidden_states.device)
196
+ self.kernel(output, hidden_states, weights_2bit, weights_4bit, scale, workspace, out_channels, tokens,
197
+ in_channels, split_k)
198
+
199
+ def get_workspace(self, out_channels: int, tokens: int, in_channels: int, split_k: int, dtype,
200
+ device) -> torch.Tensor:
201
+ """
202
+ Allocate workspace for the kernel. The workspace is used to store the intermediate results of the matmul before
203
+ split-K. The split-K size is determined by the size of the matmul.
204
+ """
205
+ workspace = torch.empty((split_k, out_channels, tokens), dtype=dtype, device=device)
206
+
207
+ return workspace
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/configs.h ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ // This is a copy of FP6-LLM kernel code: https://arxiv.org/abs/2401.14112
7
+
8
+ #ifndef CONFIGS_H
9
+ #define CONFIGS_H
10
+
11
+ // #define DEBUG_MODE
12
+ #define PIPELINE_LEVEL_GMEM 2
13
+ #define PIPELINE_LEVEL_SMEM 2 // only support 2
14
+
15
+ /************************ Hardware Parameters ************************/
16
+ #define WARP_SIZE 32
17
+ #define REG_BIT_WIDTH 32
18
+ // mma: M=16 K=16 N=8
19
+ #define MMA_8 8
20
+ #define MMA_16 16
21
+ // for memory access
22
+ #define THREAD_OPT_ACCESS_BIT_WIDTH_128 128 // LDS.128, cp_async.128, ...
23
+ #define BIT_WIDTH_PER_HALF 16 // Half precision: FP16
24
+
25
+ /******************** Register Allocation For GEMM ********************/
26
+ #define REG_PER_THREAD_C_TENSOR_16_16 8 // 8 for FP32 Accumulation
27
+ /********************** Memory Padding Parameters **********************/
28
+ // Eliminating bank-conflict
29
+ #define PADDING_BYTES_16 16 // Padding 16 bytes each column
30
+ #define PADDING_SHARED_MEM_FOR_B_8 \
31
+ 8 // Padding 8 half each column, during CopyFromGlobalToShared() for B
32
+ #define PADDING_SHARED_MEM_FOR_C_4 \
33
+ 4 // Padding 4 float each column, during StoreToSharedMemoryFromRegister() for C
34
+ /************************* WARP Tiling part-1 *************************/
35
+ #define WARP_ROW_MMA_TENSORS 4
36
+ #define WARP_M (WARP_ROW_MMA_TENSORS * MMA_16) // 64
37
+ #define WARP_K_MMA_TENSORS 4
38
+ #define WARP_K (WARP_K_MMA_TENSORS * MMA_16) // 64
39
+ template <int BLOCK_ROW_WARPS_, int BLOCK_COL_WARPS_, int WARP_COL_MMA_TENSORS_>
40
+ struct TilingConfig {
41
+ // Depending on "n" dimension of the GEMM
42
+ static constexpr int BLOCK_ROW_WARPS = BLOCK_ROW_WARPS_;
43
+ static constexpr int BLOCK_COL_WARPS = BLOCK_COL_WARPS_;
44
+ static constexpr int WARP_COL_MMA_TENSORS = WARP_COL_MMA_TENSORS_;
45
+ /************************* WARP Tiling part-2 *************************/
46
+ static constexpr int WARP_N = WARP_COL_MMA_TENSORS * MMA_8;
47
+ /*************************Thread Block Tiling *************************/
48
+ static constexpr int TILE_M = WARP_M * BLOCK_ROW_WARPS;
49
+ static constexpr int TILE_N = MMA_8 * WARP_COL_MMA_TENSORS * BLOCK_COL_WARPS;
50
+ static constexpr int TILE_K = WARP_K;
51
+ /********************** #Thread per Thread Block **********************/
52
+ static constexpr int BLOCK_WARPS = BLOCK_ROW_WARPS * BLOCK_COL_WARPS;
53
+ static constexpr int BLOCK_THREADS = BLOCK_WARPS * WARP_SIZE;
54
+ /******************************* Others *******************************/
55
+ static constexpr int SMEM_SIZE_B_TILE = TILE_N * (TILE_K + PADDING_BYTES_16) * 2 *
56
+ PIPELINE_LEVEL_GMEM; // sizeof(half)=2, doubleBuffer=2
57
+ static constexpr int SMEM_SIZE_C_TILE =
58
+ TILE_N * (TILE_M + PADDING_BYTES_16) * 4; // sizeof(float)=4
59
+ };
60
+
61
+ /************************ General Config for Quant-LLM **********************/
62
+ #define WEIGHT_FRAG1_BIT_WIDTH 2
63
+ #define WEIGHT_FRAG2_BIT_WIDTH 4
64
+ #define WEIGHT_BIT_WIDTH (WEIGHT_FRAG1_BIT_WIDTH + WEIGHT_FRAG2_BIT_WIDTH) // 6
65
+ // #define QUANT_GROUP_SIZE_DIVIDED_BY_64 4 //
66
+ // QuantGroupSize: 4*64 = 256
67
+ /*************************** 64*64 Weghts of A WARP *************************/
68
+ #define WEIGHT_PER_UNIT (WARP_M * WARP_K) // 64*64
69
+ #define SMEM_SIZE_IN_BYTES_PER_WARP_A1 \
70
+ (WEIGHT_PER_UNIT * WEIGHT_FRAG1_BIT_WIDTH / \
71
+ 8) // 1024 Bytes #doubleBuffer not takedn into consideration
72
+ #define SMEM_SIZE_IN_BYTES_PER_WARP_A2 \
73
+ (WEIGHT_PER_UNIT * WEIGHT_FRAG2_BIT_WIDTH / \
74
+ 8) // 2048 Bytes #doubleBuffer not takedn into consideration
75
+ #define SMEM_SIZE_A1_TILE \
76
+ (SMEM_SIZE_IN_BYTES_PER_WARP_A1 * 4 * \
77
+ PIPELINE_LEVEL_GMEM) // #WARP=4, #Trible-Buffer for 3-level pipeline for A = 12 KB; double
78
+ // buffer for 2-level pipeline A= 8 KB.
79
+ #define SMEM_SIZE_A2_TILE \
80
+ (SMEM_SIZE_IN_BYTES_PER_WARP_A2 * 4 * \
81
+ PIPELINE_LEVEL_GMEM) // #WARP=4, #Trible-Buffer for 3-level pipeline for A = 24 KB; double
82
+ // buffer for 2-level pipeline A= 16 KB.
83
+ /******************** Global Memory Layout For QUANTIZED DATA ******************/
84
+ #define NUM_INT4_PER_UNIT_2BIT_FRAG (WEIGHT_PER_UNIT * WEIGHT_FRAG1_BIT_WIDTH / 128) // 64
85
+ #define NUM_INT4_PER_UNIT_4BIT_FRAG (WEIGHT_PER_UNIT * WEIGHT_FRAG2_BIT_WIDTH / 128) // 128
86
+ /******************** Register Allocation For QUANTIZED DATA ******************/
87
+ #define WEIGHT_PER_THREAD (WEIGHT_PER_UNIT / WARP_SIZE) // 128
88
+ #define REG_PER_THREAD_2BIT_FRAG (WEIGHT_PER_THREAD / REG_BIT_WIDTH * 2) // 8
89
+ #define REG_PER_THREAD_4BIT_FRAG (WEIGHT_PER_THREAD / REG_BIT_WIDTH * 4) // 16
90
+ /******************** Register Allocation For QUANT Scales ******************/
91
+ #define WARP_REG_QUANT_SCALE 4 // 8 rows per thread -> 8 FP16 scales -> 4 registers
92
+ #define WARP_REG_QUANT_SCALE_DISTRIBUTED \
93
+ 1 // T0-T3, T4-T7, ..., T28-T31 share the same scales, using shfl to get all the scales for
94
+ // each thread
95
+
96
+ #endif // CONFIGS_H
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/kernel_matmul.cuh ADDED
@@ -0,0 +1,272 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ // This is a copy of FP6-LLM kernel code: https://arxiv.org/abs/2401.14112
7
+
8
+ #ifndef DEEPSPEED_CUDA_LINEAR_KERNEL_MATMUL_CUH
9
+ #define DEEPSPEED_CUDA_LINEAR_KERNEL_MATMUL_CUH
10
+
11
+ #include "configs.h"
12
+ #include "utils_core.cuh"
13
+ #include "utils_gmem.cuh"
14
+
15
+ /*
16
+ * C = A*B
17
+ * A: row major with ahead-of-time layout transformation, FP6
18
+ * B: col major, FP16
19
+ * C: col major, FP16
20
+ */
21
+ template <typename TilingConfig, typename OutputDataType>
22
+ __global__ void QUANT_GEMM_Kernel(const uint4* Weight1,
23
+ const uint4* Weight2,
24
+ const half* Scales,
25
+ const half* B,
26
+ OutputDataType* C,
27
+ const size_t M_Global,
28
+ const size_t N_Global,
29
+ const size_t K_Global,
30
+ int Split_K)
31
+ {
32
+ #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800 && __CUDA_ARCH__ < 900
33
+
34
+ #ifdef DEBUG_MODE
35
+ assert(K_Global % TilingConfig::TILE_K == 0);
36
+ assert(M_Global % TilingConfig::TILE_M == 0);
37
+ assert(gridDim.y == Split_K * (M_Global / TilingConfig::TILE_M));
38
+ #endif
39
+ extern __shared__ __align__(128)
40
+ half smem[]; // Dynamic shared memory for FP16 A tiles, 128 Bytes aligned
41
+ half(*smem_array)[WARP_K + PADDING_SHARED_MEM_FOR_B_8] =
42
+ reinterpret_cast<half(*)[WARP_K + PADDING_SHARED_MEM_FOR_B_8]>(
43
+ smem +
44
+ (SMEM_SIZE_A1_TILE + SMEM_SIZE_A2_TILE) / 2); // Dynamic shared memory for FP16 B tiles
45
+ __shared__ half QuantScales[64 * TilingConfig::BLOCK_WARPS]; // static shared memory for
46
+ // quantization scales, 64 row per
47
+ // warp * 4 warps = 512 Bytes
48
+ // Thread Block Mapping, considering SplitK
49
+ const size_t BatchID = blockIdx.y / (M_Global / TilingConfig::TILE_M);
50
+ const size_t x = blockIdx.x; // Output Block ID: (BlockID_Row = y; BlockID_Col = x )
51
+ const size_t y =
52
+ blockIdx.y %
53
+ (M_Global / TilingConfig::TILE_M); // Output Block ID: (BlockID_Row = y; BlockID_Col = x )
54
+ const size_t Tile_Start_M = y * TilingConfig::TILE_M;
55
+ const size_t Tile_Start_N = x * TilingConfig::TILE_N;
56
+ const size_t NumColumnToCopy = (N_Global - Tile_Start_N) < TilingConfig::TILE_N
57
+ ? (N_Global - Tile_Start_N)
58
+ : TilingConfig::TILE_N;
59
+ const size_t NumBlock_K = K_Global / TilingConfig::TILE_K;
60
+ const size_t AverageNumBlock_K = NumBlock_K / Split_K;
61
+ const size_t ExtraNumBlock_K = NumBlock_K - AverageNumBlock_K * Split_K;
62
+ size_t NumIter = AverageNumBlock_K;
63
+ if (BatchID < ExtraNumBlock_K) NumIter++;
64
+ size_t StartBlockID_K = AverageNumBlock_K * BatchID;
65
+ if (BatchID < ExtraNumBlock_K)
66
+ StartBlockID_K += BatchID;
67
+ else
68
+ StartBlockID_K += ExtraNumBlock_K;
69
+ // Warp ID.
70
+ const int warpId = threadIdx.x / WARP_SIZE;
71
+ int WARP_i =
72
+ warpId / TilingConfig::BLOCK_COL_WARPS; // WARP_i: row number; WARP_j: column number
73
+ // int WARP_j = warpId % TilingConfig::BLOCK_COL_WARPS;
74
+ // Global Memory Address for Matrix A (Weight)
75
+ // ///////////////////////////////////////////////////////////////////////// StartPTR for each
76
+ // ThreadBlock(TB)
77
+ const uint4* TB_StartGPTR_A1 =
78
+ Weight1 + (y * TilingConfig::BLOCK_ROW_WARPS) * NumBlock_K * NUM_INT4_PER_UNIT_2BIT_FRAG;
79
+ const uint4* TB_StartGPTR_A2 =
80
+ Weight2 + (y * TilingConfig::BLOCK_ROW_WARPS) * NumBlock_K * NUM_INT4_PER_UNIT_4BIT_FRAG;
81
+ // StartPTR for each WARP.
82
+ const uint4* WARP_StartGPTR_A1 =
83
+ TB_StartGPTR_A1 + WARP_i * NumBlock_K * NUM_INT4_PER_UNIT_2BIT_FRAG;
84
+ const uint4* WARP_StartGPTR_A2 =
85
+ TB_StartGPTR_A2 + WARP_i * NumBlock_K * NUM_INT4_PER_UNIT_4BIT_FRAG;
86
+ // StartPTR for each WARP, considering SplitK
87
+ const size_t WARP_Start_UnitID_K = StartBlockID_K;
88
+ WARP_StartGPTR_A1 += WARP_Start_UnitID_K * NUM_INT4_PER_UNIT_2BIT_FRAG;
89
+ WARP_StartGPTR_A2 += WARP_Start_UnitID_K * NUM_INT4_PER_UNIT_4BIT_FRAG;
90
+ // Copying A tile from Global to Shared, using double-buffer
91
+ // ////////////////////////////////////////////////////////// StartSPTR for each ThreadBlock
92
+ uint32_t* AFrag_2BIT_SPTR = reinterpret_cast<uint32_t*>(smem);
93
+ uint32_t* AFrag_4BIT_SPTR =
94
+ AFrag_2BIT_SPTR +
95
+ SMEM_SIZE_IN_BYTES_PER_WARP_A1 / 4 * TilingConfig::BLOCK_WARPS *
96
+ PIPELINE_LEVEL_GMEM; // 8 buffers including double buffers, 12 for trible buffers
97
+ // StartSPTR for each WARP
98
+ AFrag_2BIT_SPTR += warpId * SMEM_SIZE_IN_BYTES_PER_WARP_A1 / 4;
99
+ AFrag_4BIT_SPTR += warpId * SMEM_SIZE_IN_BYTES_PER_WARP_A2 / 4;
100
+ // Pre-fetch of A tile
101
+ for (int i = 0; i < PIPELINE_LEVEL_GMEM - 1; i++) {
102
+ CopyFromGlobalToShared_A<SMEM_SIZE_IN_BYTES_PER_WARP_A1>(
103
+ AFrag_2BIT_SPTR + i * SMEM_SIZE_IN_BYTES_PER_WARP_A1 / 4 * 4, WARP_StartGPTR_A1);
104
+ CopyFromGlobalToShared_A<SMEM_SIZE_IN_BYTES_PER_WARP_A2>(
105
+ AFrag_4BIT_SPTR + i * SMEM_SIZE_IN_BYTES_PER_WARP_A2 / 4 * 4, WARP_StartGPTR_A2);
106
+ WARP_StartGPTR_A1 += SMEM_SIZE_IN_BYTES_PER_WARP_A1 / 16;
107
+ WARP_StartGPTR_A2 += SMEM_SIZE_IN_BYTES_PER_WARP_A2 / 16;
108
+ }
109
+ // Global Memory Address for Matrix A (QuantScale)
110
+ // /////////////////////////////////////////////////////////////////////
111
+ const half* TB_StartGPTR_A_Scale = Scales + (y * TilingConfig::BLOCK_ROW_WARPS) * 64;
112
+ const half* WARP_StartGPTR_A_Scales = TB_StartGPTR_A_Scale + WARP_i * 64;
113
+ CopyFromGlobalToShared_Scales(QuantScales + WARP_i * 64, WARP_StartGPTR_A_Scales);
114
+ // Copying B tile from Global to Shared, considering SplitK
115
+ // /////////////////////////////////////////////////////////////
116
+ const half* BTile_GPTR = B + Tile_Start_N * K_Global + StartBlockID_K * TilingConfig::TILE_K;
117
+ for (int i = 0; i < PIPELINE_LEVEL_GMEM - 1; i++) {
118
+ CopyFromGlobalToShared<TilingConfig::TILE_N, TilingConfig::BLOCK_WARPS>(
119
+ smem_array + i * TilingConfig::TILE_N, BTile_GPTR, K_Global, NumColumnToCopy);
120
+ BTile_GPTR += TilingConfig::TILE_K;
121
+ }
122
+ // Register Allocation for A,B, and C, Initilazed to Zeros
123
+ // /////////////////////////////////////////////////////////////////////
124
+ constexpr int NumRegSets_a =
125
+ WARP_ROW_MMA_TENSORS; // 1 set = 4 registers, containing a 16*16 MMA block
126
+ constexpr int NumRegSets_b = (TilingConfig::WARP_COL_MMA_TENSORS == 1)
127
+ ? 1
128
+ : TilingConfig::WARP_COL_MMA_TENSORS /
129
+ 2; // 1 set = 4 registers, containing a 16*16 MMA block
130
+ #ifdef PIPELINE_LEVEL_SMEM
131
+ uint32_t a[NumRegSets_a * PIPELINE_LEVEL_SMEM]
132
+ [4]; // double/Trible buffer is used // Registers to store decompressed FP6
133
+ uint32_t b[NumRegSets_b * PIPELINE_LEVEL_SMEM]
134
+ [4]; // double/Triple buffer is used // Register to store FP16 B matrix (a slice)
135
+ #endif
136
+ float c[NumRegSets_a * NumRegSets_b][REG_PER_THREAD_C_TENSOR_16_16];
137
+ for (int i = 0; i < NumRegSets_a * NumRegSets_b; i++)
138
+ for (int j = 0; j < REG_PER_THREAD_C_TENSOR_16_16; j++) c[i][j] = 0.0f;
139
+ //
140
+ cp_async_wait_all();
141
+ __syncthreads();
142
+
143
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
144
+ uint32_t Scales_RPTR[4]; // 4 Registers per thread for Quantization Scales
145
+ ExtractFromSharedToReg_Scales(Scales_RPTR, QuantScales + WARP_i * 64);
146
+ #ifdef PIPELINE_LEVEL_SMEM
147
+ // Initializing the Software Pipeline: writing registers.
148
+ // ////////////////////////////////////////////////////////////////////////////////////////////////
149
+ initialize_mma_slice<TilingConfig>(
150
+ a, b, AFrag_2BIT_SPTR, AFrag_4BIT_SPTR, smem_array, Scales_RPTR);
151
+ #endif
152
+ // The outer loop.
153
+ // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
154
+ #pragma unroll(1)
155
+ for (size_t tile_id_k = 0; tile_id_k < NumIter; tile_id_k++) {
156
+ // Trible-Buffer for A Tile
157
+ uint32_t* __restrict__ read_SPTR_Frag1 =
158
+ AFrag_2BIT_SPTR + ((tile_id_k + 0) % PIPELINE_LEVEL_GMEM) *
159
+ SMEM_SIZE_IN_BYTES_PER_WARP_A1 / 4 *
160
+ 4; // 1024 (1)*4: 4 WARPs; (2)/4: int*+1 = char*+16
161
+ uint32_t* __restrict__ read_SPTR_Frag2 =
162
+ AFrag_4BIT_SPTR + ((tile_id_k + 0) % PIPELINE_LEVEL_GMEM) *
163
+ SMEM_SIZE_IN_BYTES_PER_WARP_A2 / 4 *
164
+ 4; // 2048 (1)*4: 4 WARPs; (2)/4: int*+1 = char*+16
165
+ #ifdef PIPELINE_LEVEL_SMEM
166
+ uint32_t* __restrict__ read2_SPTR_Frag1 =
167
+ AFrag_2BIT_SPTR +
168
+ ((tile_id_k + 1) % PIPELINE_LEVEL_GMEM) * SMEM_SIZE_IN_BYTES_PER_WARP_A1 / 4 * 4;
169
+ uint32_t* __restrict__ read2_SPTR_Frag2 =
170
+ AFrag_4BIT_SPTR +
171
+ ((tile_id_k + 1) % PIPELINE_LEVEL_GMEM) * SMEM_SIZE_IN_BYTES_PER_WARP_A2 / 4 * 4;
172
+ #endif
173
+ uint32_t* __restrict__ write_SPTR_Frag1 =
174
+ AFrag_2BIT_SPTR + ((tile_id_k + (PIPELINE_LEVEL_GMEM - 1)) % PIPELINE_LEVEL_GMEM) *
175
+ SMEM_SIZE_IN_BYTES_PER_WARP_A1 / 4 *
176
+ 4; // 1024 (1)*4: 4 WARPs; (2)/4: int*+1 = char*+16
177
+ uint32_t* __restrict__ write_SPTR_Frag2 =
178
+ AFrag_4BIT_SPTR + ((tile_id_k + (PIPELINE_LEVEL_GMEM - 1)) % PIPELINE_LEVEL_GMEM) *
179
+ SMEM_SIZE_IN_BYTES_PER_WARP_A2 / 4 *
180
+ 4; // 2048 (1)*4: 4 WARPs; (2)/4: int*+1 = char*+16
181
+ // Trible-Buffer for B Tile
182
+ half(*__restrict__ read_SPTR)[WARP_K + PADDING_SHARED_MEM_FOR_B_8] =
183
+ smem_array + ((tile_id_k + 0) % PIPELINE_LEVEL_GMEM) * TilingConfig::TILE_N;
184
+ #ifdef PIPELINE_LEVEL_SMEM
185
+ half(*__restrict__ read2_SPTR)[WARP_K + PADDING_SHARED_MEM_FOR_B_8] =
186
+ smem_array + ((tile_id_k + 1) % PIPELINE_LEVEL_GMEM) * TilingConfig::TILE_N;
187
+ #endif
188
+ half(*__restrict__ write_SPTR)[WARP_K + PADDING_SHARED_MEM_FOR_B_8] =
189
+ smem_array +
190
+ ((tile_id_k + (PIPELINE_LEVEL_GMEM - 1)) % PIPELINE_LEVEL_GMEM) * TilingConfig::TILE_N;
191
+ //
192
+ bool GlobalCopy = (tile_id_k + PIPELINE_LEVEL_GMEM - 1) < NumIter;
193
+ // Copying A tile from Global to Register, Bypassing L1, using double-buffer
194
+ CopyFromGlobalToShared_A<SMEM_SIZE_IN_BYTES_PER_WARP_A1>(
195
+ write_SPTR_Frag1, WARP_StartGPTR_A1, GlobalCopy);
196
+ CopyFromGlobalToShared_A<SMEM_SIZE_IN_BYTES_PER_WARP_A2>(
197
+ write_SPTR_Frag2, WARP_StartGPTR_A2, GlobalCopy);
198
+ // copying B tile from GlobalMemory to SharedMemory
199
+ CopyFromGlobalToShared<TilingConfig::TILE_N, TilingConfig::BLOCK_WARPS>(
200
+ write_SPTR, BTile_GPTR, K_Global, NumColumnToCopy, GlobalCopy);
201
+ cp_async_group_commit();
202
+ #ifdef PIPELINE_LEVEL_SMEM
203
+ core_mma_slice<TilingConfig>(c,
204
+ a,
205
+ b,
206
+ read_SPTR_Frag1,
207
+ read_SPTR_Frag2,
208
+ read_SPTR,
209
+ Scales_RPTR,
210
+ 1); // read_SPTR_Frag1, read_SPTR_Frag2 are different for each
211
+ // WARP; read_SPTR is shared among WARPs
212
+ core_mma_slice<TilingConfig>(
213
+ c, a, b, read_SPTR_Frag1, read_SPTR_Frag2, read_SPTR, Scales_RPTR, 2);
214
+ core_mma_slice<TilingConfig>(
215
+ c, a, b, read_SPTR_Frag1, read_SPTR_Frag2, read_SPTR, Scales_RPTR, 3);
216
+ // Barriers and Synchronizations
217
+ cp_async_wait_group<PIPELINE_LEVEL_GMEM - 2>();
218
+ __syncthreads();
219
+ core_mma_slice<TilingConfig>(
220
+ c, a, b, read2_SPTR_Frag1, read2_SPTR_Frag2, read2_SPTR, Scales_RPTR, 0);
221
+ // Updating global PTRs
222
+ WARP_StartGPTR_A1 +=
223
+ SMEM_SIZE_IN_BYTES_PER_WARP_A1 / 16; // 4KB/16=256 (1)/16: int4*+1 = char*+16
224
+ WARP_StartGPTR_A2 +=
225
+ SMEM_SIZE_IN_BYTES_PER_WARP_A2 / 16; // 8KB/16=512 (1)/16: int4*+1 = char*+16
226
+ BTile_GPTR += TilingConfig::TILE_K;
227
+ #else
228
+ PipelinedCoreLoop<TilingConfig>(
229
+ c,
230
+ read_SPTR,
231
+ read_SPTR_Frag1,
232
+ read_SPTR_Frag2,
233
+ Scales_RPTR); // read_SPTR_Frag1, read_SPTR_Frag2 are different for each WARP;
234
+ // read_SPTR is shared among WARPs
235
+ // Updating global PTRs
236
+ WARP_StartGPTR_A1 +=
237
+ SMEM_SIZE_IN_BYTES_PER_WARP_A1 / 16; // 4KB/16=256 (1)/16: int4*+1 = char*+16
238
+ WARP_StartGPTR_A2 +=
239
+ SMEM_SIZE_IN_BYTES_PER_WARP_A2 / 16; // 8KB/16=512 (1)/16: int4*+1 = char*+16
240
+ BTile_GPTR += TilingConfig::TILE_K;
241
+ // Barriers and Synchronizations
242
+ cp_async_wait_group<PIPELINE_LEVEL_GMEM - 2>();
243
+ __syncthreads();
244
+ #endif
245
+ }
246
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
247
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
248
+ // Store the C fragments to shared memory.
249
+ float(*smem_CFrag)[TilingConfig::TILE_M + PADDING_SHARED_MEM_FOR_C_4] =
250
+ reinterpret_cast<float(*)[TilingConfig::TILE_M + PADDING_SHARED_MEM_FOR_C_4]>(smem);
251
+ StoreToSharedMemoryFromRegister<TilingConfig>(smem_CFrag, c);
252
+ __syncthreads();
253
+ // Now that shared memory contains all the D tiles, stream them to global memory.
254
+ OutputDataType* BlockGlobalPTR =
255
+ C + BatchID * (M_Global * N_Global) + Tile_Start_M + Tile_Start_N * M_Global;
256
+ for (size_t i = warpId; i < NumColumnToCopy; i += TilingConfig::BLOCK_WARPS) // i-th column
257
+ #pragma unroll
258
+ for (size_t j = threadIdx.x % WARP_SIZE; j < TilingConfig::TILE_M;
259
+ j += WARP_SIZE) // j-th row
260
+ {
261
+ if constexpr (std::is_same<OutputDataType, half>::value)
262
+ BlockGlobalPTR[j + i * M_Global] = __float2half_rn(smem_CFrag[i][j]);
263
+ else
264
+ BlockGlobalPTR[j + i * M_Global] = smem_CFrag[i][j];
265
+ }
266
+
267
+ #else
268
+ assert(("The FP6 functions are only available on Ampere GPUs.", false));
269
+ #endif
270
+ }
271
+
272
+ #endif
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/kernel_reduction.cuh ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ // This is a copy of FP6-LLM kernel code: https://arxiv.org/abs/2401.14112
7
+
8
+ #ifndef DEEPSPEED_CUDA_LINEAR_KERNEL_REDUCTION_CUH
9
+ #define DEEPSPEED_CUDA_LINEAR_KERNEL_REDUCTION_CUH
10
+
11
+ #include <cuda.h>
12
+ #include <cuda_fp16.h>
13
+ #include <cuda_runtime.h>
14
+
15
+ #define REDUCTION_ELEMENT_PER_THREADBLOCK 256
16
+ #define HALF_PER_128BIT 8
17
+
18
+ __global__ void SplitK_Reduction(half* C,
19
+ float* Reduction_Workspace,
20
+ size_t M_Global,
21
+ size_t N_Global,
22
+ int Split_K)
23
+ {
24
+ half* WARP_GPTR_C = C + REDUCTION_ELEMENT_PER_THREADBLOCK * blockIdx.x;
25
+ float* WARP_GPTR_R = Reduction_Workspace + REDUCTION_ELEMENT_PER_THREADBLOCK * blockIdx.x;
26
+ half* THREAD_GPTR_C = WARP_GPTR_C + threadIdx.x * HALF_PER_128BIT;
27
+ float* THREAD_GPTR_R = WARP_GPTR_R + threadIdx.x * HALF_PER_128BIT;
28
+ // Initializing Thread-Local Results
29
+ float Results[HALF_PER_128BIT];
30
+ #pragma unroll
31
+ for (int i = 0; i < HALF_PER_128BIT; i++) Results[i] = 0.0f;
32
+ // Reduction
33
+ for (int i = 0; i < Split_K; i++) {
34
+ #pragma unroll
35
+ for (int j = 0; j < HALF_PER_128BIT; j++) Results[j] += THREAD_GPTR_R[j];
36
+ THREAD_GPTR_R += M_Global * N_Global;
37
+ }
38
+ // Writing to global memory
39
+ #pragma unroll
40
+ for (int i = 0; i < HALF_PER_128BIT; i++) THREAD_GPTR_C[i] = __float2half_rn(Results[i]);
41
+ }
42
+
43
+ #endif
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/ptx_cp.async.cuh ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ // This is a copy of FP6-LLM kernel code: https://arxiv.org/abs/2401.14112
7
+
8
+ #ifndef DEEPSPEED_CUDA_LINEAR_PTX_CP_ASYNC_CUH
9
+ #define DEEPSPEED_CUDA_LINEAR_PTX_CP_ASYNC_CUH
10
+
11
+ #include <cuda.h>
12
+ #include <cuda_fp16.h>
13
+ #include <cuda_runtime.h>
14
+
15
+ template <int SizeInBytes>
16
+ __device__ __forceinline__ void cp_async(half* smem_ptr,
17
+ const half* global_ptr,
18
+ bool pred_guard = true)
19
+ {
20
+ #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800
21
+ static_assert(SizeInBytes == 16, "Size is not supported");
22
+ unsigned smem_int_ptr = __cvta_generic_to_shared(smem_ptr);
23
+ asm volatile(
24
+ "{ \n"
25
+ " .reg .pred p;\n"
26
+ " setp.ne.b32 p, %0, 0;\n"
27
+ " @p cp.async.cg.shared.global [%1], [%2], %3;\n"
28
+ "}\n" ::"r"((int)pred_guard),
29
+ "r"(smem_int_ptr),
30
+ "l"(global_ptr),
31
+ "n"(SizeInBytes));
32
+ #else
33
+ assert(
34
+ ("The async copy functions are only supported on Ampere and newer architectures", false));
35
+ #endif
36
+ }
37
+
38
+ /// Establishes an ordering w.r.t previously issued cp.async instructions. Does not block.
39
+ __device__ __forceinline__ void cp_async_group_commit()
40
+ {
41
+ #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800
42
+ asm volatile("cp.async.commit_group;\n" ::);
43
+ #else
44
+ assert(
45
+ ("The async copy functions are only supported on Ampere and newer architectures", false));
46
+ #endif
47
+ }
48
+
49
+ /// Blocks until all but <N> previous cp.async.commit_group operations have committed.
50
+ template <int N>
51
+ __device__ __forceinline__ void cp_async_wait_group()
52
+ {
53
+ #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800
54
+ asm volatile("cp.async.wait_group %0;\n" ::"n"(N));
55
+ #else
56
+ assert(
57
+ ("The async copy functions are only supported on Ampere and newer architectures", false));
58
+ #endif
59
+ }
60
+
61
+ /// Blocks until all previous cp.async.commit_group operations have committed.
62
+ // cp.async.wait_all is equivalent to :
63
+ // cp.async.commit_group;
64
+ // cp.async.wait_group 0;
65
+ __device__ __forceinline__ void cp_async_wait_all()
66
+ {
67
+ #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800
68
+ asm volatile("cp.async.wait_all;\n" ::);
69
+ #else
70
+ assert(
71
+ ("The async copy functions are only supported on Ampere and newer architectures", false));
72
+ #endif
73
+ }
74
+
75
+ #endif
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/ptx_mma.cuh ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ // This is a copy of FP6-LLM kernel code: https://arxiv.org/abs/2401.14112
7
+
8
+ #ifndef DEEPSPEED_CUDA_LINEAR_PTX_MMA_CUH
9
+ #define DEEPSPEED_CUDA_LINEAR_PTX_MMA_CUH
10
+
11
+ #include <cuda.h>
12
+ #include <cuda_fp16.h>
13
+ #include <cuda_runtime.h>
14
+
15
+ #include <assert.h>
16
+ #include "configs.h"
17
+
18
+ #ifdef PIPELINE_LEVEL_SMEM
19
+ template <typename TilingConfig>
20
+ __device__ __forceinline__ void B_FromSharedToReg(
21
+ uint32_t (*__restrict__ Reg)[4],
22
+ half (*__restrict__ read_SPTR)[WARP_K + PADDING_SHARED_MEM_FOR_B_8],
23
+ int slice_id)
24
+ {
25
+ #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800
26
+ #ifdef DEBUG_MODE
27
+ static_assert((TilingConfig::WARP_COL_MMA_TENSORS == 1) ||
28
+ (TilingConfig::WARP_COL_MMA_TENSORS % 2 == 0));
29
+ #endif
30
+
31
+ const int warpId = threadIdx.x / WARP_SIZE;
32
+ int lane_id = threadIdx.x % WARP_SIZE;
33
+ int WARP_j = warpId % TilingConfig::BLOCK_COL_WARPS;
34
+ int warp_start_col = TilingConfig::WARP_COL_MMA_TENSORS * MMA_8 *
35
+ WARP_j; // each warp may start from reading warp_start_col'th column of
36
+ // the B tile in shared memory
37
+ #ifdef DEBUG_MODE
38
+ assert(warp_start_col == 0);
39
+ #endif
40
+
41
+ int col = (lane_id % 8) + (lane_id / 16) * 8;
42
+ int row = (lane_id % 16) / 8 * 8;
43
+ uint32_t smem_local_ptr = static_cast<uint32_t>(
44
+ __cvta_generic_to_shared(&read_SPTR[warp_start_col + col][slice_id * MMA_16 + row]));
45
+ if (TilingConfig::WARP_COL_MMA_TENSORS == 1) {
46
+ asm volatile("ldmatrix.sync.aligned.x2.m8n8.shared.b16 {%0, %1}, [%2];\n"
47
+ : "=r"(Reg[0][0]), "=r"(Reg[0][1])
48
+ : "r"(smem_local_ptr));
49
+ } else {
50
+ #pragma unroll
51
+ for (int i = 0; i < TilingConfig::WARP_COL_MMA_TENSORS / 2; i++) {
52
+ asm volatile("ldmatrix.sync.aligned.x4.m8n8.shared.b16 {%0, %1, %2, %3}, [%4];\n"
53
+ : "=r"(Reg[i][0]), "=r"(Reg[i][1]), "=r"(Reg[i][2]), "=r"(Reg[i][3])
54
+ : "r"(smem_local_ptr));
55
+ smem_local_ptr += 16 * (WARP_K + PADDING_SHARED_MEM_FOR_B_8) * sizeof(half);
56
+ }
57
+ }
58
+ #else
59
+ assert(
60
+ ("The matrix load functions are only supported on Ampere and newer architectures", false));
61
+ #endif
62
+ }
63
+ #else
64
+ // Debug: Whether ldmatrix.trans is required???
65
+ // B is in column-major
66
+ template <typename TilingConfig>
67
+ __device__ __forceinline__ void B_FromSharedToReg(
68
+ uint32_t (*__restrict__ Reg)[4],
69
+ half (*__restrict__ read_SPTR)[WARP_K + PADDING_SHARED_MEM_FOR_B_8],
70
+ int k_offset)
71
+ {
72
+ #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800
73
+ #ifdef DEBUG_MODE
74
+ static_assert((TilingConfig::WARP_COL_MMA_TENSORS == 1) ||
75
+ (TilingConfig::WARP_COL_MMA_TENSORS % 2 == 0));
76
+ #endif
77
+
78
+ const int warpId = threadIdx.x / WARP_SIZE;
79
+ int lane_id = threadIdx.x % WARP_SIZE;
80
+ int WARP_j = warpId % TilingConfig::BLOCK_COL_WARPS;
81
+ int warp_start_col = TilingConfig::WARP_COL_MMA_TENSORS * MMA_8 *
82
+ WARP_j; // each warp may start from reading warp_start_col'th column of
83
+ // the B tile in shared memory
84
+ #ifdef DEBUG_MODE
85
+ assert(warp_start_col == 0);
86
+ #endif
87
+
88
+ int col = (lane_id % 8) + (lane_id / 16) * 8;
89
+ int row = (lane_id % 16) / 8 * 8;
90
+ uint32_t smem_local_ptr = static_cast<uint32_t>(
91
+ __cvta_generic_to_shared(&read_SPTR[warp_start_col + col][k_offset + row]));
92
+ if (TilingConfig::WARP_COL_MMA_TENSORS == 1) {
93
+ asm volatile("ldmatrix.sync.aligned.x2.m8n8.shared.b16 {%0, %1}, [%2];\n"
94
+ : "=r"(Reg[0][0]), "=r"(Reg[0][1])
95
+ : "r"(smem_local_ptr));
96
+ } else {
97
+ #pragma unroll
98
+ for (int i = 0; i < TilingConfig::WARP_COL_MMA_TENSORS / 2; i++) {
99
+ asm volatile("ldmatrix.sync.aligned.x4.m8n8.shared.b16 {%0, %1, %2, %3}, [%4];\n"
100
+ : "=r"(Reg[i][0]), "=r"(Reg[i][1]), "=r"(Reg[i][2]), "=r"(Reg[i][3])
101
+ : "r"(smem_local_ptr));
102
+ smem_local_ptr += 16 * (WARP_K + PADDING_SHARED_MEM_FOR_B_8) * sizeof(half);
103
+ }
104
+ }
105
+ #else
106
+ assert(
107
+ ("The matrix load functions are only supported on Ampere and newer architectures", false));
108
+ #endif
109
+ }
110
+ #endif
111
+
112
+ __device__ __forceinline__ void MMA_FP16_M16N8K16(uint32_t* __restrict__ c,
113
+ uint32_t* __restrict__ a,
114
+ uint32_t* __restrict__ b)
115
+ {
116
+ #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800
117
+ asm volatile(
118
+ "mma.sync.aligned.m16n8k16.row.col.f32.f16.f16.f32"
119
+ "{ %0, %1, %2, %3},"
120
+ "{ %4, %5, %6, %7 },"
121
+ "{ %8, %9 },"
122
+ "{ %10, %11, %12, %13 };"
123
+ : "=r"(c[0]), "=r"(c[1]), "=r"(c[2]), "=r"(c[3])
124
+ : "r"(a[0]),
125
+ "r"(a[1]),
126
+ "r"(a[2]),
127
+ "r"(a[3]),
128
+ "r"(b[0]),
129
+ "r"(b[1]),
130
+ "r"(c[0]),
131
+ "r"(c[1]),
132
+ "r"(c[2]),
133
+ "r"(c[3]));
134
+ #else
135
+ assert(("The mma functions are only implemented for Ampere and newer architectures", false));
136
+ #endif
137
+ }
138
+
139
+ #endif
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/utils_core.cuh ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ // This is a copy of FP6-LLM kernel code: https://arxiv.org/abs/2401.14112
7
+
8
+ #ifndef DEEPSPEED_CUDA_LINEAR_UTILS_CORE_CUH
9
+ #define DEEPSPEED_CUDA_LINEAR_UTILS_CORE_CUH
10
+
11
+ #include <assert.h>
12
+
13
+ #include "configs.h"
14
+ #include "ptx_mma.cuh"
15
+ #include "utils_paralleldequant.cuh"
16
+
17
+ #ifdef PIPELINE_LEVEL_SMEM
18
+ template <int NUM_INT_PER_THREAD>
19
+ __device__ __forceinline__ void CopyFromSharedToRegister_AFrag(uint32_t Reg[],
20
+ uint32_t* SPTR,
21
+ int slice_id)
22
+ {
23
+ SPTR += slice_id * (NUM_INT_PER_THREAD * WARP_SIZE);
24
+ int lane_id = threadIdx.x % WARP_SIZE;
25
+ #pragma unroll
26
+ for (int i = 0; i < NUM_INT_PER_THREAD; i++) { Reg[i] = SPTR[lane_id + i * WARP_SIZE]; }
27
+ }
28
+
29
+ template <typename TilingConfig>
30
+ __device__ __forceinline__ void initialize_mma_slice(
31
+ uint32_t (*a)[4],
32
+ uint32_t (*b)[4],
33
+ uint32_t* __restrict__ A1_SPTR_read,
34
+ uint32_t* __restrict__ A2_SPTR_read,
35
+ half (*__restrict__ B_SPTR_read)[WARP_K + PADDING_SHARED_MEM_FOR_B_8],
36
+ uint32_t* RPTR_Scales)
37
+ {
38
+ // Writing registers
39
+ // Registers to store FP6 fragments for a slice (64*16) of A matrix => 32 FP6 per thread => 6
40
+ // register per thread;
41
+ uint32_t a_1[2]; // NO double buffer
42
+ uint32_t a_2[4]; // NO double buffer
43
+ CopyFromSharedToRegister_AFrag<2>(a_1, A1_SPTR_read, 0);
44
+ CopyFromSharedToRegister_AFrag<4>(a_2, A2_SPTR_read, 0);
45
+ Dequant_32FP6_4Way(a, a_1, a_2, RPTR_Scales); // SIMT Dequant: dequantizing FP6 to FP16 at
46
+ // register level, dequantizing a slice each time
47
+ B_FromSharedToReg<TilingConfig>(b, B_SPTR_read, 0); // Loading B from shared to registers
48
+ }
49
+
50
+ template <typename TilingConfig>
51
+ __device__ __forceinline__ void core_mma_slice(
52
+ float c[][REG_PER_THREAD_C_TENSOR_16_16],
53
+ uint32_t (*a)[4],
54
+ uint32_t (*b)[4],
55
+ uint32_t* __restrict__ A1_SPTR_read,
56
+ uint32_t* __restrict__ A2_SPTR_read,
57
+ half (*__restrict__ B_SPTR_read)[WARP_K + PADDING_SHARED_MEM_FOR_B_8],
58
+ uint32_t* RPTR_Scales,
59
+ int slice_id) // writing slice[slice_id] to registers, k=0 -> slice_id=1 for prefetching
60
+ {
61
+ #ifdef DEBUG_MODE
62
+ assert(
63
+ (TilingConfig::WARP_COL_MMA_TENSORS == 1) ||
64
+ (TilingConfig::WARP_COL_MMA_TENSORS % 2 ==
65
+ 0)); // if WARP_COL_MMA_TENSORS == 1, B tile in registers is padded to a 16*16 MMA block
66
+ #endif
67
+ const int NumRegSets_a =
68
+ WARP_ROW_MMA_TENSORS; // 1 set = 4 registers, containing a 16*16 MMA block
69
+ const int NumRegSets_b = (TilingConfig::WARP_COL_MMA_TENSORS == 1)
70
+ ? 1
71
+ : TilingConfig::WARP_COL_MMA_TENSORS /
72
+ 2; // 1 set = 4 registers, containing a 16*16 MMA block
73
+ uint32_t(*c_uint_ptr)[REG_PER_THREAD_C_TENSOR_16_16] =
74
+ reinterpret_cast<uint32_t(*)[REG_PER_THREAD_C_TENSOR_16_16]>(
75
+ c); // Registers for accumulated FP32 results
76
+
77
+ // Setting RPTRs for double buffers
78
+ uint32_t(*a_read)[4] = a;
79
+ uint32_t(*a_write)[4] = a;
80
+ uint32_t(*b_read)[4] = b;
81
+ uint32_t(*b_write)[4] = b;
82
+ if (slice_id % 2 == 1) {
83
+ b_write += NumRegSets_b;
84
+ a_write += NumRegSets_a;
85
+ } else {
86
+ b_read += NumRegSets_b;
87
+ a_read += NumRegSets_a;
88
+ }
89
+
90
+ // Reading registers and issuing core tensor core computations (a slice of A and B tile in shared
91
+ // memory)
92
+ #pragma unroll
93
+ for (int i = 0; i < WARP_ROW_MMA_TENSORS; i++) {
94
+ if (TilingConfig::WARP_COL_MMA_TENSORS == 1) {
95
+ MMA_FP16_M16N8K16(c_uint_ptr[i], a_read[i], b_read[0]);
96
+ } else {
97
+ #pragma unroll
98
+ for (int j = 0; j < TilingConfig::WARP_COL_MMA_TENSORS / 2; j++) {
99
+ MMA_FP16_M16N8K16(c_uint_ptr[i + j * WARP_ROW_MMA_TENSORS], a_read[i], b_read[j]);
100
+ MMA_FP16_M16N8K16(c_uint_ptr[i + j * WARP_ROW_MMA_TENSORS] + 4,
101
+ a_read[i],
102
+ b_read[j] + 2); // c+4; b+2
103
+ }
104
+ }
105
+ }
106
+
107
+ // Writing registers
108
+ // Registers to store FP6 fragments for a slice (64*16) of A matrix => 32 FP6 per thread => 6
109
+ // register per thread;
110
+ uint32_t a_1[2]; // NO double buffer
111
+ uint32_t a_2[4]; // NO double buffer
112
+ CopyFromSharedToRegister_AFrag<2>(a_1, A1_SPTR_read, slice_id);
113
+ CopyFromSharedToRegister_AFrag<4>(a_2, A2_SPTR_read, slice_id);
114
+ Dequant_32FP6_4Way(
115
+ a_write, a_1, a_2, RPTR_Scales); // SIMT Dequant: dequantizing FP6 to FP16 at register
116
+ // level, dequantizing a slice each time
117
+ B_FromSharedToReg<TilingConfig>(
118
+ b_write, B_SPTR_read, slice_id); // Loading B from shared to registers
119
+ }
120
+
121
+ #else
122
+ // Old version with naive pipeline design
123
+ template <int NUM_INT_PER_THREAD>
124
+ __device__ __forceinline__ void CopyFromSharedToRegister_AFrag(uint32_t Reg[], uint32_t* SPTR)
125
+ {
126
+ int lane_id = threadIdx.x % WARP_SIZE;
127
+ #pragma unroll
128
+ for (int i = 0; i < NUM_INT_PER_THREAD; i++) { Reg[i] = SPTR[lane_id + i * WARP_SIZE]; }
129
+ }
130
+ template <typename TilingConfig>
131
+ __device__ __forceinline__ void PipelinedCoreLoop(
132
+ float c[][REG_PER_THREAD_C_TENSOR_16_16],
133
+ half __restrict__ (*read_SPTR)[WARP_K + PADDING_SHARED_MEM_FOR_B_8],
134
+ uint32_t* __restrict__ read_SPTR_Frag1,
135
+ uint32_t* __restrict__ read_SPTR_Frag2,
136
+ uint32_t* RPTR_Scales)
137
+ {
138
+ #ifdef DEBUG_MODE
139
+ assert(
140
+ (TilingConfig::WARP_COL_MMA_TENSORS == 1) ||
141
+ (TilingConfig::WARP_COL_MMA_TENSORS % 2 ==
142
+ 0)); // if WARP_COL_MMA_TENSORS == 1, B tile in registers is padded to a 16*16 MMA block
143
+ #endif
144
+ const int NumRegSets_a =
145
+ WARP_ROW_MMA_TENSORS; // 1 set = 4 registers, containing a 16*16 MMA block
146
+ const int NumRegSets_b = (TilingConfig::WARP_COL_MMA_TENSORS == 1)
147
+ ? 1
148
+ : TilingConfig::WARP_COL_MMA_TENSORS /
149
+ 2; // 1 set = 4 registers, containing a 16*16 MMA block
150
+
151
+ // Registers to store FP32 results
152
+ uint32_t(*c_uint_ptr)[REG_PER_THREAD_C_TENSOR_16_16] =
153
+ reinterpret_cast<uint32_t(*)[REG_PER_THREAD_C_TENSOR_16_16]>(c);
154
+ // Registers to store FP6 fragments for a slice (64*16) of A matrix => 32 FP6 per thread => 6
155
+ // register per thread;
156
+ uint32_t a_1[2 * 2]; // double buffer is used
157
+ uint32_t a_2[4 * 2]; // double buffer is used
158
+ // Registers to store decompressed FP6
159
+ uint32_t a[NumRegSets_a * 1][4]; // No double buffer
160
+ // Register to store FP16 B matrix (a slice)
161
+ uint32_t b[NumRegSets_b * 2][4]; // double buffer is used
162
+
163
+ // Overlapped Smem and TC pipeline: pre-loading from shared to registers
164
+ CopyFromSharedToRegister_AFrag<2>(a_1, read_SPTR_Frag1);
165
+ CopyFromSharedToRegister_AFrag<4>(a_2, read_SPTR_Frag2);
166
+ B_FromSharedToReg<TilingConfig>(b, read_SPTR, 0);
167
+
168
+ #pragma unroll
169
+ for (int k = 0; k < WARP_K_MMA_TENSORS; k++) {
170
+ uint32_t(*b_read)[4] = b;
171
+ uint32_t(*b_write)[4] = b;
172
+ uint32_t* a_1_read = a_1;
173
+ uint32_t* a_1_write = a_1;
174
+ uint32_t* a_2_read = a_2;
175
+ uint32_t* a_2_write = a_2;
176
+ if (k % 2 == 0) {
177
+ b_write += NumRegSets_b;
178
+ a_1_write += 2;
179
+ a_2_write += 4;
180
+ } else {
181
+ b_read += NumRegSets_b;
182
+ a_1_read += 2;
183
+ a_2_read += 4;
184
+ }
185
+ // data loading
186
+ if (k + 1 < WARP_K_MMA_TENSORS) {
187
+ // updating SPTR for fragment1 and fragment2
188
+ read_SPTR_Frag1 += 2 * WARP_SIZE;
189
+ read_SPTR_Frag2 += 4 * WARP_SIZE;
190
+ CopyFromSharedToRegister_AFrag<2>(a_1_write, read_SPTR_Frag1);
191
+ CopyFromSharedToRegister_AFrag<4>(a_2_write, read_SPTR_Frag2);
192
+ B_FromSharedToReg<TilingConfig>(b_write, read_SPTR, (k + 1) * MMA_16);
193
+ }
194
+ // SIMT Dequant + Tensor Core computations
195
+ Dequant_32FP6_4Way(
196
+ a, a_1_read, a_2_read, RPTR_Scales); // Dequantizing FP6 to FP16 at register level,
197
+ // dequantizing a slice each time
198
+ #pragma unroll
199
+ for (int i = 0; i < WARP_ROW_MMA_TENSORS; i++) {
200
+ if (TilingConfig::WARP_COL_MMA_TENSORS == 1)
201
+ MMA_FP16_M16N8K16(c_uint_ptr[i], a[i], b_read[0]);
202
+ else {
203
+ #pragma unroll
204
+ for (int j = 0; j < TilingConfig::WARP_COL_MMA_TENSORS / 2; j++) {
205
+ MMA_FP16_M16N8K16(c_uint_ptr[i + j * WARP_ROW_MMA_TENSORS], a[i], b_read[j]);
206
+ MMA_FP16_M16N8K16(c_uint_ptr[i + j * WARP_ROW_MMA_TENSORS] + 4,
207
+ a[i],
208
+ b_read[j] + 2); // c+4; b+2
209
+ }
210
+ }
211
+ }
212
+ }
213
+ }
214
+ #endif // #ifdef PIPELINE_LEVEL_SMEM
215
+
216
+ template <typename TilingConfig>
217
+ __device__ __forceinline__ void StoreToSharedMemoryFromRegister(
218
+ float (*smem_CFrag)[TilingConfig::TILE_M + PADDING_SHARED_MEM_FOR_C_4],
219
+ float c[][REG_PER_THREAD_C_TENSOR_16_16])
220
+ {
221
+ const int lane_id = threadIdx.x % WARP_SIZE;
222
+ const int warpId = threadIdx.x / WARP_SIZE;
223
+ int warp_row_offset = warpId * (MMA_16 * WARP_ROW_MMA_TENSORS);
224
+ #pragma unroll
225
+ for (int i = 0; i < WARP_ROW_MMA_TENSORS; i++) {
226
+ #pragma unroll
227
+ for (int j = 0; j < TilingConfig::WARP_COL_MMA_TENSORS;
228
+ j++) { // Dealing with one 16*8 Tensor
229
+ int RegSetID = i + (j / 2) * WARP_ROW_MMA_TENSORS;
230
+ int RegOffset = (j % 2) * (REG_PER_THREAD_C_TENSOR_16_16 / 2);
231
+ int Tensor_row_offset = warp_row_offset + i * MMA_16;
232
+ int Tensor_col_offset = j * MMA_8;
233
+ #pragma unroll
234
+ for (int r = 0; r < REG_PER_THREAD_C_TENSOR_16_16 / 2; r++) {
235
+ int row_offset = lane_id / 4;
236
+ if (r >= 2) row_offset += 8;
237
+ int col_offset = (lane_id % 4) * 2;
238
+ if (r % 2 == 1) col_offset += 1;
239
+ smem_CFrag[Tensor_col_offset + col_offset][Tensor_row_offset + row_offset] =
240
+ c[RegSetID][r + RegOffset];
241
+ }
242
+ }
243
+ }
244
+ }
245
+
246
+ #endif
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/utils_gmem.cuh ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ // This is a copy of FP6-LLM kernel code: https://arxiv.org/abs/2401.14112
7
+
8
+ #ifndef DEEPSPEED_CUDA_LINEAR_UTILS_GMEM_CUH
9
+ #define DEEPSPEED_CUDA_LINEAR_UTILS_GMEM_CUH
10
+
11
+ #include <assert.h>
12
+ #include "configs.h"
13
+ #include "ptx_cp.async.cuh"
14
+
15
+ /*
16
+ * Copying A1/A2 from global memory to shared memory.
17
+ * Usually 1024 or 2048 Bytes
18
+ */
19
+ template <int SMEM_SIZE_IN_BYTES_PER_WARP>
20
+ __device__ __forceinline__ void CopyFromGlobalToShared_A(uint32_t* SPTR,
21
+ const uint4* GPTR,
22
+ bool pred_guard = true)
23
+ {
24
+ #ifdef DEBUG_MODE
25
+ static_assert(SMEM_SIZE_IN_BYTES_PER_WARP / WARP_SIZE % 16 == 0);
26
+ #endif
27
+ int lane_id = threadIdx.x % WARP_SIZE;
28
+ half* SPTR_HALF = reinterpret_cast<half*>(SPTR);
29
+ const half* GPTR_HALF = reinterpret_cast<const half*>(GPTR);
30
+ SPTR_HALF += lane_id * 8;
31
+ GPTR_HALF += lane_id * 8;
32
+ #pragma unroll
33
+ for (int i = 0; i < SMEM_SIZE_IN_BYTES_PER_WARP / WARP_SIZE / 16; i++) {
34
+ cp_async<16>(SPTR_HALF, GPTR_HALF, pred_guard);
35
+ SPTR_HALF += 256; // Forward 512 Bytes
36
+ GPTR_HALF += 256; // Forward 512 Bytes
37
+ }
38
+ }
39
+
40
+ /*
41
+ * Copying 64 Quant Scales (FP16) from global memory to shared memory.
42
+ */
43
+ __device__ __forceinline__ void CopyFromGlobalToShared_Scales(half* SPTR_QuantScales,
44
+ const half* GPTR_A_Scales)
45
+ {
46
+ int lane_id = threadIdx.x % WARP_SIZE;
47
+ int Offset_Shared = lane_id * 2;
48
+ int Offset_Global = lane_id / 4 + (lane_id % 4) * 16;
49
+ for (int i = 0; i < 2; i++)
50
+ SPTR_QuantScales[Offset_Shared + i] = GPTR_A_Scales[Offset_Global + i * 8];
51
+ }
52
+
53
+ /*
54
+ * (1) Copying X rows * 64 columns of FP16 values, originally in row major
55
+ * (2) Copying 64 rows * X columns of FP16 values, originally in column major
56
+ * 16 Bytes per thread -> 512 Bytes per WARP = 4 line per WARP = 1 line per 8 Threads
57
+ */
58
+ template <int MaxNumOfLinesToCopy, int BLOCK_WARPS>
59
+ __device__ __forceinline__ void CopyFromGlobalToShared(
60
+ half (*__restrict__ SharedPTR)[WARP_K + PADDING_SHARED_MEM_FOR_B_8],
61
+ const half* GlobalPTR,
62
+ const int GlobalStride,
63
+ const int NumOfLinesLeft, // To support arbitrary N dimensions.
64
+ bool Pred = true)
65
+ {
66
+ // static parameters: 1 Group (8 Threads) can copy 1 line (64 FP16) each time
67
+ const int NumOfThreads = BLOCK_WARPS * WARP_SIZE;
68
+ const int NumOfGroups = NumOfThreads / 8;
69
+ const int MaxIteration = (MaxNumOfLinesToCopy - 1) / NumOfGroups + 1;
70
+ // runtime variables
71
+ const int line_id = threadIdx.x / 8;
72
+ const int line_offset = (threadIdx.x % 8) * 8;
73
+ // PTR for source global memory and target shared memory
74
+ GlobalPTR += line_id * GlobalStride + line_offset;
75
+ SharedPTR += line_id;
76
+ #pragma unroll
77
+ for (int i = 0; i < MaxIteration; i++) {
78
+ bool AsyncCopyPred = (line_id + i * NumOfGroups) < NumOfLinesLeft && Pred;
79
+ cp_async<16>(&(*SharedPTR)[line_offset], GlobalPTR, AsyncCopyPred);
80
+ //
81
+ GlobalPTR += NumOfGroups * GlobalStride;
82
+ SharedPTR += NumOfGroups;
83
+ }
84
+ }
85
+
86
+ #endif
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/utils_paralleldequant.cuh ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ // This is a copy of FP6-LLM kernel code: https://arxiv.org/abs/2401.14112
7
+
8
+ #ifndef DEEPSPEED_CUDA_LINEAR_UTILS_PARALLELDEQUANT_CUH
9
+ #define DEEPSPEED_CUDA_LINEAR_UTILS_PARALLELDEQUANT_CUH
10
+
11
+ #include <cuda.h>
12
+ #include <cuda_fp16.h>
13
+ #include <cuda_runtime.h>
14
+
15
+ /*
16
+ * Input: R1
17
+ * Outputs: R1, R2
18
+ * Note: Simplified Exponent calculation is applied.
19
+ */
20
+ __device__ __forceinline__ void FP6_FP16_Cast_4Way(uint32_t* R1, uint32_t* R2)
21
+ {
22
+ *R2 = *R1 & 0x80808080;
23
+ *R1 = *R1 >> 2;
24
+ *R1 = *R1 & 0x1f1f1f1f;
25
+ *R2 = *R2 | *R1;
26
+ *R1 = *R2 & 0x9f009f00;
27
+ *R2 = *R2 & 0x009f009f;
28
+ *R2 = *R2 << 8;
29
+ }
30
+
31
+ /*
32
+ * Input: R1
33
+ * Outputs: R1, R2
34
+ * Note: Simplified Exponent calculation is NOT applied.
35
+ */
36
+ __device__ __forceinline__ void FP6_FP16_Cast_4Way_Naive(uint32_t* R1, uint32_t* R2)
37
+ {
38
+ //*R2 = *R1 & 0x80808080;
39
+ *R2 = *R1 & 0xc0c0c0c0;
40
+ *R1 = *R1 >> 2;
41
+ //*R1 = *R1 & 0x1f1f1f1f;
42
+ *R1 = *R1 & 0x0f0f0f0f;
43
+ *R2 = *R2 | *R1;
44
+ //
45
+ //*R1 = *R2 & 0x9f009f00;
46
+ //*R2 = *R2 & 0x009f009f;
47
+ *R1 = *R2 & 0xcf00cf00;
48
+ if (!(*R1 & 0x40000000) && (*R1 & 0x0c000000)) *R1 = *R1 | 0x30000000;
49
+ if (!(*R1 & 0x00004000) && (*R1 & 0x00000c00)) *R1 = *R1 | 0x00003000;
50
+ *R2 = *R2 & 0x00cf00cf;
51
+ if (!(*R2 & 0x00400000) && (*R2 & 0x000c0000)) *R2 = *R2 | 0x00300000;
52
+ if (!(*R2 & 0x00000040) && (*R2 & 0x0000000c)) *R2 = *R2 | 0x00000030;
53
+ //
54
+ *R2 = *R2 << 8;
55
+ //*R1 = 0x3c003c00;
56
+ //*R2 = 0x3c003c00;
57
+ }
58
+
59
+ __device__ __forceinline__ uint32_t MultScale(uint32_t PackedFP16Pair, half Scale)
60
+ {
61
+ half* FP16_1 = reinterpret_cast<half*>(&PackedFP16Pair);
62
+ half* FP16_2 = FP16_1 + 1;
63
+ uint32_t output;
64
+ half* output_half_ptr = reinterpret_cast<half*>(&output);
65
+ output_half_ptr[0] = __hmul(__hmul(*FP16_1, __float2half(4096.0f)), Scale);
66
+ output_half_ptr[1] = __hmul(__hmul(*FP16_2, __float2half(4096.0f)), Scale);
67
+ return output;
68
+ }
69
+
70
+ __device__ __forceinline__ void Dequant_32FP6_4Way(uint32_t (*__restrict__ Reg)[4],
71
+ uint32_t* __restrict__ read_RPTR_Frag1,
72
+ uint32_t* __restrict__ read_RPTR_Frag2,
73
+ uint32_t* Scales)
74
+ {
75
+ uint32_t* OutputRegs = reinterpret_cast<uint32_t*>(Reg);
76
+ uint32_t* Frag1_PTR = read_RPTR_Frag1;
77
+ uint32_t* Frag2_PTR = read_RPTR_Frag2;
78
+ half* Scale_RPTR = reinterpret_cast<half*>(Scales);
79
+ uint32_t Packed_FP6 = 0;
80
+ uint32_t tmp = 0;
81
+ // Dequantizing 32 FP6, each Loop dequantizing 4 FP6
82
+ #pragma unroll(8)
83
+ for (int i = 0; i < 8; i++) {
84
+ // Frag1
85
+ Packed_FP6 = (*Frag1_PTR) & 0xc0c0c0c0;
86
+ if (i % 4 == 3)
87
+ Frag1_PTR++;
88
+ else
89
+ (*Frag1_PTR) = (*Frag1_PTR) << 2;
90
+ // Frag2
91
+ tmp = (*Frag2_PTR) & 0xf0f0f0f0;
92
+ tmp = tmp >> 2;
93
+ if (i % 2 == 1)
94
+ Frag2_PTR++;
95
+ else
96
+ (*Frag2_PTR) = (*Frag2_PTR) << 4;
97
+ // Packed_FP6
98
+ Packed_FP6 = Packed_FP6 | tmp;
99
+ //
100
+ FP6_FP16_Cast_4Way(&Packed_FP6, &tmp);
101
+ //
102
+ *OutputRegs = MultScale(Packed_FP6, Scale_RPTR[0]); // Muliply FP16 scales
103
+ OutputRegs += 1;
104
+ *OutputRegs = MultScale(tmp, Scale_RPTR[1]); // Muliply FP16 scales
105
+ OutputRegs += 1;
106
+ // Updating offset for FP16 scales for every two iterations
107
+ if (i % 2 == 1) Scale_RPTR += 2;
108
+ }
109
+ }
110
+
111
+ /*
112
+ *
113
+ */
114
+ __device__ __forceinline__ void ExtractFromSharedToReg_Scales(uint32_t* Scales,
115
+ half* WARP_SPTR_Scales)
116
+ {
117
+ int lane_id = threadIdx.x % WARP_SIZE;
118
+ uint32_t* SPTR_uint = reinterpret_cast<uint32_t*>(WARP_SPTR_Scales);
119
+ uint32_t tmpReg = SPTR_uint[lane_id];
120
+ #pragma unroll
121
+ for (int i = 0; i < 4; i++) {
122
+ // T __shfl_sync(unsigned mask, T var, int srcLane, int width=warpSize);
123
+ Scales[i] = __shfl_sync(0xffffffff, tmpReg, i, 4);
124
+ }
125
+ }
126
+
127
+ #endif
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/weight_prepacking.h ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ // This is a copy of FP6-LLM kernel code: https://arxiv.org/abs/2401.14112
7
+
8
+ #ifndef DEEPSPEED_CUDA_LINEAR_WEIGHT_PREPACKING_H
9
+ #define DEEPSPEED_CUDA_LINEAR_WEIGHT_PREPACKING_H
10
+
11
+ #include <assert.h>
12
+ #include <stdio.h>
13
+ #include <vector>
14
+
15
+ using namespace std;
16
+
17
+ void Padding_8_FP6_To_8_Bytes(unsigned char Padded_FP6[],
18
+ unsigned char* FP6_Array) // padding 0 to the lowerest bit location
19
+ {
20
+ Padded_FP6[0] = FP6_Array[0] & 0xfc;
21
+ Padded_FP6[1] = (FP6_Array[0] << 6) | ((FP6_Array[1] >> 2) & 0xfc);
22
+ Padded_FP6[2] = (FP6_Array[1] << 4) | ((FP6_Array[2] >> 4) & 0xfc);
23
+ Padded_FP6[3] = FP6_Array[2] << 2;
24
+ Padded_FP6[4] = FP6_Array[3] & 0xfc;
25
+ Padded_FP6[5] = (FP6_Array[3] << 6) | ((FP6_Array[4] >> 2) & 0xfc);
26
+ Padded_FP6[6] = (FP6_Array[4] << 4) | ((FP6_Array[5] >> 4) & 0xfc);
27
+ Padded_FP6[7] = FP6_Array[5] << 2;
28
+ }
29
+
30
+ unsigned char Extract_2_Bits_From_4_PaddedFP6(unsigned char B1,
31
+ unsigned char B2,
32
+ unsigned char B3,
33
+ unsigned char B4)
34
+ {
35
+ unsigned char out;
36
+ out = (B1 & 0xc0) | ((B2 & 0xc0) >> 2) | ((B3 & 0xc0) >> 4) | ((B4 & 0xc0) >> 6);
37
+ return out;
38
+ }
39
+
40
+ unsigned char Extract_4_Bits_From_2_PaddedFP6(
41
+ unsigned char B1,
42
+ unsigned char
43
+ B2) // The highest two bits are already extracted by Extract_2_Bits_From_4_PaddedFP6();
44
+ {
45
+ unsigned char out;
46
+ out = ((B1 << 2) & 0xf0) | ((B2 >> 2) & 0x0f);
47
+ return out;
48
+ }
49
+
50
+ // dealing with 4 1*8 blocks of FP6
51
+ void Assign_32_FP6_To_4_Thread(vector<unsigned char> Seg_2bit[],
52
+ vector<unsigned char> Seg_4bit[],
53
+ unsigned char* PTR_1,
54
+ unsigned char* PTR_2,
55
+ unsigned char* PTR_3,
56
+ unsigned char* PTR_4)
57
+ {
58
+ unsigned char Padded_8_FP8[4][8];
59
+ Padding_8_FP6_To_8_Bytes(Padded_8_FP8[0], PTR_1);
60
+ Padding_8_FP6_To_8_Bytes(Padded_8_FP8[1], PTR_2);
61
+ Padding_8_FP6_To_8_Bytes(Padded_8_FP8[2], PTR_3);
62
+ Padding_8_FP6_To_8_Bytes(Padded_8_FP8[3], PTR_4);
63
+ //
64
+ unsigned char Seg1_Byte1_T[4];
65
+ unsigned char Seg1_Byte2_T[4];
66
+ unsigned char Seg2_Byte1_T[4];
67
+ unsigned char Seg2_Byte2_T[4];
68
+ unsigned char Seg2_Byte3_T[4];
69
+ unsigned char Seg2_Byte4_T[4];
70
+ for (int t = 0; t < 4; t++) {
71
+ Seg1_Byte1_T[t] = Extract_2_Bits_From_4_PaddedFP6(Padded_8_FP8[0][0 + t * 2],
72
+ Padded_8_FP8[0][1 + t * 2],
73
+ Padded_8_FP8[1][0 + t * 2],
74
+ Padded_8_FP8[1][1 + t * 2]);
75
+ Seg1_Byte2_T[t] = Extract_2_Bits_From_4_PaddedFP6(Padded_8_FP8[2][0 + t * 2],
76
+ Padded_8_FP8[2][1 + t * 2],
77
+ Padded_8_FP8[3][0 + t * 2],
78
+ Padded_8_FP8[3][1 + t * 2]);
79
+ Seg2_Byte1_T[t] =
80
+ Extract_4_Bits_From_2_PaddedFP6(Padded_8_FP8[0][0 + t * 2], Padded_8_FP8[0][1 + t * 2]);
81
+ Seg2_Byte2_T[t] =
82
+ Extract_4_Bits_From_2_PaddedFP6(Padded_8_FP8[1][0 + t * 2], Padded_8_FP8[1][1 + t * 2]);
83
+ Seg2_Byte3_T[t] =
84
+ Extract_4_Bits_From_2_PaddedFP6(Padded_8_FP8[2][0 + t * 2], Padded_8_FP8[2][1 + t * 2]);
85
+ Seg2_Byte4_T[t] =
86
+ Extract_4_Bits_From_2_PaddedFP6(Padded_8_FP8[3][0 + t * 2], Padded_8_FP8[3][1 + t * 2]);
87
+ }
88
+ //
89
+ for (int t = 0; t < 4; t++) {
90
+ Seg_2bit[t].push_back(Seg1_Byte1_T[t]);
91
+ Seg_2bit[t].push_back(Seg1_Byte2_T[t]);
92
+ Seg_4bit[t].push_back(Seg2_Byte1_T[t]);
93
+ Seg_4bit[t].push_back(Seg2_Byte2_T[t]);
94
+ Seg_4bit[t].push_back(Seg2_Byte3_T[t]);
95
+ Seg_4bit[t].push_back(Seg2_Byte4_T[t]);
96
+ }
97
+ return;
98
+ }
99
+
100
+ void BitInterleaving_2bit(unsigned char* PTR_4Bytes)
101
+ {
102
+ unsigned int* PTR_UINT = reinterpret_cast<unsigned int*>(PTR_4Bytes);
103
+ unsigned int input = *PTR_UINT;
104
+ //
105
+ // int order_2bit[16] = {1,5,9,13,3,7,11,15,2,6,10,14,4,8,12,16}; // pre-defined order for
106
+ // bit-interleaving in QuantLLM
107
+ int order_2bit[16] = {
108
+ 2, 6, 10, 14, 4, 8, 12, 16, 1, 5, 9, 13, 3, 7, 11, 15}; // pre-defined order for
109
+ // bit-interleaving in QuantLLM
110
+ unsigned int Frags_2bit[16]; // The highest 2 bits are used to store the extracted fragments.
111
+ for (int i = 0; i < 16; i++) Frags_2bit[i] = (input << 2 * (order_2bit[i] - 1)) & 0xc0000000;
112
+ //
113
+ unsigned int output = 0x00000000;
114
+ for (int i = 0; i < 16; i++) output |= (Frags_2bit[i] >> (i * 2));
115
+ //
116
+ *PTR_UINT = output;
117
+ }
118
+
119
+ void BitInterleaving_4bit(unsigned char* PTR_4Bytes)
120
+ {
121
+ unsigned int* PTR_UINT = reinterpret_cast<unsigned int*>(PTR_4Bytes);
122
+ unsigned int input = *PTR_UINT;
123
+ //
124
+ // int order_4bit[8] = {1,5,3,7,2,6,4,8}; // pre-defined order for bit-interleaving in QuantLLM
125
+ int order_4bit[8] = {
126
+ 2, 6, 4, 8, 1, 5, 3, 7}; // pre-defined order for bit-interleaving in QuantLLM
127
+ unsigned int Frags_4bit[8]; // The highest4 bits are used to store the extracted fragments.
128
+ for (int i = 0; i < 8; i++) Frags_4bit[i] = (input << 4 * (order_4bit[i] - 1)) & 0xf0000000;
129
+ //
130
+ unsigned int output = 0x00000000;
131
+ for (int i = 0; i < 8; i++) output |= (Frags_4bit[i] >> (i * 4));
132
+ //
133
+ *PTR_UINT = output;
134
+ }
135
+
136
+ /*
137
+ * Inputs:
138
+ * (1) unsigned char Weight_6bit [M*K*6/8]
139
+ * Outputs:
140
+ * (1) unsigned char Weight_2bit [M*K*2/8]
141
+ * (2) unsigned char Weight_4bit [M*K*4/8]
142
+ *
143
+ * Assumption: Weight_6bit, Weight_2bit, Weight_4bit all stored continuously in row-major.
144
+ * 8 FP6 = 6 Bytes
145
+ * 8 FP4 = 4 Bytes
146
+ * 8 FP2 = 2 Bytes
147
+ */
148
+ void weight_matrix_prepacking(int* FP6Weights, size_t M, size_t K)
149
+ {
150
+ assert(M % 64 == 0);
151
+ assert(K % 64 == 0);
152
+ //
153
+ unsigned char* Weight_6bit = reinterpret_cast<unsigned char*>(FP6Weights);
154
+ unsigned char* Weight_2bit = Weight_6bit;
155
+ unsigned char* Weight_4bit = Weight_6bit + M * K * 2 / 8;
156
+ //
157
+ vector<unsigned char> A_Segment_2bit[32];
158
+ vector<unsigned char> A_Segment_4bit[32];
159
+ //
160
+ size_t BytesPerRow = K * 6 / 8;
161
+ // Pass-1: (1) 2+4 split; (2) assign weights to 32 threads.
162
+ for (size_t i = 0; i < M / 64; i++) //
163
+ {
164
+ for (size_t j = 0; j < K / 16; j++) {
165
+ for (size_t k = 0; k < 64 / 16; k++) {
166
+ size_t row = i * 64 + k * 16;
167
+ size_t col = j * 16;
168
+ unsigned char* StartPTR_1 = Weight_6bit + row * BytesPerRow + col * 6 / 8;
169
+ unsigned char* StartPTR_2 = StartPTR_1 + 8 * BytesPerRow;
170
+ unsigned char* StartPTR_3 = StartPTR_1 + 8 * 6 / 8;
171
+ unsigned char* StartPTR_4 = StartPTR_2 + 8 * 6 / 8;
172
+ // Dealing with each 16*16 blocks then...
173
+ for (int l = 0; l < 8; l++)
174
+ Assign_32_FP6_To_4_Thread(&A_Segment_2bit[l * 4],
175
+ &A_Segment_4bit[l * 4],
176
+ StartPTR_1 + l * BytesPerRow,
177
+ StartPTR_2 + l * BytesPerRow,
178
+ StartPTR_3 + l * BytesPerRow,
179
+ StartPTR_4 + l * BytesPerRow);
180
+ }
181
+ }
182
+ }
183
+ // Verifying the length of 2_bit segments and 4_bit segments
184
+ size_t BytesPerThread_2bit = M * K * 2 / 8 / 32;
185
+ size_t BytesPerThread_4bit = M * K * 4 / 8 / 32;
186
+ for (int i = 0; i < 32; i++) {
187
+ assert(A_Segment_2bit[i].size() == BytesPerThread_2bit);
188
+ assert(A_Segment_4bit[i].size() == BytesPerThread_4bit);
189
+ }
190
+ // Pass-2: Optimizing coleasced global memory access
191
+ for (size_t i = 0; i < BytesPerThread_2bit / 4; i++)
192
+ for (int t = 0; t < 32; t++)
193
+ for (int b = 0; b < 4; b++)
194
+ Weight_2bit[i * 128 + t * 4 + (3 - b)] =
195
+ A_Segment_2bit[t]
196
+ [i * 4 + b]; // why (3-b): special byte order within a register
197
+ for (size_t i = 0; i < BytesPerThread_4bit / 4; i++)
198
+ for (int t = 0; t < 32; t++)
199
+ for (int b = 0; b < 4; b++)
200
+ Weight_4bit[i * 128 + t * 4 + (3 - b)] =
201
+ A_Segment_4bit[t][i * 4 + b]; // why (3-b):special byte order within a register
202
+ // Pass-3: Bit-level interleaving
203
+ for (size_t i = 0; i < BytesPerThread_2bit * 32 / 4; i++)
204
+ BitInterleaving_2bit(Weight_2bit + 4 * i);
205
+ for (size_t i = 0; i < BytesPerThread_4bit * 32 / 4; i++)
206
+ BitInterleaving_4bit(Weight_4bit + 4 * i);
207
+ }
208
+
209
+ #endif
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/linear_kernels.cpp ADDED
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ #include <ATen/cuda/CUDAContext.h>
7
+
8
+ #include "linear_kernels.h"
9
+
10
+ namespace {
11
+
12
+ // For bit-level debugging.
13
+ template <typename T>
14
+ void print_bits(T num)
15
+ {
16
+ char bits[sizeof(T) * 8 + 1] = {'\0'};
17
+ for (int bit = 0; bit < (sizeof(T) * 8); bit++) {
18
+ bits[sizeof(T) * 8 - 1 - bit] = '0' + (num & 0x01);
19
+ num = num >> 1;
20
+ }
21
+ printf("%s\n", bits);
22
+ }
23
+
24
+ void print_bits(half num)
25
+ {
26
+ char bits[sizeof(half) * 8 + 1] = {'\0'};
27
+ auto int_num = *reinterpret_cast<uint16_t*>(&num);
28
+ for (int bit = 0; bit < (sizeof(half) * 8); bit++) {
29
+ bits[sizeof(half) * 8 - 1 - bit] = '0' + (int_num & 0x01);
30
+ int_num = int_num >> 1;
31
+ }
32
+ printf("%s\n", bits);
33
+ }
34
+
35
+ /*
36
+ * Function to pack 4 fake quantized FP16 value into continuously stored 4 FP6 values.
37
+ */
38
+ void cast_fp16_fp6(uint16_t* FP16x4, uint8_t* FP6x4)
39
+ {
40
+ // Constants for FP6
41
+ constexpr int exponent_nbits_fp6 = 3;
42
+ constexpr int mantissa_nbits_fp6 = 2;
43
+ constexpr int exp_bias_fp6 = (1 << (exponent_nbits_fp6 - 1)) - 1;
44
+ // Constants for FP16
45
+ constexpr int exponent_nbits_fp16 = 5;
46
+ constexpr int mantissa_nbits_fp16 = 10;
47
+ constexpr int exp_bias_fp16 = (1 << (exponent_nbits_fp16 - 1)) - 1;
48
+
49
+ int fp6_temp[4];
50
+
51
+ float absmin_nonzero_fp6 = 0.0625;
52
+ // Note that we regard the exponent of '111' as a regular value rather than NaN or inf. This is
53
+ // the same with that in qtorch.
54
+ float absmax_fp6 = 28;
55
+
56
+ for (int i = 0; i < 4; ++i) {
57
+ uint16_t source = FP16x4[i];
58
+ float fp6_value_abs = std::abs(__half2float(*((half*)(&source))));
59
+ if ((fp6_value_abs != 0 && fp6_value_abs < absmin_nonzero_fp6) ||
60
+ fp6_value_abs > absmax_fp6) {
61
+ // TODO(zhen): a better way may be rounding it to the nearest FP6 value.
62
+ throw std::invalid_argument("Input value out of range for FP6.");
63
+ }
64
+
65
+ // It is not safe to do shift operation on uint16_t. So we promote it to int.
66
+ int source_promote = int(source);
67
+
68
+ int sign_bit = (source_promote >> 15);
69
+ // Extracting exponent represented in FP16. The sign mask 0x7FFF is '0111 1111 1111 1111'
70
+ int exp_bit = (source_promote & 0x7FFF) >> mantissa_nbits_fp16;
71
+ // Extracting mantissa represented in FP16
72
+ int mant_bit = source_promote & ((1 << mantissa_nbits_fp16) - 1);
73
+
74
+ int new_exp_bit;
75
+ int new_mant_bit;
76
+
77
+ if (exp_bit == 0) {
78
+ // Subnormal FP16 number. Too small for FP6.
79
+ new_exp_bit = 0;
80
+ new_mant_bit = 0;
81
+ } else {
82
+ new_mant_bit = mant_bit >> (mantissa_nbits_fp16 - mantissa_nbits_fp6);
83
+ new_exp_bit = exp_bit - exp_bias_fp16 + exp_bias_fp6;
84
+
85
+ // Deal with subnormal FP6 values.
86
+ int target_exp_val = exp_bit - exp_bias_fp16;
87
+ int min_fp6_exp_val = -exp_bias_fp6 + 1;
88
+ bool subnormal_fp6 = target_exp_val < min_fp6_exp_val;
89
+ if (subnormal_fp6) {
90
+ // TODO(zhen): add the rounding logic.
91
+ new_exp_bit = 0;
92
+ // The implicit 1 in the mantissa of FP16 is not present in subnormal FP6. Thus we
93
+ // need to add it
94
+ new_mant_bit = (new_mant_bit | (1 << mantissa_nbits_fp6)) >>
95
+ (min_fp6_exp_val - target_exp_val);
96
+ }
97
+ }
98
+
99
+ fp6_temp[i] = (sign_bit << (exponent_nbits_fp6 + mantissa_nbits_fp6)) |
100
+ (new_exp_bit << mantissa_nbits_fp6) | new_mant_bit;
101
+ }
102
+ // Pack the values
103
+ FP6x4[0] = fp6_temp[0] << 2 | (fp6_temp[1] >> 4);
104
+ FP6x4[1] = (fp6_temp[1] & 0x0F) << 4 | (fp6_temp[2] >> 2);
105
+ FP6x4[2] = (fp6_temp[2] & 0x03) << 6 | fp6_temp[3];
106
+ }
107
+
108
+ /*
109
+ * Function to prepack FP16 weights into continuous FP6 values.
110
+ *
111
+ * Parameters:
112
+ * weight_16bit: input weight in FP16, size M*K
113
+ * weight_6bit: output weight in packed FP6, continuously stored, size M*K*6/8
114
+ * M, K: the shape of the weight
115
+ */
116
+ void weight_prepacking_fp16_to_fp6(uint16_t* weight_16bit,
117
+ uint8_t* weight_6bit_packed,
118
+ size_t M,
119
+ size_t K)
120
+ {
121
+ // Every four 16-bit elements are packed into three 6-bit values (4*6bit == 3*8bit).
122
+ if (K * 6 % 8 != 0) { throw std::invalid_argument("(K * 6 % 8) should be 0"); }
123
+ size_t K_fp6_packed = K * 6 / 8;
124
+ // #pragma omp parallel for
125
+ for (auto m = 0; m < M; m++) {
126
+ uint8_t* ptr_6bit = weight_6bit_packed + m * K_fp6_packed;
127
+ uint16_t* ptr_16bit = weight_16bit + m * K;
128
+ for (auto k = 0; k < K; k += 4) {
129
+ cast_fp16_fp6(ptr_16bit, ptr_6bit);
130
+ ptr_16bit += 4;
131
+ ptr_6bit += 3;
132
+ }
133
+ }
134
+ }
135
+
136
+ } // namespace
137
+
138
+ /*
139
+ * Function to execute the FP6 linear kernel.
140
+ *
141
+ * Parameters:
142
+ * output: output tensor, size M*N
143
+ * hidden_states: input activation tensor, size N*K
144
+ * weights_2bit: packed 2bit weights, size M*K*2/8
145
+ * weights_4bit: packed 4bit weights, size M*K*4/8
146
+ * scales: scale tensor, size M
147
+ * workspace: workspace tensor, size M*N*split_k
148
+ * M: the output channel number of the weight
149
+ * N: the token number of the activation
150
+ * K: the input channel number of the weight
151
+ * split_k: the split size of the GEMM calculation
152
+ */
153
+ void cuda_wf6af16_linear(torch::Tensor& output,
154
+ torch::Tensor& hidden_states,
155
+ torch::Tensor& weights_2bit,
156
+ torch::Tensor& weights_4bit,
157
+ torch::Tensor& scales,
158
+ torch::Tensor& workspace,
159
+ int M,
160
+ int N,
161
+ int K,
162
+ int split_k)
163
+ {
164
+ TORCH_CHECK(weights_2bit.device().type() == torch::kCUDA, "weight_2bit must be on CUDA");
165
+ TORCH_CHECK(weights_4bit.device().type() == torch::kCUDA, "weight_4bit must be on CUDA");
166
+ TORCH_CHECK(hidden_states.device().type() == torch::kCUDA, "X must be on CUDA");
167
+ TORCH_CHECK(scales.device().type() == torch::kCUDA, "scales must be on CUDA");
168
+
169
+ auto status = fp6_linear_kernel(at::cuda::getCurrentCUDAStream(),
170
+ (uint4*)(weights_2bit.data_ptr<uint8_t>()),
171
+ (uint4*)(weights_4bit.data_ptr<uint8_t>()),
172
+ (half*)(scales.data_ptr<at::Half>()),
173
+ (half*)(hidden_states.data_ptr<at::Half>()),
174
+ (half*)(output.data_ptr<at::Half>()),
175
+ M,
176
+ N,
177
+ K,
178
+ workspace.data_ptr<float>(),
179
+ split_k);
180
+ if (status != cudaSuccess) {
181
+ AT_ERROR("fp6_linear_kernel failed with error: ", cudaGetErrorString(status));
182
+ }
183
+ }
184
+
185
+ /*
186
+ * Function to prepack the fake 6-bit-quantized FP16 weights into 2bit and 4bit.
187
+ *
188
+ * Parameters:
189
+ * weight: input weight in FP16 (containing the quantized FP6-ranged value), size M*K
190
+ * Returns:
191
+ * weight_2bit: output weight in 2bit, size M*K*2/8
192
+ * weight_4bit: output weight in 4bit, size M*K*4/8
193
+ */
194
+ std::vector<torch::Tensor> preprocess_weight(torch::Tensor& weight)
195
+ {
196
+ TORCH_CHECK(weight.dim() == 2, "weight must be 2-dimensional");
197
+ TORCH_CHECK(weight.scalar_type() == torch::kFloat16, "weight must be FP16");
198
+ TORCH_CHECK(weight.is_contiguous(), "weight must be contiguous");
199
+ TORCH_CHECK(weight.device().type() == torch::kCPU, "weight must be on CPU");
200
+ auto M = weight.size(0);
201
+ auto K = weight.size(1);
202
+ TORCH_CHECK(K % 4 == 0, "K must be multiple of 4");
203
+
204
+ // Pack weight from FP16 to FP6.
205
+ uint16_t* weight_16bit_ptr = reinterpret_cast<uint16_t*>(weight.data_ptr<at::Half>());
206
+ std::vector<uint8_t> weight_6bit_packed(M * K * 6 / 8);
207
+ uint8_t* weight_6bit_ptr = weight_6bit_packed.data();
208
+ weight_prepacking_fp16_to_fp6(weight_16bit_ptr, weight_6bit_ptr, M, K);
209
+
210
+ // Split weight into 2bit and 4bit.
211
+ weight_matrix_prepacking(reinterpret_cast<int*>(weight_6bit_ptr), M, K);
212
+ uint8_t* weight_2bit_ptr = weight_6bit_ptr;
213
+
214
+ // Make sure that the new split tensor does not share the underlying memory with the original
215
+ // one. Otherwise it will incur some problems when the original tensor is deleted. It also
216
+ // makes the memory flattern risky.
217
+ auto weight_2bit =
218
+ torch::from_blob(weight_2bit_ptr, {M * K * 2 / 8}, torch::kUInt8).clone().detach();
219
+ uint8_t* weight_4bit_ptr = weight_2bit_ptr + M * K * 2 / 8;
220
+ auto weight_4bit =
221
+ torch::from_blob(weight_4bit_ptr, {M * K * 4 / 8}, torch::kUInt8).clone().detach();
222
+
223
+ return {weight_2bit, weight_4bit};
224
+ }
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/linear_kernels.h ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ #ifndef DEEPSPEED_CUDA_LINEAR_KERNELS_H
7
+ #define DEEPSPEED_CUDA_LINEAR_KERNELS_H
8
+
9
+ #include <c10/cuda/CUDAStream.h>
10
+ #include <torch/extension.h>
11
+ #include "ds_kernel_utils.h"
12
+
13
+ #include "linear_kernels_cuda.h"
14
+
15
+ void cuda_wf6af16_linear(torch::Tensor& output,
16
+ torch::Tensor& hidden_states,
17
+ torch::Tensor& weights_2bit,
18
+ torch::Tensor& weights_4bit,
19
+ torch::Tensor& scale,
20
+ torch::Tensor& workspace,
21
+ int M,
22
+ int N,
23
+ int K,
24
+ int split_k);
25
+
26
+ std::vector<torch::Tensor> preprocess_weight(torch::Tensor& Weight);
27
+
28
+ #endif
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/linear_kernels_cuda.cu ADDED
@@ -0,0 +1,318 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ // This is a copy of FP6-LLM kernel code: https://arxiv.org/abs/2401.14112
7
+
8
+ // clang-format off
9
+ // Put the torch headers at the front to avoid conflict with other headers on
10
+ // `at::nullopt` and `at::optional`.
11
+ #include <torch/extension.h>
12
+ #include <ATen/ATen.h>
13
+ // clang-format on
14
+
15
+ #include "include/kernel_matmul.cuh"
16
+ #include "include/kernel_reduction.cuh"
17
+ #include "include/weight_prepacking.h"
18
+
19
+ #include <assert.h>
20
+ #include <stdio.h>
21
+
22
+ #include "linear_kernels_cuda.h"
23
+
24
+ template <typename TilingConfig, typename OutputDataType>
25
+ static void Kernel_Ex(cudaStream_t stream,
26
+ const uint4* Weight1,
27
+ const uint4* Weight2,
28
+ const half* Scales,
29
+ const half* B,
30
+ OutputDataType* C,
31
+ const size_t M_Global,
32
+ const size_t N_Global,
33
+ const size_t K_Global,
34
+ int Split_K)
35
+ {
36
+ #ifdef DEBUG_MODE
37
+ printf("\n");
38
+ printf("Launcher.cu->Kernel_Ex():\n");
39
+ printf("M: %d, N: %d, K: %d, SplitK: %d\n", M_Global, N_Global, K_Global, Split_K);
40
+ printf("TILE_M: %d, TILE_K: %d, TILE_N: %d\n",
41
+ TilingConfig::TILE_M,
42
+ TilingConfig::TILE_K,
43
+ TilingConfig::TILE_N);
44
+ #endif
45
+ static size_t SHMEM_SZ =
46
+ max(TilingConfig::SMEM_SIZE_B_TILE + SMEM_SIZE_A1_TILE + SMEM_SIZE_A2_TILE,
47
+ TilingConfig::SMEM_SIZE_C_TILE);
48
+ cudaFuncSetAttribute(QUANT_GEMM_Kernel<TilingConfig, OutputDataType>,
49
+ cudaFuncAttributeMaxDynamicSharedMemorySize,
50
+ SHMEM_SZ);
51
+ size_t dimN = (N_Global - 1) / TilingConfig::TILE_N + 1;
52
+ size_t dimM = M_Global * Split_K / TilingConfig::TILE_M;
53
+ dim3 GridDim(dimN, dimM, 1);
54
+ dim3 BlockDim(WARP_SIZE * TilingConfig::BLOCK_WARPS, 1, 1);
55
+
56
+ #ifdef DEBUG_MODE
57
+ printf(
58
+ "GridDim.x: %d, GridDim.y: %d, GridDim.z: %d, BlockDim.x: %d, BlockDim.y: %d, BlockDim.z: "
59
+ "%d SHMEM_SZ: %d\n",
60
+ GridDim.x,
61
+ GridDim.y,
62
+ GridDim.z,
63
+ BlockDim.x,
64
+ BlockDim.y,
65
+ BlockDim.z,
66
+ SHMEM_SZ);
67
+ printf("\n");
68
+ #endif
69
+
70
+ QUANT_GEMM_Kernel<TilingConfig, OutputDataType><<<GridDim, BlockDim, SHMEM_SZ, stream>>>(
71
+ Weight1, Weight2, Scales, B, C, M_Global, N_Global, K_Global, Split_K);
72
+ }
73
+
74
+ /*
75
+ *
76
+ */
77
+ cudaError_t fp6_linear_kernel(cudaStream_t stream,
78
+ const uint4* Weight1,
79
+ const uint4* Weight2,
80
+ const half* Scales,
81
+ const half* B,
82
+ half* C,
83
+ const size_t M_Global,
84
+ const size_t N_Global,
85
+ const size_t K_Global,
86
+ float* Reduction_Workspace, // Reduction_Workspace_Size = Split_K *
87
+ // M_Global * N_Global * sizeof(fp32)
88
+ int Split_K)
89
+ {
90
+ assert(M_Global % 256 == 0);
91
+ assert(K_Global % 64 == 0);
92
+ assert(N_Global > 0);
93
+
94
+ // Work around to support more N shapes:
95
+ size_t N_PowerOf2;
96
+ if (N_Global > 0 && N_Global <= 8) N_PowerOf2 = 8;
97
+ if (N_Global > 8 && N_Global <= 16) N_PowerOf2 = 16;
98
+ if (N_Global > 16 && N_Global <= 32) N_PowerOf2 = 32;
99
+ if (N_Global > 32 && N_Global <= 64) N_PowerOf2 = 64;
100
+ if (N_Global > 64 && N_Global <= 128) N_PowerOf2 = 128;
101
+ if (N_Global > 128) N_PowerOf2 = ((N_Global - 1) / 128 + 1) * 128;
102
+
103
+ if (Split_K == 1) {
104
+ switch (N_PowerOf2) {
105
+ case 8:
106
+ Kernel_Ex<TilingConfig<4, 1, 1>, half>(
107
+ stream, Weight1, Weight2, Scales, B, C, M_Global, N_Global, K_Global, Split_K);
108
+ break;
109
+ case 16:
110
+ Kernel_Ex<TilingConfig<4, 1, 2>, half>(
111
+ stream, Weight1, Weight2, Scales, B, C, M_Global, N_Global, K_Global, Split_K);
112
+ break;
113
+ case 32:
114
+ Kernel_Ex<TilingConfig<4, 1, 4>, half>(
115
+ stream, Weight1, Weight2, Scales, B, C, M_Global, N_Global, K_Global, Split_K);
116
+ break;
117
+ case 64:
118
+ Kernel_Ex<TilingConfig<4, 1, 8>, half>(
119
+ stream, Weight1, Weight2, Scales, B, C, M_Global, N_Global, K_Global, Split_K);
120
+ break;
121
+ case 128:
122
+ Kernel_Ex<TilingConfig<4, 1, 8>, half>(
123
+ stream, Weight1, Weight2, Scales, B, C, M_Global, N_Global, K_Global, Split_K);
124
+ break;
125
+ default:
126
+ if (N_PowerOf2 % 128 != 0) {
127
+ printf("QuantLLM_API Error: Unsupported N dimension %lu!\n", N_PowerOf2);
128
+ return cudaErrorUnknown;
129
+ }
130
+ Kernel_Ex<TilingConfig<4, 1, 8>, half>(
131
+ stream, Weight1, Weight2, Scales, B, C, M_Global, N_Global, K_Global, Split_K);
132
+ break;
133
+ }
134
+ } else {
135
+ switch (N_PowerOf2) {
136
+ case 8:
137
+ Kernel_Ex<TilingConfig<4, 1, 1>, float>(stream,
138
+ Weight1,
139
+ Weight2,
140
+ Scales,
141
+ B,
142
+ Reduction_Workspace,
143
+ M_Global,
144
+ N_Global,
145
+ K_Global,
146
+ Split_K);
147
+ break;
148
+ case 16:
149
+ Kernel_Ex<TilingConfig<4, 1, 2>, float>(stream,
150
+ Weight1,
151
+ Weight2,
152
+ Scales,
153
+ B,
154
+ Reduction_Workspace,
155
+ M_Global,
156
+ N_Global,
157
+ K_Global,
158
+ Split_K);
159
+ break;
160
+ case 32:
161
+ Kernel_Ex<TilingConfig<4, 1, 4>, float>(stream,
162
+ Weight1,
163
+ Weight2,
164
+ Scales,
165
+ B,
166
+ Reduction_Workspace,
167
+ M_Global,
168
+ N_Global,
169
+ K_Global,
170
+ Split_K);
171
+ break;
172
+ case 64:
173
+ Kernel_Ex<TilingConfig<4, 1, 8>, float>(stream,
174
+ Weight1,
175
+ Weight2,
176
+ Scales,
177
+ B,
178
+ Reduction_Workspace,
179
+ M_Global,
180
+ N_Global,
181
+ K_Global,
182
+ Split_K);
183
+ break;
184
+ case 128:
185
+ Kernel_Ex<TilingConfig<4, 1, 8>, float>(stream,
186
+ Weight1,
187
+ Weight2,
188
+ Scales,
189
+ B,
190
+ Reduction_Workspace,
191
+ M_Global,
192
+ N_Global,
193
+ K_Global,
194
+ Split_K);
195
+ break;
196
+ default:
197
+ if (N_PowerOf2 % 128 != 0) {
198
+ printf("QuantLLM_API Error: Unsupported N dimension %lu!\n", N_PowerOf2);
199
+ return cudaErrorUnknown;
200
+ }
201
+ Kernel_Ex<TilingConfig<4, 1, 8>, float>(stream,
202
+ Weight1,
203
+ Weight2,
204
+ Scales,
205
+ B,
206
+ Reduction_Workspace,
207
+ M_Global,
208
+ N_Global,
209
+ K_Global,
210
+ Split_K);
211
+ break;
212
+ }
213
+ // Reduction for SplitK
214
+ dim3 GridDim((M_Global * N_Global) / REDUCTION_ELEMENT_PER_THREADBLOCK, 1, 1);
215
+ dim3 BlockDim(WARP_SIZE, 1, 1);
216
+ SplitK_Reduction<<<GridDim, BlockDim, 0, stream>>>(
217
+ C, Reduction_Workspace, M_Global, N_Global, Split_K);
218
+ }
219
+ return cudaGetLastError();
220
+ }
221
+
222
+ /*
223
+ Computes FP6-FP16 GEMM (PyTorch interface).
224
+
225
+ [Mathematical Formula]
226
+ Standard definition of linear layer: Out = In * trans(W), where In, Out, and W are stored in
227
+ row-major. After Equivalent transformation : trans(Out) = W * trans(In). Note that we do not
228
+ perform "transpose" during runtime, we instead interpret the In/Out as column-major matrices when
229
+ calling our CUDA kernel.
230
+
231
+ [Inputs]
232
+ _in_feats: tensor of shape [B, IC]; // half
233
+ _weights: int tensor of shape [OC, IC // 16 * 3]; // 3 INT32 words contains 16 FP6 weights.
234
+ _scales: tensor of shape [OC]; // half
235
+ splitK: splitting the MatMul problem along K dimension for higher GPU utilization, default 1.
236
+ [Outputs]
237
+ _out_feats: tensor of shape [B, OC]; // half
238
+ */
239
+ torch::Tensor fp6_linear_forward_cuda(torch::Tensor _in_feats,
240
+ torch::Tensor _weights,
241
+ torch::Tensor _scales,
242
+ int splitK)
243
+ {
244
+ int num_in_feats = _in_feats.size(0);
245
+ int num_in_channels = _in_feats.size(1);
246
+ int num_out_channels = _weights.size(0);
247
+ assert(num_in_channels % 64 == 0);
248
+ assert((num_in_channels / 16 * 3) ==
249
+ _weights.size(1)); // Making sure the K dimension is matched.
250
+ //
251
+ int M = num_out_channels;
252
+ int K = num_in_channels;
253
+ int N = num_in_feats;
254
+ // Input Tensors
255
+ auto weight1 = reinterpret_cast<const uint4*>(
256
+ _weights.data_ptr<int>()); // weights is [OC, IC] but in FP6.
257
+ auto weight2 = weight1 + num_in_channels * num_out_channels * 2 / 128;
258
+ auto in_feats = reinterpret_cast<const half*>(_in_feats.data_ptr<at::Half>());
259
+ auto scales = reinterpret_cast<const half*>(_scales.data_ptr<at::Half>());
260
+ // Output Tensors
261
+ auto options = torch::TensorOptions().dtype(_in_feats.dtype()).device(_in_feats.device());
262
+ at::Tensor _out_feats = torch::empty({num_in_feats, num_out_channels}, options);
263
+ auto out_feats = reinterpret_cast<half*>(_out_feats.data_ptr<at::Half>());
264
+
265
+ float* Reduction_Workspace = nullptr;
266
+ if (splitK != 1) {
267
+ auto options = torch::TensorOptions().dtype(torch::kFloat32).device(_in_feats.device());
268
+ at::Tensor _workspace = torch::empty({splitK, num_in_feats, num_out_channels}, options);
269
+ auto Reduction_Workspace = reinterpret_cast<float*>(
270
+ _out_feats.data_ptr<float>()); // Reduction_Workspace_Size = Split_K * M_Global *
271
+ // N_Global * sizeof(fp32)
272
+ }
273
+
274
+ fp6_linear_kernel(0, // Using default stream here.
275
+ weight1,
276
+ weight2,
277
+ scales,
278
+ in_feats,
279
+ out_feats,
280
+ M,
281
+ N,
282
+ K,
283
+ Reduction_Workspace,
284
+ splitK);
285
+
286
+ return _out_feats;
287
+ }
288
+
289
+ /*
290
+ * Inputs:
291
+ * (1) unsigned char Weight_6bit [M*K*6/8]
292
+ * Outputs:
293
+ * (1) unsigned char Weight_2bit [M*K*2/8]
294
+ * (2) unsigned char Weight_4bit [M*K*4/8]
295
+ *
296
+ * Assumption: Weight_6bit, Weight_2bit, Weight_4bit all stored continuously in row-major.
297
+ * 8 FP6 = 6 Bytes
298
+ * 8 FP4 = 4 Bytes
299
+ * 8 FP2 = 2 Bytes
300
+ */
301
+
302
+ /*
303
+ * Weight prepacking (Pytorch interface).
304
+ * [Input & Output]
305
+ * fp6_tensor: int tensor of shape [OC, IC // 16 * 3]; // 3 INT32 words contains 16 FP6 weights.
306
+ * [Output]
307
+ * packed_tensor: int tensor of shape [OC, IC // 16 * 3];
308
+ */
309
+ torch::Tensor weight_matrix_prepacking_cpu(torch::Tensor fp6_tensor, size_t OC, size_t IC)
310
+ {
311
+ assert((OC % 256 == 0) && (IC % 64 == 0));
312
+ assert((fp6_tensor.size(0) == OC) && (fp6_tensor.size(1) == IC / 16 * 3));
313
+ // auto packed_tensor = torch::empty_like(fp6_tensor);
314
+ // auto packed_tensor_ptr = reinterpret_cast<int*>(packed_tensor.data_ptr<int>());
315
+ auto fp6_tensor_ptr = reinterpret_cast<int*>(fp6_tensor.data_ptr<int>());
316
+ weight_matrix_prepacking(fp6_tensor_ptr, OC, IC);
317
+ return fp6_tensor;
318
+ }
lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/linear_kernels_cuda.h ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) Microsoft Corporation.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // DeepSpeed Team
5
+
6
+ // This is a copy of FP6-LLM kernel code: https://arxiv.org/abs/2401.14112
7
+
8
+ #ifndef DEEPSPEED_CUDA_LINEAR_FP6_LINEAR_CUH
9
+ #define DEEPSPEED_CUDA_LINEAR_FP6_LINEAR_CUH
10
+
11
+ #include <cuda.h>
12
+ #include <cuda_fp16.h>
13
+ #include <cuda_runtime.h>
14
+
15
+ #include <torch/extension.h>
16
+
17
+ /*
18
+ * Computes FP6-FP16 GEMM (C++ interface).
19
+ */
20
+ cudaError_t fp6_linear_kernel(cudaStream_t stream,
21
+ const uint4* Weight1,
22
+ const uint4* Weight2,
23
+ const half* Scales,
24
+ const half* B,
25
+ half* C,
26
+ const size_t M_Global,
27
+ const size_t N_Global,
28
+ const size_t K_Global,
29
+ float* Reduction_Workspace, // Reduction_Workspace_Size = Split_K *
30
+ // M_Global * N_Global * sizeof(fp32)
31
+ int Split_K);
32
+
33
+ /*
34
+ * Computes FP6-FP16 GEMM (PyTorch interface).
35
+ */
36
+ torch::Tensor fp6_linear_forward_cuda(torch::Tensor _in_feats,
37
+ torch::Tensor _weights,
38
+ torch::Tensor _scales,
39
+ int splitK = 1);
40
+
41
+ /*
42
+ * In-place weight prepacking (C++ interface).
43
+ */
44
+ void weight_matrix_prepacking(int* FP6Weights, size_t M, size_t K);
45
+
46
+ /*
47
+ * Weight prepacking (Pytorch interface).
48
+ */
49
+ torch::Tensor weight_matrix_prepacking_cpu(torch::Tensor fp6_tensor, size_t M, size_t K);
50
+
51
+ #endif