Files
paddlepaddle--paddle/paddle/phi/kernels/xpu/rms_norm_xpu_kernel.cc
T
2026-07-13 12:40:42 +08:00

251 lines
9.8 KiB
C++

// 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 <cassert>
#include "paddle/common/exception.h"
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/phi/kernels/empty_kernel.h"
#include "paddle/phi/backends/xpu/enforce_xpu.h"
#include "paddle/phi/backends/xpu/xpu_context.h"
#include "paddle/phi/core/kernel_registry.h"
namespace phi {
static void GetRowsCols(const std::vector<int64_t> &shape,
int64_t *p_rows,
int64_t *p_cols) {
int64_t rows = 1;
for (size_t i = 0; i + 1 < shape.size(); ++i) {
rows *= shape[i];
}
int64_t cols = shape[shape.size() - 1];
*p_rows = rows;
*p_cols = cols;
}
template <typename T, typename Context>
void RMSNormFwdKernel(const Context &dev_ctx,
const DenseTensor &x,
const optional<DenseTensor> &scale_opt,
const std::vector<int64_t> &normalized_shape,
double epsilon,
DenseTensor *y,
DenseTensor *invvar) {
int begin_norm_axis = x.dims().size() - normalized_shape.size();
PADDLE_ENFORCE_EQ(
begin_norm_axis,
x.dims().size() - 1,
common::errors::InvalidArgument(
"XPU RMSNorm only supports begin_norm_axis=%d, but got %d",
x.dims().size() - 1,
begin_norm_axis));
auto *scale_ptr = scale_opt.get_ptr();
if (scale_ptr == nullptr) {
PADDLE_THROW(common::errors::InvalidArgument(
"Scale must be provided for RMSNorm backward"));
}
const DenseTensor &scale = *scale_ptr;
int64_t rows, cols;
GetRowsCols(vectorize(x.dims()), &rows, &cols);
if (scale.dtype() == DataType::BFLOAT16) {
dev_ctx.template Alloc<phi::bfloat16>(y);
} else if (scale.dtype() == DataType::FLOAT16) {
dev_ctx.template Alloc<phi::float16>(y);
} else if (scale.dtype() == DataType::FLOAT32) {
dev_ctx.template Alloc<float>(y);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"The dtype of scale must be FLOAT32, FLOAT16 or BFLOAT16, but got [%s]",
scale.dtype()));
}
invvar->Resize({rows});
dev_ctx.template Alloc<float>(invvar);
/*
refer to:
-
https://github.com/NVIDIA/apex/blob/bfb500c8/csrc/layer_norm_cuda_kernel.cu#L1018
-
https://github.com/PaddlePaddle/PaddleNLP/blob/5b9e0b33/ops/csrc/fused_ln/layer_norm_cuda.h#L1087
Supported Type combinations:
input compute scale output
=======================================
fp32 fp32 fp32 fp32
fp16 fp32 fp16 fp16
bf16 fp32 bf16 bf16
Not supported yet:
input compute scale output
=======================================
fp32 fp32 fp16 fp16
fp32 fp32 bf16 bf16
Remarks:
Output type = Scale type
Compute always in FP32
*/
#define DISPATCH_FWD_CASE(scalar_t_out) \
using XPUType = typename XPUTypeTrait<scalar_t_out>::Type; \
auto ret = xpu::rms_layer_norm<XPUType, XPUType>( \
dev_ctx.x_context(), \
reinterpret_cast<const XPUType *>(x.data<scalar_t_out>()), \
reinterpret_cast<XPUType *>(y->data<scalar_t_out>()), \
rows, \
cols, \
epsilon, \
reinterpret_cast<const XPUType *>(scale.data<scalar_t_out>()), \
/*bias=*/nullptr, \
invvar->data<float>(), \
/*is_rstd=*/true); \
PADDLE_ENFORCE_XDNN_SUCCESS(ret, "rms_layer_norm");
// scale.dtype() same as y->dtype()
if (x.dtype() == DataType::FLOAT32 && scale.dtype() == DataType::FLOAT32) {
DISPATCH_FWD_CASE(float);
} else if (x.dtype() == DataType::FLOAT16 &&
scale.dtype() == DataType::FLOAT16) {
DISPATCH_FWD_CASE(phi::float16);
} else if (x.dtype() == DataType::BFLOAT16 &&
scale.dtype() == DataType::BFLOAT16) {
DISPATCH_FWD_CASE(phi::bfloat16);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Unsupported dtype combination: x [%s], scale [%s]. "
"Expected both to be float32, float16, or bfloat16.",
DataTypeToString(x.dtype()),
DataTypeToString(scale.dtype())));
}
#undef DISPATCH_FWD_CASE
}
template <typename T, typename Context>
void RMSNormBwdKernel(const Context &dev_ctx,
const DenseTensor &x,
const optional<DenseTensor> &scale_opt,
const DenseTensor &invvar,
const DenseTensor &y_grad,
const std::vector<int64_t> &normalized_shape,
double epsilon,
DenseTensor *x_grad,
DenseTensor *scale_grad) {
int begin_norm_axis = x.dims().size() - normalized_shape.size();
PADDLE_ENFORCE_EQ(
begin_norm_axis,
x.dims().size() - 1,
common::errors::InvalidArgument(
"XPU RMSNorm only supports begin_norm_axis=%d, but got %d",
x.dims().size() - 1,
begin_norm_axis));
auto *scale_ptr = scale_opt.get_ptr();
if (scale_ptr == nullptr) {
PADDLE_THROW(common::errors::InvalidArgument(
"Scale must be provided for RMSNorm backward"));
}
const DenseTensor &scale = *scale_ptr;
int64_t rows, cols;
GetRowsCols(vectorize(x.dims()), &rows, &cols);
dev_ctx.template Alloc<T>(x_grad);
DenseTensor actual_scale_grad;
if (scale_grad) {
if (scale.dtype() == DataType::BFLOAT16) {
dev_ctx.template Alloc<phi::bfloat16>(scale_grad);
} else if (scale.dtype() == DataType::FLOAT16) {
dev_ctx.template Alloc<phi::float16>(scale_grad);
} else if (scale.dtype() == DataType::FLOAT32) {
dev_ctx.template Alloc<float>(scale_grad);
} else {
PADDLE_THROW(
common::errors::InvalidArgument("The dtype of scale must be FLOAT32, "
"FLOAT16 or BFLOAT16, but got [%s]",
scale.dtype()));
}
actual_scale_grad = *scale_grad;
} else {
// lora specific, scale_grad is nullptr
if (scale.dtype() == DataType::BFLOAT16) {
actual_scale_grad = EmptyLike<phi::bfloat16, Context>(dev_ctx, scale);
} else if (scale.dtype() == DataType::FLOAT16) {
actual_scale_grad = EmptyLike<phi::float16, Context>(dev_ctx, scale);
} else if (scale.dtype() == DataType::FLOAT32) {
actual_scale_grad = EmptyLike<float, Context>(dev_ctx, scale);
} else {
PADDLE_THROW(
common::errors::InvalidArgument("The dtype of scale must be FLOAT32, "
"FLOAT16 or BFLOAT16, but got [%s]",
scale.dtype()));
}
}
#define DISPATCH_BWD_CASE(scalar_t_out) \
using XPUType = typename XPUTypeTrait<scalar_t_out>::Type; \
auto ret = xpu::rms_layer_norm_grad<XPUType, XPUType>( \
dev_ctx.x_context(), \
reinterpret_cast<const XPUType *>(x.data<scalar_t_out>()), \
reinterpret_cast<const XPUType *>(y_grad.data<scalar_t_out>()), \
reinterpret_cast<XPUType *>(x_grad->data<scalar_t_out>()), \
rows, \
cols, \
epsilon, \
reinterpret_cast<const XPUType *>(scale.data<scalar_t_out>()), \
invvar.data<float>(), \
reinterpret_cast<XPUType *>(actual_scale_grad.data<scalar_t_out>()), \
/*bias=*/nullptr, \
/*is_rstd=*/true); \
PADDLE_ENFORCE_XDNN_SUCCESS(ret, "rms_layer_norm_grad");
// scale.dtype() same as y->dtype()
if (x.dtype() == DataType::FLOAT32 && scale.dtype() == DataType::FLOAT32) {
DISPATCH_BWD_CASE(float);
} else if (x.dtype() == DataType::FLOAT16 &&
scale.dtype() == DataType::FLOAT16) {
DISPATCH_BWD_CASE(phi::float16);
} else if (x.dtype() == DataType::BFLOAT16 &&
scale.dtype() == DataType::BFLOAT16) {
DISPATCH_BWD_CASE(phi::bfloat16);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Unsupported dtype combination: x [%s], scale [%s]. "
"Expected both to be float32, float16, or bfloat16.",
DataTypeToString(x.dtype()),
DataTypeToString(scale.dtype())));
}
#undef DISPATCH_BWD_CASE
}
} // namespace phi
PD_REGISTER_KERNEL(rms_norm,
XPU,
ALL_LAYOUT,
phi::RMSNormFwdKernel,
float,
phi::float16,
phi::bfloat16) {}
PD_REGISTER_KERNEL(rms_norm_grad,
XPU,
ALL_LAYOUT,
phi::RMSNormBwdKernel,
float,
phi::float16,
phi::bfloat16) {}