xgboost原理與推導

  GBDT和xgboost在工業界被越來越多的使用,尤其是在一些數據比賽中經常能看到它的身影,雖然在使用起來不難,但是要能完整的理解還是有一點麻煩的。本文在分享xgboost之前,先一步一步梳理GB,GBDT,xgboost,它們之間有非常緊密的聯繫,GBDT是以決策樹(CART)爲基學習器的GB算法,xgboost擴展和改進了GDBT,xgboost算法更快,準確率也相對高一些。

1.梯度增強(GB)

      機器學習中的學習算法的目標是爲了優化或者說最小化損失功能,漸變助推的思想是迭代生成多個(M個)弱學習模型,然後將每個弱學習模型的預測結果相加,後面的模型FM + 1(x)的基於前面學習模型的FM(X)的效果生成的,關係如下:

                                              1 \ le m \ le M     F_ {m + 1}(x)= F_m(x)+ h(x)

      GB算法的思想很簡單,關鍵是怎麼生成h(x)?

      如果目標函數是迴歸問題的均方誤差,很容易想到最理想的H(X)應該是能夠完全擬合 ,這就是常說基於殘差的學習。殘差學習在迴歸問題中可以很好的使用,但是爲了一般性(分類,排序問題),實際中往往是基於Loss Function在函數空間的負梯度學習,對於迴歸問題殘差和負梯度也是相同的。中的f,不要理解爲傳統意義上的函數,而是一個函數向量 ,向量中元素的個數與訓練樣本的個數相同,因此基於Loss Function函數空間的負梯度的學習也稱爲“僞殘差”。y  -  F_m(x)\ frac {1} {2}(y  -  F(x))^ 2L(y,f)\! f(x_1),\ ldots,f(x_n)

GB算法的步驟:

  1.初始化模型爲常數值:

    F_0(x)= \ underset {\ gamma} {\ arg \ min} \ sum_ {i = 1} ^ n L(y_i,\ gamma)。

  2.迭代生成中號個基學習器

    1.計算僞殘差

      r_ {im} =  -  \ left [\ frac {\ partial L(y_i,F(x_i))} {\ partial F(x_i)} \ right] _ {F(x)= F_ {m-1}(x }} \ quad \ mbox {for} i = 1,\ ldots,n。

    2.基於     生成基學習器  \ {(x_i,r_ {im})\} _ {i = 1} ^ n\! h_m(x)的

    3.計算最優的\! \ gamma_m

      \ gamma_m = \ underset {\ gamma} {\ operatorname {arg \,min}} \ sum_ {i = 1} ^ n L \ left(y_i,F_ {m-1}(x_i)+ \ gamma h_m(x_i) \對)。

        4.更新模型

      F_m(x)= F_ {m-1}(x)+ \ gamma_m h_m(x)。

 2.梯度提升決策樹(GBDT)

GBDT(Gradient Boosted Decision Trees)在1999年由Jerome Friedman提出,將GBDT模型應用於CTR預估,最早見於
          yahoo.GBDT是一個加性迴歸模型,通過boosting迭代的構造一組弱學習器,相對LR的優勢如不需要做特徵歸一化,自動進行選擇可解釋性較低的模型,可以適應多種損失函數如Square Loss,Log Loss等。但作爲非線性模型,其相對線性模型的缺點也是顯然的:提升是個串行的過程,不能並化,計算複雜度較高,同時其不太適合高維稀疏特徵,通常採用稠密的數值特徵,如點擊率預估中的COEC。

  GB算法中最典型的基學習器是決策樹,尤其是CART,正如名字的含義,GBDT是GB和DT的結合。要注意的是GDBT中使用的決策樹是迴歸樹,GBDT中的決策樹是個弱模型,深度較小一般不會超過5,葉子節點的數量也不會超過10,對於生成的每棵決策樹乘上比較小的縮減係數(學習率<0.1),有些GBDT的實現加入了隨機抽樣(子樣0.5 <= f <= 0.8)提高模型的泛化能力。通過交叉驗證的方法選擇最優的參數。因此GBDT實際的核心問題變成怎麼基於使用CART迴歸樹生成\ {(x_i,r_ {im})\} _ {i = 1} ^ n\! h_m(x)的

作爲對比,先說分類樹,我們知道CART是二叉樹,CART分類樹在每次分枝時,是窮舉每一個功能,每的一個閾值,根據基尼係數找到使不純性降低最大的功能的以及其閥值,然後按照特徵<=閾值,和特徵>閾值分成的兩個分枝,每個分支包含符合分支條件的樣本。用同樣方法繼續分枝直到該分支下的所有樣本都屬於統一類別,或達到預設的終止條件,若最終葉子節點中的類別不唯一,則以多數人的類別作爲該葉子節點的類別

迴歸樹總體流程也是類似,不過在每個節點(不一定是葉子節點)得都會一個預測值,時分枝窮舉每一個特徵的每個閾值找最好的分割點,但衡量最好的標準不再是GINI係數,而是最小化:均方差。

3. xgboost

xgboost算法的步驟和GB基本相同,都是首先初始化爲一個常數,不同於傳統的GBDT方式,只利用了一階的導數信息rixgboost是根據一階導數gi和二階導數hi迭代生成基學習器,相加更新學習器.xgboost對損失func做了二階的泰勒展開,並在目標函數之外加入正則項整體 求最優解,用以權衡目標函數的下降和模型複雜程度,避免過擬合。

模型如何學習:添加劑訓練

