GestureRecognitionToolkit  Version: 0.1.0
The Gesture Recognition Toolkit (GRT) is a cross-platform, open-source, c++ machine learning library for real-time gesture recognition.
MultidimensionalRegression.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 
22 
23 GRT_BEGIN_NAMESPACE
24 
25 //Register the MultidimensionalRegression module with the Classifier base class
26 RegisterRegressifierModule< MultidimensionalRegression > MultidimensionalRegression::registerModule("MultidimensionalRegression");
27 
28 MultidimensionalRegression::MultidimensionalRegression(const Regressifier &regressifier,bool useScaling):regressifier(NULL)
29 {
30  this->useScaling = useScaling;
31  classType = "MultidimensionalRegression";
32  regressifierType = classType;
33  debugLog.setProceedingText("[DEBUG MultidimensionalRegression]");
34  errorLog.setProceedingText("[ERROR MultidimensionalRegression]");
35  trainingLog.setProceedingText("[TRAINING MultidimensionalRegression]");
36  warningLog.setProceedingText("[WARNING MultidimensionalRegression]");
37 
38  setRegressionModule( regressifier );
39 }
40 
42 {
43  deleteAll();
44 }
45 
47 
48  if( this != &rhs ){
49 
50  //Clean up any previous setup
51  deleteAll();
52 
53  //Set the main regression module
55 
56  //Deep copy the regression modules from the RHS to this instance
57  if( !rhs.deepCopyRegressionModules( regressionModules ) ){
58  errorLog << "const MultidimensionalRegression &rhs - Failed to deep copy regression modules!" << std::endl;
59  }
60 
61  //Copy the base variables
63  }
64  return *this;
65 }
66 
68 
69  if( regressifier == NULL ) return false;
70 
71  if( this->getRegressifierType() == regressifier->getRegressifierType() ){
72 
73  const MultidimensionalRegression *ptr = dynamic_cast<const MultidimensionalRegression*>(regressifier);
74 
75  //Set the main regression module
77 
78  //Deep copy the regression modules from the RHS to this instance
79  if( !ptr->deepCopyRegressionModules( regressionModules ) ){
80  errorLog << "deepCopyFrom(const Regressifier *regressifier) - Failed to deep copy regression modules!" << std::endl;
81  return false;
82  }
83 
84  //Copy the base variables
85  return copyBaseVariables( regressifier );
86  }
87 
88  return false;
89 }
90 
92 
93  const unsigned int M = trainingData.getNumSamples();
94  const unsigned int N = trainingData.getNumInputDimensions();
95  const unsigned int K = trainingData.getNumTargetDimensions();
96  trained = false;
97  trainingResults.clear();
98  deleteRegressionModules();
99 
100  if( !getIsRegressionModuleSet() ){
101  errorLog << "train_(RegressionData &trainingData) - The regression module has not been set!" << std::endl;
102  return false;
103  }
104 
105  if( M == 0 ){
106  errorLog << "train_(RegressionData &trainingData) - Training data has zero samples!" << std::endl;
107  return false;
108  }
109 
110  numInputDimensions = N;
111  numOutputDimensions = K;
112  inputVectorRanges.clear();
113  targetVectorRanges.clear();
114 
115  //Scale the training and validation data, if needed
116  if( useScaling ){
117  //Find the ranges for the input data
118  inputVectorRanges = trainingData.getInputRanges();
119 
120  //Find the ranges for the target data
121  targetVectorRanges = trainingData.getTargetRanges();
122 
123  //Scale the training data
124  trainingData.scale(inputVectorRanges,targetVectorRanges,0.0,1.0);
125  }
126 
127  //Setup the regression modules
128  regressionModules.resize( K, NULL );
129 
130  //Any scaling will happpen at the meta level, not the regression module letter, so ensure scaling is turned off for the modules
131  regressifier->enableScaling( false );
132 
133  for(UINT k=0; k<K; k++){
134  regressionModules[k] = regressifier->deepCopy();
135  if( regressionModules[k] == NULL ){
136  errorLog << "train(LabelledRegressionData &trainingData) - Failed to deep copy module " << k << std::endl;
137  return false;
138  }
139  }
140 
141  //Train each regression module
142  for(UINT k=0; k<K; k++){
143 
144  trainingLog << "Training regression module: " << k << std::endl;
145 
146  //We need to create a 1 dimensional training dataset for the k'th target dimension
147  RegressionData data;
148  data.setInputAndTargetDimensions(N, 1);
149 
150  for(UINT i=0; i<M; i++){
151  if( !data.addSample(trainingData[i].getInputVector(), VectorFloat(1,trainingData[i].getTargetVector()[k]) ) ){
152  errorLog << "train_(RegressionData &trainingData) - Failed to add sample to dataset for regression module " << k << std::endl;
153  return false;
154  }
155  }
156 
157  if( !regressionModules[k]->train( data ) ){
158  errorLog << "train_(RegressionData &trainingData) - Failed to train regression module " << k << std::endl;
159  return false;
160  }
161  }
162 
163  //Flag that the algorithm has been trained
164  regressionData.resize(K,0);
165  trained = true;
166  return trained;
167 }
168 
170 
171  if( !trained ){
172  errorLog << "predict_(VectorFloat &inputVector) - Model Not Trained!" << std::endl;
173  return false;
174  }
175 
176  if( !trained ) return false;
177 
178  if( inputVector.getSize() != numInputDimensions ){
179  errorLog << "predict_(VectorFloat &inputVector) - The size of the input Vector (" << inputVector.getSize() << ") does not match the num features in the model (" << numInputDimensions << std::endl;
180  return false;
181  }
182 
183  if( useScaling ){
184  for(UINT n=0; n<numInputDimensions; n++){
185  inputVector[n] = grt_scale(inputVector[n], inputVectorRanges[n].minValue, inputVectorRanges[n].maxValue, 0.0, 1.0);
186  }
187  }
188 
189  for(UINT n=0; n<numOutputDimensions; n++){
190  if( !regressionModules[ n ]->predict( inputVector ) ){
191  errorLog << "predict_(VectorFloat &inputVector) - Failed to predict for regression module " << n << std::endl;
192  }
193  regressionData[ n ] = regressionModules[ n ]->getRegressionData()[0];
194  }
195 
196  if( useScaling ){
197  for(UINT n=0; n<numOutputDimensions; n++){
198  regressionData[n] = grt_scale(regressionData[n], 0.0, 1.0, targetVectorRanges[n].minValue, targetVectorRanges[n].maxValue);
199  }
200  }
201 
202  return true;
203 }
204 
205 bool MultidimensionalRegression::saveModelToFile( std::fstream &file ) const {
206 
207  if(!file.is_open())
208  {
209  errorLog << "saveModelToFile(fstream &file) - The file is not open!" << std::endl;
210  return false;
211  }
212 
213  //Write the header info
214  file << "GRT_MULTIDIMENSIONAL_REGRESSION_MODEL_FILE_V2.0\n";
215 
216  //Write the regressifier settings to the file
218  errorLog <<"saveModelToFile(fstream &file) - Failed to save Regressifier base settings to file!" << std::endl;
219  return false;
220  }
221 
222  if( !getIsRegressionModuleSet() ){
223  file << "Regressifier: " << "NOT_SET" << std::endl;
224  return true;
225  }
226 
227  //Save the regression
228  file << "Regressifier: " << regressifier->getRegressifierType() << std::endl;
229 
230  if( !regressifier->saveModelToFile( file ) ){
231  errorLog << "saveModelToFile(fstream &file) - Failed to save regressifier!" << std::endl;
232  return false;
233  }
234 
235  for(UINT i=0; i<regressionModules.size(); i++){
236  if( !regressionModules[i]->saveModelToFile( file ) ){
237  errorLog << "saveModelToFile(fstream &file) - Failed to save regression module " << i << std::endl;
238  return false;
239  }
240  }
241 
242  return true;
243 }
244 
246 
247  trained = false;
248  numInputDimensions = 0;
249  deleteAll();
250 
251  if(!file.is_open())
252  {
253  errorLog << "loadModelFromFile(string filename) - Could not open file to load model" << std::endl;
254  return false;
255  }
256 
257  std::string word;
258 
259  //Find the file type header
260  file >> word;
261 
262  //Check to see if we should load a legacy file
263  if( word == "GRT_MULTIDIMENSIONAL_REGRESSION_MODEL_FILE_V1.0" ){
264  return loadLegacyModelFromFile( file );
265  }
266 
267  if( word != "GRT_MULTIDIMENSIONAL_REGRESSION_MODEL_FILE_V2.0" ){
268  errorLog << "loadModelFromFile( fstream &file ) - Could not find Model File Header" << std::endl;
269  return false;
270  }
271 
272  //Load the regressifier settings from the file
274  errorLog <<"loadModelFromFile( fstream &file ) - Failed to save Regressifier base settings to file!" << std::endl;
275  return false;
276  }
277 
278  file >> word;
279  if( word != "Regressifier:" ){
280  errorLog << "loadModelFromFile(string filename) - Failed to find Regressifier!" << std::endl;
281  return false;
282  }
283 
284  //Load the regressifier type
285  std::string regressifierType;
286  file >> regressifierType;
287  if( regressifierType == "NOT_SET" ){
288  return true;
289  }
290 
291  //Create the regressifer
292  regressifier = createInstanceFromString( regressifierType );
293 
294  if( regressifier == NULL ){
295  errorLog << "loadModelFromFile(fstream &file) - Failed to create regression instance from string!" << std::endl;
296  return false;
297  }
298 
299  if( !regressifier->loadModelFromFile( file ) ){
300  errorLog <<"loadModelFromFile(fstream &file) - Failed to load regressifier!" << std::endl;
301  return false;
302  }
303 
304  if( numOutputDimensions > 0 ){
305  //Initialize the regression modules
306  regressionModules.resize(numOutputDimensions, NULL);
307 
308  for(UINT i=0; i<regressionModules.getSize(); i++){
309  regressionModules[i] = createInstanceFromString( regressifierType );
310  if( !regressionModules[i]->loadModelFromFile( file ) ){
311  errorLog << "loadModelFromFile(fstream &file) - Failed to load regression module " << i << std::endl;
312  return false;
313  }
314  }
315  }
316 
317  return true;
318 }
319 
321  return regressifier != NULL ? true : false;
322 }
323 
325  return regressifier;
326 }
327 
329 
330  if( !deleteRegressionModules() ){
331  return false;
332  }
333 
334  trained = false;
335 
336  if( this->regressifier != NULL ) delete this->regressifier;
337 
338  this->regressifier = regressifier.deepCopy();
339 
340  if( this->regressifier == NULL ) return false;
341 
342  return true;
343 }
344 
345 bool MultidimensionalRegression::deepCopyRegressionModules( Vector< Regressifier* > &newModules ) const{
346 
347  const UINT N = regressionModules.getSize();
348 
349  //The newModules Vector should be empty
350  if( newModules.size() > 0 ) return false;
351 
352  //Return true if there are no modules to copy
353  if( N == 0 ) return true;
354 
355  //Perform the copy
356  newModules.resize( N );
357 
358  for(UINT i=0; i<N; i++){
359  //Deep copy the i'th module into the i'th regressionModules
360  newModules[i] = regressionModules[i]->deepCopy();
361  if( newModules[i] == NULL ){
362  for(UINT j=0; j<i; j++){
363  delete newModules[j];
364  newModules[j] = NULL;
365  }
366  newModules.clear();
367  return false;
368  }
369  }
370 
371  return true;
372 }
373 
374 bool MultidimensionalRegression::deleteAll(){
375  if( regressifier != NULL ){
376  delete regressifier;
377  regressifier = NULL;
378  }
379  return deleteRegressionModules();
380 }
381 
382 bool MultidimensionalRegression::deleteRegressionModules(){
383 
384  const UINT N = regressionModules.getSize();
385 
386  if( N == 0 ) return true;
387 
388  for(UINT i=0; i<N; i++){
389  delete regressionModules[i];
390  regressionModules[i] = NULL;
391  }
392  regressionModules.clear();
393  return true;
394 }
395 
397 
398  std::string word;
399 
400  file >> word;
401  if(word != "NumFeatures:"){
402  errorLog << "loadModelFromFile(string filename) - Could not find NumFeatures!" << std::endl;
403  return false;
404  }
405  file >> numInputDimensions;
406 
407  file >> word;
408  if(word != "NumOutputDimensions:"){
409  errorLog << "loadModelFromFile(string filename) - Could not find NumOutputDimensions!" << std::endl;
410  return false;
411  }
412  file >> numOutputDimensions;
413 
414  file >> word;
415  if(word != "UseScaling:"){
416  errorLog << "loadModelFromFile(string filename) - Could not find UseScaling!" << std::endl;
417  return false;
418  }
419  file >> useScaling;
420 
422  if( useScaling ){
423  //Resize the ranges buffer
424  inputVectorRanges.resize(numInputDimensions);
425  targetVectorRanges.resize(numOutputDimensions);
426 
427  //Load the ranges
428  file >> word;
429  if(word != "InputVectorRanges:"){
430  file.close();
431  errorLog << "loadModelFromFile(string filename) - Failed to find InputVectorRanges!" << std::endl;
432  return false;
433  }
434  for(UINT j=0; j<inputVectorRanges.getSize(); j++){
435  file >> inputVectorRanges[j].minValue;
436  file >> inputVectorRanges[j].maxValue;
437  }
438 
439  file >> word;
440  if(word != "OutputVectorRanges:"){
441  file.close();
442  errorLog << "loadModelFromFile(string filename) - Failed to find OutputVectorRanges!" << std::endl;
443  return false;
444  }
445  for(UINT j=0; j<targetVectorRanges.getSize(); j++){
446  file >> targetVectorRanges[j].minValue;
447  file >> targetVectorRanges[j].maxValue;
448  }
449  }
450 
451  file >> word;
452  if( word != "Regressifier:" ){
453  errorLog << "loadModelFromFile(string filename) - Failed to find Regressifier!" << std::endl;
454  return false;
455  }
456 
457  //Load the regressifier type
458  std::string regressifierType;
459  file >> regressifierType;
460  if( regressifierType == "NOT_SET" ){
461  return true;
462  }
463 
464  //Create the regressifer
465  regressifier = createInstanceFromString( regressifierType );
466 
467  if( regressifier == NULL ){
468  errorLog << "loadModelFromFile(fstream &file) - Failed to create regression instance from string!" << std::endl;
469  return false;
470  }
471 
472  if( !regressifier->loadModelFromFile( file ) ){
473  errorLog <<"loadModelFromFile(fstream &file) - Failed to load regressifier!" << std::endl;
474  return false;
475  }
476 
477  if( numOutputDimensions > 0 ){
478  //Initialize the regression modules
479  regressionModules.resize(numOutputDimensions, NULL);
480 
481  for(UINT i=0; i<regressionModules.getSize(); i++){
482  regressionModules[i] = createInstanceFromString( regressifierType );
483  if( !regressionModules[i]->loadModelFromFile( file ) ){
484  errorLog << "loadModelFromFile(fstream &file) - Failed to load regression module " << i << std::endl;
485  return false;
486  }
487  }
488 
489  //Resize the regression data Vector
490  regressionData.resize(numOutputDimensions,0);
491 
492  //Flag that the model has been trained
493  trained = true;
494  }
495 
496  return true;
497 }
498 
499 GRT_END_NAMESPACE
500 
virtual bool predict(VectorFloat inputVector)
Definition: MLBase.cpp:112
Vector< MinMax > getInputRanges() const
bool enableScaling(const bool useScaling)
Definition: MLBase.cpp:266
virtual bool resize(const unsigned int size)
Definition: Vector.h:133
virtual bool train(ClassificationData trainingData)
Definition: MLBase.cpp:88
virtual bool predict_(VectorFloat &inputVector)
virtual bool train_(RegressionData &trainingData)
static Regressifier * createInstanceFromString(const std::string &regressifierType)
MultidimensionalRegression(const Regressifier &regressifier=LinearRegression(), bool useScaling=false)
bool copyBaseVariables(const Regressifier *regressifier)
UINT getNumInputDimensions() const
bool loadLegacyModelFromFile(std::fstream &file)
unsigned int getSize() const
Definition: Vector.h:193
MultidimensionalRegression & operator=(const MultidimensionalRegression &rhs)
bool setInputAndTargetDimensions(const UINT numInputDimensions, const UINT numTargetDimensions)
Vector< MinMax > getTargetRanges() const
bool saveBaseSettingsToFile(std::fstream &file) const
bool scale(const Float minTarget, const Float maxTarget)
UINT getNumTargetDimensions() const
std::string getRegressifierType() const
virtual bool saveModelToFile(std::string filename) const
Definition: MLBase.cpp:146
virtual bool loadModelFromFile(std::fstream &file)
virtual bool saveModelToFile(std::fstream &file) const
bool loadBaseSettingsFromFile(std::fstream &file)
virtual bool loadModelFromFile(std::string filename)
Definition: MLBase.cpp:168
Regressifier * deepCopy() const
bool setRegressionModule(const Regressifier &regressifier)
This class implements the Multidimensional Regression meta algorithm. Multidimensional Regressionacts...
virtual bool deepCopyFrom(const Regressifier *regressifier)
bool addSample(const VectorFloat &inputVector, const VectorFloat &targetVector)
UINT getNumSamples() const