1. 程式人生 > >gbdt xgboost lighgbm三者區別

gbdt xgboost lighgbm三者區別

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

  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,最後同步。