Kaggle GPU用Win11(HOME)+WSL2+nvidia-dockerの構築(2023.03.18版)

### 対象範囲
* 🏃‍♂️ Win初期化された状態からスタート
* 💻 GPUは3060(Laptop)
* 🚩 ゴールは、ローカルでKaggle公式のDockerImageでGPUが使えるところまで

## [任意]Win初期化-WindowsUpdate
* 綺麗な状態からスタートしたい方はここからがよいかと思います。
* Winの初期化は「設定」->「回復」->「PCをリセットする」で可能です
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461687/35e1060e-dc52-0fbf-1016-3660374c44cc.png" width="320">

* 初期化完了後はひたすらWindowsUpdate。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461687/6c7708a5-9f16-053e-a84c-caf4e32322ac.png" width="320">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461687/7d34a04c-f01b-5f3e-65fe-f2dd1fe15925.png" width="320">

## NVIDIA Driverのダウンロード(CUDA)
* CUDAのバージョンはローカルとKaggleKernelをできるだけ合わせておきたいので、確認します
<details><summary><font color="silver">KaggleKernelのCUDA Versionの確認</FONT></summary><div>
本記事投稿時2023.03.18でのKaggleKernelのCUDA Versionは11.4です
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461687/0fe5b769-1ffd-a158-1038-a5bea2119588.png" width="640">
</div></details>
<details><summary><font color="silver">ローカルのCUDA Versionの確認</FONT></summary><div>
コマンドプロンプトから "nvidia-smi" で確認します
ローカルのCUDA Versionは12.0です

```
PS C:\Users\hoge> nvidia-smi
Sat Mar 18 12:58:39 2023
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 528.49       Driver Version: 528.49       CUDA Version: 12.0     |
|-------------------------------+----------------------+----------------------+
| GPU  Name            TCC/WDDM | Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA GeForce ... WDDM  | 00000000:01:00.0 Off |                  N/A |
| N/A   34C    P0    20W /  95W |      0MiB /  6144MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+
```

この環境ではCUDAのVersionが、**ローカル12.0**と先行しているため、KaggleKernelの11.4に近いバージョンでの環境構築を目指します。

</div></details>

---

* NVIDIA Driverのダウンロード(CUDA)はNVIDIA Officialから、GPUに合ったものを取得します。
    * https://www.nvidia.com/Download/Find.aspx?lang=en-us
* 今回は、CUDA11.6の**511.79**のVersionを使います。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461687/7cf698b6-f261-0cbe-fab8-dd25058325f9.png" width="320">
<details><summary><font color="silver">※補足.NvidiaDriverとCUDAの対応表</FONT></summary><div>
NvidiaDriverのVersionとCUDAのVersionの対応表は以下のOfficialにあり、NvidiaDriverのVersionは慎重に選ぶ必要があります。

https://docs.nvidia.com/deploy/cuda-compatibility/
![スクリーンショット 2023-03-18 134633.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461687/924fc633-d0ff-2987-2c97-f43648ba290c.png)

</div></details>

* ダウンロードした NVIDIA Driverをﾎﾟﾁﾎﾟﾁインストールします。(特に設定変更は不要)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461687/8f50f934-8c23-266b-2712-9a16d07d0d5e.png" width="320">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461687/9f736e12-698d-acf8-6ec1-b43788f74848.png" width="320">

* インストール後にローカルのCUDAのVersionが反映されている事を確認します。
    *  **CUDA Version: 11.6**となっているので期待したVersionが入っています。
```
PS C:\Users\hoge> nvidia-smi
Sat Mar 18 14:01:17 2023
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 511.79       Driver Version: 511.79       CUDA Version: 11.6     |
|-------------------------------+----------------------+----------------------+
| GPU  Name            TCC/WDDM | Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA GeForce ... WDDM  | 00000000:01:00.0 Off |                  N/A |
| N/A   38C    P0    19W /  N/A |      0MiB /  6144MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+
```

