ViZDoomをMacにインストールして遊んでみる


[ViZDoom](http://vizdoom.cs.put.edu.pl/) という、[Doom](https://ja.wikipedia.org/wiki/DOOM)をつかった強化学習用のベンチがあります。[コンテスト](http://vizdoom.cs.put.edu.pl/competition-cig-2016)も開催されるそうで胸熱ですね。もうエントリ締め切り過ぎたっぽいですが。(2016/6/27追記：7/25まで延期とのこと）

Mac用はテストしてないとのことで、確かに、落としたそのままではビルドできませんでした。少々模索したら動くようになったので遊んでみました。インストールの説明は見てても楽しくないでしょうからあとに回します。

## サンプルを動かしてみる

さっそくexampleスクリプトを起動しましょう。「左右とショットだけの動作で、最短時間で敵を倒せ」という問題設定に対して、「左右とショットをランダムで選ぶ」というエージェントが組み込まれています。

```
cd example/python
python basic.py
```

<blockquote class="twitter-video" data-lang="ja"><p lang="ja" dir="ltr">Doomを外部プログラムから制御するというViZDoomをインストールしてみた。ATARI環境にくらべて使いやすいし速いし楽しい。 <a href="https://t.co/lNOhykhhwB">pic.twitter.com/lNOhykhhwB</a></p>&mdash; 芦谷達治 (@ashipong) <a href="https://twitter.com/ashipong/status/746887398500376578">2016年6月26日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

exampleやconfigはこれ以外にもいろいろ入っていて、使い方が学べるようになっています。

## 簡単なエージェントを作ってみる

さて、機械学習やDQNとかを導入する前に、まず普通の画像処理で対処します。おなじ問題設定で行きましょう。初期設定を

```
game.set_screen_format(ScreenFormat.CBCGCRDB) # BGR + Depth 4channles
```

としておくことで、出力画像(BGR)にDepthを足した4チャネル画像を取得できます。Depth画像は被写体までの距離を画像にしたものです。Kinectとかを使わずにDepthで遊べるのは楽しいですね。

取得される画像がRGBではなくOpenCV等で使われるBGR配列なのと、[チャネル,y,x] という配列になっていることを考慮して取り扱いをします。取得できる画像は、たとえばこんな感じです。

![rgb_image.png](https://qiita-image-store.s3.amazonaws.com/0/30340/410faf90-311f-e13a-3682-d9092e5c85b1.png "rgb_image.png")

![depth_image.png](https://qiita-image-store.s3.amazonaws.com/0/30340/85663e7d-e7fc-5bfa-b008-dd70b8da05b7.png "depth_image.png")

縁日の射的のような風情になりますね。数値を見ていくとDepth=0に自機がいて、Depth=51に敵がいるということがわかります。ではDepth==51の領域を切り出してみます。

![threshold.png](https://qiita-image-store.s3.amazonaws.com/0/30340/b26ea6d5-c6bb-1b43-2a0f-a51a11f9cbe6.png "threshold.png")


おっと、あたりまえですが、同じ距離にあるカベも切り出されますね。いろいろ方法はあると思いますが、収縮(erosion)で潰してみます。OpenCV任せです。

![eroded.png](https://qiita-image-store.s3.amazonaws.com/0/30340/c95cc136-19cf-da57-c7c4-b987ff8a5e6f.png "eroded.png")


これで敵だけが抽出できたので、矩形で囲んでみます。同じくOpenCV任せです。

![marked.png](https://qiita-image-store.s3.amazonaws.com/0/30340/4f67e60d-73ec-3fa7-70cf-e97e5ba8f2bb.png "marked.png")

ふむ、良い感じですね。自機も同じ手順で抽出しました。

では次にアクションロジックです。といっても単純で、お互いの矩形の中心のx方向のズレをみて、右に動かすか左に動かすかを決めます。相対距離が小さくなったら撃つ、としてみました。どうでしょうか。下が動画です。

<blockquote class="twitter-video" data-lang="ja"><p lang="ja" dir="ltr">depth画像が取れるので、単純な画像処理で自機と敵の位置が取れますね。慣性があるのでただ左右だけ見ていればいいというものでもないようですね。 <a href="https://t.co/4LDLnhcYwF">pic.twitter.com/4LDLnhcYwF</a></p>&mdash; 芦谷達治 (@ashipong) <a href="https://twitter.com/ashipong/status/746951669640945665">2016年6月26日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>


慣性と発射までのディレイが絶妙で、初期位置が中心からずれるとうまくいきません。これだけの単純な問題設定でも、そこそこ学習しがいのある課題であることがわかります。まあもちろん、Doomそのもののゲーム性を高めた結果そうなっているわけなのでしょうけれど。

今日はひとまずここまでにします。ここまでのソースは[こちら](https://github.com/ashitani/ViZDoom_example/blob/master/simple_shoot.py)におきました。DQNやA3Cなど、CNN＋強化学習の枠組みには持ってこいな環境ですね。ATARI環境よりも使いやすいし速いし楽しいです。

(6/28追記）自機の画像はどうもあまり意味が無いどころか誤検出の元なので見ないようにして、ショットボタンの５フレームあとに発砲されるということから、現在の速度の5倍進んだ先に敵がいればショットボタン、という風に変更すると、だいぶ良くなりました。

<blockquote class="twitter-video" data-lang="ja"><p lang="ja" dir="ltr">自機の位置はノイズにしかならないようなので見ない、ショットボタンの5フレームあとで発砲するのでその分を予測、とすると超絶ガンマンできた。 <a href="https://t.co/W0sjKBzsuA">pic.twitter.com/W0sjKBzsuA</a></p>&mdash; 芦谷達治 (@ashipong) <a href="https://twitter.com/ashipong/status/747794396146348034">2016年6月28日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

では最後にMacへのインストール方法を書きます。

## MacOSXへのインストール

（日々updateされているようですからすぐビルド方法が変わるかもしれません。ご注意を）

私の環境は

- OSX El Capitan 10.11.5
- cmake 3.5.1
- python 2.7.11
- sdl2 2.0.4
- boost 1.60.0_2
- boost-python 1.60.0

です。まず必要な物をインストールします。

```
brew install sdl2
brew install boost --with-python
brew install boost-python
```

環境によってはほかにも足りないものがあると思います。cmakeとか。つぎにgitからソースを落とします。

```
git clone https://github.com/Marqt/ViZDoom.git
cd VizDoom
```

CMakeLists.txtの先頭に

```
set(CMAKE_MACOSX_RPATH 1)
```

を追加。さてビルドです。

```
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_PYTHON=ON \
-DPYTHON_LIBRARY=/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/libpython2.7.dylib \
-DPYTHON_INCLUDE_DIR=/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/include/python2.7/
make
```

ビルドできました。WADファイルをコピーします（これは使い方によっては不要かもしれません）。

```
mkdir ~/Library/Application\ Support/vizdoom
cp scenarios/*.wad ~/Library/Application\ Support/vizdoom/
```

open ./bin/vizdoom.appとすればVisDoomアプリが起動しました。つぎにapp内の実体をシンボリックリンクします。

```
cd bin
rm vizdoom
ln -s vizdoom.app/Contents/MacOS/vizdoom .
```

これで冒頭のexample実行ができる状態までいきました。Enjoy!