GPHIKClassifier.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  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 and 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. if (gphyper == NULL)
  45. this->gphyper = new FMKGPHyperparameterOptimization;
  46. this->noise = conf->gD(confSection, "noise", 0.01);
  47. string transform = conf->gS(confSection, "transform", "absexp" );
  48. if (pf == NULL)
  49. {
  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. }
  66. this->confSection = confSection;
  67. this->verbose = conf->gB(confSection, "verbose", false);
  68. this->debug = conf->gB(confSection, "debug", false);
  69. this->uncertaintyPredictionForClassification = conf->gB( confSection, "uncertaintyPredictionForClassification", false );
  70. if (confCopy != conf)
  71. {
  72. this->confCopy = new Config ( *conf );
  73. //we do not want to read until end of file for restoring
  74. confCopy->setIoUntilEndOfFile(false);
  75. }
  76. //how do we approximate the predictive variance for classification uncertainty?
  77. string varianceApproximationString = conf->gS(confSection, "varianceApproximation", "approximate_fine"); //default: fine approximative uncertainty prediction
  78. if ( (varianceApproximationString.compare("approximate_rough") == 0) || ((varianceApproximationString.compare("1") == 0)) )
  79. {
  80. this->varianceApproximation = APPROXIMATE_ROUGH;
  81. }
  82. else if ( (varianceApproximationString.compare("approximate_fine") == 0) || ((varianceApproximationString.compare("2") == 0)) )
  83. {
  84. this->varianceApproximation = APPROXIMATE_FINE;
  85. }
  86. else if ( (varianceApproximationString.compare("exact") == 0) || ((varianceApproximationString.compare("3") == 0)) )
  87. {
  88. this->varianceApproximation = EXACT;
  89. }
  90. else
  91. {
  92. this->varianceApproximation = NONE;
  93. }
  94. }
  95. void GPHIKClassifier::classify ( const SparseVector * example, int & result, SparseVector & scores )
  96. {
  97. double tmpUncertainty;
  98. this->classify( example, result, scores, tmpUncertainty );
  99. }
  100. void GPHIKClassifier::classify ( const SparseVector * example, int & result, SparseVector & scores, double & uncertainty )
  101. {
  102. scores.clear();
  103. int classno = gphyper->classify ( *example, scores );
  104. if ( scores.size() == 0 ) {
  105. fthrow(Exception, "Zero scores, something is likely to be wrong here: svec.size() = " << example->size() );
  106. }
  107. result = scores.maxElement();
  108. if (uncertaintyPredictionForClassification)
  109. {
  110. if (varianceApproximation != NONE)
  111. {
  112. NICE::Vector uncertainties;
  113. this->predictUncertainty( example, uncertainties );
  114. uncertainty = uncertainties.Max();
  115. }
  116. else
  117. {
  118. //do nothing
  119. uncertainty = std::numeric_limits<double>::max();
  120. }
  121. }
  122. else
  123. {
  124. //do nothing
  125. uncertainty = std::numeric_limits<double>::max();
  126. }
  127. }
  128. /** training process */
  129. void GPHIKClassifier::train ( const std::vector< NICE::SparseVector *> & examples, const NICE::Vector & labels )
  130. {
  131. if (verbose)
  132. std::cerr << "GPHIKClassifier::train" << std::endl;
  133. Timer t;
  134. t.start();
  135. FastMinKernel *fmk = new FastMinKernel ( examples, noise, this->debug );
  136. t.stop();
  137. if (verbose)
  138. std::cerr << "Time used for setting up the fmk object: " << t.getLast() << std::endl;
  139. gphyper = new FMKGPHyperparameterOptimization ( confCopy, pf, fmk, confSection );
  140. if (verbose)
  141. cerr << "Learning ..." << endl;
  142. // go go go
  143. gphyper->optimize ( labels );
  144. if (verbose)
  145. std::cerr << "optimization done, now prepare for the uncertainty prediction" << std::endl;
  146. if ( (varianceApproximation == APPROXIMATE_ROUGH) )
  147. {
  148. //prepare for variance computation (approximative)
  149. gphyper->prepareVarianceApproximation();
  150. }
  151. //for exact variance computation, we do not have to prepare anything
  152. // clean up all examples ??
  153. if (verbose)
  154. std::cerr << "Learning finished" << std::endl;
  155. }
  156. /** training process */
  157. void GPHIKClassifier::train ( const std::vector< SparseVector *> & examples, std::map<int, NICE::Vector> & binLabels )
  158. {
  159. if (verbose)
  160. std::cerr << "GPHIKClassifier::train" << std::endl;
  161. Timer t;
  162. t.start();
  163. FastMinKernel *fmk = new FastMinKernel ( examples, noise, this->debug );
  164. t.stop();
  165. if (verbose)
  166. std::cerr << "Time used for setting up the fmk object: " << t.getLast() << std::endl;
  167. gphyper = new FMKGPHyperparameterOptimization ( confCopy, pf, fmk, confSection );
  168. if (verbose)
  169. cerr << "Learning ..." << endl;
  170. // go go go
  171. gphyper->optimize ( binLabels );
  172. if (verbose)
  173. std::cerr << "optimization done, now prepare for the uncertainty prediction" << std::endl;
  174. if ( (varianceApproximation == APPROXIMATE_ROUGH) )
  175. {
  176. //prepare for variance computation (approximative)
  177. gphyper->prepareVarianceApproximation();
  178. }
  179. //for exact variance computation, we do not have to prepare anything
  180. // clean up all examples ??
  181. if (verbose)
  182. std::cerr << "Learning finished" << std::endl;
  183. }
  184. void GPHIKClassifier::clear ()
  185. {
  186. if ( gphyper != NULL )
  187. delete gphyper;
  188. gphyper = NULL;
  189. }
  190. GPHIKClassifier *GPHIKClassifier::clone () const
  191. {
  192. fthrow(Exception, "GPHIKClassifier: clone() not yet implemented" );
  193. return NULL;
  194. }
  195. void GPHIKClassifier::predictUncertainty( const NICE::SparseVector * example, NICE::Vector & uncertainties )
  196. {
  197. //we directly store the predictive variances in the vector, that contains the classification uncertainties lateron to save storage
  198. switch (varianceApproximation)
  199. {
  200. case APPROXIMATE_ROUGH:
  201. {
  202. gphyper->computePredictiveVarianceApproximateRough( *example, uncertainties );
  203. break;
  204. }
  205. case APPROXIMATE_FINE:
  206. {
  207. gphyper->computePredictiveVarianceApproximateFine( *example, uncertainties );
  208. break;
  209. }
  210. case EXACT:
  211. {
  212. gphyper->computePredictiveVarianceExact( *example, uncertainties );
  213. break;
  214. }
  215. default:
  216. {
  217. // std::cerr << "No Uncertainty Prediction at all" << std::endl;
  218. fthrow(Exception, "GPHIKClassifier - your settings disabled the variance approximation needed for uncertainty prediction.");
  219. // uncertainties.resize( 1 );
  220. // uncertainties.set( numeric_limits<double>::max() );
  221. // break;
  222. }
  223. }
  224. }
  225. //---------------------------------------------------------------------
  226. // protected methods
  227. //---------------------------------------------------------------------
  228. void GPHIKClassifier::restore ( std::istream & is, int format )
  229. {
  230. if (is.good())
  231. {
  232. is.precision (numeric_limits<double>::digits10 + 1);
  233. string tmp;
  234. is >> tmp;
  235. is >> confSection;
  236. if (pf != NULL)
  237. {
  238. delete pf;
  239. }
  240. string transform;
  241. is >> transform;
  242. if ( transform == "absexp" )
  243. {
  244. this->pf = new PFAbsExp ();
  245. } else if ( transform == "exp" ) {
  246. this->pf = new PFExp ();
  247. } else {
  248. fthrow(Exception, "Transformation type is unknown " << transform);
  249. }
  250. pf->restore(is, format);
  251. //load every options we determined explicitely
  252. confCopy->clear();
  253. //we do not want to read until the end of the file
  254. confCopy->setIoUntilEndOfFile( false );
  255. confCopy->restore(is, format);
  256. //load every settings as well as default options
  257. this->init(confCopy, confSection);
  258. //first read things from the config
  259. gphyper->initialize ( confCopy, pf );
  260. //then, load everything that we stored explicitely,
  261. // including precomputed matrices, LUTs, eigenvalues, ... and all that stuff
  262. gphyper->restore(is, format);
  263. }
  264. else
  265. {
  266. std::cerr << "GPHIKClassifier::restore -- InStream not initialized - restoring not possible!" << std::endl;
  267. }
  268. }
  269. void GPHIKClassifier::store ( std::ostream & os, int format ) const
  270. {
  271. if (os.good())
  272. {
  273. os.precision (numeric_limits<double>::digits10 + 1);
  274. os << "confSection: "<< confSection << std::endl;
  275. os << pf->sayYourName() << std::endl;
  276. pf->store(os, format);
  277. //we do not want to read until end of file for restoring
  278. confCopy->setIoUntilEndOfFile(false);
  279. confCopy->store(os,format);
  280. //store the underlying data
  281. //will be done in gphyper->store(of,format)
  282. //store the optimized parameter values and all that stuff
  283. gphyper->store(os, format);
  284. }
  285. else
  286. {
  287. std::cerr << "OutStream not initialized - storing not possible!" << std::endl;
  288. }
  289. }
  290. void GPHIKClassifier::addExample( const NICE::SparseVector * example, const double & label, const bool & performOptimizationAfterIncrement)
  291. {
  292. gphyper->addExample( *example, label, performOptimizationAfterIncrement );
  293. }
  294. void GPHIKClassifier::addMultipleExamples( const std::vector< const NICE::SparseVector *> & newExamples, const NICE::Vector & newLabels, const bool & performOptimizationAfterIncrement)
  295. {
  296. //are new examples available? If not, nothing has to be done
  297. if ( newExamples.size() < 1)
  298. return;
  299. gphyper->addMultipleExamples( newExamples, newLabels, performOptimizationAfterIncrement );
  300. }