## Ubuntu-20.04のインストール
* PowerShellを管理者権限で実行。
* 利用可能なディストリビューションの確認
```
PS C:\Windows\system32> wsl --list --online
インストールできる有効なディストリビューションの一覧を次に示します。
既定の分布は ' * ' で表されます。
 'wsl --install -d <Distro>'を使用してインストールします。

  NAME                                   FRIENDLY NAME
* Ubuntu                                 Ubuntu
  Debian                                 Debian GNU/Linux
  kali-linux                             Kali Linux Rolling
  Ubuntu-18.04                           Ubuntu 18.04 LTS
  Ubuntu-20.04                           Ubuntu 20.04 LTS
  Ubuntu-22.04                           Ubuntu 22.04 LTS
  OracleLinux_8_5                        Oracle Linux 8.5
  OracleLinux_7_9                        Oracle Linux 7.9
  SUSE-Linux-Enterprise-Server-15-SP4    SUSE Linux Enterprise Server 15 SP4
  openSUSE-Leap-15.4                     openSUSE Leap 15.4
  openSUSE-Tumbleweed                    openSUSE Tumbleweed
```
* **Ubuntu-20.04**をインストール(**22.04**ではなく**20.04**である点に注意)

```
PS C:\Windows\system32> wsl --install -d Ubuntu-20.04
インストール中: 仮想マシン プラットフォーム
仮想マシン プラットフォーム はインストールされました。
インストール中: Linux 用 Windows サブシステム
[=============             24.0%                           ]
```
* インストール完了後に再起動
```
shutdown -r -t 0
```
* 再起動後にインストールしたUbuntuのユーザ名/PWを設定
```
Ubuntu 20.04 LTS は既にインストールされています。
Ubuntu 20.04 LTS を開始しています...
Installing, this may take a few minutes...
Please create a default UNIX user account. The username does not need to match your Windows username.
For more information visit: https://aka.ms/wslusers
Enter new UNIX username:
```
* Ubuntu上からGPUが見えていることを確認
```
$ nvidia-smi
Sat Mar 18 15:05:49 2023
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 510.52       Driver Version: 511.79       CUDA Version: 11.6     |
|-------------------------------+----------------------+----------------------+
| 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  NVIDIA GeForce ...  On   | 00000000:01:00.0 Off |                  N/A |
| N/A   40C    P8     8W /  N/A |     10MiB /  6144MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|    0   N/A  N/A        28      G   /Xwayland                       N/A      |
+-----------------------------------------------------------------------------+
```
* メモリの割り当てを変更。
    * .wslconfigを以下のパスに作成する。
    * **ファイルは、 Ubuntu上で作成することを推奨**(メモ帳等から作ると文字コードやBomなどの関係から反映されない場合があります)
```
$ cd /mnt/c/Users/[ユーザ名]
$ vi .wslconfig
```
```
[wsl2]
memory=32GB
```
* PowershellからUbuntuの再起動を行い、メモリの割り当てが反映されていることを確認
```
PS C:\Windows\system32> wsl -t Ubuntu-20.04
この操作を正しく終了しました。

PS C:\Windows\system32> wsl.exe
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.
```

* メモリの割り当てを確認する
    * このマシンの例では、元々**15G**の割り当てが、**31G**になっているので問題ないです
```
$ free -h
              total        used        free      shared  buff/cache   available
Mem:           31Gi       326Mi        30Gi       2.0Mi       143Mi        30Gi
Swap:         8.0Gi          0B       8.0Gi
# ---------------------------------------------- #
# メモリ割り当て変更前
# ---------------------------------------------- #
$ free -h
              total        used        free      shared  buff/cache   available
Mem:           15Gi       336Mi        14Gi       2.0Mi       175Mi        14Gi
Swap:         4.0Gi       0.0Ki       4.0Gi
```

## nvidia-docker2のインストール
* Dockerのインストール
```
sudo curl https://get.docker.com | sh
```
* Repositoryとgpgkeyの設定
```
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
```
* nvidia-docker2のインストール
```
sudo apt-get update
sudo apt-get install -y nvidia-docker2
```
* dockerの再起動
```
$ sudo service docker stop
 * Docker already stopped - file /var/run/docker-ssd.pid not found.
```
```
$ sudo service docker start
 * Starting Docker: docker
```

