home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 624a.lha / Neural_Network_v2.0 / neural_network.h < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-28  |  15.2 KB  |  323 lines

  1.  
  2. #ifndef _NEURAL_NETWORK_H_
  3. #define _NEURAL_NETWORK_H_
  4.  
  5. #include <String.h>
  6.  
  7. #define SLOPE    1.0
  8. #define S(x)    (1.0 / (1.0 + exp (0.0 - SLOPE*(x))))
  9.  
  10. #define WRONG    0
  11. #define GOOD     1
  12. #define CORRECT  2
  13.  
  14.  
  15. //****************************************************************************
  16. //
  17. // Neural_network class:
  18. //
  19. //      This class performs all the necessary functions needed to train
  20. //      a Neural Network.  The network has an input layer, two hidden
  21. //      layers, and an output layer.  The size of each layer is specified
  22. //      a run time so there is no restriction on size except memory.
  23. //      This is a feed-forward network with full connctions from one
  24. //      layer to the next.
  25. //
  26. //      The network can perform straight back-propagation with no
  27. //      modifications (Rumelhart, Hinton, and Williams, 1985) which
  28. //      will find a solution but not very quickly.  The network can also
  29. //      perform back-propagation with the delta-bar-delta rule developed
  30. //      by Robert A. Jacobs, University of Massachusetts
  31. //      (Neural Networks, Vol 1. pp.295-307, 1988).  The basic idea of this
  32. //      rule is that every weight has its own learning rate and each
  33. //      learning rate should be continously changed according to the
  34. //      following rules -
  35. //      - If the weight changes in the same direction as the previous update,
  36. //        then the learning rate for that weight should increase by a constant.
  37. //      - If the weight changes in the opposite direction as the previous
  38. //        update, then the learning rate for that weight should decrease
  39. //        exponentially.
  40. //
  41. //      learning rate = e(t) for each individual weight
  42. //      The exact formula for the change in learning rate (DELTA e(t)) is
  43. //
  44. //
  45. //                   | K          if DELTA_BAR(t-1)*DELTA(t) > 0
  46. //      DELTA e(t) = | -PHI*e(t)  if DELTA_BAR(t-1)*DELTA(t) < 0
  47. //                   | 0          otherwise
  48. //
  49. //      where DELTA(t) = dJ(t) / dw(t) ---> Partial derivative
  50. //
  51. //      and DELTA_BAR(t) = (1 - THETA)*DELTA(t) + THETA*DELTA_BAR(t-1).
  52. //
  53. //      For full details of the algorithm, read the article in
  54. //      Neural Networks.
  55. //
  56. //
  57. //      To perform straight back-propagation, just construct a Neural_network
  58. //      with no learning parameters specified (they default to straight
  59. //      back-propagation) or set them to
  60. //      K = 0, PHI = 0, THETA = 1.0
  61. //
  62. //      However, using the delta-bar-delta rule should increase your rate of
  63. //      convergence by a factor of 10 to 100 generally.  The parameters for
  64. //      the delta-bar-delta rule I use are
  65. //      K = 0.025, PHI = 0.2, THETA = 0.8
  66. //
  67. //      One more heuristic method has been employed in this Neural net class-
  68. //      the skip heuristic.  This is something I thought of and I am sure
  69. //      other people have also.  If the output activation is within
  70. //      skip_epsilon of its desired for each output, then the calc_forward
  71. //      routine returns the skip_flag = 1.  This allows you to not waste
  72. //      time trying to push already very close examples to the exact value.
  73. //      If the skip_flag comes back '1', then don't bother calculating forward
  74. //      or back-propagating the example for X number of epochs.  You must
  75. //      write the routine to skip the example yourself, but the Neural_network
  76. //      will tell you when to skip the example.  This heuristic also has the
  77. //      advantage of reducing memorization and increases generalization.
  78. //      Typical values I use for this heuristic -
  79. //      skip_epsilon = 0.01 - 0.05
  80. //      number skipped = 2-10.
  81. //
  82. //      Experiment with all the values to see which work best for your
  83. //      application.
  84. //
  85. //
  86. //      Comments and suggestions are welcome and can be emailed to me
  87. //      anstey@sun.soe.clarkson.edu
  88. //
  89. //****************************************************************************
  90.  
  91.  
  92.  
  93.  
  94.  
  95. class Neural_network {
  96. private:
  97.   //  We need
  98.   //
  99.   //  Matrix for hidden layer 1 activation [num_hidden1]
  100.   //  Matrix for hidden layer 2 activation [num_hidden2]
  101.   //  Matrix for output layer activation [num_outputs]
  102.   //
  103.   //  Matrix for input to first hidden layer weights [num_inputs] [num_hidden1]
  104.   //  Matrix for hidden layer 1 to hidden layer 2 weights [hidden1] [hidden2]
  105.   //  Matrix for hidden layer 2 to output layer weights [hidden2] [outputs]
  106.  
  107.   //  3 Matrices for sum of all the deltas in an epoch - Back propagation
  108.   //  2 Matrices for sum of deltas * weight for each neuron in hidden layers
  109.   //    1 and 2 for backpropagation - Back propagation
  110.   //
  111.   //  3 Matrices for each weight's learning rate - delta-bar-delta rule
  112.   //  3 Matrices for each weight's learning delta - delta-bar-delta rule
  113.   //  3 Matrices for each weight's learning delta_bar - delta-bar-delta rule
  114.  
  115.   int     num_inputs;
  116.   int     num_hidden1;
  117.   int     num_hidden2;
  118.   int     num_outputs;
  119.  
  120.   double  epsilon;
  121.   double  skip_epsilon;
  122.   double  learning_rate;
  123.   double  theta;
  124.   double  phi;
  125.   double  K;
  126.   long    training_examples;
  127.   long    examples_since_update;
  128.  
  129.   double  *hidden1_act;
  130.   double  *hidden2_act;
  131.   double  *output_act;
  132.  
  133.   double  *input_weights;
  134.   double  *hidden1_weights;
  135.   double  *hidden2_weights;
  136.  
  137.   double  *input_learning_rate;
  138.   double  *hidden1_learning_rate;
  139.   double  *hidden2_learning_rate;
  140.  
  141.   double  *input_learning_delta;
  142.   double  *hidden1_learning_delta;
  143.   double  *hidden2_learning_delta;
  144.  
  145.   double  *input_learning_delta_bar;
  146.   double  *hidden1_learning_delta_bar;
  147.   double  *hidden2_learning_delta_bar;
  148.  
  149.   double  *input_weights_sum_delta;
  150.   double  *hidden1_weights_sum_delta;
  151.   double  *hidden2_weights_sum_delta;
  152.  
  153.   double  *hidden1_sum_delta_weight;
  154.   double  *hidden2_sum_delta_weight;
  155.  
  156.   void    allocate_matrices ();
  157.   void    initialize_matrices (double range);
  158.   void    deallocate_matrices ();
  159.  
  160. public:
  161.  
  162.   //***********************************************************************
  163.   // Constructors :                                                       *
  164.   //    Full size specifications and learning parameters.                 *
  165.   //         Learning parameters are provided defaults which are set to   *
  166.   //         just use the BP algorithm with no modifications.             *
  167.   //                                                                      *
  168.   //    Read constructor which reads in the size and all the weights from *
  169.   //         a file.  The network is resized to match the size specified  *
  170.   //         by the file.  Learning parameters must be specified          *
  171.   //         separately.                                                  *
  172.   //***********************************************************************
  173.  
  174.   Neural_network (int number_inputs = 1, int number_hidden1 = 1,
  175.                   int number_hidden2 = 1,
  176.                   int number_outputs = 1, double t_epsilon = 0.1,
  177.                   double t_skip_epsilon = 0.0, double t_learning_rate = 0.1,
  178.                   double t_theta = 1.0, double t_phi = 0.0, double t_K = 0.0,
  179.                   double range = 3.0);
  180.   Neural_network (String& filename, int& file_error, double t_epsilon = 0.1,
  181.                   double t_skip_epsilon = 0.0, double t_learning_rate = 0.1,
  182.                   double t_theta = 1.0, double t_phi = 0.0, double t_K = 0.0);
  183.   ~Neural_network () { deallocate_matrices ();};
  184.  
  185.  
  186.   //**************************************************************************
  187.   // Weight parameter routines:                                              *
  188.   //     save_weights : This routine saves the weights of the network        *
  189.   //          to the file <filename>.                                        *
  190.   //                                                                         *
  191.   //     read_weights : This routine reads the weight values from the file   *
  192.   //          <filename>.  The network is automatically resized to the       *
  193.   //          size specified by the file.                                    *
  194.   //                                                                         *
  195.   //     Activation routines return the node activation after a calc_forward *
  196.   //          has been performed.                                            *
  197.   //                                                                         *
  198.   //     get_weight routines return the weight between node1 and node2.      *
  199.   //                                                                         *
  200.   //**************************************************************************
  201.  
  202.   int    save_weights (String& filename);
  203.   int    read_weights (String& filename);
  204.  
  205.   double get_hidden1_activation (int node) { return (hidden1_act [node]); };
  206.   double get_hidden2_activation (int node) { return (hidden2_act [node]); };
  207.   double get_output_activation (int node) { return (output_act [node]); };
  208.  
  209.   double get_input_weight (int input_node, int hidden1_node) {
  210.          return (input_weights [hidden1_node * num_inputs + input_node]);};
  211.   double get_hidden1_weight (int hidden1_node, int hidden2_node) {
  212.          return (hidden1_weights [hidden2_node * num_hidden1 + hidden1_node]);};
  213.   double get_hidden2_weight (int hidden2_node, int output_node) {
  214.          return (hidden2_weights [output_node * num_hidden2 + hidden2_node]);};
  215.  
  216.  
  217.   //*******************************************************************
  218.   // Size parameters of network.                                      *
  219.   // The size of the network may be changed at any time.  The weights *
  220.   // will be copied from the old size to the new size.  If the new    *
  221.   // size is larger, then the extra weights will be randomly set      *
  222.   // between +-range.  The matrices used to hold learning updates     *
  223.   // and activations will be re-initialized (cleared).                *
  224.   //*******************************************************************
  225.  
  226.   int get_number_of_inputs () { return (num_inputs); };
  227.   int get_number_of_hidden1 () { return (num_hidden1); };
  228.   int get_number_of_hidden2 () { return (num_hidden2); };
  229.   int get_number_of_outputs () { return (num_outputs); };
  230.   void set_size_parameters (int number_inputs, int number_hidden1,
  231.                             int number_hidden2, int number_outputs,
  232.                             double range = 3.0);
  233.  
  234.  
  235.   //*******************************************************************
  236.   // Learning parameters functions.  These parameters may be changed  *
  237.   // on the fly.  The learning rate and K may have to be reduced as   *
  238.   // more and more training is done to prevent oscillations.          *
  239.   //*******************************************************************
  240.  
  241.   void set_epsilon (double eps) { epsilon = eps; };
  242.   void set_skip_epsilon (double eps) { skip_epsilon = eps; };
  243.   void set_learning_rate (double l_rate) { learning_rate = l_rate; };
  244.   void set_theta (double t_theta) { theta = t_theta; };
  245.   void set_phi (double t_phi) { phi = t_phi; };
  246.   void set_K (double t_K) { K = t_K; };
  247.  
  248.   double get_epsilon () { return (epsilon); };
  249.   double get_skip_epsilon () { return (skip_epsilon); };
  250.   double get_learning_rate () { return (learning_rate); };
  251.   double get_theta () { return (theta); };
  252.   double get_phi () { return (phi); };
  253.   double get_K () { return (K); };
  254.   long   get_iterations () { return (training_examples); };
  255.  
  256.  
  257.   //**************************************************************************
  258.   // The main neural network routines:                                       *
  259.   //                                                                         *
  260.   //      The network input is an array of doubles which has a size of       *
  261.   //           number_inputs.                                                *
  262.   //      The network desired output is an array of doubles which has a size *
  263.   //           of number_outputs.                                            *
  264.   //                                                                         *
  265.   //      back_propagation : Calculates how each weight should be changed.   *
  266.   //           Assumes that calc_forward has been called just prior to       *
  267.   //           this routine to calculate all of the node activations.        *
  268.   //                                                                         *
  269.   //      calc_forward : Calculates the output for a given input.  Finds     *
  270.   //           all node activations which are needed for back_propagation    *
  271.   //           to calculate weight adjustment.  Returns abs (error).         *
  272.   //           The parameter skip is for use with the skip_epsilon           *
  273.   //           parameter.  What it means is if the output is within          *
  274.   //           skip_epsilon of the desired, then it is so close that it      *
  275.   //           should be skipped from being calculated the next X times.     *
  276.   //           Careful use of this parameter can significantly increase      *
  277.   //           the rate of convergence and also help prevent over-learning.  *
  278.   //                                                                         *
  279.   //      calc_forward_test : Calculates the output for a given input.  This *
  280.   //           routine is used for testing rather than training.  It returns *
  281.   //           whether the test was CORRECT, GOOD or WRONG which is          *
  282.   //           determined by the parameters correct_epsilon and              *
  283.   //           good_epsilon.  CORRECT > GOOD > WRONG.                        *
  284.   //                                                                         *
  285.   //      update_weights : Actually adjusts all the weights according to     *
  286.   //           the calculations of back_propagation.  This routine should    *
  287.   //           be called at the end of every training epoch.  The weights    *
  288.   //           can be updated by the straight BP algorithm, or by the        *
  289.   //           delta-bar-delta algorithm developed by Robert A. Jacobs       *
  290.   //           which increases the rate of convergence generally by at       *
  291.   //           least a factor of 10.  The parameters THETA, PHI, and K       *
  292.   //           determine which algorithm is used.  The default settings      *
  293.   //           for these parameters cause update_weights to use the straight *
  294.   //           BP algorithm.                                                 *
  295.   //                                                                         *
  296.   //      kick_weights : This routine changes all weights by a random amount *
  297.   //           within +-range.  It is useful in case the network gets        *
  298.   //           'stuck' and is having trouble converging to a solution.  I    *
  299.   //           use it when the number wrong has not changed for the last 200 *
  300.   //           epochs.  Getting the range right will take some trial and     *
  301.   //           error as it depends on the application and the weights'       *
  302.   //           actual values.                                                *
  303.   //                                                                         *
  304.   //**************************************************************************
  305.  
  306.   void back_propagation (double input [], double desired_output [],
  307.                          int& done);
  308.  
  309.   double calc_forward (double input [], double desired_output [],
  310.                        int& num_wrong, int& skip, int print_it,
  311.                        int& actual_printed);
  312.  
  313.   int calc_forward_test (double input [], double desired_output [],
  314.                          int print_it, double correct_eps, double good_eps);
  315.  
  316.   void update_weights ();
  317.  
  318.   void kick_weights (double range);
  319.  
  320. };
  321.  
  322. #endif
  323.