GestureRecognitionToolkit  Version: 0.1.0
The Gesture Recognition Toolkit (GRT) is a cross-platform, open-source, c++ machine learning library for real-time gesture recognition.
MLP.cpp
1 /*
2 GRT MIT License
3 Copyright (c) <2012> <Nicholas Gillian, Media Lab, MIT>
4 
5 Permission is hereby granted, free of charge, to any person obtaining a copy of this software
6 and associated documentation files (the "Software"), to deal in the Software without restriction,
7 including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
9 subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in all copies or substantial
12 portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
15 LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
18 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 */
20 
21 #include "MLP.h"
22 
23 GRT_BEGIN_NAMESPACE
24 
25 const Float MLP_NEURON_MIN_TARGET = -1.0;
26 const Float MLP_NEURON_MAX_TARGET = 1.0;
27 
28 //Register the MLP module with the Regressifier base class
29 RegisterRegressifierModule< MLP > MLP::registerModule("MLP");
30 
32  inputLayerActivationFunction = Neuron::LINEAR;
33  hiddenLayerActivationFunction = Neuron::LINEAR;
34  outputLayerActivationFunction = Neuron::LINEAR;
35  minNumEpochs = 10;
36  numRandomTrainingIterations = 10;
37  validationSetSize = 20; //20% of the training data will be set aside for the validation set
38  trainingMode = ONLINE_GRADIENT_DESCENT;
39  momentum = 0.5;
40  gamma = 2.0;
41  trainingError = 0;
42  nullRejectionCoeff = 0.9;
43  nullRejectionThreshold = 0;
44  useValidationSet = true;
45  randomiseTrainingOrder = false;
46  useScaling = true;
47  trained = false;
48  initialized = false;
49  classificationModeActive = false;
50  useNullRejection = true;
51  clear();
52  classType = "MLP";
53  regressifierType = classType;
54  debugLog.setProceedingText("[DEBUG MLP]");
55  errorLog.setProceedingText("[ERROR MLP]");
56  trainingLog.setProceedingText("[TRAINING MLP]");
57  warningLog.setProceedingText("[WARNING MLP]");
58 }
59 
60 MLP::MLP(const MLP &rhs){
61  classType = "MLP";
62  regressifierType = classType;
63  debugLog.setProceedingText("[DEBUG MLP]");
64  errorLog.setProceedingText("[ERROR MLP]");
65  trainingLog.setProceedingText("[TRAINING MLP]");
66  warningLog.setProceedingText("[WARNING MLP]");
67 
68  *this = rhs;
69 }
70 
72  clear();
73 }
74 
75 MLP& MLP::operator=(const MLP &rhs){
76  if( this != &rhs ){
77  //MLP variables
78  this->numInputNeurons = rhs.numInputNeurons;
79  this->numHiddenNeurons = rhs.numHiddenNeurons;
80  this->numOutputNeurons = rhs.numOutputNeurons;
81  this->inputLayerActivationFunction = rhs.inputLayerActivationFunction;
82  this->hiddenLayerActivationFunction = rhs.hiddenLayerActivationFunction;
83  this->outputLayerActivationFunction = rhs.outputLayerActivationFunction;
84  this->numRandomTrainingIterations = rhs.numRandomTrainingIterations;
85  this->trainingMode = rhs.trainingMode;
86  this->momentum = rhs.momentum;
87  this->trainingError = rhs.trainingError;
88  this->gamma = rhs.gamma;
89  this->initialized = rhs.initialized;
90  this->inputLayer = rhs.inputLayer;
91  this->hiddenLayer = rhs.hiddenLayer;
92  this->outputLayer = rhs.outputLayer;
93  this->inputVectorRanges = rhs.inputVectorRanges;
94  this->targetVectorRanges = rhs.targetVectorRanges;
95  this->trainingErrorLog = rhs.trainingErrorLog;
96 
97  this->classificationModeActive = rhs.classificationModeActive;
98  this->useNullRejection = rhs.useNullRejection;
99  this->predictedClassLabel = rhs.predictedClassLabel;
100  this->nullRejectionCoeff = rhs.nullRejectionCoeff;
101  this->nullRejectionThreshold = rhs.nullRejectionThreshold;
102  this->maxLikelihood = rhs.maxLikelihood;
103  this->classLikelihoods = rhs.classLikelihoods;
104 
105  //Copy the base variables
107  }
108  return *this;
109 }
110 
111 bool MLP::deepCopyFrom(const Regressifier *regressifier){
112 
113  if( regressifier == NULL ){
114  errorLog << "deepCopyFrom(const Regressifier *regressifier) - regressifier is NULL!" << std::endl;
115  return false;
116  }
117 
118  if( this->getRegressifierType() != regressifier->getRegressifierType() ){
119  errorLog << "deepCopyFrom(const Regressifier *regressifier) - regressifier is not the correct type!" << std::endl;
120  return false;
121  }
122 
123  *this = *dynamic_cast<const MLP*>(regressifier);
124 
125  return true;
126 }
127 
128 //Classifier interface
129 bool MLP::train_(ClassificationData &trainingData){
130 
131  if( !initialized ){
132  errorLog << "train_(ClassificationData trainingData) - The MLP has not been initialized!" << std::endl;
133  return false;
134  }
135 
136  if( trainingData.getNumDimensions() != numInputNeurons ){
137  errorLog << "train_(ClassificationData trainingData) - The number of input dimensions in the training data (" << trainingData.getNumDimensions() << ") does not match that of the MLP (" << numInputNeurons << ")" << std::endl;
138  return false;
139  }
140  if( trainingData.getNumClasses() != numOutputNeurons ){
141  errorLog << "train_(ClassificationData trainingData) - The number of classes in the training data (" << trainingData.getNumClasses() << ") does not match that of the MLP (" << numOutputNeurons << ")" << std::endl;
142  return false;
143  }
144 
145  //Reformat the LabelledClassificationData as LabelledRegressionData
146  RegressionData regressionData = trainingData.reformatAsRegressionData();
147 
148  //Flag that the MLP is being used for classification, not regression
149  classificationModeActive = true;
150 
151  return trainModel(regressionData);
152 }
153 
154 bool MLP::train_(RegressionData &trainingData){
155 
156  //Flag that the MLP is being used for regression, not classification
157  classificationModeActive = false;
158 
159  return trainModel(trainingData);
160 }
161 
162 //Classifier interface
163 bool MLP::predict_(VectorFloat &inputVector){
164 
165  if( !trained ){
166  errorLog << "predict_(VectorFloat &inputVector) - Model not trained!" << std::endl;
167  return false;
168  }
169 
170  if( inputVector.size() != numInputNeurons ){
171  errorLog << "predict_(VectorFloat &inputVector) - The sie of the input Vector (" << int(inputVector.size()) << ") does not match that of the number of input dimensions (" << numInputNeurons << ") " << std::endl;
172  return false;
173  }
174 
175  //Set the mapped data as the classLikelihoods
176  regressionData = feedforward( inputVector );
177 
178  if( classificationModeActive ){
179 
180  //Estimate the class likelihoods
181  const UINT K = (UINT)regressionData.size();
182  classLikelihoods = regressionData;
183 
184  //Make sure all the values are greater than zero, we do this by finding the min value and adding this onto all the values
185  Float minValue = Util::getMin( classLikelihoods );
186  for(UINT i=0; i<K; i++){
187  classLikelihoods[i] += minValue;
188  }
189 
190  //Normalize the likelihoods so they sum to 1
191  Float sum = Util::sum(classLikelihoods);
192  if( sum > 0 ){
193  for(UINT i=0; i<K; i++){
194  classLikelihoods[i] /= sum;
195  }
196  }
197 
198  //Find the best value
199  Float bestValue = classLikelihoods[0];
200  UINT bestIndex = 0;
201  for(UINT i=1; i<K; i++){
202  if( classLikelihoods[i] > bestValue ){
203  bestValue = classLikelihoods[i];
204  bestIndex = i;
205  }
206  }
207 
208  //Set the maximum likelihood and predicted class label
209  maxLikelihood = bestValue;
210  predictedClassLabel = bestIndex+1;
211 
212  if( useNullRejection ){
213  if( maxLikelihood < nullRejectionCoeff ){
214  predictedClassLabel = 0;
215  }
216  }
217  }
218 
219  return true;
220 }
221 
222 bool MLP::init(const UINT numInputNeurons, const UINT numHiddenNeurons, const UINT numOutputNeurons){
223  return init(numInputNeurons, numHiddenNeurons, numOutputNeurons, inputLayerActivationFunction, hiddenLayerActivationFunction, outputLayerActivationFunction );
224 }
225 
226 bool MLP::init(const UINT numInputNeurons,
227  const UINT numHiddenNeurons,
228  const UINT numOutputNeurons,
229  const UINT inputLayerActivationFunction,
230  const UINT hiddenLayerActivationFunction,
231  const UINT outputLayerActivationFunction){
232 
233  //Clear any previous models
234  clear();
235 
236  //Initialize the random seed
237  random.setSeed( (UINT)time(NULL) );
238 
239  if( numInputNeurons == 0 || numHiddenNeurons == 0 || numOutputNeurons == 0 ){
240  if( numInputNeurons == 0 ){ errorLog << "init(...) - The number of input neurons is zero!" << std::endl; }
241  if( numHiddenNeurons == 0 ){ errorLog << "init(...) - The number of hidden neurons is zero!" << std::endl; }
242  if( numOutputNeurons == 0 ){ errorLog << "init(...) - The number of output neurons is zero!" << std::endl; }
243  return false;
244  }
245 
246  //Validate the activation functions
247  if( !validateActivationFunction(inputLayerActivationFunction) || !validateActivationFunction(hiddenLayerActivationFunction) || !validateActivationFunction(outputLayerActivationFunction) ){
248  errorLog << "init(...) - One Of The Activation Functions Failed The Validation Check" << std::endl;
249  return false;
250  }
251 
252  //Set the size of the MLP
253  this->numInputNeurons = numInputNeurons;
254  this->numHiddenNeurons = numHiddenNeurons;
255  this->numOutputNeurons = numOutputNeurons;
256 
257  //Set the regression IO
258  this->numInputDimensions = numInputNeurons;
259  this->numOutputDimensions = numOutputNeurons;
260 
261  //Set the validation layers
262  this->inputLayerActivationFunction = inputLayerActivationFunction;
263  this->hiddenLayerActivationFunction = hiddenLayerActivationFunction;
264  this->outputLayerActivationFunction = outputLayerActivationFunction;
265 
266  //Setup the neurons for each of the layers
267  inputLayer.resize(numInputNeurons);
268  hiddenLayer.resize(numHiddenNeurons);
269  outputLayer.resize(numOutputNeurons);
270 
271  //Init the neuron memory for each of the layers
272  for(UINT i=0; i<numInputNeurons; i++){
273  inputLayer[i].init(1,inputLayerActivationFunction); //The input size for each input neuron will always be 1
274  inputLayer[i].weights[0] = 1.0; //The weights for the input layer should always be 1
275  inputLayer[i].bias = 0.0; //The bias for the input layer should always be 0
276  inputLayer[i].gamma = gamma;
277  }
278 
279  for(UINT i=0; i<numHiddenNeurons; i++){
280  //The number of inputs to a neuron in the output layer will always match the number of input neurons
281  hiddenLayer[i].init(numInputNeurons,hiddenLayerActivationFunction);
282  hiddenLayer[i].gamma = gamma;
283  }
284 
285  for(UINT i=0; i<numOutputNeurons; i++){
286  //The number of inputs to a neuron in the output layer will always match the number of hidden neurons
287  outputLayer[i].init(numHiddenNeurons,outputLayerActivationFunction);
288  outputLayer[i].gamma = gamma;
289  }
290 
291  initialized = true;
292 
293  return true;
294 }
295 
296 bool MLP::clear(){
297 
298  //Clear the base class
300 
301  numInputNeurons = 0;
302  numHiddenNeurons = 0;
303  numOutputNeurons = 0;
304  inputLayer.clear();
305  hiddenLayer.clear();
306  outputLayer.clear();
307  initialized = false;
308 
309  return true;
310 }
311 
312 bool MLP::print() const{
313  printNetwork();
314  return true;
315 }
316 
317 bool MLP::trainModel(RegressionData &trainingData){
318 
319  trained = false;
320 
321  if( !initialized ){
322  errorLog << "train(RegressionData trainingData) - The MLP has not be initialized!" << std::endl;
323  return false;
324  }
325 
326  if( trainingData.getNumSamples() == 0 ){
327  errorLog << "train(RegressionData trainingData) - The training data is empty!" << std::endl;
328  return false;
329  }
330 
331  //Create a validation dataset, if needed
332  RegressionData validationData;
333  if( useValidationSet ){
334  validationData = trainingData.partition( 100 - validationSetSize );
335  }
336 
337  const UINT N = trainingData.getNumInputDimensions();
338  const UINT T = trainingData.getNumTargetDimensions();
339 
340  if( N != numInputNeurons ){
341  errorLog << "train(LabelledRegressionData trainingData) - The number of input dimensions in the training data (" << N << ") does not match that of the MLP (" << numInputNeurons << ")" << std::endl;
342  return false;
343  }
344  if( T != numOutputNeurons ){
345  errorLog << "train(LabelledRegressionData trainingData) - The number of target dimensions in the training data (" << T << ") does not match that of the MLP (" << numOutputNeurons << ")" << std::endl;
346  return false;
347  }
348 
349  //Set the Regressifier input and output dimensions
350  numInputDimensions = numInputNeurons;
351  numOutputDimensions = numOutputNeurons;
352 
353  //Scale the training and validation data, if needed
354  if( useScaling ){
355  //Find the ranges for the input data
356  inputVectorRanges = trainingData.getInputRanges();
357 
358  //Find the ranges for the target data
359  targetVectorRanges = trainingData.getTargetRanges();
360 
361  //Now scale the training data and the validation data if required
362  trainingData.scale(inputVectorRanges,targetVectorRanges,MLP_NEURON_MIN_TARGET,MLP_NEURON_MAX_TARGET);
363 
364  if( useValidationSet ){
365  validationData.scale(inputVectorRanges,targetVectorRanges,MLP_NEURON_MIN_TARGET,MLP_NEURON_MAX_TARGET);
366  }
367  }
368  //If scaling is enabled then the training and validation data will be scaled - so turn it off so the we do not need to scale the data again
369  //The actual scaling state will be reset at the end of traiing
370  bool tempScalingState = useScaling;
371  useScaling = false;
372 
373  //Setup the memory
374  trainingErrorLog.clear();
375  inputNeuronsOuput.resize(numInputNeurons);
376  hiddenNeuronsOutput.resize(numHiddenNeurons);
377  outputNeuronsOutput.resize(numOutputNeurons);
378  deltaO.resize(numOutputNeurons);
379  deltaH.resize(numHiddenNeurons);
380 
381  //Call the main training function
382  switch( trainingMode ){
383  case ONLINE_GRADIENT_DESCENT:
384  if( classificationModeActive ){
385  trained = trainOnlineGradientDescentClassification( trainingData, validationData );
386  }else{
387  trained = trainOnlineGradientDescentRegression( trainingData, validationData );
388  }
389  break;
390  default:
391  useScaling = tempScalingState;
392  errorLog << "train(RegressionData trainingData) - Uknown training mode!" << std::endl;
393  return false;
394  break;
395  }
396 
397  //Reset the scaling state so the prediction data will be scaled if needed
398  useScaling = tempScalingState;
399 
400  return true;
401 }
402 
403 bool MLP::trainOnlineGradientDescentClassification(const RegressionData &trainingData,const RegressionData &validationData){
404 
405  const UINT M = trainingData.getNumSamples();
406  const UINT T = trainingData.getNumTargetDimensions();
407  const UINT numTestingExamples = useValidationSet ? validationData.getNumSamples() : M;
408 
409  //Setup the training loop
410  MLP bestNetwork;
411  totalSquaredTrainingError = 0;
412  rootMeanSquaredTrainingError = 0;
413  trainingError = 0;
414  bool keepTraining = true;
415  UINT epoch = 0;
416  UINT bestIter = 0;
417  UINT bestIndex = 0;
418  UINT classLabel = 0;
419  Float alpha = learningRate;
420  Float beta = momentum;
421  Float error = 0;
422  Float lastError = 0;
423  Float accuracy = 0;
424  Float trainingSetAccuracy = 0;
425  Float trainingSetTotalSquaredError = 0;
426  Float bestError = grt_numeric_limits< Float >::max();
427  Float bestTSError = grt_numeric_limits< Float >::max();
428  Float bestRMSError = grt_numeric_limits< Float >::max();
429  Float bestAccuracy = 0;
430  Float delta = 0;
431  Float backPropError = 0;
432  Float bestValue = 0;
433  VectorFloat y;
434  Vector< UINT > indexList(M);
435  Vector< VectorFloat > tempTrainingErrorLog;
436  TrainingResult result;
437  trainingResults.reserve(M);
438 
439  //Reset the indexList, this is used to randomize the order of the training examples, if needed
440  for(UINT i=0; i<M; i++) indexList[i] = i;
441 
442  for(UINT iter=0; iter<numRandomTrainingIterations; iter++){
443 
444  epoch = 0;
445  keepTraining = true;
446  tempTrainingErrorLog.clear();
447 
448  //Randomise the start values of the neurons
449  init(numInputNeurons,numHiddenNeurons,numOutputNeurons,inputLayerActivationFunction,hiddenLayerActivationFunction,outputLayerActivationFunction);
450 
451  if( randomiseTrainingOrder ){
452  for(UINT i=0; i<M; i++){
453  SWAP(indexList[ i ], indexList[ random.getRandomNumberInt(0, M) ]);
454  }
455  }
456 
457  while( keepTraining ){
458 
459  //Perform one training epoch
460  accuracy = 0;
461  totalSquaredTrainingError = 0;
462 
463  for(UINT i=0; i<M; i++){
464  //Get the i'th training and target Vectors
465  const VectorFloat &trainingExample = trainingData[ indexList[i] ].getInputVector();
466  const VectorFloat &targetVector = trainingData[ indexList[i] ].getTargetVector();
467 
468  //Perform the back propagation
469  backPropError = back_prop(trainingExample,targetVector,alpha,beta);
470 
471  //debugLog << "i: " << i << " backPropError: " << backPropError << std::endl;
472 
473  if( isNAN(backPropError) ){
474  keepTraining = false;
475  errorLog << "train(RegressionData trainingData) - NaN found!" << std::endl;
476  return false;
477  }
478 
479  //Compute the error for the i'th example
480  if( classificationModeActive ){
481  y = feedforward( trainingExample );
482 
483  //Get the class label
484  bestValue = targetVector[0];
485  bestIndex = 0;
486  for(UINT i=1; i<targetVector.size(); i++){
487  if( targetVector[i] > bestValue ){
488  bestValue = targetVector[i];
489  bestIndex = i;
490  }
491  }
492  classLabel = bestIndex + 1;
493 
494  //Get the predicted class label
495  bestValue = y[0];
496  bestIndex = 0;
497  for(UINT i=1; i<numOutputNeurons; i++){
498  if( y[i] > bestValue ){
499  bestValue = y[i];
500  bestIndex = i;
501  }
502  }
503  predictedClassLabel = bestIndex+1;
504 
505  if( classLabel == predictedClassLabel ){
506  accuracy++;
507  }
508 
509  }else{
510  totalSquaredTrainingError += backPropError; //The backPropError is already squared
511  }
512  }
513 
514  if( checkForNAN() ){
515  keepTraining = false;
516  errorLog << "train(RegressionData trainingData) - NaN found!" << std::endl;
517  break;
518  }
519 
520  //Compute the error over all the training/validation examples
521  if( useValidationSet ){
522  trainingSetAccuracy = accuracy;
523  trainingSetTotalSquaredError = totalSquaredTrainingError;
524  accuracy = 0;
525  totalSquaredTrainingError = 0;
526 
527  //Iterate over the validation samples
528  UINT numValidationSamples = validationData.getNumSamples();
529  for(UINT i=0; i<numValidationSamples; i++){
530  const VectorFloat &inputVector = validationData[i].getInputVector();
531  const VectorFloat &targetVector = validationData[i].getTargetVector();
532 
533  y = feedforward( inputVector );
534 
535  if( classificationModeActive ){
536  //Get the class label
537  bestValue = targetVector[0];
538  bestIndex = 0;
539  for(UINT i=1; i<numInputNeurons; i++){
540  if( targetVector[i] > bestValue ){
541  bestValue = targetVector[i];
542  bestIndex = i;
543  }
544  }
545  classLabel = bestIndex + 1;
546 
547  //Get the predicted class label
548  bestValue = y[0];
549  bestIndex = 0;
550  for(UINT i=1; i<numOutputNeurons; i++){
551  if( y[i] > bestValue ){
552  bestValue = y[i];
553  bestIndex = i;
554  }
555  }
556  predictedClassLabel = bestIndex+1;
557 
558  if( classLabel == predictedClassLabel ){
559  accuracy++;
560  }
561 
562  }else{
563  //Update the total squared error
564  for(UINT j=0; j<T; j++){
565  totalSquaredTrainingError += SQR( targetVector[j]-y[j] );
566  }
567  }
568  }
569 
570  accuracy = (accuracy/Float(numValidationSamples))*Float(numValidationSamples);
571  rootMeanSquaredTrainingError = sqrt( totalSquaredTrainingError / Float(numValidationSamples) );
572 
573  }else{//We are not using a validation set
574  accuracy = (accuracy/Float(M))*Float(M);
575  rootMeanSquaredTrainingError = sqrt( totalSquaredTrainingError / Float(M) );
576  }
577 
578  //Store the errors
579  VectorFloat temp(2);
580  temp[0] = 100.0 - trainingSetAccuracy;
581  temp[1] = 100.0 - accuracy;
582  tempTrainingErrorLog.push_back( temp );
583 
584  error = 100.0 - accuracy;
585 
586  //Store the training results
587  result.setClassificationResult(iter,accuracy,this);
588  trainingResults.push_back( result );
589 
590  delta = fabs( error - lastError );
591 
592  trainingLog << "Random Training Iteration: " << iter+1 << " Epoch: " << epoch << " Error: " << error << " Delta: " << delta << std::endl;
593 
594  //Check to see if we should stop training
595  if( ++epoch >= maxNumEpochs ){
596  keepTraining = false;
597  }
598  if( delta <= minChange && epoch >= minNumEpochs ){
599  keepTraining = false;
600  }
601 
602  //Update the last error
603  lastError = error;
604 
605  //Notify any observers of the new training result
606  trainingResultsObserverManager.notifyObservers( result );
607 
608  }//End of While( keepTraining )
609 
610  if( lastError < bestError ){
611  bestIter = iter;
612  bestError = lastError;
613  bestTSError = totalSquaredTrainingError;
614  bestRMSError = rootMeanSquaredTrainingError;
615  bestAccuracy = accuracy;
616  bestNetwork = *this;
617  trainingErrorLog = tempTrainingErrorLog;
618  }
619 
620  }//End of For( numRandomTrainingIterations )
621 
622  trainingLog << "Best Accuracy: " << bestAccuracy << " in Random Training Iteration: " << bestIter+1 << std::endl;
623 
624  //Check to make sure the best network has not got any NaNs in it
625  if( checkForNAN() ){
626  errorLog << "train(LabelledRegressionData trainingData) - NAN Found!" << std::endl;
627  return false;
628  }
629 
630  //Set the MLP model to the model that best during training
631  *this = bestNetwork;
632  trainingError = bestAccuracy;
633 
634  //Compute the rejection threshold
635  if( useNullRejection ){
636 
637  Float averageValue = 0;
638  VectorFloat classificationPredictions, inputVector, targetVector;
639 
640  for(UINT i=0; i<numTestingExamples; i++){
641  inputVector = useValidationSet ? validationData[i].getInputVector() : trainingData[i].getInputVector();
642  targetVector = useValidationSet ? validationData[i].getTargetVector() : trainingData[i].getTargetVector();
643 
644  //Make the prediction
645  y = feedforward( inputVector );
646 
647  //Get the class label
648  bestValue = targetVector[0];
649  bestIndex = 0;
650  for(UINT i=1; i<targetVector.size(); i++){
651  if( targetVector[i] > bestValue ){
652  bestValue = targetVector[i];
653  bestIndex = i;
654  }
655  }
656  classLabel = bestIndex + 1;
657 
658  //Get the predicted class label
659  bestValue = y[0];
660  bestIndex = 0;
661  for(UINT i=1; i<y.size(); i++){
662  if( y[i] > bestValue ){
663  bestValue = y[i];
664  bestIndex = i;
665  }
666  }
667  predictedClassLabel = bestIndex+1;
668 
669  //Only add the max value if the prediction is correct
670  if( classLabel == predictedClassLabel ){
671  classificationPredictions.push_back( bestValue );
672  averageValue += bestValue;
673  }
674  }
675 
676  averageValue /= Float(classificationPredictions.size());
677  Float stdDev = 0;
678  for(UINT i=0; i<classificationPredictions.size(); i++){
679  stdDev += SQR(classificationPredictions[i]-averageValue);
680  }
681  stdDev = sqrt( stdDev / Float(classificationPredictions.size()-1) );
682 
683  nullRejectionThreshold = averageValue-(stdDev*nullRejectionCoeff);
684  }
685 
686  //Return true to flag that the model was trained OK
687  return true;
688 }
689 
690 bool MLP::trainOnlineGradientDescentRegression(const RegressionData &trainingData,const RegressionData &validationData){
691 
692  const UINT M = trainingData.getNumSamples();
693  const UINT T = trainingData.getNumTargetDimensions();
694  const UINT numValidationSamples = useValidationSet ? validationData.getNumSamples() : M;
695 
696  //Setup the training loop
697  bool keepTraining = true;
698  UINT epoch = 0;
699  Float alpha = learningRate;
700  Float beta = momentum;
701  UINT bestIter = 0;
702  MLP bestNetwork;
703  totalSquaredTrainingError = 0;
704  rootMeanSquaredTrainingError = 0;
705  trainingError = 0;
706  Float error = 0;
707  Float lastError = 0;
708  Float trainingSetTotalSquaredError = 0;
709  Float bestError = grt_numeric_limits< Float >::max();
710  Float bestTSError = grt_numeric_limits< Float >::max();
711  Float bestRMSError = grt_numeric_limits< Float >::max();
712  Float delta = 0;
713  Vector< UINT > indexList(M);
714  Vector< VectorFloat > tempTrainingErrorLog;
715  TrainingResult result;
716  trainingResults.reserve(M);
717 
718  //Reset the indexList, this is used to randomize the order of the training examples, if needed
719  for(UINT i=0; i<M; i++) indexList[i] = i;
720 
721  for(UINT iter=0; iter<numRandomTrainingIterations; iter++){
722 
723  epoch = 0;
724  keepTraining = true;
725  tempTrainingErrorLog.clear();
726 
727  //Randomise the start values of the neurons
728  init(numInputNeurons,numHiddenNeurons,numOutputNeurons,inputLayerActivationFunction,hiddenLayerActivationFunction,outputLayerActivationFunction);
729 
730  if( randomiseTrainingOrder ){
731  for(UINT i=0; i<M; i++){
732  SWAP(indexList[ i ], indexList[ random.getRandomNumberInt(0, M) ]);
733  }
734  }
735 
736  while( keepTraining ){
737 
738  //Perform one training epoch
739  totalSquaredTrainingError = 0;
740 
741  for(UINT i=0; i<M; i++){
742  //Get the i'th training and target Vectors
743  const VectorFloat &trainingExample = trainingData[ indexList[i] ].getInputVector();
744  const VectorFloat &targetVector = trainingData[ indexList[i] ].getTargetVector();
745 
746  //Perform the back propagation
747  Float backPropError = back_prop(trainingExample,targetVector,alpha,beta);
748 
749  //debugLog << "i: " << i << " backPropError: " << backPropError << std::endl;
750 
751  if( isNAN(backPropError) ){
752  keepTraining = false;
753  errorLog << "train(RegressionData trainingData) - NaN found!" << std::endl;
754  }
755 
756  //Compute the error for the i'th example
757  totalSquaredTrainingError += backPropError; //The backPropError is already squared
758  }
759 
760  if( checkForNAN() ){
761  keepTraining = false;
762  errorLog << "train(RegressionData trainingData) - NaN found!" << std::endl;
763  break;
764  }
765 
766  //Compute the error over all the training/validation examples
767  if( useValidationSet ){
768  trainingSetTotalSquaredError = totalSquaredTrainingError;
769  totalSquaredTrainingError = 0;
770 
771  //Iterate over the validation samples
772  for(UINT i=0; i<numValidationSamples; i++){
773  const VectorFloat &trainingExample = validationData[i].getInputVector();
774  const VectorFloat &targetVector = validationData[i].getTargetVector();
775 
776  VectorFloat y = feedforward(trainingExample);
777 
778  //Update the total squared error
779  for(UINT j=0; j<T; j++){
780  totalSquaredTrainingError += SQR( targetVector[j]-y[j] );
781  }
782 
783  }
784 
785  rootMeanSquaredTrainingError = sqrt( totalSquaredTrainingError / Float(numValidationSamples) );
786 
787  }else{//We are not using a validation set
788  rootMeanSquaredTrainingError = sqrt( totalSquaredTrainingError / Float(M) );
789  }
790 
791  //Store the errors
792  VectorFloat temp(2);
793  temp[0] = trainingSetTotalSquaredError;
794  temp[1] = rootMeanSquaredTrainingError;
795  tempTrainingErrorLog.push_back( temp );
796 
797  error = rootMeanSquaredTrainingError;
798 
799  //Store the training results
800  result.setRegressionResult(iter,totalSquaredTrainingError,rootMeanSquaredTrainingError,this);
801  trainingResults.push_back( result );
802 
803  delta = fabs( error - lastError );
804 
805  trainingLog << "Random Training Iteration: " << iter+1 << " Epoch: " << epoch << " Error: " << error << " Delta: " << delta << std::endl;
806 
807  //Check to see if we should stop training
808  if( ++epoch >= maxNumEpochs ){
809  keepTraining = false;
810  }
811  if( delta <= minChange && epoch >= minNumEpochs ){
812  keepTraining = false;
813  }
814 
815  //Update the last error
816  lastError = error;
817 
818  //Notify any observers of the new training result
819  trainingResultsObserverManager.notifyObservers( result );
820 
821  }//End of While( keepTraining )
822 
823  //Check to see if this is the best model so far
824  if( lastError < bestError ){
825  bestIter = iter;
826  bestError = lastError;
827  bestTSError = totalSquaredTrainingError;
828  bestRMSError = rootMeanSquaredTrainingError;
829  bestNetwork = *this;
830  trainingErrorLog = tempTrainingErrorLog;
831  }
832 
833  }//End of For( numRandomTrainingIterations )
834 
835  trainingLog << "Best RMSError: " << bestRMSError << " in Random Training Iteration: " << bestIter+1 << std::endl;
836 
837  //Check to make sure the best network has not got any NaNs in it
838  if( checkForNAN() ){
839  errorLog << "train(RegressionData trainingData) - NAN Found!" << std::endl;
840  return false;
841  }
842 
843  //Set the MLP model to the model that best during training
844  *this = bestNetwork;
845  trainingError = bestRMSError;
846 
847  //Return true to flag that the model was trained OK
848  return true;
849 }
850 
851 Float MLP::back_prop(const VectorFloat &trainingExample,const VectorFloat &targetVector,const Float alpha,const Float beta){
852 
853  Float update = 0;
854  Float sum = 0;
855  Float omBeta = 1.0 - beta;
856 
857  //Forward propagation
858  feedforward(trainingExample,inputNeuronsOuput,hiddenNeuronsOutput,outputNeuronsOutput);
859 
860  //Compute the error of the output layer: the derivative of the function times the error of the output
861  for(UINT i=0; i<numOutputNeurons; i++){
862  deltaO[i] = outputLayer[i].getDerivative( outputNeuronsOutput[i] ) * (targetVector[i]-outputNeuronsOutput[i]);
863  }
864 
865  //Compute the error of the hidden layer
866  for(UINT i=0; i<numHiddenNeurons; i++){
867  sum = 0;
868  for(UINT j=0; j<numOutputNeurons; j++){
869  sum += outputLayer[j].weights[i] * deltaO[j];
870  }
871  deltaH[i] = hiddenLayer[i].getDerivative( hiddenNeuronsOutput[i] ) * sum;
872  }
873 
874  //Update the hidden weights: old hidden weights + (learningRate * inputToTheHiddenNeuron * deltaHidden )
875  for(UINT i=0; i<numHiddenNeurons; i++){
876  for(UINT j=0; j<numInputNeurons; j++){
877  //Compute the update
878  //update = alpha * ((beta * hiddenLayer[i].previousUpdate[j]) + (omBeta * inputNeuronsOuput[j])) * deltaH[i];
879  update = alpha * inputNeuronsOuput[j] * deltaH[i];
880 
881  //Update the weights
882  hiddenLayer[i].weights[j] += update;
883 
884  //Store the previous update
885  hiddenLayer[i].previousUpdate[j] = update;
886  }
887  }
888 
889  //Update the output weights
890  for(UINT i=0; i<numOutputNeurons; i++){
891  for(UINT j=0; j<numHiddenNeurons; j++){
892  //Compute the update
893  //update = alpha * ((beta * outputLayer[i].previousUpdate[j]) + (omBeta * hiddenNeuronsOutput[j])) * deltaO[i];
894  update = alpha * hiddenNeuronsOutput[j] * deltaO[i];
895 
896  //Update the weights
897  outputLayer[i].weights[j] += update;
898 
899  //Store the update
900  outputLayer[i].previousUpdate[j] = update;
901  }
902  }
903 
904  //Update the hidden bias
905  for(UINT i=0; i<numHiddenNeurons; i++){
906  //Compute the update
907  //update = alpha * ((beta * hiddenLayer[i].previousBiasUpdate) + (omBeta * deltaH[i]));
908  update = alpha * deltaH[i];
909 
910  //Update the bias
911  hiddenLayer[i].bias += update;
912 
913  //Store the update
914  hiddenLayer[i].previousBiasUpdate = update;
915  }
916 
917  //Update the output bias
918  for(UINT i=0; i<numOutputNeurons; i++){
919  //Compute the update
920  //update = alpha * (beta * outputLayer[i].previousBiasUpdate) + (omBeta * deltaO[i]);
921  update = alpha * deltaO[i];
922 
923  //Update the bias
924  outputLayer[i].bias += update;
925 
926  //Store the update
927  outputLayer[i].previousBiasUpdate = update;
928  }
929 
930  //Compute the squared error between the output of the network and the target Vector
931  Float error = 0;
932  for(UINT i=0; i<numOutputNeurons; i++){
933  error += SQR( targetVector[i] - outputNeuronsOutput[i] );
934  }
935 
936  return error;
937 }
938 
940 
941  if( inputNeuronsOuput.size() != numInputNeurons ) inputNeuronsOuput.resize(numInputNeurons,0);
942  if( hiddenNeuronsOutput.size() != numHiddenNeurons ) hiddenNeuronsOutput.resize(numHiddenNeurons,0);
943  if( outputNeuronsOutput.size() != numOutputNeurons ) outputNeuronsOutput.resize(numOutputNeurons,0);
944 
945  //Scale the input Vector if required
946  if( useScaling ){
947  for(UINT i=0; i<numInputNeurons; i++){
948  trainingExample[i] = scale(trainingExample[i],inputVectorRanges[i].minValue,inputVectorRanges[i].maxValue,MLP_NEURON_MIN_TARGET,MLP_NEURON_MAX_TARGET);
949  }
950  }
951 
952  //Input layer
953  VectorFloat input(1);
954  for(UINT i=0; i<numInputNeurons; i++){
955  input[0] = trainingExample[i];
956  inputNeuronsOuput[i] = inputLayer[i].fire( input );
957  }
958 
959  //Hidden Layer
960  for(UINT i=0; i<numHiddenNeurons; i++){
961  hiddenNeuronsOutput[i] = hiddenLayer[i].fire( inputNeuronsOuput );
962  }
963 
964  //Output Layer
965  for(UINT i=0; i<numOutputNeurons; i++){
966  outputNeuronsOutput[i] = outputLayer[i].fire( hiddenNeuronsOutput );
967  }
968 
969  //Scale the output Vector if required
970  if( useScaling ){
971  for(UINT i=0; i<numOutputNeurons; i++){
972  outputNeuronsOutput[i] = scale(outputNeuronsOutput[i],MLP_NEURON_MIN_TARGET,MLP_NEURON_MAX_TARGET,targetVectorRanges[i].minValue,targetVectorRanges[i].maxValue);
973  }
974  }
975 
976  return outputNeuronsOutput;
977 
978 }
979 
980 void MLP::feedforward(const VectorFloat &data,VectorFloat &inputNeuronsOuput,VectorFloat &hiddenNeuronsOutput,VectorFloat &outputNeuronsOutput){
981 
982  if( inputNeuronsOuput.size() != numInputNeurons ) inputNeuronsOuput.resize(numInputNeurons,0);
983  if( hiddenNeuronsOutput.size() != numHiddenNeurons ) hiddenNeuronsOutput.resize(numHiddenNeurons,0);
984  if( outputNeuronsOutput.size() != numOutputNeurons ) outputNeuronsOutput.resize(numOutputNeurons,0);
985 
986  //Input layer
987  VectorFloat input(1);
988  for(UINT i=0; i<numInputNeurons; i++){
989  input[0] = data[i];
990  inputNeuronsOuput[i] = inputLayer[i].fire( input );
991  }
992 
993  //Hidden Layer
994  for(UINT i=0; i<numHiddenNeurons; i++){
995  hiddenNeuronsOutput[i] = hiddenLayer[i].fire( inputNeuronsOuput );
996  }
997 
998  //Output Layer
999  for(UINT i=0; i<numOutputNeurons; i++){
1000  outputNeuronsOutput[i] = outputLayer[i].fire( hiddenNeuronsOutput );
1001  }
1002 
1003 }
1004 
1005 void MLP::printNetwork() const{
1006  std::cout<<"***************** MLP *****************\n";
1007  std::cout<<"NumInputNeurons: "<<numInputNeurons<< std::endl;
1008  std::cout<<"NumHiddenNeurons: "<<numHiddenNeurons<< std::endl;
1009  std::cout<<"NumOutputNeurons: "<<numOutputNeurons<< std::endl;
1010 
1011  std::cout<<"InputWeights:\n";
1012  for(UINT i=0; i<numInputNeurons; i++){
1013  std::cout<<"Neuron: "<<i<<" Bias: " << inputLayer[i].bias << " Weights: ";
1014  for(UINT j=0; j<inputLayer[i].weights.getSize(); j++){
1015  std::cout << inputLayer[i].weights[j] << "\t";
1016  } std::cout << std::endl;
1017  }
1018 
1019  std::cout<<"HiddenWeights:\n";
1020  for(UINT i=0; i<numHiddenNeurons; i++){
1021  std::cout<<"Neuron: "<<i<<" Bias: " << hiddenLayer[i].bias << " Weights: ";
1022  for(UINT j=0; j<hiddenLayer[i].weights.getSize(); j++){
1023  std::cout << hiddenLayer[i].weights[j] << "\t";
1024  } std::cout << std::endl;
1025  }
1026 
1027  std::cout<<"OutputWeights:\n";
1028  for(UINT i=0; i<numOutputNeurons; i++){
1029  std::cout<<"Neuron: "<<i<<" Bias: " << outputLayer[i].bias << " Weights: ";
1030  for(UINT j=0; j<outputLayer[i].weights.getSize(); j++){
1031  std::cout << outputLayer[i].weights[j] << "\t";
1032  } std::cout << std::endl;
1033  }
1034 
1035 }
1036 
1037 bool MLP::checkForNAN() const{
1038 
1039  UINT N = 0;
1040  for(UINT i=0; i<numInputNeurons; i++){
1041  if( isNAN(inputLayer[i].bias) ) return true;
1042  N = inputLayer[i].weights.getSize();
1043  for(UINT j=0; j<N; j++){
1044  if( isNAN(inputLayer[i].weights[j]) ) return true;
1045  }
1046  }
1047 
1048  for(UINT i=0; i<numHiddenNeurons; i++){
1049  if( isNAN(hiddenLayer[i].bias) ) return true;
1050  N = hiddenLayer[i].weights.getSize();
1051  for(UINT j=0; j<N; j++){
1052  if( isNAN(hiddenLayer[i].weights[j]) ) return true;
1053  }
1054  }
1055 
1056  for(UINT i=0; i<numOutputNeurons; i++){
1057  if( isNAN(outputLayer[i].bias) ) return true;
1058  N = outputLayer[i].weights.getSize();
1059  for(UINT j=0; j<N; j++){
1060  if( isNAN(outputLayer[i].weights[j]) ) return true;
1061  }
1062  }
1063 
1064  return false;
1065 }
1066 
1067 bool inline MLP::isNAN(const Float v) const{
1068  if( v != v ) return true;
1069  return false;
1070 }
1071 
1072 bool MLP::saveModelToFile( std::fstream &file ) const{
1073 
1074  if( !file.is_open() ){
1075  errorLog << "saveModelToFile(fstream &file) - File is not open!" << std::endl;
1076  return false;
1077  }
1078 
1079  file << "GRT_MLP_FILE_V2.0\n";
1080 
1081  //Write the regressifier settings to the file
1083  errorLog <<"saveModelToFile(fstream &file) - Failed to save Regressifier base settings to file!" << std::endl;
1084  return false;
1085  }
1086 
1087  file << "NumInputNeurons: "<<numInputNeurons<< std::endl;
1088  file << "NumHiddenNeurons: "<<numHiddenNeurons<< std::endl;
1089  file << "NumOutputNeurons: "<<numOutputNeurons<< std::endl;
1090  file << "InputLayerActivationFunction: " <<activationFunctionToString(inputLayerActivationFunction)<< std::endl;
1091  file << "HiddenLayerActivationFunction: " <<activationFunctionToString(hiddenLayerActivationFunction)<< std::endl;
1092  file << "OutputLayerActivationFunction: " <<activationFunctionToString(outputLayerActivationFunction)<< std::endl;
1093  file << "NumRandomTrainingIterations: " << numRandomTrainingIterations << std::endl;
1094  file << "Momentum: " << momentum << std::endl;
1095  file << "Gamma: " << gamma << std::endl;
1096  file << "ClassificationMode: " << classificationModeActive << std::endl;
1097  file << "UseNullRejection: " << useNullRejection << std::endl;
1098  file << "RejectionThreshold: " << nullRejectionThreshold << std::endl;
1099 
1100  if( trained ){
1101  file << "InputLayer: \n";
1102  for(UINT i=0; i<numInputNeurons; i++){
1103  file << "InputNeuron: " << i+1 << std::endl;
1104  file << "NumInputs: " << inputLayer[i].numInputs << std::endl;
1105  file << "Bias: " << inputLayer[i].bias << std::endl;
1106  file << "Gamma: " << inputLayer[i].gamma << std::endl;
1107  file << "Weights: " << std::endl;
1108  for(UINT j=0; j<inputLayer[i].numInputs; j++){
1109  file << inputLayer[i].weights[j] << "\t";
1110  }
1111  file << std::endl;
1112  }
1113  file << "\n";
1114 
1115  file << "HiddenLayer: \n";
1116  for(UINT i=0; i<numHiddenNeurons; i++){
1117  file << "HiddenNeuron: " << i+1 << std::endl;
1118  file << "NumInputs: " << hiddenLayer[i].numInputs << std::endl;
1119  file << "Bias: " << hiddenLayer[i].bias << std::endl;
1120  file << "Gamma: " << hiddenLayer[i].gamma << std::endl;
1121  file << "Weights: " << std::endl;
1122  for(UINT j=0; j<hiddenLayer[i].numInputs; j++){
1123  file << hiddenLayer[i].weights[j] << "\t";
1124  }
1125  file << std::endl;
1126  }
1127  file << "\n";
1128 
1129  file << "OutputLayer: \n";
1130  for(UINT i=0; i<numOutputNeurons; i++){
1131  file << "OutputNeuron: " << i+1 << std::endl;
1132  file << "NumInputs: " << outputLayer[i].numInputs << std::endl;
1133  file << "Bias: " << outputLayer[i].bias << std::endl;
1134  file << "Gamma: " << outputLayer[i].gamma << std::endl;
1135  file << "Weights: " << std::endl;
1136  for(UINT j=0; j<outputLayer[i].numInputs; j++){
1137  file << outputLayer[i].weights[j] << "\t";
1138  }
1139  file << std::endl;
1140  }
1141  }
1142 
1143  return true;
1144 }
1145 
1146 bool MLP::loadModelFromFile( std::fstream &file ){
1147 
1148  std::string activationFunction;
1149 
1150  //Clear any previous models
1151  clear();
1152 
1153  if( !file.is_open() ){
1154  errorLog << "loadModelFromFile(fstream &file) - File is not open!" << std::endl;
1155  return false;
1156  }
1157 
1158  std::string word;
1159 
1160  file >> word;
1161 
1162  //See if we should load a legacy file
1163  if( word == "GRT_MLP_FILE_V1.0" ){
1164  return loadLegacyModelFromFile( file );
1165  }
1166 
1167  //Check to make sure this is a file with the MLP File Format
1168  if( word != "GRT_MLP_FILE_V2.0" ){
1169  file.close();
1170  errorLog << "loadModelFromFile(fstream &file) - Failed to find file header!" << std::endl;
1171  return false;
1172  }
1173 
1174  //Load the base settings from the file
1176  file.close();
1177  errorLog << "loadModelFromFile(fstream &file) - Failed to load regressifier base settings from file!" << std::endl;
1178  return false;
1179  }
1180 
1181  file >> word;
1182  if(word != "NumInputNeurons:"){
1183  file.close();
1184  errorLog << "loadModelFromFile(fstream &file) - Failed to find NumInputNeurons!" << std::endl;
1185  return false;
1186  }
1187  file >> numInputNeurons;
1188  numInputDimensions = numInputNeurons;
1189 
1190  file >> word;
1191  if(word != "NumHiddenNeurons:"){
1192  file.close();
1193  errorLog << "loadModelFromFile(fstream &file) - Failed to find NumHiddenNeurons!" << std::endl;
1194  return false;
1195  }
1196  file >> numHiddenNeurons;
1197 
1198  file >> word;
1199  if(word != "NumOutputNeurons:"){
1200  file.close();
1201  errorLog << "loadModelFromFile(fstream &file) - Failed to find NumOutputNeurons!" << std::endl;
1202  return false;
1203  }
1204  file >> numOutputNeurons;
1205 
1206  file >> word;
1207  if(word != "InputLayerActivationFunction:"){
1208  file.close();
1209  errorLog << "loadModelFromFile(fstream &file) - Failed to find InputLayerActivationFunction!" << std::endl;
1210  return false;
1211  }
1212  file >> activationFunction;
1213  inputLayerActivationFunction = activationFunctionFromString(activationFunction);
1214 
1215  file >> word;
1216  if(word != "HiddenLayerActivationFunction:"){
1217  file.close();
1218  errorLog << "loadModelFromFile(fstream &file) - Failed to find HiddenLayerActivationFunction!" << std::endl;
1219  return false;
1220  }
1221  file >> activationFunction;
1222  hiddenLayerActivationFunction = activationFunctionFromString(activationFunction);
1223 
1224  file >> word;
1225  if(word != "OutputLayerActivationFunction:"){
1226  file.close();
1227  errorLog << "loadModelFromFile(fstream &file) - Failed to find OutputLayerActivationFunction!" << std::endl;
1228  return false;
1229  }
1230  file >> activationFunction;
1231  outputLayerActivationFunction = activationFunctionFromString(activationFunction);
1232 
1233  file >> word;
1234  if(word != "NumRandomTrainingIterations:"){
1235  file.close();
1236  errorLog << "loadModelFromFile(fstream &file) - Failed to find NumRandomTrainingIterations!" << std::endl;
1237  return false;
1238  }
1239  file >> numRandomTrainingIterations;
1240 
1241  file >> word;
1242  if(word != "Momentum:"){
1243  file.close();
1244  errorLog << "loadModelFromFile(fstream &file) - Failed to find Momentum!" << std::endl;
1245  return false;
1246  }
1247  file >> momentum;
1248 
1249  file >> word;
1250  if(word != "Gamma:"){
1251  file.close();
1252  errorLog << "loadModelFromFile(fstream &file) - Failed to find Gamma!" << std::endl;
1253  return false;
1254  }
1255  file >> gamma;
1256 
1257  file >> word;
1258  if(word != "ClassificationMode:"){
1259  file.close();
1260  errorLog << "loadModelFromFile(fstream &file) - Failed to find ClassificationMode!" << std::endl;
1261  return false;
1262  }
1263  file >> classificationModeActive;
1264 
1265  file >> word;
1266  if(word != "UseNullRejection:"){
1267  file.close();
1268  errorLog << "loadModelFromFile(fstream &file) - Failed to find UseNullRejection!" << std::endl;
1269  return false;
1270  }
1271  file >> useNullRejection;
1272 
1273  file >> word;
1274  if(word != "RejectionThreshold:"){
1275  file.close();
1276  errorLog << "loadModelFromFile(fstream &file) - Failed to find RejectionThreshold!" << std::endl;
1277  return false;
1278  }
1279  file >> nullRejectionThreshold;
1280 
1281  if( trained ) initialized = true;
1282  else init(numInputNeurons,numHiddenNeurons,numOutputNeurons);
1283 
1284  if( trained ){
1285 
1286  //Resize the layers
1287  inputLayer.resize( numInputNeurons );
1288  hiddenLayer.resize( numHiddenNeurons );
1289  outputLayer.resize( numOutputNeurons );
1290 
1291  //Load the neuron data
1292  file >> word;
1293  if(word != "InputLayer:"){
1294  file.close();
1295  errorLog << "loadModelFromFile(fstream &file) - Failed to find InputLayer!" << std::endl;
1296  return false;
1297  }
1298 
1299  for(UINT i=0; i<numInputNeurons; i++){
1300  UINT tempNeuronID = 0;
1301 
1302  file >> word;
1303  if(word != "InputNeuron:"){
1304  file.close();
1305  errorLog << "loadModelFromFile(fstream &file) - Failed to find InputNeuron!" << std::endl;
1306  return false;
1307  }
1308  file >> tempNeuronID;
1309 
1310  if( tempNeuronID != i+1 ){
1311  file.close();
1312  errorLog << "loadModelFromFile(fstream &file) - InputNeuron ID does not match!" << std::endl;
1313  return false;
1314  }
1315 
1316  file >> word;
1317  if(word != "NumInputs:"){
1318  file.close();
1319  errorLog << "loadModelFromFile(fstream &file) - Failed to find NumInputs!" << std::endl;
1320  return false;
1321  }
1322  file >> inputLayer[i].numInputs;
1323 
1324  //Resize the buffers
1325  inputLayer[i].weights.resize( inputLayer[i].numInputs );
1326 
1327  file >> word;
1328  if(word != "Bias:"){
1329  file.close();
1330  errorLog << "loadModelFromFile(fstream &file) - Failed to find Bias!" << std::endl;
1331  return false;
1332  }
1333  file >> inputLayer[i].bias;
1334 
1335  file >> word;
1336  if(word != "Gamma:"){
1337  file.close();
1338  errorLog << "loadModelFromFile(fstream &file) - Failed to find Gamma!" << std::endl;
1339  return false;
1340  }
1341  file >> inputLayer[i].gamma;
1342 
1343  file >> word;
1344  if(word != "Weights:"){
1345  file.close();
1346  errorLog << "loadModelFromFile(fstream &file) - Failed to find Weights!" << std::endl;
1347  return false;
1348  }
1349 
1350  for(UINT j=0; j<inputLayer[i].numInputs; j++){
1351  file >> inputLayer[i].weights[j];
1352  }
1353  }
1354 
1355  //Load the Hidden Layer
1356  file >> word;
1357  if(word != "HiddenLayer:"){
1358  file.close();
1359  errorLog << "loadModelFromFile(fstream &file) - Failed to find HiddenLayer!" << std::endl;
1360  return false;
1361  }
1362 
1363  for(UINT i=0; i<numHiddenNeurons; i++){
1364  UINT tempNeuronID = 0;
1365 
1366  file >> word;
1367  if(word != "HiddenNeuron:"){
1368  file.close();
1369  errorLog << "loadModelFromFile(fstream &file) - Failed to find HiddenNeuron!" << std::endl;
1370  return false;
1371  }
1372  file >> tempNeuronID;
1373 
1374  if( tempNeuronID != i+1 ){
1375  file.close();
1376  errorLog << "loadModelFromFile(fstream &file) - Failed to find HiddenNeuron ID does not match!" << std::endl;
1377  return false;
1378  }
1379 
1380  file >> word;
1381  if(word != "NumInputs:"){
1382  file.close();
1383  errorLog << "loadModelFromFile(fstream &file) - Failed to find NumInputs!" << std::endl;
1384  return false;
1385  }
1386  file >> hiddenLayer[i].numInputs;
1387 
1388  //Resize the buffers
1389  hiddenLayer[i].weights.resize( hiddenLayer[i].numInputs );
1390 
1391  file >> word;
1392  if(word != "Bias:"){
1393  file.close();
1394  errorLog << "loadModelFromFile(fstream &file) - Failed to find Bias!" << std::endl;
1395  return false;
1396  }
1397  file >> hiddenLayer[i].bias;
1398 
1399  file >> word;
1400  if(word != "Gamma:"){
1401  file.close();
1402  errorLog << "loadModelFromFile(fstream &file) - Failed to find Gamma!" << std::endl;
1403  return false;
1404  }
1405  file >> hiddenLayer[i].gamma;
1406 
1407  file >> word;
1408  if(word != "Weights:"){
1409  file.close();
1410  errorLog << "loadModelFromFile(fstream &file) - Failed to find Weights!" << std::endl;
1411  return false;
1412  }
1413 
1414  for(unsigned int j=0; j<hiddenLayer[i].numInputs; j++){
1415  file >> hiddenLayer[i].weights[j];
1416  }
1417  }
1418 
1419  //Load the Output Layer
1420  file >> word;
1421  if(word != "OutputLayer:"){
1422  file.close();
1423  errorLog << "loadModelFromFile(fstream &file) - Failed to find OutputLayer!" << std::endl;
1424  return false;
1425  }
1426 
1427  for(UINT i=0; i<numOutputNeurons; i++){
1428  UINT tempNeuronID = 0;
1429 
1430  file >> word;
1431  if(word != "OutputNeuron:"){
1432  file.close();
1433  errorLog << "loadModelFromFile(fstream &file) - Failed to find OutputNeuron!" << std::endl;
1434  return false;
1435  }
1436  file >> tempNeuronID;
1437 
1438  if( tempNeuronID != i+1 ){
1439  file.close();
1440  errorLog << "loadModelFromFile(fstream &file) - Failed to find OuputNeuron ID does not match!!" << std::endl;
1441  return false;
1442  }
1443 
1444  file >> word;
1445  if(word != "NumInputs:"){
1446  file.close();
1447  errorLog << "loadModelFromFile(fstream &file) - Failed to find NumInputs!" << std::endl;
1448  return false;
1449  }
1450  file >> outputLayer[i].numInputs;
1451 
1452  //Resize the buffers
1453  outputLayer[i].weights.resize( outputLayer[i].numInputs );
1454 
1455  file >> word;
1456  if(word != "Bias:"){
1457  file.close();
1458  errorLog << "loadModelFromFile(fstream &file) - Failed to find Bias!" << std::endl;
1459  return false;
1460  }
1461  file >> outputLayer[i].bias;
1462 
1463  file >> word;
1464  if(word != "Gamma:"){
1465  file.close();
1466  errorLog << "loadModelFromFile(fstream &file) - Failed to find Gamma!" << std::endl;
1467  return false;
1468  }
1469  file >> outputLayer[i].gamma;
1470 
1471  file >> word;
1472  if(word != "Weights:"){
1473  file.close();
1474  errorLog << "loadModelFromFile(fstream &file) - Failed to find Weights!" << std::endl;
1475  return false;
1476  }
1477 
1478  for(UINT j=0; j<outputLayer[i].numInputs; j++){
1479  file >> outputLayer[i].weights[j];
1480  }
1481  }
1482 
1483  }
1484 
1485  return true;
1486 }
1487 
1488 UINT MLP::getNumClasses() const{
1489  if( classificationModeActive )
1490  return numOutputNeurons;
1491  return 0;
1492 }
1493 
1495  return numInputNeurons;
1496 }
1497 
1499  return numHiddenNeurons;
1500 }
1501 
1503  return numOutputNeurons;
1504 }
1505 
1507  return inputLayerActivationFunction;
1508 }
1509 
1511  return hiddenLayerActivationFunction;
1512 }
1513 
1515  return outputLayerActivationFunction;
1516 }
1517 
1519  return numRandomTrainingIterations;
1520 }
1521 
1522 Float MLP::getTrainingRate() const{
1523  return learningRate;
1524 }
1525 
1526 Float MLP::getMomentum() const{
1527  return momentum;
1528 }
1529 
1530 Float MLP::getGamma() const{
1531  return gamma;
1532 }
1533 
1535  return trainingError;
1536 }
1537 
1539  return classificationModeActive;
1540 }
1541 
1543  return !classificationModeActive;
1544 }
1545 
1547  return inputLayer;
1548 }
1549 
1551  return hiddenLayer;
1552 }
1553 
1555  return outputLayer;
1556 }
1557 
1559  return trainingErrorLog;
1560 }
1561 
1563  return useNullRejection;
1564 }
1565 
1567  return nullRejectionCoeff;
1568 }
1569 
1571  return nullRejectionThreshold;
1572 }
1573 
1575  if( trained ) return maxLikelihood;
1577 }
1578 
1580  if( trained && classificationModeActive ) return classLikelihoods;
1581  return VectorFloat();
1582 }
1583 
1585  //The class distances is simply the regression data
1586  if( trained && classificationModeActive ) return regressionData;
1587  return VectorFloat();
1588 }
1589 
1591  if( trained && classificationModeActive ) return predictedClassLabel;
1592  return 0;
1593 }
1594 
1595 std::string MLP::activationFunctionToString(const UINT activationFunction) const{
1596  std::string activationName;
1597 
1598  switch(activationFunction){
1599  case(Neuron::LINEAR):
1600  activationName = "LINEAR";
1601  break;
1602  case(Neuron::SIGMOID):
1603  activationName = "SIGMOID";
1604  break;
1605  case(Neuron::BIPOLAR_SIGMOID):
1606  activationName = "BIPOLAR_SIGMOID";
1607  break;
1608  default:
1609  activationName = "UNKNOWN";
1610  break;
1611  }
1612 
1613  return activationName;
1614 }
1615 
1616 UINT MLP::activationFunctionFromString(const std::string activationName) const{
1617  UINT activationFunction = 0;
1618 
1619  if(activationName == "LINEAR" ){
1620  activationFunction = 0;
1621  return activationFunction;
1622  }
1623  if(activationName == "SIGMOID" ){
1624  activationFunction = 1;
1625  return activationFunction;
1626  }
1627  if(activationName == "BIPOLAR_SIGMOID" ){
1628  activationFunction = 2;
1629  return activationFunction;
1630  }
1631  return activationFunction;
1632 }
1633 
1634 bool MLP::validateActivationFunction(const UINT actvationFunction) const{
1635  if( actvationFunction >= Neuron::LINEAR && actvationFunction < Neuron::NUMBER_OF_ACTIVATION_FUNCTIONS ) return true;
1636  return false;
1637 }
1638 
1639 bool MLP::setInputLayerActivationFunction(const UINT activationFunction){
1640 
1641  if( !validateActivationFunction(activationFunction) ){
1642  warningLog << "setInputLayerActivationFunction(const UINT activationFunction) - The activation function is not valid. It should be one of the Neuron ActivationFunctions enums." << std::endl;
1643  }
1644 
1645  this->inputLayerActivationFunction = activationFunction;
1646 
1647  if( initialized ){
1648  return init(numInputNeurons,numHiddenNeurons,numOutputNeurons);
1649  }
1650 
1651  return true;
1652 }
1653 
1654 
1655 bool MLP::setHiddenLayerActivationFunction(const UINT activationFunction){
1656 
1657  if( !validateActivationFunction(activationFunction) ){
1658  warningLog << "setHiddenLayerActivationFunction(const UINT activationFunction) - The activation function is not valid. It should be one of the Neuron ActivationFunctions enums." << std::endl;
1659  }
1660 
1661  this->hiddenLayerActivationFunction = activationFunction;
1662 
1663  if( initialized ){
1664  return init(numInputNeurons,numHiddenNeurons,numOutputNeurons);
1665  }
1666 
1667  return true;
1668 }
1669 
1670 
1671 bool MLP::setOutputLayerActivationFunction(const UINT activationFunction){
1672 
1673  if( !validateActivationFunction(activationFunction) ){
1674  warningLog << "setOutputLayerActivationFunction(const UINT activationFunction) - The activation function is not valid. It should be one of the Neuron ActivationFunctions enums." << std::endl;
1675  }
1676 
1677  this->outputLayerActivationFunction = activationFunction;
1678 
1679  if( initialized ){
1680  return init(numInputNeurons,numHiddenNeurons,numOutputNeurons);
1681  }
1682 
1683  return true;
1684 }
1685 
1686 bool MLP::setTrainingRate(const Float trainingRate){
1687  return setLearningRate( trainingRate );
1688 }
1689 
1690 bool MLP::setMomentum(const Float momentum){
1691  if( momentum >= 0 && momentum <= 1.0 ){
1692  this->momentum = momentum;
1693  return true;
1694  }
1695  return false;
1696 }
1697 
1698 bool MLP::setGamma(const Float gamma){
1699 
1700  if( gamma < 0 ){
1701  warningLog << "setGamma(const Float gamma) - Gamma must be greater than zero!" << std::endl;
1702  }
1703 
1704  this->gamma = gamma;
1705 
1706  if( initialized ){
1707  return init(numInputNeurons,numHiddenNeurons,numOutputNeurons);
1708  }
1709 
1710  return true;
1711 }
1712 
1713 bool MLP::setNumRandomTrainingIterations(const UINT numRandomTrainingIterations){
1714  if( numRandomTrainingIterations > 0 ){
1715  this->numRandomTrainingIterations = numRandomTrainingIterations;
1716  return true;
1717  }
1718  return false;
1719 }
1720 
1721 bool MLP::setNullRejection(const bool useNullRejection){
1722  this->useNullRejection = useNullRejection;
1723  return true;
1724 }
1725 
1726 bool MLP::setNullRejectionCoeff(const Float nullRejectionCoeff){
1727  if( nullRejectionCoeff > 0 ){
1728  this->nullRejectionCoeff = nullRejectionCoeff;
1729  return true;
1730  }
1731  return false;
1732 }
1733 
1734 bool MLP::loadLegacyModelFromFile( std::fstream &file ){
1735 
1736  std::string word;
1737 
1738  file >> word;
1739  if(word != "NumInputNeurons:"){
1740  file.close();
1741  errorLog << "loadModelFromFile(fstream &file) - Failed to find NumInputNeurons!" << std::endl;
1742  return false;
1743  }
1744  file >> numInputNeurons;
1745  numInputDimensions = numInputNeurons;
1746 
1747  file >> word;
1748  if(word != "NumHiddenNeurons:"){
1749  file.close();
1750  errorLog << "loadModelFromFile(fstream &file) - Failed to find NumHiddenNeurons!" << std::endl;
1751  return false;
1752  }
1753  file >> numHiddenNeurons;
1754 
1755  file >> word;
1756  if(word != "NumOutputNeurons:"){
1757  file.close();
1758  errorLog << "loadModelFromFile(fstream &file) - Failed to find NumOutputNeurons!" << std::endl;
1759  return false;
1760  }
1761  file >> numOutputNeurons;
1762 
1763  file >> word;
1764  if(word != "InputLayerActivationFunction:"){
1765  file.close();
1766  errorLog << "loadModelFromFile(fstream &file) - Failed to find InputLayerActivationFunction!" << std::endl;
1767  return false;
1768  }
1769  file >> word;
1770  inputLayerActivationFunction = activationFunctionFromString(word);
1771 
1772  file >> word;
1773  if(word != "HiddenLayerActivationFunction:"){
1774  file.close();
1775  errorLog << "loadModelFromFile(fstream &file) - Failed to find HiddenLayerActivationFunction!" << std::endl;
1776  return false;
1777  }
1778  file >> word;
1779  hiddenLayerActivationFunction = activationFunctionFromString(word);
1780 
1781  file >> word;
1782  if(word != "OutputLayerActivationFunction:"){
1783  file.close();
1784  errorLog << "loadModelFromFile(fstream &file) - Failed to find OutputLayerActivationFunction!" << std::endl;
1785  return false;
1786  }
1787  file >> word;
1788  outputLayerActivationFunction = activationFunctionFromString(word);
1789 
1790  file >> word;
1791  if(word != "MinNumEpochs:"){
1792  file.close();
1793  errorLog << "loadModelFromFile(fstream &file) - Failed to find MinNumEpochs!" << std::endl;
1794  return false;
1795  }
1796  file >> minNumEpochs;
1797 
1798  file >> word;
1799  if(word != "MaxNumEpochs:"){
1800  file.close();
1801  errorLog << "loadModelFromFile(fstream &file) - Failed to find MaxNumEpochs!" << std::endl;
1802  return false;
1803  }
1804  file >> maxNumEpochs;
1805 
1806  file >> word;
1807  if(word != "NumRandomTrainingIterations:"){
1808  file.close();
1809  errorLog << "loadModelFromFile(fstream &file) - Failed to find NumRandomTrainingIterations!" << std::endl;
1810  return false;
1811  }
1812  file >> numRandomTrainingIterations;
1813 
1814  file >> word;
1815  if(word != "ValidationSetSize:"){
1816  file.close();
1817  errorLog << "loadModelFromFile(fstream &file) - Failed to find ValidationSetSize!" << std::endl;
1818  return false;
1819  }
1820  file >> validationSetSize;
1821 
1822  file >> word;
1823  if(word != "MinChange:"){
1824  file.close();
1825  errorLog << "loadModelFromFile(fstream &file) - Failed to find MinChange!" << std::endl;
1826  return false;
1827  }
1828  file >> minChange;
1829 
1830  file >> word;
1831  if(word != "TrainingRate:"){
1832  file.close();
1833  errorLog << "loadModelFromFile(fstream &file) - Failed to find TrainingRate!" << std::endl;
1834  return false;
1835  }
1836  file >> learningRate;
1837 
1838  file >> word;
1839  if(word != "Momentum:"){
1840  file.close();
1841  errorLog << "loadModelFromFile(fstream &file) - Failed to find Momentum!" << std::endl;
1842  return false;
1843  }
1844  file >> momentum;
1845 
1846  file >> word;
1847  if(word != "Gamma:"){
1848  file.close();
1849  errorLog << "loadModelFromFile(fstream &file) - Failed to find Gamma!" << std::endl;
1850  return false;
1851  }
1852  file >> gamma;
1853 
1854  file >> word;
1855  if(word != "UseValidationSet:"){
1856  file.close();
1857  errorLog << "loadModelFromFile(fstream &file) - Failed to find UseValidationSet!" << std::endl;
1858  return false;
1859  }
1860  file >> useValidationSet;
1861 
1862  file >> word;
1863  if(word != "RandomiseTrainingOrder:"){
1864  file.close();
1865  errorLog << "loadModelFromFile(fstream &file) - Failed to find RandomiseTrainingOrder!" << std::endl;
1866  return false;
1867  }
1868  file >> randomiseTrainingOrder;
1869 
1870  file >> word;
1871  if(word != "UseScaling:"){
1872  file.close();
1873  errorLog << "loadModelFromFile(fstream &file) - Failed to find UseScaling!" << std::endl;
1874  return false;
1875  }
1876  file >> useScaling;
1877 
1878  file >> word;
1879  if(word != "ClassificationMode:"){
1880  file.close();
1881  errorLog << "loadModelFromFile(fstream &file) - Failed to find ClassificationMode!" << std::endl;
1882  return false;
1883  }
1884  file >> classificationModeActive;
1885 
1886  file >> word;
1887  if(word != "UseNullRejection:"){
1888  file.close();
1889  errorLog << "loadModelFromFile(fstream &file) - Failed to find UseNullRejection!" << std::endl;
1890  return false;
1891  }
1892  file >> useNullRejection;
1893 
1894  file >> word;
1895  if(word != "RejectionThreshold:"){
1896  file.close();
1897  errorLog << "loadModelFromFile(fstream &file) - Failed to find RejectionThreshold!" << std::endl;
1898  return false;
1899  }
1900  file >> nullRejectionThreshold;
1901 
1902  //Resize the layers
1903  inputLayer.resize( numInputNeurons );
1904  hiddenLayer.resize( numHiddenNeurons );
1905  outputLayer.resize( numOutputNeurons );
1906 
1907  //Load the neuron data
1908  file >> word;
1909  if(word != "InputLayer:"){
1910  file.close();
1911  errorLog << "loadModelFromFile(fstream &file) - Failed to find InputLayer!" << std::endl;
1912  return false;
1913  }
1914 
1915  for(UINT i=0; i<numInputNeurons; i++){
1916  UINT tempNeuronID = 0;
1917 
1918  file >> word;
1919  if(word != "InputNeuron:"){
1920  file.close();
1921  errorLog << "loadModelFromFile(fstream &file) - Failed to find InputNeuron!" << std::endl;
1922  return false;
1923  }
1924  file >> tempNeuronID;
1925 
1926  if( tempNeuronID != i+1 ){
1927  file.close();
1928  errorLog << "loadModelFromFile(fstream &file) - InputNeuron ID does not match!" << std::endl;
1929  return false;
1930  }
1931 
1932  file >> word;
1933  if(word != "NumInputs:"){
1934  file.close();
1935  errorLog << "loadModelFromFile(fstream &file) - Failed to find NumInputs!" << std::endl;
1936  return false;
1937  }
1938  file >> inputLayer[i].numInputs;
1939 
1940  //Resize the buffers
1941  inputLayer[i].weights.resize( inputLayer[i].numInputs );
1942 
1943  file >> word;
1944  if(word != "Bias:"){
1945  file.close();
1946  errorLog << "loadModelFromFile(fstream &file) - Failed to find Bias!" << std::endl;
1947  return false;
1948  }
1949  file >> inputLayer[i].bias;
1950 
1951  file >> word;
1952  if(word != "Gamma:"){
1953  file.close();
1954  errorLog << "loadModelFromFile(fstream &file) - Failed to find Gamma!" << std::endl;
1955  return false;
1956  }
1957  file >> inputLayer[i].gamma;
1958 
1959  file >> word;
1960  if(word != "Weights:"){
1961  file.close();
1962  errorLog << "loadModelFromFile(fstream &file) - Failed to find Weights!" << std::endl;
1963  return false;
1964  }
1965 
1966  for(UINT j=0; j<inputLayer[i].numInputs; j++){
1967  file >> inputLayer[i].weights[j];
1968  }
1969  }
1970 
1971  //Load the Hidden Layer
1972  file >> word;
1973  if(word != "HiddenLayer:"){
1974  file.close();
1975  errorLog << "loadModelFromFile(fstream &file) - Failed to find HiddenLayer!" << std::endl;
1976  return false;
1977  }
1978 
1979  for(UINT i=0; i<numHiddenNeurons; i++){
1980  UINT tempNeuronID = 0;
1981 
1982  file >> word;
1983  if(word != "HiddenNeuron:"){
1984  file.close();
1985  errorLog << "loadModelFromFile(fstream &file) - Failed to find HiddenNeuron!" << std::endl;
1986  return false;
1987  }
1988  file >> tempNeuronID;
1989 
1990  if( tempNeuronID != i+1 ){
1991  file.close();
1992  errorLog << "loadModelFromFile(fstream &file) - Failed to find HiddenNeuron ID does not match!" << std::endl;
1993  return false;
1994  }
1995 
1996  file >> word;
1997  if(word != "NumInputs:"){
1998  file.close();
1999  errorLog << "loadModelFromFile(fstream &file) - Failed to find NumInputs!" << std::endl;
2000  return false;
2001  }
2002  file >> hiddenLayer[i].numInputs;
2003 
2004  //Resize the buffers
2005  hiddenLayer[i].weights.resize( hiddenLayer[i].numInputs );
2006 
2007  file >> word;
2008  if(word != "Bias:"){
2009  file.close();
2010  errorLog << "loadModelFromFile(fstream &file) - Failed to find Bias!" << std::endl;
2011  return false;
2012  }
2013  file >> hiddenLayer[i].bias;
2014 
2015  file >> word;
2016  if(word != "Gamma:"){
2017  file.close();
2018  errorLog << "loadModelFromFile(fstream &file) - Failed to find Gamma!" << std::endl;
2019  return false;
2020  }
2021  file >> hiddenLayer[i].gamma;
2022 
2023  file >> word;
2024  if(word != "Weights:"){
2025  file.close();
2026  errorLog << "loadModelFromFile(fstream &file) - Failed to find Weights!" << std::endl;
2027  return false;
2028  }
2029 
2030  for(unsigned int j=0; j<hiddenLayer[i].numInputs; j++){
2031  file >> hiddenLayer[i].weights[j];
2032  }
2033  }
2034 
2035  //Load the Output Layer
2036  file >> word;
2037  if(word != "OutputLayer:"){
2038  file.close();
2039  errorLog << "loadModelFromFile(fstream &file) - Failed to find OutputLayer!" << std::endl;
2040  return false;
2041  }
2042 
2043  for(UINT i=0; i<numOutputNeurons; i++){
2044  UINT tempNeuronID = 0;
2045 
2046  file >> word;
2047  if(word != "OutputNeuron:"){
2048  file.close();
2049  errorLog << "loadModelFromFile(fstream &file) - Failed to find OutputNeuron!" << std::endl;
2050  return false;
2051  }
2052  file >> tempNeuronID;
2053 
2054  if( tempNeuronID != i+1 ){
2055  file.close();
2056  errorLog << "loadModelFromFile(fstream &file) - Failed to find OuputNeuron ID does not match!!" << std::endl;
2057  return false;
2058  }
2059 
2060  file >> word;
2061  if(word != "NumInputs:"){
2062  file.close();
2063  errorLog << "loadModelFromFile(fstream &file) - Failed to find NumInputs!" << std::endl;
2064  return false;
2065  }
2066  file >> outputLayer[i].numInputs;
2067 
2068  //Resize the buffers
2069  outputLayer[i].weights.resize( outputLayer[i].numInputs );
2070 
2071  file >> word;
2072  if(word != "Bias:"){
2073  file.close();
2074  errorLog << "loadModelFromFile(fstream &file) - Failed to find Bias!" << std::endl;
2075  return false;
2076  }
2077  file >> outputLayer[i].bias;
2078 
2079  file >> word;
2080  if(word != "Gamma:"){
2081  file.close();
2082  errorLog << "loadModelFromFile(fstream &file) - Failed to find Gamma!" << std::endl;
2083  return false;
2084  }
2085  file >> outputLayer[i].gamma;
2086 
2087  file >> word;
2088  if(word != "Weights:"){
2089  file.close();
2090  errorLog << "loadModelFromFile(fstream &file) - Failed to find Weights!" << std::endl;
2091  return false;
2092  }
2093 
2094  for(UINT j=0; j<outputLayer[i].numInputs; j++){
2095  file >> outputLayer[i].weights[j];
2096  }
2097  }
2098 
2099  if( useScaling ){
2100  //Resize the ranges buffers
2101  inputVectorRanges.resize( numInputNeurons );
2102  targetVectorRanges.resize( numOutputNeurons );
2103 
2104  //Load the ranges
2105  file >> word;
2106  if(word != "InputVectorRanges:"){
2107  file.close();
2108  errorLog << "loadModelFromFile(fstream &file) - Failed to find InputVectorRanges!" << std::endl;
2109  return false;
2110  }
2111  for(UINT j=0; j<inputVectorRanges.size(); j++){
2112  file >> inputVectorRanges[j].minValue;
2113  file >> inputVectorRanges[j].maxValue;
2114  }
2115 
2116  file >> word;
2117  if(word != "OutputVectorRanges:"){
2118  file.close();
2119  errorLog << "loadModelFromFile(fstream &file) - Failed to find OutputVectorRanges!" << std::endl;
2120  return false;
2121  }
2122  for(UINT j=0; j<targetVectorRanges.size(); j++){
2123  file >> targetVectorRanges[j].minValue;
2124  file >> targetVectorRanges[j].maxValue;
2125  }
2126  }
2127 
2128  initialized = true;
2129  trained = true;
2130 
2131  return true;
2132 }
2133 
2134 GRT_END_NAMESPACE
2135 
bool setLearningRate(const Float learningRate)
Definition: MLBase.cpp:291
UINT getNumHiddenNeurons() const
Definition: MLP.cpp:1498
MLP & operator=(const MLP &rhs)
Definition: MLP.cpp:75
VectorFloat feedforward(VectorFloat data)
Definition: MLP.cpp:939
#define DEFAULT_NULL_LIKELIHOOD_VALUE
Definition: Classifier.h:38
VectorFloat getClassDistances() const
Definition: MLP.cpp:1584
RegressionData reformatAsRegressionData() const
bool setTrainingRate(const Float trainingRate)
Definition: MLP.cpp:1686
Float getGamma() const
Definition: MLP.cpp:1530
Float scale(const Float &x, const Float &minSource, const Float &maxSource, const Float &minTarget, const Float &maxTarget, const bool constrain=false)
Definition: MLBase.h:339
virtual ~MLP()
Definition: MLP.cpp:71
bool getNullRejectionEnabled() const
Definition: MLP.cpp:1562
Vector< MinMax > getInputRanges() const
bool validateActivationFunction(const UINT avactivationFunction) const
Definition: MLP.cpp:1634
virtual bool resize(const unsigned int size)
Definition: Vector.h:133
Float back_prop(const VectorFloat &inputVector, const VectorFloat &targetVector, const Float alpha, const Float beta)
Definition: MLP.cpp:851
static Float getMin(const VectorFloat &x)
Definition: Util.cpp:256
UINT getInputLayerActivationFunction() const
Definition: MLP.cpp:1506
bool copyBaseVariables(const Regressifier *regressifier)
UINT getNumInputDimensions() const
Vector< Neuron > getHiddenLayer() const
Definition: MLP.cpp:1550
bool init(const UINT numInputNeurons, const UINT numHiddenNeurons, const UINT numOutputNeurons)
Definition: MLP.cpp:222
std::string activationFunctionToString(const UINT activationFunction) const
Definition: MLP.cpp:1595
Vector< VectorFloat > getTrainingLog() const
Definition: MLP.cpp:1558
unsigned int getSize() const
Definition: Vector.h:193
UINT getNumRandomTrainingIterations() const
Definition: MLP.cpp:1518
bool checkForNAN() const
Definition: MLP.cpp:1037
Vector< MinMax > getTargetRanges() const
bool saveBaseSettingsToFile(std::fstream &file) const
virtual bool train_(ClassificationData &trainingData)
Definition: MLP.cpp:129
bool scale(const Float minTarget, const Float maxTarget)
bool setInputLayerActivationFunction(const UINT activationFunction)
Definition: MLP.cpp:1639
This class implements a Multilayer Perceptron Artificial Neural Network.
UINT getNumTargetDimensions() const
Vector< Neuron > getOutputLayer() const
Definition: MLP.cpp:1554
bool setHiddenLayerActivationFunction(const UINT activationFunction)
Definition: MLP.cpp:1655
std::string getRegressifierType() const
MLP()
Definition: MLP.cpp:31
virtual bool saveModelToFile(std::fstream &file) const
Definition: MLP.cpp:1072
virtual bool clear()
Definition: MLP.cpp:296
Vector< Neuron > getInputLayer() const
Definition: MLP.cpp:1546
UINT getNumOutputNeurons() const
Definition: MLP.cpp:1502
bool loadBaseSettingsFromFile(std::fstream &file)
void printNetwork() const
Definition: MLP.cpp:1005
UINT getNumDimensions() const
UINT getNumClasses() const
UINT activationFunctionFromString(const std::string activationName) const
Definition: MLP.cpp:1616
Float getMomentum() const
Definition: MLP.cpp:1526
virtual bool print() const
Definition: MLP.cpp:312
bool setNullRejection(const bool useNullRejection)
Definition: MLP.cpp:1721
VectorFloat getClassLikelihoods() const
Definition: MLP.cpp:1579
UINT getOutputLayerActivationFunction() const
Definition: MLP.cpp:1514
bool setMomentum(const Float momentum)
Definition: MLP.cpp:1690
Float getTrainingError() const
Definition: MLP.cpp:1534
Float getMaximumLikelihood() const
Definition: MLP.cpp:1574
UINT getHiddenLayerActivationFunction() const
Definition: MLP.cpp:1510
Float getNullRejectionCoeff() const
Definition: MLP.cpp:1566
virtual bool deepCopyFrom(const Regressifier *regressifier)
Definition: MLP.cpp:111
bool setNumRandomTrainingIterations(const UINT numRandomTrainingIterations)
Definition: MLP.cpp:1713
bool setGamma(const Float gamma)
Definition: MLP.cpp:1698
int getRandomNumberInt(int minRange, int maxRange)
Definition: Random.h:88
UINT getNumClasses() const
Definition: MLP.cpp:1488
Float getNullRejectionThreshold() const
Definition: MLP.cpp:1570
virtual bool loadModelFromFile(std::fstream &file)
Definition: MLP.cpp:1146
bool setNullRejectionCoeff(const Float nullRejectionCoeff)
Definition: MLP.cpp:1726
bool getRegressionModeActive() const
Definition: MLP.cpp:1542
Definition: MLP.h:41
Float getTrainingRate() const
Definition: MLP.cpp:1522
bool setOutputLayerActivationFunction(const UINT activationFunction)
Definition: MLP.cpp:1671
RegressionData partition(const UINT trainingSizePercentage)
static Float sum(const VectorFloat &x)
Definition: Util.cpp:170
void setSeed(unsigned long long seed=0)
Definition: Random.h:68
UINT getNumSamples() const
virtual bool clear()
UINT getPredictedClassLabel() const
Definition: MLP.cpp:1590
bool getClassificationModeActive() const
Definition: MLP.cpp:1538
virtual bool predict_(VectorFloat &inputVector)
Definition: MLP.cpp:163
UINT getNumInputNeurons() const
Definition: MLP.cpp:1494