1. はじめに
こんにちは,(株) 日立製作所 Lumada Data Science Lab. の露木です。
今回はJupyterノートブックで引数付きのバッチ実行を可能にし,ハイパーパラメータ探索などを効率化するPapermill というOSSを紹介します。Papermillの設計思想や他ツールと組み合わせたシステムの全体像については,開発元のNetflixが詳細な記事 を公開しているのでそちらもぜひご覧ください。
1.1. Jupyterの利点
データサイエンス分野の方々であれば,機械学習スクリプトの試作やレポート作成のためにJupyterノートブックの形式でコーディングをすることはよくあるかと思います。Jupyterノートブックであれば,図1のようにMarkdownの形式の説明文とともにソースコードと実行結果をまとめられるため,第三者に計算の内容と結果をわかりやすく伝えられます (いわゆる文芸的プログラミングを自然に実践できます)。
1.2. 問題提起: ノートブックの引数にパラメータを与えられない
ところで,一般にモデルの学習処理には時間がかかります。その上,ハイパーパラメータを変えながらモデルの汎化性能が最も高くなる条件を探索するとなれば,ハイパーパラメータの組み合わせの数に,テストデータと訓練データの分割を変えた交差検証の回数を掛け算した回数だけ学習処理を実行しなければなりません。例えば,SVMの2種類のハイパーパラメータ $\gamma$ と $C$ についてそれぞれ6種類ずつ組み合わせをとり,さらに交差検証を5回実施するのであれば, $6 \times 6 \times 5 = 180$ 回の学習処理を実行することになります。
このようなハイパーパラメータ探索のための学習処理は (ベイズ最適化のようなテクニックを使わなければ) 基本的に独立していますから,並列化によって効率化しやすい処理です。先程の180回の学習処理であっても,引数が異なるバッチジョブとしてジョブスケジューラに登録し,180台の計算ノードで並列処理すれば1回分の学習処理と同じ時間で終了します。
しかし,Jupyterノートブックは人間がインタラクティブに操作することを前提にしているため,このようなバッチ実行をしにくい問題があります。細かい話をすれば,Jupyterでもコマンドラインで jupyter nbconvert --to notebook --execute --inplace hoge.ipynb
とすればバッチ実行できます。しかし,一般のPythonスクリプトのように引数を与えられません。つまり,先程のデータサイエンスのユースケースで言えば,ハイパーパラメータやデータセットのファイル名などが異なった多数のノートブックを作成しなければなりません (図2参照)。
図2. Jupyterノートブックのバッチ実行における課題。 Jupyterだけだとパラメータをノートブックに埋め込まなければならないので,バッチ実行前に多数作成しなければならない。
1.3. 対策: Papermillをつかう
この問題に対処するために,Netflixが開発したOSSのPapermill を利用できます。Papermillを使えば,ノートブックに引数を与えた上でバッチ実行できる (図3参照) ため,パラメータごとにノートブックを作成せずに済みます。そこで,本稿ではPapermillを使ったノートブックの実行方法を説明します。
図3. Papermillの利点1。 パラメータをバッチ実行時の引数として指定できるので,ノートブックを多数作成する必要がない
2. Papermillの使い方
2.1. 環境準備
最初にノートブックを実行したいマシン (お手元のノートPCや計算ノードなど) にPapermillをインストールします。インストールは以下のコマンド実行で可能です。
pip3 install 'papermill[all]'
2.2. ノートブックの準備
まず,バッチ実行するためのノートブックを準備します。今回は単にPapermillの動作確認をするだけですので,設定したパラメータを表示するだけの図4のようなノートブックを作ります。
次に,Papermillに対応するためにこのノートブックを修正します。といっても修正するのは変数を指定する部分のみです。
具体的には,ノートブックのどこか1つのセルで引数としたい変数をまとめて定義するように修正します。図4の例であれば,1つのセル内で以下のように alpha
や ratio
といった変数を指定するように修正します。なお,Papermill実行時に引数の指定がなかった場合は,このセルで定義した値 (以下のコードでは 0.1
) がデフォルト値として利用されます。
alpha = 0.1
ratio = 0.1
そして,この変数定義をしたセルをPapermillが認識できるように parameters
の値を「タグ」として指定します。タグはJupyterノートブックの基本機能としてある,セルのメタ情報を管理する仕組みです。なお,parameters
のタグを複数のセルに付与しても,Papermillに認識されるのは一つだけ (一番上のセルのみ) である点はご注意ください。
Jupyter Notebookの場合,セルにタグを付与する手順は以下のとおりです。この手順に対応する画面操作は図5を参照ください。
- (1) メニューバーの
View
→Cell Toolbar
→Tags
をクリッしてタグ入力欄を追加する - (2) タグ入力欄にタグ名
parameters
を入力 - (3)
Add tag
ボタンをクリックして,タグを確定する - (4) セルの左上に parameters タグの追加を確認したら,
- (5) ノートブックを上書き保存する
図5. JupyterLabにおけるタグ設定方法
一方,JupyterLab (Version 2.1.5) の場合は以下の手順でタグを指定できます。この手順に対応する画面操作は図6を参照ください。
- (1) タグを指定したいセルをクリックして選択
- (2) 左サイドバーの プロパティ設定ボタンをクリック
- (3) 左サイドバーの「Add Tag」の欄をクリックして
parameters
を入力したら, - (4)
+
ボタンをクリックしてタグを確定する。 - (5)
parameters
タグの確定を確認したら, - (6) ノートブックを上書き保存する
2.3. ノートブックの実行
Papermillでは,PythonAPIとCLIコマンドの2種類のインターフェイスが提供されています。今回はinput.ipynb
のファイル名で保存したノートブックをバッチ実行し,実行結果をoutput.ipynb
のファイル名で保存するものとして実行方法を示します。
(a) PythonAPIを使う方法
まず,PapermillのPythonAPIを利用する場合は,以下のようなコードをPythonスクリプトに埋め込んで実行してください。
import papermill as pm
pm.execute_notebook(
'input.ipynb',
'output.ipynb',
parameters=dict(alpha=5, ratio=7)
)
Papermillのexecute_notebook関数は,一番目の引数に実行したいノートブックのファイル名,二番目の引数に保存先のファイル名を受け取ります。また,引数parametersで辞書型の変数を受けており,ノートブック内のparameters
タグを付けたセルの変数alpha
とratio
の値をそれぞれ5
と7
に変更しています。
上記のPythonスクリプトを実行すると,実行結果として output.ipynb
が保存されます。output.ipynb
をJupyterで開くと,図7のようにalphaとratioの値が上書きされて実行されていることがわかります。
(b) CLIコマンドを使う方法
次にPapermillのCLIコマンドを使用する方法を示します。Papermillのコマンドでは -p
オプションで以下のようにパラメータを指定します。また, --request-save-on-cell-execute
と--prepare-execute
オプションで保存先のノートブックにセルの実行結果を保存せよと指定しています。
papermill input.ipynb output.ipynb \
--request-save-on-cell-execute --prepare-execute \
-p alpha 5 \
-p ratio 7
こちらのCLIコマンドでも,実行後にはファイル名 output.ipynb
で図7のような実行結果が保存されます。
なお,Papermillのコマンドに --log-output
オプションを追加すれば,セルの実行結果を標準出力に表示します。また,--progress-bar
オプションを追加すれば実行状況を出力します。どちらも,CLIコマンドとしてノートブックをバッチ実行する際に便利です。
2.4. オブジェクトストレージの読み書き
最後に,Papermillのユニークな機能を紹介します。Papermillは図8のように外部オブジェクトストレージ (AWSのS3など) からノートブックを直接に読み書きする機能を持っています。これにより,計算ノードのファイルシステムとして外部オブジェクトストレージをマウントしなくても済むので,ジョブスケジューラで束ねた計算機クラスタやCI/CDシステムでノートブックを実行する際に便利です。
図8. Papermillの利点2。 AWSのS3のような外部オブジェクトストレージからノートブックを直接に読み書きできるので,s3fsなどと組み合わせて計算ノードにオブジェクトストレージをマウントする操作などの手間はかからない
オブジェクトストレージの準備
ここでは,AWS S3互換のオブジェクトストレージとしてOSSであるMinIOをつかう例を示します。自分でMinIOを起動すれば無償で,お手元のノートPCで利用できるので簡単な試用目的にに適しています。また,MinIOを社内のサーバで起動すれば,お客様からお預かりした機密データや社外秘情報を含むノートブックを社外に送信するリスクを回避できますので,情報管理の観点からも活用する価値があります。
MinIO開発元が提供しているイメージを使って,MinIOをDockerコンテナとして起動します。コンテナ起動は以下のコマンド実行で可能です。ただし,ACCESSKEY
と SECRETKEY
は適宜,ご自分で設定したいパスワードに置き換えてください。
docker run -p 80:9000 \
-e "MINIO_ACCESS_KEY=ACCESSKEY" \
-e "MINIO_SECRET_KEY=SECRETKEY" \
minio/minio server /data
コンテナを起動したら,動作確認のために http://localhost にWebブラウザで接続します。MinIOを起動したサーバとWebブラウザが動作するノートPCが別のサーバである場合,は localhost
をサーバのIPアドレスで読み替えてください。このとき以下の図9のようにMinIOがパスワード入力を促す画面が表示されれば成功です。このログイン画面でコンテナ起動時に設定した MINIO_ACCESS_KEY
と MINIO_SECRET_KEY
の値を入力すればログインできます。
MinIOにログインしたら,任意の名称 (ここでは notebooks
) でBucketを作成し,バッチ実行したいノートブック input.ipynb
をアップロードします。
ノートブックの実行
ここまで準備ができたら,Papermillを使ってノートブックを実行できます。MinIOへの接続情報を環境変数で設定するために,以下のコマンドを実行してください。ただし,パスワードやURLの値はコメントを参考に適宜,お手元の環境に合わせて変更してください。
# 環境変数でパスワードを指定する (Papermillが呼び出すboto3ライブラリの機能)
export AWS_ACCESS_KEY_ID=ACCESSKEY # docker run時に指定したMINIO_ACCESS_KEYの値に合わせて設定してください
export AWS_SECRET_ACCESS_KEY=SECRETKEY # docker run時に指定したMINIO_SECRET_KEYの値に合わせて設定してください
# 環境変数で接続先URLを指定する (Papermill限定の機能)
export BOTO3_ENDPOINT_URL=http://localhost:80 # MinIOサーバのIPアドレスとポートを設定してください
# (会社等でHTTP Proxyを利用している場合のみ)
# MinIOに正しく接続するためHTTP Proxyを経由しないように設定する
export no_proxy=localhost
後はPapemillコマンドを実行するだけです。以下のように s3://<バケット名>/<ファイル名>
の形式で入出力用ノートブックを指定して実行すれば,Papermillが自動的にMinIOから input.ipynb
をダウンロードし,その実行結果を output.ipynb
としてアップロードします。
papermill s3://notebooks/input.ipynb s3://notebooks/outout.ipynb \
-p alpha 5 -p ratio 7
papermillコマンドの実行後にMinIOの画面を確認すると,図11のように実行結果 output.ipynb
がアップロードされていることがわかります。
3. おわりに
今回はPapermillを使ってノートブックをバッチ実行する方法を示しました。今回のようなツールと,以前紹介した ジョブスケジューラPBSProを構築して計算ジョブを投入する方法を組み合わせるとパイパーパラメータ探索などを効率的に実行できます。よろしければぜひ試してみてください。
4. 参考URL
Papermillのコンセプトに関して
- python - Can I run Jupyter notebook cells in commandline? - Stack Overflow
- Beyond Interactive: Notebook Innovation at Netflix
- Part 2: Scheduling Notebooks at Netflix - Netflix TechBlog
Papermillの使い方に関して
- Jupyter notebook をコマンドラインで実行する - Qiita
- nteract/papermill: 📚 Parameterize, execute, and analyze notebooks
- Usage papermill 2.1.1 documentation