ようやくゲームしながらUbuntuコンテナで機械学習もできる最高や!、と考え
WSL2にGPU入れようとしたら詰まって色々調べたのでまとめた。
大まかにCUDA公式のリファレンスに沿って既存の環境から構築しようとしてダメだった部分を載せていきます。
docker desktopとの共存は現時点(2020/07/16)では諦めた方が早いです。

前提となる環境

6月18日のアナウンス以降のwindows insider programでWSL2からGPUを叩けるようになった。

実際に使用するためには下記の環境が必要となる。

  • windows 10 : ビルド番号 20150.1000以降
  • WSL2: 4.19.121以降
  • cudaドライバ: 455.41_gameready_win10系列
  • docker(WSL上): 19.03以降

このうち、May 2020 Update以前のinsider programでWSL2+dockerが使える状態からGPU
を有効にしようとすると色々つまづいたので対処した内容も含めて導入部を書き綴っていくことにする。

windows側

インストーラーでガシガシインストールしていく。

windows10 20150以降のインストール

現状だと windows10 の 20150以降のバージョンは insider program をファスト(最近だとdevチャネル)に合わせてインストールする。
導入自体は直接躓くことは無かったことと分量が多くなるため、割愛する。

参考元:

Windows10 Insider Program で最新バージョンにアップデートする方法

windowsにCUDAドライバをインストールする

WSL2でCUDAドライバを利用するにはNVIDIA Drivers for CUDA on WSLを使用する必要がある。
NVIDIA Drivers for CUDA on WSLのページからexeファイルをダウンロードし実行する。
NVIDIA Developer Program に登録しておく必要があるので Nvidiaアカウントを作成・ログインしておく。
455.41_gameready_win10~が落ちてくるので必然的にCUDA11が入る。プレビュー版であるためドライバダウンロードページで検索できるドライバよりも大きいバージョンのものが落ちてくる。
インストール完了後におそらくPCの再起動を促されるので、そのまま再起動しよう。

windows側にドライバがインストールできれば、WSL2側にCUDAドライバを入れる必要はない

WSL2 Linuxカーネルの更新

WSL2のカーネルもinsiderで最新なもの(4.19.121以降)じゃないと対応してない。
少し前まで手動で「WSL 2 Linux カーネルの更新」から最新カーネルをインストールする必要があったのだが
最近だと、WSL2のカーネルのアップデートが「更新プログラムのチェック」での実行対象になったため、
「設定」->「更新とセキュリティ」->「詳細オプション」->「Windows の更新時に他の Microsoft 製品の更新プログラムを受け取る」オンすることで最新のカーネルをインストールできるようになった。

どこに存在するかが非常にわかりづらい

「更新プログラムのチェック」からのインストール完了した後は
プロンプト上でwsl --updateを実行すれば最新カーネルをインストールできる。

のだが、自分の環境だと更新直後にGSoDに直行し起動後にwslコマンドが実行できない状態になった。。
再度、「WSL 2 Linux カーネルの更新」からインストーラを実行し直すことで事なきを得ました。。

参考元:

WSL2が突然起動しなくなったときに参考にしてください

WSL2側

Ubuntu18.04を起動しCUIで操作していく。

WSL2上にdockerをインストール

今回の最大ハマりポイント。
今回のようにWSL2上でGPUを使いたい場合はWSL2上に一からdocker 19.03以降を導入する必要がある。
ここで注意する必要がある点としてdocker desktop on windowsのbackend を利用をしない ということである。

ハマった要因

自分が元々使っていた環境の場合だと、docker desktopと連携してWSL上でもdocker操作できるようにしていた。
公式の手順にもあるUse WSL 2 based engineの項目をチェックして
docker desktopのsettingの項目からResouce -> WSL integrateの項目を有効にして使用する方法だ。

