Amazon Web Services ブログ

Amazon SageMaker がサポートする、「マーチマッドネス」予想アプリケーションを構築する

「マーチマッドネス」バスケットボールトーナメントゲームのオープニングラウンドはどれもすごい試合でした!ブザービーターあり、歴史的な大番狂わせありで、どのゲームも興奮させるものでした。最初のブログ (パート 1) で構築したモデルは、いくつかあまり可能性のなさそうな番狂わせ (下位シード校の勝利) の候補を指摘しましたが (Loyola IL、 Butler)、一部の結果は予見できませんでした (Marshall、UMBC)。これから数週間は、さらなる熱狂 (マッドネス) が待ち受けているに違いありません。

私たちの側では、マーチマッドネス予測アプリケーションを作成することにしましょう。これはパート 1 で Amazon SageMaker を使用して作成したモデルとエンドポイントを活用するものです。



今回のブログでは、静的な Amazon Simple Storage Service (Amazon S3) ウェブサイトを作成し、ユーザーが 2011~2018 年のデータから想像上の対戦をシミュレートして、本日時点での全ゲームの予想スコアを表示するとともに、2018 年 NCAA トーナメントのすべての対戦について、予想スコアと勝利確率を表示できるようにします。

私たちは AWS CloudFormation スクリプトを活用して、このウェブサイトを作成するの日必要な AWS サービスを起動します。CloudFormation は強力なサービスで、クラウド環境に必要なすべてのインフラストラクチャとリソースを、シンプルな JSON または YAML テンプレートで記述し、準備できるようにします。この例では、次の物が含まれます

  • AWS Lambda 関数。データを変換して、予測を行う Amazon SageMaker エンドポイントに送信します。
  • Amazon API Gateway。ユーザーの入力を受け取り、Lambda 関数の 1 つをトリガーして、ユーザー入力に基づく予測を生成します。
  • Amazon Elastic Compute Cloud (Amazon EC2) インスタンス。新しいゲームの結果とチームの効率性データをダウンロードして、ウェブサイトと予測を最新のものに保ちます。
  • Amazon S3 バケット。データを保存し、静的ウェブサイトをホストします。
  • AWS Identity and Access Management (IAM) ロール。Lambda 関数と EC2 インスタンスが、他の AWS のサービスと対話できるようにします。

パート 1 で作成した Amazon SageMaker エンドポイントは、これらのリソースとともにバックグラウンドで作業をし、本日のゲームに対して新しい予測を生成します。また、ユーザーが開始した想像上のマッチアップにも対応します。

2 部からなるこのシリーズのパート 2 では、EC2 インスタンス (最初の時点では無料利用枠の条件を満たしていた) を強化することが必要です。Amazon SageMaker では、予期していなかった課金を避けるために、完了後にシャットダウンするのが重要であるのと同じです! 作成する Amazon S3 バケットはパブリックなので、バケットにプライベートなデータを入れないように注意してください。パート 1 で作成したエンドポイントを削除してしまっていた場合には、パート 2 を実行するために再作成する必要があります。

リソースの準備開始のため CloudFormation スクリプトを使用する前に、CloudFormation スクリプトのダウンロードや、ウェブサイトに設定される index.html ファイルを用意することなど、いくつかのシンプルなタスクを実行する必要があります。

CloudFormation の準備作業

始めるには、まずいくつかのファイルをローカルディレクトリにダウンロードする必要があります。これは次の AWS コマンドライン (AWS CLI) スクリプトで実行できます ({local_file_location} は自分の実際のローカルディレクトリで置き換えてください)。 インストールと AWS CLI の使用方法の詳細については、このリンクを参照してください。

aws s3 cp s3://aws-ml-blog/artifacts/bball/mm_cloudformation.json local_file_location
aws s3 cp s3://aws-ml-blog/artifacts/bball/index.html local_file_location

このコードを実行すると、 index.html および mm_cloudformation.json というファイルが、選択したローカルディレクトリにコピーされます。

