/*PAGE Introduction backprop.c Dwayne Phillips August 1992 April 1994 - resumed work The functions in this file implement the backpropogation neural network. NOTES: Dimensions of arrays m = number of inputs n = number of layers of neurons o = number of outputs p = number of neurons in each layer input layer x = 1 X m The weights between input and first neurons win = m X p outputs of the hidden layers h = p X n The weights between hidden layers whid = (n-1) X p X p The weights between last neurons and output wout = p X o output layer y = o X 1 the target target = o x 1 output layer error delta = o x 1 Note Because of problems with malloc and 2 and 3 dimensional arrays, I will use 1 dimensional arrays for everything. For example, if there is an a[2][3], I will make it a[6] with the elements stored as: 0 1 2 3 4 5 For array[a][b], element [i][j] is: array[(i*b) + j] If there is an a[3][2][5], I will make it a[30] with the elements stored as: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 For array[a][b][c], element [i][j][k] is: array[(i*b*c) + (j*c) + k] 5-18-94 Let's use Widrow's method which does not use the weight_delta arrays. Those are used in the momentum variation to backpropogation. Widrow also describes that technique. 5-20-94 ASCII Text Files This program can read many of the user inputs from ASCII text files. This makes it easier on the user sometimes. Instead of typing in everything everytime, you type it into an ASCII file once using any old text editor. This feature works for entering the program parameters and also for entering arrays of input and target data. 5-21-94 The data_sets variable In the input and training modes you have more than one set of input and target data. The working mode only has one data set. The tmp_x and tmp_target variables hold all the data sets and you copy one data set at a time into x and target. 5-30-94 I needed to remove all the references to the h_file since it is not used. 5-30-94 This program only uses the sigmoid function. It does not use any of the other functions so I need to remove the references to the other function types. */ /*PAGE Includes and defines */ #include #include #include #include #include #include typedef float ELEMENT; #define FILL 33.33 #define LENGTH 80 #define TWOMU 0.7 #define MIN_ERROR 0.02 #define TRAINING_LIMIT 99999 #undef ACTIVATE_TEST #undef INIT_TEST #undef SUM_TEST #undef MAT_MUL_TEST #undef INPUT_LAYER_TEST #undef TEST_3D_COPY #undef TEST_1D_COPY #undef TEST_2D_COPY #undef INNER_TEST #undef OUTPUT_LAYER_TEST #undef FORWARD_TEST #undef FILE_TEST #define NORMAL_INPUT #undef DEBUG void malloc_2d(); void malloc_3d(); void vector_sum_of_products(); void initialize_2d_weights(); void initialize_3d_weights(); void display_2d_weights(); void display_3d_weights(); void matrix_multiply(); void input_layer(); void inner_layers(); void output_layer(); void fill_array(); void zero_array(); void copy_3d_to_2d(); void copy_2d_to_1d(); void copy_1d_to_2d(); void apply_function(); void lower_case_string(); void get_program_parameters(); void get_array_from_user(); void write_to_file(); void read_from_file(); void output_layer_error(); void neuron_deltas(); void change_output_weights(); void change_hidden_weights(); void change_input_weights(); void file_input_parameters(); FILE *open_file(); ELEMENT activation_function(); ELEMENT el_abs(); int error_is_acceptable(); /***************************************************/ /***************************************************/ /*PAGE main */ main(argc, argv) int argc; char *argv[]; { char in_file_name[LENGTH], mode[LENGTH], out_file_name[LENGTH], target_file_name[LENGTH], type[LENGTH], whid_file_name[LENGTH], win_file_name[LENGTH], wout_file_name[LENGTH]; FILE *in_file, *out_file, *target_file, *whid_file, *win_file, *wout_file; int big_pass = 0, changing_weights = 1, data_sets = 1, i = 0, m = 0, n = 0, o = 0, p = 0, still_training = 1, this_data_set = 0, training_all_data_sets = 1; ELEMENT *delta, *h, *h_delta, *target, *tmp_target, *tmp_x, *x, *y, *whid, *win, *wout; unsigned long training_pass = 0; get_program_parameters(mode, &m, &n, &o, &p, &data_sets, type, in_file_name, out_file_name, target_file_name, whid_file_name, win_file_name, wout_file_name); /********************************* * * Malloc each of the arrays * **********************************/ x = (ELEMENT *) malloc((int)(m) * sizeof(ELEMENT)); y = (ELEMENT *) malloc((int)(o) * sizeof(ELEMENT)); delta = (ELEMENT *) malloc((int)(o) * sizeof(ELEMENT)); target = (ELEMENT *) malloc((int)(o) * sizeof(ELEMENT)); win = (ELEMENT *) malloc((int)(m*p) * sizeof(ELEMENT)); wout = (ELEMENT *) malloc((int)(p*o) * sizeof(ELEMENT)); h = (ELEMENT *) malloc((int)(p*n) * sizeof(ELEMENT)); h_delta = (ELEMENT *) malloc((int)(p*n) * sizeof(ELEMENT)); whid = (ELEMENT *) malloc((int) ((n-1)*p*p) * sizeof(ELEMENT)); tmp_x = (ELEMENT *) malloc((int) (m*data_sets) * sizeof(ELEMENT)); tmp_target = (ELEMENT *) malloc((int) (o*data_sets) * sizeof(ELEMENT)); /********************************* * * Modes of operation * **********************************/ /********************************* * * Input * **********************************/ if( (strncmp(mode, "input", 3) == 0)){ in_file = open_file(in_file_name, "w+b"); target_file = open_file(target_file_name,"w+b"); printf("\n\nEnter the inputs"); get_array_from_user(tmp_x, m*data_sets); printf("\n\nEnter the targets"); get_array_from_user(tmp_target, o*data_sets); write_to_file(tmp_x, m*data_sets, in_file); write_to_file(tmp_target, o*data_sets, target_file); fclose(in_file); fclose(target_file); } /* ends if input */ /********************************* * * Training * **********************************/ if( (strncmp(mode, "training", 3) == 0)){ in_file = open_file(in_file_name, "r+b"); target_file = open_file(target_file_name,"r+b"); win_file = open_file(win_file_name, "w+b"); whid_file = open_file(whid_file_name, "w+b"); wout_file = open_file(wout_file_name, "w+b"); read_from_file(tmp_x, m*data_sets, in_file); read_from_file(tmp_target, o*data_sets, target_file); initialize_2d_weights(win, m, p); initialize_2d_weights(wout, p, o); initialize_3d_weights(whid, (n-1), p, p); changing_weights = 1; while(changing_weights){ printf("\n\n\nbig pass %d training pass %ld ----------------------------", big_pass++, training_pass); changing_weights = 0; this_data_set = 0; training_all_data_sets = 1; while(training_all_data_sets){ for(i=0; i TRAINING_LIMIT)) still_training = 0; else{ changing_weights = 1; training_pass++; neuron_deltas(h, h_delta, delta, whid, wout, n, o, p); change_output_weights(wout, delta, h, n, o, p); change_hidden_weights(whid, h, h_delta, n,p); change_input_weights(x, win,h_delta, m, n, p); } /* ends else still_training */ } /* ends while still_training */ printf("\n\nFinished training data set %d --- training pass %ld", this_data_set, training_pass); printf("\nThis is the result"); display_2d_weights(y, 1, o); printf("\nThis is the target "); display_2d_weights(target, 1, o); printf("\nThis is the delta"); display_2d_weights(delta, 1, o); this_data_set++; if(this_data_set >= data_sets) training_all_data_sets = 0; } /* ends while training_all_data_sets */ } /* ends while changing_weights */ write_to_file(win, m*p, win_file); write_to_file(whid, (n-1)*p*p, whid_file); write_to_file(wout, p*o, wout_file); fclose(in_file); fclose(target_file); fclose(win_file); fclose(whid_file); fclose(wout_file); } /* ends if training */ /********************************* * * Working * **********************************/ if( (strncmp(mode, "working", 3) == 0)){ printf("\nHey this is the working mode!"); in_file = open_file(in_file_name, "r+b"); out_file = open_file(out_file_name,"w+b"); win_file = open_file(win_file_name, "r+b"); whid_file = open_file(whid_file_name, "r+b"); wout_file = open_file(wout_file_name, "r+b"); read_from_file(x, m, in_file); read_from_file(win, m*p, win_file); read_from_file(whid, (n-1)*p*p, whid_file); read_from_file(wout, p*o, wout_file); input_layer(h, x, win, m, p, n, type); inner_layers(h, whid, p, n, type); output_layer(h, wout, y, p, n, o, type); printf("\nThe input was"); display_2d_weights(x, 1, m); printf("\n\nResults: (output)"); display_2d_weights(y, 1, o); fclose(in_file); fclose(out_file); fclose(win_file); fclose(whid_file); fclose(wout_file); } /* ends if working */ /********************************* * * Free each of the arrays * **********************************/ free(x); free(y); free(delta); free(h_delta); free(target); free(h); free(whid); free(win); free(wout); free(tmp_x); free(tmp_target); return(1); } /* ends main */ /***************************************************/ /*PAGE input_layer void input_layer(... This function performs the calculations between the input array and the input weights to produce the first layer of neurons. x[1][m] win[m][p] = first column of h[p][n] Use a tmp array in the call to matrix_multiply then copy the answer back to the first column of h. */ void input_layer(ELEMENT *h, ELEMENT *x, ELEMENT *win, int m, int p, int n, char type[]) { ELEMENT *tmp; tmp = (ELEMENT *) malloc((int)(p) * sizeof(ELEMENT)); zero_array(tmp, p); matrix_multiply(x, 1, m, win, p, tmp); apply_function(tmp, p, type); copy_1d_to_2d(tmp, h, p, n, 0, "col"); free(tmp); } /* ends input_layer */ /***************************************************/ /*PAGE output_layer void output_layer(... This function performs the calculations between the last layer of neurons and the output weights to produce the outputs of the network. last column of h[p][n] wout[p][o] = y[o][1] */ void output_layer(ELEMENT *h, ELEMENT *wout, ELEMENT *y, int p, int n, int o, char type[]) { ELEMENT *tmp; tmp = (ELEMENT *) malloc((int)(p) * sizeof(ELEMENT)); copy_2d_to_1d(tmp, h, p, n, (n-1), "col"); zero_array(y, o); matrix_multiply(tmp, 1, p, wout, o, y); apply_function(y, o, type); free(tmp); } /* ends output_layer */ /***************************************************/ /*PAGE inner_layers void inner_layers(... This function performs the forward calculations for the inner layers. h[p][n] whid[(n-1)][p][p] Perform the multiplications by using the matrix multiplication function and temporary arrays. for i=0; i 1.0) count = count/(ELEMENT)(10.0); if( (odd % 2) == 1) count = count*(ELEMENT)(-1.0); /****array[(i*a) + j] = (ELEMENT)((i*a) + j);****/ array[(i*b) + j] = count; } /* ends loop over j */ } /* ends loop over i */ } /* ends initialize_2d_weights */ /***************************************************/ /*PAGE initialize_3d_weights void initialize_3d_weights(... This function initializes the weights in the 2-dimensional array. They are set to 0 2 4 6 0 2 4 6 ... */ void initialize_3d_weights(ELEMENT *array, int a, int b, int c) { ELEMENT count = (ELEMENT)(0.0); int i, j, k, odd = 0;; for(i=0; i 1.0) count = count/(ELEMENT)(10.0); if( (odd % 2) == 1) count = count*(ELEMENT)(-1.0); array[(i*b*c) + (j*c) + k] = count; } /* ends loop over k */ } /* ends loop over j */ } /* ends loop over i */ } /* ends initialize_3d_weights */ /***************************************************/ /*PAGE display_2d_weights void display_2d_weights(... This function displays the 2-dimemsional weights to the screen. array[a][b] */ void display_2d_weights(ELEMENT *array, int a, int b) { int i, j; printf("\n %d X %d", a, b); for(i=0; i>", i); for(j=0; j>"); for(j=0; j>", i); for(k=0; k