home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
listings
/
v_07_03
/
v7n3061a.txt
< prev
next >
Wrap
Text File
|
1989-01-18
|
17KB
|
463 lines
Listing1
/* define WORD to be signed sixteen bit integer */
#ifdef MEGAMAX
#define WORD int
#else
#define WORD short
#endif
typedef struct
{
WORD activation; /* activation of neuron for feedforward */
WORD errors; /* sum of errors from feedback */
} NEURON;
#define NEURON_SIZE 4 /* sizeof(NEURON) for assembler */
#define O_ERROR 2 /* offset of neuron.errors for assembler */
#define ACTIVATION_SHIFT 7 /* units of 1/128: 2**-7 */
#define RATE_SHIFT 7 /* units of 1/128: 2**-7 */
Listing2
typedef WORD SYNAPSE;
#define MAX_SYNAPSE 32767
#define SYNAPSE_SHIFT 10 /* units of 1/1024: 2**-10 */
typedef struct layer
{
struct layer *prev_layer; /* pointer to previous layer, if any */
int n_inputs; /* number of input neurons */
NEURON *inputs; /* same address as outputs of previous layer*/
SYNAPSE *synapses; /* synapses[n_inputs][n_outputs] */
SYNAPSE *history; /* previous values for use in learning */
char rate; /* learning rate, larger values learn faster*/
char momentum; /* learning momentum in powers of two, 0 to 7 */
int n_outputs; /* number of output neurons */
NEURON *outputs; /* same address as inputs of next layer */
struct layer *next_layer; /* pointer to next layer, if any */
} LAYER;
typedef struct
{
LAYER *first_layer;
LAYER *last_layer;
} NETWORK;
Listing3
transfer(n_inputs, inputs, output, synapses)
register int n_inputs; /* number of input neurons */
register NEURON *inputs; /* vector of input neurons */
NEURON *output; /* output neuron */
register SYNAPSE *synapses; /* vector of synapses on */
{
register long sum = 0; /* for accumulating inputs */
long i; /* for intermediate */
/* feed input activation forward through synapses by accumulating
products */
#ifndef MEGAMAX
while (--n_inputs >= 0)
sum += (long) * synapses++*(inputs++)->activation;
#else /* use Megamax inline assembly for Motorola */
asm
{
bra test
loop:
;
while (--n_inputs >= 0)
move.w(synapses) + , D0;
D0 = *synapses++muls(inputs), D0;
D0 *= input->activation addq.l#NEURON_SIZE, inputs;
input++add.l D0, sum;
sum += D0
test:
dbf n_inputs, loop
}
#endif
/* limit activation overload with log if below -100 or above 100) */
if (sum > 0)
{
sum += 1 << SYNAPSE_SHIFT - 1; /* round sum */
sum >>= SYNAPSE_SHIFT; /* shift sum back into range */
if (sum > 100) /* sum = 100 + log2(sum-100) */
for (i = sum, sum = 100; (i >>= 1) >= 100; sum++)
;
}
else if (sum < 0)
{
sum -= 1 << SYNAPSE_SHIFT - 1; /* round sum */
sum >>= SYNAPSE_SHIFT; /* shift sum back into range */
if (sum < -100) /* sum = -100 - log2(-sum-100) */
for (i = -sum, sum = -100; (i >>= 1) >= 100; sum--)
;
}
output->activation = sum;
}
Listing4
error(n_inputs, inputs, output, synapses, history, rate, momentum)
register int n_inputs; /* number of input neurons */
register NEURON *inputs; /* vector of input neurons */
NEURON *output; /* output neuron */
register SYNAPSE *synapses; /* vector of synapses on output */
SYNAPSE *history; /* vector of synapse history */
int rate; /* transfer learning rate */
int momentum; /* if true use synapse history */
{
WORD error; /* correction error for synapse */
long weight; /* synapse weight */
long feedback; /* amount to feedback to previous layer */
long delta; /* amount to change synapse weight */
/* amount of left shift to bring feedback and delta back into proper
range */
#define FEEDBACK_SHIFT \
SYNAPSE_SHIFT+ACTIVATION_SHIFT+RATE_SHIFT-ACTIVATION_SHIFT
#define DELTA_SHIFT \
ACTIVATION_SHIFT+ACTIVATION_SHIFT+RATE_SHIFT-SYNAPSE_SHIFT
/* get error, factor in derivative of log limit function if overload*/
error = output->errors;
if (output->activation > 100)
error = (error * 100) / output->activation;
else if (output->activation < -100)
error = (error * 100) / output->activation;
error *= rate; /* error proportional to learning rate */
#ifndef MEGAMAX
while (--n_inputs >= 0) /* calculate new synapse weights: */
{
weight = *synapses; /* get weight from synapse */
feedback = weight; /* feedback proportional to weight */
feedback *= error; /* feedback proportional to error */
feedback >>= FEEDBACK_SHIFT; /* shift feedback into range of
errors */
inputs->errors += feedback; /* feedback to input errors */
delta = inputs->activation; /* delta proportional to input */
inputs++; /* next input */
delta *= error; /* delta proportional to error */
delta >>= DELTA_SHIFT; /* shift delta into range of weight */
if (momentum)
{
delta += *history; /* add momentum to delta */
*history++ = (SYNAPSE)delta; /* save delta for next
feedback cycle */
}
weight += delta; /* synapse weight corrected by delta */
if (weight > MAX_SYNAPSE)
weight = MAX_SYNAPSE; /* limit weight in case of overflow */
else if (weight < -MAX_SYNAPSE)
weight = -MAX_SYNAPSE; /* limit weight in case of underflow */
*/
*synapses++ = (SYNAPSE)weight; /* put new weight back in synapse*/
}
#else /* use Megamax inline assembly for Motorola */
asm
{
move.w history(A6), A1;
A1 = history move.w momentum(A6), D2;
D2 = momentum move.w error(A6), D3;
D3 = error move.w#FEEDBACK_SHIFT, D4;
D4 = shift factorfor feedback move.w#DELTA_SHIFT, D5;
D5 = shift factorfor delta bra end;
loop:; while (--n >= 0)
;
get weight from synapse clr.l D0;
weight = 0L move.w(synapses), D0;
weight = *synapse;
feedback error to inputs move.w D0, D1;
feedback = weight muls D3, D1;
feedback *= error asr.l D4, D1;
feedback >>= FEEDBACK_SHIFT add.w D1, O_ERROR()(inputs);
inputs->errors += feedback;
delta proportional to input move.w(inputs), D1;
delta = inputs->activation adda.l#NEURON_SIZE, inputs;
inputs++;
delta proportional to error muls D3, D1;
delta *= error asr.l D5, D1;
delta >>= DELTA_SHIFT;
add momentum to delta cmp.w#0, D2;
if (0 != momentum)
beq.s mod;
add.w(A1), D1;
delta += *history move.w D1, (A1) + ;
*history++ = delta;
modify weight by delta ext.l D1;
(long)delta
mod:
add.l D1, D0;
weight += delta;
limit overflow or underflow cmp.w#MAX_SYNAPSE, D0;
if (MAX_SYNAPSE < weight)
blt.s low;
move.w#MAX_SYNAPSE, D0;
weight = MAX_SYNAPSE bra.s new;
low:
cmp.w# - MAX_SYNAPSE, D0;
else if (-MAX_SYNAPSE > weight)
bgt.s new;
move.w# - MAX_SYNAPSE, D0;
weight = -MAX_SYNAPSE;
put new weight back in synapse
new:
move.w D0, (synapses) + ;
*synapse++ = weight
end:
dbf n_inputs, loop
}
#endif
}
Listing5
#include <stdio.h>
#include "synapsys.h"
#ifdef MEGAMAX
long tickcount();
#define TickCount() tickcount()
#else /* MPW */
#include <events.h>
#endif
main()
{
char s[81];
int i, j, err, n_layer, n_neuron[2], rate, momentum;
long n, n_inp, n_out, t1, t2;
float tt, te, sse;
NETWORK *network;
NEURON *inputs, *outputs;
/* prompt for network to test */
printf("enter number of iterations:\n");
gets(s), n = atoi(s);
printf("enter number of inputs:\n");
gets(s), n_inp = atoi(s);
n_neuron[0] = n_inp;
printf("enter number of outputs:\n");
gets(s), n_out = atoi(s);
n_neuron[1] = n_out;
printf("enter learning rate (0 to 128):\n");
gets(s), rate = atoi(s);
printf("enter momentum (0 or 1):\n");
gets(s), momentum = atoi(s);
/* create one layer network, randomize synapses */
network = new_network(1, n_neuron, &rate, &momentum);
if (!network)
printf("\nout of memory\n"), exit(0);
inputs = network->first_layer->inputs;
outputs = network->last_layer->outputs;
randomize(network, 127, 1L);
/* initialize input */
for (i = 1; i <= n_inp; i++)
inputs[i].activation = i * 100 / n_inp;
/* time network */
for (tt = te = i = 0; i < n; i++)
{
/* calculate outputs */
t1 = TickCount();
feedforward(network);
t2 = TickCount();
tt += (float)(t2 - t1);
/* calculate errors, report mean squared error */
for (sse = 0, j = 0; j < n_out; j++, sse += err * err)
err = outputs[j].errors = j * 100 / n_out - outputs[j].activation;
printf("iteration %d mse %f\n", i, sse / n_out);
/* correct synapse weights */
t1 = TickCount();
feedback(network);
t2 = TickCount();
te += (float)(t2 - t1);
}
/* report results */
printf("feedforward: %7.2f transfers/sec\n",
(n * n_inp * n_out) / (tt / 60.));
printf("feedback: %7.2f errors/sec\n",
(n * n_inp * n_out) / (te / 60.));
getchar();
}
/* create a new network of n_layer synapse layers with
n_neuron[i] input neurons and
n_neuron[i+1] output neurons
for each layer of synapses
the learning rate for each layer is set to rate[i]
the presence of history synapses for each layer is controlled by
momentum[i]
return pointer to network, or 0 if out of memory
*/
NETWORK *new_network(n_layer, n_neuron, rate, momentum)
int n_layer, n_neuron[], rate[], momentum[];
{
NETWORK *network;
int i;
LAYER *layer, *prev_layer = 0;
char *calloc();
network = (NETWORK *)calloc(1, sizeof(NETWORK));
if (!network)
return 0;
for (i = 0; i < n_layer; i++, prev_layer = layer)
{
layer = (LAYER *)calloc(1, sizeof(LAYER));
if (!layer)
return 0;
layer->n_inputs = n_neuron[i];
layer->n_outputs = n_neuron[i + 1];
layer->rate = rate[i];
layer->momentum = momentum[i];
layer->inputs = (NEURON *)calloc(layer->n_inputs, sizeof(NEURON));
if (!layer->inputs)
return 0;
if (prev_layer)
{
layer->prev_layer = prev_layer;
layer->prev_layer->next_layer = layer;
layer->prev_layer->outputs = layer->inputs;
}
else
network->first_layer = layer;
layer->synapses = (SYNAPSE *)calloc(layer->n_inputs *
layer->n_outputs,
sizeof(SYNAPSE));
if (!layer->synapses)
return 0;
if (momentum[i])
{
layer->history = (SYNAPSE *)calloc(layer->n_inputs *
layer->n_outputs,
sizeof(SYNAPSE));
if (!layer->history)
return 0;
}
else
layer->history = 0;
}
layer->outputs = (NEURON *)calloc(layer->n_outputs, sizeof(NEURON));
if (!layer->outputs)
return 0;
network->last_layer = layer;
return network;
}
/* feed activations forward through all layers of a network */
feedforward(network)
NETWORK *network;
{
int n_inputs;
SYNAPSE *synapses;
NEURON *inputs, *output, *end_out;
LAYER *layer;
/* loop forward through all layers */
for (layer = network->first_layer; layer; layer = layer->next_layer)
{
synapses = layer->synapses;
n_inputs = layer->n_inputs;
inputs = layer->inputs;
output = layer->outputs;
end_out = layer->n_outputs + output;
/* feed activations forward through this layer */
for (; output < end_out; output++, synapses += n_inputs)
transfer(n_inputs, inputs, output, synapses);
}
}
/* feed errors back through all layers of a network */
feedback(network)
NETWORK *network;
{
int n_inputs, rate, momentum;
SYNAPSE *synapses, *history;
NEURON *inputs, *output, *end;
LAYER *layer;
/* loop back through all layers */
for (layer = network->last_layer; layer; layer = layer->prev_layer)
{
/* clear out previous errors */
n_inputs = layer->n_inputs;
inputs = layer->inputs;
while (--n_inputs >= 0)
(inputs++)->errors = 0;
/* feed errors back through this layer */
n_inputs = layer->n_inputs;
inputs = layer->inputs;
output = layer->outputs;
synapses = layer->synapses;
history = layer->history;
rate = layer->rate;
momentum = layer->momentum;
end = output + layer->n_outputs;
for (; output < end;
output++, synapses += n_inputs, history += n_inputs)
error(n_inputs, inputs, output, synapses, history, rate,
momentum);
}
}
/*
Good random number generator with period 4286449341.
Result is unsigned WORD with uniform
distribution in range 0 to 65535.
Seeds must be unsigned WORD, with no side effects.
Quite fast if seeds are in registers.
*/
#define U2RAND(seed1,seed2) \
(((seed1)*=65421,++(seed1))+((seed2)*=65521,++(seed2)))
/* add a signed pseudo-random value to all weights in a network */
randomize(network, max, seed)
NETWORK *network;
unsigned max;
long seed;
{
register unsigned WORD seed1 = seed, seed2 = seed >> 16;
WORD div = 32768 / max;
register SYNAPSE *weight, *end;
LAYER *layer = network->first_layer;
do
{
weight = layer->synapses;
if (weight)
{
end = weight + layer->n_inputs * layer->n_outputs;
do
*weight++ += (WORD)((long)U2RAND(seed1, seed2) - 32768) / div;
while (weight < end);
}
} while (layer = layer->next_layer);
}