WSLとDockerを使ってWindowsでTensorflowとPytorchをCUDAを使える状態で共存させる
はじめまして、ふかふかです。
この記事はTCU-CTRL場外乱闘 Advent Calendar 2021 - Adventar15日の記事です。
ブログは初めてなので色々至らぬ点もあるかもしれませんが暖かい目でお願いします。
前回の記事はコットンさんです。
最近やってることについて書こうかと思ってましたが、環境構築で苦労したので備忘録も兼ねてやり方を記録しておきます。
いきさつ
普段の課題などでは手持ちのGeforceグラフィックボードを搭載したWindowsマシンでTensorflowを使っており、最近Pytorchを使う必要が出てきて環境構築の仕方を調べました。するとどうもGPU使用の前提となるCUDAのバージョンが競合しているようで、そのままでの両立は不可能なようでした。
ご覧の通り要求するCUDAのバージョンが一致していません。Windowsで複数のバージョンのCUDAを両立させる方法を調べてみましたが、複数インストールして都度環境変数を変更するとかいうミスと不具合を誘発しそうなやり方しか見つかりません。
方針
そもそも事の原因は複数のバージョンのCUDAのpassが同一ということにあるようです。
そこでDockerを使います。幸い最近のWindowsにはWSL(Windows subsystem for Linux)というものがあります。これがあればWindows上でDockerを動かし、そこからCUDAやそれを要求するソフトウェアを動かせます。
つまりどういうことかと言うと、Windows上でWSLでLinuxを動かし、Linux上でDockerを動かし、Docker ContainerでTensorflowやPytorchやその前提ソフトウェアを動かします(厳密には他のソフトウェアも関わったり、名前が正確じゃないですがイメージってことで)
この方法の難点は、動かせるのはLinux用のソフトウェアだけでWindows用のソフトウェアは対応しないという点です。TensorflowやPytorchは当然Linuxで動作しますが、Windowsのみのソフトウェアでは利用できません。じゃあ初めからLinux使えよとか言うな
WindowsコンテナというDockerでwindowsを動かす技術もありますが、そちらでCUDAを動かす方法というのは無さそうです。
準備
ここから本題です。
まず、今回実行した環境を示します。
- Windows 11 21H2 64bit
- i7-11700F
- Nvidia Geforce RTX 3080
OSについてはWin11を勧めます。後述しますが、WSLでGUIが簡単に使えるので便利です。Win10についても執筆時点(2021/12)でinsider preview版ではGUIに対応しているのでそのうち利用できるようになると思います。
また、今回は複数のCUDAの両立が問題なので、Nvidia GPUが必須です。と言うか、使用していない場合はそもそもこの記事の対象じゃないです。
加えて今回はVisual Studio Codeを使用します。簡単にコンテナに接続できるので便利です。
この記事ではDockerを使用しますが説明が面倒なので詳しい用語までは逐一説明しません。
WSLのインストール
まずはDockerを動かすWSLをインストールします。
wsl --install
上のガイドのようにPowerShellでインストールしてもよいですし、Microsoft Storeでディストリビューションを選んでインストールすることも可能です。
起動するとアカウントの作成を求められるので行いましょう。
WSL用CUDAドライバのインストール
次にWSL用のCUDAドライバーをインストールします。
developer.nvidia.comページ下部のGet CUDA Driver からダウンロードページに飛び、GeforceかQuadroの使用している方を選んでダウンロードします。
Visual Studio Codeのインストール
次にVSCode(Visual Studio Code)をインストールします。
azure.microsoft.comこちらも公式サイトでダウンロードしてもよいですし、wingetを使ってpowershellでインストールしてもいいです。
Docker Desktopのインストール
最後にDocker Desktopをインストールします。
インストール時にInstall required Windows components for WSL 2というオプションについて聞かれるのでチェックを入れます。(デフォルトで入っているはず。)
チェックを入れ忘れたとか既にインストールしている人はDocker DesktopのSettingから設定できます。
VScodeの設定
必要なソフトウェアのダウンロードが終わったので次はVSCodeの設定を行います。VScodeのRemote-Containersという拡張機能を使うことで、コンテナ内でVScodeを立ち上げてローカル環境のように開発を行うことができます。
拡張機能のインストールのためにVScodeを起動し拡張機能タブを開き、Remote Developmentをインストールします。
注意点として、コンテナ内でVScodeを使用する際VScodeの主体として稼働しているのは図のようにコンテナ内のVScodeサーバであることがあります。従って、Windows上のVScodeの拡張機能はUIをカスタマイズするタイプのものを除きコンテナ内のVScodeにインストールする必要があります。
この拡張機能はRemote-WSL,Remote-Containers,Remote-SSHの三つの拡張機能がセットになっています。
WSLの設定
続けて、WSLでもいくつか設定をしていきます。まず、VScodeでWSLに接続します。左下の緑色の><が重なった感じのボタンを押します。
ここでNew WSL Windowを選び、WSLに接続します。
すると新しくウィンドウが開き、左下の表示がWSL:OS名になっていることが確認できます。これでVScodeでWSL上のファイルにアクセスできます。
接続が確認できたら上のメニューからターミナルを選び、WSLのターミナルにアクセスします。別にVScodeでターミナルを開く必要性はないですが、ファイル編集が楽なのでこのまま続けます。
$ apt update
$ apt upgrade
$ apt install x11-xserver-utils
$ xhost local:
ターミナルを開いたら、x11-xserver-utilsをインストールします。apt updateやupgradeがまだならそちらもやっておきます。
このx11-xserver-utilsというのはLinuxでGUI表示に使われるX Window System関連のソフトで、これをインストールすることでマシンをxサーバとして利用できます。これによってDockerコンテナ上でGUIアプリが使えます。X Window SystemではGUIを使う側がサーバなのに注意してください。
また、この操作でGUIが使えるのはWSLgが利用できるWin11とWin10 insider previewのみです。執筆時点のWin10では対応していないので該当する方は別途Windows上にXサーバーアプリを用意するなどして対応してください。
そして末尾のxhost local:というのはX Windowのホストにlocalのアクセスを許可するという意味になります。あまりないシチュエーションかと思いますが、localからであれば全許可してしまうので多人数で使用するマシンの場合には注意してください。
最後にターミナルで
env
を実行し、その中からDISPLAY=の数値を確認しましょう。多分:0か0:0だと思います。
WSLの動作確認
ここからDockerの設定をする前に、一度WSLの動作確認をしてみましょう。まずLinuxがグラフィックボードを認識しているか確認するために
$ nvidia-smi
を実行します。
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 510.00 Driver Version: 510.06 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 On | N/A |
| 0% 45C P8 40W / 320W | 1023MiB / 10240MiB | N/A Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
いくつかWSLの仕様上表示されないパラメータがありますが、グラボを認識していることがわかります。
次にGUI表示を試します。
$ xeyes
を実行します。win11ならGUIが起動するはずです。
便利な時代になりましたね。
コンテナ設定
ではここから実際にコンテナを作成します。
まずWSLで作業用のディレクトリを作成します。この記事ではホームディレクトリ直下にProject1という名前で作成していきます。この作業用ディレクトリがDockerコンテナにマウントされます。
ホームディレクトリにいろいろモノがあって紛らわしい場合はVScodeの左上のファイルからフォルダーを開くを選んで作成したディレクトリに移動しましょう。
Project1/
└ .devcontainer/
├ Dockerfile
└ devcontainer.json
ディレクトリに移動したら、上の構成でフォルダとファイルを作成します。.devcontainerのドット'.'を忘れないように。
一ファイルづつ確認していきましょう。
まずはDockerfileです。最小構成はこんな感じです。
FROM nvcr.io/nvidia/pytorch:21.11-py3
# これはPytorchの場合
ENV TZ=Asia/Tokyo
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt update && apt install -y x11-apps python3-tk
RUN pip install matplotlib
Dockerイメージは、NVIDIA のコンテナカタログから選びます。
コンテナカタログにアクセスしてTensorflowやPytorch等の必要なコンテナを選び(紛らわしいのが多いので注意!)右上のPull Tagを押すと、クリップボードにコンテナ名がコピーされます。そのままDockerfileに貼り付けると余計なコマンドまでついてくるので貼り付けたときに削除します。
また、Tensorflowが使いたい場合はこのイメージの部分をTensorflow用のイメージに変更してください。
このDockerfileはイメージの指定とGUI表示に必要なソフトをダウンロードするだけなので、別に必要なソフトウェアのインストールやユーザー生成、設定などは適宜Dockerfileに追記するかコンテナにログインして行って下さい。
TZ云々の設定をしているのは、ビルド中にTZを聞かれてビルドが止まるのを防ぐためです。
次にdevcontainer.jsonを編集します。
{ "name": "TestProjectContainer", // コンテナ表示名 "dockerFile": "Dockerfile", //Dockerfileの指定 "workspaceMount": "source=${localWorkspaceFolder},target=/workspaces/Project1,type=bind,consistency=cached",// Workspaceとしてマウントするフォルダを指定 "workspaceFolder": "/workspaces/Project1", // Workspaceのフォルダを指定 "runArgs": ["--shm-size=1g" ,"--ulimit" ,"memlock=-1", "--ulimit","stack=67108864","--gpus","all","-it"],//その他引数を指定 "mounts": ["source=/tmp/.X11-unix/,target=/tmp/.X11-unix,type=bind"],//マウントするフォルダを指定 "containerEnv": {"DISPLAY":":0"}//変数の設定 }
このように設定します。基本的にはコメントの通りですが、最後の方はわかりにくいので説明します。"mounts"ではディレクトリをマウントすることでDockerホストのXサーバのソケットに接続します。
また、"containerEnv": {"DISPLAY":":0"}では先ほどメモしたWSLのDISPLAYの値を入力します。
それ以外にも使用する拡張機能などがあれば設定できます。詳しくは以下のリファレンスを参照して下さい。
実行
ここまで設定して、やっと準備が終わりました。
WSLを開いた時のように左下の緑のボタンを押し、開いたメニューからReopen Containerを選びましょう。ここまでの設定が間違っていなければ、イメージがビルドされてVScodeがコンテナにアクセスするはずです。(初回は時間がかかる)
また、原因不明の謎現象として、この時失敗してどうやってもビルドが通らなくなった時、Dockerfileを使用せずイメージ単体で一度コンテナを作成するとうまくいくようになります。
テスト
コンテナに接続できたら、GPU認識とGUIをテストしてみましょう。
まずはさっきも使ったnvidia-smiを実行してみましょう。
次にtorchのCUDA識別とgui機能を試します。
Pythonを起動し以下のコマンドを入力してみてください。
import torch
print(torch.__version__)
print(torch.cuda.is_available())#正しく認識していればTrue
さらにVScodeで適当なpythonファイルを作成し、以下のプログラムを実行してみましょう。
import numpy as np import matplotlib.pyplot as plt
x = np.arange(0, np.pi * 2, 0.1) y = np.sin(x) plt.plot(x, y) plt.show()
無事グラフが表示できたかと思います。
まとめ
このような方法でWindows上にDockerでグラフィックボードを用いた環境を実現できました。今回の例ではPytorchで構築しましたが、別ディレクトリに新たにdevcontainerを設定することで、容易にTensorflowの環境を用意できます。これでPytorchとTensorflowをwindows上に両立できるかと思います。
次回は
たちさんの記事です。よろしくお願いします。
参考サイト
CUDA on WSL :: CUDA Toolkit Documentation
Developing inside a Container using Visual Studio Code Remote Development
Dockerコンテナの中でGUIアプリケーションを起動させる | Unskilled?