機器學習教程 之 梯度提升方法:GBDT及其擴展模型XGBoost

Gradient boosting是一種廣泛被用於迴歸、分類和排序任務的集成方法,於2001年被Friedman提出
該類算法通過以上一輪基學習器的誤差的負梯度爲訓練目標訓練本輪的基學習器,不斷降低集成模型在訓練集上的偏差實現高精度的集成
基於Gradient Boosting算法的學習器被稱爲Gradient Boosting Machine(GBM),如果說AdaBoost是boosting方法的開山之作,那麼GBM就是boosting方法的集大成者。GBM幾乎刷新了各個領域衆多數據集的精度記錄,有人認爲GBM是性能最好的機器學習方法,這種說法有點激進,但通常各類數據競賽贏家的策略裏也確實都會有這類算法的方法或者思想

由於集成學習方法在實際應用中出色的性能,我曾經寫過幾篇這方面的博文,關於集成學習及其boosting方法的

機器學習教程 之 Boosting 與 bagging:集成學習框架
人工智能裏的數學修煉 | AdaBoost的數學原理: 分佈更新推導
機器學習教程 之 集成學習算法: 深入刨析AdaBoost

還有一片關於 bagging 類隨機森林的
機器學習教程 之 隨機森林: 算法及其特徵選擇原理

感興趣的朋友可以瞭解一下,可以幫助你們更好的瞭解集成學習的整體情況
其實很早就打算着手寫GBDT還有XGBoost,但是之前一直感覺還不太能駕馭,所以一直沒有動手,這次藉着課題組報告的機會花了一個星期把GBDT的大綱整理了一下做成了ppt,這篇文章是對ppt的解釋和擴充,算是給自己的一個總結和交待。

ppt在這裏,想要看精簡版的可以瞭解一下
Gradient Boost Decision Tree(GBDT)及其拓展模型

這篇文章主要分爲三個部分:

第一部分 以GBDT的迴歸模型來詳細講解模型的原理和算法
第二部分 講解GBDT的擴展實現:XGBoost
第三部分 這裏會介紹一下xgboost庫以及常用的GBDT類模型庫的調參方法

一、GBDT的迴歸模型

GBDT可以用於迴歸、分類、排序等各種任務,這裏以迴歸模型爲例進行講解是因爲GBDT在迴歸問題上可解釋性是最強的,分類及排序等模型只需要在迴歸原理上稍做修改即可。關於GBDT的理解主要有一下幾個比較重要的點

1. GBDT的基分類器爲CART樹(分類迴歸樹)
2. 一種boosting方法:Boosting Tree 提升樹
3. 加性模型與前向分佈算法
4. Gradient Boosting 梯度提升
5. GBDT採用的一些小技巧

接下來我會從這五個方面,一步一步的把GBDT說清楚

1.1 GBDT的基分類器:CART樹

CART樹的全稱是分類迴歸樹,這是一種二叉樹,可以處理分類與迴歸兩種問題,是Breiman於1984年提出的一種樹模型,後來他還基於這種方法提出了著名的隨機森林。

CART樹可以處理分類與迴歸兩種問題,處理兩類問題的策略不同,但分類樹與迴歸樹的生成框架是相同的,唯一不同的地方在於節點的屬性選擇標準。分類樹採用的選擇標準是Gini係數,認爲Gini係數小的屬性比較好,迴歸樹採用最小二乘計算每個屬性的劃分誤差,認爲劃分誤差小的屬性比較好

分類樹與普通的決策樹計算並沒有什麼不同,這裏主要講一下最小二乘迴歸樹的具體計算方法,迴歸樹主要有以下幾點:

1.迴歸樹在每個劃分節點都會得到一個預測值,以標籤是身高爲例,這個預測值就是這個節點上所有樣本身高的平均值

這裏寫圖片描述

2.分枝時遍歷所有的屬性進行二叉劃分,挑選使平方誤差最小的劃分屬性作爲本節點的劃分屬性

