Files
paddlepaddle--paddle/paddle/phi/kernels/fusion/cutlass/gemm_epilogue_kernel.cu
T
2026-07-13 12:40:42 +08:00

209 lines
7.3 KiB
Plaintext

// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <glog/logging.h>
#include "paddle/phi/backends/gpu/gpu_context.h"
#include "paddle/phi/common/memory_utils.h"
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/phi/core/enforce.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/kernels/fusion/cutlass/gemm_epilogue/gemm_epilogue_decl.h"
#include "paddle/phi/backends/dynload/cutlass_gemm_epilogue.h"
#include "paddle/phi/kernels/funcs/common_shape.h"
namespace phi {
namespace fusion {
namespace cutlass_internal {
typedef void (*func)(phi::fusion::cutlass_internal::GemmEpilogueAllParams);
template <typename T, typename Context>
void GemmEpilogueKernel(const Context& dev_ctx,
const DenseTensor& input,
const DenseTensor& w,
const optional<DenseTensor>& bias,
const int in_num_col_dims,
const std::string& activation_type,
const bool padding_weights,
DenseTensor* out) {
if (!bias) {
PADDLE_THROW(common::errors::InvalidArgument(
"In gemm_epilogue kernel, bias should be provided."));
return;
}
PADDLE_ENFORCE_EQ(
padding_weights,
false,
common::errors::PermissionDenied(
"Weight padding in gemm_epilogue can not be used in GPU scope."));
auto weight_dims = w.dims();
PADDLE_ENFORCE_EQ(weight_dims.size(),
2UL,
common::errors::InvalidArgument(
"In gemm_epilogue kernel, weight_dims should be 2."));
// gemm_epilogue_out should be reshape since can not get lod in infershape
std::vector<int64_t> output_dims;
funcs::FCOutputSize(
input.dims(), weight_dims, output_dims, in_num_col_dims, padding_weights);
out->Resize(output_dims);
out->set_lod(input.lod());
dev_ctx.template Alloc<T>(out);
auto out_dims = out->dims();
auto bias_dims = bias->dims();
// This Op supports two types of bias elementwiseAdd.
// For an output of dimension [M,N], a bias is either a vector of length N or
// also a matrix of dimension [M,N]. isVec_bias is used to distinguish whether
// bias is a vector or not
bool isVec_bias = true;
if (bias_dims.size() > 2 || (bias_dims.size() == 2 && bias_dims[0] != 1)) {
isVec_bias = false;
}
int M = common::product(out_dims) / weight_dims[1];
const int K = weight_dims[0];
const int N = weight_dims[1];
const int lda = K;
const int ldb = N;
const int ldd = N;
const int alignA = 8;
const int alignB = 8;
bool isAMisaligned = false;
bool isBMisaligned = false;
isAMisaligned = lda % alignA;
isBMisaligned = ldb % alignB;
if (isAMisaligned) {
PADDLE_THROW(common::errors::InvalidArgument(
" returning kErrorMisalignedOperand for input operand"));
return;
}
if (isBMisaligned) {
PADDLE_THROW(common::errors::InvalidArgument(
" returning kErrorMisalignedOperand for weight operand"));
return;
}
int64_t device_id = dev_ctx.GetPlace().GetDeviceId();
int sm_version = backends::gpu::GetGPUComputeCapability(device_id);
auto get_gemm_epilogue_dtype = [&](decltype(input.dtype()) input_type)
-> phi::fusion::cutlass_internal::GemmEpilogueDataType {
switch (input_type) {
case phi::DataType::FLOAT32:
return GemmEpilogueDataType::fp32;
case phi::DataType::FLOAT16:
return GemmEpilogueDataType::fp16;
case phi::DataType::BFLOAT16:
return GemmEpilogueDataType::bf16;
default:
return GemmEpilogueDataType::fp32;
}
};
auto gemm_epilogue_dtype = get_gemm_epilogue_dtype(input.dtype());
if ((gemm_epilogue_dtype != GemmEpilogueDataType::fp16) &&
(gemm_epilogue_dtype != GemmEpilogueDataType::bf16)) {
PADDLE_THROW(common::errors::InvalidArgument(
"Gemm_epilogue kernel only supports fp16 "
"and bf16, input dtype error!"));
return;
}
auto cutlass_dispatch_sm_version = [&](int device_sm_version) -> int {
if (device_sm_version < 80) {
PADDLE_ENFORCE_GE(device_sm_version,
80,
common::errors::PreconditionNotMet(
"Gemm_epilogue only supports sm >= 80, but got %d.",
device_sm_version));
} else if (device_sm_version > 80) {
return 80;
} else {
return device_sm_version;
}
};
void* workspace = nullptr;
size_t workspace_size_bytes =
((M - 1 + 16) / 16) * ((N - 1 + 64) / 64) * sizeof(int);
phi::Allocator::AllocationPtr tmp_ptr = phi::memory_utils::Alloc(
dev_ctx.GetPlace(),
workspace_size_bytes,
phi::Stream(reinterpret_cast<phi::StreamId>(dev_ctx.stream())));
workspace = tmp_ptr->ptr();
GemmEpilogueAllParams params = {
reinterpret_cast<const void*>(input.data<T>()),
reinterpret_cast<const void*>(w.data<T>()),
reinterpret_cast<const void*>(bias->data<T>()),
reinterpret_cast<void*>(out->data<T>()),
M,
N,
K,
lda,
ldb,
ldd,
dev_ctx.stream(),
gemm_epilogue_dtype,
isVec_bias,
cutlass_dispatch_sm_version(sm_version),
0.01, // for leaky_relu
workspace,
};
void* dlhandler = dynload::GetCutlassGemmEpilogueHandle();
func gemm_epilogue_func = NULL;
PADDLE_ENFORCE_NOT_NULL(
dlhandler,
common::errors::PreconditionNotMet(
"CutlassGemmEpilogueHandle should not be NULL, dynload error."));
if (activation_type == "identity" || activation_type == "") {
gemm_epilogue_func = (func)(dlsym(dlhandler, "MatmulAdd"));
} else if (activation_type == "relu") {
gemm_epilogue_func = (func)(dlsym(dlhandler, "MatmulAddRelu"));
} else if (activation_type == "gelu") {
gemm_epilogue_func = (func)(dlsym(dlhandler, "MatmulAddGelu"));
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Cutlass does not support this activation_type: %s.",
activation_type.c_str()));
}
/// these three acts are not supported by pass now and are commented out to
/// prevent the lib.so too large.
// else if (activation_type == "leaky_relu") {
// gemm_epilogue_func = (func)(dlsym(dlhandler, "MatmulAddLeakyRelu"));
// }
// else if (activation_type == "sigmoid") {
// gemm_epilogue_func = (func)(dlsym(dlhandler, "MatmulAddSigmoid"));
// }
// else if (activation_type == "swish") {
// gemm_epilogue_func = (func)(dlsym(dlhandler, "MatmulAddSilu"));
// }
gemm_epilogue_func(params);
}
} // namespace cutlass_internal
} // namespace fusion
} // namespace phi
PD_REGISTER_KERNEL(gemm_epilogue,
GPU,
ALL_LAYOUT,
phi::fusion::cutlass_internal::GemmEpilogueKernel,
phi::bfloat16,
phi::float16) {}