// pittnet.CPP // Backpropagation / ART1 / Kohonen / Radial Basis
// The purpose of this prototype is to allow the user to construct and
// initialize a series of neural nets. Using the concept of inheritance and
// derived classes from C++ object oriented programming, the neceessity to
// declare multiple large structures that duplicate attributes is eliminated
// Utilizing pointers and the "new" function, dynamic arrays are established
// The user can then specify the storage array size for the number of hidden
// units and output units for the neural network while the program is running.
// This strategy eliminates the need to establish extremely large arrays
// while still maintaining the flexibility required to design nets of various.
// shapes and sizes. The "Neural" classes allows the attributes of the newly
// constructed networks to be stored for further processing.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <iostream.h>
#include <string.h>
#include <conio.h>
#include <float.h>
#include <fstream.h>
#include <ctype.h>
#define IA 16807
#define IM 2147483647
#define AM (1.0 / IM)
#define IQ 127773
#define IR 2836
#define NTAB 32
#define NDIV (1+(IM-1) / NTAB)
#define EPS 1.2e-7
#define RNMX (1.0 - EPS)
// The following function is a random number generator
float bedlam(long *idum);
int gaset = -2500;
float bedlam(long *idum)
{
int xj;
long xk;
static long iy=0;
static long iv[NTAB];
float temp;
if(*idum <= 0 || !iy)
{
if(-(*idum) < 1)
{
*idum = 1 + *idum;
}
else
{
*idum = -(*idum);
}
for(xj = NTAB+7; xj >= 0; xj--)
{
xk = (*idum) / IQ;
*idum = IA * (*idum - xk * IQ) - IR * xk;
if(*idum < 0)
{
*idum += IM;
}
if(xj < NTAB)
{
iv[xj] = *idum;
}
}
iy = iv[0];
}
xk = (*idum) / IQ;
*idum = IA * (*idum - xk * IQ) - IR * xk;
if(*idum < 0)
{
*idum += IM;
}
xj = iy / NDIV;
iy = iv[xj];
iv[xj] = *idum;
if((temp=AM*iy) > RNMX)
{
return(RNMX);
}
else
{
return(temp);
}
} // end of bedlam function
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// (Fully connected network using backpropagation)
// In this base class, all nodes in the network have the following attributes
class Processing_units
{
public:
float *processing_unit_input;
int number_of_input_units;
void establish_array_of_processing_unit_inputs(void);
float *weight_of_inputs;
void establish_weight_vector_for_processing_units(void);
float bias;
float output_signal;
void calculate_output_signal(int activation_function);
float calculate_output_signal_derivative(int afun);
float error_information_term;
void calculate_weight_and_bias_correction_terms(float learning_rate);
float *weight_correction_term;
float bias_correction_term;
float sum_of_weighted_inputs;
void update_weights_and_biases(void);
Processing_units();
~Processing_units();
};
Processing_units::Processing_units()
{
bias = 0.0;
output_signal = 0.0;
error_information_term = 0.0;
bias_correction_term = 0.0;
sum_of_weighted_inputs = 0.0;
}
Processing_units::~Processing_units()
{
delete [] processing_unit_input;
delete [] weight_of_inputs;
delete [] weight_correction_term;
}
// Define base class member functions
void Processing_units::establish_array_of_processing_unit_inputs(void)
{
processing_unit_input = new float[number_of_input_units];
weight_of_inputs = new float[number_of_input_units];
weight_correction_term = new float[number_of_input_units];
}
void Processing_units::establish_weight_vector_for_processing_units(void)
{
for(int i = 0; i < number_of_input_units; i++)
{
// weights range from 1 to -1
weight_of_inputs[i] = 1.0 - (2.0 * bedlam((long*)(gaset)));
}
}
void Processing_units::calculate_output_signal(int activation_function)
{
sum_of_weighted_inputs = 0.0;
for(int i = 0; i < number_of_input_units; i++)
{
if(i == number_of_input_units - 1)
{sum_of_weighted_inputs += (processing_unit_input[i] * weight_of_inputs[i]) + bias;}
else
{sum_of_weighted_inputs += processing_unit_input[i] * weight_of_inputs[i];}
}
switch(activation_function)
{
case 1: // binary sigmoid function
output_signal = 1.0 / (1.0 + exp(-1.0 * sum_of_weighted_inputs));
break;
case 2: // bipolar sigmoid function
output_signal = (2.0 / (1.0 + exp(-1.0 * sum_of_weighted_inputs))) - 1;
break;
}
}
float Processing_units::calculate_output_signal_derivative(int afun)
{
float derivative;
switch(afun) // derivative used based on activation function seleted
{
case 1: // binary sigmoid function
derivative = output_signal * (1.0 - output_signal);
break;
case 2: // bipolar sigmoid function
derivative = 0.5 * (1.0 + output_signal) * (1.0 - output_signal);
break;
}
return derivative;
}
void Processing_units::calculate_weight_and_bias_correction_terms(float learning_rate)
{
for(int i = 0; i < number_of_input_units; i++)
{weight_correction_term[i] = learning_rate * error_information_term * processing_unit_input[i];}
bias_correction_term = learning_rate * error_information_term;
error_information_term = 0.0;
update_weights_and_biases();
}
void Processing_units::update_weights_and_biases(void)
{
for(int i = 0; i < number_of_input_units; i++)
{weight_of_inputs[i] = weight_of_inputs[i] + weight_correction_term[i];}
bias = bias + bias_correction_term;
}
// Declare a derived class "Hidden_units" for hidden layer of network
class Hidden_units : public Processing_units
{
public:
void calculate_hidden_error_information_term(int afun);
};
// Define member functions for derived class "Hidden_units"
void Hidden_units::calculate_hidden_error_information_term(int afun)
{
float af = afun;
float output_signal_derivative = calculate_output_signal_derivative(af);
error_information_term = error_information_term * output_signal_derivative;
}
// Declare a derived class "Output_units" for output layer of network
class Output_units : public Processing_units
{
public:
void calculate_output_error_information_term(float target_value, int af);
float absolute_error_difference;
float error_difference_squared;
};
// Define member functions for derived class "Output_units"
void Output_units::calculate_output_error_information_term(float target_value, int af)
{
float afun = af;
float output_signal_derivative = calculate_output_signal_derivative(afun);
absolute_error_difference = fabs(target_value - output_signal);
error_information_term = (target_value - output_signal) * output_signal_derivative;
error_difference_squared = pow((target_value - output_signal), 2.0);
}
// Create classes to contain neural net specifications
class Hidden_layer
{
public:
Hidden_units *node_in_hidden_layer;
int nodes_in_hidden_layer;
~Hidden_layer();
};
Hidden_layer::~Hidden_layer()
{delete [] node_in_hidden_layer;}
// The following class represents an artificial neural network containing
// the topology, weights, training performance and testing performance
class Back_Topology
{
public:
Hidden_layer *hidden_layer_number;
Output_units *node_in_output_layer;
int number_of_hidden_layers;
int activation_function_for_hidden_layer;
int nodes_in_output_layer;
int activation_function_for_output_layer;
int signal_dimensions;
int number_of_tests;
void establish_activation_functions(void);
void construct_and_initialize_backprop_network(void);
void upload_network(void);
void savenet(void);
~Back_Topology();
};
void Back_Topology::construct_and_initialize_backprop_network(void)
{
int nodes, inputs_to_output_node;
char netcreate;
int looploc = 0;
do
{
cout <<"\n";
cout << "Do you wish to" << "\n\n";
cout << "C. Create your own Backprop Network " << "\n";
cout << "U. Upload an existing Backprop Network " << "\n\n";
cout << "Your choice?: "; cin >> netcreate;
netcreate = toupper(netcreate);
cout << "\n";
if((netcreate == 'C') || (netcreate == 'U')) {looploc = 1;}
} while(looploc <= 0);
if(netcreate == 'U')
{upload_network();}
else
{
cout << "Please enter the dimensions of the input vector: ";
cin >> signal_dimensions;
cout << "\n\n";
do
{
cout << "please enter the number of hidden layers (0 - 2): ";
cin >> number_of_hidden_layers;
cout << "\n\n";
} while(number_of_hidden_layers > 2);
if(number_of_hidden_layers > 0)
{
hidden_layer_number = new Hidden_layer[number_of_hidden_layers];
for(int layer = 0; layer < number_of_hidden_layers; layer++)
{
cout << "please enter the number of nodes in hidden layer " << layer + 1 << ": ";
cin >> hidden_layer_number[layer].nodes_in_hidden_layer;
cout << "\n\n";
}
}
cout << "\n";
cout << "please enter the number of nodes in the output layer: ";
cin >> nodes_in_output_layer;
cout << "\n\n";
// establish for dynamic arrays for number of nodes in hidden and output layers
if(number_of_hidden_layers > 0)
{
for(int layer = 0; layer < number_of_hidden_layers; layer++)
{
nodes = hidden_layer_number[layer].nodes_in_hidden_layer;
hidden_layer_number[layer].node_in_hidden_layer = new Hidden_units[nodes];
}
}
node_in_output_layer = new Output_units[nodes_in_output_layer];
if(number_of_hidden_layers > 0)
{
// establish input connection between signal and hidden layer
for(nodes = 0; nodes < hidden_layer_number[0].nodes_in_hidden_layer; nodes++)
{
hidden_layer_number[0].node_in_hidden_layer[nodes].number_of_input_units = signal_dimensions;
hidden_layer_number[0].node_in_hidden_layer[nodes].establish_array_of_processing_unit_inputs();
hidden_layer_number[0].node_in_hidden_layer[nodes].establish_weight_vector_for_processing_units();
hidden_layer_number[0].node_in_hidden_layer[nodes].bias = 1.0 - (2.0 * bedlam((long*)(gaset)));
}
if(number_of_hidden_layers > 1)
{
// establish connection between first and second hidden layers
for(nodes = 0; nodes < hidden_layer_number[1].nodes_in_hidden_layer; nodes++)
{
hidden_layer_number[1].node_in_hidden_layer[nodes].number_of_input_units = hidden_layer_number[0].nodes_in_hidden_layer;
hidden_layer_number[1].node_in_hidden_layer[nodes].establish_array_of_processing_unit_inputs();
hidden_layer_number[1].node_in_hidden_layer[nodes].establish_weight_vector_for_processing_units();
hidden_layer_number[1].node_in_hidden_layer[nodes].bias = 1.0 - (2.0 * bedlam((long*)(gaset)));
}
}
}
// determine number of inputs to the output layer
if(number_of_hidden_layers > 0)
{inputs_to_output_node = hidden_layer_number[number_of_hidden_layers - 1].nodes_in_hidden_layer;}
else
{inputs_to_output_node = signal_dimensions;}
// establish input connections to output layer
for(nodes = 0; nodes < nodes_in_output_layer; nodes++)
{
node_in_output_layer[nodes].number_of_input_units = inputs_to_output_node;
node_in_output_layer[nodes].establish_array_of_processing_unit_inputs();
node_in_output_layer[nodes].establish_weight_vector_for_processing_units();
node_in_output_layer[nodes].bias = 1.0 - (2.0 * bedlam((long*)(gaset)));
}
establish_activation_functions(); // for hidden and output nodes
}
} // end construct and initialize neural network function
void Back_Topology::upload_network(void)
{
char getname[13];
ifstream get_ptr;
int netid, nodes, dim, inputs_to_output_node, hid, inputs;
int dolock = 0;
do
{
cout << "\n\n";
cout << "Please enter the name of the file which holds the Backpropagation network" << "\n";
cin >> getname; cout << "\n";
get_ptr.open(getname, ios::in);
get_ptr >> netid;
if(netid == 1) {dolock = 1;}
else
{
cout << "Error** file contents do not match Backprop specifications" << "\n";
cout << "try again" << "\n";
get_ptr.close();
}
} while(dolock <= 0);
get_ptr >> signal_dimensions;
get_ptr >> activation_function_for_output_layer;
get_ptr >> nodes_in_output_layer;
get_ptr >> inputs_to_output_node;
// establish output layer
node_in_output_layer = new Output_units[nodes_in_output_layer];
for(nodes = 0; nodes < nodes_in_output_layer; nodes++)
{
node_in_output_layer[nodes].number_of_input_units = inputs_to_output_node;
node_in_output_layer[nodes].establish_array_of_processing_unit_inputs();
node_in_output_layer[nodes].establish_weight_vector_for_processing_units();
get_ptr >> node_in_output_layer[nodes].bias;
}
for(nodes = 0; nodes < nodes_in_output_layer; nodes++)
{
for(dim = 0; dim < inputs_to_output_node; dim++)
{get_ptr >> node_in_output_layer[nodes].weight_of_inputs[dim];}
}
// establish hidden layer(s)
get_ptr >> number_of_hidden_layers;
if(number_of_hidden_layers > 0)
{
hidden_layer_number = new Hidden_layer[number_of_hidden_layers];
get_ptr >> activation_function_for_hidden_layer;
for(hid = 0; hid < number_of_hidden_layers; hid++)
{
get_ptr >> hidden_layer_number[hid].nodes_in_hidden_layer;
nodes = hidden_layer_number[hid].nodes_in_hidden_layer;
hidden_layer_number[hid].node_in_hidden_layer = new Hidden_units[nodes];
if(hid == 0) {inputs = signal_dimensions;}
else
{inputs = hidden_layer_number[0].nodes_in_hidden_layer;}
for(nodes = 0; nodes < hidden_layer_number[hid].nodes_in_hidden_layer; nodes++)
{
hidden_layer_number[hid].node_in_hidden_layer[nodes].number_of_input_units = inputs;
hidden_layer_number[hid].node_in_hidden_layer[nodes].establish_array_of_processing_unit_inputs();
get_ptr >> hidden_layer_number[hid].node_in_hidden_layer[nodes].bias;
}
for(nodes = 0; nodes < hidden_layer_number[hid].nodes_in_hidden_layer; nodes++)
{
for(dim = 0; dim < inputs; dim++)
{get_ptr >> hidden_layer_number[hid].node_in_hidden_layer[nodes].weight_of_inputs[dim];}
}
}
}
get_ptr.close();
}
void Back_Topology::savenet(void)
{
char savename[13];
ofstream save_ptr;
int nodes, dim, inputs, hid;
cout << "\n\n";
cout << "Please enter the name of the file that will hold" << "\n";
cout << "the Backpropagation network: "; cin >> savename;
save_ptr.open(savename, ios::out);
save_ptr << 1 << "\n"; // network identifier number
save_ptr << signal_dimensions << "\n";
save_ptr << activation_function_for_output_layer << "\n";
save_ptr << nodes_in_output_layer << "\n";
if(number_of_hidden_layers > 0)
{inputs = hidden_layer_number[number_of_hidden_layers - 1].nodes_in_hidden_layer;}
else
{inputs = signal_dimensions;}
save_ptr << inputs << "\n";
for(nodes = 0; nodes < nodes_in_output_layer; nodes++)
{save_ptr << node_in_output_layer[nodes].bias << " ";}
save_ptr << "\n";
for(nodes = 0; nodes < nodes_in_output_layer; nodes++)
{
for(dim = 0; dim < inputs; dim++)
{save_ptr << node_in_output_layer[nodes].weight_of_inputs[dim] << " ";}
save_ptr << "\n";
}
save_ptr << number_of_hidden_layers << "\n";
if(number_of_hidden_layers > 0)
{
save_ptr << activation_function_for_hidden_layer << "\n";
for(hid = 0; hid < number_of_hidden_layers; hid++)
{
save_ptr << hidden_layer_number[hid].nodes_in_hidden_layer << "\n";
if(hid == 0) {inputs = signal_dimensions;}
else {inputs = hidden_layer_number[0].nodes_in_hidden_layer;}
for(nodes = 0; nodes < hidden_layer_number[hid].nodes_in_hidden_layer; nodes++)
{save_ptr << hidden_layer_number[hid].node_in_hidden_layer[nodes].bias << " ";}
save_ptr << "\n";
for(nodes = 0; nodes < hidden_layer_number[hid].nodes_in_hidden_layer; nodes++)
{
for(dim = 0; dim < inputs; dim++)
{save_ptr << hidden_layer_number[hid].node_in_hidden_layer[nodes].weight_of_inputs[dim] << " ";}
save_ptr << "\n";
}
}
}
save_ptr.close();
}
Back_Topology::~Back_Topology()
{
delete [] hidden_layer_number;
delete [] node_in_output_layer;
}
void Back_Topology::establish_activation_functions(void)
{
int bchoice, count;
int dolock = 1;
for(count = 0; count < 2; count++)
{
cout << "\n";
if((count == 0) && (number_of_hidden_layers > 0))
{cout << "For the nodes in the hidden layer(s):" << "\n";}
else
{cout << "For the output layer:" << "\n";}
do
{
cout << "please select the type of activation function you wish the nodes to use" << "\n\n";
cout << "1. Binary Sigmoid Function " << "\n";
cout << "2. Bipolar Sigmoid Function " << "\n\n";
cout << "Your Selection "; cin >> bchoice;
cout << "\n\n";
if((bchoice == 1) || (bchoice == 2)) {dolock = 0;}
} while(dolock >= 1);
if((count == 0) && (number_of_hidden_layers > 0))
{activation_function_for_hidden_layer = bchoice;}
else
{activation_function_for_output_layer = bchoice;}
}
}
// Declare classes that will establish training and testing data arrays
class sample_data
{
public:
float *data_in_sample; // pointer to the dimensions of a single signal
~sample_data();
};
sample_data:: ~sample_data()
{delete [] data_in_sample;}
class Data_type
{
public:
char filename[13]; // File containing data for network training or testing
char resultsname[13]; // File containing data for results of training or testing
int signal_dimensions; // Number of dimensions contained in signal
int sample_number; // Number of signals in training set
int nodes_in_output_layer; // Dimensions of test data output
sample_data *number_of_samples; // Pointer to the array containing signals
float *max_output_value;
float *min_output_value;
virtual void determine_sample_number(void);
void specify_signal_sample_size(void);
virtual void load_data_into_array(void); // Function to place data into the array
void acquire_net_info(int signal, int no_output_nodes);
void delete_signal_array(void); // Function to free memory allocated to hold signals
virtual void normalize_data_in_array(void);
~Data_type(); // class destructor
};
Data_type::~Data_type()
{
delete [] max_output_value;
delete [] min_output_value;
}
// define functions of Data_type Class
void Data_type :: determine_sample_number(void)
{
ifstream dfile_ptr; // pointer to a file
dfile_ptr.open(filename, ios::in);
float hold;
int lock = 1;
sample_number = 0;
do
{
if(dfile_ptr.eof()){lock = 0;}
else
{dfile_ptr >> hold; sample_number += 1;}
}while(lock > 0);
dfile_ptr.close();
sample_number = int(sample_number / (signal_dimensions + nodes_in_output_layer));
}
void Data_type::specify_signal_sample_size(void)
{
char tchoice;
int dolock = 1;
do
{
cout <<"\n";
cout << "Please select the number of samples you wish to use" << "\n\n";
cout << " A. All samples in the file" << "\n";
cout << " S. Specific number of samples"<< "\n\n";
cout << " Your Selection: "; cin >> tchoice;
cout << "\n\n";
tchoice = toupper(tchoice);
if((tchoice == 'A') || (tchoice == 'S')) {dolock = 0;}
} while(dolock >= 1);
cout <<"\n";
if(tchoice == 'A') {determine_sample_number();}
else
{
cout << "\n";
cout << "please enter the number of testing samples you wish to use: ";
cin >> sample_number;
cout << "\n";
}
load_data_into_array();
}
void Data_type::normalize_data_in_array(void)
{
int imax, imin, trigger;
float min, max, rmax, rmin;
int total_dimension = signal_dimensions + nodes_in_output_layer;
int i, j;
max_output_value = new float[nodes_in_output_layer];
min_output_value = new float[nodes_in_output_layer];
for(j = 0; j < total_dimension; j++)
{
trigger = 1;
// identify the minimum and maximum values for each dimension
for(i = 0; i < sample_number; i++)
{
if(i == 0)
{
max = number_of_samples[i].data_in_sample[j];
min = number_of_samples[i].data_in_sample[j];
if((j >= (total_dimension - nodes_in_output_layer)))
{
min_output_value[j - (total_dimension - nodes_in_output_layer)] = min;
max_output_value[j - (total_dimension - nodes_in_output_layer)] = max;
}
}
else
{
if(number_of_samples[i].data_in_sample[j] < min)
{
min = number_of_samples[i].data_in_sample[j];
if(j >= (total_dimension - nodes_in_output_layer))
{min_output_value[j - (total_dimension - nodes_in_output_layer)] = min;}
}
if(number_of_samples[i].data_in_sample[j] > max)
{
max = number_of_samples[i].data_in_sample[j];
if(j >= (total_dimension - nodes_in_output_layer))
{max_output_value[j - (total_dimension - nodes_in_output_layer)] = max;}
}
}
}
imax = int(max_output_value[j - (total_dimension - nodes_in_output_layer)]);
imin = int(min_output_value[j - (total_dimension - nodes_in_output_layer)]);
rmax = max_output_value[j - (total_dimension - nodes_in_output_layer)];
rmin = min_output_value[j - (total_dimension - nodes_in_output_layer)];
if((imax == 1) && (imin == 0) && (rmax <= 1.0) && (rmin <= 0.0))
{trigger = 0;}
if((imax == 1) && (imin == 1) && (rmax <= 1.0) && (rmin <= 1.0))
{trigger = 0;}
if((imax == 0) && (imin == 0) && (rmax <= 0.0) && (rmin <= 0.0))
{trigger = 0;}
// normalize the values in each dimension of the signal
if(trigger != 0)
{
for(i = 0; i < sample_number; i++)
{number_of_samples[i].data_in_sample[j] = (number_of_samples[i].data_in_sample[j] - min) / (max - min);}
}
}
}
void Data_type :: acquire_net_info(int signal, int no_output_nodes)
{
signal_dimensions = signal;
nodes_in_output_layer = no_output_nodes;
}
void Data_type :: load_data_into_array(void)
{
// open the file containing the data
ifstream file_ptr; // pointer to a file
int i;
file_ptr.open(filename, ios::in);
// create dynamic array to hold the specified number of samples
number_of_samples = new sample_data[sample_number];
for(i = 0; i < sample_number; i++)
// create a dynamic array to hold the dimensions of each signal
{number_of_samples[i].data_in_sample = new float[signal_dimensions + nodes_in_output_layer];}
int dimensions = signal_dimensions + nodes_in_output_layer;
//read in data from file and place in array
for(i = 0; i < sample_number; i++)
{
for(int j = 0; j < dimensions; j++)
{file_ptr >> number_of_samples[i].data_in_sample[j];}
}
file_ptr.close();
cout << "\n";
}
void Data_type::delete_signal_array(void)
{delete [] number_of_samples;}
class signal_data // Class for randomizing the input signals
{
public:
int signal_value;
float signal_rank;
};
class Training : public Data_type // Derived Class For Training Data
{
public:
void request_training_data(int net_no); // Function to request data for training
int number_of_epochs;
signal_data *signalpoint;
float rate_of_learning; // learning rate constant used by the net
char presentation_order; // determines fixed or random signal presentation
void scramble_data_in_array(void);
float minimum_average_squared_error;
void delete_signal_data_array(void);
~Training();
};
Training::~Training()
{
delete [] signalpoint;
delete [] max_output_value;
delete [] min_output_value;
}
void Training::request_training_data(int net_no)
{
cout << "Please enter the file name containing the training data for neural net no. "<< net_no << "\n";
cin >> filename;
specify_signal_sample_size();
signalpoint = new signal_data[sample_number];
for(int i = 0; i < sample_number; i++) {signalpoint[i].signal_value = i;}
normalize_data_in_array();
}
void Training::scramble_data_in_array(void)
{
int swap1, swap2, hold_sample;
float hold_rank;
// randomly assign rank to all signals
for(int sig = 0; sig < sample_number; sig ++)
{signalpoint[sig].signal_rank = bedlam((long*)(gaset));}
// reorder signals according to rank
for(swap1 = 0; swap1 < sample_number - 1; swap1++)
{
for(swap2 = swap1 + 1; swap2 < sample_number; swap2++)
{
if(signalpoint[swap1].signal_rank > signalpoint[swap2].signal_rank)
{
hold_sample = signalpoint[swap2].signal_value;
hold_rank = signalpoint[swap2].signal_rank;
signalpoint[swap2].signal_value = signalpoint[swap1].signal_value;
signalpoint[swap2].signal_rank = signalpoint[swap1].signal_rank;
signalpoint[swap1].signal_value = hold_sample;
signalpoint[swap1].signal_rank = hold_rank;
}
}
}
}
void Training::delete_signal_data_array(void)
{
delete [] signalpoint;
delete_signal_array();
}
class Testing : public Training // Derived Class For Testing Data
{
public:
void request_testing_data(int net_no, int test); // Function to request data for testing
float average_squared_error;
};
void Testing::request_testing_data(int net_no, int test)
{
cout << "Please enter the file name containing the testing data for neural net no. "<< net_no << "\n\n";
cin >> filename;
cout << "\n\n";
cout << "For test #" << test + 1 << ":";
cout << "\n\n";
specify_signal_sample_size();
normalize_data_in_array();
}
//************************************************************************//
class NeuralB // class containing neural net structure for backpropagation
{ // along with training and testing data
private:
Training Training_Data; // file name and dynamic array for training
Testing *Test_Data; // files containing data to test the network
void initialize_training_storage_array(int N);
void establish_test_battery_size(void);
void train_net_with_backpropagation(void);
void test_neural_network(int BNET);
public:
Back_Topology Net_Design; // specifications for backpropagating network
int number_of_tests;
void establish_backprop_network(void);
void network_training_testing(int TT);
~NeuralB();
};
//************************************************************************//
// these Neural class member function transmits data from the topology
// to the data storage arrays
NeuralB:: ~NeuralB()
{delete [] Test_Data;}
void NeuralB :: initialize_training_storage_array(int N)
{
Training_Data.acquire_net_info(Net_Design.signal_dimensions, Net_Design.nodes_in_output_layer);
Training_Data.request_training_data(N);
}
void NeuralB :: establish_test_battery_size(void)
{
clrscr();
cout << "Please enter the number of tests you wish to run on the BP neural net: ";
cin >> number_of_tests; cout << "\n";
if(number_of_tests > 0)
{
Test_Data = new Testing[number_of_tests];
for(int i = 0; i < number_of_tests; i++)
{Test_Data[i].acquire_net_info(Net_Design.signal_dimensions, Net_Design.nodes_in_output_layer);}
}
}
// define the establish_backprop_network function
void NeuralB::establish_backprop_network(void)
{
clrscr();
cout << " **** Feedforward network using backpropagation **** " << "\n\n\n";
Net_Design.construct_and_initialize_backprop_network();
} // end establish_backprop_network function
// set the activation functions of the nodes of the network
// define train_net_with_backpropagation function
void NeuralB::train_net_with_backpropagation(void)
{
char savefile;
float output_error, sum_of_error, real_error_difference, target_minimum_average_squared_error;
int sig, layers, sigdim, epoch, hidnode, hidnode2, outnode;
int loopexit = 0;
float *maxdifference;
float *meandifference;
ofstream savefile_ptr;
clrscr();
cout << "please enter the number of epochs you wish to use for training: ";
cin >> Training_Data.number_of_epochs; cout<< "\n";
cout << "please enter the learning rate constant for backpropagation (0-1): ";
cin >> Training_Data.rate_of_learning; cout << "\n";
cout << "please enter the minimum average squared error you wish to target" << "\n";
cin >> target_minimum_average_squared_error; cout << "\n";
do
{
cout << "do you wish to save the mean error, maximum error" << "\n";
cout << "and average squared error for each epoch to a file? (Y or N): "; cin >> savefile;
savefile = toupper(savefile);
if((savefile == 'Y') || (savefile == 'N')) {loopexit = 2;}
cout << "\n";
} while(loopexit <= 1);
if(savefile == 'Y')
{
cout << "please enter the name of the file which will hold the results of training:" << "\n";
cin >> Training_Data.resultsname; cout <<"\n";
savefile_ptr.open(Training_Data.resultsname, ios::out);
}
cout << "Do you want signal presentation in random or fixed order(R or F): ";
cin >> Training_Data.presentation_order; cout << "\n";
Training_Data.presentation_order = toupper(Training_Data.presentation_order); cout << "\n";
maxdifference = new float[Net_Design.nodes_in_output_layer];
meandifference = new float[Net_Design.nodes_in_output_layer];
// intiate backpropagation for appropriate number of epochs
epoch = 0;
do
{
sum_of_error = 0;
for(sig = 0; sig < Training_Data.sample_number; sig++)
{
output_error = 0;
for(sigdim = 0; sigdim < Training_Data.signal_dimensions; sigdim++)
{
if(Net_Design.number_of_hidden_layers == 0) // no hidden layers present
{
for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++)
{Net_Design.node_in_output_layer[outnode].processing_unit_input[sigdim] = Training_Data.number_of_samples[Training_Data.signalpoint[sig].signal_value].data_in_sample[sigdim];}
}
else // 1 or 2 hidden layers present
{
for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[0].nodes_in_hidden_layer; hidnode++)
{Net_Design.hidden_layer_number[0].node_in_hidden_layer[hidnode].processing_unit_input[sigdim] = Training_Data.number_of_samples[Training_Data.signalpoint[sig].signal_value].data_in_sample[sigdim];}
}
}
if(Net_Design.number_of_hidden_layers == 2) // two layers are present
{
for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[0].nodes_in_hidden_layer; hidnode++)
{
Net_Design.hidden_layer_number[0].node_in_hidden_layer[hidnode].calculate_output_signal(Net_Design.activation_function_for_hidden_layer);
for(hidnode2 = 0; hidnode2 < Net_Design.hidden_layer_number[1].nodes_in_hidden_layer; hidnode2++)
{Net_Design.hidden_layer_number[1].node_in_hidden_layer[hidnode2].processing_unit_input[hidnode] = Net_Design.hidden_layer_number[0].node_in_hidden_layer[hidnode].output_signal;}
}
}
if(Net_Design.number_of_hidden_layers > 0)
{
for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers -1].nodes_in_hidden_layer; hidnode++)
{
Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers -1].node_in_hidden_layer[hidnode].calculate_output_signal(Net_Design.activation_function_for_hidden_layer);
for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++)
{Net_Design.node_in_output_layer[outnode].processing_unit_input[hidnode] = Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers -1].node_in_hidden_layer[hidnode].output_signal;}
}
}
for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++)
{
Net_Design.node_in_output_layer[outnode].calculate_output_signal(Net_Design.activation_function_for_output_layer);
Net_Design.node_in_output_layer[outnode].calculate_output_error_information_term(Training_Data.number_of_samples[Training_Data.signalpoint[sig].signal_value].data_in_sample[Training_Data.signal_dimensions + outnode], Net_Design.activation_function_for_output_layer);
// calculate the instantaneous sum of squared errors (Haykin, 1994)
real_error_difference = (pow(Net_Design.node_in_output_layer[outnode].error_difference_squared, 0.5)) * (Training_Data.max_output_value[outnode] - Training_Data.min_output_value[outnode]);
output_error += 0.5 * pow(real_error_difference, 2.0);
// calculate maximum and mean absolute error difference for each node
real_error_difference = Net_Design.node_in_output_layer[outnode].absolute_error_difference * (Training_Data.max_output_value[outnode] - Training_Data.min_output_value[outnode]);
meandifference[outnode] += real_error_difference / float(Training_Data.sample_number);
if(sig == 0) {maxdifference[outnode] = real_error_difference;}
else
{
if(real_error_difference > maxdifference[outnode])
{maxdifference[outnode] = real_error_difference;}
}
}
// average squared error for each signal is saved
sum_of_error += output_error / float (Training_Data.sample_number);
// backpropagation of error will depend on the number of hidden layers
if(Net_Design.number_of_hidden_layers > 0)
{ // backpropagate from output node to adjacent hidden layer
for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++)
{
for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers - 1].nodes_in_hidden_layer; hidnode++)
{Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers - 1].node_in_hidden_layer[hidnode].error_information_term += Net_Design.node_in_output_layer[outnode].error_information_term * Net_Design.node_in_output_layer[outnode].weight_of_inputs[hidnode];}
}
// calculate error information term for each node in hiddenlayer
for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers - 1].nodes_in_hidden_layer; hidnode++)
{Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers - 1].node_in_hidden_layer[hidnode].calculate_hidden_error_information_term(Net_Design.activation_function_for_hidden_layer);}
if(Net_Design.number_of_hidden_layers > 1)
{ // backpropagate error from hidden layer 2 to hidden layer 1
for(hidnode2 = 0; hidnode2 < Net_Design.hidden_layer_number[1].nodes_in_hidden_layer; hidnode2++)
{
for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[0].nodes_in_hidden_layer; hidnode++)
{Net_Design.hidden_layer_number[0].node_in_hidden_layer[hidnode].error_information_term += Net_Design.hidden_layer_number[1].node_in_hidden_layer[hidnode2].error_information_term * Net_Design.hidden_layer_number[1].node_in_hidden_layer[hidnode2].weight_of_inputs[hidnode];}
}
for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[0].nodes_in_hidden_layer; hidnode++)
{Net_Design.hidden_layer_number[0].node_in_hidden_layer[hidnode].calculate_hidden_error_information_term(Net_Design.activation_function_for_hidden_layer);}
}
}
// update the networks output nodes
for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++)
{Net_Design.node_in_output_layer[outnode].calculate_weight_and_bias_correction_terms(Training_Data.rate_of_learning);}
// update the networks hidden nodes (if they exist)
if(Net_Design.number_of_hidden_layers > 0)
{
for(layers = 0; layers < Net_Design.number_of_hidden_layers; layers++)
{
for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[layers].nodes_in_hidden_layer; hidnode++)
{Net_Design.hidden_layer_number[layers].node_in_hidden_layer[hidnode].calculate_weight_and_bias_correction_terms(Training_Data.rate_of_learning);}
}
}
} // end sig loop
// save error information (if required)
if(savefile == 'Y')
{
savefile_ptr << epoch + 1 << " ";
savefile_ptr << sum_of_error << " ";
for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++)
{savefile_ptr << maxdifference[outnode] << " " << meandifference[outnode] << " ";}
savefile_ptr << endl;
cout.width(6);
clrscr();
cout << "Epoch #"<< epoch + 1 <<" is completed " << endl;
}
if(epoch == 0)
{Training_Data.minimum_average_squared_error = sum_of_error;}
else
{
if(sum_of_error < Training_Data.minimum_average_squared_error)
{Training_Data.minimum_average_squared_error = sum_of_error;}
}
// scramble the order of signal presentation (if required)
if(Training_Data.presentation_order == 'R')
{Training_Data.scramble_data_in_array();}
for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++)
{ maxdifference[outnode] = 0.0; meandifference[outnode] = 0.0;}
if(Training_Data.minimum_average_squared_error <= target_minimum_average_squared_error)
{break;}
epoch = epoch + 1;
} while(epoch < Training_Data.number_of_epochs);
savefile_ptr.close();
// delete arrays holding the training data
Training_Data.delete_signal_data_array();
delete [] maxdifference;
delete [] meandifference;
} // end of backpropagation function
// define the function that tests the neural network
void NeuralB::test_neural_network(int BNET)
{
float output_error, sum_of_error, real_output;
int sig, sigdim, hidnode, hidnode2, outnode;
int bnet = BNET;
for(int t = 0; t < number_of_tests; t++)
{
Test_Data[t].request_testing_data(bnet, t);
sum_of_error = 0;
cout << "please enter the name of the file wich will hold the results of test: "<< t+1 << "\n";
cin >> Test_Data[t].resultsname; cout <<"\n";
ofstream savefile_ptr(Test_Data[t].resultsname);
for(sig = 0; sig < Test_Data[t].sample_number; sig++)
{
output_error = 0;
savefile_ptr << sig + 1 << " ";
for(sigdim = 0; sigdim < Test_Data[t].signal_dimensions; sigdim++)
{
if(Net_Design.number_of_hidden_layers == 0) // no hidden layers present
{
for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++)
{Net_Design.node_in_output_layer[outnode].processing_unit_input[sigdim] = Test_Data[t].number_of_samples[sig].data_in_sample[sigdim];}
}
else // 1 or 2 hidden layers present
{
for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[0].nodes_in_hidden_layer; hidnode++)
{Net_Design.hidden_layer_number[0].node_in_hidden_layer[hidnode].processing_unit_input[sigdim] = Test_Data[t].number_of_samples[sig].data_in_sample[sigdim];}
}
}
if(Net_Design.number_of_hidden_layers == 2) // two layers are present
{
for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[0].nodes_in_hidden_layer; hidnode++)
{
Net_Design.hidden_layer_number[0].node_in_hidden_layer[hidnode].calculate_output_signal(Net_Design.activation_function_for_hidden_layer);
for(hidnode2 = 0; hidnode2 < Net_Design.hidden_layer_number[1].nodes_in_hidden_layer; hidnode2++)
{Net_Design.hidden_layer_number[1].node_in_hidden_layer[hidnode2].processing_unit_input[hidnode] = Net_Design.hidden_layer_number[0].node_in_hidden_layer[hidnode].output_signal;}
}
}
if(Net_Design.number_of_hidden_layers > 0)
{
for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers -1].nodes_in_hidden_layer; hidnode++)
{
Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers -1].node_in_hidden_layer[hidnode].calculate_output_signal(Net_Design.activation_function_for_hidden_layer);
for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++)
{Net_Design.node_in_output_layer[outnode].processing_unit_input[hidnode] = Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers -1].node_in_hidden_layer[hidnode].output_signal;}
}
}
for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++)
{
Net_Design.node_in_output_layer[outnode].calculate_output_signal(Net_Design.activation_function_for_output_layer);
Net_Design.node_in_output_layer[outnode].calculate_output_error_information_term(Test_Data[t].number_of_samples[sig].data_in_sample[Test_Data[t].signal_dimensions + outnode], Net_Design.activation_function_for_output_layer);
}
// convert normalized target output data and send to file
for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++)
{
real_output = Test_Data[t].min_output_value[outnode] + (Test_Data[t].number_of_samples[sig].data_in_sample[outnode + Test_Data[t].signal_dimensions] * (Test_Data[t].max_output_value[outnode] - Test_Data[t].min_output_value[outnode]));
savefile_ptr << real_output << " ";
}
savefile_ptr << " ";
// convert normalized output data and send to file
for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++)
{
real_output = Test_Data[t].min_output_value[outnode] + (Net_Design.node_in_output_layer[outnode].output_signal * (Test_Data[t].max_output_value[outnode] - Test_Data[t].min_output_value[outnode]));
savefile_ptr << real_output << " ";
}
// send absolute differences between each node and its output to a file
for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++)
{
real_output = (pow(Net_Design.node_in_output_layer[outnode].error_difference_squared, 0.5)) * (Test_Data[t].max_output_value[outnode] - Test_Data[t].min_output_value[outnode]);
savefile_ptr << real_output << " ";
real_output = pow(real_output, 2.0);
output_error += 0.5 * real_output;
}
// sum square of error
savefile_ptr << output_error << "\n";
if(sig == Test_Data[t].sample_number - 1)
{savefile_ptr.close();}
sum_of_error += output_error;
}
Test_Data[t].average_squared_error = sum_of_error / Test_Data[t].sample_number;
Test_Data[t].delete_signal_array();
}
} // end test neural network function
void NeuralB::network_training_testing(int TT)
{
int tt = TT;
int menu_choice;
clrscr();
cout << "\n\n\n\n";
cout << "**************** Operations Menu ****************" << "\n\n";
cout << " Please select one of the following options:" <<"\n\n";
cout << " 1. Train Backprop network only " <<"\n\n";
cout << " 2. Test Backprop network only " <<"\n\n";
cout << " 3. Train and Test Backprop network" <<"\n\n";
cout << "*************************************************" << "\n\n";
cout << " Your choice?: "; cin >> menu_choice;
cout << "\n\n";
switch(menu_choice)
{
case 1:
initialize_training_storage_array(tt);
train_net_with_backpropagation();
break;
case 2:
establish_test_battery_size();
if(number_of_tests > 0)
{test_neural_network(tt);}
break;
case 3:
initialize_training_storage_array(tt);
train_net_with_backpropagation();
establish_test_battery_size();
if(number_of_tests > 0)
{test_neural_network(tt);}
break;
default:network_training_testing(tt);
}
}
// This concludes the backpropagation section of the program
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// (ART 1) Define base class for Interface and Cluster units of the
// Adaptive Resonance Theory Neural Network 1
class ART_units
{
public:
float *input_value;
float *output_value;
float *input_weight_vector;
int number_of_inputs;
int number_of_outputs;
float activation;
void establish_input_output_arrays(void);
virtual void establish_input_weight_vector_array(void);
virtual void initialize_inputs_and_weights(void);
~ART_units();
};
ART_units::~ART_units()
{
delete [] input_value;
delete [] output_value;
delete [] input_weight_vector;
}
void ART_units::establish_input_output_arrays(void)
{
input_value = new float[number_of_inputs];
output_value = new float[number_of_outputs];
}
void ART_units::establish_input_weight_vector_array(void)
{input_weight_vector = new float[number_of_inputs - 1];}
void ART_units::initialize_inputs_and_weights(void)
{
for(int w = 0; w < number_of_inputs - 1; w++)
{input_weight_vector[w] = 1.0;}
for(int c = 1; c < number_of_inputs; c++)
{input_value[c] = 0.0;}
activation = 0.0;
}
// establish Interface node attributes
class Interface_units: public ART_units
{
public:
void recompute_activation(int winning_cluster);
void calculate_output_value(int G1);
};
void Interface_units::recompute_activation(int winning_cluster)
{activation = input_value[0] * input_weight_vector[winning_cluster];}
void Interface_units::calculate_output_value(int G1)
{
float feedback_signal, node_output, two_thirds_rule;
feedback_signal = 0.0;
// calculate feedback signal through use of weighted sum
for(int f = 0; f < number_of_inputs-1; f++)
{feedback_signal+=input_weight_vector[f]*input_value[f+1];}
two_thirds_rule = feedback_signal + input_value[0] + float(G1);
// use Two Thirds Rule to determine node output
if(two_thirds_rule >= 2.0) {node_output = 1.0;} else {node_output = 0.0;}
// establish output vector to cluster units
for(int p = 0; p < number_of_outputs; p++)
{output_value[p] = node_output;}
}
// establish Cluster node attributes
class Cluster_units: public ART_units
{
public:
int cluster_tag;
float net_input;
void establish_input_weight_vector_array(void);
void initialize_inputs_and_weights(void);
void calculate_net_input(void);
void establish_node_output(void);
Cluster_units(); // default constructor
};
Cluster_units::Cluster_units()
{cluster_tag = 0;}
void Cluster_units::establish_input_weight_vector_array(void)
{input_weight_vector = new float[number_of_inputs];}
void Cluster_units::initialize_inputs_and_weights(void)
{
for(int c = 0; c < number_of_inputs; c++)
{input_weight_vector[c] = 1.0 / (1.0 + number_of_inputs);}
}
void Cluster_units::calculate_net_input(void)
{
net_input = 0.0;
for(int n = 0; n < number_of_inputs; n++)
{net_input += input_value[n] * input_weight_vector[n];}
}
void Cluster_units::establish_node_output(void)
{
for(int oput = 0; oput < number_of_outputs - 1; oput++)
if(activation >= 0.0)
{output_value[oput] = activation;}
else
{output_value[oput] = 0.0;}
}
// establish Inputs unit attributes
class Input_units {public: float signal_value;};
// establish ART1 neural network attributes
class ART_Topology
{
public:
char netcreate;
int clustercount;
int dimensions_of_signal;
int number_of_cluster_units;
int reset_value;
int resetcount;
float vigilance_parameter;
float norm_of_activation_vector;
float norm_of_input_vector;
float weight_update_parameter;
int cluster_champ;
int clusterange;
Input_units *node_in_input_layer;
Interface_units *node_in_interface_layer;
Cluster_units *node_in_cluster_layer;
void establish_net_topology(void);
void upload_network(void);
void transmit_pattern_to_interface(void);
void transmit_pattern_to_cluster(void);
void broadcast_output_to_cluster_layer(void);
void cluster_nodes_compete_for_activation(int train_or_test);
void compute_norm_of_activation_vector(void);
void compute_norm_of_input_vector(void);
void recompute_activation_vector_of_interface_layer(void);
void update_the_network(void);
void set_cluster_activation_to_zero(void);
void savenet(void);
ART_Topology();
~ART_Topology(); // class destructor
};
ART_Topology::ART_Topology()
{
clustercount = 0;
clusterange = 0;
resetcount = 0;
}
ART_Topology::~ART_Topology()
{
delete [] node_in_input_layer;
delete [] node_in_interface_layer;
delete [] node_in_cluster_layer;
}
void ART_Topology::establish_net_topology(void)
{
weight_update_parameter = 2.0;
node_in_input_layer = new Input_units[dimensions_of_signal];
node_in_interface_layer = new Interface_units[dimensions_of_signal];
node_in_cluster_layer = new Cluster_units[number_of_cluster_units];
// Establish interface layer of ART1 network
for(int I = 0; I < dimensions_of_signal; I++)
{
node_in_interface_layer[I].number_of_inputs = number_of_cluster_units + 1;
node_in_interface_layer[I].number_of_outputs = number_of_cluster_units;
node_in_interface_layer[I].establish_input_output_arrays();
node_in_interface_layer[I].establish_input_weight_vector_array();
node_in_interface_layer[I].initialize_inputs_and_weights();
}
// Establish cluster layer of ART1 network
for(int C = 0; C < number_of_cluster_units; C++)
{
node_in_cluster_layer[C].number_of_inputs = dimensions_of_signal;
node_in_cluster_layer[C].number_of_outputs = dimensions_of_signal + 1;
node_in_cluster_layer[C].establish_input_output_arrays();
node_in_cluster_layer[C].establish_input_weight_vector_array();
node_in_cluster_layer[C].initialize_inputs_and_weights();
}
}
void ART_Topology::upload_network(void)
{
char getname[13];
ifstream get_ptr;
int netid, node, dim;
int dolock = 0;
do
{
cout << "\n\n";
cout << "Please enter the name of the file which holds the ART1 Network" << "\n";
cin >> getname; cout << "\n";
get_ptr.open(getname, ios::in);
get_ptr >> netid;
if(netid == 2) {dolock = 1;}
else
{
cout << "Error** file contents do not match ART1 specifications" << "\n";
cout << "try again" << "\n";
get_ptr.close();
}
} while(dolock <= 0);
get_ptr >> dimensions_of_signal;
get_ptr >> weight_update_parameter;
get_ptr >> vigilance_parameter;
get_ptr >> clusterange;
get_ptr >> clustercount;
get_ptr >> number_of_cluster_units;
node_in_input_layer = new Input_units[dimensions_of_signal];
node_in_interface_layer = new Interface_units[dimensions_of_signal];
node_in_cluster_layer = new Cluster_units[number_of_cluster_units];
for(node = 0; node < dimensions_of_signal; node++)
{
node_in_interface_layer[node].number_of_inputs = number_of_cluster_units + 1;
node_in_interface_layer[node].number_of_outputs = number_of_cluster_units;
node_in_interface_layer[node].establish_input_output_arrays();
node_in_interface_layer[node].establish_input_weight_vector_array();
node_in_interface_layer[node].initialize_inputs_and_weights();
for(dim = 1; dim < number_of_cluster_units + 1; dim++)
{get_ptr >> node_in_interface_layer[node].input_weight_vector[dim];}
}
for(node = 0; node < number_of_cluster_units; node++)
{
node_in_cluster_layer[node].number_of_inputs = dimensions_of_signal;
node_in_cluster_layer[node].number_of_outputs = dimensions_of_signal + 1;
node_in_cluster_layer[node].establish_input_output_arrays();
node_in_cluster_layer[node].establish_input_weight_vector_array();
node_in_cluster_layer[node].initialize_inputs_and_weights();
get_ptr >> node_in_cluster_layer[node].cluster_tag;
for(dim = 0; dim < dimensions_of_signal; dim++)
{get_ptr >> node_in_cluster_layer[node].input_weight_vector[dim];}
}
get_ptr.close();
}
void ART_Topology::transmit_pattern_to_interface(void)
{
for(int d = 0; d < dimensions_of_signal; d++)
{
node_in_interface_layer[d].input_value[0] = node_in_input_layer[d].signal_value;
node_in_interface_layer[d].activation = node_in_input_layer[d].signal_value;
}
}
void ART_Topology::transmit_pattern_to_cluster(void)
{
int c;
for(int d = 0; d < dimensions_of_signal; d++)
{
for(c = 0; c < number_of_cluster_units; c++)
{node_in_cluster_layer[c].input_value[d] = node_in_input_layer[d].signal_value;}
}
}
void ART_Topology::broadcast_output_to_cluster_layer(void)
{
int Gain_one;
int cluster_active = 0;
int d, c;
for(c = 0; c < number_of_cluster_units; c++)
{if(node_in_cluster_layer[c].activation == 1.0) {cluster_active = 1;} }
compute_norm_of_input_vector();
if((cluster_active != 1) && (norm_of_input_vector > 0.0))
{Gain_one = 1;} else {Gain_one = 0;}
// establish interface output vector
for(d = 0; d < dimensions_of_signal; d++)
{node_in_interface_layer[d].calculate_output_value(Gain_one);}
//transmit interface output to units in cluster layer
for(d = 0; d < dimensions_of_signal; d++)
{
for(c = 0; c < number_of_cluster_units; c++)
{node_in_cluster_layer[c].input_value[d] = node_in_interface_layer[d].output_value[c];}
}
}
void ART_Topology::cluster_nodes_compete_for_activation(int train_or_test)
{
int d, cluster;
float champion = 0.0;
for(cluster = 0; cluster < clusterange + 1; cluster++)
{
if(node_in_cluster_layer[cluster].activation != -1.0)
{
node_in_cluster_layer[cluster].calculate_net_input();
if(node_in_cluster_layer[cluster].net_input > champion)
{
champion = node_in_cluster_layer[cluster].net_input;
cluster_champ = cluster;
}
}
}
if((node_in_cluster_layer[cluster_champ].cluster_tag == 0) && (train_or_test < 2))
{
node_in_cluster_layer[cluster_champ].cluster_tag = clustercount + 1;
clustercount = clustercount + 1;
}
if(train_or_test < 2)
{
for(cluster = 0; cluster < clusterange + 1; cluster++)
{
if(cluster == cluster_champ)
{node_in_cluster_layer[cluster].activation = 1.0;}
else
{
if(node_in_cluster_layer[cluster].activation != -1.0)
{node_in_cluster_layer[cluster].activation = 0.0;}
}
node_in_cluster_layer[cluster].establish_node_output();
// send output signals to Interface layer
for(d = 0; d < dimensions_of_signal; d++)
{node_in_interface_layer[d].input_value[cluster + 1] = node_in_cluster_layer[cluster].output_value[d];}
}
}
}
void ART_Topology::compute_norm_of_activation_vector(void)
{
norm_of_activation_vector = 0.0;
for(int d = 0; d < dimensions_of_signal; d++)
{norm_of_activation_vector += node_in_interface_layer[d].activation;}
compute_norm_of_input_vector();
}
void ART_Topology::compute_norm_of_input_vector(void)
{
norm_of_input_vector = 0.0;
for(int d = 0; d < dimensions_of_signal; d++)
{norm_of_input_vector += node_in_input_layer[d].signal_value;}
}
void ART_Topology::recompute_activation_vector_of_interface_layer(void)
{
for(int d = 0; d < dimensions_of_signal; d++)
{node_in_interface_layer[d].recompute_activation(cluster_champ);}
}
void ART_Topology:: update_the_network(void)
{
recompute_activation_vector_of_interface_layer();
compute_norm_of_activation_vector();
float ratio_test = norm_of_activation_vector / norm_of_input_vector;
if(ratio_test < vigilance_parameter)
{
node_in_cluster_layer[cluster_champ].activation = -1.0;
reset_value = 1;
resetcount += reset_value;
if(resetcount == number_of_cluster_units - 1)
{
clusterange = clusterange + 1;
if(clusterange > number_of_cluster_units)
{clusterange = number_of_cluster_units;}
}
}
else
{
// update the weights of the champion cluster unit
for(int u = 0; u < node_in_cluster_layer[cluster_champ].number_of_inputs; u++)
{node_in_cluster_layer[cluster_champ].input_weight_vector[u] = (weight_update_parameter * node_in_interface_layer[u].activation * node_in_cluster_layer[cluster_champ].input_weight_vector[u]) / ((weight_update_parameter - 1.0) + norm_of_activation_vector);}
for(int n = 0; n < dimensions_of_signal; n++)
{node_in_interface_layer[n].input_weight_vector[cluster_champ] = node_in_interface_layer[n].input_weight_vector[cluster_champ] * node_in_interface_layer[n].activation;}
reset_value = 0;
resetcount = 0;
}
}
void ART_Topology::set_cluster_activation_to_zero(void)
{
for(int cnode = 0; cnode < clusterange + 1; cnode++)
{node_in_cluster_layer[cnode].activation = 0.0;}
}
void ART_Topology::savenet(void)
{
char savename[13];
ofstream save_ptr;
int node, dim;
cout << "\n\n";
cout << "Please enter the name of the file which will hold the ART network"<<"\n";
cin >> savename; cout <<"\n";
save_ptr.open(savename, ios::out);
save_ptr << 2 << "\n"; //network identifier number
save_ptr << dimensions_of_signal << "\n";
save_ptr << weight_update_parameter << "\n";
save_ptr << vigilance_parameter << "\n";
save_ptr << clusterange << "\n";
save_ptr << clustercount << "\n";
save_ptr << number_of_cluster_units << "\n";
for(node = 0; node < dimensions_of_signal; node++)
{
for(dim = 1; dim < number_of_cluster_units + 1; dim++)
{save_ptr << node_in_interface_layer[node].input_weight_vector[dim] << " ";}
save_ptr << "\n";
}
for(node = 0; node < number_of_cluster_units; node++)
{
save_ptr << node_in_cluster_layer[node].cluster_tag << "\n";
for(dim = 0; dim < dimensions_of_signal; dim++)
{save_ptr << node_in_cluster_layer[node].input_weight_vector[dim] << " ";}
save_ptr << "\n";
}
save_ptr.close();
}
// Classes which specifies the containers of ART training and test data
class ART_Training_Data : public Data_type
{
public:
void determine_sample_number(void);
void load_data_into_array(void);
virtual void request_ART_data(int net_no);
};
void ART_Training_Data::load_data_into_array(void)
{
int d, i;
float dimensions;
// open the file containing the data
ifstream Afile_ptr; // pointer to a file
Afile_ptr.open(filename, ios::in);
//create a dynamic array to hold the specified number of samples
number_of_samples = new sample_data[sample_number];
for(i = 0; i < sample_number; i++)
{number_of_samples[i].data_in_sample = new float[signal_dimensions];}
// read in data from file and place in array
for(i = 0; i < sample_number; i++)
{
for(d = 0; d < signal_dimensions; d++)
{
Afile_ptr >> dimensions;
number_of_samples[i].data_in_sample[d] = dimensions;
}
}
Afile_ptr.close();
}
void ART_Training_Data :: determine_sample_number(void)
{
ifstream dfile_ptr; // pointer to a file
dfile_ptr.open(filename, ios::in);
float hold;
int lock = 1;
sample_number = 0;
do
{
if(dfile_ptr.eof()){lock = 0;}
else
{dfile_ptr >> hold; sample_number += 1;}
}while(lock > 0);
dfile_ptr.close();
sample_number = int(sample_number / signal_dimensions);
}
void ART_Training_Data::request_ART_data(int net_no)
{
cout << "Please enter the file name containing the training data for ART network no. "<< net_no << "\n";
cin >> filename; cout << "\n";
specify_signal_sample_size();
}
class ART_Test_Data : public ART_Training_Data
{public: void request_ART_data(int net_no);};
void ART_Test_Data::request_ART_data(int net_no)
{
cout << "Please enter the file name containing the test data for ART network no. " << net_no << "\n";
cin >> filename; cout << "\n";
specify_signal_sample_size();
}
//************************************************************************//
class NeuralA // class containing the ART1 neural net structure
{ // along with training and testing data
private:
ART_Training_Data ART_Train;
ART_Test_Data * ART_Test; // the number of test is variable
int number_of_ART_tests;
void initialize_ART_training_storage_array(int AN);
void establish_ART_test_battery_size(void);
void train_ART_network(int ARTN);
void test_ART_network(int ANET);
public:
ART_Topology ART_Design;
void construct_ART_network(void);
void network_training_testing(int TT);
~NeuralA();
};
//****************************************************************************//
NeuralA::~NeuralA()
{ delete [] ART_Test; }
void NeuralA::construct_ART_network(void)
{
int looploc = 0;
clrscr();
cout << " **** Adaptive Resonance Theory network for binary signals **** " <<"\n\n\n";
do
{
cout <<"\n";
cout << "Do you wish to" << "\n\n";
cout << "C. Create your own ART1 Network " << "\n";
cout << "U. Upload an existing ART1 Network " << "\n\n";
cout << "Your choice?: "; cin >> ART_Design.netcreate;
cout << "\n\n";
ART_Design.netcreate = toupper(ART_Design.netcreate);
if((ART_Design.netcreate == 'C') || (ART_Design.netcreate == 'U')) {looploc = 1;}
} while(looploc <= 0);
if(ART_Design.netcreate == 'U')
{ART_Design.upload_network();}
else
{
cout << "\n";
cout << "Please enter the dimensions of the ART network's input signal vector: ";
cin >> ART_Design.dimensions_of_signal; cout << "\n";
cout << "Please enter the vigilance parameter of the ART network: ";
cin >> ART_Design.vigilance_parameter; cout << "\n";
}
}
void NeuralA::initialize_ART_training_storage_array(int AN)
{
int AT = AN;
ART_Train.acquire_net_info(ART_Design.dimensions_of_signal, ART_Design.number_of_cluster_units);
ART_Train.request_ART_data(AT);
if(ART_Design.netcreate == 'C') // constructing new network
{
ART_Design.number_of_cluster_units = ART_Train.sample_number;
ART_Design.establish_net_topology();
}
}
void NeuralA::train_ART_network(int ARTN)
{
int dim, nodes_available_for_clustering;
char savetrain;
int dolock = 0;
clrscr();
cout << "\n\n";
cout << "For Neural Network #" << ARTN << "\n";
do
{
cout << "do you wish to save the ART Training results to a file? (Y or N): ";
cin >> savetrain;
savetrain = toupper(savetrain);
if((savetrain == 'N') || (savetrain == 'Y')) {dolock = 1;}
cout << "\n";
} while(dolock <= 0);
if(savetrain == 'Y')
{
cout << "please enter the name of the file to hold the results of the ART Training" << "\n";
cin >> ART_Train.resultsname; cout << "\n";
}
for(int pattern = 0; pattern < ART_Train.sample_number; pattern++)
{
// present pattern to input layer
for(dim = 0; dim < ART_Design.dimensions_of_signal; dim++)
{ART_Design.node_in_input_layer[dim].signal_value = ART_Train.number_of_samples[pattern].data_in_sample[dim];}
nodes_available_for_clustering = ART_Design.number_of_cluster_units;
do
{
ART_Design.transmit_pattern_to_interface();
ART_Design.broadcast_output_to_cluster_layer();
ART_Design.cluster_nodes_compete_for_activation(1);
ART_Design.update_the_network();
nodes_available_for_clustering = nodes_available_for_clustering - ART_Design.reset_value;
if(nodes_available_for_clustering < 1) // input pattern cannot be clustered
{
// clrscr();
cout << "Input pattern #" << pattern + 1 << ": ";
for(dim = 0; dim < ART_Design.dimensions_of_signal; dim++)
{cout << int(ART_Design.node_in_input_layer[dim].signal_value);}
cout << " cannot be clustered" << "\n";
break;
}
} while (ART_Design.reset_value >=1);
if(savetrain == 'Y')
{
ofstream ART_savefile_ptr(ART_Train.resultsname, ios::out|ios::app);
ART_savefile_ptr << pattern + 1 << " ";
for(dim = 0; dim < ART_Design.dimensions_of_signal; dim++)
{ART_savefile_ptr << int(ART_Design.node_in_input_layer[dim].signal_value);}
ART_savefile_ptr << " " << ART_Design.node_in_cluster_layer[ART_Design.cluster_champ].cluster_tag << "\n";
ART_savefile_ptr.close();
}
ART_Design.set_cluster_activation_to_zero();
}
// delete array containing training data
ART_Train.delete_signal_array();
}
void NeuralA::establish_ART_test_battery_size(void)
{
cout <<"Please enter the number of tests you wish to run on the ART neural network: ";
cin >> number_of_ART_tests; cout <<"\n";
// create testing array
if(number_of_ART_tests > 0)
{
ART_Test = new ART_Test_Data[number_of_ART_tests];
for(int t = 0; t < number_of_ART_tests; t++)
{ART_Test[t].acquire_net_info(ART_Design.dimensions_of_signal, ART_Design.number_of_cluster_units);}
}
}
void NeuralA::test_ART_network(int ANET)
{
int tnet, dim, pattern;
tnet = ANET;
for(int Atest = 0; Atest < number_of_ART_tests; Atest++)
{
ART_Test[Atest].request_ART_data(tnet);
cout << "For ART1 neural network #" << ANET <<" and test #"<<Atest+1<<":" <<"\n";
cout << "please enter the name of the file to hold the results of the ART Testing " << "\n";
cin >> ART_Test[Atest].resultsname; cout << "\n";
ofstream ART_savefile_ptr(ART_Test[Atest].resultsname);
for(pattern = 0; pattern < ART_Test[Atest].sample_number; pattern++)
{
for(dim = 0; dim < ART_Design.dimensions_of_signal; dim++)
{ART_Design.node_in_input_layer[dim].signal_value = ART_Test[Atest].number_of_samples[pattern].data_in_sample[dim];}
ART_Design.transmit_pattern_to_cluster();
ART_Design.cluster_nodes_compete_for_activation(2);
ART_savefile_ptr <<pattern + 1<<" ";
for(dim = 0; dim < ART_Design.dimensions_of_signal; dim++)
{ART_savefile_ptr << int(ART_Design.node_in_input_layer[dim].signal_value);}
ART_savefile_ptr << " " << ART_Design.node_in_cluster_layer[ART_Design.cluster_champ].cluster_tag << "\n";
}
ART_savefile_ptr.close(); // end of test
ART_Test[Atest].delete_signal_array();
}
}
void NeuralA::network_training_testing(int TT)
{
int tt = TT;
int menu_choice;
clrscr();
cout << "\n\n\n\n";
cout << "**************** Operations Menu ****************" << "\n\n";
cout << " Please select one of the following options:" <<"\n\n";
cout << " 1. Train ART1 network only " <<"\n\n";
if(ART_Design.netcreate == 'U')
{
cout << " 2. Test ART1 network only " <<"\n\n";
cout << " 3. Train and Test ART1 network" <<"\n\n";
}
else
{
cout << " 2. Train and Test ART1 network" <<"\n\n";
}
cout << "*************************************************" << "\n\n";
cout << " Your choice?: "; cin >> menu_choice;
cout << "\n\n";
if((menu_choice == 2) && (ART_Design.netcreate == 'C')) {menu_choice = 3;}
if((menu_choice == 3) && (ART_Design.netcreate == 'U')) {menu_choice = 3;}
switch(menu_choice)
{
case 1:
initialize_ART_training_storage_array(tt);
train_ART_network(tt);
break;
case 2:
establish_ART_test_battery_size();
if(number_of_ART_tests > 0)
{test_ART_network(tt);}
break;
case 3:
initialize_ART_training_storage_array(tt);
train_ART_network(tt);
establish_ART_test_battery_size();
if(number_of_ART_tests > 0)
{test_ART_network(tt);}
break;
default:network_training_testing(tt);
}
}
// This concludes the ART1 section of the program
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// (Kohonen) Define base class for the Clustering Nodes of
// the Kohonen Self-Organizing Map
//************************ ATTENTION ************************************
// Note that the Class Kohonen_units will also contain variables and
// functions relevant to the Radial Basis Function Neural Network (RBFN)
//***********************************************************************
class Kohonen_units: public ART_units
{
public:
void establish_input_weight_vector_array(void);
void initialize_inputs_and_weights(void);
void calculate_sum_square_Euclidean_distance(void);
void update_the_weights(float learning_rate);
Kohonen_units(); // default constructor
//*******************************************************
float transfer_function_width; // RBFN
float Gaussian_transfer_output; // RBFN
void execute_Gaussian_transfer_function(void); // RBFN
//*******************************************************
};
Kohonen_units::Kohonen_units()
{number_of_outputs = 1;}
void Kohonen_units::establish_input_weight_vector_array(void)
{input_weight_vector = new float[number_of_inputs];}
void Kohonen_units::initialize_inputs_and_weights(void)
{
for(int k = 0; k < number_of_inputs; k++)
{input_weight_vector[k] = bedlam((long*)(gaset));}
}
void Kohonen_units::calculate_sum_square_Euclidean_distance(void)
{
double sumsquare;
float ss1;
int ci;
output_value[0] = 0.0;
for(int k = 0; k < number_of_inputs; k++)
{
ci = k;
if(input_value[ci] == 0.0)
{
sumsquare = pow(input_weight_vector[ci], 2.0);
}
else
{
sumsquare = pow(fabs(input_weight_vector[ci] - input_value[ci]), 2.0);
}
output_value[0] += sumsquare;
// cout << output_value[0] << "\n";
// cin >> output_value[0];
}
ss1 = output_value[0];
output_value[0] = sqrt(fabs(ss1));
}
void Kohonen_units::update_the_weights(float learning_rate)
{
for(int k = 0; k < number_of_inputs; k++)
{input_weight_vector[k] = input_weight_vector[k] + (learning_rate * (input_value[k] - input_weight_vector[k]));}
}
// RBFN //
void Kohonen_units::execute_Gaussian_transfer_function(void)
{
float transfer_ratio = (-1.0) * pow((output_value[0] / transfer_function_width), 2.0);
Gaussian_transfer_output = exp(transfer_ratio);
}
// define class and member functions which define Kohonen Topology
class Kohonen_Topology
{
public:
int kluster_champ;
int dimensions_of_signal;
int maximum_number_of_clusters;
float max_learning_rate;
float min_learning_rate;
float interim_learning_rate;
Kohonen_units *node_in_cluster_layer;
void establish_Kohonen_topology(int netuse);
void kluster_nodes_compete_for_activation(void);
void update_the_Kohonen_network(int epoch_count, int max_epochs);
virtual void upload_network(void); // retrieve network from file
virtual void savenet(void); // save network to file
Kohonen_Topology(); // class constructor
~Kohonen_Topology(); // class destructor
};
Kohonen_Topology::Kohonen_Topology()
{interim_learning_rate = 1.0;}
Kohonen_Topology::~Kohonen_Topology()
{delete [] node_in_cluster_layer;}
void Kohonen_Topology::establish_Kohonen_topology(int netuse)
{
char netcreate;
int looploc = 0;
if(netuse == 1)
{
do
{
cout <<"\n";
cout << "Do you wish to" << "\n\n";
cout << "C. Create your own Kohonen Map " << "\n";
cout << "U. Upload an existing Kohonen Map " << "\n\n";
cout << "Your choice?: "; cin >> netcreate;
cout << "\n\n";
netcreate = toupper(netcreate);
if((netcreate == 'C') || (netcreate == 'U')) {looploc = 1;}
} while(looploc <= 0);
}
else
{
netcreate = 'C';
}
if((netcreate == 'U') && (netuse == 1))
{upload_network();}
else
{
if(netuse == 1)
{
cout <<"Please enter the dimensions of the network's input signal vector: ";
cin >> dimensions_of_signal; cout <<"\n";
}
cout << "please enter the maximum number of clusters to be formed: ";
cin >> maximum_number_of_clusters; cout << "\n";
// establish clustering layer of Kohonen network
node_in_cluster_layer = new Kohonen_units[maximum_number_of_clusters];
for(int c = 0; c < maximum_number_of_clusters; c++)
{
node_in_cluster_layer[c].number_of_inputs = dimensions_of_signal;
node_in_cluster_layer[c].establish_input_output_arrays();
node_in_cluster_layer[c].establish_input_weight_vector_array();
node_in_cluster_layer[c].initialize_inputs_and_weights();
}
}
}
void Kohonen_Topology::upload_network(void)
{
char getname[13];
ifstream get_ptr;
int netid, nodes, dim;
int dolock = 0;
do
{
cout << "\n\n";
cout << "Please enter the name of the file which holds the Kohonen Map" << "\n";
cin >> getname; cout << "\n";
get_ptr.open(getname, ios::in);
get_ptr >> netid;
if(netid == 3) {dolock = 1;}
else
{
cout << "Error** file contents do not match Kohonen specifications" << "\n";
cout << "try again" << "\n";
get_ptr.close();
}
} while(dolock <= 0);
get_ptr >> dimensions_of_signal;
get_ptr >> maximum_number_of_clusters;
node_in_cluster_layer = new Kohonen_units[maximum_number_of_clusters];
for(nodes = 0; nodes < maximum_number_of_clusters; nodes++)
{
node_in_cluster_layer[nodes].number_of_inputs = dimensions_of_signal;
node_in_cluster_layer[nodes].establish_input_output_arrays();
node_in_cluster_layer[nodes].establish_input_weight_vector_array();
}
for(nodes = 0; nodes < maximum_number_of_clusters; nodes++)
{
for(dim = 0; dim < dimensions_of_signal; dim++)
{get_ptr >> node_in_cluster_layer[nodes].input_weight_vector[dim];}
}
get_ptr.close();
}
void Kohonen_Topology:: kluster_nodes_compete_for_activation(void)
{
float minimum_distance;
for(int m = 0; m < maximum_number_of_clusters; m++)
{
node_in_cluster_layer[m].calculate_sum_square_Euclidean_distance();
if(m == 0)
{
kluster_champ = m;
minimum_distance = node_in_cluster_layer[m].output_value[0];
}
else
{
if(node_in_cluster_layer[m].output_value[0] < minimum_distance)
{
kluster_champ = m;
minimum_distance = node_in_cluster_layer[m].output_value[0];
}
}
}
}
void Kohonen_Topology::update_the_Kohonen_network(int epoch_count, int max_epochs)
{
int maxepoch;
if(max_epochs == 1) {maxepoch = 1;} else {maxepoch = max_epochs - 1;}
float adjusted_learning_rate = max_learning_rate - (((max_learning_rate - min_learning_rate) / maxepoch) * epoch_count);
interim_learning_rate = adjusted_learning_rate * interim_learning_rate;
node_in_cluster_layer[kluster_champ].update_the_weights(interim_learning_rate);
}
void Kohonen_Topology::savenet(void)
{
char savename[13];
ofstream save_ptr;
int node, dim;
cout << "\n\n";
cout << "Please enter the name of the file which will hold the Kohonen Map" <<"\n";
cin >> savename; cout <<"\n";
save_ptr.open(savename, ios::out);
save_ptr << 3 << "\n"; // network identifier number
save_ptr << dimensions_of_signal << "\n";
save_ptr << maximum_number_of_clusters << "\n";
for(node = 0; node < maximum_number_of_clusters; node++)
{
for(dim = 0; dim < dimensions_of_signal; dim++)
{save_ptr << node_in_cluster_layer[node].input_weight_vector[dim] << " ";}
save_ptr <<"\n";
}
save_ptr.close();
}
// define class and member functions which define training and test data
// storage for the Kohonen Self_Organizing Map
class Kohonen_Training_Data : public ART_Training_Data
{
public:
void acquire_net_info(int signal);
void normalize_data_in_array(void);
virtual void request_Kohonen_data(int net_no);
};
void Kohonen_Training_Data::acquire_net_info(int signal)
{signal_dimensions = signal;}
void Kohonen_Training_Data::normalize_data_in_array(void)
{
int i, j, imax, imin;
int trigger;
float min, max;
max_output_value = new float[signal_dimensions];
min_output_value = new float[signal_dimensions];
for(j = 0; j < signal_dimensions; j++)
{
trigger = 1;
// identify minimum and maximum values for each dimension
for(i = 0; i < sample_number; i++)
{
if(i == 0)
{
max = number_of_samples[i].data_in_sample[j];
min = number_of_samples[i].data_in_sample[j];
}
else
{
if(number_of_samples[i].data_in_sample[j] < min)
{min = number_of_samples[i].data_in_sample[j];}
if(number_of_samples[i].data_in_sample[j] > max)
{max = number_of_samples[i].data_in_sample[j];}
}
}
// normalize the values in each dimension of the signal
max_output_value[j] = max;
min_output_value[j] = min;
imax = int(max);
imin = int(min);
if((imax == 1) && (imin == 0) && (max <= 1.0) && (min <= 0.0))
{trigger = 0;}
if((imax == 1) && (imin == 1) && (max <= 1.0) && (min <= 1.0))
{trigger = 0;}
if((imax == 0) && (imin == 0) && (max <= 0.0) && (min <= 0.0))
{trigger = 0;}
if(trigger != 0) // do not normalize binary signals
{
for(i = 0; i < sample_number; i++)
{number_of_samples[i].data_in_sample[j] = (number_of_samples[i].data_in_sample[j] - min)/(max - min);}
}
}
}
void Kohonen_Training_Data::request_Kohonen_data(int net_no)
{
cout << "Enter the file name containing the training data for Kohonen network no. " <<net_no << "\n";
cin >> filename; cout <<"\n";
specify_signal_sample_size();
normalize_data_in_array();
}
class Kohonen_Test_Data: public Kohonen_Training_Data
{public: void request_Kohonen_data(int net_no);};
void Kohonen_Test_Data::request_Kohonen_data(int net_no)
{
cout << "Please enter the file name containing the test data for Kohonen network no. " <<net_no << "\n";
cin >> filename; cout <<"\n";
specify_signal_sample_size();
normalize_data_in_array();
}
//************************************************************************//
class NeuralK // class containing the Kohonen neural net structure
{ // along with training and testing data
private:
Kohonen_Training_Data Kohonen_Train;
Kohonen_Test_Data *Kohonen_Test; // number of tests is variable
int number_of_Kohonen_tests;
void initialize_Kohonen_training_storage_array(int KN);
void establish_Kohonen_test_battery_size(void);
void train_Kohonen_network(int KOHN);
void test_Kohonen_network(int KNET);
public:
Kohonen_Topology Kohonen_Design;
void construct_Kohonen_network(void);
void network_training_testing(int TT);
~NeuralK();
};
//*************************************************************************//
NeuralK::~NeuralK()
{delete [] Kohonen_Test;}
void NeuralK::construct_Kohonen_network(void)
{
clrscr();
cout <<"**** Kohonen Self-Organizing Map ****"<< "\n\n\n";
Kohonen_Design.establish_Kohonen_topology(1);
}
void NeuralK::initialize_Kohonen_training_storage_array(int KN)
{
int KT = KN;
Kohonen_Train.acquire_net_info(Kohonen_Design.dimensions_of_signal);
Kohonen_Train.request_Kohonen_data(KT);
}
void NeuralK::establish_Kohonen_test_battery_size(void)
{
cout << "Please enter the number of tests you wish to run on the Kohonen Neural Network: ";
cin >> number_of_Kohonen_tests; cout << "\n";
if(number_of_Kohonen_tests > 0)
{
// create testing array
Kohonen_Test = new Kohonen_Test_Data[number_of_Kohonen_tests];
for(int t = 0; t < number_of_Kohonen_tests; t++)
{Kohonen_Test[t].acquire_net_info(Kohonen_Design.dimensions_of_signal);}
}
}
void NeuralK::train_Kohonen_network(int KOHN)
{
int dim, ep, k_epochs, pattern, knodes, dolock;
clrscr();
cout <<"\n\n";
cout << "For Neural Network #"<<KOHN<<"\n\n";
cout << "please enter the maximum learning rate parameter (0-1): ";
cin >> Kohonen_Design.max_learning_rate; cout <<"\n";
cout << "please enter the minimum learning rate parameter (0-1): ";
cin >> Kohonen_Design.min_learning_rate; cout <<"\n";
cout << "please enter the number of epochs used to train the Kohonen Map: ";
cin >> k_epochs; cout << "\n";
ep = 0;
dolock = 0;
do
{
for(pattern = 0; pattern < Kohonen_Train.sample_number; pattern++)
{
for(knodes = 0; knodes < Kohonen_Design.maximum_number_of_clusters; knodes++)
{
for(dim = 0; dim < Kohonen_Design.dimensions_of_signal; dim++)
{Kohonen_Design.node_in_cluster_layer[knodes].input_value[dim] = Kohonen_Train.number_of_samples[pattern].data_in_sample[dim];}
}
Kohonen_Design.kluster_nodes_compete_for_activation();
Kohonen_Design.update_the_Kohonen_network(ep, k_epochs);
}
cout << "Epoch " << ep + 1 << " is completed" <<"\n";
if((ep == k_epochs - 1) || (Kohonen_Design.interim_learning_rate == 0.0))
{dolock = 1;}
ep = ep + 1;
} while(dolock <= 0);
Kohonen_Train.delete_signal_array();
}
void NeuralK::test_Kohonen_network(int KNET)
{
int tnet, dim, pattern, knodes;
float realvalue;
tnet = KNET;
clrscr();
for(int ktest = 0; ktest < number_of_Kohonen_tests; ktest++)
{
Kohonen_Test[ktest].request_Kohonen_data(tnet);
cout <<"For Kohonen neural network #"<< KNET <<" and test #"<< ktest+1 <<":" <<"\n";
cout <<"please enter the name of the file to hold the test" << "\n";
cin >> Kohonen_Test[ktest].resultsname; cout <<"\n";
ofstream Kohonen_savefile_ptr(Kohonen_Test[ktest].resultsname);
for(pattern = 0; pattern < Kohonen_Test[ktest].sample_number; pattern++)
{
for(knodes = 0; knodes < Kohonen_Design.maximum_number_of_clusters; knodes++)
{
for(dim = 0; dim < Kohonen_Design.dimensions_of_signal; dim++)
{Kohonen_Design.node_in_cluster_layer[knodes].input_value[dim] = Kohonen_Test[ktest].number_of_samples[pattern].data_in_sample[dim];}
}
Kohonen_Design.kluster_nodes_compete_for_activation();
Kohonen_savefile_ptr << pattern + 1 << " ";
for(dim = 0; dim < Kohonen_Design.dimensions_of_signal; dim++)
{
realvalue = (Kohonen_Test[ktest].number_of_samples[pattern].data_in_sample[dim]*(Kohonen_Test[ktest].max_output_value[dim] - Kohonen_Test[ktest].min_output_value[dim])) + Kohonen_Test[ktest].min_output_value[dim];
Kohonen_savefile_ptr << realvalue << " ";
}
Kohonen_savefile_ptr << " " << Kohonen_Design.kluster_champ + 1 << "\n";
}
Kohonen_savefile_ptr.close();
Kohonen_Test[ktest].delete_signal_array();
} // end test loop
}
void NeuralK::network_training_testing(int TT)
{
int tt = TT;
int menu_choice;
clrscr();
cout << "\n\n\n\n";
cout << "**************** Operations Menu ****************" << "\n\n";
cout << " Please select one of the following options:" <<"\n\n";
cout << " 1. Train Kohonen network only " <<"\n\n";
cout << " 2. Test Kohonen network only " <<"\n\n";
cout << " 3. Train and Test Kohonen network" <<"\n\n";
cout << "*************************************************" << "\n\n";
cout << " Your choice?: "; cin >> menu_choice;
cout << "\n\n";
switch(menu_choice)
{
case 1:
initialize_Kohonen_training_storage_array(tt);
train_Kohonen_network(tt);
break;
case 2:
establish_Kohonen_test_battery_size();
if(number_of_Kohonen_tests > 0)
{test_Kohonen_network(tt);}
break;
case 3:
initialize_Kohonen_training_storage_array(tt);
train_Kohonen_network(tt);
establish_Kohonen_test_battery_size();
if(number_of_Kohonen_tests > 0)
{test_Kohonen_network(tt);}
break;
default:network_training_testing(tt);
}
}
// This concludes the Kohonen section of the program
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// (Radial Basis Function Network)
// define class and member functions which define Radial Basis Topology
class Radial_Basis_Topology: public Kohonen_Topology
{
public:
int number_of_output_units;
Output_units *node_in_output_layer;
int activation_function;
void establish_Radial_Basis_topology(void);
void establish_activation_function(void);
void calculate_transfer_function_widths(void);
void transfer_Gaussian_to_Output_layer(void);
void upload_network(void); // retrieve network from file
void savenet(void);
~Radial_Basis_Topology();
};
Radial_Basis_Topology::~Radial_Basis_Topology()
{ delete [] node_in_output_layer;}
void Radial_Basis_Topology::establish_activation_function(void)
{
int dolock = 1;
int bchoice;
cout << "\n";
cout << "For the output layer:" << "\n";
do
{
cout << "please select the type of activation function you wish the nodes to use" << "\n\n";
cout << "1. Binary Sigmoid Function " << "\n";
cout << "2. Bipolar Sigmoid Function " << "\n\n";
cout << "Your Selection "; cin >> bchoice;
cout << "\n\n";
if((bchoice == 1) || (bchoice == 2)) {dolock = 0;}
} while(dolock >= 1);
activation_function = bchoice;
}
void Radial_Basis_Topology::establish_Radial_Basis_topology(void)
{
char netcreate;
int looploc = 0;
do
{
cout <<"\n";
cout << "Do you wish to" << "\n\n";
cout << "C. Create your own RBF Network " << "\n";
cout << "U. Upload an existing RBF Network " << "\n\n";
cout << "Your choice?: "; cin >> netcreate;
cout << "\n\n";
netcreate = toupper(netcreate);
if((netcreate == 'C') || (netcreate == 'U')) {looploc = 1;}
} while(looploc <= 0);
if(netcreate == 'U')
{upload_network();}
else
{
cout << "Please enter the dimensions of the RBF networks's input signal vector: ";
cin >> dimensions_of_signal; cout << "\n";
establish_Kohonen_topology(2); // establishes maximum number of clusters
cout << "\n";
cout << "please enter the number of nodes in the RBF output layer: ";
cin >> number_of_output_units;
cout << "\n\n";
node_in_output_layer = new Output_units[number_of_output_units];
for(int o = 0; o < number_of_output_units; o++)
{
node_in_output_layer[o].number_of_input_units = maximum_number_of_clusters;
node_in_output_layer[o].establish_array_of_processing_unit_inputs();
node_in_output_layer[o].establish_weight_vector_for_processing_units();
node_in_output_layer[o].bias = 1.0 - (2.0 * bedlam((long*)(gaset)));
}
establish_activation_function();
}
}
void Radial_Basis_Topology::upload_network(void)
{
char getname[13];
ifstream get_ptr;
int netid, node, dim;
int dolock = 0;
do
{
cout << "\n\n";
cout << "Please enter the name of the file which holds the RBF network" << "\n";
cin >> getname; cout << "\n";
get_ptr.open(getname, ios::in);
get_ptr >> netid;
if(netid == 4) {dolock = 1;}
else
{
cout << "Error** file contents do not match RBF specifications" << "\n";
cout << "try again" << "\n";
get_ptr.close();
}
} while(dolock <= 0);
get_ptr >> dimensions_of_signal;
get_ptr >> number_of_output_units;
get_ptr >> activation_function;
get_ptr >> maximum_number_of_clusters;
node_in_output_layer = new Output_units[number_of_output_units];
for(node = 0; node < number_of_output_units; node++)
{
node_in_output_layer[node].number_of_input_units = maximum_number_of_clusters;
node_in_output_layer[node].establish_array_of_processing_unit_inputs();
node_in_output_layer[node].establish_weight_vector_for_processing_units();
get_ptr >> node_in_output_layer[node].bias;
}
for(node = 0; node < number_of_output_units; node++)
{
for(dim = 0; dim < maximum_number_of_clusters; dim++)
{get_ptr >> node_in_output_layer[node].weight_of_inputs[dim];}
}
node_in_cluster_layer = new Kohonen_units[maximum_number_of_clusters];
for(node = 0; node < maximum_number_of_clusters; node++)
{
node_in_cluster_layer[node].number_of_inputs = dimensions_of_signal;
node_in_cluster_layer[node].establish_input_output_arrays();
node_in_cluster_layer[node].establish_input_weight_vector_array();
get_ptr >> node_in_cluster_layer[node].transfer_function_width;
}
for(node = 0; node < maximum_number_of_clusters; node++)
{
for(dim = 0; dim < maximum_number_of_clusters; dim++)
{get_ptr >> node_in_cluster_layer[node].input_weight_vector[dim];}
}
get_ptr.close();
}
void Radial_Basis_Topology::calculate_transfer_function_widths(void)
{
float sum, w1, w2;
int i, j, k, ihold, jhold, khold;
for(i = 0; i < maximum_number_of_clusters; i++)
{node_in_cluster_layer[i].transfer_function_width = 0.0;}
for(i = 0; i < maximum_number_of_clusters - 1; i++)
{
for(j = i + 1; j < maximum_number_of_clusters; j++)
{
sum = 0.0;
for(k = 0; k < dimensions_of_signal; k++)
{
khold = k;
ihold = i;
jhold = j;
w1 = node_in_cluster_layer[ihold].input_weight_vector[khold];
w2 = node_in_cluster_layer[jhold].input_weight_vector[khold];
sum = pow((w1 - w2), 2.0);
node_in_cluster_layer[ihold].transfer_function_width += sum;
node_in_cluster_layer[jhold].transfer_function_width += sum;
}
}
}
for(i = 0; i < maximum_number_of_clusters; i++)
{
node_in_cluster_layer[i].transfer_function_width = (1.0 / (maximum_number_of_clusters - 1)) * node_in_cluster_layer[i].transfer_function_width;
node_in_cluster_layer[i].transfer_function_width = pow(node_in_cluster_layer[i].transfer_function_width, 0.5);
}
}
void Radial_Basis_Topology::transfer_Gaussian_to_Output_layer(void)
{
int i, j;
for(i = 0; i < maximum_number_of_clusters; i++)
{
node_in_cluster_layer[i].calculate_sum_square_Euclidean_distance();
node_in_cluster_layer[i].execute_Gaussian_transfer_function();
}
// transfer signal from cluster to output units and calculate output
for(i = 0; i < number_of_output_units; i++)
{
for(j = 0; j < maximum_number_of_clusters; j++)
{node_in_output_layer[i].processing_unit_input[j] = node_in_cluster_layer[j].Gaussian_transfer_output;}
node_in_output_layer[i].calculate_output_signal(activation_function);
}
}
void Radial_Basis_Topology::savenet(void)
{
char savename[13];
ofstream save_ptr;
int node, dim;
cout << "\n\n";
cout << "Please enter the name of the file which will hold the RBF network"<<"\n";
cin >> savename; cout <<"\n";
save_ptr.open(savename, ios::out);
save_ptr << 4 << "\n"; //network identifier number
save_ptr << dimensions_of_signal << "\n";
save_ptr << number_of_output_units << "\n";
save_ptr << activation_function << "\n";
save_ptr << maximum_number_of_clusters << "\n";
for(node = 0; node < number_of_output_units; node++)
{save_ptr << node_in_output_layer[node].bias << " ";}
save_ptr << "\n";
for(node = 0; node < number_of_output_units; node++)
{
for(dim = 0; dim < maximum_number_of_clusters; dim++)
{save_ptr << node_in_output_layer[node].weight_of_inputs[dim] << " ";}
save_ptr << "\n";
}
for(node = 0; node < maximum_number_of_clusters; node++)
{save_ptr << node_in_cluster_layer[node].transfer_function_width << " ";}
save_ptr << "\n";
for(node = 0; node < maximum_number_of_clusters; node++)
{
for(dim = 0; dim < dimensions_of_signal; dim++)
{save_ptr << node_in_cluster_layer[node].input_weight_vector[dim] << " ";}
save_ptr << "\n";
}
save_ptr.close();
}
//******************************************************************************
class NeuralR // class containing the Radial Basis neural net structure
{ // along with training and testing data
private:
Training RTrain; // file name and dynamic array for training
Testing *RTests; // files containing data to test network
int number_of_tests; // number of tests run on the neural net
void initialize_training_storage_array(int R);
void establish_test_battery_size(void);
void train_RBF_neural_network(int RBF);
void test_neural_network(int RBN);
public:
Radial_Basis_Topology RBF_Design; // specification of radial basis network
void establish_Radial_Basis_network(void);
void network_training_testing(int TT);
~NeuralR();
};
//******************************************************************************
NeuralR::~NeuralR()
{delete [] RTests;}
void NeuralR::initialize_training_storage_array(int R)
{
RTrain.acquire_net_info(RBF_Design.dimensions_of_signal, RBF_Design.number_of_output_units);
RTrain.request_training_data(R);
}
void NeuralR::establish_test_battery_size(void)
{
clrscr();
cout << "Please enter the number of tests you wish to run on the RBF network: ";
cin >> number_of_tests; cout << "\n";
RTests = new Testing[number_of_tests];
for(int i = 0; i < number_of_tests; i++)
{RTests[i].acquire_net_info(RBF_Design.dimensions_of_signal, RBF_Design.number_of_output_units);}
}
void NeuralR::establish_Radial_Basis_network(void)
{
clrscr();
cout << " **** Radial Basis Function Network **** " << "\n\n\n";
RBF_Design.establish_Radial_Basis_topology();
}
void NeuralR::train_RBF_neural_network(int RBF)
{
char savefile;
float output_error, sum_of_error, real_error_difference, target_minimum_average_squared_error;
int bepoch, outnode, sig, sigdim, cnode;
int dim, ep, k_epochs, pattern, knodes, dolock;
float *maxdifference;
float *meandifference;
int loopexit = 1;
ofstream savefile_ptr;
// establish cluster centers weight vectors via K-means clustering
clrscr();
cout <<"\n\n";
cout << "For Neural Network #"<<RBF<<"\n\n";
cout << "please enter the maximum learning rate parameter (0-1): ";
cin >> RBF_Design.max_learning_rate; cout <<"\n";
cout << "please enter the minimum learning rate parameter (0-1): ";
cin >> RBF_Design.min_learning_rate; cout <<"\n";
cout << "please enter the number of epochs used to train the RBF clusters: ";
cin >> k_epochs; cout << "\n\n\n";
ep = 0;
dolock = 0;
do
{
for(pattern = 0; pattern < RTrain.sample_number; pattern++)
{
for(knodes = 0; knodes < RBF_Design.maximum_number_of_clusters; knodes++)
{
for(dim = 0; dim < RBF_Design.dimensions_of_signal; dim++)
{
RBF_Design.node_in_cluster_layer[knodes].input_value[dim] = RTrain.number_of_samples[pattern].data_in_sample[dim];
}
}
RBF_Design.kluster_nodes_compete_for_activation();
RBF_Design.update_the_Kohonen_network(ep, k_epochs);
}
if((ep == k_epochs - 1) || (RBF_Design.interim_learning_rate == 0.0))
{dolock = 1;}
ep = ep + 1;
} while(dolock <= 0);
RBF_Design.calculate_transfer_function_widths();
// use supervised learning for output layer weight vector
cout << "Cluster center vectors established" << "\n\n";
cout << "please enter the number of epochs you wish to use for training"<< "\n";
cout << "the output layer: "; cin >> RTrain.number_of_epochs; cout<< "\n\n";
cout << "please enter the learning rate constant for backpropagation (0-1): ";
cin >> RTrain.rate_of_learning; cout << "\n";
cout << "please enter the minimum average squared error you wish to target" << "\n";
cin >> target_minimum_average_squared_error; cout << "\n";
do
{
cout << "do you wish to save the mean error, maximum error" << "\n";
cout << "and average squared error for each epoch to a file? (Y or N): "; cin >> savefile;
savefile = toupper(savefile);
if((savefile == 'Y') || (savefile == 'N')) {loopexit = 2;}
cout << "\n";
} while(loopexit <= 1);
if(savefile == 'Y')
{
cout << "please enter the name of the file which will hold the results of training:" << "\n";
cin >> RTrain.resultsname; cout <<"\n";
savefile_ptr.open(RTrain.resultsname, ios::out);
}
maxdifference = new float[RBF_Design.number_of_output_units];
meandifference = new float[RBF_Design.number_of_output_units];
// intiate backpropagation for appropriate number of epochs
bepoch = 0;
do
{
sum_of_error = 0;
for(sig = 0; sig < RTrain.sample_number; sig++)
{
output_error = 0;
for(sigdim = 0; sigdim < RTrain.signal_dimensions; sigdim++)
{
for(cnode = 0; cnode < RBF_Design.maximum_number_of_clusters; cnode++)
{RBF_Design.node_in_cluster_layer[cnode].input_value[sigdim] = RTrain.number_of_samples[sig].data_in_sample[sigdim];}
}
RBF_Design.transfer_Gaussian_to_Output_layer();
for(outnode = 0; outnode < RBF_Design.number_of_output_units; outnode++)
{
RBF_Design.node_in_output_layer[outnode].calculate_output_error_information_term(RTrain.number_of_samples[sig].data_in_sample[RTrain.signal_dimensions + outnode], RBF_Design.activation_function);
// calculate the instantaneous sum of squared errors (Haykin, 1994)
real_error_difference = (pow(RBF_Design.node_in_output_layer[outnode].error_difference_squared, 0.5)) * (RTrain.max_output_value[outnode] - RTrain.min_output_value[outnode]);
output_error += 0.5 * pow(real_error_difference, 2.0);
// calculate maximum and mean absolute error difference for each node
real_error_difference = RBF_Design.node_in_output_layer[outnode].absolute_error_difference * (RTrain.max_output_value[outnode] - RTrain.min_output_value[outnode]);
meandifference[outnode] += real_error_difference / float(RTrain.sample_number);
if(sig == 0) {maxdifference[outnode] = real_error_difference;}
else
{
if(real_error_difference > maxdifference[outnode])
{maxdifference[outnode] = real_error_difference;}
}
}
// average squared error for each signal is saved
sum_of_error += output_error / float (RTrain.sample_number);
// update the RBF network's output nodes
for(outnode = 0; outnode < RBF_Design.number_of_output_units; outnode++)
{RBF_Design.node_in_output_layer[outnode].calculate_weight_and_bias_correction_terms(RTrain.rate_of_learning);}
} // end sig loop
// save error information (if required)
if(savefile == 'Y')
{
savefile_ptr << bepoch + 1 << " ";
savefile_ptr << sum_of_error << " ";
for(outnode = 0; outnode < RBF_Design.number_of_output_units; outnode++)
{savefile_ptr << maxdifference[outnode] << " " << meandifference[outnode] << " ";}
savefile_ptr << endl;
cout.width(6);
clrscr();
cout << "Epoch #"<< bepoch + 1 <<" is completed " << endl;
}
if(bepoch == 0)
{RTrain.minimum_average_squared_error = sum_of_error;}
else
{
if(sum_of_error < RTrain.minimum_average_squared_error)
{RTrain.minimum_average_squared_error = sum_of_error;}
}
for(outnode = 0; outnode < RBF_Design.number_of_output_units; outnode++)
{ maxdifference[outnode] = 0.0; meandifference[outnode] = 0.0;}
if(RTrain.minimum_average_squared_error <= target_minimum_average_squared_error)
{break;}
bepoch = bepoch + 1;
} while(bepoch < RTrain.number_of_epochs);
savefile_ptr.close();
// delete arrays holding the training data
RTrain.delete_signal_data_array();
delete [] maxdifference;
delete [] meandifference;
}
void NeuralR::test_neural_network(int RBN)
{
float output_error, real_output;
int sig, sigdim, knodes, outnode;
int rbn = RBN;
for(int RBtest = 0; RBtest < number_of_tests; RBtest++)
{
RTests[RBtest].request_testing_data(rbn, RBtest + 1);
cout << "please enter the name of the file which will hold the results of test: " << RBtest + 1 << "\n";
cin >> RTests[RBtest].resultsname; cout << "\n";
ofstream savefile_ptr(RTests[RBtest].resultsname);
for(sig = 0; sig < RTests[RBtest].sample_number; sig++)
{
output_error = 0.0;
savefile_ptr << sig + 1 <<" ";
for(knodes = 0; knodes < RBF_Design.maximum_number_of_clusters; knodes++)
{
for(sigdim = 0; sigdim < RBF_Design.dimensions_of_signal; sigdim++)
{RBF_Design.node_in_cluster_layer[knodes].input_value[sigdim] = RTests[RBtest].number_of_samples[sig].data_in_sample[sigdim];}
}
RBF_Design.transfer_Gaussian_to_Output_layer();
// send target output to a file
for(outnode = 0; outnode < RBF_Design.number_of_output_units; outnode++)
{
real_output = RTests[RBtest].min_output_value[outnode] + (RTests[RBtest].number_of_samples[sig].data_in_sample[outnode + RBF_Design.dimensions_of_signal] * (RTests[RBtest].max_output_value[outnode] - RTests[RBtest].min_output_value[outnode]));
savefile_ptr << real_output << " ";
}
savefile_ptr <<" ";
// send network output to a file
for(outnode = 0; outnode < RBF_Design.number_of_output_units; outnode++)
{
RBF_Design.node_in_output_layer[outnode].calculate_output_error_information_term(RTests[RBtest].number_of_samples[sig].data_in_sample[RTests[RBtest].signal_dimensions + outnode], RBF_Design.activation_function);
real_output = RTests[RBtest].min_output_value[outnode] + (RBF_Design.node_in_output_layer[outnode].output_signal * (RTests[RBtest].max_output_value[outnode] - RTests[RBtest].min_output_value[outnode]));
savefile_ptr << real_output << " ";
}
// send absolute error difference to a file
for(outnode = 0; outnode < RBF_Design.number_of_output_units; outnode++)
{
real_output = (pow(RBF_Design.node_in_output_layer[outnode].error_difference_squared, 0.5)) * (RTests[RBtest].max_output_value[outnode] - RTests[RBtest].min_output_value[outnode]);
savefile_ptr << real_output << " ";
real_output = pow(real_output, 2.0);
output_error += 0.5 * real_output;
}
// save sum square of error
savefile_ptr << output_error << "\n";
if(sig == RTests[RBtest].sample_number - 1)
{savefile_ptr.close();}
}
RTests[RBtest].delete_signal_array();
}
} // end test neural network function
void NeuralR::network_training_testing(int TT)
{
int tt = TT;
int menu_choice;
clrscr();
cout << "\n\n\n\n";
cout << "**************** Operations Menu ****************" << "\n\n";
cout << " Please select one of the following options:" <<"\n\n";
cout << " 1. Train RBF network only " <<"\n\n";
cout << " 2. Test RBF network only " <<"\n\n";
cout << " 3. Train and Test RBF network" <<"\n\n";
cout << "*************************************************" << "\n\n";
cout << " Your choice?: "; cin >> menu_choice;
cout << "\n\n";
switch(menu_choice)
{
case 1:
initialize_training_storage_array(tt);
train_RBF_neural_network(tt);
break;
case 2:
establish_test_battery_size();
if(number_of_tests > 0)
{test_neural_network(tt);}
break;
case 3:
initialize_training_storage_array(tt);
train_RBF_neural_network(tt);
establish_test_battery_size();
if(number_of_tests > 0)
{test_neural_network(tt);}
break;
default:network_training_testing(tt);
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// this template class stores the neural networks to a file
template <class Type>
class Storage
{
public:
void save_neural_network(Type & NET_Topology);
};
template <class Type>
void Storage<Type>::save_neural_network(Type & NET_Topology)
{
char schoice;
int dolock = 0;
do
{
clrscr();
cout << "\n\n\n\n";
cout << "Do you wish to save this neural network? (Y/N): ";
cin >> schoice;
schoice = toupper(schoice);
if((schoice == 'Y') || (schoice == 'N')) {dolock = 1;}
} while(dolock <= 0);
if(schoice == 'Y')
{NET_Topology.savenet();}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
class Neural_Window // this class holds the different types of neural nets
{
private:
void establish_network_type(void);
public: // user interface
char neural_network_type;
int neural_network_number;
void display_menu_for_net_selection(int NNnum);
};
void Neural_Window::display_menu_for_net_selection(int NNnum)
{
clrscr();
neural_network_number = NNnum;
cout.fill('*');
cout.width(70); cout << "\n";
cout.width(42);
cout << " Neural Network " << neural_network_number << " ";
cout.width(26); cout << "\n";
cout.width(71); cout << "\n\n";
cout << "Please select one of the following network types from the Main Menu";
int i = 0;
do {cout << "\n"; i = i + 1;} while (i < 3);
cout.fill(' ');
cout.width(10);
cout << " *** / Main Menu \\ ***"; cout << "\n\n";
cout.width(6);
cout << " F. Feedforward network using backpropagation " << "\n\n";
cout.width(6);
cout << " A. Adaptive Resonance Theory network for binary signals " <<"\n\n";
cout.width(6);
cout << " K. Kohonen Self-Organizing Map " <<"\n\n";
cout.width(6);
cout << " R. Radial Basis Function Network " <<"\n\n";
cout.width(6);
cout << " E. Exit Program" <<"\n\n";
cout << "\n\n\n";
cout.width(6);
cout << "Network Type (?) "; cin >> neural_network_type;
neural_network_type = toupper(neural_network_type);
if(neural_network_type != 'E')
{establish_network_type();}
}
void Neural_Window::establish_network_type(void)
{
int NNN = neural_network_number;
NeuralA *ART;
NeuralB *Backpropagation;
NeuralK *KOH;
NeuralR *RBF;
switch(neural_network_type)
{
case 'A': // Adaptive Resonance Theory Network (ART1) for clustering
ART = new NeuralA;
Storage<ART_Topology> Astore;
ART->construct_ART_network();
ART->network_training_testing(NNN);
Astore.save_neural_network(ART->ART_Design);
break;
case 'F': // Feedforward Network Using Backpropagation
Backpropagation = new NeuralB;
Storage<Back_Topology> Bstore;
Backpropagation->establish_backprop_network();
Backpropagation->network_training_testing(NNN);
Bstore.save_neural_network(Backpropagation->Net_Design);
break;
case 'K': // Kohonen Self-Organizing Map
KOH = new NeuralK;
Storage<Kohonen_Topology> Kstore;
KOH->construct_Kohonen_network();
KOH->network_training_testing(NNN);
Kstore.save_neural_network(KOH->Kohonen_Design);
break;
case 'R': // Radial Basis Function Network
RBF = new NeuralR;
Storage<Radial_Basis_Topology> Rstore;
RBF->establish_Radial_Basis_network();
RBF->network_training_testing(NNN);
Rstore.save_neural_network(RBF->RBF_Design);
break;
default: display_menu_for_net_selection(neural_network_number);
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void main(void)
{
_control87(MCW_EM, MCW_EM); // will mask floating point overflows,
// underflows, or divisions by 0
int number_of_nets;
Neural_Window User_net;
clrscr();
cout << " ******* Welcome to Pitt-Networks!! ******** " << "\n\n\n\a";
cout << "Please enter the number of networks you wish to develop: "; cin >> number_of_nets;
for(int NWnet = 1; NWnet < number_of_nets + 1; NWnet++)
{
User_net.display_menu_for_net_selection(NWnet);
if(User_net.neural_network_type == 'E')
{break;}
}
}
神经网络基本算法源程序BF,ART I,RBF,自组织算法
来源:互联网 发布日期:2011-12-04 19:26:42 浏览:25077次
导读:人工神经网络算法的诸多应用...
相关内容
AiLab云推荐
最新资讯
本月热点
热门排行
-
不被“机器狗之父”看好的人形机器人,未来要如何发展?
阅读量:72838
-
国产版达芬奇手术机器人价格跳水,是价格战要来了吗?
阅读量:67706
-
借势智元机器人,富临精工跨界入局人形机器人,准备好了吗?
阅读量:43605
-
实探全球首个核电灯塔工厂,这里有各式各样的机器人 | 碳访
阅读量:41897
-
傅盛:我不看好双足机器人的商业化
阅读量:13266
-
特斯拉要重返“万亿市值俱乐部”?Wedbush:AI和机器人技术是关键!
阅读量:12176
推荐内容
- 2024山东国际玻璃工业技术展览会
- 2024第二十二届中国广州国际汽车展览会
- 2024年阿尔及利亚国际暖通空调制冷展览会ALGERIA
- 2024第12届中国(青岛)国际茶产业博览会(华巨臣茶博会)
- 2024阿尔及利亚国际建材展
- 2024 第二十三届新加坡国际石油及天然气展览会暨研讨会
- 2024年荷兰阿姆斯特丹船舶游艇设备展览会METS TRADE
- 2024第12届巴基斯坦(卡拉奇)国际防务与军警展
- 2024年俄罗斯莫斯科电力、电网技术展览会
- 2024(京津冀)水果产销对接会
- 2024第二十一届北方(烟台)国际果业博览会(北方果博会 NIFIE)
- 2024第十六届中国(上海)振威国际化工装备博览会(CTEF)
- 2024第七届欧洲(德国不来梅)国际空间技术展
- 2024第十七届上海国际电池工业展览会(振威电池展 CNIBF)
- 2024第二十届上海国际充电设施产业展览会(振威充电设施展 evse)
- 2024第十一届浙江义乌国际智能装备博览会
- 2024第89届全国药品交易会(药交会 PHARMCHINA)
- 2024年中国北京国际高端食品饮料博览会
- 2024年中国(北京)国际有机绿色食品展览会
- IADE2024第三届突尼斯(杰尔巴)国际航空航天与防务展
- 2024年土耳其温室农业展土耳其畜牧机械展GrowTech Eurasia
- 2024中国北京名酒节暨世界葡萄酒博览会
- 2024第十三届杭州国际跨境电商交易博览会(跨交会 ICBE)
- 2024中国健康营养博览会(秋季)(NHNE)
- 2024乌兹别克斯坦食品及包装展 UZ PROD &INTER PACK
- 日本第45届国际建筑建材与家居材料展
- 2024中国国际制造业数智化博览会
- 2024第29届深圳国际服装供应链博览会(秋季)(FS展 Fashion Source)暨AW深圳原创设计时装周
- 2024越南(胡志明)轴承展览会
- 2024越南(胡志明)橡胶机械及塑料展览会
- 2024越南(胡志明)五金机械展览会
- 2024秋季中国(广州)国际茶业博览会
- 2024越南(胡志明)电机及线圈展览会
- 2024越南(胡志明)电线电缆展览会
- 2024越南(胡志明)润滑油及应用技术展览会
- 2024越南(胡志明)焊接与切割展览会
- 2024越南(胡志明)电池产品展览会
- 2024中国国际天然提取物和健康食品配料展览会(FIC-健康展2024)暨第23届全国秋季食品添加剂和配料展览会
- 2024厦门国际眼镜业展览会(厦门眼镜展)
- 2024第十八届中国宁波中小工厂展览会
- 2024越南(胡志明市)国际工业技术装备及产品展览会
- 2024深圳国际照明展览会
- 2024越南(胡志明)煤矿技术设备展览会
- 2024第20届越南胡志明国际工业展览会
- 2024第二十二届中国(北京)国际医疗旅游展览会(正和医疗旅游展 CMTF)
- 2024越南(胡志明)金属及冶金展览会
- 2024年越南国际制药装备及医疗器械展览会
- 2024越南国际表面处理及涂料涂装展览会
- 2024越南(胡志明)国际复合材料展览会
- 2024越南(胡志明)工程机械设备展览会
- 2024越南(胡志明)锅炉及压力容器展览会
- 2024越南(胡志明)化工展览会
- 2024越南(胡志明)工业自动化及仪器仪表展览会
- 2024越南(胡志明)机床工具展览会
- 2024越南(胡志明)金属加工及焊接技术展览会
- 2024越南(胡志明)铝工业展览会