爆速で Docker コンテナにデータ分析環境を生成するテンプレート を作りました

機械学習の実験における悩みの一つに**実験の再現性**があります。再現性は実験を共同研究者に引き継いたり、ソフトウェアエンジニアにモデルをデプロイしてもらう時に問題になります。残念ながら、機械学習で利用するライブラリは数も多く、アップデートも頻繁に行われます。そのため動作する開発環境を維持、共有するのは難しい問題と言えます。

そこでデータサイエンティストが実験結果を他人に引き継ぐことを容易にするテンプレート、[Cookiecutter Docker Science](https://github.com/docker-science/cookiecutter-docker-science) を作ってみました。このテンプレートは機械学習の実験環境を Docker コンテナ上に爆速で構築できます。仮想環境なのでライブラリ群の不足やバージョンの不一致に悩まされず実験結果を確実にシェアできます。

また Docker でコンテナを作ったり、削除したり設定したりといった作業の煩雑さを低減するための機能を提供しています。そのため、データサイエンティストは Docker コマンドの詳細に気を使うことなく作業に集中できます。

## TL;DR

- Cookiecutter Data Science を利用するとデータ分析環境の再現性が向上しますが、それでもシステムライブラリなど、環境に依存する部分が統一化できないので不十分です
- そこで仮想化ツール Docker を利用してデータ分析環境を構築するテンプレート（[Cookiecutter Docker Science](https://github.com/docker-science/cookiecutter-docker-science)）を作ってみました
- Docker コンテナ上に環境が構築されるので再現性が高く、実験結果を確実にシェアできます。コンテナ上で立ち上げる Jupyter Notebook サーバもホスト側からシームレスにアクセスできます
- 機械学習のスクリプトはホスト環境から好きなエディタで編集できます

## 準備

本節ではCookiecutter Docker Science に関連するトピックについて解説します。

### Cookiecutter

Cookiecutter はプロジェクトを指定したテンプレートを元に生成してくれるツールです。たとえば、Cookicutter をインストールした後、以下のコマンドを実行すると Python のプロジェクトが生成されます。プロジェクトを生成する時に、プロジェクト名や著者など質問が投げられ、答えてゆくとプロジェクトが最後に生成されます。

```console
$ cookiecutter https://github.com/audreyr/cookiecutter-pypackage.git full_name [Audrey Roy Greenfeld]: Takahiko Ito
email [aroy@alum.mit.edu]: takahiko03@gmail.com
github_username [audreyr]: takahi-i
project_name [Python Boilerplate]: ExcellentMLProject
project_slug [excellentmlproject]:
project_short_description [Python Boilerplate contains all the boilerplate you need to create a Python package.]: This project contains a excellent implementation of excellent machine learning algorithm.
pypi_username [takahi-i]:
version [0.1.0]:
use_pytest [n]:
use_pypi_deployment_with_travis [y]:
Select command_line_interface:
1 - Click
2 - No command-line interface
Choose from 1, 2 [1]: 1
create_author_file [y]: y
Select open_source_license:
1 - MIT license
2 - BSD license
3 - ISC license
4 - Apache Software License 2.0
5 - GNU General Public License v3
6 - Not open source
Choose from 1, 2, 3, 4, 5, 6 [1]: 4
```

これでプロジェクトが Python 用のプロジェクト生成されました。プロジェクトディレクトリを覗いてみると、Python プロジェクトで利用するファイル、ディレクトリが生成されているのが分かります。

```console
$ ls excellentmlproject
AUTHORS.rst          LICENSE              README.rst           requirements_dev.txt tests
CONTRIBUTING.rst     MANIFEST.in          docs                 setup.cfg            tox.ini
HISTORY.rst          Makefile             excellentmlproject   setup.py             travis_pypi_setup.py
```

本節で紹介したのは Python プロジェクトでしたが、Cookicutter は他にも色々なテンプレートが提供されています。次節で紹介する Cookiecutter Data Science もその一つです。

### Cookiecutter Data Science

Cookiecutter Data Science は Cookiecutter で利用できるテンプレートの一つです。Cookiecutter Data Science ではデータサイエンティストがデータ分析業務をするプロジェクトの雛形を自動生成してくれます。

Cookiecutter Data Science については[テンプレートを使って爆速で機械学習プロジェクトを作成する](https://qiita.com/Hironsan/items/4479bdb13458249347a1)で詳しく解説されています。

Cookiecutter Data Science テンプレートを使うことで、ディレクトリ構造が統一され機械学習系のプロジェクトの知識がシェアしやくすなり、業務の引き継ぎコストの低減が期待できます。

しかし Cookiecutter Data Science を利用した場合でもシステムライブラリが環境に入っていなかったりすると実験が再現できません。とくに Deep Learning での実験ではシステムライブラリへの依存が多くなります。

そこで以下の節では仮想化ツール、 Docker を利用してデータ分析における実験環境の再現性をさらに向上してみます。

## Docker コンテナでのデータ分析とその困難

Docker は Vagrant や VMWare のような OS の仮想化ツールです。Docker コンテナ上で作業すると、ライブラリのインストールなどでローカル環境を汚すことなく作業できます。さらに必要なライブラリ群のインストールは設定ファイルに記述されているので確実に作業環境を再現できます。

Docker のインストール方法については [DockerをMacにインストールする (更新：2017/5/26)
](https://qiita.com/kurkuru/items/127fa99ef5b2f0288b81)を参照してください :pray: Mac 以外のプラットフォームについては、グーグルで「Docker インストール」で検索するとインストール方法が出てきます。

しかし Docker 環境での作業には困難を伴います。ライブラリを追加するたびに、Docker イメージ、コンテナを再生成しなくてはなりません。また Dockerコンテナ上で立ち上げた Jupyter Notebook をローカル環境で利用するにはポートフォワード設定を指定して生成しなくてはなりません。

これらの作業は一つ一つはそれほどコストではありませんが、コマンドを覚えておくのが大変です。

## Cookiecutter Docker Science

今回作成した Cookiecutter Docker Science は Cookiecutter data science と同様に機械学習に最適なディレクトリ構造を自動で生成します。さらに Cookiecutter Docker Science は Docker を利用した作業をサポートする機能を幾つか提供します。

### クィックスタート

本節では cookiecutter-docker-science を使ってプロジェクト作成から、Jupyter Notebook の立ち上げまでをやってみます。

#### 準備

まだ `cookiecutter` をインストールしていない場合には、以下のコマンドでインストールします。

```sh
pip install cookiecutter
```

#### プロジェクト作成

以下は　cookiecutter-docker-science を利用してプロジェクトを自動生成している様子です。

```console
$ cookiecutter git@github.com:docker-science/cookiecutter-docker-science.git
project_name [project_name]: food-image-classification
repo_name [food-image-classification]:
jupyter_host_port [8888]:
description [Please Input a short description]: This repository contains experiments on image classification
data_source [Please Input data source in S3]: s3://data/images
Select use_nvidia_docker:
1 - no
2 - yes
```

これでプロジェクトディレクトリ（food-image-classification）が生成されました。

```console
$  cd food-image-classification
$  ls
Makefile                  config                    docker                    model                     requirements.txt
README.md                 data                      food-image-classification notebook                  scripts
```

プロジェクトディレクトリ内に `Makefile` を始めとして多数のファイルが生成されているのが分かります。プロジェクトディレクトリで、`make` コマンドを実行すると、Makefile が提供するターゲットの一覧が表示されます。

```console
$ make
help                 show this message
init                 initialize repository for traning
sync-from-source     download data data source to local envrionment
init-docker          initialize docker image
init-docker-no-cache initialize docker image without cachhe
sync-to-source       sync local data to data source
create-container     create docker container
start-container      start docker container
jupyter              start Jupyter Notebook server
test                 run test cases in tests directory
lint                 check style with flake8
profile              show profile of the project
clean                remove all artifacts
clean-model          remove model artifacts
clean-pyc            remove Python file artifacts
distclean            remove all the reproducible resources including Docker images
clean-data           remove files under data
clean-docker         remove Docker image and container
clean-container      remove Docker container
clean-image          remove Docker image
```

#### Docker コンテナを作る

では早速 Docker コンテナを作成してみましょう。`make init-docker` を実行すると Docker イメージが作成され、その後 `make create-docker-container` を実行すると Docker コンテナが生成され自動的にログインされます。この時プロジェクトディレクトリはコンテナ内の `/work` にマウントされます。

#### Jupyter Notebook を立ち上げる

コンテナ内で `make jupyter` を実行すると、Jupyter Notebook が起動します。コンテナ内で立ち上がったJupyter Notebook はプロジェクト生成時に指定されたホストポート（デフォルト `8888`）にフォワードされます。

```console
$ make jupyter
jupyter-notebook --ip=0.0.0.0 --port=8888 --config=config/jupyter_config.py
[I 00:40:04.059 NotebookApp] Serving notebooks from local directory: /work/notebook
[I 00:40:04.059 NotebookApp] 0 active kernels
[I 00:40:04.059 NotebookApp] The Jupyter Notebook is running at:
[I 00:40:04.059 NotebookApp] http://0.0.0.0:8888/?token=2db969a134896b3f84c9231fecb76cc51bb2a59bdb20d55c
[I 00:40:04.060 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[W 00:40:04.061 NotebookApp] No web browser found: could not locate runnable browser.
[C 00:40:04.061 NotebookApp]

    Copy/paste this URL into your browser when you connect for the first time,
    to login with a token:
        http://0.0.0.0:8888/?token=2db969a134896xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

これで Docker　コンテナに Jupyter Notebook が立ち上がりました。Docker コンテナとホストPC間のポートフォワード設定は cookiecutter-docker-science がやってくれています（デフォルトでは Docker コンテナの `8888`　ポートをホスト PC の `8888` ポートにフォワードするように設定されます）。

ウェブブラウザで　http://localhost:8888 にアクセスすると、以下のように Jupyter Notebook にアクセスできます。

<img width="1157" alt="Screen Shot 2018-02-14 at 22.28.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/61252/afbe96ff-5a18-768c-dc31-cf2d4955131d.png">

### ディレクトリ構造

Cookiecutter Docker Science は以下のディレクトリ、ファイルを含むプロジェクトを自動生成します。

```
├── Makefile                          <- 設定や Docker コンテナ上での作業をサポートするターゲットを提供します。
│                                        
├── config                            <- 設定ファイルが入っています。
│   │                                    
│   └── jupyter_config.py
├── data                              <- 入力データを保存します。
├── docker                            
│   └── Dockerfile                    <- Docker イメージの設定。必要なライブラリがあれば順次設定を追加して下さい。
│                                        
├── model                             <- 機械学習の学習結果（モデル）を保持するディレクトリ。
├── my-data-science-project           <- cookie-cutter-docker-science はプロジェクト名と同名の
│   │                                    　ディレクトリを生成します。ここにライブラリファイルを追加して下さい。
│   └── __init__.py
├── notebook                          <- このディレクトリに　Jupyter Notebook の　ipynb ファイルが生成されます。
├── requirements.txt                  <- 実験に必要なPythonライブラリを追加します。ここに記載されたライブラリ
│ 　　　　　　　　　　　　　　　　                            　　　　　　　は生成される Docker イメージにインストールされます。
│                                        
└── scripts                           <- ユーザが実行するスクリプトはこのディレクトリに保存します。
```

### Cookiecutter Docker Science が提供する機能

Cookiecutter Docker Science はデータサイエンティストが Docker コンテナ内で作業するのをサポートする機能をいくつか提供します。具体的には以下のものがあります。

#### 実験用 Docker コンテナの起動

プロジェクトで使用しているDockerコンテナの起動（及び attach）を `make start-container` コマンドで実行できます。コンテナ名、イメージ名はプロジェクト生成時に決定されるので、Dockerコマンドを実行するときのように覚える必要はありません。

#### Docker イメージ、コンテナの追加 / 削除

`make init-docker`　および　`make create-container` でプロジェクトと同名のDockerイメージ及びコンテナを生成します。

#### Jupyter Notebook を起動

`make jupyter` を実行すると Docker コンテナ上に Jupyter Notebook を立ち上げます。Docker コンテナ側からホストPCへのポートフォワードの設定も自動でなされているので、ホストPCのウェブブラウザからシームレスに接続できます。

#### コンテナの状態確認

コンテナ内、`make profile` を実行するとポートフォワードの設定やコンテナの状態が表示されます。


## Dockerコンテナで実行する機械学習用のコードをホスト環境で編集する

Cookiecutter Docker Science では、Dockerコンテナ上で Jupyter や作成した機械学習のスクリプトを実行できます。しかし Docker コンテナには十分なエディタが存在しません。もちろん、Vim や Emacs などのエディタを Docker イメージにインストールできるのですが、すべてのプロジェクトに設定ファイルを含めて環境を作るのは大変です。また　PyCharm や VSCode などのIDEを利用することもできません。

Cookiecutter Docker Science で `make create-container`　を実行するとプロジェクトのトップディレクトリを Docker コンテナに自動マウントします。ホスト環境のトップディレクトリはマウントされた状態なので、ホスト環境でファイルを編集すると、そのまま Docker コンテナに反映されます。
そのため、ユーザはホスト環境から好きなエディタを利用してファイルを編集し、実験や機械学習ライブラリを作成できます（以下のイメージを参照）。

![](https://docker-science.github.io/resources/images/edit-with-preferred-editors.png)

## まとめ

機械学習プロジェクトの再現性を向上するための、環境を爆速で作る Cookiecutter Docker Science の紹介をしました。まだまだ改良点があります。Issue登録などで改善点を教えていただけるとたすかります :pray: 

## 参考資料

今回紹介した cookie-cutter-docker-science の全体像については[Cookiecutter for ML experiments with Docker](https://speakerdeck.com/takahiko03/cookiecutter-for-ml-experiments-with-docker)に詳しく記述されています。

また、Cookiecutter Docker Science を開発したモチベーションや開発状況については [Cookiecutter Template for Data Scientists Working in Docker containers](https://speakerdeck.com/takahiko03/cookiecutter-template-for-data-scientists-working-in-docker-containers) にかかれています。