LightGBMをGPUで使うのが簡単になってた件

# LightGBM on GPU

GPUでLightGBMを使う方法を探すと、ソースコードを落としてきてコンパイルする方法が出てきますが、今では環境周りが改善されていて、もっとずっと簡単に導入することが出来ます（NVIDIAの場合）。

まず、GPUドライバーが入っていない場合、入れます。

```sh
$ sudo apt install nvidia-driver-450
```

ビルドツールも入っていない場合、入れます。

```sh
$ sudo apt install build-essential
$ sudo apt install cmake
```

OpenCLと、opencl-headers、libboostを入れます。

```sh
$ sudo apt install clinfo
$ sudo apt install opencl-headers
$ sudo apt install libboost-all-dev
```

システムからlibOpenCL.soを探して、--install-optionに「--gpu」と「--opencl-library」を指定して、pipでインストールします。

```sh
$ pip install lightgbm --install-option=--gpu --install-option="--opencl-library=/usr/lib/x86_64-linux-gnu/libOpenCL.so.1"
```

これだけでGPUで動くLightGBMがインストールされます。

Pythonから使うときは、こんな感じで、parametersに「'device':'gpu'」を追加します。

```python
lgb_params = {
    'objective': ...,
    'boosting' : ...,
    'max_bin': 100,
    'device':'gpu'
    ...
}

lgb_train = lgb.Dataset(X, y)
lgb_eval = lgb.Dataset(X_val, y_val, reference=lgb_train)

model = lgb.train(
        params, lgb_train,
        valid_sets = [lgb_train, lgb_eval],
        categorical_feature = [...],
        verbose_eval = ...,
        num_boost_round = ...,
        early_stopping_rounds = ...
    )
```

なんで「'max_bin': 100」にしてるかというと、bin sizeが大きすぎると、GPUでは使えないみたいだからです（GPUメモリが余ってても駄目みたい）。

```
LightGBMError: bin size 800 cannot run on GPU
```

こんな感じでGPUを使うというメッセージが出て学習が進みます。

```
[LightGBM] [Info] This is the GPU trainer!!
[LightGBM] [Info] Total Bins 1104
[LightGBM] [Info] Number of data points in the train set: 5535952, number of used features: 29
[LightGBM] [Info] Using GPU Device: Quadro M6000 24GB, Vendor: NVIDIA Corporation
[LightGBM] [Info] Compiling OpenCL Kernel with 256 bins...
[LightGBM] [Info] GPU programs have been built
```

nvidia-smiで見ても、きちんとPythonがGPUを使っています。

```
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 450.80.02    Driver Version: 450.80.02    CUDA Version: 11.0     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  Quadro M6000 24GB   Off  | 00000000:01:00.0  On |                  Off |
| 27%   64C    P0    65W / 250W |    456MiB / 24474MiB |     12%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|    0   N/A  N/A       861      G   /usr/lib/xorg/Xorg                124MiB |
|    0   N/A  N/A      1476      G   cinnamon                           24MiB |
|    0   N/A  N/A     23249      C   ...conda3/envs/py/bin/python      257MiB |
+-----------------------------------------------------------------------------+
```

・・・ただし、GPUメモリの使用量も少なく、GPU-Utilも消費電力も少なく、GPUを飽和させる事は出来ないみたいです。
速度も、劇的に速くなった、という感じではありません。

# CatBoost on GPU

一方、CatBoostの場合はさらに簡単で、GPUドライバーとcudaが入っていれば、通常通りpipでインストールして、

```sh
$ pip install catboost
```

Pythonからは「task_type='GPU'」を付けるだけです。max_binも大きくてもいけます。

```python
model = CatBoostClassifier( iterations = ...,
                            custom_metric = ...,
                            max_bin=800,
                            task_type='GPU')
eval_dataset = Pool(X_val,y_val,cat_features = [...])
model.fit(X,
          y,
          cat_features=[...],
          eval_set=eval_dataset,
          early_stopping_rounds = ...,
          verbose_eval = ...)
```

nvidia-smiで見ると、GPUメモリもほとんど使い切っており、GPU-Utilも消費電力も大きく、GPUをガシガシ使っている感があります。

そして実際、CPUだけよりずっと速い！です。めっちゃ早！って思いました。

```
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 450.80.02    Driver Version: 450.80.02    CUDA Version: 11.0     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  Quadro M6000 24GB   Off  | 00000000:01:00.0  On |                  Off |
| 24%   53C    P0   126W / 250W |  23263MiB / 24474MiB |     97%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|    0   N/A  N/A       861      G   /usr/lib/xorg/Xorg                123MiB |
|    0   N/A  N/A      1476      G   cinnamon                           20MiB |
|    0   N/A  N/A     14498      C   ...conda3/envs/py/bin/python    23110MiB |
+-----------------------------------------------------------------------------+
```

というわけで、GPU環境でGBTアルゴリズムを使いたいときはCatBoostを使いましょう、という話でした。