28 GMM::GMM(UINT numMixtureModels,
bool useScaling,
bool useNullRejection,Float nullRejectionCoeff,UINT maxIter,Float minChange){
30 classifierType = classType;
31 classifierMode = STANDARD_CLASSIFIER_MODE;
32 debugLog.setProceedingText(
"[DEBUG GMM]");
33 errorLog.setProceedingText(
"[ERROR GMM]");
34 warningLog.setProceedingText(
"[WARNING GMM]");
36 this->numMixtureModels = numMixtureModels;
37 this->useScaling = useScaling;
38 this->useNullRejection = useNullRejection;
39 this->nullRejectionCoeff = nullRejectionCoeff;
40 this->maxIter = maxIter;
41 this->minChange = minChange;
46 classifierType = classType;
47 classifierMode = STANDARD_CLASSIFIER_MODE;
48 debugLog.setProceedingText(
"[DEBUG GMM]");
49 errorLog.setProceedingText(
"[ERROR GMM]");
50 warningLog.setProceedingText(
"[WARNING GMM]");
59 this->numMixtureModels = rhs.numMixtureModels;
60 this->maxIter = rhs.maxIter;
61 this->minChange = rhs.minChange;
62 this->models = rhs.models;
64 this->debugLog = rhs.debugLog;
65 this->errorLog = rhs.errorLog;
66 this->warningLog = rhs.warningLog;
76 if( classifier == NULL )
return false;
80 GMM *ptr = (
GMM*)classifier;
82 this->numMixtureModels = ptr->numMixtureModels;
83 this->maxIter = ptr->maxIter;
84 this->minChange = ptr->minChange;
85 this->models = ptr->models;
87 this->debugLog = ptr->debugLog;
88 this->errorLog = ptr->errorLog;
89 this->warningLog = ptr->warningLog;
99 predictedClassLabel = 0;
101 if( classDistances.
getSize() != numClasses || classLikelihoods.
getSize() != numClasses ){
102 classDistances.
resize(numClasses);
103 classLikelihoods.
resize(numClasses);
107 errorLog <<
"predict_(VectorFloat &x) - Mixture Models have not been trained!" << std::endl;
111 if( x.
getSize() != numInputDimensions ){
112 errorLog <<
"predict_(VectorFloat &x) - The size of the input vector (" << x.
getSize() <<
") does not match that of the number of features the model was trained with (" << numInputDimensions <<
")." << std::endl;
117 for(UINT i=0; i<numInputDimensions; i++){
118 x[i] = grt_scale(x[i], ranges[i].minValue, ranges[i].maxValue,
GMM_MIN_SCALE_VALUE, GMM_MAX_SCALE_VALUE);
126 for(UINT k=0; k<numClasses; k++){
127 classDistances[k] = computeMixtureLikelihood(x,k);
130 classLikelihoods[k] = classDistances[k];
131 sum += classLikelihoods[k];
132 if( classLikelihoods[k] > bestDistance ){
133 bestDistance = classLikelihoods[k];
139 for(
unsigned int k=0; k<numClasses; k++){
140 classLikelihoods[k] /= sum;
142 maxLikelihood = classLikelihoods[bestIndex];
144 if( useNullRejection ){
150 if( classDistances[bestIndex] >= models[bestIndex].getNullRejectionThreshold() ){
151 predictedClassLabel = models[bestIndex].getClassLabel();
152 }
else predictedClassLabel = GRT_DEFAULT_NULL_CLASS_LABEL;
155 predictedClassLabel = models[bestIndex].getClassLabel();
167 errorLog <<
"train_(ClassificationData &trainingData) - Training data is empty!" << std::endl;
174 models.
resize(numClasses);
176 if( numInputDimensions >= 6 ){
177 warningLog <<
"train_(ClassificationData &trainingData) - The number of features in your training data is high (" << numInputDimensions <<
"). The GMMClassifier does not work well with high dimensional data, you might get better results from one of the other classifiers." << std::endl;
183 errorLog <<
"train_(ClassificationData &trainingData) - Failed to scale training data!" << std::endl;
188 for(UINT k=0; k<numClasses; k++){
199 errorLog <<
"train_(ClassificationData &trainingData) - Failed to train Mixture Model for class " << classLabel << std::endl;
204 models[k].
resize( numMixtureModels );
205 models[k].setClassLabel( classLabel );
208 for(UINT j=0; j<numMixtureModels; j++){
210 models[k][j].sigma = gaussianMixtureModel.
getSigma()[j];
214 if( !ludcmp.inverse( models[k][j].invSigma ) ){
216 errorLog <<
"train_(ClassificationData &trainingData) - Failed to invert Matrix for class " << classLabel <<
"!" << std::endl;
219 models[k][j].det = ludcmp.det();
223 models[k].recomputeNormalizationFactor();
231 predictionResults[i] = models[k].computeMixtureLikelihood( sample );
232 mu += predictionResults[i];
240 sigma += grt_sqr( (predictionResults[i]-mu) );
241 sigma = grt_sqrt( sigma / (Float(classData.
getNumSamples())-1.0) );
245 models[k].setTrainingMuAndSigma(mu,sigma);
247 if( !models[k].recomputeNullRejectionThreshold(nullRejectionCoeff) && useNullRejection ){
248 warningLog <<
"train_(ClassificationData &trainingData) - Failed to recompute rejection threshold for class " << classLabel <<
" - the nullRjectionCoeff value is too high!" << std::endl;
256 classLabels.
resize(numClasses);
257 for(UINT k=0; k<numClasses; k++){
258 classLabels[k] = models[k].getClassLabel();
262 nullRejectionThresholds.
resize(numClasses);
263 for(UINT k=0; k<numClasses; k++){
264 nullRejectionThresholds[k] = models[k].getNullRejectionThreshold();
273 Float GMM::computeMixtureLikelihood(
const VectorFloat &x,
const UINT k){
274 if( k >= numClasses ){
275 errorLog <<
"computeMixtureLikelihood(const VectorFloat x,const UINT k) - Invalid k value!" << std::endl;
278 return models[k].computeMixtureLikelihood( x );
284 errorLog <<
"saveGMMToFile(fstream &file) - The model has not been trained!" << std::endl;
288 if( !file.is_open() )
290 errorLog <<
"saveGMMToFile(fstream &file) - The file has not been opened!" << std::endl;
295 file <<
"GRT_GMM_MODEL_FILE_V2.0\n";
299 errorLog <<
"saveModelToFile(fstream &file) - Failed to save classifier base settings to file!" << std::endl;
303 file <<
"NumMixtureModels: " << numMixtureModels << std::endl;
308 for(UINT k=0; k<numClasses; k++){
309 file <<
"ClassLabel: " << models[k].getClassLabel() << std::endl;
310 file <<
"K: " << models[k].getK() << std::endl;
311 file <<
"NormalizationFactor: " << models[k].getNormalizationFactor() << std::endl;
312 file <<
"TrainingMu: " << models[k].getTrainingMu() << std::endl;
313 file <<
"TrainingSigma: " << models[k].getTrainingSigma() << std::endl;
314 file <<
"NullRejectionThreshold: " << models[k].getNullRejectionThreshold() << std::endl;
316 for(UINT index=0; index<models[k].getK(); index++){
317 file <<
"Determinant: " << models[k][index].det << std::endl;
320 for(UINT j=0; j<models[k][index].mu.size(); j++) file <<
"\t" << models[k][index].mu[j];
324 for(UINT i=0; i<models[k][index].sigma.getNumRows(); i++){
325 for(UINT j=0; j<models[k][index].sigma.getNumCols(); j++){
326 file << models[k][index].sigma[i][j];
327 if( j < models[k][index].sigma.getNumCols()-1 ) file <<
"\t";
332 file <<
"InvSigma:\n";
333 for(UINT i=0; i<models[k][index].invSigma.getNumRows(); i++){
334 for(UINT j=0; j<models[k][index].invSigma.getNumCols(); j++){
335 file << models[k][index].invSigma[i][j];
336 if( j < models[k][index].invSigma.getNumCols()-1 ) file <<
"\t";
352 numInputDimensions = 0;
359 errorLog <<
"loadModelFromFile(fstream &file) - Could not open file to load model" << std::endl;
367 if( word ==
"GRT_GMM_MODEL_FILE_V1.0" ){
372 if(word !=
"GRT_GMM_MODEL_FILE_V2.0"){
373 errorLog <<
"loadModelFromFile(fstream &file) - Could not find Model File Header" << std::endl;
379 errorLog <<
"loadModelFromFile(string filename) - Failed to load base settings from file!" << std::endl;
384 if(word !=
"NumMixtureModels:"){
385 errorLog <<
"loadModelFromFile(fstream &file) - Could not find NumMixtureModels" << std::endl;
388 file >> numMixtureModels;
394 if(word !=
"Models:"){
395 errorLog <<
"loadModelFromFile(fstream &file) - Could not find the Models Header" << std::endl;
400 models.
resize(numClasses);
401 classLabels.
resize(numClasses);
404 for(UINT k=0; k<numClasses; k++){
407 Float normalizationFactor;
410 Float rejectionThreshold;
413 if(word !=
"ClassLabel:"){
414 errorLog <<
"loadModelFromFile(fstream &file) - Could not find the ClassLabel for model " << k+1 << std::endl;
418 models[k].setClassLabel( classLabel );
419 classLabels[k] = classLabel;
423 errorLog <<
"loadModelFromFile(fstream &file) - Could not find K for model " << k+1 << std::endl;
429 if(word !=
"NormalizationFactor:"){
430 errorLog <<
"loadModelFromFile(fstream &file) - Could not find NormalizationFactor for model " << k+1 << std::endl;
433 file >> normalizationFactor;
434 models[k].setNormalizationFactor(normalizationFactor);
437 if(word !=
"TrainingMu:"){
438 errorLog <<
"loadModelFromFile(fstream &file) - Could not find TrainingMu for model " << k+1 << std::endl;
444 if(word !=
"TrainingSigma:"){
445 errorLog <<
"loadModelFromFile(fstream &file) - Could not find TrainingSigma for model " << k+1 << std::endl;
448 file >> trainingSigma;
451 models[k].setTrainingMuAndSigma(trainingMu, trainingSigma);
454 if(word !=
"NullRejectionThreshold:"){
455 errorLog <<
"loadModelFromFile(fstream &file) - Could not find NullRejectionThreshold for model " << k+1 << std::endl;
458 file >>rejectionThreshold;
461 models[k].setNullRejectionThreshold(rejectionThreshold);
467 for(UINT index=0; index<models[k].getK(); index++){
470 models[k][index].mu.
resize( numInputDimensions );
471 models[k][index].sigma.
resize( numInputDimensions, numInputDimensions );
472 models[k][index].invSigma.
resize( numInputDimensions, numInputDimensions );
475 if(word !=
"Determinant:"){
476 errorLog <<
"loadModelFromFile(fstream &file) - Could not find the Determinant for model " << k+1 << std::endl;
479 file >> models[k][index].det;
484 errorLog <<
"loadModelFromFile(fstream &file) - Could not find Mu for model " << k+1 << std::endl;
487 for(UINT j=0; j<models[k][index].mu.size(); j++){
488 file >> models[k][index].mu[j];
493 if(word !=
"Sigma:"){
494 errorLog <<
"loadModelFromFile(fstream &file) - Could not find Sigma for model " << k+1 << std::endl;
497 for(UINT i=0; i<models[k][index].sigma.getNumRows(); i++){
498 for(UINT j=0; j<models[k][index].sigma.getNumCols(); j++){
499 file >> models[k][index].sigma[i][j];
504 if(word !=
"InvSigma:"){
505 errorLog <<
"loadModelFromFile(fstream &file) - Could not find InvSigma for model " << k+1 << std::endl;
508 for(UINT i=0; i<models[k][index].invSigma.getNumRows(); i++){
509 for(UINT j=0; j<models[k][index].invSigma.getNumCols(); j++){
510 file >> models[k][index].invSigma[i][j];
519 nullRejectionThresholds.
resize(numClasses);
520 for(UINT k=0; k<numClasses; k++) {
521 models[k].recomputeNullRejectionThreshold(nullRejectionCoeff);
522 nullRejectionThresholds[k] = models[k].getNullRejectionThreshold();
526 bestDistance = DEFAULT_NULL_DISTANCE_VALUE;
528 classDistances.
resize(numClasses,DEFAULT_NULL_DISTANCE_VALUE);
548 for(UINT k=0; k<numClasses; k++) {
549 models[k].recomputeNullRejectionThreshold(nullRejectionCoeff);
550 nullRejectionThresholds[k] = models[k].getNullRejectionThreshold();
558 return numMixtureModels;
562 if( trained ){
return models; }
568 numMixtureModels = K;
575 this->minChange = minChange;
582 this->maxIter = maxIter;
593 if(word !=
"NumFeatures:"){
594 errorLog <<
"loadModelFromFile(fstream &file) - Could not find NumFeatures " << std::endl;
597 file >> numInputDimensions;
600 if(word !=
"NumClasses:"){
601 errorLog <<
"loadModelFromFile(fstream &file) - Could not find NumClasses" << std::endl;
607 if(word !=
"NumMixtureModels:"){
608 errorLog <<
"loadModelFromFile(fstream &file) - Could not find NumMixtureModels" << std::endl;
611 file >> numMixtureModels;
614 if(word !=
"MaxIter:"){
615 errorLog <<
"loadModelFromFile(fstream &file) - Could not find MaxIter" << std::endl;
621 if(word !=
"MinChange:"){
622 errorLog <<
"loadModelFromFile(fstream &file) - Could not find MinChange" << std::endl;
628 if(word !=
"UseScaling:"){
629 errorLog <<
"loadModelFromFile(fstream &file) - Could not find UseScaling" << std::endl;
635 if(word !=
"UseNullRejection:"){
636 errorLog <<
"loadModelFromFile(fstream &file) - Could not find UseNullRejection" << std::endl;
639 file >> useNullRejection;
642 if(word !=
"NullRejectionCoeff:"){
643 errorLog <<
"loadModelFromFile(fstream &file) - Could not find NullRejectionCoeff" << std::endl;
646 file >> nullRejectionCoeff;
651 ranges.
resize(numInputDimensions);
654 if(word !=
"Ranges:"){
655 errorLog <<
"loadModelFromFile(fstream &file) - Could not find the Ranges" << std::endl;
658 for(UINT n=0; n<ranges.size(); n++){
659 file >> ranges[n].minValue;
660 file >> ranges[n].maxValue;
666 if(word !=
"Models:"){
667 errorLog <<
"loadModelFromFile(fstream &file) - Could not find the Models Header" << std::endl;
672 models.
resize(numClasses);
673 classLabels.
resize(numClasses);
676 for(UINT k=0; k<numClasses; k++){
679 Float normalizationFactor;
682 Float rejectionThreshold;
685 if(word !=
"ClassLabel:"){
686 errorLog <<
"loadModelFromFile(fstream &file) - Could not find the ClassLabel for model " << k+1 << std::endl;
690 models[k].setClassLabel( classLabel );
691 classLabels[k] = classLabel;
695 errorLog <<
"loadModelFromFile(fstream &file) - Could not find K for model " << k+1 << std::endl;
701 if(word !=
"NormalizationFactor:"){
702 errorLog <<
"loadModelFromFile(fstream &file) - Could not find NormalizationFactor for model " << k+1 << std::endl;
705 file >> normalizationFactor;
706 models[k].setNormalizationFactor(normalizationFactor);
709 if(word !=
"TrainingMu:"){
710 errorLog <<
"loadModelFromFile(fstream &file) - Could not find TrainingMu for model " << k+1 << std::endl;
716 if(word !=
"TrainingSigma:"){
717 errorLog <<
"loadModelFromFile(fstream &file) - Could not find TrainingSigma for model " << k+1 << std::endl;
720 file >> trainingSigma;
723 models[k].setTrainingMuAndSigma(trainingMu, trainingSigma);
726 if(word !=
"NullRejectionThreshold:"){
727 errorLog <<
"loadModelFromFile(fstream &file) - Could not find NullRejectionThreshold for model " << k+1 << std::endl;
730 file >>rejectionThreshold;
733 models[k].setNullRejectionThreshold(rejectionThreshold);
739 for(UINT index=0; index<models[k].getK(); index++){
742 models[k][index].mu.
resize( numInputDimensions );
743 models[k][index].sigma.
resize( numInputDimensions, numInputDimensions );
744 models[k][index].invSigma.
resize( numInputDimensions, numInputDimensions );
747 if(word !=
"Determinant:"){
748 errorLog <<
"loadModelFromFile(fstream &file) - Could not find the Determinant for model " << k+1 << std::endl;
751 file >> models[k][index].det;
756 errorLog <<
"loadModelFromFile(fstream &file) - Could not find Mu for model " << k+1 << std::endl;
759 for(UINT j=0; j<models[k][index].mu.size(); j++){
760 file >> models[k][index].mu[j];
765 if(word !=
"Sigma:"){
766 errorLog <<
"loadModelFromFile(fstream &file) - Could not find Sigma for model " << k+1 << std::endl;
769 for(UINT i=0; i<models[k][index].sigma.getNumRows(); i++){
770 for(UINT j=0; j<models[k][index].sigma.getNumCols(); j++){
771 file >> models[k][index].sigma[i][j];
776 if(word !=
"InvSigma:"){
777 errorLog <<
"loadModelFromFile(fstream &file) - Could not find InvSigma for model " << k+1 << std::endl;
780 for(UINT i=0; i<models[k][index].invSigma.getNumRows(); i++){
781 for(UINT j=0; j<models[k][index].invSigma.getNumCols(); j++){
782 file >> models[k][index].invSigma[i][j];
791 nullRejectionThresholds.
resize(numClasses);
792 for(UINT k=0; k<numClasses; k++) {
793 models[k].recomputeNullRejectionThreshold(nullRejectionCoeff);
794 nullRejectionThresholds[k] = models[k].getNullRejectionThreshold();
bool saveBaseSettingsToFile(std::fstream &file) const
#define DEFAULT_NULL_LIKELIHOOD_VALUE
virtual bool train_(ClassificationData &trainingData)
virtual bool loadModelFromFile(std::fstream &file)
std::string getClassifierType() const
Vector< ClassTracker > getClassTracker() const
virtual bool recomputeNullRejectionThresholds()
ClassificationData getClassData(const UINT classLabel) const
virtual bool resize(const unsigned int size)
virtual bool train(ClassificationData trainingData)
#define GMM_MIN_SCALE_VALUE
Vector< MixtureModel > getModels()
bool setMinChange(const Float minChange)
bool setNumMixtureModels(UINT K)
unsigned int getSize() const
virtual bool saveModelToFile(std::fstream &file) const
MatrixFloat getMu() const
This class implements the Gaussian Mixture Model Classifier algorithm. The Gaussian Mixture Model Cla...
UINT getNumSamples() const
virtual bool predict_(VectorFloat &inputVector)
GMM(UINT numMixtureModels=2, bool useScaling=false, bool useNullRejection=false, Float nullRejectionCoeff=1.0, UINT maxIter=100, Float minChange=1.0e-5)
Vector< T > getRowVector(const unsigned int r) const
UINT getNumMixtureModels()
bool copyBaseVariables(const Classifier *classifier)
bool loadBaseSettingsFromFile(std::fstream &file)
UINT getNumDimensions() const
UINT getNumClasses() const
Vector< MatrixFloat > getSigma() const
GMM & operator=(const GMM &rhs)
bool loadLegacyModelFromFile(std::fstream &file)
Vector< MinMax > getRanges() const
MatrixFloat getDataAsMatrixFloat() const
virtual bool deepCopyFrom(const Classifier *classifier)
bool setMaxNumEpochs(const UINT maxNumEpochs)
bool scale(const Float minTarget, const Float maxTarget)
bool setMinChange(Float minChange)
bool setNumClusters(const UINT numClusters)
bool setMaxIter(UINT maxIter)