Amazon Personalize/Forecastハンズオンの私的補講

- Amazon Personalize
- Amazon Forecast

こちらの2つのサービスはAWSで提供されている機械学習サービスで、機械学習に詳しくなくても簡単に始められることが特徴です。
この2つのサービスを体験するためのハンズオン資料がAWSより公開されています。
https://pages.awscloud.com/event_JAPAN_Hands-on-Amazon-Personalize-Forecast-2019.html

先日こちらのハンズオンを資料を元に実際にやってみて、個人的に気になった箇所などを補足としてまとめてみます。

# Amazon Personalize

## ソリューションのレシピ(学習アルゴリズム)

- Automatic (AutoML)
    - 適切なアルゴリズムをPersonalizeが判断して採用する
    - 指定したレシピリストの中から選択する設定も可能
        - 現状はHRNNとHRNN-Metadataの2択？今後レシピが増えると選択肢が増すかも
- HRNN
    - Hierarchical Recurrent Neural Networks
    - UserとItemの関係(Interactions)のみを利用
    - 時間経過で重み付けされる
- HRNN-Metadata
    - Interactionsの他にUsersやItemsの属性情報を利用
    - datasetに少なくともUsersかItemsのどちらかをインポートしておかないと選択出来ない
- HRNN-ColdStart
    - 頻繁にItemsやInteractionsを追加する場合に利用
    - 関連性の低いItemやInteractionを除外したサブセットを作成することで高速に新しいItemのレコメンドが可能になる
    - datasetにItemsをインポートしておかないと選択出来ない
- Popularity Count
    - 人気のItemをそのまま返す
    - 全てのユーザに同じ結果を返す
- Personalized Ranking
    - インプットとしてItemのリストを渡すと、ユーザごとに最適化されたランキングを返す
- SIMS
    - Itemの協調フィルタリングとして動作する
    - インプットとしてItemを渡すと類似のItemを返す

