Files
paddlepaddle--paddle/paddle/phi/kernels/funcs/uniform_random_functor.h
T
2026-07-13 12:40:42 +08:00

213 lines
7.3 KiB
C++

// 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 <algorithm>
#include <utility>
#include <vector>
#include "paddle/phi/backends/context_pool.h"
#if defined(__NVCC__) || defined(__HIPCC__)
#include <thrust/random.h>
#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 <typename T>
inline void UniformRealDistribution(T* data,
const int64_t& size,
const float& min,
const float& max,
const unsigned int seed) {
VLOG(4) << "[CPU] UniformRandomKernel<T>";
std::uniform_real_distribution<T> dist(static_cast<T>(min),
static_cast<T>(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<bfloat16>";
std::uniform_real_distribution<float> dist(min, max);
auto engine = phi::GetCPURandomEngine(seed);
for (int64_t i = 0; i < size; ++i) {
data[i] = static_cast<phi::bfloat16>(dist(*engine));
}
}
inline std::vector<int64_t> 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<int64_t>();
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<int64_t>();
}
std::vector<int64_t> 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<int32_t>();
std::vector<int64_t> 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<int32_t>();
}
for (int64_t i = 0; i < new_data_tensor->numel(); ++i) {
vec_new_data.push_back(static_cast<int64_t>(*(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<int64_t> GetNewDataFromShapeTensorList(
const std::vector<const DenseTensor*>& list_new_shape_tensor) {
DenseTensor temp;
auto* dev_ctx = DeviceContextPool::Instance().Get(temp.place());
std::vector<int64_t> 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<int64_t>(*temp.data<int32_t>()));
} else {
vec_new_shape.push_back(static_cast<int64_t>(*tensor->data<int32_t>()));
}
} 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<int64_t>());
} else {
vec_new_shape.push_back(*tensor->data<int64_t>());
}
} 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 <typename T>
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<T> 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 <typename T>
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<T>(tensor);
if (size <= 0) return;
unsigned int seed = static_cast<unsigned int>(attr_seed);
T min = static_cast<T>(attr_min);
T max = static_cast<T>(attr_max);
unsigned int diag_num = static_cast<unsigned int>(attr_diag_num);
unsigned int diag_step = static_cast<unsigned int>(attr_diag_step);
T diag_val = static_cast<T>(attr_diag_val);
if (seed == 0) {
// Use global Generator seed
using MT = typename MPTypeTrait<T>::Type;
funcs::uniform_distribution<MT> dist;
funcs::uniform_real_transform<MT> trans(min, max);
funcs::distribution_and_transform<T>(dev_ctx, tensor, dist, trans);
} else {
// Use OP seed
auto func =
UniformGenerator<T>(min, max, seed, diag_num, diag_step, diag_val);
phi::IndexKernel<T, UniformGenerator<T>>(dev_ctx, tensor, func);
}
}
#endif
} // namespace funcs
} // namespace phi