轉載自: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×|u−v| 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。