1. 程式人生 > >Boosting學習總結及理解(2)

Boosting學習總結及理解(2)

其他內容見上一篇博文。

GBDT(梯度提升決策樹):

GBDT屬於提升樹,所以也是決策樹的加法模型:

                                              {f_M}(x) = \sum\limits_{m = 1}^M {{T_m}(x)}   ,其中T_m(x)表示第m顆樹對輸入資料 x 的預測值

如何來學習得到這個加法模型?

從前往後一步一步學習,每一步學習得到一個模型即可:

                                                 \begin{array}{l} {f_0}(x) = 0\\ {f_1}(x) = {f_0}(x) + {T_1}(x)\\ {f_2}(x) = {f_1}(x) + {T_2}(x)\\ ...\\ {f_m}(x) = {f_{m - 1}}(x) + {T_m}(x),m=1,2...M \end{array}

                                                {f_M}(x) = \sum\limits_{m = 1}^M {{T_m}(x)}

初始化預測值為0,

1)使用訓練資料建立第一顆樹T_1,輸出為初始化值 + 第1個決策樹的預測值

第2步t=2,使用新的訓練資料建立第二顆樹T_2,模型輸出為第一顆樹的預測值 + 第2個決策樹的預測值

....

第m步,使用新的訓練資料建立第m顆樹T_m,模型輸出為上一顆樹的預測值 + 第m個決策樹的預測值

所以最終的輸出是所有樹預測值總和。

從第二顆樹開始其實擬合的資料都改變了,所以上文說的新的訓練資料是什麼?

假設訓練資料為,一共有n個樣本

構建損失函式,這裡採用平方差損失函式:

                                                           L = \frac{1}{2} {{{({y_i} - f({x_i}))}^2}}

現在要使損失函式不斷減小,如何減小損失函式呢,沿著損失函式的負梯度方向不就可以使損失函式不斷減小了嘛。

GBDT沿著負梯度方向減小損失函式的方法:

簡寫損失函式為L({y_i},f({x_i})),對損失函式求導(即求梯度),我們令這個負梯度為 r_i 得到下式:

                                                 {r_i} = - {[\frac{{\partial L({y_i},f({x_i}))}}{{\partial f({x_i})}}]_{f(x) = {f_{m - 1}}(x)}} , i=1,2...n

這樣我們就得到了n個 r(因為對於每一個樣本都會有一個 r,所以會有n個)稱之為殘差,作為第m顆樹需要進行擬合的資料,可以看出第m顆樹的訓練資料就是損失函式對預測值的導數在第m-1顆樹時的取值。

為什麼稱 r 為殘差呢:當損失函式為平方差損失函式時,看看求導之後變成:

                                                 \frac{{\partial L}}{{\partial f({x_i})}} = {y_i} - f({x_i}){|_{f(x) = {f_{m - 1}}(x)}}

上式化簡之後得:

                                               \frac{{\partial L}}{{\partial f({x_i})}} = {y_i} - {f_{m - 1}}({x_i})

結果就是實際值與上一個模型的預測值的差,上一個模型就是第m-1個樹T_m_-_1,所以當損失函式時平方差時,這個 r 就是殘差。但是當損失函式不是平方差時,就不能說 r 是殘差了。所以可以總結為GBDT是用損失函式的一階導數近似來殘差,當損失函式是平方差時,這個近似殘差就是真正的殘差(實際值與前一個模型的輸出值的差值);當損失函式是其他損失函式時,這個近似殘差是偽殘差。 

其實上面紅字部分的新的資料指的就是損失函式的一階導數在前一個模型下的取值,下面對比下原始訓練資料和新的訓練資料:

T_1 需要擬

合的資料

x_1 x_2 ... x_n

T_2 需要擬

合的資料

x_1 x_2 ... x_n
y_1 y_2 ... y_n r_1 r_2 ... r_n

 可以看出下一個模型擬合的其實是上一個模型的預測殘差,只不過這個殘差是用損失函式的一階導近似得到的為殘差。

到這兒,每一顆樹擬合的是什麼已經知道了,下面就得看如何得到這些樹,也就是如何建樹。上一篇博文已經介紹瞭如何建樹,只不過給出的例子只有一個特徵。可以看出GBDT是個序列的過程,唯一能夠實現並行的地方也就是建立迴歸樹這個地方,比如可以同時進行多個特徵的選擇以及分裂點的分裂。

XGBoost:

跟GBDT一樣是一個提升的過程:

                                              

(a)XGBoost中把模型的複雜度加入到目標函式中作為正則化項,降低了模型的過擬合風險:

                                                        

這裡的損失函式可以是任意的損失函式。因為,所以損失函式等價為:

                             

上式中除了,其他都是已知的,所以優化目標函式就等於求

(b)XGBoost採用二階泰勒展開式逼近目標函式。二階泰勒展開式為:

                               

把(1)式中的看成是x看成是\Delta x按泰勒二階展開得:

           

其中g_i為損失函式的一階導數,h_i為損失函式的二階導數,而且這個損失函式是第 t-1 個模型的損失。如果此時的損失函式是平方損失即

                                         

因為在第 t 步建樹時,前一顆樹的預測結果是已知的,即是一個常數,常數項對目標函式的優化不會產生影響,所以去掉(3)式中的常數項之後為:

                              

由(4)式可知,只要知道第 t-1 個模型對應的 g_i 和 h_i ,就能求得第 t 個模型{f_t}({x_i})

