FPCFullSearch.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /**
  2. * @file FPCFullSearch.cpp
  3. * @brief optimal feature search like performed by boosting
  4. * @author Erik Rodner
  5. * @date 04/21/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 "FPCFullSearch.h"
  14. #include "vislearning/features/fpfeatures/createFeatures.h"
  15. using namespace OBJREC;
  16. using namespace std;
  17. // refactor-nice.pl: check this substitution
  18. // old: using namespace ice;
  19. using namespace NICE;
  20. #undef DEBUG_BOOSTING
  21. FPCFullSearch::FPCFullSearch( const Config *_conf ) : conf(_conf)
  22. {
  23. f = NULL;
  24. srand(time(NULL));
  25. use_regression = _conf->gB("FPCFullSearch", "use_regression", false);
  26. }
  27. FPCFullSearch::~FPCFullSearch()
  28. {
  29. if ( f != NULL )
  30. delete f;
  31. }
  32. ClassificationResult FPCFullSearch::classify ( Example & pe )
  33. {
  34. assert ( f != NULL );
  35. double value = f->val ( &pe );
  36. int indicator = 0;
  37. if ( parity*value > parity*threshold )
  38. indicator = 1;
  39. else
  40. indicator = -1;
  41. FullVector scores(2);
  42. scores[0] = 0.0;
  43. if ( use_regression )
  44. scores[1] = alpha*indicator + beta;
  45. else
  46. scores[1] = indicator;
  47. int classno = (scores[1] >= 0);
  48. return ClassificationResult ( classno, scores );
  49. }
  50. void FPCFullSearch::train ( FeaturePool & fp, Examples & examples )
  51. {
  52. f = NULL;
  53. fprintf (stderr, "FPCFullSearch: Feature optimization ...\n");
  54. // ------------ search for a optimal hypothesis
  55. // hypothesis defined by feature index and threshold (i,t)
  56. // [v_i > t]
  57. const Feature *optimal_feature = NULL;
  58. double optimal_alpha = 1.0;
  59. double optimal_beta = 0.0;
  60. double minimum_error = numeric_limits<double>::max();
  61. double optimal_threshold = 0.0;
  62. int optimal_parity = 1;
  63. for ( FeaturePool::const_iterator feature_i = fp.begin();
  64. feature_i != fp.end() ; feature_i++ )
  65. {
  66. const Feature *fcurrent = feature_i->second;
  67. #ifdef DEBUG_BOOSTING
  68. fcurrent->store(cerr); cerr << endl; // DEBUG
  69. #endif
  70. FeatureValues values;
  71. int example_index = 0;
  72. double overallWeight1 = 0.0;
  73. double overallWeight0 = 0.0;
  74. for ( vector< pair<int, Example> >::const_iterator example_i = examples.begin();
  75. example_i != examples.end() ; example_i++, example_index++ )
  76. {
  77. int classno = example_i->first;
  78. assert ( (classno == 0) || (classno == 1) );
  79. const Example & ce = example_i->second;
  80. double value;
  81. value = fcurrent->val ( &ce );
  82. values.insert (
  83. quadruplet<double,int,int,double> (
  84. value, classno, example_index, ce.weight
  85. )
  86. );
  87. overallWeight0 += ( 1 - classno ) * ce.weight;
  88. overallWeight1 += classno * ce.weight;
  89. }
  90. assert ( overallWeight0 + overallWeight1 > 10e-8 );
  91. int previous_class = 0;
  92. double previous_value = 0.0;
  93. //unused:
  94. //double first_value = values.begin()->first;
  95. FeatureValues::const_iterator lastElement = values.end();
  96. lastElement--;
  97. //unused:
  98. //double last_value = lastElement->first;
  99. double minimum_feature_error = minimum_error;
  100. double w0 = 0.0;
  101. double w1 = 0.0;
  102. for ( FeatureValues::const_iterator i = values.begin();
  103. i != values.end(); i++ )
  104. {
  105. double w = i->fourth;
  106. int current_class = i->second;
  107. double current_value = i->first;
  108. #ifdef DEBUG_BOOSTING
  109. fprintf (stderr, "w %f w0 %f w1 %f cc %f\n", w, w0, w1, current_value );
  110. #endif
  111. assert (! isnan(current_value));
  112. if ( (i != values.begin()) // do not check at the begin
  113. #ifdef CHECK_AT_CLASS_BOUNDARIES_ONLY
  114. && (current_class != previous_class) // check only at class splits
  115. #endif
  116. && ( (current_value != previous_value) // check only at possible value splits
  117. #ifdef CHECK_AT_EQUAL_SPLIT
  118. || ( (current_value != first_value)
  119. && (current_value != last_value) // or if it is an equal split
  120. // but can split the values somehow
  121. )
  122. #endif
  123. )
  124. )
  125. {
  126. // possible split found -----
  127. #ifdef DEBUG_BOOSTING
  128. fprintf (stderr, "Current Best Setting: minimum_feature_error %f; optimal_threshold %f\n", minimum_feature_error, optimal_threshold );
  129. fprintf (stderr, "Current Split: 0(%f | %f) 1(%f | %f) w %f %d\n",
  130. w0, overallWeight0 - w0, w1, overallWeight1 - w1, w, current_class );
  131. #endif
  132. double current_threshold = (current_value + previous_value) / 2.0;
  133. // case: parity 1 -> all above threshold belongs to class 1
  134. // -> error: w1 + overallWeight0 - w0
  135. double error1 = 1.0;
  136. // some variables which are important for regression
  137. double a = 0.0;
  138. double c = 0.0;
  139. double d = 0.0;
  140. double W = 0.0;
  141. double regerror = 0.0;
  142. double det = 0.0;
  143. if ( use_regression )
  144. {
  145. /* We solve the following linear equation system:
  146. (MATLAB syntax)
  147. [ [ w, a ]; [ a, w ] ] * [ alpha; beta ] = [ c ; d ]
  148. with the following definitions (x_i is the response, indicator)
  149. */
  150. // W = \sum_i w_i = \sum_i w_i x_i^2
  151. W = overallWeight0 + overallWeight1;
  152. // a = \sum_i w_i x_i
  153. a = (overallWeight0 - w0) + (overallWeight1 - w1) - (w0 + w1);
  154. // \sum_i x_i y_i w_i
  155. c = w0 - w1 + (overallWeight1 - w1) - (overallWeight0 - w0);
  156. // \sum_i y_i
  157. d = overallWeight1 - overallWeight0;
  158. // the determinant of the coefficient matrix
  159. det = W*W - a*a;
  160. /* The following is somewhat tricky.
  161. We do not want to recalculate the regression
  162. error by looping over all examples. Therefore
  163. one can derive the following formula for the regression
  164. error.
  165. To derive this formula, one has to
  166. solve the linear equations above and substitute
  167. the optimal alpha and beta in the formulation of
  168. the error: \sum_i ( \alpha x_i + \beta - y_i )^2.
  169. FIXME: write a tex-note about this stuff.
  170. */
  171. regerror = - (W*c*c - 2*a*c*d + W*d*d) / det + W;
  172. error1 = regerror;
  173. } else {
  174. error1 = w1 + overallWeight0 - w0;
  175. }
  176. // prefer splits which really seperate classes !
  177. if ( current_class == previous_class ) error1 += 1e-12;
  178. #ifdef DEBUG_BOOSTING
  179. fprintf (stderr, "a=%f; c=%f, d=%f, W=%f, regerror=%f, alpha=%f, beta=%f\n", a, c, d, W, regerror,
  180. c/a - (d-c)/(W-a), (d-c) / (W-a));
  181. fprintf (stderr, "> %f (>=%f) belongs to class 1: err=%f\n", current_threshold, current_value, error1);
  182. #endif
  183. if ( error1 < minimum_feature_error )
  184. {
  185. optimal_threshold = current_threshold;
  186. optimal_parity = 1;
  187. if ( use_regression )
  188. {
  189. // solution of the linear equation system
  190. optimal_beta = (W*d - a*c)/det;
  191. optimal_alpha = (W*c - a*d)/det;
  192. } else {
  193. optimal_beta = 0.0;
  194. optimal_alpha = 1.0;
  195. }
  196. minimum_feature_error = error1;
  197. #ifdef DEBUG_BOOSTING
  198. fprintf (stderr, "optimal feature: 0(%f | %f) 1(%f | %f) %f %d\n",
  199. w0, overallWeight0 - w0, w1, overallWeight1 - w1, w, current_class );
  200. #endif
  201. }
  202. if ( ! use_regression )
  203. {
  204. // case: parity -1 -> all below threshold belongs to class 1
  205. // -> error: w0 + overallWeight1 - w1
  206. double error0 = w0 + overallWeight1 - w1;
  207. if ( current_class == previous_class ) error0 += 1e-12;
  208. #ifdef DEBUG_BOOSTING
  209. fprintf (stderr, "< %f (<=%f) belongs to class 1: err=%f\n", current_threshold, previous_value, error0);
  210. #endif
  211. if ( error0 < minimum_feature_error )
  212. {
  213. optimal_threshold = current_threshold;
  214. optimal_parity = -1;
  215. optimal_beta = 0.0;
  216. optimal_alpha = 1.0;
  217. minimum_feature_error = error0;
  218. #ifdef DEBUG_BOOSTING
  219. fprintf (stderr, "optimal feature: 0(%f | %f) 1(%f | %f) w %f %d\n",
  220. w0, overallWeight0 - w0, w1, overallWeight1 - w1, w, current_class );
  221. #endif
  222. }
  223. }
  224. }
  225. w1 += current_class * w;
  226. w0 += (1-current_class) * w;
  227. previous_class = current_class;
  228. previous_value = current_value;
  229. }
  230. // update optimal feature
  231. if ( minimum_feature_error < minimum_error )
  232. {
  233. optimal_feature = fcurrent;
  234. minimum_error = minimum_feature_error;
  235. }
  236. }
  237. assert ( optimal_feature != NULL );
  238. fprintf (stderr, "FPCFullSearch: Feature optimization ...done\n");
  239. optimal_feature->store(cerr);
  240. cerr << endl;
  241. f = optimal_feature->clone();
  242. threshold = optimal_threshold;
  243. parity = optimal_parity;
  244. alpha = optimal_alpha;
  245. beta = optimal_beta;
  246. last_error = minimum_error;
  247. }
  248. FPCFullSearch *FPCFullSearch::clone () const
  249. {
  250. FPCFullSearch *myclone = new FPCFullSearch (conf);
  251. if ( f == NULL )
  252. myclone->f = NULL;
  253. else
  254. myclone->f = f->clone();
  255. myclone->threshold = threshold;
  256. myclone->parity = parity;
  257. myclone->beta = beta;
  258. myclone->alpha = alpha;
  259. return myclone;
  260. }
  261. void FPCFullSearch::restore (istream & is, int format)
  262. {
  263. // refactor-nice.pl: check this substitution
  264. // old: string feature_tag;
  265. std::string feature_tag;
  266. is >> feature_tag;
  267. fprintf (stderr, "feature tag: %s\n", feature_tag.c_str() );
  268. f = createFeatureFromTag ( conf, feature_tag );
  269. if ( f == NULL ) {
  270. fprintf (stderr, "Unknown feature description: %s\n",
  271. feature_tag.c_str() );
  272. exit(-1);
  273. }
  274. f->restore ( is, format );
  275. is >> threshold;
  276. is >> parity;
  277. is >> alpha;
  278. is >> beta;
  279. cerr << "T " << threshold << " P " << parity << endl;
  280. // refactor-nice.pl: check this substitution
  281. // old: string tmp;
  282. std::string tmp;
  283. is >> tmp;
  284. }
  285. void FPCFullSearch::store (ostream & os, int format) const
  286. {
  287. f->store ( os, format );
  288. os << endl;
  289. os << threshold << " " << parity << " ";
  290. os << alpha << " " << beta << endl;
  291. }
  292. void FPCFullSearch::clear()
  293. {
  294. if ( f != NULL )
  295. delete f;
  296. }
  297. const Feature *FPCFullSearch::getStump ( double & _threshold, double & _parity ) const
  298. {
  299. _threshold = threshold;
  300. _parity = parity;
  301. return f;
  302. }