Răsfoiți Sursa

adding of multiple new examples with new classes is now possible

Alexander Freytag 12 ani în urmă
părinte
comite
8646b0c6f9
2 a modificat fișierele cu 164 adăugiri și 31 ștergeri
  1. 155 27
      FMKGPHyperparameterOptimization.cpp
  2. 9 4
      FMKGPHyperparameterOptimization.h

+ 155 - 27
FMKGPHyperparameterOptimization.cpp

@@ -547,6 +547,8 @@ void FMKGPHyperparameterOptimization::computeMatricesAndLUTs ( const std::map<in
         
         
         precomputedT[ i->first ] = T;
         precomputedT[ i->first ] = T;
       }
       }
+      
+      //TODO update the variance-related matrices as well!!!
     }
     }
   }
   }
 }
 }
@@ -831,15 +833,15 @@ void FMKGPHyperparameterOptimization::optimize ( std::map<int, NICE::Vector> & b
   }
   }
 }
 }
 
 
-void FMKGPHyperparameterOptimization::optimizeAfterSingleIncrement ( const NICE::SparseVector & x, const bool & performOptimizationAfterIncrement )
+void FMKGPHyperparameterOptimization::updateAfterSingleIncrement ( const NICE::SparseVector & x, const bool & performOptimizationAfterIncrement )
 {
 {
   Timer t;
   Timer t;
   t.start();
   t.start();
   if ( fmk == NULL )
   if ( fmk == NULL )
     fthrow ( Exception, "FastMinKernel object was not initialized!" );
     fthrow ( Exception, "FastMinKernel object was not initialized!" );
 
 
-  map<int, NICE::Vector> binaryLabels;
-  set<int> classesToUse;
+  std::map<int, NICE::Vector> binaryLabels;
+  std::set<int> classesToUse;
   prepareBinaryLabels ( binaryLabels, labels , classesToUse );
   prepareBinaryLabels ( binaryLabels, labels , classesToUse );
   if ( verbose )
   if ( verbose )
     std::cerr << "labels.size() after increment: " << labels.size() << std::endl;
     std::cerr << "labels.size() after increment: " << labels.size() << std::endl;
@@ -1010,44 +1012,117 @@ void FMKGPHyperparameterOptimization::optimizeAfterSingleIncrement ( const NICE:
   }
   }
 }
 }
 
 
