支持向量機算法及其代碼實現

支持向量機算法及其代碼實現

支持向量機(SVM),起初由vapnik提出時,是作爲尋求最優(在一定程度上)二分類器的一種技術。後來它又被拓展到迴歸和聚類應用。SVM是一種基於核函數的方法,它通過某些核函數把特徵向量映射到高維空間,然後建立一個線性判別函數(或者說是一個高維空間中的能夠區分訓練數據的最優超平面,參考異或那個經典例子)。假如SVM沒有明確定義核函數,高維空間中任意兩點距離就需要定義。

解是最優的在某種意義上是兩類中距離分割面最近的特徵向量和分割面的距離最大化。離分割面最近的特徵向量被稱爲”支撐向量”,意即其它向量不影響分割面(決策函數)。

有很多關於SVM的參考文獻,這是兩篇較好的入門文獻。

【Burges98】 C. Burges. "A tutorial on support vector machines for pattern recognition", Knowledge Discovery and Data Mining 2(2), 1998. (available online at [1]).

LIBSVM - A Library for Support Vector Machines. By Chih-Chung Chang and Chih-Jen Lin ([2])

CvSVM支撐矢量機

class CvSVM : public CvStatModel //繼承自基類CvStatModel
{
public:
    // SVM type
    enum { C_SVC=100, NU_SVC=101, ONE_CLASS=102, EPS_SVR=103, NU_SVR=104 };//SVC是SVM分類器,SVR是SVM迴歸

    // SVM kernel type
    enum { LINEAR=0, POLY=1, RBF=2, SIGMOID=3 }; //提供四種核函數,分別是線性,多項式,徑向基,sigmoid型函數。

    CvSVM();
    virtual ~CvSVM();

    CvSVM( const CvMat* _train_data, const CvMat* _responses,
           const CvMat* _var_idx=0, const CvMat* _sample_idx=0,
           CvSVMParams _params=CvSVMParams() );

    virtual bool train( const CvMat* _train_data, const CvMat* _responses,
                        const CvMat* _var_idx=0, const CvMat* _sample_idx=0,
                        CvSVMParams _params=CvSVMParams() );

    virtual float predict( const CvMat* _sample ) const;
    virtual int get_support_vector_count() const;
    virtual const float* get_support_vector(int i) const;
    virtual void clear();

    virtual void save( const char* filename, const char* name=0 );
    virtual void load( const char* filename, const char* name=0 );

    virtual void write( CvFileStorage* storage, const char* name );
    virtual void read( CvFileStorage* storage, CvFileNode* node );
    int get_var_count() const { return var_idx ? var_idx->cols : var_all; }

protected:
    ...
};

CvSVMParamsSVM訓練參數struct

struct CvSVMParams
{
    CvSVMParams();
    CvSVMParams( int _svm_type, int _kernel_type,
                 double _degree, double _gamma, double _coef0,
                 double _C, double _nu, double _p,
                 CvMat* _class_weights, CvTermCriteria _term_crit );

    int         svm_type;
    int         kernel_type;
    double      degree; // for poly
    double      gamma;  // for poly/rbf/sigmoid
    double      coef0;  // for poly/sigmoid

    double      C;  // for CV_SVM_C_SVC, CV_SVM_EPS_SVR and CV_SVM_NU_SVR
    double      nu; // for CV_SVM_NU_SVC, CV_SVM_ONE_CLASS, and CV_SVM_NU_SVR
    double      p; // for CV_SVM_EPS_SVR
    CvMat*      class_weights; // for CV_SVM_C_SVC
    CvTermCriteria term_crit; // termination criteria
};

svm_type,SVM的類型:

CvSVM::C_SVC - n(n>=2)分類器,允許用異常值懲罰因子C進行不完全分類。
CvSVM::NU_SVC - n類似然不完全分類的分類器。參數nu取代了c,其值在區間【0,1】中,nu越大,決策邊界越平滑。
CvSVM::ONE_CLASS - 單分類器,所有的訓練數據提取自同一個類裏,然後SVM建立了一個分界線以分割該類在特徵空間中所佔區域和其它類在特徵空間中所佔區域。
CvSVM::EPS_SVR - 迴歸。 訓練集中的特徵向量和擬合出來的超平面的距離需要小於p。異常值懲罰因子C被採用。
CvSVM::NU_SVR - 迴歸;nu 代替了p
kernel_type//核類型:

