注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

有情况

学会慢生活,拥有平常心……

 
 
 

日志

 
 

SVM简单使用教程(一)  

2011-06-22 10:02:06|  分类: 编程相关 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
我一直觉得 SVM 是个很有趣的东西,不过也一直没办法 (mostly 衝堂) 去听林智仁老师 的 Data mining 跟 SVM 的课; 后来看了一些网路上的文件跟听 kcwu 讲了一下 libsvm 的用法后,就想整理一下,算是对於并不需要知道完整 SVM 理论的人提供使用 libsvm 的入门。 原始 libsvm 的 README 跟 FAQ 也是很好的文件, 不过你可能要先对 svm 跟流程有点了解才看得懂 (我在看时有这样的感觉); 这篇入门就是為了从零开始的人而写的。后来还有一些人提供意见,所以在此感谢!

不过请记得底下可能有些说法不一定对,但是对於只是想用 SVM 的人来说我觉得这样说明会比较易懂。 这篇入门原则上是给会写基本程式的人看的,也是给我自己一个备忘, 不用太多数学底子,也不用对 SVM 有任何先备知识。

还看不懂的话有三个情形, 一是我讲的不够清楚, 二是你的常识不足, 三是你是小白 ^_^; 我自己是以完全不懂的角度开始的,这篇入门也有不少一样不懂 SVM 的人 看过、而且看完多半都有一定程度的理解,所以假设情况一不会发生, 那如果不懂一定是后两个情况 :P 也所以, 有问题别问我。

SVM, Support Vector Machine , 简而言之它是个起源跟类神经网路有点像的东西, 不过现今最常拿来就是做分类 (classification)。 也就是说,如果我有一堆已经分好类的东西 (可是分类的依据是未知的!) ,那当收到新的东西时, SVM 可以预测 (predict) 新的资料要分到哪一堆去。

听起来是很神奇的事(如果你觉得不神奇,请重想一想这句话代表什麼: 分类的依据是未知的!,还是不神奇的话就请你写个程式 解解看这个问题), 也很像要 AI 之类的高等技巧... 不过 SVM 基於 统计学习理论 可以在合理的时间内漂亮的解决这个问题。

以图形化的例子来说明(by SVMToy), 像假定我在空间中标了一堆用顏色分类的点, 点的顏色就是他的类别, 位置就是他的资料, 那 SVM 就可以找出区隔这些点的方程式, 依此就可以分出一区区的区域; 拿到新的点(资料) 时, 只要对照该位置在哪一区就可以(predict) 找出他应该是哪一顏色(类别)了:

原始资料分布

SVM找出来的区域

当然 SVM 不是真的只有画图分区那麼简单, 不过看上面的例子应该可以了解 SVM 大概在作什么。要对 SVM 再多懂一点点,可以参考 cjlin 在 data mining 课的 slides: pdf or ps 。 底下我试著在不用看那个 slide 的情况 解释及使用 libsvm。

所以, 我们可以把 SVM 当个黑盒子, 资料丢进去让他处理然后我们再来用就好了.

林智仁(cjlin)老师的 libsvm 当然是最完美的工具.

libsvm 有很多种用法, 这篇 tutorial 只打算讲简单的部分.

解释一下几个主要执行档的作用: (UNIX/Windows 下档名稍有不同, 请用常识理解我在讲哪个)

svmtrain

Train (训练) data. 跑 SVM 被戏称為 "开火车" 也是由於这个程式名而来. train 会接受特定格式的输入, 產生一个 "Model" 档. 这个 model 你可以想像成 SVM 的内部资料, 因為 predict 要 model 才能 predict, 不能直接吃原始资料. 想想也很合理, 假定 train 本身是很耗时的动作, 而 train 好可以以某种形式存起内部资料, 那下次要 predict 时直接把那些内部资料 load 进来就快多了.

svmpredict

依照已经 train 好的 model, 再加上给定的输入 (新值), 输出 predict (预测) 新值所对应的类别 (class). 因為原始资料可能范围过大或过小, svmscale 可以先将资料重新 scale (缩放) 到适当范围. 档案格式要先交代一下. 你可以参考 libsvm 裡面附的 "heart_scale":

[label] [index1]:[value1] [index2]:[value2] ...

[label] [index1]:[value1] [index2]:[value2] ...

.

.

行一笔资料,如  

+1 1:0.708 2:1 3:1 4:-0.320 5:-0.105 6:-1 

