集成算法终极模型之《神器LightGBM》—最后的高山
關注+星標,聽說他有點東西
全文共?6481?字,閱讀全文需?16?分鐘
寫在前面的話
大家好,我是小一
2021 年第一篇文章,還是決定用 6000 多字的技術文來開篇。
今天的文章是機器學習算法里面比較重要的一篇,也是目前常規比賽較為流行的一種建模方式。
還是那句話,建議先收藏,一遍看不懂就看三遍,集成學習最后的高山,就在眼前了!
ok,直接開始 LightGBM 算法
LightGBM 是對 XgBoost 算法的強化,并且對 XgBoost 算法中的問題進行了相應的改進和優化。
回顧一下 xgb 算法:
xgb 算法是屬于 boosting 算法中的一種,是 GBDT 算法的一個工程實現。xgb 在訓練的時候關注的是殘差,通過在目標函數中使用二階泰勒展開和加入正則化的方式提高了模型的精度的同時降低模型的過擬合。
xgb 在決策樹的生成過程中采用精確貪心的思路,尋找最佳分裂點的時候使用預排序算法,對所有特征按照特征的數值進行預排序,然后遍歷每個特征上的所有分裂點,計算該分裂點分裂后的全部樣本的目標函數增益,找到最大增益對應的特征和候選分裂點位,從而進行分裂,一層一層的完成建樹過程。
xgb 訓練的時候,是通過加法的方式進行訓練,每一次通過減少殘差訓練一棵樹,最后的預測結果是所有樹的加和表示。
對應的,xgb 因為每次分裂之前先根據特征對樣本進行預排序,之后會計算所有特征對應的所有分裂點的目標函數增益,所以導致不但需要額外空間存儲預排序的結果,還會造成時間上很大的開銷,每遍歷一個分割點都需要計算分裂增益,并且在選擇最大增益的時候需要對比所有樣本的增益情況。
因此,基于 xgb 尋找最優分裂點的復雜度,可以總結如下:
復雜度 = 特征數量 * 分裂點數量 * 樣本數量
具體 xgb 的推導可以參考上篇文章:集成算法終極模型之《手撕 xgboost》—附詳細手推公式
說完了 xgb 再來看 lgb, 既然 lgb 是對 xgb 的優化,那應該也是從上面三個維度進行優化。例如:減少特診數量、優化分裂點的個數、減少樣本數量等。
Lightgbm 算法確實是這樣做的,首先 lgb 通過直方圖算法進一步減少分裂點的數量【相比 xgb 的近似算法,直方圖算法更優】,通過單邊梯度抽樣算法減少樣本數量,通過互斥特征捆綁算法減少特征的數量。
下面詳細看看這三個算法的細節優化
直方圖算法
直方圖算法是把連續的浮點特征離散化為 k 個整數,也是采用了分箱的思想,不同的是直方圖算法根據特征所在的 bin 對其進行梯度累加和個數統計。
在遍歷數據的時候,根據離散化的后的值作為索引在直方圖中累積統計量,當遍歷一次數據后,直方圖累積了需要的統計量,然后根據直方圖的離散值,遍歷尋找最優的分裂點。
具體可以參考下圖:
預排序算法中,根據特征的不同取值進行分割,在直方圖算法不考慮特征的取值,直接根據樣本的在每個 bin 中的數量,并且在新的 bin 中存儲的是特征取值的個數。
這樣在遍歷該特征的時候,只需要根據直方圖的離散值,遍歷尋找最優的分割點即可。并且由于 bins 的數量是遠遠小于特征不同取值的數量,所有分桶之后要遍歷的分裂點個數會少很多,進一步減少計算量。
另外,xgb 在進行預排序的時候只考慮非零值進行加速【稀疏感知】,lgb 也采用非零特征去構建直方圖。
由于 xgb 需要用 32 位的浮點數去存儲特征值,并且用32位的整型去存儲預排序的索引,而在 lgb 中只需要保存特征離散化的值,這個值一般用 8 位的整型存儲即可,在內存消耗上也降為原來的 1/8
直方圖做差加速
在直方圖算法中一個技巧是直方圖做差加速。當節點分裂成兩個時,右子節點直方圖等于父節點的直方圖減去左子節點的直方圖。
畫圖描述一下是這樣的:
利用這個方法,Lightgbm 可以在構造一個葉子(含有較少數據)的直方圖后,可以用非常微小的代價得到它兄弟葉子(含有較多數據)的直方圖。
注意:原來在做每個子節點的直方圖需要將該節點上的樣本都計算一遍,現在只需要計算較少子節點的直方圖,然后用父節點-子節點=另一個子節點
通過直方圖算法找到的分割點并不算是最優的分割點,畢竟相比 xgb 算法來說通過 bins 分箱之后分裂點少了很多。但是正因為這個導致加上了一個正則化的效果,使得生成的弱分類器的有效的防止過擬合。
直方圖算法可以起到的作用就是減少分割點的數量,加快計算。
xgb 中的近似算法其實也類似 lgb 的直方圖算法,為什么速度比 lgb 慢很多?
從原理上來說,xgb 的近似算法是根據對 loss 的影響權值劃分,用每個樣本的 hi 進行分裂點劃分。在分裂之前會先根據當前特征對整體的樣本都進行預排序,也就是說針對不同的特征預排序結果不一樣,這也將會導致二階導的分布發生變化。
因此,xgb 的直方圖算法并不是針對某個特征的 feature,所以在每一層都需要動態的構建直方圖。而 lgb 針對每個特征都有一個直方圖,構建一次就可以,并且在分裂的時候還可以通過直方圖進行做差加速。
所以,xgb 的近似算法是不如 lgb 的直方圖算法快的
單邊梯度抽樣算法 GOSS
單邊梯度算法:Gradient-based One-Side Sampling,簡稱 GOSS
GOSS 是從減少樣本的角度出發,排除大部分權重小的樣本,僅用剩下的樣本計算信息增益。
稍微解釋一下上一句話:我們知道 GBDT 算法關注的是殘差,并且算法的梯度大小可以反映樣本的權重,這就說明梯度越小模型擬合的越好,而殘差正是樣本梯度的一個相反數。
可參考:xgb 中對于一階梯度的推導:集成算法終極模型之《手撕 xgboost》—附詳細手推公式
總結一下:如果要想模型降低殘差的效果好,那么樣本的梯度就應該越大越好,反之梯度小的樣本對于降低殘差的效果不大。
那,直接篩選所有梯度大的樣本豈不是效果會很好?
道理沒錯,但是,如果直接去掉梯度小的數據,會改變數據的分布,所以 lgb 提出了單邊梯度抽樣算法,根據樣本的權重信息進行抽樣,減少了大量梯度小的樣本,但是還不會過多的改變數據集的分布。
主要是因為 GOSS 算法保留了梯度大的樣本,并對梯度小的樣本進行隨機抽取,在計算增益的時候為梯度小的樣本引入了一個常數進行平衡。
首先將要進行分裂的特征的所有取值按照絕對值大小降序排序,然后取前面 a% 的梯度大的樣本和剩下樣本的 b%,在計算增益的時候,后面的 b% 乘以 ?來放大梯度小的樣本的權重。
這樣做的好處是將更多的在注意力放在訓練不足的樣本上,也可以通過權重來防止采樣對原始數據分布造成太大的影響
看個例子
假設目前有 8 個訓練樣本,a=b=25%,樣本分為 3 個 bins,對應的一階導和二階導如下:
首先根據樣本的一階導數【gi】對樣本進行排序,結果如下:
利用 GOSS 算法進行采樣,選出 8*a=2 個梯度大的樣本,選出 8 *b=2 個梯度小的樣本。
選中 2 個梯度大的樣本為 6號 和 7號,從剩下的里面隨機選中兩個梯度小的樣本 2號 和 4號
梯度小的樣本需要乘以權重:,也就是隨機選出的 2號 和 4號。根據 GOSS 算法采樣后的樣本重新構建直方圖如下:
黑色的是梯度大的樣本,不需要乘以權重,紅色的是梯度小的樣本,需要乘以 ?(1-a)/b
梯度小的樣本乘以相應的權重以后,可以發現最終的樣本總個數依然是 8個,lgb 正是通過 GOSS 采樣的方式,在不降低太多精度的同時,減少了樣本數量,使得訓練速度加快。
互斥特征捆綁算法 EFB
互斥特征捆綁算法:Exclusive Feature Bundling,EFB
前面說過 EFB 算法是通過減少特征數量使用 lgb 算法更快,它指出如果將一些特征進行融合捆綁,則可以降低特征數量。
類似于 one-hot 獨熱編碼的原理,對于高維度的稀疏數據,可以通過捆綁的方式減少特征的維度。通常被捆綁的特征之間是互斥的【特征不會同時為非零值】,這樣才不會丟失信息。但是當特征之間并不是互斥的時候,就需要用一個指標對特征不互斥程度進行衡量【稱之為沖突比率】,當沖突比率比較小的時候可以把兩個不完全互斥的特征進行捆綁,從而不影響最后的精度
極端情況下,x1、x2、x3、x4之間完全互斥,則可以進行如下捆綁:
如何判定哪些特征可以進行捆綁?
Greedy bundle 算法利用特征和特征間的關系構造一個加權無向圖,并將其轉換為圖著色問題,通過貪心策略得到近似解,以此來生成 bundle。
圖著色問題:給定無向連通圖 G 和 m 種不同的顏色。用這些顏色為圖 G 的各頂點著色,每個頂點著一種顏色。是否有一種著色法使 G 中每條邊的 2 個頂點著不同顏色?
看一個圖著色的例子:
Greedy bundle 算法在處理的時候的具體步驟如下:
構造一個加權無向圖,頂點是特征,邊的權重是兩個特征的總沖突值【即兩個特征上同時不為0的樣本個數】
根據節點的度進行降序排序,度越大,表示與其他特征的沖突越大
對于每一個特征,通過遍歷已有的特征簇【沒有則新建一個】,如果該特征加入到特征簇中的沖突值不超過某個閾值,則將該特征加入到該簇中。如果該特征不能加入任何一個已有的特征簇,則新建一個簇,并加入該特征。
EFB 算法允許特征并不完全互斥來增加特征捆綁的數量,在具體計算的時候需要設置一個最大互斥率指標,一般情況下這個指標設置會相對較小,此時算法的精度和效率之間會有一個最優值
像上面極端情況下,特征之間都是相互獨立的點,度都為0,所以排序之后發現與其他特征的沖突為0,直接放到一個簇里面并不影響。
但是大多數的特征之間并不是相互獨立的,比如說下圖中的特征:
針對上圖的訓練集,EFB 算法在處理的時候:① 首先會先建圖,計算每個頂點的總沖突值,② 其次根據節點的度進行排序,③ 最后針對每個特征進行遍歷,根據特征的沖突值對其進行簇的劃分
具體的操作流程是這樣的:
最后,可以發現是將特征 x1、x4 進行了特征捆綁,最后的捆綁之后特征如下:
上面的過程存在一個缺點:在特征數量特征多的時候,第一步建立加權無向圖會影響效率,此時可以直接統計特征之間非零樣本的個數,并將其進行排序。
這樣做的原因是因為更多的非零值的特征會導致更多的沖突,同樣可以達到特征加權的目的
Greedy bundle 【貪婪捆綁】算法的偽代碼如下:
特征如何捆綁?捆綁之后的特征值如何計算?
Merge Exclusive Features 算法將 bundle 中的特征合并為新的特征,合并的關鍵是原有的不同特征值在構建后的 bundle 中仍能夠識別。
由于基于直方圖的方法存儲的是離散的 bin 而不是連續的數值,因此可以通過添加偏移的方法將不同的 bin 值設定為不同的區間。
舉個例子:特征 A 和特征 B 可以實現特征捆綁,A 特征的原始取值區間是[0,10) ,B 特征的原始取值是[0,20)。如果直接進行特征值的相加,那么 5 這個值我們不能分清它是出自特征 A 還是特征 B。此時可以給特征 B 加一個偏移量 10 將取值區間轉換成 [10,30),這時進行特征捆綁就可以分清來源。
MEF 特征合并算法的偽代碼如下:
通過 EFB 算法,許多排他的特征會被捆綁成更少的密集特征,大大減少了特征的數量,對訓練速度帶來很大的提升。
對于類別型特征,如果在特征處理的時候有進行過 onehot 編碼,那么 EFB 算法會再次將這些特征進行捆綁,畢竟這些特征屬于互斥特征,符合特征捆綁的要求。
所以,對于類別型的特征,lgb 可以直接將每個特征取值和一個 bin 關聯,從而自動的進行處理,而不需要在特征工程中進行 onehot 編碼。
LightGBM 的生長策略 Leaf-wise
稍微總結一下,目前我們已經知道 lgb 在分裂點數量、特征數量和樣本數量上進行優化,其中直方圖算法減少了分裂點的數量、GOSS 算法減少了樣本的數量,EFB 算法減少了特征的數量。
其中在創建樹的過程中, lgb 除了在尋找最優分裂點的過程中進行了優化,在樹的生成過程中也進行了優化,它拋棄了 xgb 中的按層生成【Level-wise】,而使用了帶有深度限制的按葉子生長【Leaf-wise】。
xgb 在樹的生成過程中采用了 level-wise 的增長策略,該策略遍歷一次數據可以同時分裂同一層的所有葉子,容易進行多線程的優化,并且不會因為某個分支過深造成過擬合現象。
Level-wise 算法不加區分的對待同一層的葉子,實際上部分葉子的分裂增益較低,沒必要進行后續的分裂操作,因為帶來了很多沒有必要的計算開銷。
Leaf-wise 算法則是從當前所有葉子中,找到分裂增益最大的一個葉子,然后分裂,一直到達到要求為止。所以在分裂次數相同的情況下,Leaf-wise 生成的樹可能會較深,所以相比而言它可以降低更多的誤差,得到更好的精度。
同時因為 Leaf-wise 生成的樹比較深,容易產生過擬合現象,所以 lgb 在 Leaf-wise 之上增加了一個最大深度的限制,在保證高效率的同時防止過擬合。
總的來說,Level-wise 會產生一些低信息增益的節點,浪費運算資源的同時防止過擬合;Leaf-wise 會尋找更多高信息增益的節點,追求精度降低誤差的同時會帶來過擬合的問題。
但是過擬合問題可以通過設置 max_depth 來控制樹的深度,并且 lgb 在直方圖、GOSS 算法上都有正則化的體現,所以綜合考慮 Leaf-wise 是一種更優的選擇。
類別特征最優分割
lgb 的這個特點前面也有說到,在處理類別特征的時候,不需要通過 one-hot 編碼將類別特征轉換成多維的0/1特征,并且在決策樹模型中也并不推薦使用 one-hot 編碼,會存在以下問題:
會產生樣本切分不平衡問題,導致切分增益非常小
使用 one-hot 編碼意味著在每一個決策節點上只能使用 one vs rest 的決策方式【即 1 vs n-1】。
當對某一特征進行切分后,這一特征上只有少量樣本為 1,大量樣本為 0 【或者相反】,這時因為較小的切分樣本集占總樣本的比例太小,所以無論它的增益多大,乘以該比例后幾乎可以忽略;同樣的較大的拆分樣本集,因為幾乎是原始的樣本集,所以增益幾乎為 0。
直觀上的理解就是不平衡的切分相當于沒有切分。
會影響決策樹的學習
決策樹依賴的是數據的統計信息,而獨熱編碼會把數據切分到零散的小空間上。零散的小空間上的統計信息是不準確的,學習效果會變差。如下圖左
相反,在下圖右的切分方法,數據會被切分到兩個比較大的空間,統計信息會更準確,下一步的學習也會更好些。
下圖右葉子節點的含義是 x=A 或者 X=C 時放在左孩子,其余放到右孩子。
基于上面問題—解決 one-hot 編碼處理類別特征的不足,lgb 優化了對類別特征的支持,可以直接輸入類別特征,而不需要額外的 0/1 展開。
lgb 采用 many-vs-many 的切分方式將類別特征分為兩個子集,實現了類別特征的最優切分【即 m vs n】。
工程上的優化
和 xgb 一樣,lgb 不但有算法上的優化,還存在工程上的優化。工程優化主要涉及到兩點:
高效并行
特征并行
思想:不同機器在不同的特征集合上分別尋找最優的分割點,然后在機器間同步最優的分割點。
注意 lgb 是在每臺機器上保存全部訓練數據,在得到最佳劃分方案后可在本地執行劃分而減少了不惜要的通信。
數據并行
lgb 通過分散規約把直方圖合并的任務分攤到不同的機器,降低通信和計算,并利用直方圖做差進一步減少了一半的通信量。
投票并行
找出本地 Top K 的特征,并基于投票篩選出可能是最優分割點的特征,在合并時只合并每個機器篩選出來的特征。
可以參考隨機森林算法中的投票策略。
Cache 命中率優化
lgb 所使用的直方圖算法對 Cache 天生友好,首先是所有的特征都采用相同的方式計算梯度(區別于 xgb 不同的特征通過不同的索引獲得梯度),只需要對梯度進行排序即可實現連續訪問,大大提高了緩存的命中率。
其次,在內存上不需要存儲葉子索引的數組,所以也就不存在 Cache Miss 的問題。
總結
lgb 針對 xgb 做了很多的優化,從而導致它的速度更快,效率更優。基于 xgb 的優化策略,lgb 主要從減少分裂點數量、減少樣本數量、減少特征數量上進行優化。
在尋找最優分裂點上,我們說了直方圖算法算法原理,這個可以降低分裂點的數量,然后又通過 GOSS 技術通過單邊梯度抽樣降低了樣本的數量,最后通過 EFB 算法從貪心捆綁和特征整合上減少了特征的數量。
除此之外,lgb 在樹的生長策略上進行了優化,不再使用 xgb 的Level-wise 的生長策略,而使用基于葉子節點的 Leaf-wise 的生長策略,從而提高了模型的精度。
最后是在類別特征上,lgb 支持類別特征,并且采用 many-vs-many 的切分方式將類別特征分為兩個子集,實現類別特診的最優切分。
另外,lgb 還進行了工程上的優化,通過特征并行、數據并行和投票并行的方式實現高效并行,通過直方圖算法對 ?Cache 的命中率進行優化。
以上就是 lgb 的技術總結,lgb 正是通過上述的方式提高了訓練速度,所以相比于 xgb 會更快
lgb 相比 xgb 的優點
lgb 相比 xgb 有內存和速度上的優化,這些優點一般會在面試的時候被提到,總結如下:
速度更快
lgb 采用直方圖算法將遍歷樣本轉變為遍歷直方圖,極大的降低了時間復雜度;
lgb 在訓練過程中采用 GOSS 單邊梯度抽樣算法過濾掉梯度小的樣本,減少了大量的計算;
lgb 采用 Leaf-wise 算法的策略構建樹,減少了葉子節點的分裂,提高了模型的精度;
lgb 采用優化后的特征并行、數據并行方法加速計算,在數據量非常大的時候還可以采用投票并行策略加速計算;
lgb 對緩存進行優化,增加了緩存命中率。
內存更小
xgb 使用預排序后需要記錄特征值及其對應樣本的統計值的索引,而 lgb 使用了直方圖算法不需要記錄特征到樣本的索引,極大的減少了內存消耗;
lgb 采用了直方圖算法將存儲特征值轉變成存儲 bin 值,降低了內存消耗;
lgb 在訓練過程中采用互斥特征捆綁算法減少了特征數量,降低了內存消耗。
參考文獻
【1】LightGBM: A Highly Efficient Gradient Boosting Decision Tree
【2】LightGBM 文檔,文檔地址:https://lightgbm.readthedocs.io/en/latest/index.html
【3】終于有人把XGBoost 和 LightGBM 講明白了,項目中最主流的集成算法!地址:https://mp.weixin.qq.com/s/q4R-TAG4PZAdWLb41oov8g
【4】Lightgbm源論文解析:LightGBM: A Highly Efficient Gradient Boosting Decision Tree,地址:https://blog.csdn.net/anshuai_aw1/article/details/83048709
【5】白話機器學習算法理論+實戰番外篇之LightGBM,地址:https://blog.csdn.net/wuzhongqiang/article/details/105350579
我是小一,堅持向暮光所走的人,終將成為耀眼的存在!
期待你的?三連!我們下節見
總結
以上是生活随笔為你收集整理的集成算法终极模型之《神器LightGBM》—最后的高山的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 百度虚拟服务器上传,百度云虚拟主机好用吗
- 下一篇: 深信服---之上网行为管理