Gunosyデータ分析ブログ

Gunosyで働くデータエンジニアが知見を共有するブログです。

その実験、再現できますか?pyenvとpoetryによる “そんなに頑張らない” 再現可能な実験環境構築

Gunosy Tech Lab リサーチインターンの北田 (@shunk031)です。 深層学習の論文を読んでいるときに著者実装が公開されている旨を見ると嬉しい気持ちになりますよね。 いざ公開レポジトリに飛んだ瞬間その嬉しさは無となることが多いですが、くじけずにやっていきたいです。

f:id:shunk031:20201205181754p:plain
著者実装のrequirements.txtをベースにpythonモジュールをインストールするとよく見るやつ

こちらの記事は Gunosy Advent Calendar 2020 6日目の記事です。昨日は @625 さんの goで作るfirehoseのデータ変換lambda でした。

tech.gunosy.io

その実験、再現できますか?

リサーチインターンでは主にGunosyのデータを使った研究をしています。 特に私は深層学習による広告クリエイティブの評価や運用支援に焦点を当てて取り組んでいます*1。 深層学習を用いた研究をする際はpythonを主に利用しますが、実験を行う際に、特に次の点に注意しないと結果が再現できない可能性が出てきます:

  1. python本体のバージョン
  2. pythonモジュールのバージョン

実験では様々な試行錯誤を行い 各々が妄想する 自分の考えた最強のエーアイ を構築するため、特にどのようなpythonモジュールをインストールしたかをその都度把握することは難しいです。 昨今の深層学習フレームワークやその依存パッケージはバージョンが少しでも違うと実験結果が異なってしまう場合があります *2。 したがって、これらのバージョンを適切に扱うことが重要です。 また、研究成果を公開したり、アプリケーションとして動かす場合にも上記の点は無視できません。

上記のバージョニングは少し手間をかけて 頑張れば 解決できる話です。しかしながら、個人的な偏見ですが、私を含め研究に取り組んでいる人は本質的なところ以外で そんなに頑張れません *3。そんな手間をかけている時間があるなら論文を読みたいですし、書きたいです。

本記事では上記の2点に対して、私が実践している一例として pyenv, pyenv-virtualenv, poetry による 深層学習を用いた実験の際に頑張らずに再現性を担保する実験環境 を示します。 本記事の対象は いつも締切や雑務に追われて時間のない研究者それらと同等の方たち*4 で、以下の点にフォーカスしています:

  • 簡単に実験環境を構築可能
  • 手間をかけずに自動でモジュールのバージョンを管理

なお、本記事では以下の点については言及いたしません:

  • 本記事で取り上げるツールの詳細 *5
  • 最近の深層学習関連の技術で面白かった論文 *6

その他、私の考えた最強の実験環境構築 がある方は本記事の はてなブックマーク のコメント等でお知らせいただけると幸いです。

pyenvとpoetryによる “そんなに頑張らない” 再現可能な実験環境構築

本セクションではまず、どのようなツールを使い、どのように実験環境を構築するかを示します。 忙しい方は順にコマンドを実行していただくだけで構いません。 その後、私の視点からそれぞれのツールをどのようなモチベーションで選択したかを説明します。

以下は 2020/12/06 現在での実行方法です。最新の方法はそれぞれのREADME等を参照してください。

やり方だけ教えて

以下は簡易的な流れです:

  • 実験用のpython環境の構築
    • pyenv のインストール
    • pyenv-virtualenv のインストール
    • これらを用いたpython環境の構築
  • poetryによるpythonモジュールの管理
    • poetry のインストール
    • poetryを用いたpythonモジュールのインストール

pyenv, pyenv-virtualenv のインストール

# pyenv のインストール
$ git clone https://github.com/pyenv/pyenv.git ~/.pyenv
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile

# shellを再起動して設定を反映
$ exec "$SHELL"

# pyenv-virtualenv のインストール
$ git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv
$ echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bash_profile

# shellを再度 再起動 して設定を反映
$ exec "$SHELL"

pyenv と pyenv-virtualenv でpythonの環境を構築

# pyenv で 実験環境のベースとなる 3.8.6 をインストール
$ pyenv install 3.8.6

# 実験スクリプトがあるディレクトリへ移動
$ cd /path/to/my_exp_001/

# pyenv-virtualenv で my_exp_001 専用の python 環境を構築
$ pyenv virtualenv 3.8.6 my_exp_001

# my_exp_001 ディレクトリに入ったら my_exp_001 用のpython環境に切り替わるように設定
$ pyenv local my_exp_001

2020/12/06 現在、最新のpythonのバージョンは 3.9.0 です。しかしながら深層学習フレームワーク等がpython3.9に対応していない場合もあるため、ここでは3.8系で最新の3.8.6をインストールしています。

poetryをインストール

# 先程作った my_exp_001 環境になっているかを確認
# $ pyenv version
# my_exp_001 (Set by /path/to/.pyenv/version)

# poetry をインストール
$ pip install poetry

poetryで実験環境を初期化

  • poetry init コマンドで実験環境のモジュール管理が実施されるようにします
$ poetry init
# 実験に必要なモジュール等の情報が記述される pyproject.toml がカレントディレクトリに生成されます。
# 対話式で pyproject.toml の内容を設定します。

実験に必要なモジュールをインストール

  • 上記が完了すれば、あとは必要なモジュールをインストールしていくだけです
# みなさんが大好きなモジュール群をインストール
$ poetry add torch scikit-learn pandas

# --dev オプションで本筋の実験には関係ないがコーディングをサポートするようなモジュールをインストール
$ poetry add --dev flake8 black isort mypy

このとき、カレントディレクトリの pyproject.tomlpoetry.lock が出力・更新されます:

  • pyproject.toml には上記でインストールしたモジュールのバージョンが自動で記録されます
  • poetry.lock には上記でインストールしたモジュールの依存関係が自動で記録されます

今回の肝はこの点です。モジュールのインストール時にモジュールのバージョンとその依存関係が 自動 で記録されます。以降、新たな環境で以下のコマンドを実行することで、同様のモジュールをインストール可能です:

$ cd /path/to/my_exp_001/

# poetry がインストールされている状況で実行
$ poetry install

解説

なぜ pyenv, pyenv-virtualenv を選んだか

  • 良い点: pyenvを使うと異なるバージョンのpython環境を柔軟に構築可能
    • 深層学習や機械学習のフレームワークは発展途上であり、pythonのバージョンに厳しい場合があります。再現性の観点からこのような要件に柔軟に対応するため、pyenvでは適切なpythonのバージョンをインストール可能です。
  • 良い点: pyenv-virtualenvを使うと実験環境ごとに異なるpython環境を構築可能
    • 複数の研究プロジェクトや再現実験を行っていると、同一バージョンのpythonで、異なる環境が必要になります。同じバージョンのpython環境化で異なる実験を行うとモジュールのコンタミが発生し、それぞれの実験の再現が難しくなる恐れがあります。pyenv-virtualenvを用いることでそれぞれのプロジェクトごとにpython環境を簡単に構築するサポートをしてくれます。
  • 疑問点: python標準のvenvでも良いのではないですか?
    • プリインストールされているpythonをもとにvenvでその実験用の環境を構築可能です。これはvenvとpyenv-virtualenvは本質的にほとんど同じ動作をするためです。しかしながらpyenvのように異なるバージョンのpython環境を作ることはできません。
  • 疑問点: dockerで適切なpythonのバージョンのimageを使うほうが楽じゃないですか?
    • 楽な場合もあります。例えば研究結果を応用して実サービスで使いたいというときはコンテナ化したほうが良い場合が多く、私も使います。dockerを苦としない方はご自由にお使いください。

