1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-20 20:23:03 +02:00
vcmi/AI/GeniusAI/neuralNetwork.cpp
Trevor Standley a3b6bb4892 AI loads .brain file which contains a list of objects to visit and what features are necessary to determine how valuable that objective is.
AI creates random neural networks and assumes that their outputs are trained values.
2009-08-18 07:37:45 +00:00

416 lines
12 KiB
C++

#include "neuralNetwork.h"
//using namespace std;
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
float norm(void)//add desired mean, multiply to get desired SD
{
static float kept = 0;
static bool in = 0;
if(!in)
{
float x = (rand()+1)/float(RAND_MAX+1);
float f = sqrtf( - 2.0f * log(x) );
x = (rand()+1)/float(RAND_MAX+1);
kept = f * cosf( 2.0f * M_PI * x );
in = true;
return f * sinf( 2.0f * M_PI * x );
}
else
{
in = false;
return kept;
}
}
/*******************************************************************
* Constructors
********************************************************************/
neuralNetwork::neuralNetwork() : nInput(0), nHidden1(0), nHidden2(0), nOutput(0)
{
inputNeurons = new double[1] ;
hiddenNeurons1 = new double[1] ;
hiddenNeurons2 = new double[1] ;
outputNeurons = new double[1] ;
wInputHidden = new double*[1] ;
wInputHidden[0] = new double[1];
wHidden2Hidden = new double*[1] ;
wHidden2Hidden[0] = new (double[1]);
wHiddenOutput = new double*[1] ;
wHiddenOutput[0] = new double[1];
}
neuralNetwork::neuralNetwork(const neuralNetwork& other): nInput(0), nHidden1(0), nHidden2(0), nOutput(0)
{
inputNeurons = new double[1] ;
hiddenNeurons1 = new double[1] ;
hiddenNeurons2 = new double[1] ;
outputNeurons = new double[1] ;
wInputHidden = new double*[1] ;
wInputHidden[0] = new double[1];
wHidden2Hidden = new double*[1] ;
wHidden2Hidden[0] = new (double[1]);
wHiddenOutput = new double*[1] ;
wHiddenOutput[0] = new double[1];
*this = other;
}
neuralNetwork::neuralNetwork(int nI, int nH1, int nH2, int nO) : nInput(nI), nHidden1(nH1), nHidden2(nH2), nOutput(nO)
{
//create neuron lists
//--------------------------------------------------------------------------------------------------------
inputNeurons = new double[nInput + 1] ;
for ( int i=0; i < nInput; i++ ) inputNeurons[i] = 0;
//create input bias neuron
inputNeurons[nInput] = -1;
hiddenNeurons1 = new double[nHidden1 + 1] ;
for ( int i=0; i < nHidden1; i++ ) hiddenNeurons1[i] = 0;
//create hidden bias neuron
hiddenNeurons1[nHidden1] = -1;
hiddenNeurons2 = new double[nHidden2 + 1] ;
for ( int i=0; i < nHidden2; i++ ) hiddenNeurons2[i] = 0;
//create hidden bias neuron
hiddenNeurons2[nHidden2] = -1;
outputNeurons = new double[nOutput] ;
for ( int i=0; i < nOutput; i++ ) outputNeurons[i] = 0;
//create weight lists (include bias neuron weights)
//--------------------------------------------------------------------------------------------------------
wInputHidden = new double*[nInput + 1] ;
for ( int i=0; i <= nInput; i++ )
{
wInputHidden[i] = new double[nHidden1];
for ( int j=0; j < nHidden1; j++ ) wInputHidden[i][j] = 0;
}
wHidden2Hidden = new double*[nHidden1 + 1] ;
for ( int i=0; i <= nHidden1; i++ )
{
wHidden2Hidden[i] = new (double[nHidden2]);
for ( int j=0; j < nHidden2; j++ ) wHidden2Hidden[i][j] = 0;
}
wHiddenOutput = new double*[nHidden2 + 1] ;
for ( int i=0; i <= nHidden2; i++ )
{
wHiddenOutput[i] = new double[nOutput];
for ( int j=0; j < nOutput; j++ ) wHiddenOutput[i][j] = 0;
}
//initialize weights
//--------------------------------------------------------------------------------------------------------
initializeWeights();
}
void neuralNetwork::operator = (const neuralNetwork&cpy)//assumes same structure
{
if( nInput != cpy.nInput || nHidden1 != cpy.nHidden1 || nHidden2 != cpy.nHidden2 || nOutput != cpy.nOutput)
{
delete[] inputNeurons;
delete[] hiddenNeurons1;
delete[] hiddenNeurons2;
delete[] outputNeurons;
//delete weight storage
for (int i=0; i <= nInput; i++) delete[] wInputHidden[i];
delete[] wInputHidden;
for (int j=0; j <= nHidden2; j++) delete[] wHiddenOutput[j];
delete[] wHiddenOutput;
for (int j=0; j <= nHidden1; j++) delete[] wHidden2Hidden[j];
delete[] wHidden2Hidden;
nInput = cpy.nInput;
nHidden1 = cpy.nHidden1;
nHidden2 = cpy.nHidden2;
nOutput = cpy.nOutput;
inputNeurons = new double[nInput + 1] ;
inputNeurons[nInput] = -1;
hiddenNeurons1 = new double[nHidden1 + 1] ;
hiddenNeurons1[nHidden1] = -1;
hiddenNeurons2 = new double[nHidden2 + 1] ;
hiddenNeurons2[nHidden2] = -1;
outputNeurons = new double[nOutput] ;
//create weight lists (include bias neuron weights)
//--------------------------------------------------------------------------------------------------------
wInputHidden = new double*[nInput + 1] ;
for ( int i=0; i <= nInput; i++ )
wInputHidden[i] = new double[nHidden1];
wHidden2Hidden = new double*[nHidden1 + 1] ;
for ( int i=0; i <= nHidden1; i++ )
wHidden2Hidden[i] = new (double[nHidden2]);
wHiddenOutput = new double*[nHidden2 + 1] ;
for ( int i=0; i <= nHidden2; i++ )
wHiddenOutput[i] = new double[nOutput];
}
for ( int i=0; i < nInput; i++ ) inputNeurons[i] = cpy.inputNeurons[i];
for ( int i=0; i < nHidden1; i++ ) hiddenNeurons1[i] = cpy.hiddenNeurons1[i];
for ( int i=0; i < nHidden2; i++ ) hiddenNeurons2[i] = cpy.hiddenNeurons2[i];
for ( int i=0; i < nOutput; i++ ) outputNeurons[i] = cpy.outputNeurons[i];
for ( int i=0; i <= nInput; i++ )
for ( int j=0; j < nHidden1; j++ )
wInputHidden[i][j] = cpy.wInputHidden[i][j];
for ( int i=0; i <= nHidden1; i++ )
for ( int j=0; j < nHidden2; j++ )
wHidden2Hidden[i][j] = cpy.wHidden2Hidden[i][j];
for ( int i=0; i <= nHidden2; i++ )
for ( int j=0; j < nOutput; j++ )
wHiddenOutput[i][j] = cpy.wHiddenOutput[i][j];
}
/*******************************************************************
* Destructor
********************************************************************/
neuralNetwork::~neuralNetwork()
{
//delete neurons
delete[] inputNeurons;
delete[] hiddenNeurons1;
delete[] hiddenNeurons2;
delete[] outputNeurons;
//delete weight storage
for (int i=0; i <= nInput; i++) delete[] wInputHidden[i];
delete[] wInputHidden;
for (int j=0; j <= nHidden2; j++) delete[] wHiddenOutput[j];
delete[] wHiddenOutput;
for (int j=0; j <= nHidden1; j++) delete[] wHidden2Hidden[j];
delete[] wHidden2Hidden;
}
double* neuralNetwork::feedForwardPattern(double *pattern)
{
feedForward(pattern);
return outputNeurons;
}
void neuralNetwork::mate(const neuralNetwork&n1,const neuralNetwork&n2)
{
for(int i = 0; i <= nInput; i++)
{
for(int j = 0; j < nHidden1; j++)
{
if(rand()%2==0)
wInputHidden[i][j] = n1.wInputHidden[i][j];
else
wInputHidden[i][j] = n2.wInputHidden[i][j];
}
}
for(int i = 0; i <= nHidden1; i++)
{
for(int j = 0; j < nHidden2; j++)
{
if(rand()%2==0)
wHidden2Hidden[i][j] =n1.wHidden2Hidden[i][j];
else
wHidden2Hidden[i][j] =n2.wHidden2Hidden[i][j];
}
}
for(int i = 0; i <= nHidden2; i++)
{
for(int j = 0; j < nOutput; j++)
{
if(rand()%2==0)
wHiddenOutput[i][j] =n1.wHiddenOutput[i][j];
else
wHiddenOutput[i][j] =n2.wHiddenOutput[i][j];
}
}
}
void neuralNetwork::tweakWeights(double howMuch)
{
//set range
double rH = 1/sqrt( (double) nInput);
double rO = 1/sqrt( (double) nHidden1);
for(int i = 0; i <= nInput; i++)
{
for(int j = 0; j < nHidden1; j++)
{
wInputHidden[i][j] += howMuch*norm();
}
}
for(int i = 0; i <= nHidden1; i++)
{
for(int j = 0; j < nHidden2; j++)
{
wHidden2Hidden[i][j] += howMuch*norm();
}
}
for(int i = 0; i <= nHidden2; i++)
{
for(int j = 0; j < nOutput; j++)
{
wHiddenOutput[i][j] += howMuch* norm();
}
}
//initializeWeights();
}
void neuralNetwork::initializeWeights()
{
//set range
double rH = 2.0/sqrt( (double) nInput);
double rO = 2.0/sqrt( (double) nHidden1);
//set weights between input and hidden
//--------------------------------------------------------------------------------------------------------
for(int i = 0; i <= nInput; i++)
{
for(int j = 0; j < nHidden1; j++)
{
//set weights to random values
wInputHidden[i][j] = norm()* rH;
}
}
for(int i = 0; i <= nHidden1; i++)
{
for(int j = 0; j < nHidden2; j++)
{
//set weights to random values
wHidden2Hidden[i][j] = norm()* rO;
}
}
//set weights between hidden and output
//--------------------------------------------------------------------------------------------------------
for(int i = 0; i <= nHidden2; i++)
{
for(int j = 0; j < nOutput; j++)
{
//set weights to random values
wHiddenOutput[i][j] = norm()* rO;
}
}
}
/*******************************************************************
* Activation Function
********************************************************************/
inline double neuralNetwork::activationFunction( double x )
{
//sigmoid function
return 1/(1+exp(-x));
}
/*******************************************************************
* Feed Forward Operation
********************************************************************/
void neuralNetwork::feedForward(double* pattern)
{
//set input neurons to input values
for(int i = 0; i < nInput; i++) inputNeurons[i] = pattern[i];
//Calculate Hidden Layer values - include bias neuron
//--------------------------------------------------------------------------------------------------------
for(int j=0; j < nHidden1; j++)
{
//clear value
hiddenNeurons1[j] = 0;
//get weighted sum of pattern and bias neuron
for( int i=0; i <= nInput; i++ ) hiddenNeurons1[j] += inputNeurons[i] * wInputHidden[i][j];
//set to result of sigmoid
hiddenNeurons1[j] = activationFunction( hiddenNeurons1[j] );
}
for(int j=0; j < nHidden2; j++)
{
//clear value
hiddenNeurons2[j] = 0;
//get weighted sum of pattern and bias neuron
for( int i=0; i <= nHidden1; i++ ) hiddenNeurons2[j] += hiddenNeurons1[i] * wHidden2Hidden[i][j];
//set to result of sigmoid
hiddenNeurons2[j] = activationFunction( hiddenNeurons2[j] );
}
//Calculating Output Layer values - include bias neuron
//--------------------------------------------------------------------------------------------------------
for(int k=0; k < nOutput; k++)
{
//clear value
outputNeurons[k] = 0;
//get weighted sum of pattern and bias neuron
for( int j=0; j <= nHidden2; j++ ) outputNeurons[k] += hiddenNeurons2[j] * wHiddenOutput[j][k];
//set to result of sigmoid
//outputNeurons[k] = activationFunction( outputNeurons[k] );
}
}
void neuralNetwork::backpropigate(double* pattern, double OLR, double H2LR, double H1LR )
{
//inputError = new double[nInput + 1] ;
double * hiddenError1 = new double[nHidden1 + 1] ;
double * hiddenError2 = new double[nHidden2 + 1] ;
double * outputError = new double[nOutput] ;
memset(hiddenError1,0,sizeof(double)*nHidden1);
memset(hiddenError2,0,sizeof(double)*nHidden2);
for(int i = 0; i < nOutput; i++)
{
outputError[i] = (pattern[i]-outputNeurons[i]);//*(outputNeurons[i]*(1-outputNeurons[i]));
for(int ii = 0; ii <= nHidden2;ii++)
hiddenError2[ii]+=outputError[i]*wHiddenOutput[ii][i];
for(int ii = 0; ii <= nHidden2;ii++)
wHiddenOutput[ii][i]+=OLR*hiddenNeurons2[ii]*outputError[i];
}
for(int i = 0; i < nHidden2; i++)
{
hiddenError2[i] *= (hiddenNeurons2[i]*(1-hiddenNeurons2[i]));
for(int ii = 0; ii <= nHidden1;ii++)
hiddenError1[ii]+=hiddenError2[i]*wHidden2Hidden[ii][i];
for(int ii = 0; ii <= nHidden1;ii++)
wHidden2Hidden[ii][i]+=H2LR*hiddenNeurons1[ii]*hiddenError2[i];
}
for(int i = 0; i < nHidden1; i++)
{
hiddenError1[i] *= (hiddenNeurons1[i]*(1-hiddenNeurons1[i]));
for(int ii = 0; ii <= nInput;ii++)
wInputHidden[ii][i]+=H1LR*inputNeurons[ii]*hiddenError1[i];
}
delete [] hiddenError1;
delete [] hiddenError2;
delete [] outputError;
}