21 #define GRT_DLL_EXPORTS 27 const std::string AdaBoost::id =
"AdaBoost";
36 this->useScaling = useScaling;
37 this->useNullRejection = useNullRejection;
38 this->nullRejectionCoeff = nullRejectionCoeff;
39 this->numBoostingIterations = numBoostingIterations;
40 this->predictionMethod = predictionMethod;
41 classifierMode = STANDARD_CLASSIFIER_MODE;
46 classifierMode = STANDARD_CLASSIFIER_MODE;
61 this->numBoostingIterations = rhs.numBoostingIterations;
62 this->predictionMethod = rhs.predictionMethod;
63 this->models = rhs.models;
65 if( rhs.weakClassifiers.
getSize() > 0 ){
66 this->weakClassifiers.reserve( rhs.weakClassifiers.
getSize() );
67 for(UINT i=0; i<rhs.weakClassifiers.
getSize(); i++){
68 WeakClassifier *weakClassiferPtr = rhs.weakClassifiers[i]->createNewInstance();
69 weakClassifiers.push_back( weakClassiferPtr );
81 if( classifier == NULL ){
82 errorLog <<
"deepCopyFrom(const Classifier *classifier) - The classifier pointer is NULL!" << std::endl;
93 this->numBoostingIterations = ptr->numBoostingIterations;
94 this->predictionMethod = ptr->predictionMethod;
95 this->models = ptr->models;
97 if( ptr->weakClassifiers.size() > 0 ){
98 this->weakClassifiers.
resize( ptr->weakClassifiers.
getSize() );
99 for(UINT i=0; i<ptr->weakClassifiers.
getSize(); i++){
100 weakClassifiers[i] = ptr->weakClassifiers[i]->createNewInstance();
116 errorLog <<
"train_(ClassificationData &trainingData) - There are not enough training samples to train a model! Number of samples: " << trainingData.
getNumSamples() << std::endl;
124 const UINT NEGATIVE_LABEL = WEAK_CLASSIFIER_NEGATIVE_CLASS_LABEL;
126 const Float beta = 0.001;
131 const UINT K = weakClassifiers.
getSize();
133 errorLog <<
"train_(ClassificationData &trainingData) - No weakClassifiers have been set. You need to set at least one weak classifier first." << std::endl;
138 for(UINT k=0; k<K; k++){
142 classLabels.
resize(numClasses);
143 models.
resize(numClasses);
148 trainingData.
scale(ranges,0,1);
151 if( useValidationSet ){
152 validationData = trainingData.
split( 100-validationSetSize );
156 trainingLog <<
"Training AdaBoost model, num training examples: " << M <<
", num validation examples: " << validationData.
getNumSamples() <<
", num classes: " << numClasses <<
", num weak learners: " << K << std::endl;
164 for(UINT classIter=0; classIter<numClasses; classIter++){
167 classLabels[classIter] = trainingData.
getClassLabels()[classIter];
170 models[ classIter ].setClassLabel( classLabels[classIter] );
175 for(UINT i=0; i<M; i++){
176 UINT label = trainingData[i].getClassLabel()==classLabels[classIter] ? POSITIVE_LABEL : NEGATIVE_LABEL;
177 VectorFloat trainingSample = trainingData[i].getSample();
178 classData.
addSample(label,trainingSample);
182 std::fill(weights.begin(),weights.end(),1.0/M);
185 bool keepBoosting =
true;
188 while( keepBoosting ){
191 UINT bestClassifierIndex = 0;
193 for(UINT k=0; k<K; k++){
198 if( !weakLearner->
train(classData,weights) ){
199 errorLog << __GRT_LOG__ <<
" Failed to train weakLearner!" << std::endl;
206 Float numCorrect = 0;
207 Float numIncorrect = 0;
208 for(UINT i=0; i<M; i++){
210 Float prediction = weakLearner->
predict( classData[i].getSample() );
212 if( (prediction == positiveLabel && classData[i].getClassLabel() != POSITIVE_LABEL) ||
213 (prediction != positiveLabel && classData[i].getClassLabel() == POSITIVE_LABEL) ){
215 errorMatrix[k][i] = 1;
218 errorMatrix[k][i] = 0;
223 trainingLog <<
"PositiveClass: " << classLabels[classIter] <<
" Boosting Iter: " << t <<
" Classifier: " << k <<
" WeightedError: " << e <<
" NumCorrect: " << numCorrect/M <<
" NumIncorrect: " <<numIncorrect/M << std::endl;
227 bestClassifierIndex = k;
235 alpha = 0.5 * log( (1.0-epsilon)/epsilon );
237 trainingLog <<
"PositiveClass: " << classLabels[classIter] <<
" Boosting Iter: " << t <<
" Best Classifier Index: " << bestClassifierIndex <<
" MinError: " << minError <<
" Alpha: " << alpha << std::endl;
239 if( grt_isinf(alpha) ){ keepBoosting =
false; trainingLog <<
"Alpha is INF. Stopping boosting for current class" << std::endl; }
240 if( 0.5 - epsilon <= beta ){ keepBoosting =
false; trainingLog <<
"Epsilon <= Beta. Stopping boosting for current class" << std::endl; }
241 if( ++t >= numBoostingIterations ) keepBoosting =
false;
244 trainingResults.push_back(trainingResult);
245 trainingResultsObserverManager.notifyObservers( trainingResult );
250 models[ classIter ].addClassifierToCommitee( weakClassifiers[bestClassifierIndex], alpha );
253 Float reWeight = (1.0 - epsilon) / epsilon;
256 for(UINT i=0; i<M; i++){
257 oldSum += weights[i];
259 if( errorMatrix[bestClassifierIndex][i] == 1 ) weights[i] *= reWeight;
260 newSum += weights[i];
266 reWeight = oldSum/newSum;
267 for(UINT i=0; i<M; i++){
268 weights[i] *= reWeight;
272 trainingLog <<
"Stopping boosting training at iteration : " << t-1 <<
" with an error of " << epsilon << std::endl;
275 if( grt_isinf(alpha) ){ alpha = 1; }
276 models[ classIter ].addClassifierToCommitee( weakClassifiers[bestClassifierIndex], alpha );
284 for(UINT k=0; k<numClasses; k++){
285 models[k].normalizeWeights();
293 predictedClassLabel = 0;
295 classLikelihoods.
resize(numClasses);
296 classDistances.
resize(numClasses);
299 trainingSetAccuracy = 0;
300 validationSetAccuracy = 0;
303 bool scalingState = useScaling;
305 for(UINT i=0; i<M; i++){
306 if( !
predict_( trainingData[i].getSample() ) ){
308 errorLog << __GRT_LOG__ <<
" Failed to run prediction for training sample: " << i <<
"! Failed to fully train model!" << std::endl;
312 if( predictedClassLabel == trainingData[i].getClassLabel() ){
313 trainingSetAccuracy++;
317 if( useValidationSet ){
319 if( !
predict_( validationData[i].getSample() ) ){
321 errorLog << __GRT_LOG__ <<
" Failed to run prediction for validation sample: " << i <<
"! Failed to fully train model!" << std::endl;
325 if( predictedClassLabel == validationData[i].getClassLabel() ){
326 validationSetAccuracy++;
331 trainingSetAccuracy = trainingSetAccuracy / M * 100.0;
333 trainingLog <<
"Training set accuracy: " << trainingSetAccuracy << std::endl;
335 if( useValidationSet ){
336 validationSetAccuracy = validationSetAccuracy / validationData.
getNumSamples() * 100.0;
337 trainingLog <<
"Validation set accuracy: " << validationSetAccuracy << std::endl;
341 useScaling = scalingState;
348 predictedClassLabel = 0;
349 maxLikelihood = -10000;
352 errorLog << __GRT_LOG__ <<
" AdaBoost Model Not Trained!" << std::endl;
356 if( inputVector.
getSize() != numInputDimensions ){
357 errorLog << __GRT_LOG__ <<
" The size of the input vector (" << inputVector.size() <<
") does not match the num features in the model (" << numInputDimensions << std::endl;
362 for(UINT n=0; n<numInputDimensions; n++){
363 inputVector[n] =
scale(inputVector[n], ranges[n].minValue, ranges[n].maxValue, 0, 1);
367 if( classLikelihoods.
getSize() != numClasses ) classLikelihoods.
resize(numClasses,0);
368 if( classDistances.
getSize() != numClasses ) classDistances.
resize(numClasses,0);
370 UINT bestClassIndex = 0;
371 UINT numPositivePredictions = 0;
375 for(UINT k=0; k<numClasses; k++){
376 Float result = models[k].predict( inputVector );
378 switch ( predictionMethod ) {
379 case MAX_POSITIVE_VALUE:
381 if( result > bestDistance ){
382 bestDistance = result;
385 numPositivePredictions++;
386 classLikelihoods[k] = result;
387 }
else classLikelihoods[k] = 0;
389 classDistances[k] = result;
390 sum += classLikelihoods[k];
394 if( result > bestDistance ){
395 bestDistance = result;
398 if( result < worstDistance ){
399 worstDistance = result;
401 numPositivePredictions++;
402 classLikelihoods[k] = result;
403 classDistances[k] = result;
407 errorLog << __GRT_LOG__ <<
" Unknown prediction method!" << std::endl;
412 if( predictionMethod == MAX_VALUE ){
414 worstDistance = fabs( worstDistance );
415 for(UINT k=0; k<numClasses; k++){
416 classLikelihoods[k] += worstDistance;
417 sum += classLikelihoods[k];
423 for(UINT k=0; k<numClasses; k++)
424 classLikelihoods[k] /= sum;
426 maxLikelihood = classLikelihoods[ bestClassIndex ];
428 if( numPositivePredictions == 0 ){
429 predictedClassLabel = GRT_DEFAULT_NULL_CLASS_LABEL;
430 }
else predictedClassLabel = classLabels[ bestClassIndex ];
446 if( nullRejectionCoeff > 0 ){
447 this->nullRejectionCoeff = nullRejectionCoeff;
458 errorLog <<
"save(fstream &file) - The file is not open!" << std::endl;
463 file<<
"GRT_ADABOOST_MODEL_FILE_V2.0\n";
467 errorLog << __GRT_LOG__ <<
" Failed to save classifier base settings to file!" << std::endl;
472 file <<
"PredictionMethod: " << predictionMethod << std::endl;
476 file <<
"Models: " << std::endl;
477 for(UINT i=0; i<models.size(); i++){
478 if( !models[i].
save( file ) ){
479 errorLog << __GRT_LOG__ <<
" Failed to write model " << i <<
" to file!" << std::endl;
495 errorLog << __GRT_LOG__ <<
" Could not open file to load model!" << std::endl;
503 if( word ==
"GRT_ADABOOST_MODEL_FILE_V1.0" ){
504 return loadLegacyModelFromFile( file );
507 if( word !=
"GRT_ADABOOST_MODEL_FILE_V2.0" ){
508 errorLog << __GRT_LOG__ <<
" Failed to read file header!" << std::endl;
509 errorLog << word << std::endl;
515 errorLog << __GRT_LOG__ <<
" Failed to load base settings from file!" << std::endl;
520 if( word !=
"PredictionMethod:" ){
521 errorLog << __GRT_LOG__ <<
" Failed to read PredictionMethod header!" << std::endl;
524 file >> predictionMethod;
528 if( word !=
"Models:" ){
529 errorLog << __GRT_LOG__ <<
" Failed to read Models header!" << std::endl;
534 models.
resize( numClasses );
535 for(UINT i=0; i<models.
getSize(); i++){
536 if( !models[i].
load( file ) ){
537 errorLog << __GRT_LOG__ <<
" Failed to load model " << i <<
" from file!" << std::endl;
548 bestDistance = DEFAULT_NULL_DISTANCE_VALUE;
550 classDistances.
resize(numClasses,DEFAULT_NULL_DISTANCE_VALUE);
574 weakClassifiers.push_back( weakClassiferPtr );
582 weakClassifiers.push_back( weakClassiferPtr );
589 for(UINT i=0; i<weakClassifiers.size(); i++){
590 if( weakClassifiers[i] != NULL ){
591 delete weakClassifiers[i];
592 weakClassifiers[i] = NULL;
595 weakClassifiers.clear();
600 if( numBoostingIterations > 0 ){
601 this->numBoostingIterations = numBoostingIterations;
608 if( predictionMethod != MAX_POSITIVE_VALUE && predictionMethod != MAX_VALUE ){
611 this->predictionMethod = predictionMethod;
617 std::cout <<
"AdaBoostModel: \n";
618 std::cout<<
"NumFeatures: " << numInputDimensions << std::endl;
619 std::cout<<
"NumClasses: " << numClasses << std::endl;
620 std::cout <<
"UseScaling: " << useScaling << std::endl;
621 std::cout<<
"UseNullRejection: " << useNullRejection << std::endl;
623 for(UINT k=0; k<numClasses; k++){
624 std::cout <<
"Class: " << k+1 <<
" ClassLabel: " << classLabels[k] << std::endl;
630 bool AdaBoost::loadLegacyModelFromFile( std::fstream &file ){
635 if( word !=
"NumFeatures:" ){
636 errorLog << __GRT_LOG__ <<
" Failed to read NumFeatures header!" << std::endl;
639 file >> numInputDimensions;
642 if( word !=
"NumClasses:" ){
643 errorLog << __GRT_LOG__ <<
" Failed to read NumClasses header!" << std::endl;
649 if( word !=
"UseScaling:" ){
650 errorLog << __GRT_LOG__ <<
" Failed to read UseScaling header!" << std::endl;
656 if( word !=
"UseNullRejection:" ){
657 errorLog << __GRT_LOG__ <<
" Failed to read UseNullRejection header!" << std::endl;
660 file >> useNullRejection;
664 if( word !=
"Ranges:" ){
665 errorLog << __GRT_LOG__ <<
" Failed to read Ranges header!" << std::endl;
668 ranges.
resize( numInputDimensions );
670 for(UINT n=0; n<ranges.size(); n++){
671 file >> ranges[n].minValue;
672 file >> ranges[n].maxValue;
677 if( word !=
"Trained:" ){
678 errorLog << __GRT_LOG__ <<
" Failed to read Trained header!" << std::endl;
684 if( word !=
"PredictionMethod:" ){
685 errorLog << __GRT_LOG__ <<
" Failed to read PredictionMethod header!" << std::endl;
688 file >> predictionMethod;
692 if( word !=
"Models:" ){
693 errorLog << __GRT_LOG__ <<
" Failed to read Models header!" << std::endl;
698 models.
resize( numClasses );
699 classLabels.
resize( numClasses );
700 for(UINT i=0; i<models.
getSize(); i++){
701 if( !models[i].
load( file ) ){
702 errorLog << __GRT_LOG__ <<
" Failed to load model " << i <<
" from file!" << std::endl;
708 classLabels[i] = models[i].getClassLabel();
717 bestDistance = DEFAULT_NULL_DISTANCE_VALUE;
719 classDistances.
resize(numClasses,DEFAULT_NULL_DISTANCE_VALUE);
bool setClassificationResult(unsigned int trainingIteration, Float accuracy, MLBase *trainer)
bool saveBaseSettingsToFile(std::fstream &file) const
bool setPredictionMethod(UINT predictionMethod)
std::string getId() const
#define DEFAULT_NULL_LIKELIHOOD_VALUE
virtual Float predict(const VectorFloat &x)
virtual bool save(std::fstream &file) const
AdaBoost(const WeakClassifier &weakClassifier=DecisionStump(), bool useScaling=false, bool useNullRejection=false, Float nullRejectionCoeff=10.0, UINT numBoostingIterations=20, UINT predictionMethod=MAX_VALUE)
bool addSample(const UINT classLabel, const VectorFloat &sample)
bool getTrainingLoggingEnabled() const
virtual bool resize(const unsigned int size)
bool setNumDimensions(UINT numDimensions)
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
static std::string getId()
ClassificationData split(const UINT splitPercentage, const bool useStratifiedSampling=false)
AdaBoost & operator=(const AdaBoost &rhs)
bool setNullRejectionCoeff(Float nullRejectionCoeff)
bool scale(const Float minTarget, const Float maxTarget)
This is the main base class that all GRT Classification algorithms should inherit from...
Float scale(const Float &x, const Float &minSource, const Float &maxSource, const Float &minTarget, const Float &maxTarget, const bool constrain=false)