-void FMKGPHyperparameterOptimization::optimizeAfterMultipleIncrements ( const std::vector<const NICE::SparseVector*> & x, const bool & performOptimizationAfterIncrement )
+void FMKGPHyperparameterOptimization::updateAfterMultipleIncrements ( const std::vector<const NICE::SparseVector*> & x, const bool & performOptimizationAfterIncrement )
 {
 {
   Timer t;
   Timer t;
   t.start();
   t.start();
   if ( fmk == NULL )
   if ( fmk == NULL )
     fthrow ( Exception, "FastMinKernel object was not initialized!" );
     fthrow ( Exception, "FastMinKernel object was not initialized!" );
 
 
-  map<int, NICE::Vector> binaryLabels;
-  set<int> classesToUse;
-  prepareBinaryLabels ( binaryLabels, labels , classesToUse );
+  std::map<int, NICE::Vector> binaryLabels;
+  std::set<int> classesToUse;
+  this->prepareBinaryLabels ( binaryLabels, labels , classesToUse );
+  //actually, this is not needed, since we have the global set knownClasses
+  classesToUse.clear();
+  
+  std::map<int, NICE::Vector> newBinaryLabels;
+  if ( newClasses.size() > 0)
+  {
+    for (std::set<int>::const_iterator newClIt = newClasses.begin(); newClIt != newClasses.end(); newClIt++)
+    {
+      std::map<int, NICE::Vector>::iterator binLabelIt = binaryLabels.find(*newClIt);
+      newBinaryLabels.insert(*binLabelIt);
+    }
+  }
+  
   if ( verbose )
   if ( verbose )
     std::cerr << "labels.size() after increment: " << labels.size() << std::endl;
     std::cerr << "labels.size() after increment: " << labels.size() << std::endl;
 
 
+ 
+  
+  // ************************************************************
+  //   include the information for classes we know so far    
+  // ************************************************************
+  
   Timer t1;
   Timer t1;
   t1.start();
   t1.start();
   //update the kernel combinations
   //update the kernel combinations
   std::map<int, NICE::Vector>::const_iterator labelIt = binaryLabels.begin();
   std::map<int, NICE::Vector>::const_iterator labelIt = binaryLabels.begin();
   // note, that if we only have a single ikmsum-object, than the labelvector will not be used at all in the internal objects (only relevant in ikmnoise)
   // note, that if we only have a single ikmsum-object, than the labelvector will not be used at all in the internal objects (only relevant in ikmnoise)
 
 
-  //TODO
   for ( std::map<int, IKMLinearCombination * >::iterator it = ikmsums.begin(); it != ikmsums.end(); it++ )
   for ( std::map<int, IKMLinearCombination * >::iterator it = ikmsums.begin(); it != ikmsums.end(); it++ )
   {
   {
+    //make sure that we only work on currently known classes in this loop
+    while ( newClasses.find( labelIt->first ) != newClasses.end())
+    {
+      labelIt++;
+    }
     for ( std::vector<const NICE::SparseVector*>::const_iterator exampleIt = x.begin(); exampleIt != x.end(); exampleIt++ )
     for ( std::vector<const NICE::SparseVector*>::const_iterator exampleIt = x.begin(); exampleIt != x.end(); exampleIt++ )
     {
     {
       it->second->addExample ( **exampleIt, labelIt->second );
       it->second->addExample ( **exampleIt, labelIt->second );
     }
     }
     labelIt++;
     labelIt++;
   }
   }
-
+  
   //we have to reset the fmk explicitely
   //we have to reset the fmk explicitely
   for ( std::map<int, IKMLinearCombination * >::iterator it = ikmsums.begin(); it != ikmsums.end(); it++ )
   for ( std::map<int, IKMLinearCombination * >::iterator it = ikmsums.begin(); it != ikmsums.end(); it++ )
   {
   {
-    ( ( GMHIKernel* ) it->second->getModel ( it->second->getNumberOfModels() - 1 ) )->setFastMinKernel ( this->fmk );
+    if ( newClasses.find( it->first ) != newClasses.end() )
+      continue;
+    else
+      ( ( GMHIKernel* ) it->second->getModel ( it->second->getNumberOfModels() - 1 ) )->setFastMinKernel ( this->fmk );
   }
   }
 
 
   t1.stop();
   t1.stop();
   if (verboseTime)
   if (verboseTime)
-    std::cerr << "Time used for setting up the ikm-objects: " << t1.getLast() << std::endl;
+    std::cerr << "Time used for setting up the ikm-objects for known classes: " << t1.getLast() << std::endl;
+  
+  // *********************************************
+  //          work on the new classes
+  // *********************************************
+  
+  double tmpNoise;  
+  (ikmsums.begin()->second->getModel( 0 ))->getFirstDiagonalElement(tmpNoise);
+    
+  if ( newClasses.size() > 0)
+  {
+    //setup the new kernel combinations
+    if ( learnBalanced )
+    {
+      for ( std::set<int>::const_iterator clIt = newClasses.begin(); clIt != newClasses.end(); clIt++ )
+      {
+        IKMLinearCombination *ikmsum = new IKMLinearCombination ();
+        ikmsums.insert ( std::pair<int, IKMLinearCombination*> ( *clIt, ikmsum ) );
+      }
+    }
+    else
+    {
+      //nothing to do, we already have the single ikmsum-object
+    } 
+    
+  //   First model: noise
+    if ( learnBalanced )
+    {
+      for ( std::set<int>::const_iterator clIt = newClasses.begin(); clIt != newClasses.end(); clIt++ )
+      {
+        ikmsums.find ( *clIt )->second->addModel ( new IKMNoise ( newBinaryLabels[*clIt], tmpNoise, optimizeNoise ) );
+      }
+    }
+    else
+    {
+      //nothing to do, we already have the single ikmsum-object
+    }
+    
+    //NOTE The GMHIKernel is always the last model which is added (this is necessary for easy store and restore functionality)
+    for ( std::set<int>::const_iterator clIt = newClasses.begin(); clIt != newClasses.end(); clIt++ )
+    {
+      ikmsums.find ( *clIt )->second->addModel ( new GMHIKernel ( this->fmk, pf, NULL /* no quantization */ ) );
+    }  
+  } // if ( newClasses.size() > 0)  
+  
+  // ******************************************************************************************
+  //       now do everything which is independent of the number of new classes
+  // ******************************************************************************************  
 
 
   std::map<int, GPLikelihoodApprox * > gplikes;
   std::map<int, GPLikelihoodApprox * > gplikes;
   std::map<int, uint> parameterVectorSizes;
   std::map<int, uint> parameterVectorSizes;
@@ -1068,6 +1143,12 @@ void FMKGPHyperparameterOptimization::optimizeAfterMultipleIncrements ( const st
     std::cerr << std::endl;
     std::cerr << std::endl;
   }
   }
 
 
+  t1.start();
+  this->updateEigenVectors();
+  t1.stop();
+  if (verboseTime)
+    std::cerr << "Time used for setting up the eigenvectors-objects: " << t1.getLast() << std::endl;
+
   t1.start();
   t1.start();
   if ( usePreviousAlphas )
   if ( usePreviousAlphas )
   {
   {
@@ -1076,6 +1157,16 @@ void FMKGPHyperparameterOptimization::optimizeAfterMultipleIncrements ( const st
     
     
     for ( std::map<int, NICE::Vector>::iterator lastAlphaIt = lastAlphas.begin() ;lastAlphaIt != lastAlphas.end(); lastAlphaIt++ )
     for ( std::map<int, NICE::Vector>::iterator lastAlphaIt = lastAlphas.begin() ;lastAlphaIt != lastAlphas.end(); lastAlphaIt++ )
     {
     {
+      //make sure that we only work on currently known classes in this loop
+      while ( newClasses.find( labelIt->first ) != newClasses.end())
+      {
+        labelIt++;
+        //since we already updated the eigenvalues, they contain the eigenvalues for the new classes as well.
+        if (learnBalanced)
+        {
+          eigenMaxIt++;
+        }
+      }      
       int oldSize ( lastAlphaIt->second.size() );
       int oldSize ( lastAlphaIt->second.size() );
       lastAlphaIt->second.resize ( oldSize + x.size() );
       lastAlphaIt->second.resize ( oldSize + x.size() );
 
 
@@ -1104,6 +1195,26 @@ void FMKGPHyperparameterOptimization::optimizeAfterMultipleIncrements ( const st
         eigenMaxIt++;
         eigenMaxIt++;
       }
       }
     }
     }
+       
+    //compute unaffected alpha-vectors for the new classes
+    eigenMaxIt = eigenMax.begin();
+    std::map<int, GPLikelihoodApprox * >::const_iterator gplikesIt = gplikes.begin();
+    for (std::set<int>::const_iterator newClIt =  newClasses.begin(); newClIt != newClasses.end(); newClIt++)
+    {
+      //go to the position of the new class
+      while (gplikesIt->first < *newClIt)
+      {
+        eigenMaxIt++;
+        gplikesIt++;
+      }
+      
+      double maxEigenValue ( 1.0 );
+      if ( (*eigenMaxIt).size() > 0 )
+        maxEigenValue = (*eigenMaxIt)[0];
+      
+      NICE::Vector alphaVec = (binaryLabels[*newClIt] * (1.0 / maxEigenValue) ); //see GPLikelihoodApprox for an explanation
+      lastAlphas.insert( std::pair<int, NICE::Vector>(*newClIt, alphaVec) );
+    }      
 
 
     for ( std::map<int, GPLikelihoodApprox * >::iterator gpLikeIt = gplikes.begin(); gpLikeIt != gplikes.end(); gpLikeIt++ )
     for ( std::map<int, GPLikelihoodApprox * >::iterator gpLikeIt = gplikes.begin(); gpLikeIt != gplikes.end(); gpLikeIt++ )
     {
     {
@@ -1113,13 +1224,13 @@ void FMKGPHyperparameterOptimization::optimizeAfterMultipleIncrements ( const st
   //if we do not use previous alphas, we do not have to set up anything here  
   //if we do not use previous alphas, we do not have to set up anything here  
   t1.stop();
   t1.stop();
   if (verboseTime)
   if (verboseTime)
-    std::cerr << "Time used for setting up the alpha-objects: " << t1.getLast() << std::endl;
+    std::cerr << "Time used for setting up the alpha-objects: " << t1.getLast() << std::endl;  
+  
+/*
 
 
   t1.start();
   t1.start();
-  this->updateEigenVectors();
-  t1.stop();
-  if (verboseTime)
-    std::cerr << "Time used for setting up the eigenvectors-objects: " << t1.getLast() << std::endl;
+  this->setupGPLikelihoodApprox ( gplikes,binaryLabels, parameterVectorSizes );
+  t1.stop();  */
 
 
   if ( verbose )
   if ( verbose )
     std::cerr << "resulting eigenvalues of first class: " << eigenMax[0] << std::endl;
     std::cerr << "resulting eigenvalues of first class: " << eigenMax[0] << std::endl;
@@ -1134,7 +1245,7 @@ void FMKGPHyperparameterOptimization::optimizeAfterMultipleIncrements ( const st
   // as initialization
   // as initialization
   // OPT_NONE
   // OPT_NONE
   // nothing to do, obviously
   // nothing to do, obviously
-  //NOTE we could skip this, if we do not want to change our parameters given new examples
+  //NOTE we can skip this, if we do not want to change our parameters given new examples
   if ( performOptimizationAfterIncrement )
   if ( performOptimizationAfterIncrement )
   {
   {
     t1.start();
     t1.start();
@@ -1153,17 +1264,13 @@ void FMKGPHyperparameterOptimization::optimizeAfterMultipleIncrements ( const st
   {
   {
     t1.start();
     t1.start();
     t1.stop();
     t1.stop();
-    std::cerr << "skip optimization" << std::endl;
+    std::cerr << "skip optimization after increment" << std::endl;
     if (verboseTime)
     if (verboseTime)
       std::cerr << "Time used for performing the optimization: " << t1.getLast() << std::endl;
       std::cerr << "Time used for performing the optimization: " << t1.getLast() << std::endl;
 
 
     std::cerr << "skip feature transformation" << std::endl;
     std::cerr << "skip feature transformation" << std::endl;
     if (verboseTime)
     if (verboseTime)
       std::cerr << "Time used for transforming features with optimal parameters: " << t1.getLast() << std::endl;
       std::cerr << "Time used for transforming features with optimal parameters: " << t1.getLast() << std::endl;
-
-    std::cerr << "skip computation of A, B and LUTs" << std::endl;
-    if (verboseTime)
-      std::cerr << "Time used for setting up the A'nB -objects: " << t1.getLast() << std::endl;
   }
   }
 
 
   if ( verbose )
   if ( verbose )
@@ -1200,6 +1307,7 @@ void FMKGPHyperparameterOptimization::optimizeAfterMultipleIncrements ( const st
   {
   {
     delete gplikes.begin()->second;
     delete gplikes.begin()->second;
   }
   }
+  gplikes.clear();//TODO check whether this is useful or not
 }
 }
 
 
 void FMKGPHyperparameterOptimization::prepareVarianceApproximation()
 void FMKGPHyperparameterOptimization::prepareVarianceApproximation()
@@ -1776,6 +1884,12 @@ void FMKGPHyperparameterOptimization::clear ( ) {};
 void FMKGPHyperparameterOptimization::addExample ( const NICE::SparseVector & x, const double & label, const bool & performOptimizationAfterIncrement )
 void FMKGPHyperparameterOptimization::addExample ( const NICE::SparseVector & x, const double & label, const bool & performOptimizationAfterIncrement )
 {
 {
   this->labels.append ( label );
   this->labels.append ( label );
+  //have we seen this class already?
+  if (knownClasses.find( label ) == knownClasses.end() )
+  {
+    knownClasses.insert( label );
+    newClasses.insert( label );
+  }    
 
 
   // add the new example to our data structure
   // add the new example to our data structure
   // It is necessary to do this already here and not lateron for internal reasons (see GMHIKernel for more details)
   // It is necessary to do this already here and not lateron for internal reasons (see GMHIKernel for more details)
@@ -1786,9 +1900,14 @@ void FMKGPHyperparameterOptimization::addExample ( const NICE::SparseVector & x,
   if (verboseTime)
   if (verboseTime)
     std::cerr << "Time used for adding the data to the fmk object: " << t.getLast() << std::endl;
     std::cerr << "Time used for adding the data to the fmk object: " << t.getLast() << std::endl;
 
 
-  // do the optimization again using the previously known solutions as initialization
-  // update the corresponding matrices A, B and lookup tables T
-  optimizeAfterSingleIncrement ( x, performOptimizationAfterIncrement );
+  //TODO update the matrix for variance computations as well!!!
+  
+  // update the corresponding matrices A, B and lookup tables T  
+  // optional: do the optimization again using the previously known solutions as initialization
+  updateAfterSingleIncrement ( x, performOptimizationAfterIncrement );
+  
+  //clean up
+  newClasses.clear();
 }
 }
 
 
 void FMKGPHyperparameterOptimization::addMultipleExamples ( const std::vector<const NICE::SparseVector*> & newExamples, const NICE::Vector & _labels, const bool & performOptimizationAfterIncrement )
 void FMKGPHyperparameterOptimization::addMultipleExamples ( const std::vector<const NICE::SparseVector*> & newExamples, const NICE::Vector & _labels, const bool & performOptimizationAfterIncrement )
@@ -1798,6 +1917,12 @@ void FMKGPHyperparameterOptimization::addMultipleExamples ( const std::vector<co
   for ( uint i = 0; i < _labels.size(); i++ )
   for ( uint i = 0; i < _labels.size(); i++ )
   {
   {
     this->labels[i+oldSize] = _labels[i];
     this->labels[i+oldSize] = _labels[i];
+    //have we seen this class already?
+    if (knownClasses.find( _labels[i] ) == knownClasses.end() )
+    {
+      knownClasses.insert( _labels[i] );
+      newClasses.insert( _labels[i] );
+    }
   }
   }
 
 
   // add the new example to our data structure
   // add the new example to our data structure
@@ -1842,7 +1967,10 @@ void FMKGPHyperparameterOptimization::addMultipleExamples ( const std::vector<co
   
   
 
 
 
 
-  // do the optimization again using the previously known solutions as initialization
   // update the corresponding matrices A, B and lookup tables T
   // update the corresponding matrices A, B and lookup tables T
-  optimizeAfterMultipleIncrements ( newExamples, performOptimizationAfterIncrement );
+  // optional: do the optimization again using the previously known solutions as initialization
+  updateAfterMultipleIncrements ( newExamples, performOptimizationAfterIncrement );
+  
+  //clean up
+  newClasses.clear();
 }
 }

+ 9 - 4
FMKGPHyperparameterOptimization.h

@@ -140,10 +140,10 @@ class FMKGPHyperparameterOptimization : NICE::Persistent
     //! build the resulting matrices A and B as well as lookup tables T for fast evaluations using the optimized parameter settings
     //! build the resulting matrices A and B as well as lookup tables T for fast evaluations using the optimized parameter settings
     inline void computeMatricesAndLUTs(const std::map<int,GPLikelihoodApprox * > & gplikes);
     inline void computeMatricesAndLUTs(const std::map<int,GPLikelihoodApprox * > & gplikes);
     
     
-    //! Update optimal parameters after adding a new example.  
-    void optimizeAfterSingleIncrement (const NICE::SparseVector & x, const bool & performOptimizationAfterIncrement = false);    
-    //! Update optimal parameters after adding multiple examples.  
-    void optimizeAfterMultipleIncrements (const std::vector<const NICE::SparseVector*> & x, const bool & performOptimizationAfterIncrement = false);   
+    //! Update matrices (A, B, LUTs) and optionally find optimal parameters after adding a new example.  
+    void updateAfterSingleIncrement (const NICE::SparseVector & x, const bool & performOptimizationAfterIncrement = false);    
+    //! Update matrices (A, B, LUTs) and optionally find optimal parameters after adding multiple examples.  
+    void updateAfterMultipleIncrements (const std::vector<const NICE::SparseVector*> & x, const bool & performOptimizationAfterIncrement = false);   
     
     
     //! use the alphas from the last iteration as initial guess for the ILS?
     //! use the alphas from the last iteration as initial guess for the ILS?
     bool usePreviousAlphas;
     bool usePreviousAlphas;
@@ -153,6 +153,11 @@ class FMKGPHyperparameterOptimization : NICE::Persistent
     //! store the class number of the negative class (i.e., smaller class no), only used in binary settings
     //! store the class number of the negative class (i.e., smaller class no), only used in binary settings
     int binaryLabelNegative;
     int binaryLabelNegative;
     
     
+    //! contains all class numbers of the currently known classes
+    std::set<int> knownClasses;
+    //! contains the class numbers of new classes - only needed within the increment step
+    std::set<int> newClasses;
+    
   public:  
   public: