// Copyright (c) 2025 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/backends/xpu/enforce_xpu.h" #include "paddle/phi/core/kernel_registry.h" #ifdef PADDLE_WITH_XPU_XRE5 #include "xblas/xblas_legacy_api.h" #endif namespace phi { template void WeightOnlyLinearKernel(const Context& dev_ctx, const DenseTensor& x, const DenseTensor& weight, const optional& bias, const DenseTensor& weight_scale, const std::string& weight_dtype, const int32_t arch, const int32_t group_size, DenseTensor* out) { using XPUType = typename XPUTypeTrait::Type; int64_t n = weight.dims()[0]; int64_t k = weight.dims()[1]; int64_t m = x.numel() / k; if (weight_dtype == "int4") { n = n * 2; } out->Resize({static_cast(m), static_cast(n)}); dev_ctx.template Alloc(out); if (out->numel() == 0 || x.numel() == 0 || weight.numel() == 0) { return; } DenseTensor bias_fp32; if (bias.is_initialized() && bias.get().dtype() == DataType::FLOAT16) { bias_fp32.Resize(bias.get().dims()); dev_ctx.template Alloc(&bias_fp32); int r = baidu::xpu::api::cast( dev_ctx.x_context(), reinterpret_cast(bias.get().data()), bias_fp32.data(), n); PADDLE_ENFORCE_XDNN_SUCCESS(r, "cast"); } auto input_x = reinterpret_cast(x.data()); auto input_y = reinterpret_cast(out->data()); baidu::xpu::xblas::FcFusionTensor tensor_x{ input_x, nullptr, m, k, k, false}; baidu::xpu::xblas::FcFusionTensor tensor_y_const{ input_y, nullptr, m, n, n, false}; baidu::xpu::xblas::FcFusionTensor tensor_y{ input_y, nullptr, m, n, n, false}; DenseTensor weight_scale_fp32; if (weight_scale.dtype() != DataType::FLOAT32 && weight_scale.dims().size() != 0) { weight_scale_fp32.Resize(weight_scale.dims()); dev_ctx.template Alloc(&weight_scale_fp32); int r = baidu::xpu::api::cast( dev_ctx.x_context(), reinterpret_cast(weight_scale.data()), weight_scale_fp32.data(), weight_scale.numel()); PADDLE_ENFORCE_XDNN_SUCCESS(r, "cast"); } const float* weight_scale_ptr = nullptr; if (weight_scale.dims().size() != 0) { if (weight_scale.dtype() == DataType::FLOAT32) { weight_scale_ptr = weight_scale.data(); } else { weight_scale_ptr = weight_scale_fp32.data(); } } baidu::xpu::xblas::FcFusionEpilogue epilogue{ api::Activation_t::LINEAR, bias.is_initialized() ? (bias.get().dtype() == DataType::FLOAT16 ? bias_fp32.data() : bias.get().data()) : nullptr, nullptr, weight_scale_ptr, 0, 1, nullptr}; if (weight_dtype == "int8") { // using TGEMM=int8_wo_t; using TGEMM = float; baidu::xpu::xblas::FcFusionDesc desc{1.0f, 0.0f}; baidu::xpu::xblas::FcFusionTensor tensor_w{ reinterpret_cast(weight.data()), nullptr, n, k, k, true}; int r1 = baidu::xpu::xblas::fc_fusion(dev_ctx.x_context(), tensor_x, tensor_w, tensor_y_const, tensor_y, desc, epilogue); PD_CHECK(r1 == 0, "xblas::fc_fusion failed"); } else if (weight_dtype == "int4") { // baidu::xpu::xblas::FcFusionDesc // desc{1.0f, 0.0f}; // baidu::xpu::xblas::FcFusionTensor tensor_w{ // reinterpret_cast(weight.data()), // nullptr, // n, // k, // k, // true}; // int r1 = baidu::xpu::xblas::fc_fusion(dev_ctx.x_context(), // tensor_x, // tensor_w, // tensor_y_const, // tensor_y, // desc, // epilogue); // PD_CHECK(r1 == 0, "xblas::fc_fusion failed"); PD_THROW("unsupported weight_dtype=int4"); } else { PD_THROW("unsupported weight_dtype: ", weight_dtype); } } } // namespace phi PD_REGISTER_KERNEL(weight_only_linear, XPU, ALL_LAYOUT, phi::WeightOnlyLinearKernel, phi::float16, phi::bfloat16) {}