浏览代码

GPHIK Regression implemented and tested, incremental updates still open

Alexander Freytag 11 年之前
父节点
当前提交
f1883f8192

+ 35 - 9
FMKGPHyperparameterOptimization.cpp

@@ -206,7 +206,7 @@ void FMKGPHyperparameterOptimization::updateAfterIncrement (
 /////////////////////////////////////////////////////
 /////////////////////////////////////////////////////
 
-FMKGPHyperparameterOptimization::FMKGPHyperparameterOptimization()
+FMKGPHyperparameterOptimization::FMKGPHyperparameterOptimization( const bool & b_performRegression )
 {
   // initialize pointer variables
   pf = NULL;
@@ -227,6 +227,7 @@ FMKGPHyperparameterOptimization::FMKGPHyperparameterOptimization()
   binaryLabelNegative = -2;
   
   this->b_usePreviousAlphas = false;
+  this->b_performRegression = b_performRegression;
 }
 
 FMKGPHyperparameterOptimization::FMKGPHyperparameterOptimization ( const Config *_conf, ParameterizedFunction *_pf, FastMinKernel *_fmk, const string & _confSection )
@@ -244,7 +245,7 @@ FMKGPHyperparameterOptimization::FMKGPHyperparameterOptimization ( const Config
   binaryLabelPositive = -1;
   binaryLabelNegative = -2;  
   knownClasses.clear();
-
+  
   if ( _fmk == NULL )
     this->initialize ( _conf, _pf ); //then the confSection is also the default value
   else
@@ -287,6 +288,7 @@ void FMKGPHyperparameterOptimization::initialize ( const Config *_conf, Paramete
   }
   
   this->pf = _pf;
+ 
   
   this->verbose = _conf->gB ( _confSection, "verbose", false );
   this->verboseTime = _conf->gB ( _confSection, "verboseTime", false );
@@ -298,6 +300,9 @@ void FMKGPHyperparameterOptimization::initialize ( const Config *_conf, Paramete
     std::cerr << "|  set-up  |" << std::endl;
     std::cerr << "------------" << std::endl;
   }
+  
+  this->b_performRegression = _conf->gB ( _confSection, "b_performRegression", false );
+
 
   // this->eig = new EigValuesTRLAN();
   // My time measurements show that both methods use equal time, a comparision
@@ -713,11 +718,23 @@ void FMKGPHyperparameterOptimization::optimize ( const NICE::Vector & y )
   this->labels  = y;
   
   std::map<int, NICE::Vector> binaryLabels;
-  prepareBinaryLabels ( binaryLabels, y , knownClasses );
+  
+  if ( this->b_performRegression )
+  {
+    int regressionLabel ( 1 );    
+    binaryLabels.insert ( std::pair< int, NICE::Vector> ( regressionLabel, y ) );
+    this->knownClasses.clear();
+    this->knownClasses.insert ( regressionLabel );
+  }
+  else
+  {
+    this->prepareBinaryLabels ( binaryLabels, y , knownClasses );    
+  }
   
   //now call the main function :)
   this->optimize(binaryLabels);
 }
+
   
 void FMKGPHyperparameterOptimization::optimize ( std::map<int, NICE::Vector> & binaryLabels )
 {
@@ -887,11 +904,15 @@ int FMKGPHyperparameterOptimization::classify ( const NICE::SparseVector & xstar
   { // multi-class classification
     return scores.maxElement();
   }
-  else
-  {  // binary setting    
+  else if ( this->knownClasses.size() == 2 ) // binary setting
+  {      
     scores[binaryLabelNegative] = -scores[binaryLabelPositive];     
     return scores[ binaryLabelPositive ] <= 0.0 ? binaryLabelNegative : binaryLabelPositive;
   }
+  else //OCC or regression setting
+  {
+    return 1;
+  }
 }
 
 int FMKGPHyperparameterOptimization::classify ( const NICE::Vector & xstar, NICE::SparseVector & scores ) const
@@ -936,12 +957,15 @@ int FMKGPHyperparameterOptimization::classify ( const NICE::Vector & xstar, NICE
   { // multi-class classification
     return scores.maxElement();
   }
-  else 
-  { // binary setting
-   
+  else if ( this->knownClasses.size() == 2 ) // binary setting
+  {      
     scores[binaryLabelNegative] = -scores[binaryLabelPositive];     
     return scores[ binaryLabelPositive ] <= 0.0 ? binaryLabelNegative : binaryLabelPositive;
   }
+  else //OCC or regression setting
+  {
+    return 1;
+  }
 }
 
     //////////////////////////////////////////
@@ -1808,7 +1832,7 @@ void FMKGPHyperparameterOptimization::addExample( const NICE::SparseVector * exa
   
   this->labels.append ( label );
   //have we seen this class already?
-  if ( this->knownClasses.find( label ) == this->knownClasses.end() )
+  if ( !this->b_performRegression && ( this->knownClasses.find( label ) == this->knownClasses.end() ) )
   {
     this->knownClasses.insert( label );
     newClasses.insert( label );
@@ -1823,10 +1847,12 @@ void FMKGPHyperparameterOptimization::addExample( const NICE::SparseVector * exa
   if ( this->verboseTime)
     std::cerr << "Time used for adding the data to the fmk object: " << tFmk.getLast() << std::endl;
 
+  //TODO check that nothing serious happens here for regression setting!
   
   // add examples to all implicite kernel matrices we currently use
   this->ikmsum->addExample ( example, label, performOptimizationAfterIncrement );
   
+  //TODO check that nothing serious happens here for regression setting!
   
   // update the corresponding matrices A, B and lookup tables T  
   // optional: do the optimization again using the previously known solutions as initialization

+ 13 - 7
FMKGPHyperparameterOptimization.h

@@ -66,6 +66,9 @@ class FMKGPHyperparameterOptimization : public NICE::Persistent, public NICE::On
     // classification related variables //
     //////////////////////////////////////
     
+    /** per default, we perform classification, if not stated otherwise */
+    bool b_performRegression;
+    
     /** object storing sorted data and providing fast hik methods */
     NICE::FastMinKernel *fmk;
 
@@ -248,8 +251,8 @@ class FMKGPHyperparameterOptimization : public NICE::Persistent, public NICE::On
     * @brief simple constructor
     * @author Alexander Freytag
     */
-    FMKGPHyperparameterOptimization();
-    
+    FMKGPHyperparameterOptimization( const bool & b_performRegression = false);
+        
     /**
     * @brief standard constructor
     *
@@ -299,7 +302,8 @@ class FMKGPHyperparameterOptimization : public NICE::Persistent, public NICE::On
 #ifdef NICE_USELIB_MATIO
     /**
     * @brief Perform hyperparameter optimization
-    *
+    * @author Alexander Freytag
+    * 
     * @param data MATLAB data structure, like a feature matrix loaded from ImageNet
     * @param y label vector (arbitrary), will be converted into a binary label vector
     * @param positives set of positive examples (indices)
@@ -309,7 +313,8 @@ class FMKGPHyperparameterOptimization : public NICE::Persistent, public NICE::On
 
     /**
     * @brief Perform hyperparameter optimization for GP multi-class or binary problems
-    *
+    * @author Alexander Freytag
+    * 
     * @param data MATLAB data structure, like a feature matrix loaded from ImageNet
     * @param y label vector with multi-class labels
     * @param examples mapping of example index to new index
@@ -319,6 +324,7 @@ class FMKGPHyperparameterOptimization : public NICE::Persistent, public NICE::On
 
     /**
     * @brief Perform hyperparameter optimization (multi-class or binary) assuming an already initialized fmk object
+    * @author Alexander Freytag
     *
     * @param y label vector (multi-class as well as binary labels supported)
     */
@@ -329,8 +335,8 @@ class FMKGPHyperparameterOptimization : public NICE::Persistent, public NICE::On
     *
     * @param binLabels vector of binary label vectors (1,-1) and corresponding class no.
     */
-    void optimize ( std::map<int, NICE::Vector> & binaryLabels );    
-    
+    void optimize ( std::map<int, NICE::Vector> & binaryLabels );  
+   
     /**
     * @brief Compute the necessary variables for appxorimations of predictive variance (LUTs), assuming an already initialized fmk object
     * @author Alexander Freytag
@@ -425,7 +431,7 @@ class FMKGPHyperparameterOptimization : public NICE::Persistent, public NICE::On
     * @author Alexander Freytag
     * @date 19-12-2013 (dd-mm-yyyy)
     * @param x input example
-     * @param predVariance contains the approximation of the predictive variance
+    * @param predVariance contains the approximation of the predictive variance
     *
     */    
     void computePredictiveVarianceApproximateFine(const NICE::Vector & x, double & predVariance ) const;      

+ 649 - 0
GPHIKRegression.cpp

@@ -0,0 +1,649 @@
+/** 
+* @file GPHIKRegression.cpp
+* @brief Main interface for our GP HIK regression implementation (Implementation)
+* @author Alexander Freytag
+* @date 15-01-2014 (dd-mm-yyyy)
+*/
+
+// STL includes
+#include <iostream>
+
+// NICE-core includes
+#include <core/basics/numerictools.h>
+#include <core/basics/Timer.h>
+
+// gp-hik-core includes
+#include "GPHIKRegression.h"
+#include "gp-hik-core/parameterizedFunctions/PFAbsExp.h"
+#include "gp-hik-core/parameterizedFunctions/PFExp.h"
+#include "gp-hik-core/parameterizedFunctions/PFMKL.h"
+
+using namespace std;
+using namespace NICE;
+
+/////////////////////////////////////////////////////
+/////////////////////////////////////////////////////
+//                 PROTECTED METHODS
+/////////////////////////////////////////////////////
+/////////////////////////////////////////////////////
+
+void GPHIKRegression::init(const Config *conf, const string & s_confSection)
+{
+  //copy the given config to have it accessible lateron
+  if ( this->confCopy != conf )
+  {
+    if ( this->confCopy != NULL )
+      delete this->confCopy;
+    
+    this->confCopy = new Config ( *conf );
+    //we do not want to read until end of file for restoring    
+    this->confCopy->setIoUntilEndOfFile(false);        
+  }
+  
+
+  
+  double parameterUpperBound = confCopy->gD(confSection, "parameter_upper_bound", 5.0 );
+  double parameterLowerBound = confCopy->gD(confSection, "parameter_lower_bound", 1.0 );  
+
+  this->noise = confCopy->gD(confSection, "noise", 0.01);
+
+  string transform = confCopy->gS(confSection, "transform", "absexp" );
+  
+  if (pf == NULL)
+  {
+    if ( transform == "absexp" )
+    {
+      this->pf = new PFAbsExp( 1.0, parameterLowerBound, parameterUpperBound );
+    } else if ( transform == "exp" ) {
+      this->pf = new PFExp( 1.0, parameterLowerBound, parameterUpperBound );
+    }else if ( transform == "MKL" ) {
+      //TODO generic, please :) load from a separate file or something like this!
+      std::set<int> steps; steps.insert(4000); steps.insert(6000); //specific for VISAPP
+      this->pf = new PFMKL( steps, parameterLowerBound, parameterUpperBound );
+    } else {
+      fthrow(Exception, "Transformation type is unknown " << transform);
+    }
+  }
+  else
+  {
+    //we already know the pf from the restore-function
+  }
+  this->confSection = confSection;
+  this->verbose = confCopy->gB(confSection, "verbose", false);
+  this->debug = confCopy->gB(confSection, "debug", false);
+  this->uncertaintyPredictionForRegression = confCopy->gB( confSection, "uncertaintyPredictionForRegression", false );
+  
+
+   
+  //how do we approximate the predictive variance for regression uncertainty?
+  string s_varianceApproximation = confCopy->gS(confSection, "varianceApproximation", "approximate_fine"); //default: fine approximative uncertainty prediction
+  if ( (s_varianceApproximation.compare("approximate_rough") == 0) || ((s_varianceApproximation.compare("1") == 0)) )
+  {
+    this->varianceApproximation = APPROXIMATE_ROUGH;
+    
+    //no additional eigenvalue is needed here at all.
+    this->confCopy->sI ( confSection, "nrOfEigenvaluesToConsiderForVarApprox", 0 );
+  }
+  else if ( (s_varianceApproximation.compare("approximate_fine") == 0) || ((s_varianceApproximation.compare("2") == 0)) )
+  {
+    this->varianceApproximation = APPROXIMATE_FINE;
+    
+    //security check - compute at least one eigenvalue for this approximation strategy
+    this->confCopy->sI ( confSection, "nrOfEigenvaluesToConsiderForVarApprox", std::max( confCopy->gI(confSection, "nrOfEigenvaluesToConsiderForVarApprox", 1 ), 1) );
+  }
+  else if ( (s_varianceApproximation.compare("exact") == 0)  || ((s_varianceApproximation.compare("3") == 0)) )
+  {
+    this->varianceApproximation = EXACT;
+    
+    //no additional eigenvalue is needed here at all.
+    this->confCopy->sI ( confSection, "nrOfEigenvaluesToConsiderForVarApprox", 1 );    
+  }
+  else
+  {
+    this->varianceApproximation = NONE;
+    
+    //no additional eigenvalue is needed here at all.
+    this->confCopy->sI ( confSection, "nrOfEigenvaluesToConsiderForVarApprox", 1 );
+  } 
+  
+  if ( this->verbose )
+    std::cerr << "varianceApproximationStrategy: " << s_varianceApproximation  << std::endl;
+}
+
+/////////////////////////////////////////////////////
+/////////////////////////////////////////////////////
+//                 PUBLIC METHODS
+/////////////////////////////////////////////////////
+/////////////////////////////////////////////////////
+GPHIKRegression::GPHIKRegression( const Config *conf, const string & s_confSection ) 
+{
+  //default settings, may be overwritten lateron
+  gphyper = NULL;
+  pf = NULL;
+  confCopy = NULL;
+  //just a default value
+  uncertaintyPredictionForRegression = false;
+  
+  this->confSection = s_confSection;
+  
+  // if no config file was given, we either restore the classifier from an external file, or run ::init with 
+  // an emtpy config (using default values thereby) when calling the train-method
+  if ( conf != NULL )
+  {
+    this->init(conf, confSection);
+  }
+}
+
+GPHIKRegression::~GPHIKRegression()
+{
+  if ( gphyper != NULL )
+    delete gphyper;
+  
+  if (pf != NULL)
+    delete pf;
+
+  if ( confCopy != NULL )
+    delete confCopy;
+}
+
+///////////////////// ///////////////////// /////////////////////
+//                         GET / SET
+///////////////////// ///////////////////// ///////////////////// 
+
+
+
+///////////////////// ///////////////////// /////////////////////
+//                      REGRESSION STUFF
+///////////////////// ///////////////////// /////////////////////
+
+void GPHIKRegression::estimate ( const SparseVector * example,  double & result ) const
+{
+  double tmpUncertainty;
+  this->estimate( example, result, tmpUncertainty );
+}
+
+void GPHIKRegression::estimate ( const NICE::Vector * example,  double & result ) const
+{
+  double tmpUncertainty;
+  this->estimate( example, result, tmpUncertainty );
+}
+
+void GPHIKRegression::estimate ( const SparseVector * example,  double & result, double & uncertainty ) const
+{
+  if (gphyper == NULL)
+     fthrow(Exception, "Regression object not trained yet -- aborting!" );
+  
+  NICE::SparseVector scores;
+  scores.clear();
+  
+  gphyper->classify ( *example, scores );
+  
+  if ( scores.size() == 0 ) {
+    fthrow(Exception, "Zero scores, something is likely to be wrong here: svec.size() = " << example->size() );
+  }
+  
+  // the internal gphyper object returns for regression a sparse vector with a single entry only
+  result = scores.begin()->second;
+  
+  if (uncertaintyPredictionForRegression)
+  {
+    if (varianceApproximation != NONE)
+    {
+      this->predictUncertainty( example, uncertainty );
+    }  
+    else
+    {
+      //do nothing
+      uncertainty = std::numeric_limits<double>::max();
+    }
+  }
+  else
+  {
+    //do nothing
+    uncertainty = std::numeric_limits<double>::max();
+  }    
+}
+
+void GPHIKRegression::estimate ( const NICE::Vector * example,  double & result, double & uncertainty ) const
+{
+  if (gphyper == NULL)
+     fthrow(Exception, "Regression object not trained yet -- aborting!" );  
+  
+  NICE::SparseVector scores;
+  scores.clear();
+  
+  gphyper->classify ( *example, scores );
+
+  if ( scores.size() == 0 ) {
+    fthrow(Exception, "Zero scores, something is likely to be wrong here: svec.size() = " << example->size() );
+  }
+  
+  // the internal gphyper object returns for regression a sparse vector with a single entry only  
+  result = scores.begin()->second;
+    
+  if (uncertaintyPredictionForRegression)
+  {
+    if (varianceApproximation != NONE)
+    {
+      this->predictUncertainty( example, uncertainty );
+    }  
+    else
+    {
+      //do nothing
+      uncertainty = std::numeric_limits<double>::max();
+    }
+  }
+  else
+  {
+    //do nothing
+    uncertainty = std::numeric_limits<double>::max();
+  }  
+}
+
+/** training process */
+void GPHIKRegression::train ( const std::vector< const NICE::SparseVector *> & examples, const NICE::Vector & labels )
+{
+  // security-check: examples and labels have to be of same size
+  if ( examples.size() != labels.size() ) 
+  {
+    fthrow(Exception, "Given examples do not match label vector in size -- aborting!" );  
+  }  
+  
+  if (verbose)
+  {
+    std::cerr << "GPHIKRegression::train" << std::endl;
+  }
+  
+  //TODO add flag fpr gphyper that only regression is performed, or add a new method for this.
+  // thereby, all the binary-label-stuff should be skipped :)
+  // also think about the internal stuff, like initialization of alpha vectors and stuff like that .... :(
+  // in the worst case, stuff has to be re-written...
+  
+  if ( this->confCopy == NULL )
+  {
+    std::cerr << "WARNING -- No config used so far, initialize values with empty config file now..." << std::endl;
+    NICE::Config tmpConfEmpty ;
+    this->init ( &tmpConfEmpty, this->confSection );
+  }
+
+  Timer t;
+  t.start();
+  FastMinKernel *fmk = new FastMinKernel ( examples, noise, this->debug );
+  
+  t.stop();
+  if (verbose)
+    std::cerr << "Time used for setting up the fmk object: " << t.getLast() << std::endl;  
+  
+  if (gphyper != NULL)
+     delete gphyper;
+  
+  
+  if ( ( varianceApproximation != APPROXIMATE_FINE) )
+    confCopy->sI ( confSection, "nrOfEigenvaluesToConsiderForVarApprox", 0);
+  
+  confCopy->sB ( confSection, "b_performRegression", true );
+  gphyper = new FMKGPHyperparameterOptimization ( confCopy, pf, fmk, confSection ); 
+
+  if (verbose)
+    cerr << "Learning ..." << endl;
+
+  // go go go
+  gphyper->optimize ( labels );
+  if (verbose)
+    std::cerr << "optimization done" << std::endl;
+  
+  if ( ( varianceApproximation != NONE ) )
+  {    
+    switch (varianceApproximation)    
+    {
+      case APPROXIMATE_ROUGH:
+      {
+        gphyper->prepareVarianceApproximationRough();
+        break;
+      }
+      case APPROXIMATE_FINE:
+      {
+        gphyper->prepareVarianceApproximationFine();
+        break;
+      }    
+      case EXACT:
+      {
+       //nothing to prepare
+        break;
+      }
+      default:
+      {
+       //nothing to prepare
+      }
+    }
+  }
+
+
+  // clean up all examples ??
+  if (verbose)
+    std::cerr << "Learning finished" << std::endl;
+}
+
+
+GPHIKRegression *GPHIKRegression::clone () const
+{
+  fthrow(Exception, "GPHIKRegression: clone() not yet implemented" );
+
+  return NULL;
+}
+  
+void GPHIKRegression::predictUncertainty( const NICE::SparseVector * example, double & uncertainty ) const
+{  
+  if (gphyper == NULL)
+     fthrow(Exception, "Regression object not trained yet -- aborting!" );  
+  
+  switch (varianceApproximation)    
+  {
+    case APPROXIMATE_ROUGH:
+    {
+      gphyper->computePredictiveVarianceApproximateRough( *example, uncertainty );
+      break;
+    }
+    case APPROXIMATE_FINE:
+    {
+      gphyper->computePredictiveVarianceApproximateFine( *example, uncertainty );
+      break;
+    }    
+    case EXACT:
+    {
+      gphyper->computePredictiveVarianceExact( *example, uncertainty );
+      break;
+    }
+    default:
+    {
+      fthrow(Exception, "GPHIKRegression - your settings disabled the variance approximation needed for uncertainty prediction.");
+    }
+  }
+}
+
+void GPHIKRegression::predictUncertainty( const NICE::Vector * example, double & uncertainty ) const
+{  
+  if (gphyper == NULL)
+     fthrow(Exception, "Regression object not trained yet -- aborting!" );  
+  
+  switch (varianceApproximation)    
+  {
+    case APPROXIMATE_ROUGH:
+    {
+      gphyper->computePredictiveVarianceApproximateRough( *example, uncertainty );
+      break;
+    }
+    case APPROXIMATE_FINE:
+    {
+      gphyper->computePredictiveVarianceApproximateFine( *example, uncertainty );
+      break;
+    }    
+    case EXACT:
+    {
+      gphyper->computePredictiveVarianceExact( *example, uncertainty );
+      break;
+    }
+    default:
+    {
+      fthrow(Exception, "GPHIKRegression - your settings disabled the variance approximation needed for uncertainty prediction.");
+    }
+  }
+}
+
+///////////////////// INTERFACE PERSISTENT /////////////////////
+// interface specific methods for store and restore
+///////////////////// INTERFACE PERSISTENT ///////////////////// 
+
+void GPHIKRegression::restore ( std::istream & is, int format )
+{
+  //delete everything we knew so far...
+  this->clear();
+  
+  bool b_restoreVerbose ( false );
+#ifdef B_RESTOREVERBOSE
+  b_restoreVerbose = true;
+#endif  
+  
+  if ( is.good() )
+  {
+    if ( b_restoreVerbose ) 
+      std::cerr << " restore GPHIKRegression" << std::endl;
+    
+    std::string tmp;
+    is >> tmp; //class name 
+    
+    if ( ! this->isStartTag( tmp, "GPHIKRegression" ) )
+    {
+      std::cerr << " WARNING - attempt to restore GPHIKRegression, but start flag " << tmp << " does not match! Aborting... " << std::endl;
+      throw;
+    }   
+    
+    if (pf != NULL)
+    {
+      delete pf;
+      pf = NULL;
+    }
+    if ( confCopy != NULL )
+    {
+      delete confCopy;
+      confCopy = NULL;
+    }
+    if (gphyper != NULL)
+    {
+      delete gphyper;
+      gphyper = NULL;
+    }    
+    
+    is.precision (numeric_limits<double>::digits10 + 1);
+    
+    bool b_endOfBlock ( false ) ;
+    
+    while ( !b_endOfBlock )
+    {
+      is >> tmp; // start of block 
+      
+      if ( this->isEndTag( tmp, "GPHIKRegression" ) )
+      {
+        b_endOfBlock = true;
+        continue;
+      }      
+      
+      tmp = this->removeStartTag ( tmp );
+      
+      if ( b_restoreVerbose )
+        std::cerr << " currently restore section " << tmp << " in GPHIKRegression" << std::endl;
+      
+      if ( tmp.compare("confSection") == 0 )
+      {
+        is >> confSection;        
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }
+      else if ( tmp.compare("pf") == 0 )
+      {
+      
+        is >> tmp; // start of block 
+        if ( this->isEndTag( tmp, "pf" ) )
+        {
+          std::cerr << " ParameterizedFunction object can not be restored. Aborting..." << std::endl;
+          throw;
+        } 
+        
+        std::string transform = this->removeStartTag ( tmp );
+        
+
+        if ( transform == "PFAbsExp" )
+        {
+          this->pf = new PFAbsExp ();
+        } else if ( transform == "PFExp" ) {
+          this->pf = new PFExp ();
+        } else {
+          fthrow(Exception, "Transformation type is unknown " << transform);
+        }
+        
+        pf->restore(is, format);
+        
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      } 
+      else if ( tmp.compare("ConfigCopy") == 0 )
+      {
+        // possibly obsolete safety checks
+        if ( confCopy == NULL )
+          confCopy = new Config;
+        confCopy->clear();
+        
+        
+        //we do not want to read until the end of the file
+        confCopy->setIoUntilEndOfFile( false );
+        //load every options we determined explicitely
+        confCopy->restore(is, format);
+        
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }
+      else if ( tmp.compare("gphyper") == 0 )
+      {
+        if ( gphyper == NULL )
+          gphyper = new NICE::FMKGPHyperparameterOptimization();
+        
+        //then, load everything that we stored explicitely,
+        // including precomputed matrices, LUTs, eigenvalues, ... and all that stuff
+        gphyper->restore(is, format);  
+          
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }       
+      else
+      {
+      std::cerr << "WARNING -- unexpected GPHIKRegression object -- " << tmp << " -- for restoration... aborting" << std::endl;
+      throw;
+      }
+    }
+
+    //load every settings as well as default options
+    std::cerr << "run this->init" << std::endl;
+    this->init(confCopy, confSection);    
+    std::cerr << "run gphyper->initialize" << std::endl;
+    gphyper->initialize ( confCopy, pf, NULL, confSection );
+  }
+  else
+  {
+    std::cerr << "GPHIKRegression::restore -- InStream not initialized - restoring not possible!" << std::endl;
+    throw;
+  }
+}
+
+void GPHIKRegression::store ( std::ostream & os, int format ) const
+{
+  if (gphyper == NULL)
+     fthrow(Exception, "Regression object not trained yet -- aborting!" );  
+  
+  if (os.good())
+  {
+    // show starting point
+    os << this->createStartTag( "GPHIKRegression" ) << std::endl;    
+    
+    os.precision (numeric_limits<double>::digits10 + 1);
+    
+    os << this->createStartTag( "confSection" ) << std::endl;
+    os << confSection << std::endl;
+    os << this->createEndTag( "confSection" ) << std::endl; 
+    
+    os << this->createStartTag( "pf" ) << std::endl;
+    pf->store(os, format);
+    os << this->createEndTag( "pf" ) << std::endl; 
+
+    os << this->createStartTag( "ConfigCopy" ) << std::endl;
+    //we do not want to read until end of file for restoring    
+    confCopy->setIoUntilEndOfFile(false);
+    confCopy->store(os,format);
+    os << this->createEndTag( "ConfigCopy" ) << std::endl; 
+    
+    os << this->createStartTag( "gphyper" ) << std::endl;
+    //store the underlying data
+    //will be done in gphyper->store(of,format)
+    //store the optimized parameter values and all that stuff
+    gphyper->store(os, format);
+    os << this->createEndTag( "gphyper" ) << std::endl;   
+    
+    
+    // done
+    os << this->createEndTag( "GPHIKRegression" ) << std::endl;    
+  }
+  else
+  {
+    std::cerr << "OutStream not initialized - storing not possible!" << std::endl;
+  }
+}
+
+void GPHIKRegression::clear ()
+{
+  if ( gphyper != NULL )
+  {
+    delete gphyper;
+    gphyper = NULL;
+  }
+  
+  if (pf != NULL)
+  {
+    delete pf;
+    pf = NULL;
+  }
+
+  if ( confCopy != NULL )
+  {
+    delete confCopy; 
+    confCopy = NULL;
+  } 
+}
+
+///////////////////// INTERFACE ONLINE LEARNABLE /////////////////////
+// interface specific methods for incremental extensions
+///////////////////// INTERFACE ONLINE LEARNABLE /////////////////////
+
+void GPHIKRegression::addExample( const NICE::SparseVector * example, 
+			     const double & label, 
+			     const bool & performOptimizationAfterIncrement
+			   )
+{
+  
+  if ( this->gphyper == NULL )
+  {
+    //call train method instead
+    std::cerr << "Regression object not initially trained yet -- run initial training instead of incremental extension!"  << std::endl;
+     
+    std::vector< const NICE::SparseVector *> examplesVec;
+    examplesVec.push_back ( example );
+    
+    NICE::Vector labelsVec ( 1 , label );
+    
+    this->train ( examplesVec, labelsVec );
+  }
+  else
+  {
+    this->gphyper->addExample( example, label, performOptimizationAfterIncrement );  
+  }
+}
+
+void GPHIKRegression::addMultipleExamples( const std::vector< const NICE::SparseVector * > & newExamples,
+				      const NICE::Vector & newLabels,
+				      const bool & performOptimizationAfterIncrement
+				    )
+{
+  //are new examples available? If not, nothing has to be done
+  if ( newExamples.size() < 1)
+    return;
+
+  if ( this->gphyper == NULL )
+  {
+    //call train method instead
+    std::cerr << "Regression object not initially trained yet -- run initial training instead of incremental extension!"  << std::endl;
+    
+    this->train ( newExamples, newLabels );    
+  }
+  else
+  {
+    this->gphyper->addMultipleExamples( newExamples, newLabels, performOptimizationAfterIncrement );     
+  }
+}

+ 251 - 0
GPHIKRegression.h

@@ -0,0 +1,251 @@
+/** 
+* @file GPHIKRegression.h
+* @brief Main interface for our GP HIK regression implementation (Interface)
+* @author Alexander Freytag
+* @date 15-01-2014 (dd-mm-yyyy)
+*/
+#ifndef _NICE_GPHIKREGRESSIONINCLUDE
+#define _NICE_GPHIKREGRESSIONINCLUDE
+
+// STL includes
+#include <string>
+#include <limits>
+
+// NICE-core includes
+#include <core/basics/Config.h>
+#include <core/basics/Persistent.h>
+// 
+#include <core/vector/SparseVectorT.h>
+
+// gp-hik-core includes
+#include "gp-hik-core/FMKGPHyperparameterOptimization.h"
+#include "gp-hik-core/OnlineLearnable.h"
+#include "gp-hik-core/parameterizedFunctions/ParameterizedFunction.h"
+
+namespace NICE {
+  
+ /** 
+ * @class GPHIKRegression
+ * @brief Main interface for our GP HIK regression implementation (Interface)
+ * @author Alexander Freytag
+ */
+ 
+class GPHIKRegression : public NICE::Persistent, public NICE::OnlineLearnable
+{
+
+  protected:
+    
+    /////////////////////////
+    /////////////////////////
+    // PROTECTED VARIABLES //
+    /////////////////////////
+    /////////////////////////
+    
+    // output/debug related settings
+    
+    /** verbose flag for useful output*/
+    bool verbose;
+    /** debug flag for several outputs useful for debugging*/
+    bool debug;
+    
+    // general specifications
+    
+    /** Header in configfile where variable settings are stored */
+    std::string confSection;
+    /** Configuration file specifying variable settings */
+    NICE::Config *confCopy; 
+    
+    // internal objects 
+    
+    /** Main object doing all the jobs: training, regression, optimization, ... */
+    NICE::FMKGPHyperparameterOptimization *gphyper;    
+    
+    /** Possibility for transforming feature values, parameters can be optimized */
+    NICE::ParameterizedFunction *pf;    
+    
+    
+    
+    
+    /** Gaussian label noise for model regularization */
+    double noise;
+
+    enum VarianceApproximation{
+      APPROXIMATE_ROUGH,
+      APPROXIMATE_FINE,
+      EXACT,
+      NONE
+    };
+    
+    /** Which technique for variance approximations shall be used */
+    VarianceApproximation varianceApproximation;
+    
+    /**compute the uncertainty prediction during regression?*/
+    bool uncertaintyPredictionForRegression;
+    
+    /////////////////////////
+    /////////////////////////
+    //  PROTECTED METHODS  //
+    /////////////////////////
+    /////////////////////////
+    
+    /** 
+    * @brief Setup internal variables and objects used
+    * @author Alexander Freytag
+    * @param conf Config file to specify variable settings
+    * @param s_confSection
+    */    
+    void init(const NICE::Config *conf, const std::string & s_confSection);
+       
+
+  public:
+
+    /** 
+     * @brief standard constructor
+     * @author Alexander Freytag
+     */
+    GPHIKRegression( const NICE::Config *conf = NULL, const std::string & s_confSection = "GPHIKRegression" );
+      
+    /**
+     * @brief simple destructor
+     * @author Alexander Freytag
+     */
+    ~GPHIKRegression();
+    
+    ///////////////////// ///////////////////// /////////////////////
+    //                         GET / SET
+    ///////////////////// ///////////////////// /////////////////////      
+    
+   
+   
+    ///////////////////// ///////////////////// /////////////////////
+    //                      REGRESSION STUFF
+    ///////////////////// ///////////////////// /////////////////////      
+    
+    /** 
+     * @brief Estimate output of a given example with the previously learnt model
+     * @date 15-01-2014 (dd-mm-yyyy)
+     * @author Alexander Freytag
+     * @param example (SparseVector) for which regression shall be performed, given in a sparse representation
+     * @param result (double) regression result
+     */        
+    void estimate ( const NICE::SparseVector * example,  double & result ) const;
+    
+    /** 
+     * @brief Estimate output of a given example with the previously learnt model
+     ** @date 15-01-2014 (dd-mm-yyyy)
+     * @author Alexander Freytag
+     * @param example (SparseVector) for which regression shall be performed, given in a sparse representation
+     * @param result (double) regression result
+     * @param uncertainty (double*) predictive variance of the regression result, if computed
+     */    
+    void estimate ( const NICE::SparseVector * example,  double & result, double & uncertainty ) const;
+    
+    /** 
+     * @brief Estimate output of a given example with the previously learnt model
+     * NOTE: whenever possible, you should the sparse version to obtain significantly smaller computation times* 
+     * @date 15-01-2014 (dd-mm-yyyy)
+     * @author Alexander Freytag
+     * @param example (non-sparse Vector) for which regression shall be performed, given in a non-sparse representation
+     * @param result (double) regression result
+     */        
+    void estimate ( const NICE::Vector * example,  double & result ) const;
+    
+    /** 
+     * @brief Estimate output of a given example with the previously learnt model
+     * NOTE: whenever possible, you should the sparse version to obtain significantly smaller computation times
+     * @date 15-01-2014 (dd-mm-yyyy)
+     * @author Alexander Freytag
+     * @param example (non-sparse Vector) for which regression shall be performed, given in a non-sparse representation
+     * @param result (double)regression result
+     * @param uncertainty (double*) predictive variance of the regression result, if computed
+     */    
+    void estimate ( const NICE::Vector * example,  double & result, double & uncertainty ) const;    
+
+    /**
+     * @brief train this regression method using a given set of examples and corresponding labels
+     * @date 15-01-2014 (dd-mm-yyyy)
+     * @author Alexander Freytag
+     * @param examples (std::vector< NICE::SparseVector *>) training data given in a sparse representation
+     * @param labels (Vector) labels
+     */
+    void train ( const std::vector< const NICE::SparseVector *> & examples, const NICE::Vector & labels );
+    
+    
+    /**
+     * @brief Clone regression object
+     * @author Alexander Freytag
+     */    
+    GPHIKRegression *clone () const;
+
+    /** 
+     * @brief prediction of regression uncertainty
+     * @date 15-01-2014 (dd-mm-yyyy)
+     * @author Alexander Freytag
+     * @param examples example for which the regression uncertainty shall be predicted, given in a sparse representation
+     * @param uncertainty contains the resulting regression uncertainty
+     */       
+    void predictUncertainty( const NICE::SparseVector * example, double & uncertainty ) const;
+    
+    /** 
+     * @brief prediction of regression uncertainty
+     * @date 15-01-2014 (dd-mm-yyyy)
+     * @author Alexander Freytag
+     * @param examples example for which the regression uncertainty shall be predicted, given in a non-sparse representation
+     * @param uncertainty contains the resulting regression uncertainty
+     */       
+    void predictUncertainty( const NICE::Vector * example, double & uncertainty ) const;    
+    
+
+
+    ///////////////////// INTERFACE PERSISTENT /////////////////////
+    // interface specific methods for store and restore
+    ///////////////////// INTERFACE PERSISTENT /////////////////////   
+    
+    /** 
+     * @brief Load regression object from external file (stream)
+     * @author Alexander Freytag
+     */     
+    void restore ( std::istream & is, int format = 0 );
+    
+    /** 
+     * @brief Save regression object to external file (stream)
+     * @author Alexander Freytag
+     */     
+    void store ( std::ostream & os, int format = 0 ) const;
+    
+    /** 
+     * @brief Clear regression object
+     * @author Alexander Freytag
+     */     
+    void clear ();
+    
+    
+    ///////////////////// INTERFACE ONLINE LEARNABLE /////////////////////
+    // interface specific methods for incremental extensions
+    ///////////////////// INTERFACE ONLINE LEARNABLE /////////////////////
+    
+    /** 
+     * @brief add a new example
+     * @author Alexander Freytag
+     */    
+    virtual void addExample( const NICE::SparseVector * example, 
+                              const double & label, 
+                              const bool & performOptimizationAfterIncrement = true
+                            );
+                          
+    /** 
+     * @brief add several new examples
+     * @author Alexander Freytag
+     */    
+    virtual void addMultipleExamples( const std::vector< const NICE::SparseVector * > & newExamples,
+                                      const NICE::Vector & newLabels,
+                                      const bool & performOptimizationAfterIncrement = true
+                                    );       
+
+
+
+};
+
+}
+
+#endif

+ 1 - 1
matlab/Makefile

@@ -2,4 +2,4 @@ NICEFLAGS1=$(shell pkg-config libgp-hik-core --cflags --libs)
 NICEFLAGS=$(subst -fopenmp,,$(NICEFLAGS1))
 
 default:
-	/home/matlab/7.14/bin/mex ${NICEFLAGS} -largeArrayDims GPHIK.cpp ConverterMatlabToNICE.cpp ConverterNICEToMatlab.cpp
+	/home/alex/bin/matlab/7.14/bin/mex ${NICEFLAGS} -largeArrayDims GPHIK.cpp ConverterMatlabToNICE.cpp ConverterNICEToMatlab.cpp

+ 1 - 1
tests/TestGPHIKOnlineLearnable.h

@@ -8,7 +8,7 @@
  * CppUnit-Testcase. 
  * @brief CppUnit-Testcase to verify that GPHIKClassifierIL methods herited from OnlineLearnable (addExample and addMultipleExamples) work as desired.
  * @author Alexander Freytag
- * @date 03-11-2014 (dd-mm-yyyy)
+ * @date 03-01-2014 (dd-mm-yyyy)
  */
 class TestGPHIKOnlineLearnable : public CppUnit::TestFixture {
 

+ 238 - 0
tests/TestGPHIKRegression.cpp

@@ -0,0 +1,238 @@
+/** 
+ * @file TestGPHIKRegression.cpp
+ * @brief CppUnit-Testcase to verify that GPHIKRegression works as desired.
+ * @author Alexander Freytag
+ * @date 16-01-2014 (dd-mm-yyyy)
+*/
+
+#ifdef NICE_USELIB_CPPUNIT
+
+// STL includes
+#include <iostream>
+#include <vector>
+
+// NICE-core includes
+#include <core/basics/Config.h>
+#include <core/basics/Timer.h>
+
+// gp-hik-core includes
+#include "gp-hik-core/GPHIKRegression.h"
+
+#include "TestGPHIKRegression.h"
+
+using namespace std; //C basics
+using namespace NICE;  // nice-core
+
+const bool verboseStartEnd = true;
+const bool verbose = false;
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION( TestGPHIKRegression );
+
+void TestGPHIKRegression::setUp() {
+}
+
+void TestGPHIKRegression::tearDown() {
+}
+
+
+
+void readData ( const std::string filename, NICE::Matrix & data, NICE::Vector & yValues )
+{
+ std::ifstream ifs ( filename.c_str() , ios::in );
+
+  if ( ifs.good() )
+  {
+    NICE::Vector tmp;
+    ifs >> data;
+    ifs >> tmp; //yBin;
+    ifs >> yValues;
+    ifs.close();  
+  }
+  else 
+  {
+    std::cerr << "Unable to read data from file " << filename << " -- aborting." << std::endl;
+    CPPUNIT_ASSERT ( ifs.good() );
+  }    
+}
+
+void evaluateRegressionMethod ( double & regressionLoss, 
+                          const NICE::GPHIKRegression * regressionMethod, 
+                          const NICE::Matrix & data,
+                          const NICE::Vector & yValues
+                        ) 
+{
+  regressionLoss = 0.0;
+  
+  int i_loopEnd  ( (int)data.rows() );  
+  
+  for (int i = 0; i < i_loopEnd ; i++)
+  {
+    NICE::Vector example ( data.getRow(i) );
+    double result;    
+    
+    // classify with previously trained regression method
+    regressionMethod->estimate( &example, result );
+    
+    if ( verbose )
+      std::cerr << "i: " << i << " gt: " << yValues[i] << " result: " << result << std::endl;
+    
+    //use L2-loss for evaluation
+    regressionLoss +=  pow( yValues[i] - result, 2 ); 
+  }
+}
+
+void TestGPHIKRegression::testRegressionHoldInData()
+{
+  if (verboseStartEnd)
+    std::cerr << "================== TestGPHIKRegression::testRegressionHoldInData ===================== " << std::endl;  
+  
+  NICE::Config conf;
+  
+  conf.sB ( "GPHIKRegression", "eig_verbose", false);
+  conf.sS ( "GPHIKRegression", "optimization_method", "downhillsimplex");
+  // set pretty low built-in noise for hold-in regression estimation
+  conf.sD ( "GPHIKRegression", "noise", 1e-6 );
+  
+  std::string s_trainData = conf.gS( "main", "trainData", "toyExampleSmallScaleTrain.data" );
+  
+  //------------- read the training data --------------
+  
+  NICE::Matrix dataTrain;
+  NICE::Vector yValues; 
+  
+  readData ( s_trainData, dataTrain, yValues );
+  
+  //----------------- convert data to sparse data structures ---------
+  std::vector< const NICE::SparseVector *> examplesTrain;
+  examplesTrain.resize( dataTrain.rows() );
+  
+  std::vector< const NICE::SparseVector *>::iterator exTrainIt = examplesTrain.begin();
+  for (int i = 0; i < (int)dataTrain.rows(); i++, exTrainIt++)
+  {
+    *exTrainIt =  new NICE::SparseVector( dataTrain.getRow(i) );
+  }
+    
+  //create classifier object
+  NICE::GPHIKRegression * regressionMethod;
+  regressionMethod = new NICE::GPHIKRegression ( &conf );
+  regressionMethod->train ( examplesTrain , yValues );
+  
+  double holdInLoss ( 0.0 );
+  
+    
+  // ------------------------------------------
+  // ------------- REGRESSION --------------
+  // ------------------------------------------  
+  evaluateRegressionMethod ( holdInLoss, regressionMethod, dataTrain, yValues ); 
+  
+  
+  if ( verbose ) 
+  {
+    std::cerr << " holdInLoss: " << holdInLoss << std::endl;
+  }  
+
+  
+  CPPUNIT_ASSERT_DOUBLES_EQUAL( 0.0, holdInLoss, 1e-8);
+  
+  // don't waste memory
+  
+  delete regressionMethod;
+  
+  for (std::vector< const NICE::SparseVector *>::iterator exTrainIt = examplesTrain.begin(); exTrainIt != examplesTrain.end(); exTrainIt++)
+  {
+    delete *exTrainIt;
+  }
+  
+  
+  if (verboseStartEnd)
+    std::cerr << "================== TestGPHIKRegression::testRegressionHoldInData done ===================== " << std::endl;   
+}
+
+void TestGPHIKRegression::testRegressionHoldOutData()
+{
+  if (verboseStartEnd)
+    std::cerr << "================== TestGPHIKRegression::testRegressionHoldOutData ===================== " << std::endl;  
+
+  NICE::Config conf;
+  
+  conf.sB ( "GPHIKRegression", "eig_verbose", false);
+  conf.sS ( "GPHIKRegression", "optimization_method", "downhillsimplex");
+  // set pretty low built-in noise for hold-in regression estimation
+  conf.sD ( "GPHIKRegression", "noise", 1e-6 );
+  
+  std::string s_trainData = conf.gS( "main", "trainData", "toyExampleSmallScaleTrain.data" );
+  
+  //------------- read the training data --------------
+  
+  NICE::Matrix dataTrain;
+  NICE::Vector yValues; 
+  
+  readData ( s_trainData, dataTrain, yValues );
+  
+  //----------------- convert data to sparse data structures ---------
+  std::vector< const NICE::SparseVector *> examplesTrain;
+  examplesTrain.resize( dataTrain.rows() );
+  
+  std::vector< const NICE::SparseVector *>::iterator exTrainIt = examplesTrain.begin();
+  for (int i = 0; i < (int)dataTrain.rows(); i++, exTrainIt++)
+  {
+    *exTrainIt =  new NICE::SparseVector( dataTrain.getRow(i) );
+  }
+    
+  //create classifier object
+  NICE::GPHIKRegression * regressionMethod;
+  regressionMethod = new NICE::GPHIKRegression ( &conf );
+  regressionMethod->train ( examplesTrain , yValues );
+  
+  //------------- read the test data --------------
+  
+  
+  NICE::Matrix dataTest;
+  NICE::Vector yValuesTest; 
+  
+  std::string s_testData = conf.gS( "main", "testData", "toyExampleTest.data" );  
+  
+  readData ( s_testData, dataTest, yValuesTest );  
+  
+  double holdOutLoss ( 0.0 );
+  
+    
+  // ------------------------------------------
+  // ------------- REGRESSION --------------
+  // ------------------------------------------  
+  evaluateRegressionMethod ( holdOutLoss, regressionMethod, dataTest, yValuesTest ); 
+
+  // acceptable difference for every estimated y-value on average
+  double diffOkay ( 0.35 );
+  
+  if ( verbose ) 
+  {
+    std::cerr << " holdOutLoss: " << holdOutLoss << " accepting: " << pow(diffOkay,2)*yValuesTest.size() << std::endl;
+  }  
+  
+  CPPUNIT_ASSERT( pow(diffOkay,2)*yValuesTest.size() - holdOutLoss > 0.0);
+  
+  // don't waste memory
+  
+  delete regressionMethod;
+  
+  for (std::vector< const NICE::SparseVector *>::iterator exTrainIt = examplesTrain.begin(); exTrainIt != examplesTrain.end(); exTrainIt++)
+  {
+    delete *exTrainIt;
+  }  
+  
+  if (verboseStartEnd)
+    std::cerr << "================== TestGPHIKRegression::testRegressionHoldOutData done ===================== " << std::endl;     
+}
+    
+void TestGPHIKRegression::testRegressionOnlineLearning()
+{
+  if (verboseStartEnd)
+    std::cerr << "================== TestGPHIKRegression::testRegressionOnlineLearning ===================== " << std::endl;  
+  
+  if (verboseStartEnd)
+    std::cerr << "================== TestGPHIKRegression::testRegressionOnlineLearning done ===================== " << std::endl;   
+}
+
+#endif

+ 35 - 0
tests/TestGPHIKRegression.h

@@ -0,0 +1,35 @@
+#ifndef _TESTGPHIKREGRESSION_H
+#define _TESTGPHIKREGRESSION_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <gp-hik-core/GPHIKRegression.h>
+
+/**
+ * CppUnit-Testcase. 
+ * @brief CppUnit-Testcase to verify that GPHIKRegression works as desired.
+ * @author Alexander Freytag
+ * @date 16-01-2014 (dd-mm-yyyy)
+ */
+class TestGPHIKRegression : public CppUnit::TestFixture {
+
+    CPPUNIT_TEST_SUITE( TestGPHIKRegression );
+      CPPUNIT_TEST(testRegressionHoldInData);
+      CPPUNIT_TEST(testRegressionHoldOutData);
+      CPPUNIT_TEST(testRegressionOnlineLearning);
+      
+    CPPUNIT_TEST_SUITE_END();
+  
+ private:
+ 
+ public:
+    void setUp();
+    void tearDown();
+
+    void testRegressionHoldInData();
+    void testRegressionHoldOutData();    
+    
+    void testRegressionOnlineLearning();
+    
+};
+
+#endif // _TESTGPHIKREGRESSION_H