Windows11にGPU機械学習環境を構築した

# 構築した環境の概要

## 使用ソフトウェアとバージョン
まず、環境構築に使用したソフトウェアとそのバージョンを示します。

- Windows11
- WSL2
- NVIDIA Driver - v510.06
- Docker Desktop for Windows - v4.3.2

## 構築した環境の概要図
今回構築した環境は、[こちら](https://www.idnet.co.jp/column/page_158.html)を参考にしています。
概要図がわかりやすかったので以下に記載します。

![環境概要図](https://www.idnet.co.jp/uploads/media/2021/03/20210302141045.png)
参考: https://www.idnet.co.jp/column/page_158.html

Windows上で、Docker DesktopのバックエンドをWSL2で動作させ、その上にDockerコンテナを作成します。
図ではWindows10となっていますが、私の環境は```Windows11```です


# 環境構築手順

## 1.NVIDIA Driverのインストール
WSL2からGPUを利用するためには、WindowsにNVIDIA Driverをインストールする必要があります。
[こちら](https://developer.nvidia.com/cuda/wsl)から```GEFORCE DRIVER```を選択し、ドライバーをインストールします。
(現時点では、v510.06がインストールされました。)

## 2. WSL2の有効化
**コントロールパネル->プログラム->Windowsの機能の有効化または無効化**から、Linux用Windowsサブシステムにチェックを入れ、再起動します。

(私の環境では、.NET Framework 4.8 Advanced Servicesの中の```ASP .NET 4.8```にもチェックを入れないとWSLが有効化できなかったです。)

WSLにUbuntu20.04をインストールします。

```sh:Ubuntu20.04のインストール
wsl --install -d Ubuntu-20.04
```

## 3. Docker Desktop for Windowsのインストール
[こちら](https://docs.docker.com/desktop/windows/install/)から、Docker Desktopの最新版(v4.3.2)をインストールします。
その際、```Install required Windows components for WSL 2```のオプションにチェックを入れ、インストールを進めます。
このオプションにより、上記の概要図の構成になります。

# GPUが認識されているかチェック
nvidiaが公開しているDockerイメージを使って、GPUが認識されているか確認します。

```sh:GPUの認識確認
docker run --rm -it --gpus all nvcr.io/nvidia/k8s/cuda-sample:nbody nbody -gpu -benchmark -numbodies=512000
```

GPUが認識されていると以下のような出力となります。
GPUの名前はお使いのものによって異なります。

![GPU](https://www.idnet.co.jp/uploads/media/2021/03/20210302140457.png)
参考: https://www.idnet.co.jp/column/page_158.html

認識されていれば環境構築は終了です。


# Python&Tensorflowの環境構築
今回は、TensorflowのCNNを使用して画像分類を行うためにGPU機械学習環境を構築しました。
そこで、Python&Tensorflowの環境構築についても触れておきます。

### 注意事項
以下の手順では、```docker-compose```を使用します。
docker-composeはV1とV2が存在しており、V2だとうまく動作しないです。
そのため、Docker Desktopの設定から```Use Docker Compose V2```のチェックを外しておきます。
または、以下のコマンドでV2を無効化します。

```sh:docker-compose-V2の無効化
docker-compose disable-v2
```

## 1. ベースコンテナの作成
まず、以下のようなdocker-composeファイルを作成し、ベースとなるDockerコンテナを動作させます。

```yml:docker-compose.yml
version: '3.9'
services:
  cuda:
    image: nvidia/cuda:11.3.0-devel-ubuntu20.04
    environment:
      - CUDNN_VERSION=8.2.0.53

    # リソースを拡張したい場合の指定（任意）
    shm_size: 4gb
    ulimits:
      memlock: -1
      stack: 67108864

    # GPUを有効にする（docker-compose 1.28.0以上で対応）
    deploy:
      resources:
        reservations:
          devices:
            - capabilities: [gpu]

    # 永続起動on
    tty: true

    # ローカルPCのフォルダをコンテナ上にマウントする
    volumes:
      - C:\Users\hoge\hoge:/home/
```

**docker-compose.ymlと同じディレクトリ上で**以下のコマンドを実行し、
コンテナを作成します。

```sh:
docker-compose up
```


## 2. コンテナ内の環境を構築
手順1で作成したコンテナに入り、必要なパッケージをインストールしていきます。

```sh:コンテナに入る
docker exec -it [コンテナID] /bin/bash
```

```sh:コンテナ内での作業
apt-get update && apt-get install -y --no-install-recommends \
    libcudnn8=$CUDNN_VERSION-1+cuda11.3 \
    libcudnn8-dev=$CUDNN_VERSION-1+cuda11.3 \
    && apt-mark hold libcudnn8 && \
    rm -rf /var/lib/apt/lists/*

apt update
apt install -y python3-pip && pip install --upgrade pip
pip install tensorflow
apt install -y libgl1-mesa-dev
```

## 3. コンテナの状態を保存
手順2では、コンテナに入り、コンテナ上に必要なパッケージをインストールしました。
しかし、Dockerコンテナは状態の保存がされないため、一度コンテナが停止するとインストールしたものが消えます。
そこで、コンテナの状態を保存(イメージとして書出)します。

```sh:コンテナの状態保存
docker commit [コンテナID] [保存イメージ名]
```

## 4. docker-compose.ymlの修正
このコマンドによって生成したイメージを使ってコンテナが起動されるように```docker-compose.yml```を修正します。

```yml:docker-compose.yml
version: '3.9'
services:
  cuda:
    # image: nvidia/cuda:11.3.0-devel-ubuntu20.04
    image: [保存イメージ名]
    environment:
      - CUDNN_VERSION=8.2.0.53

    # リソースを拡張したい場合の指定（任意）
    shm_size: 4gb
    ulimits:
      memlock: -1
      stack: 67108864

    # GPUを有効にする（docker-compose 1.28.0以上で対応）
    deploy:
      resources:
        reservations:
          devices:
            - capabilities: [gpu]

    # 永続起動on
    tty: true

    # ローカルPCのフォルダをコンテナ上にマウントする
    volumes:
      - C:\Users\hoge\hoge:/home/
```

docker-compose.ymlを修正後、```docker-compose up```を実行することで、手順2でインストールしたものがそのままの状態でコンテナが起動されます。


# 参考サイト
- [【エバンジェリスト・ボイス】Windows上のDockerでGPUを使おう \| インフォメーション・ディベロプメント](https://www.idnet.co.jp/column/page_158.html)
- [Docker Desktop for Windows + WSL2 で GPUありの機械学習環境を最速で作る - Qiita](https://qiita.com/masatatsu8/items/3eeb71f7d5c7feb87482)
- [OpenCVをPythonで動かそうとしてlibGL.soが無いって言われたけど解決した。 - Qiita](https://qiita.com/toshitanian/items/5da24c0c0bd473d514c8)