label

或说是 class, 就是你要分类的种类,通常是一些整数。

index

是有顺序的索引,通常是放连续的整数。

value

就是用来 train 的资料,通常是一堆实数。

每一行都是如上的结构, 意思就是: 我有一排资料, 分别是 value1, value2, .... valueN, (而且它们的顺序已由 indexN 分别指定),这排资料的分类结果就是 label。

或许你会不太懂,為什麼会是 value1,value2,.... 这样一排呢? 这牵涉到 SVM 的原理。 你可以这样想(我没说这是正确的), 它的名字就叫 Support "Vector" Machine, 所以输入的 training data 是 "Vector"(向量), 也就是一排的 x1, x2, x3, ... 这些值就是 valueN,而 x[n] 的 n 就是 由 indexN 指定。 这些东西又称為 "attribute"。

真实的情况是, 大部份时候我们给定的资料可能有很多 "特徵(feature)" 或说 "属性(attribute)",所以输入会是 一组的。 举例来说,以前面画点分区的例子 来说,我们不是每个点都有 X 跟 Y 的座标吗? 所以它就有 两种 attribute。 假定我有两个点: (0,3) 跟 (5,8) 分别在 label(class) 1 跟 2 ,那就会写成:

1 1:0 2:3

2 1:5 2:8

同理,空间中的三维座标就等於有三组 attribute。 这种档案格式最大的好处就是可以使用 sparse matrix, 或说有些 data 的 attribute 可以不存在。  

To Run libsvm

来解释一下 libsvm 的程式怎麼用。 你可以先拿 libsvm 附的 heart_scale 来做输入,底下也以它為例:

看到这裡你应该也了解,使用 SVM 的流程大概就是:

准备资料并做成指定格式 (有必要时需 svmscale)

用 svmtrain 来 train 成 model

对新的输入,使用 svmpredict 来 predict 新资料的 class 

svmtrain

svmtrain 的语法大致就是:

svmtrain [options] training_set_file [model_file] 

training_set_file 就是之前的格式,而 model_file 如果不给就会 叫 [training_set_file].model。 options 可以先不要给。

下列程式执行结果会產生 heart_scale.model 档:(荧屏输出不是很重要,没有错误就好了)

./svm-train 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 就是我们要 predict 的资料。它的格式跟 svmtrain 的输入,也就是 training_set_file 是一样的! predict 完会顺便拿 predict 出来的值跟 test_file 裡面写的值去做比对,这代表: test_file 写的 label 是真正的分类结果,拿来跟我们 predict 的结果比对就可以 知道 predict 有没有猜对了。

也所以,我们可以拿原 training set 当做 test_file再丢给 svmpredict 去 predict (因為格式一样),看看正确率有多高, 方便后面调参数。

其它参数就很好理解了: model_file 就是 svmtrain 出来 的档案, output_file 是存输出结果的档案。

输出的格式很简单,每行一个 label,对应到你的 test_file 裡面的各行。  

下列程式执行结果会產生 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)

As you can see,我们把原输入丢回去 predict, 第一行的 Accuracy 就是预测的正确率了。 如果输入没有 label 的话,那就是真的 predict 了。

看到这裡,基本上你应该已经可以利用 svm 来作事了: 你只要写程式输出正确格式的资料,交给 svm 去 train, 后来再 predict 并读入结果即可。  

Advanced Topics

后面可以说是一些稍微进阶的部份,我可能不会讲的很清楚, 因為我的重点是想表达一些观念和解释一些你看相关文件时 很容易碰到的名词。

Scaling

svm-scale 目前不太好用,不过它有其必要性。因為 适当的scale有助於参数的选择(后述)还有解svm的速度。

svmscale 会对每个 attribute 做scale。 范围用 -l, -u 指定, 通常是[0,1]或是[-1,1]。 输出在 stdout。

另外要注意的(常常会忘记)是 testing data 和 training data要一起scale。

而 svm-scale 最难用的地方就是没办法指定 testing data/training data(不同档案) 然后一起scale。

Arguments

前面提到,在 train 的时候可以下一些参数。(直接执行 svm-train 不指定输入档与参数会列出所有参数及语法说明) 这些参数对应到原始 SVM 公式的一些参数,所以会影响 predict 的正确与否。

举例来说,改个 c=10:

./svm-train -c 10 heart_scale

再来 predict ,正确率马上变成 92.2% (249/270)。

