home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 618a.lha / NeuralNetwork / neural_net.h < prev    next >
C/C++ Source or Header  |  1992-03-08  |  21KB  |  446 lines

  1.  
  2. #ifndef _NEURAL_NET_H_
  3. #define _NEURAL_NET_H_
  4.  
  5. /* This is the "C" version of the Neural Network code */
  6.  
  7.  
  8. #define SLOPE    1.0
  9. #define S(x)    (1.0 / (1.0 + exp (0.0 - SLOPE*(x))))
  10.  
  11. #define private
  12. #define public
  13. #define class typedef struct
  14.  
  15. #define WRONG    0
  16. #define GOOD     1
  17. #define CORRECT  2
  18.  
  19.  
  20. /****************************************************************************
  21. //
  22. // Neural_net class:
  23. //
  24. //      This class performs all the necessary functions needed to train
  25. //      a Neural Network.  The network has an input layer, two hidden
  26. //      layers, and an output layer.  The size of each layer is specified
  27. //      a run time so there is no restriction on size except memory.
  28. //      This is a feed-forward network with full connctions from one
  29. //      layer to the next.
  30. //
  31. //      The network can perform straight back-propagation with no
  32. //      modifications (Rumelhart, Hinton, and Williams, 1985) which
  33. //      will find a solution but not very quickly.  The network can also
  34. //      perform back-propagation with the delta-bar-delta rule developed
  35. //      by Robert A. Jacobs, University of Massachusetts
  36. //      (Neural Networks, Vol 1. pp.295-307, 1988).  The basic idea of this
  37. //      rule is that every weight has its own learning rate and each
  38. //      learning rate should be continously changed according to the
  39. //      following rules -
  40. //      - If the weight changes in the same direction as the previous update,
  41. //        then the learning rate for that weight should increase by a constant.
  42. //      - If the weight changes in the opposite direction as the previous
  43. //        update, then the learning rate for that weight should decrease
  44. //        exponentially.
  45. //
  46. //      learning rate = e(t) for each individual weight
  47. //      The exact formula for the change in learning rate (DELTA e(t)) is
  48. //
  49. //
  50. //                   | K          if DELTA_BAR(t-1)*DELTA(t) > 0
  51. //      DELTA e(t) = | -PHI*e(t)  if DELTA_BAR(t-1)*DELTA(t) < 0
  52. //                   | 0          otherwise
  53. //
  54. //      where DELTA(t) = dJ(t) / dw(t) ---> Partial derivative
  55. //
  56. //      and DELTA_BAR(t) = (1 - THETA)*DELTA(t) + THETA*DELTA_BAR(t-1).
  57. //
  58. //      For full details of the algorithm, read the article in
  59. //      Neural Networks.
  60. //
  61. //
  62. //      To perform straight back-propagation, just construct a Neural_network
  63. //      with no learning parameters specified (they default to straight
  64. //      back-propagation) or set them to
  65. //      K = 0, PHI = 0, THETA = 1.0
  66. //
  67. //      However, using the delta-bar-delta rule should increase your rate of
  68. //      convergence by a factor of 10 to 100 generally.  The parameters for
  69. //      the delta-bar-delta rule I use are
  70. //      K = 0.025, PHI = 0.2, THETA = 0.8
  71. //
  72. //      One more heuristic method has been employed in this Neural net class-
  73. //      the skip heuristic.  This is something I thought of and I am sure
  74. //      other people have also.  If the output activation is within
  75. //      skip_epsilon of its desired for each output, then the calc_forward
  76. //      routine returns the skip_flag = 1.  This allows you to not waste
  77. //      time trying to push already very close examples to the exact value.
  78. //      If the skip_flag comes back '1', then don't bother calculating forward
  79. //      or back-propagating the example for X number of epochs.  You must
  80. //      write the routine to skip the example yourself, but the Neural_network
  81. //      will tell you when to skip the example.  This heuristic also has the
  82. //      advantage of reducing memorization and increases generalization.
  83. //      Typical values I use for this heuristic -
  84. //      skip_epsilon = 0.01 - 0.05
  85. //      number skipped = 2-10.
  86. //
  87. //      Experiment with all the values to see which work best for your
  88. //      application.
  89. //
  90. //
  91. //      Comments and suggestions are welcome and can be emailed to me
  92. //      anstey@sun.soe.clarkson.edu
  93. //
  94. / ***************************************************************************/
  95.  
  96.  
  97.  
  98. /* This 'class' (struct) is private.  You should not modify it directly */
  99. /* or corrupted data may occur.  Only modify it through the 'class' */
  100. /* functions listed below. */
  101. class Neural_net {
  102. private
  103.  
  104. /*
  105.   //  We need
  106.   //
  107.   //  Matrix for hidden layer 1 activation [num_hidden1]
  108.   //  Matrix for hidden layer 2 activation [num_hidden2]
  109.   //  Matrix for output layer activation [num_outputs]
  110.   //
  111.   //  Matrix for input to first hidden layer weights [num_inputs] [num_hidden1]
  112.   //  Matrix for hidden layer 1 to hidden layer 2 weights [hidden1] [hidden2]
  113.   //  Matrix for hidden layer 2 to output layer weights [hidden2] [outputs]
  114.  
  115.   //  3 Matrices for sum of all the deltas in an epoch - Back propagation
  116.   //  2 Matrices for sum of deltas * weight for each neuron in hidden layers
  117.   //    1 and 2 for backpropagation - Back propagation
  118.   //
  119.   //  3 Matrices for each weight's learning rate - delta-bar-delta rule
  120.   //  3 Matrices for each weight's learning delta - delta-bar-delta rule
  121.   //  3 Matrices for each weight's learning delta_bar - delta-bar-delta rule
  122. */
  123.  
  124.   int     num_inputs;
  125.   int     num_hidden1;
  126.   int     num_hidden2;
  127.   int     num_outputs;
  128.  
  129.   double  epsilon;
  130.   double  skip_epsilon;
  131.   double  learning_rate;
  132.   double  theta;
  133.   double  phi;
  134.   double  K;
  135.   long    training_examples;
  136.   long    examples_since_update;
  137.  
  138.   double  *hidden1_act;
  139.   double  *hidden2_act;
  140.   double  *output_act;
  141.  
  142.   double  *input_weights;
  143.   double  *hidden1_weights;
  144.   double  *hidden2_weights;
  145.  
  146.   double  *input_learning_rate;
  147.   double  *hidden1_learning_rate;
  148.   double  *hidden2_learning_rate;
  149.  
  150.   double  *input_learning_delta;
  151.   double  *hidden1_learning_delta;
  152.   double  *hidden2_learning_delta;
  153.  
  154.   double  *input_learning_delta_bar;
  155.   double  *hidden1_learning_delta_bar;
  156.   double  *hidden2_learning_delta_bar;
  157.  
  158.   double  *input_weights_sum_delta;
  159.   double  *hidden1_weights_sum_delta;
  160.   double  *hidden2_weights_sum_delta;
  161.  
  162.   double  *hidden1_sum_delta_weight;
  163.   double  *hidden2_sum_delta_weight;
  164.  
  165. } Neural_net;
  166.  
  167. public /* These are the functions that operate on a struct Neural_net */
  168.         /* The first parameter to any Neural_net function
  169.            (except constructors) is a pointer to an initialized Neural_net */
  170.  
  171.   /************************************************************************
  172.   // Constructors : Each constructor returns a pointer to a               *
  173.   //                Neural_net which has been initialized.                *
  174.   //                                                                      *
  175.   //    Neural_net_constr : Constructs (initializes) a Neural_net struct. *
  176.   //         Full size specifications and learning parameters need to be  *
  177.   //         specified.                                                   *
  178.   //                                                                      *
  179.   //    Neural_net_default_constr : Constructs (initializes) a Neural_net *
  180.   //         structure of the given size with the default learning        *
  181.   //         parameters for BP and weights between +-1.0.                 *
  182.   //                                                                      *
  183.   //    Neural_net_read_constr : Constructs (initializes) a Neural_net    *
  184.   //         structure by reading the weights from a file.  The size of   *
  185.   //         the Neural_net is determined by the file.  Learning          *
  186.   //         parameters need to be specified.                             *
  187.   //                                                                      *
  188.   //    Neural_net_default_read_constr : Constructs (initializes) a       *
  189.   //         Neural_net structure by reading the weights from a file.     *
  190.   //         The size of the Neural_net is determined by the file.        *
  191.   //         Learning parameters are given default BP values.             *
  192.   //                                                                      *
  193.   // Destructor : The destructor destroys (frees) all matrices in a       *
  194.   //         Neural_net structure                                         *
  195.   //                                                                      *
  196.   //    Neural_net_destr : YOU MUST CALL THIS ROUTINE TO DESTROY THE      *
  197.   //          Neural_net. The destructor frees all matrices in the        *
  198.   //          Neural_net.                                          *
  199.   / **********************************************************************/
  200.  
  201. Neural_net *Neural_net_constr (int number_inputs,
  202.                      int number_hidden1, int number_hidden2,
  203.                      int number_outputs, double t_epsilon,
  204.                      double t_skip_epsilon, double t_learning_rate,
  205.                      double t_theta, double t_phi, double t_K,
  206.                      double range);
  207.  
  208. Neural_net *Neural_net_read_constr (char *filename, int *file_error,
  209.                    double t_epsilon,
  210.                    double t_skip_epsilon, double t_learning_rate,
  211.                    double t_theta, double t_phi, double t_K);
  212.  
  213. void Neural_net_destr (Neural_net *nn);
  214.  
  215. /* Inline functions if compiler supports inlining */
  216. #ifdef __inline__
  217. inline Neural_net *Neural_net_default_constr (int number_inputs,
  218.                    int number_hidden1, int number_hidden2,
  219.                    int number_outputs)
  220. {
  221.   return (Neural_net_constr (number_inputs,number_hidden1,
  222.                              number_hidden2,number_outputs,0.1,0.05,0.1,1.0,
  223.                              0.0,0.0,1.0);
  224. };
  225.  
  226. inline Neural_net *Neural_net_default_read_constr (char *filename,
  227.                                                           int *file_error)
  228. {
  229.   return (Neural_net_read_constr (filename,file_error,0.1,0.05,0.1,1.0,0.0,
  230.                                   0.0,1.0);
  231. }
  232. #else
  233. Neural_net *Neural_net_default_constr (int number_inputs,
  234.                    int number_hidden1, int number_hidden2,
  235.                    int number_outputs);
  236. Neural_net *Neural_net_default_read_constr (char *filename,
  237.                                                    int *file_error);
  238. #endif
  239.  
  240.   /***************************************************************************
  241.   // Weight parameter routines:                                              *
  242.   //     save_weights : This routine saves the weights of the network        *
  243.   //          to the file <filename>.                                        *
  244.   //                                                                         *
  245.   //     read_weights : This routine reads the weight values from the file   *
  246.   //          <filename>.  The network is automatically resized to the       *
  247.   //          size specified by the file.                                    *
  248.   //                                                                         *
  249.   //     Activation routines return the node activation after a calc_forward *
  250.   //          has been performed.                                            *
  251.   //                                                                         *
  252.   //     get_weight routines return the weight between node1 and node2.      *
  253.   //                                                                         *
  254.   / *************************************************************************/
  255.  
  256. int    Neural_net_save_weights (Neural_net *nn, char *filename);
  257. int    Neural_net_read_weights (Neural_net *nn, char *filename);
  258.  
  259. #ifdef __inline__
  260. inline double Neural_net_get_hidden1_activation (Neural_net *nn,
  261.                                                  int node)
  262.   { return (nn->hidden1_act [node]); };
  263.  
  264. inline double Neural_net_get_hidden2_activation (Neural_net *nn,
  265.                                                  int node)
  266.   { return (nn->hidden2_act [node]); };
  267.  
  268. inline double Neural_net_get_output_activation (Neural_net *nn,
  269.                                                 int node)
  270.   { return (nn->output_act [node]); };
  271.  
  272. inline double Neural_net_get_input_weight (Neural_net *nn,
  273.                                            int input_node, int hidden1_node)
  274.   { return (nn->input_weights [hidden1_node * nn->num_inputs + input_node]);};
  275.  
  276. inline double Neural_net_get_hidden1_weight (Neural_net *nn,
  277.                                              int hidden1_node,
  278.                                              int hidden2_node)
  279.   { return (nn->hidden1_weights [hidden2_node * nn->num_hidden1 +
  280.                                  hidden1_node]);};
  281.  
  282. inline double Neural_net_get_hidden2_weight (Neural_net *nn,
  283.                                              int hidden2_node, int output_node)
  284.   { return (nn->hidden2_weights [output_node*nn->num_hidden2+hidden2_node]);};
  285.  
  286. #else
  287. double Neural_net_get_hidden1_activation (Neural_net *nn, int node);
  288. double Neural_net_get_hidden2_activation (Neural_net *nn, int node);
  289. double Neural_net_get_output_activation (Neural_net *nn, int node);
  290.  
  291. double Neural_net_get_input_weight (Neural_net *nn, int input_node,
  292.                                     int hidden1_node);
  293. double Neural_net_get_hidden1_weight (Neural_net *nn, int hidden1_node,
  294.                                       int hidden2_node);
  295. double Neural_net_get_hidden2_weight (Neural_net *nn, int hidden2_node,
  296.                                       int output_node);
  297. #endif
  298.  
  299.   /********************************************************************
  300.   // Size parameters of network.                                      *
  301.   // The size of the network may be changed at any time.  The weights *
  302.   // will be copied from the old size to the new size.  If the new    *
  303.   // size is larger, then the extra weights will be randomly set      *
  304.   // between +-range.  The matrices used to hold learning updates     *
  305.   // and activations will be re-initialized (cleared).                *
  306.   / ******************************************************************/
  307.  
  308. #ifdef __inline__
  309. inline int Neural_net_get_number_inputs (Neural_net *nn)
  310.   { return (nn->num_inputs); };
  311. inline int Neural_net_get_number_hidden1 (Neural_net *nn)
  312.   { return (nn->num_hidden1); };
  313. inline int Neural_net_get_number_hidden2 (Neural_net *nn)
  314.   { return (nn->num_hidden2); };
  315. inline int Neural_net_get_number_outputs (Neural_net *nn)
  316.   { return (nn->num_outputs); };
  317. #else
  318. int Neural_net_get_number_inputs (Neural_net *nn);
  319. int Neural_net_get_number_hidden1 (Neural_net *nn);
  320. int Neural_net_get_number_hidden2 (Neural_net *nn);
  321. int Neural_net_get_number_outputs (Neural_net *nn);
  322. #endif
  323.  
  324. void Neural_net_set_size_parameters (Neural_net *nn, int number_inputs,
  325.                                      int number_hidden1, int number_hidden2,
  326.                                      int number_outputs, double range);
  327.  
  328.   /********************************************************************
  329.   // Learning parameters functions.  These parameters may be changed  *
  330.   // on the fly.  The learning rate and K may have to be reduced as   *
  331.   // more and more training is done to prevent oscillations.          *
  332.   / ******************************************************************/
  333.  
  334. #ifdef __inline__
  335. inline void Neural_net_set_epsilon (Neural_net *nn, double eps)
  336.   { nn->epsilon = eps; };
  337. inline void Neural_net_set_skip_epsilon (Neural_net *nn, double eps)
  338.   { nn->skip_epsilon = eps; };
  339. inline void Neural_net_set_learning_rate (Neural_net *nn, double l_rate)
  340.   { nn->learning_rate = l_rate; };
  341. inline void Neural_net_set_theta (Neural_net *nn, double t_theta)
  342.   { nn->theta = t_theta; };
  343. inline void Neural_net_set_phi (Neural_net *nn, double t_phi)
  344.   { nn->phi = t_phi; };
  345. inline void Neural_net_set_K (Neural_net *nn, double t_K)
  346.   { nn->K = t_K; };
  347.  
  348. inline double Neural_net_get_epsilon (Neural_net *nn)
  349.   { return (nn->epsilon); };
  350. inline double Neural_net_get_skip_epsilon (Neural_net *nn)
  351.   { return (nn->skip_epsilon); };
  352. inline double Neural_net_get_learning_rate (Neural_net *nn)
  353.   { return (nn->learning_rate); };
  354. inline double Neural_net_get_theta (Neural_net *nn)
  355.   { return (nn->theta); };
  356. inline double Neural_net_get_phi (Neural_net *nn)
  357.   { return (nn->phi); };
  358. inline double Neural_net_get_K (Neural_net *nn)
  359.   { return (nn->K); };
  360. inline long   Neural_net_get_iterations (Neural_net *nn)
  361.   { return (nn->training_examples); };
  362.  
  363. #else
  364. void Neural_net_set_epsilon (Neural_net *nn, double eps);
  365. void Neural_net_set_skip_epsilon (Neural_net *nn, double eps);
  366. void Neural_net_set_learning_rate (Neural_net *nn, double l_rate);
  367. void Neural_net_set_theta (Neural_net *nn, double t_theta);
  368. void Neural_net_set_phi (Neural_net *nn, double t_phi);
  369. void Neural_net_set_K (Neural_net *nn, double t_K);
  370.  
  371. double Neural_net_get_epsilon (Neural_net *nn);
  372. double Neural_net_get_skip_epsilon (Neural_net *nn);
  373. double Neural_net_get_learning_rate (Neural_net *nn);
  374. double Neural_net_get_theta (Neural_net *nn);
  375. double Neural_net_get_phi (Neural_net *nn);
  376. double Neural_net_get_K (Neural_net *nn);
  377. long   Neural_net_get_iterations (Neural_net *nn);
  378. #endif
  379.  
  380.   /***************************************************************************
  381.   // The main neural network routines:                                       *
  382.   //                                                                         *
  383.   //      The network input is an array of doubles which has a size of       *
  384.   //           number_inputs.                                                *
  385.   //      The network desired output is an array of doubles which has a size *
  386.   //           of number_outputs.                                            *
  387.   //                                                                         *
  388.   //      back_propagation : Calculates how each weight should be changed.   *
  389.   //           Assumes that calc_forward has been called just prior to       *
  390.   //           this routine to calculate all of the node activations.        *
  391.   //                                                                         *
  392.   //      calc_forward : Calculates the output for a given input.  Finds     *
  393.   //           all node activations which are needed for back_propagation    *
  394.   //           to calculate weight adjustment.  Returns abs (error).         *
  395.   //           The parameter skip is for use with the skip_epsilon           *
  396.   //           parameter.  What it means is if the output is within          *
  397.   //           skip_epsilon of the desired, then it is so close that it      *
  398.   //           should be skipped from being calculated the next X times.     *
  399.   //           Careful use of this parameter can significantly increase      *
  400.   //           the rate of convergence and also help prevent over-learning.  *
  401.   //                                                                         *
  402.   //      calc_forward_test : Calculates the output for a given input.  This *
  403.   //           routine is used for testing rather than training.  It returns *
  404.   //           whether the test was CORRECT, GOOD or WRONG which is          *
  405.   //           determined by the parameters correct_epsilon and              *
  406.   //           good_epsilon.  CORRECT > GOOD > WRONG.                        *
  407.   //                                                                         *
  408.   //      update_weights : Actually adjusts all the weights according to     *
  409.   //           the calculations of back_propagation.  This routine should    *
  410.   //           be called at the end of every training epoch.  The weights    *
  411.   //           can be updated by the straight BP algorithm, or by the        *
  412.   //           delta-bar-delta algorithm developed by Robert A. Jacobs       *
  413.   //           which increases the rate of convergence generally by at       *
  414.   //           least a factor of 10.  The parameters THETA, PHI, and K       *
  415.   //           determine which algorithm is used.  The default settings      *
  416.   //           for these parameters cause update_weights to use the straight *
  417.   //           BP algorithm.                                                 *
  418.   //                                                                         *
  419.   //      kick_weights : This routine changes all weights by a random amount *
  420.   //           within +-range.  It is useful in case the network gets        *
  421.   //           'stuck' and is having trouble converging to a solution.  I    *
  422.   //           use it when the number wrong has not changed for the last 200 *
  423.   //           epochs.  Getting the range right will take some trial and     *
  424.   //           error as it depends on the application and the weights'       *
  425.   //           actual values.                                                *
  426.   //                                                                         *
  427.   / *************************************************************************/
  428.  
  429. void Neural_net_back_propagation (Neural_net *nn, double input [],
  430.                                   double desired_output [], int *done);
  431.  
  432. double Neural_net_calc_forward (Neural_net *nn, double input [],
  433.                                 double desired_output [], int *num_wrong,
  434.                                 int* skip, int print_it, int *actual_printed);
  435.  
  436. int Neural_net_calc_forward_test (Neural_net *nn, double input [],
  437.                                   double desired_output [], int print_it,
  438.                                   double correct_eps, double good_eps);
  439.  
  440. void Neural_net_update_weights (Neural_net *nn);
  441.  
  442. void Neural_net_kick_weights (Neural_net *nn, double range);
  443.  
  444.  
  445.  
  446. #endif