Improved the tensor random number generators:

* Use a mersenne twister whenebver possible instead of the default entropy source since the default one isn't very good at all.
 * Added the ability to seed the generators with a time based seed to make them non-deterministic.
This commit is contained in:
Benoit Steiner 2015-04-20 09:24:09 -07:00
parent 016c29f207
commit 43eb2ca6e1
2 changed files with 155 additions and 43 deletions

View File

@ -53,8 +53,8 @@ class TensorBase<Derived, ReadOnlyAccessors>
} }
template <typename RandomGenerator> EIGEN_DEVICE_FUNC template <typename RandomGenerator> EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE const TensorCwiseNullaryOp<RandomGenerator, const Derived> EIGEN_STRONG_INLINE const TensorCwiseNullaryOp<RandomGenerator, const Derived>
random() const { random(const RandomGenerator& gen = RandomGenerator()) const {
return nullaryExpr(RandomGenerator()); return nullaryExpr(gen);
} }
// Generic unary operation support. // Generic unary operation support.

View File

@ -182,18 +182,45 @@ template <typename T> struct ProdReducer
} }
}; };
// Random number generation
namespace {
int get_random_seed() {
#if defined _WIN32
SYSTEMTIME st;
GetSystemTime(&st);
return st.wSecond + 1000 * st.wMilliseconds;
#elif defined __APPLE__
return mach_absolute_time();
#elif defined __CUDA_ARCH__
return clock();
#else
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return ts.tv_nsec;
#endif
}
}
#if !defined (EIGEN_USE_GPU) || !defined(__CUDACC__) || !defined(__CUDA_ARCH__) #if !defined (EIGEN_USE_GPU) || !defined(__CUDACC__) || !defined(__CUDA_ARCH__)
// We're not compiling a cuda kernel // We're not compiling a cuda kernel
template <typename T> struct UniformRandomGenerator { template <typename T> class UniformRandomGenerator {
public:
static const bool PacketAccess = true; static const bool PacketAccess = true;
UniformRandomGenerator(bool deterministic = true) {
if (!deterministic) {
srand(get_random_seed());
}
}
template<typename Index> template<typename Index>
T operator()(Index, Index = 0) const { T operator()(Index, Index = 0) const {
return random<T>(); return random<T>();
} }
template<typename Index> template<typename Index>
typename internal::packet_traits<T>::type packetOp(Index, Index = 0) const { typename internal::packet_traits<T>::type packetOp(Index i, Index j = 0) const {
const int packetSize = internal::packet_traits<T>::size; const int packetSize = internal::packet_traits<T>::size;
EIGEN_ALIGN_DEFAULT T values[packetSize]; EIGEN_ALIGN_DEFAULT T values[packetSize];
for (int i = 0; i < packetSize; ++i) { for (int i = 0; i < packetSize; ++i) {
@ -203,26 +230,95 @@ template <typename T> struct UniformRandomGenerator {
} }
}; };
#if __cplusplus > 199711
template <> class UniformRandomGenerator<float> {
public:
static const bool PacketAccess = true;
UniformRandomGenerator(bool deterministic = true) {
if (!deterministic) {
m_generator.seed(get_random_seed());
}
}
UniformRandomGenerator(const UniformRandomGenerator<float>& other) {
m_generator.seed(other(0, 0) * UINT_MAX);
}
template<typename Index>
float operator()(Index, Index = 0) const {
return m_distribution(m_generator);
}
template<typename Index>
typename internal::packet_traits<float>::type packetOp(Index i, Index j = 0) const {
const int packetSize = internal::packet_traits<float>::size;
EIGEN_ALIGN_DEFAULT float values[packetSize];
for (int i = 0; i < packetSize; ++i) {
values[i] = this->operator()(i, j);
}
return internal::pload<typename internal::packet_traits<float>::type>(values);
}
private:
UniformRandomGenerator& operator = (const UniformRandomGenerator&);
mutable std::mt19937 m_generator;
mutable std::uniform_real_distribution<float> m_distribution;
};
template <> class UniformRandomGenerator<double> {
public:
static const bool PacketAccess = true;
UniformRandomGenerator(bool deterministic = true) {
if (!deterministic) {
m_generator.seed(get_random_seed());
}
}
UniformRandomGenerator(const UniformRandomGenerator<double>& other) {
m_generator.seed(other(0, 0) * UINT_MAX);
}
template<typename Index>
double operator()(Index, Index = 0) const {
return m_distribution(m_generator);
}
template<typename Index>
typename internal::packet_traits<double>::type packetOp(Index i, Index j = 0) const {
const int packetSize = internal::packet_traits<double>::size;
EIGEN_ALIGN_DEFAULT double values[packetSize];
for (int i = 0; i < packetSize; ++i) {
values[i] = this->operator()(i, j);
}
return internal::pload<typename internal::packet_traits<double>::type>(values);
}
private:
UniformRandomGenerator& operator = (const UniformRandomGenerator&);
mutable std::mt19937 m_generator;
mutable std::uniform_real_distribution<double> m_distribution;
};
#endif
#else #else
// We're compiling a cuda kernel // We're compiling a cuda kernel
template <typename T> struct UniformRandomGenerator; template <typename T> class UniformRandomGenerator;
template <> struct UniformRandomGenerator<float> {
template <> class UniformRandomGenerator<float> {
public:
static const bool PacketAccess = true; static const bool PacketAccess = true;
EIGEN_DEVICE_FUNC UniformRandomGenerator() { EIGEN_DEVICE_FUNC UniformRandomGenerator(bool deterministic = true) {
const int tid = blockIdx.x * blockDim.x + threadIdx.x; const int tid = blockIdx.x * blockDim.x + threadIdx.x;
curand_init(0, tid, 0, &m_state); const int seed = deterministic ? 0 : get_random_seed();
curand_init(seed, tid, 0, &m_state);
} }
template<typename Index> EIGEN_DEVICE_FUNC template<typename Index>
float operator()(Index, Index = 0) const { EIGEN_DEVICE_FUNC float operator()(Index, Index = 0) const {
return curand_uniform(&m_state); return curand_uniform(&m_state);
} }
template<typename Index> EIGEN_DEVICE_FUNC template<typename Index>
float4 packetOp(Index, Index = 0) const { EIGEN_DEVICE_FUNC float4 packetOp(Index, Index = 0) const {
return curand_uniform4(&m_state); return curand_uniform4(&m_state);
} }
@ -230,20 +326,21 @@ template <> struct UniformRandomGenerator<float> {
mutable curandStatePhilox4_32_10_t m_state; mutable curandStatePhilox4_32_10_t m_state;
}; };
template <> struct UniformRandomGenerator<double> { template <> class UniformRandomGenerator<double> {
public:
static const bool PacketAccess = true; static const bool PacketAccess = true;
EIGEN_DEVICE_FUNC UniformRandomGenerator() { EIGEN_DEVICE_FUNC UniformRandomGenerator(bool deterministic = true) {
const int tid = blockIdx.x * blockDim.x + threadIdx.x; const int tid = blockIdx.x * blockDim.x + threadIdx.x;
curand_init(0, tid, 0, &m_state); const int seed = deterministic ? 0 : get_random_seed();
curand_init(seed, tid, 0, &m_state);
} }
template<typename Index> EIGEN_DEVICE_FUNC template<typename Index>
double operator()(Index, Index = 0) const { EIGEN_DEVICE_FUNC double operator()(Index, Index = 0) const {
return curand_uniform_double(&m_state); return curand_uniform_double(&m_state);
} }
template<typename Index> EIGEN_DEVICE_FUNC template<typename Index>
double2 packetOp(Index, Index = 0) const { EIGEN_DEVICE_FUNC double2 packetOp(Index, Index = 0) const {
return curand_uniform2_double(&m_state); return curand_uniform2_double(&m_state);
} }
@ -256,12 +353,18 @@ template <> struct UniformRandomGenerator<double> {
#if (!defined (EIGEN_USE_GPU) || !defined(__CUDACC__) || !defined(__CUDA_ARCH__)) && __cplusplus > 199711 #if (!defined (EIGEN_USE_GPU) || !defined(__CUDACC__) || !defined(__CUDA_ARCH__)) && __cplusplus > 199711
// We're not compiling a cuda kernel // We're not compiling a cuda kernel
template <typename T> struct NormalRandomGenerator { template <typename T> class NormalRandomGenerator {
public:
static const bool PacketAccess = true; static const bool PacketAccess = true;
NormalRandomGenerator() : m_distribution(0, 1) {} NormalRandomGenerator(bool deterministic = true) : m_distribution(0, 1) {
NormalRandomGenerator(const NormalRandomGenerator& other) : m_distribution(other.m_distribution) { } if (!deterministic) {
m_generator.seed(get_random_seed());
}
}
NormalRandomGenerator(const NormalRandomGenerator& other) : m_distribution(other.m_distribution) {
m_generator.seed(other(0, 0) * UINT_MAX);
}
template<typename Index> template<typename Index>
T operator()(Index, Index = 0) const { T operator()(Index, Index = 0) const {
@ -278,29 +381,30 @@ template <typename T> struct NormalRandomGenerator {
} }
mutable std::normal_distribution<T> m_distribution; mutable std::normal_distribution<T> m_distribution;
mutable std::default_random_engine m_generator; mutable std::mt19937 m_generator;
}; };
#elif defined (EIGEN_USE_GPU) && defined(__CUDACC__) && defined(__CUDA_ARCH__) #elif defined (EIGEN_USE_GPU) && defined(__CUDACC__) && defined(__CUDA_ARCH__)
// We're compiling a cuda kernel // We're compiling a cuda kernel
template <typename T> struct NormalRandomGenerator; template <typename T> class NormalRandomGenerator;
template <> struct NormalRandomGenerator<float> {
template <> class NormalRandomGenerator<float> {
public:
static const bool PacketAccess = true; static const bool PacketAccess = true;
EIGEN_DEVICE_FUNC NormalRandomGenerator() { EIGEN_DEVICE_FUNC NormalRandomGenerator(bool deterministic = true) {
const int tid = blockIdx.x * blockDim.x + threadIdx.x; const int tid = blockIdx.x * blockDim.x + threadIdx.x;
curand_init(0, tid, 0, &m_state); const int seed = deterministic ? 0 : get_random_seed();
curand_init(seed, tid, 0, &m_state);
} }
template<typename Index> EIGEN_DEVICE_FUNC template<typename Index>
float operator()(Index, Index = 0) const { EIGEN_DEVICE_FUNC float operator()(Index, Index = 0) const {
return curand_normal(&m_state); return curand_normal(&m_state);
} }
template<typename Index> EIGEN_DEVICE_FUNC template<typename Index>
float4 packetOp(Index, Index = 0) const { EIGEN_DEVICE_FUNC float4 packetOp(Index, Index = 0) const {
return curand_normal4(&m_state); return curand_normal4(&m_state);
} }
@ -308,20 +412,21 @@ template <> struct NormalRandomGenerator<float> {
mutable curandStatePhilox4_32_10_t m_state; mutable curandStatePhilox4_32_10_t m_state;
}; };
template <> struct NormalRandomGenerator<double> { template <> class NormalRandomGenerator<double> {
public:
static const bool PacketAccess = true; static const bool PacketAccess = true;
EIGEN_DEVICE_FUNC NormalRandomGenerator() { EIGEN_DEVICE_FUNC NormalRandomGenerator(bool deterministic = true) {
const int tid = blockIdx.x * blockDim.x + threadIdx.x; const int tid = blockIdx.x * blockDim.x + threadIdx.x;
curand_init(0, tid, 0, &m_state); const int seed = deterministic ? 0 : get_random_seed();
curand_init(seed, tid, 0, &m_state);
} }
template<typename Index> EIGEN_DEVICE_FUNC template<typename Index>
double operator()(Index, Index = 0) const { EIGEN_DEVICE_FUNC double operator()(Index, Index = 0) const {
return curand_normal_double(&m_state); return curand_normal_double(&m_state);
} }
template<typename Index> EIGEN_DEVICE_FUNC template<typename Index>
double2 packetOp(Index, Index = 0) const { EIGEN_DEVICE_FUNC double2 packetOp(Index, Index = 0) const {
return curand_normal2_double(&m_state); return curand_normal2_double(&m_state);
} }
@ -329,6 +434,13 @@ template <> struct NormalRandomGenerator<double> {
mutable curandStatePhilox4_32_10_t m_state; mutable curandStatePhilox4_32_10_t m_state;
}; };
#else
template <typename T> class NormalRandomGenerator {
public:
NormalRandomGenerator(bool = true) {}
};
#endif #endif