LIBSVM用法


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];
    }
}

---------------------------------------------

歡迎拍磚。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM