SVM學習筆記(1):Win下LibSVM在Matlab中的安裝及使用

1 LibSVM工具包簡介

LIBSVM是臺灣大學林智仁(Lin Chih-Jen)教授於2001年開發設計,可在 http://www.csie.ntu.edu.tw/~cjlin/libsvm/https://github.com/cjlin1/libsvm/releases 免費獲得。
下載後解壓,主要有6個文件夾和一些源碼文件:

  • Java: 主要是應用於java平臺;
  • matlab: windows下64位matlab平臺;
  • python: 是用來參數優選的工具, 稍後介紹;
  • svm-toy: 一個可視化的工具, 用來展示訓練數據和分類界面, 裏面是源碼, 其編譯後的程序在windows文件夾下;
  • tools: 主要包含四個python文件, 用來數據集抽樣(subset), 參數優選(grid), 集成測試(easy), 數據檢查(checkdata);
  • windows: 包含libSVM四個exe程序包, 我們所用的庫就是他們.

2 Win下LIBSVM在Matlab2016b中的安裝使用

  1. 將下載的LIBSVM壓縮包libsvm-3.23.zip(2018年8月時最新版本)解壓,把解壓出的文件夾libsvm-3.23複製到Matlab的安裝路徑下...\MATLAB\R2016b\toolbox
  2. ...\MATLAB\R2016b\toolbox\libsvm-3.23添加到Matlab的搜索路徑(添加幷包含子文件夾)

注:
因爲使用的是64位的操作系統和matlab,而...\MATLAB\R2016b\toolbox\libsvm-3.23\windows下包含了matlab可執行的64位二進制文件libsvmread.mexw64/libsvmwrite.mexw64/svmpredict.mexw64/svmtrain.mexw64,故無需自己編譯。
假設你使用的是32位操作系統和matlab,則需要自己編譯相應的二進制文件:在matlab命令窗口輸入mex –setup,這時matlab會提示你選擇編譯mex文件的c/c++編譯器。選擇一個你電腦上安裝的c/c++編譯器,例如Microsoft Visual C++ 2010,將matlab當前目錄設置爲:‘…\MATLAB\R2016b\toolbox\libsvm-3.23\matlab’,輸入命令make,這時你會看到當前目錄生成了二進制文件libsvmread.mexw32/libsvmwrite.mexw32/svmpredict.mexw32/svmtrain.mexw32。將當前目錄添加到matlab路徑中即可。

  1. 把當前目錄設置爲...\MATLAB\R2016b\toolbox\libsvm-3.23,輸入如下測試代碼:
[heart_scale_label,heart_scale_inst]=libsvmread('heart_scale');
model = svmtrain(heart_scale_label, heart_scale_inst, '-c 1 -g 0.07');
[predict_label, accuracy, dec_values] =svmpredict(heart_scale_label, heart_scale_inst, model); % test the traindata

得到如下結果,說明安裝成功:

*
optimization finished, #iter = 134
nu = 0.433785
obj = -101.855060, rho = 0.426412
nSV = 130, nBSV = 107
Total nSV = 130
Accuracy = 86.6667% (234/270) (classification)

參考:SVM學習筆記(1)LIBSVM在matlab下的使用安裝

3 LIBSVM相關函數說明

3.1 libsvmread主要用於讀取數據

這裏的數據是非matlab下的.mat數據,比如說是.txt,.data等等,這個時候需要使用libsvmread函數進行轉化爲matlab可識別數據,比如自帶的數據是heart_scale數據,那麼導入到matlab有兩種方式,
一種使用libsvmread函數,在matlab下直接libsvmread(heart_scale);
第二種方式爲點擊matlab的‘導入數據’按鈕,然後導向heart_scale所在位置,直接選擇就可以了。因爲有的數據libsvmread讀取不管用,但是‘導入數據’後就可以變成matlab下數據。

3.2 libsvmwrite寫函數,就是把已知數據存起來

使用方式爲:libsvmwrite(‘filename’,label_vector, instance_matrix);
label_vector是標籤,instance_matrix爲數據矩陣(注意這個數據必須是稀疏矩陣,就是裏面的數據不包含沒用的數據(比如很多0),有這樣的數據應該去掉再存)。