Amazon EC2 キーペアの作成

このアプリケーションを構築するには、SSH を使用して EC2 インスタンスに接続する必要があり、そのためには CloudFormation スタックを起動するリージョンの Amazon EC2 キーペアにアクセスできなければなりません。既存のキーペアがあるなら、この課題でそのキーペアを使用してもかまいません。ない場合には、キーペアを作成するために、AWS マネジメントコンソールを開いて EC2 コンソールに移動します。EC2 コンソールの左ナビゲーションペインで、[Key Pairs] を選択します。

[Create Key Pair] を選択し、「march_madness」と入力して (間違えずに入力してください)、[Create] を選択します。 これにより、 march_madness.pemというファイルがダウンロードされます。このファイルは安全なプライベートの場所に保存しておきます。後ほど説明する、パブリックの S3 バケットにはアップロードしないでください。このファイルがないと、SSH で EC2 インスタンスに接続することはできなくなります。

us-west-2 以外のリージョンで起動する際に必要となる変更点

パート 1 で、Amazon S3 バケットと Amazon SageMaker ノートブックインスタンスを us-west-2 以外のリージョンで起動していた場合、パブリックの S3 バケットからのデータ (wp-public-blog-cbb) を、パート 1 で作成した S3 バケットにコピーする必要があります。wp-public-blog-cbb は us-west-2 にあり、そのバケット内の .zip ファイルを、CloudFormation スタックにより作成される Lambda 関数のデプロイメントパッケージとして使用することになります。

デプロイメントパッケージは、Lambda 関数が作成される AWS リージョンと同じリージョンになければなりませんパート 1 の Amazon SageMaker と S3 バケットを us-west-2 でデプロイしていた場合には、このデータのコピーは必要ありません。 

一方、us-west-2 以外のリージョンでデプロイしていた場合には、デプロイメントパッケージ (.zip ファイル) を、us-west-2 のパブリックバケットから、パート 1 で作成した S3 バケットにコピーする必要があります。{your_s3_bucket} の部分をパート 1 で作成した S3 バケットの名前で置き換えた上で、次のコマンドを実行してください。

aws s3 cp s3://wp-public-blog-cbb/updater.zip s3://your_s3_bucket
aws s3 cp s3://wp-public-blog-cbb/newdaydata.zip s3://your_s3_bucket
aws s3 cp s3://wp-public-blog-cbb/userinput.zip s3://your_s3_bucket
aws s3 cp s3://wp-public-blog-cbb/daily_updater.sh s3://your_s3_bucket

CloudFormation スクリプトを実行する

これで、CloudFormation スクリプトを実行する準備ができました。CloudFormation コンソールに移動し、Amazon SageMaker エンドポイントおよび S3 バケットと同じリージョンで [Create Stack] を選択します。次の画面で、[Upload a template to S3] ラジオボタンを選択して、自分のローカルディレクトリの mm_cloudformation.json ファイルをアップロードし、[Next] を選択します。

次のページで、スタックに名前を付け、自分の環境に合わせてパラメーターを編集します。それぞれのパラメーターの意味は次の通りです。 

  • CoefficientParameter: パート 1 で構築したロジスティック回帰勝率モデルと関連付けられている、モデル係数です。ロジスティック回帰モデルを構築していなければ、これはデフォルトのままにしてください。
  • DeploymentPkgS3BucketParameter: この CloudFormation スタックにより作成される Lambda 関数のためのデプロイメントパッケージを収める S3 バケットです。スタックを us-west-2 で起動していた場合には、デフォルトのバケットを使用します。別のリージョンを使用していた場合には、前のステップで説明したとおり、CloudFormation スタックを起動するリージョンの S3 バケットにデプロイメントパッケージをコピーしたことを確認してください。
  • DifferenceModelParameter: 点差モデルに関連付けられている SageMaker エンドポイントの名前です。パート 1 のエンドポイントデプロイメントコードを変更していなければ、デフォルト値を使用してください。
  • InterceptParameter: パート 1 で構築したロジスティック回帰勝率モデルと関連付けられている、インターセプトです。ロジスティック回帰モデルを構築していなければ、これはデフォルトのままにしてください。
  • KeyPairParameter: 使用する EC2 キーペアの名前です。march_madness Key Pair を作成した場合には、デフォルト値のままにしてください。
  • TotalModelParameter: 合計点モデルに関連付けられている SageMaker エンドポイントの名前です。パート 1 のエンドポイントデプロイメントコードを変更していなければ、デフォルト値を使用してください。

