XGBoost解析系列-準備


0.前言

  研究生期間有幸和各路大腿參加過些機器學習與數據挖掘的比賽,發現XGBoost單模型分類與迴歸效果往往比其他模型LR、RF、SVM、GDBT模型要好上不少,現在Microsoft還出LightGBM,首秀就在滴滴大賽中摘得10w美刀桂冠。當然也不好一概而論,比賽場景有限,數據特徵處理偏稠密方式,比如圖像領域CNN效果模型更好,而計算廣告業界更喜歡使用FM/FFM做預估,前者是高維像素級特徵,後者是千億級別的離散特徵。
  也正是體驗過XGBoost強大之處,滿懷着對陳天奇大神的欽佩之情,最近強行騰出時間閱讀&Debug完陳天奇實現XGBoost的源碼,對於飢渴已久的我來說,讀完最大感受是:實現算法需要這麼多硬技能!值得花時間去鑽研學習,不僅對XGBoost的理解更深刻了,也對日後算法工程實現都有指導意義。接下來該系列會慢慢剖析XGBoost的工程實現,敬請期待!

  對於有心想閱讀&debug陳天奇版本XGBoost源碼的讀者建議看完該博客。

1.代碼準備

  筆者以macOS系統(macOS Sierra Version:10.12.1)作爲開發環境進行說明,不同系統請讀者自行google相關替代過程,首先下載github代碼:

git clone --recursive https://github.com/dmlc/xgboost 

  加上參數–recursive,會把xgboost依賴的submodule都clone下來,並放在xgboost主目錄下。目前筆者基於git庫的log commit:d9d5293cdbbbf67dc8ff9d4a3f171d0990fdd1ee (2017.10.26 17:31:10提交的commit),xgboost依賴以下4個模塊:

  • dmlc-core:用於支撐DMLC機器學習項目的公共代碼庫
  • rabit:封裝了高度可依賴的Allreduce與Broadcast接口,用於分佈式消息同步
  • nccl:優化後的多GPU通信基礎庫
  • cub:CUDA編程相關庫

2. 編譯準備

  1. mac系統原生編譯工具基於clang與lldb,其中編譯工具clang使用的stl等庫實現與GNU是不同的,還是建議安裝GNU的編譯工具,筆者mac下安裝其他軟件使用HomeBrew。

  • gcc/g++編譯鏈接,筆者安裝gcc 6.0版本、目前有7.0+版本
  • gdb調試工具,筆者安裝的8.0.1版本,高版本有新特性支持
brew install gcc6 --without-multilib
brew install gdb

   注意:gdb在mac系統下因爲權限問題不能直接調試程序,第一次使用會出現錯誤Unable to find Mach task port,需要安裝信任證書並codesign下:
  1. command+空格輸入“鑰匙串訪問”,點擊左上角的“鑰匙串訪問”菜單選擇:證書助理->創建證書->名稱填寫gdb-cert,證書類型選代碼簽名,勾選”讓我覆蓋這些默認值”,然後一直next,直到“指定用於該證書的位置”選擇“系統”。
  2. 選擇“系統”、“我的證書”,找到剛剛的證書,選擇“始終信任”。
  3. 運行以下shell命令,重啓系統,證書才能生效

  注意:如果創建系統證書的時候出現未知錯誤Unknown Error = -2,147,414,007時,解決方法:可以先“指定用於該證書的位置”選擇“登錄”(可以執行成功),然後導出創建證書到本地,刪除剛創建的登錄證書,再把導出的文件導入到系統證書中。筆者基於macOS Sierra 10.13版本會出現這種問題,也通過該方法解決。最後,重啓按住command + R進入恢復模式,打開終端,輸入csrutil enable --without debug,再重啓系統。

codesign -s gdb-cert /usr/local/bin/gdb

  gdb調試工具功能非常強大,早前M$下做開發,基於VS界面調試直觀、方便,幾乎沒花時間去研究。現在基於Linux開發必須得會,儘管gdb無良好界面看上去很不方便,但是習慣後發現還是很順手的。記得以前都不知道如何用gdb打印輸出string、vector等stl的變量值,後來才發現可以通過配置.gdbinit定義打印函數+pretty功能(高版本gdb支持)來格式化打印stl各種容器,甚至是C++11的unorder map。究其原因,其實是自己對stl容器類實現過程,內部成員不夠熟悉,讀者可以移步vector stl庫實現詳解來了解其具體實現以及gdb配置教程來配置升級下gdb(最近會更新,並添加鏈接)。

  2. 建議檢查下

which gcc-6 # 是否爲 /usr/local/bin/gcc-6
which g++-6 # 是否爲 /usr/local/bin/g++-6

  如果有誤,配置~/.bashrc環境變量path:export PATH=/usr/local/bin:$PATH

  3. 修改make編譯配置

cd <你的directory>/xgboost
cp make/config.mk ./config.mk
vim ./config.mk
# 將其中CC與CXX註釋的2句話打開,並修改爲
export CC = gcc-6
export CXX = g++-6

  4. 執行make編譯

cd <你的directory>/xgboost
make -j4

   make程序的-j是並行度設置,-j8會更快,讀者可以根據機器的cpu核數自行調整,編譯完成會生成各種xgboost需要的庫以及可執行文件。

  5. 爲python安裝xgboost模塊

