ローカル環境におけるGPUを活用したTensorflowの環境構築

# 環境構築の流れ
次のサイトを参考にして，各ソフトウェアのバージョンを確認しつつインストールする．

https://www.tensorflow.org/install/source?hl=ja#linux

今回は下記の表にある ```tensorflow-2.17.0``` を参考にして環境を整える．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2844961/b9c6001f-9f20-f880-11d2-295a0a571ca6.png)

今回の環境構築では主に次をインストールしていく．
- GPU ドライバ
- WSL
- CUDA
- cuDNN
- tensorflow

参考までに当方の環境を示す．



# GPU ドライバのインストール
ドライバをインストールする前に，次のサイトで GPU が CUDA に対応しているかを確認する．

https://developer.nvidia.com/cuda-gpus

次のサイトで GPU のドライバをインストールする．

https://www.nvidia.com/ja-jp/geforce/drivers/

次のコマンドでドライバがインストールされているか否かを確認できる。
```sh: ドライバの確認
> nvidia-smi
Sun Oct 20 04:48:40 2024
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 560.81                 Driver Version: 560.81         CUDA Version: 12.6     |
|-----------------------------------------+------------------------+----------------------+
| GPU  Name                  Driver-Model | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA GeForce RTX 3060      WDDM  |   00000000:01:00.0  On |                  N/A |
|  0%   40C    P0             45W /  170W |     377MiB /  12288MiB |      1%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+
|   1  NVIDIA GeForce RTX 3060      WDDM  |   00000000:02:00.0  On |                  N/A |
|  0%   36C    P8             16W /  170W |      33MiB /  12288MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

### 省略 ###
```


# WSL のインストール
別途、記事をまとめているので、そちらを参考にされたい。

https://qiita.com/skm_bnn/private/eb2f4b0c921303922630

なお、Ubunutu には Python が標準でインストールされている．

奇しくもこのバージョンは ```tensorflow-2.17.0``` に対応しているため，本記事ではWSL上に Python を新たにインストールすることはしない。

```sh: Python の確認
$ python3 --version
Python 3.12.3
```

念のために、WSL 上でも GPU ドライバが正常に動作しているかを ```nvidia-smi``` コマンドで確認する。
```sh: WSL 上でのドライバの確認
$ nvidia-smi
Sun Oct 20 04:48:34 2024
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 560.31.01              Driver Version: 560.81         CUDA Version: 12.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 RTX 3060        On  |   00000000:01:00.0  On |                  N/A |
|  0%   38C    P8             21W /  170W |     351MiB /  12288MiB |      4%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+
|   1  NVIDIA GeForce RTX 3060        On  |   00000000:02:00.0  On |                  N/A |
|  0%   36C    P8             16W /  170W |      33MiB /  12288MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+
### 省略 ###
```

# CUDA ツールキットのインストール
次のサイトから，バージョンを確認しつつ CUDA をインストールする．

https://developer.nvidia.com/cuda-toolkit-archive

本記事では ```CUDA Toolkit 12.3.0``` をインストールする．

https://developer.nvidia.com/cuda-12-3-0-download-archive?target_os=Linux&target_arch=x86_64&Distribution=WSL-Ubuntu&target_version=2.0&target_type=deb_local

上記のサイトで自身の環境にあうように各項目を選択し，サイト下部に記されたコマンドを実行する．

例として，当方の選択内容およびインストールのコマンドを示す．

|項目|選択内容|
|---|---|
|Operating System|Linux|
|Architecture|x86_64|
|Distribution|WSL-Ubuntu|
|Version|2.0|
|Installer Type|deb_local|

```sh: CUDA のインストールコマンド
wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-wsl-ubuntu.pin
sudo mv cuda-wsl-ubuntu.pin /etc/apt/preferences.d/cuda-repository-pin-600
wget https://developer.download.nvidia.com/compute/cuda/12.3.2/local_installers/cuda-repo-wsl-ubuntu-12-3-local_12.3.2-1_amd64.deb
sudo dpkg -i cuda-repo-wsl-ubuntu-12-3-local_12.3.2-1_amd64.deb
sudo cp /var/cuda-repo-wsl-ubuntu-12-3-local/cuda-*-keyring.gpg /usr/share/keyrings/
sudo apt-get update
sudo apt-get -y install cuda-toolkit-12-3
```