これらのパラメーターを自分の環境に合わせて調整したら、[Next] をクリックします。次のページでは、パート 1 で使用したのと同じタグを追加します。Key には「public_blog」、Value には「cbb」 です。このページの他の設定は自由に調整してかまいませんが、これらはどれもこのアプリケーションの構築で必須なものではありません。

最後に、次ページのすべての設定を見直し、[I acknowledge that AWS CloudFormation might create IAM resources] (私は AWS CloudFormation が IAM リソースを作成する場合があることを認めています) のボックスにチェックを入れ (これはスクリプトが IAM リソースを作成するので必要です)、[Create] を選択します。 これによりこのアプリケーションが必要とするすべてのリソースが作成されます。実行にはいくらか時間がかかります。スタックの進行状況を表示するには、作成したスタックを選択して、[Events] セクションまたはパネルを選択します。

すばらしい! それから、EC2 インスタンスにプリロードされるシェルスクリプトにいくらかの調整を加えて、cron ジョブをセットアップします。これは、毎日最新のデータを取得して、自分自身の環境からこのアプリケーションを実行するためです。

自分の EC2 インスタンスのコードをカスタマイズする

これらの変更を加えるには、SSH を使用して、CloudFormation スクリプトによって作成された EC2 インスタンスに接続する必要があります。お使いのローカルマシンに SSH クライアントがインストールされていれば、これはコマンドラインから実行できます。先ほどダウンロードした march_madness.pem ファイルが保存されているディレクトリに移動し、次のコマンドを、your-public-ipyour-region を自分の EC2 インスタンスでの値で置き換えた上で実行します。SSH コマンドの実行後にプロンプトが表示されたら、yes と入力します。

chmod 400 march_madness.pem
ssh -i "march_madness.pem" ec2-user@ec2-your-public-ip.your-region.compute.amazonaws.com

詳細についての説明と、問題が生じた際にトラブルシューティングを行う方法については、このリンクを参照してください。

EC2 インスタンスで ls –l コマンドを実行すると、ホームディレクトリの内容に関する次のような情報 (日付と時刻は異なるでしょう) が表示されるはずです。これらは、CloudFormation スタートアップスクリプトの EC2 インスタンスの UserData の部分でインストールされたものです。

ec2-user のところに root が表示されていたら、スタートアップスクリプトをあと何回か実行する必要があります。EC2 インスタンスで exit と入力し、5 分ほど待ってから、SSH を使用してインスタンスに再度接続します。EC2 インスタンスでもう一度 ls –l と入力して、ec2-user という表示に出ていないか確認してください。ec2-user が表示されていたら、前に進めます!

よくできました。次はシェルスクリプトをアップデートします。EC2 インスタンスで、次のように入力します。

cd ~/
vi daily_updater.sh

これによって daily_updater.shが開かれるので、i キーを押してファイルを編集します。このファイルは、「wp-public-blog-cbb」S3 バケットから更新されたチーム成績データと毎日の対戦情報を取り込むために用いられます。

insert-s3-bucket-name は、CloudFormation スタックで作成した S3 バケットで置き換えてください。この S3 バケット名は、CloudFormation コンソール内で、以前に実行したスタックを選択した状態で [Resources] パネルを見ればすぐに確認できます (mycbbpredbucket のような名前になります)。

[Esc] :wq の順にキーを押して、 daily_updater.sh を保存します。

