Amazon Personalizeでレコメンドアイテムのスコアを取得できるようになりました
1.はじめに
データアナリティクス事業本部の貞松です。最近はレコメンデーションに想いを馳せる日々です。
Amazon Personalize(以下Personalize)のアップデートにより、レコメンドアイテムのスコアを取得できるようになりました。
個人的には待望のアップデートで、これにより取得したレコメンドアイテムの評価や優先順が可視化され、実際にシステムに組み込む際の扱いやすさが改善します(ユースケースについては後述します)
ただし、Personalizeで用意されている全てのレシピ(レコメンドアルゴリズム)に対応している訳ではないので注意が必要です(これについても後述します)
それでは早速アップデート内容について確認していきます。
2.アップデート内容について
2.1.概要
Personalizeで作成されるレコメンド結果として、レコメンドアイテムのリストに加えて、対になるスコアのリストを取得できるようになりました。
2.2.ユースケース
単純に各ユーザーに対して○○件のレコメンドアイテムをPersonalizeで作成してそのまま使用する(おすすめアイテムとして表示する等)のであれば特に必要性を感じないかと思いますが、以下のようなケースではレコメンドアイテムのスコアが必要になってきます。
- 任意の閾値を超えるアイテムだけをおすすめアイテムとして表示します。設定する閾値は相対的な値、例えばスコアの最大値の50%を超えるスコアなどを利用することをおすすめします。絶対値で閾値を設定することは妥当な値を決定するのが難しく、利用するデータの変化に追従できない為です。
- スコアが非常に高い場合に、特別な通知をユーザーに送信したり、ユーザーページに特別な表示をすることで、よりインパクトのあるレコメンドを実施します。
- Personalizeから取得したレコメンド結果を加工して利用します。特定のアイテムを除外してレコメンドリストを再構成したり、スポンサーコンテンツを既定のスコア以下に挟むなどの方法が考えられます。
2.3.制限事項
今回のアップデートで対象となるPersonalizeのレシピ(レコメンドアルゴリズム)は以下の通りです。
- HRNN
- HRNN-Metadata
- HRNN-Coldstart
- Personalized-Ranking
以下のレシピは現状対象外の為、レコメンド結果でスコアを取得することはできません。ご注意ください。
- Popularity-Count
- SIMS
3.動作検証
ここからは実際にPersonalizeでレコメンドの作成を実行しながら、アップデート内容について検証していきます。
また、データセットグループの作成〜データセットのインポートあたりの操作は本記事では割愛します。
本記事の最後に参考記事のURLを記載しますので、上記の手順を含むPersonalizeでの一連の操作についてはそちらをご参照ください。
3.1.使用するデータと検証環境
データセット
今回の検証で使用するデータは、みんな大好きMovieLensのsmallデータセットです。
下記URLページのrecommended for education and development
セクションにあるml-latest-small.zip
です。
https://grouplens.org/datasets/movielens/
データの内容は以下のような形式になっています。
検証環境
AWS SDK(Boto3)での確認は、以下の環境で実施しました。
Boto3のバージョンが古いとスコアが取得できなかった為、最新バージョンに更新しています。実際に試す場合には注意が必要です。
- macOS Catalina 10.15.4
- Python 3.7.6
- boto3 1.12.37
- botocore 1.15.37
3.2.コンソール上での確認
3.2.1.リアルタイムレコメンド
まずはスコアを取得可能なレシピを使用したソリューションを作成します。
今回はユーザーに対するレコメンドアイテムを作成する(ユーザーベースのレコメンド)為のレシピであるHRNN
を使用します。コンソールの画面上ではaws-hrnn
と表記されていますので、これを選択します。
次に上記で作成したソリューションを使用したキャンペーンを作成します。キャンペーンを作成することで、ソリューションバージョン(学習済みのレコメンドモデル)をデプロイし、それにアクセスしてレコメンド結果を得る為のエンドポイント(API)を提供します。
キャンペーンの作成が完了したら、Campaign
ページのPersonalization API
タグを開いて、Test campaign results
フィールドでレコメンド結果を取得したいUserIdを入力して実行します。
結果の出力を確認するとItem ID
と、それに対応するScore
が表示されています。
3.2.2.バッチレコメンド
前述のリアルタイムレコメンドの解説中で作成されたソリューションを利用して、バッチレコメンドについても確認します。
Create batch inference job
で作成済みのソリューションを選択し、レコメンド作成を実行する為の入力ファイルとレコメンド結果出力先のS3パスを指定して実行します。
バッチレコメンドのジョブが完了したら、レコメンド結果出力先に指定したのS3パスの中身を確認します。
拡張子.out
のファイルがレコメンド結果のファイルです。
出力ファイルの中身を確認するとoutput
にscores
が含まれていることを確認できます。
そのままだと見辛いので、1行分を抜粋して見易いフォーマットにしたものを以下に記載します。
"input":{ "userId":"1" }, "output":{ "recommendedItems":["1544","3948","2985","6863","780","34048","1198","356","33166","1208","56367","41566","2791","1573","35836","2115","2858","6502","1608","4979"], "scores":[0.0039758,0.0039564,0.0039307,0.003394,0.003388,0.0032375,0.0031021,0.0029716,0.0028737,0.0026153,0.0025612,0.0025272,0.0024808,0.002468,0.0023951,0.0023778,0.0023496,0.0022948,0.0022599,0.0022412]}, "error":null }
3.3.AWS SDK(boto3)経由での確認
3.3.1.リアルタイムレコメンド
Boto3経由で作成済みのキャンペーンのPersonalization APIを叩いてレコメンド結果を取得します。
結果として、itemId
とscore
がペアになったitemList
を取得することができます。
import boto3 import sys # 作成済みcampaignの指定 campaign_arn = "<your-campaign-arn>" def get_recommend(user_id): personalizeRt = boto3.client('personalize-runtime') response = personalizeRt.get_recommendations( campaignArn = campaign_arn, userId = user_id) print(response) # コマンドライン引数でレコメンド対象のuser_idを渡す user_id = sys.argv[1] get_recommend(user_id) # 実行結果 (user_id=1で実行した場合のresponseからitemListを抜粋) # 'itemList': [ # {'itemId': '1544', 'score': 0.0039758}, # {'itemId': '3948', 'score': 0.0039564}, # {'itemId': '2985', 'score': 0.0039307}, # (中略) # {'itemId': '1042', 'score': 0.0020001}]
3.3.2.バッチレコメンド
バッチレコメンドについてもBoto3経由でジョブを作成・実行し、結果を確認します。
import boto3 from datetime import datetime # 入出力ファイルのS3パス bucket_name = '<target_bucket_name>' input_s3_path = f's3://{bucket_name}/recommend-input/batch_recommend_input.json' output_s3_path = f's3://{bucket_name}/recommend-input/' # 作成済みのソリューションバージョンのARN(レコメンドを作成するソリューションバージョン) solution_version_arn = '<target_solution_version_arn>' # Personalizeがバッチレコメンド時に利用するIAMロール role_arn = '<target_iam_role_arn>' # バッチレコメンドジョブ名(重複しないようにcurrent_dtを付ける) current_dt = datetime.now().strftime('%Y%m%d%H%M%S') job_name = f'movie-lens-batch-interface-job-{current_dt}' personalize = boto3.Session().client('personalize') response = personalize.create_batch_inference_job( jobName=job_name, solutionVersionArn=solution_version_arn, numResults=10, # 作成するレコメンド数 jobInput={ 's3DataSource': { 'path': input_s3_path # 入力データの場所 } }, jobOutput={ 's3DataDestination': { 'path': output_s3_path # レコメンド結果の出力場所 } }, roleArn=role_arn ) job_arn = response['batchInferenceJobArn'] print(job_arn) # 実行結果として、作成されたバッチレコメンドジョブのARNが表示される # レコメンド結果はジョブ完了後にS3の出力先から取得
コンソールでバッチレコメンドを実行した場合と同様に、出力ファイルの中身を確認するとoutput
にscores
が含まれていることを確認できます。
こちらもそのままだと見辛いので、1行分を抜粋して見易いフォーマットにしたものを以下に記載します。
"input":{ "userId":"1" }, "output":{ "recommendedItems":["1676","2081","1485","1391","2700","2797","2791","788","780","1370"], "scores":[0.0076814,0.0063911,0.0057474,0.0056732,0.0048522,0.0045363,0.0040142,0.0039901,0.0039672,0.0037378]}, "error":null }
4.おわりに
Personalizeのアップデートにより追加されたレコメンドアイテムのスコアについて確認しました。
ユースケースのセクションで記載した通り、このスコアを用いることでレコメンド結果の活用の幅がさらに拡がりそうです。