Xgboost原理-XGBoost論文精讀與總結-A Scalable Tree Boosting System

1. xgboost介紹

xgboost特點:

  1. 提出了高效的、可擴展的、端到端的樹提升系統;
  2. 針對係數數據和加權分位數架構提出了一種創新性的稀疏感知算法,用於近似樹學習;
  3. 針對緩存訪問模式、數據壓縮和分片,提出相應的解決方案來構建可擴展的樹提升系統。

結果:通過整合上面幾個優勢,xgboost可以做到以更少的資源,擴展到數十億的訓練樣本。

paper的唯一的keywords-Large-scale Machine Learning 也正是反應了這一點,大規模機器學習。

在introduction部分,paper着重提到了xgboost成功祕籍:
xgboost成功背後最大的因素是其在所有場景下的可擴展性

The most important factor behind the success of XGBoost is its scalability in all scenarios

而可擴展性主要來源於兩個方面:

  1. 針對稀疏數據提出的一個創新性的樹學習算法;
  2. 具有理論支撐的加權分位數結構化的步驟,可以幫助在近似樹學習中處理樣本權重問題。

More importantly, XGBoost exploits out-of-core computation and enables data scientists to process hundred millions of examples on a desktop. Finally, it is even more exciting to combine these techniques to make an end-to-end system that scales to even larger data with the least amount of cluster resources.

哈哈,paper又是一頓推廣xgboost的優勢,不過那是真的呆佩服,能夠把這麼多的改進同時結合起來,造就了xgboost這一神作。

作者再正式介紹正文之前總結了下本paper的重要貢獻:

  1. 建立了一個具有高擴展性能的端到端樹提升系統;
  2. 以進行有效的計算,提出了一個有理論依據的加權分位草圖;
  3. 爲並行化的樹學習,提出了一個創新性的稀疏感知算法;
  4. 爲核外樹學習,提出了一個有效的緩存感知塊結構。

在上述主要貢獻之外,還有其他能夠帶來提升的貢獻,包括不限於正則化的學習方法等。

2. 樹提升模型

2.1 正則化的學習目標

在這裏插入圖片描述

再來回顧下集成模型中加性樹算法函數:
y^i=ϕ(xi)=k=1Kfk(xi),fkϝ(1) \hat y_i = \phi(x_i) = \sum_{k=1}^{K}f_k(x_i), \qquad f_k\in \digamma \qquad (1)
其中,F表示迴歸樹的空間,F中每一個組成部分fk可以用來刻畫第k棵樹,fk是指每棵樹的結構(用q表示),以及樹上每個葉子結點代表的分數(用w表示),T表示樹中葉子節點的總個數,因此可以對公式(1)進行下面條件的限制:
ϝ={f(x)=wq(x)}(q:RmT,wRT) \digamma = \{f(x) = w_{q(x)}\}(q: \mathbb{R}^m\rightarrow T, w\in \mathbb{R}^T)
與普通決策樹使用的是分類樹不同的是,這裏使用的是迴歸樹,每個迴歸樹的葉子結點是一個連續的分數值。對於每一個樣本,在每棵樹上都會依據決策規則(也就是樹的結構q)將其分類到相應的葉子結點上,而在計算該樣本的預測結果時,是將所有樹的葉子結點分數(w)做加和即可。

模型即公式(1)中的函數需要學習出來,因此需要通過loss函數進行優化,xgboost需要最優化的是下面的帶有正則化的loss函數:
ζ(ϕ)=il(y^i,yi)+kΩ(fk)(2) \zeta(\phi) = \sum_i l(\hat y_i, y_i) + \sum_k \Omega(f_k) \qquad (2)
whereΩ(f)=γT+12λw2 where \quad \Omega(f) = \gamma T + \frac{1}{2}\lambda ||w||^2
其中fk表示第k棵樹的正則化項,公式(2)中的l作爲損失函數,是一個可微的凸函數,公式(2)中的第二項是用來懲罰模型的複雜度的,這個正則項可以用來平滑最終學習到的權重參數以防止過擬合,因此模型更傾向於學習到更加簡單和泛化性能更好的參數結果。當正則項參數置爲0時,模型的目標函數就等同於傳統的梯度樹提升模型了。

2.2 梯度樹提升算法

