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