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