由於公式(2)中包含函數式參數(fk),因此無法使用傳統的優化算法在歐氏空間中對其進行優化,而作爲替代方案的是,模型需要通過加性的方式進行訓練,典型的情況是,第 i 個樣本在 t 次迭代後的預測結果爲
y^i(t) \hat y_i^{(t)}
,我們需要在上次預測結果的基礎上,加上ft後來最小化損失函數,如下所示:
ζ(t)=il(yi,y^i(t1)+ft(xi))+Ω(ft)(3) \zeta(t) = \sum_i l(y_i, \hat y_i^{(t-1)} + f_t(x_i)) + \Omega(f_t) \qquad (3)
公式(3)表示第t次迭代後的損失函數,這是一種貪心的方法,即保證加上ft後當前優化效果最好即可。下面對公式(3)進行二階泰勒展開爲:
ζ(t)i=1n[l(yi,y^i(t1))+gift(xi)+12hift2(xi)]+Ω(ft)(4) \zeta(t) \simeq \sum_{i=1}^{n} [l(y_i, \hat y_i^{(t-1)}) + g_i f_t(x_i) + \frac{1}{2}h_i f_t^2(x_i)] + \Omega(f_t) \qquad (4)
公式(4)中的n表示每一次優化時一個batch的數據量大小,另外:
gi=y^(t1)l(yi,y^(t1))(5) g_i = \partial_{\hat y_{(t-1)}}l(y_i, \hat y_{(t-1)}) \qquad (5)
hi=y^(t1)2l(yi,y^(t1))(6) h_i = \partial_{\hat y_{(t-1)}}^2l(y_i, \hat y_{(t-1)}) \qquad (6)
上面公式(5)和公式(6)分別是損失函數的一階導數和二階導數,由於公式(4)中的第一項是常數項(因爲yi和上一迭代的預測結果這兩項都是常數值),所以可以將公式(4)中的常數項去除(這不影響後面的一系列求導等過程),得到下面在第t次迭代時簡化版的損失函數爲:
ζ(t)=i=1n[gift(xi)+12hift2(xi)]+Ω(ft)(7) \zeta(t) = \sum_{i=1}^{n} [g_i f_t(x_i) + \frac{1}{2}h_i f_t^2(x_i)] + \Omega(f_t) \qquad (7)
下面我們對公式(7)做兩個改變:一個是將常數項展開,另一個是引入下面的公式(8):
Ii={iq(xi)=j}(8) I_i = {\{i|q(x_i) = j \}} \qquad (8)
上面公式(8)表示葉子結點j上的所有樣本集,q表示樹的結構,因此我們可以將公式(7)進行如下轉換:
ζ~(t)=i=1n[gift(xi)+12hift2(xi)]+γT+12λw2 \widetilde\zeta^{(t)} = \sum_{i=1}^{n} [g_i f_t(x_i) + \frac{1}{2}h_i f_t^2(x_i)] + \gamma T + \frac{1}{2}\lambda ||w||^2
=j=1T[(iIjgi)wj+12(iIjhi+λ)wj2]+γT(9) =\sum_{j=1}^{T}[(\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 \qquad (9)
上述公式(9)是一個二階多項式,對於一個結構固定的樹來說(必須要強調樹的結構固定,這樣T纔是固定的,不然T的大小也是變量),可以通過對其計算一階倒數的方式並令其一階導數等於0得到極值點爲:
wj=iIjgiiIjhi+λ(10) w_j^* = -\frac{\sum_{i\in I_j}g_i}{\sum_{i\in I_j}h_i + \lambda} \qquad (10)
經公式(10)中的極值點代入公式(9)中得:
ζ~(t)(q)=12j=1T(iIjgi)2iIjhi+λ+γT(11) \widetilde\zeta^{(t)}(q) = -\frac{1}{2}\sum_{j=1}^{T} \frac{(\sum_{i\in I_j} g_i)^2}{\sum_{i\in I_j} h_i + \lambda} + \gamma T \qquad (11)
上述公式(11)就是用來評估樹結構q的質量的打分函數,它相當於在評估決策樹時的雜質函數(例如熵函數),但是有一點不同的是,這裏的公式(11)是針對更加廣泛的目標函數形式而言(只要可以計算一階導數和二階導數值),下面圖2中也給出瞭如何計算損失函數分數的方式。
在這裏插入圖片描述

通常如果枚舉出來所有的可能的樹結構q是不現實的,因此採取了一個貪心算法是:從單個葉子結點開始,不斷迭代地往樹中加入樹枝。假設樹分裂之後的左節點和右結點包含的樣本集分別爲ILIR,樹分裂前節點所包含的樣本集爲I,即I=IL+IR,那麼在樹節點分裂成左右節點之後,損失函數降低了:
ζsplit=12[(iILgi)2iILhi+λ+(iIRgi)2iIRhi+λ(iIgi)2iIhi+λ]γ(12) \zeta_{split} = -\frac{1}{2} [\frac{(\sum_{i\in I_L} g_i)^2}{\sum_{i\in I_L} h_i + \lambda} + \frac{(\sum_{i\in I_R} g_i)^2}{\sum_{i\in I_R} h_i + \lambda} - \frac{(\sum_{i\in I} g_i)^2}{\sum_{i\in I} h_i + \lambda}] -\gamma \qquad (12)
此時T=1,因此公式(12)中就省略了,公式(12)也是常用來評估分裂的的效果。

2.3 學習率和列採樣

除了前面提到的對葉子結點數量、葉子結點分數值進行正則化,引入了更多的防止過擬合方法:

  1. 學習率的加入(來源於Friedman):減少了單棵樹的影響,給後面樹優化模型留更多的空間
  2. 列採樣即特徵採樣(來源於隨機森林):在某些情況下,使用列採樣甚至能夠獲得比行採樣更好的效果;列採樣還可以加速並行化算法的計算速度
  3. 行採樣

3. 分裂發現算法

3.1 精確貪心算法

樹學習模型的一個關鍵點就是找到最優的分裂特徵和分裂值,而爲了實現最優,精確的貪心算法會枚舉所有可能的分裂點,而當前一些單機樹提升算法都實現了精確貪心算法,例如scikit-learn、gbm、以及paper的xgboost。精確貪心算法的實現如Alg.1所示,它在計算上要求枚舉連續特徵的所有可能分裂值,因此必須首先對特徵值進行排序,然後按照排序順序訪問數據並計算公式(12)中的梯度統計結果。

在這裏插入圖片描述

3.2 近似貪心算法

將缺貪心算法儘管十分強大,但是一個明顯的缺點就是需要耗費太大計算量以及內存,特別是當內存不夠或者需要處理分佈式任務配置時,精確貪心算法將無法work,因此需要一個近似的算法。

在這裏插入圖片描述

近似算法爲Alog.2,步驟如下:

  1. 根據特徵分佈的百分位數提出候選分割點;
  2. 基於候選分割點,將連續特徵映射到各個桶裏;
  3. 根據聚合後的分割點效果(可基於公式(12)計算)找出最優的分割點。

近似算法還有兩個變體,全局變體和局部變體:

  1. 全局變體建議在算法初始階段使用所有候選分割,並在之後的所有層級使用相同的候選分割;局部變體在每個分割之後會重新生成候選建議分割;
  2. 全局變體需要更少的建議步驟,而局部變體需要更多,因爲每次分割後,局部變體都要重新建議;
  3. 全局變體需要更多的候選分割點,因此每次分裂之後沒有紀念性重新建議,而局部變體則使用更少分割點;
  4. 局部變體每次分割完都重新建議候選分割點的特性使得其更加適合較深層的樹學習模型。

不同的算法在數據集上的效果對比如圖3所示,實際發現:

  1. 局部變體確實需要更少的候選分割點;
  2. 當有足夠多的候選分割點時,全局變體可以達到可以局部變體一樣好的效果(具體體現在圖中,全局變體eps=0.5時小狗較差,但是當eps=0.03也就是分割點更多點,效果達到了和局部變體一樣的效果)

在這裏插入圖片描述

對於近似算法,還可以進行其他的嘗試,例如:

  1. 直接構建梯度統計的近似直方圖
  2. 使用分箱策略的其他變體代替分位數策略;

同時paper總結了之所以使用分位數策略,是因爲其受益於可分佈以及可計算。並且而且分箱策略可以達到和精確貪心算法一樣的效果。

xgboost不僅實現了單機上的精確貪心算法,也實現了所有配置下的包含全局變體及局部變體的近似算法。

3.3 加權分位數骨架

通常情況下,數據的百分位點是用於使候選點在數據分佈上更加均勻,並且在下面paper給出了常見的數據的百分位點計算的方法,並指出了當前方法的兩個缺點:

  1. 對於大型數據集合而言,計算候選分割點比較困難;
  2. 當數據具有不同的權重時,目前沒有穩妥的方法來計算候選分割點。
    爲了解決這個問題,paper提出了分佈式的加權分位數架構的算法

3.4 稀疏感知分裂發現算法

在真實任務中,稀疏的x形式的輸入是非常常見的。通常有三種情況產生稀疏的輸入:

  1. 數據中出現了確實值;
  2. 統計數據中頻繁出現了0值特徵;
  3. 人工特徵工程產生了的one-hot的編碼

我們需要讓算法感知到稀疏模式數據的存在,解決方式是:
在樹節點中提出一個默認的方向,可以參考圖4中:在稀疏矩陣中當一個值是確實值時,那麼這個樣本將被劃分到默認的方向上去,這每個分支上會有2個默認方向的選擇,而默認的方向時通過算法從數據中學習出來的,相應的學習算法見Alg.3,這裏的一個關鍵的提升在於只訪問非缺失值的樣本,算法會將不存在視爲缺失值,並將其最好的分裂方向學習出來以處理缺失值。而且當一個值與指定的特徵值對應不上時,xgboost會將其限制到一個統一的值上(預測時候使用?)。

在這裏插入圖片描述

據我們所知,目前已有的樹學習算法要麼是隻對連續特徵進行優化,要麼是需要特定的程度來處理有限的情況例如分類編碼類型的特徵。而xgboost中提出了一個解決稀疏模式數據的統一方法,而且其實現的複雜度與非稀疏數據的規模大小成線性關係,paper在數據集上實驗的結果顯示稀疏感知算法的計算速度比原始版本在速度上提升了50倍。
在這裏插入圖片描述

4. 系統設計

4.1 用於並行學習的列block

樹學習過程最耗時的部分是在將數據排成有序,爲了降低排序的成本,我們將數據存儲在內存單元中,並稱之爲block,每個block中的數據是以壓縮列(CSC)格式存儲的,並且對列是按照其對應的特徵值來排序的。這樣的話,輸入數據的佈局僅僅需要在訓練前計算一次,之後可以複用。

在精確貪心算法中,我們將整個數據集在一個block中存儲,並且通過線性掃描預排序好的數據來執行分裂節點查找算法,我們共同進行所有葉子結點的分裂點查找,因此對block的一次掃描將蒐集到所有葉子分支中分裂候選節點的統計信息。Fig 6中顯示如何將數據轉換成block以及使用block尋找最優分裂節點的過程。

在這裏插入圖片描述

當使用近似算法時,block結構仍然能發揮作用,由於是近似算法使用的是全量數據集的子數據集,這個時候使用多個blocks,因此每個block中對應的是全量數據集的行採樣的子數據集,不同的blocks可以進行跨機器做分佈式,或者存儲在磁盤的核外配置中,block的存儲結構對於尤其對於局部近似算法變體有很大價值,因爲其需要進行頻繁的提出候選分割點。

4.1.1 時間複雜度分析

參數定義:

  1. d:樹的最大深度
  2. K:樹的總棵樹
  3. n:訓練樣本的數量
  4. ||x||0:訓練樣本中非缺失值樣本的數量
  5. q:數據集中需要的候選分割點的數量,通常在32-100之間
  6. B:每個block中的行的最大數量
  1. 對於精確貪心算法,原始算法的時間複雜度爲:
    O(Kdx0logn) O(Kd||x||_0logn)

  2. 對於精確貪心算法,使用block結構的樹提升算法中,時間複雜度爲:
    O(Kdx0+x0logn) O(Kd||x||_0 + ||x||_0logn)
    上面加號的後面部分表示一次性預排序的時間開銷,這是可以分攤的。上面2和1的對比,block結構節省了一個logn因子的時間,這在n較大是就顯得非常重要了。

  3. 對於近似算法,原始算法的時間複雜度爲:
    O(Kdx0logq) O(Kd||x||_0logq)

  4. 對於近似算法,使用block結構的樹提升算法的時間複雜度爲:
    O(Kdx0+x0logB) O(Kd||x||_0 + ||x||_0logB)
    上面4和3的對比,block結構節省了一個logq因子的時間,而q通常在32-100之間,這也是一筆不小的開銷。

4.2 緩存感知訪問

之後更新

4.3 用於核外計算的block

之後更新

5. xgboost各種tricks總結:

一、xgboost防止過擬合方法:

  1. 對葉子結點數量、葉子結點分數(權重)值進行正則化;
  2. 學習率的加入(來源於Friedman):減少了單棵樹的影響,給後面樹的優化上留有更多的空間;
  3. 列採樣即特徵採樣(來源於隨機森林):在某些情況下,使用列採樣甚至能夠獲得比行採樣更好的效果,列採樣還可以加速並行化算法的計算速度;
  4. 行採樣

二、樹的分裂點發現算法:

  1. 精確貪心算法:在其他樹學習模型中也都有相同的實現;
  2. 近似貪心算法:連續特徵按照分位點進行特徵分桶;
    a. 全局算法
    b. 局部算法
  3. 加權分位點骨架算法
  4. 稀疏特徵:
    a. 不存在即缺失值
    b. 統計中出現的0值特徵
    c. 人工特徵工程中的編碼特徵如ont-hotd等
    xgboost對於稀疏特徵的處理方式統一爲通過訓練數據學習出來特徵稀疏值的默認劃分方向。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章