21 #define GRT_DLL_EXPORTS
29 MinDist::MinDist(
bool useScaling,
bool useNullRejection,Float nullRejectionCoeff,UINT numClusters)
31 this->useScaling = useScaling;
32 this->useNullRejection = useNullRejection;
33 this->nullRejectionCoeff = nullRejectionCoeff;
34 this->numClusters = numClusters;
35 supportsNullRejection =
true;
36 classType =
"MinDist";
37 classifierType = classType;
38 classifierMode = STANDARD_CLASSIFIER_MODE;
39 debugLog.setProceedingText(
"[DEBUG MinDist]");
40 errorLog.setProceedingText(
"[ERROR MinDist]");
41 trainingLog.setProceedingText(
"[TRAINING MinDist]");
42 warningLog.setProceedingText(
"[WARNING MinDist]");
46 classType =
"MinDist";
47 classifierType = classType;
48 classifierMode = STANDARD_CLASSIFIER_MODE;
49 debugLog.setProceedingText(
"[DEBUG MinDist]");
50 errorLog.setProceedingText(
"[ERROR MinDist]");
51 trainingLog.setProceedingText(
"[TRAINING MinDist]");
52 warningLog.setProceedingText(
"[WARNING MinDist]");
63 this->numClusters = rhs.numClusters;
64 this->models = rhs.models;
74 if( classifier == NULL )
return false;
80 this->numClusters = ptr->numClusters;
81 this->models = ptr->models;
100 errorLog <<
"train_(trainingData &labelledTrainingData) - Training data has zero samples!" << std::endl;
104 if( M <= numClusters ){
105 errorLog <<
"train_(trainingData &labelledTrainingData) - There are not enough training samples for the number of clusters. Either reduce the number of clusters or increase the number of training samples!" << std::endl;
109 numInputDimensions = N;
113 nullRejectionThresholds.
resize(K);
119 trainingData.
scale(0, 1);
123 for(UINT k=0; k<numClasses; k++){
125 trainingLog <<
"Training model for class: " << trainingData.
getClassTracker()[k].classLabel << std::endl;
131 classLabels[k] = classLabel;
138 for(UINT i=0; i<data.getNumRows(); i++){
139 for(UINT j=0; j<data.getNumCols(); j++){
140 data[i][j] = classData[i][j];
145 models[k].setGamma( nullRejectionCoeff );
146 if( !models[k].
train(classLabel,data,numClusters,minChange,maxNumEpochs) ){
147 errorLog <<
"train_(ClassificationData &labelledTrainingData) - Failed to train model for class: " << classLabel;
148 errorLog <<
". This is might be because this class does not have enough training samples! You should reduce the number of clusters or increase the number of training samples for this class." << std::endl;
154 nullRejectionThresholds[k] = models[k].getRejectionThreshold();
165 predictedClassLabel = 0;
169 errorLog <<
"predict_(VectorFloat &inputVector) - MinDist Model Not Trained!" << std::endl;
173 if( inputVector.size() != numInputDimensions ){
174 errorLog <<
"predict_(VectorFloat &inputVector) - The size of the input vector (" << inputVector.size() <<
") does not match the num features in the model (" << numInputDimensions << std::endl;
179 for(UINT n=0; n<numInputDimensions; n++){
180 inputVector[n] = grt_scale(inputVector[n], ranges[n].minValue, ranges[n].maxValue, 0.0, 1.0);
184 if( classLikelihoods.size() != numClasses ) classLikelihoods.
resize(numClasses,0);
185 if( classDistances.size() != numClasses ) classDistances.
resize(numClasses,0);
189 for(UINT k=0; k<numClasses; k++){
191 classDistances[k] = models[k].predict( inputVector );
194 if( classDistances[k] < minDist ){
195 minDist = classDistances[k];
196 predictedClassLabel = k;
200 classLikelihoods[k] = 1.0 / (classDistances[k] + 0.0001);
201 sum += classLikelihoods[k];
206 for(UINT k=0; k<numClasses; k++){
207 classLikelihoods[k] /= sum;
209 maxLikelihood = classLikelihoods[predictedClassLabel];
210 }
else maxLikelihood = classLikelihoods[predictedClassLabel];
212 if( useNullRejection ){
214 if( minDist <= models[predictedClassLabel].getRejectionThreshold() ) predictedClassLabel = models[predictedClassLabel].getClassLabel();
215 else predictedClassLabel = GRT_DEFAULT_NULL_CLASS_LABEL;
216 }
else predictedClassLabel = models[predictedClassLabel].getClassLabel();
235 for(UINT k=0; k<numClasses; k++) {
236 models[k].setGamma( nullRejectionCoeff );
237 models[k].recomputeThresholdValue();
246 if( nullRejectionCoeff > 0 ){
247 this->nullRejectionCoeff = nullRejectionCoeff;
266 errorLog <<
"save(fstream &file) - The file is not open!" << std::endl;
271 file<<
"GRT_MINDIST_MODEL_FILE_V2.0\n";
275 errorLog <<
"save(fstream &file) - Failed to save classifier base settings to file!" << std::endl;
282 for(UINT k=0; k<numClasses; k++){
283 file <<
"ClassLabel: " << models[k].getClassLabel() << std::endl;
284 file <<
"NumClusters: " << models[k].getNumClusters() << std::endl;
285 file <<
"RejectionThreshold: " << models[k].getRejectionThreshold() << std::endl;
286 file <<
"Gamma: " << models[k].getGamma() << std::endl;
287 file <<
"TrainingMu: " << models[k].getTrainingMu() << std::endl;
288 file <<
"TrainingSigma: " << models[k].getTrainingSigma() << std::endl;
289 file <<
"ClusterData:" << std::endl;
291 for(UINT i=0; i<models[k].getNumClusters(); i++){
292 for(UINT j=0; j<models[k].getNumFeatures(); j++){
293 file << clusters[i][j] <<
"\t";
310 errorLog <<
"load(string filename) - Could not open file to load model" << std::endl;
320 if( word ==
"GRT_MINDIST_MODEL_FILE_V1.0" ){
325 if(word !=
"GRT_MINDIST_MODEL_FILE_V2.0"){
326 errorLog <<
"load(string filename) - Could not find Model File Header" << std::endl;
332 errorLog <<
"load(string filename) - Failed to load base settings from file!" << std::endl;
339 models.
resize(numClasses);
340 classLabels.
resize(numClasses);
343 for(UINT k=0; k<numClasses; k++){
344 Float rejectionThreshold;
350 if( word !=
"ClassLabel:" ){
351 errorLog <<
"load(string filename) - Could not load the class label for class " << k << std::endl;
354 file >> classLabels[k];
357 if( word !=
"NumClusters:" ){
358 errorLog <<
"load(string filename) - Could not load the NumClusters for class " << k << std::endl;
364 if( word !=
"RejectionThreshold:" ){
365 errorLog <<
"load(string filename) - Could not load the RejectionThreshold for class " << k << std::endl;
368 file >> rejectionThreshold;
371 if( word !=
"Gamma:" ){
372 errorLog <<
"load(string filename) - Could not load the Gamma for class " << k << std::endl;
378 if( word !=
"TrainingMu:" ){
379 errorLog <<
"load(string filename) - Could not load the TrainingMu for class " << k << std::endl;
385 if( word !=
"TrainingSigma:" ){
386 errorLog <<
"load(string filename) - Could not load the TrainingSigma for class " << k << std::endl;
389 file >> trainingSigma;
392 if( word !=
"ClusterData:" ){
393 errorLog <<
"load(string filename) - Could not load the ClusterData for class " << k << std::endl;
398 MatrixFloat clusters(numClusters,numInputDimensions);
399 for(UINT i=0; i<numClusters; i++){
400 for(UINT j=0; j<numInputDimensions; j++){
401 file >> clusters[i][j];
405 models[k].setClassLabel( classLabels[k] );
406 models[k].setClusters( clusters );
407 models[k].setGamma( gamma );
408 models[k].setRejectionThreshold( rejectionThreshold );
409 models[k].setTrainingSigma( trainingSigma );
410 models[k].setTrainingMu( trainingMu );
418 bestDistance = DEFAULT_NULL_DISTANCE_VALUE;
420 classDistances.
resize(numClasses,DEFAULT_NULL_DISTANCE_VALUE);
427 if( numClusters > 0 ){
428 this->numClusters = numClusters;
439 if(word !=
"NumFeatures:"){
440 errorLog <<
"load(string filename) - Could not find NumFeatures " << std::endl;
443 file >> numInputDimensions;
446 if(word !=
"NumClasses:"){
447 errorLog <<
"load(string filename) - Could not find NumClasses" << std::endl;
453 if(word !=
"UseScaling:"){
454 errorLog <<
"load(string filename) - Could not find UseScaling" << std::endl;
460 if(word !=
"UseNullRejection:"){
461 errorLog <<
"load(string filename) - Could not find UseNullRejection" << std::endl;
464 file >> useNullRejection;
469 ranges.
resize(numInputDimensions);
472 if(word !=
"Ranges:"){
473 errorLog <<
"load(string filename) - Could not find the Ranges" << std::endl;
476 for(UINT n=0; n<ranges.size(); n++){
477 file >> ranges[n].minValue;
478 file >> ranges[n].maxValue;
483 models.
resize(numClasses);
484 classLabels.
resize(numClasses);
487 for(UINT k=0; k<numClasses; k++){
488 Float rejectionThreshold;
494 if( word !=
"ClassLabel:" ){
495 errorLog <<
"load(string filename) - Could not load the class label for class " << k << std::endl;
498 file >> classLabels[k];
501 if( word !=
"NumClusters:" ){
502 errorLog <<
"load(string filename) - Could not load the NumClusters for class " << k << std::endl;
508 if( word !=
"RejectionThreshold:" ){
509 errorLog <<
"load(string filename) - Could not load the RejectionThreshold for class " << k << std::endl;
512 file >> rejectionThreshold;
515 if( word !=
"Gamma:" ){
516 errorLog <<
"load(string filename) - Could not load the Gamma for class " << k << std::endl;
522 if( word !=
"TrainingMu:" ){
523 errorLog <<
"load(string filename) - Could not load the TrainingMu for class " << k << std::endl;
529 if( word !=
"TrainingSigma:" ){
530 errorLog <<
"load(string filename) - Could not load the TrainingSigma for class " << k << std::endl;
533 file >> trainingSigma;
536 if( word !=
"ClusterData:" ){
537 errorLog <<
"load(string filename) - Could not load the ClusterData for class " << k << std::endl;
542 MatrixFloat clusters(numClusters,numInputDimensions);
543 for(UINT i=0; i<numClusters; i++){
544 for(UINT j=0; j<numInputDimensions; j++){
545 file >> clusters[i][j];
549 models[k].setClassLabel( classLabels[k] );
550 models[k].setClusters( clusters );
551 models[k].setGamma( gamma );
552 models[k].setRejectionThreshold( rejectionThreshold );
553 models[k].setTrainingSigma( trainingSigma );
554 models[k].setTrainingMu( trainingMu );
562 bestDistance = DEFAULT_NULL_DISTANCE_VALUE;
564 classDistances.
resize(numClasses,DEFAULT_NULL_DISTANCE_VALUE);
bool saveBaseSettingsToFile(std::fstream &file) const
virtual bool deepCopyFrom(const Classifier *classifier)
#define DEFAULT_NULL_LIKELIHOOD_VALUE
Vector< MinDistModel > getModels() const
MinDist & operator=(const MinDist &rhs)
std::string getClassifierType() const
Vector< ClassTracker > getClassTracker() const
ClassificationData getClassData(const UINT classLabel) const
virtual bool resize(const unsigned int size)
virtual bool train(ClassificationData trainingData)
virtual bool predict_(VectorFloat &inputVector)
virtual bool save(std::fstream &file) const
UINT getNumSamples() const
virtual bool load(std::fstream &file)
bool copyBaseVariables(const Classifier *classifier)
bool loadBaseSettingsFromFile(std::fstream &file)
UINT getNumDimensions() const
UINT getNumClasses() const
virtual bool recomputeNullRejectionThresholds()
bool loadLegacyModelFromFile(std::fstream &file)
Vector< MinMax > getRanges() const
virtual bool train_(ClassificationData &trainingData)
bool scale(const Float minTarget, const Float maxTarget)
This class implements the MinDist classifier algorithm.
MinDist(bool useScaling=false, bool useNullRejection=false, Float nullRejectionCoeff=10.0, UINT numClusters=10)
virtual bool setNullRejectionCoeff(Float nullRejectionCoeff)
UINT getNumClusters() const
bool setNumClusters(UINT numClusters)