GPU有効化したLightGBMをインストールする（Ubuntu 16.04）

# 背景
- 仕事で流行りのアンサンブル学習を試すことになり、XGBoostより速いという噂のLightGBMをPythonで試してみることに
- 実際、使い勝手良く、ニューラルネットよりも学習が短時間で終わるのでもっと色々試してみたいと思う
- conda-forgeから入れたLightGBMではGPU有効化されてないので、手動でコンパイルしようと試みる
- [他の方が紹介されている方法](http://yutori-datascience.hatenablog.com/entry/2017/07/07/162509)に従ってコンパイル　→　エラー

という流れ。以下、私の環境での解決方法ですが、この問題はOpenCLの違ったバージョンがインストールされている場合に発生するようなので、まず上のURLで書かれている方法を試すことをおすすめします。

あと、本記事ではLightGBMの使い方は解説しません。Qiitaには[LightGBMについての素晴らしい解説](http://qiita.com/TomokIshii/items/3729c1b9c658cc48b5cb)が既にあるので、そこらへんを参考にしてみてください。


## インストール環境
 - Ubuntu 16.04
 - GIGABYTE GeForce GTX 1060 WINDFORCE 2X OC 6GB GDDR5
 - CUDA 8.0 
 - cuDNN 5.1
 - Anaconda 4.3 (pyenv経由)

CUDAのインストール等は公式の方法に従ってインストールしました。

# 手動インストール→コンパイルエラーまでの流れ
まず、上のリンクにある手法でLightGBMをインストールすることを試みる。

```sh
# http://yutori-datascience.hatenablog.com/entry/2017/07/07/162509 そのまま
sudo apt-get update
sudo apt-get install --no-install-recommends nvidia-375
sudo apt-get install --no-install-recommends nvidia-opencl-icd-375 nvidia-opencl-dev opencl-headers

sudo init 6

sudo apt-get install --no-install-recommends git cmake build-essential libboost-dev libboost-system-dev libboost-filesystem-dev

cd ~/tmp/
git clone --recursive https://github.com/Microsoft/LightGBM
cd LightGBM
mkdir build ; cd build
cmake -DUSE_GPU=1 .. 
make -j$(nproc)
cd ..
``` 

で、ここでLightGBM本体のコンパイル完了。で、動作確認

```sh
~/tmp/LightGBM/examples/binary_classification
../../lightgbm config=train.conf data=binary.train valid=binary.test device=gpu
```

実行した後、[こんな感じのログ](https://github.com/Microsoft/LightGBM/issues/715#issuecomment-317153351)が出力されれば成功です。

と、ここまでは順調だったのですが、Pythonのモジュールをコンパイルしようとすると、

```sh
cd python-package/
python setup.py install --gpu
```

以下のようなエラーが出てコンパイルが止まってしまう事態に遭遇

```python 
OSError: /usr/local/lib/python3.5/dist-packages/lightgbm/lib_lightgbm.so: symbol clCreateCommandQueueWithProperties, version OPENCL_2.0 not defined in file libOpenCL.so.1 with link time reference
``` 

# 解決方法
いろいろググった結果、[同様の問題をgithubの公式フォーラムで報告している人を発見](https://github.com/Microsoft/LightGBM/issues/715#issuecomment-316996166)。

そこでの議論を追っていくと、これはどうも[OpenCLのドライバーが2種類インストールされていることによるらしい](https://github.com/Microsoft/LightGBM/issues/715#issuecomment-317153721) (通常のバージョン2.0とNvidia製のバージョン1.2)。しかし、`LD_LIBRARY_PATH`の設定では**LightGBMとリンクされているバージョンとは違う、Nvidiaのドライバが先に読み込まれてしまうのでエラーが起こってしまう**のだそうで。

これは以下の方法で解決できます。

### インストールされているLightGBMをアンインストール

**pipでアンインストールする**

```sh 
pip uninstall lightgbm 
```
**または手動でアンインストール** (以下はあくまで例です)

```sh 
# remove manually installed LightGBM
rm -rf /home/so1/.pyenv/versions/anaconda3-4.3.0/lib/python3.6/site-packages/lightgbm
rm -rf /home/so1/.pyenv/versions/anaconda3-4.3.0/lightgbm
# also remove downloaded LightGBM source, just in case
rm -rf ~/tmp/LightGBM
```

### 正しいバージョン（Nvidia製）のOpenCLをリンクさせてLightGBMを再コンパイル

```sh
git clone --recursive https://github.com/Microsoft/LightGBM
cd ./LightGBM
mkdir build; cd build
sudo cmake -DUSE_GPU=1 -DOpenCL_LIBRARY=/usr/local/cuda-8.0/lib64/libOpenCL.so -DOpenCL_INCLUDE_DIR=/usr/local/cuda-8.0/include/ ..
sudo make -j$(nproc)
cd ../python-package/
python setup.py install --precompile
```
ちなみに`cmake`のところは各自の環境によって違うと思うので、適宜書き換えてください。さらに、ここで重要なのは最後の行で**--gpuオプションを使わずにコンパイルする**という点です（間違ったバージョンのOpenCLがリンクされてしまうので）。

# 動作確認
もし問題なくインストールされたようならPythonで動作確認。例えば、[この解説記事](https://analyticsai.wordpress.com/2017/04/04/lightgbm/)からテストコードをお借りして試してみます。

```python
# https://analyticsai.wordpress.com/2017/04/04/lightgbm/ より拝借
import numpy as np
from sklearn import datasets, metrics, cross_validation
from lightgbm.sklearn import LGBMRegressor
import os
diabetes = datasets.load_diabetes()
x = diabetes.data
y = diabetes.target
clf = LGBMRegressor(max_depth=50,
                       num_leaves=21,
                       n_estimators=3000,
                       min_child_weight=1,
                       learning_rate=0.001,
                       nthread=24,
                       subsample=0.80,
                       colsample_bytree=0.80,
                       seed=42)

x_t, x_test, y_t, y_test = cross_validation.train_test_split(x, y, test_size=0.2)
clf.fit(x_t, y_t, eval_set=[(x_test, y_test)])
print("Mean Square Error: ", metrics.mean_squared_error(y_test, clf.predict(x_test)))
```

ここで以下のようなログがズラっと出力されればインストール成功です。

```python
[1]	valid_0's multi_logloss: 1.83493
[2]	valid_0's multi_logloss: 1.73867
[3]	valid_0's multi_logloss: 1.6495
[4]	valid_0's multi_logloss: 1.56938
[5]	valid_0's multi_logloss: 1.49485
[6]	valid_0's multi_logloss: 1.42784
[7]	valid_0's multi_logloss: 1.36532
 .... 
```

GPUとCPUを使ったときの学習時間の比較とかは[この記事](http://qiita.com/TomokIshii/items/95c49d5e86f2eae61720)などを参考にしてください。


# おわりに

Happy Machine Learning!