فهرست منبع

minor corrections for IL when going from OCC to binary and from binary to MC

Alexander Freytag 12 سال پیش
والد
کامیت
95ba8b79ec
4فایلهای تغییر یافته به همراه118 افزوده شده و 20 حذف شده
  1. 53 11
      FMKGPHyperparameterOptimization.cpp
  2. 1 1
      FMKGPHyperparameterOptimization.h
  3. 8 1
      GPLikelihoodApprox.cpp
  4. 56 7
      tests/TestGPHIKOnlineLearnable.cpp

+ 53 - 11
FMKGPHyperparameterOptimization.cpp

@@ -92,6 +92,22 @@ void FMKGPHyperparameterOptimization::updateAfterIncrement (
     // alpha = (binaryLabels[classCnt] * (1.0 / eigenmax[0]) );
     // alpha = (binaryLabels[classCnt] * (1.0 / eigenmax[0]) );
     double factor ( 1.0 / this->eigenMax[0] );
     double factor ( 1.0 / this->eigenMax[0] );
     
     
+    // if we came from an OCC setting and are going to a binary setting,
+    // we have to be aware that the 'positive' label is always the one associated with the previous alpha
+    // otherwise, we would get into trouble when going to more classes...
+    // note that this is needed, since knownClasses is a map, so we loose the order of insertion
+    if ( ( this->previousAlphas.size () == 1 ) && ( this->knownClasses.size () == 2 ) )
+    {
+      // if the first class has a larger value then the currently added second class, we have to 
+      // switch the index, which unfortunately is not sooo easy in the map
+      if ( this->previousAlphas.begin()->first == this->binaryLabelNegative )
+      {
+        this->previousAlphas.insert( std::pair<int, NICE::Vector> ( this->binaryLabelPositive, this->previousAlphas.begin()->second) );
+        this->previousAlphas.erase( this->binaryLabelNegative );
+      }
+    }
+    
+    
     std::map<int, NICE::Vector>::const_iterator binaryLabelsIt = binaryLabels.begin();
     std::map<int, NICE::Vector>::const_iterator binaryLabelsIt = binaryLabels.begin();
     
     
     for ( std::map<int, NICE::Vector>::iterator prevAlphaIt = this->previousAlphas.begin();
     for ( std::map<int, NICE::Vector>::iterator prevAlphaIt = this->previousAlphas.begin();
@@ -847,7 +863,7 @@ int FMKGPHyperparameterOptimization::prepareBinaryLabels ( std::map<int, NICE::V
   if ( nrOfClasses > 2 )
   if ( nrOfClasses > 2 )
   {
   {
     //resize every labelVector and set all entries to -1.0
     //resize every labelVector and set all entries to -1.0
-    for ( set<int>::const_iterator k = myClasses.begin(); k != myClasses.end(); k++ )
+    for ( std::set<int>::const_iterator k = myClasses.begin(); k != myClasses.end(); k++ )
     {
     {
       binaryLabels[ *k ].resize ( y.size() );
       binaryLabels[ *k ].resize ( y.size() );
       binaryLabels[ *k ].set ( -1.0 );
       binaryLabels[ *k ].set ( -1.0 );
@@ -860,12 +876,12 @@ int FMKGPHyperparameterOptimization::prepareBinaryLabels ( std::map<int, NICE::V
   }
   }
   else if ( nrOfClasses == 2 )
   else if ( nrOfClasses == 2 )
   {
   {
-    //binary setting -- prepare two binary label vectors with opposite signs
+    //binary setting -- prepare a binary label vector
     NICE::Vector yb ( y );
     NICE::Vector yb ( y );
 
 
-    binaryLabelNegative = *(myClasses.begin());
+    this->binaryLabelNegative = *(myClasses.begin());
     std::set<int>::const_iterator classIt = myClasses.begin(); classIt++;
     std::set<int>::const_iterator classIt = myClasses.begin(); classIt++;
-    binaryLabelPositive = *classIt;
+    this->binaryLabelPositive = *classIt;
     
     
     if ( verbose )
     if ( verbose )
       std::cerr << "positiveClass : " << binaryLabelPositive << " negativeClass: " << binaryLabelNegative << std::endl;
       std::cerr << "positiveClass : " << binaryLabelPositive << " negativeClass: " << binaryLabelNegative << std::endl;
@@ -2359,7 +2375,14 @@ void FMKGPHyperparameterOptimization::addExample( const NICE::SparseVector * exa
   {
   {
     this->knownClasses.insert( label );
     this->knownClasses.insert( label );
     newClasses.insert( label );
     newClasses.insert( label );
-  }    
+  }
+  
+  // If we currently have been in a binary setting, we now have to take care
+  // that we also compute an alpha vector for the second class, which previously 
+  // could be dealt with implicitely.
+  // Therefore, we insert its label here...
+  if ( (newClasses.size() > 0 ) && ( (this->knownClasses.size() - newClasses.size() ) == 2 ) )
+    newClasses.insert( binaryLabelNegative );    
 
 
   // 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)
@@ -2416,15 +2439,34 @@ void FMKGPHyperparameterOptimization::addMultipleExamples( const std::vector< co
   if ( !this->b_performRegression)
   if ( !this->b_performRegression)
   {
   {
     for ( NICE::Vector::const_iterator vecIt = newLabels.begin(); 
     for ( NICE::Vector::const_iterator vecIt = newLabels.begin(); 
-	vecIt != newLabels.end(); vecIt++
-	)
+          vecIt != newLabels.end();
+          vecIt++
+      )
     {  
     {  
-	if ( this->knownClasses.find( *vecIt ) == this->knownClasses.end() )
+      if ( this->knownClasses.find( *vecIt ) == this->knownClasses.end() )
       {
       {
-	this->knownClasses.insert( *vecIt );
-	newClasses.insert( *vecIt );
+        this->knownClasses.insert( *vecIt );
+        newClasses.insert( *vecIt );
       } 
       } 
     }
     }
+
+    // If we currently have been in a OCC setting, and only add a single new class
+    // we have to take care that are still efficient, i.e., that we solve for alpha
+    // only ones, since scores are symmetric in binary cases
+    // Therefore, we remove the label of the secodn class from newClasses, to skip
+    // alpha computations for this class lateron...
+    // 
+    // Therefore, we insert its label here...
+    if ( (newClasses.size() == 1 ) && ( (this->knownClasses.size() - newClasses.size() ) == 1 ) )
+      newClasses.clear();
+
+    // If we currently have been in a binary setting, we now have to take care
+    // that we also compute an alpha vector for the second class, which previously 
+    // could be dealt with implicitely.
+    // Therefore, we insert its label here...
+    if ( (newClasses.size() > 0 ) && ( (this->knownClasses.size() - newClasses.size() ) == 2 ) )
+      newClasses.insert( binaryLabelNegative );      
+      
   }
   }
   // in a regression setting, we do not have to remember any "class labels"
   // in a regression setting, we do not have to remember any "class labels"
   else{}
   else{}
@@ -2440,7 +2482,7 @@ void FMKGPHyperparameterOptimization::addMultipleExamples( const std::vector< co
   
   
   // add examples to all implicite kernel matrices we currently use
   // add examples to all implicite kernel matrices we currently use
   this->ikmsum->addMultipleExamples ( newExamples, newLabels, performOptimizationAfterIncrement );
   this->ikmsum->addMultipleExamples ( newExamples, newLabels, performOptimizationAfterIncrement );
-    
+  
   // update the corresponding matrices A, B and lookup tables T  
   // update the corresponding matrices A, B and lookup tables T  
   // optional: do the optimization again using the previously known solutions as initialization
   // optional: do the optimization again using the previously known solutions as initialization
   this->updateAfterIncrement ( newClasses, performOptimizationAfterIncrement );
   this->updateAfterIncrement ( newClasses, performOptimizationAfterIncrement );

+ 1 - 1
FMKGPHyperparameterOptimization.h

@@ -415,7 +415,7 @@ class FMKGPHyperparameterOptimization : public NICE::Persistent, public NICE::On
     
     
     /**
     /**
     * @brief classify an example that is given as non-sparse vector
     * @brief classify an example that is given as non-sparse vector
-    * NOTE: whenever possible, you should sparse vectors to obtain significantly smaller computation times
+    * NOTE: whenever possible, you should use sparse vectors to obtain significantly smaller computation times
     * 
     * 
     * @date 18-06-2013 (dd-mm-yyyy)
     * @date 18-06-2013 (dd-mm-yyyy)
     * @author Alexander Freytag
     * @author Alexander Freytag

+ 8 - 1
GPLikelihoodApprox.cpp

@@ -308,7 +308,14 @@ double GPLikelihoodApprox::evaluate(const OPTIMIZATION::matrix_type & x)
     NICE::Vector alpha;
     NICE::Vector alpha;
     if ( this->initialAlphaGuess != NULL )
     if ( this->initialAlphaGuess != NULL )
     {
     {
-      alpha = this->initialAlphaGuess->find(classCnt)->second;
+      std::map<int, NICE::Vector>::iterator myIt = this->initialAlphaGuess->find(classCnt);
+      if ( myIt != this->initialAlphaGuess->end() )
+        alpha = myIt->second;
+      else
+      {
+        //NOTE this should never happen in theory...
+        alpha = (binaryLabels[classCnt] * (1.0 / eigenmax[0]) );
+      }
     }
     }
     else
     else
     {
     {

+ 56 - 7
tests/TestGPHIKOnlineLearnable.cpp

@@ -112,6 +112,46 @@ void evaluateClassifier ( NICE::Matrix & confusionMatrix,
   }
   }
 }
 }
 
 
+void compareClassifierOutputs ( const NICE::GPHIKClassifier * classifier,
+                                const NICE::GPHIKClassifier * classifierScratch, 
+                                const NICE::Matrix & data
+                              )
+{
+  int i_loopEnd  ( (int)data.rows() );  
+  
+  for (int i = 0; i < i_loopEnd ; i++)
+  {
+    NICE::Vector example ( data.getRow(i) );
+    
+    NICE::SparseVector scores;
+    int result;    
+    
+    // classify with incrementally trained classifier 
+    classifier->classify( &example, result, scores );
+
+    
+    NICE::SparseVector scoresScratch;
+    int resultScratch;
+    classifierScratch->classify( &example, resultScratch, scoresScratch );
+    
+    
+    bool equal(true);
+    NICE::SparseVector::const_iterator itScores        = scores.begin();
+    NICE::SparseVector::const_iterator itScoresScratch = scoresScratch.begin();
+    for ( ; itScores != scores.end(); itScores++, itScoresScratch++)
+    {
+      if ( fabs( itScores->second - itScores->second ) > 10e-3)
+      {
+        std::cerr << " itScores->second: " << itScores->second << " itScores->second: " << itScores->second << std::endl;
+        equal = false;
+        break;
+      }        
+    }
+    
+    CPPUNIT_ASSERT_EQUAL ( equal, true );     
+  }  
+}
+
 void TestGPHIKOnlineLearnable::testOnlineLearningStartEmpty()
 void TestGPHIKOnlineLearnable::testOnlineLearningStartEmpty()
 {
 {
   if (verboseStartEnd)
   if (verboseStartEnd)
@@ -145,7 +185,7 @@ void TestGPHIKOnlineLearnable::testOnlineLearningStartEmpty()
   //create classifier object
   //create classifier object
   NICE::GPHIKClassifier * classifier;
   NICE::GPHIKClassifier * classifier;
   classifier = new NICE::GPHIKClassifier ( &conf );  
   classifier = new NICE::GPHIKClassifier ( &conf );  
-  bool performOptimizationAfterIncrement ( false );
+  bool performOptimizationAfterIncrement ( true );
 
 
   // add training samples, but without running training method first
   // add training samples, but without running training method first
   classifier->addMultipleExamples ( examplesTrain,yMultiTrain, performOptimizationAfterIncrement );  
   classifier->addMultipleExamples ( examplesTrain,yMultiTrain, performOptimizationAfterIncrement );  
@@ -253,6 +293,10 @@ void TestGPHIKOnlineLearnable::testOnlineLearningOCCtoBinary()
   
   
   examplesTrain.resize( dataTrain.rows() );
   examplesTrain.resize( dataTrain.rows() );
   
   
+  // to check whether non-consecutive and even wrongly odered class numbers work as well
+  int clNoFirst  ( 2 );
+  int clNoSecond ( 0 );
+  
   std::vector< const NICE::SparseVector *>::iterator exTrainIt = examplesTrain.begin();
   std::vector< const NICE::SparseVector *>::iterator exTrainIt = examplesTrain.begin();
   for (int i = 0; i < (int)dataTrain.rows(); i++, exTrainIt++)
   for (int i = 0; i < (int)dataTrain.rows(); i++, exTrainIt++)
   {
   {
@@ -261,20 +305,22 @@ void TestGPHIKOnlineLearnable::testOnlineLearningOCCtoBinary()
     if ( yBinTrain[i] == 1 )
     if ( yBinTrain[i] == 1 )
     {
     {
       examplesTrainPlus.push_back ( *exTrainIt );
       examplesTrainPlus.push_back ( *exTrainIt );
+      yBinTrain[i] = clNoFirst;
     }
     }
     else
     else
     {
     {
        examplesTrainMinus.push_back ( *exTrainIt );
        examplesTrainMinus.push_back ( *exTrainIt );
+       yBinTrain[i] = clNoSecond;
     }
     }
   }
   }
-  NICE::Vector yBinPlus  ( examplesTrainPlus.size(), 1 ) ;
-  NICE::Vector yBinMinus ( examplesTrainMinus.size(), 0 );
+  NICE::Vector yBinPlus  ( examplesTrainPlus.size(), clNoFirst ) ;
+  NICE::Vector yBinMinus ( examplesTrainMinus.size(), clNoSecond );
   
   
   
   
   //create classifier object
   //create classifier object
   NICE::GPHIKClassifier * classifier;
   NICE::GPHIKClassifier * classifier;
   classifier = new NICE::GPHIKClassifier ( &conf );  
   classifier = new NICE::GPHIKClassifier ( &conf );  
-  bool performOptimizationAfterIncrement ( false );
+  bool performOptimizationAfterIncrement ( true );
 
 
   // training with examples for positive class only
   // training with examples for positive class only
   classifier->train ( examplesTrainPlus, yBinPlus );
   classifier->train ( examplesTrainPlus, yBinPlus );
@@ -365,6 +411,7 @@ void TestGPHIKOnlineLearnable::testOnlineLearningBinarytoMultiClass()
   
   
   conf.sB ( "GPHIKClassifier", "eig_verbose", false);
   conf.sB ( "GPHIKClassifier", "eig_verbose", false);
   conf.sS ( "GPHIKClassifier", "optimization_method", "downhillsimplex");
   conf.sS ( "GPHIKClassifier", "optimization_method", "downhillsimplex");
+//   conf.sS ( "GPHIKClassifier", "optimization_method", "none");
   
   
   std::string s_trainData = conf.gS( "main", "trainData", "toyExampleSmallScaleTrain.data" );
   std::string s_trainData = conf.gS( "main", "trainData", "toyExampleSmallScaleTrain.data" );
   
   
@@ -413,11 +460,11 @@ void TestGPHIKOnlineLearnable::testOnlineLearningBinarytoMultiClass()
   //create classifier object
   //create classifier object
   NICE::GPHIKClassifier * classifier;
   NICE::GPHIKClassifier * classifier;
   classifier = new NICE::GPHIKClassifier ( &conf );  
   classifier = new NICE::GPHIKClassifier ( &conf );  
-  bool performOptimizationAfterIncrement ( false );
+  bool performOptimizationAfterIncrement ( true );
 
 
-  // training with examples for positive class only
+  // training with examples for first and second class only
   classifier->train ( examplesTrain12, yMulti12 );
   classifier->train ( examplesTrain12, yMulti12 );
-  // add samples for negative class, thereby going from OCC to binary setting
+  // add samples for third class, thereby going from binary to multi-class setting
   classifier->addMultipleExamples ( examplesTrain3, yMulti3, performOptimizationAfterIncrement );  
   classifier->addMultipleExamples ( examplesTrain3, yMulti3, performOptimizationAfterIncrement );  
   
   
   // create second object trained in the standard way
   // create second object trained in the standard way
@@ -457,6 +504,8 @@ void TestGPHIKOnlineLearnable::testOnlineLearningBinarytoMultiClass()
   // ------------------------------------------
   // ------------------------------------------
   // ------------- CLASSIFICATION --------------
   // ------------- CLASSIFICATION --------------
   // ------------------------------------------  
   // ------------------------------------------  
+  
+  compareClassifierOutputs ( classifier, classifierScratch, dataTest ); 
   evaluateClassifier ( confusionMatrix, classifier, dataTest, yMultiTest,
   evaluateClassifier ( confusionMatrix, classifier, dataTest, yMultiTest,
                           mapClNoToIdxTrain,mapClNoToIdxTest ); 
                           mapClNoToIdxTrain,mapClNoToIdxTest );