21 #define GRT_DLL_EXPORTS
29 AdaBoost::AdaBoost(
const WeakClassifier &weakClassifier,
bool useScaling,
bool useNullRejection,Float nullRejectionCoeff,UINT numBoostingIterations,UINT predictionMethod)
32 this->useScaling = useScaling;
33 this->useNullRejection = useNullRejection;
34 this->nullRejectionCoeff = nullRejectionCoeff;
35 this->numBoostingIterations = numBoostingIterations;
36 this->predictionMethod = predictionMethod;
37 classType =
"AdaBoost";
38 classifierType = classType;
39 classifierMode = STANDARD_CLASSIFIER_MODE;
40 debugLog.setProceedingText(
"[DEBUG AdaBoost]");
41 errorLog.setProceedingText(
"[ERROR AdaBoost]");
42 trainingLog.setProceedingText(
"[TRAINING AdaBoost]");
43 warningLog.setProceedingText(
"[WARNING AdaBoost]");
47 classifierType =
"AdaBoost";
48 classifierMode = STANDARD_CLASSIFIER_MODE;
49 debugLog.setProceedingText(
"[DEBUG AdaBoost]");
50 errorLog.setProceedingText(
"[ERROR AdaBoost]");
51 trainingLog.setProceedingText(
"[TRAINING AdaBoost]");
52 warningLog.setProceedingText(
"[WARNING AdaBoost]");
67 this->numBoostingIterations = rhs.numBoostingIterations;
68 this->predictionMethod = rhs.predictionMethod;
69 this->models = rhs.models;
71 if( rhs.weakClassifiers.size() > 0 ){
72 for(UINT i=0; i<rhs.weakClassifiers.size(); i++){
73 WeakClassifier *weakClassiferPtr = rhs.weakClassifiers[i]->createNewInstance();
74 weakClassifiers.push_back( weakClassiferPtr );
86 if( classifier == NULL ){
87 errorLog <<
"deepCopyFrom(const Classifier *classifier) - The classifier pointer is NULL!" << std::endl;
98 this->numBoostingIterations = ptr->numBoostingIterations;
99 this->predictionMethod = ptr->predictionMethod;
100 this->models = ptr->models;
102 if( ptr->weakClassifiers.size() > 0 ){
103 for(UINT i=0; i<ptr->weakClassifiers.size(); i++){
104 WeakClassifier *weakClassiferPtr = ptr->weakClassifiers[i]->createNewInstance();
105 weakClassifiers.push_back( weakClassiferPtr );
121 errorLog <<
"train_(ClassificationData &trainingData) - There are not enough training samples to train a model! Number of samples: " << trainingData.
getNumSamples() << std::endl;
129 const UINT NEGATIVE_LABEL = WEAK_CLASSIFIER_NEGATIVE_CLASS_LABEL;
131 const Float beta = 0.001;
133 TrainingResult trainingResult;
135 const UINT K = (UINT)weakClassifiers.size();
137 errorLog <<
"train_(ClassificationData &trainingData) - No weakClassifiers have been set. You need to set at least one weak classifier first." << std::endl;
141 classLabels.
resize(numClasses);
142 models.
resize(numClasses);
147 trainingData.
scale(ranges,0,1);
156 for(UINT classIter=0; classIter<numClasses; classIter++){
159 classLabels[classIter] = trainingData.
getClassLabels()[classIter];
162 models[ classIter ].setClassLabel( classLabels[classIter] );
167 for(UINT i=0; i<M; i++){
168 UINT label = trainingData[i].getClassLabel()==classLabels[classIter] ? POSITIVE_LABEL : NEGATIVE_LABEL;
169 VectorFloat trainingSample = trainingData[i].getSample();
170 classData.
addSample(label,trainingSample);
174 std::fill(weights.begin(),weights.end(),1.0/M);
177 bool keepBoosting =
true;
180 while( keepBoosting ){
183 UINT bestClassifierIndex = 0;
185 for(UINT k=0; k<K; k++){
190 if( !weakLearner->
train(classData,weights) ){
191 errorLog <<
"Failed to train weakLearner!" << std::endl;
198 Float numCorrect = 0;
199 Float numIncorrect = 0;
200 for(UINT i=0; i<M; i++){
202 Float prediction = weakLearner->
predict( classData[i].getSample() );
204 if( (prediction == positiveLabel && classData[i].getClassLabel() != POSITIVE_LABEL) ||
205 (prediction != positiveLabel && classData[i].getClassLabel() == POSITIVE_LABEL) ){
207 errorMatrix[k][i] = 1;
210 errorMatrix[k][i] = 0;
215 trainingLog <<
"PositiveClass: " << classLabels[classIter] <<
" Boosting Iter: " << t <<
" Classifier: " << k <<
" WeightedError: " << e <<
" NumCorrect: " << numCorrect/M <<
" NumIncorrect: " <<numIncorrect/M << std::endl;
219 bestClassifierIndex = k;
227 alpha = 0.5 * log( (1.0-epsilon)/epsilon );
229 trainingLog <<
"PositiveClass: " << classLabels[classIter] <<
" Boosting Iter: " << t <<
" Best Classifier Index: " << bestClassifierIndex <<
" MinError: " << minError <<
" Alpha: " << alpha << std::endl;
231 if( grt_isinf(alpha) ){ keepBoosting =
false; trainingLog <<
"Alpha is INF. Stopping boosting for current class" << std::endl; }
232 if( 0.5 - epsilon <= beta ){ keepBoosting =
false; trainingLog <<
"Epsilon <= Beta. Stopping boosting for current class" << std::endl; }
233 if( ++t >= numBoostingIterations ) keepBoosting =
false;
235 trainingResult.setClassificationResult(t, minError,
this);
236 trainingResults.push_back(trainingResult);
237 trainingResultsObserverManager.notifyObservers( trainingResult );
242 models[ classIter ].addClassifierToCommitee( weakClassifiers[bestClassifierIndex], alpha );
245 Float reWeight = (1.0 - epsilon) / epsilon;
248 for(UINT i=0; i<M; i++){
249 oldSum += weights[i];
251 if( errorMatrix[bestClassifierIndex][i] == 1 ) weights[i] *= reWeight;
252 newSum += weights[i];
258 reWeight = oldSum/newSum;
259 for(UINT i=0; i<M; i++){
260 weights[i] *= reWeight;
264 trainingLog <<
"Stopping boosting training at iteration : " << t-1 <<
" with an error of " << epsilon << std::endl;
267 if( grt_isinf(alpha) ){ alpha = 1; }
268 models[ classIter ].addClassifierToCommitee( weakClassifiers[bestClassifierIndex], alpha );
276 for(UINT k=0; k<numClasses; k++){
277 models[k].normalizeWeights();
284 predictedClassLabel = 0;
286 classLikelihoods.
resize(numClasses);
287 classDistances.
resize(numClasses);
294 predictedClassLabel = 0;
295 maxLikelihood = -10000;
298 errorLog <<
"predict_(VectorFloat &inputVector) - AdaBoost Model Not Trained!" << std::endl;
302 if( inputVector.size() != numInputDimensions ){
303 errorLog <<
"predict_(VectorFloat &inputVector) - The size of the input vector (" << inputVector.size() <<
") does not match the num features in the model (" << numInputDimensions << std::endl;
308 for(UINT n=0; n<numInputDimensions; n++){
309 inputVector[n] =
scale(inputVector[n], ranges[n].minValue, ranges[n].maxValue, 0, 1);
313 if( classLikelihoods.size() != numClasses ) classLikelihoods.
resize(numClasses,0);
314 if( classDistances.size() != numClasses ) classDistances.
resize(numClasses,0);
316 UINT bestClassIndex = 0;
317 UINT numPositivePredictions = 0;
321 for(UINT k=0; k<numClasses; k++){
322 Float result = models[k].predict( inputVector );
324 switch ( predictionMethod ) {
325 case MAX_POSITIVE_VALUE:
327 if( result > bestDistance ){
328 bestDistance = result;
331 numPositivePredictions++;
332 classLikelihoods[k] = result;
333 }
else classLikelihoods[k] = 0;
335 classDistances[k] = result;
336 sum += classLikelihoods[k];
340 if( result > bestDistance ){
341 bestDistance = result;
344 if( result < worstDistance ){
345 worstDistance = result;
347 numPositivePredictions++;
348 classLikelihoods[k] = result;
349 classDistances[k] = result;
353 errorLog <<
"predict_(VectorFloat &inputVector) - Unknown prediction method!" << std::endl;
358 if( predictionMethod == MAX_VALUE ){
360 worstDistance = fabs( worstDistance );
361 for(UINT k=0; k<numClasses; k++){
362 classLikelihoods[k] += worstDistance;
363 sum += classLikelihoods[k];
369 for(UINT k=0; k<numClasses; k++)
370 classLikelihoods[k] /= sum;
372 maxLikelihood = classLikelihoods[ bestClassIndex ];
374 if( numPositivePredictions == 0 ){
375 predictedClassLabel = GRT_DEFAULT_NULL_CLASS_LABEL;
376 }
else predictedClassLabel = classLabels[ bestClassIndex ];
392 if( nullRejectionCoeff > 0 ){
393 this->nullRejectionCoeff = nullRejectionCoeff;
404 errorLog <<
"save(fstream &file) - The file is not open!" << std::endl;
409 file<<
"GRT_ADABOOST_MODEL_FILE_V2.0\n";
413 errorLog <<
"save(fstream &file) - Failed to save classifier base settings to file!" << std::endl;
418 file <<
"PredictionMethod: " << predictionMethod << std::endl;
422 file <<
"Models: " << std::endl;
423 for(UINT i=0; i<models.size(); i++){
424 if( !models[i].
save( file ) ){
425 errorLog <<
"save(fstream &file) - Failed to write model " << i <<
" to file!" << std::endl;
441 errorLog <<
"load(string filename) - Could not open file to load model!" << std::endl;
449 if( word ==
"GRT_ADABOOST_MODEL_FILE_V1.0" ){
450 return loadLegacyModelFromFile( file );
453 if( word !=
"GRT_ADABOOST_MODEL_FILE_V2.0" ){
454 errorLog <<
"load(fstream &file) - Failed to read file header!" << std::endl;
455 errorLog << word << std::endl;
461 errorLog <<
"load(string filename) - Failed to load base settings from file!" << std::endl;
466 if( word !=
"PredictionMethod:" ){
467 errorLog <<
"load(fstream &file) - Failed to read PredictionMethod header!" << std::endl;
470 file >> predictionMethod;
474 if( word !=
"Models:" ){
475 errorLog <<
"load(fstream &file) - Failed to read Models header!" << std::endl;
480 models.
resize( numClasses );
481 for(UINT i=0; i<models.size(); i++){
482 if( !models[i].
load( file ) ){
483 errorLog <<
"load(fstream &file) - Failed to load model " << i <<
" from file!" << std::endl;
494 bestDistance = DEFAULT_NULL_DISTANCE_VALUE;
496 classDistances.
resize(numClasses,DEFAULT_NULL_DISTANCE_VALUE);
520 weakClassifiers.push_back( weakClassiferPtr );
528 weakClassifiers.push_back( weakClassiferPtr );
535 for(UINT i=0; i<weakClassifiers.size(); i++){
536 if( weakClassifiers[i] != NULL ){
537 delete weakClassifiers[i];
538 weakClassifiers[i] = NULL;
541 weakClassifiers.clear();
546 if( numBoostingIterations > 0 ){
547 this->numBoostingIterations = numBoostingIterations;
554 if( predictionMethod != MAX_POSITIVE_VALUE && predictionMethod != MAX_VALUE ){
557 this->predictionMethod = predictionMethod;
563 std::cout <<
"AdaBoostModel: \n";
564 std::cout<<
"NumFeatures: " << numInputDimensions << std::endl;
565 std::cout<<
"NumClasses: " << numClasses << std::endl;
566 std::cout <<
"UseScaling: " << useScaling << std::endl;
567 std::cout<<
"UseNullRejection: " << useNullRejection << std::endl;
569 for(UINT k=0; k<numClasses; k++){
570 std::cout <<
"Class: " << k+1 <<
" ClassLabel: " << classLabels[k] << std::endl;
576 bool AdaBoost::loadLegacyModelFromFile( std::fstream &file ){
581 if( word !=
"NumFeatures:" ){
582 errorLog <<
"load(fstream &file) - Failed to read NumFeatures header!" << std::endl;
585 file >> numInputDimensions;
588 if( word !=
"NumClasses:" ){
589 errorLog <<
"load(fstream &file) - Failed to read NumClasses header!" << std::endl;
595 if( word !=
"UseScaling:" ){
596 errorLog <<
"load(fstream &file) - Failed to read UseScaling header!" << std::endl;
602 if( word !=
"UseNullRejection:" ){
603 errorLog <<
"load(fstream &file) - Failed to read UseNullRejection header!" << std::endl;
606 file >> useNullRejection;
610 if( word !=
"Ranges:" ){
611 errorLog <<
"load(fstream &file) - Failed to read Ranges header!" << std::endl;
614 ranges.
resize( numInputDimensions );
616 for(UINT n=0; n<ranges.size(); n++){
617 file >> ranges[n].minValue;
618 file >> ranges[n].maxValue;
623 if( word !=
"Trained:" ){
624 errorLog <<
"load(fstream &file) - Failed to read Trained header!" << std::endl;
630 if( word !=
"PredictionMethod:" ){
631 errorLog <<
"load(fstream &file) - Failed to read PredictionMethod header!" << std::endl;
634 file >> predictionMethod;
638 if( word !=
"Models:" ){
639 errorLog <<
"load(fstream &file) - Failed to read Models header!" << std::endl;
644 models.
resize( numClasses );
645 classLabels.
resize( numClasses );
646 for(UINT i=0; i<models.size(); i++){
647 if( !models[i].
load( file ) ){
648 errorLog <<
"load(fstream &file) - Failed to load model " << i <<
" from file!" << std::endl;
654 classLabels[i] = models[i].getClassLabel();
663 bestDistance = DEFAULT_NULL_DISTANCE_VALUE;
665 classDistances.
resize(numClasses,DEFAULT_NULL_DISTANCE_VALUE);
bool saveBaseSettingsToFile(std::fstream &file) const
bool setPredictionMethod(UINT predictionMethod)
#define DEFAULT_NULL_LIKELIHOOD_VALUE
Float scale(const Float &x, const Float &minSource, const Float &maxSource, const Float &minTarget, const Float &maxTarget, const bool constrain=false)
virtual Float predict(const VectorFloat &x)
virtual bool save(std::fstream &file) const
bool addSample(UINT classLabel, const VectorFloat &sample)
AdaBoost(const WeakClassifier &weakClassifier=DecisionStump(), bool useScaling=false, bool useNullRejection=false, Float nullRejectionCoeff=10.0, UINT numBoostingIterations=20, UINT predictionMethod=MAX_VALUE)
std::string getClassifierType() const
virtual bool resize(const unsigned int size)
bool setNumDimensions(UINT numDimensions)
This class contains the AdaBoost classifier. AdaBoost (Adaptive Boosting) is a powerful classifier th...
Vector< UINT > getClassLabels() const
virtual bool train_(ClassificationData &trainingData)
virtual bool train(ClassificationData &trainingData, VectorFloat &weights)
bool setNumBoostingIterations(UINT numBoostingIterations)
virtual Float getPositiveClassLabel() const
WeakClassifier * createNewInstance() const
UINT getNumSamples() const
#define WEAK_CLASSIFIER_POSITIVE_CLASS_LABEL
virtual bool load(std::fstream &file)
bool addWeakClassifier(const WeakClassifier &weakClassifer)
virtual bool recomputeNullRejectionThresholds()
virtual bool deepCopyFrom(const Classifier *classifier)
virtual bool predict_(VectorFloat &inputVector)
bool clearWeakClassifiers()
bool copyBaseVariables(const Classifier *classifier)
bool loadBaseSettingsFromFile(std::fstream &file)
UINT getNumDimensions() const
UINT getNumClasses() const
bool setWeakClassifier(const WeakClassifier &weakClassifer)
Vector< MinMax > getRanges() const
AdaBoost & operator=(const AdaBoost &rhs)
bool setNullRejectionCoeff(Float nullRejectionCoeff)
bool scale(const Float minTarget, const Float maxTarget)