3.遍歷每個屬性找到使loss最小的屬性,令其爲當前節點的屬性
第t個屬性的平方誤差計算公式爲

這裏寫圖片描述

4.如果屬性有多種可能取值,需要遍歷所有可能的切分點,找到使loss最小的切分點作爲該屬性的二叉劃分點

5.對子集繼續選擇性的最優特徵進行劃分,直到每個葉子節點僅有一個樣本(這種情況是很少見或者難以實現的,通常會設定 一個允許葉子節點保留最少樣本數的參數,滿足條件即可停止,如果葉子節點有多個樣本值,以均值作爲該葉子節點的預測值)

以上就是迴歸樹相比於分類樹需要注意的地方

補充:爲什麼集成算法大多使用樹類模型作爲基學習器?或者說爲什麼集成學習可以在樹類模型上取得成功?

樹模型具有很多優良的性質,比如預測速度快、不需要進行特徵標準化、可解釋性強等優點,
但是單獨使用決策樹會有樹節點過深導致的過擬合等問題

而集成學習的bagging和boosting兩類主流算法:
bagging,關注於提升分類器的泛化能力,比如隨機森林就通過對樣本和特徵進行採樣訓練
基分類器來增強其整體對樣本變化的適應能力, 所以在隨機森林裏對於樹的max_depth這個
參數一般不會加以限制,bagging本身就是一種避免過擬合的方法

Boosting, 關注於提升分類器在訓練集上的精度,這似乎是一種容易過擬合的方法,但是
Boosting在設計時會有很多避免過擬合的技巧,比如設置max_depth,限制樹的最大深度、
限制葉子節點的最少樣本數量等方法避免過擬合,這些限制可能會降低單個樹的精度,但boosting
可以將集成的精度問題交給其爲精度提升而設計的框架去解決

所以不論是bagging還是boosting類的方法都可以做到單獨的決策樹無法做到的方面,從
而實現性能的提升

1.2 Boosting Tree 提升樹方法

簡單來說,Boosting Tree方法通過以上一輪基學習器的誤差爲訓練目標訓練本輪的基學習器,不斷降低集成模型在訓練集上的偏差實現高精度的集成

舉個例子:對於迴歸問題,如果我們預測的標籤值是20

這裏寫圖片描述

按照如上的圖例,第三次的預測標籤爲 20-13-8 = -1 ,不斷重複這個過程,直到生成指定數量的基分類最後將所有預測結果相加即爲集成模型的預測結果

1.3 加性模型與前向分步算法

Boosting方法大多采用加性模型來組合弱學習器,即可以將集成的學習器表示爲如下形式:

這裏寫圖片描述

這裏 hm 表示第 m 個基學習器, βm 表示第 m 個基學習器的係數, am 表示第 m 個基學習器的參數, M 表示基學習器的個數

對於剛剛提到的Boosting Tree方法,基學習器的係數 βm 爲1, 將加性模型簡寫爲

這裏寫圖片描述

在給定損失函數 L 以及訓練數據的條件下,學習加性模型 H(x) 就是一個搜尋參數 α 使得損失函數極小化的過程,即

這裏寫圖片描述

直接求解這個極小值是個很複雜的優化問題,我們採用前向分步算法來簡化這一問題。前向分步算法本質上是一種貪心算法,它通過每一步只學習一個基函數及其係數,逐步逼近優化目標來簡化複雜度

首先,我們來重寫一下加性模型的表達形式,共生成 M 個基分類器,當前迭代次數爲 m ,即在第 m 個循環中,Boosting Tree的加性模型可以寫爲

這裏寫圖片描述

前向分步算法只要求在第 m 輪時,優化當前輪次的基學習器的參數,使得損失函數最小以簡化算法,即

這裏寫圖片描述

這裏優化當前輪次的基學習器的參數,在經典的GBDT算法中,採取的是非常暴力的遍歷的方式, 即在每個節點劃分的時候,遍歷所有屬性和可能的節點劃分數值,在當前指定的損失函數下使損失達到最小,這點在之前提回歸樹的時候提到了

