原作:林弘德
為什么寫這個指南
我一直覺得 SVM 是個很有趣的東西,不過一直沒辦法去聽林智仁老師 的 Data mining與SVM的課,,后來看了一些Internet上的文件,后來聽 kcwu 講了一下 libsvm 的用法后,,就想整理一下,算是對于并不需要知道完整 SVM 理論的人提供使用 libsvm 的入門,。 原始 libsvm 的README跟FAQ也是很好的文件,, 不過你可能要先對 svm 跟流程有點了解后才看得懂 (我在看時有這樣的感覺); 這篇入門就是為了從零開始的人而寫的,。
不過請記得底下可能有些說法不一定對,,但是對于只是想用 SVM 的人來說我覺得這樣說明會比較易懂。這篇入門原則上是給會寫基本程序的人看的,,也是給我自己一個備忘, 不用太多數(shù)學(xué)底子,,也不用對 SVM 有任何預(yù)備知識,。
SVM:什么是SVM,,它能為我們做什么?
SVM, Support Vector Machine , 簡而言之它是個起源與人工神經(jīng)網(wǎng)絡(luò)有點像的東西,現(xiàn)今最常拿來就是做分類,。也就是說,,如果我有一堆已經(jīng)分好類的東西(可是分類的依據(jù)是未知的),那當(dāng)收到新的東西時,,SVM可以預(yù)測新的數(shù)據(jù)要分到哪一堆去,。聽起來是很神奇的事(如果你覺得不神奇,請重想一想這句話代表什么:分類的依據(jù)是未知的,!,,還是不神奇的話就請你寫個程序,解解上面的問題),,不過 SVM 基于統(tǒng)計學(xué)習(xí)理論的,,可以在合理的時間內(nèi)漂亮的解決這個問題。
以圖形化的例子來說明,假定我在空間中標(biāo)了一堆用顏色分類的點, 點的顏色就是它的類別, 位置就是它的數(shù)據(jù), 那 SVM 就可以找出區(qū)隔這些點的程序, 依此就可以分出一個個的區(qū)域; 拿到新的點(數(shù)據(jù)) 時, 只要對照該位置在哪一區(qū)就可以找出它應(yīng)該是哪一顏色(類別)了,。當(dāng)然 SVM 不是真的只有分區(qū)那么簡單, 不過看上面的例子應(yīng)該可以了解 SVM 大概在作什么. 要對 SVM 再多懂一點點,可以參考 cjlin 在 data mining 課的 slides: pdf 或 ps ,。我們可以把 SVM 當(dāng)個黑盒子, 數(shù)據(jù)丟進(jìn)去讓他處理然后我們再來用就好了.
哪里得到SVM?
.zip 跟 .tar.gz 基本上是一樣的, 只是看你的操作系統(tǒng); 習(xí)慣上 Windows 用 .zip 比較方便 (因為有WinZIP, 也有WinRAR), UNIX 則是用 .tar.gz
編譯libsvm
解開來后, 假定是UNIX 系統(tǒng), 直接打 make 就可以了; 編不出來的話請詳讀說明和運用常識. 因為這是指南, 所以我不花時間細(xì)談, 而且編不出來的情形真是少之又少, 通常一定是你的系統(tǒng)有問題,。 其他的子目錄可以不管, 只要 svm-train, svm-scale, svm-predict 三個執(zhí)行文件有就可以了. Windows 的用戶要自己重編當(dāng)然也是可以, 不過已經(jīng)有編好的執(zhí)行文件在里面了: 請檢查 windows 子目錄, 應(yīng)該會有 svmtrain.exe, svmscale.exe, svmpredict.exe, svmtoy.exe.
SVM的使用
libsvm 有很多種用法, 這篇指南只打算講簡單的部分.
程序
svmtrain
訓(xùn)練數(shù)據(jù). 跑SVM被戲稱為 "開火車" 也是由于這個程序名而來. train會接受特定格式的輸入, 產(chǎn)生一個 "Model" 文件. 這個 model 你可以想像成SVM的內(nèi)部數(shù)據(jù),因為預(yù)測要model才能預(yù)測, 不能直接吃原始數(shù)據(jù).想想也很合理,假定 train 本身是很耗時的動作, 而 train可以以某種形式存起內(nèi)部數(shù)據(jù),那下次要預(yù)測時直接把那些內(nèi)部數(shù)據(jù)載入就快多了.
svmpredict
依照已經(jīng)訓(xùn)練好的 model, 再加上給定的輸入(新值), 輸出預(yù)測新值所對應(yīng)的類別.
svmscale
掃描數(shù)據(jù). 因為原始數(shù)據(jù)可能范圍過大或過小, svmscale 可以先將數(shù)據(jù)重新 scale (縮放) 到適當(dāng)范圍使訓(xùn)練與預(yù)測速度更快,。
文件格式要先交代一下. 你可以參考 libsvm 里面附的 "heart_scale": 這是SVM 的輸入文件格式.
[label] [index1]:[value1] [index2]:[value2] ...
[label] [index1]:[value1] [index2]:[value2] ...
一行一條記錄數(shù)據(jù),,如:
+1 1:0.708 2:1 3:1 4:-0.320 5:-0.105 6:-1
label
或說是class, 就是你要分類的種類,,通常是一些整數(shù)。
index
是有順序的索引,,通常是連續(xù)的整數(shù)。
value
就是用來 train 的數(shù)據(jù),,通常是一堆實數(shù)。
每一行都是如上的結(jié)構(gòu), 意思就是: 我有一排數(shù)據(jù), 分別是 value1, value2, .... value, (而且它們的順序已由 index 分別指定),,這排數(shù)據(jù)的分類結(jié)果就是label。
或許你會不太懂,,為什么會是 value1,value2,.... 這樣一排呢? 這牽涉到 SVM 的原理,。 你可以這樣想(我沒說這是正確的), 它的名字就叫 Support "Vector" Machine,, 所以輸入的訓(xùn)練數(shù)據(jù)是 "Vector"(向量), 也就是一排的 x1, x2, x3, ... 這些值就是 value,而 x[n] 的n就是由index 指定,。 這些東西又稱為 "(屬性)attribute"。
真實的情況是,,大部份時候我們給定的數(shù)據(jù)可能有很多 "特征(feature)" 或說 "屬性(attribute)",,所以輸入會是一組的。 舉例來說,,以前面點分區(qū)的例子 來說,我們不是每個點都有 X 跟 Y 的坐標(biāo)嗎,? 所以它就有兩種屬性。 假定我有兩個點: (0,3) 跟 (5,8) 分別在 label(class) 1 跟 2 ,,那就會寫成
1 1:0 2:3 2 1:5 2:8 同理,,空間中的三維坐標(biāo)就等于有三組屬性。這種文件格式最大的好處就是可以使用稀疏矩陣(sparse matrix),, 或說有些 數(shù)據(jù)的屬性可以有缺失,。
運行l(wèi)ibsvm
下來解釋一下libsvm 的程序怎么用,。 你可以先拿 libsvm 附的heart_scale 來做輸入,底下也以它為例:
看到這里你應(yīng)該也了解,,使用 SVM 的流程大概就是:
1. 準(zhǔn)備數(shù)據(jù)并做成指定格式 (有必要時需 svmscale)
2. 用svmtrain 來訓(xùn)練成 model
- 對新的輸入,,使用 svmpredic來預(yù)測新數(shù)據(jù)的類別.
svmtrain
svmtrain 的語法大致就是:
svmtrain [options] training_set_file [model_file]
training_set_file 就是之前的格式,,而 model_file 如果不給就會 叫 [training_set_file].model。 options 可以先不要給,。
下列程序執(zhí)行結(jié)果會產(chǎn)生 heart_scale.model 文件:(螢?zāi)惠敵霾皇呛苤匾?,沒有錯誤就好了)
./svmtrain heart_scale
optimization finished, #iter = 219
nu = 0.431030
obj = -100.877286, rho = 0.424632 nSV = 132, nBSV = 107
Total nSV = 132
svmpredict
svmpredict 的語法是 :
svmpredict test_file model_file output_file
test_file 就是我們要預(yù)測的數(shù)據(jù),。它的格式跟 svmtrain 的輸入,也就是 training_set_file 是一樣的,, 不過每行最前面的 label 可以省略 (因為預(yù)測就是要預(yù)測那個 label)。 但如果 test_file 有 label 的值的話,, predict 完會順便拿 predict 出來的值跟 test_file 里面寫的值去做比對,,這代表: test_file 寫的label是真正的分類結(jié)果,,拿來跟我們預(yù)測的結(jié)果比對就可以知道預(yù)測的效果。所以,,我們可以拿原 training set 當(dāng)做 test_file再丟給 svmpredict 去預(yù)測(因為格式一樣),看看正確率有多高,,方便后面調(diào)參數(shù)。其它參數(shù)就很好理解了: model_file就是 svmtrain 出來的文件,, output_file是存輸出結(jié)果的文件案。 輸出的格式很簡單,,每行一個 label,對應(yīng)到你的 test_file 里面的各行,。下列程序執(zhí)行結(jié)果會產(chǎn)生 heart_scale.out:
./svm-predict heart_scale heart_scale.model heart_scale.out
Accuracy = 86.6667% (234/270) (classification)
Mean squared error = 0.533333 (regression)
Squared correlation coefficient = 0.532639(regression)
我們把原輸入丟回去 predict, 第一行的 Accuracy 就是預(yù)測的正確率了,。如果輸入沒有label 的話,,那就是真的預(yù)測了,??吹竭@里,,基本上你應(yīng)該已經(jīng)可以利用 svm 來作事了: 你只要寫程序輸出正確格式的數(shù)據(jù),交給 svm 去 train,, 后來再 predict 并讀入結(jié)果即可,。
Advanced Topics
后面可以說是一些稍微進(jìn)階的部份,我可能不會講的很清楚,,因為我的重點是想表達(dá)一些觀念和解釋一些你看相關(guān)文件時很容易碰到的名詞,。
Scaling
svm-scale 目前不太好用,不過它有其必要性,。因為適當(dāng)?shù)?/span>掃描有助于參數(shù)的選擇,,還有解svm的速度。svmscale 會對每個屬性做掃描,。 范圍用 -l, -u 指定,,通常是[0,1]或是[-1,1]。 輸出在 stdout,。另外要注意的(常常會忘記)是 testing data 和 training data要一起掃描,。而 svm-scale 最難用的地方就是沒辦法指定 testing data/training data(不同文件) 然后一起掃描。
Arguments
前面提到,,在train的時候可以使用一些參數(shù),。(直接執(zhí)行 svm-train 不指定輸入文件與參數(shù)會列出所有參數(shù)及語法說明) 這些參數(shù)對應(yīng)到原始 SVM 公式的一些參數(shù),所以會影響預(yù)測的正確與否,。
舉例來說,,改個 c=10: ./svm-train -c 10 heart_scale 再來預(yù)測 ,正確率馬上變成 92.2% (249/270),。
Cross Validation
一般而言, SVM 使用的方式(在決定參數(shù)時)常是這樣:
1. 先有已分好類的一堆數(shù)據(jù)
2. 隨機(jī)拆成好幾組訓(xùn)練集
- 用某組參數(shù)去訓(xùn)練并預(yù)測別組,看正確率
- 正確率不夠的話,,換參數(shù)再重復(fù)訓(xùn)練/預(yù)測
等找到一組不錯的參數(shù)后,就拿這組參數(shù)來建model并用來做最后對未知數(shù)據(jù)的預(yù)測,。 這整個過程叫cross validation , 也就是交叉比對,。 在我們找參數(shù)的過程中,可以利用 svmtrain 的內(nèi)建交叉比對功能來幫忙:
-v n: n-fold cross validation n 就是要拆成幾組,,像 n=3 就會拆成三組,然后先拿 1跟2來訓(xùn)練并預(yù)測 3 以得到正確率,; 再來拿 2跟 3 訓(xùn)練并預(yù)測1,最后 1,3 訓(xùn)練并預(yù)測2,。其它以此類推,。如果沒有交叉比對的話,,很容易找到只在特定輸入時好的參數(shù),。像前面我們 c=10 得到 92.2%,,不過拿 -v 5 來看看:
./svm-train -v 5 -c 10 heart_scale
Cross Validation Accuracy = 80.3704%
平均之后才只有 80.37%,,比一開始的 86 還差,。
What arguments rules?
通常而言,比較重要的參數(shù)是 gamma (-g) 跟 cost (-c) ,。而交叉比對 (-v) 的參數(shù)常用 5。cost 預(yù)設(shè)值是 1, gamma 預(yù)設(shè)值是 1/k ,,k 等于輸入數(shù)據(jù)條數(shù),。 那我們怎么知道要用多少來當(dāng)參數(shù)呢,?
TRY就是嘗試找比較好的參數(shù)值。 Try 參數(shù)的過程是用指數(shù)增長的方式來增加與減少參數(shù)的數(shù)值,,也就是 2^n (2 的 n 次方)。因為有兩組參數(shù),,所以等于要嘗試 n*n=n^2 次,。 這個過程是不連續(xù)的成長,,所以可以想象成我們在一個 X-Y 平面上指定的范圍內(nèi)找一群格子點 (grid,,如果你不太明白,想成方格紙或我們把平面上所有整數(shù)交點都打個點,,就是那樣),每個格子點的 X 跟 Y 經(jīng)過換算 (如 2^x, 2^y) 就拿去當(dāng) cost 跟 gamma 的值來交叉比對。所以現(xiàn)在你應(yīng)該懂得 libsvm 的 python 子目錄下面有個 grid.py 是做啥的了: 它把上面的過程自動化,, 在你給定的范圍內(nèi)呼叫svm-train去嘗試所有的參數(shù)值。grid.py 還會把結(jié)果繪制出來,,方便你尋找參數(shù),。 libsvm 有很多跟 python 結(jié)合的部份,,由此可見 python 是強(qiáng)大方便的工具,。很多神奇的功能,,像自動登入多臺機(jī)器去平行跑 grid等等都是python幫忙的,。不過 SVM 本身可以完全不需要python,,只是會比較方便,。跑 grid (基本上用 grid.py 跑當(dāng)然是最方便,不過如果你不懂python而且覺得很難搞,,那你要自己產(chǎn)生參數(shù)來跑也是可以的)通常好的范圍是 [c,g]=[2^-10,2^10]*[2^-10,2^10]另外其實 grid 用 [-8,8] 也很夠了。
Regression(衰減)
另一個值得一提的是regression(衰減),。 簡單來說,前面都是拿 SVM 來做分類,所以label的值都是離散的數(shù)據(jù),、或說已知的固定值,。而 regression 則是求連續(xù)的值,、或說未知的值。你也可以說,,一般是二分類問題, 而 regression是可以預(yù)測一個實數(shù)。
比如說我知道股市指數(shù)受到某些因素影響, 然后我想預(yù)測股市,。股市的指數(shù)就是我們的 label, 那些因素量化以后變成屬性。 以后收集那些屬性給 SVM 它就會 預(yù)測出指數(shù)(可能是沒出現(xiàn)過的數(shù)字),,這就要用 regression,。那對于開獎的號碼呢,?因為都是固定已知的數(shù)字,很明顯我們應(yīng)該用一般SVM的分類來預(yù)測 ,。 (註這是真實的例子 --llwang就寫過這樣的東西) 所以說 label 也要掃描, 用 svm-scale -y lower upper但是比較糟糕的情況是grid.py不支持regression,而且較差對比對 regression 也常常不是很有效,。
總而言之,regression 是非常有趣的東西,,不過也是比較高級的用法。 在這里我們不細(xì)談了,,有興趣的人請再參考SVM與libsvm的其它文件,。
尾聲
到此我已經(jīng)簡單的說明了 libsvm 的使用方式,, 更完整的用法請參考 libsvm 的說明跟 cjlin 的網(wǎng)站,、。對于 SVM 的新手來說,, libsvmtools 有很多好東西,。像 SVM for dummies 就是很方便觀察 libsvm 流程的東西。
|