AllenNLPとAmazon SageMakerによる、機械学習の効率化
機械学習におけるモデルの構築と学習は、近年より速く・簡単に・自動的にできるようになってきています。この技術的な進歩は、より多くの仮説 — 様々な研究アイデア、ビジネスデータへの適用 — の検証を可能にするという点で、重要です。本記事ではAllenNLPを使うことで速く・簡単に機械学習モデルの実装を行い、さらにAmazon SageMakerを使うことで自動的に学習を行う手法を紹介します。
記事の構成は、以下のようになっています。
- AllenNLPによるモデル構築
- Amazon SageMakerによる学習の自動化
AllenNLPによるモデル構築
AllenNLPは、PyTorchをバックエンドとしたライブラリです。自然言語処理にかかわる機械学習モデルを、PyTorch(あるいはTensorFlow)でゼロから作るより簡単に構築することができます。簡単なだけではなく、AllenNLPには自然言語処理の各タスクで優秀な性能を記録したモデルが実装されており、それらを使うことで精度的にも保証されたモデルを構築することができます。
同様にPyTorchをバックエンドとしたライブラリとしては、fast.aiがあります。
AllenNLPやfast.aiを使うことは、旅行でツアーパックを使うことに似ています。ツアーパックは一定以上の満足度が保証されており、ある程度カスタマイズが可能です。初めて旅行する、また旅行先について十分な知識がない場合は、十分な選択といえるでしょう。
今回は、チュートリアルでも紹介されているPOS Taggingのモデルを使用します。POS Taggingとは、文中の各単語について品詞(Part of Speech=POS)を予測するタスクのことです。 The dog ate the apple.
なら、 ["DET", "NN", "V", "DET", "NN"]
となります。チュートリアルから、モデルの定義部分のみ抜粋したコードが以下となります。
Model
を継承し、伝搬(forward
)プロセスと loss
(output["loss"]
)、評価メトリクス(get_metrics
)を最低限定義します。
モデルを定義すれば、Trainer
により簡単に学習できます。Kerasをご存知であれば、fit
に近いと感じるかもしれません。
AllenNLPでは、Model
/Trainer
などの定義をJSONライクな形式(Jsonnet)で記述することが可能です(例)。これにより、実験の設定を記録することができるほか、JSONファイル内のパラメーターを変えるだけで簡単に異なる設定でモデルの構築/学習を行うことができます。この機能は、次に解説するハイパーパラメーターチューニングととても相性が良いです。
Amazon SageMakerによる学習の自動化
モデルの学習は複数回行うのが一般的です。モデルの構築/学習に際しては様々な設定パラメーターがあり(ex: モデルのレイヤ数、最適化を担うOptimizerの学習率など)、「どの設定値がベストか」を知るには一回の実行では不十分なためです。この設定値を探る処理を、「ハイパーパラメーターチューニング」と呼びます。これまでは、ハイパーパラメーターチューニングは人間の手で行われてきました。
近年では、複数回の学習によるハイパーパラメーターチューニングを自動で行う手法が提案されています。一番簡単な手法はパラメーター候補を列挙してすべての組み合わせを試すことですが(これはGrid Searchと呼ばれます)、もちろんこれよりも上等な手法が数多くあります。Grid Searchを含む代表的な手法は、本記事で取り上げるAmazon SageMakerだけでなく、AzureやGCPでも利用することができます。
クラウドプラットフォームでハイパーパラメーターチューニングを行うメリットは2つあります。
- 学習に必要なリソースの調達が容易である
各クラウドプラットフォームでは、モデルの学習に不可欠なGPU付きのインスタンスを提供しています。そのため、GPUを使ったハイパーパラメーターチューニングを容易に行うことができます。また、必要に応じ並列コンピューティングを行うことも容易です。 - 実験結果をログに残すことができる。
クラウドプラットフォーム上での実験結果は、ログとして記録されます。これにより、「どんなパラメーターで実験したらどんな精度だったか忘れる」ことがなくなります。こうした事態は、人間による調整だと頻繁に観測されます(経験談として)。
では、さっそく行ってみましょう。AllenNLPのチュートリアルを、実際にSageMakerでチューニングした際のJupyter Notebookがこちらになります。
SageMakerは、基本的にJupyter Notebookを実行するインスタンスになっています。そのため、ハイパーパラメーターチューニングを行うにあたり今回は以下のような構成をとっています。
- Localでモデルの開発を行う
- GitHub経由でCloud上(SageMaker)に実装を移す
- 学習用データをS3にアップロードする
- 学習を実行するEstimatorを作成する
- チューニングを実行するTunerを作成する
- Tunerを実行する
1については問題ないと思うため、2の手順から解説を行っていきます。
GitHub経由でCloud上(SageMaker)に実装を移す
SageMakerからターミナルを起動し、以下のコマンドを実行します。
cd SageMaker
git clone https://github.com/icoxfog417/allennlp-sagemaker-tuning.git
ターミナルはSageMakerから起動したJupyterから行います。New>Other>Terminalで、起動が可能です。
SageMaker
フォルダが、Notebookが格納されるフォルダになります。そのため、SageMaker
フォルダに移動してgit cloneを行っています(更新を取り込む場合はgit pull)。実行後、Jupyter上から取得したファイルが見られるはずです。これで、SageMakerのNotebookから作成したモデルを参照できるようになりました。
学習用データをS3にアップロードする
次に、学習用のデータをS3にアップロードします。これは、SageMakerにデフォルトで搭載されているsagemaker
パッケージを使うことで簡単に行うことができます。
sagemaker_session = sagemaker.Session()
s3_path = sagemaker_session.upload_data(path="path_to_file", bucket="your_s3_bucket", key_prefix="file_prefix")
bucket
は、指定しない場合自動的に作成されます。
学習を実行するEstimatorを作成する
Estimatorは、学習を実行する単位になります。具体的には、python
コマンドで起動できるスクリプト、学習データ、学習に使うリソース(インスタンス)をひとまとめにしたものになります。この後作成するTunerは、Estimatorに渡すパラメーターを変えることでチューニングを行っていきます。
AllenNLPでモデルを作成している場合、SageMakerにもAllenNLPのインストールが必要になります。pip
でインストールできれば話が早いのですが、2019/4時点ではjsonnet
がビルドできずエラーになります。そのため、ターミナルからビルドに必要なパッケージをインストールする必要があります。具体的には、g++
とclang
です。gcc
はデフォルトで存在するため、gcc
に合うg++
を導入するようにします。2019/4時点では7.2だったため、バージョンを7.2に統一しています。
sudo yum install gcc72-c++.x86_64
sudo yum install clang
なおgccが4系だと古いため、デフォルトのgccを7.2にする必要があるかもしれません(インスタンスタイプによって異なる?)。
sudo rm /usr/bin/gcc
sudo ln -s /usr/bin/gcc72 /usr/bin/gcc
これでSageMakerにはインストールできました。しかし、SageMakerから起動するEstimatorの実行インスタンス(以下の場合、ml.p2.8xlarge
)ではこのような作業を行うことができません。
そのため、今回は実行に必要な仮想環境まで含めて実行インスタンスに渡すようにしています。その処理が、以下となります。
source_dir
と dependencies
を渡しています(from_root
はsource_dir
から指定引数までのパスを絶対パスで渡すための関数です)。 pip
でインストールが可能な場合は、source_dir
内にrequirements.txt
があればそれをインストールしてくれます。ただし、SageMakerのインスタンスはanaconda
をベースとして作成されており、pip
でパッケージをインストールするとpip
とanaconda
でパッケージがバッティングする場合があります。Numpyは特にこの影響を受けやすいため、バッティングによる問題が発生した場合は今回のような対応を行う必要があります。
実装では、pipenv
で仮想環境(.venv
)を作成しそれをEstimatorにdependencies
として渡しています。
チューニングを実行するTunerを作成する
Estimatorが作成できたら、Estimatorの実行パラメーターを最適化するTunerを作成します。
HyperParameter Rangeには以下の種別があります。
ContinuousParameter
: 連続値のパラメーター。下限/上限、その間の補完方法(LinearやLogarithmic)を指定するIntegerParameter
: Continuousだが取る値が整数値のパラメーターCategoricalParameter
: 離散値のパラメーター。指定した数値で学習を行いたい場合にも使用可能(分散表現のサイズが100、200、300など)
なお、Boolean引数はサポートされていないため、CategoricalParameter
の形に変更する必要があります。(--with-padding
といったBooleanの引数があった場合、--padding-type pad
にするなど)。
HyperparameterTunerのstrategyは、Random
かBayesian
のいずれかを選択できます。(デフォルトはBayesian
です)。
注意点として、メトリクスの定義があります。Estimatorの実行結果をどのようなスコアで計測するかを指定しますが、このスコアはログから正規表現で取ることになります( validation_loss=([0-9\\.]+)
)。この表現を間違えているとチューニングがそもそも上手くいかないので注意してください。学習中に出力するスコアのフォーマットはフレームワークによってまちまちなので、ログの出力は自ら実装したほうが良いと思います。
max_jobs
は、試行回数となります。この回数だけチューニングを実行するということです。そのため、max_jobs
の回数が少ない場合はその分試行されるパラメーター候補が少なくなるため設定数には注意してください。
Tunerを実行する
最後に、Tunerを実行します。
tuner.fit({"training": s3_train_dir})
実行を行うと、SageMakerの画面から実行結果を確認できます。
また、この実行結果sagemaker.analytics.HyperparameterTuningJobAnalytics
で分析可能です。Gluon CIFAR-10 Hyperparameter Tuningでは、ハイパーパラメーター同士の相関などを分析する例を見ることができます。