[ML] 機器學習技法:第十一講 Gradient Boosted Decision Tree

ML:基礎技法學習
Package:scikit-learn
課程:機器學習技法
簡介:第十一講 Gradient Boosted Decision Tree

Adaptive Boosted Decision Tree

  • function AdaBoost-DTree(D)
    • u(1)=[1N,1N,,1N]
    • for t=1,2,,TT 自行決定
      1. 兩種方式得到 gt
        • DTree 必須為 pruned
        • 傳入 u(t)
          gt=DTree(D,u(t))
        • D~t 為依 u(t)D 抽樣
          gt=DTree(D~t)
      2. 更新 u(t)u(t+1),藉由
        (incorrect examples) [yngt(xn)]:un(t+1)un(t)t(correct examples) [yn=gt(xn)]:un(t+1)un(t) / tt=1ϵtϵt and ϵt=n=1Nun(t)[yngt(xn)]n=1Nun(t)
      3. 計算 αt=ln(t)
    • 回傳 G(x)=sign(t=1Tαtgt(x))
因 decision Tree 太過複雜,不見得可以直接計算 Einu(h)=1Nn=1Nunerr(yn,h(xn))
那為何不回到原本的概念,boostrapping-sampled 才產生 u
將 decision Tree 當作黑盒子,只是在給予的資料上動手腳
D 中取 N 筆資料得到 D~t,但其比例和 ut 成正比

假設 Decision Tree 為 fully grown tree,且所有 xn 完全不一樣
導致 Ein(gt)=0Einu(gt)=0
結果 ϵt=0αt=
這不就違反初衷,原本想要的是很多樹一起決定結果,但卻弄出個一言堂
所以在此,需要 pruned Tree 並且只針對部分資料做訓練
pruned 的方法,可參考 [ML] 機器學習技法:第九講 Decision Tree
或者直接限定樹的高度即可
而針對 u 進行取樣,其實就等同於只對部分資料進行訓練

[ML] 機器學習技法:第八講 Adaptive Boosting 的 AdaBoost-Stump
其實就是一種 AdaBoost-DTree 的特殊案例,因為它就等同於將樹限制在 H1 的情況
而且因為很簡單,所以可以直接計算 Einu(h)=1Nn=1Nunerr(yn,h(xn))

Optimization View of AdaBoost

minη minh E^ADA=n=1Nunt+1=1Nn=1Neynτ=1t1ατgτ(xn)+ηh(xn)
  1. Get gt by minh E^ADA=n=1Nun(t)eynηh(xn) 最小 Einu(t)(h)hgt
  2. 代入 gt,Get ηt by minηt E^ADA=n=1Nun(t)eynηtgt(xn) ηt=ln1ϵtϵt=αt
