123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- /**
- * @file FPCFullSearch.cpp
- * @brief optimal feature search like performed by boosting
- * @author Erik Rodner
- * @date 04/21/2008
- */
- #include <iostream>
- #include <time.h>
- #include "FPCFullSearch.h"
- #include "vislearning/features/fpfeatures/createFeatures.h"
- using namespace OBJREC;
- using namespace std;
- // refactor-nice.pl: check this substitution
- // old: using namespace ice;
- using namespace NICE;
- #undef DEBUG_BOOSTING
- FPCFullSearch::FPCFullSearch( const Config *_conf ) : conf(_conf)
- {
- f = NULL;
- srand(time(NULL));
- use_regression = _conf->gB("FPCFullSearch", "use_regression", false);
- }
- FPCFullSearch::~FPCFullSearch()
- {
- if ( f != NULL )
- delete f;
- }
- ClassificationResult FPCFullSearch::classify ( Example & pe )
- {
- assert ( f != NULL );
- double value = f->val ( &pe );
- int indicator = 0;
- if ( parity*value > parity*threshold )
- indicator = 1;
- else
- indicator = -1;
-
- FullVector scores(2);
- scores[0] = 0.0;
- if ( use_regression )
- scores[1] = alpha*indicator + beta;
- else
- scores[1] = indicator;
-
- int classno = (scores[1] >= 0);
- return ClassificationResult ( classno, scores );
- }
- void FPCFullSearch::train ( FeaturePool & fp, Examples & examples )
- {
- f = NULL;
- fprintf (stderr, "FPCFullSearch: Feature optimization ...\n");
- // ------------ search for a optimal hypothesis
- // hypothesis defined by feature index and threshold (i,t)
- // [v_i > t]
- const Feature *optimal_feature = NULL;
- double optimal_alpha = 1.0;
- double optimal_beta = 0.0;
- double minimum_error = numeric_limits<double>::max();
- double optimal_threshold = 0.0;
- int optimal_parity = 1;
- for ( FeaturePool::const_iterator feature_i = fp.begin();
- feature_i != fp.end() ; feature_i++ )
- {
- const Feature *fcurrent = feature_i->second;
- #ifdef DEBUG_BOOSTING
- fcurrent->store(cerr); cerr << endl; // DEBUG
- #endif
- FeatureValues values;
- int example_index = 0;
- double overallWeight1 = 0.0;
- double overallWeight0 = 0.0;
- for ( vector< pair<int, Example> >::const_iterator example_i = examples.begin();
- example_i != examples.end() ; example_i++, example_index++ )
- {
- int classno = example_i->first;
- assert ( (classno == 0) || (classno == 1) );
- const Example & ce = example_i->second;
- double value;
- value = fcurrent->val ( &ce );
-
- values.insert (
- quadruplet<double,int,int,double> (
- value, classno, example_index, ce.weight
- )
- );
- overallWeight0 += ( 1 - classno ) * ce.weight;
- overallWeight1 += classno * ce.weight;
- }
- assert ( overallWeight0 + overallWeight1 > 10e-8 );
- int previous_class = 0;
- double previous_value = 0.0;
- //unused:
- //double first_value = values.begin()->first;
- FeatureValues::const_iterator lastElement = values.end();
- lastElement--;
-
- //unused:
- //double last_value = lastElement->first;
- double minimum_feature_error = minimum_error;
- double w0 = 0.0;
- double w1 = 0.0;
- for ( FeatureValues::const_iterator i = values.begin();
- i != values.end(); i++ )
- {
- double w = i->fourth;
- int current_class = i->second;
- double current_value = i->first;
- #ifdef DEBUG_BOOSTING
- fprintf (stderr, "w %f w0 %f w1 %f cc %f\n", w, w0, w1, current_value );
- #endif
- assert (! NICE::isNaN(current_value));
- if ( (i != values.begin()) // do not check at the begin
- #ifdef CHECK_AT_CLASS_BOUNDARIES_ONLY
- && (current_class != previous_class) // check only at class splits
- #endif
- && ( (current_value != previous_value) // check only at possible value splits
- #ifdef CHECK_AT_EQUAL_SPLIT
- || ( (current_value != first_value)
- && (current_value != last_value) // or if it is an equal split
- // but can split the values somehow
- )
- #endif
- )
- )
- {
- // possible split found -----
- #ifdef DEBUG_BOOSTING
- fprintf (stderr, "Current Best Setting: minimum_feature_error %f; optimal_threshold %f\n", minimum_feature_error, optimal_threshold );
- fprintf (stderr, "Current Split: 0(%f | %f) 1(%f | %f) w %f %d\n",
- w0, overallWeight0 - w0, w1, overallWeight1 - w1, w, current_class );
- #endif
- double current_threshold = (current_value + previous_value) / 2.0;
-
- // case: parity 1 -> all above threshold belongs to class 1
- // -> error: w1 + overallWeight0 - w0
- double error1 = 1.0;
- // some variables which are important for regression
- double a = 0.0;
- double c = 0.0;
- double d = 0.0;
- double W = 0.0;
- double regerror = 0.0;
- double det = 0.0;
- if ( use_regression )
- {
- /* We solve the following linear equation system:
- (MATLAB syntax)
-
- [ [ w, a ]; [ a, w ] ] * [ alpha; beta ] = [ c ; d ]
- with the following definitions (x_i is the response, indicator)
- */
- // W = \sum_i w_i = \sum_i w_i x_i^2
- W = overallWeight0 + overallWeight1;
- // a = \sum_i w_i x_i
- a = (overallWeight0 - w0) + (overallWeight1 - w1) - (w0 + w1);
- // \sum_i x_i y_i w_i
- c = w0 - w1 + (overallWeight1 - w1) - (overallWeight0 - w0);
- // \sum_i y_i
- d = overallWeight1 - overallWeight0;
- // the determinant of the coefficient matrix
- det = W*W - a*a;
- /* The following is somewhat tricky.
- We do not want to recalculate the regression
- error by looping over all examples. Therefore
- one can derive the following formula for the regression
- error.
- To derive this formula, one has to
- solve the linear equations above and substitute
- the optimal alpha and beta in the formulation of
- the error: \sum_i ( \alpha x_i + \beta - y_i )^2.
-
- FIXME: write a tex-note about this stuff.
- */
- regerror = - (W*c*c - 2*a*c*d + W*d*d) / det + W;
- error1 = regerror;
- } else {
- error1 = w1 + overallWeight0 - w0;
- }
- // prefer splits which really seperate classes !
- if ( current_class == previous_class ) error1 += 1e-12;
- #ifdef DEBUG_BOOSTING
- fprintf (stderr, "a=%f; c=%f, d=%f, W=%f, regerror=%f, alpha=%f, beta=%f\n", a, c, d, W, regerror,
- c/a - (d-c)/(W-a), (d-c) / (W-a));
- fprintf (stderr, "> %f (>=%f) belongs to class 1: err=%f\n", current_threshold, current_value, error1);
- #endif
- if ( error1 < minimum_feature_error )
- {
- optimal_threshold = current_threshold;
- optimal_parity = 1;
-
- if ( use_regression )
- {
- // solution of the linear equation system
- optimal_beta = (W*d - a*c)/det;
- optimal_alpha = (W*c - a*d)/det;
- } else {
- optimal_beta = 0.0;
- optimal_alpha = 1.0;
- }
- minimum_feature_error = error1;
- #ifdef DEBUG_BOOSTING
- fprintf (stderr, "optimal feature: 0(%f | %f) 1(%f | %f) %f %d\n",
- w0, overallWeight0 - w0, w1, overallWeight1 - w1, w, current_class );
- #endif
- }
-
- if ( ! use_regression )
- {
- // case: parity -1 -> all below threshold belongs to class 1
- // -> error: w0 + overallWeight1 - w1
- double error0 = w0 + overallWeight1 - w1;
-
- if ( current_class == previous_class ) error0 += 1e-12;
- #ifdef DEBUG_BOOSTING
- fprintf (stderr, "< %f (<=%f) belongs to class 1: err=%f\n", current_threshold, previous_value, error0);
- #endif
- if ( error0 < minimum_feature_error )
- {
- optimal_threshold = current_threshold;
- optimal_parity = -1;
-
- optimal_beta = 0.0;
- optimal_alpha = 1.0;
- minimum_feature_error = error0;
- #ifdef DEBUG_BOOSTING
- fprintf (stderr, "optimal feature: 0(%f | %f) 1(%f | %f) w %f %d\n",
- w0, overallWeight0 - w0, w1, overallWeight1 - w1, w, current_class );
- #endif
- }
- }
- }
- w1 += current_class * w;
- w0 += (1-current_class) * w;
- previous_class = current_class;
- previous_value = current_value;
- }
-
- // update optimal feature
- if ( minimum_feature_error < minimum_error )
- {
- optimal_feature = fcurrent;
- minimum_error = minimum_feature_error;
- }
- }
- assert ( optimal_feature != NULL );
- fprintf (stderr, "FPCFullSearch: Feature optimization ...done\n");
- optimal_feature->store(cerr);
- cerr << endl;
- f = optimal_feature->clone();
- threshold = optimal_threshold;
- parity = optimal_parity;
- alpha = optimal_alpha;
- beta = optimal_beta;
- last_error = minimum_error;
- }
- FPCFullSearch *FPCFullSearch::clone () const
- {
- FPCFullSearch *myclone = new FPCFullSearch (conf);
- if ( f == NULL )
- myclone->f = NULL;
- else
- myclone->f = f->clone();
- myclone->threshold = threshold;
- myclone->parity = parity;
- myclone->beta = beta;
- myclone->alpha = alpha;
- return myclone;
- }
- void FPCFullSearch::restore (istream & is, int format)
- {
- // refactor-nice.pl: check this substitution
- // old: string feature_tag;
- std::string feature_tag;
- is >> feature_tag;
- fprintf (stderr, "feature tag: %s\n", feature_tag.c_str() );
- f = createFeatureFromTag ( conf, feature_tag );
- if ( f == NULL ) {
- fprintf (stderr, "Unknown feature description: %s\n",
- feature_tag.c_str() );
- exit(-1);
- }
- f->restore ( is, format );
- is >> threshold;
- is >> parity;
- is >> alpha;
- is >> beta;
- cerr << "T " << threshold << " P " << parity << endl;
- // refactor-nice.pl: check this substitution
- // old: string tmp;
- std::string tmp;
- is >> tmp;
- }
- void FPCFullSearch::store (ostream & os, int format) const
- {
- f->store ( os, format );
- os << endl;
- os << threshold << " " << parity << " ";
- os << alpha << " " << beta << endl;
- }
- void FPCFullSearch::clear()
- {
- if ( f != NULL )
- delete f;
- }
-
- const Feature *FPCFullSearch::getStump ( double & _threshold, double & _parity ) const
- {
- _threshold = threshold;
- _parity = parity;
- return f;
- }
|