OpenCV學習筆記(13)-boosting

決策樹很有用,但是他們並不是最好的分類器.在本節和下節,我們講述兩種計數:boosting和隨機森林.它們在內部使用了決策樹,所以繼承了樹的很多有用的性能(能夠處理混合數據類型、沒有歸一化的數據、特徵缺失)。這些技術能夠獲得相當好的性能,因此它們通常是ML庫中最好的監督學習的算法。

在監督學習領域,有一個叫統計提升(meta-Learning)的學習算法.Keans想知道可不可能從很多弱分類器中學習到一個強分類器.第一個boosting算法,叫AdaBossting,由Freund和Schapire提出.OpenCV包含了4種類型的boosting:

1.CvBoost::DISCRETE(discrete AdaBoost)

2.CvBoost::REAL(real AdaBoost)

3.CvBoost::LOGIT(LogitBoost)

4.CvBoost::GENTLE(gentle AdaBoost)

它們都是由原始AdaBoost變換而來的.我們發現real AdaBoost和gentle AdaBoost的效果最好.Real AdaBoost利用置信區間預測,在標籤數據上有很好的性能.Gentle AdaBoost對外圍數據(outlier data)賦較小的值,所以在迴歸問題上效果很好.LogitBoost也可以很好的處理迴歸問題.只需要設置以下標誌參數,就可以使用不同的AdaBoost算法,所以在處理實際問題的時候,可以嘗試所有的算法,然後挑選最好的那個.下面我們討論原始的AdaBoost算法.注意,OpenCV執行的boosting算法,是一個兩類分類器(不像決策樹和隨機森林).還有LogitBoost和GentleBoost不僅可以用來解決兩類分類,還可以用於迴歸問題.

AdaBoost

boosting算法訓練了T個弱分類器ht,t∈{1,....,T}.這些弱分類器很簡單.大多說情況下,它們只是包含一次分裂(稱爲決策stumps)或僅有幾次分裂(可能到3次)的決策樹.最後做決定的時候將複製權重αt給每個分類器.AdaBoost訓練時輸入的特徵向量是xi,向量的類別標籤是yi(這兒i=1,...,M,M是樣本總數),且yi∈{1,-1}.首先,我們初始化數據樣本的權值Di(i)來告訴分類器

將一個數據點分類錯誤的代價是多少.boosting算法的主要特徵是,在訓練過程之中,這個代價將會更新,使得後來的弱分類器更加關注與前面的分類器沒有分對的數據點.算法如下.

1.D1(i) = 1/m ,  i=1,...,m

2.針對t=1,..,T:


                   

注意,在2b步,如果找不到小於20%錯誤率的分類器,則停止,表明可能需要更好的特徵.

當前面講的訓練算法結束之後,最後的強分類器接受輸入向量x,使用所有弱分類器的加權和來進行分類.


這裏,符號函數把所有正數變爲1,把所有的負數變爲-1(0仍然爲0).

boosting代碼

.../opencv/samples/c/letter_recog.cpp展示了怎麼使用boosting,隨機森林和反向傳播網絡(即多層傳感網絡,MLP).boosting的代碼與決策樹的代碼相似,但是除了決策樹的參數,它還擁有自己的控制參數.


在CvBoostParams中,boost_type從前面列出的四個算法中作出選擇.

split_ctrteria爲下面的值之一:

CvBoost::DEFAULT(默認配置)

CvBoost::GINI(real AdaBoost的默認配置)

CvBoost::MISCLASS(discrete AdaBoost的默認配置)

CvBoost::MISCLASS(discrete AdaBoost的默認配置)

CvBoost::SQERR(最小平方誤差:只能在LogitBoost和gentle AdaBoost時使用)

最後一個參數weight_trim_rate用於保存計算結果.當訓練進行時,很多數據點變得不重要.也就是說,第i個點的權值Dt(i)變得很小.weight_trim_rate是一個0到1(包含)的閾值,在給定的boosting迭代中暗中丟棄一些數據點.例如:weight_trim_rate是0.95.這意味這樣本總權值小於1.0-0.95 = 0.05的點將不參加訓練的下一次迭代.這些點兵不是永久刪除.當下一個弱分類器訓練結束,所有的點的權值將被重新計算,有些前面被丟棄的樣本可能進入下一個訓練集合.關閉這個功能,只需要將weight_trim_rate置爲0即可.

我們觀察到CvBoostPrams{}是繼承於CvDTreeParams{}是繼承於CvDTreeParams{},所以可以設置其他與決策樹有關的參數.實際情況下,如果處理的特徵有丟失,可以設置CvDTreeParams::use_surrogates,它可以保證每次分裂選取的特徵將被存儲在相應的節點中.另一個重要的參數是使用proirs來設置將非物體任務是物體的代價.再說一次,如果我們訓練有毒和五毒的蘑菇,我們可以設置prior是爲float  priors = {1.0,10.0};如此一來,把有毒蘑菇標記爲無毒的錯誤代價則比把無毒蘑菇標記爲有毒的代價大10倍.

CvBoost類包含成員變量weak,他是一個CvSeq*類型的指針,指向繼承於CvDtree決策樹的弱分類器.LogitBoost和GentleBoost中,決策樹是迴歸樹,其他的boosting算法中決策樹則只判斷類別0和類別1.CvBooatTree的聲明如下:


boosting算法的訓練和決策樹的訓練幾乎一樣.不同的是多了一個外部參數update,它的默認值爲0.這樣,我們重新訓練所有的弱分類器.如果update設置爲1,我們就把新訓練出的弱分類器加到已經存在的弱分類器集合中.訓練boost分類器的函數原型如下:


../opencv/samples/c/letter_recog.cpp中有一個訓練boosting分類器的例子.訓練部分的代碼片段如下.



在預測中,我們傳入一個特徵向量sample,predict()函數返回一個預測值.

當然,有一些可選參數.第一個參數是missing,與決策樹相同,他包含一個與sample向量維度相同的字節類型向量,非0標誌着特徵的丟失.(注意這個標識只有在訓練分類器時使用了CvDTreeParams::use_surrogates的前提下才有效)

如果想得到每個弱分類器的輸出,可以傳出一個浮點型的CvMat向量weak_response,它的長度和弱分類器的個數一樣.如果向量weak_response被傳入,預測函數將根據每個分類器的輸出填充這個向量

CvMat* weak_responses = cvCreateMat(

        1,

         boostedClassifier.get_weak_predictors()->total,

         CV_32F

);

預測函數的下一個參數slice指定使用弱分類器的哪個相鄰子集,它可以這樣設置:

inline CvSlice cvSlice(int start , int end);

但是我們通常使用默認值,把slice設置爲"所有弱分類器"(CvSlice slice = CV_WHOLE_SEQ).最後,我們看raw_mose,它的默認值爲False,但是可以設置爲true.這個參數的用法與決策樹完全一樣,標誌着數據是否已經歸一化.正常情況下,我們不實用這個參數.調用boost預測的例子如下:boost.predict(temp_sample,0,weak_response);

最後,一些輔助函數可以使用.我們可以使用void CvBoost::prune(CvSlice slice)來從模型中去除一個弱分類器.

我們也可以使用 CvSeq* CvBoost::Get_weak_predictor()來獲取所有的弱分類器.這個函數返回一個類型爲CvSeq* 的指針序列,序列中元素爲CvBoostTree類型.


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