openModeller
Version 1.4.0
|
00001 #ifndef _LIBNN_H 00002 #define _LIBNN_H 00003 00004 #ifdef __cplusplus 00005 extern "C" { 00006 #endif 00007 00008 #ifndef WIN32 00009 #include <sys/time.h> 00010 #include <sys/resource.h> 00011 #else 00012 #include <time.h> 00013 #endif 00014 00015 00016 #include <ctype.h> 00017 #include <float.h> 00018 #include <string.h> 00019 #include <stdarg.h> 00020 00021 00022 struct nn_parameter 00023 { 00024 // General Variables 00025 int inp; 00026 int hid; 00027 int outp; 00028 int pattern; 00029 double learning_rate; 00030 double momentum; 00031 00032 // Choice Variable between training by epoch or minimum error 00033 int choice; 00034 00035 // Variables especified of training by epoch 00036 double epoch; 00037 00038 // Variables especified of training by minimum error 00039 double minimum_error; 00040 }; 00041 00042 00043 /* 00044 * Neural Network was based on the algorithm created by Paras Chopra. 00045 * Email: paras1987@gmail.com 00046 * Web: www.paraschopra.com 00047 * 00048 * Changes made in the algorithm are shown with A&F at the beginning of the sentence. 00049 * Amended by Alex Oshika Avilla & Fabricio Augusto Rodrigues 00050 */ 00051 00052 #include <stdio.h> 00053 #include <stdlib.h> 00054 #include <math.h> //For tanh 00055 00056 00057 /*A&F*/// returns a float in the range -1.0f -> - 1.0f 00058 #define RANDOM_CLAMP (((double)rand()-(float)rand())/10000000) 00059 00060 /*A&F*///returns a float between 0 & 1 00061 #define RANDOM_NUM ((double)rand()/(10000000+1)) 00062 00063 //using namespace std; 00064 00065 00066 /*A&F*/class Dendrite{ 00067 00068 public: 00069 00070 // Weights of the neuron 00071 double d_weight; 00072 double d_weight_ancient; 00073 double d_weight_actual; 00074 unsigned long d_points_to; // The index of the neuron of the next layer to which it points 00075 00076 Dendrite(double weight = 0.0, double weight_ancient = 0.0, double weight_actual = 0.0, unsigned long points_to = 0){ //Constructor 00077 00078 d_weight = weight; 00079 d_weight_ancient = weight_ancient; 00080 d_weight_actual = weight_actual; 00081 d_points_to = points_to; // Give it a initial value 00082 } 00083 }; 00084 00085 00086 class Neuron{ 00087 00088 public: 00089 00090 unsigned long n_ID; // ID of a particular neuron in a layer. Used to find a particular neuron in an array 00091 double n_value; // Value which Neuron currently is holding 00092 double n_bias; // Bias of the neuron 00093 double n_delta; // Used in back prop. Note it is backprop specific 00094 00095 Dendrite *Dendrites; // Dendrites 00096 00097 // Constructor assigning initial values 00098 Neuron(unsigned long ID = 0,double value = 0.0,double bias = 0.0){ 00099 00100 n_ID = ID; 00101 n_value = value; 00102 n_bias = bias; 00103 n_delta = 0.0; 00104 } 00105 00106 void SetDendrites(unsigned long dendrite){ // Set the dendrites from the neuron to given dendrite 00107 00108 Dendrites = new Dendrite[dendrite]; 00109 00110 for(unsigned long i = 0; i < dendrite; i++){ 00111 00112 Dendrites[i].d_points_to = i; // Initialize the dendrite to attach to next layer 00113 } 00114 } 00115 }; 00116 00117 00118 class Layer{ 00119 00120 public: 00121 00122 Neuron *Neurons; // Pointer to array of neurons 00123 00124 /*Layer(int size = 1){ // Size is no. of neurons in it 00125 00126 Neurons = new Neuron [size]; 00127 } */ 00128 00129 void Initialize(int size) { // Initialize the layer 00130 00131 Neurons = new Neuron [size]; 00132 } 00133 00134 ~Layer(){ // Destructor deletes Neurons from the memory 00135 00136 delete Neurons; 00137 } 00138 00139 Neuron GetNeuron(int index){ // Give the neuron at index 00140 00141 return Neurons[index]; 00142 } 00143 00144 void SetNeuron(Neuron neuron, int index){ // Sets the neuron 00145 00146 Neurons[index] = neuron; 00147 } 00148 }; 00149 00150 00151 /*A&F*/class Network { // The real neural network 00152 00153 public: 00154 00155 double net_learning_rate; // Learning rate of network 00156 Layer *Layers; // The total layers in network 00157 int net_tot_layers; // Number of layers 00158 double *net_inputs; // Input array 00159 double *net_outputs;// Output layers 00160 int *net_layers; // Array which tells no. of neurons in each layer 00161 //double GetRand(void); 00162 00163 double *square_error; // Mean square error of each training 00164 double *mean_square_error; // Total plus of each epoch 00165 00166 float progress; // Percent of training 00167 00168 Network() { 00169 // Blank Constructor 00170 } 00171 00172 00173 int SetData(double learning_rate, int layers[], int tot_layers) { // Function to set various parameters of the net 00174 00175 if (tot_layers<2) return(-1); // Return error if total no. of layers < 2 00176 // Because input and output layers are necessary 00177 00178 net_learning_rate = learning_rate; 00179 00180 net_layers = new int [tot_layers]; // Initialize the layers array 00181 00182 Layers = new Layer[tot_layers]; 00183 00184 00185 for(int i = 0; i < tot_layers; i++){ 00186 00187 net_layers[i] = layers[i]; 00188 00189 Layers[i].Initialize(layers[i]); // Initialize each layer with the specified size 00190 } 00191 00192 00193 net_inputs = new double[layers[0]]; 00194 00195 net_outputs = new double[layers[tot_layers-1]]; 00196 00197 net_tot_layers = tot_layers; 00198 00199 00200 return 0; 00201 } 00202 00203 00204 void SetInputs(vector<double> inputs) const{ // Function to set the inputs 00205 00206 for(int i = 0; i < net_layers[0]; i++){ 00207 00208 Layers[0].Neurons[i].n_value = inputs[i]; 00209 } 00210 } 00211 00212 00213 void RandomizeWB(void){ // Randomize weights and biases 00214 00215 int i,j,k; 00216 00217 for(i = 0; i < net_tot_layers; i++){ 00218 00219 for(j = 0; j < net_layers[i]; j++){ 00220 00221 if(i != net_tot_layers-1){ // Last layer does not require weights 00222 00223 Layers[i].Neurons[j].SetDendrites(net_layers[i+1]); //Initialize the dendrites 00224 00225 for(k = 0; k < net_layers[i+1]; k++){ 00226 00227 Layers[i].Neurons[j].Dendrites[k].d_weight = 0.000000; // Let weight be the zero value 00228 Layers[i].Neurons[j].Dendrites[k].d_weight_ancient = 0.000000; // Let weight be the zero value 00229 Layers[i].Neurons[j].Dendrites[k].d_weight_actual = GetRand(); // Let weight be the random value 00230 } 00231 00232 } 00233 00234 if(i != 0){ // First layer does not need biases 00235 00236 Layers[i].Neurons[j].n_bias = GetRand(); 00237 } 00238 } 00239 } 00240 } 00241 00242 00243 double * GetOutput(void) const{ // Gives the output of the net 00244 00245 double *outputs; 00246 int i,j,k; 00247 00248 outputs = new double[net_layers[net_tot_layers-1]]; // Temp ouput array 00249 00250 for(i = 1; i < net_tot_layers; i++){ 00251 00252 for(j = 0; j < net_layers[i]; j++){ 00253 00254 Layers[i].Neurons[j].n_value = 0; 00255 00256 for(k = 0; k < net_layers[i-1]; k++){ 00257 00258 Layers[i].Neurons[j].n_value = Layers[i].Neurons[j].n_value + Layers[i-1].Neurons[k].n_value * Layers[i-1].Neurons[k].Dendrites[j].d_weight; // Multiply and add all the inputs 00259 } 00260 00261 Layers[i].Neurons[j].n_value = Layers[i].Neurons[j].n_value + Layers[i].Neurons[j].n_bias; // Add bias 00262 00263 Layers[i].Neurons[j].n_value = Limiter(Layers[i].Neurons[j].n_value); // Squash that value 00264 00265 } 00266 } 00267 00268 for(i = 0; i < net_layers[net_tot_layers-1]; i++){ 00269 00270 outputs[i] = Layers[net_tot_layers-1].Neurons[i].n_value; 00271 } 00272 00273 return outputs; // Return the outputs 00274 } 00275 00276 00277 /******************************************************************/ 00278 // Used at _GetConfiguration and _SetConfiguration in the library nn_alg.cpp 00279 00280 double getWeight(int i, int j, int k) const{ // Get weights 00281 00282 return Layers[i].Neurons[j].Dendrites[k].d_weight; 00283 } 00284 00285 00286 void setWeight(int i, int j, int k, double w){ // Set weights 00287 00288 Layers[i].Neurons[j].Dendrites[k].d_weight = w; 00289 00290 } 00291 00292 00293 double getBias(int i, int j) const{ // Get bias 00294 00295 return Layers[i].Neurons[j].n_bias; 00296 } 00297 00298 00299 void setBias(int i, int j, double b){ // Set bias 00300 00301 Layers[i].Neurons[j].n_bias = b; 00302 } 00303 /******************************************************************/ 00304 00305 00306 void Update(void){ // Just a dummy function 00307 00308 double *temp; // Temperory pointer 00309 temp = GetOutput(); 00310 //GetOutput(); 00311 delete[] temp; 00312 } 00313 00314 00315 /*void SetOutputs(double outputs[]){ //Set the values of the output layer 00316 00317 for(unsigned long i = 0; i < net_layers[net_tot_layers-1]; i++){ 00318 00319 Layers[net_tot_layers-1].Neurons[i].n_value = outputs[i]; //Set the value 00320 } 00321 } */ 00322 00323 00324 double Limiter(double value) const{ // Limiet to limit value between 1 and -1 00325 00326 //return tanh(value); // To use tanh fuction 00327 return (1.0/(1+exp(-value))); // To use sigmoid function 00328 } 00329 00330 00331 double GetRand(void){ // Return a random number between range -1 e 1 using time to seed the srand function 00332 00333 int seconds; 00334 00335 #ifndef WIN32 00336 struct timeval time; 00337 gettimeofday( &time, (struct timezone *)NULL ); 00338 seconds = (int)time.tv_usec; 00339 #else 00340 time_t timer = time( NULL ); 00341 struct tm *tblock = localtime(&timer); 00342 seconds = tblock->tm_sec; 00343 #endif 00344 00345 int seed = int(seconds + 100*RANDOM_CLAMP + 100*RANDOM_NUM); 00346 //srand(seconds); 00347 srand(seed); 00348 00349 #ifdef _GLIBCPP_HAVE_DRAND48 00350 srand48(seed); 00351 #endif 00352 00353 return ((RANDOM_CLAMP+RANDOM_NUM)/400); 00354 } 00355 00356 00357 double SigmaWeightDelta( unsigned long layer_no, unsigned long neuron_no){ // Calculate sum of weights * delta. Used in back prop. layer_no is layer number. Layer number and neuron number can be zero and neuron_no is neuron number. 00358 00359 double result = 0.0; 00360 00361 for(int i = 0; i < net_layers[layer_no+1]; i++) { // Go through all the neurons in the next layer 00362 00363 result = result + Layers[layer_no].Neurons[neuron_no].Dendrites[i].d_weight * Layers[layer_no+1].Neurons[i].n_delta; // Comput the summation 00364 } 00365 00366 return result; 00367 } 00368 00369 00370 /* 00371 For output layer: 00372 00373 Delta = (TargetO - ActualO) * ActualO * (1 - ActualO) 00374 Weight = Weight + LearningRate * Delta * Input 00375 00376 For hidden layers: 00377 00378 Delta = ActualO * (1-ActualO) * Summation(Weight_from_current_to_next AND Delta_of_next) 00379 Weight = Weight + LearningRate * Delta * Input 00380 */ 00381 00382 00383 void setError(int max_pattern){ // Function to set the errors 00384 00385 mean_square_error = new double; 00386 *mean_square_error = 0.000000; 00387 00388 square_error = new double [max_pattern]; 00389 00390 for(int i = 0; i < max_pattern; i++){ 00391 00392 square_error[i] = 0.000000; 00393 } 00394 } 00395 00396 00397 void addError(int max_pattern){ // Function to add the errors 00398 00399 for(int i = 0; i < max_pattern; i++){ 00400 00401 *mean_square_error += square_error[i]; 00402 } 00403 00404 delete[] square_error; 00405 } 00406 00407 00408 int Train(vector<double> inputs, vector<double> outputs, int number_pattern, int max_pattern, double momentum){ // The standard Backprop Learning algorithm 00409 00410 int i,j,k; 00411 00412 double *Target = new double; 00413 double *Delta = new double; 00414 double *Actual = new double; 00415 double *error = new double;; 00416 00417 00418 SetInputs(inputs); // Set the inputs 00419 00420 Update(); // Update all the values 00421 00422 //SetOutputs(outputs); // Set the outputs 00423 00424 00425 if(number_pattern == 0){ 00426 00427 setError(max_pattern); 00428 } 00429 00430 00431 for(i = (net_tot_layers-1); i > 0; i--){ // Go from last layer to first layer 00432 00433 for(j = 0; j < net_layers[i]; j++) {// Go thru every neuron 00434 00435 if(i == (net_tot_layers-1)){ // Output layer, Needs special atential 00436 00437 (*Target) = outputs[j]; // Target value 00438 (*Actual) = Layers[i].Neurons[j].n_value; // Actual value 00439 00440 (*Delta) = ((*Target) - (*Actual)) * (*Actual) * (1 - (*Actual)); // Function to compute error 00441 00442 Layers[i].Neurons[j].n_delta = (*Delta); // Compute the delta 00443 00444 00445 for(k = 0; k < net_layers[i-1]; k++) { 00446 00447 Layers[i-1].Neurons[k].Dendrites[j].d_weight = ( Layers[i-1].Neurons[k].Dendrites[j].d_weight_actual) + ( net_learning_rate * (*Delta) * Layers[i-1].Neurons[k].n_value) + (momentum * ( Layers[i-1].Neurons[k].Dendrites[j].d_weight_actual - Layers[i-1].Neurons[k].Dendrites[j].d_weight_ancient)); // Calculate the new weights 00448 00449 Layers[i-1].Neurons[k].Dendrites[j].d_weight_ancient = Layers[i-1].Neurons[k].Dendrites[j].d_weight_actual; 00450 Layers[i-1].Neurons[k].Dendrites[j].d_weight_actual = Layers[i-1].Neurons[k].Dendrites[j].d_weight; 00451 } 00452 00453 Layers[i].Neurons[j].n_bias = Layers[i].Neurons[j].n_bias + (*Delta) * net_learning_rate * 1; // n_value is always 1 for bias 00454 00455 00456 *error = ((*Target) - (*Actual)); 00457 } 00458 else { // Here 00459 00460 // Target value 00461 (*Actual) = Layers[i].Neurons[j].n_value; // Actual value 00462 00463 (*Delta) = (*Actual) * (1 - (*Actual)) * SigmaWeightDelta(i,j); // Function to compute error 00464 00465 00466 for(k = 0; k < net_layers[i-1]; k++) { 00467 00468 Layers[i-1].Neurons[k].Dendrites[j].d_weight = ( Layers[i-1].Neurons[k].Dendrites[j].d_weight_actual) + ( net_learning_rate * (*Delta) * Layers[i-1].Neurons[k].n_value) + (momentum * ( Layers[i-1].Neurons[k].Dendrites[j].d_weight_actual - Layers[i-1].Neurons[k].Dendrites[j].d_weight_ancient)); // Calculate the new weights 00469 00470 Layers[i-1].Neurons[k].Dendrites[j].d_weight_ancient = Layers[i-1].Neurons[k].Dendrites[j].d_weight_actual; 00471 Layers[i-1].Neurons[k].Dendrites[j].d_weight_actual = Layers[i-1].Neurons[k].Dendrites[j].d_weight; 00472 } 00473 00474 00475 if(i != 0){ // Input layer does not have a bias 00476 00477 Layers[i].Neurons[j].n_bias = Layers[i].Neurons[j].n_bias + (*Delta) * net_learning_rate * 1; // n_value is always 1 for bias 00478 } 00479 } 00480 } 00481 } 00482 00483 00484 square_error[number_pattern] = (*error) * (*error); 00485 00486 00487 if(number_pattern == (max_pattern - 1)){ 00488 00489 addError(max_pattern); 00490 } 00491 00492 00493 delete Target; 00494 delete Actual; 00495 delete Delta; 00496 delete error; 00497 00498 00499 return 0; 00500 } 00501 00502 00503 // Used to training by epoch 00504 void trainingEpoch( unsigned long actual_epoch, double epoch_total, int patterns){ 00505 00506 *mean_square_error = sqrt(*mean_square_error/patterns); 00507 00508 00509 progress = (float)(1.0-(epoch_total - (actual_epoch+1.0))/(epoch_total)); 00510 00511 delete mean_square_error; 00512 } 00513 00514 00515 // Used to training by minimum error 00516 int trainingMinimumError( int patterns, double min_error){ 00517 00518 int converg = 0; 00519 00520 *mean_square_error = sqrt(*mean_square_error/patterns); 00521 00522 00523 if(*mean_square_error < min_error){ 00524 00525 converg = 1; 00526 progress = 1; 00527 } 00528 00529 else{ 00530 00531 progress = (float)(1.0-(*mean_square_error - min_error)/(*mean_square_error)); 00532 } 00533 00534 00535 delete mean_square_error; 00536 00537 return converg; 00538 } 00539 00540 00541 // Percent of training 00542 float getProgress(){ 00543 00544 return progress; 00545 } 00546 00547 00548 00549 ~Network(){ }//delete Layers; } 00550 00551 }; 00552 00553 00554 #ifdef __cplusplus 00555 } 00556 #endif 00557 00558 #endif /* _LIBNN_H */