當我們採用平方損失函數,即

這裏寫圖片描述

我們有

這裏寫圖片描述

這裏的 r=yHm1(x) ,即上一輪基學習器訓練完成以後, m1 個基學習器與標籤的殘差,所以,對於迴歸問題的Boosting Tree 來說,每一步只需要擬合當前模型的殘差就可以了。這裏得強調一下,Boosting Tree擬合的殘差是在平方損失函數的前提下優化出來的結果,換了別了損失函數擬合的可能就不是殘差了

1.4 Gradient Boosting 梯度提升

Gradient Boosting 是GBDT的核心思想,它相比與 Boosting Tree 的主要改進在於:
Boosting Tree 對於每一輪基學習器,擬合的是當前模型與標籤值的殘差
GBDT 對於每一輪基學習器,擬合的是當前模型與標籤值的殘差的負梯度

這裏會有一些問題:

1. 什麼是殘差的負梯度?
2. 爲什麼擬和殘差的負梯度可以降低集成模型的損失,即爲什麼擬合殘差的負梯度是可行的?
3. 即便擬合殘差的負梯度是可行的,爲什麼不直接擬合殘差?擬合殘差的負梯度好在哪裏?

這幾個問題的難度是一次增加的,接下來我們一個一個來回答

1.4.1 什麼是殘差的負梯度?

對於 i=1,2,3,N 個樣本,每一個樣本的殘差負梯度的計算公式爲:

這裏寫圖片描述

看公式可能不太清楚,舉個例子:
對於平方損失函數 L(y,H(x))=1/2(yH(x))2 ,其殘差的負梯度爲 yH(x)
可以發現,當損失爲平方損失函數時,GBDT 和Boosting Tree的擬合對象是一致的,但這只是一個特例,GBDT對於迴歸問題常用的損失函數,及負梯度如下

這裏寫圖片描述

1.4.2 擬合殘差的負梯度爲什麼是可行的?

擬合殘差的負梯度是可以用泰勒展開來解釋的, 泰勒一階展開式:

這裏寫圖片描述

加性模型在第 m 輪可以寫爲 Hm=Hm1+hm
L(y,Hm1+hm) 作一階泰勒展開可以有:

這裏寫圖片描述

其中

這裏寫圖片描述

m1 輪殘差的梯度
加性模型在第 m 輪和 m1 輪的損失分別爲:

這裏寫圖片描述

我們希望每一輪性的基學習器之後損失都是下降的,即 loss1<loss2 , 那麼比較上面兩個式子,我們可以發現,損失能否下降,關鍵在於 Key=Lm1hm(xi;αm) 項的正負如何

很簡單的,我們只需要令 hm(xi;αm)=Lm1 ,則

這裏寫圖片描述

該項便會恆爲負,即損失會向着下降的方向移動,這其實也是梯度下降的思想。這裏令 hm(xi;αm)=Lm1 也就是令第 m 個學習器擬合當前模型殘差的負梯度

這裏寫圖片描述

在之前的boosting Tree還有殘差負梯度的推導中,我們已經說明了 hm(xi;αm) 的擬合對象和參數 αm 的搜索方法(遍歷)。這裏再具體說一下每一棵樹對於殘差負梯度的擬合

這裏寫圖片描述

m 個迴歸樹的葉子節點的值 βm 都是一個向量,j 爲第 m 個迴歸樹的葉子節點個數,需要注意的是,我們每棵樹擬合的對象是殘差的負梯度,但是一棵樹的每個葉子節點裏往往不僅僅只有一個樣本,而這些樣本又會有不同的標籤值,那麼每個葉子節點的值是怎樣確定的呢?我們之前說迴歸樹是採用取平均的方法,而GBDT沒有采用這種方式,而是採用了線性搜索一個參數來進行的優化。

這裏寫圖片描述

