// Copyright (c) 2022 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/group_norm_grad_kernel.h" #include #include #include #include #include "paddle/common/layout.h" #include "paddle/phi/backends/xpu/enforce_xpu.h" #include "paddle/phi/core/kernel_registry.h" #include "paddle/phi/kernels/full_kernel.h" #include "paddle/phi/kernels/funcs/math_function.h" namespace phi { template void GroupNormGradKernel(const Context& dev_ctx, const DenseTensor& x, const optional& scale, const optional& bias, const DenseTensor& y, const DenseTensor& mean, const DenseTensor& var, const DenseTensor& d_y, double epsilon, int groups, const std::string& data_layout_str, DenseTensor* d_x, DenseTensor* d_scale, DenseTensor* d_bias) { if (x.numel() == 0) { dev_ctx.template Alloc(d_x); if (d_scale) { // If batch dim is 0, we should set d_scale to zero, or else NAN if (x.dims().size() > 0 && x.dims()[0] == 0) { Full(dev_ctx, d_scale->dims(), 0, d_scale); } else { Full(dev_ctx, d_scale->dims(), NAN, d_scale); } } if (d_bias) { Full(dev_ctx, d_bias->dims(), 0, d_bias); } return; } using XPUType = typename XPUTypeTrait::Type; xpu::ctx_guard RAII_GUARD(dev_ctx.x_context()); int ret = 0; const DataLayout data_layout = StringToDataLayout(data_layout_str); const auto scale_ptr = scale.get_ptr(); const auto bias_ptr = bias.get_ptr(); const auto x_dims = vectorize(x.dims()); const int64_t N = x_dims[0]; const bool channel_first = data_layout == DataLayout::NCHW || data_layout == DataLayout::NCDHW; const int64_t C = (channel_first ? x_dims[1] : x_dims[x_dims.size() - 1]); const int64_t L = (channel_first ? std::accumulate(x_dims.begin() + 2, x_dims.end(), 1, std::multiplies()) : std::accumulate(x_dims.begin() + 1, x_dims.end() - 1, 1, std::multiplies())); dev_ctx.template Alloc(d_x); funcs::SetConstant set_zero; auto* x_data = x.data(); auto* y_data = y.data(); auto* d_x_data = d_x->data(); auto* d_y_data = d_y.data(); T* d_scale_data = nullptr; float* d_scale_data_fp32 = nullptr; if (d_scale) { dev_ctx.template Alloc(d_scale); set_zero(dev_ctx, d_scale, static_cast(0)); d_scale_data = d_scale->data(); if (!std::is_same_v) { d_scale_data_fp32 = RAII_GUARD.alloc_l3_or_gm(d_scale->numel()); } else { d_scale_data_fp32 = reinterpret_cast(d_scale_data); } } T* d_bias_data = nullptr; float* d_bias_data_fp32 = nullptr; if (d_bias) { dev_ctx.template Alloc(d_bias); set_zero(dev_ctx, d_bias, static_cast(0)); d_bias_data = d_bias->data(); if (!std::is_same_v) { d_bias_data_fp32 = RAII_GUARD.alloc_l3_or_gm(d_bias->numel()); } else { d_bias_data_fp32 = reinterpret_cast(d_bias_data); } } const float* scale_data = nullptr; if (scale_ptr) { if (!std::is_same_v) { float* scale_data_tmp = RAII_GUARD.alloc_l3_or_gm(scale_ptr->numel()); ret = xpu::cast( dev_ctx.x_context(), reinterpret_cast(scale_ptr->data()), scale_data_tmp, scale_ptr->numel()); PADDLE_ENFORCE_XDNN_SUCCESS(ret, "cast"); scale_data = scale_data_tmp; } else { scale_data = scale_ptr->data(); } } const float* bias_data = nullptr; if (bias_ptr) { if (!std::is_same_v) { float* bias_data_tmp = RAII_GUARD.alloc_l3_or_gm(bias_ptr->numel()); ret = xpu::cast( dev_ctx.x_context(), reinterpret_cast(bias_ptr->data()), bias_data_tmp, bias_ptr->numel()); PADDLE_ENFORCE_XDNN_SUCCESS(ret, "cast"); bias_data = bias_data_tmp; } else { bias_data = bias_ptr->data(); } } ret = xpu::group_norm_grad(dev_ctx.x_context(), reinterpret_cast(x_data), reinterpret_cast(y_data), reinterpret_cast(d_y_data), reinterpret_cast(d_x_data), N, C, L, 1, groups, epsilon, scale_data, bias_data, mean.data(), var.data(), d_scale_data_fp32, d_bias_data_fp32, channel_first); PADDLE_ENFORCE_XDNN_SUCCESS(ret, "group_norm_grad"); if (!std::is_same_v) { if (d_scale) { ret = xpu::cast(dev_ctx.x_context(), d_scale_data_fp32, reinterpret_cast(d_scale_data), d_scale->numel()); PADDLE_ENFORCE_XDNN_SUCCESS(ret, "cast"); } if (d_bias) { ret = xpu::cast(dev_ctx.x_context(), d_bias_data_fp32, reinterpret_cast(d_bias_data), d_bias->numel()); PADDLE_ENFORCE_XDNN_SUCCESS(ret, "cast"); } } } } // namespace phi PD_REGISTER_KERNEL(group_norm_grad, XPU, ALL_LAYOUT, phi::GroupNormGradKernel, float, phi::float16) {}