http://www-personal.umich.edu/~jizhu/jizhu/wuke/Friedman-AoS01.pdf
https://www.cnblogs.com/bentuwuying/p/6667267.html
https://www.cnblogs.com/ModifyRong/p/7744987.html
https://www.cnblogs.com/bentuwuying/p/6264004.html
1.簡介
gbdt全稱梯度下降樹,在傳統機器學習算法里面是對真實分布擬合的最好的幾種算法之一,在前幾年深度學習還沒有大行其道之前,gbdt在各種競賽是大放異彩。原因大概有幾個,一是效果確實挺不錯。二是即可以用於分類也可以用於回歸。三是可以篩選特征。這三點實在是太吸引人了,導致在面試的時候大家也非常喜歡問這個算法。 gbdt的面試考核點,大致有下面幾個:
- gbdt 的算法的流程?
- gbdt 如何選擇特征 ?
- gbdt 如何構建特征 ?
- gbdt 如何用於分類?
- gbdt 通過什么方式減少誤差 ?
- gbdt的效果相比於傳統的LR,SVM效果為什么好一些 ?
- gbdt 如何加速訓練?
- gbdt的參數有哪些,如何調參 ?
- gbdt 實戰當中遇到的一些問題 ?
- gbdt的優缺點 ?
2. 正式介紹
首先gbdt 是通過采用加法模型(即基函數的線性組合),以及不斷減小訓練過程產生的殘差來達到將數據分類或者回歸的算法。
- gbdt的訓練過程
我們通過一張圖片,圖片來源來說明gbdt的訓練過程:
圖 1:GBDT 的訓練過程
gbdt通過多輪迭代,每輪迭代產生一個弱分類器,每個分類器在上一輪分類器的殘差基礎上進行訓練。對弱分類器的要求一般是足夠簡單,並且是低方差和高偏差的。因為訓練的過程是通過降低偏差來不斷提高最終分類器的精度,(此處是可以證明的)。
弱分類器一般會選擇為CART TREE(也就是分類回歸樹)。由於上述高偏差和簡單的要求 每個分類回歸樹的深度不會很深。最終的總分類器 是將每輪訓練得到的弱分類器加權求和得到的(也就是加法模型)。
模型最終可以描述為:
模型一共訓練M輪,每輪產生一個弱分類器 T(x;θm)T(x;θm)。弱分類器的損失函數
Fm−1(x)Fm−1(x) 為當前的模型,gbdt 通過經驗風險極小化來確定下一個弱分類器的參數。具體到損失函數本身的選擇也就是L的選擇,有平方損失函數,0-1損失函數,對數損失函數等等。如果我們選擇平方損失函數,那么這個差值其實就是我們平常所說的殘差。
-
- 但是其實我們真正關注的,1.是希望損失函數能夠不斷的減小,2.是希望損失函數能夠盡可能快的減小。所以如何盡可能快的減小呢?
-
- 讓損失函數沿着梯度方向的下降。這個就是gbdt 的 gb的核心了。 利用損失函數的負梯度在當前模型的值作為回歸問題提升樹算法中的殘差的近似值去擬合一個回歸樹。gbdt 每輪迭代的時候,都去擬合損失函數在當前模型下的負梯度。
-
- 這樣每輪訓練的時候都能夠讓損失函數盡可能快的減小,盡快的收斂達到局部最優解或者全局最優解。
- gbdt如何選擇特征?
gbdt選擇特征的細節其實是想問你CART Tree生成的過程。這里有一個前提,gbdt的弱分類器默認選擇的是CART TREE。其實也可以選擇其他弱分類器的,選擇的前提是低方差和高偏差。框架服從boosting 框架即可。
下面我們具體來說CART TREE(是一種二叉樹) 如何生成。CART TREE 生成的過程其實就是一個選擇特征的過程。假設我們目前總共有 M 個特征。第一步我們需要從中選擇出一個特征 j,做為二叉樹的第一個節點。然后對特征 j 的值選擇一個切分點 m. 一個 樣本的特征j的值 如果小於m,則分為一類,如果大於m,則分為另外一類。如此便構建了CART 樹的一個節點。其他節點的生成過程和這個是一樣的。現在的問題是在每輪迭代的時候,如何選擇這個特征 j,以及如何選擇特征 j 的切分點 m:
-
- 原始的gbdt的做法非常的暴力,首先遍歷每個特征,然后對每個特征遍歷它所有可能的切分點,找到最優特征 m 的最優切分點 j。
-
- 如何衡量我們找到的特征 m和切分點 j 是最優的呢? 我們用定義一個函數 FindLossAndSplit 來展示一下求解過程:
1 def findLossAndSplit(x,y): 2 # 我們用 x 來表示訓練數據 3 # 我們用 y 來表示訓練數據的label 4 # x[i]表示訓練數據的第i個特征 5 # x_i 表示第i個訓練樣本 6 7 # minLoss 表示最小的損失 8 minLoss = Integet.max_value 9 # feature 表示是訓練的數據第幾緯度的特征 10 feature = 0 11 # split 表示切分點的個數 12 split = 0 13 14 # M 表示 樣本x的特征個數 15 for j in range(0,M): 16 # 該維特征下,特征值的每個切分點,這里具體的切分方式可以自己定義 17 for c in range(0,x[j]): 18 L = 0 19 # 第一類 20 R1 = {x|x[j] <= c} 21 # 第二類 22 R2 = {x|x[j] > c} 23 # 屬於第一類樣本的y值的平均值 24 y1 = ave{y|x 屬於 R1} 25 # 屬於第二類樣本的y值的平均值 26 y2 = ave{y| x 屬於 R2} 27 # 遍歷所有的樣本,找到 loss funtion 的值 28 for x_1 in all x 29 if x_1 屬於 R1: 30 L += (y_1 - y1)^2 31 else: 32 L += (y_1 - y2)^2 33 if L < minLoss: 34 minLoss = L 35 feature = i 36 split = c 37 return minLoss,feature ,split
-
- 如果對這段代碼不是很了解的,可以先去看看李航第五章中對CART TREE 算法的敘述。在這里,我們先遍歷訓練樣本的所有的特征,對於特征 j,我們遍歷特征 j 所有特征值的切分點 c。找到可以讓下面這個式子最小的特征 j 以及切分點c.
-
- gbdt 如何構建特征 ?
其實說gbdt 能夠構建特征並非很准確,gbdt 本身是不能產生特征的,但是我們可以利用gbdt去產生特征的組合。在CTR預估中,工業界一般會采用邏輯回歸去進行處理,在我的上一篇博文當中已經說過,邏輯回歸本身是適合處理線性可分的數據,如果我們想讓邏輯回歸處理非線性的數據,其中一種方式便是組合不同特征,增強邏輯回歸對非線性分布的擬合能力。
長久以來,我們都是通過人工的先驗知識或者實驗來獲得有效的組合特征,但是很多時候,使用人工經驗知識來組合特征過於耗費人力,造成了機器學習當中一個很奇特的現象:有多少人工就有多少智能。關鍵是這樣通過人工去組合特征並不一定能夠提升模型的效果。所以我們的從業者或者學界一直都有一個趨勢便是通過算法自動,高效的尋找到有效的特征組合。Facebook 在2014年 發表的一篇論文便是這種嘗試下的產物,利用gbdt去產生有效的特征組合,以便用於邏輯回歸的訓練,提升模型最終的效果。
圖 2:用GBDT 構造特征
如圖 2所示,我們 使用 GBDT 生成了兩棵樹,兩顆樹一共有五個葉子節點。我們將樣本 X 輸入到兩顆樹當中去,樣本X 落在了第一棵樹的第二個葉子節點,第二顆樹的第一個葉子節點,於是我們便可以依次構建一個五緯的特征向量,每一個緯度代表了一個葉子節點,樣本落在這個葉子節點上面的話那么值為1,沒有落在該葉子節點的話,那么值為 0.
於是對於該樣本,我們可以得到一個向量[0,1,0,1,0] 作為該樣本的組合特征,和原來的特征一起輸入到邏輯回歸當中進行訓練。實驗證明這樣會得到比較顯著的效果提升。
- GBDT 如何用於分類 ?
首先明確一點,gbdt 無論用於分類還是回歸一直都是使用的CART 回歸樹。不會因為我們所選擇的任務是分類任務就選用分類樹,這里面的核心是因為gbdt 每輪的訓練是在上一輪的訓練的殘差基礎之上進行訓練的。這里的殘差就是當前模型的負梯度值 。這個要求每輪迭代的時候,弱分類器的輸出的結果相減是有意義的。殘差相減是有意義的。
如果選用的弱分類器是分類樹,類別相減是沒有意義的。上一輪輸出的是樣本 x 屬於 A類,本一輪訓練輸出的是樣本 x 屬於 B類。 A 和 B 很多時候甚至都沒有比較的意義,A 類- B類是沒有意義的。
我們具體到分類這個任務上面來,我們假設樣本 X 總共有 K類。來了一個樣本 x,我們需要使用gbdt來判斷 x 屬於樣本的哪一類。
-
圖三 gbdt 多分類算法流程
第一步 我們在訓練的時候,是針對樣本 X 每個可能的類都訓練一個分類回歸樹。舉例說明,目前樣本有三類,也就是 K = 3。樣本 x 屬於 第二類。那么針對該樣本 x 的分類結果,其實我們可以用一個 三維向量 [0,1,0] 來表示。0表示樣本不屬於該類,1表示樣本屬於該類。由於樣本已經屬於第二類了,所以第二類對應的向量維度為1,其他位置為0。
針對樣本有 三類的情況,我們實質上是在每輪的訓練的時候是同時訓練三顆樹。第一顆樹針對樣本x的第一類,輸入為(x,0)(x,0)。第二顆樹輸入針對 樣本x 的第二類,輸入為(x,1)(x,1)。第三顆樹針對樣本x 的第三類,輸入為(x,0)(x,0)
在這里每顆樹的訓練過程其實就是就是我們之前已經提到過的CATR TREE 的生成過程。在此處我們參照之前的生成樹的程序 即可以就解出三顆樹,以及三顆樹對x 類別的預測值f1(x),f2(x),f3(x)f1(x),f2(x),f3(x)。那么在此類訓練中,我們仿照多分類的邏輯回歸 ,使用softmax 來產生概率,則屬於類別 1 的概率
並且我們我們可以針對類別1 求出 殘差y11(x)=0−p1(x)y11(x)=0−p1(x);類別2 求出殘差y22(x)=1−p2(x)y22(x)=1−p2(x);類別3 求出殘差y33(x)=0−p3(x)y33(x)=0−p3(x).
然后開始第二輪訓練 針對第一類 輸入為(x,y11(x)y11(x)), 針對第二類輸入為(x,y22(x))y22(x)), 針對 第三類輸入為 (x,y33(x)y33(x)).繼續訓練出三顆樹。一直迭代M輪。每輪構建 3顆樹。
所以當K =3。我們其實應該有三個式子
當訓練完畢以后,新來一個樣本 x1 ,我們需要預測該樣本的類別的時候,便可以有這三個式子產生三個值,f1(x),f2(x),f3(x)f1(x),f2(x),f3(x)。樣本屬於 某個類別c的概率為
- GBDT 多分類舉例說明
上面的理論闡述可能仍舊過於難懂,我們下面將拿Iris 數據集中的六個數據作為例子,來展示gbdt 多分類的過程。
-
樣本編號 花萼長度(cm) 花萼寬度(cm) 花瓣長度(cm) 花瓣寬度 花的種類 1 5.1 3.5 1.4 0.2 山鳶尾 2 4.9 3.0 1.4 0.2 山鳶尾 3 7.0 3.2 4.7 1.4 雜色鳶尾 4 6.4 3.2 4.5 1.5 雜色鳶尾 5 6.3 3.3 6.0 2.5 維吉尼亞鳶尾 6 5.8 2.7 5.1 1.9 維吉尼亞鳶尾
這是一個有6個樣本的三分類問題。我們需要根據這個花的花萼長度,花萼寬度,花瓣長度,花瓣寬度來判斷這個花屬於山鳶尾,雜色鳶尾,還是維吉尼亞鳶尾。具體應用到gbdt多分類算法上面。我們用一個三維向量來標志樣本的label。[1,0,0] 表示樣本屬於山鳶尾,[0,1,0] 表示樣本屬於雜色鳶尾,[0,0,1] 表示屬於維吉尼亞鳶尾。
gbdt 的多分類是針對每個類都獨立訓練一個 CART Tree。所以這里,我們將針對山鳶尾類別訓練一個 CART Tree 1。雜色鳶尾訓練一個 CART Tree 2 。維吉尼亞鳶尾訓練一個CART Tree 3,這三個樹相互獨立。
我們以樣本 1 為例。針對 CART Tree1 的訓練樣本是[5.1,3.5,1.4,0.2][5.1,3.5,1.4,0.2],label 是 1,最終輸入到模型當中的為[5.1,3.5,1.4,0.2,1][5.1,3.5,1.4,0.2,1]。針對 CART Tree2 的訓練樣本也是[5.1,3.5,1.4,0.2][5.1,3.5,1.4,0.2],但是label 為 0,最終輸入模型的為[5.1,3.5,1.4,0.2,0][5.1,3.5,1.4,0.2,0]. 針對 CART Tree 3的訓練樣本也是[5.1,3.5,1.4,0.2][5.1,3.5,1.4,0.2],label 也為0,最終輸入模型當中的為[5.1,3.5,1.4,0.2,0][5.1,3.5,1.4,0.2,0].
下面我們來看 CART Tree1 是如何生成的,其他樹 CART Tree2 , CART Tree 3的生成方式是一樣的。CART Tree的生成過程是從這四個特征中找一個特征做為CART Tree1 的節點。比如花萼長度做為節點。6個樣本當中花萼長度 大於5.1 cm的就是 A類,小於等於 5.1 cm 的是B類。生成的過程其實非常簡單,問題 1.是哪個特征最合適? 2.是這個特征的什么特征值作為切分點? 即使我們已經確定了花萼長度做為節點。花萼長度本身也有很多值。在這里我們的方式是遍歷所有的可能性,找到一個最好的特征和它對應的最優特征值可以讓當前式子的值最小。
我們以第一個特征的第一個特征值為例。R1 為所有樣本中花萼長度小於 5.1 cm 的樣本集合,R2 為所有樣本當中花萼長度大於等於 5.1cm 的樣本集合。所以 R1={2}R1={2},R2={1,3,4,5,6}R2={1,3,4,5,6}.
圖 5 節點分裂示意圖
y1 為 R1 所有樣本的label 的均值 1/1=11/1=1。y2 為 R2 所有樣本的label 的均值 (1+0+0+0+0)/5=0.2(1+0+0+0+0)/5=0.2。
下面便開始針對所有的樣本計算這個式子的值。樣本1 屬於 R2 計算的值為(1−0.2)2(1−0.2)2, 樣本2 屬於R1 計算的值為(1−1)2(1−1)2, 樣本 3,4,5,6同理都是 屬於 R2的 所以值是(0−0.2)2(0−0.2)2. 把這六個值加起來,便是 山鳶尾類型在特征1 的第一個特征值的損失值。這里算出來(1-0.2)^2+ (1-1)^2 + (0-0.2)^2+(0-0.2)^2+(0-0.2)^2 +(0-0.2)^2= 0.84
接着我們計算第一個特征的第二個特征值,計算方式同上,R1 為所有樣本中 花萼長度小於 4.9 cm 的樣本集合,R2 為所有樣本當中 花萼長度大於等於 4.9 cm 的樣本集合.所以 R1={}R1={},R1={1,2,3,4,5,6}R1={1,2,3,4,5,6}. y1 為 R1 所有樣本的label 的均值 = 0。y2 為 R2 所有樣本的label 的均值 (1+1+0+0+0+0)/6=0.3333(1+1+0+0+0+0)/6=0.3333。
圖 6 第一個特征的第二個特偵值的節點分裂情況
我們需要針對所有的樣本,樣本1 屬於 R2, 計算的值為(1−0.333)2(1−0.333)2, 樣本2 屬於R2 ,計算的值為(1−0.333)2(1−0.333)2, 樣本 3,4,5,6同理都是 屬於 R2的, 所以值是(0−0.333)2(0−0.333)2. 把這六個值加起來山鳶尾類型在特征1 的第二個特征值的損失值。這里算出來 (1-0.333)^2+ (1-0.333)^2 + (0-0.333)^2+(0-0.333)^2+(0-0.333)^2 +(0-0.333)^2 = 2.244189. 這里的損失值大於 特征一的第一個特征值的損失值,所以我們不取這個特征的特征值。
圖 7 所有情況說明
這樣我們可以遍歷所有特征的所有特征值,找到讓這個式子最小的特征以及其對應的特征值,一共有24種情況,4個特征*每個特征有6個特征值。在這里我們算出來讓這個式子最小的特征花萼長度,特征值為5.1 cm。這個時候損失函數最小為 0.8。
於是我們的預測函數此時也可以得到:
此處 R1 = {2},R2 = {1,3,4,5,6},y1 = 1,y2 = 0.2。訓練完以后的最終式子為
借由這個式子,我們得到對樣本屬於類別1 的預測值 f1(x)=1+0.2∗5=2f1(x)=1+0.2∗5=2。同理我們可以得到對樣本屬於類別2,3的預測值f2(x)f2(x),f3(x)f3(x).樣本屬於類別1的概率 即為
下面我們用代碼來實現整個找特征的過程,大家可以自己再對照代碼看看。
1 # 定義訓練數據 2 train_data = [[5.1,3.5,1.4,0.2],[4.9,3.0,1.4,0.2],[7.0,3.2,4.7,1.4],[6.4,3.2,4.5,1.5],[6.3,3.3,6.0,2.5],[5.8,2.7,5.1,1.9]] 3 4 # 定義label 5 label_data = [[1,0,0],[1,0,0],[0,1,0],[0,1,0],[0,0,1],[0,0,1]] 6 # index 表示的第幾類 7 def findBestLossAndSplit(train_data,label_data,index): 8 sample_numbers = len(label_data) 9 feature_numbers = len(train_data[0]) 10 current_label = [] 11 12 # define the minLoss 13 minLoss = 10000000 14 15 # feature represents the dimensions of the feature 16 feature = 0 17 18 # split represents the detail split value 19 split = 0 20 21 # get current label 22 for label_index in range(0,len(label_data)): 23 current_label.append(label_data[label_index][index]) 24 25 # trans all features 26 for feature_index in range(0,feature_numbers): 27 ## current feature value 28 current_value = [] 29 30 for sample_index in range(0,sample_numbers): 31 current_value.append(train_data[sample_index][feature_index]) 32 L = 0 33 ## different split value 34 print current_value 35 for index in range(0,len(current_value)): 36 R1 = [] 37 R2 = [] 38 y1 = 0 39 y2 = 0 40 41 for index_1 in range(0,len(current_value)): 42 if current_value[index_1] < current_value[index]: 43 R1.append(index_1) 44 else: 45 R2.append(index_1) 46 47 ## calculate the samples for first class 48 sum_y = 0 49 for index_R1 in R1: 50 sum_y += current_label[index_R1] 51 if len(R1) != 0: 52 y1 = float(sum_y) / float(len(R1)) 53 else: 54 y1 = 0 55 56 ## calculate the samples for second class 57 sum_y = 0 58 for index_R2 in R2: 59 sum_y += current_label[index_R2] 60 if len(R2) != 0: 61 y2 = float(sum_y) / float(len(R2)) 62 else: 63 y2 = 0 64 65 ## trans all samples to find minium loss and best split 66 for index_2 in range(0,len(current_value)): 67 if index_2 in R1: 68 L += float((current_label[index_2]-y1))*float((current_label[index_2]-y1)) 69 else: 70 L += float((current_label[index_2]-y2))*float((current_label[index_2]-y2)) 71 72 if L < minLoss: 73 feature = feature_index 74 split = current_value[index] 75 minLoss = L 76 print "minLoss" 77 print minLoss 78 print "split" 79 print split 80 print "feature" 81 print feature 82 return minLoss,split,feature 83 84 findBestLossAndSplit(train_data,label_data,0)
- 3 總結
目前,我們總結了 gbdt 的算法的流程,gbdt如何選擇特征,如何產生特征的組合,以及gbdt 如何用於分類,這個目前可以認為是gbdt 最經常問到的四個部分。至於剩余的問題,因為篇幅的問題,我們准備再開一個篇幅來進行總結。.
Practical Lessons from Predicting Clicks on Ads at Facebook
ABSTRACT
這篇paper中作者結合GBDT和LR,取得了很好的效果,比單個模型的效果高出3%。隨后作者研究了對整體預測系統產生影響的幾個因素,發現Feature(能挖掘出用戶和廣告的歷史信息)+Model(GBDT+LR)的貢獻程度最大,而其他因素(數據實時性,模型學習速率,數據采樣)的影響則較小。
1. INTRODUCTION
介紹了先前的一些相關paper。包括Google,Yahoo,MS的關於CTR Model方面的paper。
而在Facebook,廣告系統是由級聯型的分類器(a cascade of classifiers)組成,而本篇paper討論的CTR Model則是這個cascade classifiers的最后一環節。
2. EXPERIMENTAL SETUP
作者介紹了如何構建training data和testing data,以及Evaluation Metrics。包括Normalized Entropy和Calibration。
Normalized Entropy的定義為每次展現時預測得到的log loss的平均值,除以對整個數據集的平均log loss值。之所以需要除以整個數據集的平均log loss值,是因為backgroud CTR越接近於0或1,則越容易預測取得較好的log loss值,而做了normalization后,NE便會對backgroud CTR不敏感了。這個Normalized Entropy值越低,則說明預測的效果越好。下面列出表達式:
Calibration的定義為預估CTR除以真實CTR,即預測的點擊數除以真實觀察到的點擊數。這個值越接近1,則表明預測效果越好。
3. PREDICTION MODEL STRUCTURE
作者介紹了兩種Online Learning的方法。包括Stochastic Gradient Descent(SGD)-based LR:
和Bayesian online learning scheme for probit regression(BOPR):
BOPR每輪迭代時的更新公式為:
3.1 Decision tree feature transforms
Linear Model的表達能力不夠,需要feature transformation。第一種方法是對連續feature進行分段處理(怎樣分段,以及分段的分界點是很重要的);第二種方法是進行特征組合,包括對離散feature做笛卡爾積,或者對連續feature使用聯合分段(joint binning),比如使用k-d tree。
而使用GBDT能作為一種很好的feature transformation的工具,我們可以把GBDT中的每棵樹作為一種類別的feature,把一個instance經過GBDT的流程(即從根節點一直往下分叉到一個特定的葉子節點)作為一個instance的特征組合的過程。這里GBDT采用的是Gradient Boosting Machine + L2-TreeBoost算法。這里是本篇paper的重點部分,放一張經典的原圖:
3.2 Data freshness
CTR預估系統是在一個動態的環境中,數據的分布隨時在變化,所以本文探討了data freshness對預測效果的影響,表明training data的日期越靠近,效果越好。
3.3 Online linear classifier
探討了對SGD-based LR中learning rate的選擇。最好的選擇為:
1)global效果差的原因:每個維度上訓練樣本的不平衡,每個訓練樣本擁有不同的feature。那些擁有樣本數較少的維度的learning rate下降過快,導致無法收斂到最優值。
2)per weight差的原因:雖然對於各個維度有所區分,但是其對於各個維度的learning rate下降速度都太快了,訓練過早結束,無法收斂到最優值。
SGD-based LR vs BOPR
1)SGD-based LR對比BOPR的優勢:
1-1)模型參數少,內存占用少。SGD-based LR每個維度只有一個weight值,而BOPR每個維度有1個均值 + 1個方差值。
1-2)計算速度快。SGD-LR只需1次內積計算,BOPR需要2次內積計算。
2)BOPR對比SGD-based LR的優勢:
2-1)BOPR可以得到完整的預測點擊概率分布。
4 ONLINE DATA JOINER
Online Data Joiner主要是用於在線的將label與相應的features進行join。同時作者也介紹了正負樣本的選取方式,以及選取負樣本時候的waiting time window的選擇。
5 CONTAINING MEMORY AND LATENCY
作者探討了GBDT中tree的個數,各種類型的features(包括contextual features和historical features),對預測效果的影響。結論如下:
1)NE的下降基本來自於前500棵樹。
2)最后1000棵樹對NE的降低貢獻低於0.1%。
3)Submodel 2 過擬合,數據量較少,只有其余2個模型的約四分之一。
4)Importance為feature帶來的累積信息增益 / 平方差的減少
5)Top 10 features貢獻了將近一半的importance
6)最后的300個features的貢獻不足1%
6 COPYING WITH MASSIVE TRANING DATA
作者探討了如何進行樣本采樣的過程,包括了均勻采樣(Uniform subsampling),和負樣本降采樣(Negative down sampling),以及對預測效果的影響。
一. GBDT的經典paper:《Greedy Function Approximation:A Gradient Boosting Machine》
Abstract
Function approximation是從function space方面進行numerical optimization,其將stagewise additive expansions和steepest-descent minimization結合起來。而由此而來的Gradient Boosting Decision Tree(GBDT)可以適用於regression和classification,都具有完整的,魯棒性高,解釋性好的優點。
1. Function estimation
在機器學習的任務中,我們一般面對的問題是構造loss function,並求解其最小值。可以寫成如下形式:
通常的loss function有:
1. regression:均方誤差(y-F)2,絕對誤差|y-F|
2. classification:negative binomial log-likelihood log(1+e-2yF)
一般情況下,我們會把F(x)看做是一系列帶參數的函數集合 F(x;P),於是進一步將其表示為“additive”的形式:
1.1 Numerical optimizatin
我們可以通過選取一個參數模型F(x;P),來將function optimization問題轉化為一個parameter optimization問題:
進一步,我們可以把要優化的參數也表示為“additive”的形式:
1.2 Steepest-descent
梯度下降是最簡單,最常用的numerical optimization method之一。
首先,計算出當前的梯度:
where
而梯度下降的步長為:
where ,稱為“line search”。
2. Numerical optimization in function space
現在,我們考慮“無參數”模型,轉而考慮直接在function space 進行numerical optimization。這時候,我們將在每個數據點x處的函數值F(x)看做是一個“參數”,仍然是來對loss funtion求解最小值。
在function space,為了表示一個函數F(x),理想狀況下有無數個點,但在現實中,我們用有限個(N個)離散點來表示它:。
按照之前的numerical optimization的方式,我們需要求解:
使用steepest-descent,有:
where ,and
3. Finite data
當我們面對的情況為:用有限的數據集表示x,y的聯合分布的時候,上述的方法就有點行不通了。我們可以試試“greedy-stagewise”的方法:
但是對於一般的loss function和base learner來說,(9)式是很難求解的。給定了m次迭代后的當前近似函數Fm-1(x),當步長的direction是指數函數集合
當中的一員時,
可以看做是在求解最優值上的greedy step,同樣,它也可以被看做是相同限制下的steepest-descent step。作為比較,
給出了在無限制條件下,在Fm-1(x)處的steepest-descent step direction。一種行之有效的方法就是在求解
的時候,把它取為無限制條件下的負梯度方向
:
where
這就把(9)式中較難求解的優化問題轉化為了一個基於均方誤差的擬合問題。
Gradient Boosting的通用解法如下:
二. 對於GBDT的一些理解
1. Boosting
GBDT的全稱是Gradient Boosting Decision Tree,Gradient Boosting和Decision Tree是兩個獨立的概念。因此我們先說說Boosting。Boosting的概念很好理解,意思是用一些弱分類器的組合來構造一個強分類器。因此,它不是某個具體的算法,它說的是一種理念。和這個理念相對應的是一次性構造一個強分類器。像支持向量機,邏輯回歸等都屬於后者。通常,我們通過相加來組合分類器,形式如下:
2. Gradient Boosting Modeling(GBM)
給定一個問題,我們如何構造這些弱分類器呢?Gradient Boosting Modeling (GBM) 就是構造 這些弱分類的一種方法。同樣,它指的不是某個具體的算法,仍然只是一個理念。在理解 Gradient Boosting Modeling 之前,我們先看看一個典型的優化問題:
針對這種優化問題,有一個經典的算法叫 Steepest Gradient Descent,也就是最深梯度下降法。 這個算法的過程大致如下:
以上迭代過程可以這么理解:整個尋優的過程就是個小步快跑的過程,每跑一小步,都往函數當前下降最快的那個方向走一點。
這樣尋優得到的結果可以表示成加和形式,即:
這個形式和以上Fm(x)是不是非常相似? Gradient Boosting 正是由此啟發而來。 構造Fm(x)本身也是一個尋優的過程,只不過我們尋找的不是一個最優點,而是一個最優的函數。優化的目標通常都是通過一個損失函數來定義,即:
其中Loss(F(xi), yi)表示損失函數Loss在第i個樣本上的損失值,xi和yi分別表示第 i 個樣本的特征和目標值。常見的損失函數如平方差函數:
類似最深梯度下降法,我們可以通過梯度下降法來構造弱分類器f1, f2, ... , fm,只不過每次迭代時,令
即對損失函數L,以 F 為參考求取梯度。
這里有個小問題,一個函數對函數的求導不好理解,而且通常都無法通過上述公式直接求解 到梯度函數gi。為此,采取一個近似的方法,把函數Fi−1理解成在所有樣本上的離散的函數值,即:
不難理解,這是一個 N 維向量,然后計算