cd python-package
sudo python setup.py install

  至此,已完成mac系統下的xgboost安裝,但是如果打算閱讀源碼,並debug代碼細節,需要以下設置

3. debug編譯配置

  1. 目前工程下默認編譯設置是release模式,直接debug會問題:

  • g++編譯優化級別爲-O3,-O3爲高度優化參數,debug會有問題:1)變量容易被優化而不可見,2)指令編譯重排,不容易理解,3)宏定義與inline函數會被優化。
  • g++編譯沒有-g參數,也就是說直接調試程序是拿不到debug符號symbol

   通過以下語句對所有編譯來增加debug支持

# 在xgboost主目錄下
grep '\-O3' -rl -R . |xargs  sed -i '' 's/-O3/-O0 -g -gdwarf-3/g'
sed -i '' 's/crv/crvs/g' Makefile
make -j4

  第一句對帶有-O3的編譯參數修改爲-O0(完全不優化),-g生成debug符號,-gdwarf-3生成兼容可讀的debug symbol文件,如果沒有這個參數,gdb print依賴庫的變量時會出現錯誤:error reading variable: Could not find the frame base。第二句是對於依賴靜態庫libxgboost.a改用ar打包參數crvs,否則不能debug靜態庫源代碼。

  2. xgboost主目錄下提供很多測試demo案例和模塊測試代碼:1)demo文件夾存放着各種案例的測試數據與腳本。有二分類、多分類、迴歸、LearningToRank排序。其中runexp.sh腳本可以測試xgboost啓動的整個過程,涉及train、predict、模型dump以及樹的可視化輸出。2)tests文件夾下提供很多模塊的測試代碼,調試他們對模塊功能理解也有幫助。
  下面以binary_classification案例爲例作爲說明例子,對應的配置文件爲:mushroom.conf,注意其中配置的數據文件路徑,由於運行runexp.sh腳本路徑是當前路徑,因此運行runexp.sh腳本是不會出錯的,但是我們後期debug xgboost,工作目錄區間爲xgboost主目錄,需要修改路徑爲絕對路徑:

data = "agaricus.txt.train"修改爲"<你的directory>/xgboost/demo/data/agaricus.txt.train"
eval[test] = "agaricus.txt.test"修改爲"<你的directory>xgboost/demo/data/agaricus.txt.test"
test:data = "agaricus.txt.test"修改爲"<你的directory>xgboost/demo/data/agaricus.txt.test"
增加配置項nthread = 1,默認情況下xgboost是直接基於cpu數設置OMP並行線程,debug過程中多線程運行切換容易干擾調試執行邏輯。
原本gdb調試支持多線程調試:通過設置set scheduler-locking on來阻塞其他線程的運行,只運行當前線程的運行。
但筆者在測試中會出現錯誤:Target 'native' cannot support this command.目前還未解決。

  3. 開始gdb debug

gdb xgboost
# 進入gdb界面後,設置conf路徑
set args demo/binary_classification/mushroom.conf
# b 設置相關斷點
run

  4. 查看變量名出現位置的Tips:

git grep xxx
# 前者是基於當前git庫下,遍歷當前目錄下所有找出出現xxx變量名的位置,後者是找出當前目錄下的情況。
# 因爲在xgboost主目錄下還存在其他的庫,所以使用前者無法查到其他庫出現的位置,而後者可以
grep xxx -R .

VS Code可視化調試

  原本使用vim+gdb已經能滿足調試需求,但是筆者還是習慣於使用Visual Studio Code進行代碼閱讀,使用VS可視化界面與gdb混合調試,mac版本下的VS code算業界良心,界面乾淨清爽,啓動速度快,支持插件。混合調試主要爲了追求效率:1)VS設置斷點方便,而且具備斷點保存功能,但是對於print打印輸出複雜類型string、vector目前沒找到很好的解決方案。2)配置後的gdb,幾乎能print打印輸出任何結構,任何變量的數據。不過調試需要以下步驟:

  1. 官網下載VS code:https://code.visualstudio.com/download
  2. 安裝C++開發插件:C/C++ Clang、cpptools、C++ Intellisense三大插件,方便代碼跳轉以及調試
  3. 配置make和run_test任務tasks.json:點擊“任務”->配置任務,主要是使用shell來編譯與運行測試
  4. 配置調試設置launch.json,會依賴步驟3配置的make任務:點擊“調試” -> 增加配置

tasks.json配置文件:

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "taskName": "make",
            "type": "shell",
            "command": "make -j8"
        },
        {
            "taskName": "run_test",
            "type": "shell",
            "command": "${workspaceRoot}/xgboost demo/binary_classification/mushroom.conf"
        }
    ]
}

launch.json配置文件:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "gdb",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceRoot}/xgboost",
            "args": ["${workspaceRoot}/demo/binary_classification/mushroom.conf"],
            "stopAtEntry": false,
            "cwd": "${workspaceRoot}",
            "environment": [],
            "externalConsole": true,
            "preLaunchTask": "make",
            "MIMode": "gdb"
        }
    ]
}

VS code配置效果圖:


這裏寫圖片描述

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