Amazon Personalize の一般提供を開始!
先日Amazon Personalizeの一般提供を開始しました。
プレビューの段階からお試しで使っていたので作成の一連の流れを説明していきます。
今回はユーザーに商品を推薦するモデルとエンドポイントの作成を行います。
APIGateway
とLambda
を使用してAPIも作成しました。
課金体系(絶対に最初に目を通す!!!)
料金 | |
---|---|
データ取り込み | 0.05 USD/GB |
トレーニング | 0.24 USD/トレーニング時間 |
レコメンデーション | |
最初の 20K TPS-時間まで | 0.20 USD/1 TPS-時間のリアルタイムレコメンデーション |
次の 180K TPS-時間 | 0.10 USD/1 TPS-時間のリアルタイムレコメンデーション |
200K TPS-時間以上 | 0.05 USD/1 TPS-時間のリアルタイムレコメンデーション |
やらかしてしまった(大量のリクエストには気をつけて!!!)
後に記述しますがboto3
を使用してレコメンドを取得します。
調子に乗ってAPI
を叩きまくってしまった結果がこれです。
やらかしました。3124.7$
って何円だっけ?(約33万円)思考停止です。
ユーザーがおよそ3万人いたのでどんな商品が推薦されるのか知りたくてこんなコードを書いたらなってしまいました。
len(users)
# およそ3万
for user in users:
recommend_item = personalizert.get_recommendations(
campaignArn="<Campaign ARN>",
userId=user['user_id'],)
personalizert = boto3.client(
'personalize-runtime',
region_name='ap-northeast-1')
のちに記述しますが、エンドポイント設定のTPSの上限値を低く設定して入れば回避できていました。(激しく後悔)
1. データを用意する
Amazon Personalizeにデータを読み込ませる際、S3にアップロードされたcsvファイルを使用します。
必要なデータ(ファイル)は以下の3つ(データセットの説明)
私はRedshift
からデータを取得し、pandas
等を利用してcsvファイルを作成しました。
- ユーザーIDと商品IDが紐づいているデータ
- ユーザーIDにユーザー情報が紐づいているデータ
- 商品IDに商品情報が紐づいているデータ
それぞれ必須フィールドや予約キーワードがあります。
ユーザーIDと商品IDが紐づいているデータの例
ユーザーID、商品ID、購入時刻のUNIX時間が格納されているファイル
USER_ID,ITEM_ID, TIMESTAMP
582,456,1477897643
582,458,1477897643
582,490,1472037749
601,855,1472033257
601,451,1472033257
601,451,1472033257
602,454,1472033266
..................
USER_ID
、ITEM_ID
、TIMESTAMP
が必須フィールドです。 予約語としてEVENT_TYPE
、EVENT_VALUE
が用意されています。AWSのドキュメントを読んでみた感じでは,EVENT_TYPE
は購入方法(ネット購入や店舗購入)などのデータ、EVENT_VALUE
は商品の値段などのデータを入れるフィールドだと感じました。
ユーザーIDにユーザー情報が紐づいているデータの例
ユーザーID、年齢、性別が格納されているファイル
USER_ID,AGE,GENDER
180,71,male
185,55,female
332,30,female
352,51,male
365,22,female
..................
USER_ID
が必須フィールドで残りのAGE
とGENDER
はデータセットの説明を真似しました。
商品IDに商品情報が紐づいているデータの例
商品ID、商品名、商品カテゴリーIDが格納されているファイル
ITEM_ID,ITEM_NAEM,CATEGORY_ID
461,歯ブラシ(青),1
693,オールスパイス ,10
112,赤ワイン,9
113,白ワイン,9
369,キャンドル(10本入),6
867,三角帽,15
..................
ITEM_ID
が必須フィールドで残りのITEM_NAEM
とCATEGORY_ID
はこれもデータセットの説明をまねしてみました。フィールドを増やしても問題なさそうです。
2. S3にファイルをアップロードし、バケットポリシーを設定する
PersonalizeからS3にアクセスするためにバケットポリシーを作成します。
{
"Version": "2012-10-17",
"Id": "PersonalizeS3Bucket AccessPolicy",
"Statement": [
{
"Sid": "PersonalizeS3BucketAccessPolicy",
"Effect": "Allow",
"Principal": {
"Service": "personalize.amazonaws.com"
},
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::<作成したバケット名>",
"arn:aws:s3:::<作成したバケット名>/*"
]
}
]
}
2.データをインポートする
作成したcsvファイルをS3にアップロードしたら、Personalizeのコンソール画面からDataset groups
を作成します。
csvファイルのヘッダ名と同じようにSchema definition
を編集します。
IAM service role
は今回は既存の物を使用しましたが、ここでも作成できます。
Data location
にS3のパスを書いてインポート開始です。
ダッシュボードをみるとCreate in progress
になっています。
この調子でUser data
とItem data
も作成していきます。
3. solutionsを作成する
データのインポートが全て終了したらsolutionsを作成します。
Automatic(AutoML)
にチェックを入れるとインポートしたデータから適したモデルを作成します。
割と時間かかりました(1時間以上はかかった気がします)。
モデルをトレーニングするためのレシピの一覧
今回はaws-hrnn
とaws-hrnn-metadata
を使用していきます。
4. campaignを作成する
campaignの名前、solutionを設定、スループットの下限を設定して作成(30分くらい)。
(重要!)スループットの下限はなるべく少なくした方がいいです。DynamoDBのキャパシティーと同じ感じです。私はこの値をテキトーに200
にして、エンドポイントを叩きまくってしまった結果高額な請求がきてしまいました。
5. レコメンドしてみる
campaignの作成が完了するとレコメンドのテストがコンソール画面上から行えるので適当なユーザーIDでテストしてみます。
商品IDが複数推薦されます。画面では表示しきれてないですが25件推薦されました。
6. boto3から実行する
とりあえずローカルの環境から取得できるか、試してみました。
import boto3
if __name__ == "__main__":
personalizert = boto3.client('personalize-runtime', region_name='ap-northeast-1')
response = personalizert.get_recommendations(
campaignArn="<Campaign ARN>",
userId='<User ID>',)
for item in response['itemList']:
print (item['itemId'])
注意点
ローカルのaws-cliにpersonalize-runtime
がない場合があるのでサービスを追加する必要があります。
各サービスのjsonをダウンロードしてaws-cliにセットするだけなのですぐできました。
7. APIを作成する
SeverlessFrameWork
を使用してAPIを作成しました。
コードなど
service: personalize-test
provider:
name: aws
runtime: python3.7
stage: stg
region: ap-northeast-1
profile: test
functions:
recommend:
handler: src/handler.get_recommend
events:
- http: GET /{user_id}
import json
import boto3
def get_recommend(event, context):
user_id = event['pathParameters']['user_id']
personalizert = boto3.client('personalize-runtime', region_name='ap-northeast-1')
response=personalizert.get_recommendations(
campaignArn="<Campaign ARN>",
userId=str(user_id),)
item_list = []
for item in response['itemList']:
item_list.append(item['itemId'])
body = {
'item_list': item_list
}
response = {
'statusCode': 200,
'isBase64Encoded': False,
'headers': {'Content-Type': 'application/json'},
'body': json.dumps(body)
}
return response
問題発生
sls deploy
でデプロイをしたらAPIのエンドポイントが表示されるのでcurl
で試してみたところInternal Server Error
が返って来ました。
CloudWatchのログを見た所以下のログが出ました。
[ERROR] UnknownServiceError: Unknown service: 'personalize-runtime'. .....
内容としてはboto3
でpersonalize-runtime
というサービスはないとのこと。githubのissueにもあがっていました。
解決策としてはamazon-linux
上で最新のboto3
をインストールし、zipで固めてLamdbaのLayerとしてboto3を使用するとのことでした。
AmazonPersonalizeはつい最近一般公開されたばかりでLambdaのboto3の対応が間に合っていないんですかね。
以前の記事(pandasをLambdaのLayerとして追加する)で似たようなことを行なったので同様にzipファイルを作成しました。
作成したzipファイルはgithubにあげましたので使用される人がいれば使ってみてください。
いざ再び
$ curl https://XXXXXXX.execute-api.ap-northeast-1.amazonaws.com/stg/242 | jq
{
"item_list": [
"2200399000000",
"4580118279049",
"4580168655268",
"4580216370631",
"4571243110208",
"4512442005292",
"2400040256128",
"4954540129232",
"2430002732278",
"4512442005490",
"4982757911630",
"4997640091030",
"4997640092105",
"4512442005179",
"4976631605029",
"2400040918354",
"2401020995907",
"4536361026251",
"2430002792463",
"4573222000029",
"2430000383120",
"4580127310146",
"4571243110130",
"4539427300012",
"2430000362002"
]
}
返ってきたー!これで既存のアプリケーションへの利用もできそうです。
#終わりに
今回でAmazon Personalize
の課金体系を身をもって感じたのでみなさんも気をつけてください。 それでもAmazon Personalize
は簡単にレコメーンデーションを作成するとても素晴らしいAIサービス
なのでご利用は計画的に。
今回はEvent trackers
は使用しませんでしたが、Event trackers
を使用すればリアルタイムにレコメンデーションをすることができるので知見がたまり次第紹介しようと思っています。