次のコマンドで，インストールした CUDA のバージョンを確認できる。

```sh
nvcc --version
```

## トラブルシューティング1: CUDA のインストールに失敗する
### エラー内容
当方では CUDA のインストールコマンドにある ```sudo apt-get -y install cuda-toolkit-12-3``` コマンドを実行すると，次が出力された．

```sh: CUDA をインストールするときのエラー
The following packages have unmet dependencies:
 nsight-systems-2023.3.3 : Depends: libtinfo5 but it is not installable
E: Unable to correct problems, you have held broken packages.
```

これは、```nsight-systems-2023.3.3``` パッケージをインストールする際に、その依存パッケージである ```libtinfo5``` のインストールに問題が発生したことを意味している。

### 解決方法
解決にあたり、下記のサイトが参考になった．

https://askubuntu.com/questions/1491254/installing-cuda-on-ubuntu-23-10-libt5info-not-installable

まずは、```/etc/apt/sources.list``` をテキストエディタで開く。これは、APT（Advanced Package Tool）が使用するパッケージリポジトリの設定ファイルである。この設定ファイルは、システムがどこからソフトウェアパッケージをダウンロードするかを指定する。

```sh: 設定ファイルを開く
sudo nano /etc/apt/sources.list
```

```/etc/apt/sources.list``` の最終行に下記の内容を追記する．これにより、 ```Ubuntu 23.04（Lunar Lobster）``` の ```universe``` リポジトリを参照することで、```libtinfo5``` をインストールできる。

```: /etc/apt/sources.list
deb http://archive.ubuntu.com/ubuntu/ lunar universe
```

参考までに nano エディタの操作方法を次に羅列する．
- ペースト: 右クリック
- 保存して終了する
    - ```Ctrl + X``` : Exitする
    - 「Save modified buffer?」と表示されるので ```Y``` (yes)を押す
    - Enterを押す


次のコマンドで更新内容の確認およびインストールをする．

```sh: 更新の確認とインストール
sudo apt update
sudo apt upgrade
```

## トラブルシューティング2: CUDA のバージョンが確認できない
### エラー内容
[トラブルシューティング1](#トラブルシューティング1-cuda-のインストールに失敗する) の解決後、当方ではさらに ```nvcc --version``` コマンドの実行にも失敗した。

```sh: CUDA のバージョン確認のエラー
$ nvcc --version
Command 'nvcc' not found, but can be installed with:
sudo apt install nvidia-cuda-toolkit
WSLのユーザ名@マシン名:/mnt/c/Users/Windowsのユーザ名$ cat /usr/local/cuda/version.txt
```

### 解決策1
次のコマンドを実行する
```sh: 
$ sudo apt install nvidia-cuda-toolkit
```

もう一度，```nvcc --version``` コマンドを実行すると，成功した．
```sh
$ nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2023 NVIDIA Corporation
Built on Fri_Jan__6_16:45:21_PST_2023
Cuda compilation tools, release 12.0, V12.0.140
Build cuda_12.0.r12.0/compiler.32267302_0
```


### 解決策2
nvcc (NVIDIA CUDA Compiler) のパスを通すことでコマンドが実行できるようになる。

まずは ```/usr/local``` ディレクトリに ```cuda```，```cuda-12.3``` フォルダが存在するかを確認する．

```sh: CUDA がインストールされているかの確認
$ ls /usr/local
bin  cuda  cuda-12  cuda-12.3  etc  games  include  lib  man  sbin  share  src
```

次のコマンドで nvcc のパスを確認する。
```sh: パスの確認
find /usr/local -name nvcc
```

上記のコマンド実行で出力されたディレクトリを環境変数に設定する。
```sh: 環境変数の設定
echo 'export PATH=出力されたディレクトリ/bin:$PATH' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH=出力されたディレクトリ/lib64:$LD_LIBRARY_PATH' >> ~/.bashrc
```

次のコマンドで、変更を反映する。
```sh: 設定の反映
source ~/.bashrc
```

参考として、以下に一連の操作の例を示す。

```sh: パスの設定例
$ # パスの確認
$ find /usr/local -name nvcc
/usr/local/cuda-12.3/bin/nvcc
$ # 環境変数の設定
$ echo 'export PATH=/usr/local/cuda-12.3/bin:$PATH' >> ~/.bashrc
$ echo 'export LD_LIBRARY_PATH=/usr/local/cuda-12.3/lib64:$LD_LIBRARY_PATH' >> ~/.bashrc
$ # 設定の反映
$ source ~/.bashrc
```

再度、```nvcc --version``` の実行に問題が無いかを確認する。次に実行例を示す。

```sh: 実行例
$ nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2023 NVIDIA Corporation
Built on Wed_Nov_22_10:17:15_PST_2023
Cuda compilation tools, release 12.3, V12.3.107
Build cuda_12.3.r12.3/compiler.33567101_0
```

# cuDNN のインストール
次のサイトから cuDNN をダウンロードする．

https://developer.nvidia.com/rdp/cudnn-archive

今回は ```tensorflow-2.17.0``` に対応している ```cuDNN v8.9.7 (December 5th, 2023), for CUDA 12.x > Local Installer for Ubuntu22.04 x86_64 (Deb)``` を選択する．この場合，```cudnn-local-repo-ubuntu2204-8.9.7.29_1.0-1_amd64.deb``` というパッケージファイルがダウンロードされる．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2844961/eccd46f0-4e0c-935e-2dfb-5004528e94ba.png)

