Files
2026-07-13 12:40:42 +08:00

215 lines
7.8 KiB
Plaintext

/* Copyright (c) 2023 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 "paddle/phi/kernels/weight_only_linear_kernel.h"
#include "paddle/phi/backends/gpu/gpu_context.h"
#include "paddle/phi/common/datatype_traits.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/kernels/full_kernel.h"
#include "paddle/phi/kernels/funcs/weight_only_gemv.h"
#if defined(PADDLE_WITH_CUTLASS)
#include "paddle/phi/kernels/fusion/cutlass/cutlass_kernels/fpA_intB_gemm/fpA_intB_gemm_template.h"
#endif
namespace phi {
template <typename T, typename Context>
void WeightOnlyLinearKernel(const Context& dev_ctx,
const DenseTensor& x,
const DenseTensor& weight,
const optional<DenseTensor>& bias,
const DenseTensor& weight_scale,
const std::string& weight_dtype,
const int32_t arch,
const int32_t group_size,
DenseTensor* out) {
#if defined(PADDLE_WITH_CUTLASS)
PADDLE_ENFORCE_EQ(
((arch == 70) || (arch == 75) || (arch == 80) || (arch == 86) ||
(arch == 89) || (arch == 90) || (arch == 100)),
true,
common::errors::InvalidArgument(
"Currently, arch only support 70, 75, 80, 86, 89, 90, 100."));
#else
PADDLE_THROW(common::errors::Unimplemented(
"Please compile with cutlass to make cutlass available"));
#endif
dev_ctx.template Alloc<T>(out);
Full<T, Context>(dev_ctx, out->dims(), 0, out);
if (out->numel() == 0 || x.numel() == 0 || weight.numel() == 0) {
return;
}
const T* x_data = x.data<T>();
const int8_t* weight_data = weight.data<int8_t>();
const T* bias_data = bias ? bias.get().data<T>() : nullptr;
const T* weight_scale_data = weight_scale.data<T>();
T* out_data = out->data<T>();
const auto x_dims = x.dims();
const auto w_dims = weight.dims();
int n = group_size > 0 ? weight_scale.dims()[1] : weight_scale.dims()[0];
int k = w_dims[1];
int m = x.numel() / k;
// m > 3: run gemm.
if (m > 3 || (arch == 70)) {
/*
Note(Zhengzekang):
If using arch = 70, we always dispatch to weightonly Gemm,
we havenot support sm70 weightonly gemv, because sm70 weight layout is RowMajor.
*/
#if defined(PADDLE_WITH_CUTLASS)
if (weight_dtype == "int8") {
auto mixed_gemm_runner =
CutlassFpAIntBGemmRunner<typename PDDataTypeTraits<T>::DataType,
uint8_t>();
int mixgemm_max_size = std::max(m, k);
DenseTensor mixgemm_workspace;
int64_t mixgemm_workspace_size_bytes = mixed_gemm_runner.getWorkspaceSize(
m, mixgemm_max_size, mixgemm_max_size);
mixgemm_workspace_size_bytes = 100 * 1024 * 1024;
mixgemm_workspace.Resize({mixgemm_workspace_size_bytes});
dev_ctx.template Alloc<uint8_t>(&mixgemm_workspace);
char* mixgemm_workspace_data =
reinterpret_cast<char*>(mixgemm_workspace.data<uint8_t>());
if (bias_data) {
mixed_gemm_runner.gemm_bias_act(
reinterpret_cast<const typename PDDataTypeTraits<T>::DataType*>(
x_data),
reinterpret_cast<const uint8_t*>(weight_data),
reinterpret_cast<const typename PDDataTypeTraits<T>::DataType*>(
weight_scale_data),
reinterpret_cast<const typename PDDataTypeTraits<T>::DataType*>(
bias_data),
reinterpret_cast<typename PDDataTypeTraits<T>::DataType*>(out_data),
m,
n,
k,
group_size,
"none",
mixgemm_workspace_data,
mixgemm_workspace_size_bytes,
dev_ctx.stream());
} else {
mixed_gemm_runner.gemm(
reinterpret_cast<const typename PDDataTypeTraits<T>::DataType*>(
x_data),
reinterpret_cast<const uint8_t*>(weight_data),
reinterpret_cast<const typename PDDataTypeTraits<T>::DataType*>(
weight_scale_data),
reinterpret_cast<typename PDDataTypeTraits<T>::DataType*>(out_data),
m,
n,
k,
group_size,
mixgemm_workspace_data,
mixgemm_workspace_size_bytes,
dev_ctx.stream());
}
} else {
auto mixed_gemm_runner =
CutlassFpAIntBGemmRunner<typename PDDataTypeTraits<T>::DataType,
cutlass::uint4b_t>();
int mixgemm_max_size = std::max(m, k);
DenseTensor mixgemm_workspace;
int64_t mixgemm_workspace_size_bytes = mixed_gemm_runner.getWorkspaceSize(
m, mixgemm_max_size, mixgemm_max_size);
mixgemm_workspace_size_bytes = 100 * 1024 * 1024;
mixgemm_workspace.Resize({mixgemm_workspace_size_bytes});
dev_ctx.template Alloc<uint8_t>(&mixgemm_workspace);
char* mixgemm_workspace_data =
reinterpret_cast<char*>(mixgemm_workspace.data<uint8_t>());
if (bias_data) {
mixed_gemm_runner.gemm_bias_act(
reinterpret_cast<const typename PDDataTypeTraits<T>::DataType*>(
x_data),
reinterpret_cast<const cutlass::uint4b_t*>(weight_data),
reinterpret_cast<const typename PDDataTypeTraits<T>::DataType*>(
weight_scale_data),
reinterpret_cast<const typename PDDataTypeTraits<T>::DataType*>(
bias_data),
reinterpret_cast<typename PDDataTypeTraits<T>::DataType*>(out_data),
m,
n,
k,
group_size,
"none",
mixgemm_workspace_data,
mixgemm_workspace_size_bytes,
dev_ctx.stream());
} else {
mixed_gemm_runner.gemm(
reinterpret_cast<const typename PDDataTypeTraits<T>::DataType*>(
x_data),
reinterpret_cast<const cutlass::uint4b_t*>(weight_data),
reinterpret_cast<const typename PDDataTypeTraits<T>::DataType*>(
weight_scale_data),
reinterpret_cast<typename PDDataTypeTraits<T>::DataType*>(out_data),
m,
n,
k,
group_size,
mixgemm_workspace_data,
mixgemm_workspace_size_bytes,
dev_ctx.stream());
}
}
#else
PADDLE_THROW(common::errors::Unimplemented(
"Please compile with cutlass to make cutlass available"));
#endif
} else { // m <= 3: gemv
if (weight_dtype == "int8") {
WeightOnlyGemvWrapper<T, Context>(
dev_ctx,
x_data,
weight_data,
bias_data,
weight_scale_data,
m,
n,
k,
group_size,
"int8",
group_size > 0 ? "group_wise" : "per_channel",
"None",
out->data<T>());
} else if (weight_dtype == "int4") {
WeightOnlyGemvWrapper<T, Context>(
dev_ctx,
x_data,
weight_data,
bias_data,
weight_scale_data,
m,
n,
k,
group_size,
"int4",
group_size > 0 ? "group_wise" : "per_channel",
"None",
out->data<T>());
}
}
}
} // namespace phi
PD_REGISTER_KERNEL(weight_only_linear,
GPU,
ALL_LAYOUT,
phi::WeightOnlyLinearKernel,
phi::float16,
phi::bfloat16) {}