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(input, 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(input, outputA);
68  sin(i) = original + perturbation;
69  module.Forward(input, 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(input, deriv, delta);
94 
95  jacobianB.col(i) = delta;
96  }
97 
98  return arma::max(arma::max(arma::abs(jacobianA - jacobianB)));
99 }
100 
101 // Custom Jacobian Test where we get the input from outside of this function
102 // unlike the original Jacobian Test where input is generated inside that
103 // funcion.
104 template <typename ModuleType>
105 double CustomJacobianTest(ModuleType& module,
106  arma::mat& input,
107  const double perturbation = 1e-6)
108 {
109  arma::mat output, outputA, outputB, jacobianA, jacobianB;
110 
111  // Initialize the module parameters.
112  ResetFunction(module);
113 
114  // Initialize the jacobian matrix.
115  module.Forward(input, output);
116  jacobianA = arma::zeros(input.n_elem, output.n_elem);
117 
118  for (size_t i = 0; i < input.n_elem; ++i)
119  {
120  double original = input(i);
121  input(i) = original - perturbation;
122  module.Forward(input, outputA);
123  input(i) = original + perturbation;
124  module.Forward(input, outputB);
125  input(i) = original;
126 
127  outputB -= outputA;
128  outputB /= 2 * perturbation;
129  jacobianA.row(i) = outputB.t();
130  }
131 
132  // Initialize the derivative parameter.
133  arma::mat deriv = arma::zeros(output.n_rows, output.n_cols);
134 
135  // Initialize the jacobian matrix.
136  jacobianB = arma::zeros(input.n_elem, output.n_elem);
137 
138  for (size_t i = 0; i < deriv.n_elem; ++i)
139  {
140  deriv.zeros();
141  deriv(i) = 1;
142 
143  arma::mat delta;
144  module.Backward(input, deriv, delta);
145 
146  jacobianB.col(i) = delta;
147  }
148 
149  return arma::max(arma::max(arma::abs(jacobianA - jacobianB)));
150 }
151 
152 // Approximate Jacobian and supposedly-true Jacobian, then compare them
153 // similarly to before.
154 template<typename ModuleType>
155 double JacobianPerformanceTest(ModuleType& module,
156  arma::mat& input,
157  arma::mat& target,
158  const double eps = 1e-6)
159 {
160  module.Forward(input, target);
161 
162  arma::mat delta;
163  module.Backward(input, target, delta);
164 
165  arma::mat centralDifference = arma::zeros(delta.n_rows, delta.n_cols);
166  arma::mat inputTemp = arma::mat(input.memptr(), input.n_rows, input.n_cols,
167  false, false);
168 
169  arma::mat centralDifferenceTemp = arma::mat(centralDifference.memptr(),
170  centralDifference.n_rows, centralDifference.n_cols, false, false);
171 
172  for (size_t i = 0; i < input.n_elem; ++i)
173  {
174  inputTemp(i) = inputTemp(i) + eps;
175  double outputA = module.Forward(input, target);
176  inputTemp(i) = inputTemp(i) - (2 * eps);
177  double outputB = module.Forward(input, target);
178 
179  centralDifferenceTemp(i) = (outputA - outputB) / (2 * eps);
180  inputTemp(i) = inputTemp(i) + eps;
181  }
182 
183  return arma::max(arma::max(arma::abs(centralDifference - delta)));
184 }
185 
186 // Simple numerical gradient checker.
187 template<class FunctionType>
188 double CheckGradient(FunctionType& function, const double eps = 1e-7)
189 {
190  // Get gradients for the current parameters.
191  arma::mat orgGradient, gradient, estGradient;
192  function.Gradient(orgGradient);
193 
194  estGradient = arma::zeros(orgGradient.n_rows, orgGradient.n_cols);
195 
196  // Compute numeric approximations to gradient.
197  for (size_t i = 0; i < orgGradient.n_elem; ++i)
198  {
199  double tmp = function.Parameters()(i);
200 
201  // Perturb parameter with a positive constant and get costs.
202  function.Parameters()(i) += eps;
203  double costPlus = function.Gradient(gradient);
204 
205  // Perturb parameter with a negative constant and get costs.
206  function.Parameters()(i) -= (2 * eps);
207  double costMinus = function.Gradient(gradient);
208 
209  // Restore the parameter value.
210  function.Parameters()(i) = tmp;
211 
212  // Compute numerical gradients using the costs calculated above.
213  estGradient(i) = (costPlus - costMinus) / (2 * eps);
214  }
215 
216  // Estimate error of gradient.
217  return arma::norm(orgGradient - estGradient) /
218  arma::norm(orgGradient + estGradient);
219 }
220 
221 // Simple numerical gradient checker for regularizers.
222 template<class FunctionType>
223 double CheckRegularizerGradient(FunctionType& function, const double eps = 1e-7)
224 {
225  // Get gradients for the current parameters.
226  arma::mat weight = arma::randu(10, 10);
227  arma::mat orgGradient = arma::zeros(10 * 10, 1);
228  function.Gradient(weight, orgGradient);
229 
230  arma::mat estGradient = arma::zeros(weight.n_rows, weight.n_cols);
231 
232  // Compute numeric approximations to gradient.
233  for (size_t i = 0; i < weight.n_rows; ++i)
234  {
235  for (size_t j = 0; j < weight.n_cols; ++j)
236  {
237  double tmp = weight(i, j);
238 
239  weight(i, j) += eps;
240  double costPlus = function.Output(weight, i, j);
241  weight(i, j) -= (2 * eps);
242  double costMinus = function.Output(weight, i, j);
243 
244  // Restore the weight value.
245  weight(i, j) = tmp;
246  estGradient(i, j) = (costPlus - costMinus) / (2 * eps);
247  }
248  }
249 
250  estGradient = arma::vectorise(estGradient);
251  // Estimate error of gradient.
252  return arma::norm(orgGradient - estGradient) /
253  arma::norm(orgGradient + estGradient);
254 }
255 
256 #endif
Artificial Neural Network.
Linear algebra utility functions, generally performed on matrices or vectors.
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 CustomJacobianTest(ModuleType &module, arma::mat &input, const double perturbation=1e-6)
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)