Gluon on Amazon SageMaker 上の Gluon および AWS Batch によるテキスト分類
当社の顧客は問題を抱えていました。手作業による保証クレームの分類がボトルネックとなっていたのです。これらのクレームは、イベントの詳細を短く説明するテキストフィールドに基づくものです。テキストの例は次のようなものです。「近年、天候不順が見られるアリゾナ州において、ある暑い日にプルトニウムを燃料とする原子炉が加熱しました。高温による損傷が、流束キャパシタに及びました。交換せずに元に戻すことはできません」。このクレームを分類するとしたら、「火災」か何かになるでしょう。
クレーム部門の担当者は、通常何千件にもなる、山のような保証クレームを読み、提出者がクレームを正しく分類していたことを確認するために、それぞれの例を手作業で適切な保証カテゴリに分類しなければなりません。
会社は、クレームの解決にかかる時間をできる限り短縮するため、このパイプラインをスピードアップすることを望んでいました。これは顧客満足度を保つ点で中心的な要件です。会社は過去の保証クレームについての大規模で広範なデータベースを有していたので、次のステップとして、教師あり学習のソリューションに目を向けるのは論理的なことでした。
今回のブログでは、技術には強くないクレームチームと、よりソリューションに注意を向ける傾向のあるデータサイエンスチームの間の溝を埋めることにより、顧客のワークフローをスピードアップするのに役立つ、特定のテキスト中の感情を分析するソリューションの概要について説明します。この例示シナリオでは、当社の分類モデルを MXNet の Gluon と Amazon SageMaker によってトレーニングした後、AWS Batch の弾力性のあるリソースを用いて大量のテキストのバッチを処理するため、AWS Lambda に基づいてアプリケーションを構築することになります。
始める前の注意ですが、Python、AWS のコマンドラインインターフェース (CLI)、そして Python Boto3 向けの AWS SDK になじみがあれば、このブログから十分な益を得られるでしょう。
今回のブログでのデモのため、IMDB Large Movie Review Dataset のサブセットを使うことにします。これはすでにテストとトレーニングセットに分けられています。次に示すのは、コンマ区切りのテキストと、そのテキストの感情分類です。
感情: 1、テキスト: 「あなたは今までに、スポーツのために出かけ、ベストを尽くした結果、短い時間でも自分が重要な役割に就いていて、ヒーローかチャンピオンになるチャンスが開かれていることに気づきましたが…結局失敗した、ということがありましたか? 私たちの多くは、人生できっとそのような瞬間を経験したに違いないと思います。これが、「明日へのタッチダウン」(原題は “The Best of Times.”) という映画の背景です。この物語の中で、中年の銀行員 Jack Dundee (Robin Williams) は、何年も前のフットボールの試合でのミスのために深い憂鬱を抱えていたのですが、もう一度試合をやり直そうと決心します。そのため彼は、かつて偉大なフットボールのクォーターバックだった Reno Hightower (Kurt Russell) にカムバックするように説得しなければなりませんでした。Reno は現在の苦しい生活のことをあきらめていて、心の支えであり、年とともに忘れがたくなっていた過去の栄光を書き換えることを望みません。彼らはどちらも、年月は過ぎ去ったという事実に直面しているだけでなく、結婚関係でも泥沼に陥っていて、何とかすることが必要でした。Jack の義父 (Donald Moffat) は何かにつけ、彼のミスのことを思い出させるので、容易なことではありません。それでも Dundee はあきらめず、人生最大の失策を帳消しにしようとあらゆることを試みます。青春時代を思い出したい人にとっては最高のエンターテインメントです」。
このデモのデータファイルは、 test.csv および train.csv となっています。[注記: データセットは、GitHub のリポジトリ内に含めることも、パブリックな Amazon S3 バケットを作成することもできます。どちらでも、うまくいく方を使用してください]
まず、アーキテクチャの静的なピースすべてを作成します。セキュリティポリシー、Amazon S3 バケット、コンピューティング環境とジョブキュー、AWS Lambda 関数と AWS Lambda トリガーです。それからトレーニングと予測のためのコードを Docker コンテナに配置し、それを Amazon Elastic Container Registry (Amazon ECR) にアップロードします。 作業用コンテナを作成したら、Amazon SageMaker を使用して、分類モデルのトレーニングを短時間で行うことができます。
データを予測バケットにアップロードすると、トリガーにより、Predict Job Lambda 関数は、Amazon S3 にアップロードしたばかりのデータに対して私たちのコンテナの予測スクリプトを使用するようになります。このジョブは、Amazon SageMaker タスクからのトレーニング済みパラメーターを使用して、イベントソースデータ上で予測を行います。
bash 対応のコンピューターであること、Git, Docker と AWS CLI がインストールされていることを確認します。
SageMaker をまだインストールしていない場合には、次のコマンドでインストールします。
pip install sagemaker
wget https://s3.amazonaws.com/aws-ml-blog/artifacts/text-classification-gluon/gluon-sagemaker-batch-blog.zip && unzip gluon-sagemaker-batch-blog.zip
AWS Batch へのカスタムのタイインがあるため、ビルド済みのタイインを使用する代わりに、顧客の Amazon SageMaker イメージを構築することにします。以前のブログ、 AWS Batch上のディープラーニングでしたように、Docker を使用して、Amazon SageMaker と私たちのコンピューティング環境が活用するイメージを作成します。私たちの Dockerfile は、いくつかの追加パッケージとともに、mxnet/python:gpu Docker リポジトリ上で構築されます。注意するべきインポート行は 2 番目の RUN コマンドです。ここでは spacy パッケージを使用してトレーニング済みの語句埋め込み機能をダウンロードし、トレーニングをスピードアップします。トレーニングと予測のジョブを管理するために、次の 3 つのスクリプトを追加します。train
(SageMaker が利用する python 実行ファイル)、predict.py
、およびutils.py
です。utils.py
は、様々なファイル転送を管理し、Gluon 内で言語モデルを定義し、受け取るテキストをエンコードするための構造を作成します。。train
ファイルはトレーニングデータを処理し、データに基づいて言語モデルをトレーニングし、モデルのパラメーターとテキストエンコーダーを Amazon S3 にアップロードします。。predict.py
スクリプトは、以前に作成されたそれぞれのパラメーターをダウンロードし、言語モデルの重み付けをロードし、分析対象であるファイル (test.csv
ファイル) 上での予測を行います。
DockerfileFROM mxnet/python:gpuRUN pip2 install numpy scipy sklearn pandas awscli boto3 spacy -URUN python2 -m spacy download en_core_web_md# add these files for batch predictionADD mxnet_model/utils.py /usr/local/bin/utils.pyADD mxnet_model/predict.py /usr/local/bin/predict.pyADD mxnet_model/train /usr/local/bin/train.pyENV PYTHONUNBUFFERED=TRUEENV PYTHONDONTWRITEBYTECODE=TRUEENV PATH="/opt/program:${PATH}"COPY mxnet_model /opt/programWORKDIR /opt/programUSER root
私たちのtrain
ファイルがまだ実行可能でない場合のことを考えて (実行可能になっているはずですが)、用心のため、次のコマンドを実行します。
chmod +x train
Docker イメージを Amazon ECR にプッシュするには、次のコマンドを実行します。
cd container && build_and_push.sh languagemodel && cd ..
今作成したばかりのイメージの Amazon Repository URI が必要となります。忘れてしまわないように、URI をいずれかのテキストエディタにペーストしておいてください。(本当に Repository URI を忘れてしまった場合には、Amazon ECS コンソールの [Repositories] の下で見つけることができます)。それは {account-id}.dkr.ecr.{region}.amazonaws.com/languagemodel のような形式になっています。
ここでは、AWS Lambda トリガー関数を特定の Amazon S3 バケットに割り当てます。そのバケットにファイルを入れると、特定の Lambda 関数へのトリガーになります。私たちの例では、データを Amazon S3 バケットに入れると、トリガーが Lambda 関数をアクティベートし、今度はそれがジョブのトリガーになって、ジョブはデータに基づく予測を行います。
Amazon S3 バケットを作成してトリガーを割り当てる前に、Lambda 関数のコードを、選んだ Amazon S3 バケットにアップロードする必要があります。Lambda バケットの名前を選ぶことが必要です。ここでは「mxnet-lambda」という名前にします。(この名前は後ほど必要になるので、コピーして、URI 情報を記録したテキストエディタにペースとしておいてください) 。Lambda 関数を作成する際には、それを .zip ファイルにして、構築の基にします (このファイルにも保存場所が必要です。たとえば S3 バケットにします)。まず .zip ファイルを Amazon S3 にアップロードすることにより、AWS CloudFormation スタック内で依存関係の問題が生じるのを防ぐことができます。
これを行うには、次のコマンドを実行します。
cd lambda-function && zip lambda_function.zip lambda_function.py # mxnet-lambda is the name of the bucket we will create# mxnet_batch_lambda/lambda_function.zip is the name of the key# 1. create bucket with a unique name - I used mxnet-lambdaaws s3api create-bucket --bucket mxnet-lambda --region us-east-1# 2. copy lambda_function.zip to our new bucketaws s3 cp lambda_function.zip s3://mxnet-lambda/mxnet_batch_lambda/lambda_function.zipcd .. && cd ..
同様の依存関係の問題が発生する可能性があるので、実際のトリガーは、ステップ 5 まで作成しないことにします。
このステップでは、Amazon Virtual Private Cloud (Amazon VPC) を構築し、必要な Amazon S3 バケットを作成し、適切な AWS Identity and Access Management (IAM) のロールを AWS Cloud リソースに割り当て、最後に AWS Batch 環境を構築します。このステップを開始するには次の点に注意してください。
この情報を基に、AWS CloudFormation と AWS CLI を使用して、アーキテクチャをプログラム的に作成することができます。
cd cloudformation-templates && aws cloudformation create-stack --stack-name mxnet-batch --template-body file://create.yaml --parameters ParameterKey=s3uniqueprefix,ParameterValue=MY UNIQUE NAME HERE ParameterKey=LambdaCodeBucket,ParameterValue=LAMBDA NAME FROM STEP-3 ParameterKey=IMAGE,ParameterValue=YOUR REPOSITORY URI HERE FROM STEP-2 ParameterKey=EnvironmentTag,ParameterValue=Development --capabilities CAPABILITY_NAMED_IAM
AWS マネジメントコンソールで、CloudFormation コンソールに移動し、mxnet-batch という名前のスタックが正常に実行されるか確認します。完了したら (10~20 分後)、ジョブキューを作成する必要があります。(注記: ジョブキューは、コンピューティング環境が作成され、検証された後に初めて作成できます)。 現在のフォルダが CloudFormation-templates になっていることを確認して、次のコマンドを実行します。
aws cloudformation create-stack --stack-name mxnet-batch-jobqueue --template-body file://jobqueue.yaml --capabilities CAPABILITY_NAMED_IAM
AWS Lambda トリガーを作成するのに必要なのは、Step 4 で選択した固有のバケットプレフィックスだけです。
cd lambda_triggers && bash launch_triggers.sh {MY_UNIQUE_PREFIX} && cd ..
このスクリプトにより、新しいオブジェクトが予測バケットに入れられたとき、Lambda 関数が呼び出されることが保証されます。
トレーニングスクリプトで定義した言語モデルを適切にトレーニングするには、モデルが必要としているトレーニング設定をセットしなければなりません。この設定 (config フォルダ内にあります) には、トレーニングのエポック数や、アーキテクチャおよび最適化固有の情報が含まれています。このファイルは、CloudFormation テンプレート内で定義した「MY-UNIQUE-NAME-model-config」バケットにアップロードされます。
次に示すのは、私が使用したトレーニング設定です。異なるパラメーターを試してみたい場合には、そうすることもできます。必要なのは、パラメーター MODELPARAMSURL、TRANSFORMERURL、および MODELCONFIGURL を、ステップ 4 で選択した固有のプレフィックスに合わせて変更することだけです。
{ "n_classes" : 2, "num_epoch" : 5, "optimizer" : "adam", "seq_len" : 500, "vocab_size" : 5000, "batch_size" : 64, "hidden_size" : 500, "embed_size" : 300, "dropout" : 0.2, "n_layers" : 1, "bidirectional" : true, "train_log_interval" : 10, "val_log_interval" : 5, "learning_rate" : 0.001, "use_spacy_pretrained" : true, "save_name" : "model.params", "MODELPARAMSURL" : "batch-mxnet-demo-model-paramameters", "TRANSFORMERURL" : "batch-mxnet-demo-text-transformer", "MODELCONFIGURL" : "batch-mxnet-demo-config-bucket", "epoch_factor" : 4, "power_decay" : true, "cnn" : true, "wd" : 0.0002, "kernel_size" : 8 }
設定についての説明は、次の通りです。
n_classes は、言語モデルが予測するクラスタイプの総数です。IMDB のデータセットには、2 つのクラスしかありません。公的的なレビューと否定的なレビューです。
num_epoch は、言語モデルがトレーニングを受ける、トレーニングエポックの総数です。エポックが 1 の場合、モデルはトレーニングセット全体を 1 回だけ学習します。
optimizer は、使用する学習アルゴリズムです。利用可能なオプションについては、http://mxnet.incubator.apache.org/api/python/optimization/optimization.html を参照してください。
seq_len は、シーケンス長を意味しています。このパラメーターは、特定のセンテンスにおける単語の最大数です。センテンスがこの長さより短かった場合には、0 で埋められます。センテンスが長かった場合は、切り詰められます。これはトレーニングデータとテストデータをエンコードするために使用されます。注: このパラメーターをトレーニング後にリセットすることはできません。モデルは、このパラメーターに固有のものとして構築されるからです。
vocab_size は、最も多く使われる単語から数えて何番目の順位の単語まで学習するかを指定します。あまり使われない、つまりこのパラメーターより順位が下の単語は、単に無視されます。この考え方は、私たちは存在する語彙を N 番目によく使われる単語にまで制限していて、それ以外のものはないことにしているというものです。このパラメーターを小さくすると、精度は犠牲になりますが、モデルは高速になります。ただし、小さくしすぎると、結果が無意味になってしまいます。
batch_size は、一定の時間内に、いくつのセンテンスでモデルのトレーニングを行うかをコントロールするパラメーターです。このパラメーターの増減は最適化に関する問題で、このデモが対象とする範囲を超えています。それでも、雑草の中に分け入るつもりがあるなら、https://www.quora.com/Intuitively-how-does-mini-batch-size-affect-the-performance-of-stochastic-gradient-descent での議論を参照してください。
cnn パラメーターは、たたみ込みネットワークベース言語モデルと、LSTM ベースの言語モデルのどちらを使用するかをコントロールします。
use_spacy_pretrained は、ネットワークの初期化のために、spacy のトレーニング済み単語埋め込みを使うかどうかを決めます。
embed_size では、spacy のトレーニング済み単語埋め込みを使わないことにした場合に使用する埋め込みのサイズを設定できます。デフォルトは 300 です (spacy のサイズ)。
hidden_size は、LSTM 内のレイヤーの大きさをコントロールします (LSTM オプションを選んだ場合)。ここで選択してあるサイズは、今回の問題 (imdb セットに基づく感情分析) に固有のものですが、自分自身のデータセットに関してはこの数値を増減して調査してみるべきでしょう。
dropout は、モデルが過剰適合するのを避けるための、正規化パラメーターです。推奨される値は 0.1~0.5 です (1,0 を超えられないことに注意してください)。
n_layers は、LSTM 内の再帰レイヤーの数をコントロールします (LSTM オプションを選択した場合)。hidden_size と同様に、これはデータセットに依存します。
bidirectional は興味深いパラメーターです。LSTM 内の再帰関数が、シーケンス上で順方向に進むだけでなく、逆方向にも進むかどうかをコントロールします。現在は true (真) に設定されています。
train_log_interval は、与えられたトレーニングバッチの損失と混乱に関する情報の表示を制御するパラメーターです。N 回のバッチごとに表示されるということを意味しています。このパラメーターでは、この N の値を設定します。
val_log_interval は、損失、混乱、および検証セットの精度に関する情報を制御するパラメーターです。N 回のバッチごとに表示されるということを意味しています。 このパラメーターでは、このN の値を設定します。
learning_rate は、時間の減少関数で、最適化アルゴリズムでの学習率をコントロールします。 learning rate もまたデータセットに依存しており、自分自身のデータセットで試してみるべきものです。
save_name では、モデルの重み付けを S3 に保存する際の名前を決めます。
MODELPARAMSURL は、モデルの重み付けを保存する S3 バケットです。
TRANSFORMERURL は、テキストの変換方法を保存する S3 バケットです。テキストの変換方法は重要です。受け取ったテキストが、トレーニングデータセットの語彙範囲内に制約されるようにするものだからです。
MODELCONFIGURL は、予測タスクが設定ファイルを引き出す S3 バケットです。
epoch_factor は、学習率が減衰しはじめる開始点です。
power_decay は、下の減衰関数により、シンプルに学習率を減衰させるかどうかを決めます。この方式を用いる場合のデフォルトは、現在の学習率 * 90 になります。
decay = math.floor((epoch) / config['epoch_factor'])trainer.set_learning_rate(trainer.learning_rate * math.pow(0.1, decay))
wd は重み付け減衰 (weight decay、L2 正規化係数) を意味しており、この例では 0.0002 に設定されています。これは、大きな重みを持っていた場合、ペナルティを科すことによって、目的の関数を修正します。
kernel_size は、CNN オプションを選択した場合の、たたみ込みウィンドウのサイズをコントロールします。
では、設定ファイルを Amazon S3 config-bucket にアップロードしましょう。
aws s3 cp config/config.json s3://MY-UNIQUE-PREFIX-FROM-STEP-4-config-bucket/config.json
モデルのトレーニングを開始するに当たって、2 つの選択肢があります。シンプルなスクリプトと、Jupyter Notebook のどちらを使うかということです。Python スクリプトを使用する場合には、コードのルートディレクトリで次のコマンドを入力します。
python train_sagemaker_model.py
次のものと同様の結果が出力されるはずです。
Jupyter Notebook オプションの場合には、コードのルートディレクトリで次のコマンドを入力して、Jupyter Notebook アプリを起動します。
jupyter notebook
Notebook Dashboard で、「train_sagemaker_model.ipynb」という名前のファイルを探し、クリックします。ここから、Shift-Enter を押しながらセル単位でドキュメントを実行することもできますし、ナビゲーションペインで [Cell] をクリックし、[Run All] を選択することにより、ノートブック全体を実行することもできます。
コードのトレーニングが完了し、Best Validation Accuracy が受け入れられるものであれば、バッチプロセッサーを使用するべき時です。
これで、新しいコンテンツを予測バケットにアップロードすれば、データの処理のためにバッチのパワーを使用することができます。Lambda 関数をトリガーするには、次のコードを使って、test.csv を予測バケットにアップロードします。
aws s3 cp data/test.csv s3://MY-UNIQUE-PREFIX-FROM-STEP-4-predict-bucket/test.csv
AWS Batch コンソールにログインして、状態が RUNNING (実行中) か SUCCEEDED (成功) かを確認できます。また、Batch コンソールのリンクをクリックして、ジョブの STDERR/SDTOUT 情報を Amazon CloudWatch Logs に送り、進行状況をチェックすることもできます。
aws s3 cp s3:// MY-UNIQUE-PREFIX-FROM-STEP-4-batch-results/test_output.csvtest_output.csv
このデモのように、AWS を利用するシステムを使えば、エンジニアは一定のスケールでコードを開発、テスト、そしてデプロイする自由が得られます。AWS がオーバーヘッドを管理してくれるからです。Amazon SageMaker を使用して、自分の代わりにトレーニングプロセスを管理させれば、データサイエンティストは、自分の会社のため高度に複雑なシステムの構築と編成を始められます。さらに進んで、Amazon SageMaker を AWS Batch の大規模なバッチプロセスと組み合わせれば、どのようなワークフローであっても、ボトルネックの解消に寄与することができます。
Matt Krzus は AWS プロフェッショナルサービスのデータサイエンティストです。彼は低消費電力エッジデバイスでの Machine Learning と Computer Vision の背景を有しています。彼は現在、プロフェッショナルサービス内の、IoT およびアナリティクスのチームと働いています。