GPHIKClassifier.cpp 11 KB

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