なぜ poetry を選んだか

  • 良い点: モジュールインストール時にモジュールのバージョン情報が記録・更新される
    • poetryによって自動で作成・更新される pyproject.toml および poetry.lock は共に対象python環境にインストールされているパッケージのバージョンや依存関係を正確に記録しています。このファイルをベースに環境を再構築することで、正常実行が確認されている環境での動作を担保できます。
  • 良い点: 開発用のパッケージを明示的に分けて記録できる
    • 実行時には必要がないが、コーディングや分析に必要なパッケージを明示的に分けて管理することが可能です。特にflake8等のlinterやjupyter lab/notebook といった分析に利用するものは深層学習モデルに直接は関係しないモジュールです。こうしたモジュールは分けて管理することで実行に必要ないパッケージに依存することのない環境を構築可能です (こちらは後述するpipenvでも可能です)。
  • 疑問点: そのrequirements.txtを信じているのですか?
    • 一般的に、pip freeze等で対象の実験環境にインストールされているモジュールをrequirements.txtを出力する方法がこれまでに使われています。しかしrequirements.txtで実験環境が完璧に再現できた経験がありません *7。これはモジュールのインストール時とは異なるタイミングでfreezeされているためだと考えられます。poetryを使用することで、モジュールのインストール時に依存関係を記録するような運用ならば防げると思います。
  • 疑問点: pipenvでも良いのではないですか?
    • 著者もpoetryを使う前はpipenvを使用していました。pipenvもpoetry同様にモジュールをインストール時にその依存関係を含めたPipenv.lock というファイルを作ります。このときの依存の解決が異常に遅く、人生の大半をlockで消費してしまいました *8。poetryは依存解決が非常に早く、人生を消費しません。

もう一歩: pythonの実験コードを美しく保つ

楽しくTwitterを眺めていると、頻繁に「研究者のコードは汚い」というツイートを目にすることが多く、心を痛めることが多いです。 研究者諸氏は論文を読むのを一旦やめて、リーダブルコードを読む時間があっても良いかもしれません。 これに加えて私からはpythonの実験コードを美しく保つ、以下のpythonツールを簡単に紹介します:

  • flake8: pythonの文法チェックを行うツール
  • black: pythonのソースコードを自動で整形するツール
  • isort: pythonのimport文を自動で整頓するツール
  • mypy: 型アノテーションをもとに型チェックを行うツール

以上のツールは実験の実装をサポートし、ソースコードを綺麗に保つ事が可能です。メジャーなテキストエディタを使用している方はそれぞれのエディタで上記のツールのサポートを受けられる設定があると思います。特にVisual Studio Code (VSCode) を使用している方は、以前私が書いた以下の記事が参考になると思います。これらの設定は非常に簡単なため、ぜひ設定をして実験コードを美しく保つようにしたいところです。

shunk031.hatenablog.com

おわりに

本記事では、私が実践している 深層学習を用いた実験の際に上記2点を頑張らずに管理することを目標とした実験環境 の一例を示しました。 いつも締切や雑務に追われて時間のない研究者やそれらと同等の方たちが対象に、機械学習や深層学習の実験の再現性を担保するpythonの環境構築・モジュールの管理について説明しました。

締め切り前に実験環境をエイヤと変えて再現できなくなることが非常に多いです。 日頃からpyenvやpoetry等を使用して、締切直前の自分を助けられるような、ていねいな暮らしをしていきましょう。

次の記事はmageyukiさんです!おたのしみに!

*1:リサーチインターンの成果がトップカンファレンスであるKDD2019に論文として採択されるまで - Gunosyデータ分析ブログ https://data.gunosy.io/entry/research-intern-kdd19

*2:これってどうなんだ?という気持ちもあります。そもそも乱数値で結果がそれなりに変わる場合があることも知られています。

*3:いや、私は頑張れるので…という方は素晴らしい。見習いたいです。

*4:研究を始めたばかりの学部4年生やこれから研究がんばっていくぞの修士1年生 等

*5:それぞれのツールのドキュメントをご参照ください。

*6:私のTwitter @shunk031 で話しています。ご覧ください。

*7:著者実装の公開レポジトリにあるrequirements.txtを信用してはいけません。私は何度も裏切られました。

*8:同様に、brew updateでも人生を消費する可能性があります。