// 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/uniform_kernel.h" #include #include "paddle/phi/common/complex.h" #include "paddle/phi/common/type_traits.h" #include "paddle/phi/kernels/complex_kernel.h" #include "paddle/common/flags.h" #include "paddle/phi/core/kernel_registry.h" #include "paddle/phi/kernels/funcs/distribution_helper.h" #include "paddle/phi/kernels/funcs/index_impl.cu.h" namespace phi { 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 struct UniformKernelImpl {}; template struct UniformKernelImpl { static void Apply(const Context& dev_ctx, const Scalar& min, const Scalar& max, int seed, DenseTensor* out) { using RealType = dtype::Real; RealType min_val = min.to(); RealType max_val = max.to(); if (seed == 0) { funcs::uniform_distribution dist; funcs::uniform_real_transform trans(min_val, max_val); funcs::distribution_and_transform(dev_ctx, out, dist, trans); } else { auto func = [=] __device__(int64_t idx) { thrust::minstd_rand engine; engine.seed(seed); engine.discard(idx); thrust::uniform_real_distribution dist(min_val, max_val); return dist(engine); }; // NOLINT(readability/braces) IndexKernel(dev_ctx, out, func); } } }; template struct UniformKernelImpl, Context, true> { static void Apply(const Context& dev_ctx, const Scalar& min, const Scalar& max, int seed, DenseTensor* out) { using T = dtype::complex; using RealType = float; RealType min_val = min.to(); RealType max_val = max.to(); auto gen_cuda = dev_ctx.GetGenerator(); size_t size = out->numel(); size_t increment = size * 2; auto seed_offset = gen_cuda->IncrementOffset(increment); uint64_t actual_seed = seed_offset.first; uint64_t offset = seed_offset.second; auto func = [=] __device__(int64_t idx) { thrust::minstd_rand engine; engine.seed(actual_seed); engine.discard(offset + idx * 2); thrust::uniform_real_distribution dist(min_val, max_val); RealType real_val = dist(engine); RealType imag_val = dist(engine); return T(real_val, imag_val); }; // NOLINT(readability/braces) IndexKernel(dev_ctx, out, func); } }; template struct UniformKernelImpl, Context, true> { static void Apply(const Context& dev_ctx, const Scalar& min, const Scalar& max, int seed, DenseTensor* out) { using T = dtype::complex; using RealType = double; RealType min_val = min.to(); RealType max_val = max.to(); auto gen_cuda = dev_ctx.GetGenerator(); size_t size = out->numel(); size_t increment = size * 2; auto seed_offset = gen_cuda->IncrementOffset(increment); uint64_t actual_seed = seed_offset.first; uint64_t offset = seed_offset.second; auto func = [=] __device__(int64_t idx) { thrust::minstd_rand engine; engine.seed(actual_seed); engine.discard(offset + idx * 2); thrust::uniform_real_distribution dist(min_val, max_val); RealType real_val = dist(engine); RealType imag_val = dist(engine); return T(real_val, imag_val); }; // NOLINT(readability/braces) IndexKernel(dev_ctx, out, func); } }; template struct UniformKernelImpl { static void Apply(const Context& dev_ctx, const Scalar& min, const Scalar& max, int seed, DenseTensor* out) { if (seed == 0) { using MT = typename MPTypeTrait::Type; funcs::uniform_distribution dist; funcs::uniform_real_transform trans(static_cast(min.to()), static_cast(max.to())); funcs::distribution_and_transform(dev_ctx, out, dist, trans); } else { auto func = UniformGenerator( static_cast(min.to()), static_cast(max.to()), seed, 0, 0, static_cast(0.0)); // NOLINT(readability/braces) IndexKernel>(dev_ctx, out, func); } } }; template void UniformKernel(const Context& dev_ctx, const IntArray& shape, DataType dtype, const Scalar& min, const Scalar& max, int seed, DenseTensor* out) { out->Resize(shape.GetData()); dev_ctx.template Alloc(out); constexpr bool is_complex = std::is_same>::value || std::is_same>::value; UniformKernelImpl::Apply( dev_ctx, min, max, seed, out); } } // namespace phi PD_REGISTER_KERNEL(uniform, GPU, ALL_LAYOUT, phi::UniformKernel, float, double, phi::float16, phi::bfloat16, phi::float8_e4m3fn, phi::complex64, phi::complex128) {}