_USING NEURAL NETWORKS FOR PATTERN RECOGNITION_ by Todd King [LISTING ONE] #include #define EXTERN extern #include "neural.h" /*-- MAKE_MIND --------------------------------------- Constructs a mental unit with the given number of input, hidden and output neurons. ------------------------------------------------------*/ make_mind(in, hid, out) int in; int hid; int out; { if ( in > MAX_NEURONS || hid > MAX_NEURONS || out > MAX_NEURONS ) return(0); if (in < 1 || hid < 1 || out < 1 ) return(0); Mind.n_input = in; Mind.n_hidden = hid; Mind.n_output = out; set_cluster_fun(NULL, NULL); set_all_weights(1.0); set_act_fun(pass); set_user_in_fun(prompted); set_result_fun(print_binary_state); strcpy(Prompt.string, "Input a value for neuron %d: "); Prompt.count = 1; return(1); } /*-- ACTIVATE_MIND ----------------------------------------- Sets a mind in motion. Sequentially activating each neuron -----------------------------------------------------------*/ activate_mind() { int i; float net_input; /* Activate input layer */ Prompt.count = 1; for (i = 0; i < Mind.n_input; i++) { Mind.i_layer[i].value = Mind.user_in_fun(); } /* Activate hidden layer */ for (i= 0; i < Mind.n_hidden; i++) { net_input = weighted_sum(i, HIDDEN); Mind.h_layer[i].value = Mind.act_fun(net_input); } /* Activate feedback/certainty function (if one is set) */ if ( Mind.certainty != NULL) Mind.cluster_fun(Mind.certainty); /* Activate output layer */ for (i=0; i < Mind.n_output; i++) { net_input = weighted_sum(i, OUTPUT); Mind.o_layer[i].value = Mind.act_fun(net_input); Mind.result_fun(Mind.o_layer[i].value); } } /*-- SET_ALL_WEIGHTS -------------------------------------- Sets the weight of all connections between all neurons in all layers to the given value ----------------------------------------------------------*/ set_all_weights(value) float value; { int i, j; /* Weights between input and hidden */ for(i = 0; i < Mind.n_input; i++) { for(j = 0; j < Mind.n_hidden; j++) { Input_to_hidden[i][j].weight = value; } } /* Weights between hidden and output */ for(i=0; i< Mind.n_hidden; i++) { for(j = 0; j < Mind.n_output; j++) { Hidden_to_output[i][j].weight = value; } } } /*-- SET_WEIGHT ------------------------------------- Sets the weight between two neurons to a given value. ------------------------------------------------------*/ set_weight(from, to, layer, value) int from; int to; int layer; float value; { switch (layer) { case HIDDEN: if (from > Mind.n_input) return; if (to > Mind.n_hidden) return; Input_to_hidden[from][to].weight = value; break; case OUTPUT: if (from > Mind.n_hidden) return; if (to > Mind.n_output) return; Hidden_to_output[from][to].weight = value; break; default: break; } return; } /*-- WEIGHT_SUM -------------------------------------------- Calculates the weighted sum for a given neuron in a given layer ----------------------------------------------------------*/ float weighted_sum(this_neuron, this_layer) int this_neuron; int this_layer; { int i; float sum = 0.0; switch (this_layer) { case HIDDEN: for (i = 0; i < Mind.n_input; i++) { sum += (Mind.i_layer[i].value * Input_to_hidden[i][this_neuron].weight); } break; case OUTPUT: for (i = 0; i < Mind.n_hidden; i++) { sum += (Mind.h_layer[i].value * Hidden_to_output[i][this_neuron].weight); } break; default: break; } return (sum); } /*-- PASS ---------------------------------------------- Returns the input value. A dummy activation function. --------------------------------------------------------*/ float pass(value) float value; { return (value); } /*-- PROMPTED --------------------------------------- Prompts the user for an input value and returns the value. A user input function. -----------------------------------------------------*/ float prompted() { float value; printf(Prompt.string, Prompt.count++); scanf("%f", &value); return(value); } /*-- PRINT_BINARY_STATE ------------------------------- Prints the output state of a neuron. If greater than 0.0 the value printed is "on", otherwise "off". ------------------------------------------------------*/ float print_binary_state(value) float value; { printf("The output gate is: "); if (value > 0.0) printf("ON."); else printf("OFF."); printf("\n"); } [LISTING TWO] /* Linear network */ #define EXTERN #include "neural.h" #define MEMBERS 5 float print_vote_state(); #define plural(x) (x == 1 ? "" : "s") main() { int i; make_mind(5,1,1); set_result_fun(print_vote_state); strcpy(Prompt.string, "Ballot for member %d: "); for(i=0; i 0) printf("FOR, by %d vote%s", votes, plural(votes) ); else if (votes < 0) printf("AGAINST, by %d vote%s", -votes, plural(-votes) ); else printf("A TIE"); printf(".\n"); } [LISTING THREE] /* Simple linear threshold network. Demonstates logic gates */ #define EXTERN #include "neural.h" float linear_threshold(); main() { int i; /* OR gates work using the default weights (1.0) */ strcpy(Prompt.string, "Logic state of gate %d: "); printf("Logic values: 1, on; 0, off\n\n"); printf("OR logic gate.\n"); printf("--------------\n\n"); make_mind(2, 1, 1); activate_mind(); /* AND gates must have weights < 1.0 ( and > 0.0) */ printf("\n"); printf("AND logic gate.\n"); printf("--------------\n\n"); for(i = 0; i < 2; i++) { set_weight(i, 0, HIDDEN, 0.5); } activate_mind(); /* XOR gates are the most complicated */ printf("\n"); printf("XOR logic gate.\n"); printf("--------------\n\n"); make_mind(2, 2, 1); set_weight(0, 0, HIDDEN, 1.0); set_weight(1, 0, HIDDEN, -1.0); set_weight(0, 1, HIDDEN, -1.0); set_weight(1, 1, HIDDEN, 1.0); set_weight(0, 0, OUTPUT, 1.0); set_weight(1, 0, OUTPUT, 1.0); set_act_fun(linear_threshold); activate_mind(); } /*-- LINEAR_THRESHOLD ------------------------------------- If the input value is greater than zero then it returns 1.0, otherwise it returns 0.0. A linear threshold activation function. ----------------------------------------------------------*/ float linear_threshold(value) float value; { if (value > 0.0) return(1.0); else return(0.0); } [LISTING FOUR] /* Optical Character Recognition (OCR) neural network This is a hybrid between a linear threshold, fully interconnected network and a linear network. The transition being at the hidden layer. A Feedback neuron gaurantees a pattern match in the threshold layer. */ #include #define EXTERN #include "neural.h" float percep(); float print_ocr(); float certainty_cluster(); float Certainty; FILE *Ocr_fptr; main(argc, argv) int argc; char *argv[]; { int i; if(argc < 2) { printf("proper usage: ocr [ ...] [-test ...]\n"); exit(-1); } make_mind(35, 3, 1); set_user_in_fun(percep); set_result_fun(print_ocr); set_cluster_fun(certainty_cluster, &Certainty); set_all_weights(0.0); /* Teach the network about the patterns */ i = 1; while(strcmp(argv[i], "-test") != 0) { printf("Learning: %s\n", argv[i]); if( i > Mind.n_hidden) { printf("Too many pattern groups for the given topology, aborting.\n"); exit(-1); } ocr_learn(argv[i], i - 1); i++; if(i >= argc) { printf("Nothing to test - exiting\n"); exit(-1); } } /* Classify each pattern based on what the network knows */ i++; /* Skip over "-test" deliniator */ while(i < argc) { printf("Testing %s\n", argv[i]); if ((Ocr_fptr = fopen(argv[i], "r")) == NULL) { perror(argv[i]); printf("Unable to open file, skipping pattern.\n"); i++; continue; } activate_mind(); fclose(Ocr_fptr); i++; } } /*-- PERCEP ------------------------------------------------ Returns the value of the next pixel every time its called. The pixel state is determined from the contents of the pre-opened file pointed to by 'Ocr_fptr'. ----------------------------------------------------------*/ float percep() { extern FILE *Ocr_fptr; int pixel_value; fscanf(Ocr_fptr, "%1d", &pixel_value); return( (float)pixel_value); } /*-- PRINT_OCR ------------------------------------- Prints the character which the network determines it to be. Also prints the certainty of the match. ------------------------------------------------------*/ float print_ocr(value) float value; { extern float Certainty; printf("The character is '%c' (%d).\n", (int)value, (int)value); printf("with a certainty of %3.2f%.\n", Certainty); } /*-- OCR_LEARN ----------------------------- Teach the network how to classify a pattern. --------------------------------------------*/ ocr_learn(filename, group_id) char filename[]; int group_id; { int i; FILE *fptr; int pixel_cnt = 0; int pixel_value; float dist_weight; float output_value; if ((fptr = fopen(filename, "r")) == NULL) { perror(filename); printf("Skipping pattern.\n"); return(0); } /* Determine the number of "on" pixels, hence fractional weight */ for(i=0; i < Mind.n_input; i++) { fscanf(fptr, "%1d", &pixel_value); if(pixel_value == 1) pixel_cnt++; } dist_weight = 1.0/pixel_cnt; rewind(fptr); /* Set fractional weight for each "on" connection */ for(i=0; i < Mind.n_input; i++) { fscanf(fptr, "%1d", &pixel_value); if(pixel_value == 1) set_weight(i, group_id, HIDDEN, dist_weight); } /* Now set weight for output value for this character */ fscanf(fptr, "%f", &output_value); set_weight(group_id, 0, OUTPUT, output_value); fclose(fptr); return(1); } /*-- CERTAINTY_CLUSTER ------------------------------------ Performs a cluster function. It inhibits (sets to 0) all neurons in the cluster except the one which is closest to the value 1.0. This neuron is set to 1.0. The passed variable is assigned the certainty to which the closest neuron felt it matched the pattern ----------------------------------------------------------*/ float certainty_cluster(certainty) float *certainty; { int i; float highest = 0.0; int closest = -1; for(i=0; i highest) { closest = i; highest = Mind.h_layer[i].value; } } if(closest == -1) /* All are equally likely - choose the first */ { closest = 0; } *certainty = Mind.h_layer[closest].value * 100.0; /* Cause just enough feedback to the neuron which is closest to being "on" so that it is "on". That is set it "on" All others are given negative feedback to force them to zero. (set them to zero). */ for( i = 0; i < Mind.n_hidden; i++) { if (i == closest) Mind.h_layer[i].value = 1.0; else Mind.h_layer[i].value = 0.0; } } [LISTING FIVE] #ifndef _NEURAL_ #define _NERUAL_ #define MAX_NEURONS 35 #define HIDDEN 1 #define OUTPUT 2 /* Type definition for neurons and neural networks */ typedef struct { float value; } NEURON; typedef struct { int n_input; int n_hidden; int n_output; float *certainty; float (*cluster_fun)(); float (*act_fun)(); float (*user_in_fun)(); float (*result_fun)(); NEURON i_layer[MAX_NEURONS]; NEURON h_layer[MAX_NEURONS]; NEURON o_layer[MAX_NEURONS]; } MIND; typedef struct { float weight; } WEIGHTS; typedef struct { char string[80]; int count; } PROMPT; /* Global Variables */ EXTERN MIND Mind; EXTERN WEIGHTS Input_to_hidden[MAX_NEURONS][MAX_NEURONS]; EXTERN WEIGHTS Hidden_to_output[MAX_NEURONS][MAX_NEURONS]; EXTERN PROMPT Prompt; /* Functions */ float weighted_sum(); float pass(); float prompted(); float print_binary_state(); float certainty_fun(); int activate_mind(); /* Pseudo-functions */ #define set_act_fun(f) Mind.act_fun = f #define set_user_in_fun(f) Mind.user_in_fun = f #define set_back_prop_fun(f) Mind.back_prop_fun = f #define set_result_fun(f) Mind.result_fun = f #define set_cluster_fun(f, x) Mind.cluster_fun = f; Mind.certainty = x #endif [LISTING SIX] Board: board.c (neural.h) neurlib.c (neural.h) Logic: logic.c (neural.h) neurlib.c (neural.h) OCR: ocr.c (neural.h) neurlib.c (neural.h)