PageRenderTime 52ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/SVM_Multiclass/svm_struct_cpp.cpp

https://github.com/wxiang7/iPM3F
C++ | 1070 lines | 889 code | 108 blank | 73 comment | 181 complexity | 3f36364cebef82b298fccae14ab1ac01 MD5 | raw file
  1. // SVMStruct_CPlus.cpp : Defines the entry point for the console application.
  2. //
  3. #include "stdafx.h"
  4. /***********************************************************************/
  5. /* */
  6. /* svm_struct_main.c */
  7. /* */
  8. /* Command line interface to the alignment learning module of the */
  9. /* Support Vector Machine. */
  10. /* */
  11. /* Author: Thorsten Joachims */
  12. /* Date: 03.07.04 */
  13. /* */
  14. /* Copyright (c) 2004 Thorsten Joachims - All rights reserved */
  15. /* */
  16. /* This software is available for non-commercial use only. It must */
  17. /* not be modified and distributed without prior permission of the */
  18. /* author. The author is not responsible for implications from the */
  19. /* use of this software. */
  20. /* */
  21. /***********************************************************************/
  22. /* the following enables you to use svm-learn out of C++ */
  23. //#ifdef __cplusplus
  24. //extern "C" {
  25. //#endif
  26. #include "../SVMLight/svm_common.h"
  27. #include "../SVMLight/svm_learn.h"
  28. //#ifdef __cplusplus
  29. //}
  30. //#endif
  31. # include "svm_struct_learn.h"
  32. # include "svm_struct_classify.h"
  33. # include "svm_struct_common.h"
  34. # include "svm_struct_api.h"
  35. #include <stdio.h>
  36. #include <string>
  37. #include <assert.h>
  38. #include <windows.h>
  39. #include <fstream>
  40. #include <queue>
  41. using namespace std;
  42. /* } */
  43. char trainfile[200]; /* file with training examples */
  44. char modelfile[200]; /* file for resulting classifier */
  45. bool g_bClassify;
  46. bool g_bCrossValidation;
  47. bool g_bInnerCV;
  48. bool g_bWarmStart;
  49. int g_nStopStep; /* the number of iterations to early stop. */
  50. string g_strTrainDataDir;
  51. int g_nDim;
  52. int g_nStateNum;
  53. int g_nFoldNum;
  54. void eval_CV(vector<wstring>&vecFileName, const int &nFoldNum,
  55. STRUCTMODEL &structmodel,
  56. STRUCT_LEARN_PARM &struct_parm,
  57. LEARN_PARM &learn_parm,
  58. KERNEL_PARM &kernel_parm,
  59. int alg_type, ofstream &ofs);
  60. void eval_Ratio(vector<wstring>&vecFileName, vector<int> &vecRatio,
  61. STRUCTMODEL &structmodel,
  62. STRUCT_LEARN_PARM &struct_parm,
  63. LEARN_PARM &learn_parm,
  64. KERNEL_PARM &kernel_parm,
  65. int alg_type, ofstream &ofs);
  66. double inner_CV(SAMPLE *sample, STRUCTMODEL &structmodel,
  67. STRUCT_LEARN_PARM &struct_parm,
  68. LEARN_PARM &learn_parm,
  69. KERNEL_PARM &kernel_parm,
  70. int alg_type, ofstream &ofs);
  71. void read_input_parameters(int, char **, char *, char *,long *, long *,
  72. STRUCT_LEARN_PARM *, LEARN_PARM *, KERNEL_PARM *, int *);
  73. void wait_any_key();
  74. void print_help();
  75. void partitionData(SAMPLE *sample, const int &nFoldNum, vector<int> &vecSampleNum)
  76. {
  77. if ( sample->examples[0].m_nFoldIx == -1 ) {
  78. vecSampleNum.assign( nFoldNum, 0 );
  79. int nUnitNum = sample->n / nFoldNum;
  80. for ( int i=0; i<nUnitNum*nFoldNum; i++ ) {
  81. sample->examples[i].m_nFoldIx = i / nUnitNum;
  82. vecSampleNum[sample->examples[i].m_nFoldIx] ++;
  83. }
  84. for ( int i=nUnitNum*nFoldNum; i<sample->n; i++ ) {
  85. sample->examples[i].m_nFoldIx = nFoldNum - 1;
  86. vecSampleNum[nFoldNum-1] ++;
  87. }
  88. }
  89. }
  90. SAMPLE* get_traindata(SAMPLE* c, const int&nfold, const int &foldix)
  91. {
  92. int nunit = c->n / nfold;
  93. SAMPLE *subc = (SAMPLE*)malloc(sizeof(SAMPLE));
  94. subc->examples = 0;
  95. subc->n = 0;
  96. int nd = 0;
  97. for ( int i=0; i<c->n; i++ )
  98. {
  99. if ( foldix < nfold ) {
  100. if ( (i >= (foldix-1)*nunit) && ( i < foldix*nunit ) ) continue;
  101. } else {
  102. if ( i >= (foldix-1) * nunit ) continue;
  103. }
  104. subc->examples = (EXAMPLE*) realloc(subc->examples, sizeof(EXAMPLE)*(nd+1));
  105. subc->examples[nd] = c->examples[i];
  106. nd++;
  107. }
  108. subc->n = nd;
  109. return subc;
  110. }
  111. SAMPLE* get_testdata(SAMPLE* c, const int&nfold, const int &foldix)
  112. {
  113. int nunit = c->n / nfold;
  114. SAMPLE *subc = (SAMPLE*)malloc(sizeof(SAMPLE));
  115. subc->examples = 0;
  116. subc->n = 0;
  117. int nd = 0, nw = 0;
  118. for ( int i=0; i<c->n; i++ )
  119. {
  120. if ( foldix < nfold ) {
  121. if ( i < ((foldix-1)*nunit) || i >= foldix*nunit ) continue;
  122. } else {
  123. if ( i < (foldix-1) * nunit ) continue;
  124. }
  125. subc->examples = (EXAMPLE*) realloc(subc->examples, sizeof(EXAMPLE)*(nd+1));
  126. subc->examples[nd] = c->examples[i];
  127. nd++;
  128. }
  129. subc->n = nd;
  130. return subc;
  131. }
  132. void reorder(SAMPLE* sample, char *filename)
  133. {
  134. int num, ix=0;
  135. int *order = (int*)malloc(sizeof(int)*sample->n);
  136. FILE *fileptr = fopen(filename, "r");
  137. while ( (fscanf(fileptr, "%10d", &num) != EOF ) ) {
  138. order[ix] = num;
  139. ix ++;
  140. }
  141. EXAMPLE *docs = (EXAMPLE*)malloc(sizeof(EXAMPLE) * sample->n);
  142. for ( int i=0; i<sample->n; i++ )
  143. docs[i] = sample->examples[i];
  144. for ( int i=0; i<c->num_docs; i++ )
  145. sample->examples[i] = docs[order[i]];
  146. free(docs);
  147. free(order);
  148. }
  149. double evaluation(SAMPLE *testsample, STRUCTMODEL &model, ofstream &ofs, bool bWrite)
  150. {
  151. double avgloss = 0;
  152. for( int i=0; i<testsample->n; i++)
  153. {
  154. LABEL y = classify_struct_example(testsample->examples[i].x, &model, NULL);
  155. double l = loss(testsample->examples[i].y, y, NULL);
  156. if ( bWrite ) {
  157. ofs << y.classlabel << "\t" << testsample->examples[i].y.classlabel << endl;
  158. }
  159. avgloss += l;
  160. /*if(l == 0) correct++;
  161. else incorrect++;*/
  162. //eval_prediction(i, testsample.examples[i], y, &model, &sparm, &teststats);
  163. if(empty_label(testsample->examples[i].y))
  164. //{ no_accuracy=1; } /* test data is not labeled */
  165. if(verbosity>=2) {
  166. if((i+1) % 100 == 0) {
  167. printf("%ld..",i+1); fflush(stdout);
  168. }
  169. }
  170. free_label(y);
  171. }
  172. avgloss /= testsample.n;
  173. return avgloss;
  174. }
  175. void loadTrainScheme(vector<int> &trainScheme, char *pFileName)
  176. {
  177. int dTrainingDataRatio;
  178. char buff[256];
  179. int index = 0;
  180. ifstream ifs;
  181. ifs.open(pFileName, ios_base::in);
  182. if ( !ifs.is_open() ) { exit(0);}
  183. while ( !ifs.fail() ) {
  184. ifs.getline( buff, 256 );
  185. string str(buff);
  186. dTrainingDataRatio = atoi( str.c_str() );
  187. if ( dTrainingDataRatio <= 0 ) continue;
  188. trainScheme.push_back(dTrainingDataRatio);
  189. }
  190. ifs.close();
  191. }
  192. void loadConfig(const char* pFileName)
  193. {
  194. g_bClassify = false;
  195. g_bCrossValidation = false;
  196. g_bInnerCV = false;
  197. g_bWarmStart = false;
  198. g_nStopStep = 200;
  199. ifstream ifs(pFileName, ios_base::in);
  200. if ( !ifs.is_open() ) return;
  201. char buff[512];
  202. while ( !ifs.eof() ) {
  203. ifs.getline(buff, 512);
  204. string str(buff);
  205. if ( str.empty() || str.find("%%") != str.npos ) continue;
  206. if ( str.find("classify") != str.npos) {
  207. g_bClassify = true;
  208. } else if ( str.compare("Cross-Validation") == 0 ) {
  209. g_bCrossValidation = true;
  210. } else if ( str.compare("Inner-CV") == 0 ) {
  211. g_bInnerCV = true;
  212. } else if ( str.compare("Warm-Start") == 0 ) {
  213. g_bWarmStart = true;
  214. } else;
  215. size_t stPos = str.find("=");
  216. if ( str.find("TrainDataDir") != str.npos ) {
  217. g_strTrainDataDir = str.substr(stPos+2, str.size()-stPos-2);
  218. } else if ( str.find("Total Dimension") != str.npos ) {
  219. g_nDim = atoi(str.substr(stPos+2, str.size()-stPos-2).c_str());
  220. } else if (str.find("State Number") != str.npos ) {
  221. g_nStateNum = atoi(str.substr(stPos+2, str.size()-stPos-2).c_str());
  222. } else if ( str.find("FoldNumber") != str.npos ) {
  223. g_nFoldNum = atoi(str.substr(stPos+2, str.size()-stPos-2).c_str());
  224. } else if ( str.find("EarlyStopStep") != str.npos ) {
  225. g_nStopStep = atoi(str.substr(stPos+2, str.size()-stPos-2).c_str());
  226. } else ;
  227. }
  228. ifs.close();
  229. }
  230. wstring UTF82WChar(const BYTE * pszSrc, int nLen)
  231. {
  232. int nSize = MultiByteToWideChar(CP_UTF8,
  233. 0,
  234. (LPCSTR)pszSrc,
  235. nLen,
  236. 0,
  237. 0);
  238. if (nSize <= 0)
  239. {
  240. return L"";
  241. }
  242. WCHAR * pwszDst = new WCHAR[nSize + 1];
  243. if (NULL == pwszDst)
  244. {
  245. return L"";
  246. }
  247. MultiByteToWideChar(CP_UTF8,
  248. 0,
  249. (LPCSTR) pszSrc,
  250. nLen,
  251. pwszDst,
  252. nSize);
  253. pwszDst[nSize] = L'\0';
  254. // skip 0xfeff
  255. if (pwszDst[0] == 0xFEFF) //skip UTF8 head if needed
  256. {
  257. for (int i = 0; i < nSize; i++)
  258. {
  259. pwszDst[i] = pwszDst[i + 1];
  260. }
  261. }
  262. wstring wstrTemp = pwszDst;
  263. delete[] pwszDst;
  264. return wstrTemp;
  265. }
  266. string WChar2Ansi(LPCWSTR pwszSrc)
  267. {
  268. int nLen = WideCharToMultiByte(CP_ACP,
  269. 0,
  270. pwszSrc,
  271. -1,
  272. NULL,
  273. 0,
  274. NULL,
  275. NULL);
  276. if (nLen<= 0)
  277. {
  278. return NULL;
  279. }
  280. char* pszDst = new char[nLen];
  281. if (NULL == pszDst)
  282. {
  283. return NULL;
  284. }
  285. WideCharToMultiByte(CP_ACP,
  286. 0,
  287. pwszSrc,
  288. -1,
  289. pszDst,
  290. nLen,
  291. NULL,
  292. NULL);
  293. pszDst[nLen -1] = 0;
  294. string strTemp = pszDst;
  295. delete [] pszDst;
  296. return strTemp;
  297. }
  298. int TraverseDirectory(IN const wstring &Dir,IN const wstring &Suffix, OUT vector<wstring> &vecFileName)
  299. {
  300. if ( !vecFileName.empty() ) vecFileName.resize(0);
  301. WIN32_FIND_DATA FindFileData;
  302. HANDLE hFind;
  303. queue<wstring> queDir;
  304. queDir.push(Dir);
  305. int iCount = 0;
  306. wchar_t szExt[MAX_PATH];
  307. //while ( queDir.empty() != true )
  308. //{
  309. wstring strCurrDir = queDir.front();
  310. wprintf(L"%s\n", strCurrDir.c_str());
  311. wstring strFileName = strCurrDir + wstring(L"\\*.*");;
  312. wprintf(L"%s\n\n", strFileName.c_str());
  313. wcscpy(FindFileData.cFileName, strFileName.c_str());
  314. hFind = FindFirstFile(strFileName.c_str(), &FindFileData);
  315. if ( hFind != INVALID_HANDLE_VALUE )
  316. {
  317. if ( ( FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FALSE
  318. && wcscmp(FindFileData.cFileName, L".") != 0
  319. && wcscmp(FindFileData.cFileName, L"..") != 0
  320. )
  321. {
  322. //wprintf(L"Find a Directory: %s\n", FindFileData.cFileName);
  323. //queDir.push(strCurrDir + wstring(L"\\") + wstring(FindFileData.cFileName));
  324. }
  325. else
  326. {
  327. _wsplitpath(FindFileData.cFileName, NULL, NULL, NULL, szExt);
  328. strFileName = strCurrDir + wstring(L"\\") + wstring(FindFileData.cFileName);
  329. if ( wcscmp(szExt+1, Suffix.c_str()) == 0 /*
  330. && wcscmp(FindFileData.cFileName, L".") != 0
  331. && wcscmp(FindFileData.cFileName, L"..") != 0*/
  332. )
  333. {
  334. iCount ++;
  335. wstring strFullName = strCurrDir + wstring(L"\\") + wstring(FindFileData.cFileName);
  336. vecFileName.push_back(strFullName);
  337. }
  338. }
  339. BOOL bRet = FindNextFile(hFind,&FindFileData);
  340. while ( bRet == TRUE ){
  341. if ( ( bRet == TRUE
  342. && FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FALSE
  343. && wcscmp(FindFileData.cFileName, L".") != 0
  344. && wcscmp(FindFileData.cFileName, L"..") != 0
  345. )
  346. {
  347. //wprintf(L"Find a Directory: %s\n", FindFileData.cFileName);
  348. //queDir.push(strCurrDir + wstring(L"\\") + wstring(FindFileData.cFileName));
  349. }
  350. else
  351. {
  352. _wsplitpath(FindFileData.cFileName,NULL,NULL,NULL,szExt);
  353. strFileName = strCurrDir + wstring(L"\\") + wstring(FindFileData.cFileName);
  354. if ( wcscmp(szExt+1, Suffix.c_str()) == 0 /*
  355. && wcscmp(FindFileData.cFileName, L".") != 0
  356. && wcscmp(FindFileData.cFileName, L"..") != 0*/
  357. )
  358. {
  359. iCount ++;
  360. wstring strFullName = strCurrDir + wstring(L"\\") + wstring(FindFileData.cFileName);
  361. vecFileName.push_back(strFullName);
  362. }
  363. }
  364. bRet = FindNextFile(hFind, &FindFileData);
  365. }
  366. }
  367. queDir.pop();
  368. //}
  369. return ERROR_SUCCESS;
  370. }
  371. int main (int argc, char* argv[])
  372. {
  373. SAMPLE sample; /* training sample */
  374. LEARN_PARM learn_parm;
  375. KERNEL_PARM kernel_parm;
  376. STRUCT_LEARN_PARM struct_parm;
  377. STRUCTMODEL structmodel;
  378. int alg_type;
  379. LABEL *pLabel = new LABEL();
  380. LABEL lb;
  381. lb.m_labels = NULL;
  382. EXAMPLE *pEx = new EXAMPLE();
  383. pEx->y.scores = NULL;
  384. svm_struct_learn_api_init(argc,argv);
  385. read_input_parameters(argc, argv, trainfile, modelfile, &verbosity,
  386. &struct_verbosity, &struct_parm, &learn_parm, &kernel_parm,&alg_type);
  387. loadConfig(learn_parm.addConfigFile);
  388. if ( g_bClassify ) { classify(argc, argv); return 0; }
  389. /* do evaluation */
  390. vector<wstring> vecFileName;
  391. TraverseDirectory(UTF82WChar((unsigned char *)g_strTrainDataDir.c_str(), g_strTrainDataDir.size()), L"data", vecFileName);
  392. ofstream ofs("evRes.txt", ios_base::out | ios_base::app);
  393. ofs.seekp(ios_base::end);
  394. if ( learn_parm.m_bQPSolver ) ofs << "L2-norm penalty" << endl;
  395. else ofs << "LP Solver for L1-norm penalty" << endl;
  396. ofs << "\t -- C: " << struct_parm.C;
  397. if ( g_bCrossValidation ) {
  398. ofs << "\tCV: " << g_nFoldNum << endl;
  399. eval_CV(vecFileName, g_nFoldNum, structmodel, struct_parm, learn_parm, kernel_parm, alg_type, ofs);
  400. } else {
  401. ofs << "\tSampling" << endl;
  402. vector<int> vecRatio;
  403. loadTrainScheme(vecRatio, "trainScheme.txt");
  404. eval_Ratio(vecFileName, vecRatio, structmodel, struct_parm, learn_parm, kernel_parm, alg_type, ofs);
  405. }
  406. ofs.close();
  407. svm_struct_learn_api_exit();
  408. return 0;
  409. }
  410. void eval_CV(vector<wstring> &vecFileName, const int &nFoldNum,
  411. STRUCTMODEL &structmodel,
  412. STRUCT_LEARN_PARM &struct_parm,
  413. LEARN_PARM &learn_parm,
  414. KERNEL_PARM &kernel_parm,
  415. int alg_type, ofstream &ofs)
  416. {
  417. if ( vecFileName.empty() ) return;
  418. vector<double> totalAvg( vecFileName.size() );
  419. vector<double> totalVar( vecFileName.size() );
  420. vector<double> arryAvgLoss;
  421. for ( int fIx=0; fIx<vecFileName.size(); fIx++ )
  422. {
  423. arryAvgLoss.assign(nFoldNum, 0);
  424. strcpy(trainfile, WChar2Ansi(vecFileName[fIx].c_str()).c_str());
  425. ofs << " ****** file: " << trainfile << " ********" << endl;
  426. if(struct_verbosity >=1 ) { printf("Reading training examples..."); fflush(stdout); }
  427. /* read the training examples */
  428. SAMPLE sample = read_struct_examples(trainfile, &struct_parm);
  429. if(struct_verbosity>=1) { printf("done\n"); fflush(stdout); }
  430. // 10 fold CV for the dataset
  431. vector<int> vecSampleNum;
  432. partitionData(&sample, nFoldNum, vecSampleNum);
  433. // for each partition of the data
  434. for ( int it=0; it<nFoldNum; it++ )
  435. {
  436. ofs << "\tfold: " << it;
  437. //char buff[512];
  438. sprintf(modelfile, "parm_f%d_cv%d.txt", fIx, it+1);
  439. // split the data into training & testing sets
  440. SAMPLE trSample, tsSample;
  441. trSample.n = vecSampleNum[it];
  442. trSample.examples = (EXAMPLE*)malloc( sizeof(EXAMPLE) * vecSampleNum[it] );
  443. tsSample.n = sample.n - vecSampleNum[it];
  444. tsSample.examples = (EXAMPLE*)malloc( sizeof(EXAMPLE) * tsSample.n );
  445. int trIx=0, tsIx=0;
  446. for ( int k=0; k<sample.n; k++ ) {
  447. if ( it == sample.examples[k].m_nFoldIx ) {
  448. trSample.examples[trIx].x.SetHead( sample.examples[k].x.m_pHeadNode );
  449. trSample.examples[trIx].x.m_pEndNode = sample.examples[k].x.m_pEndNode;
  450. trSample.examples[trIx].y.m_nSize = sample.examples[k].y.m_nSize;
  451. trSample.examples[trIx ++].y.m_labels = sample.examples[k].y.m_labels;
  452. } else {
  453. tsSample.examples[tsIx].x.SetHead( sample.examples[k].x.m_pHeadNode );
  454. tsSample.examples[tsIx].x.m_pEndNode = sample.examples[k].x.m_pEndNode;
  455. tsSample.examples[tsIx].y.m_nSize = sample.examples[k].y.m_nSize;
  456. tsSample.examples[tsIx ++].y.m_labels = sample.examples[k].y.m_labels;
  457. }
  458. }
  459. if ( learn_parm.m_bInnerCV ) {
  460. struct_parm.C = inner_CV( &trSample, structmodel,
  461. struct_parm, learn_parm, kernel_parm, alg_type, ofs);
  462. }
  463. /* Do the learning and return structmodel. */
  464. long runtime_start, runtime_end;
  465. runtime_start = get_runtime();
  466. bool bSucc = true;
  467. if(alg_type == 1) {
  468. if ( learn_parm.m_bQPSolver )
  469. svm_learn_struct(trSample, &struct_parm, &learn_parm, &kernel_parm, &structmodel);
  470. else
  471. bSucc = svm_learn_struct_lp(trSample, &struct_parm, &learn_parm, &kernel_parm, &structmodel, g_nStopStep, true);
  472. } else exit(1);
  473. runtime_end = get_runtime();
  474. /* Warning: The model contains references to the original data 'docs'.
  475. If you want to free the original data, and only keep the model, you
  476. have to make a deep copy of 'model'. */
  477. if(struct_verbosity>=1) { printf("Writing learned model...");fflush(stdout);}
  478. write_struct_model(modelfile, &structmodel, &struct_parm);
  479. if(struct_verbosity>=1) {printf("done\n");fflush(stdout); }
  480. // do classification on the testing data
  481. arryAvgLoss[it] = evaluation(&tsSample, structmodel, ofs, false);
  482. ofs << "\tAvgLoss: " << arryAvgLoss[it] << " [" << bSucc << "]"
  483. << "\tCPU Seconds: " << (runtime_end-runtime_start)/100.0 << endl;
  484. // free memory
  485. for ( int k=0; k<trSample.n; k++ ) {
  486. trSample.examples[k].x.SetHead(NULL);
  487. trSample.examples[k].y.m_labels = NULL;
  488. }
  489. for ( int k=0; k<tsSample.n; k++ ) {
  490. tsSample.examples[k].x.SetHead(NULL);
  491. tsSample.examples[k].y.m_labels = NULL;
  492. }
  493. free_struct_sample(trSample);
  494. free_struct_sample(tsSample);
  495. free_struct_model(structmodel);
  496. }
  497. free_struct_sample(sample);
  498. ofs << "\tAverage Loss: ";
  499. totalAvg[fIx] = 0;
  500. for ( int i=0; i<nFoldNum; i++ ) totalAvg[fIx] += arryAvgLoss[i] / nFoldNum;
  501. totalVar[fIx] = 0;
  502. for ( int i=0; i<nFoldNum; i++ ) totalVar[fIx] += (arryAvgLoss[i] - totalAvg[fIx]) * (arryAvgLoss[i] - totalAvg[fIx]) / nFoldNum;
  503. totalVar[fIx] = sqrt( totalVar[fIx] );
  504. ofs << "\t Avg: " << totalAvg[fIx] << "\tVar: " << totalVar[fIx] << endl;
  505. }
  506. ofs << "\tTotal Avg over " << vecFileName.size() << " files: " << endl;
  507. double dAvgVal = 0, dAvgVar = 0;
  508. for ( int i=0; i<vecFileName.size(); i++ ) {
  509. dAvgVal += totalAvg[i] / vecFileName.size();
  510. dAvgVar += totalVar[i] / vecFileName.size();
  511. }
  512. ofs << "\t Avg: " << dAvgVal << "\tVar: " << dAvgVar << endl;
  513. }
  514. void eval_Ratio(vector<wstring>&vecFileName, vector<int> &vecRatio,
  515. STRUCTMODEL &structmodel,
  516. STRUCT_LEARN_PARM &struct_parm,
  517. LEARN_PARM &learn_parm,
  518. KERNEL_PARM &kernel_parm,
  519. int alg_type, ofstream &ofs)
  520. {
  521. vector<vector<double> > arryAvgLoss( vecFileName.size() );
  522. for ( int db=0; db<vecFileName.size(); db++ )
  523. {
  524. strcpy(trainfile, WChar2Ansi(vecFileName[db].c_str()).c_str());
  525. ofs << " ****** file: " << trainfile << " ********" << endl;
  526. if(struct_verbosity >=1 ) { printf("Reading training examples..."); fflush(stdout); }
  527. /* read the training examples */
  528. SAMPLE sample = read_struct_examples(trainfile,&struct_parm);
  529. if(struct_verbosity>=1) { printf("done\n"); fflush(stdout); }
  530. arryAvgLoss[db].assign(vecRatio.size(), 0);
  531. // for each partition of the data
  532. for ( int it=0; it<vecRatio.size(); it++ )
  533. {
  534. ofs << "\tRatio: " << vecRatio[it] << endl;
  535. // split the data into training & testing sets
  536. int nTrainSampleNum = sample.n * vecRatio[it] / 100;
  537. SAMPLE trSample;
  538. trSample.n = nTrainSampleNum;
  539. trSample.examples = (EXAMPLE*)malloc( sizeof(EXAMPLE) * nTrainSampleNum );
  540. for ( int k=0; k<nTrainSampleNum; k++ ) {
  541. trSample.examples[k].x.SetHead( sample.examples[k].x.m_pHeadNode );
  542. trSample.examples[k].x.m_pEndNode = sample.examples[k].x.m_pEndNode;
  543. trSample.examples[k].y.m_nSize = sample.examples[k].y.m_nSize;
  544. trSample.examples[k].y.m_labels = sample.examples[k].y.m_labels;
  545. }
  546. SAMPLE tsSample;
  547. tsSample.n = sample.n - nTrainSampleNum;
  548. tsSample.examples = (EXAMPLE*)malloc( sizeof(EXAMPLE) * tsSample.n );
  549. for ( int k=0; k<tsSample.n; k++ ) {
  550. tsSample.examples[k].x.SetHead( sample.examples[nTrainSampleNum+k].x.m_pHeadNode );
  551. tsSample.examples[k].x.m_pEndNode = sample.examples[nTrainSampleNum+k].x.m_pEndNode;
  552. tsSample.examples[k].y.m_nSize = sample.examples[nTrainSampleNum+k].y.m_nSize;
  553. tsSample.examples[k].y.m_labels = sample.examples[nTrainSampleNum+k].y.m_labels;
  554. }
  555. /* perfrom inner-cv to select good param. */
  556. if ( learn_parm.m_bInnerCV ) {
  557. struct_parm.C = inner_CV( &trSample, structmodel,
  558. struct_parm, learn_parm, kernel_parm, alg_type, ofs);
  559. }
  560. /* Do the learning and return structmodel. */
  561. long runtime_start, runtime_end;
  562. runtime_start = get_runtime();
  563. bool bSucc = true;
  564. if(alg_type == 1) {
  565. if ( learn_parm.m_bQPSolver )
  566. svm_learn_struct(trSample, &struct_parm, &learn_parm, &kernel_parm, &structmodel);
  567. else
  568. bSucc = svm_learn_struct_lp(trSample, &struct_parm, &learn_parm, &kernel_parm, &structmodel, g_nStopStep, true);
  569. } else exit(1);
  570. runtime_end = get_runtime();
  571. /* Warning: The model contains references to the original data 'docs'.
  572. If you want to free the original data, and only keep the model, you
  573. have to make a deep copy of 'model'. */
  574. if(struct_verbosity>=1) { printf("Writing learned model...");fflush(stdout);}
  575. write_struct_model(modelfile, &structmodel, &struct_parm);
  576. if(struct_verbosity>=1) {printf("done\n");fflush(stdout); }
  577. // do classification on the testing data
  578. arryAvgLoss[db][it] = evaluation(&tsSample, structmodel, ofs, false);
  579. ofs << "\tAvgLoss: " << arryAvgLoss[db][it] << " [" << bSucc << "]"
  580. << "\tCPU Seconds: " << (runtime_end-runtime_start)/100.0 << endl;
  581. // free memory
  582. for ( int k=0; k<trSample.n; k++ ) {
  583. trSample.examples[k].x.SetHead(NULL);
  584. trSample.examples[k].y.m_labels = NULL;
  585. }
  586. for ( int k=0; k<tsSample.n; k++ ) {
  587. tsSample.examples[k].x.SetHead(NULL);
  588. tsSample.examples[k].y.m_labels = NULL;
  589. }
  590. free_struct_sample(trSample);
  591. free_struct_sample(tsSample);
  592. free_struct_model(structmodel);
  593. }
  594. free_struct_sample(sample);
  595. //free_struct_model(structmodel);
  596. }
  597. ofs << "\tAverage Loss over the " << vecFileName.size() << " files" << endl;
  598. vector<double> vecDBAvgLoss(vecRatio.size(), 0);
  599. for ( int i=0; i<vecRatio.size(); i++ ) {
  600. for ( int db=0; db<vecFileName.size(); db++ )
  601. vecDBAvgLoss[i] += arryAvgLoss[db][i] / vecFileName.size();
  602. ofs << "\t" << vecRatio[i] << "\t: " << vecDBAvgLoss[i] << endl;
  603. }
  604. }
  605. /* inner cross-validation to select good parameters. */
  606. double inner_CV(SAMPLE *sample, STRUCTMODEL &structmodel,
  607. STRUCT_LEARN_PARM &struct_parm,
  608. LEARN_PARM &learn_parm,
  609. KERNEL_PARM &kernel_parm,
  610. int alg_type, ofstream &ofs)
  611. {
  612. /* the candidate lambda. */
  613. vector<double> vecLambda;
  614. vecLambda.push_back(0.01);
  615. vecLambda.push_back(0.1);
  616. vecLambda.push_back(1);
  617. vecLambda.push_back(4);
  618. vecLambda.push_back(9);
  619. vecLambda.push_back(16);
  620. vector<double> arryAvgLoss( vecLambda.size(), 0 );
  621. int nUnitNum = sample->n / 5;
  622. for ( int cv=0; cv<5; cv++ ) /* 5-fold inner cv. */
  623. {
  624. // split the data into training & testing sets
  625. SAMPLE trSample, tsSample;
  626. trSample.n = nUnitNum;
  627. if ( cv == 4 ) trSample.n = sample->n - nUnitNum * 4;
  628. trSample.examples = (EXAMPLE*)malloc( sizeof(EXAMPLE) * trSample.n );
  629. tsSample.n = sample->n - trSample.n;
  630. tsSample.examples = (EXAMPLE*)malloc( sizeof(EXAMPLE) * tsSample.n );
  631. for ( int k=0; k<trSample.n; k++ ) {
  632. trSample.examples[k].x.SetHead( sample->examples[k+nUnitNum*cv].x.m_pHeadNode );
  633. trSample.examples[k].x.m_pEndNode = sample->examples[k+nUnitNum*cv].x.m_pEndNode;
  634. trSample.examples[k].y.m_nSize = sample->examples[k+nUnitNum*cv].y.m_nSize;
  635. trSample.examples[k].y.m_labels = sample->examples[k+nUnitNum*cv].y.m_labels;
  636. }
  637. int tsIx=0;
  638. for ( int k=0; k<sample->n; k++ ) {
  639. if ( k >= nUnitNum*cv && k < nUnitNum*cv+trSample.n ) continue;
  640. tsSample.examples[tsIx].x.SetHead( sample->examples[k].x.m_pHeadNode );
  641. tsSample.examples[tsIx].x.m_pEndNode = sample->examples[k].x.m_pEndNode;
  642. tsSample.examples[tsIx].y.m_nSize = sample->examples[k].y.m_nSize;
  643. tsSample.examples[tsIx ++].y.m_labels = sample->examples[k].y.m_labels;
  644. }
  645. for ( int k=0; k<vecLambda.size(); k++ ) {
  646. struct_parm.C = vecLambda[k];
  647. /* Do the learning and return structmodel. */
  648. bool bSucc = true;
  649. if(alg_type == 1) {
  650. if ( learn_parm.m_bQPSolver )
  651. svm_learn_struct(trSample, &struct_parm, &learn_parm, &kernel_parm, &structmodel);
  652. else
  653. bSucc = svm_learn_struct_lp(trSample, &struct_parm, &learn_parm, &kernel_parm, &structmodel, g_nStopStep, true);
  654. } else exit(1);
  655. /* Warning: The model contains references to the original data 'docs'.
  656. If you want to free the original data, and only keep the model, you
  657. have to make a deep copy of 'model'. */
  658. write_struct_model(modelfile, &structmodel, &struct_parm);
  659. arryAvgLoss[k] += evaluation(&tsSample, structmodel, ofs, false) / 5;
  660. // free memory
  661. for ( int k=0; k<trSample.n; k++ ) {
  662. trSample.examples[k].x.SetHead(NULL);
  663. trSample.examples[k].y.m_labels = NULL;
  664. }
  665. for ( int k=0; k<tsSample.n; k++ ) {
  666. tsSample.examples[k].x.SetHead(NULL);
  667. tsSample.examples[k].y.m_labels = NULL;
  668. }
  669. free_struct_sample(trSample);
  670. free_struct_sample(tsSample);
  671. free_struct_model(structmodel);
  672. }
  673. }
  674. double dBestLambda;
  675. double dMinErrRate = 1;
  676. for ( int k=0; k<vecLambda.size(); k++ ) {
  677. if ( arryAvgLoss[k] < dMinErrRate )
  678. {
  679. dMinErrRate = arryAvgLoss[k];
  680. dBestLambda = vecLambda[k];
  681. }
  682. }
  683. return dBestLambda;
  684. }
  685. /*---------------------------------------------------------------------------*/
  686. void read_input_parameters(int argc,char *argv[],char *trainfile,
  687. char *modelfile,
  688. long *verbosity,long *struct_verbosity,
  689. STRUCT_LEARN_PARM *struct_parm,
  690. LEARN_PARM *learn_parm, KERNEL_PARM *kernel_parm,
  691. int *alg_type)
  692. {
  693. long i;
  694. char type[100];
  695. /* set default */
  696. (*alg_type)=DEFAULT_ALG_TYPE;
  697. struct_parm->C=-0.01;
  698. struct_parm->slack_norm=1;
  699. struct_parm->epsilon=DEFAULT_EPS;
  700. struct_parm->custom_argc=0;
  701. struct_parm->loss_function=DEFAULT_LOSS_FCT;
  702. struct_parm->loss_type=DEFAULT_RESCALING;
  703. struct_parm->newconstretrain=100;
  704. struct_parm->ccache_size=5;
  705. strcpy (modelfile, "svm_struct_model");
  706. strcpy (learn_parm->predfile, "trans_predictions");
  707. strcpy (learn_parm->alphafile, "");
  708. (*verbosity)=0;/*verbosity for svm_light*/
  709. (*struct_verbosity)=1; /*verbosity for struct learning portion*/
  710. learn_parm->biased_hyperplane=1;
  711. learn_parm->remove_inconsistent=0;
  712. learn_parm->skip_final_opt_check=0;
  713. learn_parm->svm_maxqpsize=10;
  714. learn_parm->svm_newvarsinqp=0;
  715. learn_parm->svm_iter_to_shrink=-9999;
  716. learn_parm->maxiter=100000;
  717. learn_parm->kernel_cache_size=40;
  718. learn_parm->svm_c=99999999; /* overridden by struct_parm->C */
  719. learn_parm->eps=0.001; /* overridden by struct_parm->epsilon */
  720. learn_parm->transduction_posratio=-1.0;
  721. learn_parm->svm_costratio=1.0;
  722. learn_parm->svm_costratio_unlab=1.0;
  723. learn_parm->svm_unlabbound=1E-5;
  724. learn_parm->epsilon_crit=0.001;
  725. learn_parm->epsilon_a=1E-10; /* changed from 1e-15 */
  726. learn_parm->compute_loo=0;
  727. learn_parm->rho=1.0;
  728. learn_parm->xa_depth=0;
  729. learn_parm->m_bQPSolver=true; /* default to be QP solver*/
  730. kernel_parm->kernel_type=0;
  731. kernel_parm->poly_degree=3;
  732. kernel_parm->rbf_gamma=1.0;
  733. kernel_parm->coef_lin=1;
  734. kernel_parm->coef_const=1;
  735. strcpy(kernel_parm->custom,"empty");
  736. strcpy(type,"c");
  737. for(i=1;(i<argc) && ((argv[i])[0] == '-');i++) {
  738. switch ((argv[i])[1])
  739. {
  740. case '?': print_help(); exit(0);
  741. case 'a': i++; strcpy(learn_parm->alphafile,argv[i]); break;
  742. case 'c': i++; struct_parm->C=atof(argv[i]); break;
  743. case 'p': i++; struct_parm->slack_norm=atol(argv[i]); break;
  744. case 'e': i++; struct_parm->epsilon=atof(argv[i]); break;
  745. case 'k': i++; struct_parm->newconstretrain=atol(argv[i]); break;
  746. case 'h': i++; learn_parm->svm_iter_to_shrink=atol(argv[i]); break;
  747. case '#': i++; learn_parm->maxiter=atol(argv[i]); break;
  748. case 'm': i++; learn_parm->kernel_cache_size=atol(argv[i]); break;
  749. case 'w': i++; (*alg_type)=atol(argv[i]); break;
  750. case 'o': i++; struct_parm->loss_type=atol(argv[i]); break;
  751. case 'n': i++; learn_parm->svm_newvarsinqp=atol(argv[i]); break;
  752. case 'q': i++; learn_parm->svm_maxqpsize=atol(argv[i]); break;
  753. case 'l': i++; struct_parm->loss_function=atol(argv[i]); break;
  754. case 'f': i++; struct_parm->ccache_size=atol(argv[i]); break;
  755. case 't': i++; kernel_parm->kernel_type=atol(argv[i]); break;
  756. case 'd': i++; kernel_parm->poly_degree=atol(argv[i]); break;
  757. case 'g': i++; kernel_parm->rbf_gamma=atof(argv[i]); break;
  758. case 's': i++; kernel_parm->coef_lin=atof(argv[i]); break;
  759. case 'r': i++; kernel_parm->coef_const=atof(argv[i]); break;
  760. case 'u': i++; strcpy(kernel_parm->custom,argv[i]); break;
  761. case '-': strcpy(struct_parm->custom_argv[struct_parm->custom_argc++],argv[i]);i++; strcpy(struct_parm->custom_argv[struct_parm->custom_argc++],argv[i]);break;
  762. case 'v': i++; (*struct_verbosity)=atol(argv[i]); break;
  763. case 'y': i++; (*verbosity)=atol(argv[i]); break;
  764. case 'b': i++; strcpy(learn_parm->addConfigFile,argv[i]); break;
  765. case 'x': learn_parm->m_bQPSolver=false; break;
  766. default: printf("\nUnrecognized option %s!\n\n",argv[i]);
  767. print_help();
  768. exit(0);
  769. }
  770. }
  771. if(i>=argc) {
  772. printf("\nNot enough input parameters!\n\n");
  773. wait_any_key();
  774. print_help();
  775. exit(0);
  776. }
  777. strcpy (trainfile, argv[i]);
  778. if((i+1)<argc) {
  779. strcpy (modelfile, argv[i+1]);
  780. }
  781. if(learn_parm->svm_iter_to_shrink == -9999) {
  782. learn_parm->svm_iter_to_shrink=100;
  783. }
  784. if((learn_parm->skip_final_opt_check)
  785. && (kernel_parm->kernel_type == LINEAR)) {
  786. printf("\nIt does not make sense to skip the final optimality check for linear kernels.\n\n");
  787. learn_parm->skip_final_opt_check=0;
  788. }
  789. if((learn_parm->skip_final_opt_check)
  790. && (learn_parm->remove_inconsistent)) {
  791. printf("\nIt is necessary to do the final optimality check when removing inconsistent \nexamples.\n");
  792. wait_any_key();
  793. print_help();
  794. exit(0);
  795. }
  796. if((learn_parm->svm_maxqpsize<2)) {
  797. printf("\nMaximum size of QP-subproblems not in valid range: %ld [2..]\n",learn_parm->svm_maxqpsize);
  798. wait_any_key();
  799. print_help();
  800. exit(0);
  801. }
  802. if((learn_parm->svm_maxqpsize<learn_parm->svm_newvarsinqp)) {
  803. printf("\nMaximum size of QP-subproblems [%ld] must be larger than the number of\n",learn_parm->svm_maxqpsize);
  804. printf("new variables [%ld] entering the working set in each iteration.\n",learn_parm->svm_newvarsinqp);
  805. wait_any_key();
  806. print_help();
  807. exit(0);
  808. }
  809. if(learn_parm->svm_iter_to_shrink<1) {
  810. printf("\nMaximum number of iterations for shrinking not in valid range: %ld [1,..]\n",learn_parm->svm_iter_to_shrink);
  811. wait_any_key();
  812. print_help();
  813. exit(0);
  814. }
  815. if(struct_parm->C<0) {
  816. printf("\nYou have to specify a value for the parameter '-c' (C>0)!\n\n");
  817. wait_any_key();
  818. print_help();
  819. exit(0);
  820. }
  821. if(((*alg_type) < 1) || ((*alg_type) > 4)) {
  822. printf("\nAlgorithm type must be either '1', '2', '3', or '4'!\n\n");
  823. wait_any_key();
  824. print_help();
  825. exit(0);
  826. }
  827. if(learn_parm->transduction_posratio>1) {
  828. printf("\nThe fraction of unlabeled examples to classify as positives must\n");
  829. printf("be less than 1.0 !!!\n\n");
  830. wait_any_key();
  831. print_help();
  832. exit(0);
  833. }
  834. if(learn_parm->svm_costratio<=0) {
  835. printf("\nThe COSTRATIO parameter must be greater than zero!\n\n");
  836. wait_any_key();
  837. print_help();
  838. exit(0);
  839. }
  840. if(struct_parm->epsilon<=0) {
  841. printf("\nThe epsilon parameter must be greater than zero!\n\n");
  842. wait_any_key();
  843. print_help();
  844. exit(0);
  845. }
  846. if((struct_parm->slack_norm<1) || (struct_parm->slack_norm>2)) {
  847. printf("\nThe norm of the slacks must be either 1 (L1-norm) or 2 (L2-norm)!\n\n");
  848. wait_any_key();
  849. print_help();
  850. exit(0);
  851. }
  852. if((struct_parm->loss_type != SLACK_RESCALING)
  853. && (struct_parm->loss_type != MARGIN_RESCALING)) {
  854. printf("\nThe loss type must be either 1 (slack rescaling) or 2 (margin rescaling)!\n\n");
  855. wait_any_key();
  856. print_help();
  857. exit(0);
  858. }
  859. if(learn_parm->rho<0) {
  860. printf("\nThe parameter rho for xi/alpha-estimates and leave-one-out pruning must\n");
  861. printf("be greater than zero (typically 1.0 or 2.0, see T. Joachims, Estimating the\n");
  862. printf("Generalization Performance of an SVM Efficiently, ICML, 2000.)!\n\n");
  863. wait_any_key();
  864. print_help();
  865. exit(0);
  866. }
  867. if((learn_parm->xa_depth<0) || (learn_parm->xa_depth>100)) {
  868. printf("\nThe parameter depth for ext. xi/alpha-estimates must be in [0..100] (zero\n");
  869. printf("for switching to the conventional xa/estimates described in T. Joachims,\n");
  870. printf("Estimating the Generalization Performance of an SVM Efficiently, ICML, 2000.)\n");
  871. wait_any_key();
  872. print_help();
  873. exit(0);
  874. }
  875. parse_struct_parameters(struct_parm);
  876. }
  877. void wait_any_key()
  878. {
  879. printf("\n(more)\n");
  880. (void)getc(stdin);
  881. }
  882. void print_help()
  883. {
  884. printf("\nSVM-struct learning module: %s, %s, %s\n",INST_NAME,INST_VERSION,INST_VERSION_DATE);
  885. printf(" includes SVM-struct %s for learning complex outputs, %s\n",STRUCT_VERSION,STRUCT_VERSION_DATE);
  886. printf(" includes SVM-light %s quadratic optimizer, %s\n",VERSION,VERSION_DATE);
  887. copyright_notice();
  888. printf(" usage: svm_struct_learn [options] example_file model_file\n\n");
  889. printf("Arguments:\n");
  890. printf(" example_file-> file with training data\n");
  891. printf(" model_file -> file to store learned decision rule in\n");
  892. printf("General options:\n");
  893. printf(" -? -> this help\n");
  894. printf(" -v [0..3] -> verbosity level (default 1)\n");
  895. printf(" -y [0..3] -> verbosity level for svm_light (default 0)\n");
  896. printf("Learning options:\n");
  897. printf(" -c float -> C: trade-off between training error\n");
  898. printf(" and margin (default 0.01)\n");
  899. printf(" -p [1,2] -> L-norm to use for slack variables. Use 1 for L1-norm,\n");
  900. printf(" use 2 for squared slacks. (default 1)\n");
  901. printf(" -o [1,2] -> Rescaling method to use for loss.\n");
  902. printf(" 1: slack rescaling\n");
  903. printf(" 2: margin rescaling\n");
  904. printf(" (default %d)\n",DEFAULT_RESCALING);
  905. printf(" -l [0..] -> Loss function to use.\n");
  906. printf(" 0: zero/one loss\n");
  907. printf(" (default %d)\n",DEFAULT_LOSS_FCT);
  908. printf("Kernel options:\n");
  909. printf(" -t int -> type of kernel function:\n");
  910. printf(" 0: linear (default)\n");
  911. printf(" 1: polynomial (s a*b+c)^d\n");
  912. printf(" 2: radial basis function exp(-gamma ||a-b||^2)\n");
  913. printf(" 3: sigmoid tanh(s a*b + c)\n");
  914. printf(" 4: user defined kernel from kernel.h\n");
  915. printf(" -d int -> parameter d in polynomial kernel\n");
  916. printf(" -g float -> parameter gamma in rbf kernel\n");
  917. printf(" -s float -> parameter s in sigmoid/poly kernel\n");
  918. printf(" -r float -> parameter c in sigmoid/poly kernel\n");
  919. printf(" -u string -> parameter of user defined kernel\n");
  920. printf("Optimization options (see [2][3]):\n");
  921. printf(" -w [1,2,3,4]-> choice of structural learning algorithm (default %d):\n",(int)DEFAULT_ALG_TYPE);
  922. printf(" 1: algorithm described in [2]\n");
  923. printf(" 2: joint constraint algorithm (primal) [to be published]\n");
  924. printf(" 3: joint constraint algorithm (dual) [to be published]\n");
  925. printf(" 4: joint constraint algorithm (dual) with constr. cache\n");
  926. printf(" -q [2..] -> maximum size of QP-subproblems (default 10)\n");
  927. printf(" -n [2..q] -> number of new variables entering the working set\n");
  928. printf(" in each iteration (default n = q). Set n<q to prevent\n");
  929. printf(" zig-zagging.\n");
  930. printf(" -m [5..] -> size of cache for kernel evaluations in MB (default 40)\n");
  931. printf(" (used only for -w 1 with kernels)\n");
  932. printf(" -f [5..] -> number of constraints to cache for each example\n");
  933. printf(" (default 5) (used with -w 4)\n");
  934. printf(" -e float -> eps: Allow that error for termination criterion\n");
  935. printf(" (default %f)\n",DEFAULT_EPS);
  936. printf(" -h [5..] -> number of iterations a variable needs to be\n");
  937. printf(" optimal before considered for shrinking (default 100)\n");
  938. printf(" -k [1..] -> number of new constraints to accumulate before\n");
  939. printf(" recomputing the QP solution (default 100) (-w 1 only)\n");
  940. printf(" -# int -> terminate QP subproblem optimization, if no progress\n");
  941. printf(" after this number of iterations. (default 100000)\n");
  942. printf("Output options:\n");
  943. printf(" -a string -> write all alphas to this file after learning\n");
  944. printf(" (in the same order as in the training set)\n");
  945. printf("Structure learning options:\n");
  946. print_struct_help();
  947. wait_any_key();
  948. printf("\nMore details in:\n");
  949. printf("[1] T. Joachims, Learning to Align Sequences: A Maximum Margin Aproach.\n");
  950. printf(" Technical Report, September, 2003.\n");
  951. printf("[2] I. Tsochantaridis, T. Joachims, T. Hofmann, and Y. Altun, Large Margin\n");
  952. printf(" Methods for Structured and Interdependent Output Variables, Journal\n");
  953. printf(" of Machine Learning Research (JMLR), Vol. 6(Sep):1453-1484, 2005.\n");
  954. printf("[3] T. Joachims, Making Large-Scale SVM Learning Practical. Advances in\n");
  955. printf(" Kernel Methods - Support Vector Learning, B. Schölkopf and C. Burges and\n");
  956. printf(" A. Smola (ed.), MIT Press, 1999.\n");
  957. printf("[4] T. Joachims, Learning to Classify Text Using Support Vector\n");
  958. printf(" Machines: Methods, Theory, and Algorithms. Dissertation, Kluwer,\n");
  959. printf(" 2002.\n\n");
  960. }