【机器学习】用libsvm C++训练SVM模型

前言:本文大水文一篇,大神请绕道。在正文之前,首先假设读者都已经了解SVM(即支持向量机)模型。
1. introduction
libsvm是台湾大学林智仁(Chih-Jen Lin)教授于2001年开发的一套支持向量机的工具包,可以很方便地对数据进行分类或者回归分析。使用时,只需要把训练数据按照它的格式打包,然后直接喂进去训练即可。我这里的数据是保存在mat文件的,数据怎么导入这里略去不说(以下内容提及的特征向量和一个样本是一回事)。
2. prepare
几个重要的数据结构
2.1

struct svm_problem
{
    int l;      // 记录样本的总数
    double *y;  // 样本所属的标签(+1, -1)
    struct svm_node **x;    // 指向样本数据的二维数组(即一个矩阵,行数是样本数,列数是特征向量维度)
};

2.2

struct svm_node
{
    int index;
    double value;
};

svm_node是用来存储单个样本数据的,打个比方说,svm_problem是一群羊,那么svm_node就是这一群羊中的一只。需要注意的是,svm_node的存储空间应该比特征数大一位,最后一位index值必须以-1结束。比如:

    svm_node* node = new svm_node[1 + feature_size];
    for (int j = 0; j < feature_size; j++)
    {
        node[j].index = j + 1;
        node[j].value = xdata[j];
    }
    node[feature_size].index = -1;
    return node;

2.3

    struct svm_parameter
    {
        int svm_type;// SVM的类型
        int kernel_type;// 核函数
        double degree;// 多项式参数
        double gamma;// 核函数为poly/rbf/sigmoid的参数
        double coef0;// 核函数为poly/sigmoid的参数

        //下面是训练所需的参数
        double cache_size;// 训练所需的内存MB为单位
        double eps;// 训练停止的标准(误差小于eps停止)
        double C;// 惩罚因子,越大训练时间越长
        int nr_weight;// 权重的数目,目前只有两个值,默认为0
        int *weight_label;// 权重,元素个数由nr_weight决定
        double* weight;// C_SVC权重
        double nu;
        double p;
        int shrinking;// 训练过程是否使用压缩
        int probability;// 是否做概率估计
    };

3. 训练你的模型
在vs建立一个工程,把libsvm里的svm.h和svm.cpp导入你的项目中。
3.1 准备训练数据

svm_problem prob;
svm_parameter param;
/*train_x,train_y是我已经导入的数据,分别是样本及其对应的类别标签*/
void init_svm_problem()
{
    prob.l = train_size;        // 训练样本数
    prob.y = new double[train_size];
    prob.x = new svm_node*[train_size];
    svm_node* node = new svm_node[train_size*(1 + feature_size)];
    prob.y = vec2arr(train_y);
    // 按照格式打包
    for (int i = 0; i < train_size; i++)
    {
        for (int j = 0; j < feature_size; j++)
        {   // 看不懂指针就得复习C语言了,类比成二维数组的操作
            node[(feature_size + 1) * i + j].index = j + 1;
            node[(feature_size + 1) * i + j].value = train_x[i][j];
        }
        node[(feature_size + 1) * i + feature_size].index = -1;
        prob.x[i] = &node[(feature_size + 1) * i];
    }
}

3.2 设置训练参数

void init_svm_parameter()
{
    param.svm_type = C_SVC;   // 即普通的二类分类
    param.kernel_type = RBF;  // 径向基核函数
    param.degree = 3;
    param.gamma = 0.01;
    param.coef0 = 0;
    param.nu = 0.5;
    param.cache_size = 1000;
    param.C = 0.09;
    param.eps = 1e-5;
    param.p = 0.1;
    param.shrinking = 1;
    param.probability = 0;
    param.weight_label = NULL;
    param.weight = NULL;
}

上面的C和gamma是我进行调优过的,用于你的数据时应该重新调整。

3.3 进行训练

int main()
{
    load_data();            // 导入训练及测试数据
    init_svm_problem();     // 打包训练样本
    init_svm_parameter();   // 初始化训练参数
    svm_model* model = svm_train(&prob, ¶m);
    svm_save_model("model", model);     // 保存训练好的模型,下次使用时就可直接导入
    int acc_num = 0;        // 分类正确数
    //svm_model* model = svm_load_model("model");
    for (int i = 0; i < test_size; i++)
    {
        svm_node* node = init_test_data(vec2arr(xdata[i]));
        double pred = svm_predict(model, node);
        if (pred == label[i])
            acc_num++;
    }
    cout << "accuracy: " << acc_num*100.0 / test_size << "%" << endl;
    cout << "classification: " << acc_num << " / " << test_size << endl;
    return 0;
}

3.4 训练及测试结果
【机器学习】用libsvm C++训练SVM模型_第1张图片
正确率几乎达到100%,可见分类效果是非常好的(这也是我一直钟情于SVM的原因)!
训练你的模型吧!

你可能感兴趣的:(机器学习,算法)