Amazon SageMakerを使った学習済みモデルの流用　〜　ここどこサーチのデプロイまで

以前、AWS Machine Learning（以下、AWS ML）を使ってみたことがある。そこに新たなサービスが加わったということで、何がどんな風に変わって使いやすくなったのか、とかを知りたく、早速触ってみることにした。
AWSブログを辿る形ですすめるが、かなり行間を端折って記載されているので、そこを埋めつつ、デモまでデプロイした流れを記す。SageMakerについては何も予備知識ないところからスタート！

# デモ
今回後半で試したやったカスタムモデルを使ったデモサイト

* https://sage-app.cfapps.io/

![image.png](https://qiita-image-store.s3.amazonaws.com/0/39615/7c52c0b6-8fa4-d965-2ee7-95347c367a7e.png)
https://github.com/nekia/sage_geoloc_predict

URL指定した画像から取得した位置をマップ上にプロットします。EXIF情報を使わずにイメージから場所を推定する学習済みモデルをSageMakerのEndpointにDockerコンテナで組み込んで使わせてもらってます。

# SageMakerとは
## そもそもSageって何？
「sage 意味」で調べてみた。「賢者」とか「聖人」「賢い」「賢明な」という意味らしい。ついでに2chの「age」「sage」の機能的な意味も初めて知った。
「賢者生成器」というわけか。

## 早速AWSのページを読んでみる
[Amazon Web Services ブログ Amazon SageMaker – 機械学習を加速する](https://aws.amazon.com/jp/blogs/news/amazon-sagemaker/)
以下のような課題を解決するデータサイエンティストや機械学習のエキスパート向けのサービスらしい！（気安く触るもんじゃないのかも）

* 機械学習モデルの開発、学習、メンテはまだまだ面倒
* アドホックじゃなくパイプライン的にサービスに組み込みたい
    * たとえばSageMakerで作ったモデルはS3に出力されるので、それをIoTエッジデバイスで使うとか、よそから持ってきたモデルをSageMakerに取り込んでEndpointを公開するとか、がフレキシブルにできるようになった。
        * SageMakerと[DeepLens](https://aws.amazon.com/jp/deeplens/?nc2=h_mo)の連携はまさにこの特徴を活かしています

コンポーネントは以下の3つに分かれる。
![please_work.png](https://qiita-image-store.s3.amazonaws.com/0/39615/0a4c1c94-6958-86a4-7dc5-35c308bfd21c.png)

* オーサリング
    * データのクレンジングや前処理をするJupyter notebook IDEを提供
* モデルトレーニング
    * ビルトインされた教師あり／教師なし学習アルゴリズムやフレームワークを提供（Docker使った独自学習環境追加も可）
    * 数十のインスタンスにスケールした環境で学習可能
    * 学習データは S3 から読み出す。
    * 生成したモデル（パラメータ）もS3 に保存される。
        * これによりIoTデバイスとかにSageMakerで学習したモデルをデプロイしやすくなる。
* モデルホスティング
    * モデルをホストするサービスでリアルタイムに推論結果を取得するためのHTTPS エンドポイントを提供
    * エンドポイントはスケールや複数モデルでの A/B テスト　が可能。

なるほど。自由度のそれほど高くなくPoC用途向けであるAWS MLに対して、実運用環境での利用を想定したものがSageMakerになるような印象。特にA/Bテストとかモデルの比較がAWS MLでは大変だったので嬉しい追加機能の1つだと思う。あと学習アルゴリズムではMXNetを明に使っている様が見て取れます。

# 早速使ってみる

まだAsiaPacificでは利用できないみたいなので、Virginiaへリージョン変更。

## Notebookの作成
t2.mediumでNotebook用のインスタンスを立ち上げ。インスタンス種別は3つの中から選択。これが最小。
SageMakerからアクセスするサービスへの権限（AmazonSageMakerFullAccess）を持った新たなロールを作成してセット。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/39615/471d0014-8fe2-4b8e-f8c7-7d9008bad247.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/39615/8ab6061b-6ca2-377e-f2f6-bbf5dc6ff89d.png)
無事にjupyter notebookが立ち上がる
![image.png](https://qiita-image-store.s3.amazonaws.com/0/39615/badd8112-c939-f0dd-8a2b-17726486aae3.png)
## データの準備＆トレーニング
ブログにある元ネタは立ち上がったNotebook内に既にサンプルとして入ってます。Githubにもありました。
https://github.com/awslabs/amazon-sagemaker-examples/tree/master/sagemaker-python-sdk/mxnet_gluon_cifar10
サンプル（mxnet_gluon_cifar10）を実行するのに必要なpython library（scikit-image）をjupyter notebookからサクサクっとインストールして、いざ実行
![image.png](https://qiita-image-store.s3.amazonaws.com/0/39615/6bb7151d-1887-f431-e0b5-7f9fbbbfe81e.png)
特に躓くことなくResNet-34のネットワークを使ったCIFAR-10という60000枚の32x32画像を10クラスに分類するモデルの作成ができた。100行以下のPythonコードで。
様々なネットワーク構成やpretrainedモデルがAWSが提供するMXNetのAPIで取得することができる。公開のサンプルではネットワーク構成だけ利用し、予めトレーニングしたパラメータは利用せず、再トレーニングしている。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/39615/7a9dd1fe-8b76-6953-13f0-888b05db1518.png)
走ってるジョブの様子や作成済みモデルの一覧やデプロイ中のエンドポイントなどはこのダッシュボードで見渡せる。

# トレーニング済みモデルをDockerコンテナでAPI化して使う

YFCC100M Multimedia Commons datasetから生成した画像から位置を推定するモデルになります。
YFCC100Mは、Flickr に Creative Commons で投稿されたラベル付き画像1億枚のデータセットです。

* [multimedia-berkeley/tutorials](https://github.com/multimedia-berkeley/tutorials)

このモデルが paramファイルとjsonで定義されたネットワーク構成情報をMXNetに読み込ませて、学習済みモデルを利用します。
このモデルを組み込んだDockerイメージをAmazon ECRにプッシュしてAmazon SageMakerからモデルとして利用してみます。

ECRへのプッシュ方法については以下を参考にさせて頂きました。

* [【AWS】初めてのECR - Qiita](https://qiita.com/3utama/items/b19e2239edb6996a735f)

```
FROM mxnet/python:latest 
WORKDIR /app 
COPY *.py /app/ 
COPY grids.txt /app/ 
COPY models /app/models 
COPY mediaeval2016_test /app/
RUN pip install -U numpy flask scikit-image 
ENTRYPOINT ["python", "app.py"] 
EXPOSE 8080
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/39615/d972a4e3-c848-daba-dcb9-0113b18cc7a6.png)

エンドポイントのインスタンス種別を編集可能なので設定可能なミニマム設定(ml.t2.medium)を選択する。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/39615/9ccfd163-2ec7-9efa-d23a-a710660c8465.png)

`Create endpoint configuration`を実行した後、続けて`Create endpoint`を実施する。

作成したSageMaker上のエンドポイントをPostman使って動作確認。以下を参考にする。OK!

* [Use Postman to Call an API - Amazon API Gateway](http://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-use-postman-to-call-api.html)

あとはQuery用のFlask Appをどこかにホスティングする。
github.ioに置こうと思ったが、静的なものしか動かないとのことなので、Flask Appは動かせない。Pivotal Cloud Foundryの無料枠にプッシュする。

```
$ pip freeze > requirements.txt

$ cat manifest.yml
---
applications:
- name: sage-app
  command: python query.py

$ cf login -a  https://api.run.pivotal.io
API endpoint: https://api.run.pivotal.io

Email> ********

Password> 
Authenticating...
OK

(snip)

$ cf push
Using manifest file /home/ubuntu/sagemaker_ws/sage_geoloc_predict/manifest.yml

Updating app sage-app in org test-org / space development as ***...
OK

Uploading sage-app...
Uploading app files from: /home/ubuntu/sagemaker_ws/sage_geoloc_predict
Uploading 6.3K, 9 files
Done uploading               
OK

(snip)

1 of 1 instances running

App started


OK

App sage-app was started using this command `python query.py`

Showing health and status for app sage-app in org nekiaiken-org / space development as nekiaiken@gmail.com...
OK

requested state: started
instances: 1/1
usage: 1G x 1 instances
urls: sage-app.cfapps.io
last uploaded: Tue Dec 12 16:06:33 UTC 2017
stack: cflinuxfs2
buildpack: python

     state     since                    cpu    memory        disk         details
#0   running   2017-12-12 04:07:57 PM   0.0%   26.9M of 1G   195M of 1G
```

デプロイ成功！

# 最後に

後半は駆け足になって本題であるSageMakerとは違うところで時間を取られた感があります。
といわけで、SageMaker自体は非常に手間が少なく利用できることが実際に確認できました。