CvSVM::LINEAR - 沒有任何向映射至高維空間,線性區分(或迴歸)在原始特徵空間中被完成,這是最快的選擇。 d(x,y) = x?y == (x,y)
CvSVM::POLY - 多項式核: d(x,y) = (gamma*(x?y)+coef0)degree
CvSVM::RBF - 徑向基,對於大多數情況都是一個較好的選擇:d(x,y) = exp(-gamma*|x-y|2)
CvSVM::SIGMOID - sigmoid函數被用作核函數: d(x,y) = tanh(gamma*(x?y)+coef0)
degree, gamma, coef0:都是核函數的參數,具體的參見上面的核函數的方程。

C, nu, p:在一般的SVM優化求解時的參數。

class_weights: Optional weights, assigned to particular classes. They are multiplied by C and thus affect the mis-classification penalty for different classes. The larger weight, the larger penalty on mis-classification of data from the certain class.

term_crit: Termination procedure for iterative SVM training procedure (which solves a partial case of constrained quadratic optimization problem) The structure needs to be initialized and passed to the training method of CvSVM

CvSVM::train訓練SVM

bool CvSVM::train( const CvMat* _train_data, const CvMat* _responses,
                   const CvMat* _var_idx=0, const CvMat* _sample_idx=0,
                   CvSVMParams _params=CvSVMParams() );

The method trains SVM model. It follows the conventions of generic train "method" with the following limitations: only CV_ROW_SAMPLE data layout is supported, the input variables are all ordered, the output variables can be either categorical (_params.svm_type=CvSVM::C_SVC or _params.svm_type=CvSVM::NU_SVC) or ordered (_params.svm_type=CvSVM::EPS_SVR or _params.svm_type=CvSVM::NU_SVR) or not required at all (_params.svm_type=CvSVM::ONE_CLASS), missing measurements are not supported.

所有的參數都被集成在CvSVMParams這個結構中。




CvSVM::get_support_vector*得到支撐矢量和特殊矢量的數

int CvSVM::get_support_vector_count() const;
const float* CvSVM::get_support_vector(int i) const;

這個方法可以被用來得到支撐矢量的集合。

補充:在WindowsXP+OpenCVRC1平臺下整合OpenCV與libSVM 雖然從RC1版開始opencv開始增設ML類,提供對常見的分類器和迴歸算法的支持。但是尚存在一些問題,比如說例子少(官方許諾說很快會提供一批新例子,見CVS版)。單說SVM這種算法,它自己提供了一套比較完備的函數,但是並不見得優於老牌的libsvm(它也應該參考過libsvm,至於是否效率優於libsvm,我並沒有作過測試,官方也沒有什麼說法,但是libsvm持續開源更新,是公認的現存的開源SVM庫中最易上手,性能最好的庫)。所以在你的程序裏整合opencv和libSVM還是一種比較好的解決方案。在VC中整合有些小地方需要注意,這篇文檔主要是提供把圖象作爲SVM輸入時程序遇到的這些小問題的解決方案。希望大家遇到問題時,多去讀libSVM的源碼,它本身也是開源的,C代碼寫得也很優秀,數據結構定義得也比較好。

首先是SVM的訓練,這部分我並沒有整合到VC裏,直接使用它提供的python程序,雖然網格搜索這種簡易搜索也可以自己寫,但是識別時只需要訓練生成的SVMmodel文件即可,所以可以和主程序分離開。至於python在windows下的使用,還是要設置一下的,首先要在系統環境變量path裏把python的路徑設進去,libsvm畫訓練等高線圖還需要gnuplot的支持,打開python源程序(grid.py),把gnuplot_exe設置成你機器裏的安裝路徑,這樣才能正確的運行程序。然後就是改步長和搜索範圍,官方建議是先用大步長搜索,搜到最優值後再用小步長在小範圍內搜索(我覺得這有可能會陷入局部最優,不過近似出的結果還可以接受)。我用的python版本是2.4,gnuplot4.0。

常用libSVM資料鏈接 官方站點,有一些tutorial和測試數據

哈工大的機器學習論壇,非常好

上交的一個研究生還寫過libsvm2.6版的代碼中文註釋,源鏈接找不着了,大家自己搜搜吧,寫得很好,上海交通大學模式分析與機器智能實驗室。

發佈了21 篇原創文章 · 獲贊 24 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章