次に、毎日のこのプロセスを自動化する、cron ジョブをセットアップします。次のコマンドを入力して、cron スケジューラを開きます。

crontab -e

それからファイルを編集するために i キーを押し、次の行を挿入して、先ほどと同じく [Esc] :wq の順にキーを押して保存します。

00 14 * * * /home/ec2-user/daily_updater.sh

これは、daily_updater.sh ファイルに含まれているスクリプトを毎日、グリニッジ標準時の午後 2 時 (太平洋標準時の午前 7 時、東部標準時の午前 10 時) に実行します。これにより、その日の試合が始まる前に予測を更新することができます。この毎日の更新を必要とする 2 つのファイル (kenpomnew_active.csv と new_day_matchups.csv) は、wp-public-blog-cbb S3 バケットではグリニッジ標準時の午後 1 時半 (太平洋標準時の午前 6 時半、東部標準時の午前 9 時半) ころに毎日更新されます。それで、この cron ジョブをそれより早い時間に更新すると、前日のデータが除外されてしまいます。この cron ジョブを作成しないままだと、ウェブサイトのコンテンツは古いものになってしまいます。

Lambda 関数トリガーのアップデート

よくできました。今度は、イベントに基づいて Lambda 関数が実行されるように、Lambda 関数のためのトリガーを設定する必要があります。Lambda コンソールに移動して (または CloudFormation コンソールの [Resources] パネルで)、lambdaupdater Lambda 関数を選択します。左側の [Add Triggers] ペインで、[S3] を選択します。

次に、[Configure Triggers] セクションにスクロールダウンし、CloudFormation スタックにより作成された S3 バケットを選択し (「mycbbpredbucket」というような名前になっています)、次の設定に一致するように残りの項目を設定してから、[Add] を選択します。

変更を有効にするため、ページの右上にある [Save] を選択します。

実のところ、この関数の目的は、デプロイメントパッケージ (.zip ファイル) が Amazon S3 に保存されるたびに、newpreds および userpreds Lambda 関数の両方について、コードとデプロイメントパッケージを更新することです。newpreds Lambda 関数は今日の試合についての予測を表示してサイトを更新し、userpreds Lambda 関数はサイトのユーザーが入力する想像上の対戦に対応します。セットアップした cron ジョブは、パブリックの S3 バケットから新しいデータを取り込み、.zip ファイルをユーザーの S3 バケットに再アップロードすることによって、デプロイメントパッケージを更新する lambdaupdater Lambda 関数をトリガーします。この関数がなければ、サイトと予測は古い物になってしまいます。

さて、ここまでで実施したトリガー作成プロセスを、newpreds Lambda 関数でも繰り返します。[Configure Triggers] セクションで、[newpreds] 関数を選択し、前と同じステップを繰り返し、セクションに次の情報を設定して、 [Add] を選択します。

変更を有効にするため、ページの右上にある [Save] を選択します。デプロイメントパッケージ内のコードを更新した後、lambdaupdater Lambda 関数は、ユーザーの S3 バケット内にある dummy_uploader.txt という名前のファイルもアップロードします。これは newpreds Lambda 関数のトリガーとなり、当日の試合の予測をウェブサイトに掲載します。

userinput Lambda 関数はトリガー設定を必要としません。サイトのユーザーによって開始されるものであり、そのデプロイメントパッケージは lambdaupdater Lambda 関数によって毎日更新されるからです。AWS Lambda の更新については、これで完了です!

では、少し EC2 インスタンスに戻り、daily_updater.sh ファイルを実行して、AWS Lambda デプロイメントパッケージのアップロードを開始することにしましょう。SSH を使用し、資格情報の期限が切れていた場合には EC2 インスタンスに接続して、次のコマンドを実行します。

cd ~/
./daily_updater.sh

数分ほど経つと、次のファイルが S3 バケットに入ったことを確認できるはずです。

