开源SVM库libSVM介绍
一、libSVM簡(jiǎn)介
libSVM是臺(tái)灣大學(xué)林智仁教授等研究人員開(kāi)發(fā)的一個(gè)用于支持向量機(jī)分類,回歸分析及分布估計(jì)的c/c++開(kāi)源庫(kù)。另外,它也可以用于解決多類分類問(wèn)題。?libSVM最新的版本是2011年4月發(fā)布的3.1版。林智仁教授設(shè)計(jì)開(kāi)發(fā)該SVM庫(kù)的目的是為了讓其它非專業(yè)人士可以更加方便快捷的使用SVM這個(gè)統(tǒng)計(jì)學(xué)習(xí)工具。libSVM提供了一些簡(jiǎn)單易用的接口,從而使得用戶可以方便的使用,而不必關(guān)心其內(nèi)部復(fù)雜的數(shù)學(xué)模型和運(yùn)算過(guò)程。libSVM的主要特點(diǎn)有:
(1)各種SVM的表達(dá)公式;
(2)有效的多類分類能力;
(3)交叉驗(yàn)證功能;
(4)各種核函數(shù),包括預(yù)先計(jì)算得到的核矩陣;
(5)用于非平衡數(shù)據(jù)的加權(quán)svm;
(6)提供c++和java源代碼;
(7)用于演示SVM分類與回歸能力的GUI界面;
.....
很多初學(xué)者往往按照以下的步驟使用libSVM:
(1)將數(shù)據(jù)轉(zhuǎn)換到libSVM指定的格式;
(2)隨機(jī)選擇一個(gè)核函數(shù)和一些參數(shù);
(3)測(cè)試;
這種方法雖然可行,但卻不一定能很快達(dá)到好的效果。為此,林智仁教授推薦按照以下的步驟來(lái)使用libSVM:
(1)將數(shù)據(jù)轉(zhuǎn)換到libSVM指定的格式;
(2)對(duì)數(shù)據(jù)進(jìn)行尺度操作(一般指數(shù)據(jù)的歸一化);
(3)考慮RBF(徑向基)核函數(shù);
(4)利用交叉驗(yàn)證來(lái)得到最好的參數(shù)C和r;
(5)用最好的C和r來(lái)訓(xùn)練所有訓(xùn)練集合;
(6)測(cè)試;
之所以推薦首選徑向基核函數(shù),是由于該核可以將數(shù)據(jù)非線性地映射到高維空間,而且,它還能處理那種特征(數(shù)據(jù))及其屬性之間呈現(xiàn)非線性關(guān)系的情況,而線性核函數(shù)只是徑向基核函數(shù)的一個(gè)特例。另外,相比而言,多項(xiàng)式核函數(shù)在高維空間有著更多的參數(shù),從而使得模型更加復(fù)雜。同時(shí),需要提醒的是,徑向基核函數(shù)并非萬(wàn)能的,尤其當(dāng)特征數(shù)據(jù)的數(shù)值本身比較大的時(shí)候,線性核函數(shù)要更實(shí)用一些。
任何人可以在http://www.csie.ntu.edu.tw/~cjlin/libsvm?來(lái)下載libSVM開(kāi)源庫(kù)。不過(guò),按照開(kāi)發(fā)者的要求,在使用之前,請(qǐng)務(wù)必閱讀其copyright,并按照其要求進(jìn)行相應(yīng)的引用和說(shuō)明。另外,在使用之前,強(qiáng)烈推薦大家閱讀libSVM.zip里面的readme文件。該文件詳細(xì)描述了libSVM的使用方法及注意事項(xiàng)。
二、詳細(xì)介紹
鑒于libSVM中的readme文件有點(diǎn)長(zhǎng),而且,都是采用英文書寫,這里,我把其中重要的內(nèi)容提煉出來(lái),并給出相應(yīng)的例子來(lái)說(shuō)明其用法,大家可以直接參考我的代碼來(lái)調(diào)用libSVM庫(kù)。
第一部分,利用libSVM自帶的簡(jiǎn)易工具來(lái)演示SVM的兩類分類過(guò)程。(以下內(nèi)容只是利用libSVM自帶的一個(gè)簡(jiǎn)易的工具供大家更好的理解SVM,如果你對(duì)SVM已經(jīng)有了一定的了解,可以直接跳過(guò)這部分內(nèi)容)
首先,你要了解的是libSVM只是眾多SVM實(shí)現(xiàn)版本中的其中之一。而SVM是一種進(jìn)行兩類分類的分類器,在libSVM最新版(libSVM3.1)里面,已經(jīng)自帶了簡(jiǎn)單的工具,可以對(duì)二分類進(jìn)行演示。以windows平臺(tái)為例,將libSVM.zip解壓之后,有一個(gè)名為windows的子文件夾,里面有一個(gè)名為svm-toy.exe的可執(zhí)行文件。直接雙擊,運(yùn)行該可執(zhí)行文件,顯示如下的界面
點(diǎn)擊第二個(gè)按鈕“Run”,然后,在左上部分,用鼠標(biāo)左鍵隨機(jī)點(diǎn)幾下,代表你選擇的第一類模式的數(shù)據(jù)分布,下圖是我隨即點(diǎn)了幾下的結(jié)果:
之后,點(diǎn)擊“Change”,接著,用鼠標(biāo)左鍵在窗口右下方隨便點(diǎn)擊幾下,代表你選擇的第二類模式的數(shù)據(jù)分布,如下圖所示:
接著,點(diǎn)擊“Run”,libSVM就幫你把這兩類模式分開(kāi)了,并用兩種不同的顏色區(qū)域來(lái)代表兩類不同的模式,如下圖所示:
圖中左上方紫色的區(qū)域,是第一類模式所在的區(qū)域,右下方的藍(lán)色區(qū)域,是你選擇的第二類模式所在的的區(qū)域,而兩者的分界面,也就是SVM的最優(yōu)分類面。當(dāng)然,SVM是通過(guò)核函數(shù)將原始數(shù)據(jù)映射到高維空間,在高維空間進(jìn)行線性分類。換句話說(shuō),在高維空間,這兩類數(shù)據(jù)應(yīng)該是線性可分的,即:最優(yōu)分類面應(yīng)該是一條直線,而這里看到的,是將高維空間分類的結(jié)果又映射回原始空間所呈現(xiàn)的分類結(jié)果,即:非線性的分類面。細(xì)心的朋友可能已經(jīng)發(fā)現(xiàn),在上述界面的右下角,有一個(gè)編輯框,里面寫著“-t?2?-c?100”,顯然,這是libSVM的一些參數(shù),你也可以試著更改這些參數(shù),來(lái)選擇不同的核函數(shù)、不同的SVM類型等來(lái)達(dá)到最好的分類效果。
?
第二部分:libSVM中的小工具
libSVM中包含以下可執(zhí)行程序文件(小工具):
(1)svm-scale:一個(gè)用于對(duì)輸入數(shù)據(jù)進(jìn)行歸一化的簡(jiǎn)易工具
(2)svm-toy:一個(gè)帶有圖形界面的交互式SVM二分類功能演示小工具;
(3)svm-train:對(duì)用戶輸入的數(shù)據(jù)進(jìn)行SVM訓(xùn)練。其中,訓(xùn)練數(shù)據(jù)是按照以下格式輸入的:
<類別號(hào)>?<索引1>:<特征值1>?<索引2>:<特征值2>...
(4)svm-predict:根據(jù)SVM訓(xùn)練得到的模型,對(duì)輸入數(shù)據(jù)進(jìn)行預(yù)測(cè),即分類。
?
第三部分:libSVM用法介紹:`
? ? ? libSVM的所有函數(shù)申明及結(jié)構(gòu)體定義均包含在libSVM.h文件當(dāng)中,在使用過(guò)程中,你必須要包含該頭文件,并且,對(duì)libSVM.cpp進(jìn)行相應(yīng)的鏈接。在對(duì)libSVM中的函數(shù)用法進(jìn)行詳細(xì)介紹之前,我們不妨先簡(jiǎn)單了解一下libSVM.h中一些結(jié)構(gòu)體的含義。
struct?svm_node
{
int?index;
double?value;
};
該結(jié)構(gòu)體,定義了一個(gè)“SVM節(jié)點(diǎn)”,即:索引i及其所對(duì)應(yīng)的第i個(gè)特征值。這樣n個(gè)相同類別號(hào)的SVM節(jié)點(diǎn),就構(gòu)成了一個(gè)SVM輸入向量。即:一個(gè)SVM輸入向量可以表示為如下的形式:
類別標(biāo)簽?索引1:特征值1?索引2:特征值2?索引3:特征值3...
我們可以將若干個(gè)這樣的輸入向量輸入到libSVM進(jìn)行訓(xùn)練,或者,輸入一個(gè)類別標(biāo)簽未知的向量對(duì)其進(jìn)行預(yù)測(cè)。
struct?svm_problem
{
int?l;
double?*y;
struct?svm_node?**x;
};
該結(jié)構(gòu)體中的l代表訓(xùn)練樣本的個(gè)數(shù);double型指針y代表l個(gè)訓(xùn)練樣本中每個(gè)訓(xùn)練樣本的類別號(hào),也就是我們常說(shuō)的“標(biāo)簽”;而"SVM節(jié)點(diǎn)"x,則是一個(gè)指針的指針(如果你對(duì)指針的指針不熟悉,完全可以把x理解為一個(gè)矩陣),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個(gè)訓(xùn)練樣本),y=[1,2,1,2,1];指針x所指向的內(nèi)容可以視為5個(gè)行向量,每個(gè)行向量有5列,即:x指代一個(gè)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”開(kāi)頭,這是libSVM規(guī)定的特征值向量的結(jié)束標(biāo)識(shí);此外,索引應(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時(shí),停止訓(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這三個(gè)參數(shù)用于改變某些類的懲罰因子。當(dāng)輸入數(shù)據(jù)不平衡,或者誤分類的風(fēng)險(xiǎn)代價(jià)不對(duì)稱的時(shí)候,這三個(gè)參數(shù)將會(huì)對(duì)樣本訓(xùn)練起到非常重要的調(diào)節(jié)作用。
nr_weight是weight_label和weight的元素個(gè)數(shù),或者稱之為維數(shù)。Weight[i]與weight_label[i]之間是一一對(duì)應(yīng)的,weight[i]代表著類別weight_label[i]的懲罰因子的系數(shù)是weight[i]。如果你不想設(shè)置懲罰因子,直接把nr_weight設(shè)置為0即可。
為了防止錯(cuò)誤的參數(shù)設(shè)置,你還可以調(diào)用libSVM提供的接口函數(shù)svm_check_parameter()來(lái)對(duì)輸入?yún)?shù)進(jìn)行檢查。
?
????在使用libSVM進(jìn)行分類之前,你需要通過(guò)樣本學(xué)習(xí),構(gòu)建一個(gè)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)介紹過(guò),其內(nèi)部,不僅包含了訓(xùn)練樣本的個(gè)數(shù),還包含每個(gè)訓(xùn)練樣本的“標(biāo)簽”及該訓(xùn)練樣本對(duì)應(yīng)的特征數(shù)據(jù)。而svm_parameter類型的param指針則指定了libSVM所用到的諸如SVM類型,核函數(shù)類型,懲罰因子之類的參數(shù)。另外,該函數(shù)的返回值是一個(gè)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ù)量,對(duì)于regression和ne-class?SVM這兩種情況,該值為2
int?l; //支持向量的個(gè)數(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; //?每個(gè)類類別標(biāo)簽
int?*nSV; //每個(gè)類的支持向量個(gè)數(shù)
int?free_sv; //如果svm_model已經(jīng)通過(guò)svm_load_model創(chuàng)建,則該值為1;如果svm_model是通過(guò)svm_train創(chuàng)建的,該值為0
};
需要提醒的是,libSVM支持多類分類問(wèn)題,當(dāng)有k個(gè)待分類問(wèn)題時(shí),libSVM構(gòu)建k*(k-1)/2種分類模型來(lái)進(jìn)行分類,即:libSVM采用一對(duì)一的方式來(lái)構(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)的保存。
在對(duì)樣本進(jìn)行訓(xùn)練得到分類模型之后,就可以利用該分類模型對(duì)未知輸入數(shù)據(jù)進(jìn)行類別判斷了,也就是我們常說(shuō)的“預(yù)測(cè)”。用于libSVM預(yù)測(cè)的函數(shù),其申明如下所示:
double?svm_predict(const?struct?svm_model?*model,?const?struct?svm_node?*x);
該函數(shù)的第一個(gè)參數(shù)就是利用樣本訓(xùn)練得到的SVM分類模型,第二個(gè)參數(shù),是輸入的未知模式的特征數(shù)據(jù),即:得到了表征某一類別的特征數(shù)據(jù),根據(jù)這些數(shù)據(jù),來(lái)判斷它所對(duì)應(yīng)的類別標(biāo)簽。而SVM分類模型,可以由libSVM定義的下面這個(gè)接口函數(shù)來(lái)進(jìn)行加載:
struct?svm_model?*svm_load_model(const?char?*model_file_name);
此外,在使用上述函數(shù)過(guò)程中,需要對(duì)svm_model及svm_parameter申請(qǐng)內(nèi)存,而不使用它們的時(shí)候,用戶需要調(diào)用以下兩個(gè)函數(shù)進(jìn)行內(nèi)存釋放:
void?svm_destroy_model(struct?svm_model?*model);
void?svm_destroy_param(struct?svm_parameter?*param);
出處:http://blog.csdn.net/carson2005/article/details/6539192
總結(jié)
以上是生活随笔為你收集整理的开源SVM库libSVM介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 谈一下OpenCV
- 下一篇: libSVM应用举例