できるだけ公式ドキュメントに沿って、デバッグ可能な機械学習の開発環境を構築（WSL2＋GPU＋Docker＋VS Code）

# 環境
- Windows 11 Home
    - バージョン: 23H2
    - ビルド: 22631.3880

以下は構築後の環境
- `wsl --version`
    - WSL バージョン: 2.2.4.0
    - カーネル バージョン: 5.15.153.1-2
    - WSLg バージョン: 1.0.61
    - MSRDC バージョン: 1.2.5326
    - Direct3D バージョン: 1.611.1-81528511
    - DXCore バージョン: 10.0.26091.1-240325-1447.ge-release
    - Windows バージョン: 10.0.22631.3880
- `wsl -l -v`
    - ```powershell
        NAME              STATE           VERSION
      * Ubuntu-24.04      Running         2
        docker-desktop    Running         2
      ```
- GPU: NVIDIA GeForce RTX 4060 Ti (16GB)
    - ドライバーバージョン: 560.70
- Docker Desktop: 4.32.0 (157355)
    - Engine: 27.0.3
    - Compose: v2.28.1-desktop.1
    - Credential Helper: v0.8.2
    - Kubernetes: v1.29.2

# はじめに
　先日、ゲームに加えて機械学習も少しできるようにそこそこのスペックのPC[^1]を新調したので、環境構築の流れと詰まった部分について書いていきます。
　以下の記事をかなり参考にさせていただきましたが、やはり何はともあれ公式ドキュメントは大事ということで、作業自体はできるだけ公式ドキュメントに沿って行いました。
- [WSL2+docker+GPU環境構築(win11) #Docker - Qiita](https://qiita.com/nabion/items/4c4d4d4119c8586cbd9e)
- [VSCodeでWSL2上のDockerコンテナ内コードをデバッグ #Python - Qiita](https://qiita.com/c60evaporator/items/fd019f5ac6eb4d612cd4)
- [【2024年版】WSL2+Ubuntu24.04+Docker＋GPUでつくる機械学習環境](https://zenn.dev/yumizz/articles/627d4e4821c636)

なお、本記事は基本的な Linux、VS Code の操作が行えることを前提としています。

# （0. PowerShell のアップデート）
　以降の作業では PowerShell をよく使います。（恐らく古いままでも問題はありませんが）デフォルトでインストールされているものが古い場合は、新しいバージョンにアップデートすると良いと思います。
 　具体的なアップデート方法ですが、古いバージョンの PowerShell を起動すると以下のようなメッセージが表示されると思うので、指示されたURL https://aka.ms/PSWindows にアクセスします。
```powershell
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

新機能と改善のために最新の PowerShell をインストールしてください!https://aka.ms/PSWindows
```
　MSI や ZIP パッケージを使用する等いくつかインストール方法はあるようですが、自分は「[Windows への PowerShell のインストール](https://learn.microsoft.com/ja-jp/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.4#winget)」で推奨されている Winget を使用しました。
　上のドキュメントにあるように、古い PowerShell 上で`winget search Microsoft.PowerShell`を実行するとその時点での最新バージョンの PowerShell を検索でき、`winget install --id Microsoft.Powershell --source winget`でインストールできます。

:::note info
自分の場合は、このインストールが途中で止まってしまうという現象が起きました。解決策としては、5分ほど放置した後にいったん PowerShell のウィンドウを閉じ、再度インストールコマンドを実行することで上手くインストールすることができました。
:::

　インストール後は、タスクバーの検索欄で「powershell」などと検索してヒットする PowerShell 7 (x64) を実行すると、新しいバージョンの PowerShell が起動します。

# 1. GPUドライバーのアップデート
　自分はいわゆるゲーミングPCを買ったので NVIDIA GeForce Experience がプレインストールされており、そちらから GPU ドライバーをアップデートしました（Game Ready ドライバを選択しました）。
　GPU ドライバーのアップデートが終わったら、PowerShell で`nvidia-smi`コマンドが実行できることを確認しておきましょう。
```powershell
PS C:\Users\xxx> nvidia-smi
Sat Aug  3 16:07:51 2024
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 560.70                 Driver Version: 560.70         CUDA Version: 12.6     |
|-----------------------------------------+------------------------+----------------------+
（以下略）
```
なお、各プロセスの GPU メモリ使用量が`N/A`となってしまい閲覧できないのは、NVIDIA の開発者向けフォーラムの[回答](https://forums.developer.nvidia.com/t/gpu-memory-usage-shows-n-a/169140/2)によると仕様らしいです。

# 2. WSL2 のインストール
　公式ドキュメント「[WSL のインストール](https://learn.microsoft.com/ja-jp/windows/wsl/install#change-the-default-linux-distribution-installed)」に沿ってインストールしていきます。
　ドキュメントの一番上にある`wsl --install`でも問題ないと思いますが、自分はディストリビューションを明示的に指定してインストールしました。具体的には、管理者として実行した PowerShell 上で、まずは`wsl --list --online`を実行すると、以下のようにインストール可能なディストリビューションが表示されます。
```powershell
PS C:\Users\xxx> wsl --list --online
インストールできる有効なディストリビューションの一覧を次に示します。
'wsl.exe --install <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
Ubuntu-24.04                           Ubuntu 24.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.6                     openSUSE Leap 15.6
SUSE-Linux-Enterprise-15-SP5           SUSE Linux Enterprise 15 SP5
SUSE-Linux-Enterprise-Server-15-SP6    SUSE Linux Enterprise Server 15 SP6
openSUSE-Tumbleweed                    openSUSE Tumbleweed
```
　表示された案内に従って、自分は`wsl --install Ubuntu-24.04`を実行して Ubuntu 24.04 LTS をインストールしました。
　画面の指示に従って PC が再起動した後は、自動的に Ubuntu のターミナルが起動するので、そこで Ubuntu のユーザ名とパスワードを設定します。こちらについては、公式ドキュメント「[WSL 開発環境を設定する](https://learn.microsoft.com/ja-jp/windows/wsl/setup/environment#set-up-your-linux-username-and-password)」が分かりやすいので、参照しながら設定すると良いと思います。
　そして、ユーザ名とパスワードの設定が終わったら、ドキュメントに従って Ubuntu のターミナル上で `sudo apt update && sudo apt upgrade` を実行し、パッケージの更新とアップグレードを行います。
　ここまで終わったら、ターミナル上で`nvidia-smi`コマンドが実行できることを確認しておきましょう（ターミナルは、タスクバーの検索欄で「ubuntu」などと検索してヒットする Ubuntu 24.04 LTS を実行すると開きます）。
```powershell
xxx@pcname:~$ nvidia-smi
Sat Aug  3 16:48:42 2024
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 560.27                 Driver Version: 560.70         CUDA Version: 12.6     |
|-----------------------------------------+------------------------+----------------------+
（以下略）
```

# 3. Docker Desktop のインストール
　Ubuntu 内に直接 Docker をインストールするという方法もありますが、自分は Docker Desktop をインストールしました。公式ドキュメント「[WSL での Docker コンテナーの概要](https://learn.microsoft.com/ja-jp/windows/wsl/tutorials/wsl-containers#install-docker-desktop)」に沿ってインストールしていきます。
　こちらについては、公式ドキュメントと Docker Desktop インストール時の画面の指示に従っていけば特に戸惑うところはなかったと思います。ドキュメント最後の `docker run hello-world` の実行は必須ではありませんが、 Docker に慣れていなければ実行してみると良いかもしれません。
　ここまで終わったら、Ubuntu のターミナル上で Docker コマンドが使用可能になります。
```powershell
xxx@pcname:~$ docker --version
Docker version 27.0.3, build 7d4bcd8
```

# 4. NVIDIA Container Toolkit のインストール
　公式ドキュメント「[Installing the NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html#installing-with-apt)」に沿って、Docker コンテナ内で GPU を使用するのに必要な NVIDIA Container Toolkit をインストールしていきます。具体的には、Ubuntu のターミナル上で以下のコマンドを順に実行していきます。
```powershell
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/stable/deb/nvidia-container-toolkit.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
```
```powershell
sudo apt-get update
```
```powershell
sudo apt-get install -y nvidia-container-toolkit
```
　インストールが終わったら、続いてドキュメントに沿って設定をしていきます。具体的には、以下のコマンドを順に実行していきます。
```powershell
sudo nvidia-ctk runtime configure --runtime=docker
```
```powershell
sudo systemctl restart docker
```
:::note info
自分の場合は、最後の`systemctl`実行時にエラーが起きてしまったため、このタイミングで PC 自体を再起動しました。
:::

# 5. コンテナ内での GPU 使用の動作確認
　ここで、Docker コンテナ内で GPU が問題なく使用できるかを確認します。こちらについては、冒頭で紹介した[記事](https://zenn.dev/yumizz/articles/627d4e4821c636)の [6.](https://zenn.dev/yumizz/articles/627d4e4821c636#6.-%E4%BD%BF%E7%94%A8%E3%81%A7%E3%81%8D%E3%82%8Bcuda%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E3%82%92%E6%8A%8A%E6%8F%A1) と [7.](https://zenn.dev/yumizz/articles/627d4e4821c636#7.-pytorch%E3%81%A8cuda%E3%81%8C%E4%BD%BF%E3%81%88%E3%82%8Bdocker%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E8%B5%B7%E5%8B%95) でとても分かりやすく説明されています。
　自分の場合は RTX 4060 Ti なので Micro-architecture は「Ada Lovelace」、Compute capability は「8.9」であり、使用可能な CUDA SDK バージョンは「11.8」か「12.0 – 12.5」です。
　よって、上の記事内で紹介されている [PyTorch 公式の Docker Hub](https://hub.docker.com/r/pytorch/pytorch/tags) から CUDA SDK のバージョンが合うタグを探して、自分は`docker run -it --gpus all pytorch/pytorch:2.3.1-cuda12.1-cudnn8-runtime`を実行しました。

:::note info
イメージのサイズが大きく、Pull にはある程度時間がかかります。自分の場合は Pull 中にダウンロードが止まったように見えましたが、描画が遅かっただけらしくエンターキーを連打したら完了の表示が出ました。
:::

　`True`の表示と、コンテナ内でも`nvidia-smi`コマンドが実行できることを確認出来たら、最後はデバッグ実行の準備です（なお、コンテナ内からは`exit`コマンドで抜けることができます）。
```powershell
root@7fc3b6e7d197:/workspace# nvidia-smi
Sat Aug  3 08:55:15 2024
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 560.27                 Driver Version: 560.70         CUDA Version: 12.6     |
|-----------------------------------------+------------------------+----------------------+
（以下略）
```

# 6. VS Code のインストール
　WSL 内のファイルの編集とデバッグ実行を簡単に行うために、公式ドキュメント「[WSL で VS Code の使用を開始する](https://learn.microsoft.com/ja-jp/windows/wsl/tutorials/wsl-vscode#install-vs-code-and-the-wsl-extension)」に沿って、VS Code とその拡張機能（Remote Development 拡張機能パック）をインストールしていきます。こちらについても、公式ドキュメントに従っていけば特に戸惑うところはなかったと思います。

# 7. コードのデバッグ実行
　任意の GPU を使用する Python コードをデバッグ実行できるようにイメージを作っていきます。
　まず、VS Code を起動して左のメニューから「リモートエクスプローラー」をクリックします。そして、インストールした Linux のディストリビューションの右にある「新しいウィンドウで接続する」をクリックすると、VS Code 上から WSL 内のファイルの編集が可能になります。
![スクリーンショット 2024-08-03 183748.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987065/d0137b35-b4d4-d177-c2e8-9c9adc11fde6.png)
　この状態で、イメージ作成のために Dockerfile と docker-compose.yml を記述していきます。自分の例では、ひとまず以下のようなディレクトリ構成・内容にしました。app.py は GPU を使用する任意のコードです（機械学習モデルの訓練用コードなど）。
```:ディレクトリ構成
<home directory>/
└── prog_wsl/
    └── rep/
        ├── work/
        │   ├── Dockerfile
        │   └── app.py
        └── docker-compose.yml
```
```Dockerfile:Dockerfile
FROM pytorch/pytorch:2.3.1-cuda12.1-cudnn8-runtime

WORKDIR /docker_work

RUN pip install --upgrade pip
RUN pip install pandas # インストールするパッケージは app.py に合わせて変えてください
RUN pip install scikit-learn

CMD ["/bin/bash"]
```
```yaml:docker-compose.yml
version: '3'

services:
  python:
    build: ./work
    container_name: PYTHON
    tty: true
    stdin_open: true
    volumes:
      - ./work:/docker_work
    deploy: # Compose で GPU を使う方法については、 https://docs.docker.jp/compose/gpu-support.html#gpu を参考にしました
      resources:
        reservations:
          devices:
            - capabilities: [gpu]
```

　Dockerfile と docker-compose.yml を記述できたら、VS Code の画面下のターミナルから rep ディレクトリに移動して`docker compose build`を実行し、イメージをビルドします。ビルドが終わったら、`docker compose up`を実行し、コンテナを起動します。
　コンテナが起動したら、今度は「リモートエクスプローラー」の起動したコンテナの右にある「新しいウィンドウでアタッチする」をクリックすると、VS Code 上からコンテナ内のファイルの編集やコードの実行が可能になります。![スクリーンショット 2024-08-03 191546.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987065/09a753ad-acef-05e4-6eb8-812fe8184827.png)
　後は、通常通り launch.json の設定をして、app.py 内にブレークポイントを設置することにより、デバッガを使用したステップ実行を行うことができます（デバッガの詳しい使い方については、例えば[こちら](https://net-newbie.com/2020/04/11/vscode-python-remote-debug/)など解説記事が既にたくさんあるので、ここでは省略します）。

:::note info
VS Code の左側のエクスプローラーに docker_work ディレクトリが表示されず app.py が開けない場合は、エクスプローラー上で右クリック→「ワークスペースにフォルダーを追加」から docker_work を選ぶことにより、エクスプローラーに docker_work ディレクトリを表示させることができます。![スクリーンショット 2024-08-03 193810.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987065/cba3a4d5-b4eb-61f9-2fb1-a6e466a23a39.png)
:::

説明は以上です。ここまで読んでくださり、ありがとうございました。



[^1]: 具体的には、[これ](https://www.pc-koubou.jp/products/detail.php?product_id=1080729)のメモリを32GBにカスタマイズしたものを買いました