Docker & Anaconda3で機械学習環境を整える
仮想通貨の自動取引について度々取り上げてきましたが、分析に機械学習を活用する中でpythonのscikit-learn等各種ライブラリやJupyter Notebookを使用しています。仮想通貨の自動取引自体にはそれ程多くのパッケージは必要ありませんが、分析作業のためにデータサイエンス用のpythonプラットフォームであるAnacondaをベースとした環境を活用しています。今まで仮想通貨の分析で使用している環境をAnacondaをベースとしてDockerコンテナ上で再現できるイメージを作成してみました(ここではディープラーニング用のライブラリはインストールしていません)。簡単な備忘録となっています。
※AnacondaやDocker自体のインストールについては書いていません
※最新のイメージはXGBoostとOptunaも入れてあります
Why Anaconda?
AnacondaはpythonおよびRによるデータサイエンスを行うことができるオープンソースのプラットフォームで、Windows/Linux/Macでそれぞれサポートされています。pythonで仮想環境を作成するvenvなどを使用せず、Anacondaで使用可能なcondaコマンドでライブラリのインストールや環境分離ができます。Anacondaを使用する理由として、データサイエンスに必要なパッケージが一通り揃っていること、condaによる依存関係の解消や仮想環境構築の環境自体を別途構築する必要がないことが挙げられます(Anacondaはpythonのイメージ強いですがRもできます)。つまり様々な環境において機械学習やディープラーニングなどのデータサイエンスを行う基盤を構築するコストを大幅に下げているのがAnacondaです。[1]
Directly from the platform and without involving DevOps, data scientists can develop and deploy AI and machine learning models rapidly into production. Anaconda provides the tools needed to easily
- 1500個以上のpython/Rのデータサイエンス用パッケージが使用可能
- condaによるライブラリ、依存関係および環境の管理
- scikit-learn / TensorFlow / Theano による機械学習やディープラーニングモデルの構築
- Dask / NumPy / pandas / Numba によるデータ分析
- Matplotlib / Bokeh / Datashader / Holoviews を使用した可視化
python3.7対応のものとpython2.7対応がありますが、基本的にはpython3.7向けを使用しましょう。python2.x系のサポートは2020年迄となっています。
Why Docker?
Anacondaによって機械学習やディープラーニングなどのデータサイエンスを行う基盤を構築するコストは大幅に下がりました。それではなぜAnaconda環境をDockerコンテナへ乗せるのか考えてみます。Dockerはコンテナを使用した仮想化技術です。従って構築した環境を仮想化してイメージ化できるという点が最初の大きな利点となります。
ポータブルな環境は持ち運びでき、再利用が可能であるため複数人で同じ環境を使用することが容易です。依存関係の解消などに追われる必要もありません。ここでVMwareなどの仮想環境で作成したVirtual Machineも仮想化したイメージであることを思い出し、その違いについて考えてみます。Dockerの利点として箇条書きにしました。
- VMware/Hyper Vなどのハイパーバイザー環境を用意しなくていい
- Dockerのほうが色々できる(Docker-compose、Docker Hub)
- イメージをレイヤー上に重ねられる
- オーケストレーション、CI/CD
- Dockerfileなどコードによる管理と共有(githubなどのリポジトリで管理)
ネットワークやボリュームのコントロールは通常の仮想化技術でもできると思いますが、Docker-composeによる複数サービスの連携やDocker Hubによるイメージのリポジトリ管理とpullによる取得はDockerの強力な特徴の一つです。また既にリポジトリにあるDockerイメージをベースとしつつ新しいレイヤーを重ねてイメージを作成できるため、1からイメージを作成する手間が省けます。このようなイメージ作成は通常の仮想化技術ではできません。Docker hubはgithubのようでもあり、Dockerイメージのレイヤー差分をDocker Hubで管理することができます。また多くのイメージはDocker Hubから自由にpullできます。これらの特徴は今までの仮想化技術と顕著に異なります。
仮想化イメージが容易に管理できることになったことを受けてデプロイ(CI/CD)やオーケストレーション、またはオートスケーリングの文脈でもDockerが活用されるようになってきました。デプロイ(CI/CD含む)やオーケストレーションの中ではDockerコンテナは使い捨てであることが多く、古いコンテナは廃棄し新しいコンテナをロールインさせることが多いかと思います。但しここで行っている機械学習やディープラーニングの分析作業においてはDockerコンテナは特に使い捨てではありません。またAWS ECSなどのコンテナサービス上でコンテナを動かすこともKubenetesといったオーケストレーションサービス上でコンテナを稼働させることも目指してはいません。[2]
k8sやECSなどのオーケストレーションではコンテナは使い捨てですが、素のDockerではコンテナは使い捨てではありません。正確には使い捨てもできるし、stop状態としてデータを維持することもできます。
従ってここでは機械学習(やディープラーニング)のDocker imageをポータブルな環境としてあらゆるサーバやクライアントで再現し分析作業ができる、ということをメリットにAnacondaのDockerイメージを作成します。イメージをDocker Hubなどのリポジトリにプッシュしておくことで、リモートサーバ上で作業する場合やクライアントのローカルマシンでもdocker pullするだけですぐに作業を始められます。
公式Dockerイメージ
一連の分析に使用しているのはAnaconda3の公式DockerイメージをベースとしたDockerイメージです(ベースとして各種ライブラリを追加しています)。イメージは2.6Gあるのでpullする際はストレージ容量に注意してください。docker pullしてJupyter Notebookを立ち上げる方法がDocker Hubおよびgithubに掲載されています。[3]
$ docker pull continuumio/anaconda3
$ docker images
continuumio/anaconda3 latest cd83b04b8169 2 months ago 2.6GB
このイメージではbaseというデフォルトの仮想環境が容易され、Dockerコンテナを立ち上げるとその仮想環境がアクティベートされるようになっています。ちなみにbaseはAnacondaの仮想環境のデフォルト名です(たしか)。
$ docker run -it --rm --name continuumio-anaconda3 continuumio/anaconda3 /bin/bash
(base) root@29f6783cd140:/# python -V
Python 3.7.3
(base) root@29f6783cd140:/# conda info -e
# conda environments:
#
base * /opt/conda
Anacondaではcondaコマンドでパッケージ管理を行います。 conda list
で最初からインストールされているパッケージの一覧を表示してみました。
Numpy/Scipy/pandas/matplotlib/scikit-learnなど主要なライブラリのバージョンが分析する上での要件を満たしているか確認してください。 conda update
で指定のライブラリのアップデートが可能です。[4]
公式サイトに掲載されているコマンドではJupyter Notebookの起動でエラーが発生します。 --allow-root
のオプションが必要です。
$ docker run -it -p 8888:8888 continuumio/anaconda3 /bin/bash -c "/opt/conda/bin/conda install jupyter -y --quiet && mkdir /opt/notebooks && /opt/conda/bin/jupyter notebook --notebook-dir=/opt/notebooks --ip='*' --port=8888 --no-browser"Collecting package metadata (current_repodata.json): ...working... done
Solving environment: ...working... done## Package Plan ##environment location: /opt/condaadded / updated specs:
- jupyterThe following packages will be downloaded:package | build
---------------------------|-----------------
conda-4.7.12 | py37_0 3.0 MB
------------------------------------------------------------
Total: 3.0 MBPreparing transaction: ...working... done
Verifying transaction: ...working... done
Executing transaction: ...working... done
[I 10:23:14.350 NotebookApp] Writing notebook server cookie secret to /root/.local/share/jupyter/runtime/notebook_cookie_secret
[W 10:23:15.683 NotebookApp] WARNING: The notebook server is listening on all IP addresses and not using encryption. This is not recommended.
[I 10:23:15.791 NotebookApp] JupyterLab extension loaded from /opt/conda/lib/python3.7/site-packages/jupyterlab
[I 10:23:15.791 NotebookApp] JupyterLab application directory is /opt/conda/share/jupyter/lab
[C 10:23:15.794 NotebookApp] Running as root is not recommended. Use --allow-root to bypass.
以下のコマンドでJupyter Notebookが起動でき、トークン付きのアクセスURLが表示されます。アクセスURLの後に ?token=
以降を追加することで起動したJupyter Notebookにアクセスできます。
$ docker run -it -p 8888:8888 continuumio/anaconda3 /bin/bash -c "/opt/conda/bin/conda install jupyter -y --quiet && mkdir /opt/notebooks && /opt/conda/bin/jupyter notebook --notebook-dir=/opt/notebooks --ip='*' --port=8888 --no-browser --allow-root"Preparing transaction: ...working... done
Verifying transaction: ...working... done
Executing transaction: ...working... done
[I 10:32:40.089 NotebookApp] Writing notebook server cookie secret to /root/.local/share/jupyter/runtime/notebook_cookie_secret
[W 10:32:40.371 NotebookApp] WARNING: The notebook server is listening on all IP addresses and not using encryption. This is not recommended.
[I 10:32:40.419 NotebookApp] JupyterLab extension loaded from /opt/conda/lib/python3.7/site-packages/jupyterlab
[I 10:32:40.419 NotebookApp] JupyterLab application directory is /opt/conda/share/jupyter/lab
[I 10:32:40.422 NotebookApp] Serving notebooks from local directory: /opt/notebooks
[I 10:32:40.422 NotebookApp] The Jupyter Notebook is running at:
[I 10:32:40.422 NotebookApp] http://81d6027bbe25:8888/?token=00a94af51e704cb66a105c576377081cd5ac0619c2137429
[I 10:32:40.422 NotebookApp] or http://127.0.0.1:8888/?token=00a94af51e704cb66a105c576377081cd5ac0619c2137429
[I 10:32:40.422 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 10:32:40.439 NotebookApp]To access the notebook, open this file in a browser:
file:///root/.local/share/jupyter/runtime/nbserver-1-open.html
Or copy and paste one of these URLs:
http://81d6027bbe25:8888/?token=00a94af51e704cb66a105c576377081cd5ac0619c2137429
or http://127.0.0.1:8888/?token=00a94af51e704cb66a105c576377081cd5ac0619c2137429
Jupyter Notebookではバージョン4.3からノートブックへのアクセスにトークンもしくはパスワードを使用するようになりました。[5]
トークンはノートブック起動時に表示されますがトークンを紛失してしまった場合には、以下のように jupyter notebook list
コマンドで確認できます。トークンでなくパスワードを設定した場合、ハッシュ化されたパスワードが jupyter_notebook_config.json
に保存されるようになっています。
$ docker exec -it anaconda3 /bin/bash
(base) root@996de06c5352:/# jupyter notebook list
Currently running servers:
http://localhost:8888/?token=fd76558c5e7998352a8c2a07c4ea888460d19def662164db :: /opt/notebooks
次にAnacondaの公式Dockerコンテナを改良して仮想通貨の自動取引向けのイメージを作成していきます。
Dockerfileの作成
Dockerコンテナを使用する上でDockerfileを作成することは必須ではありません。Docker Hub上のイメージはあくまでレイヤーであり、Dockerfileは必要であれば使用するツールの1つという認識です。従って公式Dockerイメージをpullしてその中でパッケージやファイルを追加し、Dockerコミットしてもイメージを作ることは十分可能です。しかしDockerfileをgithubなどのリポジトリで管理できることや、以下のブログのようにDocker Hubとgithubを連携させて自動でビルドさせることで生まれる利便性は無視できません。[6]
そこでここでは公式Dockerイメージを作成した元となっているDockerfileに以下のような変更を2点加えていきたいと思います。
1.Jupyter Notebook環境のコンテナ化(手動で実行したくない)
2.パッケージの追加(仮想通貨関連のパッケージ)
分析で使用した以下のようなパッケージをコンテナへ入れていきます。
- Ta-Lib
- python-bitbankcc
- backtesting
- pandas-highcharts
- mpl-finance
公式のcontinuumio/anaconda3のgithubに公式イメージを作成したDockerfileが管理されています。以下をベースとします。[7]
FROM debian:buster-slimENV LANG=C.UTF-8 LC_ALL=C.UTF-8 RUN apt-get update --fix-missing && \
apt-get install -y wget bzip2 ca-certificates libglib2.0-0 libxext6 libsm6 libxrender1 git mercurial subversion && \
apt-get clean RUN wget --quiet https://repo.anaconda.com/archive/Anaconda3-2019.07-Linux-x86_64.sh -O ~/anaconda.sh && \
/bin/bash ~/anaconda.sh -b -p /opt/conda && \
rm ~/anaconda.sh && \
ln -s /opt/conda/etc/profile.d/conda.sh /etc/profile.d/conda.sh && \
echo ". /opt/conda/etc/profile.d/conda.sh" >> ~/.bashrc && \
echo "conda activate base" >> ~/.bashrc && \
find /opt/conda/ -follow -type f -name '*.a' -delete && \
find /opt/conda/ -follow -type f -name '*.js.map' -delete && \
/opt/conda/bin/conda clean -afy CMD [ "/bin/bash" ]
まずは元のDockerfileからCMD指定を取り除いて、各種パッケージのインストールとcondaによるJupyter Notebookのインストールを追加しました。SHELLはDockerバージョン1.12から追加された、Dockerコンテナのビルド時のシェルを変更できる便利指定です。
RUN wget --quiet http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz -O ~/ta-lib-0.4.0-src.tar.gz && \
tar xvf ~/ta-lib-0.4.0-src.tar.gz && \
cd ta-lib && \
./configure --prefix=/usr && \
make && make install
SHELL ["/bin/bash", "-l", "-c"]
RUN pip install git+https://github.com/bitbankinc/python-bitbankcc.git TA-Lib backtesting pandas-highcharts mpl_finance && \
mkdir /opt/notebooks && /opt/conda/bin/conda install jupyter -y --quiet
docker-entrypoint.sh
を作成してエントリーポイントとして渡します。また /opt/notebooks
をボリュームマウントしています。このディレクトリが分析用に作成したノートブックの保管場所となります。ボリューム設定についてはお好みで変更してください。このケースではコンテナ側でユーザを作成していないため、ノートブックがホスト側にroot権限で保存されていきます。
ADD docker-entrypoint.sh ./
RUN ["chmod", "+x", "/docker-entrypoint.sh"]
VOLUME /opt/notebooks
ENTRYPOINT ["/docker-entrypoint.sh"]
docker-entrypoint.sh
の中身はJupyter Notebookの起動部分です。公式のイメージで手動実行していた部分を起動時に叩くようにします。
#!/bin/bash
/opt/conda/bin/jupyter notebook --notebook-dir=/opt/notebooks --ip='*' --port=8888 --no-browser --allow-root
ビルドして実行したコンテナ内で conda list
を実行しました。追加でインストールしたパッケージが仮想環境内で使用可能になっています。
デフォルトではポート8888を使用しますが、リモートサーバ等で特定ポートを指定したい場合は以下のように -p
オプションを使用してください。
$ docker run -p 3000:8888 anaconda3:latest
このDockerコンテナをバックグラウンドで動作させることで、ローカルからでもリモートサーバ上でも同じ環境で分析作業ができるようになりました。Dockerfileのコードは以下のリポジトリに上げてあります。
Dockerhubはこちらです。 docker pull suganoyuya/anaconda3