即以每一個葉子節點爲單元進行優化, 這裏的 bmj 表示是葉子節點的輸出值, ρmj 表示的是以損失函數最低爲目標進行線性搜索得到的值,所以,每課樹在訓練完成之後,其葉子節點的輸出值,是要經過一個 ρmj 的更新的,對於一些特殊的情況Fredman在論文中給出了ρmj 的估計式子,從而避免了線性搜索的計算量,關於這部分,我會具體的在下一篇關於GBDT的博文中進行展開的講解,上面的式子可以寫爲
這裏寫圖片描述

到目前爲止我們已經討論了GBDT的主要原理,包括:每一個基學習器的擬合目標是什麼?爲什麼對負梯度進行擬合是可行的?每個基學習器的參數αmρmj 是怎樣得到的?

1.4.3爲什麼GBDT要以殘差的負梯度替代Boosting Tree的殘差作爲基學習器的學習目標?

這是問的最多的一個問題,也是很難回答的一個問題。Boosting Tree 和 GBDT 兩者的相同之處在於,都是迭代迴歸樹,都是累加每棵樹的結果作爲最終結果,每棵樹都在學習前m-1棵樹尚存的不足,從總體流程和輸入輸出上兩者是沒有區別的

兩者的主要區別就在於每步迭代的時候是否使用殘差的負梯度作爲樹的擬合對象,前者不用殘差的負梯度而是使用殘差,是全局最優值,後者使用的是 局部最優方向(負梯度)*步長(β ),即前者是每一步都試圖讓結果變成最好,後者則每步試圖讓結果更好一點

Boosting Tree的最大問題在於,它依賴殘差進行優化,損失函數一般固定爲反應殘差的均方差損失函數,因此當均方差損失函數失效(該損失函數對異常值敏感)的時候,換了其他一般的損失函數,便很難得到優化的結果。同時,因爲損失函數的問題,它也很難處理迴歸之外問題。 而後者使用梯度下降的方法,對於任意可以求導的損失函數它都可以處理

GBDT本質上是以梯度下降的辦法簡化了Boosting Tree對於損失函數的優化求解問題

1.5 GBDT 裏用到的一些技巧

除了以上說明的梯度提升辦法,GBDT還採用了很多使用技巧,之所以說他們是技巧,是因爲這些方法在實際中取得成功,卻很難在理論上證明

1.5.1 Shrinkage 收縮

Shrinkage的思想認爲,每次走一小步逐漸逼近結果的效果,要比每次邁一大步很快逼近結果的方式更容易得到精確值,即它不完全信任每一棵殘差樹,認爲每棵樹只學到了真理的一部分累加的時候只累加了一小部分多學幾棵樹來彌補不足。 這個技巧類似於梯度下降裏的學習率

這裏寫圖片描述

學習率 是一個人爲設置的參數,用來調整學習的快慢和精度, 學習率一般取0.001到0.01,設置的越小,需要訓練的迴歸樹越多。

這裏寫圖片描述

1.5.1 重複使用屬性

在GBDT的每一棵迴歸樹中,一個屬性可以在多個節點用用到,更準確的說,這是CART樹本身具有的性質,CART每一個節點都是遍歷每一個屬性和劃分點得來的,即便是同一個屬性也有可能因爲不同的劃分點帶來不同的劃分效果

1.5.2樣本採樣

GBDT學習了隨機森林裏的樣本採樣方法,每一棵樹基於原始樣本的一個子集進行訓練達到防止過擬合和提升訓練速度的目的

到這裏爲止,我們就講完了GBDT迴歸模型的全部內容

二、GBDT的最強實現 Extreme Gradient Boosting (XGBoost)

XGBoost是華盛頓大學的陳天奇博士於2014年開源的一個GBDT庫,論文發於2016年,它在算法層面和實現層面較以往的GBDT有很大改進,在實踐中,精度有很大的提升同時,計算速度較傳統的GBDT實現也快了近10倍量級
XGBoost在算法層面相比於GBDT做出的改進主要有以下幾點:

