LIBSVM和LIBLINEAR的優化

前面介紹了LIBSVM和LIBLINEAR的優化算法,下面簡單總結一下不同算法的應用場景吧:

  • 所有線性問題都是用LIBLINEAR,而不要使用LIBSVM。
  • LIBSVM中的不同算法,如C-SVM和nu-SVM在模型和求解上並沒有本質的區別,只是做了一個參數的變換,所以選擇自己習慣的就好。
  • LIBLINEAR的優化算法主要分爲兩大類,即求解原問題(primal problem)和對偶問題(dual problem)。求解原問題使用的是TRON的優化算法,對偶問題使用的是Coordinate Descent優化算法。總的來說,兩個算法的優化效率都較高,但還是有各自更加擅長的場景。對於樣本量不大,但是維度特別高的場景,如文本分類,更適合對偶問題求解,因爲由於樣本量小,計算出來的Kernel Matrix也不大,後面的優化也比較方便。而如果求解原問題,則求導的過程中要頻繁對高維的特徵矩陣進行計算,如果特徵比較稀疏的話,那麼就會多做很多無意義的計算,影響優化的效率。相反,當樣本數非常多,而特徵維度不高時,如果採用求解對偶問題,則由於Kernel Matrix過大,求解並不方便。反倒是求解原問題更加容易。

多分類問題

LIBSVM和LIBLINEAR都支持多分類(Multi-class classification)問題。所謂多分類問題,就是說每一個樣本的類別標籤可以超過2個,但是最終預測的結果只能是一個類別。比如經典的手寫數字識別問題,輸入是一幅圖像,最後輸出的是0-9這十個數字中的某一個。

LIBSVM與LIBLINEAR但實現方式卻完全不同。LIBSVM採取的one vs one的策略,也就是所有的分類兩兩之間都要訓練一個分類器。這樣一來,如果存在k個class,理論上就需要訓練 k(k?1)/2個分類器。實際上,libsvm在這一步也進行了一定的優化,利用已有分類的關係,減少分類器的個數。儘管如此,LIBSVM在多分類問題上還是要多次訓練分類器。但是,考慮到前面說的LIBSVM的優化方法,隨着樣本數量的增加,訓練的複雜度會非線性的增加。而通過1VS1的策略,可以保證每一個子分類問題的樣本量不至於太多,其實反倒是方便了整個模型的訓練。

而LIBLINEAR則採取了另一種訓練策略,即one vs all。每一個class對應一個分類器,副樣本就是其他類別的所有樣本。由於LIBLINEAR能夠和需要處理的訓練規模比LIBSVM大得多,因此這種方式要比one vs one更加高效。此外,LIBLINEAR還實現了基於Crammer and Singer方法的SVM多分類算法,在一個統一的目標函數中學習每一個class對應的分類器。

輸出文件

一般來說,我們使用LIBLINEAR或者LIBSVM,可以直接調用系統的訓練與預測函數,不需要直接去接觸訓練得到的模型文件。但有時候我們也可能需要在自己的平臺實現預測的算法,這時候就不可避免的要對模型文件進行解析。

由於LIBLINEAR與LIBSVM的訓練模型不同,因此他們對應的模型文件格式也不同。LIBLINEAR訓練結果的格式相對簡單,例如:

 1 solver_type L2R_L2LOSS_SVC_DUAL
 2 nr_class 3
 3 label 0 1 2 
 4 nr_feature 5
 5 bias -1
 6 w
 7 -0.4021097293855418 0.1002472498884907 -0.1619908595357437
 8 0.008699468444669581 0.2310109611908343 -0.2295723940247394
 9 -0.6814324057724231 0.4263611607497726 -0.4190714505083906
10 -0.1505088594898125 0.2709227166451816 -0.1929294695905781
11 2.14656708009991 -0.007495770268046003 -0.1880325536062815

上面的solver_type表示求解算法,w以下表示求解得到的模型權重。其中每一列對應一個class的分類器,而每一行對應特徵的一個維度。其中nr_class表示求解的個數,nr_feature表示特徵的維度,bias表示模型的bias,可以人工設置權重。這裏容易產生誤解的是label這個字段,表示的是每一個用戶訓練文件中label對應w的列數。比如在上面的模型中,用戶指定編號爲0的分類器對應w的第一列。但是上面的對應關係並不是一定存在的,比如在二分類場景中,用將整樣本標爲1,負樣本標爲0,但在模型訓練中,LIBLINEAR會按照自己的編號系統進行訓練,因而有可能出現負樣本在前,正樣本在後的情形。這時候,就必須要根據label 1 0將LIBLIENAR內部的編號體系與真實的用戶標籤進行對應。當然,後來LIBLINEAR和LIBSVM做了一些優化,在二分類時,如果正負樣本標籤分別是-1+1,那麼可以始終保證正樣本出現在w的第一列。但是這個機制也不是完全靠譜,比如說在LIBLINEAR的Spark實現代碼中,就沒有實現這個特性,曾經把我整的很慘。因此在這裏還是需要十分注意。

LIBSVM的訓練結果格式就更復雜一些,例如:

 1 kernel_type rbf
 2 gamma 0.0769231
 3 nr_class 3
 4 total_sv 140
 5 rho -1.04496 0.315784 1.03037
 6 label 1 0 -1
 7 nr_sv 2 2 1
 8 SV
 9 0 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
10 0 0.6416468628860974 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
11 0 1 1:0.333333 2:1 3:-1 4:-0.245283 5:-0.506849 6:-1 7:-1 8:0.129771 9:-1 10:-0.16129 12:0.333333 13:-1
12 0.2685466895842373 0 1:0.583333 2:1 3:1 4:-0.509434 5:-0.52968 6:-1 7:1 8:-0.114504 9:1 10:-0.16129 12:0.333333 13:1
13 0 1 1:0.208333 2:1 3:0.333333 4:-0.660377 5:-0.525114 6:-1 7:1 8:0.435115 9:-1 10:-0.193548 12:-0.333333 13:1

上面參數的意義都比較直接,需要注意的是SV後面就是訓練出的模型參數,以支持向量的方式進行存儲。nr_sv給出了每一個支持向量所對應的模型,比如“2 2 1”就表示前兩行是標籤爲1類的支持向量,其後面兩行是標籤爲0類的支持向量,最後一行是標籤爲-1類的支持向量。而具體每一行支持向量,在上面的模型中,由於存在三類,所以每一個支持向量有可能都會存在於兩個分類器中,所以前兩列的數分別對應了對剩下兩個分類作爲支持向量時候的α值,後面纔是真正的支持向量。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章