GPHIKClassifier.cpp 12 KB

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