はじめに
機械学習ライブラリで有名なものの一つにPyTorchがあります.それによって様々な機械学習アプリケーションがOSSとして開発されています.そのOSSを利用したりコミットしたりするためにはPyTorchを使うことが要求されますし,そもそもPyTorchを利用してアプリケーションを作り出したいということも考えられます.
その際,高速で学習を回すためにはGPUを積んだPCを用意して,汎用GPUとして利用したいわけですが,GPU周りの依存は大変な問題です.さらに厄介なのは,PyTorch自身もバージョンに応じて特定のCUDAバージョンを要求してくるということです.詳しくは以下の記事に譲ります.
ざっくりまとめると,物理的ハードウェアから順に,
- GPUアーキテクチャ/OS (厳密には同じ階層ではないが,CUDAから見た場合に同じ依存レベルなので一緒に並べる)
- NVIDIAドライバ
- CUDA
- cuDNN
- 言語(Python)
- ライブラリ(PyTorch)
- アプリケーション
というように依存しています.
ということは,下から順に依存関係を考えてインストールしていけばいいということになります.
まず物理的なGPUハードウェアに対してNVIDIAドライバが決めます.NVIDIAドライバに依存するCUDA,cuDNNも,NVIDIAドライバのバージョンを考慮してインストールするのが良いでしょう.
言語すなわちPython環境は,pyenvやcondaといった仮想化技術があるし,複数の言語をインストールするというのはよくやられる手法なので,CUDAやライブラリに応じてインストールして切り替えればよいです.
その上に必要なライブラリをインストールして(さらにこちらも仮想化して),その上にアプリケーションを構築すればよいです.
しかし,それで全てうまく行くのでしょうか.
先ほど述べたとおり,PyTorchも必要なCUDAのバージョンを指定してきます.したがって使いたいPyTorchのバージョンが決まっている場合には,CUDAのバージョンがNVIDIAドライバとPyTorchからのダブルバインド状態になります.自分でアプリケーションを作る場合でもPyTorchのバージョンは必要に応じてアップグレードしたいでしょうし,OSSのプロジェクトを再利用したい場合には,そのプロジェクトの中でPyTorchのバージョンが指定されているでしょう.
そうすると,PyTorchのバージョンとNVIDIAドライバの要件を同時に満たすCUDAのバージョンを選択する必要があります.(一度でも触ったことがある人はわかると思いますが)NVIDIA関係の依存関係は厄介なので1完全にアンインストールして再インストールして,といった手順の方が安心感はありますが,複数のCUDAバージョンを切り替えたいというニーズも生じてきます.
その下のNVIDIAドライバはどうでしょう.もしかしたら複数のドライバを切り替える手もあるのかもしれませんが,NVIDIAドライバはGPUを直接触るものですし,他のグラフィックス関係に影響を与えるものなので,容易に変更したくありません.下手をしたら,Nvidiaドライバ周りのせいでディスプレイが映らなくなってrecovery modeで復旧して…なんてことになりかねません(筆者も経験しました).
この辺りを突き詰めていくと,物理ハードウェアと最上位アプリケーションの間のソフトウェアでどのレイヤーまでを仮想化するか(それこそDockerとか)といった設計思想の話になるわけですが,やはり現状では,
- GPUアーキテクチャやOSに依存したNVIDIAドライバは固定
- NVIDIAドライバに依存するCUDA/cuDNNはよほどでない限り固定するが,PyTorchに応じて複数切り替え
- 言語(Python)環境はアプリケーションに応じて仮想化/切り替え
- 言語の上に乗るライブラリ(PyTorch)も仮想化/切り替え
といった具合になるでしょうか.
この記事では,まず初めにPyTorchのバージョンを考えずに下から順にNVIDIAドライバ,CUDA,cuDNN,PyTorchをインストールする方法をまとめた後,想定するケースとして
- CUDAのバージョンに対応するPyTorchがなかった場合→PyTorchをソースからビルドして対応させる
- PyTorchのバージョンに対応するCUDA/cuDNNが入っていなかった場合→複数CUDA/cuDNNをインストールして切り替える
の方法をまとめます.
Ubuntuへのnvidia関係のインストール
にしたがって行きます.
実行環境は以下の通りです.
UbuntuのOSやCPU, GPUの情報を確認するコマンドにしたがって確認します.
- PC: ThinkStation P620
- OS: Ubuntu 18.04
- kernel: 5.4.0-150-generic
- CPU: AMD Ryzen Threadripper PRO 3975WX 32-Cores (x86_64)
- GPU: Quadro RTX 4000 (ちゃんと見えない場合は,
sudo update-pciids
してから見る)
NVIDIAドライバ
既にドライバが入っている場合は,
$ sudo apt-get --purge remove nvidia-*
$ sudo apt-get --purge remove cuda-*
といった感じで消しましょう.
何もない状態で,以下のようにインストールします.
$ sudo apt update
$ sudo apt install ubuntu-drivers-common
$ ubuntu-drivers devices # recommendedなものを覚えておく
$ sudo apt install nvidia-driver-470 # recommendedな数字に
再起動してから(ディスプレイ関係が壊れていないことを確認すると良いでしょう.)
$ nvidia-smi
Wed Sep 13 22:36:48 2023
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 470.182.03 Driver Version: 470.182.03 CUDA Version: 11.4 |
|-------------------------------+----------------------+----------------------+
| 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 Quadro RTX 4000 Off | 00000000:61:00.0 On | N/A |
| 32% 60C P0 37W / 125W | 1524MiB / 7959MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| 0 N/A N/A 2221 G /usr/lib/xorg/Xorg 740MiB |
| 0 N/A N/A 2540 G /usr/bin/gnome-shell 86MiB |
| 0 N/A N/A 12735 G ...509484734731481859,262144 694MiB |
+-----------------------------------------------------------------------------+
こんな感じの表示になれば完了です.
ちなみにここで CUDA Version: 11.4
と出ているのは,インストールされているCUDAのバージョンではなくて,依存互換性のある最新バージョンを指しています.つまり,CUDAをインストールしていなくても出ます.
CUDA
nvidia-smi
で推奨バージョンが見れますが,念の為NVIDIA CUDA Toolkit Release Notesでも確認すると良いでしょう.例えばnvidia-driver-470に対してはCUDA 11.4が最高バージョンであることが確認できます.
となればCUDA 11.4をインストールしようと思うので,https://developer.nvidia.com/cuda-11-4-0-download-archive にアクセスします("cuda 11.4 install"とかでググれば出ます.)
この画像のようにOSや何やらを選択する画面が出るので選択して,その下に出るコマンドに従ってインストールします.
インストールできたらrebootして,~/.bashrc
に以下を追記したあとにsourceして
export PATH=/usr/local/cuda:/usr/local/cuda/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/cuda/lib64:$LD_LIBRARY_PATH
最後に以下で確認できれば完了です.
$ nvcc -V
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2021 NVIDIA Corporation
Built on Wed_Jun__2_19:15:15_PDT_2021
Cuda compilation tools, release 11.4, V11.4.48
Build cuda_11.4.r11.4/compiler.30033411_0
cuDNN
cuDNNとは、NVIDIAが提供するディープラーニングタスクの高速化と最適化を可能にした高性能なGPUアクセラレーションライブラリのことです。
公式のInstallation Guidaにしたがってインストールします.
-
Zlibをインストール
sudo apt-get install zlib1g
-
cuDNNをダウンロード
ArchiveからUbuntu18.04かつCUDAのバージョンと合わせてCUDA for 11.xを選択.(下の写真)
$ cd ~/Download
$ sudo dpkg -i cudnn-local-repo-ubuntu1804-8.9.4.25_1.0-1_amd64.deb
$ sudo cp /var/cudnn-local-repo-ubuntu1804-8.9.4.25/cudnn-local-F51359E2-keyring.gpg /usr/share/keyrings/
$ sudo apt update
その後”Install the runtime library.”に従って,バージョン名をそれぞれcuDNN,CUDAに揃えてインストールしようとしたら,以下のようなエラーになりました.
$ sudo apt install libcudnn8=8.9.4.25-1+cuda11.4
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Version '8.9.4.25-1+cuda11.4' for 'libcudnn8' was not found
なので,apt list
で見てみると,以下のバージョンが見つかったので,それをインストール(でいいのか?)
- 一応同じようなエラーを受けた報告もある
- あと,上記の公式Installation Guideの中の1.3.4.1. Ubuntu/Debian Network Installationでは "
${cuda_version} is cuda12.2 or cuda11.8"とかいてある
$ sudo apt list -a libcudnn8
Listing... Done
libcudnn8/unknown 8.9.4.25-1+cuda11.8 amd64
$ sudo apt install libcudnn8=8.9.4.25-1+cuda11.8
$ sudo apt install libcudnn8-dev=8.9.4.25-1+cuda11.8
$ sudo apt install libcudnn8-samples=8.9.4.25-1+cuda11.8
下のコマンドでインストールを確認して,
$ dpkg -l | grep cudnn -i
ii cudnn-local-repo-ubuntu1804-8.9.4.25 1.0-1 amd64 cudnn-local repository configuration files
ii libcudnn8 8.9.4.25-1+cuda11.8 amd64 cuDNN runtime libraries
ii libcudnn8-dev 8.9.4.25-1+cuda11.8 amd64 cuDNN development libraries and headers
ii libcudnn8-samples 8.9.4.25-1+cuda11.8 amd64 cuDNN samples
最後1.4. Verifying the Install on LinuxとしてTest passed!
と出れば大丈夫そうです.
一応rebootしておきましょう.
PyTorchのインストール
先も話したとおり,PyTorchのどのバージョンをインストールするかを決めなくてはいけません.
今回はCUDA, cuDNNを先に決めていることを想定しているので,それに従って適切に選択しなくてはいけません.
公式サイトのトップページには最新のものがあるので,INSTALLING PREVIOUS VERSIONS OF PYTORCHなども見て決めます.
今回は,CUDA11.4なのでそれに対応したバージョンは…って考えると,あれ?CUDA11.4はサポートされていません.念の為pip
の--index-url
オプション2で指定されているURL(https://download.pytorch.org/whl/torch_stable.html) を見に行ってもCUDA11.4に対応するPyTorchのバージョンはありません.(ちなみに,頭についているcu113
のような数字はCUDA11.3に対応することを示しています.)
なので,今回はうまくやる必要がありそうです.
Pythonの仮想環境
PyTorchはもちろんPythonのバージョンも特定のものを要求します.
例えば3.7系のlatestである3.7.17にしておきます.ちなみにpip環境も後で取り返しのつくように仮想環境にしておきます.
個人的には,pyenv+venvをよく使っていますが,最近はRustベースのRyeってのもあるらしいです.
$ pyenv local 3.7.17
$ python --version
Python 3.7.17
$ python -m venv .venv
$ source .venv/bin/activate
(.venv) $ pip install --upgrade pip setuptools wheel
PyTorchのpipインストール
最新バージョンのインストール
回りくどいですが,試しに最新バージョンをインストールして挙動を確かめてみましょう.
公式トップページに従って,最新バージョンをインストールしてみます.
$ pip3 install torch torchvision torchaudio
このページによるとPython3.7系がサポートされているのはPyTorch1.13までなので,PyTorch1.13.1が入りました.3 (Python3.8系で仮想環境を作った場合はPyTorch2.0.1が入ります)
ここで,以下のようにPythonでtorchを使おうとするとエラーが出ます.
$ nvcc -V
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2021 NVIDIA Corporation
Built on Wed_Jun__2_19:15:15_PDT_2021
Cuda compilation tools, release 11.4, V11.4.48
Build cuda_11.4.r11.4/compiler.30033411_0
$ pip list | grep torch
torch 1.13.1
torchvision 0.14.1
$ python --version
Python 3.7.17
$ python
>>> import torch
(略) symbol cublasLtGetStatusString version libcublasLt.so.11 not defined in file libcublasLt.so.11 with link time reference
これは,CUDAのバージョンが異なるからこそ起こるエラーです(このIssueでも回答されてますね)
想定どおりですね.やはりCUDAのバージョンをちゃんと合わせてインストールする必要があります.
解決策
1. PyTorchをソースからビルドして対応させる
今回,CUDA11.4に対応するPyTorchのバイナリファイルが公開されていないことが問題でした.この場合,ソースからビルドすれば対応できます.
これは,既に入っているCUDAのバージョンを固定したまま,PyTorch側を頑張って合わせたいというケースです.
この記事のようにして,PyTorchをpipで入れずにソースビルドすればいいらしいです.
1-α バージョンが違っても対応できることがある
このコメントによると,
There's no plans to publish binaries for CUDA 11.4 since CUDA 11.3 binaries have been shown to work with CUDA 11.4
とあって,CUDA11.3用のPyTorchを使えば,CUDA11.4でも動くらしいです.だからCUDA11.4用のバイナリはリリースされていなかったらしいです.(この規則に従えば,CUDAバージョンが見つからなければその前にあるやつを使えばいい?)
したがって,INSTALLING PREVIOUS VERSIONS OF PYTORCHをみて,CUDA11.3に対応するうちの最新のであるv1.12.1をインストールします.
$ pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu113
2. 複数CUDA/cuDNNをインストールして切り替える
もう一つの解決策は,既に入っているのとは別のCUDA/cuDNNを入れて,それを使えるようにすることです.アプリケーションによって使いたいPyTorchのバージョンが決まっている場合などはこの方法が有効です.
既に入っているものをアンインストールしてから入れ直せば安心ですが,そのCUDAのバージョンを別のアプリケーションで使いたい場合は,アンインストールしたくありません.
そこで,update-alternatives
を使って,複数のCUDAを切り替えられるようにします.
CUDA
とりあえず現状を見てみましょう.
$ sudo update-alternatives --config cuda
There is only one alternative in link group cuda (providing /usr/local/cuda): /usr/local/cuda-11.4
Nothing to configure.
update-alternatives
内部のシンボリックリンク機構を見てみると,以下のようになっていて,最初に入れたCUDA11.4が指定されていることも確認できます.
$ ls -l /usr/local/cuda
lrwxrwxrwx 1 root root 22 9月 13 19:29 /usr/local/cuda -> /etc/alternatives/cuda
$ ls -l /etc/alternatives/cuda
lrwxrwxrwx 1 root root 20 9月 13 19:29 /etc/alternatives/cuda -> /usr/local/cuda-11.4
ここで,上のCUDAインストール手順を繰り返し,CUDA11.3をインストールします.(最後CUDAをapt install
するときにsudo apt install cuda-11-3
のようにバージョンまで指定しないと入りませんでした)
このあと,もう一度見てみると,このように複数のCUDAがインストールされていることがわかります.
$ sudo update-alternatives --config cuda
There are 2 choices for the alternative cuda (providing /usr/local/cuda).
Selection Path Priority Status
------------------------------------------------------------
* 0 /usr/local/cuda-11.4 114 auto mode
1 /usr/local/cuda-11.3 113 manual mode
2 /usr/local/cuda-11.4 114 manual mode
Press <enter> to keep the current choice[*], or type selection number: 1
ここで11.3を選んだのちに以下を見ると,切り替わっていることがわかります.
$ nvcc -V
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2021 NVIDIA Corporation
Built on Mon_May__3_19:15:13_PDT_2021
Cuda compilation tools, release 11.3, V11.3.109
Build cuda_11.3.r11.3/compiler.29920130_0
cuDNN
インストールのときを振り返ればわかりますが,cuDNNはCUDA11.xのようにCUDAのメジャーバージョンにしか依存していなかったので,今回のようにCUDA11.4と11.3を切り替えるような場合は必要ありません.
ちなみに公式1.5. Upgrading from cuDNN 7.x.x to cuDNN 8.x.xの,
Since version 8 can coexist with previous versions of cuDNN, if the user has an older version of cuDNN such as v6 or v7, installing version 8 will not automatically delete an older revision. Therefore, if the user wants the latest version, install cuDNN version 8 by following the installation steps.
を信じると,cuDNN7と8などのメジャーバージョン違う場合も複数の使い分けができるらしいです.
一応,cuDNN12.xのインストールも行ってみて,切り替えられるか試してみましょう.
上記のインストール手順を再度行って,cuDNNv8.9.3 for CUDA12.xを入れてみます.
すると,以下のようになります.
cuDNNの設定ファイルのリポジトリは複数存在しますが,aptで入れるライブラリの方は上書きされてしまって共存できていないことがわかります.
$ dpkg -l | grep cudnn -i
ii cudnn-local-repo-ubuntu1804-8.9.3.28 1.0-1 amd64 cudnn-local repository configuration files
ii cudnn-local-repo-ubuntu1804-8.9.4.25 1.0-1 amd64 cudnn-local repository configuration files
ii libcudnn8 8.9.3.28-1+cuda12.1 amd64 cuDNN runtime libraries
ii libcudnn8-dev 8.9.3.28-1+cuda12.1 amd64 cuDNN development libraries and headers
ii libcudnn8-samples 8.9.3.28-1+cuda12.1 amd64 cuDNN samples
update-alternatives
で見てみても,以下のようにcudnn_v8.h
のようなメジャーバージョンでの単位しかなく,切り替えられません.
$ sudo update-alternatives --config libcudnn
There is 1 choice for the alternative libcudnn (providing /usr/include/cudnn.h).
Selection Path Priority Status
------------------------------------------------------------
0 /usr/include/x86_64-linux-gnu/cudnn_v8.h 80 auto mode
* 1 /usr/include/x86_64-linux-gnu/cudnn_v8.h 80 manual mode
Press <enter> to keep the current choice[*], or type selection number:
$ ls -l /etc/alternatives/libcudnn
lrwxrwxrwx 1 root root 40 9月 13 23:44 /etc/alternatives/libcudnn -> /usr/include/x86_64-linux-gnu/cudnn_v8.h
cuDNNは,メジャーバージョンの切り替えはできるが,マイナーバージョンの切り替えはできないので,基本的にはアンインストール&再インストールすると考えておくとよいでしょう.
PyTorchでCUDA/cuDNNの確認方法
ここまで解決策を紹介しましたが,それぞれの場合でこの記事(PyTorchでGPU情報を確認(使用可能か、デバイス数など)などを参考に,以下のように確認できればよいです.4
(ちなみにこれは,「2. 複数CUDA/cuDNNをインストールして切り替える」の結果の出力です.)
$ python
Python 3.7.17 (default, Sep 13 2023, 17:45:56)
>>> import torch
>>> print(torch.__version__)
1.12.1+cu113
>>> print(torch.cuda.is_available())
True
>>> print(torch.version.cuda)
11.3
>>> print(torch.cuda.device_count())
1
>>> print(torch.cuda.get_device_capability())
(7, 5)
>>> print(torch.cuda.get_device_name())
Quadro RTX 4000
>>> print(torch.backends.cudnn.is_available())
True
>>> print(torch.backends.cudnn.version())
8302
-
LinusがFワードで怒っている動画はあまりにも有名です https://gigazine.net/news/20120618-linus-nvidia-f-word/ ↩
-
pipはそのPython環境に付随して個別に存在するので(例えば今回のように仮想環境をactivateしていれば
.venv/bin/pip
が使われる),pip自身は自身のPythonバージョンを知っている.その上で,PyTorchがPyPIにPython3.7系として公開しているもので最新のものを取りに行く.もちろんpipはCUDAのバージョンなんか見ません.pipの依存関係についてはこの記事も詳しいです. ↩ -
厳密にここで出るCUDAやcuDNNのバージョンは,torchライブラリの中の静的な情報っぽい(例えば,
update-alternatives
でCUDAのバージョンを切り替えても,torch.version.cuda
で出力される値は変わらなかった.つまり,OSに存在するバージョンを動的に取得しているわけではなさそう).したがって,PyTorchが想定するCUDAのバージョンとOSに実際にインストールされているバージョンが若干異なっていることはあり得るが,とりあえずこの辺りのコマンドが正常に動けば,依存関係は解決できていると考えることができるだろう. ↩