集成學習(5)boosting代表——XGBoost

XGBoost(eXtreme Gradient Boosting)中文名叫極端梯度提升,可以看出它是一種gradient boosting算法,事實上,XGBoost是GBDT的一種高效實現,并對GBDT做了一定的改進和優化,所以咱們最好結合著上一篇講過的GBDT來理解XGBoost。

1 XGBoost 原理

我們先來捋一遍XGBoost的原理及實現,首先,XGBoost和GBDT的基本思想都是一樣的,通過加法模型和前向分步算法來一步一步的靠近目標,得到很多個弱學習器,將這些弱學習器的預測值加起來作為最終的預測結果,如下圖所示預測家人對電腦游戲的喜歡程度:

\text{obj}(F_M(x)) = \sum_i^N L(y_i, F_M(x)) + \sum_{i=1}^M \Omega(f_i)

在前向分布算法中,每一步的前面各步的學習器都已經確定,因此針對每一步的目標函數是:

\text{obj}^{(m)} = \sum_i^n L[y_i, F_{m-1}(x)+f_m(x)] + \Omega(f_m)+constant

還是從損失函數是平方損失MSE開始理解,將MSE代入并展開可得(下式中兩個constant不同,第二個多了個(F_{m-1}(x_i)- y_i)^2項):

\begin{split}\text{obj}^{(m)} & = \sum_{i=1}^N [y_i - (F_{m-1}(x_i) + f_m(x_i))]^2 + \Omega(f_m)+constant\\ & = \sum_{i=1}^N [2(F_{m-1}(x_i)- y_i)f_m(x_i) + f_m(x_i)^2] + \Omega(f_m)+constant \end{split}

這個形式非常好,是當前變量f_m(x_i)的一次項(殘差)+二次項的形式,由這個形式去繼續推導和優化的話,想必是很nice的,但是對一般的損失函數來說,是很難展開成這個形式的,這意味著我們由MSE推導出的結果不具有普適性,每個損失函數的推導過程都會不一樣,怎么辦呢?如果能讓所有損失函數都成為一次項+二次項的形式就好了,于是大神們想到了泰勒展開,沒錯,這就是二階泰勒展開在XGBoost中的重要作用之一,它統一了損失函數的形式,解耦了損失函數與弱學習器之間的聯系,并以此優良特性支持了用戶自定義損失函數,我們來看看二階泰勒展開的過程及結果:

\begin{align} obj^{(m)} & = \sum\limits_{i=1}^NL[y_i, F_{m-1}(x_i)+ f_m(x_i)]+ \Omega(f_m)+constant \\ & \approx \sum\limits_{i=1}^m[ L(y_i, f_{m-1}(x_i)) + \frac{\partial L(y_i, f_{m-1}(x_i) }{\partial f_{m-1}(x_i)}f_m(x_i) + \frac{1}{2}\frac{\partial^2 L(y_i, f_{m-1}(x_i) }{\partial f_{m-1}^2(x_i)} f_m^2(x_i)]+ \Omega(f_m)+constant\end{align}

其中L(y_i, f_{m-1}(x_i))為定值,令:

g_{i}=\frac{\partial L(y_i, f_{m-1}(x_i))}{\partial f_{m-1}(x_i)}, \; h_{i}=\frac{\partial^2 L(y_i, f_{m-1}(x_i))}{\partial f_{m-1}^2(x_i)}

則目標函數為:

\begin{align} obj^{(m)} \approx \sum\limits_{i=1}^m[ g_if_m(x_i)+\frac{1}{2}h_if_m^2(x_i)]+ \Omega(f_m)+constant\end{align}

這樣形式就統一成一次項+二次項的形式了,

上式中obj^{(m)}就是我們在當前輪迭代中生成決策樹的目標函數,.可以發現,一個重要的特點是這個目標函數中,我們要求的f_m(x)與損失函數相關的項g_i,h_i是解耦的,這是一種“模塊化”的形式,正是這種損失函數和弱學習器的獨立性,使得XGBoost 能夠支持我們自定義損失函數,只要我們定義的損失函數二階可導,就不會影響XGBoost 的運行流程。

用二階展開還有一個好處,我們知道GBDT中使用損失函數的一階泰勒展開作為偽殘差來近似的,而二階泰勒展開式展開后與原目標函數更接近,算法收斂的更快更準,類似于牛頓法對比梯度下降的優勢。

至此目標函數中損失部分的形式確定了,還剩下正則項,在每一步的目標函數中,正則項表示當前步弱學習器(決策樹)的復雜程度,對決策樹的復雜度我們一般考慮其葉子結點數量,XGBoost還加入了對其葉子結點取值的正則,首先我們看看決策樹的表示:

f_t(x) = w_{q(x)}, w \in R^T, q:R^d\rightarrow \{1,2,\cdots,T\} .

因此正則化可表示為:

\Omega(f) = \gamma T + \frac{1}{2}\lambda \sum_{j=1}^T w_j^2

現在,綜合我們以上對XGBoost 算法原理及正則化的討論,可得我們的目標函數的形式:

\begin{split}\text{obj}^{(t)} &\approx \sum_{i=1}^n [g_i w_{q(x_i)} + \frac{1}{2} h_i w_{q(x_i)}^2] + \gamma T + \frac{1}{2}\lambda \sum_{j=1}^T w_j^2\\ & = \sum\limits_{j=1}^J (\sum\limits_{x_i \in R_{tj}}g_{ti}w_{tj} + \frac{1}{2} \sum\limits_{x_i \in R_{tj}}h_{ti} w_{tj}^2) + \gamma J + \frac{\lambda}{2}\sum\limits_{j=1}^Jw_{tj}^2\\ &= \sum^T_{j=1} [(\sum_{i\in I_j} g_i) w_j + \frac{1}{2} (\sum_{i\in I_j} h_i + \lambda) w_j^2 ] + \gamma T\end{split}

我們把每個葉子節點區域樣本的一階和二階導數的和單獨表示如下:

G_{tj} = \sum\limits_{x_i \in I_{tj}}g_{ti},\; H_{tj} = \sum\limits_{x_i \in I_{tj}}h_{ti}

損失函數可以表示為:

\text{obj}^{(t)} = \sum^T_{j=1} [G_jw_j + \frac{1}{2} (H_j+\lambda) w_j^2] +\gamma T

2 損失函數優化求解

目標是要最小化\text{obj}^{(t)},我們知道,\text{obj}^{(t)}中其實有兩個未知數是需要計算的,一個是比較明顯的w_j,表示在每個葉子結點上的取值;另一個是T,表示這棵樹有多少個葉子結點。先看w_j的求法,這個比較簡單,就是一個二次函數的極值求法,求導可得:

w_j^\ast = -\frac{G_j}{H_j+\lambda}

代入目標函數可得:

\text{obj}^\ast = -\frac{1}{2} \sum_{j=1}^T \frac{G_j^2}{H_j+\lambda} + \gamma T

要求葉子結點數量T,實際上就是樹的分裂問題,而且這次的分裂是有目標函數的,這跟以前的決策樹分裂不太一樣,以前都是自己根據樣本和label設定規則分裂的。既然有目標函數我們就按使得目標函數減小的方法分裂,我們定義:

Gain = \frac{1}{2} \left[\frac{G_L^2}{H_L+\lambda}+\frac{G_R^2}{H_R+\lambda}-\frac{(G_L+G_R)^2}{H_L+H_R+\lambda}\right] - \gamma

這個Gain很好理解,其中的幾項分別是: 1) 分裂后新的左子樹的目標函數值; 2) 分裂后新的右子樹的目標函數值;3) 為分裂時的原始樹的目標函數值;4) 正則項。思路就是找到分裂后使得目標函數減小最多的特征,以這個特征作為分裂特征即可。

3 正則化

除了原理中提到的目標函數中的正則項外,XGBoost還使用了另外兩種技術來進一步防止過擬合。

  • 第一種技術是由Friedman引入的Shrinkage。Shrinkage與模型優化中的學習率相似,收縮減小了每棵樹的影響,為未來樹改進模型留下了空間,在GBDT和Adaboost中也有這種方法的使用;

  • 第二種技術是列(特征)子抽樣。使用列子抽樣比傳統的行子抽樣(XGBoost也支持行子抽樣)更能防止過擬合,這就類似于隨機森林中的做法,而且列子樣本的使用也加速了后面描述的并行算法的計算。

4 缺失值的處理