しかしながら、docker desktopとの連携を切っておかないと衝突して、docker desktopが起動失敗->GSoD->windows強制再起動コンボが頻発する羽目になった。Insider Preview Build 20150初期マイナーバージョンだとGSoD後の自動再起動すらしない状態に。。

Docker Desktop WSL 2 backendの無効化

docker desktopの状態をWSL側と共有する必要が無い場合は、上記の公式の手順で有効にした項目を全て無効にし、WSL上でdockerに関するエイリアスなどを貼っているならこれも無効にする必要がある。
もしくはdocker desktopswitch to Windows Containeres...をクリックしてWSL側との連携を切ることもできる。

インストール

docker desktopとの連携が切れていることを確認できれば最新のdockerをWSL2にインストールする。
基本的にはdocker公式の手順通り。

docker_install
sudo apt-get install -y \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo apt-key fingerprint 0EBFCD88

sudo add-apt-repository \
    "deb [arch=amd64] https://download.docker.com/linux/ubuntu\
$(lsb_release -cs) \
stable"

sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io

sudo usermod -aG docker $USER
sudo mkdir /sys/fs/cgroup/systemd
sudo mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd

dockerをrestartさせても設定が反映されないことがある。
その場合はCUIを一度再起動してやる。

動作確認

無事インストールできたか下記コマンドで確認する。

sudo docker run hello-world

powershellを立ち上げてdesktop docker側にhello-worldイメージが存在していない事を確認できれば尚良し

wsl上のUbuntuに cuda toolkit を導入

win上にインストールしたCUDAを仮想的に使用するため、WSL2にはCUDAドライバをインストールする必要はないものの
WSL2上でもCUDAを使うためにcuda-toolkitを導入する必要がある。

折角windows側に最新のCUDA11が入っているのでこれに合わせる事とする。
そのためにはWSL2側でcuda-toolkitの最新版をインストールすればよい。

対話的な処理でもいいならrunファイルを実行し、cuda-toolkitの項目だけ選択してインストールするのが多分一番簡単。
ただ、個人的になるべくスクリプトファイルを叩いた後は操作したくないためaptでインストールできるようにしていく。

nvidiaのCUDAダウンロードサイトのスクリプト利用してインストールする。
肝はcudacuda-driverじゃなくて cuda-toolkit-11-0 を指定すること

install_cuda-toolkit
sudo apt-get --purge remove nvidia-*
sudo apt-get --purge remove cuda-*

wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-ubuntu1804.pin
sudo mv cuda-ubuntu1804.pin /etc/apt/preferences.d/cuda-repository-pin-600
sudo apt-key adv --fetch-keys http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub
sudo sh -c 'echo "deb http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64 /" > /etc/apt/sources.list.d/cuda.list'
sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt-get install -y cuda-toolkit-11-0

あとは使用しているシェルにPATHを追記して適用すればOK

add_PATH
echo "set -x PATH /usr/local/cuda-11.0/bin \$PATH" >> .config/fish/config.fish
echo "set -x LD_LIBRARY_PATH /usr/local/cuda-11.0/lib64 \$LD_LIBRARY_PATH" >> .config/fish/config.fish
source .config/fish/config.fish

動作確認

インストールが完了すれば/usr/local/cuda/にSample含め展開される。
下記のサンプルを実行してやれば、GPUデバイスが認識できるかどうかが確認できる。

BlackScholes
cd /usr/local/cuda/samples/4_Finance/BlackScholes
sudo make
./BlackScholes

nvidia-container-toolkit のインストール

nvidia dockerを動かすためにnvidia-container-toolkitを導入していく。

'Docker Desktop WSL 2 backend'経由だとGPUサポートされていないため、WSL2のlinux上でnvidia-container-toolkitnvidia-docker2を使用して使う必要がある。
将来的にnvidia-docker2が廃止される予定みたいなので今回はnvidia-container-toolkitをインストールする。

Nvidia-containerのQuickstartを元にしながら入れていく。

