概要
- LightGBM CLI のインストール
- LightGBM CLIをC++で実行
はじめに
今回はLightGBMをマイクロソフトが提供しているLightGBMのCLI版を用いて、c++でコンパイルできる方法を紹介していきます。
処理の流れとしては
- LigthGBM CLIを用いてモデルを学習
- 学習したモデルファイルを用いて、C++のコードを作成
- g++でコンパイル、実行ファイルの作成
という感じになっています。
実験環境は
- google colaboratory
です。
興味のある方はぜひ途中まででも大丈夫ですので、ご付き合いください(^^)
メイン
LightGBM CLI とは?
まず、「LightGBM CLIとはなんぞや?」となってる方に簡単に説明すると、LightGBM CLIという名の通り、LightGBMのCLI(CUI)バージョンです。通常であればLightGBMはpip
、scikit-learn
でインストールして来て.py
にimport lightgbm as gbm
として使ったりしますよね。CLIバージョンでは、./lightgbm
とCUIで入力して使います。
とまあ、脇道に逸れた話は置いといて、先に進みましょう。
LightGBM CLIのインストール
それではCLIバージョンのLightGBMをインストールしていきましょう。
と言っても、そんなに難しいことはしなくて公式サイトのインストール手順の通りにインストールしていきます。
今回はcolabで実験したので環境はLinuxで行ってます。実行コードは↓です。
!git clone --recursive https://github.com/microsoft/LightGBM
%cd LightGBM
!mkdir build
%cd build
!cmake ..
!make -j4
!make -j4 install
上記のコードを実行するとLightGBMというディレクリの中に、lightgbmという実行ファイルが作成されます。
LightGBM CLIの使い方
インストールが終わったので、次にCLIでLightGBMを使う方法を見ていきましょう。
今回使うデータは定番のirisデータセットを使っていきます。
Datasetの準備
まずはirisデータセットを準備していきましょう。今回はseaborn
の方のirisを使っています。
import seaborn as sns
iris = sns.load_dataset('iris')
import numpy as np
import pandas as pd
columns = ["sepal_length", "sepal_width", "petal_length", "petal_width"]
data = iris[columns]
conditions=[(iris["species"] == "setosa"),(iris["species"] == "versicolor"), (iris["species"] == "virginica")]
choice = [0,1,2]
target = pd.Series(np.select(conditions, choice))
データの整形後、trainとtestに分割していきます。
その後、CLIでtrainingするために、CSVの形でtrainとtestデータを保存しておきます。
from sklearn.model_selection import train_test_split
train_data, test_data, train_target, test_target = train_test_split(data, target, test_size=0.2, shuffle=True,random_state=42)
pd.concat([train_target, train_data], axis=1).to_csv("iris.train", header=False, index=False)
pd.concat([test_target, test_data],axis=1).to_csv("iris.test", header=False, index=False)
Train, Testファイルについて
iris.train
とiris.test
について軽く説明をしたいと思います。
まずファイル名ですが、エイリアスが設定されておりそれに合わせて名前を決めることができます。
次にtrainの目的変数と説明変数の順番ですが、何も設定をしなければデフォルトで一番最初の列が目的変数になります。
設定するパラメータはlabel_column
で設定することができます。
Train, Convert, Predictのファイルを作成
CLIでは、taskに合わせてconfig fileのようなものを作成する必要があります。
ここでは、主に使用するであろうtrain、predict、convert_model(convert)
について説明したいと思います。(refit、save_binaryはよくわからないです)
trainとpredictは名前の通りの役割なのでわかりやすいのかなと思うのですが、convertはわかりにくい感が満載です。
convertで何をするか簡単に説明しますと、
- 学習したモデルを
.cpp
の形で保存 -
build
、make
で学習したタスクの新しいLightGBM実行ファイルを構築 - 新しく構築したLightGBMを使ってpredictを行う
という感じです。(下記で参考サイト乗っけてます。)
個人的には、predict機能がCLIで元からできるのになんでconvertという機能があるのかなと感じました。
最初はconvertした.cpp
を使って、c++でそのモデルを使えるようになるのかなと思ったのですが、これは僕のc++に対する理解不足と相まって、「おそらく使えないだろうけどわからないな」という結論になりました。(もし分かる方がいたらご教授お願いします)
とまあ機能の説明はここまでにして、まずはファイルの作り方を紹介していきます。
ファイルの作り方としては、設定したいパラメータを羅列して、ファイル名をaliasに合わせて保存するだけです。
以下のコードはパラメータの例です。パラメータはpythonでLightGBMを使うときと変わらないので、そんなに違和感なくて設定できると思います。
# train
train_conf = """
task = train
objective = multiclass
metric = multi_logloss
data = iris.train
num_class = 3
output_model = trained_model.txt
num_tree = 5
num_leaves = 3
"""
with open("train.conf", "w") as f:
f.write(train_conf)
# convert
convert_conf = """
task = convert_model
input_model= trained_model.txt
convert_model_language = cpp
"""
with open("convert.conf", "w") as f:
f.write(convert_conf)
# predict
predict_conf = """
task = predict
input_model = trained_model.txt
data = iris.test
"""
with open("predict.conf", "w") as f:
f.write(predict_conf)
上記のコードを実行すると、train.conf
,convert.conf
,predict.conf
の3つのファイルが作成できます。
それぞれの使い方は公式サイトの通りです。
Train
! ./lightgbm config=train.conf
oupput_modelのパラメータで設定した.txt
ファイルが作成されます。
今回であれば、trained_model.txtという名前でモデルのファイルが作成されます。
ちなみになんですが、このモデルファイルはpythonで作成したモデルファイルと中身は一緒です。
このコマンドですね → model.save_model('model.txt')
Convert
! ./lightgbm config=convert.conf
ここではパラメータを設定してないので、デフォルトのgbdt_prediction.cpp
が作成されます。
convert_model
のパラメータで設定することができます。
ちなみにConvertで生成されたファイルの使い方はGithubのIssueのところにあったので参考にしてもらえればと思います。
一応該当コードも添付しときます。
cd $BUILD_DIRECTORY/tests/cpp_test && ../../lightgbm config=train.conf convert_model_language=cpp convert_model=../../src/boosting/gbdt_prediction.cpp && ../../lightgbm config=predict.conf output_result=origin.pred || exit -1
cd $BUILD_DIRECTORY/build && make lightgbm -j4 || exit -1
cd $BUILD_DIRECTORY/tests/cpp_test && ../../lightgbm config=predict.conf output_result=ifelse.pred && python test.py || exit -1
Predict
! ./lightgbm config=predict.conf
ここでもパラメータを設定してないので、デフォルトのLightGBM_predict_result.txt
が作成されます。
output_result
のパラメータで設定することができます。
C++で使う
それではいよいよc++でコンパイルしていきます。ここで必要になってくるファイルはTrainで生成された.txt
ファイルと、testデータセットです。
そしてLightGBMのC API
というものを使用します。
c++に関してはあまり知識がないので、誰か海外ニキが試みてないのかなーと探してたら、あるにはあったんですがそれだけでは実行ができませんでした。ただ参考にはとてもなったので、そのサイトを以下に載せています。
コード
まずc++のコードです。colabで実行しているので、%%writefile skeleton_test.cpp
が記載してあります。
%%writefile skeleton_test.cpp
#include "LightGBM/c_api.h"
#include <stdio.h>
#include <iostream>
#include <vector>
void predict()
{
int temp;
int p = 1;
BoosterHandle handle;
// load model
temp = LGBM_BoosterCreateFromModelfile("trained_model.txt", &p, &handle);
std::cout <<"load result value is "<<temp <<std::endl;
// predict file data
const char* para = "None";
int res = LGBM_BoosterPredictForFile(handle, "iris.test", 0, C_API_PREDICT_NORMAL, 0, 0, para, "result");
std::cout << "file predict result is " << res << std::endl;
// row data
std::vector<float> row={6.1,2.8,4.7,1.2};
void* in_p = static_cast<void*>(row.data());
std::vector<double> out = (3, 0); //result用
double* out_result = static_cast<double*>(out.data());
int64_t *out_len = new int64_t();
res = LGBM_BoosterPredictForMat(handle, in_p, C_API_DTYPE_FLOAT32, 1, 4, 1, C_API_PREDICT_NORMAL, 0, 2, "None", out_len, out_result);
std::cout << "row predict return is " << res << std::endl;
std::cout << "row predict result size is " << int(out.size()) << " value is " << out_result[0] << " "<< out_result[1] << " " << out_result[2] << std::endl;
delete out_len;
}
int main(void) {
predict();
std::cout << "Ok complete!"<< std::endl;
return 0;
}
このコードの主な点は、
- モデルをロード
- ファイルデータからpredictする
- 配列などのrowデータから予測する
といった感じです。
使ったC APIとしては
の3つです。
最後に以下のコマンドを実行することで完了です。
!g++ -fpermissive -o a.out -v skeleton_test.cpp lib_lightgbm.so -Wl,-rpath,/content/LightGBM
./a.out
実行結果としては、まずファイルデータからpredictした場合はパラメータで指定してるresult
という結果ファイルが作成されます。
そしてrowデータから予測してる場合は、コマンドラインに結果が表示されます。
↓こんな感じです。
load result value is 0
file predict result is 0
row predict return is 0
row predict result size is 3 value is 0.274069 0.45598 0.269951
Ok complete!
これにて完了!!
最後に
今回はLightGBMをC++で使えるようにしてみました。エッジデバイスとかで使うときに役に立つかもなくらいには考えています。C++も使えようになりたいなと思った今日このごろでした。