LibSVM库的使用说明

转载自:http://blog.csdn.net/ajianyingxiaoqinghan/article/details/73480476

本文摘自《libsvm》的GitHub中的README文档

前言

LibSVM库的函数和结构体都在头文件 svm.h 中声明,我们需要在 C/C++ 文件中添加语句 #include “svm.h” ,然后就可以将我们的程序链接到 svm.cpp 文件上。我们可以以 svm-train.c 和 svm-predict.c 作为例程,了解它们是如何使用LibSVM库函数的。我们定义了 LIBSVM_VERSION 并在 svm.h 中声明了 extern int libsvm_version,所以我们可以检查库函数版本号。
在我们分类测试数据之前,我们需要使用训练数据构建一个 SVM 模型(即 svm_model)。一个模型也可以被存储到文件中,以便以后的运用。一旦一个 SVM 模型是可用的,你可以用它分类新数据。

LibSVM函数与结构体

svm_train

  • struct svm_model* svm_train(const struct svm_problem* prob, const struct svm_parameter* param);

该函数根据给定的训练数据和参数,构建并返回了一个 SVM 模型。

svm_problem

svm_problem 结构体描述了问题:

struct svm_problem
{
    int l;
    double *y;
    struct svm_node **x;
};
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

上述结构体的说明如下:

  • l:训练数据的数量;
  • y:包含目标数据的数组;
  • x:数组指针,每一个指针指向一个训练向量,训练向量是一个 svm_node 的数组;

例如,如果我们有下列的训练数据:

LABEL    ATTR1    ATTR2    ATTR3    ATTR4    ATTR5
-----    -----    -----    -----    -----    -----
  1        0        0.1      0.2      0        0
  2        0        0.1      0.3     -1.2      0
  1        0.4      0        0        0        0
  2        0        0.1      0        1.4      0.5
  3       -0.1     -0.2      0.1      1.1      0.1

那么此时 svm_problem 的组成就是:

    l = 5
    y -> 1 2 1 2 3
    x -> [ ] -> (2,0.1) (3,0.2) (-1,?)
         [ ] -> (2,0.1) (3,0.3) (4,-1.2) (-1,?)
         [ ] -> (1,0.4) (-1,?)
         [ ] -> (2,0.1) (4,1.4) (5,0.5) (-1,?)
         [ ] -> (1,-0.1) (2,-0.2) (3,0.1) (4,1.1) (5,0.1) (-1,?)
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

svm_node

svm_node 结构体中存储的是(index, value):

struct svm_node
{
    int index;
    double value;
};
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

index = -1 表明了一个向量的结尾。
注:标签号(index)的排列必须是升序排序。

svm_parameter

结构体 svm_parameter 描述了 SVM 模型的参数:

struct svm_parameter
{
    int svm_type;
    int kernel_type;
    int degree; /* for poly */
    double gamma;   /* for poly/rbf/sigmoid */
    double coef0;   /* for poly/sigmoid */

    /* these are for training only */
    double cache_size; /* in MB */
    double eps; /* stopping criteria */
    double C;   /* for C_SVC, EPSILON_SVR, and NU_SVR */
    int nr_weight;      /* for C_SVC */
    int *weight_label;  /* for C_SVC */
    double* weight;     /* for C_SVC */
    double nu;  /* for NU_SVC, ONE_CLASS, and NU_SVR */
    double p;   /* for EPSILON_SVR */
    int shrinking;  /* use the shrinking heuristics */
    int probability; /* do probability estimates */
};
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

参数说明如下:

  • svm_type:可以是C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR其中之一;
    • C_SVC:C-SVM 分类器;
    • NU_SVC:NU-SVM 分类器;
    • ONE_CLASS:one-class SVM;
    • EPSILON_SVR:epsilon-SVM 回归;
    • NU_SVR:nu-SVM 回归;
  • kernel_type:可以是 LINEAR, POLY, RBF, SIGMOID 其中之一;
    • LINEAR u T v 
    • POLY (gammau T v+coef0) degree  
    • RBF exp(gamma×|uv| 2 ) 
    • SIGMOID tanh(gamma×u T v+coef0) 
    • PRECOMPUTED:在训练集文件中的存放核函数值;
  • cache_size:是核缓存的大小,单位是MBytes;
  • eps:停止标准(我们在 NU-SVC 中使用的标准是0.00001,在其他分类器中使用 0.001);
  • nu:用于 nu-SVM, nu-SVR, one-class-SVM 的参数;
  • p:epsilon-SVM 回归中损失函数的小量,损失函数对小量不敏感;
  • shrinking
    • shrinking = 1,则收缩是进行的;
    • shrinking = 0,则收缩无效;
  • probability
    • probability = 1,模型中包含概率信息;
    • probability = 0,模型中不包含概率信息;

