lightgbm,xgboost,gbdt的區別與聯系


今天是周末,之前給自己定了一個小目標:每周都要寫一篇博客,不管是關於什么內容的都行,關鍵在於總結和思考,今天我選的主題是梯度提升樹的一些方法,主要從這些方法的原理以及實現過程入手講解這個問題。

本文按照這些方法出現的先后順序敘述。

GBDT

梯度提升樹實在提升樹的基礎上發展而來的一種使用范圍更廣的方法,當處理回歸問題時,提升樹可以看作是梯度提升樹的特例(分類問題時是不是特例?)。 因為提升樹在構建樹每一步的過程中都是去擬合上一步獲得模型在訓練集上的殘差。后面我們將會介紹,這個殘存正好是損失函數的梯度,對應於GBDT每一步要擬合的對象。

主要思想

在目標函數所在的函數空間中做梯度下降,即把待求的函數模型當作參數,每一步要擬合目標函數關於上一步獲得的模型的梯度,從而使得參數朝着最小化目標函數的方向更新。

一些特性

  1. 每次迭代獲得的決策樹模型都要乘以一個縮減系數,從而降低每棵樹的作用,提升可學習空間。
  2. 每次迭代擬合的是一階梯度。

XGBoost

XGBoost 是GBDT的一個變種,最大的區別是xgboost通過對目標函數做二階泰勒展開,從而求出下一步要擬合的樹的葉子節點權重(需要先確定樹的結構),從而根據損失函數求出每一次分裂節點的損失減小的大小,從而根據分裂損失選擇合適的屬性進行分裂。

這個利用二階展開的到的損失函數公式與分裂節點的過程是息息相關的。先遍歷所有節點的所有屬性進行分裂,假設選擇了這個a屬性的一個取值作為分裂節點,根據泰勒展開求得的公式可計算該樹結構各個葉子節點的權重,從而計算損失減小的程度,從而綜合各個屬性選擇使得損失減小最大的那個特征作為當前節點的分裂屬性。依次類推,直到滿足終止條件。

一些特性

  1. 除了類似於GBDT的縮減系數外,xgboost對每棵樹的葉子節點個數和權重都做了懲罰,避免過擬合

  2. 類似於隨機森林,XGBoost在構建樹的過程中,對每棵樹隨機選擇一些屬性作為分裂屬性。

  3. 分裂算法有兩種,一種是精確的分裂,一種是近似分裂算法,精確分裂算法就是把每個屬性的每個取值都當作一次閾值進行遍歷,采用的決策樹是CART。近似分裂算法是對每個屬性的所有取值進行分桶,按照各個桶之間的值作為划分閾值,xgboost提出了一個特殊的分桶策略,一般的分桶策略是每個樣本的權重都是相同 的,但是xgboost使每個樣本的權重為損失函數在該樣本點的二階導(泰勒展開不應該是損失函數關於模型的展開嗎?為什么會有在該樣本點的二階導這種說法? 因為模型是對所有樣本點都通用的,把該樣本輸入到二階導公式中就可以得到了)。

  4. xgboost添加了對稀疏數據的支持,在計算分裂收益的時候只利用沒有missing值的那些樣本,但是在推理的時候,也就是在確定了樹的結構,需要將樣本映射到葉子節點的時候,需要對含有缺失值的樣本進行划分,xgboost分別假設該樣本屬於左子樹和右子樹,比較兩者分裂增益,選擇增益較大的那一邊作為該樣本的分裂方向。

  5. xgboost在實現上支持並行化,這里的並行化並不是類似於rf那樣樹與樹之間的並行化,xgboost同boosting方法一樣,在樹的粒度上是串行的,但是在構建樹的過程中,也就是在分裂節點的時候支持並行化,比如同時計算多個屬性的多個取值作為分裂特征及其值,然后選擇收益最大的特征及其取值對節點分裂。

  6. xgboost 在實現時,需要將所有數據導入內存,做一次pre-sort(exact algorithm),這樣在選擇分裂節點時比較迅速。