缺失值導致三個問題:

  • 分裂特征選擇時怎么處理存在缺失值的特征?
  • 對于選定的分裂特征存在缺失值的情況,缺失值分裂到哪一邊?
  • 預測時遇到缺失值,往那邊分支走?

不同于GBDT中靠決策樹自身的能力來處理缺失值,xgboost模型提供了自己特有的缺失值處理方法,下面是針對上述三個問題xgboost給出的解決方法:

  • 在尋找split point的時候,不會對該特征為missing的樣本進行遍歷統計,只對該列特征值為non-missing的樣本上對應的特征值進行遍歷,通過這個技巧來減少了為稀疏離散特征尋找split point的時間開銷。在邏輯實現上,為了保證完備性,會分別處理將missing該特征值的樣本分配到左葉子結點和右葉子結點的兩種情形,計算增益后選擇增益大的方向進行分裂即可,如下圖所示:
  • 根據上面的方法得到分裂后缺失值的方向,可以作為缺失值或者指定的值指定分支的默認方向,這能大大提升算法的效率;

  • 如果在訓練中沒有缺失值而在預測中出現缺失,那么會自動將缺失值的劃分方向放到右子樹。

5 工程上的優化——提速

樹學習中最耗費時間的部分是將數據排序。為了降低排序成本,我們建議將數據存儲在內存單元中,我們稱之為塊。每個塊中的數據以壓縮列(compressed column, CSC)格式存儲,每列按對應的特征值排序。這個輸入數據布局只需要在訓練之前計算一次,并且可以在以后的迭代中重用。

6 總結

主要對比GBDT

  1. XGBoost使用CART做基分類器的時候,顯式地加入了正則項來控制模型的復雜度,有利于防止過擬合,提高泛化能力 ;
  2. 正則項里包含了樹的葉子節點個數、每個葉子節點上輸出的score的L2模的平方和,能更有效的防止過擬合;
  3. GBDT在模型訓練的時候只使用了一階導數信息,XGBoost對代價函數進行了二階泰勒展開,同時使用一階、二階導數信息,并且可以自定義代價函數;
  4. 傳統GBDT使用CART作為基分類器;XGB支持多種類型的基分類器,如線性分類器,這時候其實XGBoost就是一個線性模型;
  5. 缺失值: 傳統GBDT沒有專門針對缺失值進行處理;XGBoost有專門的缺失值的處理策略:
  • 指定缺失值的分隔方向:可以為缺失值或者指定的值指定分支的默認方向,為了保證完備性,會分別處理將missing該特征值的樣本分配到左葉子結點和右葉子結點的兩種情形,分到那個子節點帶來的增益大,默認的方向就是哪個子節點,這能大大提升算法的效率;
  • 忽略缺失值:在尋找splitpoint的時候,不會對該特征為missing的樣本進行遍歷統計,只對該列特征值為non-missing的樣本上對應的特征值進行遍歷,通過這個工程技巧來減少了為稀疏離散特征尋找splitpoint的時間開銷 。
  1. Shrinkage(縮減),相當于學習速率(xgboost中的eta)。每次迭代,增加新的模型,在前面成上一個小于1的系數,降低優化的速度,每次走一小步逐步逼近最優模型比每次走一大步逼近更加容易避免過擬合現象;
  2. 抽樣
  • 列抽樣(column subsampling)。xgboost借鑒了隨機森林的做法,支持列抽樣(即每次的輸入特征不是全部特征),不僅能降低過擬合,還能減少計算,這也是xgboost異于傳統gbdt的一個特性。
  • 行抽樣:傳統GBDT在每輪迭代時使用全部的數據;XGB則采用了類似RF的策略,支持對數據進行采樣
  1. 并行化處理:
  • 在訓練之前,預先對每個特征內部進行了排序找出候選切割點,然后保存為block結構,后面的迭代中重復地使用這個結構,大大減小計算量。
  • 在進行節點的分裂時,需要計算每個特征的增益,最終選增益最大的那個特征去做分裂,那么各個特征的增益計算就可以開多線程進行,即在不同的特征屬性上采用多線程并行方式尋找最佳分割點。

BoostedTree.pdf ——Tianqi Chen
XGBoost: A Scalable Tree Boosting System ——Tianqi Chen
XGBoost文檔

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。