Azure VM でgpu pytorch環境を構築する 

# GPU環境構築

pytorchをgpu環境で使用するには以下のインストールが必要

- driver
- cuda
- cudnn
- pytorch


cuda, cudnnなど、バージョン依存が大きく、バージョンがあっていないと動いてくれないので
注意

## 想定環境　

マシン    : Standard_NC4as_T4_v3
OS       : Ubuntu 20.04 x64 Gen2
driver   :
cuda     : 11.6
cudnn    :  
pytorch  : 

## 初めに

### 使用しているGPUの確認

```bash
$ lspci | grep -i nvidia
```

Standard_NC4as_T4_v3での結果
```
0001:00:00.0 3D controller: NVIDIA Corporation TU104GL [Tesla T4] (rev a1)
```

```bash
$ dpkg -l | grep nvidia
$ dpkg -l | grep cuda
```

### 現状入っているCUDA nvidiaドライバの削除

他のバージョンがあったりすると、競合して変なインストールエラーが出る.
```bash 
$ sudo apt-get --purge remove nvidia-*
$ sudo apt-get --purge remove cuda-*
```

## driverのインストール

### インストールするdriverのバージョンを確認

```bash
$ sudo apt install ubuntu-drivers-common
$ sudo ubuntu-drivers devices
```

結果下記のような出力がされる.  `recommended`となっている`nvidia-driver-525 `をインストール. 
```
vendor   : NVIDIA Corporation
model    : TU104GL [Tesla T4]
driver   : nvidia-driver-470 - distro non-free
driver   : nvidia-driver-515 - distro non-free
driver   : nvidia-driver-525 - distro non-free recommended
driver   : nvidia-driver-515-server - distro non-free
driver   : nvidia-driver-450-server - distro non-free
driver   : nvidia-driver-470-server - distro non-free
driver   : nvidia-driver-510 - distro non-free
driver   : xserver-xorg-video-nouveau - distro free builtin
```


### driverのインストール

```bash
$ sudo add-apt-repository ppa:graphics-drivers/ppa
$ sudo apt update
$ sudo apt install nvidia-driver-525 
```
そこそこ時間かかるので待つ. 

### インストールできたら再起動
```
$ sudo reboot
```
再ログインして、

```
$ nvidia-smi
```

下記のような結果が出力
```
Sat Dec 17 03:48:17 2022       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 525.60.11    Driver Version: 525.60.11    CUDA Version: 12.0     |
|-------------------------------+----------------------+----------------------+
| 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  Tesla T4            Off  | 00000001:00:00.0 Off |                  Off |
| N/A   48C    P8    14W /  70W |     93MiB / 16384MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|    0   N/A  N/A       930      G   /usr/lib/xorg/Xorg                 82MiB |
|    0   N/A  N/A      1079      G   /usr/bin/gnome-shell                7MiB |
+-----------------------------------------------------------------------------+
```
ここで右上に出てくる`CUDA Version: 12.0`は実際のcudaのバージョンではないので注意. 


## cudaのインストール

