OpenNN  2.2
Open Neural Networks Library
performance_term.cpp
1 /****************************************************************************************************************/
2 /* */
3 /* OpenNN: Open Neural Networks Library */
4 /* www.artelnics.com/opennn */
5 /* */
6 /* P E R F O R M A N C E T E R M C L A S S */
7 /* */
8 /* Roberto Lopez */
9 /* Artelnics - Making intelligent use of data */
11 /* */
12 /****************************************************************************************************************/
13 
14 // OpenNN includes
15 
16 #include "performance_term.h"
17 
18 namespace OpenNN
19 {
20 
21 // DEFAULT CONSTRUCTOR
22 
26 
28  : neural_network_pointer(NULL),
29  data_set_pointer(NULL),
30  mathematical_model_pointer(NULL),
31  numerical_differentiation_pointer(NULL)
32 {
33  set_default();
34 }
35 
36 
37 // NEURAL NETWORK CONSTRUCTOR
38 
44 
45 PerformanceTerm::PerformanceTerm(NeuralNetwork* new_neural_network_pointer)
46  : neural_network_pointer(new_neural_network_pointer),
47  data_set_pointer(NULL),
48  mathematical_model_pointer(NULL),
49  numerical_differentiation_pointer(NULL)
50 {
51  set_default();
52 }
53 
54 
55 // DATA SET CONSTRUCTOR
56 
62 
64  : neural_network_pointer(NULL),
65  data_set_pointer(new_data_set_pointer),
66  mathematical_model_pointer(NULL),
67  numerical_differentiation_pointer(NULL)
68 {
69  set_default();
70 }
71 
72 
73 // MATHEMATICAL MODEL CONSTRUCTOR
74 
80 
81 PerformanceTerm::PerformanceTerm(MathematicalModel* new_mathematical_model_pointer)
82  : neural_network_pointer(NULL),
83  data_set_pointer(NULL),
84  mathematical_model_pointer(new_mathematical_model_pointer),
85  numerical_differentiation_pointer(NULL)
86 {
87  set_default();
88 }
89 
90 
91 // NEURAL NETWORK AND DATA SET CONSTRUCTOR
92 
99 
100 PerformanceTerm::PerformanceTerm(NeuralNetwork* new_neural_network_pointer, DataSet* new_data_set_pointer)
101  : neural_network_pointer(new_neural_network_pointer),
102  data_set_pointer(new_data_set_pointer),
103  mathematical_model_pointer(NULL),
104  numerical_differentiation_pointer(NULL)
105 {
106  set_default();
107 }
108 
109 
110 // NEURAL NETWORK AND MATHEMATICAL MODEL CONSTRUCTOR
111 
118 
119 PerformanceTerm::PerformanceTerm(NeuralNetwork* new_neural_network_pointer, MathematicalModel* new_mathematical_model_pointer)
120  : neural_network_pointer(new_neural_network_pointer),
121  data_set_pointer(NULL),
122  mathematical_model_pointer(new_mathematical_model_pointer),
123  numerical_differentiation_pointer(NULL)
124 {
125  set_default();
126 }
127 
128 
129 // NEURAL NETWORK, MATHEMATICAL MODEL AND DATA SET CONSTRUCTOR
130 
138 
139 PerformanceTerm::PerformanceTerm(NeuralNetwork* new_neural_network_pointer, MathematicalModel* new_mathematical_model_pointer, DataSet* new_data_set_pointer)
140  : neural_network_pointer(new_neural_network_pointer),
141  data_set_pointer(new_data_set_pointer),
142  mathematical_model_pointer(new_mathematical_model_pointer),
143  numerical_differentiation_pointer(NULL)
144 {
145  set_default();
146 }
147 
148 
149 // XML CONSTRUCTOR
150 
155 
156 PerformanceTerm::PerformanceTerm(const tinyxml2::XMLDocument& performance_term_document)
157  : neural_network_pointer(NULL),
158  data_set_pointer(NULL),
159  mathematical_model_pointer(NULL),
160  numerical_differentiation_pointer(NULL)
161 {
162  set_default();
163 
164  from_XML(performance_term_document);
165 }
166 
167 
168 // COPY CONSTRUCTOR
169 
173 
174 PerformanceTerm::PerformanceTerm(const PerformanceTerm& other_performance_term)
175  : neural_network_pointer(NULL),
176  data_set_pointer(NULL),
177  mathematical_model_pointer(NULL),
178  numerical_differentiation_pointer(NULL)
179 {
180  neural_network_pointer = other_performance_term.neural_network_pointer;
181 
182  data_set_pointer = other_performance_term.data_set_pointer;
184 
185  if(other_performance_term.numerical_differentiation_pointer)
186  {
188  }
189 
190  display = other_performance_term.display;
191 }
192 
193 
194 // DESTRUCTOR
195 
198 
200 {
202 }
203 
204 
205 // ASSIGNMENT OPERATOR
206 
207 // PerformanceTerm& operator = (const PerformanceTerm&) method
208 
212 
214 {
215  if(this != &other_performance_term)
216  {
217  neural_network_pointer = other_performance_term.neural_network_pointer;
218 
219  data_set_pointer = other_performance_term.data_set_pointer;
220 
222 
223  if(other_performance_term.numerical_differentiation_pointer == NULL)
224  {
226 
228  }
229  else
230  {
232  }
233 
234  display = other_performance_term.display;
235  }
236 
237  return(*this);
238 }
239 
240 
241 // EQUAL TO OPERATOR
242 
243 // bool operator == (const PerformanceTerm&) const method
244 
248 
249 bool PerformanceTerm::operator == (const PerformanceTerm& other_performance_term) const
250 {
251  if(neural_network_pointer != other_performance_term.neural_network_pointer
252  || data_set_pointer != other_performance_term.data_set_pointer
253  || mathematical_model_pointer != other_performance_term.mathematical_model_pointer)
254  {
255  return(false);
256  }
257 /*
258  else if((numerical_differentiation_pointer == NULL && other_performance_term.numerical_differentiation_pointer !=NULL)
259  || (numerical_differentiation_pointer != NULL && other_performance_term.numerical_differentiation_pointer ==NULL))
260  {
261  return(false);
262  }
263  else if(numerical_differentiation_pointer != NULL)
264  {
265  if(&numerical_differentiation_pointer != &other_performance_term.numerical_differentiation_pointer)
266  {
267  return(false);
268  }
269  }
270 */
271  else if(display != other_performance_term.display)
272  {
273  return(false);
274  }
275 
276  return(true);
277 
278 }
279 
280 
281 // METHODS
282 
283 // const bool& get_display(void) const method
284 
287 
288 const bool& PerformanceTerm::get_display(void) const
289 {
290  return(display);
291 }
292 
293 
294 // bool has_neural_network(void) const method
295 
298 
300 {
302  {
303  return(true);
304  }
305  else
306  {
307  return(false);
308  }
309 }
310 
311 
312 // bool has_mathematical_model(void) const method
313 
316 
318 {
320  {
321  return(true);
322  }
323  else
324  {
325  return(false);
326  }
327 }
328 
329 
330 // bool has_data_set(void) const method
331 
334 
336 {
337  if(data_set_pointer)
338  {
339  return(true);
340  }
341  else
342  {
343  return(false);
344  }
345 }
346 
347 
348 // bool has_numerical_differentiation(void) const method
349 
352 
354 {
356  {
357  return(true);
358  }
359  else
360  {
361  return(false);
362  }
363 }
364 
365 
366 // void set(void) method
367 
370 
372 {
373  neural_network_pointer = NULL;
374  data_set_pointer = NULL;
377 
378  set_default();
379 }
380 
381 
382 // void set(NeuralNetwork*) method
383 
387 
388 void PerformanceTerm::set(NeuralNetwork* new_neural_network_pointer)
389 {
390  neural_network_pointer = new_neural_network_pointer;
391  data_set_pointer = NULL;
394 
395  set_default();
396 }
397 
398 
399 // void set(DataSet*) method
400 
404 
405 void PerformanceTerm::set(DataSet* new_data_set_pointer)
406 {
407  neural_network_pointer = NULL;
408  data_set_pointer = new_data_set_pointer;
411 
412  set_default();
413 }
414 
415 
416 // void set(MathematicalModel*) method
417 
421 
422 void PerformanceTerm::set(MathematicalModel* new_mathematical_model_pointer)
423 {
424  neural_network_pointer = NULL;
425  data_set_pointer = NULL;
426  mathematical_model_pointer = new_mathematical_model_pointer;
428 
429  set_default();
430 }
431 
432 
433 // void set(NeuralNetwork*, DataSet*) method
434 
440 
441 void PerformanceTerm::set(NeuralNetwork* new_neural_network_pointer, DataSet* new_data_set_pointer)
442 {
443  neural_network_pointer = new_neural_network_pointer;
444  data_set_pointer = new_data_set_pointer;
447 
448  set_default();
449 }
450 
451 
452 // void set(NeuralNetwork*, MathematicalModel*) method
453 
459 
460 void PerformanceTerm::set(NeuralNetwork* new_neural_network_pointer, MathematicalModel* new_mathematical_model_pointer)
461 {
462  neural_network_pointer = new_neural_network_pointer;
463  data_set_pointer = NULL;
464  mathematical_model_pointer = new_mathematical_model_pointer;
466 
467  set_default();
468 }
469 
470 
471 // void set(NeuralNetwork*, MathematicalModel*, DataSet*) method
472 
479 
480 void PerformanceTerm::set(NeuralNetwork* new_neural_network_pointer, MathematicalModel* new_mathematical_model_pointer, DataSet* new_data_set_pointer)
481 {
482  neural_network_pointer = new_neural_network_pointer;
483  data_set_pointer = new_data_set_pointer;
484  mathematical_model_pointer = new_mathematical_model_pointer;
486 
487  set_default();
488 }
489 
490 
491 // void set(const PerformanceTerm&) method
492 
495 
496 void PerformanceTerm::set(const PerformanceTerm& other_performance_term)
497 {
498  neural_network_pointer = other_performance_term.neural_network_pointer;
499 
500  data_set_pointer = other_performance_term.data_set_pointer;
501 
503 
504  if(other_performance_term.numerical_differentiation_pointer)
505  {
507  }
508 
509  display = other_performance_term.display;
510 }
511 
512 
513 // void set_neural_network_pointer(NeuralNetwork*) method
514 
517 
519 {
520  neural_network_pointer = new_neural_network_pointer;
521 }
522 
523 
524 // void set_mathematical_model_pointer(MathematicalModel*) method
525 
527 
529 {
530  mathematical_model_pointer = new_mathematical_model_pointer;
531 }
532 
533 
534 // void set_data_set_pointer(DataSet*) method
535 
537 
539 {
540  data_set_pointer = new_data_set_pointer;
541 }
542 
543 
544 // void set_numerical_differentiation_pointer(NumericalDifferentiation*) method
545 
548 
550 {
551  numerical_differentiation_pointer = new_numerical_differentiation_pointer;
552 }
553 
554 
555 // void set_default(void) method
556 
561 
563 {
564  display = true;
565 }
566 
567 
568 // void set_display(const bool&) method
569 
574 
575 void PerformanceTerm::set_display(const bool& new_display)
576 {
577  display = new_display;
578 }
579 
580 
581 // void construct_numerical_differentiation(void) method
582 
584 
586 {
588  {
590  }
591 }
592 
593 
594 // void delete_numerical_differentiation_pointer(void) method
595 
597 
599 {
601 
603 }
604 
605 
606 // void check(void) const method
607 
610 
611 void PerformanceTerm::check(void) const
612 {
613  std::ostringstream buffer;
614 
616  {
617  buffer << "OpenNN Exception: PerformanceTerm class.\n"
618  << "void check(void) const.\n"
619  << "Pointer to neural network is NULL.\n";
620 
621  throw std::logic_error(buffer.str());
622  }
623 }
624 
625 
626 // Vector< Vector<double> > calculate_layers_delta(const Vector< Vector<double> >&, const Vector<double>&) method
627 
632 
634 (const Vector< Vector<double> >& layers_activation_derivative,
635  const Vector<double>& output_objective_gradient) const
636 {
637  // Neural network stuff
638 
639  #ifndef NDEBUG
640 
641  check();
642 
643  #endif
644 
645  const MultilayerPerceptron* multilayer_perceptron_pointer = neural_network_pointer->get_multilayer_perceptron_pointer();
646 
647  #ifndef NDEBUG
648 
649  std::ostringstream buffer;
650 
651  if(!multilayer_perceptron_pointer)
652  {
653  buffer << "OpenNN Exception: PerformanceTerm class.\n"
654  << "Vector< Vector<double> > calculate_layers_delta(const Vector< Vector<double> >&, const Vector<double>&) const method.\n"
655  << "Pointer to multilayer perceptron in neural network is NULL.\n";
656 
657  throw std::logic_error(buffer.str());
658  }
659 
660  #endif
661 
662  const size_t layers_number = multilayer_perceptron_pointer->get_layers_number();
663  const Vector<size_t> layers_perceptrons_number = multilayer_perceptron_pointer->arrange_layers_perceptrons_numbers();
664 
665  // Control sentence (if debug)
666 
667  #ifndef NDEBUG
668 
669  // Forward propagation activation derivative size
670 
671  const size_t layers_activation_derivative_size = layers_activation_derivative.size();
672 
673  if(layers_activation_derivative_size != layers_number)
674  {
675  buffer << "OpenNN Exception: PerformanceTerm class.\n"
676  << "Vector< Vector<double> > calculate_layers_delta(const Vector< Vector<double> >&, const Vector<double>&) method.\n"
677  << "Size of forward propagation activation derivative vector must be equal to number of layers.\n";
678 
679  throw std::logic_error(buffer.str());
680  }
681 
682  if(layers_number > 0)
683  {
684  const size_t output_objective_gradient_size = output_objective_gradient.size();
685 
686  if(output_objective_gradient_size != layers_perceptrons_number[layers_number-1])
687  {
688  buffer << "OpenNN Exception: PerformanceTerm class.\n"
689  << "Vector<double> calculate_layers_delta(const Vector< Vector<double> >&, const Vector<double>&) method.\n"
690  << "Size of outputs objective gradient (" << output_objective_gradient_size << ") must be equal to "
691  << "number of outputs (" << layers_perceptrons_number[layers_number-1] << ").\n";
692 
693  throw std::logic_error(buffer.str());
694  }
695  }
696 
697  #endif
698 
699  // Neural network stuff
700 
701  Matrix<double> layer_synaptic_weights;
702 
703  // Performance functional stuff
704 
705  Vector< Vector<double> > layers_delta(layers_number);
706 
707  // Output layer
708 
709  if(layers_number > 0)
710  {
711  layers_delta[layers_number-1] = layers_activation_derivative[layers_number-1]*output_objective_gradient;
712 
713  // Rest of hidden layers
714 
715  for(int i = (int)layers_number-2; i >= 0; i--)
716  {
717  layer_synaptic_weights = neural_network_pointer->get_multilayer_perceptron_pointer()->get_layer(i+1).arrange_synaptic_weights();
718 
719  layers_delta[i] = layers_activation_derivative[i]*(layers_delta[i+1].dot(layer_synaptic_weights));
720  }
721  }
722 
723  return(layers_delta);
724 }
725 
726 
727 // Vector< Vector<double> > calculate_layers_delta(const Vector< Vector<double> >&, const Vector<double>&, const Vector<double>&) method
728 
734 
736 (const Vector< Vector<double> >& layers_activation_derivative,
737  const Vector<double>& homogeneous_solution,
738  const Vector<double>& output_objective_gradient) const
739 {
740  const MultilayerPerceptron* multilayer_perceptron_pointer = neural_network_pointer->get_multilayer_perceptron_pointer();
741 
742  const size_t layers_number = multilayer_perceptron_pointer->get_layers_number();
743  const Vector<size_t> layers_perceptrons_number = multilayer_perceptron_pointer->arrange_layers_perceptrons_numbers();
744 
745  // Control sentence (if debug)
746 
747  #ifndef NDEBUG
748 
749  // Forward propagation activation derivative size
750 
751  const size_t layers_activation_derivative_size = layers_activation_derivative.size();
752 
753  if(layers_activation_derivative_size != layers_number)
754  {
755  std::ostringstream buffer;
756 
757  buffer << "OpenNN Exception: PerformanceTerm class.\n"
758  << "Vector< Vector<double> > calculate_layers_delta(const Vector< Vector<double> >&, const Vector<double>&) const method.\n"
759  << "Size of forward propagation activation derivative vector must be equal to number of layers.\n";
760 
761  throw std::logic_error(buffer.str());
762  }
763 
764  const size_t objective_function_output_gradient_size = output_objective_gradient.size();
765 
766  if(objective_function_output_gradient_size != layers_perceptrons_number[layers_number-1])
767  {
768  std::ostringstream buffer;
769 
770  buffer << "OpenNN Exception: PerformanceTerm class.\n"
771  << "Vector<double> calculate_layers_delta(const Vector< Vector<double> >&, const Vector<double>&) const method.\n"
772  << "Size of objective function outputs derivative (" << objective_function_output_gradient_size << ")must be equal to "
773  << "number of outputs (" << layers_perceptrons_number[layers_number-1] << ").\n";
774 
775  throw std::logic_error(buffer.str());
776  }
777 
778  #endif
779 
780  const Vector<PerceptronLayer>& layers = multilayer_perceptron_pointer->get_layers();
781 
782  Matrix<double> synaptic_weights;
783 
784  double sum;
785 
786  // Set layers delta vector of vectors
787 
788  Vector< Vector<double> > layers_delta(layers_number);
789 
790  for(size_t i = 0; i < layers_number; i++)
791  {
792  layers_delta[i].set(layers_perceptrons_number[i]);
793  }
794 
795  // Output layer
796 
797  layers_delta[layers_number-1] = layers_activation_derivative[layers_number-1]*homogeneous_solution*output_objective_gradient;
798 
799  // Rest of hidden layers
800 
801  for(int h = (int)layers_number-2; h >= 0; h--)
802  {
803  for(size_t i = 0; i < layers_perceptrons_number[h]; i++)
804  {
805  sum = 0.0;
806 
807  for(size_t j = 0; j < layers_perceptrons_number[h+1]; j++)
808  {
809  synaptic_weights = layers[h+1].arrange_synaptic_weights();
810 
811  sum += (synaptic_weights(i,j))*layers_delta[h+1][j];
812  }
813 
814  layers_delta[h][i] = layers_activation_derivative[h][i]*sum;
815  }
816  }
817 
818  return(layers_delta);
819 }
820 
821 
822 // Vector<double> calculate_point_gradient(const Vector<double>&, const Vector< Vector<double> >&, const Vector<double>&) const method
823 
828 
830 (const Vector<double>& inputs,
831  const Vector< Vector<double> >& layers_activation,
832  const Vector< Vector<double> >& layers_delta) const
833 {
834  // Control sentence (if debug)
835 
836  #ifndef NDEBUG
837 
838  check();
839 
840  #endif
841 
842  const MultilayerPerceptron* multilayer_perceptron_pointer = neural_network_pointer->get_multilayer_perceptron_pointer();
843 
844  #ifndef NDEBUG
845 
846  std::ostringstream buffer;
847 
848  if(!multilayer_perceptron_pointer)
849  {
850  buffer << "OpenNN Exception: PerformanceTerm class.\n"
851  << "Vector<double> calculate_point_gradient(const Vector<double>&, const Vector< Vector<double> >&, const Vector<double>&) const method.\n"
852  << "Pointer to multilayer perceptron is NULL.\n";
853 
854  throw std::logic_error(buffer.str());
855  }
856 
857  #endif
858 
859  const size_t inputs_number = multilayer_perceptron_pointer->get_inputs_number();
860  const size_t layers_number = multilayer_perceptron_pointer->get_layers_number();
861  const Vector<size_t> layers_perceptrons_number = multilayer_perceptron_pointer->arrange_layers_perceptrons_numbers();
862 
863  // Control sentence (if debug)
864 
865  #ifndef NDEBUG
866 
867  // Input size
868 
869  const size_t inputs_size = inputs.size();
870 
871  if(inputs_size != inputs_number)
872  {
873  buffer << "OpenNN Exception: PerformanceTerm class.\n"
874  << "Vector< Vector<double> > calculate_layers_objective_gradient(const Vector< Vector<double> >&, const Vector<double>&, const Vector<double>&) method.\n"
875  << "Size of inputs (" << inputs_size << ") must be equal to inputs number (" << inputs_number << ").\n";
876 
877  throw std::logic_error(buffer.str());
878  }
879 
880  // Forward propagation activation size
881 
882  const size_t layers_activation_size = layers_activation.size();
883 
884  if(layers_activation_size != layers_number)
885  {
886  buffer << "OpenNN Exception: PerformanceTerm class.\n"
887  << "Vector< Vector<double> > calculate_layers_objective_gradient(const Vector< Vector<double> >&, const Vector<double>&, const Vector<double>&) method.\n"
888  << "Size of forward propagation activation (" << layers_activation_size << ") must be equal to number of layers (" << layers_number << ").\n";
889 
890  throw std::logic_error(buffer.str());
891  }
892 
893  // Hidden errors size
894 
895  const size_t layers_delta_size = layers_delta.size();
896 
897  if(layers_delta_size != layers_number)
898  {
899  buffer << "OpenNN Exception: PerformanceTerm class.\n"
900  << "Vector< Vector<double> > calculate_layers_objective_gradient(const Vector< Vector<double> >&, const Vector<double>&) method.\n"
901  << "Size of layers delta ("<< layers_delta_size << ") must be equal to number of layers (" << layers_number << ").\n";
902 
903  throw std::logic_error(buffer.str());
904  }
905 
906  #endif
907 
908  const size_t parameters_number = neural_network_pointer->count_parameters_number();
909 
910  Vector<double> point_gradient(parameters_number);
911 
912  size_t index = 0;
913 
914  const Vector< Vector<double> > layers_inputs = multilayer_perceptron_pointer->arrange_layers_input(inputs, layers_activation);
915 
916  const Vector< Matrix<double> > layers_combination_parameters_Jacobian = multilayer_perceptron_pointer->calculate_layers_combination_parameters_Jacobian(layers_inputs);
917 
918  for(size_t i = 0; i < layers_number; i++)
919  {
920  point_gradient.tuck_in(index, layers_delta[i].dot(layers_combination_parameters_Jacobian[i]));
921 
922  index += multilayer_perceptron_pointer->get_layer(i).count_parameters_number();
923  }
924 
925  if(layers_number != 0)
926  {
927  Vector<double> synaptic_weights;
928 
929  size_t index = 0;
930 
931  // First layer
932 
933  for(size_t i = 0; i < layers_perceptrons_number[0]; i++)
934  {
935  // Bias
936 
937  point_gradient[index] = layers_delta[0][i];
938  index++;
939 
940  // Synaptic weights
941 
942  synaptic_weights = multilayer_perceptron_pointer->get_layer(0).get_perceptron(i).arrange_synaptic_weights();
943 
944  for(size_t j = 0; j < inputs_number; j++)
945  {
946  point_gradient[index] = layers_delta[0][i]*inputs[j];
947  index++;
948  }
949  }
950 
951  // Rest of layers
952 
953  for(size_t h = 1; h < layers_number; h++)
954  {
955  for(size_t i = 0; i < layers_perceptrons_number[h]; i++)
956  {
957  // Bias
958 
959  point_gradient[index] = layers_delta[h][i];
960  index++;
961 
962  // Synaptic weights
963 
964  synaptic_weights = multilayer_perceptron_pointer->get_layer(h).get_perceptron(i).arrange_synaptic_weights();
965 
966  for(size_t j = 0; j < layers_perceptrons_number[h-1]; j++)
967  {
968  point_gradient[index] = layers_delta[h][i]*layers_activation[h-1][j];
969  index++;
970  }
971  }
972  }
973 
974  }
975 
976  return(point_gradient);
977 }
978 
979 
980 // Vector<double> calculate_point_gradient(const Vector< Matrix<double> >&, const Vector< Vector<double> >&) const method
981 
985 
987 (const Vector< Matrix<double> >& layers_combination_parameters_Jacobian,
988  const Vector< Vector<double> >& layers_delta) const
989 {
990  // Control sentence (if debug)
991 
992  #ifndef NDEBUG
993 
994  check();
995 
996  #endif
997 
998  const MultilayerPerceptron* multilayer_perceptron_pointer = neural_network_pointer->get_multilayer_perceptron_pointer();
999 
1000  // Control sentence (if debug)
1001 
1002  #ifndef NDEBUG
1003 
1004  std::ostringstream buffer;
1005 
1006  if(!multilayer_perceptron_pointer)
1007  {
1008  buffer << "OpenNN Exception: PerformanceTerm class.\n"
1009  << "Vector<double> calculate_point_gradient(const Vector<double>&, const Vector< Vector<double> >&, const Vector<double>&) const method.\n"
1010  << "Pointer to network is NULL.\n";
1011 
1012  throw std::logic_error(buffer.str());
1013  }
1014 
1015  #endif
1016 
1017  const size_t layers_number = multilayer_perceptron_pointer->get_layers_number();
1018  const Vector<size_t> layers_size = multilayer_perceptron_pointer->arrange_layers_perceptrons_numbers();
1019 
1020  // Control sentence (if debug)
1021 
1022  #ifndef NDEBUG
1023 
1024  // Input size
1025 
1026  const size_t layers_combination_parameters_Jacobian_size = layers_combination_parameters_Jacobian.size();
1027 
1028  if(layers_combination_parameters_Jacobian_size != layers_number)
1029  {
1030  buffer << "OpenNN Exception: PerformanceTerm class.\n"
1031  << "Vector< Vector<double> > calculate_layers_objective_gradient(const Vector< Vector<double> >&, const Vector<double>&, const Vector<double>&) method.\n"
1032  << "Size of forward propagation activation (" << layers_combination_parameters_Jacobian_size << ") must be equal to number of layers (" << layers_number << ").\n";
1033 
1034  throw std::logic_error(buffer.str());
1035  }
1036 
1037  // Hidden errors size
1038 
1039  const size_t layers_delta_size = layers_delta.size();
1040 
1041  if(layers_delta_size != layers_number)
1042  {
1043  buffer << "OpenNN Exception: PerformanceTerm class.\n"
1044  << "Vector< Vector<double> > calculate_layers_objective_gradient(const Vector< Vector<double> >&, const Vector<double>&) method.\n"
1045  << "Size of layers delta ("<< layers_delta_size << ") must be equal to number of layers (" << layers_number << ").\n";
1046 
1047  throw std::logic_error(buffer.str());
1048  }
1049 
1050  #endif
1051 
1052  const size_t parameters_number = multilayer_perceptron_pointer->count_parameters_number();
1053 
1054  Vector<double> point_gradient(parameters_number);
1055 
1056  size_t index = 0;
1057 
1058  for(size_t i = 0; i < layers_number; i++)
1059  {
1060  point_gradient.tuck_in(index, layers_delta[i].dot(layers_combination_parameters_Jacobian[i]));
1061 
1062  index += neural_network_pointer->get_multilayer_perceptron_pointer()->get_layer(i).count_parameters_number();
1063  }
1064 
1065  return(point_gradient);
1066 }
1067 
1068 
1069 // Matrix< Matrix<double> > calculate_interlayers_Delta(const Vector< Vector<double> >&, const Vector< Vector<double> >&, const Vector<double>&, const Matrix<double>&, const Vector< Vector<double> >&) method
1070 
1080 
1082 (const Vector< Vector<double> >& layers_activation_derivative,
1083  const Vector< Vector<double> >& layers_activation_second_derivative,
1084  const Matrix< Matrix<double> >& interlayers_combination_combination_Jacobian_form,
1085  const Vector<double>& output_objective_gradient,
1086  const Matrix<double>& output_objective_Hessian,
1087  const Vector< Vector<double> >& layers_delta) const
1088 {
1089  // Neural network stuff
1090 
1091  #ifndef NDEBUG
1092 
1093  check();
1094 
1095  #endif
1096 
1097  const MultilayerPerceptron* multilayer_perceptron_pointer = neural_network_pointer->get_multilayer_perceptron_pointer();
1098 
1099  #ifndef NDEBUG
1100 
1101  std::ostringstream buffer;
1102 
1103  if(!multilayer_perceptron_pointer)
1104  {
1105  buffer << "OpenNN Exception: PerformanceTerm class.\n"
1106  << "Matrix< Matrix<double> > calculate_interlayers_Delta() method.\n"
1107  << "Multilayer perceptron pointer is NULL.\n";
1108 
1109  throw std::logic_error(buffer.str());
1110  }
1111 
1112  #endif
1113 
1114  const size_t layers_number = multilayer_perceptron_pointer->get_layers_number();
1115  const Vector<size_t> layers_size = multilayer_perceptron_pointer->arrange_layers_perceptrons_numbers();
1116 
1117  // Control sentence (if debug)
1118 
1119  #ifndef NDEBUG
1120 
1121  if(layers_number != 0)
1122  {
1123  const size_t output_objective_gradient_size = output_objective_gradient.size();
1124 
1125  if(output_objective_gradient_size != layers_size[layers_number-1])
1126  {
1127  buffer << "OpenNN Exception: PerformanceTerm class.\n"
1128  << "Vector<double> calculate_interlayers_Delta() method.\n"
1129  << "Size of layer " << layers_number-1 << " must be equal to size of output objective gradient (" << output_objective_gradient_size << ")."
1130  << std::endl;
1131 
1132  throw std::logic_error(buffer.str());
1133  }
1134 
1135  const size_t output_objective_Hessian_rows_number = output_objective_Hessian.get_rows_number();
1136  const size_t output_objective_Hessian_columns_number = output_objective_Hessian.get_columns_number();
1137 
1138  if(output_objective_Hessian_rows_number != layers_size[layers_number-1])
1139  {
1140  buffer << "OpenNN Exception: PerformanceTerm class.\n"
1141  << "Vector<double> calculate_interlayers_Delta() method.\n"
1142  << "Size of layer " << layers_number-1 << " must be equal to number of rows in output objective Hessian (" << output_objective_Hessian_rows_number << ")."
1143  << std::endl;
1144 
1145  throw std::logic_error(buffer.str());
1146  }
1147 
1148  if(output_objective_Hessian_columns_number != layers_size[layers_number-1])
1149  {
1150  buffer << "OpenNN Exception: PerformanceTerm class.\n"
1151  << "Vector<double> calculate_interlayers_Delta() method.\n"
1152  << "Size of layer " << layers_number-1 << ") must be equal to number of columns in output objective Hessian (" << output_objective_Hessian_columns_number << ")."
1153  << std::endl;
1154 
1155  throw std::logic_error(buffer.str());
1156  }
1157  }
1158 
1159  #endif
1160 
1161  const Vector< Matrix<double> > layers_synaptic_weights = multilayer_perceptron_pointer->arrange_layers_synaptic_weights();
1162 
1163  // Objective functional stuff
1164 
1165  Matrix< Matrix<double> > interlayers_Delta(layers_number, layers_number);
1166 
1167  for(size_t i = 0; i < layers_number; i++)
1168  {
1169  for(size_t j = 0; j < layers_number; j++)
1170  {
1171  interlayers_Delta(i,j).set(layers_size[i], layers_size[j]);
1172  }
1173  }
1174 
1175  // @todo
1176 
1177  if(layers_number > 0)
1178  {
1179  // Output-outputs layer
1180 
1181  interlayers_Delta(layers_number-1,layers_number-1) = (output_objective_Hessian*(layers_activation_derivative[layers_number-1]*layers_activation_derivative[layers_number-1])).sum_diagonal(output_objective_gradient*layers_activation_second_derivative[layers_number-1]);
1182 
1183  // Rest of hidden layers
1184 
1185  for(int i = (int)layers_number-1; i >= 0; i--)
1186  {
1187  for(int j = (int)layers_number-1; j >= 0; j--)
1188  {
1189  if((int)i != (int)layers_number-1 && (int)j != (int)layers_number-1)
1190  {
1191  interlayers_Delta(i,j)
1192  = layers_activation_second_derivative[j]
1193  *interlayers_combination_combination_Jacobian_form(i,j)
1194  *(layers_delta[j+1].dot(layers_synaptic_weights[j+1]))
1195  + layers_activation_second_derivative[j]
1196  *(interlayers_Delta(i,j+1).dot(layers_synaptic_weights[j+1]));
1197  }
1198  }
1199  }
1200  }
1201 
1202  return(interlayers_Delta);
1203 }
1204 
1205 
1206 // Matrix<double> calculate_point_Hessian(const Vector<double>&, const Matrix< Matrix<double> >&, const Vector< Vector<double> >&, const Matrix< Matrix<double> >&) const method
1207 
1215 
1217 (const Vector< Vector<double> >& layers_activation_derivative,
1218  const Vector< Vector< Vector<double> > >& perceptrons_combination_parameters_gradient,
1219  const Matrix< Matrix<double> >& interlayers_combination_combination_Jacobian,
1220  const Vector< Vector<double> >& layers_delta,
1221  const Matrix< Matrix<double> >& interlayers_Delta) const
1222 {
1223  // Neural network stuff
1224 
1225  #ifndef NDEBUG
1226 
1227  check();
1228 
1229  #endif
1230 
1231  const MultilayerPerceptron* multilayer_perceptron_pointer = neural_network_pointer->get_multilayer_perceptron_pointer();
1232 
1233  #ifndef NDEBUG
1234 
1235  std::ostringstream buffer;
1236 
1237  if(!multilayer_perceptron_pointer)
1238  {
1239  buffer << "OpenNN Exception: PerformanceTerm class.\n"
1240  << "Matrix<double> calculate_point_Hessian(const Vector<double>&, const Matrix< Matrix<double> >&, const Vector< Vector<double> >&, const Matrix< Matrix<double> >&) const method.\n"
1241  << "Multilayer perceptron pointer is NULL.\n";
1242 
1243  throw std::logic_error(buffer.str());
1244  }
1245 
1246  #endif
1247 
1248  const size_t layers_number = multilayer_perceptron_pointer->get_layers_number();
1249 
1250  const size_t parameters_number = multilayer_perceptron_pointer->count_parameters_number();
1251 
1252  #ifndef NDEBUG
1253 
1254  const size_t layers_activation_derivative_size = layers_activation_derivative.size();
1255 
1256  if(layers_activation_derivative_size != layers_number)
1257  {
1258  buffer << "OpenNN Exception: PerformanceTerm class.\n"
1259  << "Matrix<double> calculate_point_Hessian(const Vector<double>&, const Matrix< Matrix<double> >&, const Vector< Vector<double> >&, const Matrix< Matrix<double> >&) const method.\n"
1260  << "Size of layers activation derivative must be equal to number of layers in multilayer perceptron.\n";
1261 
1262  throw std::logic_error(buffer.str());
1263  }
1264 
1265 // const size_t perceptrons_combination_parameters_gradient_size = perceptrons_combination_parameters_gradient.size();
1266 
1267 // const size_terlayers_combination_combination_Jacobian_rows_number = interlayers_combination_combination_Jacobian.get_rows_number();
1268 // const size_terlayers_combination_combination_Jacobian_columns_number = interlayers_combination_combination_Jacobian.get_columns_number();
1269 
1270 // const size_t layers_delta_size = layers_delta.size();
1271 
1272 // const size_terlayers_Delta_rows_number = interlayers_Delta.get_rows_number();
1273 // const size_terlayers_Delta_columns_number = interlayers_Delta.get_columns_number();
1274 
1275  #endif
1276 
1277  // Objective functional
1278 
1279  Matrix<double> point_Hessian(parameters_number, parameters_number, 0.0);
1280 
1281  Vector<size_t> parameter_indices(3);
1282 
1283  size_t layer_index_i;
1284  size_t neuron_index_i;
1285  size_t parameter_index_i;
1286 
1287  size_t layer_index_j;
1288  size_t neuron_index_j;
1289  size_t parameter_index_j;
1290 
1291  // @todo
1292 
1293 
1294  if(layers_number > 0)
1295  {
1296  for(size_t i = 0; i < parameters_number; i++)
1297  {
1298  parameter_indices = multilayer_perceptron_pointer->arrange_parameter_indices(i);
1299  layer_index_i = parameter_indices[0];
1300  neuron_index_i = parameter_indices[1];
1301  parameter_index_i = parameter_indices[2];
1302 
1303  for(size_t j = 0; j < parameters_number; j++)
1304  {
1305  parameter_indices = multilayer_perceptron_pointer->arrange_parameter_indices(j);
1306  layer_index_j = parameter_indices[0];
1307  neuron_index_j = parameter_indices[1];
1308  parameter_index_j = parameter_indices[2];
1309 
1310  point_Hessian(i,j)
1311  = perceptrons_combination_parameters_gradient[layer_index_i][neuron_index_i][parameter_index_i]
1312  *perceptrons_combination_parameters_gradient[layer_index_j][neuron_index_j][parameter_index_j]
1313  *interlayers_Delta(layer_index_j,layer_index_i)(neuron_index_j,neuron_index_i)
1314  + perceptrons_combination_parameters_gradient[layer_index_i][neuron_index_i][parameter_index_i]
1315  *layers_delta[layer_index_j][neuron_index_j]
1316  *layers_activation_derivative[layer_index_j][neuron_index_j]
1317  *interlayers_combination_combination_Jacobian(layer_index_j,layer_index_i)(neuron_index_j,neuron_index_i);
1318  }
1319  }
1320 
1321  for(size_t i = 0; i < parameters_number; i++)
1322  {
1323  for(size_t j = 0; j < i; j++)
1324  {
1325  point_Hessian(i,j) = point_Hessian(j,i);
1326  }
1327  }
1328  }
1329 
1330  return(point_Hessian);
1331 }
1332 
1333 
1334 // Vector<double> calculate_gradient(void) const method
1335 
1338 
1340 {
1341  // Neural network stuff
1342 
1343  #ifndef NDEBUG
1344 
1345  check();
1346 
1347  #endif
1348 
1349  // Performance functional stuff
1350 
1351  #ifndef NDEBUG
1352 
1353  std::ostringstream buffer;
1354 
1356  {
1357  buffer << "OpenNN Exception: PerformanceTerm class.\n"
1358  << "Vector<double> calculate_gradient(void) const method.\n"
1359  << "Numerical differentiation pointer is NULL.\n";
1360 
1361  throw std::logic_error(buffer.str());
1362  }
1363 
1364  #endif
1365 
1367 
1369 }
1370 
1371 
1372 // Vector<double> calculate_gradient(const Vector<double>&) const method
1373 
1376 
1378 {
1379  // Neural network stuff
1380 
1381  #ifndef NDEBUG
1382 
1383  check();
1384 
1385  #endif
1386 
1387  // Performance functional stuff
1388 
1389  #ifndef NDEBUG
1390 
1391  std::ostringstream buffer;
1392 
1394  {
1395  buffer << "OpenNN Exception: PerformanceTerm class.\n"
1396  << "Vector<double> calculate_gradient(const Vector<double>&) const method.\n"
1397  << "Numerical differentiation pointer is NULL.\n";
1398 
1399  throw std::logic_error(buffer.str());
1400  }
1401 
1402  #endif
1403 
1405 }
1406 
1407 
1408 // Matrix<double> calculate_Hessian(void) const method
1409 
1411 
1413 {
1414  // Neural network stuff
1415 
1416  #ifndef NDEBUG
1417 
1418  check();
1419 
1420  #endif
1421 
1423 
1425 }
1426 
1427 
1428 // Matrix<double> calculate_Hessian(const Vector<double>&) const method
1429 
1431 
1433 {
1434  // Neural network stuff
1435 
1436  #ifndef NDEBUG
1437 
1438  check();
1439 
1440  #endif
1441 
1443 }
1444 
1445 
1446 // Vector<double> calculate_terms(void) const method
1447 
1449 
1451 {
1452  std::ostringstream buffer;
1453 
1454  buffer << "OpenNN Exception: PerformanceTerm class.\n"
1455  << "Vector<double> calculate_terms(void) const method.\n"
1456  << "The terms function is not defined for this performance term.\n";
1457 
1458  throw std::logic_error(buffer.str());
1459 }
1460 
1461 
1462 // Vector<double> calculate_terms(const Vector<double>&) const method
1463 
1465 
1467 {
1468  std::ostringstream buffer;
1469 
1470  buffer << "OpenNN Exception: PerformanceTerm class.\n"
1471  << "Vector<double> calculate_terms(const Vector<double>&) const method.\n"
1472  << "The terms function is not defined for this performance term.\n";
1473 
1474  throw std::logic_error(buffer.str());
1475 }
1476 
1477 
1478 // Matrix<double> calculate_terms_Jacobian(void) const method
1479 
1481 
1483 {
1484  std::ostringstream buffer;
1485 
1486  buffer << "OpenNN Exception: PerformanceTerm class.\n"
1487  << "Matrix<double> calculate_terms_Jacobian(void) const method.\n"
1488  << "The terms function is not defined for this performance term.\n";
1489 
1490  throw std::logic_error(buffer.str());
1491 }
1492 
1493 
1494 // PerformanceTerm::FirstOrderTerms calculate_first_order_terms(void) const
1495 
1497 
1499 {
1500  std::ostringstream buffer;
1501 
1502  buffer << "OpenNN Exception: PerformanceTerm class.\n"
1503  << "Vector<double> calculate_terms(void) const method.\n"
1504  << "The terms function is not defined for this performance term.\n";
1505 
1506  throw std::logic_error(buffer.str());
1507 }
1508 
1509 
1510 // std::string write_performance_term_type(void) const method
1511 
1513 
1515 {
1516  return("USER_PERFORMANCE_TERM");
1517 }
1518 
1519 
1520 // std::string write_information(void) const method
1521 
1525 
1526 std::string PerformanceTerm::write_information(void) const
1527 {
1528  return("");
1529 }
1530 
1531 
1532 // std::string to_string(void) const method
1533 
1535 
1536 std::string PerformanceTerm::to_string(void) const
1537 {
1538  std::ostringstream buffer;
1539 
1540  buffer << "Performance term\n"
1541  << "Display: " << display << "\n";
1542 
1543  return(buffer.str());
1544 }
1545 
1546 
1547 // tinyxml2::XMLDocument* to_XML(void) const method
1548 
1551 
1552 tinyxml2::XMLDocument* PerformanceTerm::to_XML(void) const
1553 {
1554  std::ostringstream buffer;
1555 
1556  tinyxml2::XMLDocument* document = new tinyxml2::XMLDocument;
1557 
1558  // Performance term
1559 
1560  tinyxml2::XMLElement* root_element = document->NewElement("PerformanceTerm");
1561 
1562  document->InsertFirstChild(root_element);
1563 
1564  return(document);
1565 }
1566 
1567 
1568 // void from_XML(const tinyxml2::XMLDocument&) method
1569 
1572 
1573 void PerformanceTerm::from_XML(const tinyxml2::XMLDocument& document)
1574 {
1575  // Display warnings
1576 
1577  const tinyxml2::XMLElement* display_element = document.FirstChildElement("Display");
1578 
1579  if(display_element)
1580  {
1581  std::string new_display_string = display_element->GetText();
1582 
1583  try
1584  {
1585  set_display(new_display_string != "0");
1586  }
1587  catch(const std::logic_error& e)
1588  {
1589  std::cout << e.what() << std::endl;
1590  }
1591  }
1592 }
1593 
1594 
1595 // size_t calculate_Kronecker_delta(const size_t&, const size_t&) const method
1596 
1600 
1601 size_t PerformanceTerm::calculate_Kronecker_delta(const size_t& a, const size_t& b) const
1602 {
1603  if(a == b)
1604  {
1605  return(1);
1606  }
1607  else
1608  {
1609  return(0);
1610  }
1611 }
1612 
1613 }
1614 
1615 
1616 // OpenNN: Open Neural Networks Library.
1617 // Copyright (c) 2005-2015 Roberto Lopez.
1618 //
1619 // This library is free software; you can redistribute it and/or
1620 // modify it under the terms of the GNU Lesser General Public
1621 // License as published by the Free Software Foundation; either
1622 // version 2.1 of the License, or any later version.
1623 //
1624 // This library is distributed in the hope that it will be useful,
1625 // but WITHOUT ANY WARRANTY; without even the implied warranty of
1626 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1627 // Lesser General Public License for more details.
1628 
1629 // You should have received a copy of the GNU Lesser General Public
1630 // License along with this library; if not, write to the Free Software
1631 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
void set_numerical_differentiation_pointer(NumericalDifferentiation *)
size_t calculate_Kronecker_delta(const size_t &, const size_t &) const
Matrix< double > calculate_Hessian(const T &t, double(T::*f)(const Vector< double > &) const, const Vector< double > &x) const
const Vector< PerceptronLayer > & get_layers(void) const
virtual tinyxml2::XMLDocument * to_XML(void) const
bool has_data_set(void) const
virtual std::string write_performance_term_type(void) const
Returns a string with the default type of performance term, "USER_PERFORMANCE_TERM".
Vector< double > arrange_parameters(void) const
MathematicalModel * mathematical_model_pointer
Pointer to a mathematical model object.
Matrix< Matrix< double > > calculate_interlayers_Delta(const Vector< Vector< double > > &, const Vector< Vector< double > > &, const Matrix< Matrix< double > > &, const Vector< double > &, const Matrix< double > &, const Vector< Vector< double > > &) const
Vector< double > calculate_gradient(const T &t, double(T::*f)(const Vector< double > &) const, const Vector< double > &x) const
size_t count_parameters_number(void) const
Returns the number of parameters (biases and synaptic weights) of the layer.
virtual Vector< double > calculate_gradient(void) const
Returns the performance term gradient.
size_t get_inputs_number(void) const
Returns the number of inputs to the multilayer perceptron.
Vector< double > calculate_point_gradient(const Vector< double > &, const Vector< Vector< double > > &, const Vector< Vector< double > > &) const
virtual void set_data_set_pointer(DataSet *)
Sets a new data set on which the performance term is to be measured.
virtual PerformanceTerm::FirstOrderTerms calculate_first_order_terms(void) const
Returns the performance of all the subterms composing the performance term.
void set(void)
Sets the size of a vector to zero.
Definition: vector.h:656
size_t get_layers_number(void) const
Returns the number of layers in the multilayer perceptron.
Vector< size_t > arrange_layers_perceptrons_numbers(void) const
Returns a vector with the size of each layer.
virtual void check(void) const
virtual std::string to_string(void) const
Returns the default string representation of a performance term.
virtual double calculate_performance(void) const =0
Returns the performance value of the performance term.
void set_display(const bool &)
Vector< size_t > arrange_parameter_indices(const size_t &) const
bool has_neural_network(void) const
virtual bool operator==(const PerformanceTerm &) const
const size_t & get_columns_number(void) const
Returns the number of columns in the matrix.
Definition: matrix.h:1090
virtual void set_neural_network_pointer(NeuralNetwork *)
virtual Matrix< double > calculate_terms_Jacobian(void) const
Returns the Jacobian matrix of the subterms composing the performance term.
const PerceptronLayer & get_layer(const size_t &) const
virtual Vector< double > calculate_terms(void) const
Returns the performance of all the subterms composing the performance term.
virtual Matrix< double > calculate_Hessian(void) const
Returns the performance term Hessian.
void construct_numerical_differentiation(void)
This method constructs the numerical differentiation object which composes the performance term class...
const Perceptron & get_perceptron(const size_t &) const
Vector< Matrix< double > > calculate_layers_combination_parameters_Jacobian(const Vector< Vector< double > > &) const
virtual void set_mathematical_model_pointer(MathematicalModel *)
Sets a new mathematical model on which the performance term is to be measured.
NeuralNetwork * neural_network_pointer
Pointer to a multilayer perceptron object.
NumericalDifferentiation * numerical_differentiation_pointer
Numerical differentiation object.
virtual std::string write_information(void) const
void tuck_in(const size_t &, const Vector< T > &)
Definition: vector.h:4891
Matrix< double > calculate_point_Hessian(const Vector< Vector< double > > &, const Vector< Vector< Vector< double > > > &, const Matrix< Matrix< double > > &, const Vector< Vector< double > > &, const Matrix< Matrix< double > > &) const
double dot(const Vector< double > &) const
Definition: vector.h:3654
void set(void)
This method set the numbers of rows and columns of the matrix to zero.
Definition: matrix.h:1101
const size_t & get_rows_number(void) const
Returns the number of rows in the matrix.
Definition: matrix.h:1079
const Vector< double > & arrange_synaptic_weights(void) const
Returns the synaptic weight values of the neuron.
Definition: perceptron.cpp:212
bool display
Display messages to screen.
Vector< double > dot(const Vector< double > &) const
Definition: matrix.h:5772
virtual void from_XML(const tinyxml2::XMLDocument &)
DataSet * data_set_pointer
Pointer to a data set object.
virtual void set_default(void)
void delete_numerical_differentiation_pointer(void)
This method deletes the numerical differentiation object which composes the performance term class...
Matrix< T > sum_diagonal(const T &) const
Definition: matrix.h:1992
bool has_mathematical_model(void) const
const bool & get_display(void) const
Vector< Vector< double > > calculate_layers_delta(const Vector< Vector< double > > &, const Vector< double > &) const
bool has_numerical_differentiation(void) const
Vector< Matrix< double > > arrange_layers_synaptic_weights(void) const
Vector< Vector< double > > arrange_layers_input(const Vector< double > &, const Vector< Vector< double > > &) const
virtual PerformanceTerm & operator=(const PerformanceTerm &)
size_t count_parameters_number(void) const
Returns the number of parameters (biases and synaptic weights) in the multilayer perceptron.