「ゼロから作るDeep Learning」の環境をDockerで作る

# ゼロから作るDeep Learning

僕はpythonも機械学習も全く知識が無かったのですが、ここ最近のニュースでも話題が多いですし、何か触りだけでも勉強できたらなと思っていたところにオライリーの[ゼロから作るDeep Learning](https://www.oreilly.co.jp/books/9784873117584/)がわかりやすいという話を聞いて買ってみました。

適度に数学的な部分も省かれてて、自分のような厳密な証明とかよりイメージを知りたいようなライトな感じの人にはとてもおもしろく読めました。また解説されていることがソースレベルで説明されているのが大変わかりやすかったです。

で、普段pythonとかをガリガリ書いている人はいいんだと思いますが、とりあえずやってみたいときに、pythonいれてnumpyいれて、matplotlibいれてやるのも（一回作ってしまえばいいですが）ちょっとメンドいですよね。

ならDockerで作ってしまおうと思ったのですが、この本ででくるmatplolibでグラフ描画（GUI）があるところでちょっとハマったので記事として残しておきます。
(が、mac側にも何個かライブラリ入れたり、コンテナ起動前の作業があったり若干微妙かもしれないと後から気付きましたが。。)

## 環境構築
最初一式楽に入れようと思って`Jupiter notebook`とかも考えたんですが、Dockerイメージが4Gぐらいあるとかお手軽でなかったのと、この「ゼロから作るDeep Learning」自体が「最低限のライブラリでゼロから作ってみよう」というコンセプトのようなのでそれに必要なライブラリだけいれる環境が欲しいとおもって自分で作ってみました。

*注意*
ただし僕の環境がmacなのでGUIの部分のメインはmac用です。

### 必須環境

- Python3系環境
- numpy
- matplotlib

がこの本のサンプルで必要なモノのようです。

このうち、この本でよく出てくるグラフ描画の部分(matplotlib)でGUIの環境があるととてもいい感じにすすめていけるのですが、これをDocker環境で行うとなるとDocker環境からグラフ描画出来る仕組みが必要になります。

いままでそういうことをしたことはなかったので出来るのかどうかわからなかったですが調べてみると

[DockerコンテナのGUIをMac側に飛ばして表示させよう](http://qiita.com/akiko-pusu/items/e42aab2df1a5772f9585)

というナイスな記事がありました。これを元に作ってみたところ、コンパクトにこの本をすすめる環境が出来きました。

### Docker環境構築

Dockerファイル自体はライブラリを入れるだけなので、`Docker hub`の公式のpythonイメージを元に必要なライブラリを入れます。

```
FROM python:3.5.2

WORKDIR /var/python

RUN pip install \
        ipython \
        numpy \
        matplotlib

CMD ["ipython"]
```

で、この環境で作ったDockerコンテナの中で、例えば、

```py3
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()
```

というようなスクリプトを実行してmac側でグラフ描画したいわけです。

内容は上記のリンクのままですが、mac側のIPアドレスを元にDockerコンテナ側からグラフの内容を送ってもらうために、

- mac側にXサーバ(`XQuartz`)を入れる。
- `socat`でDockerコンテナ側からの描画内容を受けるポートをたててそれをmac内のXサーバに渡すようにする

の二点を行うことでDockerで実行しているpythonからmac側にグラフの内容を描画することができました。

#### 必要ライブラリのインストール
`socat`と`XQuartz`を`brew`で入れます。

```
brew install socat
brew install caskroom/cask/brew-cask
brew cask install xquartz
```

これで準備完了です。

## Dockerのビルド

Docker build自体は通常通り、上記の`Docker`ファイルで行います。
ここではイメージ名を`python-dl`としています。

```
docker build -t python-dl .
```

## 実行！

まずmac側で`X`の準備を行います。
```
socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\"
```

参考記事では事前に明示的に`open -a XQuartz`を実行していましたが、僕が試した限りでは特に事前に実行していなくても必要になったら勝手に起動されているようでした。

これで準備が整ったので、dockerコンテナを起動します。

先程ビルドしたイメージを起動する際に、コンテナ側にXサーバのアドレスとしてmac側のipアドレスを渡すことで`socat`で作った口からmac側にGUIの描画を行います。

mac側のIPアドレスはおそらく多くの人が`ipconfig en0`で取得出来ると思うのでこの内容からipアドレスを取得するために

```sh
ifconfig en0 | grep -v inet6 | grep inet | awk '{print $2 ":0"}'`
```

で取得します（実際には`macのIPアドレス:0`をコンテナに渡すので上記のようなスクリプトになっています)。

また各種サンプルのソースをマウントするために、`-v`でカレントディレクトリをマウントする、などを考慮して下記コマンドでコンテナを起動します。

```sh
docker run --rm -it -e DISPLAY=$(ifconfig en0 | grep -v inet6 | grep inet | awk '{print $2 ":0"}') -v $(pwd):/var/python python-dl bash
```

これでコンテナ側のbashが起動するので、サンプルとして`samples/sample01.py`に、

```py3
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()
```

があるとして、

```sh
python samples/sample01.py
```

で、下記のようなグラフがmac側で描画されれば成功です。

<img width="300" alt="スクリーンショット 2016-12-10 13.56.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/34692/2368ebcb-d032-783a-88d2-2c5dc1fc135f.png">

## その他

ここまでの環境(＋α)をいれた内容を

https://github.com/pocari/python-dl-docker

においています

###書籍のサンプルコードも一緒に取得する
この本のサンプルは`github`に[登録](https://github.com/oreilly-japan/deep-learning-from-scratch/tree/dd866b35c7fe05798470ca94cf51f405f7be0e55)されているので、それのリポジトリを`book-sample`というフォルダ以下にgitのサブモジュールとして登録しているので、

- この記事のリポジトリclone

  ```
  git clone https://github.com/pocari/python-dl-docker
  ```

- 書籍のサンプルコードディレクトリのコードをclone

  ```
  git submodule update -i
  ```

すれば、書籍のサンプルも実行出来ます。

例)上記の`docker run`コマンドでコンテナに入った後

```sh
cd samples/book-sample/ch07
python apply_filter.py
```

で、下記のような結果がmac側で表示されます。
<img width="600" alt="スクリーンショット 2016-12-11 0.46.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/34692/465d4a41-a863-ad5d-c90a-b8f35f3696c6.png">