【環境構築まとめ】GPUでCUDA / TensorFlowを扱うまでの流れ 


GeForce GTX 1050搭載のパソコンを購入したので、Ubuntu18.04でTensorflowをGPUで扱うための流れをまとめました。Tensorflowのソースコードをダウンロードし、コンパイルすることで、GPUの性能を最大限に活用します。
また、最後にcupyというnumpy配列をCUDAで扱えるようにするパッケージのインストール方法も紹介します。
本記事で例として挙げているものと環境が違っても、バージョン互換性を確認するためのサイトを逐次挙げているので、ご自身の環境にあったバージョンをお選びください。

※本記事はできるだけ正確に私自身が環境構築を行ったときの手順をまとめたものであり、他の人の役に立てるようにという意味でも執筆してはいるものの、正確さは保証できません。ご自身の責任のもと、実行お願いいたします。

### 編集履歴
|日付|更新内容|
|---|---|
|2019年10月17日|記事公開|
|2024年2月16日|RTX 3090のCUDAインストールについても追記|

### 使用環境
|名称|バージョン|
|---|---|
|GPU|NVIDIA GeForce GTX 1050<br>NVIDIA GeForce RTX 3090|
|OS|Ubuntu 18.04 LTS<br>Ubuntu 22.04 LTS|
|CUDA|10.0<br>12.3|
|cuDNN|7.6.4|
|NCCL|2.4.8|
|Bazel|0.26.1|
|Tensorflow|2.0|

### 最終的なpipインストールリスト (`pip3 freeze`)

```
absl-py==0.8.1
astor==0.8.0
gast==0.2.2
google-pasta==0.1.7
grpcio==1.24.1
h5py==2.8.0
Keras-Applications==1.0.8
Keras-Preprocessing==1.1.0
Markdown==3.1.1
mock==3.0.5
numpy==1.16.2
opt-einsum==3.1.0
pkg-resources==0.0.0
protobuf==3.10.0
six==1.12.0
tensorboard==2.0.0
tensorflow-estimator==2.0.0
tensorflow-gpu-cuda-10.0==2.0.0
termcolor==1.1.0
Werkzeug==0.16.0
wrapt==1.11.2
```
必要十分かどうかはわかりません。この中のほとんどは`pip3 install setuptools`でインストールされます。
また、この段階でインストールする必要はありません。後のステップで解説していくパッケージをインストールすれば大丈夫です。



## 参考サイト
はじめに、大変参考にさせていただいたサイトを挙げさせていただきます。

- 全体的に参考にさせていただいたサイト
https://qiita.com/ishizakiyu/items/bcf1b76f1f4f02b0ac57

- Tensorflowをコンパイルする前までを参考にさせていただいたサイト
https://qiita.com/konzo_/items/3e2d1d7480f7ef632603

- Ubuntu18.04をデュアルブートする際に参考にさせていただいたサイト(本記事には関係ないですが)
https://qiita.com/TDC/items/9704e7981dd7a072a22d


## Ubuntuバージョン確認
```
uname -m && cat /etc/*release
```

## NVIDIA-GPUバージョン確認

```
lspci | grep -i nvidia
```

分からないこともあります。
その場合はシステム情報などから確認してください。


## GRUB編集
デフォルトのグラフィックドライバを使わないように`/etc/default/grub`を編集します。
デフォルトでは次のようになっています。

```sh:[default] /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX=""
```

これを次のように編集します。

```sh:[update] /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash pci=nomsi nomodeset"
GRUB_CMDLINE_LINUX="pci=noaer"
```


## NVIDIA-GPUドライバインストール
以下のURLで対応するドライバを検索して、ダウンロードします。
https://www.nvidia.co.jp/Download/index.aspx?lang=jp

ダウンロードしたファイルに実行権限を付けてインストールします。
GeForce-GTX1050の場合は次のようになります。

```sh:
chmod +x NVIDIA-Linux-x86_64-430.50.run 
sudo ./NVIDIA-Linux-x86_64-430.50.run
```


## compute capability確認
あとで、Tensorflowをコンパイルする際に必要なcompute capabilityを確認します。
http://developer.nvidia.com/cuda-gpus
GeForce-GTX1050なら6.1です。

## 事前インストール

```sh:
sudo apt-get install build-essential 
sudo apt-get install cmake git unzip zip
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt-get update
sudo apt-get install python2.7-dev python3.5-dev python3.6-dev pylint

sudo apt-get install libcupti-dev
echo 'export LD_LIBRARY_PATH=/usr/local/cuda/extras/CUPTI/lib64:$LD_LIBRARY_PATH' >> ~/.bashrc
```

## CUDAインストール
CUDA10.1は、Tensorflowに現在(2019年)対応していない(できるかもしれないが[公式](https://www.tensorflow.org/install/source#ConfigureInstallation)では確認されていない)ため、CUDA10.0を公式サイトからダウンロードします。
今回は、`deb(network)`を選択しました。
https://developer.nvidia.com/cuda-toolkit-archive

```sh:
sudo dpkg -i cuda-repo-ubuntu1604_10.0.130-1_amd64.deb
sudo apt-key adv --fetch-keys sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub
sudo apt-get update
sudo apt-get install cuda-toolkit-10-0
```

`.bashrc`や`.zshrc`の末尾に以下を追加します。
CUDAが10.0のときは以下のようになります。

```sh:
export PATH="/usr/local/cuda-10.0/bin:$PATH"
export LD_LIBRARY_PATH="/usr/local/cuda-10.0/lib64:$LD_LIBRARY_PATH"
```

CUDAが12.3のときは次のようになります。
パスは実際のディレクトリ構造も確認しながら適宜書き換えが必要です。

```sh:
export PATH="/usr/local/cuda-12.3/bin:$PATH"
export LD_LIBRARY_PATH="/usr/local/cuda-12.3/lib64:$LD_LIBRARY_PATH"
```

再起動後、`nvcc -V`でインストールできたか確認できます。
CUDAのバージョンが10.0のときは以下のようになります。
```
$ nvcc -V
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2018 NVIDIA Corporation
Built on Sat_Aug_25_21:08:01_CDT_2018
Cuda compilation tools, release 10.0, V10.0.130
```

CUDAのバージョンが12.3の場合は以下のようになります。
```sh:
$ nvcc -V
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
```

また`nvidia-smi`コマンドで、GPUの型番がわかります。

## cuDNNのインストール

https://developer.nvidia.com/rdp/cudnn-download
CUDA10.0に対応する`Download cuDNN v7.6.4 (September 27, 2019), for CUDA 10.0`をクリックして、対応するOSのものを3種類ダウンロード。(Ubuntu18.04の場合は以下の3つ)

`cuDNN Runtime Library for Ubuntu18.04 (Deb)`
`cuDNN Developer Library for Ubuntu18.04 (Deb)`
`cuDNN Code Samples and User Guide for Ubuntu18.04 (Deb)`

そして、インストール。(順番もこのまま)

```sh:
sudo dpkg -i libcudnn7_7.4.1.5-1+cuda10.0_amd64.deb
sudo dpkg -i libcudnn7-dev_7.4.1.5-1+cuda10.0_amd64.deb
sudo dpkg -i libcudnn7-doc_7.4.1.5-1+cuda10.0_amd64.deb
```

## NCCLインストール

https://developer.nvidia.com/nccl/nccl-download
CUDA10.0に対応する`Download NCCL v2.4.8, for CUDA 10.0, July 31,2019`をクリックして、`O/S agnostic local installer`をダウンロードして、以下のコマンドを実行してインストール。

```sh:
tar -xf nccl_2.4.8-1+cuda10.0_x86_64.txz
cd nccl_2.2.13-1+cuda10.0_x86_64
sudo cp -R * /usr/local/cuda-10.0/targets/x86_64-linux/
sudo ldconfig
```

## Bazelインストール
まずは、適当に最新版をインストールし、あとで、tensorflowのコンパイル(`./configure`)を行ったときに出るErrorに合わせて、バージョンをインストールし直します。
現時点での最新バージョンは2.0.0のようですが、コンパイルをすると、「バージョンは0.26以下にしなさい」と怒られたので、0.26.1をダウンロードしました。

```sh:
wget https://github.com/bazelbuild/bazel/releases/download/0.26.1/bazel-0.26.1-installer-linux-x86_64.sh
chmod +x bazel-0.26.1-installer-linux-x86_64.sh
./bazel-0.26.1-installer-linux-x86_64.sh --user
echo 'export PATH="$PATH:$HOME/bin"' >> ~/.bashrc
```

## tensorflowソースコードのコンパイル・pipパッケージ化・インストール
tensorflow-gpuを単純にpipでインストールしただけでは、GPUの性能を十分に活かすことができない場合があるため、ソースコードをダウンロードしてコンパイルします。
今回は、OSのデフォルトのpythonを傷つけないように、pythonの仮想環境venvを用いてコンパイルします。
好きなディレクトリに仮想環境を作り、必要なpip-packageをインストールします。
Anacondaなど他の環境を使っても問題ないが、venvはpythonにデフォルトで搭載されている機能なのでより手軽にできます。

```sh:
python3 -m venv venv
source venv/bin/activate
pip3 install pip six wheel mock
pip3 install setuptools==41.4.0
pip3 install numpy==1.16.2
pip3 install keras_applications==1.0.5 --no-deps
pip3 install keras_preprocessing==1.0.3 --no-deps
pip3 install h5py==2.8.0
```

各パッケージの最新バージョンが何か知りたい場合は、例えばnumpyの場合なら、次のコマンドを実行します。

```sh:
pip3 search numpy
```

このように調べて、最新バージョンをインストールすればよいが、tensorflowを実行する際に互換性が無い場合は適宜ダウングレードする必要があります。(コマンド例:numpyのダウングレード)

```sh:
pip3 uninstall numpy
pip3 install numpy==1.16.2
```

本記事と同じ環境なら、上のバージョンで良いはず。

次に、tensorflowのソースコードをクローンする。
最新版のブランチにチェックアウトするには、下の`git checkout r2.0`の`git checkout r`まで打った時点で`tab`キーを押せば、候補が出るため、それを見て最新のブランチにチェックアウトすればよい。

```sh:
git clone https://github.com/tensorflow/tensorflow.git
cd tensorflow
git pull
git checkout r2.0
```

`./configure`で、コンパイル実行。このときにBazelのバージョンがダメだと言われれば、それに従って、条件を満たす最大のBazelのバージョンをインストールすれば良い。また、その他にも色々聞かれるが、これまで調べた情報を元に入力する。基本的には、デフォルトの内容のままで良いならそのまま`Enter`、必要のない機能は「n」で良い。(ここの詳細は[参考サイト](https://qiita.com/ishizakiyu/items/bcf1b76f1f4f02b0ac57)へ。ただ、バージョンによって質問内容はかなり異なるようなので注意。)

```sh:
bazel build --verbose_failures --config=opt --config=cuda tensorflow/tools/pip_package:build_pip_package
```

かなりコンパイルに時間がかかる(私の環境では約2時間)が、待つ。
コンパイルが終わったら、pipパッケージ化し、`/tmp/tensorflow_pkg/`ディレクトリ下に置く。

```sh:
bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg --project_name tensorflow_gpu_cuda_10.0
```

利用する際は、以下のようにする。
これで、コンパイルした際に使った仮想環境だけでなく、どの環境でも、pip3でこの自分で作ったpip-packageをインストールすれば、使えるようになった。

```sh:
pip3 install /tmp/tensorflow_pkg/tensorflow_gpu_cuda_10.0-2.0.0-cp36-cp36m-linux_x86_64.whl
```

## 検証
[Tensorflow-Tutorial](https://github.com/tensorflow/docs/blob/master/site/ja/tutorials/quickstart/beginner.ipynb)でインストールできたか検証する。
別ウィンドウで`nvidia-smi -l`でGPUを監視していると、学習中はこのプログラムのためにリソースが使われているはず。

```python:test.py
import tensorflow as tf
mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(512, activation=tf.nn.relu),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test)
```

## cupyのインストール(おまけ)
cupyは、CUDAで並列計算するためのpythonパッケージ。
numpyで作成した行列をcupy用の配列に変換することで高速に行列演算を計算できる。
numpyのCUDA版と考えればよい(?)
pyCUDAなどの他のパッケージとの違いは、CPU・GPUの違いを意識せずにコーディングできること(agnostic coding)などがある。
インストールはpipで簡単にできる。まずは、次のコマンドを実行してみる。

```sh:
pip3 search cupy-cuda
```

すると、以下のような内容が出てきます。

```sh:
cupy-cuda91 (6.4.0)   - CuPy: NumPy-like API accelerated with CUDA
cupy-cuda92 (6.4.0)   - CuPy: NumPy-like API accelerated with CUDA
cupy-cuda100 (6.4.0)  - CuPy: NumPy-like API accelerated with CUDA
cupy-cuda90 (6.4.0)   - CuPy: NumPy-like API accelerated with CUDA
cupy-cuda80 (6.4.0)   - CuPy: NumPy-like API accelerated with CUDA
cupy-cuda101 (6.4.0)  - CuPy: NumPy-like API accelerated with CUDA
```

インストールするべきcupyは、cudaのバージョンによって異なる。例えば、CUDA9.1を使っているならcupy-cuda91。
今回はCUDA10.0を使っているのでcupy-cuda100をインストールする。

```sh:
pip3 install cupy-cuda100==6.4.0
```

また、CUDAのバージョンが11.2以上のときは次のようになります。
|CUDAバージョン|pipパッケージ|
|-|-|
|v11.2 ~ 11.8|cupy-cuda11x|
|v12.x|cupy-cuda12x|

`x`は自身のCUDAのマイナーバージョンを当てはめるのではなく、`11x`/`12x`というパッケージ名です。
詳しくは以下のサイトに記載されています。
https://docs.cupy.dev/en/stable/install.html#installing-cupy

## 編集後記
この界隈を調べていると頻繁に`agnostic`という用語に出会いました。ここでの意味は「CPUやGPUの違いを意識せずに実装できる」というもので、IT界隈ではよく使われるものの、一般的にはあまり使わない言葉のようです。