zip ファイルは前のものと同じですが、アップデートを実行することにより、Lambda 関数は空の dummy_uploader.txt ファイル (前に述べたもの) と、 new_day_preds.csvファイルを作成します。この CSV ファイルには当日の試合の予測データが入っており、それがウェブサイトに設定されます。このチュートリアルを完了した日に試合がなかった場合、サイトの下半分には何も表示されませんが、それでも大量の歴史的情報にアクセスできます。再び試合が始まれば、サイトには当日の試合に関する情報が表示されます。

2018 年の NCAA トーナメントの予測に追加する

この 2 パートからなるブログシリーズのパート 1 を終えていたなら、Amazon SageMaker でのモデリングで使用した S3 バケットに tourney_outcome.csv というファイルがあるはずです。AWS CLI を使ってその S3 バケット内のファイルを CloudFormation スタックが作成した S3 バケットにコピーし、今年のトーナメントからの予測をウェブサイトに掲載しましょう。{your_model_bucket} と {your_cloudformation_bucket} は、自分の S3 バケットの名前で置き換えてください。

aws s3 cp s3://your_model_bucket/tourney_outcome.csv s3://your_cloudformation_bucket

これで、S3 バケットの内容は次のようになるはずです。

このセクションをまだ実施していなくても、心配は要りません。サイトにはやはり、今日行われる試合についての予測が掲示されます。ただ、2018 年の NCAA トーナメント全体についての予測が行われないだけです。

Index.html を更新して、ウェブサイトをテストする

次に、CloudFormation スタックが作成した API Gateway を反映するように、Index.html を更新しましょう。サイトのユーザーからのリクエストが、ブログのパート 1 で作成した Amazon SageMaker エンドポイントに適切にダイレクトされるようにするためです。

CloudFormation コンソールで、[Resources] パネルを選択して、[Physical ID] (Rest API ID) をコピーします。これは PredAPI と関連付けられているものです。この課題の初めにダウンロードした index.html ファイルを開き、フォームエレメントに対応するアクションを、自分の Rest API ID とリージョンで更新します。

index.html ファイルを mycbbpredbucket S3 バケットに保存します。ファイルをパブリックにしたことを確認してください。CloudFormation スクリプトは S3 バケットをパブリックに閲覧できる静的なウェブサイトとして設定したので、次のアドレスにアクセスすれば (your-s3-bucket-name と your-region を自分の S3 バケットとリージョンに置き換えてください)、ページの上方にフォームがあって、今日の試合についての予測されたスコアが表示されており、(tourney_outcome.csv ファイルをアップロードしていれば) ページの下には 2018 年の NCAA トーナメント全体の予測結果が表示されるはずです。

http://your-s3-bucket-name.s3-website.your-region.amazonaws.com

おめでとうございます! これで、新しい予測を毎日生成し、2011~2018 年の想像上の対戦についてのユーザーの入力に対応し、2018 年のトーナメントを予測するウェブサイトができました。これらすべては、Amazon SageMaker のパワーを活用しているのです!

プロセスは、自分の用途に合うように、自由に変えられます。アプリケーションをサポートしているコードと関数を深く調べれば、望んでいるような調整や改善を加えられるでしょう。値がウェブサイトに表示されない場合には、S3 バケット内のすべてのエレメントがパブリックに表示できること、そして、S3 バケットに今日の予測のための new_day_preds.csv というファイルと、2018 年のトーナメントを予測するための tourney_outcome.csv というファイルがあることを確認してください。CSV ファイルがなかったり、古かったりした場合には、Amazon EC2 の cron ジョブが目的通りに動作していること、そして Lambda 関数が正しく機能していることを確認してください。


Wesley Pasfield は AWS プロフェッショナルサービスのデータサイエンティストです。 彼はノースウェスタン大学から理学修士号を受けており、スポーツ、ゲーム、コンシューマエレクトロニクス、小売業といった様々な業界で問題に取り組んできました。彼は現在、顧客が AWS での機械学習と人工知能のユースケースに対応できるよう支援しています。