深層強化学習フレームワークmachinaを使ってみた

# はじめに

深層強化学習フレームワーク[machina](https://github.com/DeepX-inc/machina)が気になったので、どんなものかとりあえず[quickstart](https://github.com/DeepX-inc/machina/tree/master/example/quickstart)をやってみることにする

環境: Mac, pyenv viertualenv セットアップ済み

# セットアップする

とりあえずvirtualenvで専用環境を作る。Python3.7.3をコンパイラに指定する

```shell
pyenv install 3.7.3
pyenv virtualenv 3.7.3 machina
pyenv activate machina
pip install -U pip
pip install numpy torch torchvision jupyter machina-rl
```

Pythonインストール中に`zipimport.ZipImportError: can't decompress data; zlib not available`エラーが発生してインストールができなかった。以下の記事に記載されている対処法で無事インストールできた

[[MacOS Mojave]pyenvでpythonのインストールがzlibエラーで失敗した時の対応](https://qiita.com/zreactor/items/c3fd04417e0d61af0afe)

# quickstartをやってみる

レポジトリをクローンする

```
git clone https://github.com/DeepX-inc/machina.git
cd machina
```

jupyter notebookを起動する

```
jupyter notebook
```

notebookで example -> quickstart -> ppo_acrobot.ipynb を開いてポチポチやってトレーニングし、結果を表示する。*4.Visualize behavior after trainning*を実行すると、トレーニング結果の動画が再生される

![capture-1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61995/2854033f-d1e7-52f4-b2f2-782c65ca2de8.gif)

まあ100エポックほどなのでちゃんと立たないが、学習していることは確認できる

# 他のexampleをやってみる

ソースコードを追いかけるのは後でやるとして、quickstartがあっさり終わったので別のexampleをやってみようと思う。[IMITATION.md](https://github.com/DeepX-inc/machina/blob/master/example/IMITATION.md)に記載されている`Behavioral Cloning`のサンプルコードを動かしてみる。

`IMITATION.md`に記載されている手順で`expert_epis`をダウンロードしたりして、以下を実行する

```
cd example
python run_behavior_clone.py
```

```
{'batch_size': 256,
 'c2d': False,
 'check_rate': 0.05,
 'cuda': -1,
 'data_parallel': False,
 'deterministic': False,
 'env_name': 'Pendulum-v0',
 'epoch': 1000,
 'expert_dir': '../data/expert_epis',
 'expert_fname': 'Pendulum-v0_100epis.pkl',
 'gamma': 0.99,
 'h1': 32,
 'h2': 32,
 'lam': 1,
 'log': 'garbage',
 'max_epis': 100000000,
 'max_epis_per_iter': 10,
 'num_parallel': 4,
 'pol_lr': 0.0001,
 'record': False,
 'seed': 256,
 'tau': 0.001,
 'train_size': 0.7}
/Users/user/.pyenv/versions/machina/lib/python3.7/site-packages/gym/envs/registration.py:14: PkgResourcesDeprecationWarning: Parameters to load are deprecated.  Call .resolve and .require separately.
  result = entry_point.load(False)
WARN: gym.spaces.Box autodetected dtype as <class 'numpy.float32'>. Please provide explicit dtype.
WARN: gym.spaces.Box autodetected dtype as <class 'numpy.float32'>. Please provide explicit dtype.
2019-05-26 16:18:47.056642 JST | observation space: Box(3,)
2019-05-26 16:18:47.056818 JST | action space: Box(1,)
2019-05-26 16:18:47.224460 JST | expert_score=-203.31068420410156
2019-05-26 16:18:47.225109 JST | num_train_epi=70
2019-05-26 16:18:48.468546 JST | sample: 0.8718sec
2019-05-26 16:18:48.469228 JST | outdir /Users/user/machina/example/garbage
2019-05-26 16:18:48.475059 JST | ------------------  ------------
2019-05-26 16:18:48.475268 JST | PolLossAverage          1.16213
2019-05-26 16:18:48.475474 JST | PolLossStd              0.20314
2019-05-26 16:18:48.475698 JST | PolLossMedian           1.17578
2019-05-26 16:18:48.475883 JST | PolLossMin              0.743538
2019-05-26 16:18:48.476050 JST | PolLossMax              1.57056
2019-05-26 16:18:48.476134 JST | TestPolLossAverage      0.775926
2019-05-26 16:18:48.476208 JST | TestPolLossStd          0
2019-05-26 16:18:48.476281 JST | TestPolLossMedian       0.775926
2019-05-26 16:18:48.476547 JST | TestPolLossMin          0.775926
2019-05-26 16:18:48.476738 JST | TestPolLossMax          0.775926
2019-05-26 16:18:48.476887 JST | RewardAverage       -1289.41
2019-05-26 16:18:48.477021 JST | RewardStd              54.1989
2019-05-26 16:18:48.477150 JST | RewardMedian        -1285.32
2019-05-26 16:18:48.477271 JST | RewardMin           -1404.18
2019-05-26 16:18:48.477401 JST | RewardMax           -1200.5
2019-05-26 16:18:48.477508 JST | CurrentEpoch            0
2019-05-26 16:18:48.477638 JST | ------------------  ------------
2019-05-26 16:19:05.279398 JST | sample: 0.7552sec
2019-05-26 16:19:05.280429 JST | outdir /Users/user/machina/example/garbage
...(中略)...
2019-05-26 16:24:19.457548 JST | ------------------  -----------
2019-05-26 16:24:19.457641 JST | PolLossAverage        -2.19763
2019-05-26 16:24:19.457720 JST | PolLossStd             0.040569
2019-05-26 16:24:19.457795 JST | PolLossMedian         -2.19817
2019-05-26 16:24:19.457868 JST | PolLossMin            -2.2765
2019-05-26 16:24:19.458061 JST | PolLossMax            -2.06869
2019-05-26 16:24:19.458231 JST | TestPolLossAverage    -2.1701
2019-05-26 16:24:19.458352 JST | TestPolLossStd         0
2019-05-26 16:24:19.458442 JST | TestPolLossMedian     -2.1701
2019-05-26 16:24:19.458536 JST | TestPolLossMin        -2.1701
2019-05-26 16:24:19.458669 JST | TestPolLossMax        -2.1701
2019-05-26 16:24:19.458774 JST | RewardAverage       -254.439
2019-05-26 16:24:19.458955 JST | RewardStd             86.3936
2019-05-26 16:24:19.459045 JST | RewardMedian        -242.488
2019-05-26 16:24:19.459119 JST | RewardMin           -364.349
2019-05-26 16:24:19.459191 JST | RewardMax           -127.547
2019-05-26 16:24:19.459263 JST | CurrentEpoch         950
2019-05-26 16:24:19.459334 JST | ------------------  -----------
```

同階層に`garbage`ディレクトリが生成されてmodelやログが保存される

```
python take_movie.py
```

を実行すると、`garbage/optimal_movie`ディレクトリが生成されて、中にベストモデルの結果動画が作成される

![openaigym.video.0.34642.video000004.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61995/536a6526-88e9-0908-6625-c0fcc968eadd.gif)


`take_movie.py`実行時に`objc[35514]: +[__NSCFConstantString initialize] may have been in progress in another thread when fork() was called.`というエラーが発生する場合は、[ここ](https://stackoverflow.com/questions/50168647/multiprocessing-causes-python-to-crash-and-gives-an-error-may-have-been-in-progr)を参考に環境変数を追加して実行するとうまくいく

```
export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
```

# まとめ

サンプルコードをざっと眺めてみると、PytorchをベースにNNと学習のための環境、強化学習アルゴリズムがうまく抽象化されていてコンポーネントになっている。環境とアルゴリズムをテンプレ化しておいていろいろなNNを入れ替えて学習させてみるとか容易にできそう。ドキュメントで説明されている通りの印象を受けた

なんか実用してみたいところ