次のコマンドで，さきほどダウンロードしたパッケージファイルから，cuDNN をインストールする．

```/mnt/c/Users/ユーザ名/Downloads/cudnn-local-repo-ubuntu2204-8.9.7.29_1.0-1_amd64.deb``` はご自身でダウンロードしたディレクトリおよびファイル名に変更されたい．

```sh: cuDNN のインストール
sudo dpkg -i /mnt/c/Users/ユーザ名/Downloads/cudnn-local-repo-ubuntu2204-8.9.7.29_1.0-1_amd64.deb
sudo cp /var/cudnn-local-repo-*/cudnn-local-*-keyring.gpg /usr/share/keyrings/
sudo apt update
sudo apt -y install libcudnn8 libcudnn8-dev libcudnn8-samples
```

次のコマンドでインストールした cuDNN のバージョンを確認できる．
```sh: cuDNN の確認
cat /usr/include/cudnn_version.h | grep CUDNN_MAJOR -A 2
```

次に実行例を示す。
```sh: 実行例
$ cat /usr/include/cudnn_version.h | grep CUDNN_MAJOR -A 2
#define CUDNN_MAJOR 8
#define CUDNN_MINOR 9
#define CUDNN_PATCHLEVEL 7
--
#define CUDNN_VERSION (CUDNN_MAJOR * 1000 + CUDNN_MINOR * 100 + CUDNN_PATCHLEVEL)

/* cannot use constexpr here since this is a C-only file */
```

# VSCodeの設定
拡張機能の WSL をインストールする．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2844961/11a5112c-4e6c-ddb7-96a0-aea0d1ab1889.png)


```Ctrl + Shift + P``` でコマンドパレットを開いて，「WSL: Open Folder in WSL...」を選択する．

VSCodeで開きたいディレクトリを選択する．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2844961/68eab85f-d4de-adb8-83f7-b417595d1bf0.png)


VSCodeが再起度する．画面左下に「WSL: Ubuntu」の記載があればよい．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2844961/8be5839c-249a-5cbf-2baa-340e44074ea2.png)

WSL ではなく Windows でプログラムを実行したい場合は，
```Ctrl + Shift + P``` でコマンドパレットを開いて，
「Remote-WSL: Close Remote Connection」を選択する．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2844961/076e6f6e-7316-bd4c-d8ed-7889e12ac48e.png)

# Tensorflow のインストール
以下のコマンドは WSL 下で実行されたい．

## 仮想環境の用意
Python の仮想環境を利用したい場合は，```python3.12-venv``` をインストールする．
これにより，Python ライブラリの汚染を防ぐことができる．

```sh: Python 仮想環境パッケージのインストール
sudo apt install python3.12-venv
```

