LightGBM——提升機器算法(圖解+理論+安裝方法+python代碼)

轉自:https://blog.csdn.net/huacha__/article/details/81057150

前言

LightGBM是個快速的,分佈式的,高性能的基於決策樹算法的梯度提升框架。可用於排序,分類,迴歸以及很多其他的機器學習任務中。

在競賽題中,我們知道XGBoost算法非常熱門,它是一種優秀的拉動框架,但是在使用過程中,其訓練耗時很長,內存佔用比較大。在2017年年1月微軟在GitHub的上開源了一個新的升壓工具--LightGBM。在不降低準確率的前提下,速度提升了10倍左右,佔用內存下降了3倍左右。因爲他是基於決策樹算法的,它採用最優的葉明智策略分裂葉子節點,然而其它的提升算法分裂樹一般採用的是深度方向或者水平明智而不是葉,明智的。因此,在LightGBM算法中,當增長到相同的葉子節點,葉明智算法比水平-wise算法減少更多的損失。因此導致更高的精度,而其他的任何已存在的提升算法都不能夠達。與此同時,它的速度也讓人感到震驚,這就是該算法名字  燈  的原因。

    2014年3月,XGBOOST最早作爲研究項目,由陳天奇提出

     (XGBOOST的部分在我的另一篇博客裏:https://blog.csdn.net/huacha__/article/details/81029680

    2017年1月,微軟發佈首個穩定版LightGBM

在微軟亞洲研究院AI頭條分享中的「LightGBM簡介」中,機器學習組的主管研究員王太峯提到:微軟DMTK團隊在github上開源了性能超越其它推動決策樹工具LightGBM後,三天之內星了1000+次,叉了超過200次。知乎上有近千人關注“如何看待微軟開源的LightGBM?”問題,被評價爲“速度驚人”,“非常有啓發”,“支持分佈式” “代碼清晰易懂”,“佔用內存小”等。以下是微軟官方提到的LightGBM的各種優點,以及該項目的開源地址。

科普鏈接:如何玩轉LightGBM https://v.qq.com/x/page/k0362z6lqix.html

目錄

前言

一、"What We Do in LightGBM?"

二、在不同數據集上的對比

三、LightGBM的細節技術

1、直方圖優化

2、存儲記憶優化

3、深度限制的節點展開方法

4、直方圖做差優化

5、順序訪問梯度

6、支持類別特徵

7、支持並行學習

四、MacOS安裝LightGBM

五、用python實現LightGBM算法
一、"What We Do in LightGBM?"

下面這個表格給出了XGBoost和LightGBM之間更加細緻的性能對比,包括了樹的生長方式,LightGBM是直接去選擇獲得最大收益的結點來展開,而XGBoost是通過按層增長的方式來做,這樣呢LightGBM能夠在更小的計算代價上建立我們需要的決策樹。當然在這樣的算法中我們也需要控制樹的深度和每個葉子結點的最小數據量,從而減少過擬合。

小小翻譯一下,有問題還望指出
      XGBoost     LightGBM
樹木生長算法     

按層生長的方式

有利於工程優化,但對學習模型效率不高
    

直接選擇最大收益的節點來展開,在更小的計算代價上去選擇我們需要的決策樹

控制樹的深度和每個葉子節點的數據量,能減少過擬合
劃分點搜索算 法     對特徵預排序的方法     直方圖算法:將特徵值分成許多小筒,進而在筒上搜索分裂點,減少了計算代價和存儲代價,得到更好的性能。另外數據結構的變化使得在細節處的變化理上效率會不同
內存開銷     8個字節     1個字節
劃分的計算增益     數據特徵     容器特徵
高速緩存優化     無     在Higgs數據集上加速40%
類別特徵處理     無     在Expo數據集上速度快了8倍
二、在不同數據集上的對比

higgs和expo都是分類數據,yahoo ltr和msltr都是排序數據,在這些數據中,LightGBM都有更好的準確率和更強的內存使用量。

準確率

 

內存使用情況

計算速度的對比,完成相同的訓練量XGBoost通常耗費的時間是LightGBM的數倍之上,在higgs數據集上,它們的差距更是達到了15倍以上。

三、LightGBM的細節技術
1、直方圖優化

XGBoost中採用預排序的方法,計算過程當中是按照value的排序,逐個數據樣本來計算劃分收益,這樣的算法能夠精確的找到最佳劃分值,但是代價比較大同時也沒有較好的推廣性。

在LightGBM中沒有使用傳統的預排序的思路,而是將這些精確的連續的每一個value劃分到一系列離散的域中,也就是筒子裏。以浮點型數據來舉例,一個區間的值會被作爲一個筒,然後以這些筒爲精度單位的直方圖來做。這樣一來,數據的表達變得更加簡化,減少了內存的使用,而且直方圖帶來了一定的正則化的效果,能夠使我們做出來的模型避免過擬合且具有更好的推廣性。

看下直方圖優化的細節處理

可以看到,這是按照bin來索引“直方圖”,所以不用按照每個“特徵”來排序,也不用一一去對比不同“特徵”的值,大大的減少了運算量。
2、存儲記憶優化

當我們用數據的bin描述數據特徵的時候帶來的變化:首先是不需要像預排序算法那樣去存儲每一個排序後數據的序列,也就是下圖灰色的表,在LightGBM中,這部分的計算代價是0;第二個,一般bin會控制在一個比較小的範圍,所以我們可以用更小的內存來存儲

3、深度限制的節點展開方法

LightGBM使用了帶有深度限制的節點展開方法(Leaf-wise)來提高模型精度,這是比XGBoost中Level-wise更高效的方法。它可以降低訓練誤差得到更好的精度。但是單純的使用Leaf-wise可能會生長出比較深的樹,在小數據集上可能會造成過擬合,因此在Leaf-wise之上多加一個深度限制

4、直方圖做差優化

直方圖做差優化可以達到兩倍的加速,可以觀察到一個葉子節點上的直方圖,可以由它的父親節點直方圖減去它兄弟節點的直方圖來得到。根據這一點我們可以構造出來數據量比較小的葉子節點上的直方圖,然後用直方圖做差來得到數據量比較大的葉子節點上的直方圖,從而達到加速的效果。

5、順序訪問梯度

預排序算法中有兩個頻繁的操作會導致cache-miss,也就是緩存消失(對速度的影響很大,特別是數據量很大的時候,順序訪問比隨機訪問的速度快4倍以上  )。

    對梯度的訪問:在計算增益的時候需要利用梯度,對於不同的特徵,訪問梯度的順序是不一樣的,並且是隨機的
    對於索引表的訪問:預排序算法使用了行號和葉子節點號的索引表,防止數據切分的時候對所有的特徵進行切分。同訪問梯度一樣,所有的特徵都要通過訪問這個索引表來索引。

這兩個操作都是隨機的訪問,會給系統性能帶來非常大的下降。

LightGBM使用的直方圖算法能很好的解決這類問題。首先。對梯度的訪問,因爲不用對特徵進行排序,同時,所有的特徵都用同樣的方式來訪問,所以只需要對梯度訪問的順序進行重新排序,所有的特徵都能連續的訪問梯度。並且直方圖算法不需要把數據id到葉子節點號上(不需要這個索引表,沒有這個緩存消失問題)
6、支持類別特徵

傳統的機器學習一般不能支持直接輸入類別特徵,需要先轉化成多維的0-1特徵,這樣無論在空間上還是時間上效率都不高。LightGBM通過更改決策樹算法的決策規則,直接原生支持類別特徵,不需要轉化,提高了近8倍的速度。

7、支持並行學習

LightGBM原生支持並行學習,目前支持特徵並行(Featrue Parallelization)和數據並行(Data Parallelization)兩種,還有一種是基於投票的數據並行(Voting Parallelization)

    特徵並行的主要思想是在不同機器、在不同的特徵集合上分別尋找最優的分割點,然後在機器間同步最優的分割點。
    數據並行則是讓不同的機器先在本地構造直方圖,然後進行全局的合併,最後在合併的直方圖上面尋找最優分割點。

LightGBM針對這兩種並行方法都做了優化。

    特徵並行算法中,通過在本地保存全部數據避免對數據切分結果的通信。
    數據並行中使用分散規約 (Reduce scatter) 把直方圖合併的任務分攤到不同的機器,降低通信和計算,並利用直方圖做差,進一步減少了一半的通信量。
    基於投票的數據並行(Voting Parallelization)則進一步優化數據並行中的通信代價,使通信代價變成常數級別。在數據量很大的時候,使用投票並行可以得到非常好的加速效果。

下圖更好的說明了以上這三種並行學習的整體流程:

在直方圖合併的時候,通信代價比較大,基於投票的數據並行能夠很好的解決這一點。

四、MacOS安裝LightGBM

    #先安裝cmake和gcc,安裝過的直接跳過前兩步
    brew install cmake
    brew install gcc
     
    git clone --recursive https://github.com/Microsoft/LightGBM
    cd LightGBM
     
    #在cmake之前有一步添加環境變量
    export CXX=g++-7 CC=gcc-7
    mkdir build ; cd build
     
    cmake ..
    make -j4
    cd ../python-package
    sudo python setup.py install

來測試一下:

大功告成!

值得注意的是:pip list裏面沒有lightgbm,以後使用lightgbm需要到特定的文件夾中運行。我的地址是:

/Users/ fengxianhe / LightGBM /python-package

 
五,用python實現LightGBM算法

爲了演示LightGBM在蟒蛇中的用法,本代碼以sklearn包中自帶的鳶尾花數據集爲例,用lightgbm算法實現鳶尾花種類的分類任務。

    # coding: utf-8
    # pylint: disable = invalid-name, C0111
     
    # 函數的更多使用方法參見LightGBM官方文檔:http://lightgbm.readthedocs.io/en/latest/Python-Intro.html
     
    import json
    import lightgbm as lgb
    import pandas as pd
    from sklearn.metrics import mean_squared_error
    from sklearn.datasets import load_iris
    from sklearn.model_selection import train_test_split
    from sklearn.datasets import  make_classification
     
    iris = load_iris()   # 載入鳶尾花數據集
    data=iris.data
    target = iris.target
    X_train,X_test,y_train,y_test =train_test_split(data,target,test_size=0.2)
     
     
    # 加載你的數據
    # print('Load data...')
    # df_train = pd.read_csv('../regression/regression.train', header=None, sep='\t')
    # df_test = pd.read_csv('../regression/regression.test', header=None, sep='\t')
    #
    # y_train = df_train[0].values
    # y_test = df_test[0].values
    # X_train = df_train.drop(0, axis=1).values
    # X_test = df_test.drop(0, axis=1).values
     
    # 創建成lgb特徵的數據集格式
    lgb_train = lgb.Dataset(X_train, y_train) # 將數據保存到LightGBM二進制文件將使加載更快
    lgb_eval = lgb.Dataset(X_test, y_test, reference=lgb_train)  # 創建驗證數據
     
    # 將參數寫成字典下形式
    params = {
        'task': 'train',
        'boosting_type': 'gbdt',  # 設置提升類型
        'objective': 'regression', # 目標函數
        'metric': {'l2', 'auc'},  # 評估函數
        'num_leaves': 31,   # 葉子節點數
        'learning_rate': 0.05,  # 學習速率
        'feature_fraction': 0.9, # 建樹的特徵選擇比例
        'bagging_fraction': 0.8, # 建樹的樣本採樣比例
        'bagging_freq': 5,  # k 意味着每 k 次迭代執行bagging
        'verbose': 1 # <0 顯示致命的, =0 顯示錯誤 (警告), >0 顯示信息
    }
     
    print('Start training...')
    # 訓練 cv and train
    gbm = lgb.train(params,lgb_train,num_boost_round=20,valid_sets=lgb_eval,early_stopping_rounds=5) # 訓練數據需要參數列表和數據集
     
    print('Save model...')
     
    gbm.save_model('model.txt')   # 訓練後保存模型到文件
     
    print('Start predicting...')
    # 預測數據集
    y_pred = gbm.predict(X_test, num_iteration=gbm.best_iteration) #如果在訓練期間啓用了早期停止,可以通過best_iteration方式從最佳迭代中獲得預測
    # 評估模型
    print('The rmse of prediction is:', mean_squared_error(y_test, y_pred) ** 0.5) # 計算真實值和預測值之間的均方根誤差

輸出結果:

可以看到預測值和真實值之間的均方根誤差爲0.722972。

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