xgb gbdt lgb 算法的比較

本文主要簡要的比較了常用的boosting算法的一些區別,從AdaBoost到LightGBM,包括AdaBoost,GBDT,XGBoost,LightGBM四個模型的簡單介紹,一步一步從原理到優化對比。 AdaBoost原理 原始的AdaBoost算法是在算法開始的時候,爲每一個樣本賦上一個權重值,初始的時候,大家都是一樣重要的。在每一步訓練中得到的模型,會使得數據點的估計有對有錯,我們就在每一步結束後,增加分錯的點的權重,減少分對的點的權重,這樣使得某些點如果老是被分錯,那麼就會被“重點關注”,也就被賦上一個很高的權重。然後等進行了N次迭代(由用戶指定),將會得到N個簡單的分類器(basic learner),然後我們將它們組合起來(比如說可以對它們進行加權、或者讓它們進行投票等),得到一個最終的模型。 關鍵字:樣本的權重分佈 GBDT概述 GBDT(Gradient Boosting Decison Tree)中的樹都是迴歸樹,GBDT用來做迴歸預測,調整後也可以用於分類(設定閾值,大於閾值爲正例,反之爲負例),可以發現多種有區分性的特徵以及特徵組合。GBDT是把所有樹的結論累加起來做最終結論的,GBDT的核心就在於,每一棵樹學的是之前所有樹結論和的殘差(負梯度),這個殘差就是一個加預測值後能得真實值的累加量。比如A的真實年齡是18歲,但第一棵樹的預測年齡是12歲,差了6歲,即殘差爲6歲。那麼在第二棵樹裏我們把A的年齡設爲6歲去學習,如果第二棵樹真的能把A分到6歲的葉子節點,那累加兩棵樹的結論就是A的真實年齡;如果第二棵樹的結論是5歲,則A仍然存在1歲的殘差,第三棵樹裏A的年齡就變成1歲,繼續學。 Boosting的最大好處在於,每一步的殘差計算其實變相地增大了分錯instance的權重,而已經分對的instance則都趨向於0。這樣後面的樹就能越來越專注那些前面被分錯的instance。 Gradient Boost與AdaBoost的區別 Gradient Boost每一次的計算是爲了減少上一次的殘差(residual),而爲了消除殘差,我們可以在殘差減少的梯度(Gradient)方向上建立一個新的模型。所以說,在Gradient Boost中,每個新的模型的建立是爲了使得之前模型的殘差往梯度方向減少。Shrinkage(縮減)的思想認爲,每次走一小步逐漸逼近結果的效果,要比每次邁一大步很快逼近結果的方式更容易避免過擬合。即它不完全信任每一個棵殘差樹,它認爲每棵樹只學到了真理的一小部分,累加的時候只累加一小部分,通過多學幾棵樹彌補不足。本質上,Shrinkage爲每棵樹設置了一個weight,累加時要乘以這個weight,但和Gradient並沒有關係。 Adaboost是另一種boost方法,它按分類對錯,分配不同的weight,計算cost function時使用這些weight,從而讓“錯分的樣本權重越來越大,使它們更被重視” Gradient Boost優缺點 優點: 它的非線性變換比較多,表達能力強,而且不需要做複雜的特徵工程和特徵變換。 缺點:Boost是一個串行過程,不好並行化,而且計算複雜度高,同時不太適合高維稀疏特徵。 XGBoost XGBoost能自動利用cpu的多線程,而且適當改進了gradient boosting,加了剪枝,控制了模型的複雜程度 傳統GBDT以CART作爲基分類器,特指梯度提升決策樹算法,而XGBoost還支持線性分類器(gblinear),這個時候XGBoost相當於帶L1和L2正則化項的邏輯斯蒂迴歸(分類問題)或者線性迴歸(迴歸問題)。 傳統GBDT在優化時只用到一階導數信息,xgboost則對代價函數進行了二階泰勒展開,同時用到了一階和二階導數。順便提一下,xgboost工具支持自定義代價函數,只要函數可一階和二階求導。 xgboost在代價函數里加入了正則項,用於控制模型的複雜度。正則項裏包含了樹的葉子節點個數、每個葉子節點上輸出的score的L2模的平方和。從Bias-variance tradeoff角度來講,正則項降低了模型的variance,使學習出來的模型更加簡單,防止過擬合,這也是xgboost優於傳統GBDT的一個特性。 xgboost中樹節點分裂時所採用的公式: Shrinkage(縮減),相當於學習速率(xgboost中的eta)。xgboost在進行完一次迭代後,會將葉子節點的權重乘上該係數,主要是爲了削弱每棵樹的影響,讓後面有更大的學習空間。實際應用中,一般把eta設置得小一點,然後迭代次數設置得大一點。(傳統GBDT的實現也有學習速率) 列抽樣(column subsampling)。xgboost借鑑了隨機森林的做法,支持列抽樣,不僅能降低過擬合,還能減少計算,這也是xgboost異於傳統gbdt的一個特性。 對缺失值的處理。對於特徵的值有缺失的樣本,xgboost可以自動學習出它的分裂方向。 xgboost工具支持並行。注意xgboost的並行不是tree粒度的並行,xgboost也是一次迭代完才能進行下一次迭代的(第t次迭代的代價函數裏包含了前面t-1次迭代的預測值)。xgboost的並行是在特徵粒度上的。我們知道,決策樹的學習最耗時的一個步驟就是對特徵的值進行排序(因爲要確定最佳分割點),xgboost在訓練之前,預先對數據進行了排序,然後保存爲block結構,後面的迭代中重複地使用這個結構,大大減小計算量。這個block結構也使得並行成爲了可能,在進行節點的分裂時,需要計算每個特徵的增益,最終選增益最大的那個特徵去做分裂,那麼各個特徵的增益計算就可以開多線程進行。(特徵粒度上的並行,block結構,預排序) 這個公式形式上跟ID3算法、CART算法是一致的,都是用分裂後的某種值減去分裂前的某種值,從而得到增益。爲了限制樹的生長,我們可以加入閾值,當增益大於閾值時才讓節點分裂,上式中的gamma即閾值,它是正則項裏葉子節點數T的係數,所以xgboost在優化目標函數的同時相當於做了預剪枝。另外,上式中還有一個係數lambda,是正則項裏leaf score的L2模平方的係數,對leaf score做了平滑,也起到了防止過擬合的作用,這個是傳統GBDT裏不具備的特性。 XGBoost實現層面 內置交叉驗證方法 能夠輸出特徵重要性文件輔助特徵篩選 XGBoost優勢小結: a.公式推導裏用到了二階導數信息,而普通的GBDT只用到一階 b.顯式地將樹模型的複雜度作爲正則項加在優化目標,penalty function Omega主要是對樹的葉子數和葉子分數做懲罰,這點確保了樹的簡單性。 c.借鑑了Random Forest的思想,允許使用列抽樣(column(feature) sampling)來防止過擬合,sklearn裏的gbm好像也有類似實現。 d.Pre-sorted 算法,樣本數據事先排好序並以block的形式存儲,利於並行計算 e.實現了一種分裂節點尋找的近似算法,用於加速和減小內存消耗,節點分裂算法能自動利用特徵的稀疏性。 f.支持分佈式計算可以運行在MPI,YARN上,得益於底層支持容錯的分佈式通信框架rabit。 LightGBM lightGBM:基於決策樹算法的分佈式梯度提升框架。 大多數機器學習工具都無法直接支持類別特徵作爲輸入,一般需要轉換成多維0/1特徵,帶來計算和內存上的額外消耗。LightGBM增加了針對於類別特徵的決策規則,這在決策樹上也很好實現。主要的思想是,在對類別特徵計算分割增益的時候,不是按照數值特徵那樣由一個閾值進行切分,而是直接把其中一個類別當成一類,其他的類別當成另一類。這實際上與0/1展開的效果是一樣的。 GBDT 雖然是個強力的模型,但卻有着一個致命的缺陷,不能用類似 mini batch 的方式來訓練,需要對數據進行無數次的遍歷。如果想要速度,就需要把數據都預加載在內存中,但這樣數據就會受限於內存的大小;如果想要訓練更多的數據,就要使用外存版本的決策樹算法。雖然外存算法也有較多優化,SSD 也在普及,但在頻繁的 IO 下,速度還是比較慢的。 爲了能讓 GBDT 高效地用上更多的數據,我們把思路轉向了分佈式 GBDT, 然後就有了 LightGBM。 設計的思路主要是兩點,1. 單個機器在不犧牲速度的情況下,儘可能多地用上更多的數據;2.多機並行的時候,通信的代價儘可能地低,並且在計算上可以做到線性加速。 基於這兩個需求,LightGBM 選擇了基於 histogram 的決策樹算法。相比於另一個主流的算法 pre-sorted(如 xgboost 中的 exact 算法),histogram 在內存消耗和計算代價上都有不少優勢。 Pre-sorted 算法需要的內存約是訓練數據的兩倍(2 * #data * #features* 4Bytes),它需要用32位浮點來保存 feature value,並且對每一列特徵,都需要一個額外的排好序的索引,這也需要32位的存儲空間。對於 histogram 算法,則只需要(#data* #features * 1Bytes)的內存消耗,僅爲 pre-sorted算法的1/8。因爲 histogram 算法僅需要存儲 feature bin value (離散化後的數值),不需要原始的 feature value,也不用排序,而 bin value 用 uint8_t (256 bins) 的類型一般也就足夠了。 在計算上的優勢則主要體現在“數據分割”。決策樹算法有兩個主要操作組成,一個是“尋找分割點”,另一個是“數據分割”。從算法時間複雜度來看,Histogram 算法和 pre-sorted 算法在“尋找分割點”的代價是一樣的,都是O(#feature*#data)。而在“數據分割”時,pre-sorted 算法需要O(#feature*#data),而 histogram 算法是O(#data)。因爲 pre-sorted 算法的每一列特徵的順序都不一樣,分割的時候需要對每個特徵單獨進行一次分割。Histogram算法不需要排序,所有特徵共享同一個索引表,分割的時候僅需對這個索引表操作一次就可以。(更新: 這一點不完全正確,pre-sorted 與 level-wise 結合的時候,其實可以共用一個索引表(row_idx_to_tree_node_idx)。然後在尋找分割點的時候,同時操作同一層的節點,省去分割的步驟。但這樣做的問題是會有非常多隨機訪問,有很大的chche miss,速度依然很慢。)。 最後,在數據並行的時候,用 histgoram 可以大幅降低通信代價。用 pre-sorted 算法的話,通信代價是非常大的(幾乎是沒辦法用的)。所以 xgoobst 在並行的時候也使用 histogram 進行通信。 當然, histogram 算法也有缺點,它不能找到很精確的分割點,訓練誤差沒有 pre-sorted 好。但從實驗結果來看, histogram 算法在測試集的誤差和 pre-sorted 算法差異並不是很大,甚至有時候效果更好。實際上可能決策樹對於分割點的精確程度並不太敏感,而且較“粗”的分割點也自帶正則化的效果。 在 histogram 算法之上, LightGBM 進行進一步的優化。首先它拋棄了大多數 GBDT 工具使用的按層生長(level-wise) 的決策樹生長策略,而使用了帶有深度限制的按葉子生長 (leaf-wise) 算法。 level-wise 過一次數據可以同時分裂同一層的葉子,容易進行多線程優化,不容易過擬合。但實際上level-wise是一種低效的算法,因爲它不加區分的對待同一層的葉子,帶來了很多沒必要的開銷。因爲實際上很多葉子的分裂增益較低,沒必要進行搜索和分裂。leaf-wise則是一種更爲高效的策略,每次從當前所有葉子中,找到分裂增益最大(一般也是數據量最大)的一個葉子,然後分裂,如此循環。因此同 level-wise 相比,在分裂次數相同的情況下,leaf-wise 可以降低更多的誤差,得到更好的精度。leaf-wise 的缺點是可能會長出比較深的決策樹,產生過擬合。因此 LightGBM 在leaf-wise 之上增加了一個最大深度的限制,在保證高效率的同時防止過擬合。 另一個比較巧妙的優化是 histogram 做差加速。一個容易觀察到的現象:一個葉子的直方圖可以由它的父親節點的直方圖與它兄弟的直方圖做差得到。通常構造直方圖,需要遍歷該葉子上的所有數據,但直方圖做差僅需遍歷直方圖的 k 個桶。利用這個方法,LightGBM 可以在構造一個葉子的直方圖後,可以用非常微小的代價得到它兄弟葉子的直方圖,在速度上可以提升一倍。 lightGBM與XGBoost的區別: 切分算法(切分點的選取) 佔用的內存更低,只保存特徵離散化後的值,而這個值一般用8位整型存儲就足夠了,內存消耗可以降低爲原來的1/8。 降低了計算的代價:預排序算法每遍歷一個特徵值就需要計算一次分裂的增益,而直方圖算法只需要計算k次(k可以認爲是常數),時間複雜度從O(#data#feature)優化到O(k#features)。(相當於LightGBM犧牲了一部分切分的精確性來提高切分的效率,實際應用中效果還不錯)空間消耗大,需要保存數據的特徵值以及特徵排序的結果(比如排序後的索引,爲了後續快速計算分割點),需要消耗兩倍於訓練數據的內存時間上也有較大開銷,遍歷每個分割點時都需要進行分裂增益的計算,消耗代價大對cache優化不友好,在預排序後,特徵對梯度的訪問是一種隨機訪問,並且不同的特徵訪問的順序不一樣,無法對cache進行優化。同時,在每一層長樹的時候,需要隨機訪問一個行索引到葉子索引的數組,並且不同特徵訪問的順序也不一樣,也會造成較大的cache miss。 XGBoost使用的是pre-sorted算法(對所有特徵都按照特徵的數值進行預排序,基本思想是對所有特徵都按照特徵的數值進行預排序;然後在遍歷分割點的時候用O(#data)的代價找到一個特徵上的最好分割點最後,找到一個特徵的分割點後,將數據分裂成左右子節點。優點是能夠更精確的找到數據分隔點;但這種做法有以下缺點 LightGBM使用的是histogram算法,基本思想是先把連續的浮點特徵值離散化成k個整數,同時構造一個寬度爲k的直方圖。在遍歷數據的時候,根據離散化後的值作爲索引在直方圖中累積統計量,當遍歷一次數據後,直方圖累積了需要的統計量,然後根據直方圖的離散值,遍歷尋找最優的分割點; 優點在於決策樹生長策略上: XGBoost採用的是帶深度限制的level-wise生長策略,Level-wise過一次數據可以能夠同時分裂同一層的葉子,容易進行多線程優化,不容易過擬合;但不加區分的對待同一層的葉子,帶來了很多沒必要的開銷(因爲實際上很多葉子的分裂增益較低,沒必要進行搜索和分裂) LightGBM採用leaf-wise生長策略,每次從當前所有葉子中找到分裂增益最大(一般也是數據量最大)的一個葉子,然後分裂,如此循環;但會生長出比較深的決策樹,產生過擬合(因此 LightGBM 在leaf-wise之上增加了一個最大深度的限制,在保證高效率的同時防止過擬合)。 histogram 做差加速。一個容易觀察到的現象:一個葉子的直方圖可以由它的父親節點的直方圖與它兄弟的直方圖做差得到。通常構造直方圖,需要遍歷該葉子上的所有數據,但直方圖做差僅需遍歷直方圖的k個桶。利用這個方法,LightGBM可以在構造一個葉子的直方圖後,可以用非常微小的代價得到它兄弟葉子的直方圖,在速度上可以提升一倍。 直接支持類別特徵:LightGBM優化了對類別特徵的支持,可以直接輸入類別特徵,不需要額外的0/1展開。並在決策樹算法上增加了類別特徵的決策規則。 分佈式訓練方法上(並行優化) 在特徵並行算法中,通過在本地保存全部數據避免對數據切分結果的通信; 在數據並行中使用分散規約(Reduce scatter)把直方圖合併的任務分攤到不同的機器,降低通信和計算,並利用直方圖做差,進一步減少了一半的通信量。基於投票的數據並行(Parallel Voting)則進一步優化數據並行中的通信代價,使通信代價變成常數級別。 特徵並行的主要思想是在不同機器在不同的特徵集合上分別尋找最優的分割點,然後在機器間同步最優的分割點。 數據並行則是讓不同的機器先在本地構造直方圖,然後進行全局的合併,最後在合併的直方圖上面尋找最優分割點。 原始LightGBM針對這兩種並行方法都做了優化,Cache命中率優化 基於直方圖的稀疏特徵優化 DART(Dropout + GBDT) GOSS(Gradient-based One-Side Sampling):一種新的Bagging(row subsample)方法,前若干輪(1.0f / gbdtconfig->learning_rate)不Bagging;之後Bagging時, 採樣一定比例g(梯度)大的樣本 LightGBM優點小結(相較於XGBoost) 速度更快 內存消耗更低 --------------------- 本文來自 akenseren 的CSDN 博客 ,全文地址請點擊:https://blog.csdn.net/akenseren/article/details/80766112?utm_source=copy

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