3.3 svmtrain訓練函數,訓練數據產生模型的

Options:可用的選項即表示的涵義如下
  -s svm類型:SVM設置類型(默認0)
  0 – C-SVC
  1 --v-SVC
  2 – 一類SVM
  3 – e-SVR
  4 – v-SVR
  (分類問題主要使用0 – C-SVC,迴歸問題主要使用3 – e-SVR)
  -t 核函數類型:核函數設置類型(默認2)
  0 – 線性:u’v
  1 – 多項式:(ru’v + coef0)^degree(關聯參數:-g -r -d)
  2 – RBF函數:exp(-gamma|u-v|^2)(關聯參數:-g)
  3 –sigmoid:tanh(r
u’v + coef0)(關聯參數:-g -r)
  (一般使用RBF核函數)
  -d degree:核函數中的degree設置(針對多項式核函數)(默認3)
  -g r(gamma):核函數中的gamma函數設置(針對多項式/rbf/sigmoid核函數)(默認1/ num_features,即屬性數目的倒數)
  -r coef0:核函數中的coef0設置(針對多項式/sigmoid核函數)((默認0)
  -c cost:設置C-SVC,e -SVR和v-SVR的參數(損失函數)(範圍(0,+∞),默認1)
  -n nu:設置v-SVC,一類SVM和v- SVR的參數(範圍(0,1],默認0.5)
  -p p:設置e -SVR 中損失函數p的值(範圍(0,+∞),默認0.1)
  -m cachesize:設置cache內存大小,以MB爲單位(默認40)
  -e eps:設置允許的終止判據(默認0.001)
  -h shrinking:是否使用啓發式,0或1(默認1)
  -wi weight:設置第幾類的參數C爲weight*C(C-SVC中的C)(默認1)
  -v n: n-fold交互檢驗模式,n爲fold的個數,必須大於等於2
  
其中
  這裏寫圖片描述
  這裏寫圖片描述
  以上這些參數設置可以按照SVM的類型和核函數所支持的參數進行任意組合。如果設置的參數在函數或SVM類型中沒有也不會產生影響,程序不會接受該參數;如果應有的參數設置不正確,參數將採用默認值。

附:利用libsvm-mat建立分類模型model參數解密

4 LIBSVM實際應用方法

4.1 獲取原始數據(LIBSVM格式)

function write4libsvm 
% 爲了使得數據滿足libsvm的格式要求而進行的數據格式轉換 注意原始格式是mat的數據格式,轉化成txt或者dat都可以。
% 原始數據保存格式爲: 
%             [標籤 第一個屬性值 第二個屬性值...] 
% 轉換後文件格式爲滿足libsvm的格式要求,即: 
%             [標籤 1:第一個屬性值 2:第二個屬性值 3:第三個屬性值 ...] 
% Genial@ustc 
% 2004.6.16 
[filename, pathname] = uigetfile( {'*.mat', ... 
       '數據文件(*.mat)'; ... 
       '*.*',                   '所有文件 (*.*)'}, ... 
   '選擇數據文件'); 
try 
   S=load([pathname filename]); 
   fieldName = fieldnames(S); 
   str = cell2mat(fieldName); 
   B = getfield(S,str); 
   [m,n] = size(B); 
   [filename, pathname] = uiputfile({'*.txt;*.dat' ,'數據文件(*.txt;*.dat)';'*.*','所有文件 (*.*)'},'保存數據文件'); 
   fid = fopen([pathname filename],'w'); 
   if(fid~=-1) 
       for k=1:m 
           fprintf(fid,'%3d',B(k,1)); 
           for kk = 2:n 
               fprintf(fid,'\t%d',(kk-1)); 
               fprintf(fid,':'); 
               fprintf(fid,'%d',B(k,kk)); 
           end 
           k; 
           fprintf(fid,'\n'); 
       end 
       fclose(fid); 
   else 
       msgbox('無法保存文件!'); 
   end 
catch 
end

參考:
如何轉成libsvm支持的數據格式並做迴歸分析

4.2 數據預處理(歸一化)

先歸一化再劃分訓練集、測試集

% 數據集歸一化
dataset_c21_label = dataset_c21(:,1);dataset_c21_inst = dataset_c21(:,2:136);
[dataset_c21_scale_T,PS] = mapminmax(dataset_c21_inst'); dataset_c21_scale = dataset_c21_scale_T';

% Matlab中的mapminmax用法
% [inputtrain,setting] = mapminmax(input_train');
% inputtest = mapminmax('apply',input_test',setting);

4.3 劃分訓練集、測試集

% 隨機劃分訓練集、測試集,訓練集:測試集=6:4,使用函數split_train_test.m,ratio=0.6
[X_train, y_train,  X_test, y_test] = split_train_test(dataset_c21_scale(:,1:5*i), dataset_c21_label, 2, 0.6);
function [X_train, y_train,  X_test, y_test] = split_train_test(X, y, k, ratio)
%SPLIT_TRAIN_TEST 分割訓練集和測試集
%  參數X是數據矩陣 y是對應類標籤 k是類別個數 ratio是訓練集的比例
%  返回訓練集X_train和對應的類標籤y_train 測試集X_test和對應的類標籤y_test

m = size(X, 1);
y_labels = unique(y); % 去重,k應該等於length(y_labels) 
d = [1:m]';

X_train_0 = [];y_train_0= [];
for i = 1:k
    comm_i = find(y == y_labels(i));
    if isempty(comm_i) % 如果該類別在數據集中不存在
        continue;
    end
    size_comm_i = length(comm_i);
    rp = randperm(size_comm_i); % random permutation
    rp_ratio = rp(1:floor(size_comm_i * ratio));
    ind = comm_i(rp_ratio);
    X_train_0 = [X_train_0; X(ind, :)];
    y_train_0 = [y_train_0; y(ind, :)];
    d = setdiff(d, ind);
end
X_test = X(d, :);y_test = y(d, :);
% famirtse增加:打亂訓練集的順序,日期:20180901
Xy_train_0 = [y_train_0,X_train_0];
rowrank = randperm(size(Xy_train_0, 1));Xy_train = Xy_train_0(rowrank, :); % 隨機打亂矩陣的行數
X_train = Xy_train(:,2:end);y_train = Xy_train(:,1);
end

參考:再議歸一化問題
歸一化函數mapminmax的討論
歸一化問題
Matlab實現 把數據集X分割成訓練集和測試集
Matlab劃分測試集和訓練集

4.4 採取交叉驗證選擇最佳c,g

 % 參數(c,g)尋優,使用函數SVMcg.m
[bestacc,bestc,bestg] = SVMcg(y_train,X_train,-8,8,-8,8,10,0.5,0.5,0.9);
cmd = ['-c',num2str(bestc),'-g',num2str(bestg),'-w1 2 -w0 0.5'];
function [bestacc,bestc,bestg] = SVMcg(train_label,train,cmin,cmax,gmin,gmax,v,cstep,gstep,accstep)
%SVMcg cross validation by faruto
%Email:[email protected] QQ:516667408 http://blog.sina.com.cn/faruto BNU
%last modified 2009.8.23
%Super Moderator @ www.ilovematlab.cn
%% 參數說明:
% train_label:訓練集標籤.要求與libsvm工具箱中要求一致.
% train:訓練集.要求與libsvm工具箱中要求一致.
% cmin:懲罰參數c的變化範圍的最小值(取以2爲底的對數後),即 c_min = 2^(cmin).默認爲 -5
% cmax:懲罰參數c的變化範圍的最大值(取以2爲底的對數後),即 c_max = 2^(cmax).默認爲 5
% gmin:參數g的變化範圍的最小值(取以2爲底的對數後),即 g_min = 2^(gmin).默認爲 -5
% gmax:參數g的變化範圍的最小值(取以2爲底的對數後),即 g_min = 2^(gmax).默認爲 5
% v:cross validation的參數,即給測試集分爲幾部分進行cross validation.默認爲 3
% cstep:參數c步進的大小.默認爲 1
% gstep:參數g步進的大小.默認爲 1
% accstep:最後顯示準確率圖時的步進大小. 默認爲 1.5
%% about the parameters of SVMcg 
if nargin < 10
    accstep = 1.5;
end
if nargin < 8
    accstep = 1.5;
    cstep = 1;
    gstep = 1;
end
if nargin < 7
    accstep = 1.5;
    v = 3;
    cstep = 1;
    gstep = 1;
end
if nargin < 6
    accstep = 1.5;
    v = 3;
    cstep = 1;
    gstep = 1;
    gmax = 5;
end
if nargin < 5
    accstep = 1.5;
    v = 3;
    cstep = 1;
    gstep = 1;
    gmax = 5;
    gmin = -5;
end
if nargin < 4
    accstep = 1.5;
    v = 3;
    cstep = 1;
    gstep = 1;
    gmax = 5;
    gmin = -5;
    cmax = 5;
end
if nargin < 3
    accstep = 1.5;
    v = 3;
    cstep = 1;
    gstep = 1;
    gmax = 5;
    gmin = -5;
    cmax = 5;
    cmin = -5;
end
%% X:c Y:g cg:acc
[X,Y] = meshgrid(cmin:cstep:cmax,gmin:gstep:gmax);
[m,n] = size(X);
cg = zeros(m,n);
%% record acc with different c & g,and find the bestacc with the smallest c
bestc = 0;
bestg = 0;
bestacc = 0;
basenum = 2;
for i = 1:m
    for j = 1:n
        cmd = ['-v ',num2str(v),' -c ',num2str( basenum^X(i,j) ),' -g ',num2str( basenum^Y(i,j) )];
        cg(i,j) = svmtrain(train_label, train, cmd);

        if cg(i,j) > bestacc
            bestacc = cg(i,j);
            bestc = basenum^X(i,j);
            bestg = basenum^Y(i,j);
        end
        if ( cg(i,j) == bestacc && bestc > basenum^X(i,j) )
            bestacc = cg(i,j);
            bestc = basenum^X(i,j);
            bestg = basenum^Y(i,j);
        end
    end
end
%% to draw the acc with different c & g
[C,h] = contour(X,Y,cg,60:accstep:100);
clabel(C,h,'FontSize',10,'Color','r');
xlabel('log2c','FontSize',10);
ylabel('log2g','FontSize',10);
grid on;

參考:
關於SVM參數c&g選取的總結帖[matlab-libsvm]

4.5 訓練、測試、預測

% 訓練
model = svmtrain(y_train, X_train, cmd);
% 測試/預測
[predict_label, accuracy, dec_values] = svmpredict(y_test, X_test, model);
acc = accuracy(1);

4.6 評估

% 計算敏感性和特異性
sens = sum(predict_label==1&y_test==1)/sum(y_test==1)*100;
spec = sum(predict_label==0&y_test==0)/sum(y_test==0)*100;

5 其他一些問題

5.1 Matlab中使用libsvm進行分類預測時的標籤問題

首先用svm(libsvm,lssvm、hssvm)等等進行分類預測,要進行三個步驟1、訓練 2、測試 3、預測
1、訓練——大家都知道,就是用訓練數據集,不管你採用那種尋優方式,得到相對的最優參數,訓練模型。

2、測試——就是用剛剛得到的模型,對測試數據進行測試,此時測試數據集的label是已知的,這主要是用來對剛剛的模型的檢測,或者是對參數的檢測、或者是對模型的泛化能力的檢測。此時會得到一個準確率,這時的準確率是有用的,是有實際意義的,因爲原來的label是已知的。

3、預測——預測就是對未知類別的樣本在測試確定了模型有好的泛化能力的情況下的預測分類,這步纔是真的預測能力功能的實現。此時數據的label隨便給了,這樣是爲了滿足libsvm對數據格式的要求。此時也會得到一個準確率,但是這個是沒有實際意義的,因爲原始的label是隨便給的,沒有意義,我們只是關心的是最後得到的類別號——達到分類的目的。

5.2 交叉驗證(CrossValidation)方法思想簡介

以下簡稱交叉驗證(Cross Validation)爲CV.CV是用來驗證分類器的性能一種統計分析方法,基本思想是把在某種意義下將原始數據(dataset)進行分組,一部分做爲訓練集(train set),另一部分做爲驗證集(validation set),首先用訓練集對分類器進行訓練,在利用驗證集來測試訓練得到的模型(model),以此來做爲評價分類器的性能指標.常見CV的方法如下:

1).Hold-Out Method
將原始數據隨機分爲兩組,一組做爲訓練集,一組做爲驗證集,利用訓練集訓練分類器,然後利用驗證集驗證模型,記錄最後的分類準確率爲此Hold-OutMethod下分類器的性能指標.此種方法的好處的處理簡單,只需隨機把原始數據分爲兩組即可,其實嚴格意義來說Hold-Out Method並不能算是CV,因爲這種方法沒有達到交叉的思想,由於是隨機的將原始數據分組,所以最後驗證集分類準確率的高低與原始數據的分組有很大的關係,所以這種方法得到的結果其實並不具有說服性.

2).K-fold Cross Validation(記爲K-CV)
將原始數據分成K組(一般是均分),將每個子集數據分別做一次驗證集,其餘的K-1組子集數據作爲訓練集,這樣會得到K個模型,用這K個模型最終的驗證集的分類準確率的平均數作爲此K-CV下分類器的性能指標.K一般大於等於2,實際操作時一般從3開始取,只有在原始數據集合數據量小的時候纔會嘗試取2.K-CV可以有效的避免過學習以及欠學習狀態的發生,最後得到的結果也比較具有說服性.

3).Leave-One-Out Cross Validation(記爲LOO-CV)
如果設原始數據有N個樣本,那麼LOO-CV就是N-CV,即每個樣本單獨作爲驗證集,其餘的N-1個樣本作爲訓練集,所以LOO-CV會得到N個模型,用這N個模型最終的驗證集的分類準確率的平均數作爲此下LOO-CV分類器的性能指標.相比於前面的K-CV,LOO-CV有兩個明顯的優點:
①a.每一回閤中幾乎所有的樣本皆用於訓練模型,因此最接近原始樣本的分佈,這樣評估所得的結果比較可靠。
②b.實驗過程中沒有隨機因素會影響實驗數據,確保實驗過程是可以被複制的。

但LOO-CV的缺點則是計算成本高,因爲需要建立的模型數量與原始數據樣本數量相同,當原始數據樣本數量相當多時,LOO-CV在實作上便有困難幾乎就是不顯示,除非每次訓練分類器得到模型的速度很快,或是可以用並行化計算減少計算所需的時間.

參考:交叉驗證(CrossValidation)方法思想簡介

5.3 關於SVM參數c&g選取的總結

選取SVM中參數 c和g的最佳值
尋找最佳c和g的思想仍然是讓c和g在一定的範圍裏跑(比如 c = 2(-5),2(-4),…,2^(5),g = 2(-5),2(-4),…,2^(5)),然後用cross validation的想法找到是的準確率最高的c和g,在這裏做了一點修改是: 因爲會有不同的c和g都對應最高的的準確率,我把具有最小c的那組c和g認爲是最佳的c和g,因爲懲罰參數不能設置 太高,很高的懲罰參數能使得validation數據的準確率提高,但過高的懲罰參數c會造成過學習狀態,往往都是懲罰參數c過高會導致最終測試集合的準確率並不是很理想 。

先大範圍粗糙的找 比較理想的c和g,然後再細範圍找更加理想的c和g.
比如首先讓 c = 2(-5),2(-4),…,2^(5),g = 2(-5),2(-4),…,2^(5)在這個範圍找比較理想的c和g。
此時bestc = 0.5,bestg=1,bestacc = 98.8764[cross validation 的準確率]
最終測試集合的準確率 Accuracy = 96.6292% (86/89) (classification)

6 Libsvm-Faruto Ultimate工具箱

下載:
libsvm-3.1-FarutoUltimate3.1Mcode,faruto最新加強工具箱
參考:
Libsvm-Faruto Ultimate工具箱學習筆記
libsvm-3.1-[FarutoUltimate3.1Mcode]——輔助函數簡介(修改

參考:
學習SVM
SVM學習筆記(1)LIBSVM在matlab下的使用安裝
【svm】使用libsvm分類的一般操作步驟

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章