こんにちは、BBです。
10月のLT会でも発表の際にAmazon SageMakerを使ったので、資源の有効活用という観点でブログにもまとめていきます。ややタイトル詐欺の感もありありですがお付き合いください。
Amazon SageMakerってなに??
Amazon SageMaker(以降はSageMaker)はAmazon Web Service(以降はAWS)が提供する機械学習サービスの中の一つです。SageMakerは2017年末に発表され、東京リージョンで公開されたのは2018年6月という比較的ナウいサービスです。SageMakerは機械学習のコーディング~デプロイまでを一括してカバーしている点を売りにしており、運用やバックエンドについてとやかく考えたくないAIエンジニアでもAWSの庇護のもと安心してサービスを展開できます。また、学習済みのモデルも用意されており、機械学習のことはあまり詳しくないエンジニアでも簡単に利用することができます。得意分野の垣根を越えて機械学習をより使いやすくするためのサービスともいえそうです。
参照:https://aws.amazon.com/jp/
Amazon SageMakerの仕組み
御託は判ったけど、仕組みが分からないと取っ付き辛いと思いますのでここで、簡単にSageMakerの仕組みというかできることを説明していきます。SageMakerには大きく分けて以下3つの機能があります。
- コーディング
- トレーニング
- デプロイ
それぞれの機能に対して専用のインスタンスを作成しますのでSageMakerでは3種類のインスタンスを使い分けていることになります。ちなみにインスタンス?ってなった方はサーバーと読み替えてもらって大きな認識の違いはないと思います。
1. コーディング
コーディングの言語はPythonで、エディタは機械学習ではおなじみのJupyter Notebookを使います。AIエンジニアなら使い慣れている方が多いと思いますので、利用する際のハードルが低くて助かりますね。また、うれしいことにAnacondaをはじめ、機械学習や深層学習で利用するライブラリがすでにそろった状態で開発が始められるというのもお手軽でいいと思います。コーディングやちょっとしたデータの前処理に利用する程度であれば低スペックインスタンスを利用することで費用を抑えることができます。
2. トレーニング
深層学習のモデルをトレーニングする際は低スペックのPCではかなり時間がかかってしまい効率が悪いです。こんな時に一時的にでもハイスペックなPCが利用できたら……という願いを叶えたのがこちらのSageMakerです。GPU付きのハイスペックインスタンスを一時的に利用して効率よく学習を完了します。また、トレーニングの実行から完了にかかった時間のみ課金される仕組みになっており、トレーニング完了次第インスタンスは解放される為、消し忘れなど無駄に料金がかさむ心配がありません。
3. デプロイ
学習済みのモデルは専用インスタンスにデプロイしエンドポイントとして利用することができます。なんかカタカナが多くてよくわからない感じですが、要するに学習させたモデルにデータを突っ込んで、結果を返してもらうための専用サーバーを簡単に作れるよってことです。エンドポイントは動いている限り課金されてしまうので、用がないときは消しておくことを強くお勧めします。
Amazon SageMakerでWebアプリを作ってみる
さて、前段が長くなりましたが今回の本題に入ります。SageMakerを組み込んだWebアプリを作ってみたので手順をまとめていきます。Webアプリは手書き数字画像データの分類を行うものとします。教師データは機械学習の入門でもおなじみのMNISTを使って学習させています。
こんなの作りました
作成したWebアプリの構成はこちらになっております。SageMakerで作成したエンドポイントを使用していますが、APIとして利用するためにAPI Gateway、AWS Lambdaを利用しています。Webサーバは動作検証のみなのでローカルに立てました。フレームワークはFlaskを利用しています。色々慣れないことが多くハードルを下げないと頭がパンクしてしまいますので使用した言語はPythonのみとなっております。
エンドポイント周辺
エンドポイント周辺の構成を説明していきます。サーバレスという言葉にそこはかとない憧れを感じておりますのでAWS LambdaとAPI Gatewayを使った構成にしていきます。以下で説明しているのはとりあえず動けばよいかという動作検証前提の設定です。
機能 | |
---|---|
AWS Lambda | SageMakerのエンドポイントを起動するトリガーの役割を果たします |
API Gateway | APIを提供します。リクエストに対してLambdaとの橋渡しをします |
エンドポイント作成
では手始めにSageMakerでエンドポイントを作成してみましょう。SageMakerのダッシュボード画面に入り、ノートブックインスタンスを作成します。
学習用のソースを作成して実行していくのですが、MNISTの分類問題はすでにソースのサンプルがJupyter Notebook内に保存してありますので、サンプルをそのまま実行していけば何も感じることなくエンドポイントが出来上がってしまいます。ノートブックを開いてSageMaker Examplesタブを選択、SageMaker Python Sdkの中の「tensorflow_distributed_mnist.ipynb」の右にあるUseボタンを押下します。するとFilesタブにフォルダが追加されています。
フォルダ内の「tensorflow_distributed_mnist.ipynb」を開いてそのまま「Run All」するとエンドポイントを作成するまで一気に処理が進み、最後に作成したエンドポイントを削除してしまうので最後の
1 2 3 |
sagemaker.Session().delete_endpoint(mnist_predictor.endpoint) |
だけは事前にコメントアウトしておきましょう。実行完了したらエンドポイントが作成されているかどうかを確認して終了です。SageMakerの出番はこれでおしまいです……。
AWS Lambdaの設定
AWS Lambdaの役割はAPI Gatewayから受け取ったデータをSageMakerのエンドポイントに受け渡してやる事です。その為、作成するLambdaの「トリガー」にはAPI Gateway、「アクセスが許可されているリソース」にはAmazon SageMakerが最低限設定されている必要があります。「トリガー」はAPI Gatewayを作成するときに追加されますので、「アクセスが許可されているリソース」をIAMから編集してSageMakerの権限を追加しました。
画像の「test-lambda」部分を選択すると画面下部に関数コードエディタが表示されますのでPythonで以下の通りコードを入力します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
import json import boto3 def lambda_handler(event, context): # 受け取ったJsonの「img」に格納されたデータを受け取る payload = event['img'] # sagemakerにアクセスする runtime = boto3.Session().client('sagemaker-runtime') # 作成したエンドポイント名称 endpoint_name = 'sagemaker-tensorflow-2018-10-17-06-36-46-632' # 指定したエンドポイントにデータを渡す response = runtime.invoke_endpoint(EndpointName=endpoint_name, ContentType='text/csv', Body=payload) # sagemakerからのレスポンスを受け取る result = json.loads(response['Body'].read().decode()) # レスポンスから分類結果を取り出す result_class = result['outputs']['classes']['int64Val'][0] # APIにレスポンスを返す return { 'statusCode': 200, 'body': result_class } |
受け取ったデータをSageMakerに渡して分類結果を返却するだけの簡単なお仕事です。
API Gatewayの設定
API Gatewayでは設定されたURLにリクエストを送るとLambdaを起動するように設定します。API Gatewayで新規APIを作成しPOSTメソッドを追加します。
メソッドを追加すると統合ポイントの選択画面が表示されますので、統合タイプにLambda関数を選択してやり、作成したLambda関数名を入力すれば完了です。
API呼び出し用のURLはメソッドを追加した画面で「アクション」ボタンからAPIのデプロイを行うことで作成されます。
Webサーバー
次はWebサーバーですが、Python以外使いたくないので簡単だと噂のFlaskを使います。本題とそれるのでFlaskの説明はまた機会がある際にでも回して、APIとアクセスする為の関数の作り方を紹介します。APIへのアクセスを検証する場合はPostmanが非常に使いやすいです。Postmanの使い方はこちらを参考にしました。API Gatewayへのアクセスを検証したいので以下のような設定をしてリクエストを送ります。ここではAPIキーの設定はしていません。
- URLに先ほどAPI Gatewayで取得した参照用URLを入力
- URLの左にある選択ボタンからPOSTを選択
- URLの左にある選択ボタンからBody→rowを選択
- 表示された入力欄に送信するJsonを入力する
送信するJsonはLambdaで設定した通り’img’をキーに指定します。’img’の中身は784次元で0~1の値を持つベクトルです。MNISTの画像が28×28格子の白黒データである為、このような形の値を入力としています。ここでは数字の8にあたるデータを送信しているので結果は以下の通りになります。
1 2 3 |
{"statusCode": 200, "body": "8"} |
Amazon Lambdaに設定した通りの結果が返却されていい感じです。この”body”に格納された”8″が分類の結果となりますので、入力に対してこの値をクライアントの画面に表示すればよいことになります。センスが全くない画面ですがこんな感じになりました。
画像を選択すると選択した画像を784次元のベクトルに変換してAPIに投げるようにしています。
まとめ
今回は簡単ではありますが、Amazon SageMakerを利用したWebアプリを作成しました。Webアプリの構築は初めてということもあり、UIもダサダサですが何とか思った通りの結果を出力することができました。Pythonのみ(ほぼ)を使ってアプリの作成ができたということがPythonをメインに使用している僕にとってはうれしい発見でした。SageMaker部分以外での躓きが多かったのですが、SageMaker自体の使い方は簡潔で取っ付きやすいと思います。あとはエンドポイントを連続稼働し続けても費用がかさまない仕組みがあれば遊びで使っても楽しそうだと思います。
今回は以上です!