TensorFlowをMac & Dockerで使ってみたよ

# はじめに

TensorFlowは、機械学習用のアルゴリズムを記述するためのインターフェースで、大規模システムからスマホまで、幅広い環境で使えるのが利点のようです。

Qiitaでもかなり話題になっており、現時点ですでに**100以上の投稿**があります。そのため、もう特に書くことはないのかなーと思ってましたが、Mac + Dockerの環境でインストールする例が見当たらなかったので、そちらのメモを書いておくことにしました。TensorFlowの基本的な解説を知りたい方は、[こちらの記事を御覧ください](http://qiita.com/icoxfog417/items/fb5c24e35a849f8e2c5d)。

# Dockerを使った理由

今まで使ったことがなかったので面白そう、というのが主な理由ですが、MacでTensorFlowを使う場合は、Dockerでインストールするのが簡単だよ、と[こちらの記事](http://www.raydaq.com/getting-started-with-tensorflow-mac/)に書いてあったせいもあります。Windowsの場合も、Dockerを使うのが一番楽、と[こちらの方](https://github.com/tensorflow/tensorflow/issues/42)で言われてます。

## Docker環境の準備

まず、[こちら](https://www.docker.com/docker-toolbox)からDocker Toolboxをダウンロードして、インストールしましょう。これにより、VirtualBox（仮想化ソフト）、Dockerクライアント、などが一括インストールされます。
インストールの途中で"Choose a tool to get started with Docker"というプロンプトが出て、Docker Quickstart TerminalかKitematicを選ぶことができますが、ここはDocker Quickstart Terminalを選びましょう。

<img width="629" alt="Docker.png" src="https://qiita-image-store.s3.amazonaws.com/0/58503/6d8aa2d1-ad64-1999-e4f5-1225f1d5f244.png">


すると、ターミナルが起動し、defaultと言われるDocker machine（Docker用の仮想マシン）の起動などが行われ、最終的にDockerが走り出します。

<img width="510" alt="DockerQuickStart.png" src="https://qiita-image-store.s3.amazonaws.com/0/58503/c99f2ac7-9ff3-8a3b-7336-fa462b311ad3.png">


ちなみに、このDocker Quickstart Terminalはアプリケーション/Dockerフォルダ内に保存されています。

Dockerがうまくインストールされたかを確認するため、`docker run hello-world`と打ってみましょう。すると、
```
Hello from Docker. 
This message shows (以下略)
```
を含む一連のメッセージが出るはずです。

<img width="561" alt="DockerRunHelloWorld.png" src="https://qiita-image-store.s3.amazonaws.com/0/58503/addacc12-a825-9cab-f2b3-ff9e31346133.png">


これで、動作確認できました。

## TensorFlowのDocker containerを起動する。

Dockerでは、OSとアプリケーションをパッケージ化した「image」をdockerfileからビルドとしてレポジトリに登録し、ユーザーの環境上のDockerクライアントでそのイメージを実行することで、アプリケーションを含むcontainerを作成します。

[公式にある通り](https://www.tensorflow.org/versions/master/get_started/os_setup.html#docker_install)、Tensorflowのcontainerは以下のコマンドで作成します。

`$ docker run -it b.gcr.io/tensorflow/tensorflow`

ここで、`docker run`はコンテナを作成するコマンド、オプション `-it` はコンテナ内にシェルを起動させてコマンド操作をするのに使います。`b.gcr.io/tensorflow/tensorflow`はDockerイメージの場所です。MacやWindows環境では、GPUサポートは無いので悪しからず。

コマンドを実行させると、サーバーからイメージをダウンロードして、シェルのプロンプトが出てきます。

<img width="565" alt="ImageLoad.png" src="https://qiita-image-store.s3.amazonaws.com/0/58503/f9f00d8a-d987-5616-d1bb-13aad2469e83.png">


ここで、`~# python`

の形で、pythonターミナルを起動できます。とりあえず、[公式にあるサンプル](https://www.tensorflow.org/versions/master/get_started/os_setup.html#docker_install)を入力してみましょう。

```
>>> import tensorflow as tf
>>> hello = tf.constant('Hello, TensorFlow!')
>>> sess = tf.Session()
>>> print(sess.run(hello))
Hello, TensorFlow!
>>> a = tf.constant(10)
>>> b = tf.constant(32)
>>> print(sess.run(a + b))
42
>>>
```

うまくいったら、`exit()`をタイプして、pythonターミナルを終了できます。Docker containerのシェル自体は、exitで終了できます。

## デモモデルを実行する

[こちらの公式チュートリアル](https://www.tensorflow.org/versions/master/tutorials/mnist/beginners/index.html)にある手書き文字認識のデモモデルを実行します。結構メモリを必要とするので、あらかじめdocker machineのメモリを増やします。おそらく、この時点ではDocker Quickstartが起動したdefaultマシーンが起動しているはずです。ターミナルで `docker-machine ls`を実行し、現在走っているDocker machineを確認しましょう。

<img width="288" alt="DockerMachineLs.png" src="https://qiita-image-store.s3.amazonaws.com/0/58503/80410a43-fcc4-56f7-477c-22fa96e46613.png">


また、defaultマシーンの現在のメモリ容量は`docker-machine inspect default`で確認できます("Driver"の"Memory"の部分）。

<img width="213" alt="DockerInspect.png" src="https://qiita-image-store.s3.amazonaws.com/0/58503/8fc6b921-43ab-d92e-45e4-58ce2ba8f67b.png">


CPUは１つ、Memoryは2048(KB)のようです。

ここで、`docker-machine rm default`でdefaultマシーンを停止し、`docker-machine create --driver virtualbox --virtualbox-memory 4096 --virtualbox-cpu-count 4 default`で4CPU, 4096KBメモリのdefaultマシーンを改めて起動しましょう（[参考1](https://github.com/tensorflow/tensorflow/issues/136), [参考2](http://stackoverflow.com/questions/32834082/how-to-increase-docker-machine-memory-mac)）。起動したら、`docker-machine inspect default`で、設定が反映されているか確認してください。

確認できたら、
`docker run -it b.gcr.io/tensorflow/tensorflow`　でTensorFlowコンテナを作成して、
`python -m tensorflow.models.image.mnist.convolutional`でデモモデルを実行してください。ちなみに、-mオプションは、pythonモジュールを実行するときに使います。計算終了まで時間がかかるので、気長に待ってください。


## Mac上のファイルにアクセスする

今度は、自分が書いたTensorFlow用pythonスクリプトを動かします。この場合、ホスト（ここではMacマシン）のディレクトリを指定し、コンテナ内のファイルシステムにマウントする、という方法をとります。まず、ローカルのPCのある場所（ここでは/Users/TensorFlow）に、以下のようなファイルを作ります。

```py:test.py
import tensorflow as tf
hello = tf.constant('Hello, TensorFlow!')
sess = tf.Session()
print sess.run(hello)
```
つぎに、
`docker run -v /Users/TensorFlow:/tensorflow_dev -it b.gcr.io/tensorflow/tensorflow`
とすると、ローカルのTensorFlowフォルダがコンテナ内のtensorflow_devフォルダにマウントされて、コンテナが作成されます。

シェルに入ったら`ls /tensor_flow`でtest.pyがあることを確認してください。

大丈夫なら、`python /tensorflow_dev/test.py`でスクリプトを走らせましょう。もし、エラーメッセージが出たら、ホスト（Mac）上で`test.py`を修正してセーブすれば、コンテナ内の`tensorflow_dev`の`test.py`にも変更が反映されます。うまくいけば、`Hello TensorFlow!`のメッセージが出るはずです。

## おわりに

とりあえず、機械学習どころかDockerやLinuxも怪しい私でも、最低限の作業はできそうです。次はもう少し具体的な問題について取り組んでみます。あと、Windowsでも動かしてみようかな。