123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590 |
- #ifdef NICE_USELIB_MEX
- /**
- * @file GPHIKRawClassifierMex.cpp
- * @author Alexander Freytag
- * @date 21-09-2015 (dd-mm-yyyy)
- * @brief Matlab-Interface of our GPHIKRawClassifier, allowing for training and classification without more advanced methods.
- */
- // STL includes
- #include <math.h>
- #include <matrix.h>
- #include <mex.h>
- // NICE-core includes
- #include <core/basics/Config.h>
- #include <core/basics/Timer.h>
- #include <core/vector/MatrixT.h>
- #include <core/vector/VectorT.h>
- // gp-hik-core includes
- #include "gp-hik-core/GPHIKRawClassifier.h"
- // Interface for conversion between Matlab and C objects
- #include "gp-hik-core/matlab/classHandleMtoC.h"
- #include "gp-hik-core/matlab/ConverterMatlabToNICE.h"
- #include "gp-hik-core/matlab/ConverterNICEToMatlab.h"
- using namespace std; //C basics
- using namespace NICE; // nice-core
- NICE::Config parseParametersGPHIKRawClassifier(const mxArray *prhs[], int nrhs)
- {
- NICE::Config conf;
- // if first argument is the filename of an existing config file,
- // read the config accordingly
- int i_start ( 0 );
- std::string variable = MatlabConversion::convertMatlabToString(prhs[i_start]);
- if(variable == "conf")
- {
- conf = NICE::Config ( MatlabConversion::convertMatlabToString( prhs[i_start+1] ) );
- i_start = i_start+2;
- }
- // now run over all given parameter specifications
- // and add them to the config
- for( int i=i_start; i < nrhs; i+=2 )
- {
- std::string variable = MatlabConversion::convertMatlabToString(prhs[i]);
- /////////////////////////////////////////
- // READ STANDARD BOOLEAN VARIABLES
- /////////////////////////////////////////
- if( (variable == "verbose") ||
- (variable == "debug") ||
- (variable == "use_quantization") ||
- (variable == "ils_verbose")
- )
- {
- if ( mxIsChar( prhs[i+1] ) )
- {
- string value = MatlabConversion::convertMatlabToString( prhs[i+1] );
- if ( (value != "true") && (value != "false") )
- {
- std::string errorMsg = "Unexpected parameter value for \'" + variable + "\'. In string modus, \'true\' or \'false\' expected.";
- mexErrMsgIdAndTxt( "mexnice:error", errorMsg.c_str() );
- }
- if( value == "true" )
- conf.sB("GPHIKRawClassifier", variable, true);
- else
- conf.sB("GPHIKRawClassifier", variable, false);
- }
- else if ( mxIsLogical( prhs[i+1] ) )
- {
- bool value = MatlabConversion::convertMatlabToBool( prhs[i+1] );
- conf.sB("GPHIKRawClassifier", variable, value);
- }
- else
- {
- std::string errorMsg = "Unexpected parameter value for \'" + variable + "\'. \'true\', \'false\', or logical expected.";
- mexErrMsgIdAndTxt( "mexnice:error", errorMsg.c_str() );
- }
- }
- /////////////////////////////////////////
- // READ STANDARD INT VARIABLES
- /////////////////////////////////////////
- /////////////////////////////////////////
- // READ STRICT POSITIVE INT VARIABLES
- /////////////////////////////////////////
- if ( (variable == "num_bins") ||
- ( variable == "ils_max_iterations" )||
- ( variable == "eig_value_max_iterations" )
- )
- {
- if ( mxIsDouble( prhs[i+1] ) )
- {
- double value = MatlabConversion::convertMatlabToDouble(prhs[i+1]);
- if( value < 1 )
- {
- std::string errorMsg = "Expected parameter value larger than 0 for \'" + variable + "\'.";
- mexErrMsgIdAndTxt( "mexnice:error", errorMsg.c_str() );
- }
- conf.sI("GPHIKRawClassifier", variable, (int) value);
- }
- else if ( mxIsInt32( prhs[i+1] ) )
- {
- int value = MatlabConversion::convertMatlabToInt32(prhs[i+1]);
- if( value < 1 )
- {
- std::string errorMsg = "Expected parameter value larger than 0 for \'" + variable + "\'.";
- mexErrMsgIdAndTxt( "mexnice:error", errorMsg.c_str() );
- }
- conf.sI("GPHIKRawClassifier", variable, value);
- }
- else
- {
- std::string errorMsg = "Unexpected parameter value for \'" + variable + "\'. Int32 or Double expected.";
- mexErrMsgIdAndTxt( "mexnice:error", errorMsg.c_str() );
- }
- }
- /////////////////////////////////////////
- // READ STANDARD DOUBLE VARIABLES
- /////////////////////////////////////////
- /////////////////////////////////////////
- // READ POSITIVE DOUBLE VARIABLES
- /////////////////////////////////////////
- if ( (variable == "f_tolerance") ||
- (variable == "ils_min_delta") ||
- (variable == "ils_min_residual") ||
- (variable == "noise")
- )
- {
- if ( mxIsDouble( prhs[i+1] ) )
- {
- double value = MatlabConversion::convertMatlabToDouble(prhs[i+1]);
- if( value < 0.0 )
- {
- std::string errorMsg = "Expected parameter value larger than 0 for \'" + variable + "\'.";
- mexErrMsgIdAndTxt( "mexnice:error", errorMsg.c_str() );
- }
- conf.sD("GPHIKRawClassifier", variable, value);
- }
- else
- {
- std::string errorMsg = "Unexpected parameter value for \'" + variable + "\'. Double expected.";
- mexErrMsgIdAndTxt( "mexnice:error", errorMsg.c_str() );
- }
- }
- /////////////////////////////////////////
- // READ REMAINING SPECIFIC VARIABLES
- /////////////////////////////////////////
- if(variable == "ils_method")
- {
- string value = MatlabConversion::convertMatlabToString(prhs[i+1]);
- if(value != "CG" && value != "CGL" && value != "SYMMLQ" && value != "MINRES")
- mexErrMsgIdAndTxt("mexnice:error","Unexpected parameter value for \'ils_method\'. \'CG\', \'CGL\', \'SYMMLQ\' or \'MINRES\' expected.");
- conf.sS("GPHIKRawClassifier", variable, value);
- }
- if(variable == "s_quantType")
- {
- string value = MatlabConversion::convertMatlabToString( prhs[i+1] );
- if( value != "1d-aequi-0-1" && value != "1d-aequi-0-max" && value != "nd-aequi-0-max" )
- mexErrMsgIdAndTxt("mexnice:error","Unexpected parameter value for \'s_quantType\'. \'1d-aequi-0-1\' , \'1d-aequi-0-max\' or \'nd-aequi-0-max\' expected.");
- conf.sS("GPHIKRawClassifier", variable, value);
- }
- }
- return conf;
- }
- // MAIN MATLAB FUNCTION
- void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
- {
- // get the command string specifying what to do
- if (nrhs < 1)
- mexErrMsgTxt("No commands and options passed... Aborting!");
- if( !mxIsChar( prhs[0] ) )
- mexErrMsgTxt("First argument needs to be the command, ie.e, the class method to call... Aborting!");
- std::string cmd = MatlabConversion::convertMatlabToString( prhs[0] );
- // create object
- if ( !strcmp("new", cmd.c_str() ) )
- {
- // check output variable
- if (nlhs != 1)
- mexErrMsgTxt("New: One output expected.");
- // read config settings
- NICE::Config conf = parseParametersGPHIKRawClassifier(prhs+1,nrhs-1);
- // create class instance
- NICE::GPHIKRawClassifier * classifier = new NICE::GPHIKRawClassifier ( &conf, "GPHIKRawClassifier" /*sectionName in config*/ );
- // handle to the C++ instance
- plhs[0] = MatlabConversion::convertPtr2Mat<NICE::GPHIKRawClassifier>( classifier );
- return;
- }
- // in all other cases, there should be a second input,
- // which the be the class instance handle
- if (nrhs < 2)
- mexErrMsgTxt("Second input should be a class instance handle.");
- // delete object
- if ( !strcmp("delete", cmd.c_str() ) )
- {
- // Destroy the C++ object
- MatlabConversion::destroyObject<NICE::GPHIKRawClassifier>(prhs[1]);
- return;
- }
- // get the class instance pointer from the second input
- // every following function needs the classifier object
- NICE::GPHIKRawClassifier * classifier = MatlabConversion::convertMat2Ptr<NICE::GPHIKRawClassifier>(prhs[1]);
- ////////////////////////////////////////
- // Check which class method to call //
- ////////////////////////////////////////
- // standard train - assumes initialized object
- if (!strcmp("train", cmd.c_str() ))
- {
- // Check parameters
- if (nlhs < 0 || nrhs < 4)
- {
- mexErrMsgTxt("Train: Unexpected arguments.");
- }
- //------------- read the data --------------
- std::vector< const NICE::SparseVector *> examplesTrain;
- NICE::Vector yMultiTrain;
- if ( mxIsSparse( prhs[2] ) )
- {
- examplesTrain = MatlabConversion::convertSparseMatrixToNice( prhs[2] );
- }
- else
- {
- NICE::Matrix dataTrain;
- dataTrain = MatlabConversion::convertDoubleMatrixToNice(prhs[2]);
- //----------------- convert data to sparse data structures ---------
- examplesTrain.resize( dataTrain.rows() );
- std::vector< const NICE::SparseVector *>::iterator exTrainIt = examplesTrain.begin();
- for (int i = 0; i < (int)dataTrain.rows(); i++, exTrainIt++)
- {
- *exTrainIt = new NICE::SparseVector( dataTrain.getRow(i) );
- }
- }
- yMultiTrain = MatlabConversion::convertDoubleVectorToNice(prhs[3]);
- //----------------- train our classifier -------------
- NICE::Timer t;
- t.start();
-
- classifier->train ( examplesTrain , yMultiTrain );
-
- t.stop();
-
-
- FILE * pFile;
- pFile = fopen ("/home/freytag/experiments/gphik/2015-08-28-gphik-classif/training_times_gphik_raw.txt","a");
- fprintf (pFile, "GPHIKRaw-Mex -- Time for training without data conversion: %f \n",t.getLast());
- fclose (pFile);
- //----------------- clean up -------------
- for(int i=0;i<examplesTrain.size();i++)
- delete examplesTrain[i];
- return;
- }
- // Classify
- if ( !strcmp("classify", cmd.c_str() ) )
- {
- // Check parameters
- if ( (nlhs < 0) || (nrhs < 2) )
- {
- mexErrMsgTxt("Test: Unexpected arguments.");
- }
- if ( mxIsSparse( prhs[2] ) )
- {
- if ( MatlabConversion::isSparseDataAMatrix( prhs[2] ) )
- {
- //----------------- conversion -------------
- std::vector< const NICE::SparseVector *> examplesTest;
- examplesTest = MatlabConversion::convertSparseMatrixToNice( prhs[2] );
-
- //----------------- classification -------------
- NICE::Vector results;
- NICE::Matrix scores;
- NICE::Timer t;
- t.start();
- classifier->classify ( examplesTest, results, scores );
- t.stop();
- FILE * pFile;
- pFile = fopen ("/home/freytag/experiments/gphik/2015-08-28-gphik-classif/test_times_gphik_raw_quant.txt","a");
- fprintf (pFile, "GPHIKRaw-Mex-Quant test time %f \n",t.getLast());
- fclose (pFile);
-
- //----------------- clean up -------------
- for ( std::vector< const NICE::SparseVector *>::iterator exIt = examplesTest.begin();
- exIt != examplesTest.end();
- exIt++
- )
- {
- delete *exIt;
- }
-
- //----------------- output -------------
- plhs[0] = MatlabConversion::convertVectorFromNice( results );
- if(nlhs >= 2)
- {
- plhs[1] = MatlabConversion::convertMatrixFromNice( scores );
- }
- return;
- }
- else
- {
- //----------------- conversion -------------
- NICE::SparseVector * example;
- example = new NICE::SparseVector ( MatlabConversion::convertSparseVectorToNice( prhs[2] ) );
-
- //----------------- classification -------------
- uint result;
- NICE::SparseVector scores;
- NICE::Timer t;
- t.start();
- classifier->classify ( example, result, scores );
- t.stop();
- FILE * pFile;
- pFile = fopen ("/home/freytag/experiments/gphik/2015-08-28-gphik-classif/test_times_gphik_raw_quant.txt","a");
- fprintf (pFile, "GPHIKRaw-Mex-Quant test time %f \n",t.getLast());
- fclose (pFile);
- //----------------- clean up -------------
- delete example;
-
- //----------------- output -------------
- plhs[0] = mxCreateDoubleScalar( result );
- if(nlhs >= 2)
- {
- plhs[1] = MatlabConversion::convertSparseVectorFromNice( scores, true /*b_adaptIndex*/);
- }
- return;
- }
- }
- else
- {
- //----------------- conversion -------------
- NICE::Vector * example;
- example = new NICE::Vector ( MatlabConversion::convertDoubleVectorToNice(prhs[2]) );
- NICE::SparseVector * svec = new NICE::SparseVector( *example );
- delete example;
- //----------------- classification -------------
- uint result;
- NICE::SparseVector scores;
- classifier->classify ( svec, result, scores );
- //----------------- clean up -------------
- delete svec;
-
-
- //----------------- output -------------
- plhs[0] = mxCreateDoubleScalar( result );
- if(nlhs >= 2)
- {
- plhs[1] = MatlabConversion::convertSparseVectorFromNice( scores, true /*b_adaptIndex*/);
- }
- return;
- }
- }
- // Test - evaluate classifier on whole test set
- if ( !strcmp("test", cmd.c_str() ) )
- {
- // Check parameters
- if (nlhs < 0 || nrhs < 4)
- mexErrMsgTxt("Test: Unexpected arguments.");
- //------------- read the data --------------
- bool dataIsSparse ( mxIsSparse( prhs[2] ) );
- std::vector< const NICE::SparseVector *> dataTest_sparse;
- NICE::Matrix dataTest_dense;
- if ( dataIsSparse )
- {
- dataTest_sparse = MatlabConversion::convertSparseMatrixToNice( prhs[2] );
- }
- else
- {
- dataTest_dense = MatlabConversion::convertDoubleMatrixToNice(prhs[2]);
- }
- NICE::Vector yMultiTest;
- yMultiTest = MatlabConversion::convertDoubleVectorToNice(prhs[3]);
- // ------------------------------------------
- // ------------- PREPARATION --------------
- // ------------------------------------------
- // determine classes known during training and corresponding mapping
- // thereby allow for non-continous class labels
- std::set< uint > classesKnownTraining = classifier->getKnownClassNumbers();
- uint noClassesKnownTraining ( classesKnownTraining.size() );
- std::map< uint, uint > mapClNoToIdxTrain;
- std::set< uint >::const_iterator clTrIt = classesKnownTraining.begin();
- for ( uint i=0; i < noClassesKnownTraining; i++, clTrIt++ )
- mapClNoToIdxTrain.insert ( std::pair< uint, uint > ( *clTrIt, i ) );
- // determine classes known during testing and corresponding mapping
- // thereby allow for non-continous class labels
- std::set< uint > classesKnownTest;
- classesKnownTest.clear();
- // determine which classes we have in our label vector
- // -> MATLAB: myClasses = unique(y);
- for ( NICE::Vector::const_iterator it = yMultiTest.begin(); it != yMultiTest.end(); it++ )
- {
- if ( classesKnownTest.find ( *it ) == classesKnownTest.end() )
- {
- classesKnownTest.insert ( *it );
- }
- }
- int noClassesKnownTest ( classesKnownTest.size() );
- std::map< uint, uint> mapClNoToIdxTest;
- std::set< uint >::const_iterator clTestIt = classesKnownTest.begin();
- for ( uint i=0; i < noClassesKnownTest; i++, clTestIt++ )
- mapClNoToIdxTest.insert ( std::pair< uint, uint > ( *clTestIt, i ) );
- int i_numTestSamples;
- if ( dataIsSparse )
- i_numTestSamples = dataTest_sparse.size();
- else
- i_numTestSamples = (int) dataTest_dense.rows();
- NICE::Matrix confusionMatrix( noClassesKnownTraining, noClassesKnownTest, 0.0);
- NICE::Matrix scores( i_numTestSamples, noClassesKnownTraining, 0.0);
- // ------------------------------------------
- // ------------- CLASSIFICATION --------------
- // ------------------------------------------
- NICE::Timer t;
- double testTime (0.0);
- for (int i = 0; i < i_numTestSamples; i++)
- {
- //----------------- convert data to sparse data structures ---------
- uint result;
- NICE::SparseVector exampleScoresSparse;
- if ( dataIsSparse )
- {
- // and classify
- t.start();
- classifier->classify( dataTest_sparse[ i ], result, exampleScoresSparse );
- t.stop();
- testTime += t.getLast();
- }
- else
- {
- NICE::Vector example ( dataTest_dense.getRow(i) );
- NICE::SparseVector * svec = new NICE::SparseVector ( example );
- // and classify
- t.start();
- classifier->classify( svec, result, exampleScoresSparse );
- t.stop();
- testTime += t.getLast();
- delete svec;
- }
- confusionMatrix( mapClNoToIdxTrain.find(result)->second, mapClNoToIdxTest.find(yMultiTest[i])->second ) += 1.0;
- int scoreCnt ( 0 );
- for ( NICE::SparseVector::const_iterator scoreIt = exampleScoresSparse.begin(); scoreIt != exampleScoresSparse.end(); scoreIt++, scoreCnt++ )
- {
- scores(i,scoreCnt) = scoreIt->second;
- }
- }
- std::cerr << "Time for testing: " << testTime << std::endl;
- // clean up
- if ( dataIsSparse )
- {
- for ( std::vector<const NICE::SparseVector *>::iterator it = dataTest_sparse.begin(); it != dataTest_sparse.end(); it++)
- delete *it;
- }
- confusionMatrix.normalizeColumnsL1();
- double recRate = confusionMatrix.trace()/confusionMatrix.cols();
- plhs[0] = mxCreateDoubleScalar( recRate );
- if(nlhs >= 2)
- plhs[1] = MatlabConversion::convertMatrixFromNice(confusionMatrix);
- if(nlhs >= 3)
- plhs[2] = MatlabConversion::convertMatrixFromNice(scores);
- return;
- }
- ///////////////////// INTERFACE ONLINE LEARNABLE /////////////////////
- // interface specific methods for incremental extensions
- ///////////////////// INTERFACE ONLINE LEARNABLE /////////////////////
- // not supported here
- ///////////////////// INTERFACE PERSISTENT /////////////////////
- // interface specific methods for store and restore
- ///////////////////// INTERFACE PERSISTENT /////////////////////
- // not supported here
- // Got here, so command not recognized
- std::string errorMsg (cmd.c_str() );
- errorMsg += " -- command not recognized.";
- mexErrMsgTxt( errorMsg.c_str() );
- }
- #endif
|