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