Docker + TensorFlow + matplotlibでグラフを表示させる

# はじめに
TensorFlowの利用はDockerを使うと簡単です。
TensorFlowのDocker公式イメージにはmatplotlibがインストールされているのですが、そのままではpyplot.show()などが使えません。
要するにデフォルトではGUIが表示できません。
そこで今回はTensorFlow + Docker + matplotlibでGUIを利用可能にします。
また、今回はホストOSがwindowsであるという前提で進めます。

なお、今回の内容はGitHubで公開している[スライド](https://hyt-sasaki.github.io/docker_slides/)の内容に基づいています。

# Dockerのインストール
Dockerのインストールについては[ここ](http://qiita.com/hyt-sasaki/items/8f8312e277d1a4815ab6)を参照してください。

# MobaXtermのインストール
MobaXtermはWindowsで動作するターミナルです。
このMobaXtermはX11フォワーディング機能を標準機能として備えています。
今回はこのMobaXtermを利用してdockerから起動したGUIを利用可能にします。

[公式サイト](http://mobaxterm.mobatek.net/MobaXterm_Setup_9.1.msi)からインストーラをダウンロード

あとはインストーラの指示に従うとインストールが完了します。

# MobaXtermからdockerを利用
まずはDocker Quickstart TerminalからDocker machineを立ち上げます。
そのターミナル画面からDocker machineのIPアドレスを確認します。

![docker_terminal_ip.png](https://qiita-image-store.s3.amazonaws.com/0/118119/9f63024e-b598-9a2a-f76e-03b44681684e.png)

続いて先ほどインストールしたMobaXtermを起動します。
起動したらSessionボタンをクリックします。

![mobaxterm.png](https://qiita-image-store.s3.amazonaws.com/0/118119/581cc9d8-c0f8-7eb0-3abf-da7d6c5cf243.png)

Sessionボタンを押すと、SSH接続の設定ができます。
以下のように各項目を設定してください。

![mobaxterm_ssh.png](https://qiita-image-store.s3.amazonaws.com/0/118119/6033891e-d231-6769-8f78-aa0ccce02c75.png)

上記の画面でOKを押すとdocker machineにSSH接続できます。
なお、初回のSSH接続時には, ログインパスワードを聞かれるはずです。

パスワードは`tcuser`と設定されています。
うまく行けば、次のような画面になるはずです。

![docker_logined.png](https://qiita-image-store.s3.amazonaws.com/0/118119/201e9d84-b70e-f519-7c50-5f8e923157be.png)

また、今後の利用を考えてsession名を変更しておくと良いでしょう。

![Image.png](https://qiita-image-store.s3.amazonaws.com/0/118119/fb8148cc-d599-23d7-a633-5390fd85bb47.png)


# DockerからTensorFlowを利用する
MobaXtermからdockerが利用できるようになったら、TensorFlowイメージをダウンロードします。
ただし今回はmatplotlibでグラフが表示できるように、TensorFlowイメージに手を加えた[dockerfile](https://github.com/hyt-sasaki/docker_slides/blob/master/dockerfiles/TensorFlow/Dockerfile)を利用します。


以下、docker machineに接続したMobaXterm上で操作してください。
なお、今回は二通りの方法を紹介しますが、後者のDocker Hubを利用する方が簡単です。

## Dockerfileからイメージを作成する場合
```bash
# Windowsのユーザ名を`hoge`と仮定
# 作業用のディレクトリを作成
$ mkdir -p /c/Users/hoge/docker
$ cd /c/Users/hoge/docker
$ git clone https://github.com/hyt-sasaki/docker_slides.git 
$ cd docker_slides
$ git checkout master
```
```bash
$ docker build -t mytensorflow dockerfiles/TensorFlow
$ docker run -d --name tensorflow -p 8888:8888 -p 6006:6006 -p 10022:22 -v "${PWD}"/testcodes/TensorFlow:/home/developer/notebooks/host mytensorflow
```

以上で, TensorFlowのコンテナが作成されました。
ちなみに、このコンテナの`/home/developer/notebooks/host`ディレクトリとWindowsの`C:\\Users\hoge\docker\docker_slides\testcodes\TensorFlow`は共有フォルダになっています。

### docker buildでエラーが出る場合

`W: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/trusty/InRelease`
というエラーが出る場合、docker machineのDNSがうまく動作していないことが考えられます。
以下のコマンドで適当なDNSサーバを追加してから、もう一度buildコマンドを実行してください。

```bash
$ echo "nameserver 8.8.8.8" >> /etc/resolv.conf
```

## [Docker Hub](https://hub.docker.com/)からイメージをダウンロードする場合

```bash
# Windowsのユーザ名を`hoge`と仮定
# 作業用ディレクトリの作成
$ mkdir -p /c/Users/hoge/docker/work/tensorflow
$ cd /c/Users/hoge/docker/work/tensorflow
$ docker run -d --name tensorflow -p 8888:8888 -p 6006:6006 -p 10022:22 -v "${PWD}":/home/developer/notebooks/host hytssk/tensorflow
```

共有フォルダは`C:\\Users\hoge\docker\work\tensorflow`。

# コンテナにSSH接続する
今回立ち上げたコンテナではSSHサーバが動作しています。そこで、そのコンテナにSSHで接続します。
上記のコンテナではSSH接続用に10022番のポートが利用できます。
そこでMobaXterm上で、コンテナへのSSH接続の設定を行います。

まずはMobaXtermのSessionボタンを押してください。

![mobaxterm.png](https://qiita-image-store.s3.amazonaws.com/0/118119/581cc9d8-c0f8-7eb0-3abf-da7d6c5cf243.png)

あとは、以下の画面の通りに設定を行うとコンテナに接続できます。
![mobaxterm_x11_ssh.png](https://qiita-image-store.s3.amazonaws.com/0/118119/5c0c366c-9833-6617-2d22-d4d98da26deb.png)

以下はExcute commandの項目のコピペ用です。

```bash
export DISPLAY=`echo $SSH_CLIENT | cut -d' ' -f1`:0.0
```
初回ログイン時にはパスワードが求められます。
パスワードは`developer`です。

# 動作確認
コンテナにログインできたら、テストプログラムで動作確認を行います。
以下、MobaXtermで動作しているコンテナ上ターミナルでの操作です。

```bash
$ cd notebooks/host
$ python matplotlib_test.py
```

```py:matplotlib_test.py
import numpy as np
import matplotlib.pyplot as plt

x = np.arange(-3, 3, 0.1)
y = np.sin(x)
plt.plot(x, y)
plt.show()
```

上記のコマンドを実行して、グラフが表示されれば成功です。

![matplot_test.png](https://qiita-image-store.s3.amazonaws.com/0/118119/53cbda2e-d76f-b662-8b6b-dcc63f07149e.png)

# 普段の利用方法
コンテナはホストマシンをシャットダウンすると動作が停止してしまいます。
ホストマシン再起動後はコンテナを再開させる必要があります。

以下、手順です。

1. Docker Quickstart Terminalを実行し、docker machineを立ち上げる。
2. MobaXtermを起動し、画面左のSessionsタブからDockerへのSessionを立ち上げる。
3. `$ docker start tensorflow`というコマンドを実行し、コンテナを起動し直す。
4. MobaXtermのSessionsタブからTensorFlowのコンテナを選択し、Sessionを立ち上げる。
5. Windowsの`C:\\Users\hoge\docker\docker_slides\testcodes\TensorFlow`フォルダ内に実行したいコードを置く。
6. コンテナ上でコードを実行する。

# Tips: LinuxでmatplotlibのGUIを動作させる
LinuxからmatplotlibのGUIを動作させる場合、以下のコマンドでコンテナを立ち上げます。

```bash
$ xhost +
$ docker run -d --name tensorflow -p 8888:8888 -p 6006:6006 -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix mytensorflow
$ docker exec -it tensorflow bash
```