### nvidia-docker2でのGPUの動確
* docker上でcudaが認識できているか確認します。
```
$sudo docker run --runtime=nvidia --rm nvidia/cuda:9.0-base nvidia-smi
```
* 実行結果として、以下のようにGPU情報が出力されていれば問題ありません。
```
Unable to find image 'nvidia/cuda:9.0-base' locally
9.0-base: Pulling from nvidia/cuda
61e03ba1d414: Pull complete
4afb39f216bd: Pull complete
e489abdc9f90: Pull complete
999fff7bcc24: Pull complete
280cc4937d8b: Pull complete
bd4da60b84d7: Pull complete
3f54977ba563: Pull complete
c2cffbbbe321: Pull complete
Digest: sha256:c8faefab71dabdffa31dcf411bd6df072e3d9a4a54d49d46a993b4a945b9d37f
Status: Downloaded newer image for nvidia/cuda:9.0-base
Sat Mar 18 06:56:28 2023
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 510.52       Driver Version: 511.79       CUDA Version: 11.6     |
|-------------------------------+----------------------+----------------------+
| 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  NVIDIA GeForce ...  On   | 00000000:01:00.0 Off |                  N/A |
| N/A   38C    P8     9W /  N/A |     10MiB /  6144MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|    0   N/A  N/A        22      G   /Xwayland                       N/A      |
+-----------------------------------------------------------------------------+
```

* "sudo"が面倒ですので、不要で実行できるようにユーザグループに追加しておきます。
```
# ユーザグループがあることを確認
$ cat /etc/group | grep docker
docker:x:999:

# ユーザグループに追加
$ sudo gpasswd -a [ユーザ名] docker
Adding user [ユーザ名] to group docker
```
```
# Dockerの再起動
$ sudo service docker stop
 * Stopping Docker: docker                                                                                                                                                            [ OK ]
$ sudo service docker start
 * Starting Docker: docker
```
```
# Ubuntuへログアウト/ログイン
$ exit
logout
PS C:\Windows\system32> wsl.exe

# sudoが不要になっていることを確認
$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
```

## Kaggle Kernelの構築
* kaggleのdokcer imageを取得します(40GBのDLですので結構時間かかります)
```
docker pull gcr.io/kaggle-gpu-images/python:latest
```
<details><summary><font color="silver">参考.KaggleKernelのImageの確認方法</FONT></summary><div>
Kaggleで利用されているdockerのimageは、以下のように公開されています。

https://console.cloud.google.com/gcr/images/kaggle-gpu-images/global/python

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461687/541d5ce7-4f40-6012-741d-c11be3150a43.png" width="320">

また、Kaggle上で使われているdockerのimageのVersionは、Kaggle上から確認ができます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461687/aae0923a-f151-7e16-f56d-66b77b360e94.png" width="320">

---
</div></details>

* imageがダウンロードできていることを確認します
```
$ docker images
REPOSITORY                        TAG        IMAGE ID       CREATED         SIZE
gcr.io/kaggle-gpu-images/python   latest     2670d08e5aa5   3 weeks ago     40.2GB
nvidia/cuda                       9.0-base   0bedd0dfd4cb   20 months ago   152MB
```

* Kaggleのimageからコンテナを構築します
    * 今回は大まかに以下の条件(オプション)で構築します
        * メモリサイズは32GB(--shm-size=32g)
        * GPUはすべて使用する(--gpus all)
        * ドライブはDドライブにマウント(-v /mnt/d/docker_work_dir/test_dir)
```
docker run --name testcontainer-9998 -v /mnt/d/docker_work_dir/test_dir:/work -w=/work -it --gpus all --shm-size=32g -p 9998:9998 2670d08e5aa5 jupyter notebook --no-browser --port 9998 --ip="0.0.0.0" --notebook-dir=/work --allow-root
```
* 起動後に以下のようにNotebookのURLが表示されているのでブラウザアクセスし、Notebookが表示されればOKです。
```
[C 08:36:22.076 NotebookApp]

    To access the notebook, open this file in a browser:
        file:///root/.local/share/jupyter/runtime/nbserver-1-open.html
    Or copy and paste one of these URLs:
        http://b37dfe8eb576:9998/?token=ef9d97c2ea13ce3e5b7adfcc92c7e427fe5510036544e769
     or http://127.0.0.1:9998/?token=ef9d97c2ea13ce3e5b7adfcc92c7e427fe5510036544e769
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461687/3ba2004d-071c-7cc3-92bf-fda32ee39e96.png" width="640">

## Notebook上でのGPUの動確
* NotebookからGPUが見えていることを確認します。
```
!nvidia-smi
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461687/b2a05a42-43f0-eadb-e3ed-f0cb17a7639e.png" width="640">