un(t+1)={un(t)tif incorrectun(t)/tif correct=un(t)tyngt(xn)=un(t)eynαtgt(xn)un(T+1)=un(1)t=1Teynαtgt(xn)=1Neynt=1Tαtgt(xn) G(xn)=sign(t=1Tαtwigt(xn)ϕi(xn)voting score) 且 hard-margin SVM margin=yn(wTϕ(xn)+b)w
可參考 [ML] 機器學習技法:第一講 linear SVM

然而 voting score 只是把 b=0 而已
所以 yn(voting score) = 未正規化的 margin
而且希望 yn(voting score) 是個很大的正值
所以 eyn(voting score) 會是個很小的值
un(T+1) 也會是個很小的值

在 AdaBoost 中,將會令 n=1Nun(t) 越來越小,相對而言,也相當在縮小 un(t)
如何證明呢?
首先,最後的 unT+1 的結果,會如下式
n=1NunT+1=1Nn=1Neynt=1Tαtgt(xn)=1Nn=1NeynG(xn) 所以當 G(xn) 正確且絕對值又很大時,那麼 ynG(xn) 就會是個很大的正值
若令 s=t=1Tαtgt(xn)
那麼 err0/1(s,y)=[ys0] 是分類的錯誤
而原式中可定義 errADA(s,y)=eys,就是 exponential error measure
如下圖可看出,當把 errADA 做好時,其實就等同把 err0/1做好
可參考 [ML] 機器學習基石:第十一講 Linear Models for Classification
[ML] 機器學習基石:第十講 Logistic Regression 知道 gradient descent
借由 taylor 展開式或者是 f(x)=limdx0f(x+dx)f(x)dx
minv=1 Ein(wt+ηv)Ein(wt)+ηvTEin(wt)
換個角度來看,向量不也是函數的一種,給予特定的 index,返回當下的值
所以把上式延伸概念,從找一個好的向量,延伸至找一個好的函數
那麼在 t 輪時,可借由下式,找到 gt
minh E^ADA=n=1Nunt+1=1Nn=1Neynτ=1t1ατgτ(xn)+ηh(xn)=1Nn=1Neynτ=1t1ατgτ(xn)eynηh(xn)=n=1N1Neynτ=1t1ατgτ(xn)eynηh(xn)=n=1Nun(t)eynηh(xn)[by taylor]n=1Nun(t)(1ynηh(xn))=n=1Nun(t)n=1Nun(t)ynηh(xn)=n=1Nun(t)+ηn=1Nun(t)(ynh(xn)) 實際上即是最小化 n=1Nun(t)(ynh(xn)),故
n=1Nun(t)(ynh(xn))=n=1Nun(t){1if yn=h(xn)+1if ynh(xn)=n=1Nun(t)+n=1Nun(t){0if yn=h(xn)2if ynh(xn)[Einu(t)(h)=1Nn=1Nun(t)[ynh(xn)]]=n=1Nun(t)+2NEinu(t)(h) 故最小化 Einu(t)(h) 即可得到 gt
如何做呢?這不就是 AdaBoost 的 A 在做的事,可參考 [ML] 機器學習技法:第八講 Adaptive Boosting
即然有了 gt 那應該也可以求當前最大步的 η,此種方法稱為 steepest descent for optimization
minη E^ADA=n=1Nun(t)eynηgt(xn)=n=1Nun(t){eηif yn=gt(xn)eηif yngt(xn)=n=1Nun(t)(eη[yn=gt(xn)]+eη[yngt(xn)])=n=1Neηun(t)[yn=gt(xn)]+eηun(t)[yngt(xn)]=eηn=1Nun(t)[yn=gt(xn)]+eηn=1Nun(t)[yngt(xn)]=(n=1Nun(t))(eηn=1Nun(t)[yn=gt(xn)]n=1Nun(t)+eηn=1Nun(t)[yngt(xn)]n=1Nun(t))[ϵt=n=1Nun(t)[yngt(xn)]n=1Nun(t)]=(n=1Nun(t))(eη(1ϵt)+eηϵt)E^ADAη=0E^ADAη=(n=1Nun(t))(ηeη(1ϵt)+ηeηϵt)=00=ηeη(1ϵt)+ηeηϵtηeη(1ϵt)=ηeηϵteη(1ϵt)=eηϵt(1ϵt)=e2ηϵt1ϵtϵt=e2η1ϵtϵt=eηη=ln1ϵtϵt

Gradient Boosted Decision Tree (GBDT)

  • s1=s2==sN=0 
  • for t=1,2,,T
    1. gt(xn)=A({(xn,ynsn)})
      A 為 squared-error regression algorithm 
      • A 為 sampled and pruned C&RT 是不錯的選擇
    2. αt=OneVarLinearRegression({(gt(xn),ynsn)})=n=1Ng(xn)(ynsn)n=1Ngt2(xn)
    3. 更新 snsn+αtgt(xn)
  • 回傳 G(x)=t=1Tαtgt(x)
已知 E^ADA
minη minh E^ADA=1Nn=1Neynτ=1t1ατgτ(xn)+ηh(xn) 這是用在二元分類的 h,那是否可以將之延伸至任意的 h 呢?
EADA,也就是 exponential error measure 替換成其他 err 不就好了
minη minh 1Nn=1Nerr(τ=1t1ατgτ(xn)sn+ηh(xn),yn)=minη minh 1Nn=1Nerr(sn+ηh(xn),yn)[by taylor]minη minh 1Nn=1Nerr(sn,yn)+ηh(xn)err(s,yn)s|s=sn=minη minh 1Nn=1Nerr(sn,yn)+1Nn=1Nηh(xn)err(s,yn)s|s=sn=minη minh 1Nn=1Nerr(sn,yn)constants+ηNn=1Nh(xn)err(s,yn)s|s=sn=minη minh constants+ηNn=1Nh(xn)err(s,yn)s|s=sn 如果將 err(s,y)=(sy)2,也就是 square error 代入
minη minh constants+ηNn=1Nh(xn)err(s,yn)s|s=sn=minη minh constants+ηNn=1Nh(xn)2(snyn) 直覺來看,當 h(xn)=(snyn) 不就得到最小值
這樣不就怪怪的,因為 h(xn) 決定方向,多大步皆由 η 決定才對
所以必須為 h(xn) 加入限制
minη minh constants+ηNn=1N(h(xn)2(snyn)+(h(xn))2)=minη minh constants+ηNn=1N((snyn)2+(snyn)2+h(xn)2(snyn)+(h(xn))2)=minη minh constants+ηNn=1N((snyn)2+(snyn+h(xn))2)=minη minh constants+ηNn=1N((snyn)2constant+(h(xn)(ynsn))2)=minη minh constants+ηNn=1N(constant+(h(xn)(ynsn))2) 若對 h 做最小化時,其他都是常數,所以只要把 (h(xn)(ynsn))2 做到最小,就行了
這不就是 regression,只是資料變成 {(xn,ynsnresidual)}
利用此資料,找到 h 的最佳解 gt,然後代進去求 η
minη 1Nn=1Nerr(τ=1t1ατgτ(xn)sn+ηgt(xn),yn)[err(s,y)=(sy)2]=minη 1Nn=1N(sn+ηgt(xn)yn)2=minη 1Nn=1N(snηgt(xn)+yn)2=minη 1Nn=1N((ynsn)ηgt(xn))2 這就是一個 one-variable linear regression 在 {(gttransformed input,residual)}
代公式解就好了,可參考 [ML] 機器學習基石:第九講 Linear Regression
或者求微分=0
0=η(1Nn=1N((ynsn)ηgt(xn))2)0=η(n=1N((ynsn)ηgt(xn))2)0=n=1N2((ynsn)ηgt(xn))gt(xn)0=n=1N((ynsn)ηgt(xn))gt(xn)0=n=1Ng(xn)(ynsn)ηn=1Ngt2(xn)ηn=1Ngt2(xn)=n=1Ng(xn)(ynsn)η=n=1Ng(xn)(ynsn)n=1Ngt2(xn)=αt

綜合比較

  • Aggregation Models
    • blending (aggregate 需先有多樣性的 gt)
      • uniform
        • 簡單
        • voting/averaging of gt 
        • 穩定,可互相修正
      • non-uniform
        • linear model on gt-transformed inputs 
        • powerful 但需小心 overfitting
      • conditional 
        • nonlinear model on gt-transformed inputs 
        • powerful 但需小心 overfitting
    • learning (aggregate 會自動得到多樣性的 gt)
      • Bagging
        • 多樣性的 gt 來自 bootsrapping
        • uniform vote by nothing
        • 延伸
          • Random Forest
            • 實務上常用
            • randomized bagging + strong DTree
      • Boost 
        • 實務上常用
        • AdaBoost
          • 多樣性的 gt 來自 reweighting
          • linear vote by steepest search 
          • 延伸
            • AdaBoost-DTree
              •  AdaBoost + weak DTree
        • GradientBoost
          • 多樣性的 gt 來自 residual fitting
          • linear vote by steepest search
          • 延伸
            • Gradient Boosted Decision Tree (GBDT)
              • GradientBoost + weak DTree
      • Decision Tree
        • 多樣性的 gt 來自 data splitting
        • condition vote by branching
    • Specialty
      • cure underfitting
        • G(x) strong
        • aggregation 等同在做 feature transform
      • cure overfitting
        • G(x) moderate
        • aggregation 等同在做 regularization
    • 不同的 aggregation,有不同的特性
      合適地混用 aggregation (a.k.a. ensemble) 可得到更好的結果

程式碼

即使是當下 stage 的最佳化 αn,對 Eout 也不見得是好的
  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3.  
  4. from sklearn import ensemble
  5. from sklearn import datasets
  6. from sklearn.utils import shuffle
  7. from sklearn.metrics import mean_squared_error
  8.  
  9. # 讀取波士頓房子價錢的資料
  10. boston = datasets.load_boston()
  11. # 重新洗牌
  12. X, y = shuffle(boston.data, boston.target, random_state=13)
  13. X = X.astype(np.float32)
  14.  
  15. # 分開 測試 與 訓練 資料
  16. offset = int(X.shape[0] * 0.9)
  17. X_train, y_train = X[:offset], y[:offset]
  18. X_test, y_test = X[offset:], y[offset:]
  19.  
  20. # G_n(x) = G_{n-1}(x) + learning_rate * alpha_n * g_t(x)
  21. # learning_rate=1 表示維持原本的演算法
  22. lrs = [1, 0.1, 0.01]
  23. plt.figure()
  24. for index, lr in enumerate(lrs):
  25. # 建立 500 棵樹,最大深度 4,loss 為‘ls’表示 least squares regression
  26. params = {'n_estimators': 500, 'max_depth': 4, 'learning_rate': lr, 'loss': 'ls'}
  27. clf = ensemble.GradientBoostingRegressor(**params)
  28. clf.fit(X_train, y_train)
  29. mse = mean_squared_error(y_test, clf.predict(X_test))
  30. print("MSE: %.4f" % mse)
  31.  
  32. # 計算每個 stage 的分數
  33. test_score = np.zeros((params['n_estimators'],), dtype=np.float64)
  34. for i, y_pred in enumerate(clf.staged_predict(X_test)):
  35. test_score[i] = clf.loss_(y_test, y_pred)
  36.  
  37. #畫圖
  38. plt.subplot(len(lrs), 1, index+1)
  39. plt.plot(np.arange(params['n_estimators']) + 1, clf.train_score_, 'b-',
  40. label='Training Set')
  41. plt.plot(np.arange(params['n_estimators']) + 1, test_score, 'r-',
  42. label='Test Set')
  43.  
  44. plt.legend(loc='right')
  45. plt.title("learning rate = {}".format(lr))
  46. plt.ylabel('Loss')
  47.  
  48. plt.xlabel('Boosting Iterations')
  49. plt.subplots_adjust(hspace=0.6)
  50. plt.suptitle("Learning Rate")
  51. plt.show()

參考

如何通俗地解释泰勒公式?
sklearn.ensemble.GradientBoostingClassifier
sklearn.ensemble.GradientBoostingRegressor

留言