TestGPHIKOnlineLearnable.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. /**
  2. * @file TestGPHIKOnlineLearnable.cpp
  3. * @brief CppUnit-Testcase to verify that GPHIKClassifier methods herited from Persistent (store and restore) work as desired.
  4. * @author Alexander Freytag
  5. * @date 21-12-2013
  6. */
  7. #ifdef NICE_USELIB_CPPUNIT
  8. // STL includes
  9. #include <iostream>
  10. #include <vector>
  11. // NICE-core includes
  12. #include <core/basics/Config.h>
  13. #include <core/basics/Timer.h>
  14. // gp-hik-core includes
  15. #include "gp-hik-core/GPHIKClassifier.h"
  16. #include "TestGPHIKOnlineLearnable.h"
  17. using namespace std; //C basics
  18. using namespace NICE; // nice-core
  19. const bool verboseStartEnd = true;
  20. CPPUNIT_TEST_SUITE_REGISTRATION( TestGPHIKOnlineLearnable );
  21. void TestGPHIKOnlineLearnable::setUp() {
  22. }
  23. void TestGPHIKOnlineLearnable::tearDown() {
  24. }
  25. void readData ( const std::string filename, NICE::Matrix & data, NICE::Vector & yBin, NICE::Vector & yMulti )
  26. {
  27. std::ifstream ifs ( filename.c_str() , ios::in );
  28. if ( ifs.good() )
  29. {
  30. ifs >> data;
  31. ifs >> yBin;
  32. ifs >> yMulti;
  33. ifs.close();
  34. }
  35. else
  36. {
  37. std::cerr << "Unable to read data from file " << filename << " -- aborting." << std::endl;
  38. CPPUNIT_ASSERT ( ifs.good() );
  39. }
  40. }
  41. void prepareLabelMappings (std::map<int,int> mapClNoToIdxTrain, const GPHIKClassifier * classifier, std::map<int,int> mapClNoToIdxTest, const NICE::Vector & yMultiTest)
  42. {
  43. // determine classes known during training and corresponding mapping
  44. // thereby allow for non-continous class labels
  45. std::set<int> classesKnownTraining = classifier->getKnownClassNumbers();
  46. int noClassesKnownTraining ( classesKnownTraining.size() );
  47. std::set<int>::const_iterator clTrIt = classesKnownTraining.begin();
  48. for ( int i=0; i < noClassesKnownTraining; i++, clTrIt++ )
  49. mapClNoToIdxTrain.insert ( std::pair<int,int> ( *clTrIt, i ) );
  50. // determine classes known during testing and corresponding mapping
  51. // thereby allow for non-continous class labels
  52. std::set<int> classesKnownTest;
  53. classesKnownTest.clear();
  54. // determine which classes we have in our label vector
  55. // -> MATLAB: myClasses = unique(y);
  56. for ( NICE::Vector::const_iterator it = yMultiTest.begin(); it != yMultiTest.end(); it++ )
  57. {
  58. if ( classesKnownTest.find ( *it ) == classesKnownTest.end() )
  59. {
  60. classesKnownTest.insert ( *it );
  61. }
  62. }
  63. int noClassesKnownTest ( classesKnownTest.size() );
  64. std::set<int>::const_iterator clTestIt = classesKnownTest.begin();
  65. for ( int i=0; i < noClassesKnownTest; i++, clTestIt++ )
  66. mapClNoToIdxTest.insert ( std::pair<int,int> ( *clTestIt, i ) );
  67. }
  68. void evaluateClassifier ( NICE::Matrix & confusionMatrix,
  69. const NICE::GPHIKClassifier * classifier,
  70. const NICE::Matrix & data,
  71. const NICE::Vector & yMulti,
  72. const std::map<int,int> & mapClNoToIdxTrain,
  73. const std::map<int,int> & mapClNoToIdxTest
  74. )
  75. {
  76. int i_loopEnd ( (int)data.rows() );
  77. for (int i = 0; i < i_loopEnd ; i++)
  78. {
  79. NICE::Vector example ( data.getRow(i) );
  80. NICE::SparseVector scores;
  81. int result;
  82. // classify with incrementally trained classifier
  83. classifier->classify( &example, result, scores );
  84. confusionMatrix( mapClNoToIdxTrain.find(result)->second, mapClNoToIdxTest.find(yMulti[i])->second ) += 1.0;
  85. }
  86. }
  87. void TestGPHIKOnlineLearnable::testOnlineLearningStartEmpty()
  88. {
  89. if (verboseStartEnd)
  90. std::cerr << "================== TestGPHIKOnlineLearnable::testOnlineLearningStartEmpty ===================== " << std::endl;
  91. NICE::Config conf;
  92. conf.sB ( "GPHIKClassifier", "eig_verbose", false);
  93. conf.sS ( "GPHIKClassifier", "optimization_method", "downhillsimplex");
  94. std::string s_trainData = conf.gS( "main", "trainData", "toyExampleSmallScaleTrain.data" );
  95. //------------- read the training data --------------
  96. NICE::Matrix dataTrain;
  97. NICE::Vector yBinTrain;
  98. NICE::Vector yMultiTrain;
  99. readData ( s_trainData, dataTrain, yBinTrain, yMultiTrain );
  100. //----------------- convert data to sparse data structures ---------
  101. std::vector< const NICE::SparseVector *> examplesTrain;
  102. examplesTrain.resize( dataTrain.rows() );
  103. std::vector< const NICE::SparseVector *>::iterator exTrainIt = examplesTrain.begin();
  104. for (int i = 0; i < (int)dataTrain.rows(); i++, exTrainIt++)
  105. {
  106. *exTrainIt = new NICE::SparseVector( dataTrain.getRow(i) );
  107. }
  108. //create classifier object
  109. NICE::GPHIKClassifier * classifier;
  110. classifier = new NICE::GPHIKClassifier ( &conf );
  111. bool performOptimizationAfterIncrement ( false );
  112. // add training samples, but without running training method first
  113. classifier->addMultipleExamples ( examplesTrain,yMultiTrain, performOptimizationAfterIncrement );
  114. // create second object trained in the standard way
  115. NICE::GPHIKClassifier * classifierScratch = new NICE::GPHIKClassifier ( &conf );
  116. classifierScratch->train ( examplesTrain, yMultiTrain );
  117. // TEST both classifiers to produce equal results
  118. //------------- read the test data --------------
  119. NICE::Matrix dataTest;
  120. NICE::Vector yBinTest;
  121. NICE::Vector yMultiTest;
  122. std::string s_testData = conf.gS( "main", "testData", "toyExampleTest.data" );
  123. readData ( s_testData, dataTest, yBinTest, yMultiTest );
  124. // ------------------------------------------
  125. // ------------- PREPARATION --------------
  126. // ------------------------------------------
  127. // determine classes known during training/testing and corresponding mapping
  128. // thereby allow for non-continous class labels
  129. std::map<int,int> mapClNoToIdxTrain;
  130. std::map<int,int> mapClNoToIdxTest;
  131. prepareLabelMappings (mapClNoToIdxTrain, classifier, mapClNoToIdxTest, yMultiTest);
  132. NICE::Matrix confusionMatrix ( mapClNoToIdxTrain.size(), mapClNoToIdxTest.size(), 0.0);
  133. NICE::Matrix confusionMatrixScratch ( mapClNoToIdxTrain.size(), mapClNoToIdxTest.size(), 0.0);
  134. // ------------------------------------------
  135. // ------------- CLASSIFICATION --------------
  136. // ------------------------------------------
  137. evaluateClassifier ( confusionMatrix, classifier, dataTest, yMultiTest,
  138. mapClNoToIdxTrain,mapClNoToIdxTest );
  139. evaluateClassifier ( confusionMatrixScratch, classifierScratch, dataTest, yMultiTest,
  140. mapClNoToIdxTrain,mapClNoToIdxTest );
  141. // post-process confusion matrices
  142. confusionMatrix.normalizeColumnsL1();
  143. double arr ( confusionMatrix.trace()/confusionMatrix.cols() );
  144. confusionMatrixScratch.normalizeColumnsL1();
  145. double arrScratch ( confusionMatrixScratch.trace()/confusionMatrixScratch.cols() );
  146. CPPUNIT_ASSERT_DOUBLES_EQUAL( arr, arrScratch, 1e-8);
  147. // don't waste memory
  148. delete classifier;
  149. delete classifierScratch;
  150. for (std::vector< const NICE::SparseVector *>::iterator exTrainIt = examplesTrain.begin(); exTrainIt != examplesTrain.end(); exTrainIt++)
  151. {
  152. delete *exTrainIt;
  153. }
  154. if (verboseStartEnd)
  155. std::cerr << "================== TestGPHIKOnlineLearnable::testOnlineLearningStartEmpty done ===================== " << std::endl;
  156. }
  157. void TestGPHIKOnlineLearnable::testOnlineLearningOCCtoBinary()
  158. {
  159. if (verboseStartEnd)
  160. std::cerr << "================== TestGPHIKOnlineLearnable::testOnlineLearningOCCtoBinary ===================== " << std::endl;
  161. if (verboseStartEnd)
  162. std::cerr << "================== TestGPHIKOnlineLearnable::testOnlineLearningOCCtoBinary done ===================== " << std::endl;
  163. }
  164. void TestGPHIKOnlineLearnable::testOnlineLearningBinarytoMultiClass()
  165. {
  166. if (verboseStartEnd)
  167. std::cerr << "================== TestGPHIKOnlineLearnable::testOnlineLearningBinarytoMultiClass ===================== " << std::endl;
  168. if (verboseStartEnd)
  169. std::cerr << "================== TestGPHIKOnlineLearnable::testOnlineLearningBinarytoMultiClass done ===================== " << std::endl;
  170. }
  171. void TestGPHIKOnlineLearnable::testOnlineLearningMultiClass()
  172. {
  173. if (verboseStartEnd)
  174. std::cerr << "================== TestGPHIKOnlineLearnable::testOnlineLearningMultiClass ===================== " << std::endl;
  175. NICE::Config conf;
  176. conf.sB ( "GPHIKClassifier", "eig_verbose", false);
  177. conf.sS ( "GPHIKClassifier", "optimization_method", "downhillsimplex");
  178. std::string s_trainData = conf.gS( "main", "trainData", "toyExampleSmallScaleTrain.data" );
  179. //------------- read the training data --------------
  180. NICE::Matrix dataTrain;
  181. NICE::Vector yBinTrain;
  182. NICE::Vector yMultiTrain;
  183. readData ( s_trainData, dataTrain, yBinTrain, yMultiTrain );
  184. //----------------- convert data to sparse data structures ---------
  185. std::vector< const NICE::SparseVector *> examplesTrain;
  186. examplesTrain.resize( dataTrain.rows()-1 );
  187. std::vector< const NICE::SparseVector *>::iterator exTrainIt = examplesTrain.begin();
  188. for (int i = 0; i < (int)dataTrain.rows()-1; i++, exTrainIt++)
  189. {
  190. *exTrainIt = new NICE::SparseVector( dataTrain.getRow(i) );
  191. }
  192. // TRAIN INITIAL CLASSIFIER FROM SCRATCH
  193. NICE::GPHIKClassifier * classifier;
  194. classifier = new NICE::GPHIKClassifier ( &conf );
  195. //use all but the first example for training and add the first one lateron
  196. NICE::Vector yMultiRelevantTrain ( yMultiTrain.getRangeRef( 0, yMultiTrain.size()-2 ) );
  197. classifier->train ( examplesTrain , yMultiRelevantTrain );
  198. // RUN INCREMENTAL LEARNING
  199. bool performOptimizationAfterIncrement ( false );
  200. NICE::SparseVector * exampleToAdd = new NICE::SparseVector ( dataTrain.getRow( (int)dataTrain.rows()-1 ) );
  201. classifier->addExample ( exampleToAdd, yMultiTrain[ (int)dataTrain.rows()-2 ], performOptimizationAfterIncrement );
  202. std::cerr << "label of example to add: " << yMultiTrain[ (int)dataTrain.rows()-1 ] << std::endl;
  203. // TRAIN SECOND CLASSIFIER FROM SCRATCH USING THE SAME OVERALL AMOUNT OF EXAMPLES
  204. examplesTrain.push_back( exampleToAdd );
  205. NICE::GPHIKClassifier * classifierScratch = new NICE::GPHIKClassifier ( &conf );
  206. classifierScratch->train ( examplesTrain, yMultiTrain );
  207. std::cerr << "trained both classifiers - now start evaluating them" << std::endl;
  208. // TEST that both classifiers produce equal store-files
  209. std::string s_destination_save_IL ( "myClassifierIL.txt" );
  210. std::filebuf fbOut;
  211. fbOut.open ( s_destination_save_IL.c_str(), ios::out );
  212. std::ostream os (&fbOut);
  213. //
  214. classifier->store( os );
  215. //
  216. fbOut.close();
  217. std::string s_destination_save_scratch ( "myClassifierScratch.txt" );
  218. std::filebuf fbOutScratch;
  219. fbOutScratch.open ( s_destination_save_scratch.c_str(), ios::out );
  220. std::ostream osScratch (&fbOutScratch);
  221. //
  222. classifierScratch->store( osScratch );
  223. //
  224. fbOutScratch.close();
  225. // TEST both classifiers to produce equal results
  226. //------------- read the test data --------------
  227. NICE::Matrix dataTest;
  228. NICE::Vector yBinTest;
  229. NICE::Vector yMultiTest;
  230. std::string s_testData = conf.gS( "main", "testData", "toyExampleTest.data" );
  231. readData ( s_testData, dataTest, yBinTest, yMultiTest );
  232. // ------------------------------------------
  233. // ------------- PREPARATION --------------
  234. // ------------------------------------------
  235. // determine classes known during training/testing and corresponding mapping
  236. // thereby allow for non-continous class labels
  237. std::map<int,int> mapClNoToIdxTrain;
  238. std::map<int,int> mapClNoToIdxTest;
  239. prepareLabelMappings (mapClNoToIdxTrain, classifier, mapClNoToIdxTest, yMultiTest);
  240. NICE::Matrix confusionMatrix ( mapClNoToIdxTrain.size(), mapClNoToIdxTest.size(), 0.0);
  241. NICE::Matrix confusionMatrixScratch ( mapClNoToIdxTrain.size(), mapClNoToIdxTest.size(), 0.0);
  242. // ------------------------------------------
  243. // ------------- CLASSIFICATION --------------
  244. // ------------------------------------------
  245. evaluateClassifier ( confusionMatrix, classifier, dataTest, yMultiTest,
  246. mapClNoToIdxTrain,mapClNoToIdxTest );
  247. evaluateClassifier ( confusionMatrixScratch, classifierScratch, dataTest, yMultiTest,
  248. mapClNoToIdxTrain,mapClNoToIdxTest );
  249. // post-process confusion matrices
  250. confusionMatrix.normalizeColumnsL1();
  251. double arr ( confusionMatrix.trace()/confusionMatrix.cols() );
  252. confusionMatrixScratch.normalizeColumnsL1();
  253. double arrScratch ( confusionMatrixScratch.trace()/confusionMatrixScratch.cols() );
  254. CPPUNIT_ASSERT_DOUBLES_EQUAL( arr, arrScratch, 1e-8);
  255. // don't waste memory
  256. delete classifier;
  257. delete classifierScratch;
  258. for (std::vector< const NICE::SparseVector *>::iterator exTrainIt = examplesTrain.begin(); exTrainIt != examplesTrain.end(); exTrainIt++)
  259. {
  260. delete *exTrainIt;
  261. }
  262. if (verboseStartEnd)
  263. std::cerr << "================== TestGPHIKOnlineLearnable::testOnlineLearningMultiClass done ===================== " << std::endl;
  264. }
  265. #endif