1. 程式人生 > >【機器學習】用libsvm C++訓練SVM模型

【機器學習】用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, &param);
    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 訓練及測試結果
這裡寫圖片描述
正確率幾乎達到100%,可見分類效果是非常好的(這也是我一直鍾情於SVM的原因)!
訓練你的模型吧!