LIBSVM用法
2012-10-23 23:36 ggzwtj 阅读(3546) 评论(1) 编辑 收藏 举报svm-train用来从样本数据中训练出用来判定的规则,其中的参数设置如下:
options: -s svm_type : set type of SVM (default 0) 0 -- C-SVC 1 -- nu-SVC 2 -- one-class SVM 3 -- epsilon-SVR 4 -- nu-SVR -t kernel_type : set type of kernel function (default 2) 0 -- linear: u'*v 1 -- polynomial: (gamma*u'*v + coef0)^degree 2 -- radial basis function: exp(-gamma*|u-v|^2) 3 -- sigmoid: tanh(gamma*u'*v + coef0) -d degree : set degree in kernel function (default 3) -g gamma : set gamma in kernel function (default 1/num_features) -r coef0 : set coef0 in kernel function (default 0) -c cost : set the parameter C of C-SVC, epsilon-SVR, and nu-SVR (default 1) -n nu : set the parameter nu of nu-SVC, one-class SVM, and nu-SVR (default 0.5) -p epsilon : set the epsilon in loss function of epsilon-SVR (default 0.1) -m cachesize : set cache memory size in MB (default 100) -e epsilon : set tolerance of termination criterion (default 0.001) -h shrinking: whether to use the shrinking heuristics, 0 or 1 (default 1) -b probability_estimates: whether to train a SVC or SVR model for probability estimates, 0 or 1 (default 0) -wi weight: set the parameter C of class i to weight*C, for C-SVC (default 1)
如果不知道各种参数之间的区别也不会玩的开心,首先来看-s参数的含义:
C-SVC对应的原问题是:
它的对偶问题如下:
对应的决策函数为:
nu-CVS对应的原问题是:
它的对偶问题为:
它的决策函数是:
one-class SVM原始问题是:
对偶问题为:
判定函数:
epsilon-SVR的原型为:
它的对偶问题为:
nu-SVR原问题如下:
对偶问题为:
使用软件包中的heart_scale文件用来测试,使用下面命令用来测试:
svm-train -s 0 -t 2 ../heart_scale result_module
输入文件的格式为:
+1 1:0.708333 2:1 3:1 4:-0.320755 5:-0.105023 6:-1 7:1 8:-0.419847 9:-1 10:-0.225806 12:1 13:-1
-1 1:0.583333 2:-1 3:0.333333 4:-0.603774 5:1 6:-1 7:1 8:0.358779 9:-1 10:-0.483871 12:-1 13:1
+1 1:0.166667 2:1 3:-0.333333 4:-0.433962 5:-0.383562 6:-1 7:-1 8:0.0687023 9:-1 10:-0.903226 11:-1 12:-1 13:1
-1 1:0.458333 2:1 3:1 4:-0.358491 5:-0.374429 6:-1 7:-1 8:-0.480916 9:1 10:-0.935484 12:-0.333333 13:1
……
在result中的输出如下:
svm_type c_svc # SVM类型
kernel_type rbf # 核函数类型
gamma 0.0769231 # 核函数中的g
nr_class 2 # 分类时的类别数
total_sv 132 # 总共的支持向量个数
rho 0.424462 # 决策函数中的常量b
label 1 -1 # 类别标签
nr_sv 64 68 # 各类别分别的支持向量的个数
SV # 支持向量的列表
1 1:0.166667 2:1 3:-0.333333 4:-0.433962 5:-0.383562 6:-1 7:-1 8:0.0687023 9:-1 10:-0.903226 11:-1 12:-1 13:1
0.5104832128985164 1:0.125 2:1 3:0.333333 4:-0.320755 5:-0.406393 6:1 7:1 8:0.0839695 9:1 10:-0.806452 12:-0.333333 13:0.5
……
其中的svm-toy就像一个玩具,比如。。。
从这个图中可以看出上面大于2的类的划分还是基于两个类的划分的,当然在下面的代码中也可以很明显地看到这一点。
而svm-predict则是用train出来的module来预测数据的,我们这里就用heart_scale建立的module来在heart_scale做检验,如下:
svm-predict.exe ../heart_scale ../result_module ../a
输出为:
Accuracy = 86.6667% (234/270) (classification)
也就是说准确度达到了86.6667。那这个predict是怎么利用Module来预测的,虽然知道预测函数了,但是貌似看到代码才算完,如下:
1 struct svm_model 2 { 3 struct svm_parameter param; /* parameter */ 4 int nr_class; /* number of classes, = 2 in regression/one class svm */ 5 int l; /* total #SV */ 6 struct svm_node **SV; /* SVs (SV[l]) */ 7 double **sv_coef; /* coefficients for SVs in decision functions (sv_coef[k-1][l]) */ 8 double *rho; /* constants in decision functions (rho[k*(k-1)/2]) */ 9 double *probA; /* pariwise probability information */ 10 double *probB; 11 12 /* for classification only */ 13 14 int *label; /* label of each class (label[k]) */ 15 int *nSV /* number of SVs for each class (nSV[k]) */ 16 /* nSV[0] + nSV[1] + ... + nSV[k-1] = l */ 17 /* XXX */ 18 int free_sv; /* 1 if svm_model is created by svm_load_model*/ 19 /* 0 if svm_model is created by svm_train */ 20 };
在具体的程序中大段的代码都是在解析文件,核心的代码如下(里面有注释):
double svm_predict_values(const svm_model *model, const svm_node *x, double* dec_values) { int i; if(model->param.svm_type == ONE_CLASS || model->param.svm_type == EPSILON_SVR || model->param.svm_type == NU_SVR) { double *sv_coef = model->sv_coef[0]; double sum = 0; for(i=0;i<model->l;i++) sum += sv_coef[i] * Kernel::k_function(x,model->SV[i],model->param); sum -= model->rho[0]; *dec_values = sum; if(model->param.svm_type == ONE_CLASS) return (sum>0)?1:-1; else return sum; } else { int nr_class = model->nr_class; int l = model->l; double *kvalue = Malloc(double,l); // 依次计算Kernel for(i=0;i<l;i++) kvalue[i] = Kernel::k_function(x,model->SV[i],model->param); int *start = Malloc(int,nr_class); start[0] = 0; // 计算各个类的支持向量的开始的位置 for(i=1;i<nr_class;i++) start[i] = start[i-1]+model->nSV[i-1]; int *vote = Malloc(int,nr_class); for(i=0;i<nr_class;i++) vote[i] = 0; int p=0; for(i=0;i<nr_class;i++) for(int j=i+1;j<nr_class;j++) { double sum = 0; int si = start[i]; int sj = start[j]; int ci = model->nSV[i]; int cj = model->nSV[j]; int k; // 支持向量对应的参数 double *coef1 = model->sv_coef[j-1]; double *coef2 = model->sv_coef[i]; // 计算出各个类之间的差距 for(k=0;k<ci;k++) sum += coef1[si+k] * kvalue[si+k]; for(k=0;k<cj;k++) sum += coef2[sj+k] * kvalue[sj+k]; sum -= model->rho[p]; dec_values[p] = sum; // 如果大于0的话选i,否则选j if(dec_values[p] > 0) ++vote[i]; else ++vote[j]; p++; } int vote_max_idx = 0; // 从中选出最大的一个类型 for(i=1;i<nr_class;i++) if(vote[i] > vote[vote_max_idx]) vote_max_idx = i; free(kvalue); free(start); free(vote); // 返回地vote_max_idx对应的label return model->label[vote_max_idx]; } }
---------------------------------------------
欢迎拍砖。