home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 306_01 / synapsys.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-20  |  11.3 KB  |  312 lines

  1. /******************************************************************************
  2.  
  3.                                   SYNAPSYS.C
  4.  
  5.                           NEURAL NETWORK SIMULATION
  6.  
  7.       COPYRIGHT 1988, 1989, 1990, 1991 GREGORY COLVIN, ALL RIGHTS RESERVED
  8.  
  9.     Under copyright law this code may be used for educational and experimental
  10.     purposes according to the "fair use" doctrine. If you wish to use or modify
  11.     this code for a commercial product you must obtain a license from me at:
  12.  
  13.          17890 CIMARRON CIRCLE, NATHROP, COLORADO 81236  (719)539-4942
  14.  
  15.     This code implements a very fast backpropagation type network by
  16.     representing synapse layers as word arrays and implementing all
  17.     operationswith integer arithmetic. Some instability in learning may
  18.     result from truncation error. If this is a problem you may want to try
  19.     implementing momentum as a fraction rather that a boolean, or try adding
  20.     rounding logic to the FEEDBACK_SHIFT and DELTA_SHIFT operations in error(),
  21.     as in the SYNAPSE_SHIFT operation in transfer().
  22.  
  23.     This code compiles to excellent code on most 32 bit machines. On 16 bit
  24.     machines it would be a good idea to code the transfer() and error()
  25.     functions in Assembly; the transfer() function will typically run twice
  26.     as fast, and the error() function will typically run ten times as
  27.     fast, when coded in Assembly on 16 bit machines. This is because most
  28.     16 bit machines will multiply two 16 bit quantities to produce a 32 bit
  29.     result, and all multiply operands in this program are designed not to
  30.     exceed 16 bits. However, most compilers cannot find this optimization.
  31.  
  32.     This code compiles cleanly on most K&R compilers. ANSI compilers may
  33.     complain about missing prototypes but should generate good code.
  34.  
  35. *****************************************************************************/
  36.  
  37. #include <stdio.h>
  38. #include "synapsys.h"
  39.  
  40. /* create a new network of n_layer synapse layers with
  41.      n_neuron[i] input neurons and
  42.      n_neuron[i+1] output neurons
  43.    for each layer of synapses
  44.  
  45.    the learning rate for each layer is set to rate[i]
  46.    the presence of history synapses for each layer is controlled by momentum[i]
  47.    return pointer to network, or 0 if out of memory
  48. */
  49. NETWORK *new_network( n_layer, n_neuron, rate, momentum )
  50. int n_layer, n_neuron[], rate[], momentum[];
  51. {
  52.   NETWORK *network;
  53.   int i;
  54.   LAYER *layer, *prev_layer=0;
  55.   char *calloc();
  56.  
  57.   network = (NETWORK *)calloc( 1, sizeof(NETWORK) );
  58.   if (!network)
  59.     return 0;
  60.   for (i = 0; i < n_layer; i++, prev_layer = layer)
  61.   {
  62.     layer = (LAYER *)calloc( 1, sizeof(LAYER) );
  63.     if (!layer)
  64.       return 0;
  65.     layer->n_inputs = n_neuron[i];
  66.     layer->n_outputs = n_neuron[i+1];
  67.     layer->rate = rate[i];
  68.     layer->momentum = momentum[i];
  69.     layer->inputs = (NEURON *)calloc( layer->n_inputs, sizeof(NEURON) );
  70.     if (!layer->inputs)
  71.       return 0;
  72.     if (prev_layer)
  73.     {
  74.       layer->prev_layer = prev_layer;
  75.       layer->prev_layer->next_layer = layer;
  76.       layer->prev_layer->outputs = layer->inputs;
  77.     }
  78.     else
  79.       network->first_layer = layer;
  80.     layer->synapses =
  81.       (SYNAPSE *)calloc( layer->n_inputs*layer->n_outputs, sizeof(SYNAPSE) );
  82.     if (!layer->synapses)
  83.       return 0;
  84.     if (momentum[i])
  85.     {
  86.       layer->history =
  87.         (SYNAPSE *)calloc( layer->n_inputs*layer->n_outputs, sizeof(SYNAPSE) );
  88.       if (!layer->history)
  89.         return 0;
  90.     }
  91.     else
  92.       layer->history = 0;
  93.   }
  94.   layer->outputs = (NEURON *)calloc( layer->n_outputs, sizeof(NEURON) );
  95.   if (!layer->outputs)
  96.     return 0;
  97.   network->last_layer = layer;
  98.   return network;
  99. }
  100.  
  101. /* feed activations forward through all layers of a network */
  102. feedforward( network )
  103. NETWORK *network;
  104. {
  105.   int n_inputs;
  106.   SYNAPSE *synapses;
  107.   NEURON *inputs, *output, *end_out;
  108.   LAYER *layer;
  109.  
  110.   /* loop forward through all layers */
  111.   for (layer = network->first_layer; layer; layer = layer->next_layer)
  112.   {
  113.     synapses = layer->synapses;
  114.     n_inputs = layer->n_inputs;
  115.     inputs   = layer->inputs;
  116.     output   = layer->outputs;
  117.     end_out  = layer->n_outputs + output;
  118.  
  119.     /* feed activations forward through this layer */
  120.     for ( ; output < end_out; output++, synapses += n_inputs)
  121.       transfer( n_inputs, inputs, output, synapses );
  122.   }
  123. }
  124.  
  125.  
  126. /* feed errors back through all layers of a network */
  127. feedback( network )
  128. NETWORK *network;
  129. {
  130.   int n_inputs, rate, momentum;
  131.   SYNAPSE *synapses, *history;
  132.   NEURON *inputs, *output, *end;
  133.   LAYER *layer;
  134.  
  135.   /* loop back through all layers */
  136.   for (layer = network->last_layer; layer; layer = layer->prev_layer)
  137.   {
  138.     /* clear out previous errors */
  139.     n_inputs = layer->n_inputs;
  140.     inputs   = layer->inputs;
  141.     while (--n_inputs >= 0)
  142.       (inputs++)->errors = 0;
  143.  
  144.     /* feed errors back through this layer */
  145.     n_inputs = layer->n_inputs;
  146.     inputs   = layer->inputs;
  147.     output   = layer->outputs;
  148.     synapses = layer->synapses;
  149.     history  = layer->history;
  150.     rate     = layer->rate;
  151.     momentum = layer->momentum;
  152.     end = output + layer->n_outputs;
  153.     for ( ; output < end; output++, synapses += n_inputs, history += n_inputs)
  154.       error( n_inputs, inputs, output, synapses, history, rate, momentum );
  155.   }
  156. }
  157.  
  158. /* transfer function */
  159. transfer( n_inputs, inputs, output, synapses )
  160. register int      n_inputs;                  /* number of input neurons      */
  161. register NEURON  *inputs;                    /* vector of input neurons      */
  162.          NEURON  *output;                    /* output neuron                */
  163. register SYNAPSE *synapses;                  /* vector of synapses on output */
  164. {
  165.   register long sum = 0;                     /* for accumulating inputs      */
  166.   long i;                                    /* for intermediate calculation */
  167.  
  168.   /* feed input activation forward through synapses by accumulating products */
  169.   while (--n_inputs >= 0)
  170.     sum += (long)*synapses++ * (inputs++)->activation;
  171.  
  172.   /* limit activation overload with log if below -100 or above 100) */
  173.   if (sum > 0)
  174.   {
  175.     sum += 1 << SYNAPSE_SHIFT-1;             /* round sum                    */
  176.     sum >>= SYNAPSE_SHIFT;                   /* shift sum back into range    */
  177.     if (sum > 100)                           /* sum = 100 + log2(sum-100)    */
  178.       for (i = sum, sum = 100; (i >>= 1) >= 100; sum++)
  179.         ;
  180.   }
  181.   else if (sum < 0)
  182.   {
  183.     sum -= 1 << SYNAPSE_SHIFT-1;             /* round sum                    */
  184.     sum >>= SYNAPSE_SHIFT;                   /* shift sum back into range    */
  185.     if (sum < -100)                          /* sum = -100 - log2(-sum-100)  */
  186.       for (i = -sum, sum = -100; (i >>= 1) >= 100; sum--)
  187.         ;
  188.   }
  189.   output->activation = sum;
  190. }
  191.  
  192. /* error function */
  193. error( n_inputs, inputs, output, synapses, history, rate, momentum )
  194. register int       n_inputs;        /* number of input neurons               */
  195. register NEURON   *inputs;          /* vector of input neurons               */
  196.          NEURON   *output;          /* output neuron                         */
  197. register SYNAPSE  *synapses;        /* vector of synapses on output          */
  198.          SYNAPSE  *history;         /* vector of synapse history             */
  199. int                rate;            /* transfer learning rate                */
  200. int                momentum;        /* if true use synapse history           */
  201. {
  202.   WORD error;                       /* correction error for synapse          */
  203.   long weight;                      /* synapse weight                        */
  204.   long feedback;                    /* amount to feedback to previous layer  */
  205.   long delta;                       /* amount to change synapse weight       */
  206.  
  207.   /* amount of left shift to bring feedback and delta back into proper range */
  208. #define FEEDBACK_SHIFT \
  209.         SYNAPSE_SHIFT+ACTIVATION_SHIFT+RATE_SHIFT-ACTIVATION_SHIFT
  210. #define DELTA_SHIFT \
  211.         ACTIVATION_SHIFT+ACTIVATION_SHIFT+RATE_SHIFT-SYNAPSE_SHIFT
  212.  
  213.   /* get error, factor in derivative of log limit function if overload */
  214.   error = output->errors;
  215.   if (output->activation > 100)
  216.     error = (error * 100) / output->activation;
  217.   else if (output->activation < -100)
  218.     error = (error * 100) / output->activation;
  219.   error *= rate;                    /* error proportional to learning rate   */
  220.  
  221.   while (--n_inputs >= 0)           /* calculate new synapse weights:        */
  222.   {
  223.     weight = *synapses;             /*   get weight from synapse             */
  224.     feedback = weight;              /*   feedback proportional to weight     */
  225.     feedback *= error;              /*   feedback proportional to error      */
  226.     feedback >>= FEEDBACK_SHIFT;    /*   shift feedback into range of errors */
  227.     inputs->errors += feedback;     /*   feedback to input errors            */
  228.     delta = inputs->activation;     /*   delta proportional to input         */
  229.     inputs++;                       /*   next input                          */
  230.     delta *= error;                 /*   delta proportional to error         */
  231.     delta >>= DELTA_SHIFT;          /*   shift delta into range of weight    */
  232.     if (momentum)
  233.     { delta += *history;            /*   add momentum to delta               */
  234.       *history++ = (SYNAPSE)delta;  /*   save delta for next feedback cycle  */
  235.     }
  236.     weight += delta;                /*   synapse weight corrected by delta   */
  237.     if (weight > MAX_SYNAPSE)
  238.       weight = MAX_SYNAPSE;         /*   limit weight in case of overflow    */
  239.     else if (weight < -MAX_SYNAPSE)
  240.       weight = -MAX_SYNAPSE;        /*   limit weight in case of underflow   */
  241.     *synapses++ = (SYNAPSE)weight;  /*   put new weight back in synapse      */
  242.   }
  243. }
  244.  
  245.  
  246. /* set all synapse weights and history in a network to zero */
  247. clear( network )
  248. NETWORK *network;
  249. {
  250.   register SYNAPSE *s, *end;
  251.   register LAYER *layer = network->first_layer;
  252.   do
  253.   {
  254.     s = layer->synapses;
  255.     if (s)
  256.     { end = s + layer->n_inputs * layer->n_outputs;
  257.       do *s++ = 0; while (s < end);
  258.     }
  259.     s = layer->history;
  260.     if (s)
  261.     { end = s + layer->n_inputs * layer->n_outputs;
  262.       do *s++ = 0; while (s < end);
  263.     }
  264.   } while (layer = layer->next_layer);
  265. }
  266.  
  267. /* set all synapse weights in a network to val, set history to zero */
  268. set( network, val )
  269. NETWORK *network;
  270. int val;
  271. {
  272.   register SYNAPSE *s, *end;
  273.   register LAYER *layer = network->first_layer;
  274.   do
  275.   {
  276.     s = layer->synapses;
  277.     if (s)
  278.     { end = s + layer->n_inputs * layer->n_outputs;
  279.       do *s++ = val; while (s < end);
  280.     }
  281.     s = layer->history;
  282.     if (s)
  283.     { end = s + layer->n_inputs * layer->n_outputs;
  284.       do *s++ = 0; while (s < end);
  285.     }
  286.   } while (layer = layer->next_layer);
  287. }
  288.  
  289. /* add a signed pseudo-random value to all weights in a network */
  290. randomize( network, max, seed )
  291. NETWORK *network;
  292. unsigned max;
  293. long seed;
  294. {
  295.   register unsigned WORD seed1 = seed, seed2 = seed>>16;
  296.   WORD div = 32768/max;
  297.   register SYNAPSE *weight, *end;
  298.   LAYER *layer = network->first_layer;
  299.   do
  300.   {
  301.     weight = layer->synapses;
  302.     if (weight)
  303.     {
  304.       end = weight + layer->n_inputs * layer->n_outputs;
  305.       do
  306.         *weight++ += (WORD)((long)U2RAND(seed1,seed2)-32768)/div;
  307.  
  308.       while (weight < end);
  309.     }
  310.   } while (layer = layer->next_layer);
  311. }
  312.