Kaggle環境をWindows11+dockerで構築(Windows11+wsl2+Ubuntu22.04+docker+gpu+Kaggle)

## 前書き
以前からKaggle notebookではなく自前で環境構築してみたいと思っていました。(先代PCはGPUがなくイマイチやる気が出なかった)
PCを新調したのでこの機会に本腰入れてKaggle環境を整えてみます。
ネットで検索したら先人の情報がありますが、自分の備忘録として記録します。

## 環境
OS: Windows11 home
GPU: NVIDIA GeForce RTX4060 Laptop

## 参考
大まかな流れは[こちらの記事](https://qiita.com/yukiZ/items/387e4b99c1f8c3db17ca)を参考に作業を進めていきます。

## NVIDIA ドライバーダウンロード ※最終的に諦めました
私の環境ではPC購入時点でNVIDIAドライバーはインストールされていました。
しかし参考記事には
>CUDAのバージョンはローカルとKaggleKernelをできるだけ合わせておきたいので

とあるので、いい感じのバージョンのものを再度インストールする必要があると判断。
とりあえず今のデフォルトで入っているもののバージョンを確認します。
コマンドプロンプトで以下のコマンドを実行。
~~~
C:\Users\hoge>nvidia-smi
Fri Aug 11 19:11:09 2023
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 536.99                 Driver Version: 536.99       CUDA Version: 12.2     |
|-----------------------------------------+----------------------+----------------------+
| 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 RTX 4060 ...  WDDM  | 00000000:01:00.0 Off |                  N/A |
| N/A   44C    P8               3W /  65W |    269MiB /  8188MiB |      0%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+

+---------------------------------------------------------------------------------------+
| Processes:                                                                            |
|  GPU   GI   CI        PID   Type   Process name                            GPU Memory |
|        ID   ID                                                             Usage      |
|=======================================================================================|
|    0   N/A  N/A     13268    C+G   ...Brave-Browser\Application\brave.exe    N/A      |
+---------------------------------------------------------------------------------------+
~~~

CUDA Versionが12.2であることが分かりました。
参考記事によると、これをKaggleKernelのCUDA Versionである11.4(2023.8.11時点で)に近づけなければなりません。
[NVIDIAの公式ページ](https://www.nvidia.com/Download/Find.aspx?lang=en-us#)にアクセスし、自分のPCのGPU情報を入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531112/481789f5-6d18-12f5-d685-1bc3dd038824.png)

自分のPCのGPUであるRTX4060 Laptopは最近出たものですので、一番古いバージョンは2023年2月にリリースされたver528.49です。
[こちらのページ](https://docs.nvidia.com/deploy/cuda-compatibility/)から、ver528.49はCUDA 12.0であることが分かります。...少しバージョンは遠いですが、これ以上古いものがないので仕方ありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531112/83128871-98c9-11b0-3eed-41628a0174f9.png)

ダウンロードしてインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531112/578b2462-fc44-9ca4-70ff-739ab1f5caf0.png)

しかし..
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531112/950de5dd-9bcf-41a8-0e34-b40b108cf38c.png)
ダメでした..。
他のバージョンのドライバを試しましたが同様に失敗。
よく分かりませんがNVIDIAのドライバのバージョンを11.4に近づけるのは諦めて今のバージョンのままで次に進みます。

## Ubuntuのインストール
dockerはUbuntu上で動作するらしいのでUbuntuのインストールが必要です。
しかし自分のPCはWindows11。そこで登場するのがwslです。
wslとはWindows上でLinuxを動作させるための実行環境らしいです。
最近wslがwsl2になって「完全なLinux」をWindows上で実現できるようになったとか..(すごい)
管理者権限でコマンドプロンプトを開き、以下のコマンドを実行します。
~~~
wsl --install -d ＜Linuxディストリビューション名＞
~~~
これでWSL2とLinuxディストリビューションを同時に行えます。
利用できるLinuxディストリビューションを以下のコマンドで確認します。
~~~
C:\Users\hoge>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_7_9                        Oracle Linux 7.9
  OracleLinux_8_7                        Oracle Linux 8.7
  OracleLinux_9_1                        Oracle Linux 9.1
  openSUSE-Leap-15.5                     openSUSE Leap 15.5
  SUSE-Linux-Enterprise-Server-15-SP4    SUSE Linux Enterprise Server 15 SP4
  SUSE-Linux-Enterprise-15-SP5           SUSE Linux Enterprise 15 SP5
  openSUSE-Tumbleweed                    openSUSE Tumbleweed
~~~
因みにディストリビューション名を省略するとデフォルトでUbuntuがインストールされるらしいです。
今回はUbuntu 22.04をインストールします。
以下のコマンドを実行。
~~~
PS C:\Users\hoge> wsl --install -d Ubuntu-22.04
インストール中: Linux 用 Windows サブシステム
Linux 用 Windows サブシステム はインストールされました。
インストール中: Ubuntu 22.04 LTS
Ubuntu 22.04 LTS はインストールされました。
要求された操作は正常に終了しました。変更を有効にするには、システムを再起動する必要があります。
~~~
するとエクスプローラーにペンギン君が...!
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531112/3f85a10a-56aa-546c-d512-365ffacc0f2b.png)

