// 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 "paddle/phi/kernels/swiglu_grad_kernel.h" #include "paddle/phi/backends/gpu/gpu_context.h" #include "paddle/phi/backends/gpu/gpu_launch_config.h" #include "paddle/phi/core/kernel_registry.h" #include "paddle/phi/kernels/funcs/activation_functor.h" #include "paddle/phi/kernels/funcs/aligned_vector.h" #include "paddle/phi/kernels/primitive/kernel_primitives.h" namespace phi { template __global__ void SwiGLUGradCUDAKernel(const T *__restrict__ x, const T *__restrict__ y, const T *__restrict__ dz, T *__restrict__ dx, T *__restrict__ dy, int64_t m, int64_t n) { funcs::SwiGLUGradFunctor functor; if constexpr (IsCombine) { int64_t idx = static_cast(blockIdx.x) * blockDim.x + threadIdx.x; int64_t stride = static_cast(blockDim.x) * gridDim.x; int64_t n_vec_piece = n / VecSize; int64_t valid_num = m * n_vec_piece; while (idx < valid_num) { int64_t row_offset = idx / n_vec_piece * n; int64_t col_offset = idx % n_vec_piece * VecSize; int64_t dz_offset = row_offset + col_offset; int64_t x_offset = dz_offset + row_offset; AlignedVector x_vec; AlignedVector y_vec; AlignedVector dz_vec; Load(x + x_offset, &x_vec); Load(y + x_offset, &y_vec); Load(dz + dz_offset, &dz_vec); #pragma unroll for (int i = 0; i < VecSize; ++i) { functor(x_vec[i], y_vec[i], dz_vec[i], &x_vec[i], &y_vec[i]); } Store(x_vec, dx + x_offset); Store(y_vec, dy + x_offset); idx += stride; } } else { int64_t idx = (static_cast(blockIdx.x) * blockDim.x + threadIdx.x) * VecSize; int64_t stride = static_cast(blockDim.x) * gridDim.x * VecSize; int64_t numel = m * n; int64_t limit = numel - VecSize; while (idx <= limit) { AlignedVector x_vec; AlignedVector y_vec; AlignedVector dz_vec; Load(x + idx, &x_vec); if constexpr (HasDX) { Load(y + idx, &y_vec); } Load(dz + idx, &dz_vec); #pragma unroll for (int i = 0; i < VecSize; ++i) { functor(x_vec[i], HasDX ? y_vec[i] : x_vec[i], dz_vec[i], &x_vec[i], &dz_vec[i]); } if constexpr (HasDX) { Store(x_vec, dx + idx); } if constexpr (HasDY) { Store(dz_vec, dy + idx); } idx += stride; } while (idx < numel) { functor(x[idx], HasDX ? y[idx] : x[idx], dz[idx], HasDX ? &dx[idx] : nullptr, HasDY ? &dy[idx] : nullptr); ++idx; } } } template void SwiGLUGradKernelImpl(const Context &dev_ctx, const T *x, const T *y, const T *dz, T *dx, T *dy, int64_t m, int64_t n) { int vec_size = std::min(GetVectorizedSize(x), GetVectorizedSize(dz)); if (y) { vec_size = std::min(vec_size, GetVectorizedSize(y)); } if (dx) { vec_size = std::min(vec_size, GetVectorizedSize(dx)); } if (dy) { vec_size = std::min(vec_size, GetVectorizedSize(dy)); } #define PD_LAUNCH_SWIGLU_GRAD_CUDA_KERNEL_BASE( \ __vec_size, __is_combine, __has_dx, __has_dy) \ case __vec_size: { \ SwiGLUGradCUDAKernel \ <<>>(x, y, dz, dx, dy, m, n); \ break; \ } #define PD_LAUNCH_SWIGLU_GRAD_CUDA_KERNEL(__is_combine, __has_dx, __has_dy) \ do { \ switch (vec_size) { \ PD_LAUNCH_SWIGLU_GRAD_CUDA_KERNEL_BASE( \ VecSizeVL, __is_combine, __has_dx, __has_dy); \ PD_LAUNCH_SWIGLU_GRAD_CUDA_KERNEL_BASE( \ VecSizeL, __is_combine, __has_dx, __has_dy); \ PD_LAUNCH_SWIGLU_GRAD_CUDA_KERNEL_BASE( \ VecSizeM, __is_combine, __has_dx, __has_dy); \ PD_LAUNCH_SWIGLU_GRAD_CUDA_KERNEL_BASE( \ VecSizeS, __is_combine, __has_dx, __has_dy); \ default: \ PADDLE_THROW(common::errors::Unimplemented( \ "Unsupported vectorized size: %d !", vec_size)); \ break; \ } \ } while (0) if (y) { auto config = backends::gpu::GetGpuLaunchConfig1D(dev_ctx, m * n, vec_size); if (dx) { if (dy) { PD_LAUNCH_SWIGLU_GRAD_CUDA_KERNEL(false, true, true); } else { PD_LAUNCH_SWIGLU_GRAD_CUDA_KERNEL(false, true, false); } } else { PADDLE_ENFORCE_NOT_NULL( dy, common::errors::InvalidArgument( "Both gradients of Input(X) and Input(Y) is None.")); PD_LAUNCH_SWIGLU_GRAD_CUDA_KERNEL(false, false, true); } } else { PADDLE_ENFORCE_NOT_NULL( dx, common::errors::InvalidArgument( "Both gradients of Input(X) and Input(Y) is None.")); while (n % vec_size != 0) { vec_size /= 2; } y = x + n; dy = dx + n; auto config = backends::gpu::GetGpuLaunchConfig1D(dev_ctx, m * n / vec_size, 1); PD_LAUNCH_SWIGLU_GRAD_CUDA_KERNEL(true, true, true); } } } // namespace phi PD_REGISTER_KERNEL(swiglu_grad, GPU, ALL_LAYOUT, phi::SwiGLUGradKernel, float, double, phi::float16, phi::bfloat16) {}