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.
SOMQuantizer.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 "SOMQuantizer.h"
23 
24 GRT_BEGIN_NAMESPACE
25 
26 //Register your module with the FeatureExtraction base class
27 RegisterFeatureExtractionModule< SOMQuantizer > SOMQuantizer::registerModule("SOMQuantizer");
28 
29 SOMQuantizer::SOMQuantizer(const UINT numClusters){
30 
31  this->numClusters = numClusters;
32 
33  classType = "SOMQuantizer";
34  featureExtractionType = classType;
35  debugLog.setProceedingText("[DEBUG SOMQuantizer]");
36  errorLog.setProceedingText("[ERROR SOMQuantizer]");
37  warningLog.setProceedingText("[WARNING SOMQuantizer]");
38 }
39 
41 
42  classType = "SOMQuantizer";
43  featureExtractionType = classType;
44  debugLog.setProceedingText("[DEBUG SOMQuantizer]");
45  errorLog.setProceedingText("[ERROR SOMQuantizer]");
46  warningLog.setProceedingText("[WARNING SOMQuantizer]");
47 
48  //Invoke the equals operator to copy the data from the rhs instance to this instance
49  *this = rhs;
50 }
51 
53  //Here you should add any specific code to cleanup your custom feature extraction module if needed
54 }
55 
57  if(this!=&rhs){
58  //Here you should copy any class variables from the rhs instance to this instance
59  this->numClusters = rhs.numClusters;
60  this->som = rhs.som;
61  this->quantizationDistances = rhs.quantizationDistances;
62 
63  //Copy the base variables
65  }
66  return *this;
67 }
68 
69 bool SOMQuantizer::deepCopyFrom(const FeatureExtraction *featureExtraction){
70 
71  if( featureExtraction == NULL ) return false;
72 
73  if( this->getFeatureExtractionType() == featureExtraction->getFeatureExtractionType() ){
74 
75  //Cast the feature extraction pointer to a pointer to your custom feature extraction module
76  //Then invoke the equals operator
77  *this = *(SOMQuantizer*)featureExtraction;
78 
79  return true;
80  }
81 
82  errorLog << "clone(FeatureExtraction *featureExtraction) - FeatureExtraction Types Do Not Match!" << std::endl;
83 
84  return false;
85 }
86 
87 bool SOMQuantizer::computeFeatures(const VectorFloat &inputVector){
88 
89  //Run the quantize algorithm
90  quantize( inputVector );
91 
92  return true;
93 }
94 
96 
97  //Reset the base class
99 
100  if( trained ){
101  som.reset();
102  std::fill(quantizationDistances.begin(),quantizationDistances.end(),0);
103  }
104 
105  return true;
106 }
107 
109 
110  //Clear the base class
112 
113  som.clear();
114  quantizationDistances.clear();
115 
116  return true;
117 }
118 
119 bool SOMQuantizer::saveModelToFile( std::string filename ) const{
120 
121  std::fstream file;
122  file.open(filename.c_str(), std::ios::out);
123 
124  if( !saveModelToFile( file ) ){
125  return false;
126  }
127 
128  file.close();
129 
130  return true;
131 }
132 
133 bool SOMQuantizer::loadModelFromFile( std::string filename ){
134 
135  std::fstream file;
136  file.open(filename.c_str(), std::ios::in);
137 
138  if( !loadModelFromFile( file ) ){
139  return false;
140  }
141 
142  //Close the file
143  file.close();
144 
145  return true;
146 }
147 
148 bool SOMQuantizer::saveModelToFile( std::fstream &file ) const{
149 
150  if( !file.is_open() ){
151  errorLog << "saveModelToFile(fstream &file) - The file is not open!" << std::endl;
152  return false;
153  }
154 
155  //First, you should add a header (with no spaces) e.g.
156  file << "SOM_QUANTIZER_FILE_V1.0" << std::endl;
157 
158  //Second, you should save the base feature extraction settings to the file
160  errorLog << "saveFeatureExtractionSettingsToFile(fstream &file) - Failed to save base feature extraction settings to file!" << std::endl;
161  return false;
162  }
163 
164  file << "QuantizerTrained: " << trained << std::endl;
165  file << "NumClusters: " << numClusters << std::endl;
166 
167  if( trained ){
168  file << "SOM: \n";
169  if( !som.saveModelToFile( file ) ){
170  errorLog << "saveModelToFile(fstream &file) - Failed to save SelfOrganizingMap settings to file!" << std::endl;
171  return false;
172  }
173  }
174 
175  return true;
176 }
177 
178 bool SOMQuantizer::loadModelFromFile( std::fstream &file ){
179 
180  //Clear any previous model
181  clear();
182 
183  if( !file.is_open() ){
184  errorLog << "loadModelFromFile(fstream &file) - The file is not open!" << std::endl;
185  return false;
186  }
187 
188  std::string word;
189 
190  //First, you should read and validate the header
191  file >> word;
192  if( word != "SOM_QUANTIZER_FILE_V1.0" ){
193  errorLog << "loadModelFromFile(fstream &file) - Invalid file format!" << std::endl;
194  return false;
195  }
196 
197  //Second, you should load the base feature extraction settings to the file
199  errorLog << "loadFeatureExtractionSettingsFromFile(fstream &file) - Failed to load base feature extraction settings from file!" << std::endl;
200  return false;
201  }
202 
203  file >> word;
204  if( word != "QuantizerTrained:" ){
205  errorLog << "loadModelFromFile(fstream &file) - Failed to load QuantizerTrained!" << std::endl;
206  return false;
207  }
208  file >> trained;
209 
210  file >> word;
211  if( word != "NumClusters:" ){
212  errorLog << "loadModelFromFile(fstream &file) - Failed to load NumClusters!" << std::endl;
213  return false;
214  }
215  file >> numClusters;
216 
217  if( trained ){
218  file >> word;
219  if( word != "SOM:" ){
220  errorLog << "loadModelFromFile(fstream &file) - Failed to load SOM!" << std::endl;
221  return false;
222  }
223 
224  if( !som.loadModelFromFile( file ) ){
225  errorLog << "loadModelFromFile(fstream &file) - Failed to load SelfOrganizingMap settings from file!" << std::endl;
226  return false;
227  }
228 
229  initialized = true;
230  featureDataReady = false;
231  quantizationDistances.resize(numClusters,0);
232  }
233 
234  return true;
235 }
236 
238  MatrixFloat data = trainingData.getDataAsMatrixFloat();
239  return train_( data );
240 }
241 
243  MatrixFloat data = trainingData.getDataAsMatrixFloat();
244  return train_( data );
245 }
246 
248  MatrixFloat data = trainingData.getDataAsMatrixFloat();
249  return train_( data );
250 }
251 
253  MatrixFloat data = trainingData.getDataAsMatrixFloat();
254  return train_( data );
255 }
256 
257 bool SOMQuantizer::train_(MatrixFloat &trainingData){
258 
259  //Clear any previous model
260  clear();
261 
262  if( trainingData.getNumRows() == 0 ){
263  errorLog << "train_(MatrixFloat &trainingData) - Failed to train quantizer, the training data is empty!" << std::endl;
264  return false;
265  }
266 
267  //Train the SOM model
268  som.setNetworkSize( numClusters );
269  som.setNetworkTypology( SelfOrganizingMap::RANDOM_NETWORK );
270  som.setAlphaStart( 0.5 );
271  som.setAlphaEnd( 0.1 );
272  som.setMaxNumEpochs( 1000 );
273 
274  if( !som.train_( trainingData ) ){
275  errorLog << "train(MatrixFloat &trainingData) - Failed to train quantizer!" << std::endl;
276  return false;
277  }
278 
279  //Flag that the feature extraction module is now initialized
280  initialized = true;
281  trained = true;
282  numInputDimensions = trainingData.getNumCols();
283  numOutputDimensions = 1; //This is always 1 for the SOMQuantizer
284  featureVector.resize(numOutputDimensions,0);
285  quantizationDistances.resize(numClusters,0);
286 
287  return true;
288 }
289 
290 UINT SOMQuantizer::quantize(const Float inputValue){
291  return quantize( VectorFloat(1,inputValue) );
292 }
293 
294 UINT SOMQuantizer::quantize(const VectorFloat &inputVector){
295 
296  if( !trained ){
297  errorLog << "computeFeatures(const VectorFloat &inputVector) - The quantizer model has not been trained!" << std::endl;
298  return 0;
299  }
300 
301  if( inputVector.getSize() != numInputDimensions ){
302  errorLog << "computeFeatures(const VectorFloat &inputVector) - The size of the inputVector (" << inputVector.getSize() << ") does not match that of the filter (" << numInputDimensions << ")!" << std::endl;
303  return 0;
304  }
305 
306  //Pass the input data through the map
307  if( !som.predict( inputVector ) ){
308  errorLog << "computeFeatures(const VectorFloat &inputVector) - Failed to perform map!" << std::endl;
309  return 0;
310  }
311  quantizationDistances = som.getMappedData();
312 
313  //Search for the neuron with the maximum output
314  UINT quantizedValue = 0;
315  Float maxValue = 0;
316  for(UINT k=0; k<numClusters; k++){
317  if( quantizationDistances[k] > maxValue ){
318  maxValue = quantizationDistances[k];
319  quantizedValue = k;
320  }
321  }
322 
323  featureVector[0] = quantizedValue;
324  featureDataReady = true;
325 
326  return quantizedValue;
327 }
328 
330  return trained;
331 }
332 
334  return numClusters;
335 }
336 
338  return (trained ? static_cast<UINT>(featureVector[0]) : 0);
339 }
340 
342  return quantizationDistances;
343 }
344 
346  return som;
347 }
348 
349 bool SOMQuantizer::setNumClusters(const UINT numClusters){
350  clear();
351  this->numClusters = numClusters;
352  return true;
353 }
354 
355 GRT_END_NAMESPACE
virtual bool saveModelToFile(std::string filename) const
UINT quantize(const Float inputValue)
virtual bool predict(VectorFloat inputVector)
Definition: MLBase.cpp:113
virtual bool train_(ClassificationData &trainingData)
bool setNumClusters(const UINT numClusters)
VectorFloat getQuantizationDistances() const
bool saveFeatureExtractionSettingsToFile(std::fstream &file) const
virtual bool computeFeatures(const VectorFloat &inputVector)
MatrixFloat getDataAsMatrixFloat() const
The SOMQuantizer module quantizes the N-dimensional input vector to a 1-dimensional discrete value...
virtual bool resize(const unsigned int size)
Definition: Vector.h:133
virtual bool train_(MatrixFloat &trainingData)
UINT getSize() const
Definition: Vector.h:191
bool getQuantizerTrained() const
SOMQuantizer(const UINT numClusters=10)
virtual bool deepCopyFrom(const FeatureExtraction *featureExtraction)
std::string getFeatureExtractionType() const
virtual bool reset()
virtual bool clear()
virtual ~SOMQuantizer()
unsigned int getNumRows() const
Definition: Matrix.h:542
MatrixFloat getDataAsMatrixFloat() const
SelfOrganizingMap getSelfOrganizingMap() const
unsigned int getNumCols() const
Definition: Matrix.h:549
virtual bool saveModelToFile(std::fstream &file) const
virtual bool loadModelFromFile(std::fstream &file)
bool loadFeatureExtractionSettingsFromFile(std::fstream &file)
SOMQuantizer & operator=(const SOMQuantizer &rhs)
MatrixFloat getDataAsMatrixFloat() const
virtual bool reset()
bool copyBaseVariables(const FeatureExtraction *featureExtractionModule)
bool setMaxNumEpochs(const UINT maxNumEpochs)
Definition: MLBase.cpp:273
virtual bool loadModelFromFile(std::string filename)
UINT getNumClusters() const
UINT getQuantizedValue() const