CodebookRandomForestMex.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. #ifdef NICE_USELIB_MEX
  2. /**
  3. * @file GPHIKRegressionMex.cpp
  4. * @author Alexander Freytag
  5. * @date 17-01-2014 (dd-mm-yyyy)
  6. * @brief Matlab-Interface of our GPHIKRegression, allowing for training, regression, optimization, variance prediction, incremental learning, and storing/re-storing.
  7. */
  8. // STL includes
  9. #include <math.h>
  10. #include <matrix.h>
  11. #include <mex.h>
  12. // NICE-core includes
  13. #include <core/basics/Config.h>
  14. #include <core/basics/Timer.h>
  15. #include <core/vector/MatrixT.h>
  16. #include <core/vector/VectorT.h>
  17. // CodebookRandomForest stuff
  18. #include "vislearning/features/simplefeatures/CodebookRandomForest.h"
  19. #include "vislearning/features/fpfeatures/VectorFeature.h"
  20. // Interface for conversion between Matlab and C objects
  21. #include "gp-hik-core/matlab/classHandleMtoC.h"
  22. #include "gp-hik-core/matlab/ConverterMatlabToNICE.h"
  23. #include "gp-hik-core/matlab/ConverterNICEToMatlab.h"
  24. using namespace std; //C basics
  25. using namespace NICE; // nice-core
  26. #define DEBUG_VERBOSE
  27. NICE::Config parseParametersERC(const mxArray *prhs[], int nrhs)
  28. {
  29. NICE::Config conf;
  30. // Check parameters
  31. if ( nrhs % 2 == 1 )
  32. {
  33. mexErrMsgTxt("parseParametersERC: uneven number of config arguments.");
  34. }
  35. // now run over all given parameter specifications
  36. // and add them to the config
  37. for( int i=0; i < nrhs; i+=2 )
  38. {
  39. std::string variable = MatlabConversion::convertMatlabToString(prhs[i]);
  40. /////////////
  41. //CodebookRandomForest( int maxDepth
  42. // number_of_trees = conf->gI(section, "number_of_trees", 20 );
  43. // features_per_tree = conf->gD(section, "features_per_tree", 1.0 );
  44. // samples_per_tree = conf->gD(section, "samples_per_tree", 0.2 );
  45. // use_simple_balancing = conf->gB(section, "use_simple_balancing", false);
  46. // weight_examples = conf->gB(section, "weight_examples", false);
  47. // memory_efficient = conf->gB(section, "memory_efficient", false);
  48. //std::string builder_section = conf->gS(section, "builder_section", "DTBRandom");
  49. #ifdef DEBUG_VERBOSE
  50. std::cerr << "config variable: "<< variable << std::endl;
  51. #endif
  52. if(variable == "conf")
  53. {
  54. // if first argument is the filename of an existing config file,
  55. // read the config accordingly
  56. conf = NICE::Config ( MatlabConversion::convertMatlabToString( prhs[i+1] ) );
  57. #ifdef DEBUG_VERBOSE
  58. std::cerr << "conf " << MatlabConversion::convertMatlabToString( prhs[i+1] ) << std::endl;
  59. #endif
  60. }
  61. else if( variable == "number_of_trees")
  62. {
  63. if ( mxIsInt32( prhs[i+1] ) )
  64. {
  65. int value = MatlabConversion::convertMatlabToInt32(prhs[i+1]);
  66. conf.sI("RandomForest", variable, value);
  67. #ifdef DEBUG_VERBOSE
  68. std::cerr << "number_of_trees " << value << std::endl;
  69. #endif
  70. }
  71. else
  72. {
  73. std::string errorMsg = "Unexpected parameter value for \'" + variable + "\'. Int32 expected.";
  74. mexErrMsgIdAndTxt( "mexnice:error", errorMsg.c_str() );
  75. }
  76. }
  77. else if( variable == "maxDepthTree")
  78. {
  79. if ( mxIsInt32( prhs[i+1] ) )
  80. {
  81. int value = MatlabConversion::convertMatlabToInt32(prhs[i+1]);
  82. conf.sI("CodebookRandomForest", variable, value);
  83. #ifdef DEBUG_VERBOSE
  84. std::cerr << "maxDepthTree " << value << std::endl;
  85. #endif
  86. }
  87. else
  88. {
  89. std::string errorMsg = "Unexpected parameter value for \'" + variable + "\'. Int32 expected.";
  90. mexErrMsgIdAndTxt( "mexnice:error", errorMsg.c_str() );
  91. }
  92. }
  93. else if( variable == "verbose")
  94. {
  95. if ( mxIsLogical( prhs[i+1] ) )
  96. {
  97. bool bVerbose = MatlabConversion::convertMatlabToBool(prhs[i+1]);
  98. conf.sB("CodebookRandomForest", variable, bVerbose);
  99. #ifdef DEBUG_VERBOSE
  100. std::cerr << "verbose " << bVerbose << std::endl;
  101. #endif
  102. }
  103. else
  104. {
  105. std::string errorMsg = "Unexpected parameter value for \'" + variable + "\'. Boolean expected.";
  106. mexErrMsgIdAndTxt( "mexnice:error", errorMsg.c_str() );
  107. }
  108. }
  109. }
  110. return conf;
  111. }
  112. // MAIN MATLAB FUNCTION
  113. void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
  114. {
  115. #ifdef DEBUG_VERBOSE
  116. std::cerr << "Verbose Debug Output on (compiled with debug definition)." << std::endl;
  117. #endif
  118. // get the command string specifying what to do
  119. if (nrhs < 1)
  120. mexErrMsgTxt("No commands and options passed... Aborting!");
  121. if( !mxIsChar( prhs[0] ) )
  122. mexErrMsgTxt("First argument needs to be the command, ie.e, the class method to call... Aborting!");
  123. std::string cmd = MatlabConversion::convertMatlabToString( prhs[0] );
  124. // in all other cases, there should be a second input,
  125. // which the be the class instance handle
  126. if (nrhs < 2)
  127. mexErrMsgTxt("Second input should be a class instance handle.");
  128. // delete object
  129. if ( !strcmp("delete", cmd.c_str() ) )
  130. {
  131. // Destroy the C++ object
  132. MatlabConversion::destroyObject<OBJREC::CodebookRandomForest>(prhs[1]);
  133. return;
  134. }
  135. ////////////////////////////////////////
  136. // Check which class method to call //
  137. ////////////////////////////////////////
  138. // standard train - assumes initialized object
  139. if (!strcmp("createAndTrain", cmd.c_str() ))
  140. {
  141. // Check parameters
  142. if (nlhs < 0 || nrhs < 4 )
  143. {
  144. mexErrMsgTxt("Train: Unexpected arguments.");
  145. }
  146. //------------- read the data --------------
  147. if (nrhs < 4)
  148. {
  149. mexErrMsgTxt("needs at least 2 matrix inputs, first the training features, second the sample labels");
  150. return;
  151. }
  152. const mxArray *t_pArrTrainData = prhs[1];
  153. const mxArray *t_pArrTrainLabels = prhs[2];
  154. //----------------- parse config options -------------
  155. NICE::Config conf = parseParametersERC(prhs+3, nrhs-3 );
  156. int iNumFeatureDimension = mxGetM( t_pArrTrainData ); // feature dimensions
  157. #ifdef DEBUG_VERBOSE
  158. std::cerr << "iNumFeatureDimension " << iNumFeatureDimension << std::endl;
  159. #endif
  160. //----------------- create examples object -------------
  161. NICE::Vector t_vecLabelsTrain = MatlabConversion::convertDoubleVectorToNice( t_pArrTrainLabels );
  162. NICE::Matrix t_matDataTrain = MatlabConversion::convertDoubleMatrixToNice( t_pArrTrainData );
  163. OBJREC::Examples examplesTrain;
  164. bool bRet = OBJREC::Examples::wrapExamplesAroundFeatureMatrix( t_matDataTrain, t_vecLabelsTrain, examplesTrain );
  165. if( !bRet )
  166. {
  167. mexErrMsgTxt("createAndTrain: Error creating Examples from raw feature matrix and labels.");
  168. }
  169. //----------------- create raw feature mapping -------------
  170. OBJREC::FeaturePool fp;
  171. OBJREC::VectorFeature *pVecFeature = new OBJREC::VectorFeature(iNumFeatureDimension);
  172. pVecFeature->explode(fp);
  173. #ifdef DEBUG_VERBOSE
  174. //----------------- debug features -------------
  175. OBJREC::Example t_Exp = examplesTrain[0].second;
  176. NICE::Vector t_FeatVector;
  177. fp.calcFeatureVector(t_Exp, t_FeatVector);
  178. std::cerr << "first full Feature Vec: " <<t_FeatVector << std::endl;
  179. #endif
  180. //----------------- train our random Forest -------------
  181. OBJREC::FPCRandomForests *pRandForest = new OBJREC::FPCRandomForests(&conf,"RandomForest");
  182. pRandForest->train(fp, examplesTrain);
  183. //----------------- create codebook ERC clusterer -------------
  184. int nMaxDepth = conf.gI("CodebookRandomForest", "maxDepthTree",10);
  185. int nMaxCodebookSize = conf.gI("CodebookRandomForest", "maxCodebookSize",100);
  186. #ifdef DEBUG_VERBOSE
  187. std::cerr << "maxDepthTree " << nMaxDepth << std::endl;
  188. std::cerr << "nMaxCodebookSize " << nMaxCodebookSize << std::endl;
  189. #endif
  190. OBJREC::CodebookRandomForest *pCodebookRandomForest = new OBJREC::CodebookRandomForest(pRandForest, nMaxDepth,nMaxCodebookSize);
  191. // handle to the C++ instance
  192. plhs[0] = MatlabConversion::convertPtr2Mat<OBJREC::CodebookRandomForest>( pCodebookRandomForest );
  193. //----------------- clean up -------------
  194. delete pVecFeature;
  195. pVecFeature = NULL;
  196. // delete all "exploded" features, they are internally cloned in the random trees anyway
  197. fp.destroy();
  198. //
  199. examplesTrain.clean();
  200. return;
  201. }
  202. ///// generate Histogram over trees
  203. else if (!strcmp("generateHistogram", cmd.c_str() ))
  204. {
  205. //------------- read the data --------------
  206. if (nrhs < 3)
  207. {
  208. mexErrMsgTxt("needs at least 1 matrix inputs, first the training features");
  209. return;
  210. }
  211. //----------------- convert ptr of trained codebook forest -------------
  212. OBJREC::CodebookRandomForest *pCodebookRandomForest = MatlabConversion::convertMat2Ptr<OBJREC::CodebookRandomForest>(prhs[1]);
  213. if( pCodebookRandomForest == NULL )
  214. {
  215. mexErrMsgTxt("classify: No valid trained classifier given");
  216. }
  217. //----------------- convert matlab data into NICE data -------------
  218. const mxArray *t_pArrTrainData = prhs[2];
  219. NICE::Matrix matDataTrain = MatlabConversion::convertDoubleMatrixToNice( t_pArrTrainData );
  220. size_t numTrainSamples = matDataTrain.cols();
  221. size_t iNumFeatureDimension = matDataTrain.rows();
  222. size_t iNumCodewords = pCodebookRandomForest->getCodebookSize();
  223. #ifdef DEBUG_VERBOSE
  224. std::cerr << "numTrainSamples " << numTrainSamples << std::endl;
  225. std::cerr << "iNumFeatureDimension " << iNumFeatureDimension << std::endl;
  226. std::cerr << "iNumCodewords " << iNumCodewords << std::endl;
  227. #endif
  228. //----------------- parse config options -------------
  229. bool bVerboseOutput = false;
  230. if( nrhs > 3)
  231. {
  232. NICE::Config conf = parseParametersERC(prhs+3, nrhs-3 );
  233. bVerboseOutput = conf.gB("CodebookRandomForest", "verbose", false);
  234. }
  235. //----------------- quantize samples into histogram -------------
  236. NICE::Vector histogram(iNumCodewords, 0.0f);
  237. const double *pDataPtr = matDataTrain.getDataPointer();
  238. int t_iCodebookEntry; double t_fWeight; double t_fDistance;
  239. for (size_t i = 0; i < numTrainSamples; i++, pDataPtr+= iNumFeatureDimension )
  240. {
  241. const NICE::Vector t_VecTrainData( pDataPtr , iNumFeatureDimension);
  242. pCodebookRandomForest->voteVQ(t_VecTrainData, histogram, t_iCodebookEntry, t_fWeight, t_fDistance );
  243. if(bVerboseOutput)
  244. std::cerr << i << ": " << "CBEntry " << t_iCodebookEntry << " Weight: " << t_fWeight << " Distance: " << t_fDistance << std::endl;
  245. }
  246. //----------------- convert NICE histogram into MATLAB data -------------
  247. plhs[0] = MatlabConversion::convertVectorFromNice(histogram);
  248. return;
  249. }
  250. ///// get distribution of classes per sample
  251. else if (!strcmp("calcClassDistributionPerSample", cmd.c_str() ))
  252. {
  253. //------------- read the data --------------
  254. if (nrhs < 3)
  255. {
  256. mexErrMsgTxt("needs at least 1 matrix inputs, first the training features");
  257. return;
  258. }
  259. //----------------- convert ptr of trained codebook forest -------------
  260. OBJREC::CodebookRandomForest *pCodebookRandomForest = MatlabConversion::convertMat2Ptr<OBJREC::CodebookRandomForest>(prhs[1]);
  261. if( pCodebookRandomForest == NULL )
  262. {
  263. mexErrMsgTxt("classify: No valid trained classifier given");
  264. }
  265. //----------------- convert matlab data into NICE data -------------
  266. const mxArray *t_pArrTrainData = prhs[2];
  267. NICE::Matrix matData = MatlabConversion::convertDoubleMatrixToNice( t_pArrTrainData );
  268. size_t numTrainSamples = matData.cols();
  269. size_t iNumFeatureDimension = matData.rows();
  270. #ifdef DEBUG_VERBOSE
  271. std::cerr << "numTrainSamples " << numTrainSamples << std::endl;
  272. std::cerr << "iNumFeatureDimension " << iNumFeatureDimension << std::endl;
  273. #endif
  274. //----------------- parse config options -------------
  275. bool bVerboseOutput = false;
  276. if( nrhs > 3)
  277. {
  278. NICE::Config conf = parseParametersERC(prhs+3, nrhs-3 );
  279. bVerboseOutput = conf.gB("CodebookRandomForest", "verbose", false);
  280. }
  281. //----------------- quantize samples into histogram -------------
  282. const double *pDataPtr = matData.getDataPointer();
  283. for (size_t i = 0; i < numTrainSamples; i++, pDataPtr+= iNumFeatureDimension )
  284. {
  285. NICE::SparseVector votes;
  286. NICE::Vector distribution;
  287. const NICE::Vector t_VecTrainData( pDataPtr , iNumFeatureDimension);
  288. pCodebookRandomForest->voteAndClassify(t_VecTrainData, votes, distribution);
  289. if(bVerboseOutput)
  290. {
  291. NICE::Vector t_fullVector;
  292. votes.convertToVectorT( t_fullVector );
  293. std::cerr << i << ": " << "votes " << t_fullVector << " distribution: " << distribution << std::endl;
  294. }
  295. }
  296. //----------------- convert NICE histogram into MATLAB data -------------
  297. //plhs[0] = MatlabConversion::convertVectorFromNice(histogram);
  298. plhs[0] = mxCreateLogicalScalar( true );
  299. return;
  300. }
  301. // store codebook random forest to file
  302. else if ( strcmp("storeToFile", cmd.c_str()) == 0 )
  303. {
  304. //------------- read the data --------------
  305. if (nrhs != 3)
  306. {
  307. mexErrMsgTxt("needs a string for filename to save to");
  308. return;
  309. }
  310. //----------------- convert ptr of trained codebook forest -------------
  311. OBJREC::CodebookRandomForest *pCodebookRandomForest = MatlabConversion::convertMat2Ptr<OBJREC::CodebookRandomForest>(prhs[1]);
  312. if( pCodebookRandomForest == NULL )
  313. {
  314. mexErrMsgTxt("classify: No valid trained classifier given");
  315. }
  316. bool bSuccess = false;
  317. try
  318. {
  319. std::string sStoreFilename = MatlabConversion::convertMatlabToString( prhs[2] );
  320. std::ofstream ofs;
  321. ofs.open (sStoreFilename.c_str(), std::ofstream::out);
  322. pCodebookRandomForest->store( ofs );
  323. ofs.close();
  324. bSuccess = true;
  325. }
  326. catch( std::exception &e)
  327. {
  328. std::cerr << "exception occured: " << e.what() << std::endl;
  329. mexErrMsgTxt("storing failed");
  330. }
  331. plhs[0] = mxCreateLogicalScalar( bSuccess );
  332. return;
  333. }
  334. // restore codebook random forest from file
  335. else if (!strcmp("restoreFromFile", cmd.c_str() ))
  336. {
  337. //------------- read the data --------------
  338. if (nrhs != 2)
  339. {
  340. mexErrMsgTxt("needs a string for filename to load from");
  341. return;
  342. }
  343. //----------------- convert ptr of trained codebook forest -------------
  344. OBJREC::CodebookRandomForest *pRestoredCRF = new OBJREC::CodebookRandomForest(-1, -1);
  345. bool bSuccess = false;
  346. try
  347. {
  348. std::string sStoreFilename = MatlabConversion::convertMatlabToString( prhs[1] );
  349. std::ifstream ifs;
  350. ifs.open( sStoreFilename.c_str() );
  351. pRestoredCRF->restore( ifs );
  352. ifs.close();
  353. bSuccess = true;
  354. }
  355. catch( std::exception &e)
  356. {
  357. std::cerr << "exception occured: " << e.what() << std::endl;
  358. mexErrMsgTxt("restoring failed");
  359. }
  360. // handle to the C++ instance
  361. if(bSuccess)
  362. plhs[0] = MatlabConversion::convertPtr2Mat<OBJREC::CodebookRandomForest>( pRestoredCRF );
  363. else
  364. plhs[0] = mxCreateLogicalScalar(false);
  365. return;
  366. }
  367. // Got here, so command not recognized
  368. std::string errorMsg (cmd.c_str() );
  369. errorMsg += "--command not recognized.";
  370. mexErrMsgTxt( errorMsg.c_str() );
  371. }
  372. #endif