メモ帳

python, juliaで機械学習をやっていく

PythonからJulialangの関数を使える、Python + Julia + TensorFlow + Jupyter 環境をDockerのマルチステージビルドで構築する

前処理の高速化のためにPythonからJulialangの関数を使える、Python + Julia + TensorFlow + Jupyter 環境をDockerのマルチステージビルドで構築してみました。

Dockerでデータ分析、機械学習モデル開発用の環境構築

データ分析や機械学習モデルをJupyter Notebook上で、開発することは主流になっていると思います。 ですが、環境構築は結構大変ではないでしょうか。データ分析やモデル開発するぞという気分の時にインフラが原因で問題が起こるのは避けたいはずです。 また、チーム間でのパッケージのバージョン違いも厄介な問題を引き起こす可能性があります。

そこで、Dockerでの開発環境構築が便利です。一度インフラ環境を構成するだけで、Dockerfileを使い回せばチームで環境をそろえられます。 さらに、開発環境の再現性を担保できるという旨味もあります。

よくある以下のライブラリの使用を想定すると、

  • tensorflow (tensorflow-gpu)
  • sklearn

tensorflowでGPUを使う際に 以下の公式ドキュメントで紹介されているベースイメージが、バージョン管理とjupyterの環境構築も一緒にやってくれるという点で便利です。

上記のベースイメージだけでも十分満足の行く環境構築が可能だと思います。

Julialang でボトルネックを解消

pythonは速度に難があるのでどうしても解消できないボトルネックがある場合はnumpy, cython, numbaなどを使ってパフォーマンス改善に努めていくと思います。 ただ、これらは結構クセがあるのでもっとラフに他の速い言語で部分的にコードを置き換えたいなと思っています。

ここで、機械学習数値計算界隈で近年話題にあがることの多いJuliaという言語に注目したいと思います。 公式のイントロダクションでは以下の様に紹介されています。

pythonみたいに楽でc並に速いJuliaが実現した、典型的な動的プログラミング言語からの最も 重要な発展は以下の通りです。

  • 標準ライブラリは、整数演算などの基本操作を含め、Julia自身により 作成されており、コア言語は非常に少なくなっています。
  • C言語のような静的にコンパイルされた言語を使用しているかのような 高いパフォーマンスを発揮します。

https://hshindo.github.io/julia-doc-ja-v0.6/manual/introduction.html

要は、依存関係が少なく、楽な記法で高パフォーマンスがだせるという触れ込みです。 ボトルネックを解消するために部分的に置き換えるにはもってこいだと思います。

なので、今回は上記のtensorflow-gpuとsklearnに加えて、Juliaの関数をPythonから呼びだせる環境を構築します。

dockerのオールインワンのベースイメージは以下がありますが、余計なものがたくさんはいっています。

ここでは、メンテナンス性を上げるために必要なものだけいれられるようなDockerfileを書きたいと思います。

まずは使ってみる

作成したソースコードこちらにあります。 以下のようなディレクトリ構造になっています。

├── README.md
├── docker-compose.yml
├── jupyter_notebook_config.json # jupyterの設定 (暗号化されたpasswordなど)
└── src # メインディレクトリ
    ├── Dockerfile
    ├── demo # デモファイルの格納
    │   ├── counting.jl
    │   └── demo.ipynb
    └── requirements.txt # pip install したいライブラリ一覧

まずはとにかく使い方の説明だけします。 gitとdockerとdocker-composeが使える前提です。 もしまだであれば、以下が詳しいです。

ソースコードgithubからクローン

$ git clone https://github.com/tokusumi/docker-py-julia-tf-jupyter.git

docker-composeで起動

$ cd docker-py-julia-tf-jupyter
$ docker-compose up

すると、jupyter notebookが起動するので, ブラウザから 0.0.0.0/ にアクセスして、password欄にtestとうつと利用可能です。

f:id:atelier-0213:20191021224642p:plain
jupyter notebookからpythonとjuliaの両方が使える

ただし、passwordを変えたい場合は以下です。

$ docker-compose run tf jupyer notebook password

また、簡単なデモもあるのでよければ目を通してもらえればと思います。 圧倒的な速度差です。

f:id:atelier-0213:20191022000322p:plain
PythonとJuliaの速度比較

Dockerfileの説明

肝心のDockerfileについて説明します。

調べると、pythonのベースイメージやjupyterのベースイメージにapt-getでjuliaをいれたり、ソースからダウンロードしてコンパイルしたりという記事がいくつか見つかりました。

何やっているのか見えなかったり、Dockerfileが長くなっていてメンテナンスが大変そうです。 インフラとかlinuxに気を配りたくないのでDockerfileではライブラリの管理程度にとどめたいです。

なので、言語の構築自体はそれぞれの公式イメージにまかせることとします。

複数のベースイメージを使う場合はマルチステージビルドという手法を使います。

マルチステージビルド

マルチステージビルドを行うには、Dockerfile 内に FROM 行を複数記述します。 各 FROM 命令のベースイメージは、それぞれに異なるものとなり、各命令から新しいビルドステージが開始されます。 イメージ内に生成された内容を選び出して、一方から他方にコピーすることができます。 そして最終イメージに含めたくない内容は、放っておくことができます。

つまり、以下の様に書けます。

# juliaのバージョン指定
# juliaが動く環境の構築
FROM julia:1.3.0 as julia

# tensorflow (tf)のバージョン指定 
# tfとjupyterが動く環境の構築 (上記juliaの環境とは切り離されている)
FROM tensorflow/tensorflow:2.0.0-py3-jupyter

# copy Julia build file and set path for julia
# コンパイルされたjuliaのアプリケーションファイルをtfとjupyterが動く環境にコピー
COPY --from=julia /usr/local/julia /usr/local/julia

# tfとjupyterが動く環境でjuliaのpathを通す
ENV PATH=/usr/local/julia/bin:$PATH

# --- ここまででtensorflowとjupyterとjuliaが動く環境が完成 ---
# juliaを構築した環境は最終イメージには含まれません

すごく見通しがいいと思います。 また、juliaのソースファイルのダウンロードなどを行った環境は最終イメージには含まれないので容量も小さくなります。

juliaを.ipynb形式でインタラクティブに動かせるようにする

スクリプトからjuliaに直接IJuliaをインストールします。 不必要な場合はコメントアウトしてください。

# install package to use Julia in Jupyter Notebook
RUN julia -e 'using Pkg; Pkg.add("IJulia"); using IJulia'

juliaをpythonから呼び出せるようにする

pip 経由でjuliaというパッケージをインストールします。 また、スクリプトから直接 julia.installをよんで、juliaに依存パッケージをインストールします。 不必要な場合はコメントアウトしてください。

# install packages to call Julia function in Python
RUN python -m pip install pip --upgrade
RUN python -m pip install julia \
    && python -c 'import julia; julia.install()'

pythonにパッケージをインストールする

pythonのDockerfileでは鉄板だと思いますが、以下をかきます。 なお、requirements.txtはADDで入れないと、requirements.txtに変更がなくてもdocker imageのビルドの度にパッケージをすべて再インストールしてしまうので時間をむだにします。

WORKDIR /notebooks
ADD requirements.txt /notebooks/requirements.txt

RUN python -m pip install -r requirements.txt
COPY . /notebooks

jupyter notebook の起動

CMD jupyter notebook --ip=0.0.0.0 --allow-root

以上です。 ここまでやれば後は使いまわして、インフラや環境構築のことを考えずにデータ分析や機械学習の開発に集中できると思います。 よければ使ってみて下さい!