// 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/index_sample_kernel.h" #include #include #include "paddle/common/enforce.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/core/utils/data_type.h" #include "paddle/phi/kernels/funcs/math_function.h" namespace phi { namespace { #define PREDEFINED_BLOCK_SIZE_X 512 #define PREDEFINED_BLOCK_SIZE 1024 #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define UINT32_MAX std::numeric_limits::max() } // namespace template __global__ void IndexSampleForward(const SampleIndexT* index, const T* in_data, T* out_data, size_t index_length, size_t input_length, size_t batch_size) { ElementIndexT index_i = blockDim.x * blockIdx.x + threadIdx.x; ElementIndexT index_j = blockDim.y * blockIdx.y + threadIdx.y; for (; index_j < batch_size; index_j += blockDim.y * gridDim.y) { index_i = blockDim.x * blockIdx.x + threadIdx.x; for (; index_i < index_length; index_i += blockDim.x * gridDim.x) { ElementIndexT index_idx = index_j * index_length + index_i; ElementIndexT in_idx = index_j * input_length + index_i; SampleIndexT sample_idx = index[index_idx]; out_data[index_idx] = in_data[in_idx - index_i + sample_idx]; } } } template void IndexSampleKernel(const Context& dev_ctx, const DenseTensor& x, const DenseTensor& index, DenseTensor* out) { auto index_type = index.dtype(); bool index_type_match = index_type == DataType::INT32 || index_type == DataType::INT64; PADDLE_ENFORCE_EQ(index_type_match, true, errors::InvalidArgument( "Input(Index) holds the wrong type, it holds %s, but " "desires to be %s or %s", DataTypeToString(index_type), DataTypeToString(DataType::INT32), DataTypeToString(DataType::INT64))); const T* in_data = x.data(); T* out_data = dev_ctx.template Alloc(out); if (out && out->numel() == 0) { return; } auto stream = reinterpret_cast(dev_ctx).stream(); auto input_dim = x.dims(); auto index_dim = index.dims(); size_t batch_size = input_dim[0]; size_t input_length = input_dim[1]; size_t index_length = index_dim[1]; if (batch_size == 0 || input_length == 0 || index_length == 0) { return; } auto block_width = backends::gpu::RoundToPowerOfTwo(index_length); block_width = MIN(block_width, PREDEFINED_BLOCK_SIZE_X); int64_t block_height = backends::gpu::RoundToPowerOfTwo(index_length * batch_size) / block_width; block_height = MIN(block_height, PREDEFINED_BLOCK_SIZE / block_width); dim3 block_dim(block_width, block_height); const uint64_t grid_x = (index_length + block_dim.x - 1) / block_dim.x; const uint64_t grid_y = (batch_size + block_dim.y - 1) / block_dim.y; PADDLE_ENFORCE_LE_UINT32_MAX(grid_x, "grid.x"); PADDLE_ENFORCE_LE_UINT32_MAX(grid_y, "grid.y"); dim3 grid_dim(static_cast(grid_x), static_cast(grid_y)); backends::gpu::LimitGridDim(dev_ctx, &grid_dim); // choose the element index type ; uint32 or int64 based on the tensor size bool use_uint32 = true; if (x.numel() > UINT32_MAX || out->numel() > UINT32_MAX) { use_uint32 = false; } if (index_type == DataType::INT64) { const int64_t* index_data = index.data(); if (use_uint32) { IndexSampleForward <<>>(index_data, in_data, out_data, index_length, input_length, batch_size); } else { IndexSampleForward <<>>(index_data, in_data, out_data, index_length, input_length, batch_size); } } else if (index_type == DataType::INT32) { const int* index_data = index.data(); if (use_uint32) { IndexSampleForward <<>>(index_data, in_data, out_data, index_length, input_length, batch_size); } else { IndexSampleForward <<>>(index_data, in_data, out_data, index_length, input_length, batch_size); } } } } // namespace phi PD_REGISTER_KERNEL(index_sample, GPU, ALL_LAYOUT, phi::IndexSampleKernel, phi::float16, phi::bfloat16, float, double, int, int64_t, phi::complex64, phi::complex128) {}