Cross Validation

一般而言, SVM 使用的方式(在决定参数时)常是这样:

先有已分好类的一堆资料

乱数拆成好几组 training set

用某组参数去 train 并 predict 别组看正确率

正确率不够的话,换参数再重复 train/predict

等找到一组不错的参数后,就拿这组参数来建 model 并用来做最后对未知资料的 predict。 这整个过程叫 cross validation , 也就是交叉比对。  

在我们找参数的过程中,可以利用 svmtrain 的内建 cross validation 功能来帮忙:

-v n: n-fold cross validation

n 就是要拆成几组,像 n=3 就会拆成三组,然后先拿 1跟2来 train model 并 predict 3 以得到正确率; 再来拿 2跟 3 train 并 predict 1,最后 1,3 train 并 predict 2。其它以此类推。

如果没有交叉比对的话,很容易找到只在特定输入时好的 参数。像前面我们 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?

通常而言,比较重要的参数是 gamma (-g) 跟 cost (-c) 。而 cross validation (-v) 的参数常用 5。 cost 预设值是 1, gamma 预设值是 1/k ,k 等於输入 资料笔数。 那我们怎麼知道要用多少来当参数呢?

用试的

是的,别怀疑,就是 Try 参数找比较好的值。

Try 参数的过程常用 exponential 指数成长的方式来增加与减少参数的数值, 也就是 2^n (2 的 n 次方)。

因為有两组参数,所以等於要 try n*n=n^2 次。 这个过程是不连续的成长,所以可以想成我们在一个 X-Y 平面上指定的范围内找一群格子点 (grid, 如果你不太明白,想成方格纸或我们把平面上所有 整数交点都打个点,就是那样),每个格子点的 X 跟 Y 经过换算 (如 2^x, 2^y) 就拿去当 cost 跟 gamma 的值来 cross validation。

所以现在你应该懂得 libsvm 的 python 子目录下面 有个 grid.py 是做啥的了: 它把上面的过程自动化, 在你给定的范围内呼叫 svm-train 去 try 所有的参数值。 python 是一种语言,在这裡我不做介绍,因為我会了 :P (just a joke,真正原因是 -- 这是 libsvm 的 tutorial)。 grid.py 还会把结果 plot 出来,方便你寻找参数。 libsvm 有很多跟 python 结合的部份,由此可见 python 是强大方便的工具。很多神奇的功能,像自动登入多台 机器去平行跑 grid等等都是 python 帮忙的。不过 SVM 本身可以完全不需要 python,只是会比较方便。  

跑 grid (基本上用 grid.py 跑当然是最方便,不过 如果你不懂 python 而且觉得很难搞,那你要自己產生 参数来跑也是可以的) 通常好的范围是 [c,g]=[2^-10,2^10]*[2^-10,2^10] 另外其实 grid 用 [-8,8] 也很够了。

Regression

另一个值得一提的是 regression。

简单来说,前面都是拿 SVM 来做分类 (classification), 所以 label 的值都是 discrete data、或说已知的固定值。 而 regression 则是求 continuous 的值、或说未知的值。 你也可以说,一般是 binary classification, 而 regression是可以预测一个实数。 

比如说我知道股市指数受到某些因素影响, 然后我想预测股市.. 股市的指数就是我们的 label, 那些因素量化以后变成 attributes。 以后蒐集那些 attributes 给 SVM 它就会 预测出指数(可能是没出现过的数字),这就要用 regression。 那乐透开奖的号码呢? 因為都是固定已知的数字, 很明显我们应该用一般 SVM 的 classification 来 predict。 (註:这是真实的例子 -- llwang 就写过这样的东西) 

所以说 label 也要 scale, 用 svm-scale -y lower upper

但是比较糟糕的情况是 grid.py 不支援 regression , 而且cross validation 对 regression 也常常不是很有效。

总而言之,regression 是非常有趣的东西,不过也是比较 进阶的用法。 在这裡我们不细谈了,有兴趣的人请再 参考 SVM 与 libsvm 的其它文件。

到此我已经简单的说明了 libsvm 的使用方式, 更完整的用法请参考 libsvm 的说明跟 cjlin 的网站、 SVM 的相关文件,或是去上 cjlin 的课。  

对于 SVM 的新手来说, libsvmtools 有很多好东西。像 SVM for dummies 就是很方便观察 libsvm 流程的东西。  

 
  评论这张
 
阅读(236)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2016