所以對於每一步求得的模型,求出這個模型損失函式對應的一階導和二階導,帶入目標函式並優化目標函式,就能求得下一個模型。

如何用決策樹表示目標函式?

由於Boosting的基模型是由決策樹實現,則一顆生成好的決策樹,其結構是確定的,也就是說樹的葉子結點是確定的。假設這棵樹 T 個葉子節點,而每個葉子節點對應的值 w \in R^T ,{R^T} = \{ {w_1},{w_2}...{w_T}\}T個葉子對應就會有T個權值。每一片葉子結點中樣本的預測值都會是一樣的,在分類問題中,是某一類,在迴歸問題中,是某一個值在用最小二乘法構建迴歸樹時,這個值就是這個葉節點包含的所有樣本值的平均值,但XGBoost中這個值其實就是我們要預測的值那麼肯定存在這樣一個函式 q:{R ^n} \to \{ 1,2...T\} ,{R^n}是樣本空間,一共有n個樣本,q為對映函式,能夠將 f_{t}(x) 中的每個樣本對映到各自對應的葉子結點上,每一個葉子節點都有自己的權值w,即

                                                        

如果決策樹的複雜度可以由正則項來定義,即

                                                         

即決策樹模型的複雜度由生成的樹的葉子節點數量和葉子節點對應的值向量的L2範數決定,就是葉子數量的懲罰因子。

假設 I_j=\{ i \vert q(x_i)=j \} 為第 j 個葉子節點的樣本集合,j=1,2...T,則(5),(6)式帶入(4)式得:

                                     

此時我們就把所有的樣本都對映到各自對應的葉節點了,每一個葉節點都含有一個或多個樣本,因此才有了 \sum\limits_{i \in {I_j}} {{g_i}} 和 \sum\limits_{i \in {I_j}} {{h_i}} 這兩項。

定義 {G_j} = \sum\limits_{i \in {I_j}} {{g_i}} ,{H_j} = \sum\limits_{i \in {I_j}} {{h_i}}則等式(7)可寫為:

                                       

如果樹的結構是固定的,那麼說明樹的葉子節點是固定的,那麼把樣本對映到這些節點的對映函式 q 也是固定的,這說明一旦樹的結構固定,q就是固定的,進而我們就能知道每個節點上對應有多少樣本了,所以 {G_j} 和 {H_j} 也是固定的, 權值 w 使我們想要預測的值,所以此時對(8)式求一階導,令導數為 0 可求得葉子節點 j 對應的值為(星號代表最優解):

                                     

 將(9)式帶入(8)式中得                                

                                       

上面的(10)式即為最終的目標函式,如何優化這個目標函式?

最笨的方法就是對於每一顆決策樹,列舉所有可能的樹結構,每一顆樹每一顆樹的驗證:

a、首先列舉所有可能的樹結構,即 q ;

b、計算每種樹結構下的目標函式值,即等式(10)的值;

c、取目標函式最小(大)值為最佳的樹結構,根據等式(9)求得每個葉子節點的 w 取值,即對應樣本的預測值。

但上面的方法肯定是不可行的,因為樹的結構千千萬,所以一般用貪心策略來優化:

a、從深度為0的樹開始,對每個葉節點列舉所有的可用特徵

b、 針對每個特徵,把屬於該節點的訓練樣本根據該特徵值升序排列,通過線性掃描的方式來決定該特徵的最佳分裂點,並記錄該特徵的最大收益(採用最佳分裂點時的收益)

c、 選擇收益最大的特徵作為分裂特徵,用該特徵的最佳分裂點作為分裂位置,把該節點生長出左右兩個新的葉節點,併為每個新節點關聯對應的樣本集

d、回到第1步,遞迴執行到滿足特定條件為止

那麼如何計算上面的收益呢

仍然緊扣目標函式就可以了。假設我們在某一節點上二分裂成兩個節點,分別是左(L)右(R),則分列前的目標函式是 -\frac12 [\frac{(G_L+G_R)^2}{H_L+H_R+\lambda}] + \gamma ,分裂後則是 -\frac12 [ \frac{G_L^2}{H_L+\lambda} + \frac{G_R^2}{H_R+\lambda}] +2\gamma ,則對於來目標函式說,分裂後的收益是,即:

                               

所以GBDT的演算法可以總結為:

a、演算法在擬合的每一步都新生成一顆決策樹;

b、在擬合這棵樹之前,需要計算損失函式在每個樣本上的一階導和二階導,即 g_{i} 和 h_{i} ;

c、通過上面的貪心策略生成一顆樹,計算每個葉子結點的的 G_{j} 和 H_{j} ,利用等式6計算預測值 w ;

d、把新生成的決策樹 f_t(x) 加入 \hat{y}_i^t = \hat{y}_i^{t-1} + \epsilon f_t(x_i) ,其中 \epsilon 為學習率,主要為了抑制模型的過擬合

與GBDT相比,XGBoost的優點:

1. 顯示的把樹模型複雜度作為正則項加到優化目標中(上文中的(a))。

2. 公式推導中用到了二階導數,用了二階泰勒展開(上文中的(b))。

3. 實現了分裂點尋找近似演算法。

4. 利用了特徵的稀疏性。

5. 在建立迴歸樹的時候,訓練資料事先排序並且以 block 形式儲存,有利於平行計算。

6. 基於分散式通訊框架 rabit,可以執行在 MPI 和 yarn 上。(最新已經不基於 rabit 了)

7. 實現做了面向體系結構的優化,針對 cache 和記憶體做了效能優化

參考資料:

3. 李航《統計學習方法》