GCPとkaggle公式イメージ(docker)でGPU環境の構築

# はじめに
kaggleの画像コンペに参加するにあたりGPU搭載のマシンパワーが必要になったためGCPでGPU環境の構築を行いました。
既に大変参考になる記事がいくつもあり、私もそれらを参考に構築をしましたが、バージョンの違いなどでエラーが発生することも多々あったのでここで改めてまとめようと思います。
GCP入門者の方の助けになれば幸いです。
また、詳しい方々は間違いや改善点のご指摘をいただけますと大変感謝いたします。


# GCPへの登録

1. まずはGCPへの登録を行ってください。ガイダンスに従うだけなので問題ないと思います。
 - https://console.cloud.google.com/
2. 有料利用のアクティベーションを行います。ウィンドウの右上に"ACTIVATE"のボタンがあると思うので、そちらをクリックしてください。
 - なお、アクティベートしたからといって即料金が発生するわけではありません。登録の過程で300ドルの無料クレジット（クーポンみたいなもの）を得たと思いますが、これを超過して初めて実費の請求が始まります。この300ドルというのは、GPU1つのインスタンスの利用では1か月間使用しっぱなしでちょうどくらいです。

# インスタンスの起動
1. まず、GPU利用の申請を行います。左上の「三」のようなメニューアイコンをクリック →「IAMと管理」→「割り当て」→「表をフィルタ」→「上限名」→「GPUs (all regions)」→「Compute Engine API」の「すべての割り当て量」→上部の「割り当てを編集」→チェックボックスで選択 → 右に出る画面で新しい上限を1(または任意の必要数)と入力 → リクエストの説明には「in order to run deep learning model for kaggle」など入れれば大丈夫なはずです。
 - このリクエストの承認には数時間～数日かかる場合があります。たまにこのページをリロードして、上限が更新されているか確認ください。
2. 次にインスタンスのデプロイを行います。左上の「三」のようなメニューアイコンをクリック → 「Marketplace」→ 「Deep Learning VM」で検索 → 「運用開始」 → 設定は以下のように行います。 →設定完了後、「デプロイ」
 - Deployment name : 任意の環境名を設定。
 - Zone : そのままで大丈夫です。
 - Machine Type : CPUの個数、メモリを設定します。分析によって必要数は異なりますが、指標としてKaggleのkernel notebook は4CPU 16GB RAMです。
 - GPUs : NVIDIA Tesla K80を選択すれば問題ないと思います。
 - Framework ：　そのままで大丈夫です。
 - GPU、Access to Jupyter Lab：どちらもチェックを入れてください。
 - Boot disk ： disk typeはそのままで大丈夫ですが、必要であれば設定を変えてください。Boot disk sizeは増やしてください。最低でも300~500は必要かと思います。
 - Networking ： そのままで大丈夫です。
 - **料金** ： ページの右上では現在の設定状況から予想される料金が表示されています。予算と相談して上記設定をいろいろ微修正してください。

3. インスタンスの起動をします。左上の「三」のようなメニューアイコンをクリック → 「Compute Engine」→「VMインスタンス」→先ほどデプロイしたインスタンスの右端にある「・・・」マーク（縦）をクリック→「開始」を選択。
 - これでインスタンスの起動ができたはずなので、課金対象になります。必要のない際には同様の操作から、「停止」を選択してください。

# 環境構築

1. まずは黒い画面（プロンプト）を立ち上げます。上記と同じページ（左上の「三」のようなメニューアイコンをクリック → 「Compute Engine」→「VMインスタンス」）から、右端2番目の「接続」の「▼」をクリック → 「ブラウザウィンドウで開く」
 - この際、起動した画面でエラー表示がされる場合がありますが、その際は起動した画面を閉じて再度同じ工程で黒い画面を開いてください。
 - このほかに、gcloudで接続する方法もあります。ご興味のある方は調べてみてください。

2. Kaggle公式のdockerイメージをビルドします。以下のコマンドを黒い画面で打ってください。（#の行を除く）

```shell
# 公式イメージ
# https://github.com/Kaggle/docker-python
git clone https://github.com/Kaggle/docker-python.git
cd docker-python

# GPU版のビルド
# 30分ほどかかると思います
./build --gpu

# イメージを確認
# kaggle/python-gpu-buildが表示されれば成功です
docker images

```

3.　コンテナの生成をします。以下のコマンドを黒い画面で打ってください。（#の行を除く）

```shell
docker run -itd  --runtime=nvidia  -p 8888:8888   -v /home:/home   --name cont-1   -h host   kaggle/python-gpu-build /bin/bash
```

ここで、以下は変更の可能性のある部分なのでご注意ください。

-  cont-1：コンテナ名は任意です。今回はこのようにしました。これ以降現れるcont-1も同様です。
-  kaggle/python-gpu-build：これはひとつ前の手順「docker images」で表示されたイメージ名です。手順のまま実行していれば、この例で問題ないはずです。

