CodebookRandomForestMex.cpp 16 KB

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