FPCBoosting.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. /**
  2. * @file FPCBoosting.cpp
  3. * @brief implementation of boosting algorithms
  4. * @author Erik Rodner
  5. * @date 04/24/2008
  6. */
  7. #include <iostream>
  8. #include "vislearning/classifier/fpclassifier/randomforest/FPCRandomForests.h"
  9. #include "vislearning/baselib/Gnuplot.h"
  10. #include "FPCBoosting.h"
  11. #include "FPCFullSearch.h"
  12. using namespace OBJREC;
  13. using namespace std;
  14. // refactor-nice.pl: check this substitution
  15. // old: using namespace ice;
  16. using namespace NICE;
  17. #undef DEBUG_BOOST
  18. #define ESTIMATETRAINERROR
  19. #undef DEBUG_ERROR_ESTIMATION
  20. static inline double
  21. pRatio( double val )
  22. {
  23. const double eps = 1e-5;
  24. if ( val < eps ) val = eps;
  25. if ( val > 1 - eps ) val = 1 - eps;
  26. return val/(1. - val);
  27. }
  28. FPCBoosting::FPCBoosting( const Config *_conf,
  29. // refactor-nice.pl: check this substitution
  30. // old: string section ) : conf(_conf)
  31. std::string section ) : conf(_conf)
  32. {
  33. // refactor-nice.pl: check this substitution
  34. // old: string weakClassifier_s = conf->gS(section, "weak_classifier", "full_search" );
  35. std::string weakClassifier_s = conf->gS(section, "weak_classifier", "full_search" );
  36. if ( weakClassifier_s == "random_forest" )
  37. {
  38. weakClassifier = new FPCRandomForests ( _conf, "RandomForest" );
  39. memory_efficient = _conf->gB("RandomForest", "memory_efficient", false );
  40. } else if ( weakClassifier_s == "full_search" ) {
  41. fprintf (stderr, "Boost: using full search methods\n");
  42. weakClassifier = new FPCFullSearch ( _conf );
  43. memory_efficient = false;
  44. } else {
  45. fprintf (stderr, "FPCBoosting: weak classifier type unknown !\n");
  46. exit(-1);
  47. }
  48. // refactor-nice.pl: check this substitution
  49. // old: string boosting_method_s = conf->gS(section, "method", "realboost" );
  50. std::string boosting_method_s = conf->gS(section, "method", "realboost" );
  51. if ( boosting_method_s == "realboost" )
  52. {
  53. boosting_method = BOOSTINGMETHOD_REAL_ADABOOST;
  54. } else if ( boosting_method_s == "adaboost" ) {
  55. boosting_method = BOOSTINGMETHOD_ADABOOST;
  56. } else if ( boosting_method_s == "gentleboost" ) {
  57. boosting_method = BOOSTINGMETHOD_GENTLEBOOST;
  58. } else {
  59. fprintf (stderr, "FPCBoosting: boosting method unknown !\n");
  60. exit(-1);
  61. }
  62. classwise_normalization = _conf->gB(section, "classwise_normalization", false );
  63. positive_class = _conf->gI(section, "positive_class", 1 );
  64. maxRounds = _conf->gI(section, "max_rounds", 100 );
  65. }
  66. FPCBoosting::~FPCBoosting()
  67. {
  68. if ( weakClassifier != NULL )
  69. delete weakClassifier;
  70. for ( StrongClassifier::iterator i = strongClassifier.begin();
  71. i != strongClassifier.end();
  72. i++ )
  73. delete ( i->third );
  74. }
  75. ClassificationResult FPCBoosting::classify ( Example & pce )
  76. {
  77. FullVector overall_distribution;
  78. for ( StrongClassifier::const_iterator i = strongClassifier.begin();
  79. i != strongClassifier.end();
  80. i++ )
  81. {
  82. double alpha = i->first;
  83. double beta = i->second;
  84. FeaturePoolClassifier *classifier = i->third;
  85. ClassificationResult r = classifier->classify ( pce );
  86. if ( boosting_method == BOOSTINGMETHOD_REAL_ADABOOST )
  87. {
  88. // transform probabilities into nasty scores
  89. double p = r.scores[positive_class];
  90. r.scores[positive_class] = 0.5 * log ( pRatio ( p ) );
  91. r.scores[0] = - r.scores[positive_class];
  92. }
  93. if ( overall_distribution.empty() )
  94. {
  95. overall_distribution = r.scores;
  96. overall_distribution.multiply(alpha);
  97. } else {
  98. overall_distribution.add ( r.scores, alpha );
  99. }
  100. overall_distribution.add ( beta );
  101. }
  102. int overall_classno = 0;
  103. overall_classno = overall_distribution.maxElement();
  104. return ClassificationResult ( overall_classno, overall_distribution );
  105. }
  106. void FPCBoosting::train ( FeaturePool & fp,
  107. Examples & examples )
  108. {
  109. maxClassNo = examples.getMaxClassNo();
  110. FeatureStorage featureStorage;
  111. #ifdef DEBUG_BOOST
  112. fprintf (stderr, "FPCBoosting : training examples %d\n", (int)examples.size() );
  113. #endif
  114. boosting ( featureStorage, fp, examples );
  115. }
  116. void FPCBoosting::normalizeWeights ( Examples & examples ) const
  117. {
  118. if ( classwise_normalization )
  119. {
  120. double sump = 0.0;
  121. double sumn = 0.0;
  122. int np = 0;
  123. int nn = 0;
  124. for ( Examples::const_iterator i = examples.begin();
  125. i != examples.end();
  126. i++ )
  127. if ( i->first == positive_class )
  128. {
  129. sump += i->second.weight;
  130. np++;
  131. } else {
  132. sumn += i->second.weight;
  133. nn++;
  134. }
  135. if ( fabs(sump) < 1e-10 ) sump = np;
  136. if ( fabs(sumn) < 1e-10 ) sump = nn;
  137. for ( Examples::iterator i = examples.begin();
  138. i != examples.end();
  139. i++ )
  140. if ( i->first == positive_class )
  141. i->second.weight /= 2*sump;
  142. else
  143. i->second.weight /= 2*sumn;
  144. } else {
  145. double sum = 0.0;
  146. for ( Examples::const_iterator i = examples.begin();
  147. i != examples.end();
  148. i++ )
  149. sum += i->second.weight;
  150. if ( fabs(sum) < 1e-10 ) sum = examples.size();
  151. for ( Examples::iterator i = examples.begin();
  152. i != examples.end();
  153. i++ )
  154. i->second.weight /= sum;
  155. }
  156. }
  157. void FPCBoosting::boosting ( const FeatureStorage & featureStorage,
  158. FeaturePool & fp,
  159. Examples & examples )
  160. {
  161. normalizeWeights ( examples );
  162. #ifdef ESTIMATETRAINERROR
  163. vector<double> error_boosting;
  164. vector<double> weak_error_boosting;
  165. #endif
  166. for ( uint iteration = 0 ; iteration < (uint)maxRounds ; iteration++ )
  167. {
  168. // fit a classifier using the current weights
  169. FeaturePoolClassifier *best = weakClassifier->clone();
  170. best->train ( fp, examples );
  171. // ---------------------------------------------
  172. // Estimate the error of the current hypothesis
  173. // ---------------------------------------------
  174. double error = 0.0;
  175. long int index = 0;
  176. vector<double> h_values (examples.size(), 0.0);
  177. vector<int> h_results (examples.size(), 0);
  178. for ( Examples::iterator i = examples.begin();
  179. i != examples.end();
  180. i++, index++ )
  181. {
  182. double weight = i->second.weight;
  183. ClassificationResult r = best->classify ( i->second );
  184. double p_value = r.scores[positive_class];
  185. int h_result = r.classno == positive_class ? 1 : -1;
  186. double h_value;
  187. // assume p_value is between [0:1]
  188. if ( boosting_method == BOOSTINGMETHOD_REAL_ADABOOST )
  189. {
  190. if ( (p_value < 0.0) || (p_value > 1.0) )
  191. {
  192. fprintf (stderr, "FPCBoosting: do not use real adaboost with hypothesis values outside of [0,1]\n");
  193. exit(-1);
  194. }
  195. h_value = 0.5 * log (pRatio ( p_value ));
  196. } else {
  197. h_value = p_value;
  198. }
  199. assert ( index < (int)h_values.size() );
  200. assert ( index < (int)h_results.size() );
  201. h_values[index] = h_value;
  202. h_results[index] = h_result;
  203. if ( r.classno != i->first )
  204. error += weight;
  205. #ifdef DEBUG_BOOST
  206. fprintf (stderr, "FPCBoosting:w(%ld) = %f gt %d est %d\n", index, weight, i->first, h_result );
  207. #endif
  208. if ( memory_efficient ) i->second.ce->dropPreCached();
  209. }
  210. #ifdef DEBUG_ERROR_ESTIMATION
  211. fprintf (stderr, "Boost: iteration %zd error %lf\n", iteration, error );
  212. FPCFullSearch *search = dynamic_cast< FPCFullSearch * > ( best );
  213. /*
  214. if ( fabs(error - search->last_error) > 1e-5 ) {
  215. fprintf (stderr, "Boost: FIX THIS BUG postest=%lf preest=%lf %e\n", error, search->last_error, fabs(error - search->last_error) );
  216. exit(-1);
  217. }
  218. */
  219. if ( error > 0.5 )
  220. {
  221. fprintf (stderr, "Boost: weak hypothesis with an error > 0.5 ? postest=%lf preeest=%lf\n", error, search->last_error);
  222. exit(-1);
  223. }
  224. #endif
  225. double likelihood_ratio = 1.0;
  226. if (boosting_method == BOOSTINGMETHOD_REAL_ADABOOST)
  227. {
  228. strongClassifier.push_back ( triplet<double, double, FeaturePoolClassifier *> ( 1.0, 0.0, best ) );
  229. } else if ( (boosting_method == BOOSTINGMETHOD_GENTLEBOOST) ) {
  230. strongClassifier.push_back ( triplet<double, double, FeaturePoolClassifier *> ( 1.0, 0.0, best ) );
  231. } else {
  232. // likelihood_ratio corresponds to \beta_t in the
  233. // Viola&Jones Paper
  234. likelihood_ratio = pRatio ( error );
  235. double alpha = - log ( likelihood_ratio );
  236. double beta = alpha/2;
  237. #ifdef DEBUG_BOOST
  238. fprintf (stderr, "estimated parameters: lratio=%f alpha=%f beta=%f\n", likelihood_ratio, alpha, beta);
  239. #endif
  240. strongClassifier.push_back ( triplet<double, double, FeaturePoolClassifier *> ( alpha, beta, best ) );
  241. }
  242. #ifdef ESTIMATETRAINERROR
  243. // --------- estimate training error
  244. double error_sum = 0.0;
  245. index = 0;
  246. for ( Examples::iterator i = examples.begin();
  247. i != examples.end();
  248. i++, index++ )
  249. {
  250. ClassificationResult r = classify ( i->second );
  251. if ( r.classno != i->first )
  252. error_sum += 1.0 / examples.size();
  253. }
  254. fprintf (stderr, "Boost: training error %f\n", error_sum );
  255. error_boosting.push_back ( error_sum );
  256. weak_error_boosting.push_back ( error );
  257. #endif
  258. // ---------- readjust weights
  259. index = 0;
  260. for ( Examples::iterator i = examples.begin();
  261. i != examples.end();
  262. i++, index++ )
  263. {
  264. double weight = i->second.weight;
  265. assert ( index < (int)h_values.size() );
  266. assert ( index < (int)h_results.size() );
  267. double h_value = h_values[index];
  268. int h_result = h_results[index];
  269. int y = (i->first == positive_class) ? 1 : -1;
  270. if (boosting_method == BOOSTINGMETHOD_REAL_ADABOOST)
  271. {
  272. // weight update of Real-AdaBoost
  273. // as presented by Friedman et al.
  274. weight *= exp( - y*h_value );
  275. } else if (boosting_method == BOOSTINGMETHOD_GENTLEBOOST) {
  276. // h_value is still between [0,1]
  277. weight *= exp( - y*h_value );
  278. } else {
  279. // standard AdaBoost weight update
  280. // according to Viola & Jones
  281. if ( y == h_result )
  282. weight *= likelihood_ratio;
  283. }
  284. #ifdef DEBUG_BOOST
  285. fprintf (stderr, "Boost: iteration %d y %d p %f w %f\n", iteration, y, h_value, weight );
  286. #endif
  287. i->second.weight = weight;
  288. }
  289. normalizeWeights ( examples );
  290. }
  291. #ifdef ESTIMATETRAINERROR
  292. Gnuplot gp ("lines");
  293. vector<double> upper_bound;
  294. // Compute the upper bound on the training error
  295. // the formula and an explanation can be found in the
  296. // paper of Freund & Shapire
  297. // 2^T can be incorporated into the product
  298. // and a quick glance at the formula shows that the
  299. // upper bound is at least below 1 (otherwise this
  300. // bound we be cound of useless
  301. double prod = 1.0;
  302. for ( vector<double>::const_iterator i = weak_error_boosting.begin();
  303. i != weak_error_boosting.end(); i++ )
  304. {
  305. double epsilon_t = *i;
  306. prod *= 2 * sqrt( epsilon_t * (1 - epsilon_t) );
  307. // according to the improvment of the upper bound in the paper
  308. upper_bound.push_back ( 0.5*prod );
  309. }
  310. gp.plot_x ( error_boosting, "Boosting Training Error" );
  311. gp.plot_x ( weak_error_boosting, "Error of the weak learner" );
  312. gp.plot_x ( upper_bound, "Upper bound of the training error (AdaBoost using a Soft-Decision)" );
  313. #ifndef NOVISUAL
  314. // refactor-nice.pl: check this substitution
  315. // old: GetChar();
  316. getchar();
  317. #else
  318. getchar();
  319. #endif
  320. #endif
  321. }
  322. void FPCBoosting::restore (istream & is, int format)
  323. {
  324. // refactor-nice.pl: check this substitution
  325. // old: string tag;
  326. std::string tag;
  327. weakClassifier->maxClassNo = maxClassNo;
  328. while ( (is >> tag) && (tag == "WEAKCLASSIFIER") )
  329. {
  330. FeaturePoolClassifier *classifier = weakClassifier->clone();
  331. double alpha;
  332. double beta;
  333. is >> alpha;
  334. is >> beta;
  335. classifier->restore ( is );
  336. strongClassifier.push_back ( triplet<double, double, FeaturePoolClassifier *>
  337. ( alpha, beta, classifier ) );
  338. }
  339. cerr << "TAG: " << tag << endl;
  340. assert ( strongClassifier.size() > 0 );
  341. }
  342. void FPCBoosting::store (ostream & os, int format) const
  343. {
  344. for ( StrongClassifier::const_iterator i = strongClassifier.begin();
  345. i != strongClassifier.end();
  346. i++ )
  347. {
  348. const FeaturePoolClassifier *classifier = i->third;
  349. double alpha = i->first;
  350. double beta = i->second;
  351. os << "WEAKCLASSIFIER" << endl;
  352. os << alpha << endl;
  353. os << beta << endl;
  354. classifier->store (os);
  355. os << "ENDWEAKCLASSIFIER" << endl;
  356. }
  357. }
  358. void FPCBoosting::clear ()
  359. {
  360. strongClassifier.clear();
  361. }
  362. FeaturePoolClassifier *FPCBoosting::clone () const
  363. {
  364. FPCBoosting *fpcBoost = new FPCBoosting ();
  365. fpcBoost->maxRounds = maxRounds;
  366. fpcBoost->weakClassifier = weakClassifier->clone();
  367. fpcBoost->positive_class = positive_class;
  368. fpcBoost->memory_efficient = memory_efficient;
  369. fpcBoost->maxClassNo = maxClassNo;
  370. return fpcBoost;
  371. }
  372. void FPCBoosting::setComplexity ( int size )
  373. {
  374. fprintf (stderr, "FPCBoosting: set complexity to %d, overwriting current value %d\n",
  375. size, maxRounds );
  376. maxRounds = size;
  377. }