GPHIKClassifier.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. /**
  2. * @file GPHIKClassifier.cpp
  3. * @brief Main interface for our GP HIK classifier (similar to the feature pool classifier interface in vislearning) (Implementation)
  4. * @author Erik Rodner, Alexander Freytag
  5. * @date 02/01/2012
  6. */
  7. #include <iostream>
  8. #include "core/basics/numerictools.h"
  9. #include <core/basics/Timer.h>
  10. #include "GPHIKClassifier.h"
  11. #include "gp-hik-core/parameterizedFunctions/PFAbsExp.h"
  12. #include "gp-hik-core/parameterizedFunctions/PFExp.h"
  13. #include "gp-hik-core/parameterizedFunctions/PFMKL.h"
  14. using namespace std;
  15. using namespace NICE;
  16. GPHIKClassifier::GPHIKClassifier( const Config *conf, const string & confSection )
  17. {
  18. //default settings, may be overwritten lateron
  19. gphyper = NULL;
  20. pf = NULL;
  21. confCopy = NULL;
  22. //just a default value
  23. uncertaintyPredictionForClassification = false;
  24. if ( conf == NULL )
  25. {
  26. fthrow(Exception, "GPHIKClassifier: the config is NULL -- use a default config or the restore-function instaed!");
  27. }
  28. else
  29. this->init(conf, confSection);
  30. }
  31. GPHIKClassifier::~GPHIKClassifier()
  32. {
  33. if ( gphyper != NULL )
  34. delete gphyper;
  35. if (pf != NULL)
  36. delete pf;
  37. if ( confCopy != NULL )
  38. delete confCopy;
  39. }
  40. void GPHIKClassifier::init(const Config *conf, const string & confSection)
  41. {
  42. double parameterLowerBound = conf->gD(confSection, "parameter_lower_bound", 1.0 );
  43. double parameterUpperBound = conf->gD(confSection, "parameter_upper_bound", 5.0 );
  44. this->noise = conf->gD(confSection, "noise", 0.01);
  45. string transform = conf->gS(confSection, "transform", "absexp" );
  46. if (pf == NULL)
  47. {
  48. if ( transform == "absexp" )
  49. {
  50. this->pf = new PFAbsExp( 1.0, parameterLowerBound, parameterUpperBound );
  51. } else if ( transform == "exp" ) {
  52. this->pf = new PFExp( 1.0, parameterLowerBound, parameterUpperBound );
  53. }else if ( transform == "MKL" ) {
  54. //TODO generic, please :) load from a separate file or something like this!
  55. std::set<int> steps; steps.insert(4000); steps.insert(6000); //specific for VISAPP
  56. this->pf = new PFMKL( steps, parameterLowerBound, parameterUpperBound );
  57. } else {
  58. fthrow(Exception, "Transformation type is unknown " << transform);
  59. }
  60. }
  61. else{
  62. //we already know the pf from the restore-function
  63. }
  64. this->confSection = confSection;
  65. this->verbose = conf->gB(confSection, "verbose", false);
  66. this->debug = conf->gB(confSection, "debug", false);
  67. this->uncertaintyPredictionForClassification = conf->gB( confSection, "uncertaintyPredictionForClassification", false );
  68. if (confCopy != conf)
  69. {
  70. this->confCopy = new Config ( *conf );
  71. //we do not want to read until end of file for restoring
  72. confCopy->setIoUntilEndOfFile(false);
  73. }
  74. //how do we approximate the predictive variance for classification uncertainty?
  75. string s_varianceApproximation = conf->gS(confSection, "varianceApproximation", "approximate_fine"); //default: fine approximative uncertainty prediction
  76. if ( (s_varianceApproximation.compare("approximate_rough") == 0) || ((s_varianceApproximation.compare("1") == 0)) )
  77. {
  78. this->varianceApproximation = APPROXIMATE_ROUGH;
  79. }
  80. else if ( (s_varianceApproximation.compare("approximate_fine") == 0) || ((s_varianceApproximation.compare("2") == 0)) )
  81. {
  82. this->varianceApproximation = APPROXIMATE_FINE;
  83. }
  84. else if ( (s_varianceApproximation.compare("exact") == 0) || ((s_varianceApproximation.compare("3") == 0)) )
  85. {
  86. this->varianceApproximation = EXACT;
  87. }
  88. else
  89. {
  90. this->varianceApproximation = NONE;
  91. }
  92. std::cerr << "varianceApproximationStrategy: " << s_varianceApproximation << std::endl;
  93. }
  94. void GPHIKClassifier::classify ( const SparseVector * example, int & result, SparseVector & scores )
  95. {
  96. double tmpUncertainty;
  97. this->classify( example, result, scores, tmpUncertainty );
  98. }
  99. void GPHIKClassifier::classify ( const NICE::Vector * example, int & result, SparseVector & scores )
  100. {
  101. double tmpUncertainty;
  102. this->classify( example, result, scores, tmpUncertainty );
  103. }
  104. void GPHIKClassifier::classify ( const SparseVector * example, int & result, SparseVector & scores, double & uncertainty )
  105. {
  106. if (gphyper == NULL)
  107. fthrow(Exception, "Classifier not trained yet -- aborting!" );
  108. scores.clear();
  109. int classno = gphyper->classify ( *example, scores );
  110. if ( scores.size() == 0 ) {
  111. fthrow(Exception, "Zero scores, something is likely to be wrong here: svec.size() = " << example->size() );
  112. }
  113. result = scores.maxElement();
  114. if (uncertaintyPredictionForClassification)
  115. {
  116. if (varianceApproximation != NONE)
  117. {
  118. this->predictUncertainty( example, uncertainty );
  119. }
  120. else
  121. {
  122. //do nothing
  123. uncertainty = std::numeric_limits<double>::max();
  124. }
  125. }
  126. else
  127. {
  128. //do nothing
  129. uncertainty = std::numeric_limits<double>::max();
  130. }
  131. }
  132. void GPHIKClassifier::classify ( const NICE::Vector * example, int & result, SparseVector & scores, double & uncertainty )
  133. {
  134. if (gphyper == NULL)
  135. fthrow(Exception, "Classifier not trained yet -- aborting!" );
  136. scores.clear();
  137. int classno = gphyper->classify ( *example, scores );
  138. if ( scores.size() == 0 ) {
  139. fthrow(Exception, "Zero scores, something is likely to be wrong here: svec.size() = " << example->size() );
  140. }
  141. result = scores.maxElement();
  142. if (uncertaintyPredictionForClassification)
  143. {
  144. if (varianceApproximation != NONE)
  145. {
  146. this->predictUncertainty( example, uncertainty );
  147. }
  148. else
  149. {
  150. //do nothing
  151. uncertainty = std::numeric_limits<double>::max();
  152. }
  153. }
  154. else
  155. {
  156. //do nothing
  157. uncertainty = std::numeric_limits<double>::max();
  158. }
  159. }
  160. /** training process */
  161. void GPHIKClassifier::train ( const std::vector< NICE::SparseVector *> & examples, const NICE::Vector & labels )
  162. {
  163. if (verbose)
  164. std::cerr << "GPHIKClassifier::train" << std::endl;
  165. Timer t;
  166. t.start();
  167. FastMinKernel *fmk = new FastMinKernel ( examples, noise, this->debug );
  168. t.stop();
  169. if (verbose)
  170. std::cerr << "Time used for setting up the fmk object: " << t.getLast() << std::endl;
  171. if (gphyper != NULL)
  172. delete gphyper;
  173. gphyper = new FMKGPHyperparameterOptimization ( confCopy, pf, fmk, confSection );
  174. if (verbose)
  175. cerr << "Learning ..." << endl;
  176. // go go go
  177. gphyper->optimize ( labels );
  178. if (verbose)
  179. std::cerr << "optimization done" << std::endl;
  180. if ( ( varianceApproximation != NONE ) )
  181. {
  182. std::cerr << "now prepare for the uncertainty prediction" << std::endl;
  183. switch (varianceApproximation)
  184. {
  185. case APPROXIMATE_ROUGH:
  186. {
  187. gphyper->prepareVarianceApproximationRough();
  188. break;
  189. }
  190. case APPROXIMATE_FINE:
  191. {
  192. gphyper->prepareVarianceApproximationFine();
  193. break;
  194. }
  195. case EXACT:
  196. {
  197. //nothing to prepare
  198. break;
  199. }
  200. default:
  201. {
  202. //nothing to prepare
  203. }
  204. }
  205. }
  206. // clean up all examples ??
  207. if (verbose)
  208. std::cerr << "Learning finished" << std::endl;
  209. }
  210. /** training process */
  211. void GPHIKClassifier::train ( const std::vector< SparseVector *> & examples, std::map<int, NICE::Vector> & binLabels )
  212. {
  213. if (verbose)
  214. std::cerr << "GPHIKClassifier::train" << std::endl;
  215. Timer t;
  216. t.start();
  217. FastMinKernel *fmk = new FastMinKernel ( examples, noise, this->debug );
  218. t.stop();
  219. if (verbose)
  220. std::cerr << "Time used for setting up the fmk object: " << t.getLast() << std::endl;
  221. if (gphyper != NULL)
  222. delete gphyper;
  223. gphyper = new FMKGPHyperparameterOptimization ( confCopy, pf, fmk, confSection );
  224. if (verbose)
  225. cerr << "Learning ..." << endl;
  226. // go go go
  227. gphyper->optimize ( binLabels );
  228. if (verbose)
  229. std::cerr << "optimization done, now prepare for the uncertainty prediction" << std::endl;
  230. if ( ( varianceApproximation != NONE ) )
  231. {
  232. std::cerr << "now prepare for the uncertainty prediction" << std::endl;
  233. switch (varianceApproximation)
  234. {
  235. case APPROXIMATE_ROUGH:
  236. {
  237. gphyper->prepareVarianceApproximationRough();
  238. break;
  239. }
  240. case APPROXIMATE_FINE:
  241. {
  242. gphyper->prepareVarianceApproximationFine();
  243. break;
  244. }
  245. case EXACT:
  246. {
  247. //nothing to prepare
  248. break;
  249. }
  250. default:
  251. {
  252. //nothing to prepare
  253. }
  254. }
  255. }
  256. // clean up all examples ??
  257. if (verbose)
  258. std::cerr << "Learning finished" << std::endl;
  259. }
  260. void GPHIKClassifier::clear ()
  261. {
  262. if ( gphyper != NULL )
  263. delete gphyper;
  264. gphyper = NULL;
  265. }
  266. GPHIKClassifier *GPHIKClassifier::clone () const
  267. {
  268. fthrow(Exception, "GPHIKClassifier: clone() not yet implemented" );
  269. return NULL;
  270. }
  271. void GPHIKClassifier::predictUncertainty( const NICE::SparseVector * example, double & uncertainty )
  272. {
  273. if (gphyper == NULL)
  274. fthrow(Exception, "Classifier not trained yet -- aborting!" );
  275. //we directly store the predictive variances in the vector, that contains the classification uncertainties lateron to save storage
  276. switch (varianceApproximation)
  277. {
  278. case APPROXIMATE_ROUGH:
  279. {
  280. gphyper->computePredictiveVarianceApproximateRough( *example, uncertainty );
  281. break;
  282. }
  283. case APPROXIMATE_FINE:
  284. {
  285. std::cerr << "predict uncertainty fine" << std::endl;
  286. gphyper->computePredictiveVarianceApproximateFine( *example, uncertainty );
  287. break;
  288. }
  289. case EXACT:
  290. {
  291. gphyper->computePredictiveVarianceExact( *example, uncertainty );
  292. break;
  293. }
  294. default:
  295. {
  296. fthrow(Exception, "GPHIKClassifier - your settings disabled the variance approximation needed for uncertainty prediction.");
  297. // uncertainty = numeric_limits<double>::max();
  298. // break;
  299. }
  300. }
  301. }
  302. void GPHIKClassifier::predictUncertainty( const NICE::Vector * example, double & uncertainty )
  303. {
  304. if (gphyper == NULL)
  305. fthrow(Exception, "Classifier not trained yet -- aborting!" );
  306. //we directly store the predictive variances in the vector, that contains the classification uncertainties lateron to save storage
  307. switch (varianceApproximation)
  308. {
  309. case APPROXIMATE_ROUGH:
  310. {
  311. gphyper->computePredictiveVarianceApproximateRough( *example, uncertainty );
  312. break;
  313. }
  314. case APPROXIMATE_FINE:
  315. {
  316. std::cerr << "predict uncertainty fine" << std::endl;
  317. gphyper->computePredictiveVarianceApproximateFine( *example, uncertainty );
  318. break;
  319. }
  320. case EXACT:
  321. {
  322. gphyper->computePredictiveVarianceExact( *example, uncertainty );
  323. break;
  324. }
  325. default:
  326. {
  327. fthrow(Exception, "GPHIKClassifier - your settings disabled the variance approximation needed for uncertainty prediction.");
  328. // uncertainty = numeric_limits<double>::max();
  329. // break;
  330. }
  331. }
  332. }
  333. //---------------------------------------------------------------------
  334. // protected methods
  335. //---------------------------------------------------------------------
  336. void GPHIKClassifier::restore ( std::istream & is, int format )
  337. {
  338. if (is.good())
  339. {
  340. is.precision (numeric_limits<double>::digits10 + 1);
  341. string tmp;
  342. is >> tmp;
  343. is >> confSection;
  344. if (pf != NULL)
  345. {
  346. delete pf;
  347. }
  348. string transform;
  349. is >> transform;
  350. if ( transform == "absexp" )
  351. {
  352. this->pf = new PFAbsExp ();
  353. } else if ( transform == "exp" ) {
  354. this->pf = new PFExp ();
  355. } else {
  356. fthrow(Exception, "Transformation type is unknown " << transform);
  357. }
  358. pf->restore(is, format);
  359. //load every options we determined explicitely
  360. confCopy->clear();
  361. //we do not want to read until the end of the file
  362. confCopy->setIoUntilEndOfFile( false );
  363. confCopy->restore(is, format);
  364. //load every settings as well as default options
  365. this->init(confCopy, confSection);
  366. //first read things from the config
  367. gphyper->initialize ( confCopy, pf );
  368. //then, load everything that we stored explicitely,
  369. // including precomputed matrices, LUTs, eigenvalues, ... and all that stuff
  370. gphyper->restore(is, format);
  371. }
  372. else
  373. {
  374. std::cerr << "GPHIKClassifier::restore -- InStream not initialized - restoring not possible!" << std::endl;
  375. }
  376. }
  377. void GPHIKClassifier::store ( std::ostream & os, int format ) const
  378. {
  379. if (gphyper == NULL)
  380. fthrow(Exception, "Classifier not trained yet -- aborting!" );
  381. if (os.good())
  382. {
  383. os.precision (numeric_limits<double>::digits10 + 1);
  384. os << "confSection: "<< confSection << std::endl;
  385. os << pf->sayYourName() << std::endl;
  386. pf->store(os, format);
  387. //we do not want to read until end of file for restoring
  388. confCopy->setIoUntilEndOfFile(false);
  389. confCopy->store(os,format);
  390. //store the underlying data
  391. //will be done in gphyper->store(of,format)
  392. //store the optimized parameter values and all that stuff
  393. gphyper->store(os, format);
  394. }
  395. else
  396. {
  397. std::cerr << "OutStream not initialized - storing not possible!" << std::endl;
  398. }
  399. }
  400. std::set<int> GPHIKClassifier::getKnownClassNumbers ( ) const
  401. {
  402. if (gphyper == NULL)
  403. fthrow(Exception, "Classifier not trained yet -- aborting!" );
  404. return gphyper->getKnownClassNumbers();
  405. }