FPCBoosting.cpp 13 KB

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