其它的,nr_weight, weight_label 和 weight 用来为某些类改变惩罚因子(如果一个类的 weight 值没有改变,则被设置为1).这将有助于训练分类器使用不平衡输入数据,或者有利于降低不对称错误分类的代价。
nr_weight 是在 weight_label 数组和 weight 数组的元素个数。每一个 weight[i] 对应了一个 weight_label[i],意味着类 weight_label[i] 的惩罚,就是与 weight[i] 相乘的结果。
如果我们不想改变任何分类的惩罚因子,就把 nr_weight 设置为0;。

注:
1. 因为 svm_model 包含了 svm_problem 的指针,所以如果我们仍然需要使用由 svm_train() 函数生成的 svm_model ,我们不能释放包含了 svm_problem 的内存空间。
2. 为了避免错误参数,函数 svm_check_parameter() 应该在 svm_train() 函数之前调用。

svm_model

结构体 svm_model 存储了从训练过程中得到的模型。这里并不推荐直接访问该结构体中的值,编程者应该使用接口函数获得其中的值。

struct svm_model
{
    struct svm_parameter param; /* parameter */
    int nr_class;       /* number of classes, = 2 in regression/one class svm */
    int l;          /* total #SV */
    struct svm_node **SV;       /* SVs (SV[l]) */
    double **sv_coef;   /* coefficients for SVs in decision functions (sv_coef[k-1][l]) */
    double *rho;        /* constants in decision functions (rho[k*(k-1)/2]) */
    double *probA;      /* pairwise probability information */
    double *probB;
    int *sv_indices;        /* sv_indices[0,...,nSV-1] are values in [1,...,num_traning_data] to indicate SVs in the training set */

    /* for classification only */
    int *label;     /* label of each class (label[k]) */
    int *nSV;       /* number of SVs for each class (nSV[k]) */
                    /* nSV[0] + nSV[1] + ... + nSV[k-1] = l */
    /* XXX */
    int free_sv;        /* 1 if svm_model is created by svm_load_model*/
                        /* 0 if svm_model is created by svm_train */
};
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

参数解释如下:

  • param:描述了在该模型中使用的参数;
  • nr_class:分类数量。对于回归问题和 one-class SVM,其值为2;
  • l:支持向量的个数;
  • SV, sv_coef:分别代表支持向量和其相应系数。

假设有 k 种分类。对于数据中的分类 j,相应的 sv_coef 包含了 (k - 1) y * alpha 个向量,alpha的向量是一系列二分类问题的解决方案:1 vs j, 2 vs j, …, j-1 vs j, j vs j+1, j vs j+2, …, j vs k。并且 y=1 对应前面 j-1 个向量,y=-1 代表后面剩余的 k-j 个向量。
举例说明,如果这里有 4 个分类,那么 sv_coef 和 SV 如下所示:

    +-+-+-+--------------------+
    |1|1|1|                    |
    |v|v|v|  SVs from class 1  |
    |2|3|4|                    |
    +-+-+-+--------------------+
    |1|2|2|                    |
    |v|v|v|  SVs from class 2  |
    |2|3|4|                    |
    +-+-+-+--------------------+
    |1|2|3|                    |
    |v|v|v|  SVs from class 3  |
    |3|3|4|                    |
    +-+-+-+--------------------+
    |1|2|3|                    |
    |v|v|v|  SVs from class 4  |
    |4|4|4|                    |
    +-+-+-+--------------------+

可以以函数 svm_train() 为例,观察其中如何将值分配给 sv_coef。

  • rho:偏差值 (-b);
  • probA, probB:在概率输出中使用的参数。如果有 k 个类别,则会存在 k×(k-1)/2 个二值问题,以及 rho, probA, probB 值,它们按照二值问题的顺序对齐:1 vs 2, 1 vs 3, …, 1 vs k, 2 vs 3, …, 2 vs k, …, k-1 vs k
  • sv_indices[0, …, nSV-1]:在 [1, …, num_training_data]中,标示训练集里面支持向量的值;
  • label:包含训练数据的标签;
  • nSV:每个类中的支持向量的数量;
  • free_sv:标志位,用来决定 SV 的空间是否应该被函数 free_model_content(struct svm_model*) 和 free_and_destroy_model(struct svm_model**) 释放。如果模型是由函数 svm_train() 生成的,那么 SV 在 svm_problem 中指向的数据不应该被移除。例如,如果 svm_model 不是由 svm_train 函数生成,那么free_sv值为0;但是如果是由 svm_load_model 函数生成,则 free_sv 值为1;

svm_predict

  • double svm_predict(const struct svm_model* model, const struct svm_node* x);

该函数以模型 model 为基础,对测试向量 x 进行分类或回归预测。

  • 对于分类模型,将会返回 x 的预测分类;
  • 对于回归模型,将会返回使用模型计算得到的 x 值;
  • 对于 one-class 模型,返回 +1 或 -1;

svm_cross_validation

  • void svm_cross_validation(const struct svm_problem* prob, const struct svm_parameter* param, int nr_fold, double* target);

该函数用来进行交叉验证。数据被分离成 nr_fold 组,在给定的参数下,按照顺序的每一组用由剩余数据训练得到的模型进行验证。验证过程中的预测标签(所有概率情况)被存到目标数组中。
svm_prob 格式与 svm_train() 相同。

