【NVIDIA RAPIDS】cuDFライブラリを使ってみた

# 内容
[NVIDIA RAPIDS](https://developer.nvidia.com/rapids)が提供するGPU DataFrameライブラリ [cuDF](https://docs.rapids.ai/api/cudf/stable/)を使ってみました。
[Pandas](https://pandas.pydata.org/docs/)と似たような操作でデータの前処理/加工をGPUで行うことができるみたいです。
CPUで処理するよりも早いとの事で気になったので入れて試してみました。

# 実行環境
- OS
    - Windows 10 Home 64bit
    - WSL2 Ubuntu 20.04
        - Docker 20.10.10
- CPU
    - Intel Core i7-7820X
- Memory
    - DDR4-3200MHz 96GB
- GPU
    - NVIDIA GeForce RTX3060Ti


# cuDFについて
- pipでは提供されていない
    - [condaで提供](https://github.com/rapidsai/cudf#conda)されている
    - pipはサポートしなくなった（[リンク](https://rapids.ai/start.html)ページ下部 WHERE IS PIP?に記載)
- Python対応バージョンは3.8 or 3.9
- [Dockerコンテナでの提供](https://hub.docker.com/r/rapidsai/rapidsai)もされている


## 前提条件確認

導入するための[前提条件](https://rapids.ai/start.html)をチェック
![SnapCrab_NoName_2022-3-21_20-52-11_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/d2755ca8-df41-12b8-b464-ddea2ef897a7.png)

### GPU
- Pascalコア採用以降のGPUかつ[compute capability](https://developer.nvidia.com/cuda-gpus)ページでの数字が6.0+以降の製品
    - Pascalコア採用は一般向けビデオカードでいうとGTX1xxxシリーズ以降が対応
        - GT1030はPascalコアだがcompute capabilityに未記載
    - 自分が使用しているRTX3060Tiは対応


### OS
- Ubuntu 18.04/20.04 or CentOS 7/8 かつ gcc/++ 9.0以降
    - 後半の要件は`gcc -v`でバージョンチェック
- 自分の環境では`gcc -v`結果9.3.0

### Docker
- Docker CE(コミュニティ エディション) v19.03
    - CEはエディションの違い。無料版。
    - `docker -v`でバージョンチェック
- 自分の環境では`docker -v`結果20.10.10


### CUDA & NVIDIA Drivers

- 上記画像の4種類のドライババージョンとCUDA Toolkitのバージョンが必要
- 自分の環境はNVIDIA Driver 511.79&CUDA Toolkit未インストール
    - **Docker**の項目に[nvidia-container-toolkit](https://github.com/NVIDIA/nvidia-docker#quickstart)が必要とあるが、そのページでは`Note that you do not need to install the CUDA Toolkit on the host system, but the NVIDIA driver needs to be installed`とある。CUDA Toolkitは入れなくてもいい？
    - 一応以下のように項目を選択して入れた![SnapCrab_NoName_2022-3-21_21-12-41_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/d6b2dbb6-be3c-3bed-d422-9c731d7e4be1.png)
    - `nvidia-smi`で確認![SnapCrab_NoName_2022-3-21_21-26-34_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/70710ff8-83fa-9a79-48cc-299dcdbbf463.png)
        - GPUの名前が隠れますが`nvidia-smi -L`ですべての名前を見ることが可能![SnapCrab_NoName_2022-3-21_21-30-54_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/ca6cdf54-366e-3661-1b3e-11b0e8f5552f.png)

## 導入
[RAPIDS RELEASE SELECTOR](https://rapids.ai/start.html)なるもので環境を選んで入れられるようなので以下のように選択した


![SnapCrab_NoName_2022-3-21_21-34-26_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/18898c8e-e1ef-a613-38b8-91310466bd62.png)



ボリュームマウントしたいので`docker run`のコマンドを以下に変更

```shell
docker run -v /mnt:/rapids/notebooks/host --gpus all --rm -it -p 8888:8888 -p 8787:8787 -p 8786:8786 \
rapidsai/rapidsai-core:22.02-cuda11.5-runtime-ubuntu20.04-py3.8
```


`/rapids/notebooks/host`へbindすることにより、hostフォルダからボリュームマウントしたフォルダ群が見れるようになる

![SnapCrab_NoName_2022-3-21_21-50-6_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/4fa8f89e-1485-d85f-3aab-cca1008e41f5.png)



WSL2で`/mnt`としてボリュームマウントするとWindows側のフォルダ群が見れる

![SnapCrab_NoName_2022-3-21_21-50-53_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/ca1b9570-cc00-bf4f-bf87-f6b1e874e4b6.png)





# 処理速度比較
[cuDFドキュメント](https://docs.rapids.ai/api/cudf/stable/)を見ながら、Pandasとの処理速度の違いを比較してみました。
ノートブックは[Gistにアップロード](https://gist.github.com/nijigen-plot/09fd8b387730cb03dcd71a63b120febe)しています。

## 対象データ

対象データは[Kaggle H&M Personalized Fashion Recommendations](https://www.kaggle.com/c/h-and-m-personalized-fashion-recommendations/data)のcustomers.csv(207MB)とtransactions_train.csvをcustomer_id毎に集計したデータを用いました。
余談ですが、transactions_train.csv(3.49GB)をそのまま用いた場合、`cuDF.read_csv`時にエラーを吐いてしまいました。
[RAPIDS 概要](https://www.slideshare.net/NVIDIAJapan/rapids-120510206)資料の8ページに
> 必要なメモリサイズ
> 作業メモリとしてデータセットサイズの2-3倍

とありましたので、おそらくVRAMが足りなかったのかと思います。

![SnapCrab_NoName_2022-3-21_22-16-29_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/fb751853-b88a-02a4-8591-9e6e606aa597.png)


## 結果
Notebookの`%%timeit`を使って処理に掛かった時間を見ています。

|関数|cuDF処理速度 |Pandas処理速度 | 処理速度倍率|
| ---|--- |--- | --- |
| describe| 76.2ms|203ms |2.66倍 |
|apply | 140ms| 385ms|2.75倍 |
|merge | 46.6ms|1.63s |<font color='red'>**34.98倍**</font>|
| fillna| 50.7ms| 544ms|<font color='red'>**10.73倍**</font>|
|sort_values | 85.6ms| 2.07s|<font color='red'>**24.18倍**</font>|
|groupby | 16.9ms| 1.21s|<font color='red'>**71.60倍**</font>|
|drop_duplicates | 120ms| 550ms|4.58倍|
|round | 1.41ms| 1.57ms|1.11倍|

試した関数については、**すべてcuDFのほうが速い**という結果になりました！
`groupby`や`merge`はびっくりするくらい速かったです。


### 多少気になったところ
- pickleファイルの読み書き関数が無い
    - `pickle.dump()`,`pickle.load()`を使えばいい
- groupby後の結果がDataFrameにならない
    - Pandasの場合、`as_index=False`でgroupby後もDataFrame型になりますがcuDFではSeriesになってしまいます![SnapCrab_NoName_2022-3-23_1-54-33_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/1a7326e3-4928-8f1d-96d8-9bbde0b36328.png)
- object型に対してcuDF.applyができない？
    - customer_id,postal_codeに対してapplyをしたところTypingErrorを返されました。![SnapCrab_NoName_2022-3-23_1-57-25_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/87db4c6e-f47e-7a12-f7b6-b55bdda7d20f.png)



# 感想

- 速くてとてもいい！けどPandasと思って使うとちょいちょい躓く部分があるかも
- VRAM量が無いと大きなデータについては抑々読み込めない
    - colaboratoryで使えるT4,P100で使うのが良いかも
    - 買える方ならVRAM 12GB以上のビデオカード
- 実行環境もDockerで提供されてて楽に使える
- GPUで機械学習アルゴリズムが使える[cuML](https://docs.rapids.ai/api/cuml/stable/)も良さそう