這是一個函數對向量的求導,得到的也是一個梯度向量。注意,這里求導時的變量還是函數F,不是樣本xk。
嚴格來說 ĝi(xk) for k = 1,2, ... , N 只是描述了gi在某些個別點上的值,並不足以表達gi,但我們可以通過函數擬合的方法從ĝi(xk) for k = 1,2, ... , N 構造gi,這樣我們就通過近似的方法得到了函數對函數的梯度求導。
因此 GBM 的過程可以總結為如下:
常量函數f0通常取樣本目標值的均值,即
3. Gradient Boosting Decision Tree
以上 Gradient Boosting Modeling 的過程中,還沒有說清楚如何通過離散值 ĝi−1(xj) for j = 1,2,3,...N 構造擬合函數gi−1。函數擬合是個比較熟知的概念,有很多現成的方法,不過有一種擬合方法廣為應用,那就是決策樹 Decision Tree,有關決策樹的概念,理解GBDT重點首先是Gradient Boosting,其次才是 Decision Tree。GBDT 是 Gradient Boosting 的一種具體實例,只不過這里的弱分類器是決策樹。如果你改用其他弱分類器 XYZ,你也可以稱之為 Gradient Boosting XYZ。只不過 Decision Tree 很好用,GBDT 才如此引人注目。
4. 損失函數
談到 GBDT,常聽到一種簡單的描述方式:“先構造一個(決策)樹,然后不斷在已有模型和實際樣本輸出的殘差上再構造一顆樹,依次迭代”。其實這個說法不全面,它只是 GBDT 的一種特殊情況,為了看清這個問題,需要對損失函數的選擇做一些解釋。
從對GBM的描述里可以看到Gradient Boosting過程和具體用什么樣的弱分類器是完全獨立的,可以任意組合,因此這里不再刻意強調用決策樹來構造弱分類器,轉而我們來仔細看看弱分類器擬合的目標值,即梯度ĝi−1(xj ),之前我們已經提到過
5. GBDT 和 AdaBoost
Boosting 是一類機器學習算法,在這個家族中還有一種非常著名的算法叫 AdaBoost,是 Adaptive Boosting 的簡稱,AdaBoost 在人臉檢測問題上尤其出名。既然也是 Boosting,可以想象它的構造過程也是通過多個弱分類器來構造一個強分類器。那 AdaBoost 和 GBDT 有什么區別呢?
兩者最大的區別在於,AdaBoost 不屬於 Gradient Boosting,即它在構造弱分類器時並沒有利用到梯度下降法的思想,而是用的Forward Stagewise Additive Modeling (FSAM)。為了理解 FSAM,在回過頭來看看之前的優化問題。
嚴格來說之前描述的優化問題要求我們同時找出α1, α2, ... , αm和f1, f2, f3 ... , fm,這個問題很 難。為此我們把問題簡化為分階段優化,每個階段找出一個合適的α 和f 。假設我們已經 得到前 m-1 個弱分類器,即Fm−1(x),下一步在保證Fm−1(x)不變的前提下,尋找合適的 αmfm(x)。按照損失函數的定義,我們可以得到
如果 Loss 是平方差函數,則我們有
這里yi − Fm−1(xi)就是當前模型在數據上的殘差,可以看出,求解合適的αmfm(x)就是在這 當前的殘差上擬合一個弱分類器,且損失函數還是平方差函數。這和 GBDT 選擇平方差損失 函數時構造弱分類器的方法恰好一致。
(1)擬合的是“殘差”,對應於GBDT中的梯度方向。
(2)損失函數是平方差函數,對應於GBDT中用Decision Tree來擬合“殘差”。
其中 wim−1= exp(−yi(Fm−1(xi))和要求解的αmfm(x)無關,可以當成樣本的權重,因此在這種情況下,構造弱分類器就是在對樣本設置權重后的數據上擬合,且損失函數還是指數形式。 這個就是 AdaBoost,不過 AdaBoost 最早並不是按這個思路推出來的,相反,是在 AdaBoost 提出 5 年后,人們才開始用 Forward Stagewise Additive Modeling 來解釋 AdaBoost 背后的原理。
為什么要把平方差和指數形式 Loss 函數單獨拿出來說呢?這是因為對這兩個損失函數來說, 按照 Forward Stagewise Additive Modeling 的思路構造弱分類器時比較方便。如果是平方差損 失函數,就在殘差上做平方差擬合構造弱分類器; 如果是指數形式的損失函數,就在帶權 重的樣本上構造弱分類器。但損失函數如果不是這兩種,問題就沒那么簡單,比如絕對差值 函數,雖然構造弱分類器也可以表示成在殘差上做絕對差值擬合,但這個子問題本身也不容 易解,因為我們是要構造多個弱分類器的,所以我們當然希望構造弱分類器這個子問題比較 好解。因此 FSAM 思路無法推廣到其他一些實用的損失函數上。相比而言,Gradient Boosting Modeling (GBM) 有什么優勢呢?GBM 每次迭代時,只需要計算當前的梯度,並在平方差損 失函數的基礎上擬合梯度。雖然梯度的計算依賴原始問題的損失函數形式,但這不是問題, 只要損失函數是連續可微的,梯度就可以計算。至於擬合梯度這個子問題,我們總是可以選 擇平方差函數作為這個子問題的損失函數,因為這個子問題是一個獨立的回歸問題。
因此 FSAM 和 GBM 得到的模型雖然從形式上是一樣的,都是若干弱模型相加,但是他們求 解弱分類器的思路和方法有很大的差別。只有當選擇平方差函數為損失函數時,這兩種方法 等同。
6. 為何GBDT受人青睞
以上比較了 GBM 和 FSAM,可以看到 GBM 在損失函數的選擇上有更大的靈活性,但這不足以解釋GBDT的全部優勢。GBDT是拿Decision Tree作為GBM里的弱分類器,GBDT的優勢 首先得益於 Decision Tree 本身的一些良好特性,具體可以列舉如下:
-
Decision Tree 可以很好的處理 missing feature,這是他的天然特性,因為決策樹的每個節點只依賴一個 feature,如果某個 feature 不存在,這顆樹依然可以拿來做決策,只是少一些路徑。像邏輯回歸,SVM 就沒這個好處。
-
Decision Tree 可以很好的處理各種類型的 feature,也是天然特性,很好理解,同樣邏輯回歸和 SVM 沒這樣的天然特性。
-
對特征空間的 outlier 有魯棒性,因為每個節點都是 x < 𝑇 的形式,至於大多少,小多少沒有區別,outlier 不會有什么大的影響,同樣邏輯回歸和 SVM 沒有這樣的天然特性。
-
如果有不相關的 feature,沒什么干擾,如果數據中有不相關的 feature,頂多這個 feature 不出現在樹的節點里。邏輯回歸和 SVM 沒有這樣的天然特性(但是有相應的補救措施,比如邏輯回歸里的 L1 正則化)。
-
數據規模影響不大,因為我們對弱分類器的要求不高,作為弱分類器的決策樹的深 度一般設的比較小,即使是大數據量,也可以方便處理。像 SVM 這種數據規模大的時候訓練會比較麻煩。
當然 Decision Tree 也不是毫無缺陷,通常在給定的不帶噪音的問題上,他能達到的最佳分類效果還是不如 SVM,邏輯回歸之類的。但是,我們實際面對的問題中,往往有很大的噪音,使得 Decision Tree 這個弱勢就不那么明顯了。而且,GBDT 通過不斷的疊加組合多個小的 Decision Tree,他在不帶噪音的問題上也能達到很好的分類效果。換句話說,通過GBDT訓練組合多個小的 Decision Tree 往往要比一次性訓練一個很大的 Decision Tree 的效果好很多。因此不能把 GBDT 理解為一顆大的決策樹,幾顆小樹經過疊加后就不再是顆大樹了,它比一顆大樹更強。