📄 cconditionaldistribution.cpp
字号:
//Tanks
//Copyright John Manslow
//29/09/2001
////////////////////////////////////////////////////
//Remove this include if not compiling under windows
#include "stdafx.h"
#define new DEBUG_NEW
#define false FALSE
////////////////////////////////////////////////////
#include "CConditionalDistribution.h"
#include "stdlib.h"
#include "math.h"
#include "stdio.h"
#include "assert.h"
#include "fstream.h"
#include "time.h"
//Where backups will be made during training (guards against crashes, fires, etc.)
#define FileForBackupSaves "ErrorTrainingBackup.cdm"
CConditionalDistribution::CConditionalDistribution(
const unsigned long ulNewNumberOfInputs,
const unsigned long ulNewNumberOfHiddenNodes,
const unsigned long ulNewNumberOfOutputs
)
{
TRACE("\t\tCreating conditional distribution...");
//Record the structure (number of inputs, hidden neurons, and bins) of the model
ulNumberOfInputs=ulNewNumberOfInputs;
ulNumberOfHiddenNodes=ulNewNumberOfHiddenNodes;
ulNumberOfOutputs=ulNewNumberOfOutputs;
//Allocate memory to store the model's structure
AllocateMemory();
//Reset the learning procedure
Reset();
//Set these character pointers to NULL so we know they're not used yet
pTrainingStartTime=NULL;
pTrainingStartDate=NULL;
TRACE("successful.\n");
}
void CConditionalDistribution::AllocateMemory(void)
{
unsigned long i;
//Allocate memory to store the current values of the input to hidden layer weights
//of the neural network component of the model and their best values
ppdwih=new double*[ulNumberOfHiddenNodes];
ppdBestwih=new double*[ulNumberOfHiddenNodes];
assert(ppdwih && ppdBestwih);
for(i=0;i<ulNumberOfHiddenNodes;i++)
{
ppdwih[i]=new double[ulNumberOfInputs+1];
ppdBestwih[i]=new double[ulNumberOfInputs+1];
assert(ppdwih[i] && ppdBestwih[i]);
}
//Do the same for the hidden to output layer weights
ppdwho=new double*[ulNumberOfOutputs];
ppdBestwho=new double*[ulNumberOfOutputs];
assert(ppdwho && ppdBestwho);
for(i=0;i<ulNumberOfOutputs;i++)
{
ppdwho[i]=new double[ulNumberOfHiddenNodes+1];
ppdBestwho[i]=new double[ulNumberOfHiddenNodes+1];
assert(ppdwho[i] && ppdBestwho[i]);
}
}
void CConditionalDistribution::DeallocateMemory(void)
{
//Deallocate the storage used for current and best weight values.
unsigned long i;
for(i=0;i<ulNumberOfHiddenNodes;i++)
{
delete []ppdwih[i];
delete []ppdBestwih[i];
}
delete []ppdwih;
delete []ppdBestwih;
for(i=0;i<ulNumberOfOutputs;i++)
{
delete []ppdwho[i];
delete []ppdBestwho[i];
}
delete []ppdwho;
delete []ppdBestwho;
//If we've recorded the time and date of the start of training, delete them too.
if(pTrainingStartTime)
{
delete []pTrainingStartTime;
}
if(pTrainingStartDate)
{
delete []pTrainingStartDate;
}
}
CConditionalDistribution::~CConditionalDistribution()
{
TRACE("\t\tDestroying conditional distribution...");
DeallocateMemory();
TRACE("successful.\n");
}
void CConditionalDistribution::Reset(void)
{
unsigned long i,j;
//Give the neural network component of the model weights random values between -1 and +1.
//Since this effectively resets training the best recorded weights (stored in ppdBest...) are set
//to the new random values.
for(i=0;i<ulNumberOfHiddenNodes;i++)
{
for(j=0;j<ulNumberOfInputs+1;j++)
{
ppdwih[i][j]=2.0*(double(rand())/double(RAND_MAX)-0.5);
ppdBestwih[i][j]=ppdwih[i][j];
}
}
//Do the same for the hidden to output layer weights
for(i=0;i<ulNumberOfOutputs;i++)
{
for(j=0;j<ulNumberOfHiddenNodes+1;j++)
{
ppdwho[i][j]=2.0*(double(rand())/double(RAND_MAX)-0.5);
ppdBestwho[i][j]=ppdwho[i][j];
}
}
//Reset the best recorded error to an impossible value (error is always positive) to indicate
//that no training has taken place with the current values of the weights.
dBestError=-1.0;
//Reset the step size to a conservative value.
dStepSize=0.001;
}
//This function trains the conditional distribution model by using a perturbation search (as discussed in the
//book Game Programming Gems 2) to search for weights its neural network component
//that are most consistent with the exemplar data passed to this function
double CConditionalDistribution::dTrainingStep(
const unsigned long ulNumberOfPatternsInTrainingSet,
double ** const ppdTrainingInputs,
double * const ppdTrainingTargets
)
{
unsigned long i,j;
double dNewError;
//If dBestError=-1, this is the first training step so we need to do some initialisation
if(dBestError==-1.0)
{
//Make sure we deallocate memory pointed to by these pointers (if any) before we
//reassign them
if(pTrainingStartTime)
{
delete []pTrainingStartTime;
}
if(pTrainingStartDate)
{
delete []pTrainingStartDate;
}
//Record time and date that training started.
pTrainingStartTime=new char[256];
_strtime(pTrainingStartTime);
pTrainingStartDate=new char[256];
_strdate(pTrainingStartDate);
//Measure the performance of the model with the weights set to their current values.
//Since this is the only performance measurement so far, it must be the best. Store it.
dBestError=dGetPerformance(
ulNumberOfPatternsInTrainingSet,
ppdTrainingInputs,
ppdTrainingTargets
);
}
//Perturb the model's weights by adding a random value between +dStepSize and -StepSize
//to each one.
for(i=0;i<ulNumberOfHiddenNodes;i++)
{
for(j=0;j<ulNumberOfInputs+1;j++)
{
ppdwih[i][j]+=dStepSize*(double(rand())/double(RAND_MAX)-0.5)*2.0;
}
}
//And for the hidden to output layer weights
for(i=0;i<ulNumberOfOutputs;i++)
{
for(j=0;j<ulNumberOfHiddenNodes+1;j++)
{
ppdwho[i][j]+=dStepSize*(double(rand())/double(RAND_MAX)-0.5)*2.0;
}
}
//Measure the performance of the model with its new weights
dNewError=dGetPerformance(
ulNumberOfPatternsInTrainingSet,
ppdTrainingInputs,
ppdTrainingTargets
);
//If its performance has deteriorated (the new error is larger)
if(dNewError>dBestError)
{
//Reduce the size of the perturbation a bit - we need to be more conservative!
dStepSize*=0.9;
//Restore the weights back to their old values
for(i=0;i<ulNumberOfHiddenNodes;i++)
{
for(j=0;j<ulNumberOfInputs+1;j++)
{
ppdwih[i][j]=ppdBestwih[i][j];
}
}
for(i=0;i<ulNumberOfOutputs;i++)
{
for(j=0;j<ulNumberOfHiddenNodes+1;j++)
{
ppdwho[i][j]=ppdBestwho[i][j];
}
}
}
else
{
//Otherwise the new weights performed at least as well as the old ones, so record the
//performance of the model with its new weights,
dBestError=dNewError;
//Increase the step size a little - we're doing well and can afford to be more
//adventurous.
dStepSize*=1.2;
//Record the new weights as the best so far discovered
for(i=0;i<ulNumberOfHiddenNodes;i++)
{
for(j=0;j<ulNumberOfInputs+1;j++)
{
ppdBestwih[i][j]=ppdwih[i][j];
}
}
for(i=0;i<ulNumberOfOutputs;i++)
{
for(j=0;j<ulNumberOfHiddenNodes+1;j++)
{
ppdBestwho[i][j]=ppdwho[i][j];
}
}
//Save the model just in case we have a crash (or power failure or something)
Save(FileForBackupSaves);
}
//Tell the calling function what the performance of the model currently is, so it can
//decide whether to continue training. This function always leaves the model with the
//best weights found so far, so there's no need to restore them externally at the end of
//training
return dBestError;
}
//This function uses the neural network component of the conditional distribution model to calculate
//the probability associated with each bin in the distribution. This is done simply by querying the neural
//network with the distribution inputs because it has one output for each bin
double *CConditionalDistribution::pdGetBinProbabilities(
const double * const pdInputs
)
{
//For detailed comments on querying a neural network, see CMLP.cpp
unsigned long i,j;
//Declare storage for the activities of the hidden and output neurons
double *pdah=new double[ulNumberOfHiddenNodes];
double *pdao=new double[ulNumberOfOutputs];
//Declare storage for the amount of stimulation coming onto a neuron
double dStimulus;
//Calculate the activity of the network's hidden neurons.
for(i=0;i<ulNumberOfHiddenNodes;i++)
{
dStimulus=ppdwih[i][0];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -