TensorFlowでGPU学習させるためにCUDA周りではまったときの対処法

## 概要
　TensorFlowでの学習にGPU使いたくて、CUDA周りのセットアップしたときにはまったときのメモです。半分怪文章なので、話半分くらいで読んでください。

　誰か1人でも、この情報で救われることを祈って公開します。

## TensorFlowでGPU学習させるために必要なもの
　以下6つが必要です。

- Linux PC(Ubuntu OS）
- NVIDIAのGPU
- TensorFlow(GPU版）
- NVIDIAのGPUのドライバ
- CUDA（NVIDIA GPU専用の行列演算のための有名なライブラリ）
- cuDNN（NVIDIA GPU専用のディープラーニング用のライブラリ）

　上記6つそれぞれに、バージョンの組み合わせの制約や相性、ドキュメントにない挙動を見せる可能性が頻繁にあるので地獄です。

　とりあえずPCとGPUはなるべく実績のあるやつを買うのがオススメです。

## NVIDIA GPUドライバ、CUDA、cuDNNのバージョンの関係
　下記リンク先で、自分のマシンのNVIDIAのGPUのドライバの最新のバージョンを確認します。
[NVIDIA Driver Downloads](https://www.nvidia.com/Download/index.aspx)

　下記リンク先で、CUDAとNVIDIAのGPUドライバのバージョンの組み合わせを確認します。
[NVIDIA CUDA Toolkit Release Notes](https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html)

　次に、GPUの型番とCUDAとcuDNNのバージョンの組み合わせを確認します。アーキテクチャ名で書かれているので、型番との関係分かりにくいです（例えばRTXシリーズはNVIDIA Ampere GPU architecture）。地道に調べましょう。
[cuDNN Support Matrix](https://docs.nvidia.com/deeplearning/cudnn/support-matrix/index.html)

　下記リンク先でビルドされたTensorFlowとCUDAとcuDNNのバージョンの組み合わせを確認します。
[Tested build configurations](https://www.tensorflow.org/install/source#tested_build_configurations)

　ただ上記のページは、最新のTensorFlowは載っていなかったりします。最新のTensorFlowに関してはNVIDIAがNGCで提供しているDockerイメージのTensorFlowの[tensorflow-release-notes](https://docs.nvidia.com/deeplearning/frameworks/tensorflow-release-notes/)を参考にしたりしています（もっと良い情報あれば教えてください）。

　これらのバージョンの組み合わせの全てを満たす組み合わせを選ぶ必要があります。バージョン選定のポイントは以下です。

- NVIDIAのドライバは、新しければ古いCUDAでも動くので、基本は新しい方が良い。ただ、PCとの相性でGUI(X Window)が表示できないケースがあるので、その場合は違うバージョンを試す
- CUDAとcuDNNのバージョンは、GPUの型番に合わせる必要がある
- CUDAとcuDNNのバージョンはTensorFlowの推奨するバージョンに合わせる必要がある（推奨と違って動く場合もあるが、大抵動かない）

　以上が一通りまとまっているマトリックスは以下となります。といってもいきなりこれをみても混乱するので、一通り上から順に確認してからこれをみると整理ができるのではないかと思います。
[Framework Containers Support Matrix](https://docs.nvidia.com/deeplearning/frameworks/support-matrix/index.html)

## GPU・GPUドライババージョンの確認
　GPUとGPUドライババージョンを確認するコマンドは以下です。

```sh
$ lspci | grep -i nvidia
$ cat /proc/driver/nvidia/version
```

## CUDA/cuDNNのバージョンの確認方法
　CUDAのバージョンを確認する方法は以下です。

```sh
$ cat /usr/local/cuda/version.txt
```

 cuDNNは以下です。

```
$ cat /usr/include/cudnn.h | grep CUDNN_MAJOR -A 2
```

　CUDAよくバージョン確認する方法として、以下のコマンドが紹介されていますが、実際のバージョンと異なる場合があるので注意ください。

```sh
$ nvcc -V
```

```sh
$ nvidia-smi
```

　nvccの方は、以下のパスの方を使えば正しいバージョンが取得できます。

```sh
$ /usr/local/cuda/bin/nvcc -V
```

　もしnvccが入っていなければ、aptで`nvidia-cuda-toolkit`をインストールします。

```sh
$ sudo apt install nvidia-cuda-toolkit
```

　`nvidia-smi`に関しては、現在インストールしたNVIDIAドライバが対応しているCUDAのバージョンを表示しているだけのようです。

参考：[CUDA,cuDNNのバージョン確認](https://blog.mktia.com/get-cuda-and-cudnn-version/)

## NVIDIAのドライバの新しいバージョンをapt-getで入れたい
　直接NVIDIAのサイトのインストールスクリプトで入れる方法もありますが、私はあえなく失敗しました。
[NVIDIA Driver Downloads](https://www.nvidia.com/Download/index.aspx)

　古いバージョンのドライバしか無い場合は、以下実行すると入れられるようになります。

```sh
$ sudo add-apt-repository ppa:graphics-drivers/ppa
$ sudo apt update
$ sudo apt install nvidia-driver-xxx # xxxにはGPUに合わせたバージョンを選択
```


参考：[How do I install NVIDIA and CUDA drivers into Ubuntu?](https://askubuntu.com/questions/1077061/how-do-i-install-nvidia-and-cuda-drivers-into-ubuntu)

## 依存関係のエラーでCUDAをインストールできない
　CUDAをインストールしようとすると「満たせない依存関係があります」と表示されるケースです。`aptitude`でインストールできる場合がありました。

```sh
$ sudo apt install aptitude
$ sudo aptitude install cuda
```

## CUDAを入れ直したいが依存関係のエラーで古いCUDAをアンインストールできない
　CUDAを入れ直そうとしたら、依存関係のエラーが発生し `sudo apt-get -f install`をやってもエラーが返ってきてにっちもさっちも行かなくなった場合です。

　以下サイトを参考に対処しました。
[Error: Depends: libcublas-dev (>= 10.1.0.105) but it is not installed, Ubuntu 18.04](https://devtalk.nvidia.com/default/topic/1048021/error-depends-libcublas-dev-gt-10-1-0-105-but-it-is-not-installed-ubuntu-18-04/?offset=11)

　自分の場合は、以下コマンドで解決しました。

```sh
$ sudo mv /etc/apt/sources.list.d/cuda.list $HOME/cuda.list.bak
$ sudo apt update
$ sudo apt-get -f install
$ sudo apt-get remove --purge nvidia-*
$ sudo apt-get remove --purge cuda*
```

　削除後に、以下を実行してNVIDIAのドライバやら、CUDAを入れ直します。

```sh
$ sudo mv $HOME/cuda.list.bak /etc/apt/sources.list.d/cuda.list
$ sudo apt update 
```

## ログインループの回避方法
　NVIDIAのドライバの適切なバージョンを選ぶのが基本ですが、デスクトップ環境を変えることで回避できるケースもあるようです。Ubuntu 16.04標準のUnityからLXDEに変える場合は、CUI環境で以下実行すればOKです。

```sh
$ sudo apt update
$ sudo apt install lubuntu-desktop fcitx-mozc -y
```

## CUDAを確認
 Pythonを起動して、以下実行するのが簡単です。

```python
>>> from tensorflow.python.client import device_lib
>>> device_lib.list_local_devices()
```

　GPUという文字が出てきたらOKです。エラーが出たり、CPUだけだとNGです。

　CUDA、cuDNNの組み合わせが正しくなかったり、`pip install tensorflow-gpu`してなかったりしている可能性が高いです。がんばりましょう。

## 学習するときの注意点
　複数プログラムを走らせたい場合や、共用のマシンを使っている時、GPUを使い切ってしまうと困ります。そんなときは以下のように使用するGPUを指定します。指定するGPUの番号は、CUDAの確認のところの `device_lib.list_local_devices() `で確認しましょう。

```sh
$ export CUDA_VISIBLE_DEVICES=0
```

　`nvidia-smi`で負荷の様子がわかります。逆にGPUを使わない（CPUのみを使う）場合は、以下のように指定します。

```sh
$ export CUDA_VISIBLE_DEVICES=-1
```

　詳細および、Jupyter Notebook上で使う場合などに関しては以下記事が参考になりした。
[Jupyter上で使用するGPUを指定する最適解](https://qiita.com/forblgac/items/56d265155e617a679245)


## Object Detection学習時のNumpyエラー
 GPUと関係ないかもしれませんが、TensorFlowの物体検出（Object Detection）の学習時に以下のようなエラーができた時の対応です。

`TypeError: 'numpy.float64' object cannot be interpreted as an integer`

　Numpyが1.18.1の場合に発生するので、以下コマンドで1.17.4にダウングレードします。

```sh
$ sudo pip3 install numpy==1.17.4
```

参考：[PyTorch and TensorFlow object detection - evaluate - object of type <class 'numpy.float64'> cannot be safely interpreted as an integer](https://stackoverflow.com/questions/59493606/pytorch-and-tensorflow-object-detection-evaluate-object-of-type-class-nump)

## Dockerを使う方法
　この記事のコメントにありますがDockerを使う方法があります。NVIDIAのドライバさえ最新にすれば、CUDAやcuDNNのバージョンを気にせずにセットアップできるので便利です。以下記事にまとめたので参照ください。

[DockerでディープラーニングのGPU学習環境構築方法](https://qiita.com/karaage0703/items/e79a8ad2f57abc6872aa)

## 参考記事・関連記事
[ubuntu18.04でTensorFlow-gpuを動かす](https://qiita.com/sho8e69/items/66c1662c49ac89a024be)

[Tensorflow, CUDA, CuDNN バージョン確認方法](https://masaeng.hatenablog.com/entry/2019/08/14/231828?_ga=2.42924257.591222665.1565744930-478420615.1562993885)

[Tensorflow GPU, CUDA, CuDNNのバージョン早見表](https://qiita.com/chin_self_driving_car/items/f00af2dbd022b65c9068)

[ubuntu18.04にnvidiaドライバを入れるの苦労した](https://qiita.com/kawazu191128/items/8a46308be6949f5bda57)

[UbuntuでGPU設定時に使うコマンド](https://note.com/npaka/n/n653e17306696)

[ubuntuにCUDA、nvidiaドライバをインストールするメモ](https://qiita.com/porizou1/items/74d8264d6381ee2941bd)


## 変更履歴
- 2021/10/27 関連記事のリンク追記
- 2021/09/18 GPU型番とCUDAの関係に関して追記
- 2021/01/26 GPU情報確認に関して追記
- 2020/10/14 CUDAのインストールに関して追記
- 2020/08/07 Dockerに関して追記
- 2020/07/14 ログインループの回避方法追記