GPHIKClassifier.cpp 14 KB

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