* TorchでのGPUの動確
```
!pip install torch==1.13.0+cu116 torchvision==0.14.0+cu116 torchaudio==0.13.0 --extra-index-url https://download.pytorch.org/whl/cu116
```
<details><summary><font color="silver">参考.torchのcudaバージョン</FONT></summary><div>
今回の構築ではCUDAを11.6で組んでいるため、"cu116"版のTorchを入れなおします。

(pullしたKaggleのimageではCUDA11.4であるため)


その他のCUDAのバージョンは以下のTorchのオフィシャルドキュメントにあります。
https://pytorch.org/get-started/previous-versions/

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461687/031653a8-44a1-120f-501b-0327cc617cbd.png" width="640">
</div></details>

---

* ベンチマークの実行
    * エラー出力なく計算結果が出ていれば問題ありません。
    * また、新たにコンソールをあげておき、GPUを確認することでより安心できると思います。
```
import timeit
import torch
import datetime

def batched_dot_mul_sum(a, b):
    return a.mul(b).sum(-1)

def batched_dot_bmm(a, b):
    a = a.reshape(-1, 1, a.shape[-1])
    b = b.reshape(-1, b.shape[-1], 1)
    return torch.bmm(a, b).flatten(-3)

"""
    GPU
"""
GPU_ID = '0'
device = torch.device("cuda:{}".format(GPU_ID))

x = torch.randn(10000, 1024, device=device)
t0 = timeit.Timer(
stmt='batched_dot_mul_sum(x, x)',
setup='from __main__ import batched_dot_mul_sum',
globals={'x': x})
t1 = timeit.Timer(
stmt='batched_dot_bmm(x, x)',
setup='from __main__ import batched_dot_bmm',
globals={'x': x})

# Ran each twice to show difference before/after warmup
print(f'mul_sum(x, x):  {t0.timeit(100) / 100 * 1e6:>5.1f} us')
print(f'mul_sum(x, x):  {t0.timeit(100) / 100 * 1e6:>5.1f} us')
print(f'bmm(x, x):      {t1.timeit(100) / 100 * 1e6:>5.1f} us')
print(f'bmm(x, x):      {t1.timeit(100) / 100 * 1e6:>5.1f} us')
```
```
mul_sum(x, x):   32.6 us
mul_sum(x, x):   18.1 us
bmm(x, x):      27282.6 us
bmm(x, x):       22.4 us
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461687/e66ae611-13e0-1b71-be20-9c1a15d41aac.png" width="640">

* また、コンテナをrunしているターミナルは、停止して、起動で問題ないです。
```
# 起動中のコンテナを「ctrl」+「c」で停止
[I 09:06:30.874 NotebookApp] Saving file at /Untitled.ipynb
[I 09:06:30.878 NotebookApp] Saving Untitled.ipynb
^C[I 09:18:52.857 NotebookApp] interrupted
Serving notebooks from local directory: /work
1 active kernel
Jupyter Notebook 6.5.2 is running at:
http://b37dfe8eb576:9998/?token=ef9d97c2ea13ce3e5b7adfcc92c7e427fe5510036544e769
 or http://127.0.0.1:9998/?token=ef9d97c2ea13ce3e5b7adfcc92c7e427fe5510036544e769
Shutdown this notebook server (y/[n])? y

# コンテナのIDを確認
$ docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS                          PORTS     NAMES
b37dfe8eb576   2670d08e5aa5   "/entrypoint.sh jupy…"   44 minutes ago   Exited (0) About a minute ago             testcontainer-9998

# コンテナの起動
$ docker start b37dfe8eb576
b37dfe8eb576
```

---

### 🚩これにて構築完了です。それではよりよいKaggleライフを。

---