其中第一部分是訓練誤差,也就是大家相對比較熟悉的如平方誤差,logistic loss等。而第二部分是每棵樹的複雜度的和。這個在後面會繼續講到。因爲現在我們的參數可以認爲是在一個函數空間裏面,我們不能採用傳統的如SGD之類的算法來學習我們的模型,因此我們會採用一種叫做添加劑訓練的方式也就是Boosting。每一次保留原來的模型不變,加入一個新的函數f到我們的模型中。

xgboost推導過程

我們會採用如下的泰勒展開近似來定義一個近似的目標函數,方便我們進行這一步的計算。

其中,表示損失函數,     表示正則項,包括L1,L2,常數項。

 GI爲一階導數,喜爲二階導數。

當我們把常數項移除之後,我們會發現如下一個比較統一的目標函數。這一個目標函數有一個非常明顯的特點,它只依賴於每個數據點的在誤差函數上的一階導數和二階導數。

想一想當你被要求使用平方損失和logistic loss實現梯度樹時,如何用代碼分解模塊?

一個樹的定義可以分成兩個部分:結構部分和葉子權重部分。 
假設q是結構映射函數把輸入映射到葉子的索引號上面去,w表示葉子節點的權重。則樹可以表示爲:

定義樹的正則項(複雜度):包含兩個部分樹的葉子節點的個數T和葉子節點的權重的平方(L2),即:

目標函數的OBJ

 

此時單棵決策樹的學習過程如下:

(1)枚舉所有可能的樹結構q 
(2)計算對應的分數(損失值)obj,obj越小越好 
(3)找到最佳的樹結構,爲每個葉子節點計算權值w

然而,的可能樹結構數量的英文無窮的,所以實際上我們不可能枚舉所有可能的樹結構。通常情況下,採用我們貪心策略來生成決策樹的每個節點。

  1. 從深度爲0的樹開始,每個對葉節點枚舉所有的可用特徵
  2. 針對每個特徵,屬於把該節點的訓練樣本根據該特徵值升序個結果排列,通過線性掃描的方式來決定該特徵的最佳分裂點,並記錄該特徵的最大收益(採用最佳分裂點時的收益
  3. 選擇收益最大的特徵作爲分裂特徵,用該特徵的最佳分裂點作爲分裂位置,把該節點生長出左右兩個新的葉節點,併爲每個新節點關聯對應的樣本集
  4. 回到第1步,遞歸執行到滿足特定條件爲止

xgboost實現在做時還許多了優化

  • 在尋找最佳分割點時,考慮傳統的枚舉每個特徵的所有可能分割點的貪心法效率太低,xgboost實現了一種近似的算法。的大致思想的英文根據百分位行業釋義法律列舉幾個可能成爲分割點的候選者,然後從候選者中根據上面求分割點的公式計算找出最佳的分割點
  • xgboost考慮了訓練數據爲稀疏值的情況,爲可以缺失值或者指定的值指定分支的默認方向,這能大大提升算法的效率,造紙提到50倍
  • 列特徵排序後以的形式存儲在內存中,在迭代中可以重複使用;雖然提高算法迭代必須串行,但是處理在每個特徵列時可以來到來到lái parallel-
  • 按照特徵列方式存儲能優化尋找最佳的分割點,但是當以行計算梯度數據時會導致內存的不連續訪問,嚴重時會導致緩存未命中,降低算法效率。造紙中提到,先柯林斯將數據收集到線程內部的緩衝區,然後再計算,提高算法的效率。
  • xgboost還考慮了當數據量比較大,內存不夠時怎麼有效的使用磁盤,主要是結合多線程,數據壓縮,分片的方法,儘可能的提高算法的效率。

分佈式xgboost發展過程

Xgboost分佈式算法開始基本成熟後,分佈式版本的變更主要是底層的AllReduce接口支持不同平臺[mpi,yarn ....]的過程。

第一版支持MPI

Rabit開始兼容mpi的AllReduce,但是運行mpi的分佈式程序需要讀寫hdfs,並分割數據。當時沒有實現C ++讀寫hdfs功能,跑hdfs數據比較麻煩。

第二版支持Hadoop Streaming

通過Hadoop Streamingg把xgboost作爲地圖運行。在每個地圖中進行allreduce的通信完xgboost每輪的迭代,減少只是負責輸出模型。通過在一個地圖中完成xgboost所有的迭代,避免了傳統基於hadoop的機器學習程序每輪迭代間的資源重新分配,使得基於hadoop的xgboost的迭代速度能媲美基於mpi的xgboost,同時避免了,同時避免了mpi程序讀寫hdfs的麻煩。

第三版原生支持Yarn
Yarn爲了能自由的掌控各個節點資源分配並且使文件均衡割到各個節點,直接把rabit作爲紗的一個APP運行。在這一版裏,實現了c ++讀寫hdfs的功能,解決了流版本中xgboost中對文件操作自由不高的問題。

目前xgboost支持 Python, R, Java, Scala, C++ and more.

Runs on single machine, Hadoop, Spark, Flink and DataFlow , https://xgboost.ai/

參考

陳天奇博士幻燈片:https://homes.cs.washington.edu/~tqchen/pdf/BoostedTree.pdf

xgboost導讀和實戰:https://pan.baidu.com/s/1BWdIOUYaxA2PuN_TPcLEBg密碼:m7py

對於如何安裝xgboost可參考我的博文:Windows環境下安裝xgboost

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