ann_test_tools.hpp
Go to the documentation of this file.
1 
12 #ifndef MLPACK_TESTS_ANN_TEST_TOOLS_HPP
13 #define MLPACK_TESTS_ANN_TEST_TOOLS_HPP
14 
15 #include <mlpack/core.hpp>
16 
17 using namespace mlpack;
18 using namespace mlpack::ann;
19 
20 // Helper function which calls the Reset function of the given module.
21 template<class T>
23  T& layer,
24  typename std::enable_if<HasResetCheck<T, void(T::*)()>::value>::type* = 0)
25 {
26  layer.Reset();
27 }
28 
29 template<class T>
31  T& /* layer */,
32  typename std::enable_if<!HasResetCheck<T, void(T::*)()>::value>::type* = 0)
33 {
34  /* Nothing to do here */
35 }
36 
37 // Approximate Jacobian and supposedly-true Jacobian, then compare them
38 // similarly to before.
39 template<typename ModuleType>
40 double JacobianTest(ModuleType& module,
41  arma::mat& input,
42  const double minValue = -2,
43  const double maxValue = -1,
44  const double perturbation = 1e-6)
45 {
46  arma::mat output, outputA, outputB, jacobianA, jacobianB;
47 
48  // Initialize the input matrix.
49  RandomInitialization init(minValue, maxValue);
50  init.Initialize(input, input.n_rows, input.n_cols);
51 
52  // Initialize the module parameters.
53  ResetFunction(module);
54 
55  // Initialize the jacobian matrix.
56  module.Forward(std::move(input), std::move(output));
57  jacobianA = arma::zeros(input.n_elem, output.n_elem);
58 
59  // Share the input paramter matrix.
60  arma::mat sin = arma::mat(input.memptr(), input.n_rows, input.n_cols,
61  false, false);
62 
63  for (size_t i = 0; i < input.n_elem; ++i)
64  {
65  double original = sin(i);
66  sin(i) = original - perturbation;
67  module.Forward(std::move(input), std::move(outputA));
68  sin(i) = original + perturbation;
69  module.Forward(std::move(input), std::move(outputB));
70  sin(i) = original;
71 
72  outputB -= outputA;
73  outputB /= 2 * perturbation;
74  jacobianA.row(i) = outputB.t();
75  }
76 
77  // Initialize the derivative parameter.
78  arma::mat deriv = arma::zeros(output.n_rows, output.n_cols);
79 
80  // Share the derivative parameter.
81  arma::mat derivTemp = arma::mat(deriv.memptr(), deriv.n_rows, deriv.n_cols,
82  false, false);
83 
84  // Initialize the jacobian matrix.
85  jacobianB = arma::zeros(input.n_elem, output.n_elem);
86 
87  for (size_t i = 0; i < derivTemp.n_elem; ++i)
88  {
89  deriv.zeros();
90  derivTemp(i) = 1;
91 
92  arma::mat delta;
93  module.Backward(std::move(input), std::move(deriv), std::move(delta));
94 
95  jacobianB.col(i) = delta;
96  }
97 
98  return arma::max(arma::max(arma::abs(jacobianA - jacobianB)));
99 }
100 
101 // Approximate Jacobian and supposedly-true Jacobian, then compare them
102 // similarly to before.
103 template<typename ModuleType>
104 double JacobianPerformanceTest(ModuleType& module,
105  arma::mat& input,
106  arma::mat& target,
107  const double eps = 1e-6)
108 {
109  module.Forward(std::move(input), std::move(target));
110 
111  arma::mat delta;
112  module.Backward(std::move(input), std::move(target), std::move(delta));
113 
114  arma::mat centralDifference = arma::zeros(delta.n_rows, delta.n_cols);
115  arma::mat inputTemp = arma::mat(input.memptr(), input.n_rows, input.n_cols,
116  false, false);
117 
118  arma::mat centralDifferenceTemp = arma::mat(centralDifference.memptr(),
119  centralDifference.n_rows, centralDifference.n_cols, false, false);
120 
121  for (size_t i = 0; i < input.n_elem; ++i)
122  {
123  inputTemp(i) = inputTemp(i) + eps;
124  double outputA = module.Forward(std::move(input), std::move(target));
125  inputTemp(i) = inputTemp(i) - (2 * eps);
126  double outputB = module.Forward(std::move(input), std::move(target));
127 
128  centralDifferenceTemp(i) = (outputA - outputB) / (2 * eps);
129  inputTemp(i) = inputTemp(i) + eps;
130  }
131 
132  return arma::max(arma::max(arma::abs(centralDifference - delta)));
133 }
134 
135 // Simple numerical gradient checker.
136 template<class FunctionType>
137 double CheckGradient(FunctionType& function, const double eps = 1e-7)
138 {
139  // Get gradients for the current parameters.
140  arma::mat orgGradient, gradient, estGradient;
141  function.Gradient(orgGradient);
142 
143  estGradient = arma::zeros(orgGradient.n_rows, orgGradient.n_cols);
144 
145  // Compute numeric approximations to gradient.
146  for (size_t i = 0; i < orgGradient.n_elem; ++i)
147  {
148  double tmp = function.Parameters()(i);
149 
150  // Perturb parameter with a positive constant and get costs.
151  function.Parameters()(i) += eps;
152  double costPlus = function.Gradient(gradient);
153 
154  // Perturb parameter with a negative constant and get costs.
155  function.Parameters()(i) -= (2 * eps);
156  double costMinus = function.Gradient(gradient);
157 
158  // Restore the parameter value.
159  function.Parameters()(i) = tmp;
160 
161  // Compute numerical gradients using the costs calculated above.
162  estGradient(i) = (costPlus - costMinus) / (2 * eps);
163  }
164 
165  // Estimate error of gradient.
166  return arma::norm(orgGradient - estGradient) /
167  arma::norm(orgGradient + estGradient);
168 }
169 
170 // Simple numerical gradient checker for regularizers.
171 template<class FunctionType>
172 double CheckRegularizerGradient(FunctionType& function, const double eps = 1e-7)
173 {
174  // Get gradients for the current parameters.
175  arma::mat weight = arma::randu(10, 10);
176  arma::mat orgGradient = arma::zeros(10 * 10, 1);
177  function.Gradient(weight, orgGradient);
178 
179  arma::mat estGradient = arma::zeros(weight.n_rows, weight.n_cols);
180 
181  // Compute numeric approximations to gradient.
182  for (size_t i = 0; i < weight.n_rows; ++i)
183  {
184  for (size_t j = 0; j < weight.n_cols; ++j)
185  {
186  double tmp = weight(i, j);
187 
188  weight(i, j) += eps;
189  double costPlus = function.Output(weight, i, j);
190  weight(i, j) -= (2 * eps);
191  double costMinus = function.Output(weight, i, j);
192 
193  // Restore the weight value.
194  weight(i, j) = tmp;
195  estGradient(i, j) = (costPlus - costMinus) / (2 * eps);
196  }
197  }
198 
199  estGradient = arma::vectorise(estGradient);
200  // Estimate error of gradient.
201  return arma::norm(orgGradient - estGradient) /
202  arma::norm(orgGradient + estGradient);
203 }
204 
205 #endif
Artificial Neural Network.
strip_type.hpp
Definition: add_to_po.hpp:21
double CheckGradient(FunctionType &function, const double eps=1e-7)
This class is used to initialize randomly the weight matrix.
Definition: random_init.hpp:24
void ResetFunction(T &layer, typename std::enable_if< HasResetCheck< T, void(T::*)()>::value >::type *=0)
void Initialize(arma::Mat< eT > &W, const size_t rows, const size_t cols)
Initialize randomly the elements of the specified weight matrix.
Definition: random_init.hpp:56
double JacobianPerformanceTest(ModuleType &module, arma::mat &input, arma::mat &target, const double eps=1e-6)
double JacobianTest(ModuleType &module, arma::mat &input, const double minValue=-2, const double maxValue=-1, const double perturbation=1e-6)
Include all of the base components required to write mlpack methods, and the main mlpack Doxygen docu...
double CheckRegularizerGradient(FunctionType &function, const double eps=1e-7)