FMKGPHyperparameterOptimization.cpp 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395
  1. /**
  2. * @file FMKGPHyperparameterOptimization.cpp
  3. * @brief Heart of the framework to set up everything, perform optimization, classification, and variance prediction (Implementation)
  4. * @author Erik Rodner, Alexander Freytag
  5. * @date 01/02/2012
  6. */
  7. // STL includes
  8. #include <iostream>
  9. #include <map>
  10. // NICE-core includes
  11. #include <core/algebra/ILSConjugateGradients.h>
  12. #include <core/algebra/ILSConjugateGradientsLanczos.h>
  13. #include <core/algebra/ILSSymmLqLanczos.h>
  14. #include <core/algebra/ILSMinResLanczos.h>
  15. #include <core/algebra/ILSPlainGradient.h>
  16. #include <core/algebra/EigValuesTRLAN.h>
  17. #include <core/algebra/CholeskyRobust.h>
  18. //
  19. #include <core/basics/Timer.h>
  20. #include <core/basics/ResourceStatistics.h>
  21. #include <core/basics/Exception.h>
  22. //
  23. #include <core/vector/Algorithms.h>
  24. #include <core/vector/Eigen.h>
  25. //
  26. #include <core/optimization/blackbox/DownhillSimplexOptimizer.h>
  27. // gp-hik-core includes
  28. #include "FMKGPHyperparameterOptimization.h"
  29. #include "FastMinKernel.h"
  30. #include "GMHIKernel.h"
  31. #include "IKMNoise.h"
  32. using namespace NICE;
  33. using namespace std;
  34. FMKGPHyperparameterOptimization::FMKGPHyperparameterOptimization()
  35. {
  36. pf = NULL;
  37. eig = NULL;
  38. linsolver = NULL;
  39. fmk = NULL;
  40. q = NULL;
  41. precomputedTForVarEst = NULL;
  42. verbose = false;
  43. verboseTime = false;
  44. debug = false;
  45. //stupid unneeded default values
  46. binaryLabelPositive = -1;
  47. binaryLabelNegative = -2;
  48. }
  49. FMKGPHyperparameterOptimization::FMKGPHyperparameterOptimization ( const Config *_conf, ParameterizedFunction *_pf, FastMinKernel *_fmk, const string & _confSection )
  50. {
  51. //default settings, may become overwritten lateron
  52. pf = NULL;
  53. eig = NULL;
  54. linsolver = NULL;
  55. fmk = NULL;
  56. q = NULL;
  57. precomputedTForVarEst = NULL;
  58. //stupid unneeded default values
  59. binaryLabelPositive = -1;
  60. binaryLabelNegative = -2;
  61. knownClasses.clear();
  62. //TODO
  63. if ( _fmk == NULL )
  64. this->initialize ( _conf, _pf ); //then the confSection is also the default value
  65. //TODO not needed anymore, only for backword compatibility
  66. // else if ( _confSection.compare ( "HIKGP" ) == 0 )
  67. // this->initialize ( _conf, _pf, _fmk );
  68. else
  69. this->initialize ( _conf, _pf, _fmk, _confSection );
  70. }
  71. FMKGPHyperparameterOptimization::~FMKGPHyperparameterOptimization()
  72. {
  73. //pf will delete from outer program
  74. if ( this->eig != NULL )
  75. delete this->eig;
  76. if ( this->linsolver != NULL )
  77. delete this->linsolver;
  78. if ( this->fmk != NULL )
  79. delete this->fmk;
  80. if ( this->q != NULL )
  81. delete this->q;
  82. for ( uint i = 0 ; i < precomputedT.size(); i++ )
  83. delete [] ( precomputedT[i] );
  84. if ( precomputedTForVarEst != NULL )
  85. delete precomputedTForVarEst;
  86. if ( ikmsum != NULL )
  87. delete ikmsum;
  88. }
  89. void FMKGPHyperparameterOptimization::initialize ( const Config *_conf, ParameterizedFunction *_pf, FastMinKernel *_fmk, const std::string & _confSection )
  90. {
  91. if ( this->fmk != NULL )
  92. delete this->fmk;
  93. if ( _fmk != NULL )
  94. this->fmk = _fmk;
  95. this->pf = _pf;
  96. std::cerr << "------------" << std::endl;
  97. std::cerr << "| set-up |" << std::endl;
  98. std::cerr << "------------" << std::endl;
  99. this->eig = new EVArnoldi ( _conf->gB ( _confSection, "eig_verbose", false ) /* verbose flag */, 10 );
  100. // this->eig = new EigValuesTRLAN();
  101. // My time measurements show that both methods use equal time, a comparision
  102. // of their numerical performance has not been done yet
  103. this->parameterUpperBound = _conf->gD ( _confSection, "parameter_upper_bound", 2.5 );
  104. this->parameterLowerBound = _conf->gD ( _confSection, "parameter_lower_bound", 1.0 );
  105. this->parameterStepSize = _conf->gD ( _confSection, "parameter_step_size", 0.1 );
  106. this->verifyApproximation = _conf->gB ( _confSection, "verify_approximation", false );
  107. this->nrOfEigenvaluesToConsider = _conf->gI ( _confSection, "nrOfEigenvaluesToConsider", 1 );
  108. this->nrOfEigenvaluesToConsiderForVarApprox = _conf->gI ( _confSection, "nrOfEigenvaluesToConsiderForVarApprox", 2 );
  109. this->verbose = _conf->gB ( _confSection, "verbose", false );
  110. this->verboseTime = _conf->gB ( _confSection, "verboseTime", false );
  111. this->debug = _conf->gB ( _confSection, "debug", false );
  112. bool useQuantization = _conf->gB ( _confSection, "use_quantization", false );
  113. std::cerr << "_confSection: " << _confSection << std::endl;
  114. std::cerr << "use_quantization: " << useQuantization << std::endl;
  115. if ( _conf->gB ( _confSection, "use_quantization", false ) ) {
  116. int numBins = _conf->gI ( _confSection, "num_bins", 100 );
  117. if ( verbose )
  118. cerr << "FMKGPHyperparameterOptimization: quantization initialized with " << numBins << " bins." << endl;
  119. this->q = new Quantization ( numBins );
  120. } else {
  121. this->q = NULL;
  122. }
  123. bool ils_verbose = _conf->gB ( _confSection, "ils_verbose", false );
  124. ils_max_iterations = _conf->gI ( _confSection, "ils_max_iterations", 1000 );
  125. if ( verbose )
  126. cerr << "FMKGPHyperparameterOptimization: maximum number of iterations is " << ils_max_iterations << endl;
  127. double ils_min_delta = _conf->gD ( _confSection, "ils_min_delta", 1e-7 );
  128. double ils_min_residual = _conf->gD ( _confSection, "ils_min_residual", 1e-7/*1e-2 */ );
  129. string ils_method = _conf->gS ( _confSection, "ils_method", "CG" );
  130. if ( ils_method.compare ( "CG" ) == 0 )
  131. {
  132. if ( verbose )
  133. std::cerr << "We use CG with " << ils_max_iterations << " iterations, " << ils_min_delta << " as min delta, and " << ils_min_residual << " as min res " << std::endl;
  134. this->linsolver = new ILSConjugateGradients ( ils_verbose , ils_max_iterations, ils_min_delta, ils_min_residual );
  135. if ( verbose )
  136. cerr << "FMKGPHyperparameterOptimization: using ILS ConjugateGradients" << endl;
  137. }
  138. else if ( ils_method.compare ( "CGL" ) == 0 )
  139. {
  140. this->linsolver = new ILSConjugateGradientsLanczos ( ils_verbose , ils_max_iterations );
  141. if ( verbose )
  142. cerr << "FMKGPHyperparameterOptimization: using ILS ConjugateGradients (Lanczos)" << endl;
  143. }
  144. else if ( ils_method.compare ( "SYMMLQ" ) == 0 )
  145. {
  146. this->linsolver = new ILSSymmLqLanczos ( ils_verbose , ils_max_iterations );
  147. if ( verbose )
  148. cerr << "FMKGPHyperparameterOptimization: using ILS SYMMLQ" << endl;
  149. }
  150. else if ( ils_method.compare ( "MINRES" ) == 0 )
  151. {
  152. this->linsolver = new ILSMinResLanczos ( ils_verbose , ils_max_iterations );
  153. if ( verbose )
  154. cerr << "FMKGPHyperparameterOptimization: using ILS MINRES" << endl;
  155. }
  156. else
  157. {
  158. cerr << "FMKGPHyperparameterOptimization: " << _confSection << ":ils_method (" << ils_method << ") does not match any type (CG,CGL,SYMMLQ,MINRES), I will use CG" << endl;
  159. this->linsolver = new ILSConjugateGradients ( ils_verbose , ils_max_iterations, ils_min_delta, ils_min_residual );
  160. }
  161. string optimizationMethod_s = _conf->gS ( _confSection, "optimization_method", "greedy" );
  162. if ( optimizationMethod_s == "greedy" )
  163. optimizationMethod = OPT_GREEDY;
  164. else if ( optimizationMethod_s == "downhillsimplex" )
  165. optimizationMethod = OPT_DOWNHILLSIMPLEX;
  166. else if ( optimizationMethod_s == "none" )
  167. optimizationMethod = OPT_NONE;
  168. else
  169. fthrow ( Exception, "Optimization method " << optimizationMethod_s << " is not known." );
  170. if ( verbose )
  171. cerr << "Using optimization method: " << optimizationMethod_s << endl;
  172. downhillSimplexMaxIterations = _conf->gI ( _confSection, "downhillsimplex_max_iterations", 20 );
  173. // do not run longer than a day :)
  174. downhillSimplexTimeLimit = _conf->gD ( _confSection, "downhillsimplex_time_limit", 24 * 60 * 60 );
  175. downhillSimplexParamTol = _conf->gD ( _confSection, "downhillsimplex_delta", 0.01 );
  176. optimizeNoise = _conf->gB ( _confSection, "optimize_noise", false );
  177. if ( verbose )
  178. cerr << "Optimize noise: " << ( optimizeNoise ? "on" : "off" ) << endl;
  179. std::cerr << "------------" << std::endl;
  180. std::cerr << "| start |" << std::endl;
  181. std::cerr << "------------" << std::endl;
  182. }
  183. // get and set methods
  184. void FMKGPHyperparameterOptimization::setParameterUpperBound ( const double & _parameterUpperBound )
  185. {
  186. parameterUpperBound = _parameterUpperBound;
  187. }
  188. void FMKGPHyperparameterOptimization::setParameterLowerBound ( const double & _parameterLowerBound )
  189. {
  190. parameterLowerBound = _parameterLowerBound;
  191. }
  192. std::set<int> FMKGPHyperparameterOptimization::getKnownClassNumbers ( ) const
  193. {
  194. return this->knownClasses;
  195. }
  196. //high level methods
  197. void FMKGPHyperparameterOptimization::setupGPLikelihoodApprox ( GPLikelihoodApprox * & gplike, const std::map<int, NICE::Vector> & binaryLabels, uint & parameterVectorSize )
  198. {
  199. gplike = new GPLikelihoodApprox ( binaryLabels, ikmsum, linsolver, eig, verifyApproximation, nrOfEigenvaluesToConsider );
  200. gplike->setDebug( debug );
  201. gplike->setVerbose( verbose );
  202. parameterVectorSize = ikmsum->getNumParameters();
  203. }
  204. void FMKGPHyperparameterOptimization::updateEigenDecomposition( const int & i_noEigenValues )
  205. {
  206. //compute the largest eigenvalue of K + noise
  207. try
  208. {
  209. eig->getEigenvalues ( *ikmsum, eigenMax, eigenMaxVectors, i_noEigenValues );
  210. }
  211. catch ( char const* exceptionMsg)
  212. {
  213. std::cerr << exceptionMsg << std::endl;
  214. throw("Problem in calculating Eigendecomposition of kernel matrix. Abort program...");
  215. }
  216. // EigenValue computation does not necessarily extract them in decreasing order.
  217. // Therefore: sort eigenvalues decreasingly!
  218. NICE::VectorT< int > ewPermutation;
  219. eigenMax.sortDescend ( ewPermutation );
  220. }
  221. void FMKGPHyperparameterOptimization::performOptimization ( GPLikelihoodApprox & gplike, const uint & parameterVectorSize )
  222. {
  223. if (verbose)
  224. std::cerr << "perform optimization" << std::endl;
  225. if ( optimizationMethod == OPT_GREEDY )
  226. {
  227. if ( verbose )
  228. std::cerr << "OPT_GREEDY!!! " << std::endl;
  229. // simple greedy strategy
  230. if ( ikmsum->getNumParameters() != 1 )
  231. fthrow ( Exception, "Reduce size of the parameter vector or use downhill simplex!" );
  232. NICE::Vector lB = ikmsum->getParameterLowerBounds();
  233. NICE::Vector uB = ikmsum->getParameterUpperBounds();
  234. if ( verbose )
  235. cerr << "lower bound " << lB << " upper bound " << uB << " parameterStepSize: " << parameterStepSize << endl;
  236. NICE::Vector tmp = gplike.getBestParameters( );
  237. for ( double mypara = lB[0]; mypara <= uB[0]; mypara += this->parameterStepSize )
  238. {
  239. OPTIMIZATION::matrix_type hyperp ( 1, 1, mypara );
  240. gplike.evaluate ( hyperp );
  241. }
  242. }
  243. else if ( optimizationMethod == OPT_DOWNHILLSIMPLEX )
  244. {
  245. //standard as before, normal optimization
  246. if ( verbose )
  247. std::cerr << "DOWNHILLSIMPLEX WITHOUT BALANCED LEARNING!!! " << std::endl;
  248. // downhill simplex strategy
  249. OPTIMIZATION::DownhillSimplexOptimizer optimizer;
  250. OPTIMIZATION::matrix_type initialParams ( parameterVectorSize, 1 );
  251. NICE::Vector currentParameters;
  252. ikmsum->getParameters ( currentParameters );
  253. for ( uint i = 0 ; i < parameterVectorSize; i++ )
  254. initialParams(i,0) = currentParameters[ i ];
  255. if ( verbose )
  256. std::cerr << "Initial parameters: " << initialParams << std::endl;
  257. //the scales object does not really matter in the actual implementation of Downhill Simplex
  258. //OPTIMIZATION::matrix_type scales ( parameterVectorSize, 1);
  259. //cales.Set(1.0);
  260. OPTIMIZATION::SimpleOptProblem optProblem ( &gplike, initialParams, initialParams /* scales*/ );
  261. // cerr << "OPT: " << mypara << " " << nlikelihood << " " << logdet << " " << dataterm << endl;
  262. optimizer.setMaxNumIter ( true, downhillSimplexMaxIterations );
  263. optimizer.setTimeLimit ( true, downhillSimplexTimeLimit );
  264. optimizer.setParamTol ( true, downhillSimplexParamTol );
  265. optimizer.optimizeProb ( optProblem );
  266. }
  267. else if ( optimizationMethod == OPT_NONE )
  268. {
  269. if ( verbose )
  270. std::cerr << "NO OPTIMIZATION!!! " << std::endl;
  271. // without optimization
  272. if ( optimizeNoise )
  273. fthrow ( Exception, "Deactivate optimize_noise!" );
  274. if ( verbose )
  275. std::cerr << "Optimization is deactivated!" << std::endl;
  276. double value (1.0);
  277. if ( this->parameterLowerBound == this->parameterUpperBound)
  278. value = this->parameterLowerBound;
  279. pf->setParameterLowerBounds ( NICE::Vector ( 1, value ) );
  280. pf->setParameterUpperBounds ( NICE::Vector ( 1, value ) );
  281. // we use the standard value
  282. OPTIMIZATION::matrix_type hyperp ( 1, 1, value );
  283. gplike.setParameterLowerBound ( value );
  284. gplike.setParameterUpperBound ( value );
  285. //we do not need to compute the likelihood here - we are only interested in directly obtaining alpha vectors
  286. gplike.computeAlphaDirect( hyperp, eigenMax );
  287. }
  288. if ( verbose )
  289. std::cerr << "Optimal hyperparameter was: " << gplike.getBestParameters() << std::endl;
  290. std::map<int, Vector> bestAlphas = gplike.getBestAlphas();
  291. std::cerr << "length of alpha vectors: " << bestAlphas.size() << std::endl;
  292. std::cerr << "alpha vector: " << bestAlphas.begin()->second << std::endl;
  293. }
  294. void FMKGPHyperparameterOptimization::transformFeaturesWithOptimalParameters ( const GPLikelihoodApprox & gplike, const uint & parameterVectorSize )
  295. {
  296. // transform all features with the "optimal" parameter
  297. ikmsum->setParameters ( gplike.getBestParameters() );
  298. }
  299. void FMKGPHyperparameterOptimization::computeMatricesAndLUTs ( const GPLikelihoodApprox & gplike )
  300. {
  301. precomputedA.clear();
  302. precomputedB.clear();
  303. for ( std::map<int, NICE::Vector>::const_iterator i = gplike.getBestAlphas().begin(); i != gplike.getBestAlphas().end(); i++ )
  304. {
  305. PrecomputedType A;
  306. PrecomputedType B;
  307. fmk->hik_prepare_alpha_multiplications ( i->second, A, B );
  308. A.setIoUntilEndOfFile ( false );
  309. B.setIoUntilEndOfFile ( false );
  310. precomputedA[ i->first ] = A;
  311. precomputedB[ i->first ] = B;
  312. if ( q != NULL )
  313. {
  314. double *T = fmk->hik_prepare_alpha_multiplications_fast ( A, B, *q, pf );
  315. //just to be sure that we do not waste space here
  316. if ( precomputedT[ i->first ] != NULL )
  317. delete precomputedT[ i->first ];
  318. precomputedT[ i->first ] = T;
  319. }
  320. //TODO update the variance-related matrices as well here - currently it is done before in the outer method!!!
  321. }
  322. }
  323. #ifdef NICE_USELIB_MATIO
  324. void FMKGPHyperparameterOptimization::optimizeBinary ( const sparse_t & data, const NICE::Vector & yl, const std::set<int> & positives, const std::set<int> & negatives, double noise )
  325. {
  326. map<int, int> examples;
  327. Vector y ( yl.size() );
  328. int ind = 0;
  329. for ( uint i = 0 ; i < yl.size(); i++ )
  330. {
  331. if ( positives.find ( i ) != positives.end() ) {
  332. y[ examples.size() ] = 1.0;
  333. examples.insert ( pair<int, int> ( i, ind ) );
  334. ind++;
  335. } else if ( negatives.find ( i ) != negatives.end() ) {
  336. y[ examples.size() ] = -1.0;
  337. examples.insert ( pair<int, int> ( i, ind ) );
  338. ind++;
  339. }
  340. }
  341. y.resize ( examples.size() );
  342. cerr << "Examples: " << examples.size() << endl;
  343. optimize ( data, y, examples, noise );
  344. }
  345. void FMKGPHyperparameterOptimization::optimize ( const sparse_t & data, const NICE::Vector & y, const std::map<int, int> & examples, double noise )
  346. {
  347. Timer t;
  348. t.start();
  349. cerr << "Initializing data structure ..." << std::endl;
  350. if ( fmk != NULL ) delete fmk;
  351. fmk = new FastMinKernel ( data, noise, examples );
  352. t.stop();
  353. if (verboseTime)
  354. std::cerr << "Time used for initializing the FastMinKernel structure: " << t.getLast() << std::endl;
  355. optimize ( y );
  356. }
  357. #endif
  358. int FMKGPHyperparameterOptimization::prepareBinaryLabels ( std::map<int, NICE::Vector> & binaryLabels, const NICE::Vector & y , std::set<int> & myClasses )
  359. {
  360. myClasses.clear();
  361. // determine which classes we have in our label vector
  362. // -> MATLAB: myClasses = unique(y);
  363. for ( NICE::Vector::const_iterator it = y.begin(); it != y.end(); it++ )
  364. {
  365. if ( myClasses.find ( *it ) == myClasses.end() )
  366. {
  367. myClasses.insert ( *it );
  368. }
  369. }
  370. //count how many different classes appear in our data
  371. int nrOfClasses = myClasses.size();
  372. binaryLabels.clear();
  373. //compute the corresponding binary label vectors
  374. if ( nrOfClasses > 2 )
  375. {
  376. //resize every labelVector and set all entries to -1.0
  377. for ( set<int>::const_iterator k = myClasses.begin(); k != myClasses.end(); k++ )
  378. {
  379. binaryLabels[ *k ].resize ( y.size() );
  380. binaryLabels[ *k ].set ( -1.0 );
  381. }
  382. // now look on every example and set the entry of its corresponding label vector to 1.0
  383. // proper existance should not be a problem
  384. for ( int i = 0 ; i < ( int ) y.size(); i++ )
  385. binaryLabels[ y[i] ][i] = 1.0;
  386. }
  387. else if ( nrOfClasses == 2 )
  388. {
  389. //binary setting -- prepare two binary label vectors with opposite signs
  390. NICE::Vector yb ( y );
  391. binaryLabelNegative = *(myClasses.begin());
  392. std::set<int>::const_iterator classIt = myClasses.begin(); classIt++;
  393. binaryLabelPositive = *classIt;
  394. if ( verbose )
  395. std::cerr << "positiveClass : " << binaryLabelPositive << " negativeClass: " << binaryLabelNegative << std::endl;
  396. for ( uint i = 0 ; i < yb.size() ; i++ )
  397. yb[i] = ( y[i] == binaryLabelNegative ) ? -1.0 : 1.0;
  398. binaryLabels[ binaryLabelPositive ] = yb;
  399. //NOTE
  400. //uncomment the following, if you want to perform real binary computations with 2 classes
  401. // //we only need one vector, which already contains +1 and -1, so we need only one computation too
  402. // binaryLabels[ negativeClass ] = yb;
  403. // binaryLabels[ negativeClass ] *= -1.0;
  404. // std::cerr << "binaryLabels.size(): " << binaryLabels.size() << std::endl;
  405. // binaryLabels[ 0 ] = yb;
  406. // binaryLabels[ 0 ] *= -1.0;
  407. //comment the following, if you want to do a real binary computation. It should be senseless, but let's see...
  408. //we do NOT do real binary computation, but an implicite one with only a single object
  409. nrOfClasses--;
  410. std::set<int>::iterator it = myClasses.begin(); it++;
  411. // myClasses.erase(it);
  412. }
  413. else //OCC setting
  414. {
  415. //we set the labels to 1, independent of the previously given class number
  416. //however, the original class numbers are stored and returned in classification
  417. Vector yNew ( y.size(), 1 );
  418. myClasses.clear();
  419. myClasses.insert ( 1 );
  420. //we have to indicate, that we are in an OCC setting
  421. nrOfClasses--;
  422. }
  423. return nrOfClasses;
  424. }
  425. void FMKGPHyperparameterOptimization::optimize ( const NICE::Vector & y )
  426. {
  427. if ( fmk == NULL )
  428. fthrow ( Exception, "FastMinKernel object was not initialized!" );
  429. this->labels = y;
  430. std::map<int, NICE::Vector> binaryLabels;
  431. prepareBinaryLabels ( binaryLabels, y , knownClasses );
  432. //now call the main function :)
  433. this->optimize(binaryLabels);
  434. }
  435. void FMKGPHyperparameterOptimization::optimize ( std::map<int, NICE::Vector> & binaryLabels )
  436. {
  437. Timer t;
  438. t.start();
  439. //how many different classes do we have right now?
  440. int nrOfClasses = binaryLabels.size();
  441. if (verbose)
  442. {
  443. std::cerr << "Initial noise level: " << fmk->getNoise() << endl;
  444. std::cerr << "Number of classes (=1 means we have a binary setting):" << nrOfClasses << std::endl;
  445. std::cerr << "Effective number of classes (neglecting classes without positive examples): " << knownClasses.size() << std::endl;
  446. }
  447. // combine standard model and noise model
  448. Timer t1;
  449. t1.start();
  450. //setup the kernel combination
  451. ikmsum = new IKMLinearCombination ();
  452. if ( verbose )
  453. {
  454. std::cerr << "binaryLabels.size(): " << binaryLabels.size() << std::endl;
  455. }
  456. //First model: noise
  457. ikmsum->addModel ( new IKMNoise ( fmk->get_n(), fmk->getNoise(), optimizeNoise ) );
  458. // set pretty low built-in noise, because we explicitely add the noise with the IKMNoise
  459. fmk->setNoise ( 0.0 );
  460. //NOTE The GMHIKernel is always the last model which is added (this is necessary for easy store and restore functionality)
  461. ikmsum->addModel ( new GMHIKernel ( fmk, pf, NULL /* no quantization */ ) );
  462. t1.stop();
  463. if (verboseTime)
  464. std::cerr << "Time used for setting up the ikm-objects: " << t1.getLast() << std::endl;
  465. GPLikelihoodApprox * gplike;
  466. uint parameterVectorSize;
  467. t1.start();
  468. this->setupGPLikelihoodApprox ( gplike, binaryLabels, parameterVectorSize );
  469. t1.stop();
  470. if (verboseTime)
  471. std::cerr << "Time used for setting up the gplike-objects: " << t1.getLast() << std::endl;
  472. if (verbose)
  473. {
  474. std::cerr << "parameterVectorSize: " << parameterVectorSize << std::endl;
  475. }
  476. t1.start();
  477. this->updateEigenDecomposition( this->nrOfEigenvaluesToConsider );
  478. t1.stop();
  479. if (verboseTime)
  480. std::cerr << "Time used for setting up the eigenvectors-objects: " << t1.getLast() << std::endl;
  481. if ( verbose )
  482. std::cerr << "resulting eigenvalues for first class: " << eigenMax[0] << std::endl;
  483. t1.start();
  484. this->performOptimization ( *gplike, parameterVectorSize );
  485. t1.stop();
  486. if (verboseTime)
  487. std::cerr << "Time used for performing the optimization: " << t1.getLast() << std::endl;
  488. if ( verbose )
  489. cerr << "Preparing classification ..." << endl;
  490. t1.start();
  491. this->transformFeaturesWithOptimalParameters ( *gplike, parameterVectorSize );
  492. t1.stop();
  493. if (verboseTime)
  494. std::cerr << "Time used for transforming features with optimal parameters: " << t1.getLast() << std::endl;
  495. t1.start();
  496. this->computeMatricesAndLUTs ( *gplike );
  497. t1.stop();
  498. if (verboseTime)
  499. std::cerr << "Time used for setting up the A'nB -objects: " << t1.getLast() << std::endl;
  500. t.stop();
  501. ResourceStatistics rs;
  502. std::cerr << "Time used for learning: " << t.getLast() << std::endl;
  503. long maxMemory;
  504. rs.getMaximumMemory ( maxMemory );
  505. std::cerr << "Maximum memory used: " << maxMemory << " KB" << std::endl;
  506. //don't waste memory
  507. delete gplike;
  508. }
  509. void FMKGPHyperparameterOptimization::prepareVarianceApproximationRough()
  510. {
  511. PrecomputedType AVar;
  512. fmk->hikPrepareKVNApproximation ( AVar );
  513. precomputedAForVarEst = AVar;
  514. precomputedAForVarEst.setIoUntilEndOfFile ( false );
  515. if ( q != NULL )
  516. {
  517. double *T = fmk->hikPrepareLookupTableForKVNApproximation ( *q, pf );
  518. precomputedTForVarEst = T;
  519. }
  520. }
  521. void FMKGPHyperparameterOptimization::prepareVarianceApproximationFine()
  522. {
  523. this->updateEigenDecomposition( this->nrOfEigenvaluesToConsiderForVarApprox );
  524. }
  525. int FMKGPHyperparameterOptimization::classify ( const NICE::SparseVector & xstar, NICE::SparseVector & scores ) const
  526. {
  527. // loop through all classes
  528. if ( precomputedA.size() == 0 )
  529. {
  530. fthrow ( Exception, "The precomputation vector is zero...have you trained this classifier?" );
  531. }
  532. uint maxClassNo = 0;
  533. for ( std::map<int, PrecomputedType>::const_iterator i = precomputedA.begin() ; i != precomputedA.end(); i++ )
  534. {
  535. uint classno = i->first;
  536. maxClassNo = std::max ( maxClassNo, classno );
  537. double beta;
  538. if ( q != NULL ) {
  539. map<int, double *>::const_iterator j = precomputedT.find ( classno );
  540. double *T = j->second;
  541. fmk->hik_kernel_sum_fast ( T, *q, xstar, beta );
  542. } else {
  543. const PrecomputedType & A = i->second;
  544. std::map<int, PrecomputedType>::const_iterator j = precomputedB.find ( classno );
  545. const PrecomputedType & B = j->second;
  546. // fmk->hik_kernel_sum ( A, B, xstar, beta ); if A, B are of type Matrix
  547. // Giving the transformation pf as an additional
  548. // argument is necessary due to the following reason:
  549. // FeatureMatrixT is sorted according to the original values, therefore,
  550. // searching for upper and lower bounds ( findFirst... functions ) require original feature
  551. // values as inputs. However, for calculation we need the transformed features values.
  552. fmk->hik_kernel_sum ( A, B, xstar, beta, pf );
  553. }
  554. scores[ classno ] = beta;
  555. }
  556. scores.setDim ( maxClassNo + 1 );
  557. if ( precomputedA.size() > 1 )
  558. { // multi-class classification
  559. return scores.maxElement();
  560. }
  561. else
  562. { // binary setting
  563. scores[binaryLabelNegative] = -scores[binaryLabelPositive];
  564. return scores[ binaryLabelPositive ] <= 0.0 ? binaryLabelNegative : binaryLabelPositive;
  565. }
  566. }
  567. int FMKGPHyperparameterOptimization::classify ( const NICE::Vector & xstar, NICE::SparseVector & scores ) const
  568. {
  569. // loop through all classes
  570. if ( precomputedA.size() == 0 )
  571. {
  572. fthrow ( Exception, "The precomputation vector is zero...have you trained this classifier?" );
  573. }
  574. uint maxClassNo = 0;
  575. for ( std::map<int, PrecomputedType>::const_iterator i = precomputedA.begin() ; i != precomputedA.end(); i++ )
  576. {
  577. uint classno = i->first;
  578. maxClassNo = std::max ( maxClassNo, classno );
  579. double beta;
  580. if ( q != NULL ) {
  581. std::map<int, double *>::const_iterator j = precomputedT.find ( classno );
  582. double *T = j->second;
  583. fmk->hik_kernel_sum_fast ( T, *q, xstar, beta );
  584. } else {
  585. const PrecomputedType & A = i->second;
  586. std::map<int, PrecomputedType>::const_iterator j = precomputedB.find ( classno );
  587. const PrecomputedType & B = j->second;
  588. // fmk->hik_kernel_sum ( A, B, xstar, beta ); if A, B are of type Matrix
  589. // Giving the transformation pf as an additional
  590. // argument is necessary due to the following reason:
  591. // FeatureMatrixT is sorted according to the original values, therefore,
  592. // searching for upper and lower bounds ( findFirst... functions ) require original feature
  593. // values as inputs. However, for calculation we need the transformed features values.
  594. fmk->hik_kernel_sum ( A, B, xstar, beta, pf );
  595. }
  596. scores[ classno ] = beta;
  597. }
  598. scores.setDim ( maxClassNo + 1 );
  599. if ( precomputedA.size() > 1 )
  600. { // multi-class classification
  601. return scores.maxElement();
  602. }
  603. else
  604. { // binary setting
  605. scores[binaryLabelNegative] = -scores[binaryLabelPositive];
  606. return scores[ binaryLabelPositive ] <= 0.0 ? binaryLabelNegative : binaryLabelPositive;
  607. }
  608. }
  609. //////////////////////////////////////////
  610. // variance computation: sparse inputs
  611. //////////////////////////////////////////
  612. void FMKGPHyperparameterOptimization::computePredictiveVarianceApproximateRough ( const NICE::SparseVector & x, double & predVariance ) const
  613. {
  614. // security check!
  615. if ( pf == NULL )
  616. fthrow ( Exception, "pf is NULL...have you prepared the uncertainty prediction? Aborting..." );
  617. // ---------------- compute the first term --------------------
  618. double kSelf ( 0.0 );
  619. for ( NICE::SparseVector::const_iterator it = x.begin(); it != x.end(); it++ )
  620. {
  621. kSelf += pf->f ( 0, it->second );
  622. // if weighted dimensions:
  623. //kSelf += pf->f(it->first,it->second);
  624. }
  625. // ---------------- compute the approximation of the second term --------------------
  626. double normKStar;
  627. if ( q != NULL )
  628. {
  629. if ( precomputedTForVarEst == NULL )
  630. {
  631. fthrow ( Exception, "The precomputed LUT for uncertainty prediction is NULL...have you prepared the uncertainty prediction? Aborting..." );
  632. }
  633. fmk->hikComputeKVNApproximationFast ( precomputedTForVarEst, *q, x, normKStar );
  634. }
  635. else
  636. {
  637. if ( precomputedAForVarEst.size () == 0 )
  638. {
  639. fthrow ( Exception, "The precomputedAForVarEst is empty...have you trained this classifer? Aborting..." );
  640. }
  641. fmk->hikComputeKVNApproximation ( precomputedAForVarEst, x, normKStar, pf );
  642. }
  643. predVariance = kSelf - ( 1.0 / eigenMax[0] )* normKStar;
  644. }
  645. void FMKGPHyperparameterOptimization::computePredictiveVarianceApproximateFine ( const NICE::SparseVector & x, double & predVariance ) const
  646. {
  647. // security check!
  648. if ( eigenMaxVectors.rows() == 0 )
  649. {
  650. fthrow ( Exception, "eigenMaxVectors is empty...have you trained this classifer? Aborting..." );
  651. }
  652. // ---------------- compute the first term --------------------
  653. // Timer t;
  654. // t.start();
  655. double kSelf ( 0.0 );
  656. for ( NICE::SparseVector::const_iterator it = x.begin(); it != x.end(); it++ )
  657. {
  658. kSelf += pf->f ( 0, it->second );
  659. // if weighted dimensions:
  660. //kSelf += pf->f(it->first,it->second);
  661. }
  662. // ---------------- compute the approximation of the second term --------------------
  663. // t.stop();
  664. // std::cerr << "ApproxFine -- time for first term: " << t.getLast() << std::endl;
  665. // t.start();
  666. NICE::Vector kStar;
  667. fmk->hikComputeKernelVector ( x, kStar );
  668. /* t.stop();
  669. std::cerr << "ApproxFine -- time for kernel vector: " << t.getLast() << std::endl;*/
  670. // NICE::Vector multiplicationResults; // will contain nrOfEigenvaluesToConsiderForVarApprox many entries
  671. // multiplicationResults.multiply ( *eigenMaxVectorIt, kStar, true/* transpose */ );
  672. NICE::Vector multiplicationResults( nrOfEigenvaluesToConsiderForVarApprox-1, 0.0 );
  673. //ok, there seems to be a nasty thing in computing multiplicationResults.multiply ( *eigenMaxVectorIt, kStar, true/* transpose */ );
  674. //wherefor it takes aeons...
  675. //so we compute it by ourselves
  676. // for ( uint tmpI = 0; tmpI < kStar.size(); tmpI++)
  677. NICE::Matrix::const_iterator eigenVecIt = eigenMaxVectors.begin();
  678. // double kStarI ( kStar[tmpI] );
  679. for ( int tmpJ = 0; tmpJ < nrOfEigenvaluesToConsiderForVarApprox-1; tmpJ++)
  680. {
  681. for ( NICE::Vector::const_iterator kStarIt = kStar.begin(); kStarIt != kStar.end(); kStarIt++,eigenVecIt++)
  682. {
  683. multiplicationResults[tmpJ] += (*kStarIt) * (*eigenVecIt);//eigenMaxVectors(tmpI,tmpJ);
  684. }
  685. }
  686. double projectionLength ( 0.0 );
  687. double currentSecondTerm ( 0.0 );
  688. double sumOfProjectionLengths ( 0.0 );
  689. int cnt ( 0 );
  690. NICE::Vector::const_iterator it = multiplicationResults.begin();
  691. while ( cnt < ( nrOfEigenvaluesToConsiderForVarApprox - 1 ) )
  692. {
  693. projectionLength = ( *it );
  694. currentSecondTerm += ( 1.0 / eigenMax[cnt] ) * pow ( projectionLength, 2 );
  695. sumOfProjectionLengths += pow ( projectionLength, 2 );
  696. it++;
  697. cnt++;
  698. }
  699. double normKStar ( pow ( kStar.normL2 (), 2 ) );
  700. currentSecondTerm += ( 1.0 / eigenMax[nrOfEigenvaluesToConsiderForVarApprox-1] ) * ( normKStar - sumOfProjectionLengths );
  701. if ( ( normKStar - sumOfProjectionLengths ) < 0 )
  702. {
  703. std::cerr << "Attention: normKStar - sumOfProjectionLengths is smaller than zero -- strange!" << std::endl;
  704. }
  705. predVariance = kSelf - currentSecondTerm;
  706. }
  707. void FMKGPHyperparameterOptimization::computePredictiveVarianceExact ( const NICE::SparseVector & x, double & predVariance ) const
  708. {
  709. // security check!
  710. if ( ikmsum->getNumberOfModels() == 0 )
  711. {
  712. fthrow ( Exception, "ikmsum is empty... have you trained this classifer? Aborting..." );
  713. }
  714. Timer t;
  715. // t.start();
  716. // ---------------- compute the first term --------------------
  717. double kSelf ( 0.0 );
  718. for ( NICE::SparseVector::const_iterator it = x.begin(); it != x.end(); it++ )
  719. {
  720. kSelf += pf->f ( 0, it->second );
  721. // if weighted dimensions:
  722. //kSelf += pf->f(it->first,it->second);
  723. }
  724. // ---------------- compute the second term --------------------
  725. // t.stop();
  726. // std::cerr << "ApproxExact -- time for first term: " << t.getLast() << std::endl;
  727. // t.start();
  728. NICE::Vector kStar;
  729. fmk->hikComputeKernelVector ( x, kStar );
  730. // t.stop();
  731. // std::cerr << "ApproxExact -- time for kernel vector: " << t.getLast() << std::endl;
  732. //
  733. //now run the ILS method
  734. NICE::Vector diagonalElements;
  735. ikmsum->getDiagonalElements ( diagonalElements );
  736. // t.start();
  737. // init simple jacobi pre-conditioning
  738. ILSConjugateGradients *linsolver_cg = dynamic_cast<ILSConjugateGradients *> ( linsolver );
  739. //perform pre-conditioning
  740. if ( linsolver_cg != NULL )
  741. linsolver_cg->setJacobiPreconditioner ( diagonalElements );
  742. NICE::Vector beta;
  743. /** About finding a good initial solution (see also GPLikelihoodApproximation)
  744. * K~ = K + sigma^2 I
  745. *
  746. * K~ \approx lambda_max v v^T
  747. * \lambda_max v v^T * alpha = k_* | multiply with v^T from left
  748. * => \lambda_max v^T alpha = v^T k_*
  749. * => alpha = k_* / lambda_max could be a good initial start
  750. * If we put everything in the first equation this gives us
  751. * v = k_*
  752. * This reduces the number of iterations by 5 or 8
  753. */
  754. beta = (kStar * (1.0 / eigenMax[0]) );
  755. /* t.stop();
  756. std::cerr << "ApproxExact -- time for preconditioning etc: " << t.getLast() << std::endl;
  757. t.start();*/
  758. // t.start();
  759. linsolver->solveLin ( *ikmsum, kStar, beta );
  760. // t.stop();
  761. // t.stop();
  762. // t.stop();
  763. // std::cerr << "ApproxExact -- time for lin solve: " << t.getLast() << std::endl;
  764. beta *= kStar;
  765. double currentSecondTerm( beta.Sum() );
  766. predVariance = kSelf - currentSecondTerm;
  767. }
  768. //////////////////////////////////////////
  769. // variance computation: non-sparse inputs
  770. //////////////////////////////////////////
  771. void FMKGPHyperparameterOptimization::computePredictiveVarianceApproximateRough ( const NICE::Vector & x, double & predVariance ) const
  772. {
  773. // security check!
  774. if ( pf == NULL )
  775. fthrow ( Exception, "pf is NULL...have you prepared the uncertainty prediction? Aborting..." );
  776. // ---------------- compute the first term --------------------
  777. double kSelf ( 0.0 );
  778. int dim ( 0 );
  779. for ( NICE::Vector::const_iterator it = x.begin(); it != x.end(); it++, dim++ )
  780. {
  781. kSelf += pf->f ( 0, *it );
  782. // if weighted dimensions:
  783. //kSelf += pf->f(dim,*it);
  784. }
  785. // ---------------- compute the approximation of the second term --------------------
  786. double normKStar;
  787. if ( q != NULL )
  788. {
  789. if ( precomputedTForVarEst == NULL )
  790. {
  791. fthrow ( Exception, "The precomputed LUT for uncertainty prediction is NULL...have you prepared the uncertainty prediction? Aborting..." );
  792. }
  793. fmk->hikComputeKVNApproximationFast ( precomputedTForVarEst, *q, x, normKStar );
  794. }
  795. else
  796. {
  797. if ( precomputedAForVarEst.size () == 0 )
  798. {
  799. fthrow ( Exception, "The precomputedAForVarEst is empty...have you trained this classifer? Aborting..." );
  800. }
  801. fmk->hikComputeKVNApproximation ( precomputedAForVarEst, x, normKStar, pf );
  802. }
  803. predVariance = kSelf - ( 1.0 / eigenMax[0] )* normKStar;
  804. }
  805. void FMKGPHyperparameterOptimization::computePredictiveVarianceApproximateFine ( const NICE::Vector & x, double & predVariance ) const
  806. {
  807. // security check!
  808. if ( eigenMaxVectors.rows() == 0 )
  809. {
  810. fthrow ( Exception, "eigenMaxVectors is empty...have you trained this classifer? Aborting..." );
  811. }
  812. // ---------------- compute the first term --------------------
  813. // Timer t;
  814. // t.start();
  815. double kSelf ( 0.0 );
  816. int dim ( 0 );
  817. for ( NICE::Vector::const_iterator it = x.begin(); it != x.end(); it++, dim++ )
  818. {
  819. kSelf += pf->f ( 0, *it );
  820. // if weighted dimensions:
  821. //kSelf += pf->f(dim,*it);
  822. }
  823. // ---------------- compute the approximation of the second term --------------------
  824. // t.stop();
  825. // std::cerr << "ApproxFine -- time for first term: " << t.getLast() << std::endl;
  826. // t.start();
  827. NICE::Vector kStar;
  828. fmk->hikComputeKernelVector ( x, kStar );
  829. /* t.stop();
  830. std::cerr << "ApproxFine -- time for kernel vector: " << t.getLast() << std::endl;*/
  831. // NICE::Vector multiplicationResults; // will contain nrOfEigenvaluesToConsiderForVarApprox many entries
  832. // multiplicationResults.multiply ( *eigenMaxVectorIt, kStar, true/* transpose */ );
  833. NICE::Vector multiplicationResults( nrOfEigenvaluesToConsiderForVarApprox-1, 0.0 );
  834. //ok, there seems to be a nasty thing in computing multiplicationResults.multiply ( *eigenMaxVectorIt, kStar, true/* transpose */ );
  835. //wherefor it takes aeons...
  836. //so we compute it by ourselves
  837. // for ( uint tmpI = 0; tmpI < kStar.size(); tmpI++)
  838. NICE::Matrix::const_iterator eigenVecIt = eigenMaxVectors.begin();
  839. // double kStarI ( kStar[tmpI] );
  840. for ( int tmpJ = 0; tmpJ < nrOfEigenvaluesToConsiderForVarApprox-1; tmpJ++)
  841. {
  842. for ( NICE::Vector::const_iterator kStarIt = kStar.begin(); kStarIt != kStar.end(); kStarIt++,eigenVecIt++)
  843. {
  844. multiplicationResults[tmpJ] += (*kStarIt) * (*eigenVecIt);//eigenMaxVectors(tmpI,tmpJ);
  845. }
  846. }
  847. double projectionLength ( 0.0 );
  848. double currentSecondTerm ( 0.0 );
  849. double sumOfProjectionLengths ( 0.0 );
  850. int cnt ( 0 );
  851. NICE::Vector::const_iterator it = multiplicationResults.begin();
  852. while ( cnt < ( nrOfEigenvaluesToConsiderForVarApprox - 1 ) )
  853. {
  854. projectionLength = ( *it );
  855. currentSecondTerm += ( 1.0 / eigenMax[cnt] ) * pow ( projectionLength, 2 );
  856. sumOfProjectionLengths += pow ( projectionLength, 2 );
  857. it++;
  858. cnt++;
  859. }
  860. double normKStar ( pow ( kStar.normL2 (), 2 ) );
  861. currentSecondTerm += ( 1.0 / eigenMax[nrOfEigenvaluesToConsiderForVarApprox-1] ) * ( normKStar - sumOfProjectionLengths );
  862. if ( ( normKStar - sumOfProjectionLengths ) < 0 )
  863. {
  864. std::cerr << "Attention: normKStar - sumOfProjectionLengths is smaller than zero -- strange!" << std::endl;
  865. }
  866. predVariance = kSelf - currentSecondTerm;
  867. }
  868. void FMKGPHyperparameterOptimization::computePredictiveVarianceExact ( const NICE::Vector & x, double & predVariance ) const
  869. {
  870. if ( ikmsum->getNumberOfModels() == 0 )
  871. {
  872. fthrow ( Exception, "ikmsum is empty... have you trained this classifer? Aborting..." );
  873. }
  874. Timer t;
  875. // t.start();
  876. // ---------------- compute the first term --------------------
  877. double kSelf ( 0.0 );
  878. int dim ( 0 );
  879. for ( NICE::Vector::const_iterator it = x.begin(); it != x.end(); it++, dim++ )
  880. {
  881. kSelf += pf->f ( 0, *it );
  882. // if weighted dimensions:
  883. //kSelf += pf->f(dim,*it);
  884. }
  885. // ---------------- compute the second term --------------------
  886. // t.stop();
  887. // std::cerr << "ApproxExact -- time for first term: " << t.getLast() << std::endl;
  888. // t.start();
  889. NICE::Vector kStar;
  890. fmk->hikComputeKernelVector ( x, kStar );
  891. // t.stop();
  892. // std::cerr << "ApproxExact -- time for kernel vector: " << t.getLast() << std::endl;
  893. //
  894. //now run the ILS method
  895. NICE::Vector diagonalElements;
  896. ikmsum->getDiagonalElements ( diagonalElements );
  897. // t.start();
  898. // init simple jacobi pre-conditioning
  899. ILSConjugateGradients *linsolver_cg = dynamic_cast<ILSConjugateGradients *> ( linsolver );
  900. //perform pre-conditioning
  901. if ( linsolver_cg != NULL )
  902. linsolver_cg->setJacobiPreconditioner ( diagonalElements );
  903. NICE::Vector beta;
  904. /** About finding a good initial solution (see also GPLikelihoodApproximation)
  905. * K~ = K + sigma^2 I
  906. *
  907. * K~ \approx lambda_max v v^T
  908. * \lambda_max v v^T * alpha = k_* | multiply with v^T from left
  909. * => \lambda_max v^T alpha = v^T k_*
  910. * => alpha = k_* / lambda_max could be a good initial start
  911. * If we put everything in the first equation this gives us
  912. * v = k_*
  913. * This reduces the number of iterations by 5 or 8
  914. */
  915. beta = (kStar * (1.0 / eigenMax[0]) );
  916. /* t.stop();
  917. std::cerr << "ApproxExact -- time for preconditioning etc: " << t.getLast() << std::endl;
  918. t.start();*/
  919. // t.start();
  920. linsolver->solveLin ( *ikmsum, kStar, beta );
  921. // t.stop();
  922. // t.stop();
  923. // t.stop();
  924. // std::cerr << "ApproxExact -- time for lin solve: " << t.getLast() << std::endl;
  925. beta *= kStar;
  926. double currentSecondTerm( beta.Sum() );
  927. predVariance = kSelf - currentSecondTerm;
  928. }
  929. // ---------------------- STORE AND RESTORE FUNCTIONS ----------------------
  930. void FMKGPHyperparameterOptimization::restore ( std::istream & is, int format )
  931. {
  932. if ( is.good() )
  933. {
  934. //load the underlying data
  935. if (fmk != NULL)
  936. delete fmk;
  937. fmk = new FastMinKernel;
  938. fmk->restore(is,format);
  939. //now set up the GHIK-things in ikmsums
  940. ikmsum->addModel ( new GMHIKernel ( fmk, this->pf, this->q ) );
  941. is.precision ( numeric_limits<double>::digits10 + 1 );
  942. string tmp;
  943. is >> tmp; //class name
  944. is >> tmp;
  945. is >> tmp; //precomputedA:
  946. is >> tmp; //size:
  947. int preCompSize ( 0 );
  948. is >> preCompSize;
  949. precomputedA.clear();
  950. for ( int i = 0; i < preCompSize; i++ )
  951. {
  952. int nr;
  953. is >> nr;
  954. PrecomputedType pct;
  955. pct.setIoUntilEndOfFile ( false );
  956. pct.restore ( is, format );
  957. precomputedA.insert ( std::pair<int, PrecomputedType> ( nr, pct ) );
  958. }
  959. is >> tmp; //precomputedB:
  960. is >> tmp; //size:
  961. is >> preCompSize;
  962. precomputedB.clear();
  963. for ( int i = 0; i < preCompSize; i++ )
  964. {
  965. int nr;
  966. is >> nr;
  967. PrecomputedType pct;
  968. pct.setIoUntilEndOfFile ( false );
  969. pct.restore ( is, format );
  970. precomputedB.insert ( std::pair<int, PrecomputedType> ( nr, pct ) );
  971. }
  972. is >> tmp;
  973. int precomputedTSize;
  974. is >> precomputedTSize;
  975. precomputedT.clear();
  976. if ( precomputedTSize > 0 )
  977. {
  978. is >> tmp;
  979. int sizeOfLUT;
  980. is >> sizeOfLUT;
  981. for (int i = 0; i < precomputedTSize; i++)
  982. {
  983. is >> tmp;
  984. int index;
  985. is >> index;
  986. double * array = new double [ sizeOfLUT];
  987. for ( int i = 0; i < sizeOfLUT; i++ )
  988. {
  989. is >> array[i];
  990. }
  991. precomputedT.insert ( std::pair<int, double*> ( index, array ) );
  992. }
  993. }
  994. //now restore the things we need for the variance computation
  995. is >> tmp;
  996. int sizeOfAForVarEst;
  997. is >> sizeOfAForVarEst;
  998. if ( sizeOfAForVarEst > 0 )
  999. if (precomputedAForVarEst.size() > 0)
  1000. {
  1001. precomputedAForVarEst.setIoUntilEndOfFile ( false );
  1002. precomputedAForVarEst.restore ( is, format );
  1003. }
  1004. is >> tmp; //precomputedTForVarEst
  1005. is >> tmp; // NOTNULL or NULL
  1006. if (tmp.compare("NOTNULL") == 0)
  1007. {
  1008. int sizeOfLUT;
  1009. is >> sizeOfLUT;
  1010. precomputedTForVarEst = new double [ sizeOfLUT ];
  1011. for ( int i = 0; i < sizeOfLUT; i++ )
  1012. {
  1013. is >> precomputedTForVarEst[i];
  1014. }
  1015. }
  1016. else
  1017. {
  1018. if (precomputedTForVarEst != NULL)
  1019. delete precomputedTForVarEst;
  1020. }
  1021. //restore eigenvalues and eigenvectors
  1022. is >> eigenMax;
  1023. is >> eigenMaxVectors;
  1024. IKMLinearCombination *ikmsum = new IKMLinearCombination ();
  1025. int nrOfModels ( 0 );
  1026. is >> nrOfModels;
  1027. //the first one is always our noise-model
  1028. IKMNoise * ikmnoise = new IKMNoise ();
  1029. ikmnoise->restore ( is, format );
  1030. ikmsum->addModel ( ikmnoise );
  1031. //NOTE are there any more models you added? then add them here respectively in the correct order
  1032. //.....
  1033. //the last one is the GHIK - which we do not have to restore, but simply reset it lateron
  1034. //restore the class numbers for binary settings (if mc-settings, these values will be negative by default)
  1035. is >> tmp; // "binaryLabelPositive: "
  1036. is >> binaryLabelPositive;
  1037. is >> tmp; // " binaryLabelNegative: "
  1038. is >> binaryLabelNegative;
  1039. }
  1040. else
  1041. {
  1042. std::cerr << "InStream not initialized - restoring not possible!" << std::endl;
  1043. }
  1044. }
  1045. void FMKGPHyperparameterOptimization::store ( std::ostream & os, int format ) const
  1046. {
  1047. if ( os.good() )
  1048. {
  1049. fmk->store ( os, format );
  1050. os.precision ( numeric_limits<double>::digits10 + 1 );
  1051. os << "FMKGPHyperparameterOptimization" << std::endl;
  1052. //we only have to store the things we computed, since the remaining settings come with the config file afterwards
  1053. os << "precomputedA: size: " << precomputedA.size() << std::endl;
  1054. std::map< int, PrecomputedType >::const_iterator preCompIt = precomputedA.begin();
  1055. for ( uint i = 0; i < precomputedA.size(); i++ )
  1056. {
  1057. os << preCompIt->first << std::endl;
  1058. ( preCompIt->second ).store ( os, format );
  1059. preCompIt++;
  1060. }
  1061. os << "precomputedB: size: " << precomputedB.size() << std::endl;
  1062. preCompIt = precomputedB.begin();
  1063. for ( uint i = 0; i < precomputedB.size(); i++ )
  1064. {
  1065. os << preCompIt->first << std::endl;
  1066. ( preCompIt->second ).store ( os, format );
  1067. preCompIt++;
  1068. }
  1069. os << "precomputedT.size(): " << precomputedT.size() << std::endl;
  1070. if ( precomputedT.size() > 0 )
  1071. {
  1072. int sizeOfLUT ( 0 );
  1073. if ( q != NULL )
  1074. sizeOfLUT = q->size() * this->fmk->get_d();
  1075. os << "SizeOfLUTs: " << sizeOfLUT << std::endl;
  1076. for ( std::map< int, double * >::const_iterator it = precomputedT.begin(); it != precomputedT.end(); it++ )
  1077. {
  1078. os << "index: " << it->first << std::endl;
  1079. for ( int i = 0; i < sizeOfLUT; i++ )
  1080. {
  1081. os << ( it->second ) [i] << " ";
  1082. }
  1083. os << std::endl;
  1084. }
  1085. }
  1086. //now store the things needed for the variance estimation
  1087. os << "precomputedAForVarEst.size(): "<< precomputedAForVarEst.size() << std::endl;
  1088. if (precomputedAForVarEst.size() > 0)
  1089. {
  1090. precomputedAForVarEst.store ( os, format );
  1091. os << std::endl;
  1092. }
  1093. if ( precomputedTForVarEst != NULL )
  1094. {
  1095. os << "precomputedTForVarEst NOTNULL" << std::endl;
  1096. int sizeOfLUT ( 0 );
  1097. if ( q != NULL )
  1098. sizeOfLUT = q->size() * this->fmk->get_d();
  1099. os << sizeOfLUT << std::endl;
  1100. for ( int i = 0; i < sizeOfLUT; i++ )
  1101. {
  1102. os << precomputedTForVarEst[i] << " ";
  1103. }
  1104. os << std::endl;
  1105. }
  1106. else
  1107. {
  1108. os << "precomputedTForVarEst NULL" << std::endl;
  1109. }
  1110. //store the eigenvalues and eigenvectors
  1111. os << eigenMax << std::endl;
  1112. os << eigenMaxVectors << std::endl;
  1113. //store the ikmsum object
  1114. os << "numberOfModels: " << ikmsum->getNumberOfModels() << std::endl;
  1115. for ( int j = 0; j < ikmsum->getNumberOfModels() - 1; j++ )
  1116. {
  1117. ( ikmsum->getModel ( j ) )->store ( os, format );
  1118. }
  1119. //store the class numbers for binary settings (if mc-settings, these values will be negative by default)
  1120. os << "binaryLabelPositive: " << binaryLabelPositive << " binaryLabelNegative: " << binaryLabelNegative << std::endl;
  1121. }
  1122. else
  1123. {
  1124. std::cerr << "OutStream not initialized - storing not possible!" << std::endl;
  1125. }
  1126. }
  1127. void FMKGPHyperparameterOptimization::clear ( ) {};