1,SVM 的输入文件格式.
[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, .... value, (而且它们的順序已由 index 分別指定),这排数据的分类結果就是label。
或許你会不太懂,为什么会是 value1,value2,.... 这样一排呢? 这牵涉到SVM 的原理。 你可以这样想(我沒说这是正确的), 它的名字就叫 Support "Vector" Machine, 所以输入的训练数据是 "Vector"(向量), 也就是一排的 x1, x2, x3, ... 这些值就是 value,而 x[n] 的n就是由index 指定。 这些东西又称为 "(属性)attribute"。
真实的情况是,大部份时候我们给定的数据可能有很多 "特征(feature)" 或说"属性(attribute)",所以输入会是一组的。 举例来说,以前面点分区的例子 来说,我们不是每个点都有 X 跟 Y 的坐标吗? 所以它就有两种属性。 假定我有两个点: (0,3) 跟 (5,8) 分別在 label(class) 1 跟 2 ,那就会写成
1 1:0 2:3
2 1:5 2:8
同理,空间中的三維坐标就等于有三组属性。这种文件格式最大的好处就是可以使用稀疏矩阵(sparse matrix), 或说有些 数据的属性可以有缺失。
2,SVM的使用
libsvm 有很多种用法, 这篇指南只打算讲简单的部分.
程序
svmtrain
训练数据. 跑SVM被戏称为 "开火車" 也是由于这个程序名而来. train会接受特定格式的输入, 产生一个 "Model" 文件. 这个 model 你可以想像成SVM的內部数据,因为预测要model才能预测, 不能直接吃原始数据.想想也很合理,假定 train 本身是很耗时的动作, 而 train可以以某种形式存起內部数据,那下次要预测时直接把那些內部数据载入就快多了.
svmpredict
依照已经训练好的 model, 再加上给定的输入(新值), 输出預测新值所对应的类別.
svmscale
扫描数据. 因为原始数据可能范围过大或过小, svmscale 可以先将数据重新scale (縮放) 到适当范围使训练与预测速度更快。
3,运行libsvm
下来解释一下libsvm 的程序怎么用。 你可以先拿 libsvm 附的heart_scale 来做输入,底下也以它为例:
看到这里你应该也了解,使用 SVM 的流程大概就是:
1.
2.
3.
svmtrain
svmtrain 的语法大致就是:
svmtrain [options] training_set_file [model_file]
training_set_file 就是之前的格式,而 model_file 如果不给就会 叫[training_set_file].model。 options 可以先不要给。
下列程序执行結果会产生 heart_scale.model 文件:(螢幕输出不是很重要,沒有错誤就好了)
./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 就是我们要预测的数据。它的格式跟 svmtrain 的输入,也就是training_set_file 是一样的, 不过每行最前面的 label 可以省略 (因为预测就是要预测那个 label)。 但如果 test_file 有 label 的值的话, predict 完会順便拿 predict出来的值跟 test_file 里面写的值去做比对,这代表: test_file 写的label是真正的分类結果,拿来跟我们预测的結果比对就可以知道预测的效果。所以,我们可以拿原 training set 当做 test_file再丟给 svmpredict 去预测(因为格式一样),看看正确率有多高,方便后面调参数。其它参数就很好理解了: 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)
我们把原输入丟回去 predict, 第一行的 Accuracy 就是預测的正确率了。如果输入沒有label 的话,那就是真的预测了。看到这里,基本上你应该已经可以利用svm 来作事了: 你只要写程序输出正确格式的数据,交给 svm 去 train, 后来再predict 并读入結果即可。
Advanced Topics
后面可以说是一些稍微进阶的部份,我可能不会讲的很清楚,因为我的重点是想表达一些观念和解释一些你看相关文件时很容易碰到的名詞。
Scaling
svm-scale 目前不太好用,不过它有其必要性。因为适当的扫描有助于参数的选择,还有解svm的速度。svmscale 会对每个属性做扫描。 范围用 -l, -u 指定,通常是[0,1]或是[-1,1]。 输出在 stdout。另外要注意的(常常会忘记)是 testing data和 training data要一起扫描。而 svm-scale 最难用的地方就是沒办法指定 testing data/training data(不同文件) 然后一起扫描。
Arguments
前面提到,在train的时候可以使用一些参数。(直接执行 svm-train 不指定输入文件与参数会列出所有参数及语法说明) 这些参数对应到原始 SVM 公式的一些参数,所以会影响预测的正确与否。
举例来说,改个 c=10:
./svm-train -c 10 heart_scale
再来预测 ,正确率馬上变成 92.2% (249/270)。
Cross Validation
一般而言, SVM 使用的方式(在决定参数时)常是这样:
1.
2.
3.
4.
等找到一组不错的参数后,就拿这组参数来建model并用来做最后对未知数据的预测。 这整个过程叫cross validation , 也就是交叉比对。 在我们找参数的过程中,可以利用 svmtrain 的內建交叉比对功能来帮忙:
-v n: n-fold cross validation
n 就是要拆成几组,像 n=3 就会拆成三组,然后先拿 1跟2来训练并预测 3 以得到正确率; 再来拿 2跟 3 训练并预测1,最后 1,3 训练并预测2。其它以此类推。如果沒有交叉比对的话,很容易找到只在特定输入时好的参数。像前面我们 c=10 得到 92.2%,不过拿 -v 5 来看看:
Cross Validation Accuracy = 80.3704%
平均之后才只有 80.37%,比一开始的 86 还差。
What arguments rules?
通常而言,比较重要的参数是 gamma (-g) 跟 cost (-c) 。而交叉比对 (-v) 的参数常用 5。cost 預设值是 1, gamma 預设值是 1/k ,k 等于输入数据条数。 那我们怎么知道要用多少来当参数呢?
Regression(衰减)
另一个值得一提的是regression(衰减)。 简单来说,前面都是拿 SVM 来做分类,所以label的值都是离散的数据、或说已知的固定值。而 regression 则是求连续的值、或说未知的值。你也可以说,一般是二分类问题, 而 regression是可以預测一个实数。
比如说我知道股市指数受到某些因素影响, 然后我想預测股市。股市的指数就是我们的 label, 那些因素量化以后变成属性。 以后收集那些属性给 SVM 它就会 預测出指数(可能是沒出現过的数字),这就要用 regression。那对于开奖的号码呢?因为都是固定已知的数字,很明显我们应该用一般SVM的分类来预测 。 (註这是真实的例子 --llwang就写过这样的东西) 所以说 label 也要扫描, 用 svm-scale -y lower upper但是比较糟糕的情况是grid.py不支持regression,而且较差对比对regression 也常常不是很有效。
尾声
到此我已经简单的说明了 libsvm 的使用方式, 更完整的用法请参考 libsvm 的说明跟 cjlin 的网站、。对于SVM 的新手来说, libsvmtools 有很多好东西。像 SVM for dummies 就是很方便观察 libsvm 流程的东西。