PCを再起動してUbuntuのユーザ名とパスワードを設定します。

~~~
Enter new UNIX username:
New password:
Retype new password:
~~~
これでUbuntuのインストールは完了です！
~~~
passwd: password updated successfully
Installation successful!
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

Welcome to Ubuntu 22.04.2 LTS (GNU/Linux 5.15.90.1-microsoft-standard-WSL2 x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
 ~~~

ちゃんとUbuntu 22.04がインストールされています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531112/bdd487f8-214c-3ddc-4c2a-35f3c4d52fba.png)

## dockerのインストール
Ubuntuのインストールが完了したのでdockerのインストールが可能になりました。
[こちらの記事](https://zenn.dev/itch/articles/4b432b73c36826)を参考に、wsl2のUbuntu 22.04にdockerをインストールします。
非常に分かりやすくまとめられている記事のため、上から順番にコマンドを叩けば問題ないです。
以下のコマンドでdockerのバージョンを確認できます。
~~~
hoge@hoge:~$ sudo docker version
Client: Docker Engine - Community
 Version:           24.0.5
 API version:       1.43
 Go version:        go1.20.6
 Git commit:        ced0996
 Built:             Fri Jul 21 20:35:18 2023
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          24.0.5
  API version:      1.43 (minimum version 1.12)
  Go version:       go1.20.6
  Git commit:       a61e2b4
  Built:            Fri Jul 21 20:35:18 2023
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.22
  GitCommit:        8165feabfdfe38c65b599c4993d227328c231fca
 runc:
  Version:          1.1.8
  GitCommit:        v1.1.8-0-g82f18fe
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0
~~~
無事にインストールされました。

## ユーザー権限付与
ところで今までdockerコマンドの頭で
~~~
sudo コマンド
~~~
としてきましたが、これが面倒くさい。
[こちらの記事](https://zenn.dev/ttani/articles/wsl2-docker-setup)によると、以下のコマンドでsudoを毎回打たなくてよくなるらしい。
~~~
sudo usermod -aG docker [ユーザ名]
~~~
以下のコマンドでユーザーを変更します。
~~~
hoge@hoge:~$ su - [ユーザ名]
~~~
これでsudoなしでコマンドが通るようになりました。
~~~
hoge@hoge:~$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
~~~

## NVIDIA Container Toolkitのインストール
[こちらの記事](https://qiita.com/nabion/items/4c4d4d4119c8586cbd9e)と[こちらの記事](https://zenn.dev/holliy/articles/e1ac7f2f806c35#fn-8f18-2)を参考に、NVIDIA Container Toolkitをインストールします。
NVIDIA Container ToolkitとはコンテナからGPUを使う際になんか良い感じにしくれるやつらしいです。
nvidia-docker2を使う方法もあるみたいですが、非推奨だそうです。

~~~
distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
      && curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
      && curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \
            sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
            sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
~~~
~~~
sudo apt update
~~~
~~~
sudo apt-get install -y nvidia-container-toolkit
~~~
~~~
sudo systemctl restart docker
~~~

動作確認として、以下のコマンドを実行します。
~~~
 sudo docker run --rm --gpus all nvidia/cuda:12.2.0-base-ubuntu22.04 nvidia-smi
~~~

これで
~~~
nvidia-smi
~~~
を実行したときと同様のGPU情報が表示されればOKです。

~~~
hoge@hoge:~$ sudo docker run --rm --gpus all nvidia/cuda:12.2.0-base-ubuntu22.04 nvidia-smi
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.98.01              Driver Version: 536.99       CUDA Version: 12.2     |
|-----------------------------------------+----------------------+----------------------+
| 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 RTX 4060 ...    On  | 00000000:01:00.0 Off |                  N/A |
| N/A   47C    P8               3W /  65W |    466MiB /  8188MiB |      0%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+

+---------------------------------------------------------------------------------------+
| Processes:                                                                            |
|  GPU   GI   CI        PID   Type   Process name                            GPU Memory |
|        ID   ID                                                             Usage      |
|=======================================================================================|
|    0   N/A  N/A        30      G   /Xwayland                                 N/A      |
+---------------------------------------------------------------------------------------+
~~~
大丈夫のようです!

## Kaggle Kernelの構築
Kaggleのdocker imageをpullします。
~~~
docker pull gcr.io/kaggle-gpu-images/python:latest
~~~
[こちらの記事](https://ko-ya346.hatenablog.com/entry/2022/11/21/005003)によると、
~~~
docker pull kaggle/python
~~~
だと古いイメージを持ってきてしまうそうです。
ダウンロードに時間がかかるためしばらく放置します。

ダウンロード後、以下のコマンドで無事にdocker imageがダウンロードされたことを確認します。
~~~
hoge@hoge:~$ sudo docker images
REPOSITORY                        TAG                       IMAGE ID       CREATED       SIZE
gcr.io/kaggle-gpu-images/python   latest                    87983e20c290   4 weeks ago   48.1GB
nvidia/cuda                       12.2.0-base-ubuntu22.04   8d51d68dba42   6 weeks ago   238MB
~~~

[こちらの記事](https://qiita.com/yukiZ/items/387e4b99c1f8c3db17ca)通りに以下のコマンドを実行します。
~~~
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にアクセスします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531112/53453621-ef78-033c-8377-486ef23c3b3c.png)

notebookが表示されました。
続けて記事の
>NotebookからGPUが見えていることを確認します。

の通り新しくnotebookファイルを作成してコマンド実行しようとしました...が、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531112/6176f322-55dd-338d-e39e-f5eb6140046c.png)

「An error occurred while creating a new notebook.
Forbidden」エラーが発生。
色々と調べると、[こちらの記事](https://github.com/jupyter/notebook/issues/6702)に
~~~
pip install --upgrade 'jupyter-server<2.0.0'
~~~
を実行しなければならないとの情報が。
これにはDockerfileで上記のコマンドを実行するように設定するのが良さそうです。
ここからは[こちらの記事](https://amalog.hateblo.jp/entry/data-analysis-docker)を参考に進めていきます。

docker composeが必要なので、念のためdocker composeが入っているかを以下のコマンドで確認します。
~~~
hoge@hoge:~$ docker compose version
Docker Compose version v2.20.2
~~~
(docker composeが無い場合は[こちらの記事](https://zenn.dev/ikkik/articles/3f7548428b2c1a)を参考にしてdocker composeをインストールしてください。)

手順通りにファイルを作成します。
今回は
~~~
\\wsl.localhost\Ubuntu-22.04\home\hoge\docker_work_dir\test_dir
~~~
の中に以下の構成でファイルを作成しました。
~~~
test_dir
├── .dockerignore
├── Dockerfile
├── docker-compose.yml
├── input/     # データ
├── notebook/  # Jupyter Notebook
└── script/    # スクリプト
~~~
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531112/878c2273-dd70-f519-51da-d2b0043a1026.png)

Dockerfileの作り方は[こちらの記事](https://ko-ya346.hatenablog.com/entry/2022/11/21/005003)も参考にしました。
### Dockerfile
~~~
# kaggleのpython環境をベースにする
FROM gcr.io/kaggle-gpu-images/python:latest

RUN pip install -U pip && \
pip install fastprogress japanize-matplotlib && \
pip install --upgrade 'jupyter-server<2.0.0'
~~~

### docker-compose.yml
~~~
version: "3"
services:
    jupyter:
        build: .
        volumes:
            - $PWD:/tmp/working
        working_dir: /tmp/working
        ports:
            - 8889:8889
        command: jupyter notebook --port=8889 --ip=0.0.0.0 --allow-root
        deploy:
            resources:
                reservations:
                    devices:
                        - driver: nvidia
                          count: 1
                          capabilities: [gpu]
                                               
~~~

test_dirに移動し、以下のコマンドを実行します。
~~~
docker compose up --build
~~~
jupyterのURLを開き、
~~~
!nvidia-smi
~~~
コマンドで今度こそGPUが認識されていることを確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531112/57afb50f-dfd1-2c69-c492-4a136e353a4f.png)

ここで後でアクセスできるように、jupyterのURLはブクマで保存しておきましょう。
コンテナを停止後も、作成したコンテナは以下のコマンドで確認することができます。
~~~
hoge@hoge:~/docker_work_dir/test_dir$ docker container ls -a
CONTAINER ID   IMAGE              COMMAND                  CREATED             STATUS         PORTS                                                 NAMES
8bf85249486a   test_dir-jupyter   "/entrypoint.sh jupy…"   About an hour ago   Up 2 minutes   8080/tcp, 0.0.0.0:8889->8889/tcp, :::8889->8889/tcp   test_dir-jupyter-1
~~~
コンテナを起動するには以下のコマンドを実行します。
~~~
 docker container start test_dir-jupyter-1
~~~
この状態で先ほどブクマしたjupyterのページにアクセスすると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531112/799de1b7-4ede-4241-11fc-a34ce9bb328d.png)
再度jupyterを開くことができました。

因みに起動中のコンテナ内でコマンドを実行するには
~~~
docker container exec [オプション] containername コマンド
~~~
とすれば良いらしいです。
試しに以下を実行しました。
~~~
hoge@hoge:~/docker_work_dir/test_dir$ docker container exec test_dir-jupyter-1 nvidia-smi
Sat Aug 12 04:43:54 2023
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.98.01              Driver Version: 536.99       CUDA Version: 12.2     |
|-----------------------------------------+----------------------+----------------------+
| 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 RTX 4060 ...    On  | 00000000:01:00.0 Off |                  N/A |
| N/A   40C    P8               2W /  65W |    255MiB /  8188MiB |      0%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+

+---------------------------------------------------------------------------------------+
| Processes:                                                                            |
|  GPU   GI   CI        PID   Type   Process name                            GPU Memory |
|        ID   ID                                                             Usage      |
|=======================================================================================|
|    0   N/A  N/A        27      G   /Xwayland                                 N/A      |
+---------------------------------------------------------------------------------------+
~~~
コンテナの環境でGPUが認識されていることが分かります。
続いて以下のコマンドでコンテナ環境にインストールされているライブラリを確認します。
~~~
hoge@hoge:~/docker_work_dir/test_dir$ docker container exec test_dir-jupyter-1 pip list
Package                                  Version               Editable project location
---------------------------------------- --------------------- -------------------------
absl-py                                  1.4.0
accelerate                               0.20.3
access                                   1.1.9
affine                                   2.4.0
aiobotocore                              2.5.2
aiofiles                                 22.1.0
.
.
~~~
ライブラリの数が多すぎて省略しましたが、scikit-learnやtensorflow等、有名どころはほとんどインストールされています!
自分のPCのローカル環境は一切汚さずにKaggle用の環境を構築することができました。

## Kaggle APIのインストール (2023.8.14追記)
ブラウザからKaggleのホームページにアクセスしなくても、コマンドラインからデータのダウンロードや開催中のコンペの表示、サブミットができる便利なやつがあるらしいのでインストールが吉です。
[こちらの記事](https://www.kkaneko.jp/ai/win/kaggle.html)を参考にインストールします。

コンテナを起動した状態で以下のコマンドを実行。
~~~
docker container exec [コンテナ名] pip install -U pip
docker container exec [コンテナ名] pip install kaggle
~~~
これでKaggle APIはインストールできましたが、このままではコマンドラインからKaggleアクセスすることができません。
Kaggleのホームページから、自分のKaggleアカウント情報が入力されたjsonファイルを入手する必要があります。

[Kaggle公式ページ](https://www.kaggle.com/)にアクセスし、ユーザープロファイルをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531112/ceba0063-407b-e186-e52d-74ce73c39938.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531112/4e2b68a0-ad64-b071-c20d-1cbbdb1896ef.png)

続いてアカウントボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531112/be11084c-6cb6-a4de-fc43-bde9d1701bf3.png)

「Create New Token」をクリックすると「kaggle.json」ファイルがダウンロードされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531112/015b056c-e281-9c46-4b46-056e222bfdd3.png)
「kaggle.json」ファイルには、自分のKaggleアカウントのユーザー名とキーが入力されています。

続いて、ダウンロードされた「kaggle.json」ファイルを、コンテナ内の以下のディレクトリ下に配置します。
~~~
/root/.kaggle
~~~
以下のようなフォルダ構成にしたいわけですね。
~~~
/root/.kaggle/kaggle.json
~~~

[こちらの記事](https://maku77.github.io/p/y8cfimp/)を参考に、以下のコマンドを入力します。
~~~
 docker container exec -it [コンテナ名] /bin/bash
~~~
~~~
root@677b0c9e2c2b:~# cd /root/.kaggle
root@677b0c9e2c2b:~/.kaggle# vim kaggle.json
~~~

vimはLinuxで使用できるテキストエディタです。詳しい使い方は[こちらの記事](https://www.motokis-brain.com/article/143)を参照して下さい。
「i」を押すと「入力モード」になり文字を入力できます。
「esc」を押すと「コマンドモード」になります。(文字は入力できなくなります)

「i」を押して入力モードに切り替えた後、「kaggle.json」ファイルの中身の内容をコピペして下さい。
その後「esc」でコマンドモードに切り替え、「:wq」でファイルを保存して終了します。

以下のコマンドでファイルを正しく作成できたか確認します。
~~~
root@677b0c9e2c2b:~/.kaggle# cat /root/.kaggle/kaggle.json
{"username":"自分のユーザ名","key":"自分のキー"}
~~~

これでKaggle APIを使用する準備が整いました!
試しに以下のコマンドを実行し、コンペの一覧を確認してみましょう。
~~~
root@677b0c9e2c2b:~/.kaggle# kaggle competitions list
ref                                                                              deadline             category            reward  teamCount  userHasEntered
-------------------------------------------------------------------------------  -------------------  ---------------  ---------  ---------  --------------
https://www.kaggle.com/competitions/asl-fingerspelling                           2023-08-24 23:59:00  Research          $200,000       1154           False
https://www.kaggle.com/competitions/commonlit-evaluate-student-summaries         2023-10-11 23:59:00  Featured           $60,000        712           False
https://www.kaggle.com/competitions/bengaliai-speech                             2023-10-17 23:59:00  Research           $53,000        249           False
https://www.kaggle.com/competitions/cafa-5-protein-function-prediction           2023-08-21 23:59:00  Research           $50,000       1552           False
https://www.kaggle.com/competitions/kaggle-llm-science-exam                      2023-10-10 23:59:00  Featured           $50,000       1166           False
https://www.kaggle.com/competitions/rsna-2023-abdominal-trauma-detection         2023-10-13 23:59:00  Featured           $50,000        218           False
https://www.kaggle.com/competitions/playground-series-s3e20                      2023-08-21 23:59:00  Playground            Swag        943           False
・
・
・
~~~
大丈夫なようです!