2.1 顯式的將樹模型的複雜度作爲正則項加在優化目標裏

數學模型的修改:

這裏寫圖片描述

上式中 M 代表基分類器的個數,Ω(hm) 代表第 m 棵樹模型的複雜度
那麼,XGBoost是具體以怎樣方式來描述樹模型的複雜度的?

首先,我們將一棵迴歸樹的定義做一下細化,將一棵樹拆分爲結構部分 q 和葉子權重部分 w

hm=wq(x)

上式中 q 代表從輸入到輸出的映射結構,w 是一個向量,向量的元素是每個葉子節點的值。( xϵRl,q:Rl>T,wϵRT ,這裏的T代表葉子節點的數量,下圖中的T爲3)

這裏寫圖片描述

每一棵樹的正則項 Ω(hm) 由兩部分組成:

2.2 GBDT用了泰勒展開的一階導數信息,XGBoost將它擴展到了二階信息

XGBoost的損失函數:

這裏寫圖片描述

根據前向分佈算法,在第m輪優化的目標就是
這裏寫圖片描述

將每棵樹拆分成葉子節點,即將 hw 表示,可將上式重寫爲
這裏寫圖片描述

當樹的結構q確定時,我們可以通過調整 wj 即葉子節點的輸出降低損失,對上式求導取0,可以得到優化值:
這裏寫圖片描述

上面這個式子可以理解爲對樹的結構 q 的一個打分函數,損失越小,結構 q 越好,不過我們不太可能在計算時枚舉所有的樹結構,一般採用的是貪心算法。即每一次嘗試去對已有的葉子加入一個分割。對於一個具體的分割方案,我們獲得的增益可由下式計算
這裏寫圖片描述

上式中 ab 代表新分裂的子節點,j 代表母節點,上式代表產生的兩個新的子節點損失之和與原先一個母節點的損失的差值的負值,該值越大,增益越大。

2.3 GBDT在XGBoost樣本採樣的基礎上,增加了屬性採樣防止過擬合

GBDT模仿了隨機森林的橫豎採樣,用以加速計算和防止過擬合

除了上述幾點算法層面的改進,XGBoost相比於GBDT在具體實現上還有一些其他的設計用以加速運行

三、XGBoost參數講解

XGBoost作爲一個集成的分類器,有着大約20個可調參數,但其中主要的也就一手之數,理解這些參數的意義可以更好的幫助我們理解和使用它,下面是xgboost的主要參數

class XGBRegressor(XGBModel, sklearn.base.RegressorMixin)

Parameters
max_depth : int 表示基分類器的最大深度 一般取3~6
learning_rate : float 學習率,一般取0.001~0.1
n_estimators : int 訓練的基分類器個數,默認100個
min_child_weight : int 葉子節點裏樣本預測值的最小和,用來防止過擬合,默認爲1
subsample : float 樣本採樣比例
colsample_bytree : float 屬性採樣比例
reg_alpha : float (xgb’s alpha) L1 正則項的係數
reg_lambda : float (xgb’s lambda) L2正則項的係數

關於XGBoost和GBDT的調參方法,我還有另一篇博客講述了具體的方法
機器學習教程 之 參數搜索:GridSearchCV 與 RandomizedSearchCV || 以阿里IJCAI廣告推薦數據集與XGBoostClassifier分類器爲例

參考文獻

[1] Chen T, Guestrin C. XGBoost: A Scalable Tree Boosting System[J]. 2016:785-794.
[2] Library W P. Classification and regression tree[J].
[3] Friedman J, Hastie T, Tibshirani R. Additive logistic regression: a statistical view of boosting (With discussion and a rejoinder by the authors)[J]. Annals of Statistics, 2000, 28(2):337-374.
[4] Friedman J H. Greedy Function Approximation: A Gradient Boosting Machine[J]. Annals of Statistics, 2001, 29(5):1189-1232.

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