// Copyright 2013 Yangqing Jia
+// Copyright 2014 Evan Shelhamer
#ifndef CAFFE_COMMON_HPP_
#define CAFFE_COMMON_HPP_
-#include <boost/random/mersenne_twister.hpp>
#include <boost/shared_ptr.hpp>
#include <cublas_v2.h>
#include <cuda.h>
#include <driver_types.h> // cuda driver types
#include <glog/logging.h>
-// various checks for different function calls.
-#define CUDA_CHECK(condition) CHECK_EQ((condition), cudaSuccess)
-#define CUBLAS_CHECK(condition) CHECK_EQ((condition), CUBLAS_STATUS_SUCCESS)
-#define CURAND_CHECK(condition) CHECK_EQ((condition), CURAND_STATUS_SUCCESS)
-
-#define CUDA_KERNEL_LOOP(i, n) \
- for (int i = blockIdx.x * blockDim.x + threadIdx.x; \
- i < (n); \
- i += blockDim.x * gridDim.x)
-
-// After a kernel is executed, this will check the error and if there is one,
-// exit loudly.
-#define CUDA_POST_KERNEL_CHECK \
- if (cudaSuccess != cudaPeekAtLastError()) \
- LOG(FATAL) << "Cuda kernel failed. Error: " \
- << cudaGetErrorString(cudaPeekAtLastError())
-
// Disable the copy and assignment operator for a class.
#define DISABLE_COPY_AND_ASSIGN(classname) \
private:\
// is executed we will see a fatal log.
#define NOT_IMPLEMENTED LOG(FATAL) << "Not Implemented Yet"
-namespace caffe {
+// CUDA: various checks for different function calls.
+#define CUDA_CHECK(condition) CHECK_EQ((condition), cudaSuccess)
+#define CUBLAS_CHECK(condition) CHECK_EQ((condition), CUBLAS_STATUS_SUCCESS)
+#define CURAND_CHECK(condition) CHECK_EQ((condition), CURAND_STATUS_SUCCESS)
-// We will use the boost shared_ptr instead of the new C++11 one mainly
-// because cuda does not work (at least now) well with C++11 features.
-using boost::shared_ptr;
+// CUDA: grid stride looping
+#define CUDA_KERNEL_LOOP(i, n) \
+ for (int i = blockIdx.x * blockDim.x + threadIdx.x; \
+ i < (n); \
+ i += blockDim.x * gridDim.x)
+// CUDA: check for error after kernel execution and exit loudly if there is one.
+#define CUDA_POST_KERNEL_CHECK \
+ if (cudaSuccess != cudaPeekAtLastError()) \
+ LOG(FATAL) << "Cuda kernel failed. Error: " \
+ << cudaGetErrorString(cudaPeekAtLastError())
-// We will use 1024 threads per block, which requires cuda sm_2x or above.
-#if __CUDA_ARCH__ >= 200
- const int CAFFE_CUDA_NUM_THREADS = 1024;
-#else
- const int CAFFE_CUDA_NUM_THREADS = 512;
-#endif
+namespace caffe {
-inline int CAFFE_GET_BLOCKS(const int N) {
- return (N + CAFFE_CUDA_NUM_THREADS - 1) / CAFFE_CUDA_NUM_THREADS;
-}
+// We will use the boost shared_ptr instead of the new C++11 one mainly
+// because cuda does not work (at least now) well with C++11 features.
+using boost::shared_ptr;
// A singleton class to hold common caffe stuff, such as the handler that
enum Brew { CPU, GPU };
enum Phase { TRAIN, TEST };
- // The getters for the variables.
- // Returns the cublas handle.
+
+ // This random number generator facade hides boost and CUDA rng
+ // implementation from one another (for cross-platform compatibility).
+ class RNG {
+ public:
+ RNG();
+ explicit RNG(unsigned int seed);
+ ~RNG();
+ RNG(const RNG&);
+ RNG& operator=(const RNG&);
+ const void* generator() const;
+ void* generator();
+ private:
+ class Generator;
+ Generator* generator_;
+ };
+
+ // Getters for boost rng, curand, and cublas handles
+ inline static RNG &rng_stream() {
+ return Get().random_generator_;
+ }
inline static cublasHandle_t cublas_handle() { return Get().cublas_handle_; }
- // Returns the curand generator.
inline static curandGenerator_t curand_generator() {
return Get().curand_generator_;
}
- // boost RNG
- typedef boost::mt19937 random_generator_t;
- inline static random_generator_t &rng_stream() {
- return Get().random_generator_;
- }
-
// Returns the mode: running on CPU or GPU.
inline static Brew mode() { return Get().mode_; }
// Returns the phase: TRAIN or TEST.
protected:
cublasHandle_t cublas_handle_;
curandGenerator_t curand_generator_;
- random_generator_t random_generator_;
+ RNG random_generator_;
Brew mode_;
Phase phase_;
};
+// CUDA: thread number configuration.
+// Use 1024 threads per block, which requires cuda sm_2x or above,
+// or fall back to attempt compatibility (best of luck to you).
+#if __CUDA_ARCH__ >= 200
+ const int CAFFE_CUDA_NUM_THREADS = 1024;
+#else
+ const int CAFFE_CUDA_NUM_THREADS = 512;
+#endif
+
+// CUDA: number of blocks for threads.
+inline int CAFFE_GET_BLOCKS(const int N) {
+ return (N + CAFFE_CUDA_NUM_THREADS - 1) / CAFFE_CUDA_NUM_THREADS;
+}
+
+
} // namespace caffe
#endif // CAFFE_COMMON_HPP_
// Copyright 2013 Yangqing Jia
+// Copyright 2014 Evan Shelhamer
#include <cstdio>
#include <ctime>
#include "caffe/common.hpp"
+#include "caffe/util/rng.hpp"
namespace caffe {
shared_ptr<Caffe> Caffe::singleton_;
+// curand seeding
int64_t cluster_seedgen(void) {
int64_t s, seed, pid;
pid = getpid();
LOG(ERROR) << "Curand not available. Skipping setting the curand seed.";
}
// RNG seed
- Get().random_generator_ = random_generator_t(seed);
+ Get().random_generator_ = RNG(seed);
}
void Caffe::SetDevice(const int device_id) {
return;
}
+
+class Caffe::RNG::Generator {
+ public:
+ caffe::rng_t rng;
+};
+
+Caffe::RNG::RNG()
+: generator_(new Generator) { }
+
+Caffe::RNG::RNG(unsigned int seed)
+: generator_(new Generator) {
+ generator_->rng = caffe::rng_t(seed);
+}
+
+Caffe::RNG::~RNG() { delete generator_; }
+
+Caffe::RNG::RNG(const RNG& other) : generator_(new Generator) {
+ *generator_ = *other.generator_;
+}
+
+Caffe::RNG& Caffe::RNG::operator=(const RNG& other) {
+ *generator_ = *other.generator_;
+ return *this;
+}
+
+void* Caffe::RNG::generator() {
+ return &generator_->rng;
+}
+
+const void* Caffe::RNG::generator() const {
+ return &generator_->rng;
+}
+
} // namespace caffe
// Copyright 2013 Yangqing Jia
// Copyright 2014 kloudkl@github
+// Copyright 2014 Evan Shelhamer
#include <boost/math/special_functions/next.hpp>
#include <boost/random.hpp>
#include "caffe/common.hpp"
#include "caffe/util/math_functions.hpp"
+#include "caffe/util/rng.hpp"
namespace caffe {
boost::uniform_real<Dtype> random_distribution(
a, caffe_nextafter<Dtype>(b));
- Caffe::random_generator_t &generator = Caffe::rng_stream();
- boost::variate_generator<Caffe::random_generator_t,
+ boost::variate_generator<caffe::rng_t,
boost::uniform_real<Dtype> > variate_generator(
- generator, random_distribution);
+ caffe_rng(), random_distribution);
for (int i = 0; i < n; ++i) {
r[i] = variate_generator();
CHECK(r);
CHECK_GT(sigma, 0);
boost::normal_distribution<Dtype> random_distribution(a, sigma);
- Caffe::random_generator_t &generator = Caffe::rng_stream();
- boost::variate_generator<Caffe::random_generator_t,
+ boost::variate_generator<caffe::rng_t,
boost::normal_distribution<Dtype> > variate_generator(
- generator, random_distribution);
+ caffe_rng(), random_distribution);
for (int i = 0; i < n; ++i) {
r[i] = variate_generator();
CHECK_GE(p, 0);
CHECK_LE(p, 1);
boost::bernoulli_distribution<double> random_distribution(p);
- Caffe::random_generator_t &generator = Caffe::rng_stream();
- boost::variate_generator<Caffe::random_generator_t,
+ boost::variate_generator<caffe::rng_t,
boost::bernoulli_distribution<double> > variate_generator(
- generator, random_distribution);
+ caffe_rng(), random_distribution);
for (int i = 0; i < n; ++i) {
r[i] = variate_generator();