Windows版TensorFlow 1.13～1.15でGPUを使う (CUDAのインストール)

## 【目的】
Windows環境のTensorFlowでGPUを使えるようにします。

## 【内容】
Windows環境のTensorFlow1.13～1.15でCPUよりも高速で処理が行えるGPUを使えるようにします。
TensorFlow2.5以上の場合は下記の記事を参照してください。
[【Windows版TensorFlow 2.5以上でGPUを使う (CUDAのインストール)】- Zenn](https://zenn.dev/rhene/articles/af7a0162ee3a6332decc)

大まかには以下の手順を行います。

- ディスプレイドライバのインストールまたは更新
- CUDA 10.0のインストール
- cuDNN SDKのインストール
- PATHの設定
- GPU版TensorFlowのインストール

詳細手順はTensorFlowの公式手順を参照してください。

[【TensorFlow - GPU support】](https://www.tensorflow.org/install/gpu)


## 【システム構成】
本記事を書いている2019年4月15日時点では以下の通り。

- CUDA 3.5以上に対応しているGPUが搭載されているPC  
　[【NVIDIA - CUDA GPUs】](https://developer.nvidia.com/cuda-gpus)  
　(※ なお GeoForce MX150 上記サイトに記載されていませんが、動作確認できました)
- Windows 10/8.1/7 または Windows Server 2019/2016/2012 R2
- Python 3.4以上 (本記事では3.7.3で確認)
- TensorFlow 1.13.0以上 (本記事では1.13.1で確認)  
　(※2.0 Alphaは未確認ですがCUDA10.0で動くようです)
- CUDA 10.0  
　(※最新の10.1では動作せず)
- cuDNN 7.5.0 for CUDA 10.0  
　(※ 最新のfor CUDA 10.1では動作せず)


## 【前提条件】
本記事ではPyhon3.4以上およびpipが使える状態になっていることを想定しています。
なお、Anaconda環境は想定していません。


## 【1. ディスプレイドライバのインストールまたは更新】
下記サイトより対応するGPUの最新のドライバを取得して、インストールします。
[【NVIDIA Driver Downloads】](https://www.nvidia.com/Download/index.aspx)

すでにドライバが入っている場合、可能ならばカスタムインストールからクリーンインストールを選択します。
その場合、設定済みの項目は全て初期化されます。


## 【2. CUDA 10.0のインストール】
下記サイトよりCUDAをダウンロードしてインストールします。
[【NVIDIA - CUDA Zone】](https://developer.nvidia.com/cuda-zone)

なお、2019年4月15日現在で最新バージョンの「10.1」では動作確認ができませんでした。
[Legacy Releases]から「CUDA Toolkit 10.0 (Sept 2018)」をダウンロードしてください。
【直リン】
[【CUDA Toolkit 10.0 Archive】](https://developer.nvidia.com/cuda-10.0-download-archive)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454012/ea1d4a8f-1eb4-9939-533c-034d53908833.png)

インストール自体はデフォルトで構いません。


### 【2.1 CUDAインストール時に「Visual Studio Integration」のインストールに失敗する場合】(2019/07/15 追記)
以下の記事を参考にしてください。
[【Windows端末にCUDAをインストールする際に、「Visual Studio Integration」のインストールに失敗する場合】](https://qiita.com/rhene/items/2a2eac7d1c0a8edc3ac5)

## 【3. cuDNN SDKのインストール】
下記URLからcuDNNをダウンロードします。
上記でダウンロードしたCUDAのバージョンに合ったものをダウンロードしてください。
なお、ダウンロード時には開発者登録を行う必要があります。

[【NVIDIA - NVIDIA cuDNN】](https://developer.nvidia.com/cudnn)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454012/fd323615-4217-5070-bc49-9de64d0e6056.png)

ダウンロードしたらzipファイルを解凍して適当な場所に展開します。
場所はどこでも構いませんが、TensorFlowの手順に合わせるのであれば「C:\tools\cuda\bin」に「cuDNN64_7.dll」が含まれるように解凍します。


## 【4. PATHの設定】
下記を参考にCUDAおよびcuDNNにPATHが通るように設定します。
最低限cuDNNの「cuDNN64_7.dll」が置いてあるディレクトリにPATHが通っている必要があります。

【必須設定】

- C:\tools\cuda\bin (← 上記の例の場合のcuDNN64_7.dllの置き場所)  
　※ここにPATHに通っていないとimport TensorFlowでエラーになる

以下オプション (TensorFlowの手順には書いてあるが特に必要ない?)

- C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0\bin
- C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0\extras\CUPTI\libx64
- C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0\include


## 【5. GPU版TensorFlowのインストール】
TensorFlowはCPUのみを使うバージョンと、GPUを使うバージョンの2種類があります。
GPUを使うバージョンは以下のコマンドでインストールできます。

`pip install tensorflow-gpu`

なお、事前にCPU版がインストールされている場合は上書きされるようです。
気になる場合は『事前に』CPU版をアンインストールしておいたほうが良さそうです。
アンインストールする場合は以下のコマンドを実行。

`pip uninstall tensorflow`

GPU版を入れてから上記コマンドを実行するとimport tensorflowでエラーになるので注意してください。
その場合は再度GPU版をインストールしなおせば直ります。


## 【動作確認】
以下のコマンドを実行します。
「出力結果」に `tensorflow/core/common_runtime/gpu/gpu_device.cc:1640] Found device 0 with properties:` や `device_type: "GPU"` の文言が確認できればGPUを認識しています。
(本記事では「GeForce MX150」を認識しています)

```shell

python -c "from tensorflow.python.client import device_lib;print(device_lib.list_local_devices());"
```
```出力結果.txt
2019-07-27 19:43:40.377037: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
2019-07-27 19:43:41.132310: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1433] Found device 0 with properties:
name: GeForce MX150 major: 6 minor: 1 memoryClockRate(GHz): 1.5315
pciBusID: 0000:01:00.0
totalMemory: 2.00GiB freeMemory: 1.62GiB
2019-07-27 19:43:41.143239: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1512] Adding visible gpu devices: 0
2019-07-27 19:43:41.779110: I tensorflow/core/common_runtime/gpu/gpu_device.cc:984] Device interconnect StreamExecutor with strength 1 edge matrix:
2019-07-27 19:43:41.783984: I tensorflow/core/common_runtime/gpu/gpu_device.cc:990]      0
2019-07-27 19:43:41.787937: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1003] 0:   N
2019-07-27 19:43:41.791116: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1115] Created TensorFlow device (/device:GPU:0 with 1364 MB memory) -> physical GPU (device: 0, name: GeForce MX150, pci bus id: 0000:01:00.0, compute capability: 6.1)
[name: "/device:CPU:0"
device_type: "CPU"
memory_limit: 268435456
locality {
}
incarnation: 12884386107899363910
, name: "/device:GPU:0"
device_type: "GPU"
memory_limit: 1431112499
locality {
  bus_id: 1
  links {
  }
}
incarnation: 16905718725287129387
physical_device_desc: "device: 0, name: GeForce MX150, pci bus id: 0000:01:00.0, compute capability: 6.1"
]
```

## 【TensorFlowとCUDA】
TensorFlowを使ったプログラムは、CPU版で動いていたものはそのままGPU版で動きます。
内部処理がすべてCUDAを利用するように変更されているため、プログラムを変更すことなくGPUを利用できるようになります。

ちなみにChainerの場合、numpyによる演算処理をcupyというCUDAを使ったnumpy互換のライブラリに置き換えることでGPUを使った処理ができるようになるようです。
cupy自体はChainerの機能ではありません。
そのためcupyを単体で利用することで、どんなプログラムでもGPUを使うように変更できますが、CPU版との互換はありません。
(そもそもCUDA対応のGPUが搭載されていないとCUDAがインストールできない上に、CUDAが入っていないとcupyがインストールできない)


## 【GPU利用時の速度差】
Yolo v3で物体検知を行った場合

|スペック|処理時間|備考|
|:--|--:|:--|
|Core i5 4200 2.3GHz|2.5～2.6秒|GPU非搭載 CPUのみ|
|Core i7 8550U 1.8GHz |0.9~1.1秒|CPU版|
|上記 + GeForce MX150|0.24～0.25秒|GPU版|
|Jetson Nano (参考)|0.22～0.25秒|GPU版|

下記のリポジトリをもとにしてWebカメラでリアルタイムで物体認識できるように改変したもので測定しました。
(認識サイズ416×416 RGB)
[【GitHub - keras-yolo3】](https://github.com/qqwweee/keras-yolo3)

ショボいモバイルGPUでもそれなりに効果は出ますね。
でもエッジデバイスのJetson Nanoと同等とは…