1. 程式人生 > 其它 >經典機器學習演算法原理回顧 (LR / FMs / DT / GBDT / XGBoost)

經典機器學習演算法原理回顧 (LR / FMs / DT / GBDT / XGBoost)

目錄

1. Linear Regression

以一元線性迴歸為例,該演算法的中心思想是:找一條直線,並且讓這條直線儘可能地擬合圖中的資料點:

該模型可簡寫為:y = ax + b,我們需要根據已有的資料對(x, y),找到最佳的引數a, b 。同理,在高維空間中,我們尋找的就是線性分割空間的高維超平面。在優化模型的過程中,我們需要用損失函式 \(L(\hat y, y)\) 來衡量模型引數的好壞,線性迴歸常用的損失函式為均方誤差(MSELoss):
\(L(\hat y, y)=\frac{1}{m} \sum_{i=1}^{m} (\hat y^{(i)} - y^{(i)})^2\)

模型訓練(尋找最佳引數)的過程就是求解以下函式的過程:
\(a^*, b^* = \textstyle\arg\min_{a,b}L(\hat y, y)\)

該函式可以通過微積分和線代計算求解(最小二乘法),也可以通過最優化方法求解。在實踐中,由於模型涉及的訓練資料往往規模較大,如果用最小二乘法來解矩陣方程將會消耗過多的計算資源,因此我們常用最優化方法中的梯度下降法來求解該函式

梯度下降法的原理並不複雜,我們只需要從引數的初始值開始,根據訓練資料的計算結果不斷更新引數即可:
\(w_j := w_j - \alpha \frac{\partial }{\partial w_j}L(\omega )\)

批梯度下降和隨機梯度下降都是在上述公式的基礎上做的簡單改進,其目在於提升演算法的優化效率,這裡就暫時先不展開了

2. Factorization Machines

相關Paper:

  1. Rendle S . Factorization Machines[C] ICDM 2010
  2. Rendle S , et al. Fast context-aware recommendations with factorization machines[C]

演算法介紹:

  • FMs的優點:
    • FMs考慮了特徵的二階交叉,彌補了邏輯迴歸表達能力差的缺陷
    • FMs模型複雜度保持為線性,並且改進為高階特徵組合時,仍為線性複雜度
    • FMs引入隱向量,緩解了資料稀疏帶來的引數難訓練問題
      • 在推薦演算法的應用場景中,使用者和物品特徵中有很多項是categorical型別的,需要經過One-Hot編碼轉化成數值型特徵,這將導致樣本資料變得非常稀疏:
  • FMs的缺點:
    • 雖然考慮了特徵的交叉,但是表達能力仍然有限,不及深度模型
    • 同一特徵 x_i 與不同特徵組合使用的都是同一隱向量 v_i ,違反了特徵與不同特徵組合可發揮不同重要性的事實
  • 模型原理:
    • FM線上性模型的基礎上添加了一個多項式,用於描述特徵之間的二階交叉:
      \(y = \omega _0 + \sum _{i=1}^{n} \omega _i x_i + \sum _{i=1}^{n-1} \sum _{j=i+1}^{n} \omega _{ij} x_i x_j\)
      • 上式中:n表示特徵維數,不同特徵兩兩組合可以得到n(n-1)/2個交叉
      • 舉個例子描述特徵交叉:假如我們知道“小明既喜歡看戰爭電影,又曾購買過坦克模型”,那麼我們就能比僅知道“小明喜歡看戰爭電影”或“小明購買過坦克模型”更能推斷出小明對某軍事類廣告的點選傾向。從數學角度看,就是我們原本只建模f(x) = z 和 f(y) = z,現在我們能建模f(x, y) = z,這其實就是模型複雜度提升所帶來的擬合能力的提升
  • 引入交叉特徵後帶來的問題:
    • 上式中引數w_ij的優化其實是比較困難的,因為在計算梯度時,只有x_i和x_j都不為0時,我們才能得到有效的結果,但由於特徵矩陣的稀疏性,使得大部分引數w都難以得到充分的訓練
  • 解決方案:
    • FM對於每個特徵x_i,學習一個長度為k(k << n)的一維向量v,進而得到一個n×k的矩陣V,於是,兩個特徵 x_i 和 x_j 的特徵組合的權重值,通過特徵對應的向量 v_i 和 v_j 的內積 <v_i, v_j> 來表示,等同於對特徵做了一個embedding:
    • 這個embedding並不依賴某個特定的特徵組合是否出現過,所以只要特徵 x_i 和其它任意特徵組合出現過,那麼就可以學習自己對應的embedding向量
  • 複雜度分析:演算法的計算複雜度為O(kn),推導和化簡過程可見Rendle S . Factorization Machines中的 Lemma 3.1
  • 在優化方面,隨機梯度下降(SGD)和交替最小二乘(ALS)的單輪迭代複雜度都是O(kN_z(X)),ALS的優勢在於它不需要指定額外的超參(學習率),因此在效果上更加穩定

3. XGBoost

GBDT是以決策樹(CART)為基學習器的GB演算法,XGBoost擴充套件和改進了GDBT,XGBoost演算法更快,準確率也相對較高。我們接下來按順序依次對其進行介紹。

先看決策樹:

  • 決策樹模型的構造過程可概括為:迴圈執行“特徵選擇+分裂子樹”,最後觸達閾值停止分裂。在預測階段,我們把樣本特徵按樹的分裂過程依次展開,最後樣本的標籤就是葉子節點中佔大多數的樣本所對應的標籤:

  • 決策樹如何做特徵選擇?—— 三種演算法(ID3, C4.5, CART)

    • ID3以資訊熵減幅度作為特徵選擇依據,缺點是該演算法偏好細粒度高的特徵(如uuid),容易過擬合;C4.5在熵減式子中增加了一個分母(分枝數目)作為懲罰項,規避了ID3特徵分裂時細粒度過高的問題;CART採用Gini係數作為特徵選擇依據,在保持其他演算法優點的同時(Gini係數可理解為熵模型的一階泰勒展開),減少了大量的對數運算
  • 剪枝策略:

    • 預剪枝:在分裂子樹前判斷是否繼續。常用的停止標準包括:“計算分裂前後準確率是否提升”,“檢查分裂後節點內樣本容量是否低於閾值”等。預剪枝策略可以降低過擬合風險,減少模型訓練時間,但同時也會帶來欠擬合風險
    • 後剪枝:在決策樹構建完成後刪去不必要的子樹。典型的後剪枝策略如C4.5的“悲觀剪枝法”:自底向上依次判斷各節點分裂前後模型準確率是否提升,刪去對結果無增益的子樹。後剪枝策略的泛化效能常優於預剪枝策略,但其需要更多的訓練時間
  • 連續值處理(以CART為例):

    • 在解決迴歸問題時,CART採用和方差作為特徵分割點的選擇方式:對任意有序數值特徵a,窮舉分割界限s,計算分割後的兩團簇資料的和方差,最後取分割後和方差最小的界限作為切割閾值:
      \(min_{a,s}\left [ min_{c_1} \sum_{x_i \in D_1} (y_i - c_1)^2 + min_{c_2} \sum_{x_i \in D_2} (y_i - c_2)^2\right ]\)
      上式中D1,D2代表分割後的兩團資料簇,c1, c2代表兩團資料簇中的資料均值
  • 接下來我們看GB與GBDT:

    • GB(Gradient boosting)是一種整合學習方法,通過聚合多個弱模型,來獲得一個強模型。其核心思路是各模型通過“串聯”的方式,依次擬合其前置模型的殘差,進而實現對模型總體偏差(bias)的糾正。假設我們有M個弱模型,那麼上述思想可用公式表述為:
      \(\begin{matrix} F_{m+1}(x) = F_m(x) + h(x) , & 1 \le m \le M \end{matrix}\)
    • 注意上式中後置學習器擬合的h(x)是通過訓練資料計算出來的,其不同於真實資料分佈中的殘差,為了對二者作區分,h(x)又被稱作“偽殘差”
  • GBDT就是用決策樹(CART)充當GB方法中的弱模型(基學習器),進而實現的整合學習演算法,其中基學習器的迭代步驟為:

    我們注意到:在第一步計算偽殘差時,我們對損失函式求了一個偏導,以此作為目標殘差的近似。為什麼這裡能用負梯度來估算殘差呢?其實這裡蘊含了一個隱藏條件,就是基學習器(CART)的損失函式必須為平方誤差(Square Error Loss),只有這個條件滿足時,我們才能用負梯度近似殘差,相關數學證明可參考:GBDT理解難點 - 擬合負梯度

最後我們看XGBoost:

  • XGBoost在總體思路上與GBDT是相同的,它們都是通過串聯決策樹來擬合殘差,二者的不同之處在於目標函式的定義以及實現細節上的差異。從另一個角度看,我們也可以把XGBoost理解為工程視角下,加入了各種tricks以進行強化的GBDT
  • XGBoost的目標函式推導:
    • XGBoost通過疊加t個基學習器來擬合目標資料分佈,從整體來看,其目標函式可分為兩部分——預測誤差懲罰項和模型複雜度懲罰項:
    \[\begin{matrix} Obj = \sum_{i=1}^n l(\hat y_i,y_i) + \sum_{t=1}^k \Omega(f_t) & , & \Omega(f_t) = \gamma T_t + \frac{1}{2}\lambda \sum_{j=1}^T \omega _j^2 \end{matrix} \]
    • 上式中n代表訓練樣本樹,函式l代表預測誤差懲罰項,函式Omega代表模型複雜度懲罰項,T_t代表基學習器t下的葉子節點數目,omega代表基學習器中的權重引數(即L2正則項),gamma和lambda是平衡兩個複雜度懲罰項的權重超參
    • 由於Boosting需要依次對各基學習器的結果求和,所以在訓練第t個模型時,演算法給出的預測值為:
    \[\hat y_i^t = \hat y_i^{t-1} + f_t(x_i) \]
    • 上式中y hat代表已構建好的基學習器的預測結果,函式f代表正在訓練的基學習器,將其帶入前面給出的目標函式,得到:
    \[Obj^{(t)} = \sum_{i=1}^n l(\hat y_i^{t-1} + f_t(x_i),y_i) + \sum_{i=1}^t \Omega(f_i) \]
    • 已知泰勒二階展開式:
    \[f(x+\bigtriangleup x) \approx f(x) + f'(x) \bigtriangleup x + \frac{1}{2}f''(x)\bigtriangleup x^2 \]
    • \(\hat y_i^t = \hat y_i^{t-1} + f_t(x_i)\) 中的第一個加項視為x,第二個加項視為delta x,對目標函式中的預測誤差懲罰項做二階泰勒展開,得到:
    \[Obj^{(t)} \approx \sum_{i=1}^n \left [ l(\hat y_i^{t-1},y_i) + g_i f_t(x_i) + \frac{1}{2}h_if_t^2(x_i) \right ] + \sum_{i=1}^t \Omega(f_i) \]
    • 上式中g_i是損失函式loss()的一階導數,h_i是損失函式的二階導數
    • 由於前置基學習器的預測結果已知,因此 \(l(\hat y_i^{t-1},y_i)\) 在式中是一個常數,其值不影響優化結果,固可從目標式中移除:
    \[Obj^{(t)} \approx \sum_{i=1}^n \left [ g_i f_t(x_i) + \frac{1}{2}h_if_t^2(x_i) \right ] + \sum_{i=1}^t \Omega(f_i) \]
    • 同樣,由於前置學習器的y hat已知,因此在損失函式確定後(比如指定SELoss),g_i和h_i的值也可以通過計算得出,在式中為常數。至此,目標函式中的未知量就只剩當前學習器的輸出值f了。考慮到XGBoost使用的基學習器是決策樹,因此遍歷所有樣本後對各樣本的損失求和,就等同於決策樹接收所有訓練樣本後,對各葉子節點給出的預測值計算損失並求和,即:
    \[\sum_{i=1}^n \left [ g_i f_t(x_i) + \frac{1}{2}h_if_t^2(x_i) \right ] = \sum_{j=1}^T \left [ \left ( \sum_{i \in I_j} g_i \right ) \omega_j + \frac{1}{2}\left ( \sum_{i \in I_j} h_i \right ) \omega_j^2 \right ] \]這裡T代表葉子節點總數,j代表葉子節點序號,I_j代表該葉子節點中的訓練樣本集,omega_j 代表該葉子節點給出的預測值
    • 將上式代入目標函式式中,並將複雜度懲罰項Omega()展開,得到:
    \[\begin{aligned} Obj^{(t)} &\approx \sum_{j=1}^T \left [ \left ( \sum_{i \in I_j} g_i \right ) \omega_j + \frac{1}{2}\left ( \sum_{i \in I_j} h_i \right ) \omega_j^2 \right ] + \gamma T + \frac{1}{2}\lambda \sum_{j=1}^T \omega _j^2 \\ &= \sum_{j=1}^T \left [ \left ( \sum_{i \in I_j} g_i \right ) \omega_j + \frac{1}{2}\left ( \sum_{i \in I_j} h_i + \lambda \right ) \omega_j^2 \right ] + \gamma T\\ \end{aligned} \]
    • 進一步,記\(\begin{matrix} G_j = \sum_{i \in I_j} g_i & , & H_j = \sum_{i \in I_j} h_i \end{matrix}\),則上述目標函式可表示為:
    \[Obj^{(t)} = \sum_{j=1}^T \left [ G_j \omega_j + \frac{1}{2}\left ( H_j + \lambda \right ) \omega_j^2 \right ] + \gamma T \]
    • 我們可以在上式中對omega_j求一階導,並令其等於0:
    \[\frac{\partial Obj^{(t)}}{\partial\omega_j} = G_j + (H_j + \lambda)\omega_j = 0 \]
    • 進而將omega_j用其他已知項表達出來:
    \[\omega_j^* = -\frac{G_j}{H_J + \lambda} \]
    • 將上式代入目標函式式,進一步化簡得到:
    \[obj = -\frac{1}{2}\sum^T_{j=1}\frac{G_j^2}{H_j+\lambda} + \gamma T \]該式就是我們最終使用的目標函式的形式了,上式中的G和H需要我們指定損失函式,然後分別求一階和二階導得到。通過該目標函式,我們即可在決策樹中對特徵進行選擇分裂(窮舉得到使目標函式下降最多的分割方案,當然,其中依然有工程上的優化tricks)。由於XGBoost的目標函式中本身有對模型複雜度的懲罰項,因此我們不需要再做額外的剪枝工作。同時,由於G和H對各訓練樣本間相互沒有依賴,因此各樣本的損失可以平行計算,從而加快了模型的訓練速度。

【參考】

  1. 分解機(Factorization Machines)推薦演算法原理
  2. 【白話機器學習】演算法理論+實戰之Xgboost演算法
  3. 一步一步理解GB、GBDT、xgboost
  4. 《深度學習推薦演算法》王喆