作者:JSong, 日期:2017.10.10
集成學習(ensemble learning)通過構建並結合多個學習器來完成學習任務,常可獲得比單一學習器顯著優越的泛化性能,這對“弱學習器”尤為明顯。
目前,有三種常見的集成學習框架:bagging,boosting和stacking。第一種是並行的,各個基學習器之間不存在強依賴關系,代表是隨機森林算法。后兩者是串行的,基學習器之間存在強依賴關系,必須串行生成。具體可參見我的文章 機器學習|集成學習。
1、前向分步算法(forward stagewise algorithm)
考慮加法模型
其中, \(b(x;\gamma_{m}),\,\beta_{m}\) 分別為基函數和基函數的系數。
在給定訓練數據及損失函數 \(L(y,f(x))\) 的條件下,學習加法模型成為一個極小化問題:
這是一種典型的加法模型,令
當M=m時,代入上面的式子可得
即我們可以通過構造迭代把求解所有參數的問題簡化為逐次求解每一對參數的問題(這是一種貪婪的算法)。
算法(前向分步算法):
(1). 初始化\(f_{0}(x)=0\);
(2). 對m=1,2,...M
(a). 極小化損失函數:
\[(\beta_{m},\gamma_{m})=\arg_{\beta_{m},\gamma_{m}}\min\sum_{i=1}^{N}L\left(y_i,f_{m-1}(x)+\beta_{m}b(x_i;\gamma_{m})\right) \]得到參數 \(\beta_m,\,\gamma_m\)
(b). 更新:
\[f_{m}(x)=f_{m-1}(x)+\beta_{m}b(x;\gamma_{m}) \](3). 得到加法模型
\[f(x)=f_{M}(x)=\sum_{i=m}^{M} \beta_{m}b(x;\gamma_m) \]
2、AdaBoost算法
前向分布算法是一種算法的框架,接下來我們對於二分類問題構造一個具體的boosting算法。
考慮二分類問題,令 \(y\in \{-1,1\}\) ,在邏輯回歸模型中,對應的損失函數是log(1+exp(-yf(x))), 這里我們用x近似log(1+x),選取一個簡單的指數損失函數:
同時規定所有的基函數滿足 \(b(x;\gamma)\in \{-1,1\}\) ,利用前向分布算法,我們每一步需要極小化損失函數:
其中 \(\bar{w}_{mi}=\exp[-y_{i}f_{m-1}(x_i)]\) ,其與 \(\gamma\) 和 \(\beta\) 都無關,所以不影響到上述的極小化。
在上述這個損失函數中,兩個參數之間存在耦合項,在不確定b的形式時無法用導數求極值。考慮到b只能取值1和-1,繼續簡化上述損失函數可得:
在這個式子中,兩個參數實現了分離,計算它的梯度會發現,其等價於兩個極小化問題。首先求解極小化問題:
帶入損失函數中,再利用導數求解參數 \(\beta\) 的值:
其中
求解導數值可得
注:此時的 \(e_{m}\) 與 \(\gamma_{m}\) 的極小化函數完全等價,又注意到 \(w_{mi}\) 和為1,所以不妨把 \(\gamma_{m}\) 的極小化函數修改為 \(e_m\), 這個意義下 \(e_m\) 即是基函數的分類誤差率。
注意到,這個時候事實上並不需要參數 \(\gamma\) 的顯示存在,其隱形的存在於每個基函數的訓練時使用的損失函數中,更進一步,其代表了每個樣本的權重。通俗點講,算法在串行迭代過程中,那些分類不准確的樣本點在下一步的基分類模型中是會被重點照顧。
最后我們把上述過程整理成Adaboost算法
算法(Adaboost算法):
(1). 初始化訓練數據的權值分布
\[D_1=(w_{11},\cdots,w_{1i},\cdots,w_{1N}),\,\,w_{1i}=\frac{1}{N} \](2). 對m=1,2,...M
( a ). 使用具有權值分布 \(D_{m}\) 的訓練數據集學習,得到基本分類器
\[G_{m}(x): X \rightarrow\{-1,1\} \]\[G_{m}(x)=\arg_{G(x)}\min\sum_{i=1}^{N}w_{mi}\mathcal{I}(G(x_i)\neq_{}y_{i}) \]( b ). 計算 \(G_{m}(x)\) 在訓練數據集上的分類誤差率
\[e_{m}=Pr(G_{m}(x_i)\neq_{}y_{i})=\sum_{i=1}^{N}w_{mi}\mathcal{I}(G(x_i)\neq_{}y_{i}) \]( c ). 計算 \(G_{m}(x)\) 的系數
\[\alpha_{m}=\frac{1}{2}\ln\frac{1-e_m}{e_m} \]( d ). 更新訓練數據集的權值分布
\[D_{m+1}=(w_{m+1,1},\cdots,w_{m+1,i},\cdots,w_{m+1,N}) \]\[w_{m+1,i}=\frac{w_{mi}\exp(-\alpha_{m}y_{i}G_{m}(x_i))}{Z_m} \]這里 \(Z_m\) 是規范化因子,它使得 \(\sum_{i}w_{m+1,i}=1\)
(3). 構建基本分類器的線性組合
\[f(x)=\sum_{m=1}^{M}\alpha_{m}G_{m}(x) \]得到最終分類器
\[G(x)=sign(f(x))=sign\left(\sum_{i=m}^{M}\alpha_{m}G_{m}(x)\right) \]
一些注釋
1、\(\alpha_m\) 表示 \(G_{m}(x)\) 在最終分類器中的重要性(和並不為1),當 \(e_m\) 不大於 1/2 時, \(\alpha_m\) 非負,且隨着 \(e_m\) 的減小而增大,即分類誤差率越小的基礎分類器越重要。
2、訓練集數據的權值分布可以寫成:
由此可知,被基礎分類器誤分類樣本權值得以擴大,而被正確分類樣本權值得以縮小,且這個縮放的倍數是指數級別的。通過不斷改變訓練數據的權值分布,使得訓練數據在每個基礎分類器的訓練中起到不同的作用,同時也使得模型的方差得以降低(過擬合)。
3、Friedman指出Adaboost事實上是基於邏輯回歸的加法模型。
在上面的這些論述,我們從從損失函數出發推導出Adaboost算法的,指數損失函數在Adaboost算法中有很重要的作用,但它不是Adaboost算法核心的思想。Adaboost算法最大的魅力在於它在給樣本分配權重,那根據這個思路,即只限定到Adaboost算法的第(2)(b)步,看看我們能不能推出損失函數來(限定每個基礎分類器的輸出為1或-1)。
經過一些計算,我們發現損失函數必須滿足以下幾個條件(加上可導就差不多充要了)
- 分離性
- 關於xf(x)值不變?
而指數損失函數正好滿足,而且相對也簡單
3、Gradient Boosting
一條不一樣的路,待續
Adaboost算法的推導過程
回到前向分步算法,給定初始 \(f_0(x)\) 后, 我們每一步迭代需要計算如下最優化問題
在不清楚基礎分類器的情況下,它是一個泛函,很難求解。現在我們換一個思路,上式可以寫成
此時損失函數可以看成是關於 \(\{f_{m}(x_i)\}\) 的函數,這個時候就可以用梯度下降算法來求解啦:
這里的步長不是固定值,而是設計為
最終可得Gradient Boosting 回歸算法
算法:Gradient Boosting
輸入: 訓練集 X和y,一個可微的損失函數 \(L(y,f(x))\),迭代數M
算法:
(1). 用一個常數值初始化:
\[f_{0}(x)=\arg_{\gamma}\min\sum_{i=1}^{N}L(y_i,\gamma) \](2). For m=1 to M:
(a) 計算偽殘差:
\[\gamma_{im}=-\left[\frac{\partial\,L(y_{i},f(x_{i}))}{\partial\,f(x_{i})}\right]_{f(x)=f_{m-1}(x)} \]根據偽殘差擬合一個基礎分類器(例如決策樹)\(b_{m}(x)\),即利用訓練集 \(\{x_{i},\gamma_{im}\}\) 訓練基礎分類器.
( c ) 計算乘子:
\[\beta_{m}=\arg_{\beta}\min\sum_{i=1}^{n}L(y_i,f_{m-1}(x_{i})+\beta_{}b_{m}(x_{i})) \](d) 更新模型:
\[f_{m}(x)=f_{m-1}(x)+\beta_{m}b_{m}(x) \](3) 輸出 \(f_{m}(x)\)
對於回歸任務,最常用的損失函數是L2測度,此時
剛好是模型的殘差。另外常用的損失函數還有L1測度和修正的Huber loss函數(L1測度存在不可導點)
- L1測度(絕對值損失函數):
- Huber 損失函數:
對於分類任務,假設一共有K類,我們首先建立K個score函數 \(F_{1}(x)、\ldots,F_{K}(x)\)
其次將score函數用於計算概率:
然后擬合K個模型就好,其中可以用K-L散度作為損失函數。這種方法的好處在於對異常值不敏感。
Gradient tree boosting
Gradient boosting 一般使用決策樹(尤其是CART)作為基礎分類器。針對這種特殊情況,Friedman設計了一個修正的gradient boosting 算法。
在第m步,模型需要擬合一顆決策樹 \(b_{m}(x)\). 令 \(J_m\) 是葉子數目,該決策樹將輸入空間分配到不相交的 \(J_m\) 個區域中: \(R_{1m},\ldots,R_{J_{m}m}\) ,並把每一個區域中的輸入預測為常數。利用示性函數,我們可以把決策樹的輸出寫為:
其中 \(v_{jm}\) 是對應區域預測的值。
將該系數乘以某個值,並利用線性搜索方法使得損失函數最小化:
Friedman 提出可以針對每一個區域選出一個最好的乘子 \(\beta\), 並且把這種方法稱為 “Tree Boost”:
4、XGBoost
我們重新來考慮 Tree Boosting. 給定含n個樣本m個特征的數據集:
假定基礎模型是CART決策樹,當決策樹的葉子數為T時,Tree將輸入值划分到T個區域,每一個區域都有指定的值,令 \(q:\mathbb{R}^{m}\rightarrow\{1,2,\ldots,T\}\) 為數的結構,則決策樹的輸出可以表示為:
XGBoost 不考慮梯度,直接將損失函數泰勒展開知道二階導數
二階泰勒逼近可以快速優化上述問題
其中g和h是l的一階導數和二階導數(自變量為 \(\hat{y}\) ). 可以看到第一項是常數項,所以我們只需要優化第二項。
另外指定正則項為
則上式可以重寫為
其中 \(I_{j}=\{i|q(x_i)=j\}\) . 對於固定的決策樹結構 q(x), 我們可以計算葉子j上的最優權重 \(w_{j}^{* }\) :
以及對應的損失函數
上式可以用於度量決策樹結構q,可以當成打分函數。我們可以遍歷所有的結構找到最優的決策樹。當然一般的遍歷所有決策樹是不可能的,一個貪婪的想法是將其作為增益函數,每一次嘗試去對已有的葉子加入一個分割,對於一個具體的分割方案,我們可以獲得的增益可以由如下公式計算:
-
傳統GBDT以CART作為基分類器,xgboost還支持線性分類器,這個時候xgboost相當於帶L1和L2正則化項的邏輯斯蒂回歸(分類問題)或者線性回歸(回歸問題)。
-
傳統GBDT在優化時只用到一階導數信息,xgboost則對代價函數進行了二階泰勒展開,同時用到了一階和二階導數。順便提一下,xgboost工具支持自定義代價函數,只要函數可一階和二階求導。
-
xgboost在代價函數里加入了正則項,用於控制模型的復雜度。正則項里包含了樹的葉子節點個數、每個葉子節點上輸出的score的L2模的平方和。從Bias-variance tradeoff角度來講,正則項降低了模型的variance,使學習出來的模型更加簡單,防止過擬合,這也是xgboost優於傳統GBDT的一個特性。
-
Shrinkage(縮減),相當於學習速率(xgboost中的eta)。xgboost在進行完一次迭代后,會將葉子節點的權重乘上該系數,主要是為了削弱每棵樹的影響,讓后面有更大的學習空間。實際應用中,一般把eta設置得小一點,然后迭代次數設置得大一點。(補充:傳統GBDT的實現也有學習速率)
-
列抽樣(column subsampling)。xgboost借鑒了隨機森林的做法,支持列抽樣,不僅能降低過擬合,還能減少計算,這也是xgboost異於傳統gbdt的一個特性。
-
對缺失值的處理。對於特征的值有缺失的樣本,xgboost可以自動學習出它的分裂方向。
-
xgboost工具支持並行。boosting不是一種串行的結構嗎?怎么並行的?注意xgboost的並行不是tree粒度的並行,xgboost也是一次迭代完才能進行下一次迭代的(第t次迭代的代價函數里包含了前面t-1次迭代的預測值)。xgboost的並行是在特征粒度上的。我們知道,決策樹的學習最耗時的一個步驟就是對特征的值進行排序(因為要確定最佳分割點),xgboost在訓練之前,預先對數據進行了排序,然后保存為block結構,后面的迭代中重復地使用這個結構,大大減小計算量。這個block結構也使得並行成為了可能,在進行節點的分裂時,需要計算每個特征的增益,最終選增益最大的那個特征去做分裂,那么各個特征的增益計算就可以開多線程進行。
-
可並行的近似直方圖算法。樹節點在進行分裂時,我們需要計算每個特征的每個分割點對應的增益,即用貪心法枚舉所有可能的分割點。當數據無法一次載入內存或者在分布式情況下,貪心算法效率就會變得很低,所以xgboost還提出了一種可並行的近似直方圖算法,用於高效地生成候選的分割點
[2]. Friedman. Greedy function approximation: A gradient boosting machine.