1 #ifndef UTILS_RANDOM_H_
2 #define UTILS_RANDOM_H_
3
4 #include <Eigen/Core>
5 #include "../Config.h"
6 #include "../RNG.h"
7
8 namespace MiniDNN
9 {
10
11 namespace internal
12 {
13
14
15 // Shuffle the integer array
shuffle(int * arr,const int n,RNG & rng)16 inline void shuffle(int* arr, const int n, RNG& rng)
17 {
18 for (int i = n - 1; i > 0; i--)
19 {
20 // A random non-negative integer <= i
21 const int j = int(rng.rand() * (i + 1));
22 // Swap arr[i] and arr[j]
23 const int tmp = arr[i];
24 arr[i] = arr[j];
25 arr[j] = tmp;
26 }
27 }
28
29 template <typename DerivedX, typename DerivedY, typename XType, typename YType>
create_shuffled_batches(const Eigen::MatrixBase<DerivedX> & x,const Eigen::MatrixBase<DerivedY> & y,int batch_size,RNG & rng,std::vector<XType> & x_batches,std::vector<YType> & y_batches)30 inline int create_shuffled_batches(
31 const Eigen::MatrixBase<DerivedX>& x, const Eigen::MatrixBase<DerivedY>& y,
32 int batch_size, RNG& rng,
33 std::vector<XType>& x_batches, std::vector<YType>& y_batches
34 )
35 {
36 const int nobs = x.cols();
37 const int dimx = x.rows();
38 const int dimy = y.rows();
39
40 if (y.cols() != nobs)
41 {
42 throw std::invalid_argument("Input X and Y have different number of observations");
43 }
44
45 // Randomly shuffle the IDs
46 Eigen::VectorXi id = Eigen::VectorXi::LinSpaced(nobs, 0, nobs - 1);
47 shuffle(id.data(), id.size(), rng);
48
49 // Compute batch size
50 if (batch_size > nobs)
51 {
52 batch_size = nobs;
53 }
54
55 const int nbatch = (nobs - 1) / batch_size + 1;
56 const int last_batch_size = nobs - (nbatch - 1) * batch_size;
57 // Create shuffled data
58 x_batches.clear();
59 y_batches.clear();
60 x_batches.reserve(nbatch);
61 y_batches.reserve(nbatch);
62
63 for (int i = 0; i < nbatch; i++)
64 {
65 const int bsize = (i == nbatch - 1) ? last_batch_size : batch_size;
66 x_batches.push_back(XType(dimx, bsize));
67 y_batches.push_back(YType(dimy, bsize));
68 // Copy data
69 const int offset = i * batch_size;
70
71 for (int j = 0; j < bsize; j++)
72 {
73 x_batches[i].col(j).noalias() = x.col(id[offset + j]);
74 y_batches[i].col(j).noalias() = y.col(id[offset + j]);
75 }
76 }
77
78 return nbatch;
79 }
80
81 // Fill array with N(mu, sigma^2) random numbers
82 inline void set_normal_random(Scalar* arr, const int n, RNG& rng,
83 const Scalar& mu = Scalar(0),
84 const Scalar& sigma = Scalar(1))
85 {
86 // For simplicity we use Box-Muller transform to generate normal random variates
87 const double two_pi = 6.283185307179586476925286766559;
88
89 for (int i = 0; i < n - 1; i += 2)
90 {
91 const double t1 = sigma * std::sqrt(-2 * std::log(rng.rand()));
92 const double t2 = two_pi * rng.rand();
93 arr[i] = t1 * std::cos(t2) + mu;
94 arr[i + 1] = t1 * std::sin(t2) + mu;
95 }
96
97 if (n % 2 == 1)
98 {
99 const double t1 = sigma * std::sqrt(-2 * std::log(rng.rand()));
100 const double t2 = two_pi * rng.rand();
101 arr[n - 1] = t1 * std::cos(t2) + mu;
102 }
103 }
104
105
106 } // namespace internal
107
108 } // namespace MiniDNN
109
110
111 #endif /* UTILS_RANDOM_H_ */
112