libSVM介绍
? ?轉(zhuǎn)自:http://blog.csdn.net/carson2005/article/details/6539192
?? 鑒于libSVM中的readme文件有點(diǎn)長,而且,都是采用英文書寫,這里,我把其中重要的內(nèi)容提煉出來,并給出相應(yīng)的例子來說明其用法,大家可以直接參考我的代碼來調(diào)用libSVM庫。
第一部分,利用libSVM自帶的簡易工具來演示SVM的兩類分類過程。(以下內(nèi)容只是利用libSVM自帶的一個簡易的工具供大家更好的理解SVM,如果你對SVM已經(jīng)有了一定的了解,可以直接跳過這部分內(nèi)容)
首先,你要了解的是libSVM只是眾多SVM實(shí)現(xiàn)版本中的其中之一。而SVM是一種進(jìn)行兩類分類的分類器,在libSVM最新版(libSVM3.1)里面,已經(jīng)自帶了簡單的工具,可以對二分類進(jìn)行演示。以windows平臺為例,將libSVM.zip解壓之后,有一個名為windows的子文件夾,里面有一個名為svm-toy.exe的可執(zhí)行文件。直接雙擊,運(yùn)行該可執(zhí)行文件,顯示如下的界面
點(diǎn)擊第二個按鈕“Run”,然后,在左上部分,用鼠標(biāo)左鍵隨機(jī)點(diǎn)幾下,代表你選擇的第一類模式的數(shù)據(jù)分布,下圖是我隨即點(diǎn)了幾下的結(jié)果:
之后,點(diǎn)擊“Change”,接著,用鼠標(biāo)左鍵在窗口右下方隨便點(diǎn)擊幾下,代表你選擇的第二類模式的數(shù)據(jù)分布,如下圖所示:
接著,點(diǎn)擊“Run”,libSVM就幫你把這兩類模式分開了,并用兩種不同的顏色區(qū)域來代表兩類不同的模式,如下圖所示:
圖中左上方紫色的區(qū)域,是第一類模式所在的區(qū)域,右下方的藍(lán)色區(qū)域,是你選擇的第二類模式所在的的區(qū)域,而兩者的分界面,也就是SVM的最優(yōu)分類面。當(dāng)然,SVM是通過核函數(shù)將原始數(shù)據(jù)映射到高維空間,在高維空間進(jìn)行線性分類。換句話說,在高維空間,這兩類數(shù)據(jù)應(yīng)該是線性可分的,即:最優(yōu)分類面應(yīng)該是一條直線,而這里看到的,是將高維空間分類的結(jié)果又映射回原始空間所呈現(xiàn)的分類結(jié)果,即:非線性的分類面。細(xì)心的朋友可能已經(jīng)發(fā)現(xiàn),在上述界面的右下角,有一個編輯框,里面寫著“-t?2?-c?100”,顯然,這是libSVM的一些參數(shù),你也可以試著更改這些參數(shù),來選擇不同的核函數(shù)、不同的SVM類型等來達(dá)到最好的分類效果。
?
第二部分:libSVM中的小工具
libSVM中包含以下可執(zhí)行程序文件(小工具):
(1)svm-scale:一個用于對輸入數(shù)據(jù)進(jìn)行歸一化的簡易工具
(2)svm-toy:一個帶有圖形界面的交互式SVM二分類功能演示小工具;
(3)svm-train:對用戶輸入的數(shù)據(jù)進(jìn)行SVM訓(xùn)練。其中,訓(xùn)練數(shù)據(jù)是按照以下格式輸入的:
<類別號>?<索引1>:<特征值1>?<索引2>:<特征值2>...
(4)svm-predict:根據(jù)SVM訓(xùn)練得到的模型,對輸入數(shù)據(jù)進(jìn)行預(yù)測,即分類。
?
第三部分:libSVM用法介紹:`
? ? ? libSVM的所有函數(shù)申明及結(jié)構(gòu)體定義均包含在libSVM.h文件當(dāng)中,在使用過程中,你必須要包含該頭文件,并且,對libSVM.cpp進(jìn)行相應(yīng)的鏈接。在對libSVM中的函數(shù)用法進(jìn)行詳細(xì)介紹之前,我們不妨先簡單了解一下libSVM.h中一些結(jié)構(gòu)體的含義。
struct?svm_node
{
int?index;
double?value;
};
該結(jié)構(gòu)體,定義了一個“SVM節(jié)點(diǎn)”,即:索引i及其所對應(yīng)的第i個特征值。這樣n個相同類別號的SVM節(jié)點(diǎn),就構(gòu)成了一個SVM輸入向量。即:一個SVM輸入向量可以表示為如下的形式:
類別標(biāo)簽?索引1:特征值1?索引2:特征值2?索引3:特征值3...
我們可以將若干個這樣的輸入向量輸入到libSVM進(jìn)行訓(xùn)練,或者,輸入一個類別標(biāo)簽未知的向量對其進(jìn)行預(yù)測。
struct?svm_problem
{
int?l;
double?*y;
struct?svm_node?**x;
};
該結(jié)構(gòu)體中的l代表訓(xùn)練樣本的個數(shù);double型指針y代表l個訓(xùn)練樣本中每個訓(xùn)練樣本的類別號,也就是我們常說的“標(biāo)簽”;而"SVM節(jié)點(diǎn)"x,則是一個指針的指針(如果你對指針的指針不熟悉,完全可以把x理解為一個矩陣),x所指向的內(nèi)容就是所有訓(xùn)練樣本所有的特征值數(shù)據(jù)。
假如我們有下面的訓(xùn)練樣本數(shù)據(jù):
類別標(biāo)簽 ??特征值1? 特征值2 特征值3 特征值4 特征值5
???1 ??? ??0 ????0.1 ????0.2 ?????0 ??????0
???2 ?????0 ????0.1 ????0.3 ????-1.2 ??????0
???1 ???????0.4 ?????0 ?????0 ?????0 ??????0
???2 ?????0 ????0.1 ??????0 ?????1.4 ?????0.5
??1 ???-0.1 ???-0.2 ??????0.1 ?????1.1 ?????0.1
那么,svm_problem結(jié)構(gòu)體中的l=5(共有5個訓(xùn)練樣本),y=[1,2,1,2,1];指針x所指向的內(nèi)容可以視為5個行向量,每個行向量有5列,即:x指代一個5*5的矩陣,其值為:
(1,0)(2,0.1)(3,0.2)(4,0)(5,0)(-1,?)
(1,0)(2,0.1)(3,0.3)(4,-1.2)(5,0)(-1,?)
(1,0.4)(2,0)(3,0)(4,0)(5,0)(-1,?)
(1,0)(2,0.1)(3,0)(4,1.4)(5,0.5)(-1,?)
(1,-0.1)(2,-0.2)(3,0.1)(4,1.1)(5,0.1)(-1,?)?
需要提醒的是,這里,每一行最后一列都是以“-1”開頭,這是libSVM規(guī)定的特征值向量的結(jié)束標(biāo)識;此外,索引應(yīng)該按照升序方式進(jìn)行排列。
???????
enum?{?C_SVC,?NU_SVC,?ONE_CLASS,?EPSILON_SVR,?NU_SVR?};//libSVM規(guī)定的SVM類型
?
enum?{?LINEAR,?POLY,?RBF,?SIGMOID,?PRECOMPUTED?};//libSVM規(guī)定的核函數(shù)的類型
?
struct?svm_parameter
{
int?svm_type;//取值為前面提到的枚舉類型中的值
int?kernel_type;//取值為前面提到的枚舉類型中的值
int?degree; //用于多項(xiàng)式核函數(shù)/
double?gamma;//用于多項(xiàng)式、徑向基、S型核函數(shù)
???double?coef0;//用于多項(xiàng)式和S型核函數(shù)
?
/*?以下參數(shù)僅僅用于訓(xùn)練階段?*/
double?cache_size;?//核緩存大小,以MB為單位
double?eps; //誤差精度小于eps時,停止訓(xùn)練
double?C; //用于C_SVC,EPSILON_SVR,NU_SVR
int?nr_weight; //用于C_SVC
int?*weight_label;//用于C_SVC
double*?weight;//用于C_SVC
double?nu;//用于NU_SVC,ONE_CLASS,NU_SVR
double?p;//用于EPSILON_SVR
int?shrinking; //等于1代表執(zhí)行啟發(fā)式收縮
int?probability;//等于1代表模型的分布概率已知
};
該結(jié)構(gòu)體定義了libSVM中的用到的SVM參數(shù)。其中svm_type可以是C_SVC,?NU_SVC,?ONE_CLASS,?EPSILON_SVR,?NU_SVR中的任意一種,代表著SVM的類型;
C_SVC: C-SVM?classification
????NU_SVC: nu-SVM?classification
????ONE_CLASS: one-class-SVM
????EPSILON_SVR: epsilon-SVM?regression
????NU_SVR: nu-SVM?regression
kernel_type可以是LINEAR,?POLY,?RBF,?SIGMOID中的一種,代表著核函數(shù)的類型;
LINEAR: u'*v,線性核函數(shù);
????POLY: (gamma*u'*v?+?coef0)^degree,多項(xiàng)式核函數(shù);
????RBF: exp(-gamma*|u-v|^2),徑向基核函數(shù);
????SIGMOID: tanh(gamma*u'*v?+?coef0),S型核函數(shù);
PRECOMPUTED:?kernel?values?in?training_set_file,自定義的核函數(shù);
nr_weight,?weight_label,?and?weight這三個參數(shù)用于改變某些類的懲罰因子。當(dāng)輸入數(shù)據(jù)不平衡,或者誤分類的風(fēng)險代價不對稱的時候,這三個參數(shù)將會對樣本訓(xùn)練起到非常重要的調(diào)節(jié)作用。
nr_weight是weight_label和weight的元素個數(shù),或者稱之為維數(shù)。Weight[i]與weight_label[i]之間是一一對應(yīng)的,weight[i]代表著類別weight_label[i]的懲罰因子的系數(shù)是weight[i]。如果你不想設(shè)置懲罰因子,直接把nr_weight設(shè)置為0即可。
為了防止錯誤的參數(shù)設(shè)置,你還可以調(diào)用libSVM提供的接口函數(shù)svm_check_parameter()來對輸入?yún)?shù)進(jìn)行檢查。
?
????在使用libSVM進(jìn)行分類之前,你需要通過樣本學(xué)習(xí),構(gòu)建一個SVM分類模型。該分類模型也可以理解為生成一些用于分類的“數(shù)據(jù)”。當(dāng)然,構(gòu)建的分類模型需要保存為文件,以便后續(xù)使用。用于libSVM訓(xùn)練的函數(shù),其申明如下所示:
struct?svm_model?*svm_train(const?struct?svm_problem?*prob,?const?struct?svm_parameter?*param);
顯然,該函數(shù)的輸入,就是svm_problem結(jié)構(gòu)體的prob指針?biāo)赶虻膬?nèi)容。該結(jié)構(gòu)體在前面已經(jīng)介紹過,其內(nèi)部,不僅包含了訓(xùn)練樣本的個數(shù),還包含每個訓(xùn)練樣本的“標(biāo)簽”及該訓(xùn)練樣本對應(yīng)的特征數(shù)據(jù)。而svm_parameter類型的param指針則指定了libSVM所用到的諸如SVM類型,核函數(shù)類型,懲罰因子之類的參數(shù)。另外,該函數(shù)的返回值是一個svm_model結(jié)構(gòu)體,該結(jié)構(gòu)體的定義,在libSVM.cpp當(dāng)中:
struct?svm_model
{
svm_parameter?param; //SVM參數(shù)設(shè)置
int?nr_class; //類別數(shù)量,對于regression和ne-class?SVM這兩種情況,該值為2
int?l; //支持向量的個數(shù)
svm_node?**SV; //支持向量
double?**sv_coef; //用于決策函數(shù)的支持向量系數(shù)
double?*rho; //決策函數(shù)中的常數(shù)項(xiàng)
double?*probA; //?pariwise?probability?information
double?*probB;
?
//?for?classification?only
?
int?*label; //?每個類類別標(biāo)簽
int?*nSV; //每個類的支持向量個數(shù)
int?free_sv; //如果svm_model已經(jīng)通過svm_load_model創(chuàng)建,則該值為1;如果svm_model是通過svm_train創(chuàng)建的,該值為0
};
需要提醒的是,libSVM支持多類分類問題,當(dāng)有k個待分類問題時,libSVM構(gòu)建k*(k-1)/2種分類模型來進(jìn)行分類,即:libSVM采用一對一的方式來構(gòu)建多類分類器,如下所示:
1?vs?2,?1?vs?3,?...,?1?vs?k,?2?vs?3,?...,?2?vs?k,?...,?k-1?vs?k。
用戶在得到SVM分類模型之后,需要將其進(jìn)行保存。在這里,libSVM已經(jīng)提供了相應(yīng)的函數(shù)接口:
int?svm_save_model(const?char?*model_file_name,?const?struct?svm_model?*model);
在調(diào)用訓(xùn)練函數(shù)之后,只需要指定保存位置,直接調(diào)用該函數(shù),就可以進(jìn)行相應(yīng)的保存。
在對樣本進(jìn)行訓(xùn)練得到分類模型之后,就可以利用該分類模型對未知輸入數(shù)據(jù)進(jìn)行類別判斷了,也就是我們常說的“預(yù)測”。用于libSVM預(yù)測的函數(shù),其申明如下所示:
double?svm_predict(const?struct?svm_model?*model,?const?struct?svm_node?*x);
該函數(shù)的第一個參數(shù)就是利用樣本訓(xùn)練得到的SVM分類模型,第二個參數(shù),是輸入的未知模式的特征數(shù)據(jù),即:得到了表征某一類別的特征數(shù)據(jù),根據(jù)這些數(shù)據(jù),來判斷它所對應(yīng)的類別標(biāo)簽。而SVM分類模型,可以由libSVM定義的下面這個接口函數(shù)來進(jìn)行加載:
struct?svm_model?*svm_load_model(const?char?*model_file_name);
此外,在使用上述函數(shù)過程中,需要對svm_model及svm_parameter申請內(nèi)存,而不使用它們的時候,用戶需要調(diào)用以下兩個函數(shù)進(jìn)行內(nèi)存釋放:
void?svm_destroy_model(struct?svm_model?*model);
void?svm_destroy_param(struct?svm_parameter?*param);
總結(jié)
- 上一篇: c++ DirectShow播放任意格式
- 下一篇: libsvm 使用介绍