4.　コンテナに入ります。以下を実行してください。

```shell
# コンテナを起動します
$ docker container start cont-1

# コンテナに入ります
$ docker container attach cont-1
```

なお、コンテナから抜けるには```exit```と入力してください。

5.　GPUの動作確認。コンテナに入った状態で、以下を実行してください。

```shell
# パスの設定
export LD_LIBRARY_PATH=/usr/local/cuda/lib64

# 動作確認
nvidia-smi
```

これでGPUの詳細が表示されればコンテナからGPUが認識されていることになります。
もしエラーが発生する場合は下で述べるトラブルシューティングをしてください。

6.　pythonからGPUの動作確認。コンテナに入った状態で、まずは```python```と入力し、Pythonクライアントを立ち上げてください。立ち上がりましたら、以下を実行してください。

```python
from tensorflow.python.client import device_lib
device_lib.list_local_devices()
```

ここでもエラーなくGPUが表示されればGPUの設定はばっちりです。
エラーがある場合はトラブルシューティングをしてください。

### GPU利用のトラブルシューティング

1. そもそも自体インスタンスからGPUが使えているのか確認をします。

```shell
nvidia-smi
```

これでGPUが表示されない場合はインスタンスの設定でGPUが選択できていないことが疑われます。
GCPの「VMインスタンス」→インスタンスをクリック→インスタンスの詳細画面でCtrl+FでGPUを検索してください。なければインスタンスの起動のセクションからやり直してください。


2.　別の方法でGPUを認識して起動できないか確かめてみます。以下のコマンドを実行してもうまくいかない場合ば、cudoのバージョンを更新する必要があるかもしれません。

```shell
docker run --runtime nvidia -itd -p 8887:8887 -v /home:/home --name gpu-test -h host
```

詳しくは[こちらのコメント](https://qiita.com/yota-p/items/affe6d970ac4896d6e70#comments)をご覧ください。

# Jupyter notebook の起動

1. まず、Jupyter notebookの起動をします。コンテナに入った状態で以下を実行します。

```shell
jupyter notebook --port 8888 --ip=0.0.0.0 --allow-root
```

2.　次に、起動したnotebookにアクセスするための設定をします。[こちらの記事](https://qiita.com/tk_01/items/307716a680460f8dbe17)が非常に詳しいので、説明は譲ります。

なお、httpsではつながらない場合があるので、その場合はhttpでも試してみてください。

# kaggle APIの導入
kaggleのデータセットのダウンロード、アップロードはAPIを通じて行うのでこの設定が必要になります。

1. pipでkaggleパッケージをインストールします。

```shell
pip install kaggle
```

2.　kaggle API keyを取得します。kaggle HP → My account → API → Create New API Tokenをクリック。jsonファイルがダウンロードされます。

3.　API keyをGCPインスタンスに保存します。インスタンス上でまずはディレクトリを作成、そこにキーを保存、実行権限を付与するという手順です。

```shell
# ディレクトリの作成
mkdir ~/.kaggle

# ファイルの作成
touch ~/.kaggle/kaggle.json

# ファイルへ書き込み
# kaggleからダウンロードしたキーをコピペすると楽です
vim  ~/.kaggle/kaggle.json

# 実行権限の付与
chmod 777 ~/.kaggle/kaggle.json

```

4.　kaggle APIを用いた操作をします。これは[公式ドキュメント](https://www.kaggle.com/docs/api)が詳しいのでご覧になってください。

# その他知っておくべきこと

以上で基本的には開発環境が整ったと思いますが、今後はそれぞれの実験によって異なるエラーが生じることかと思います。その際に知っておくと自己解決しやすくなること、ググりやすくなることをいくつか紹介します。

- ファイル操作
 - ディレクトリやファイルの作成、削除、移動など、何かにつけてLinuxコマンドは覚えておいたほうが楽です。
 - [こちら](https://qiita.com/savaniased/items/d2c5c699188a0f1623ef)が重要コマンドを簡潔にまとめられています。
- 占有容量確認
 - 容量不足によるエラーの発生などもよく起こります。df、duコマンドを覚えておくといいです。
 - [こちら](https://eng-entrance.com/linux-storage)が簡潔にまとめられています。


# 参考
- [GCPとDockerでKaggle用計算環境構築](https://qiita.com/lain21/items/a33a39d465cd08b662f1)
- [GCPとdockerによるkaggle環境の構築手順](https://kutohonn.hatenablog.com/entry/2020/03/01/203934)
- [Anacondaを利用してCompute Engineのインスタンス上にJupyter Notebookを導入する](https://qiita.com/tk_01/items/307716a680460f8dbe17#vm%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%82%A2%E3%83%BC%E3%82%A6%E3%82%A9%E3%83%BC%E3%83%AB%E3%81%AE%E8%A8%AD%E5%AE%9A)