svm_get_svm_type

  • int svm_get_svm_type(const struct svm_model* model);

该函数返回模型的 svm_type。svm_type 可能存在的值在文件 svm.h 中已经定义。

svm_get_nr_class

  • int svm_get_nr_class(const svm_model* model);

对于分类模型,函数返回分类的数量;
对于回归模型或 one-class 模型,返回值为 2 ;

svm_get_labels

  • void svm_get_labels(const svm_model* model, int* label);

对于分类模型,该函数将标签名称输出到标签数组。
对于回归模型和 one-class 模型,标签不变。

svm_get_sv_indices

  • void svm_get_sv_indices(const struct svm_model* model, int* sv_indices);

该函数将支持向量的编号输出到 sv_indices 数组。
sv_indices 的大小是支持向量的大小,该值可以通过调用 svm_get_nr_sv 函数得到。
每个 sv_indices[i] 的范围都在 [1, …, num_training_data] 之中。

svm_get_nr_sv

  • int svm_get_nr_sv(const struct svm_model* model);

该函数返回所有支持向量的个数。

svm_get_svr_probability

  • double svm_get_svr_probability(const struct svm_model* model);

对于带有概率信息的回归模型,该函数输出一个大于 0 的 sigma 值。对于测试数据,我们认为概率模型为:目标值 = 预测值 + z。
其中,z 是拉普拉斯变换: exp(|z|/sigma)2×sigma  
如果模型不是 svr ,或者不包含需要的信息,返回 0 值。

svm_predict_values

  • double svm_predict_values(const svm_model* model, const svm_node* x, double* dec_values);

该函数通过一个模型 model 计算向量 x ,得到预测决策值,并返回其预测标签(分类问题)或函数值(回归问题)。
对于 nr_class 个分类的分类模型,该函数在数组 dec_values 中给出 nr_class * (nr_class - 1) / 2 个决策值,其中 nr_class 的值可以通过函数 svm_get_nr_class 得到,其顺序是:

label[0] vs. label[1],
...,
label[0] vs. label[nr_class-1],
..., 
label[nr_class-2] vs. label[nr_class-1]

标签 label 可以由函数 svm_get_labels 得到。
该函数返回值是 x 的预测分类结果。注:当 nr_class = 1 时,该函数不会给出任何决策值。

对于回归问题,dec_values[0] 和返回值都是通过模型计算 x 得到的预测值。
对于 one-class 模型,dec_values[0] 是 x 的决策结果,返回值是 +1 或 -1。

svm_predict_probability

  • double svm_predict_probability(const struct svm_model* model, const struct svm_node* x, double* prob_estimates);

该函数对一个带有概率信息的模型,对测试向量 x 进行分类或回归操作。
对于带有概率信息的分类模型,该函数在数组 prob_estimates 中给出了 nr_class 种概率估计(nr_class 值可以从函数 svm_get_nr_class 得到)。结果将返回高概率的分类。
对于回归问题或 one-class 问题,数组 prob_estimates 不变,返回值与函数 svm_predict 相同。

svm_check_parameter

  • const char* svm_check_parameter(const struct svm_problem* prob, const struct svm_parameter* param);

该函数检测参数是否在该问题的可行范围之中。该函数应该在调用 svm_train() 和 svm_cross_validation() 之前调用。如果参数是可行的,则返回 NULL 值;否则返回一个错误信息。

svm_check_probability_model

  • int svm_check_probability_model(const struct svm_model* model);

该函数检测模型是否包含概率估计的所需信息。如果是,将返回 +1;否则,返回 0。
该函数应该在调用 svm_get_svr_probability 和 svm_predict_probability 函数之前进行调用。

svm_save_model

  • int svm_save_model(const char* model_file_name, const struct svm_model* model);

该函数将模型存到一个文件中。
存储成功,返回 0;存储出现错误,返回 -1。

svm_load_model

  • struct svm_model* svm_load_model(const char* model_file_name);

该函数从一个文件中读取模型,返回一个模型的指针。
如果模型不能被读取,则返回一个空指针。

svm_free_model_content

  • void svm_free_model_content(struct svm_model* model_ptr);

该函数释放被模型结构体占用的内存空间。

svm_free_and_destroy_model

  • void svm_free_and_destroy_model(struct svm_model** model_ptr_ptr);

该函数用来释放被模型占用的内存空间,并销毁模型结构体。
该函数与函数 svm_destroy_model 相同,但函数 svm_destroy_model 在版本 3.0 之后被弃用。

svm_destroy_param

  • void svm_destroy_param(struct svm_parameter* param);

该函数释放被参数集合占用的内存空间。

svm_set_print_string_function

  • void svm_set_print_string_function(void (* print_func)(const char *));

用户可以指定一个函数的输出格式。例如:

svm_set_print_string_function(NULL);
 
 
  • 1
  • 1

可以使用默认输出到stdout。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值