Ubuntu18.04にCUDA9.0とcuDNN7.0.5を入れて、Tensorflow-gpuを動かす

#まず簡潔に
Ubuntu18.04を前提として、Tensorflow-gpu環境構築で行うことは主に以下の５つです
・Nvidia driverの導入
・CUDAの導入
・cuDNNの導入
・Anacondaの導入
・Tensorflow-gpuの導入

これらの操作は以下に記載している[参考リンク](https://qiita.com/sho8e69/items/66c1662c49ac89a024be#ubuntu%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)が非常に参考になります。
こちらの記事を参考に環境構築を行った後であることを、本記事では前提とします。

環境構築を行い、実際にコードを書いて何かしらの学習をスタートさせると、
「Tensorflow-gpuはcuDNN7.0向けに設計されているが、実際に環境にインストールされているのはcuDNN7.3ですよ」
とのエラーを受け、学習がスタートしないという問題がありました。

解決の結論としては、
「Tensorflow-gpuのバージョンごとに、cuDNNバージョンが指定されているので、正しいcuDNNを入れましょう」
ということです。

上記の内容を以下で詳しく書いていきます。

#実施環境
Ubuntu 18.04.1 LTS
Celeron G3930
NVIDIA Geforce GTX1080
CUDA 9.0
cuDNN 7.0.5
Python 3.6.7
Tensorflow-gpu 1.5.0（1.6.0以上では、CPUによる動作制限があるようです）
Keras 2.2.4

#参考リンク
環境構築の全体の流れがとても整理されている記事です
https://qiita.com/sho8e69/items/66c1662c49ac89a024be#ubuntu%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB

このあたりのQ＆Aを読むとかなりヒントがあります
https://groups.google.com/forum/m/#!topic/keras-users/kfzPSDvmhPo
https://stackoverflow.com/questions/37663064/cudnn-compile-configuration-in-tensorflow

今回、Tensorflow-gpu 1.5.0を入れている理由です
http://arakan-pgm-ai.hatenablog.com/entry/2018/06/21/090000

#具体的なエラー
上記で紹介した、
「Tensorflow-gpuはcuDNN7.0向けに設計されているが、実際に環境にインストールされているのはcuDNN7.3ですよ」
とは具体的に一体どういうものなのか示します。

```
2018-11-06 18:00:04.565740: E
tensorflow/stream_executor/cuda/cuda_dnn.cc:378] Loaded runtime CuDNN library: 7300 (compatibility version 7300) but source was compiled with 7004 (compatibility version 7000).
If using a binary install, upgrade your CuDNN library to match.
If building from sources, make sure the library loaded at runtime matches a compatible version specified during compile configuration.
2018-11-06 18:00:04.566903: F 
tensorflow/core/kernels/conv_ops.cc:717] Check failed: stream->parent()->GetConvolveAlgorithms( conv_parameters.ShouldIncludeWinogradNonfusedAlgo<T>(), &algorithms) 
中止 (コアダンプ)
```
これです、このエラーの意味が、
「Tensorflow-gpuはcuDNN7.0向けに設計されているが、実際に環境にインストールされているのはcuDNN7.3ですよ」
となります。

#解決
エラーの意味がわかったので、解決していきます。

Tensorflow-gpuが本当にcuDNN7.0向けに設計されているかどうかの確認は置いておいて、
ローカル環境にインストールされているcuDNNのバージョンを確認しましょう。
以下のコードをターミナルに入力します。

```
$ dpkg -l | grep cuda
```
出力は以下のようになりました。

```
ii  cuda-command-line-tools-9-0                9.0.176-1                                   amd64        CUDA command-line tools
ii  cuda-core-9-0                              9.0.176-1                                   amd64        CUDA core tools
ii  cuda-cublas-9-0                            9.0.176-1                                   amd64        CUBLAS native runtime libraries
ii  cuda-cublas-dev-9-0                        9.0.176-1                                   amd64        CUBLAS native dev links, headers
ii  cuda-cudart-9-0                            9.0.176-1                                   amd64        CUDA Runtime native Libraries
ii  cuda-cudart-dev-9-0                        9.0.176-1                                   amd64        CUDA Runtime native dev links, headers
ii  cuda-cufft-9-0                             9.0.176-1                                   amd64        CUFFT native runtime libraries
ii  cuda-cufft-dev-9-0                         9.0.176-1                                   amd64        CUFFT native dev links, headers
ii  cuda-curand-9-0                            9.0.176-1                                   amd64        CURAND native runtime libraries
ii  cuda-curand-dev-9-0                        9.0.176-1                                   amd64        CURAND native dev links, headers
ii  cuda-cusolver-9-0                          9.0.176-1                                   amd64        CUDA solver native runtime libraries
ii  cuda-cusolver-dev-9-0                      9.0.176-1                                   amd64        CUDA solver native dev links, headers
ii  cuda-cusparse-9-0                          9.0.176-1                                   amd64        CUSPARSE native runtime libraries
ii  cuda-cusparse-dev-9-0                      9.0.176-1                                   amd64        CUSPARSE native dev links, headers
ii  cuda-documentation-9-0                     9.0.176-1                                   amd64        CUDA documentation
ii  cuda-driver-dev-9-0                        9.0.176-1                                   amd64        CUDA Driver native dev stub library
ii  cuda-libraries-dev-9-0                     9.0.176-1                                   amd64        CUDA Libraries 9.0 development meta-package
ii  cuda-license-9-0                           9.0.176-1                                   amd64        CUDA licenses
ii  cuda-misc-headers-9-0                      9.0.176-1                                   amd64        CUDA miscellaneous headers
ii  cuda-npp-9-0                               9.0.176-1                                   amd64        NPP native runtime libraries
ii  cuda-npp-dev-9-0                           9.0.176-1                                   amd64        NPP native dev links, headers
ii  cuda-nvgraph-9-0                           9.0.176-1                                   amd64        NVGRAPH native runtime libraries
ii  cuda-nvgraph-dev-9-0                       9.0.176-1                                   amd64        NVGRAPH native dev links, headers
ii  cuda-nvml-dev-9-0                          9.0.176-1                                   amd64        NVML native dev links, headers
ii  cuda-nvrtc-9-0                             9.0.176-1                                   amd64        NVRTC native runtime libraries
ii  cuda-nvrtc-dev-9-0                         9.0.176-1                                   amd64        NVRTC native dev links, headers
ii  cuda-repo-ubuntu1704-9-0-local             9.0.176-1                                   amd64        cuda repository configuration files
ii  cuda-samples-9-0                           9.0.176-1                                   amd64        CUDA example applications
ii  cuda-toolkit-9-0                           9.0.176-1                                   amd64        CUDA Toolkit 9.0 meta-package
ii  cuda-visual-tools-9-0                      9.0.176-1                                   amd64        CUDA visual tools
ii  libcudnn7                                  7.3.0.29-1+cuda9.0                          amd64        cuDNN runtime libraries
ii  libcudnn7-dev                              7.3.0.29-1+cuda9.0                          amd64        cuDNN development libraries and headers
ii  libcudnn7-doc                              7.3.0.29-1+cuda9.0                          amd64        cuDNN documents and samples

```
下３つにcuDNNのバージョンが記載されています。
libcudnn7、libcudnn7-dev、libcudnn7-docの３つです。
バージョンは7.3のようです。

エラーの意味は、
「Tensorflow-gpuはcuDNN7.0向けに設計されているが、実際に環境にインストールされているのはcuDNN7.3ですよ」
だったので、
「7.3を消して7.0を入れる」
ことを目指せばエラーが解消されそうです。

以下のコードで、cuDNN7.3を消しましょう

```
$ sudo apt-get --purge remove libcudnn7
```

この操作だけで、libcudnn7、libcudnn7-dev、libcudnn7-docの３つが消去されます。

次に、cuDNN7.0を入れていきます。
が、実際に入れるのはcuDNN7.0.5です。
[cuDNNダウンロードリンク](https://developer.nvidia.com/rdp/cudnn-archive#a-collapse714-9)からダウンロードします。
![Screenshot from 2018-11-07 10-57-19.png](https://qiita-image-store.s3.amazonaws.com/0/244627/778ff1a9-48d7-4e89-3c1b-6cc66d2de609.png)
「Download cuDNN v7.0.5 [Dec 5, 2017], for CUDA 9.0」を選択肢するとプルダウンが現れます。
![Screenshot from 2018-11-07 11-01-01.png](https://qiita-image-store.s3.amazonaws.com/0/244627/4b0355e0-9037-5cd2-0723-422debb394ff.png)
「cuDNN v7.0.5 Runtime Library for Ubuntu16.04 (Deb)」、
「cuDNN v7.0.5 Developer Library for Ubuntu16.04 (Deb)」、
「cuDNN v7.0.5 Code Samples and User Guide for Ubuntu16.04 (Deb)」
の３つをダウンロードします。

ターミナル上で保存先のディレクトリに移動し、
以下のコマンドを実行すると、cuDNN7.0.5がインストールされます。

```
$ sudo dpkg -i libcudnn7_7.0.5.15-1+cuda9.0_amd64.deb
$ sudo dpkg -i libcudnn7-dev_7.0.5.15-1+cuda9.0_amd64.deb
$ sudo dpkg -i libcudnn7-doc_7.0.5.15-1+cuda9.0_amd64.deb
```

cuDNNのバージョンを確認してみましょう。
以下のコマンドで確認します。

```
$ dpkg -l | grep cuda
```
出力は以下です。cuDNN以外の部分は省略しました。

```
ii  libcudnn7                                  7.0.5.15-1+cuda9.0                          amd64        cuDNN runtime libraries
ii  libcudnn7-dev                              7.0.5.15-1+cuda9.0                          amd64        cuDNN development libraries and headers
ii  libcudnn7-doc                              7.0.5.15-1+cuda9.0                          amd64        cuDNN documents and samples
```
#GPU動作の確認
ここまでで、問題だったエラー
「Tensorflow-gpuはcuDNN7.0向けに設計されているが、実際に環境にインストールされているのはcuDNN7.3ですよ」
が解決されているはずです。

実際にGPU動作を確認してみましょう。

pythonコンソールの起動

```
$ python
```
Tesorflowのインポート
GPU認識確認

```
>>> import tensorflow as tf
>>> tf.test.gpu_device_name()
```
以下が表示されるか確認してください。

```
'/device:GPU:0'
```
さあ、GPU動作を確認しましょう。
以下のコードが書かれたpythonファイルを作成し、実行してください。
引用：https://www.kaggle.com/getting-started/47096#post271139

```GPU_performance_check.py
import tensorflow as tf
import timeit

# See https://www.tensorflow.org/tutorials/using_gpu#allowing_gpu_memory_growth
config = tf.ConfigProto()
config.gpu_options.allow_growth = True

with tf.device('/cpu:0'):
  random_image_cpu = tf.random_normal((100, 100, 100, 3))
  net_cpu = tf.layers.conv2d(random_image_cpu, 32, 7)
  net_cpu = tf.reduce_sum(net_cpu)

with tf.device('/gpu:0'):
  random_image_gpu = tf.random_normal((100, 100, 100, 3))
  net_gpu = tf.layers.conv2d(random_image_gpu, 32, 7)
  net_gpu = tf.reduce_sum(net_gpu)

sess = tf.Session(config=config)

# Test execution once to detect errors early.
try:
  sess.run(tf.global_variables_initializer())
except tf.errors.InvalidArgumentError:
  print(
      '\n\nThis error most likely means that this notebook is not '
      'configured to use a GPU.  Change this in Notebook Settings via the '
      'command palette (cmd/ctrl-shift-P) or the Edit menu.\n\n')
  raise

def cpu():
  sess.run(net_cpu)

def gpu():
  sess.run(net_gpu)

# Runs the op several times.
print('Time (s) to convolve 32x7x7x3 filter over random 100x100x100x3 images '
      '(batch x height x width x channel). Sum of ten runs.')
print('CPU (s):')
cpu_time = timeit.timeit('cpu()', number=10, setup="from __main__ import cpu")
print(cpu_time)
print('GPU (s):')
gpu_time = timeit.timeit('gpu()', number=10, setup="from __main__ import gpu")
print(gpu_time)
print('GPU speedup over CPU: {}x'.format(int(cpu_time/gpu_time)))

sess.close()
```

以下のような結果が表示されれば、GPUが確かに動作しており、
CPUとGPUの処理時間の比較結果が見れます。

```
CPU (s):
8.017979502001253
GPU (s):
2.884423554998648
GPU speedup over CPU: 2x
```

#まとめ
[参考リンク](https://qiita.com/sho8e69/items/66c1662c49ac89a024be#ubuntu%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)を前提としてTensorflow-gpu環境構築を行った後、いざ学習してみようとしたら、
「Tensorflow-gpuが想定しているcuDNNのバージョンと、実際のcuDNNのバージョンが異なる」
ことに起因するエラーについて、解決策を示しました。

バージョンに関して、互換性・整合性をちゃんと確認しなければいけないなと思いました。

誰かのご参考になれば幸いです。