如何在Visual Studio(VS)2012里使用libsvm工具箱


原文:http://blog.csdn.net/u014691453/article/details/40393137

 

軟件版本:

Visual Studio版本:VS2012 

(注:使用方法在 VS2010 上面親測同樣可用,只是可能會出現的問題是: VS2010 和 VS2012 之間有些函數寫法不同,需在編譯前做改動,譬如 VS2010 的 scanf 對比 VS2012 的 scanf_s )

libsvm版本:libsvm-3.18

 

聲明:

如果你找到了我這篇標題的文章,那很大程度上意味着你一定是在 VS 里或者 MFC 里使用 libsvm 工具箱出現了問題。那你也一定知道了,libsvm 在VS工程里的使用與它在 matlab 或者是 python 里面的使用,是多么的不同。

 

致謝:

如果沒有 gg 百分之百的幫助,就憑我在 VS 里編程的菜鳥能力,是絕對不可能1天就搞好的,我絕對會弄半年不止委屈所以非常感謝非常感謝,今后我一定認真學習編程。

 

正文:

分三部分:第一部分:先把 VS 工程的框架建好

                  第二部分:工程里包含主函數的 cpp 文件要怎么寫

                  第三部分:把 libsvm 工具箱移植到 MFC 中進行使用

                  第四部分:在本文代碼中能夠正確運行的數據格式

資源地址:如何在Visual Studio(VS)里使用libsvm工具箱(與博文相關的代碼包)

第一部分:先把 VS 工程的框架建好

之前一直都是在 matlab 里面使用這個 libsvm 工具箱,也曾經有一段時間在 python 里面使用過,剛接觸的時候還在 cmd 控制台上面使用過,libsvm 的編寫者真的很贊,打開此工具箱我們看到的情景是這樣的:
 

對於java、matlab、python、windows 都有相對應的文件夾,文件夾里面的內容和上圖中的這個 readme 就可以幫助你在以上四種情況下使用了。

那在 VS 里該怎么使用呢?

首先,我們先建立一個Win32控制台項目,起名為 MM ,如下步驟:

然后,把 libsvm 文件夾里的這幾個文件(如下圖),都拷貝到 MM 項目的文件夾(如下下圖)里去,以備后續使用。

然后,在 MM 項目里,我們把 svm.h 和 svm.cpp 分別添加到頭文件和源文件里面去,如下圖:

然后,在源文件里,右鍵——新建項:MM.cpp

接下來是第二部分

 

 第二部分:工程里包含主函數的 cpp 文件要怎么寫

MM.cpp也就是上面說的包含主函數的 cpp 文件,我們最終要執行的就是它。
首先,我們先給 MM.cpp 里寫好需要用到的頭文件,如下:
[cpp]  view plain copy
 
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <ctype.h>  
  4. #include <list>  
  5. #include <fstream>  
  6. #include <iostream>  
  7. #include "svm.h"  
  8. using namespace std;  

接下來的內容大致分五部分:
第一:讀入訓練數據和測試數據
第二:構建參數 param 的結構體(主要目的就是讓VS知道你要用的參數都是什么)
第三:構建分類問題 prob 的結構體(主要就是把第一步讀入的數據傳遞給 svm_train 和 svm_predict)
第四:主函數如下
第五:結果展示
 

第一:讀入訓練數據和測試數據

