// 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/core/kernel_registry.h" #include "paddle/phi/kernels/cast_kernel.h" #include "paddle/phi/kernels/full_kernel.h" #include "paddle/phi/kernels/funcs/eigen/common.h" #include "paddle/phi/kernels/funcs/gather.cu.h" #include "paddle/phi/kernels/funcs/scatter.cu.h" #include "paddle/phi/kernels/gather_kernel.h" namespace phi { template void GatherGradKernel(const Context& dev_ctx, const DenseTensor& x, const DenseTensor& index, const DenseTensor& out_grad, const Scalar& axis, DenseTensor* x_grad) { // x [4, 2], index [2, 0], out [2, 0], x_grad [4, 2] if (out_grad.numel() == 0 || (x_grad && x_grad->numel() == 0)) { if (x_grad) { Full(dev_ctx, x_grad->dims(), 0, x_grad); } return; } const auto& index_type = index.dtype(); auto axis_v = axis.to(); if (axis_v < 0) { axis_v += static_cast(x.dims().size()); } if (axis_v != 0) { if (index_type == DataType::INT32) { funcs::GatherV2GradCUDAFunction( &out_grad, &index, axis_v, x_grad, dev_ctx); } else if (index_type == DataType::INT64) { funcs::GatherV2GradCUDAFunction( &out_grad, &index, axis_v, x_grad, dev_ctx); } return; } dev_ctx.template Alloc(x_grad); funcs::set_constant(dev_ctx, x_grad, static_cast(0)); if (out_grad.numel() == 0) { return; } if (index.dims().size() != 0) { if (index_type == DataType::INT32) { DenseTensor index_int64 = Cast(dev_ctx, index, DataType::INT64); funcs::GPUScatterAdd( dev_ctx, out_grad, index_int64, x_grad, axis_v); } else if (index_type == DataType::INT64) { funcs::GPUScatterAdd( dev_ctx, out_grad, index, x_grad, axis_v); } else { PADDLE_THROW(common::errors::InvalidArgument( "The data type of Input(Index) of gather_grad must be int32 or int64 " "on GPU.")); } } else { if (index_type == DataType::INT32) { funcs::GPUScatterAssign(dev_ctx, out_grad, index, x_grad, false); } else if (index_type == DataType::INT64) { funcs::GPUScatterAssign( dev_ctx, out_grad, index, x_grad, false); } else { PADDLE_THROW(common::errors::InvalidArgument( "The data type of Input(Index) of gather_grad must be int32 or int64 " "on GPU.")); } } } } // namespace phi PD_REGISTER_KERNEL(gather_grad, GPU, ALL_LAYOUT, phi::GatherGradKernel, float, double, int64_t, int, phi::float16, phi::bfloat16, phi::complex64, phi::complex128) {}