レシピごとのハイパーパラメータの詳細についてはドキュメントを参照
[参考: HRNN レシピ](https://docs.aws.amazon.com/ja_jp/personalize/latest/dg/native-recipe-hrnn.html)

## APIでの推論実行

レコメンドの実行はAWS APIで実行出来ます。
現在のところHTTPエンドポイントとしてデプロイする機能などはなさそうですので、リアルタイム推論のAPIを構築したい場合はServerlessAPIなどでLambdaなどから呼び出す形がよさそうです。
Personalizeのリアルタイム実行コマンドは`personalize-runtime`で、推論のサブコマンドは`get-recommendations`、ランキングのサブコマンドは`get-personalized-ranking`です。

### HRNN推論

#### AWS CLIでリクエスト実行

```
aws personalize-runtime get-recommendations \
 --campaign-arn arn:aws:personalize:ap-northeast-1:xxxxxxx:campaign/my-campaign \
 --user-id 1 \
 --num-results 3
```

#### レスポンス

```
{
    "itemList": [
        {
            "itemId": "163"
        },
        {
            "itemId": "2355"
        },
        {
            "itemId": "353"
        }
    ]
}
```

### SIMS

#### AWS CLIでリクエスト実行

```
aws personalize-runtime get-recommendations \
 --campaign-arn arn:aws:personalize:ap-northeast-1:xxxxxxx:campaign/sims-campaign \
 --item-id 163 \
 --num-results 3
```

#### レスポンス

```
{
    "itemList": [
        {
            "itemId": "198"
        },
        {
            "itemId": "22"
        },
        {
            "itemId": "173"
        }
    ]
}
```

### Personalized Ranking

#### AWS CLIでリクエスト実行

```
aws personalize-runtime get-personalized-ranking \
 --campaign-arn arn:aws:personalize:ap-northeast-1:xxxxxxx:campaign/ranking-campaign \
 --user-id 1 \
 --input-list 22 192 239
```

#### レスポンス

```
{
    "personalizedRanking": [
        {
            "itemId": "22"
        },
        {
            "itemId": "239"
        },
        {
            "itemId": "192"
        }
    ]
}
```


## 料金

- S3

0.023USD/GB/mo

少額なので基本気にする額ではないですが、データセットが大きい場合はそれなりに掛かってくる可能性もあります。
不要であればハンズオン終了時に削除は忘れずに。

- Amazon Personalize

サインアップ直後であれば無料期間が適用される可能性があります。
継続的に課金されそうなのはデータストレージ料金くらいのようです。
エンドポイント維持費用などは無いようなので慌てて削除する必要もなさそうですが、こちらもハンズオンが終わり次第ひととおり削除しておくのが無難です。

以下は2019年12月現在の料金抜粋です。
ハンズオンを超えて利用する場合は必ず公式を確認してください。


| | 料金 |
|:--|:--|
| データ取り込み | 0.05 USD/GB |
| トレーニング時間 | 0.24 USD/トレーニング時間 |
| 推論実行(リアルタイム) | 0.20 USD/TPS時間 |
| 推論実行(バッチ) | 0.067 USD/レコメンデーション1000件 |

[参考: 料金表](https://aws.amazon.com/jp/personalize/pricing/)

#### トレーニング時間

4v CPU と 8 GiB メモリを使用する 1 時間のコンピューティング能力
実際のインスタンスタイプはデータ等に応じてPersonalizeの方で自動選択するため、実際のトレーニング実行時間とは異なる

#### TPS時間

TPS = 1秒あたりのリクエストの平均 (5分ごとの平均)
TPS時間 = 最小プロビジョンドTPS、または実際のTPSのどちらか大きい値(1時間単位での平均)

#### バッチ推論

UserごとのPersonalizeやRankingの場合はUser数に対してカウント、SIMSなどのItemの場合はItem数に対してカウント

# Amazon Forecast

## サンプルデータの注意点

ハンズオン資料のsmallデータを利用しましたが、このsmallデータには時系列データが`2015-01-01 00:00:00`の分まで存在します。
資料では予測フェーズでのLookup forecastの際に、予測範囲の開始指定が以下のように記述されていますが、

```text
Start: 2015/01/01 0時0分
(インポートしたデータ
2014/12/31 23時の次)
```

実際にインポートしたデータとは1時間のズレがあります。
ConsoleからLookup forecastを実行する分には問題なく実行できていますが、実際に生成される予測値は`2015-01-01 01:00:00`からのデータとなっています。
AWS APIからこの範囲で実行した場合は、指定範囲エラーとなり実行できません。
start-dateは`2015-01-01 01:00:00`を指定する必要があります。
ちなみにコンソールで開始時刻を`2014-12-31 23:00:00`を指定して実行すると以下のようになります。

![forecast.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204890/0572869e-d454-676d-02e1-2a3b10d1afd1.png)

Consoleでは`2015-01-01 00:00:00`までの実データと、`2015-01-01 01:00:00`からの予測データが合わせて表示されていることが分かります。

## Predictorのアルゴリズム

- Automatic (AutoML)
    - 適切なアルゴリズムをForecastが判断して採用する
    - Personalizeにあったような選択肢機能はなさそう
- ETS
    - 指数平滑法
    - 季節性のあるデータに強い
    - 時間の経過とともに重みが減少する
- ARIMA
    - 自己回帰和分移動平均
    - 季節性、定常性のあるデータに強い
    - 時間経過に依存しない
- DeepAR+
    - RNNを利用した学習アルゴリズム
    - ARIMAやETSのような比較的シンプルな統計アルゴリズムよりも複雑な予測が可能
- NPTS
    - ノンパラメトリック時系列アルゴリズム
    - 時系列データが断続的であったりスパースなデータの場合に強い
- Prophet
    - 局所的なベイズ構造時系列モデル
    - 複数の強い季節性を持つ場合や大きな外れ値がある場合に強い

アルゴリズムごとの詳しい特性やハイパーパラメータの詳細についてはドキュメントを参照
[参考: ETS](https://docs.aws.amazon.com/ja_jp/forecast/latest/dg/aws-forecast-recipe-ets.html)

## APIでの予測実行

予測実行のコマンドは`forecastquery`、サブコマンドは`query-forecast`です。

#### AWS CLIでリクエスト実行

```
aws forecastquery query-forecast \
 --forecast-arn arn:aws:forecast:ap-northeast-1:xxxxxxx:forecast/test_forecast \
 --start-date 2015-01-01T01:00:00Z \
 --end-date 2015-01-01T02:00:00Z \
 --filters "{\"item_id\":\"client_1\"}"
```

#### レスポンス

```
{
    "Forecast": {
        "Predictions": {
            "p10": [
                {
                    "Timestamp": "2015-01-01T01:00:00",
                    "Value": 18.008272171020508
                },
                {
                    "Timestamp": "2015-01-01T02:00:00",
                    "Value": 16.235431671142578
                }
            ],
            "p50": [
                {
                    "Timestamp": "2015-01-01T01:00:00",
                    "Value": 19.338420867919922
                },
                {
                    "Timestamp": "2015-01-01T02:00:00",
                    "Value": 17.989978790283203
                }
            ],
            "p90": [
                {
                    "Timestamp": "2015-01-01T01:00:00",
                    "Value": 20.668569564819336
                },
                {
                    "Timestamp": "2015-01-01T02:00:00",
                    "Value": 19.744525909423828
                }
            ]
        }
    }
}
```

## 料金

こちらも初めてForecastを使う場合は無料範囲で利用できる可能性があります。

| | 料金 |
|:--|:--|
| データ取り込み | 0.088 USD/GB |
| トレーニング時間 | 0.24 USD/トレーニング時間 |
| 予測生成 | 0.60 USD/予測1000件 |

#### トレーニング時間

内部で並列に学習が行われる場合などもあるため、実際の実行時間とは異なる
Predictorの作成とForecastの作成どちらもこの価格が適用される

#### 予測

予測件数は、予測期間に依らず、1つの時系列で1件
予測を生成したユーザの数と、作成した分位点(Forecast types)に依存する
Forecast typesは、デフォルトでP10,P50,P90の3分位点
5ユーザに対してデフォルトの3分位点で予測を生成した場合、予測件数は15件

こちらもストレージ以外に維持費用がかかるものはなさそうですが、不要であればハンズオン終了時点で忘れずに一通り削除しましょう。