TensorFlowのObjectDetectionでGPUを使いこなしてなかったことに気づいてしまった話。

# はじめに
前の記事で、Object Detectionでネコとライオンを見つけてみる、ということをやってみたのだがCPU Onlyでやるととても時間がかかって話になりません。ということでGCPのGPUインスタンスを使ってみました。その際、GPUの速さに驚いて使いこなしていないことに気づいていなかったというお話をします。

# 前提
GCPのGPUインスタンスの準備はできていることを仮定します。
分からない方は、[こっちの記事](https://cafe-and-cookies.tokyo/wp/?p=911)でやってるので参考にどうぞ。

# 何が起こったか。

## CPU Onlyの時の性能
CPU Onlyでトレーニングを行った時の性能。1ステップあたり１０秒強かかっていました。これで数千回のStepを踏むと思うと気が遠くなりますね。

```
python36 ./legacy/train.py --logtostderr --train_dir=log --pipeline_config_path=training/ssd_mobilenet_v2_coco.config
<snip>
INFO:tensorflow:Recording summary at step 0.
INFO:tensorflow:Recording summary at step 0.
INFO:tensorflow:global step 1: loss = 14.8737 (37.709 sec/step)
INFO:tensorflow:global step 1: loss = 14.8737 (37.709 sec/step)
INFO:tensorflow:global step 2: loss = 14.1087 (12.528 sec/step)
INFO:tensorflow:global step 2: loss = 14.1087 (12.528 sec/step)
INFO:tensorflow:global step 3: loss = 13.5204 (12.200 sec/step)
INFO:tensorflow:global step 3: loss = 13.5204 (12.200 sec/step)
INFO:tensorflow:global step 4: loss = 12.9567 (12.427 sec/step)
INFO:tensorflow:global step 4: loss = 12.9567 (12.427 sec/step)
INFO:tensorflow:global step 5: loss = 12.8636 (10.828 sec/step)
```

## GPUインスタンスの時の性能
CPU Onlyでやってたら時間がいくらあっても足りない。タイムイズマネーやで。と言われていたのですが、そうはいっても先立つものがなければなんとやら。ということで、何とかGCPで一番安いK80を使う資金をねん出しました。

で実行した結果がこれ。やばいよこれ！！１ステップあたり１秒かかっていない。１５倍以上の性能が出ているよ。
ばんざーい。ということでしばらくこれで使い続けていました。

```
$ python3 ./legacy/train.py --logtostderr --train_dir=log --pipeline_config_path=training/ssd_mobilenet_v2_coco.config
<snip>
INFO:tensorflow:global step 1: loss = 15.3566 (23.664 sec/step)
INFO:tensorflow:global step 1: loss = 15.3566 (23.664 sec/step)
INFO:tensorflow:global step 2: loss = 14.8838 (0.622 sec/step)
INFO:tensorflow:global step 2: loss = 14.8838 (0.622 sec/step)
INFO:tensorflow:global step 3: loss = 14.1156 (0.649 sec/step)
INFO:tensorflow:global step 3: loss = 14.1156 (0.649 sec/step)
INFO:tensorflow:global step 4: loss = 13.5529 (0.654 sec/step)
INFO:tensorflow:global step 4: loss = 13.5529 (0.654 sec/step)
INFO:tensorflow:global step 5: loss = 13.0792 (0.615 sec/step)

```

**が、しかし！！！**
GPUの性能はこんなものではなかった。
ふとnvidia-smiを実行してみると、なんかGPU一つしか動こいていないように見える。読み方わからんのだけど、なんだか不安。

```
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 410.72       Driver Version: 410.72       CUDA Version: 10.0     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla K80           Off  | 00000000:00:04.0 Off |                    0 |
| N/A   36C    P0   129W / 149W |  10941MiB / 11441MiB |     51%      Default |
+-------------------------------+----------------------+----------------------+
|   1  Tesla K80           Off  | 00000000:00:05.0 Off |                    0 |
| N/A   36C    P0    69W / 149W |    118MiB / 11441MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   2  Tesla K80           Off  | 00000000:00:06.0 Off |                    0 |
| N/A   32C    P0    56W / 149W |    118MiB / 11441MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   3  Tesla K80           Off  | 00000000:00:07.0 Off |                    0 |
| N/A   37C    P0    73W / 149W |    118MiB / 11441MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   4  Tesla K80           Off  | 00000000:00:08.0 Off |                    0 |
| N/A   35C    P0    58W / 149W |    118MiB / 11441MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   5  Tesla K80           Off  | 00000000:00:09.0 Off |                    0 |
| N/A   36C    P0    70W / 149W |    118MiB / 11441MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   6  Tesla K80           Off  | 00000000:00:0A.0 Off |                    0 |
| N/A   34C    P0    54W / 149W |    118MiB / 11441MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   7  Tesla K80           Off  | 00000000:00:0B.0 Off |                    0 |
| N/A   35C    P0    72W / 149W |    118MiB / 11441MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
 
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0      9844      C   python3                                    10928MiB |
|    1      9844      C   python3                                      105MiB |
|    2      9844      C   python3                                      105MiB |
|    3      9844      C   python3                                      105MiB |
|    4      9844      C   python3                                      105MiB |
|    5      9844      C   python3                                      105MiB |
|    6      9844      C   python3                                      105MiB |
|    7      9844      C   python3                                      105MiB |
+-----------------------------------------------------------------------------+
```

ということで、色々調べてみた結果、どうもtrain.pyにはnum_clonesというオプションがあるではないですか。試しにこれを8にしてみました。うわやべーー、なんかさらに倍以上早くなってる！

```
python3 ./legacy/train.py --logtostderr --train_dir=log --pipeline_config_path=training/ssd_mobilenet_v2_coco.config --num_clones=8
<snip>
INFO:tensorflow:Recording summary at step 0.
INFO:tensorflow:global step 1: loss = 15.0075 (37.466 sec/step)
INFO:tensorflow:global step 1: loss = 15.0075 (37.466 sec/step)
INFO:tensorflow:global step 2: loss = 15.1670 (0.235 sec/step)
INFO:tensorflow:global step 2: loss = 15.1670 (0.235 sec/step)
INFO:tensorflow:global step 3: loss = 14.1090 (0.229 sec/step)
INFO:tensorflow:global step 3: loss = 14.1090 (0.229 sec/step)
INFO:tensorflow:global step 4: loss = 13.5047 (0.233 sec/step)
INFO:tensorflow:global step 4: loss = 13.5047 (0.233 sec/step)
INFO:tensorflow:global step 5: loss = 13.2573 (0.222 sec/step)
INFO:tensorflow:global step 5: loss = 13.2573 (0.222 sec/step)
```

再度、nvidia-smiを実行してみるとGPU8個動いている！

```
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 410.72       Driver Version: 410.72       CUDA Version: 10.0     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla K80           Off  | 00000000:00:04.0 Off |                    0 |
| N/A   38C    P0    72W / 149W |  10943MiB / 11441MiB |     30%      Default |
+-------------------------------+----------------------+----------------------+
|   1  Tesla K80           Off  | 00000000:00:05.0 Off |                    0 |
| N/A   43C    P0    98W / 149W |  10943MiB / 11441MiB |     28%      Default |
+-------------------------------+----------------------+----------------------+
|   2  Tesla K80           Off  | 00000000:00:06.0 Off |                    0 |
| N/A   36C    P0    79W / 149W |  10943MiB / 11441MiB |     51%      Default |
+-------------------------------+----------------------+----------------------+
|   3  Tesla K80           Off  | 00000000:00:07.0 Off |                    0 |
| N/A   43C    P0   105W / 149W |  10943MiB / 11441MiB |     28%      Default |
+-------------------------------+----------------------+----------------------+
|   4  Tesla K80           Off  | 00000000:00:08.0 Off |                    0 |
| N/A   38C    P0    72W / 149W |  10943MiB / 11441MiB |     42%      Default |
+-------------------------------+----------------------+----------------------+
|   5  Tesla K80           Off  | 00000000:00:09.0 Off |                    0 |
| N/A   42C    P0    85W / 149W |  10943MiB / 11441MiB |     18%      Default |
+-------------------------------+----------------------+----------------------+
|   6  Tesla K80           Off  | 00000000:00:0A.0 Off |                    0 |
| N/A   38C    P0    87W / 149W |  10943MiB / 11441MiB |     51%      Default |
+-------------------------------+----------------------+----------------------+
|   7  Tesla K80           Off  | 00000000:00:0B.0 Off |                    0 |
| N/A   41C    P0    91W / 149W |  10943MiB / 11441MiB |     55%      Default |
+-------------------------------+----------------------+----------------------+
```

# ということで
GPUを8個も搭載しておきながら長らく１個しか使っていなかったという、情けないお話でした。いや、ちゃんと調べてから使わないともったいないですな。しょぼん:sob:。

ちなみに、もう少し学習の仕方をチューニングするとGPU-Utilを平均70%くらいまでは引き上げられるようです。バッチサイズを増やしたり。また、CPUやディスクが遅いとそちらがネックとなり、GPUを使い切れなくなるということもあるようです。GPUx8でCPUコアx8くらいだとGPUが遊んでしまう。16コアあってなんとか上のような状況。

# 参考、元ネタ
[Tensorflowでライオンとネコを検出する with GPU 1/2](https://cafe-and-cookies.tokyo/wp/?p=911)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/365991/4ee44d2e-20a2-1f74-2654-3777ce500cde.png)