install_nvidia-container-toolkit
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
curl -s -L https://nvidia.github.io/libnvidia-container/experimental/$distribution/libnvidia-container-experimental.list | sudo tee /etc/apt/sources.list.d/libnvidia-container-experimental.list

sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
sudo service docker restart

WSL2ではそのままだとsystemdが使えないためsystemctlが使えない。Quickstartの最後の行はserviceコマンドに置き換えた。

参考元:

nvidiaのフォーラム
【WSL2】systemctlが動かない問題をきちんと解決する

動作確認

これで漸く、nvidia-dockerがWSL2でも実行できるようになったはずだ。
下記コマンドを実行して確認する

exec_nvidia-docker
docker run --gpus all nvcr.io/nvidia/k8s/cuda-sample:nbody nbody -gpu -benchmark

...

> Windowed mode
> Simulation data stored in video memory
> Single precision floating point simulation                                                                            > 1 Devices used for simulation
MapSMtoCores for SM 7.5 is undefined.  Default to use 64 Cores/SM
GPU Device 0: "GeForce RTX 2060 SUPER" with compute capability 7.5
> Compute 7.5 CUDA device: [GeForce RTX 2060 SUPER]
34816 bodies, total time for 10 iterations: 56.069 ms
= 216.188 billion interactions per second
= 4323.764 single-precision GFLOP/s at 20 flops per interaction

GPUが認識できたようだ。これでやっと機械学習ができる環境が整った訳である。

Compute 7.5 CUDA deviceってなんだ?と調べたところハードウェア側のバージョンを表示しているようだ。GeForce RTX 2060 SUPERはTuringアーキテクチャを採用しているので7.5となる。ソフトウェアのCUDAのバージョンかと思い焦ったのは内緒)
https://docs.nvidia.com/deploy/cuda-compatibility/index.html#support-title

docker実行時にエラーが出た場合

もし、上記コマンドを実行した際にエラーが出てdockerイメージを実行できない場合は

  1. docker desktopにイメージが作られていないか確認
    • 作られていれば連携している状態にあるので解除
  2. WSL2からGPUが認識できているか確認
    • cudaサンプルコードを再実行してみる
    • 認識できなければ再インストール
    • 認識できている場合はdocker desktopを使おうとしてないか確認
  3. docker のオプションとして--gpuが利用可能か確認する
    • dockerバージョンを確認する(19.03以前にはこのコマンドは存在しない)
    • /usr/bin/nvidia-container-toolkitが存在する確認

以上を確認する。

docker・nvidia-dockerのバージョンが古い

docker_run_log
docker: Error response from daemon: OCI runtime create failed: container_linux.go:348: starting container process caused
"process_linux.go:402: container init caused \"process_linux.go:385: running prestart hook 1 caused
...
...

エラーをざっくり解釈すると、指定したコマンドが間違っていたりした時に出るエラーのようで、
--gpusオプションが使えない、dockerバージョン(19.03以前)だったりnvidia-dockerを使って実行しようとした時に出る模様。
各々のバージョンをアップグレードしよう。
Upgrading with nvidia-docker2 (Deprecated)

GPUが認識できていない場合

WSL2
docker: Error response from daemon: linux runtime spec devices: could not select device driver "" with capabilities: [[gpu]].

docker実行時のコマンド自体は合っているが、GPUが見つからず落ちる場合。
サンプルを実行し直して認識できていなければ再インストールしよう。

ちなみに、nvidia-dockerがサポートされていないwindowsで直接実行しても似たようなエラーが得られる。

windows
docker: Error response from daemon: could not select device driver "" with capabilities: [[gpu]]

docker desktopをbackendとして使用している場合もこのエラーが出るため中々原因に気付けなかった。。
docker desktopとの連携が有効になっていないか確認しよう。

参考元:

NVIDIA Docker って今どうなってるの? (19.11版)
nvidia-dockerのwiki


今回の内容をgitでまとめました -> https://github.com/naka345/wsl2_gpu
やることが...やることが多い...!!