tensorflow2.0で強化学習を試みたが強制終了した理由

#流れ
僕：今まであまり変数の多くない学習を機械学習を試していたが，弊ラボには折角GPU4枚刺しマシンがあるので，tensorflow-gpuを使ってみよう．
僕：ついでに心新たにtensorflow2.0のkerasを使ってみよう．
僕：openaigymのtaxiでこんな感じに．．．
僕：さ～て学習は進んでいるかな？？？
PC：ターミナル「強制終了」
僕：え？
PC：強制終了！

決まって120学習ステップくらいで停止するのであった．

#環境
OS:ubuntu18系
GPU：GTX1080x4枚
python:3.6.9(Anaconda)
cudnn:7.6.0
cudatoolkit:10.0.130
以下使用したニューラルネットワーク構成

```
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
embedding (Embedding)        (None, 1, 10)             5000
_________________________________________________________________
reshape (Reshape)            (None, 10)                0
_________________________________________________________________
dense (Dense)                (None, 50)                550
_________________________________________________________________
dense_1 (Dense)              (None, 50)                2550
_________________________________________________________________
dense_2 (Dense)              (None, 6)                 306
=================================================================
Total params: 8,406
Trainable params: 8,406
Non-trainable params: 0
_________________________________________________________________
```

#結論から言うと・・・
強制終了前にネットワークを適宜保存．
繰り返しプログラム回して学習という力業．
とりあえずこれでなんとかなる．

#解決するまでに試したこと(こっちの方が為になった)
##linuxのログを確認
tensorflowがエラーを吐いてくれているならターミナル上にメッセ―ジで問題を伝えてくれるが，今回の場合は唐突に

```
強制終了
```
の文字が表れた．
こういう時はやはりまずはlogを確認する．

```
sudo cat /var/log/syslog

Oct 27 18:27:41 hoge kernel: [1056250.835731] Out of memory: Kill process 1034 (python) score 949 or sacrifice child
Oct 27 18:27:41 hoge kernel: [1056250.835735] Killed process 1034 (python) total-vm:133873604kB, anon-rss:47517436kB, file-rss:440992kB
```

Out of memory: Kill processおせっかいにもメモリを心配してプロセスを強制終了をしてくれたこいつのことをoom killerなんて巷では言うらしい．

僕：そんなにメモリー必要なネットワークじゃないと思うんだけど・・・

##GPU使用状況確認＆メモリ確認


```
nvidia-smi #GPUの使用状況が分かる

free　#メモリの使用状況が分かる

top　#他ユーザー含めてプロセスの確認
```

```
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 418.67       Driver Version: 418.67       CUDA Version: 10.1     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 108...  Off  | 00000000:05:00.0  On |                  N/A |
| 47%   78C    P2    72W / 250W |    625MiB / 11178MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   1  GeForce GTX 108...  Off  | 00000000:06:00.0 Off |                  N/A |
| 39%   71C    P2    59W / 250W |    149MiB / 11178MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   2  GeForce GTX 108...  Off  | 00000000:09:00.0 Off |                  N/A |
| 35%   67C    P2    58W / 250W |    149MiB / 11178MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   3  GeForce GTX 108...  Off  | 00000000:0A:00.0 Off |                  N/A |
| 29%   62C    P2    56W / 250W |    149MiB / 11178MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0      1808      G   /usr/bin/X                                   168MiB |
|    0      2567      G   compiz                                       171MiB |
|    0     15131      C   python                                       273MiB |
|    1     15131      C   python                                       137MiB |
|    2     15131      C   python                                       137MiB |
|    3     15131      C   python                                       137MiB |
+-----------------------------------------------------------------------------+
```
nvidia-smiを実行すると上記のような出力がある．
注目すべきはMemory-Usage
今回載せているのはメモリ確保の設定変更後の学習中の様子なのでGPUは一枚だけかつ600MiB程度で学習が行えている．
oom killerが動作時はこれが10000MiB近い値が出てしまっていた．
それでもステップ序盤は止まらなかった・・・どうするとkillされるのか．

freeの出力を観察しているとなんとなくそれが分かった．

```
             total       used       free     shared    buffers     cached
Mem:      49374704   43332596    6042108      37000      67152     808784
-/+ buffers/cache:   42456660    6918044
Swap:      7999484    1564196    6435288
```
こちらがfreeの出力．これも修正後（問題発生時を再現するのがめんどくさかった）.
oom killerが発動するまでになにが起きていたのかというと
ステップが進むたびにusedが爆上がり，そしてとあるタイミングでSwapが0に落ちる．

僕：で？？

Swapメモリについてやlinuxのメモリ確保の仕組みバッファキャッシュ確保の仕組みについてｇｇりましたが，今回どういう流れでoom killerが働いたのかまではわかりませんでした．．．

読者:いや，結局そこわからんのかい！

僕：またわかったら追記します．．．

##ところで実際ニューラルネットワーク作るのに必要なメモリってどれくらいなの？
[https://nori-life-log.com/nn%E3%81%AE%E5%AD%A6%E7%BF%92%E3%81%A7%E5%BF%85%E8%A6%81%E3%81%AAgpu%E3%83%A1%E3%83%A2%E3%83%AA%E3%82%92%E7%AE%97%E5%87%BA%E3%81%99%E3%82%8B]

こちらのブログで紹介されている式より
必要メモリ量(byte) 
=(ニューロンの数 × Batch Size ＋ パラメータ数) × 2 (data & grad) × 4(byte)
これを僕のネットワークで計算すると．．．約95000Byte
強化学習でtarget networkとreplay memory採用してても知れてる．
そう，ここで気づく．

僕：いや，GPU占有しすぎじゃね？？

##tensorflowのGPU確保設定の変更
```python
gpu_devices = tf.config.experimental.list_physical_devices('GPU')
if len(gpu_devices) > 0:
    for i in range(len(gpu_devices)):
        tf.config.experimental.set_memory_growth(gpu_devices[i], True)
        print('memory growth:', tf.config.experimental.get_memory_growth(gpu_devices[i]))
```
memory_growthをTrueにすると解決した．
これがFalseだとGPUの使用可能スペースをフルで確保してしまい，oomkillerを呼び出す羽目になる．
tensorflow2.0ではGPU1枚ずつこれを設定できるので，for文で全てのGPUについて設定しておいた．

#まとめ
oom killerによって学習プロセスを途中で強制終了されるのは強化学習の性質上仕方ないか？途中でモデルをクリアしてメモリ解放なんてことを画像処理系モデルでは推奨されているが強化学習では環境であったりエージェントであったりをクリアすることはできないので難しそう．
実際にメモリの必要量を推定してみたり，linuxのメモリシステムについて再度いろいろ調べて勉強になりました．（実はtensorflowのmulti_gpu_modelとかも試したけどまるで見当違いだったので省略しました）
本当は実装に関する記事を書きたかったのでそれはまた今度書きます．