首先,在讀數據之前,先定義一些變量(整個程序還是主要參考的 libsvm/svm_toy/qt/svm_toy.cpp 這個代碼,由於目前我編程能力實在是差,所以一些冗余的代碼我都沒有刪改,僅僅只實現了能夠使用libsvm的目的。)
[cpp]  view plain copy
 
  1. #define XLEN 10  //生產測試數據,這個感覺就是無用的地方  
  2. #define YLEN 10  
  3.   
  4.   
  5. ofstream outdata;  //需要准備的所有數據的標簽label和特征feature都是分開的,而且特征feature前面不需要加序號冒號這種東西,只需用空格隔開就好  
  6. ifstream indata;   //所以這里indata只包含特征,indata_label只包含label,每一行是一個樣本的。  
  7. ofstream outdata_lable;  
  8. ifstream indata_lable;  
  9.   
  10. int NUM = 1440;   //由於我的樣本特征是 1440 維,所以讀數據的時候,我定義了個數,你可以根據自己特征的維度對 NUM 進行更改。  
  11.   
  12. //char default_param[] = "-t 2 -c 100";  // 這個是 svm_toy.cpp 里對參數的選擇  
  13. char default_param[] = "-t 2 -c 4 -g 32";  // 這個是匹配我數據的參數  
  14. struct point {                           //這個是后面 svm_train 拿來數據做訓練時候的數據傳入方式  
  15.     double *feature;  
  16.     //signed char value;  
  17.     int value;  
  18. };  
  19.   
  20. list<point> point_list;        // 通過 indata 讀進來的數據就放在 point_list 里面  
  21. int current_value = 1;          // 路人甲變量  
  22.   
  23. void clear_all()         // 清空鏈表  
  24. {  
  25.     point_list.clear();  
  26. }  

然后,我們先讀入訓練數據,用來訓練模型
[cpp]  view plain copy
 
  1. void readFile1(char *file,char *file_lable)  //定義讀入訓練數據的函數叫做 readFile1  
  2. {  
  3.   
  4.     indata.open(file,ios::in);               //讀入特征  
  5.     indata_lable.open(file_lable,ios::in);    // 讀入標簽  
  6.     cout <<"read data begin"<<endl;          // 屏顯  
  7.       
  8.     clear_all();  
  9.     while(!indata.eof())              // 如果沒有讀到文件結束,就繼續讀,知道讀完整個 traindata 文件  
  10.     {  
  11.           
  12.         double *line = new double[NUM];  
  13.         for(int i =0;i<NUM;i++)  
  14.         {  
  15.             indata >> line[i];       //把特征存起來  
  16.         }  
  17.         point p;  
  18.         indata_lable >>p.value;          //把label存起來  
  19.   
  20.         p.feature = line;  
  21.         point_list.push_back(p);  
  22.     }  
  23.       
  24.     point_list.pop_back();        //如果你的 traindata.txt 文件數據的最后有一個空格的話,需要加上這句話,否則預測會有錯如果沒有空格,這句話就不需要了  
  25.     indata.close();  
  26.     indata_lable.close();  
  27.     cout <<"read data end"<<endl;  
  28. }  
 

接下來,讀入測試數據:
[cpp]  view plain copy
 
  1. void readFile2(char *file,char *file_lable)  // 讀入測試文件的函數叫做 readFile2  
  2. {  
  3.   
  4.     indata.open(file,ios::in);      //接下來代碼和上面讀訓練數據是一個樣子的  
  5.     indata_lable.open(file_lable,ios::in); // <span style="font-family: Arial, Helvetica, sans-serif;">由於讀訓練數據之后就會建立model,然后才會讀測試數據,所以不用擔心會有數據覆蓋的問題</span>  
  6.     cout <<"read test data begin"<<endl;  
  7.     clear_all();  
  8.     while(!indata.eof())  
  9.     {  
  10.           
  11.         double *line = new double[NUM];  
  12.         for(int i =0;i<NUM;i++)  
  13.         {  
  14.             indata >> line[i];  
  15.         }  
  16.         point p;  
  17.         indata_lable >>p.value;  
  18.   
  19.         p.feature = line;  
  20.         point_list.push_back(p);  
  21.     }  
  22.     point_list.pop_back();  
  23.     cout <<"read test data end size = "<<point_list.size()<<endl;  
  24.     indata.close();  
  25.     indata_lable.close();  
  26. }  
 

第二:構建參數 param 的結構體


然后,訓練模型!:包括了構建參數param結構和構建 prob結構。
由於太長了,我上傳到 CSDN 下載頁面吧,免積分下載。這段代碼主要就是參考的 svm_toy.cpp 文件,同學們好好研讀。
 

