Note to Self by notekunst

ただの備忘録です

古いGPUのためのPyTorchのビルド(Ubuntu 20.04 on MacBookPro 15" Late2013)

通常は、PyTorchの下記ページで得られるコマンドの実行によって、PyTorchをインストールできます。
https://pytorch.org/
しかし、この方法でインストールされるPyTorchは、3.5よりも小さい"Compute Capability"をサポートしていません。"GeForce GT 750M"の"Compute Capability"は"3.0"なので、これはサポート対象外です。仮にこのPyTorchを用いる場合、"torch.cuda.is_available()"の結果は"True"ですが、GPUを使う処理で、以下のように"カーネルが無い"というエラーが発生します。

RuntimeError: CUDA error: no kernel image is available for execution on the device

ネットで調べた情報によると、PyTorchをソースコードからビルドすれば、古いGPU用のカーネルをビルドできるそうです。そこで、PyTorchをソースコードからビルドします。
私はcondaでpythonの環境を切り替えています。今回は、condaでPyTorch用の環境を作成し、その環境下でPyTorchをビルドしました。

ツールのインストール

condaでPyTorch用の環境を有効化し、ツールをインストールします(XXXXXは予め作成しておいた環境の名前を示します)。最初の2つはconda上で見つからなかったので、普通にインストールしました。

$ sudo apt install libgoogle-glog-dev
$ sudo apt install libgflags-dev
$ conda activate XXXXX
$ conda install pyyaml
$ conda install numpy
$ conda install ninja
$ conda install cmake
$ conda install glog

PyTorchのインストール

PyTorchのリポジトリを取得します。

$ git clone --recursive http://github.com/pytorch/pytorch
$ cd pytorch

以下のように、環境変数を設定します。TORCH_CUDA_ARCH_LISTに"GeForce GT 750M"の"Compute Capability"である"3.0"を設定します。

$ export USE_CUDA=1 USE_CUDNN=1 TORCH_CUDA_ARCH_LIST="3.0"

PyTorchのビルド・インストールを行います。

$ python setup.py install

これで、PyTorchのインストールは完了です。

PyTorchのテスト

pythonを起動してPyTorchを試してみます。

$ python
Python 3.8.3 (default, Jul  2 2020, 16:21:59) 
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import torch
>>> torch.cuda.is_available()
True
>>> torch.cuda.device(0)
<torch.cuda.device object at 0x7f00bddc3a90>
>>> torch.cuda.get_device_name(0)
/...(一部省略).../torch/cuda/__init__.py:102: UserWarning: 
    Found GPU0 GeForce GT 750M which is of cudacapability 3.0.
    PyTorch no longer supports this GPU because it is too old.
    The minimum cuda capability that we support is 3.5.
    
  warnings.warn(old_gpu_warn % (d, name, major, capability[1]))
'GeForce GT 750M'

"GPUが古い"という警告が表示されます。GPUが古いことは分かっているので、警告にある"__init__.py"を、警告を表示しないように編集してもよいと思います。

計算を実行する前に、python上でGPUメモリの使用状況を見てみます。

>>> print('Total:    ', round(torch.cuda.get_device_properties(0).total_memory/(1024**2),1), 'MB')
Total:     1999.7 MB
>>> print('Allocated:', round(torch.cuda.memory_allocated(0)/(1024**2),1), 'MB')
Allocated: 0.0 MB
>>> print('Cached:   ', round(torch.cuda.memory_reserved(0)/(1024**2),1), 'MB') 
Cached:    0.0 MB

python上では、GPUメモリのキャッシュはゼロです。別のターミナルで"nvidia-smi"を実行してみます。

$ nvidia-smi 
...
|===============================+======================+======================|
|   0  GeForce GT 750M     On   | 00000000:01:00.0 N/A |                  N/A |
| N/A   60C    P0    N/A /  N/A |    271MiB /  1999MiB |     N/A      Default |
+-------------------------------+----------------------+----------------------+

GPUメモリの使用量は、それほど多くはありません。
次に、起動済のpython上で、GPU上に大きなテンソルa,bを生成し、メモリ使用状況を確認してみます。

>>> a = torch.rand(11000,11000,device="cuda:0")
>>> b = torch.rand(11000,11000,device="cuda:0")
>>> print('Allocated:', round(torch.cuda.memory_allocated(0)/(1024**2),1), 'MB')
Allocated: 924.0 MB
>>> print('Cached:   ', round(torch.cuda.memory_reserved(0)/(1024**2),1), 'MB')
Cached:    924.0 MB

GPUメモリのうち924.0 MBが、python用にキャッシュされています。別のターミナル上で"nvidia-smi"を実行してみます。

$ nvidia-smi
...
|===============================+======================+======================|
|   0  GeForce GT 750M     On   | 00000000:01:00.0 N/A |                  N/A |
| N/A   55C    P0    N/A /  N/A |   1378MiB /  1999MiB |     N/A      Default |
+-------------------------------+----------------------+----------------------+

GPUメモリの使用量が増大しています。
起動済のpython上でテンソルa,bの積を計算し、メモリ使用状況を確認してみます。

>>> c = torch.mm(a,b)
>>> print('Allocated:', round(torch.cuda.memory_allocated(0)/(1024**2),1), 'MB')
Allocated: 1386.0 MB
>>> print('Cached:   ', round(torch.cuda.memory_reserved(0)/(1024**2),1), 'MB')
Cached:    1386.0 MB

テンソルの計算は、数秒で終わります(速い?)。また、演算によりキャッシュが増大しています。別のターミナル上で"nvidia-smi"を実行してみます。

$ nvidia-smi
...
|===============================+======================+======================|
|   0  GeForce GT 750M     On   | 00000000:01:00.0 N/A |                  N/A |
| N/A   60C    P0    N/A /  N/A |   1866MiB /  1999MiB |     N/A      Default |
+-------------------------------+----------------------+----------------------+

GPUメモリのほぼ全てが使用されています。pythonを終了すると、GPUメモリは解放されます。

$ nvidia-smi
...
|===============================+======================+======================|
|   0  GeForce GT 750M     On   | 00000000:01:00.0 N/A |                  N/A |
| N/A   61C    P0    N/A /  N/A |    269MiB /  1999MiB |     N/A      Default |
+-------------------------------+----------------------+----------------------+

このように、PyTorchは、GPUを用いて動作できました。

なお、PyTorchには、テスト用のスクリプトもあります。以下のコマンドにより、複数のテストコードが順次に実行されます。

$ python test/run_test.py

MacBookPro (15" Late2013) で実行したところ、複数のテストをパスしましたが、GPUメモリ不足のエラーが生じるテストもありました。

別の記事で"torchvision"のインストールの話を書く予定です。