// 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. #pragma once #include #include #include #include "paddle/phi/backends/context_pool.h" #if defined(__NVCC__) || defined(__HIPCC__) #include #include "paddle/phi/core/generator.h" #include "paddle/phi/kernels/full_kernel.h" #include "paddle/phi/kernels/funcs/distribution_helper.h" #include "paddle/phi/kernels/funcs/index_impl.cu.h" #endif #include "glog/logging.h" #include "paddle/phi/common/memory_utils.h" #include "paddle/phi/core/tensor_utils.h" namespace phi { namespace funcs { template inline void UniformRealDistribution(T* data, const int64_t& size, const float& min, const float& max, const unsigned int seed) { VLOG(4) << "[CPU] UniformRandomKernel"; std::uniform_real_distribution dist(static_cast(min), static_cast(max)); auto engine = phi::GetCPURandomEngine(seed); for (int64_t i = 0; i < size; ++i) { data[i] = dist(*engine); } } template <> inline void UniformRealDistribution(phi::bfloat16* data, const int64_t& size, const float& min, const float& max, const unsigned int seed) { VLOG(4) << "[CPU] UniformRandomKernel"; std::uniform_real_distribution dist(min, max); auto engine = phi::GetCPURandomEngine(seed); for (int64_t i = 0; i < size; ++i) { data[i] = static_cast(dist(*engine)); } } inline std::vector GetNewDataFromShapeTensor( const DenseTensor* new_data_tensor) { DenseTensor cpu_starts_tensor; auto* dev_ctx = DeviceContextPool::Instance().Get(cpu_starts_tensor.place()); if (new_data_tensor->dtype() == DataType::INT64) { auto* new_data = new_data_tensor->data(); if (new_data_tensor->place().GetType() == AllocationType::GPU) { phi::Copy( *dev_ctx, *new_data_tensor, CPUPlace(), true, &cpu_starts_tensor); new_data = cpu_starts_tensor.data(); } std::vector vec_new_data(new_data, new_data + new_data_tensor->numel()); return vec_new_data; } else if (new_data_tensor->dtype() == DataType::INT32) { auto* new_data = new_data_tensor->data(); std::vector vec_new_data; if (new_data_tensor->place().GetType() == AllocationType::GPU) { phi::Copy( *dev_ctx, *new_data_tensor, CPUPlace(), true, &cpu_starts_tensor); new_data = cpu_starts_tensor.data(); } for (int64_t i = 0; i < new_data_tensor->numel(); ++i) { vec_new_data.push_back(static_cast(*(new_data + i))); } return vec_new_data; } else { PADDLE_THROW(common::errors::InvalidArgument( "Expected dtype of ShapeTensor must be int32, int64. But got " "unsupported dtype: %s.", new_data_tensor->dtype())); } } inline std::vector GetNewDataFromShapeTensorList( const std::vector& list_new_shape_tensor) { DenseTensor temp; auto* dev_ctx = DeviceContextPool::Instance().Get(temp.place()); std::vector vec_new_shape; vec_new_shape.reserve(list_new_shape_tensor.size()); for (size_t i = 0; i < list_new_shape_tensor.size(); ++i) { auto tensor = list_new_shape_tensor[i]; PADDLE_ENFORCE_EQ( tensor->dims(), make_ddim({1}), common::errors::InvalidArgument( "Shape of dim tensor in uniform_random_op should be [1]" "But received tensor's dim=%s.", tensor->dims())); if (tensor->dtype() == DataType::INT32) { if (tensor->place().GetType() == AllocationType::GPU) { phi::Copy(*dev_ctx, *tensor, CPUPlace(), true, &temp); vec_new_shape.push_back(static_cast(*temp.data())); } else { vec_new_shape.push_back(static_cast(*tensor->data())); } } else if (tensor->dtype() == DataType::INT64) { if (tensor->place().GetType() == AllocationType::GPU) { DenseTensor temp; phi::Copy(*dev_ctx, *tensor, CPUPlace(), true, &temp); vec_new_shape.push_back(*temp.data()); } else { vec_new_shape.push_back(*tensor->data()); } } else { PADDLE_THROW(common::errors::InvalidArgument( "Expected dtype of ShapeTensorList of %d-th must be int32, int64. " "But got " "unsupported dtype: %s.", i, DataTypeToString(tensor->dtype()))); } } return vec_new_shape; } #if defined(__NVCC__) || defined(__HIPCC__) template struct UniformGenerator { T min_, max_; unsigned int seed_; T diag_val_; unsigned int diag_num_; unsigned int diag_step_; __host__ __device__ UniformGenerator( T min, T max, int seed, int diag_num, int diag_step, T diag_val) : min_(min), max_(max), seed_(seed), diag_num_(diag_num), diag_step_(diag_step), diag_val_(diag_val) {} __host__ __device__ T operator()(const unsigned int n) const { thrust::minstd_rand rng; rng.seed(seed_); thrust::uniform_real_distribution dist(min_, max_); rng.discard(n); T out = dist(rng); unsigned int remainder = n % (diag_step_ + 1); if (remainder == 0 && diag_num_ > n / (diag_step_ + 1)) { out = diag_val_; } return out; } }; template void UniformRandom(const GPUContext& dev_ctx, DenseTensor* tensor, int attr_seed, float attr_min, float attr_max, int attr_diag_num, int attr_diag_step, float attr_diag_val) { int64_t size = tensor->numel(); T* data = dev_ctx.Alloc(tensor); if (size <= 0) return; unsigned int seed = static_cast(attr_seed); T min = static_cast(attr_min); T max = static_cast(attr_max); unsigned int diag_num = static_cast(attr_diag_num); unsigned int diag_step = static_cast(attr_diag_step); T diag_val = static_cast(attr_diag_val); if (seed == 0) { // Use global Generator seed using MT = typename MPTypeTrait::Type; funcs::uniform_distribution dist; funcs::uniform_real_transform trans(min, max); funcs::distribution_and_transform(dev_ctx, tensor, dist, trans); } else { // Use OP seed auto func = UniformGenerator(min, max, seed, diag_num, diag_step, diag_val); phi::IndexKernel>(dev_ctx, tensor, func); } } #endif } // namespace funcs } // namespace phi