第三:構建分類問題 prob 的結構體

 
同第二,代碼是一起的,我會把整體代碼,包括以上寫的讀入feature和label的代碼,發到下載頁面
 

第四:主函數如下

[cpp]  view plain copy
 
  1. int main()  
  2. {  
  3.     int choice;  
  4.     cout<<"1 train model\n2 test1\n3 test2\n"<<endl;   
  5.     cin >>choice;  
  6.     switch(choice)  
  7.     {  
  8.     case 1:  
  9.         {  
  10.             readFile1("traindata.txt","trainlabel.txt"); //選擇1 是訓練模型,模型會保存為“model.txt”  
  11.             run();  
  12.             break;  
  13.         }  
  14.     case 2:  
  15.         {  
  16.             readFile2("1.txt","1_label.txt");   // 選擇2 是用第一份測試數據進行測試  
  17.             testData();  
  18.             break;  
  19.         }  
  20.     case 3:  
  21.         {  
  22.             readFile2("11.txt","11_label.txt");  // 選擇3 是用第二份測試數據進行測試  
  23.             testData();  
  24.             break;  
  25.         }  
  26.   
  27.     }  
  28.     system("pause");  
  29.     return 0;  
  30. }  
 

第五:結果展示

等啊等~ 訓練結束啦~
接下來就是測試了:
 

第三部分:把 libsvm 工具箱移植到 MFC 中進行使用

 
其實在 MFC 中的使用,和libsvm在普通VS 項目中的使用是一樣的。
如果你不想在MFC 里訓練 model,那么完全可以把在第二部分中訓練出來的 model 拷貝到 MFC 的這個項目里面,然后在 測試數據之前,把 model load進去就好了,具體load方式參照我的代碼里 test()函數里寫的內容。
那么在 MFC 的代碼里,你就可以把第二部分代碼中的  void run() ,即訓練模型部分去掉了
 
注:我就是在 MFC 里使用 libsvm 的時候,發現了 VS2010 和 VS2012 的不同,svm.cpp 和 svm.h 這兩個文件里的一些函數,可以在 VS2010 的 MFC 工程里跑的很好,可是到了 VS2012 里就會提示說 “你把 XX 換成 XX_s 會更安全”,是錯誤而不是警告,所以如果在 VS2012 里面用libsvm的話,需要在svm.cpp 和 svm.h 這兩個文件里修改部分函數的表達形式,這個在網上都有解答,可以自行查詢。
 

第四部分:在本文代碼中能夠正確運行的數據格式

在第二部分給出的資源鏈接里,我上傳的資料里包括我的測試數據,1.txt和1_label.txt 就是test1測試的內容,11.txt 和 11_label.txt 就是test2 測試的內容,如果你要測試你自己的數據,記得在 test()代碼里更改成你自己數據的名稱。
 
可以使用的數據格式: 大家可以參照我上傳的 1.txt,大致如以下:
 
0.564 0.436 0.675 0.453 0.000 0.345 
0.354 0.345 0.456 0.000 0.346 0.645 
0.678 0.678 0.866 0.757 0.575 0.867 
0.866 0.865 0.856 0.867 0.557 0.754 
 
我的1_label.txt,大致如以下:
 
1
1
2
2
 
如以上格式,因為我的數據是之前通過 matlab 處理過的,所以空格位置用的是 ‘\t’ 。
 
如果你的數據格式和我不一樣,只有兩條路: 1:改成我這樣的數據格式  2:更改代碼里讀數據這部分的程序,保證讀進去的數據是對的就好 
或者還有一條路,就是自己按照你的需要重新寫代碼。
 
利用了寶貴的一個下午來整理這些東西,希望能夠真的幫到像之前的我一樣有需要的人。
 
感覺該說的應該都說完了,如果有解釋不正確或者漏掉的地方,也請大家告知我,我會再修改


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM