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