缺點

  1. level-wise 建樹方式對當前層的所有葉子節點一視同仁,有些葉子節點分裂收益非常小,對結果沒影響,但還是要分裂,加重了計算代價。
  2. 預排序方法空間消耗比較大,不僅要保存特征值,也要保存特征的排序索引,同時時間消耗也大,在遍歷每個分裂點時都要計算分裂增益(不過這個缺點可以被近似算法所克服)

lightGBM

https://github.com/Microsoft/LightGBM/wiki/Features
關於lightGBM的論文目前並沒有放出來,只是從網上一些信息得出以下的一些與xgboost不同的地方:

  1. xgboost采用的是level-wise的分裂策略,而lightGBM采用了leaf-wise的策略,區別是xgboost對每一層所有節點做無差別分裂,可能有些節點的增益非常小,對結果影響不大,但是xgboost也進行了分裂,帶來了務必要的開銷。 leaft-wise的做法是在當前所有葉子節點中選擇分裂收益最大的節點進行分裂,如此遞歸進行,很明顯leaf-wise這種做法容易過擬合,因為容易陷入比較高的深度中,因此需要對最大深度做限制,從而避免過擬合。

  2. lightgbm使用了基於histogram的決策樹算法,這一點不同與xgboost中的 exact 算法,histogram算法在內存和計算代價上都有不小優勢。
    -. 內存上優勢:很明顯,直方圖算法的內存消耗為(#data* #features * 1Bytes)(因為對特征分桶后只需保存特征離散化之后的值),而xgboost的exact算法內存消耗為:(2 * #data * #features* 4Bytes),因為xgboost既要保存原始feature的值,也要保存這個值的順序索引,這些值需要32位的浮點數來保存。
    -. 計算上的優勢,預排序算法在選擇好分裂特征計算分裂收益時需要遍歷所有樣本的特征值,時間為(#data),而直方圖算法只需要遍歷桶就行了,時間為(#bin)

  3. 直方圖做差加速
    -. 一個子節點的直方圖可以通過父節點的直方圖減去兄弟節點的直方圖得到,從而加速計算。

  4. lightgbm支持直接輸入categorical 的feature
    -. 在對離散特征分裂時,每個取值都當作一個桶,分裂時的增益算的是”是否屬於某個category“的gain。類似於one-hot編碼。

  5. 但實際上xgboost的近似直方圖算法也類似於lightgbm這里的直方圖算法,為什么xgboost的近似算法比lightgbm還是慢很多呢?
    -. xgboost在每一層都動態構建直方圖, 因為xgboost的直方圖算法不是針對某個特定的feature,而是所有feature共享一個直方圖(每個樣本的權重是二階導),所以每一層都要重新構建直方圖,而lightgbm中對每個特征都有一個直方圖,所以構建一次直方圖就夠了。
    -. lightgbm做了cache優化?

  6. lightgbm哪些方面做了並行?
    -. feature parallel
    一般的feature parallel就是對數據做垂直分割(partiion data vertically,就是對屬性分割),然后將分割后的數據分散到各個workder上,各個workers計算其擁有的數據的best splits point, 之后再匯總得到全局最優分割點。但是lightgbm說這種方法通訊開銷比較大,lightgbm的做法是每個worker都擁有所有數據,再分割?(沒懂,既然每個worker都有所有數據了,再匯總有什么意義?這個並行體現在哪里??)
    -. data parallel
    傳統的data parallel是將對數據集進行划分,也叫 平行分割(partion data horizontally), 分散到各個workers上之后,workers對得到的數據做直方圖,匯總各個workers的直方圖得到全局的直方圖。 lightgbm也claim這個操作的通訊開銷較大,lightgbm的做法是使用”Reduce Scatter“機制,不匯總所有直方圖,只匯總不同worker的不同feature的直方圖(原理?),在這個匯總的直方圖上做split,最后同步。

參考:https://github.com/Microsoft/LightGBM/wiki/Features


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM