Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- lib/python3.12/site-packages/deepspeed/inference/v2/__pycache__/engine_factory.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/__init__.py +6 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/__pycache__/ds_kernel.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/__init__.py +11 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/__init__.py +6 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/__pycache__/bias_activation.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/bias_activation.cpp +68 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/bias_activation.h +22 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/bias_activation.py +62 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/bias_activations/bias_activation_cuda.cu +140 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/blas_kernels/__init__.py +6 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/blas_kernels/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/blas_kernels/__pycache__/blas_linear.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/blas_kernels/blas.h +138 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/blas_kernels/blas_linear.py +55 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/blas_kernels/blas_utils.h +299 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/core_ops.cpp +42 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/__init__.py +8 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/__pycache__/cuda_fp_ln_base.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/__pycache__/cuda_ln.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/__pycache__/cuda_post_ln.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/__pycache__/cuda_pre_ln.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/cuda_fp_ln_base.py +37 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/cuda_ln.py +30 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/cuda_post_ln.py +34 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/cuda_pre_ln.py +39 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/layer_norm.cpp +102 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/layer_norm.h +67 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_layer_norm/layer_norm_cuda.cu +489 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/__init__.py +6 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/__pycache__/cuda_linear.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/cuda_linear.py +207 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/configs.h +96 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/kernel_matmul.cuh +272 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/kernel_reduction.cuh +43 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/ptx_cp.async.cuh +75 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/ptx_mma.cuh +139 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/utils_core.cuh +246 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/utils_gmem.cuh +86 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/utils_paralleldequant.cuh +127 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/include/weight_prepacking.h +209 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/linear_kernels.cpp +224 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/linear_kernels.h +28 -0
- lib/python3.12/site-packages/deepspeed/inference/v2/kernels/core_ops/cuda_linear/linear_kernels_cuda.cu +318 -0
- 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
|