Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save glennismade/e280e461eff8ce3ebea969703dffc879 to your computer and use it in GitHub Desktop.
Save glennismade/e280e461eff8ce3ebea969703dffc879 to your computer and use it in GitHub Desktop.
Basic MLP Neural Net with Sigmoidal activation
// Library file for handling datasets for MLPs
// Dr Richard Mitchell 15/12/06 ...7/6/11 .. 23/09/15
using namespace std;
#include <fstream>
#include <vector>
#include "mlpdata.h"
#include <iostream>
#include <iomanip>
//void vcopy (int num, int spos, int dpos, const double fromarray[], double toarray[]) {
// copy num doubles from the fromarray starting at index spos to the toarray starting at index dpos
// for (int ct=0; ct<num; ct++) toarray[ct+dpos] = fromarray[ct+spos];
//}
void arrout (char *s, int num, vector<double> data, int nl) {
// routine to output the num values in array data
// s is a string which precedes the array
// if nl is true, then \n is then output
cout.precision (3); // set precision : format of numbers
cout << s; // output s
// next do num doubles in data
for (int ct = 0; ct < num; ct++) cout << setw(8) << data[ct];
if (nl) cout << "\n"; // if desired output newline
}
// Implementation of dataset class
dataset::dataset() {
// argument less constructor, just initialises to 0
GetMemory(""); // initialise all relevant memory to 0
}
dataset::dataset (char *filename, char *name) {
// constructor where argument is name of file which contains data
// this opens files, initialises the number of inputs, etc
// creates space for the data
// then reads all the data from the file
ifstream datafile; // define stream variable for data
datafile.open(filename); // open file of given name
if (datafile.is_open()) {
datafile >> numinputs >> numoutputs >> numdataset >> datatype;
// read amounts of data from file and type
GetMemory(name); // create space for in/outs/errors etc
int nd, ndi=0, ct; // counters
if (datatype > 0) { // if not logic, then read min/max for ins/targets
for (ct=0; ct<numinputs + numoutputs; ct++) // read min values inputs and targets
datafile >> minNData[ct];
for (ct=0; ct<numinputs + numoutputs; ct++) // read max inputs and targets
datafile >> maxNData[ct];
for (ct=0; ct<numoutputs; ct++) { // ensure outputs have same min/max as targets
minNData[numinputs+numoutputs+ct] = minNData[numinputs+ct];
maxNData[numinputs+numoutputs+ct] = maxNData[numinputs+ct];
}
}
for (nd=0; nd<numdataset; nd++) { // read each item from set
for (ct=0; ct<numinputs + numoutputs; ct++) // read n inputs and targets
datafile >> alldata[ndi++];
ndi += numoutputs; // skip passed actual outputs
}
ScaleInsTargets(); // scaled inputs and targets
datafile.close(); // close file
}
else GetMemory("");
}
dataset::dataset (int nin, int nout, int nset, vector<double> netdata, char *name) {
// constructor to create dataset where raw data in array
// arguments passed numbers of inputs, nin, outputs, nout, and in set, nset
// data is a large enough array
numinputs = nin; // first store data sizes
numoutputs = nout;
numdataset = nset;
datatype = 0;
GetMemory(name); // create space for in/outs/errors etc
int wd = 0, nd, ndi=0, ct;
for (nd=0; nd<numdataset; nd++) { // now read each data item from data
for (ct=0; ct<numinputs + numoutputs; ct++) // read n inputs and targets
alldata[ndi++] = netdata[wd++];
ndi += numoutputs; // skip passed actual outputs
}
}
dataset::~dataset () {
// return memory to heap ... not needed as vectors used
}
void dataset::GetMemory(char *name) {
// create space for vectors for inputs, outputs, targets and SSEs
// first initialise memory
numinrow = numinputs + 2 * numoutputs; // how many elements in a row ie inputs, targets, outputs
alldata.resize(numinrow * numdataset); // get memory for all data
errors.resize(numoutputs); // and for vector of SSEs
classifications.resize(numoutputs); // and for % classifications
scaleddata.resize(numinrow); // and for row of re-Scaled data
minNData.resize(numinrow); // for min of all ins/targets/outputs
maxNData.resize(numinrow); // for max of all ins/targets/outputs
for (int ct=0; ct<numinrow; ct++) { // set min/max to 0 so no scaling
minNData[ct] = 0;
maxNData[ct] = 0;
}
strcpy_s(dataname, 40, name); // copy name to dataname
}
void dataset::ScaleInsTargets(void) {
// scale all ins/targets linearly to 0.1..0.9
// minNData and maxNData have minimum and maximum values for each in/target
int ndi = 0; // index into alldata.
for (int nd=0; nd<numdataset; nd++) { // read each item from set
for (int ct=0; ct<numinputs + numoutputs; ct++) { // read n inputs and targets
if (maxNData[ct] > minNData[ct])
alldata[ndi] = 0.1 + 0.8 * (alldata[ndi] - minNData[ct]) / (maxNData[ct] - minNData[ct]);
ndi++;
}
ndi += numoutputs; // skip passed actual outputs
}
}
vector<double> dataset::GetNthInputs (int n) {
// return a vector the inputs of nth item in data set
vector <double> ans;
for (int ct = 0; ct < numinputs; ct++) ans.push_back(alldata[n*numinrow + ct]);
return ans;
}
vector<double> dataset::GetNthTargets (int n){
// return a vector of targets of nth item in data set
vector <double> ans;
for (int ct = 0; ct < numoutputs; ct++) ans.push_back(alldata[n*numinrow + numinputs + ct]);
return ans;
}
vector<double> dataset::GetNthOutputs (int n){
// return address of (first) output of nth item in data set
vector <double> ans;
for (int ct = 0; ct < numoutputs; ct++) ans.push_back(alldata[n*numinrow + numinputs + numoutputs + ct]);
return ans;
}
void dataset::SetNthOutputs(int n, vector<double> outputs) {
// copy actual calculated outputs into nth item in data set
for (int ct = 0; ct < numoutputs; ct++)
alldata[n*numinrow + numinputs + numoutputs + ct] = outputs[ct];
}
void dataset::SetNthOutput(int n, double oneout) {
// for network with one output ... store oneout in dataset
alldata[n*numinrow + numinputs + numoutputs] = oneout;
}
vector<double> dataset::GetNthErrors (int n){
// calculate and return errors (targets-outouts) for n'th set in dataset
// for each output
int tarNdx = n*numinrow + numinputs; // index into targets array
int opNdx = tarNdx+numoutputs; // and to outputs
for (int ct = 0; ct < numoutputs; ct++)
errors[ct] = alldata[tarNdx++] - alldata[opNdx++]; // calc next error
return errors;
}
double dataset::GetNthError(int n) {
// return the error of the nth item in the data set (target - output)
return alldata[n*numinrow + numinputs] - alldata[n*numinrow + numinputs + 1];
}
double sqr (double v) { return v*v; } // calculate v^2
vector <double> dataset::CalcSSE (void){
// calculate and return sum of square of errors (targets-outouts)
// for each output
int ct, nct;
int tarNdx; // index into targets array
int opNdx; // and to outputs
for (ct = 0; ct < numoutputs; ct++)
errors[ct] = 0;
for (nct=0; nct<numdataset; nct++) {
tarNdx = nct*numinrow + numinputs; // index to first target for nct'th item
opNdx = tarNdx + numoutputs; // and to first output
for (ct=0; ct<numoutputs; ct++)
errors[ct] += sqr(alldata[tarNdx++] - alldata[opNdx++]); // add error ^ 2, and move indexes on
}
for (ct=0; ct<numoutputs; ct++)
errors[ct] = errors[ct] / numdataset; // divide by num in set
return errors;
}
vector<double> dataset:: CalcCorrectClassifications(void) {
// calculate and return sum of square of errors (targets-outouts)
// for each output
int tarNdx; // index into targets array
int outNdx; // into output array
int ct, nct;
for (ct=0; ct<numoutputs; ct++)
classifications [ct] = 0; // correct classifications = 0
for (nct=0; nct<numdataset; nct++) {
tarNdx = nct*numinrow + numinputs; // have index of first target for nct'th item in set
outNdx = tarNdx + numoutputs; // and of first output
for (ct=0; ct<numoutputs; ct++)
if (abs (DeScale(alldata[tarNdx++], ct, 1) - DeScale(alldata[outNdx++], ct, 1)) < 0.01) classifications[ct] += 1; // if scaled Target ~ Scaled Output
}
for (ct=0; ct<numoutputs; ct++)
classifications[ct] = (100 * classifications[ct] ) / numdataset; // turn result into a %
return classifications;
}
double dataset::DeScale(double val, int sCt, int forOut) {
// descale value val, according to datatype, min and max values (which are at index [sCt]
// forOut is true if this applies to target / output - so for instance floor/ceil to 0 or 1
double ans = val;
if (datatype == 0) {
if (forOut) {
if (val <= 0.5) ans = 0; else ans = 1;
}
}
else {
if (maxNData[sCt] > minNData[sCt])
ans = minNData[sCt] + (val - 0.1) * (maxNData[sCt] - minNData[sCt]) / 0.8;
if ((datatype == 2) && forOut)
ans = floor(0.5 + val);
}
return ans;
}
vector <double> dataset::CalcScaledData(int n, char which) {
int dataNdx = n*numinrow;
int minnum, maxnum;
switch (which) {
case 'I' : minnum = 0; maxnum = numinputs; break;
case 'T' : minnum = numinputs; maxnum = minnum + numoutputs; break;
case 'O' : minnum = numinputs+numoutputs; maxnum = minnum + numoutputs; break;
case 'A' : minnum = 0; maxnum = numinrow; break;
}
for (int ct=minnum; ct<maxnum; ct++) {
scaleddata[ct - minnum] = DeScale(alldata[ct + dataNdx], ct, ct>=numinputs);
} // call descale for each item
return scaleddata;
}
double dataset::TotalSSE (void) {
// calc and return sum of all SSEs of data in set
double ans = 0;
CalcSSE();
for (int ct=0; ct<numoutputs; ct++) ans += errors[ct];
return ans;
}
int dataset::numIns(void) {
// return number of data sets
return numinputs;
}
int dataset::numOuts(void) {
// return number of data sets
return numoutputs;
}
int dataset::numData(void) {
// return number of data sets
return numdataset;
}
void dataset::printarray (char *s, char which, int n, int nl) {
// print s then specifc array and \n if nl
// if which is 'I' print inputs; if 'O' print outputs;
// if 'T print targets, if 'S' print SSEs
// n specifies nth set of inputs,outputs, targets
switch (which) {
case 'i':
case 'I' : arrout(s, numinputs, GetNthInputs(n), nl); break;
case 'o' :
case 'O' : arrout(s, numoutputs, GetNthOutputs(n), nl); break;
case 't' :
case 'T' : arrout(s, numoutputs, GetNthTargets(n), nl); break;
case 's' :
case 'S' : arrout(s, numoutputs, CalcSSE(), nl); break;
case 'c' :
case 'C' : arrout(s, numoutputs, CalcCorrectClassifications(), nl); break;
case 'r' :
case 'R' : arrout(s, numoutputs, CalcScaledData(n, 'O'), nl); break;
}
}
void dataset::printdata (int showall) {
// pass a training set in data to network, show results
if ( (showall > 0) && (showall < 3) ) {
cout << setw(1 + 8*numinputs) << "Inputs"
<< setw(3 + 8*numoutputs) << "Targets"
<< setw(3 + 8*numoutputs) << " Actuals"
<< setw(3 + 8*numoutputs) << "Rescaled\n";
for (int ct=0; ct<numdataset; ct++) {
printarray (" ", 'I', ct, 0);
printarray (" : ", 'T', ct, 0);
printarray (" : ", 'O', ct, 0);
printarray (" : ", 'R', ct, 0);
cout << "\n";
}
}
else cout << dataname << " : ";
if (showall >= 3) printarray("% Correct Classifications ", 'C', 0, 1);
else {
printarray ("Mean Sum Square Errors are ", 'S', 0, 1);
if (showall && (datatype != 1) ) printarray("% Correct Classifications ", 'C', 0, 1);
}
}
void dataset::savedata (int goplot) {
// save data set (ins, targets and outs)
ofstream datafile; // define stream variable for data
int ct2;
char temp[80];
strcpy_s(temp, 50, dataname); // copy name to temp
strcat_s(temp, 60, "full.txt"); // add full.txt to name
datafile.open(temp); // open file of given name for writing to
if (datafile.is_open()) {
datafile << numinputs << " " << numoutputs << " " << numdataset << "\n";
for (int ct=0; ct<numdataset; ct++) {
CalcScaledData(ct, 'A');
for (ct2=0; ct2<numinrow; ct2++) datafile << scaleddata[ct2] << "\t";
datafile << "\n";
}
datafile.close();
if (goplot) { // evoke tadpole.exe with name of file .. does not work automatically
// strcpy (temp, "tadpole.exe ");
// strcat (temp, dataname);
// strcat(temp, "full.txt");
// system (temp);
cout << "Invoke the tadpole program, select file " << dataname << "full.txt and plot response.\n" ;
}
}
else cout << "Unable to create " << temp << "\n";
}
// Header file for mlpdata
// has class for storing data set for mlp
// inputs and targets can be read from file or from an array
// space also for calculated outputs and sum squares errors
// 2012, now have data fiels for logic; numerical and classification
//
// Dr Richard Mitchell 15/12/06 ...7/6/11 .. 23/08/11 .. 07/09/12 .. 18/09/15
#include <vector>
using namespace std;
class dataset {
int numdataset;
int numinputs;
int numoutputs;
int numinrow; // is numinputs + 2 * numoutputs
int datatype; // 0 for logic, 1 for numerical, 2 for classifier
vector<double> alldata; // array for inputs, outputs and targets
vector<double> minNData; // array for minimum values of each input/target
vector<double> maxNData; // array for maximum values of each input/target
vector<double> errors; // array for errors of each output : used fro errors, SSE, etc
vector<double> classifications; // array for % of correct classifications
vector<double> scaleddata; // for rescaling outputs at end for display
char dataname[40]; // name of data
void GetMemory(char *name);
void ScaleInsTargets(void);
double DeScale(double val, int sCt, int forOut);
// descale value val, according to datatype, min and max values index sCt, forOut is true if for target or out
public:
dataset();
dataset(char *filename, char *name);
dataset(int nin, int nout, int nset, vector<double> netdata, char *name);
~dataset();
vector<double> GetNthInputs (int n);
// return vector of inputs of nth item in data set
vector<double> GetNthTargets (int n);
// return vector of targets of nth item in data set
vector<double> GetNthOutputs (int n);
// return vector of array of output of nth item in data set
vector<double> GetNthErrors (int n);
// return vector of errors of nth item in data set (targets - outputs)
double GetNthError(int n);
// return the error of the nth item in the data set (target - output
void SetNthOutputs(int n, vector<double> outputs);
// copy actual calculated outputs into nth item in data set
void SetNthOutput(int n, double oneout);
// for network with one output ... store oneout in dataset
vector<double> CalcSSE (void);
// calculate SSE across data set, and return address of array with SSEs for each output
double TotalSSE (void);
// calc and return sum of all SSEs of data in set
vector<double> CalcCorrectClassifications(void);
// calculate and return vector of % of correct classifications
vector<double> CalcScaledData (int n, char which);
// calculate and return vector of scaled version for nth output set
int numIns (void);
// return number of inputs
int numOuts (void);
// return number of outputs
int numData (void);
// return number of data sets
void printarray (char *s, char which, int n, int nl = 0);
// print s then specifc array and \n if nl
// if which is 'I' print inputs; if 'O' print outputs;
// if 'T print targets, if 'S' print SSEs
// n specifies nth set of inputs,outputs,targets
void printdata (int showall);
// print data in set (all if showall) then its SSE
void savedata (int goplot = 0);
// save data set (ins, targets and outs) into file
// if goplot, then call tadpole program to plot
};
// Library Module Implementing Layers of Perceptrons for CY2D7 .. SE2NN11
// Dr Richard Mitchell 15/12/06 ... 18/09/13
// Adapted by
#include "mlplayer.h"
#include <math.h>
#include <iomanip>
#include <valarray>
// functions students write which return vectors need to be safe
// before student writes the code ... so by default they call this function
vector<double> dummyVector (int num) {
vector<double> dummy(num, 0);
return dummy;
}; // dummy vector :
double myrand (void) {
// return a random number in the range -1..1
// do so calling the rand function in math library
return -1.0 + (2.0 * rand() / RAND_MAX);
}
// Implementation of LinearLayerNetwork *****************************
LinearLayerNetwork::LinearLayerNetwork (int numIns, int numOuts) {
// constructor for Layer of linearly activated neurons
// it is passed the numbers of inputs and of outputs
// there are numOuts neurons in the layer
// each neuron has an output, a delta and an error -
// so have an array of outputs, deltas and errors
// each neuron has numIns+1 weights (first being the bias weight)
// so have large array of weights, and of weight changes
int ct;
numInputs = numIns; // store number inputs
numNeurons = numOuts; // and of outputs in object
numWeights = (numInputs + 1) * numNeurons; // for convenience calculate number of weights
// each neuron has bias + weight for each input
outputs.resize(numNeurons); // get space for array for outputs
deltas.resize(numNeurons); // and deltas
weights.resize(numWeights); // get space for weights
changeInWeights.resize(numWeights); // and change in weights
for (ct=0; ct<numWeights; ct++) {
weights[ct] = myrand(); // initialise weights randomly
changeInWeights[ct] = 0; // initialise changeInWeights to 0
}
for (ct=0; ct < numNeurons; ct++) { // initialise outputs and deltas to 0
outputs[ct] = 0;
deltas[ct] = 0;
}
}
LinearLayerNetwork::~LinearLayerNetwork() {
// destructor ... returns all 'new' memory to heap ... do nowt as all are vectors
}
void LinearLayerNetwork::CalcOutputs(vector<double> ins) {
// calculate the sum of each input in (ins) * associated weight, for each neuron in the layer
// store the results in the array of outputs
// as weights are stored in array, and accessed in order, use a counter auto indexed through array
int wtindex = 0; // counter/index set to refer to first weight of first neuron
for (int neuronct=0; neuronct < numNeurons; neuronct++) { // process each neuron in the layer, in order
outputs[neuronct] = weights[wtindex++]; // output = bias weight (move index to next weight)
for (int inputct=0; inputct < numInputs; inputct++) // for each input
outputs[neuronct] += ins[inputct] * weights[wtindex++]; // add input * next weight
}
}
void LinearLayerNetwork::ComputeNetwork (dataset &data) {
// pass each item in dataset to network and calculate the outputs
for (int ct=0; ct<data.numData(); ct++) { // for each item in data set
CalcOutputs (data.GetNthInputs(ct)); // calculate the weighted sum of inputs
StoreOutputs(ct, data); // copy outputs back into data set
}
}
void LinearLayerNetwork::StoreOutputs (int n, dataset &data) {
// copy calculated network outputs into n'th outputs in data
data.SetNthOutputs(n, outputs);
// Pass the outputs from the layer back to the data set, data
}
void LinearLayerNetwork::FindDeltas (vector<double> errors) {
// find the deltas of each neuron in layer, from the errors which are in the array passed here
deltas = errors; //the deltas for a linear neuron are the same as the errors, this simply applys this rule by assiging the erros variable to the deltas variable
}
void LinearLayerNetwork::ChangeAllWeights (vector<double> ins, double learnRate, double momentum) {
// Change all weights in layer - using inputs ins and [learning rate, momentum]
double numIns;
int nnwud = 0;
for (int countNeurons = 0; countNeurons < numNeurons; countNeurons++)
{
for (int wct = 0; wct < numInputs + 1; wct++) {
if (wct == 0) numIns = 1.0; else numIns = ins[wct - 1];
changeInWeights[nnwud] = numIns * deltas[countNeurons] * learnRate + changeInWeights[nnwud] * momentum;
weights[nnwud] += changeInWeights[nnwud];
nnwud++;
//takes the value of numIns and loops over the wct variable telling it to +1 to numInputs and then uses the function changeInWeights[wct] = numIns * deltas[wct] * learnRate + changeInWeights[wct] * momentum; to take the previouse weight(changeInWeights) and multiply by the deltas, momentum and learn rate and then pass it back to the changeInWeights[wct] variable before assiging these values to weights
}
}
}
void LinearLayerNetwork::AdaptNetwork (dataset &data, double learnRate, double momentum) {
// pass whole dataset to network : for each item
// calculate outputs, copying them back to data
// adjust weights using the delta rule : targets are in data
// where learnparas[0] is learning rate; learnparas[1] is momentum
for (int ct=0; ct<data.numData(); ct++) {
// for each item in data set
CalcOutputs(data.GetNthInputs(ct));
// get inputs from data and pass to network to calculate the outputs
StoreOutputs (ct, data);
// return calculated outputs from network back to dataset
FindDeltas(data.GetNthErrors(ct));
// get errors from data and so get neuron to calculate the deltas
ChangeAllWeights(data.GetNthInputs(ct), learnRate, momentum);
// and then change all the weights, passing inputs and learning constants
}
}
void LinearLayerNetwork::SetTheWeights (vector<double> initWt) {
// set the weights of the layer to the values in initWt
// do so by copying from initWt into object's weights
weights = initWt;
// copy all weights (numweights says how many) from array initWt to layer's array Weights
}
int LinearLayerNetwork::HowManyWeights (void) {
// return the number of weights in layer
return numWeights;
}
vector<double> LinearLayerNetwork::ReturnTheWeights () {
// return in theWts the current value of all the weights in the layer
return weights; //this function is asking the compiler to return a value of double (weights) and the return weights; function tells the system to return the vector double weights to the system
}
vector<double> LinearLayerNetwork::PrevLayersErrors () {
// find weighted sum of deltas in this layer, being errors for prev layer : return result
vector<double> errorcount(numInputs, 0); //temp vector for storing outputs
for (int ctr = 0; ctr < numInputs; ctr++) // loops through the below function
{
for (int ctr2 = 0; ctr2 < numNeurons; ctr2++)
{
errorcount[ctr] += deltas[ctr2] * weights[ctr2*(numInputs +1) + ctr + 1]; //tells the network take errorcount vectore at possistion of the counter and initilise it to the deltas at possistion 0 and * by the weights at possistion of counter plus 1
}
}
return errorcount; // returns my vector of errorcount thats storing the output of the prev layer errors
}
// Implementation of SigmoidalLayerNetwork *****************************
SigmoidalLayerNetwork::SigmoidalLayerNetwork (int numIns, int numOuts)
:LinearLayerNetwork (numIns, numOuts) {
// just use inherited constructor - no extra variables to initialise
}
SigmoidalLayerNetwork::~SigmoidalLayerNetwork() {
// destructor - does not need to do anything other than call inherited destructor
}
void SigmoidalLayerNetwork::CalcOutputs(vector<double> ins) {
// Calculate outputs being Sigmoid (WeightedSum of ins)
LinearLayerNetwork::CalcOutputs(ins); // takes the function of LinearLayerNetwork calcoutputs and uses inheritance to take the member variables.
for (int i = 0; i < outputs.size(); i++) //loops through the function for each output of the vector rather than the entire vector at once
{
outputs[i] = 1.0 / (1.0 + exp(-outputs[i])); // states that outputs is equal to 1/1 + the expinential function(-outputs)
}
}
void SigmoidalLayerNetwork::FindDeltas (vector<double> errors) {
// Calculate the Deltas for the layer -
// For this class these are Outputs * (1 - Outputs) * Errors
for (int i = 0; i < deltas.size(); i++) //used to loop through the vector for the below function
{
deltas[i] = outputs[i] * (1.0 - outputs[i]) *errors[i]; //calculates the deltas by taking the outputs and multiplying the the (1-outputs) and multiplying by errors (sets a value of 1 -outputs *errors *outputs as delta)
}
}
// Implementation of MultiLayerNetwork *****************************
MultiLayerNetwork::MultiLayerNetwork (int numIns, int numOuts, LinearLayerNetwork *tonextlayer)
:SigmoidalLayerNetwork (numIns, numOuts) {
// construct a hidden layer with numIns inputs and numOuts outputs
// where (a pointer to) its next layer is in tonextlayer
// use inherited constructor for hidden layer
// and attach the pointer to the next layer that is passed
nextlayer = tonextlayer;
}
MultiLayerNetwork::~MultiLayerNetwork() {
delete nextlayer; // remove output layer, then auto-call inherited destructor
}
void MultiLayerNetwork::CalcOutputs(vector<double> ins) {
// calculate the outputs of network given the inputs ins
SigmoidalLayerNetwork::CalcOutputs(ins); //calls the inherited function of calcOutputs from the sigmoidlayer
nextlayer->CalcOutputs(outputs); // tells the network to point to the next layer and tells it that (this) uses calcOutputs with the outputs veriable as a condidition
}
void MultiLayerNetwork::StoreOutputs(int n, dataset &data) {
nextlayer->StoreOutputs(n, data);// calls the StoreOutputs function from the previous layer and points (this) to the nextlayer and returns the nth dataset
}
void MultiLayerNetwork::FindDeltas (vector<double> errors) {
// find all deltas in the network
nextlayer->FindDeltas(errors); //points to the next layer finddeltas method passing errors as a peramiter
SigmoidalLayerNetwork::FindDeltas(nextlayer->PrevLayersErrors()); //calls the finddeltas function from the sigmoid layer and points it tothr next layer and tells it (this) is calculated using prev layer errors
}
void MultiLayerNetwork::ChangeAllWeights(vector<double> ins, double learnRate, double momentum) {
// Change all weights in network
SigmoidalLayerNetwork::ChangeAllWeights(ins, learnRate, momentum); // calls the sigmoid layer change all weights and pases them the peramiters of the method
nextlayer->ChangeAllWeights(outputs, learnRate, momentum); // this tells the network take the change in weights and move it to the next layer and by taking outputs from previous layer and passing it as a peramiter
}
void MultiLayerNetwork::SetTheWeights(vector<double> initWt) {
// load all weights in network using values in initWt
// initWt has the weights for this layer, followed by those for next layer
// first numWeights weights are for this layer
// set vector wthis so has weights from start of initWt til one before numWeights
vector<double> wthis(initWt.begin(), initWt.begin() + numWeights);
// set these into this layer
SigmoidalLayerNetwork::SetTheWeights(wthis);
// next copy rest of weights from initWt[numWeights..] to vector wrest
vector<double> wrest(initWt.begin() + numWeights, initWt.end());
// and then send them to the next layer
nextlayer->SetTheWeights(wrest);
}
int MultiLayerNetwork::HowManyWeights (void) {
// return the number of weights in network
return nextlayer->HowManyWeights() + numWeights; // takes a pointer to the nextlayer and tells the network nextlayer(this) = howmanyweights then add the number of weights (this layer) and return them both
}
vector<double> MultiLayerNetwork::ReturnTheWeights () {
// return the weights of the network into theWts
// the weights in this layer are put at the start, followed by those of next layer
vector<double> tmpWts = weights; //stores the weights on this layer into a tempry vector to prevent overwrighting of data
vector<double> strWts = nextlayer->ReturnTheWeights(); //takes a tempry vector and assigns it to a pointer of nextlayer(this) + return the weights inherited from sigmoid in the next layer
tmpWts.insert(tmpWts.end(), strWts.begin(), strWts.end()); // tells the network, take my vector of tmpWts and add on to the end of tmpWts the vector from nextlayer the start of strWts until the end of strWts
return tmpWts; //returns the tmpWts vector with the weights of this and the next layer
}
// include file for single and multiple layer network
// Dr Richard Mitchell 15/12/06 ... 18/09/13
// Adapted by
// First include definition of dataset class
#include "mlpdata.h"
// Next define classes for layers of networks
class LinearLayerNetwork { // simple layer with linear activation
protected:
friend class MultiLayerNetwork; // so MultiLayerNetwork can access protected functions
int numInputs, numNeurons, numWeights; // how many inputs, neurons and weights
vector<double> outputs; // array of neuron Outputs
vector<double> deltas; // and Deltas
vector<double> weights; // array of weights
vector<double> changeInWeights; // array of weight changes
virtual void CalcOutputs (vector<double> ins);
// ins are passed to net, weighted sums of ins are calculated
virtual void StoreOutputs (int n, dataset &data);
// copy calculated network outputs into the nth outputs in data
virtual void FindDeltas (vector<double> errors);
// find the deltas: from errors between targets and outputs
virtual void ChangeAllWeights (vector<double> ins, double learnRate, double momentum);
// change all weights in layer using deltas, inputs (ins), learning rate and momentum
vector <double> PrevLayersErrors ();
// find weighted sum of deltas in this layer being errors in prev layer
public:
LinearLayerNetwork (int numIns, int numOuts);
// constructor pass num of inputs and outputs (=neurons)
virtual ~LinearLayerNetwork ();
// destructor
virtual void ComputeNetwork (dataset &data);
// pass whole dataset to network, calculating outputs, storing in data
virtual void AdaptNetwork (dataset &data, double learnRate, double momentum);
// pass whole dataset to network : for each item
// calculate outputs, copying them back to data
// adjust weights using the delta rule : targets are in data
// adapt using learning rate and momentum
virtual void SetTheWeights (vector<double> initWt);
// initialise weights in network to values in initWt
virtual int HowManyWeights (void);
// return number of weights
virtual vector <double> ReturnTheWeights ();
// return the weights in the network into theWts
};
class SigmoidalLayerNetwork : public LinearLayerNetwork {
protected: // Output Layer with Sigmoid Activation
virtual void FindDeltas (vector<double> errors);
// find the deltas: being errors * output * (1 - output)
virtual void CalcOutputs (vector<double> ins);
// Calculate outputs as Sigmoid(Weighted Sum of ins)
public:
SigmoidalLayerNetwork (int numIns, int numOuts);
// constructor
virtual ~SigmoidalLayerNetwork ();
// destructor
};
class MultiLayerNetwork : public SigmoidalLayerNetwork {
// Network : a Sigmoid Activated Hidden Layer with output layer
protected:
LinearLayerNetwork *nextlayer; // pointer to next layer
virtual void CalcOutputs (vector<double> ins);
// // Calculate outputs of network from inputs
virtual void StoreOutputs (int n, dataset &data);
// copy calculated network outputs into the nth outputs in data
virtual void FindDeltas (vector<double> errors);
// find the deltas in next and this layer
virtual void ChangeAllWeights (vector<double> ins, double learnRate, double momentum);
// calc change in weights using deltas, inputs, learning rate and mmtum
public:
MultiLayerNetwork (int numIns, int numOuts, LinearLayerNetwork *tonextlayer);
// constructor
virtual ~MultiLayerNetwork ();
// destructor
virtual void SetTheWeights (vector<double> initWt);
// set the woeights of main layer and the nextlayer(s) using values in initWt
virtual int HowManyWeights (void);
// return number of weights in whole network
virtual vector<double> ReturnTheWeights ();
// return the weights of whole network into theWts
};
// Simple Multi Layer Perceptron program ... for SE2NN11
//
// Has single/multi layer network with multiple inputs and outputs,
// Can have linear or sigmoidal activation
// Configuration is set by files containing data sets used
// Can be tested on simple logic problems or numerical problems
// Dr Richard Mitchell 15/12/06 ... 18/09/13 .. 24/09/15
// Adapted by << Enter Your Name >>
#include <iostream>
#include <fstream>
#include <iomanip>
#include "mlplayer.h"
// define the classes for layers of neurons and for datasets
#include <windows.h>
using namespace std;
double learnRate = 0.2;
double momentum = 0;
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
void TestTheNet (LinearLayerNetwork *net, dataset &data, int howprint) {
// pass each item in the data set, data, to network, net,
// and store the outputs which were calculated back into data
// if howprint = 0; then just print SSE / % classifications;
// if howprint = 1, then also print ins/outs
// if howprint = -1, print nothing
net -> ComputeNetwork (data);
// pass whole of dataset to network
if (howprint >= 0) data.printdata(howprint);
} // if appropriate print result suitably
void SetTheWeights (LinearLayerNetwork *net, int nopt) {
// if called this initialises network net with specific weights
// some weights array are defined for xor and three logic probs
vector<double> pictonweights = {0.862518, -0.155797, 0.282885,
0.834986, -0.505997, -0.864449,
0.036498, -0.430437, 0.481210};
// weights given in Picton's book for XOR problem only
vector<double> logweights = {0.2, 0.5, 0.3, 0.3, 0.5, 0.1, 0.4, 0.1, 0.2};
// initial weights for neuron layer as used in lectures
vector<double> nlsweights = {0.2, 0.5, 0.4, 0.1, 0.2, 0.4,
-0.1, 0.5, 0.7, -0.2, -0.7, 0, 0, 0.1, -0.3, 0.3, 0.4, 0.1,
0.1, 0.2, 0.3, 0.2, 0.1, 0.2,-0.2, 0.4, -0.5, 0.1};
// initial weighst for non lin sep
if (nopt == 'X') // if doing XOR problem init with pictonweights
net -> SetTheWeights (pictonweights);
else if (nopt == 'O') // for non linear sep problem
net -> SetTheWeights (nlsweights);
else if ( (nopt == 'L') || (nopt == 'S') ) // if doing logic problems, init with logweights
net -> SetTheWeights (logweights);
// otherwise the default (random) weights are left unchanged
}
LinearLayerNetwork * MakeNet (char nopt, int numhids, dataset &data) {
// create and return appropriate network type
// nopt specifies linear activation/sigmoidal or multi layer
// number of inputs/outputs are defined in data set data
// for multilayer, numhids has number of nodes in hidden layers
if (nopt == 'L') // if specify linear layer
return new LinearLayerNetwork (data.numIns(), data.numOuts());
// call constructor for LinearLayerNetwork
else if (nopt == 'S') // if specify sigmoidal layer
return new SigmoidalLayerNetwork (data.numIns(), data.numOuts());
// call constructor for SigmoidalLayerNetwork
else // if multi-layer
return new MultiLayerNetwork (data.numIns(), numhids,
new SigmoidalLayerNetwork (numhids, data.numOuts()) );
// call constructor for SigmoidalLayerNetwork
} // whose next layer is a SigmoidalLayerNetwork
char getcapch(void) {
// gets next character input by user from console,
// if lower case convert to equiv upper case
char och;
cin >> och; // get character
cin.ignore(1); // skip rest of line
if ( (och >= 'a') && (och <= 'z')) och = och - 32;
// if lower case convert
return och;
}
void showweights (LinearLayerNetwork *net) {
// function to print the weights of the neurons in the network net
// first get space for sufficient number of weights
vector<double> warray(net->HowManyWeights(), 0);
// next get the weights from the network
warray = net->ReturnTheWeights ();
// now print them out in turn
for (int ct=0; ct<net->HowManyWeights(); ct++)
cout << warray[ct] << ',';
cout << '\n';
}
void setlparas () { // allow user to enter learning rate and momentum
cout << "Enter l-rate & momentum (both in range 0..1) > ";
cin >> learnRate >> momentum;
cin.ignore(1);
}
void testnet (char nopt, int wopt, int nhid, char *filename, char *dataname) {
// routine to test the network
// nopt is network option selected
// wopt is 0 if specific initial weights are to be used, otherwise default random ones
// s is name of file with training data
int emax, esofar = 0; // maximum number of epochs at a time, and total number of epochs so far
char och = ' '; // character used for commands input by user
dataset data (filename, dataname); // get data sets from file
if (data.numIns() == 0) {
cout << dataname << " file not found : may be in wrong folder\n";
return; // abort function
}
srand(wopt); // initialise random number generator
if (nopt == 'L') emax = 7; else emax = 1001;
// if sigmoidal/XOR have 1001 epochs .. else 7
LinearLayerNetwork *net = MakeNet (nopt, nhid, data);
// create appropriate form of network
if (wopt == 0) SetTheWeights (net, nopt);
// if not random weights, initialise weights as appropriate.
TestTheNet (net, data, 1); // test untrained net and print results unless Classifier
while (och != 'A') { // loop as follows depending on user commands
cout << "Enter (L)earn, (P)resent data, (C)hange learn consts, find (W)eights, (S)ave learntdata, (A)bort >";
och = getcapch();
if (och == 'L') { // choose to learn, so pass to network for emax epochs
for (int ct = 0; ct < emax; ct++) {
net->AdaptNetwork(data, learnRate, momentum);
// pass data to network and update weights; print if needed
if ((emax < 10) || (ct % 200 == 0)) {
// print SSE every 200'th epoch if sigmoidal, else each time
cout << " Epoch " << setw(6) << ct + esofar << " ";
data.printdata(0);
}
}
esofar = esofar + emax - 1; // update how many epochs taught so far
}
else if (och == 'C')
setlparas();
else if (och == 'P') // choose to pass training data to network and print
TestTheNet (net, data, 1);
else if (och == 'W') // choose to display weights of neurons
showweights (net);
else if (och == 'S') { // choose to save data file
TestTheNet (net, data, -1); // pass to network
data.savedata(); // save to file
}
}
}
void classtest (int numhid, int emax, int wopt, char *tstr, char *ustr) {
// test network on the classification problem
// specified are the learning rate, momentum, number of hidden neurpons
// emax is max number of epochs for learning
// wopt is seed used to initialise random number generators used to initialise weights
// data files names are in training and unseen sets are in tstr and ustr
double vwas = 1000, vsum = 0; // previous sum of valid.SSE, current sum
srand(wopt); // initialise random number generator
dataset train (tstr, "IrisTrain"); // create training set
dataset unseen (ustr, "IrisUnseen"); // and unseen set
LinearLayerNetwork * net = MakeNet ('N', numhid, train);
// create network with given hidden neurons
TestTheNet (net, train, 0); // test training set on untrained net
TestTheNet (net, unseen, 0); // and unseen set
int epoch = 0, learnt = 0;
while ( (learnt == 0) && (epoch < emax) ) { // keep going til stop training
net -> AdaptNetwork (train, learnRate, momentum); // pass training set
if (epoch % 50 == 0) { // every 50th epoch
cout << " " << epoch; // print epoch
train.printarray (" ", 'C', 0, -1); // and the number of correct classifications
}
epoch++; // increase epoch count
}
TestTheNet (net, train, 0); // test training set on trained net : 0 means just print % classifications
train.savedata(1); // save data in data file, so can do tadpole plot
TestTheNet (net, unseen, 0); // and unseen set
unseen.savedata(1);
}
void numtest (int numhid, int emax, int usevalid, int wopt, char *tstr, char *vstr, char *ustr) {
// test network on the numerical problem
srand(wopt); //calls the random number generator function (allready within the network)
dataset numTrain (tstr, "TestTrain"); //opens the dataset file iristrain and passes it to the network
dataset numUnseen(ustr, "TestUnseen"); //opens the dataset file irisunseen and passed it to the network
dataset validateSSE(vstr, "Validate");
double ssePrev = 1000, sseCurrent = 0;
LinearLayerNetwork * net = MakeNet('N', numhid, numTrain); //calls the createnetwork function and assignes it to the Makenet method/
TestTheNet(net, numTrain, 0);
TestTheNet(net, numUnseen, 0);
TestTheNet(net, validateSSE, 0);
//presents the datasets to the network for training
int epoch = 0, learnt = 0; //sets the learning rate and number of epochs to 0 prior to running
while ((learnt == 0) && (epoch < emax)) { // tells the network to loop through the learning function for a given number or epochs
net->AdaptNetwork(numTrain, learnRate, momentum); // passes the training set to the network
if (usevalid) { // checks is usevalid is true, calls TestTheNet and compares the current SSE to the validate dataset and points to the total SSE.
TestTheNet(net, validateSSE, -1);
sseCurrent += validateSSE.TotalSSE();
if (epoch > 150 && epoch % 10 == 0) // checks to see if the epochs are greater than 100, and if the epochs divided by 10 are = to 0 and if they are checks if the current SSE is greater than the previouse SSE when its multiplied by 0.999
{
if (sseCurrent > ssePrev * 0.999) { // if current SSE is equal to previouse SSE x by 0.999 it sets the learnt veriable to true / 1
learnt = 1;
}
ssePrev = sseCurrent; // else it sets the previouse sse to be equal to current SSE and sets the current sse to 0 to contnue the loop
sseCurrent = 0;
}
}
if (epoch % 20 == 0) { //checks to see if the conditions are met (epochs are set to check every 20)
cout << " " << epoch; // returns the number of epochs taken so far (for given number of epochs)
numTrain.printarray(" ", 'C', 0, -1); // calls the instance of the dataset and points it to the printarray function
}
epoch++; // increase epoch count by 1 every time it loops
}
cout << " " << epoch; // adds an aditional print of the epochs and SSE to the screen incase it terminates at an odd number of epochs
numTrain.printarray(" ", 'C', 0, -1);
TestTheNet(net, numTrain, 0); // prints the dataset results to the network and returns the SSE
numTrain.savedata(1); // saves the results of the dataset to the file irisTrainfull
TestTheNet(net, numUnseen, 0); // does the same as the above but for the unseen set
numUnseen.savedata(1); // does the same as the above but for the unseen set
TestTheNet(net, validateSSE, 0); // prints the results of the validation function and returns the SSE
validateSSE.savedata(1);
}
void main() {
// function to create and test single/multi layer network
int wopt = 0, hopt = 10, emax = 1001; // initialse key options
char och = 'A', nopt = 'L', usevalid = 'Y'; // characters used for selecting options
SMALL_RECT windowSize = {0, 0, 180, 180};
SetConsoleWindowInfo(hConsole, TRUE, &windowSize);
cout << "RJMs Perceptron network adapted by RJM\n";
while (och != 'Q') { // loop til quit
cout << "\nSelected Network is "; // display current set up
if (nopt == 'L') cout << "Linear Layer";
else if (nopt == 'S') cout << "Sigmoidal Layer";
else if (nopt == 'X') cout << "for XOR";
else if (nopt == 'O') cout << "for other NonLinSep problem";
else cout << "for Lin Prob with " << hopt << " hidden neurons";
cout << ". \nInitial random weights seed is " << wopt << "; ";
cout << "Learning rate is " << learnRate << " and Momentum " << momentum << "\n";
cout << "\nSelect (T)est network, set (N)etwork, set learning (C)onstants, (I)nitialise random seed, or (Q)uit > ";
// specify user's options
och = getcapch(); // read user's choice
if (och == 'N') { // user to choose network
cout << "\nSelect (L)inear layer (S)igmoidal (X)OR (O)ther nonseparable (C)lassifier (N)umerical Problem > ";
nopt = getcapch(); // get network type
if ( (nopt != 'L') && (nopt != 'S') && (nopt != 'X') && (nopt != 'O') && (nopt != 'U')) {
cout << "Enter number of nodes in hidden layer > ";
cin >> hopt; // if approp, get num hidden nodes also
cin.ignore(1);
cout << "Enter max number of epochs for learning >";
cin >> emax;
cin.ignore(1);
if (nopt != 'C') { // for numerical problem, ask about using validation
cout << "Use validation set to stop learning (Y/N) > ";
usevalid = getcapch();
}
}
}
else if (och == 'C') setlparas();
else if (och == 'I') { // user to specify initial weights
if ( (nopt != 'L') && (nopt != 'S') && (nopt != 'X') && (nopt != 'O'))
cout << "\nEnter seed used for random weights> ";
else
cout << "\nEnter 0 to use weights in notes, else set random weights> ";
cin >> wopt;
cin.ignore(1);
}
else if (och == 'T') { // option to test network
if ( (nopt == 'L') || (nopt == 'S') ) // test single layer network
testnet (nopt, wopt, 4, "logdata.txt", "AndOrXor");
else if (nopt == 'X') // test MLP on XOR
testnet (nopt, wopt, 2, "xordata.txt", "XOR");
else if (nopt == 'O') // test MLP on XOR
testnet (nopt, wopt, 4, "nonlinsep.txt", "NonLinSep");
else if (nopt == 'C') // test MLP on XOR
classtest (hopt, emax, wopt, "iristrain.txt", "irisunseen.txt");
else if (nopt == 'U') // test MLP on XOR
testnet (nopt, wopt, 4, "username.txt", "Username");
else if(nopt == 'M') // test on numerical problem normalised
numtest (hopt, emax, usevalid == 'Y', wopt, "trainNorm.txt", "validNorm.txt", "unseenNorm.txt");
else // test on numerical problem
numtest (hopt, emax, usevalid == 'Y', wopt, "GlennTrain.txt", "GlennValid.txt", "GlennUnseen.txt");
}
}
}
Neural Networks for Stock Market Prediction
Glenn Healy
BCs Computer Science
ABSTRACT
A Neural Network is used for data mining and analysis. It it an intelligent computer program that can detect patterns and changes in a data-set. For the purpose of stock market prediction, it uses Time Series prediction methods to analyze the patterns and changes in the data overtime. The type of neural network used in this paper is a back propagation multi-layer perceptron (MLP) network. This paper shall detail the process of collating data and applying it to the network to see if the network is capable of predicting the stock price. The network gave varying results but always hovered around a Mean Sum of Squared Errors of around 0.08…. thus showing potential.
1. INTRODUCTION
Attempting to predict the value of stock prices is not a new concept. People have tried numerous methods for decades. There are hundreds of techniques for market prediction. Most notable is the idea of Quant analysis, used by the large investment banks throughout the world.
They rely on the principle of Time Series Prediction. The idea of being able to calculate future data based on the analysis of trends and patterns within data. The principle is based on probability, for example if you flipped a coin 50 times and it landed face up (heads) 39 times odds are you would pick heads guessing/making an assumption that it was most likely to land on heads again. Time series prediction attempts to apply this principle to larger groups of data.
For the purpose of stock market prices using an MLP, the idea is that given enough data and an adequate learning rate and momentum, the network will be able to predict the mean price for the next day of trading. Thus predicting the financial crash of 2008 and by feeding it data from 2006 - 2007 and comparing the predicted numbers of Mean Sum of Squared Errors of the network's outputs to the actual numbers available to us we can see it has learnt.
The Network works on the principle of Sigmoidal Neurons and the back propagation algorithm, it takes a series of inputs and applies an associated weight, then passes the inputs to a series of hidden neurons and does the weighted sum. The process then repeats until the data has been "learnt". This is achieved through object orientated program using C++ and is developed in such a way that simple yet refined learning algorithms are hard coded into the very framework of the system.
2. APPLICATION OF DATA
For this task, the problem was about experimenting with the neural networks ability to "learn" certain types of problems and its inability to learn others. This presented an interesting opportunity, because of the way the network learns, it is able to be applied to "TSP" and allowed for an experiment on Stock Market data. Using historic stock prices, in sets of open, high, low and close values (e.g. O = 400, H = 600, L = 250, C = 500) I was able to apply the idea to 3 inputs and 1 output variable. With the close being the associated output for the particular set. The data sets are the stock prices for each day during the period 2006 - 2007.
Applying stock market data to a neural network is commonly done in investment banks to give them an edge on the stock market when making trading decisions. The thought was to take an already established network and highly analyzed data and attempt to see if it can 'learn' trends in financial data and test its ability to spot declines. Thus in principle it would allow for predictions of crashes and would help to alleviate some of the fallout from such an event.
Figure 1. Stock Market Graph
2.1. Reasoning Behind Data
One of the things that needed to be considered was the idea that any problem applied to the network would need to fit within the constraints of the system. So we had to pick a problem that could easily be applied to the network, otherwise major changes and alterations to the network would need to be made. so for this, data was sought that could be sorted and formatted to the desired template and then simply called in the program and the tests applied.
All the data for the tests was sourced from the Yahoo Finance archive online and was then converted into the desired format and then split into three files train.txt. unseen.txt and valid.txt, the ratio for splitting the data was based on a genetic algorithm utilizing a ratio of 30 sets for train, 15 sets for valid and 5 sets for unseen this out of 533 sets of data. giving values of 326 for train, 53 for unseen and 154 for valid.
This ratio proved to be better than simply taking it in larger chunks. We initially started off by simply taking the first 310 inputs at train and then the next 153 as valid and the rest as unseen, while the ratio was ok the splitting method was poor, showing that smaller ratios are better, as an experiment done later on with a smaller data set but with a ratio of 10, 5 and 2 provided a much smaller sum of squared errors. Even getting down to as little as 0.008 for one of the tests. The genetic algorithm can be found here - http://people.cs.pitt.edu/~hashemi/papers/CISIM2010_HBHashemi.pdf
2.2. Testing The Concept
After sorting through the the data and formatting and splitting the data had been done, I needed to ensure the network could read the files, luckily DR Mitchell had already provided a method for reading in files for the Numerical problem. This allowed me to simply change the file names in the code and copy the .text files into the program folder.
Next comes applying the tests to the data and checking if the network can learn the stock market.
For my initial tests I went with the default weights and 5 hidden neurons, 500 epochs and validation on with a learning rate of 0.7 and momentum of 0.8 I kept these settings for for tests of test changing only the learn rate and momentum for 5 tests.
This provided a mean SSE of around 0.3 and severally limited the networks ability to learn. So the number of hidden neurons was changed to 10 for the next 10 tests.
Figure 2. Tadpole Plot Graph
After this the number of hidden neurons was then increased to 15 for the nest 20 tests and the learn rate and momentum were altered to lower and lower numbers including 0.009. this provided a much better Mean SSE of around 0.088 - 0.0814
Figure 3. Output from Console.
Figure 4. Output from Console.
Eventually after increasing the number of neurons in blocks of around 5 for a long time I ended up with 200 neurons and the default Picton weights and momentum and learn rates changing with every test.
Figure 4. Output from Console 2.
2.3. What are the Results
So after over 100 different experiments with varying learning rates and momentum values and hidden neurons ranging from 5 - 200 and the weights set to default the network provided an estimated output of around 5133 according to validfull.txt and a lowest a mean sum of squared errors of around 0.08001. the network consistently stopped learning between 180 - 210 epochs.
2.4. Discussion of Results
The networks ability to learn is on show as the SSE drops lower, this clearly demonstrates the networks ability to at least partially learn patterns in complex data.
The lowest the SSE ever got to was 0.08001 indicating that although the network appears to be learning the problem partially it is clearly lacking.
It clearly indicates a strong foundation to start building off of, but the results are a lot less than ideal.
They are not as accurate as anticipated/desired and have been unable to empirically prove weather or not the network is capable or predicting a financial crash in the stock market.
The tadpole graphs show a slow depression/decline in the price of the stocks but doesn't provide enough detail to be a true indicator of a potential crash.
3. TO CONCLUDE
The experimented demonstrated that in principle neural networks have the ability to recognize patterns in large sets of data and can be used to solve complex problems by data analysis.
While the network couldn't indicate with 100% certainty that there would be a crash in 2008, given that we already know it happened the networks limited but clear results show that with enough data and time, and a well defined ratio the program would indicated potential falls in stock prices and maybe even allow economists to more carefully monitor the price and develop methods for limiting the potential fallout of future collapses. Providing a reference point for future work to be carried out on the topic.
Acknowledgement: with thanks to Mary Eyo - when the project was given to us, both myself and Mary Eyo decided to work together with the permission of DR Mitchell. We both researched the topic once we had decided to to stock market prediction. And she helped to provide the genetic algorithm for splitting the data.
4. REFERENCES
[1] Link to genetic algorithm and neural networks for stock market data http://people.cs.pitt.edu/~hashemi/papers/CISIM2010_HBHashemi.pdf
[2] Yahoo Finance Archive - https://uk.finance.yahoo.com/q/hp?s=%5EFTSE&b=3&a=00&c=2009&e=3&d=00&f=2011&g=d
[3] General topic research - http://www.fool.com/investing/general/2014/10/29/stock-market-crash-4-high-yield-dividend-stocks-yo.aspx
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <pthread.h>
#define N 5 /* define the total number of processes we want */
/* Set global variable */
float total=0;
int numthreads;
void *PrintthreadID(void *threadid)
{
long tid;
tid = (long)threadid;
printf("threadid = #%i\n", tid);
pthread_exit(NULL);
}
/* compute function just does something. */
int compute()
{
int i;
float oldtotal=0, result=0;
/* for a large number of times just square root and square the arbitrary number 1000 */
for(i=0;i<2000000000;i++)
{
result=sqrt(1000.0)*sqrt(1000.0);
}
/* Print the result – should be no surprise */
printf("Result is %f\n",result);
/* We want to keep a running total in the global variable total */ oldtotal = total;
total = oldtotal + result;
/* Print running total so far. */
printf("Total is %f\n",total);
return(0); }
int main() {
int pid[N], i, j, rc;
numthreads = 0;
pthread_t threads[N];
float result=0;
printf("\n");
for (i = 0; i < N; i++) {
rc = pthread_create(&threads[i], NULL, PrintthreadID, (void *)i);
compute();
}
for (i = 0; i < N; i++){
rc = pthread_join(i, NULL);
}
pthread_exit(NULL);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment