無須推導的LightGBM|機器學習

LightGBM

上文中我們瞭解了一下XGBoost的原理,本文再來了解一下GBDT的另一個進化算法LightGBM,從原理上來說它和GBDT及XGBoost類似,都採用損失函數的負梯度作爲當前決策樹的殘差近似值,去擬合新的決策樹。

不瞭解LightGBM的人可能會有疑問,XGBoost已經在各大場景有很好的表現了,爲什麼還要用LightGBM呢?我們先來看一下LightGBM相對於XGBoost的優點,再來決定要不要了解一下這個算法。

LightGBM相對於XGBoost的優點:

  • 更快的訓練效率
  • 低內存使用
  • 更高的準確率
  • 支持並行化學習
  • 可以處理大規模數據
  • 可以直接使用類別特徵

WTF?這不就是傳說中的更高、更快、更強嗎,下面就讓我們來看一下LightGBM究竟是怎麼做的。

LightGBM的特點

  • 基於Histogram的決策樹算法
  • 帶深度限制的Leaf-wise的葉子生長策略
  • 直方圖做差加速
  • 直接使用類別特徵
  • Cache命中率優化
  • 基於直方圖的稀疏特徵優化
  • 多線程優化

決策樹算法

爲了展示出LightGBM相對於XGBoost的優點,我們先給出XGBoost所使用的預排序算法,再和LightGBM所使用的算法來進行對比。

XGBoost

  1. 對所有的特徵按照數值進行預排序;
  2. 找到最優的分割點,進行樣本分割(假設數據量爲n,則此過程消耗時間爲O(n));
  3. 找到分割點,根據分割特徵將數據分爲左右兩個子結點。

這個尋找特徵的方式看上去沒有什麼問題,但是我們再深入去思考的話就會發現,當我們對所有的特徵進行排序的時候,爲了後續快速的計算分類點,我們不僅要保留特徵還需要保留排序後的索引值,這也就意味着我們需要使用雙倍的內存開銷來保存這些東。同樣在我們計算最優分割點的時候,需要從頭遍歷到尾,每一次都要進行增益的計算,時間和計算的開銷也是巨大的。

由於XGBoost存在的這些不足,LightGBM考慮新的方法來進行最優分割點的尋找,讓我們來了解一下。

LightGBM

LightGBM中使用的是直方圖算法(histogram algorithm),該算法所佔用的內存更小,尋找分割點的複雜度也更低。其思想是將連續的浮點特徵離散成k個離散值,並構造出一個寬度爲k的直方圖,然後遍歷訓練數據,統計每個離散值在直方圖中的累計統計量。在進行特徵選擇時,只需要根據直方圖的離散值,遍歷尋找最優的分割點。

這麼敘述起來顯得比較抽象,也不利於理解,我們從下面的圖出發,細緻的來說明一下這個問題:

在這裏插入圖片描述

直方圖算法的原理很簡單,首先要做的就是把浮點型數據轉化爲bin數據(圖中灰色到紅色的過程),我們首先要確定對於每一個特徵需要多少個桶(分割爲多少個數據範圍),然後均分,將屬於該桶的樣本數據更新爲bin的值,最後用直方圖來表示數據。這裏所表達的意思就類似於上圖中的Eg,如果數據屬於[0,0.1)這個桶,就把數據的值更新爲0。

直方圖算法有幾個我們需要注意的點:

  1. 使用bin替代原始數據相當於增加了正則化;
  2. 使用bin意味着很多數據的細節特徵被放棄了,相似的數據可能被分到相同的桶中,這樣數據之間的差異也就隨之消失了;
  3. bin數量選擇決定了正則化的程度,bin越少懲罰越嚴重,欠擬合的風險也就越高;
  4. 構建直方圖的時候不需要對數據進行排序(比XGB的時間消耗少);
  5. 直方圖除了保存劃分閾值和當前bin內樣本數以外,還保存了當前bin內所有樣本的一階梯度和(一階梯度和的平方的均值等價於均方損失);
  6. 閾值的選取是按照直方圖從小到大遍歷,使用了上面的一階梯度和,目的是得到劃分之後△loss最大的特徵及閾值。

Histogram 算法的優缺點:

  1. 由於特徵被離散化後,找到的並不是很精確的分割點,所以會對結果產生影響。但在實際的數據集上表明,離散化的分裂點對最終的精度影響並不大,甚至會好一些。原因在於decision tree本身就是一個弱學習器,採用Histogram算法會起到正則化的效果,有效地防止模型的過擬合。
  2. 時間上的開銷由原來的O(datafeatures)O(data * features)降到O(kfeatures)O(k * features)。由於離散化,k遠小於data,因此時間上有很大的提升。

Histogram加速:

一個葉子節點的Histogram可以直接由父節點的Histogram和兄弟節點的Histogram做差得到。一般情況下,構造Histogram需要遍歷該葉子上的所有數據,通過該方法,只需要遍歷Histogram的k個捅。速度提升了一倍。

在這裏插入圖片描述

決策樹的生長策略

XGBoost採用的是按層生長level(depth)-wise生長策略,能夠同時分裂同一層的葉子,從而進行多線程優化,不容易過擬合;但不加區分的對待同一層的葉子,帶來了很多沒必要的開銷。因爲實際上很多葉子的分裂增益較低,沒必要進行搜索和分裂。

LightGBM採用leaf-wise生長策略,每次從當前所有葉子中找到分裂增益最大(一般也是數據量最大)的一個葉子,然後分裂,如此循環。因此同Level-wise相比,在分裂次數相同的情況下,Leaf-wise可以降低更多的誤差,得到更好的精度。Leaf-wise的缺點是可能會長出比較深的決策樹,產生過擬合。因此LightGBM在Leaf-wise之上增加了一個最大深度的限制,在保證高效率的同時防止過擬合。

在這裏插入圖片描述

LightGBM原理

明白了LightGBM中樹的生成,再讓我們來了解一下LightGBM的原理,LightGBM主要包含GOSS和EFB算法,讓我們來了解一下:

單邊梯度採樣(GOSS)

主要思想

GOSS算法的主要思想就在於梯度的大小對於信息增益的貢獻上的差別,梯度大的樣本點在信息增益的計算上扮演主要的作用,也就是說梯度大的樣本點會貢獻更多的信息增益,爲了保持信息增益評估的精度,當我們對樣本進行下采樣的時候保留這些梯度大的樣本點,而對於梯度小的樣本點按比例進行隨機採樣即可。我們證明此措施在相同的採樣率下比隨機採樣獲得更準確的結果,尤其是在信息增益範圍較大時。

算法描述

在AdaBoost算法中,我們在每次迭代時更加註重上一次錯分的樣本點,也就是上一次錯分的樣本點的權重增大,而在GBDT中並沒有本地的權重來實現這樣的過程,所以在AdaBoost中提出的採樣模型不能應用在GBDT中。但是,每個樣本的梯度對採樣提供了非常有用的信息。也就是說,如果一個樣本點的梯度小,那麼該樣本點的訓練誤差就小並且已經經過了很好的訓練。一個直接的辦法就是直接拋棄梯度小的樣本點,但是這樣做的話會改變數據的分佈和損失學習的模型精度。GOSS的提出就是爲了避免這兩個問題的發生。我們來看一下對於GOSS的算法描述:

輸入:訓練數據,迭代步數d,大梯度數據的採樣率a,小梯度數據的採樣率b,損失函數和弱學習器的類型(一般爲決策樹);

輸出:訓練好的強學習器;

  1. 根據樣本點的梯度的絕對值對它們進行降序排序;

  2. 對排序後的結果選取前a*100%的樣本生成一個大梯度樣本點的子集;

  3. 對剩下的樣本集合(1a)100(1-a)*100%的樣本,隨機的選取b(1a)100b*(1-a)*100%個樣本點,生成一個小梯度樣本點的集合;

  4. 將大梯度樣本和採樣的小梯度樣本合併;

  5. 將小梯度樣本乘上一個權重係數;

  6. 使用上述的採樣的樣本,學習一個新的弱學習器;

  7. 不斷地重複(1)~(6)步驟直到達到規定的迭代次數或者收斂爲止。

通過上面的算法可以在不改變數據分佈的前提下不損失學習器精度的同時大大的減少模型學習的速率。

從上面的描述可知,當a=0時,GOSS算法退化爲隨機採樣算法;當a=1時,GOSS算法變爲採取整個樣本的算法。在許多情況下,GOSS算法訓練出的模型精確度要高於隨機採樣算法。另一方面,採樣也將會增加弱學習器的多樣性,從而潛在的提升了訓練出的模型泛化能力。

GOSS算法的僞代碼

在這裏插入圖片描述

互斥特徵綁定(EFB)

主要思想

一個有高維特徵空間的數據往往是稀疏的,而稀疏的特徵空間中,許多特徵是互斥的。所謂互斥就是他們從來不會同時具有非0值(一個典型的例子是進行One-hot編碼後的類別特徵)。

LightGBM利用這一點提出Exclusive Feature Bundling(EFB)算法來進行互斥特徵的合併,從而減少特徵的數目。做法是先確定哪些互斥的特徵可以合併(可以合併的特徵放在一起,稱爲bundle),然後將各個bundle合併爲一個特徵。(記住這裏的bundle是什麼)

這樣建立直方圖的時間將從O(featuredata)O(feature*data)變爲O(bundledata)O(bundle*data),而bundle<<feature,這樣GBDT能在精度不損失的情況下進一步提高訓練速度。

算法描述

  1. 將特徵按照非零值的個數進行排序;
  2. 計算不同特徵之間的衝突比率;
  3. 遍歷每個特徵並嘗試合併特徵,使衝突比率最小化。

根據這種思想,隨之而來的是下面的兩個問題:

  1. 怎麼判定哪些特徵應該綁定在一起?
  2. 怎麼把特徵綁定爲一個?

哪些特徵被綁定

由於將特徵劃分爲更小的互斥綁定數量,這是一個NP-hard問題,即在多項式時間內不可能去找到準確的解決辦法。所以這裏使用的是一種近似的解決辦法,即特徵之間允許存在少數的樣本點並不是互斥的(如存在某些對應的樣本點之間不同時爲非0值),允許小部分的衝突可以得到更小的特徵綁定數量,更進一步的提高了計算的有效性。在理論上可以證明,通過允許小部分的衝突的話,使得模型的accuracy被影響O([(1γ)n]23)O([(1-\gamma)n]^{-\frac{2}{3}}),這裏的是每個綁定的最大沖突率。所以,當我們選擇很小的時,我們可以在精確度和效率上獲得很好的權衡。

注意:這裏構建圖的方法是,圖上的頂點代表特徵,若兩個特徵不互斥,則在他們之間連一條邊。

算法描述如下:

輸入:特徵F,最大沖突數K,圖G;

輸出:特徵捆綁集合bundles;

  1. 建立一個圖,每個邊有權重,其權值對應於特徵之間的總衝突。
  2. 按照降序排列圖中的度數來排序特徵。
  3. 按順序對排好序的特徵進行遍歷,對於當前特徵,查看是否能加入已有的bundle(衝突要小於k),若不行,則新建一個bundle。

建圖的過程如下:

將每個特徵視爲圖中的一個頂點。遍歷每一個樣本,如果在當前樣本中特徵i,j之間不互斥,則:

  • 如果在圖上i,j間不存在邊,則連接一條邊,權重爲1;
  • 如果存在邊,權重加1。

算法的僞代碼如下:

在這裏插入圖片描述

該算法的時間複雜度是O(feature2)O(feature^2),訓練之前只處理一次,其時間複雜度在特徵不是特別多的情況下是可以接受的,但難以應對百萬維的特徵。爲了繼續提高效率,我們提出了一個更加高效的無圖的排序策略:將特徵按照非零值個數排序,這和使用圖節點的度排序相似,因爲更多的非零值通常會導致衝突,新算法在該算法基礎上改變了排序策略,我們再來看一下對該算法的優化。

合併互斥特徵

Lightgbm關於互斥特徵的合併用到了直方圖(Histogram)算法。直方圖算法的基本思想是先把連續的特徵值離散化成k個整數,同時構造一個寬度爲k的直方圖。在遍歷數據的時候,根據離散化後的值作爲索引在直方圖中累積統計量,當遍歷一次數據後,直方圖累積了需要的統計量,然後根據直方圖的離散值,遍歷尋找最優的分割點。

由於基於直方圖的算法存儲的是離散的bins而不是連續的特徵值,我們可以通過讓互斥特徵駐留在不同的bins中來構造feature bundle。這可以通過增加特徵原始值的偏移量來實現。比如,假設我們有兩個特徵,特徵A的取值範圍是[0,10),而特徵B的取值範圍是[0,20),我們可以給特徵B增加偏移量10,使得特徵B的取值範圍爲[10, 30),最後合併特徵A和B,形成新的特徵,取值範圍爲[0,30)來取代特徵A和特徵B。
當然,Histogram算法並不是完美的。由於特徵被離散化後,找到的並不是很精確的分割點,所以會對結果產生影響。但在不同的數據集上的結果表明,離散化的分割點對最終的精度影響並不是很大,甚至有時候會更好一點。原因是決策樹本來就是弱模型,分割點是不是精確並不是太重要;差一點的切分點也有正則化的效果,可以有效地防止過擬合;即使單棵樹的訓練誤差比精確分割的算法稍大,但在Gradient Boosting的框架下沒有太大的影響。

最終我們稱使用GOSS算法和EFB算法的梯度提升樹(GBDT)稱之爲LightGBM。

在這裏插入圖片描述

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