フリーランチ食べたい

No Free Lunch in ML and Life. Pythonや機械学習のことを書きます。

Amazon PersonalizeとServerless Frameworkを使って半日でレコメンドAPIを作成する

前回の記事でGAになったばかりのAmazon Personalizeの使い方の解説をしました。 ただ、前回の記事では実際にアプリケーションから利用するところ、つまりWeb APIとして公開するところまでは書くことができませんでした。

ということでこの記事では、Serverless Frameworkと組み合わせることで半日でレコメンドAPIを公開する方法を書きたいと思います。

基本的なワークフローの解説については下の記事を参照してください。

blog.ikedaosushi.com

またコード全体はGitHubにアップロードしており、記事の最後に記載しています。

それでは早速レコメンドAPIを作成していきましょう。

環境

まず前提として下記の環境を想定しています。これらの環境がない場合はインストール or アップデートしておいてください。

  • Python: 3.7
  • serverless-framework: 1.45.1
  • boto3: 1.9.169

構成図

全体の構成図は下記のようになります。 複雑に見えるかもしれませんが、CloudFormation、API Gateway、Lambda部分は全てServerlessいい感じにやってくれるので作業としてはそんなに複雑ではないと思います。

f:id:ikedaosushi:20190617220905p:plain

プロジェクト作成&boto3の最新版利用

まず、Serverlessプロジェクトを作成します。 注意点としてAmazon Personalizeを利用するにはboto3の最新版が必要なので serverless-python-requirements をインストールしておきます。

sls create -t aws-python3 -n serverless-amazon-personalize-example
# boto3を最新版にするための準備
sls plugin install -n serverless-python-requirements
pipenv install boto3 # Pipfileを作成するのでもOKです。

またboto3の最新版を使うために設定ファイルに下記のような設定を行います。 これは serverless-python-requirements がデフォルトだとboto3のデプロイを除外してしまうためです。

serverless.yml

custom:
  pythonRequirements:
    usePipenv: true
    noDeploy: [pytest, jmespath, docutils, pip, python-dateutil, setuptools, s3transfer, six]

boto3の最新版をLambda Layerとしてデプロイする方法もあります。 そちらを使いたい方は下記の記事を参考にしてみてください。

これでServerless側の事前準備は終了です。

Amazon Personalize準備

Amazon Personalize側の準備をしていきます。

一応前回の復習ですが、Amazon Personalizeには下記のようなリソースがあります。

f:id:ikedaosushi:20190617211938p:plain

それぞれが、

  • Dataset Group: レコメンドアプリケーションのプロジェクト
  • Datasets: データ
  • Solutions: モデル
  • Recipes: アルゴリズム
  • Campaigns: 予測API

を表しています。

予測に必要なのはCampaignのARN のみです。今回は前回の記事と同じように条件で学習を行いCampaignのARNを出力するスクリプトを用意しました。

serverless-amazon-personalize-example/train.py at master · ikedaosushi/serverless-amazon-personalize-example · GitHub

# データをダウンロード
wget -N http://files.grouplens.org/datasets/movielens/ml-100k.zip
unzip -o ml-100k.zip
mv ml-100k data
rm ml-100k.zip

# データの読み込み/学習/予測準備
python scripts/train.py
# => campaign_arn: arn:aws:personalize:xxxx....

実行するとCampaignのARNが出力されます。 データのアップロードから学習、予測準備まで行うので時間は20~30分くらいかかると思います。

Serverlessを使ってAPI作成

それではServerlessを使ってAPIを作成していきましょう。ポイントだけ抜粋して説明します。詳細な設定ファイルが見たい方は記事の最後までスクロールしてGitHubを見てください。

やることはシンプルで、次の2つです。

  • CAMPAIGN_ARN という環境変数に今出力されたCampaignのARNを設定
  • functions.events.http にAPIのための設定

設定ファイルは次のようになります。

provider:
  environment:
    CAMPAIGN_ARN: arn:aws:personalize:... # 今出力されたCampaignのARNを入力
  iamRoleStatements:
    - Effect: Allow
      Action:
        - "personalize:*"
      Resource: "*"

functions:
  get_reccomendation:
    handler: handler.get_reccomendation
    events:
      - http:
          path: get/{user_id}
          method: get
          request:
            parameters:
              paths:
                user_id: true

呼び出されるPythonスクリプトは次のようになります。 pathParameters からパラメータを読み取って、Amazon PersonalizeのAPIを呼び出すだけの単純な処理です。

handler.py

import json
import os

import boto3

CAMPAIGN_ARN = os.environ.get("CAMPAIGN_ARN")

def get_reccomendation(event, context):
    user_id = event['pathParameters']['user_id'] # string

    personalize_runtime = boto3.client('personalize-runtime')
    recommendations_response = personalize_runtime.get_recommendations(
        campaignArn = CAMPAIGN_ARN,
        userId = user_id # stringでない場合はcastする必要がある
    )

    item_list = recommendations_response['itemList']

    response = {
        "statusCode": 200,
        "body": json.dumps(item_list)
    }

    return response

これで、あとはデプロイするだけです。 エンドポイントが出力されます。

sls deploy
# 略
# endpoints:
#   GET - https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/get/{user_id}
# 略

作成されたエンドポイントにuser_idを適当に 384 と設定してリクエストを送ってみましょう。

curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/get/384
[{"itemId": "879"}, {"itemId": "264"}, {"itemId": "343"}, ...]

無事レコメンドされたItemId(映画のID)が返ってきました🍻 後はアプリケーション側でItemのマスタと紐付ければレコメンドAPIとして使えると思います。

さいごに

Amazon PersonalizeとServerless Frameworkを組み合わせて素早くレコメンドAPIを作成する方法を紹介しました。簡単にAPIが作成できるのは大きなメリットですね。

気になった点としてはAmazon PersonalizeがCloudFormationに対応していないことです。対応すればCloudFormationだけでレコメンドエンジンを作ることも可能(!)ではないでしょうか。

またUser属性やItem属性に情報を入れた場合の結果の違いや、他のタイプのアルゴリズムを使うと結果がどう変わるのかなどは、実際にプロダクトに使ってみて試したいと思います。また何か知見が得られたらブログにまとめますね!

今回使ったコードはすべてGitHubに上げています。 github.com