[nvidiaのcuda toollitのページ](https://developer.nvidia.com/cuda-11-6-0-download-archive?target_os=Linux&target_arch=x86_64&Distribution=Ubuntu&target_version=20.04&target_type=deb_local)でcudaのバージョン、OS環境などを選択すると、インストールコマンドが表示される. 

私の場合は以下

![cudaインストール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1154503/81108a1b-cf38-9987-b528-2cae892045c5.png)

上記をもとに↓の手順でinstall.
(表示されているコマンドとほぼ同じだが、最後だけcuda-11-6を明示的に指定した.)

```bash
$ wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/cuda-ubuntu2004.pin
$ sudo mv cuda-ubuntu2004.pin /etc/apt/preferences.d/cuda-repository-pin-600
$ wget https://developer.download.nvidia.com/compute/cuda/11.6.0/local_installers/cuda-repo-ubuntu2004-11-6-local_11.6.0-510.39.01-1_amd64.deb
$ sudo dpkg -i cuda-repo-ubuntu2004-11-6-local_11.6.0-510.39.01-1_amd64.deb
```

上記を実行すると、標準出力の最後に、
```
To install the key, run this command:
sudo apt-key add /var/cuda-repo-ubuntu2004-11-6-local/7fa2af80.pub
```

と出てくるので、
```bash
$ sudo apt-key add /var/cuda-repo-ubuntu2004-11-6-local/7fa2af80.pub
```
を実行 

ここでまた、
```
sudo apt-get update
```

### cuda11.6をインストール

まず、aptでインストールできるcuda11を確認. 
```
$ sudo apt-cache search cuda-11
```

`cuda-11-6 - CUDA 11.6 meta-package`
が含まれていればOK

```
sudo apt-get -y install cuda-11-6
```

### nvccのパスを通す

~/.bashrcの末尾に以下を追加
```
export PATH="/usr/local/cuda/bin:$PATH"
export LD_LIBRARY_PATH="/usr/local/cuda/lib64:$LD_LIBRARY_PATH"
```

反映
```bash
$ source ~/.bashrc 
```



## cudnnのインストール

cudnnを使用するにはnvidiaからインストーラを持ってくる必要がある
[cudnnページ](https://developer.nvidia.com/cudnn)からdownload cudnnを選択し、ダウンロードページに進む. 
この時、nvidiaに登録する必要がある

登録すると上記ページから、cuda11に対応するcudnnのインストーラが表示される
![cudnn インストーラーダウンロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1154503/16209553-0169-6442-9908-c158e13b707d.png)

`Local Installer for Ubuntu20.04 x86_64 (Deb)`を選択.
今回は手動でローカルマシンにダウンロードしてscpでVMに送った.

VM上でダウンロードしたファイルがある状態で、(私の場合、`cudnn-local-repo-ubuntu2004-8.7.0.84_1.0-1_amd64.deb`がある場所で)

```bash
$ sudo dpkg -i cudnn-local-repo-ubuntu2004-8.7.0.84_1.0-1_amd64.deb 
```
を実行. 

実行すると、標準出力の最後に、
```
To install the key, run this command:
sudo cp /var/cudnn-local-repo-ubuntu2004-8.7.0.84/cudnn-local-A3837CDF-keyring.gpg /usr/share/keyrings/

```

と出てくるので上記を実行. 

```bash
$ sudo cp /var/cudnn-local-repo-ubuntu2004-8.7.0.84/cudnn-local-A3837CDF-keyring.gpg /usr/share/keyrings/
```

続いて、
```bash
$ cd /var/cudnn-local-repo-ubuntu2004-8.7.0.84/
$ sudo dpkg -i libcudnn8_8.7.0.84-1+cuda11.8_amd64.deb 
$ sudo dpkg -i libcudnn8-dev_8.7.0.84-1+cuda11.8_amd64.deb 
$ sudo dpkg -i libcudnn8-samples_8.7.0.84-1+cuda11.8_amd64.deb
```

上記のコマンドの順番は間違えるとエラーになる. 

### cudnn動作確認. 

nvidiaの[cudaデモページ](https://developer.nvidia.com/blog/easy-introduction-cuda-c-and-c/)で
以下のサンプルスクリプトをコピー. 

```hello.cu
#include <stdio.h>

__global__
void saxpy(int n, float a, float *x, float *y)
{
  int i = blockIdx.x*blockDim.x + threadIdx.x;
  if (i < n) y[i] = a*x[i] + y[i];
}

int main(void)
{
  int N = 1<<20;
  float *x, *y, *d_x, *d_y;
  x = (float*)malloc(N*sizeof(float));
  y = (float*)malloc(N*sizeof(float));

  cudaMalloc(&d_x, N*sizeof(float)); 
  cudaMalloc(&d_y, N*sizeof(float));

  for (int i = 0; i < N; i++) {
    x[i] = 1.0f;
    y[i] = 2.0f;
  }

  cudaMemcpy(d_x, x, N*sizeof(float), cudaMemcpyHostToDevice);
  cudaMemcpy(d_y, y, N*sizeof(float), cudaMemcpyHostToDevice);

  // Perform SAXPY on 1M elements
  saxpy<<<(N+255)/256, 256>>>(N, 2.0f, d_x, d_y);

  cudaMemcpy(y, d_y, N*sizeof(float), cudaMemcpyDeviceToHost);

  float maxError = 0.0f;
  for (int i = 0; i < N; i++)
    maxError = max(maxError, abs(y[i]-4.0f));
  printf("Max error: %f\n", maxError);

  cudaFree(d_x);
  cudaFree(d_y);
  free(x);
  free(y);
}
```

上記スクリプトをVMのどこかプログラムが実行できる場所で(手順通りやると現在/var/は以下にいるので/home/azureuser/配下など適切な場所に移動)

```bash
$ vi hello.cu
```
とかで.cuファイルにスクリプトをコピー

nvccでコンパイル&実行
```bash
nvcc hello.cu
./a.out 
```

下記のエラー分が出ればOK

```
Max error: 2.000000
```


## pytorchのインストール

### Minicondaインストール

python, pipが使用できる環境をVM上に用意する. 今回はminicondaを使用するがおそらくpyvenvでもanacondaでも問題ない. 

ubuntu上にminicondaを導入する方法は情報がいっぱいあるのでここでは説明は省くが、

```
$ wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
```
で公式のインストーラを落とせるのでこれを実行してパスとか通せば良い. 

condaコマンドが使用できるようになったら

```
$ conda create -n torch python=3.9.5 -y
```
とかでconda仮想環境を構築する 

仮想環境有効化
```
$ conda activate torch 
```

ターミナルが、
```
(torch) azureuser@gpu01:~$
```
のようになっていれば`torch`環境がactivateになっている

python確認

```
$ which python 
```

```
/home/azureuser/miniconda3/envs/torch/bin/python
```

### pytorch公式からインストールコマンドの入手. 
[pytorch公式](https://pytorch.org/get-started/locally/)のget start locallyから、自分の環境に合ったpytorchのインストールコマンドを取得する

下記に例を表示

![pytorch-pip-gpu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1154503/028730d1-b6ab-800e-6e04-c18405b43b37.png)

上記から下記コマンドでインストールできるとわかる(今回のconda環境において、pip3じゃなくてpipで良い)
```
$ pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu116
```

## pytorchでgpuの確認

上記の手順が完了した後、`sudo reboot`で再起動した後、再度conda仮想環境にはいり、pythonを実行する

```python
>>> import torch
>>> torch.cuda.is_available() # cuda使用可否確認
# True
>>> torch.cuda.device_count() # 使用できるGPUの数
1
```

pytorchでgpuが使用できた！


## その他注意事項

- 今回は記載時点でのpytorch stable(1.13)を導入する前提でバージョンを揃えたが、他のpytorchのバージョンを導入したい場合は、適合する
cuda, cudnnを選ぶ必要がある. 

- どのバージョンにするかは、[pytorchの以前のバージョン](https://pytorch.org/get-started/previous-versions/)のページをもとに、cudaのバージョンを特定し、それに適合するようにdriver, cudnnを選ぶ. 


- 途中でちょいちょい出てくる`sudo apt-get update`は忘れるとエラーになったりするので、エラーが出たら、一旦試してみると良いかも. 

- driverは最新のやつ入れとけば大体OKっぽい

### pytorch実行時にエラー

installはうまく行っても、pytorchでgpuを使用しようとした際に、
```
/home/azureuser/miniconda3/envs/torch/lib/python3.9/site-packages/torch/cuda/__init__.py:88: UserWarning: CUDA initialization: Unexpected error from cudaGetDeviceCount(). Did you run some cuda functions before calling NumCudaDevices() that might have already set an error? Error 803: system has unsupported display driver / cuda driver combination (Triggered internally at ../c10/cuda/CUDAFunctions.cpp:109.)
  return torch._C._cuda_getDeviceCount() > 0
False

```
にたいなエラーが出ることがある. 
上記はcuda, cudnnなどインストール直後なことが原因なので、
```
sudo reboot
```
で再起動すれば解決する.