Google Colaboratory でVNCサーバーを動かして、OpenAI Gym を動かしてみる

[株式会社ACCESS Advent Calendar 2018](https://qiita.com/advent-calendar/2018/access)の20日目の投稿です。

会社のAdvent Calendarですが、完全にネタです。

# Google Colaboratory 上でVNCサーバを動かしたい！？

Google Colaboratory 良いですよね（以下略。詳しくは[こちら](https://qiita.com/tomo_makes/items/b3c60b10f7b25a0a5935)

Google Colaboratory で、[強化学習](https://qiita.com/ikeyasu/items/67dcddce088849078b85)をしようとして障害になるのが、画面を出せないという事です。
せっかくゲーム等を解いているのに、プレイ画面が見れないようでは意味がありません。
そこで、[ChainerRL を Colaboratory で動かす
](https://qiita.com/ikeyasu/items/ec3c88ce13a2d5e41f26)では、画面の画像をアニメーションに変換して、Notebook上に表示していました。
動作の様子は[こちら](https://chainer-colab-notebook.readthedocs.io/ja/latest/notebook/hands_on/chainerrl/quickstart.html)からも確認できます。

ですが、これではリアルタイムに見ているわけではないので、面白くありません。いや、リアルタイムで見る意味なんてないんですが、とにかく面白くありません。

なので、Colaboratory上で、VNC Serverを立てて動作させられないか、と思ったので、色々やってみました。

と思って調べていたら、 https://github.com/KiranArun/Reinforcement_Learning-101-demo でまさにそういうことをやっている人がいた！

ので、この記事は、上記レポジトリでやっている内容を解説しているだけです。
上記レポジトリにもNotebookがありますが、もう少しシンプルにした以下のNotebookで動作を確認しました。

https://colab.research.google.com/drive/1Jk_Lse6AwppNX6dAbFkBA6KGx1KJtV2J

こんな感じで動作しています。

![screen.gif](https://qiita-image-store.s3.amazonaws.com/0/38555/b36ac09a-7836-152f-d769-b9a7cef2cbd0.gif)

# インストール

[(該当部分のセル)](https://colab.research.google.com/drive/1Jk_Lse6AwppNX6dAbFkBA6KGx1KJtV2J#scrollTo=7fPJbOIdpwC8&line=2&uniqifier=1)

細かいaptやpipでインストールしているもの意外に、以下を入れています。

* apt
  * xvfb <== 仮想フレームバッファー。OpenGLを動かすのに必要
  * freeglut3-dev <== OpenGLを動かすのに必要
  * その他いろいろ
* VNC
  * TurboVNC : VNC server
  * NoVNC : ブラウザでVNCを見れるビューワ
  * websockify : WebSocket を使って、TCPへブリッジするライブラリ。NoVNCの一部みたいなもの

* Ngrok
  * ローカルに立てたサーバー中継してくれるサービス

VNCのインストールは大変だったのでサボって[上記リポジトリにあるスクリプト](https://github.com/KiranArun/Reinforcement_Learning-101-demo/blob/master/scripts/install_novnc.sh)を使っています。

# VNCサーバーを起動

[(該当部分のセル)](https://colab.research.google.com/drive/1Jk_Lse6AwppNX6dAbFkBA6KGx1KJtV2J#scrollTo=IUEAaPYX2IlO&line=6&uniqifier=1)

ここはどうも謎があります。

最初の

```
!kill $(ps ax | grep websockify | grep -v grep | awk '{ print $1 }') >/dev/null
!pkill ngrok
!pkill vncserver
!pkill Xvnc
!pkill Xvfb
!pkill x11vnc
```

は念のため、関連するプロセスをKillしておきます。
以下では、VNCサーバーを起動し、ngrokを起動し、ウインドウシステム(openbox)を起動しています。

```py
! timeout 5 /opt/websockify/run 5901 --web=/opt/noVNC --wrap-mode=ignore -- /opt/TurboVNC/bin/vncserver :1 -securitytypes otp -otp -noxstartup 2>/dev/null
get_ipython().system_raw('python /opt/websockify/run 5901 --web=/opt/noVNC --wrap-mode=ignore -- /opt/TurboVNC/bin/vncserver :1 -securitytypes otp -otp -noxstartup > /content/.vnc/stdout 2>&1 &')
get_ipython().system_raw('/opt/ngrok http -config=/content/config.yml 5901 &')
! sleep 1
get_ipython().system_raw('DISPLAY=:1 openbox &')
```

なぜか、VNCサーバーを2回起動しているのは、、謎です。ですが、こうしないとうまく動作しませんでした。
`get_ipython().system_raw()`を使っているのは、バックグラウンドで動作させるためです。（通常の、`!`はバックグラウンドで動作できない）

# ブラウザでアクセス

[(該当部分のセル)](https://colab.research.google.com/drive/1Jk_Lse6AwppNX6dAbFkBA6KGx1KJtV2J#scrollTo=ncmmaur18xyZ&line=4&uniqifier=1)

そして、ブラウザでnoVNCにアクセスします。/content/.vnc/stdout にワンタイムパスワードが出力されているのでそれを使います。また、http://localhost:4045/api/tunnels を見ると、NgrokのPublic URLが見れるので、それにアクセスします。

```
!grep "one-time password:" /content/.vnc/stdout

import requests
import json
r = requests.get("http://localhost:4045/api/tunnels", headers={"content-type": "application/json"})
print(r.json()['tunnels'][0]['public_url'])
```

# OpenGLを使うためXvfbを起動

[(該当部分のセル)](https://colab.research.google.com/drive/1Jk_Lse6AwppNX6dAbFkBA6KGx1KJtV2J#scrollTo=O14Q6_fzNH-7&line=5&uniqifier=1)

ここまでの所で、VNCサーバーは起動しているのですが、Open AI Gymを動かすことはできません。
というのも、Open AI Gymの多くの環境が、OpenGLを使っているためです。
OpenGLを動かすのは骨なので、、Xvfbで仮想ディスプレイを作成し、さらにそこにVNCサーバーを起動します。
そして、VNC Viewerを起動し、そのXvfbの画面を表示しています。

```py
get_ipython().system_raw('/usr/bin/Xvfb :99 -screen 0 768x1024x24 &')
!sleep 1
get_ipython().system_raw('/usr/bin/x11vnc -rfbport 5902 -forever -display :99 &')
!sleep 1
get_ipython().system_raw('DISPLAY=:1 /usr/bin/vncviewer localhost:5902 &')
!sleep 1
get_ipython().system_raw('DISPLAY=:99 xterm &')
```

うーん、これ、最初から、Xvfb のサーバーをnoVncでラップして、Ngrokで公開すればこの入れ子要らないような。。と思うのですが、試していないです。

# ChainerRLを動かしてみる

以降のセルは、ChainerRLを動作させるためのものです。

# まとめ

上記で、Colaboratory上でVNCサーバーを動かすことができました。
が、、全然お手軽じゃないですし、特に意味が無い気がしています。。

明日は、@Yam3939 さんです！