次のコマンドで仮想環境の構築と有効化を実行する．
```sh: 仮想環境の構築と有効化
# .venv 仮想環境の構築
python3 -m venv .venv
# 仮想環境の有効化
. .venv/bin/activate
```

以降は2つ目のコマンドを実行するだけでよい．
```sh: 仮想環境の有効化
. .venv/bin/activate
```

なお，仮想環境を無効化したい場合は次を実行すればよい．
```sh: 仮想環境の無効化
deactivate
```

## インストール

次のコマンドで Tensorflow 2.17.0 をインストールする．
```sh
pip install tensorflow==2.17.0
```

# 動作確認
## プログラム
動作確認のために，Tensorflow から GPU に接続するプログラムを作成する．
```py: test.py
import tensorflow as tf
from tensorflow.python.client import device_lib

# GPUが利用可能か確認
gpus = tf.config.list_physical_devices('GPU')
if gpus:
    print(f"利用可能なGPUの個数: {len(gpus)}")
    print(f">> {gpus}")
else:
    print("No GPU available")

# CUDAとcuDNNのバージョンを表示
cuda_version = tf.sysconfig.get_compile_flags()
cudnn_version = tf.sysconfig.get_link_flags()

print("CUDA Version:", cuda_version)
print("cuDNN Version:", cudnn_version)

# GPUデバイスの情報を表示
for device in gpus:
    print(device)
```

## 実行結果
仮想環境を構築している場合は，有効にする．
```sh
. .venv/bin/activate
```

次のコマンドでプログラムを実行できる．
出力を参考にされたい．
```sh: 実行結果
$ python3 test.py
2024-10-19 02:37:47.709760: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:485] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered
2024-10-19 02:37:48.287631: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:8454] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered
2024-10-19 02:37:48.452555: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1452] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered
2024-10-19 02:37:49.668576: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.
To enable the following instructions: AVX2 FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.
2024-10-19 02:37:56.686536: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
I0000 00:00:1729273086.503500   20765 cuda_executor.cc:1001] could not open file to read NUMA node: /sys/bus/pci/devices/0000:01:00.0/numa_node
Your kernel may have been built without NUMA support.
I0000 00:00:1729273086.503582   20765 cuda_executor.cc:1001] could not open file to read NUMA node: /sys/bus/pci/devices/0000:02:00.0/numa_node
Your kernel may have been built without NUMA support.
I0000 00:00:1729273086.522308   20765 cuda_executor.cc:1001] could not open file to read NUMA node: /sys/bus/pci/devices/0000:01:00.0/numa_node
Your kernel may have been built without NUMA support.
I0000 00:00:1729273086.522373   20765 cuda_executor.cc:1001] could not open file to read NUMA node: /sys/bus/pci/devices/0000:02:00.0/numa_node
Your kernel may have been built without NUMA support.
I0000 00:00:1729273086.522415   20765 cuda_executor.cc:1001] could not open file to read NUMA node: /sys/bus/pci/devices/0000:01:00.0/numa_node
Your kernel may have been built without NUMA support.
I0000 00:00:1729273086.525424   20765 cuda_executor.cc:1001] could not open file to read NUMA node: /sys/bus/pci/devices/0000:02:00.0/numa_node
Your kernel may have been built without NUMA support.
利用可能なGPUの個数: 2
>> [PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU'), PhysicalDevice(name='/physical_device:GPU:1', device_type='GPU')]
CUDA Version: ['-I/mnt/c/Users/省略/.venv/lib/python3.12/site-packages/tensorflow/include', '-D_GLIBCXX_USE_CXX11_ABI=1', '--std=c++17', '-DEIGEN_MAX_ALIGN_BYTES=64']
cuDNN Version: ['-L/mnt/c/Users/省略/.venv/lib/python3.12/site-packages/tensorflow', '-l:libtensorflow_framework.so.2']
PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')
PhysicalDevice(name='/physical_device:GPU:1', device_type='GPU')
```

# 参考

https://plant-smile.work/tf216-wsl2-gpu-p1/

https://gihyo.jp/admin/serial/01/ubuntu-recipe/0677