SageMaker+APIGateway+Lambdaで作るサーバレスアプリケーション~①

SageMaker+APIGateway+Lambdaで作るサーバレスアプリケーション~①
この記事をシェアする

はじめに

こんにちは!スカイアーチHRソリューションズのnakaoです!
皆さん、サーバレス開発してますか?!
インフラの設計やサーバーの管理・運用など頭を悩ます問題から避け、開発に注力できるので、バックエンドエンジニア出身の私にとってはとても魅力的な開発なんですよね。
皆さんにも是非、この魅力を体験していただきたいと思い、今回から数回に分けて、SageMakerとAWS各種サービスを使用した簡単なサーバレスアプリケーションを作ってみたいと思います!
SageMakerを使用したのは直近で使う機会があったので、せっかくならアウトプットしたいという思いからです!
全体のアーキテクチャはこちらです!
S3はClientからアップロードした画像を保存するために用意します。

第一回目の今回はSageMakerしか使用しません。 SageMakerエンドポイントを作成して、作成したエンドポイントにリクエストを投げ、レスポンスが確認できるところまでやっていきたいと思います!

Amazon SageMakerとは

SageMakerとは、フルマネージドインフラストラクチャ、ツール、ワークフローを使用して、あらゆるユースケース向けの機械学習 (ML) モデルを構築、トレーニング、デプロイします。
簡単にまとめますと、機械学習におけるフロー(「モデル構築」、「トレーニング」、「デプロイ」など)を「Jupyter Notebook」上で実行できる特徴があるサービスです。機械学習に携わっておられる方には 「Jupyter Notebook」 は身近なインターフェイスなのではないでしょうか。似たようなサービスとしては「Google Colaboratory」などをイメージしていただければと思います。

詳細に関しては以下、公式ドキュメントを参照してください。

SageMakerエンドポイントとは

SageMakerでは、学習済みモデルを使用してエンドポイントを作成することが可能です。
このエンドポイントを利用して、機械学習したモデルの結果をリクエスト、レスポンスすることができます。

SageMakerエンドポイントの作成まで

それではさっそくSageMakerエンドポイントの作成まで実施してみましょう!

ノートブックインスタンスの作成

まず、AWSコンソールにログインし、上部の検索バーに「SageMaker」と入力して「SageMaker」を開きます。
※今回リージョンは東京リージョンを使用します。
「SageMaker」を開いたら、左タブ「ノートブック」の中にある「ノートブックインスタンス」をクリックします。
「ノートブックインスタンス」右上の「ノートブックインスタンスの作成」をクリックして、ノートブックインスタンスを作成していきます。

私は「sagemaker-test01」というインスタンス名で作成します。
今回は基本的に設定はデフォルトのまま作成していきます。
「アクセス許可と暗号化」では「新しいIAMロールの作成」を選びましょう。
その際に「指定するS3バケット」を選択しますが、「任意のS3バケット」を選択します。
ここで選択したS3バケット上に学習用データ、学習後のモデル結果などを格納します。
※「特定のS3バケット」を選択することで、事前に用意したS3バケットを使用することが可能です。

ステータスが「InService」に変更されるまで数分かかります。少々お待ちください。
数分後、ノートブックインスタンスの作成ができました!

「 Jupyter Notebook 」の作成

ノートブックインスタンスの作成が完了し、 ステータスが「InService」 に変更されたら、右上の「アクション」から「Jupyterを開く」をクリックします。

※ノートブックインスタンスは「InService」の間はお金がかかります!使用していない時は「アクション」から「停止」をクリックして、インスタンスを停止させておきましょう!!!

「Jupyter Notebook」が開きました。今回はAWSがサンプルコードを用意してくれているので、そちらを使用して機械学習させていきたいと思います。「SageMaker Examples」タブを選択し、その中にある「Image-classification-lst-format.ipynb」を選択し、右側の「Use」をクリックします。

新規でタブが開くので、「Create copy」をクリックします。

「Image-classification-lst-format」という名前の Jupyter Notebook が立ち上がります。
Kernelを選択するようタブが立ち上がるので、「conda_mxnet_p38」を選択し、「Set Kernel」をクリックします。

「 Jupyter Notebook 」の実行

今回使用するサンプルコードはAWS組み込みアルゴリズムを使用して、画像分類の機械学習を行います。
今回は AWSの組み込みアルゴリズムを使用しますが、tensorflowなどのフレームワークを使用した機械学習ももちろん可能です。
今回使用するサンプルコードの説明も含むと記事が膨大になってしまうため、概要だけかいつまんで、別の記事で詳細な説明はしたいと思います!

Jupyter Notebookの使用方法ですが、詳細は今回割愛します。
「Run」をクリックするとコードがセル単位で実行されます。
順番に上から最後まで実行されると、SageMakerエンドポイントの作成まで行われます。

ただ、2023年2月現在だと、このままデフォルトの状態で最後まで実施できない人が大半だと思います。
環境差異はありますが、今回私が修正、取り組んだ部分を共有します。

まず、クオーター引き上げを実行します。
今回使用する学習や推論用で使用するインスタンスサイズは「ml.p2.xlarge」、「ml.m4.xlarge」です。
「Service Quotas」をAWSサービスから検索し、「ml.p2.xlarge for training job usage」、「ml.m4.xlarge for endpoint usage」の クオーターを引き上げておきましょう。デフォルトのままだと使用できない人が大半だと思います。

次に、コードを一部修正します。
まず、「deploy_amt_model = True」をFalseに変更します。これをTrueにすると、SageMaker Automatic Model Tuning (AMT)を利用してパラメータの自動調整を行おうとするのですが、今回はこのノートブックだけでスタンドアロントレーニングを行うため、Falseにします。

# deploy_amt_model = True
deploy_amt_model = False

そして推論用のエンドポイントを作成するコードで、インスタンスサイズを小さくしておきます。
デフォルトのままでも可能ですが、推論用のエンドポイントで使用するインスタンスは学習で使用する「ml.p2.xlarge」ほどの性能は必要ありません。「ml.m4.xlarge」に変更します。

from time import gmtime, strftime

timestamp = time.strftime("-%Y-%m-%d-%H-%M-%S", time.gmtime())
endpoint_config_name = job_name_prefix + "-epc-" + timestamp
endpoint_config_response = sagemaker.create_endpoint_config(
    EndpointConfigName=endpoint_config_name,
    ProductionVariants=[
        {
            # "InstanceType": "ml.p2.xlarge",
            "InstanceType": "ml.m4.xlarge",
            "InitialInstanceCount": 1,
            "ModelName": model_name,
            "VariantName": "AllTraffic",
        }
    ],
)

print("Endpoint configuration name: {}".format(endpoint_config_name))
print("Endpoint configuration arn:  {}".format(endpoint_config_response["EndpointConfigArn"]))

最後に実行するコードはコメントアウトしておきます。
こちらを実行すると作成したエンドポイントが削除されてしまいます。

# sagemaker.delete_endpoint(EndpointName=endpoint_name)

ここまで修正できたら、Jupyter Notebookを上から順番に上から最後まで実行します。

最後まで実行されるとコンソール画面の左タブ、「エンドポイント」からもSageMakerエンドポイントが作成されているのが確認できます。

※SageMakerエンドポイントはインスタンスを常時起動させているか、削除するかのどちらかです。使用しなくなったエンドポイントは削除しましょう!!!削除しない限りお金がかかります。「エンドポイント設定」が残っていれば「エンドポイント設定」から同じエンドポイントを作成することがいつでもできるので安心してください!

コンソール画面の左タブ 、「モデル」から作成したモデルの詳細を確認することができます。
モデルデータの場所は指定したS3バケットもしくはデフォルト設定の場合は新規にS3バケットを作成し、そちらに格納されています。

コンソール画面の左タブ 、 「トレーニングジョブ」では学習したトレーニングの詳細を確認することができます。
学習で使用したハイパラメーター一覧や、学習ログの格納先(CloudWatch Logs)なども確認できます。

今回使用した Jupyter Notebook はもう使用しないので、「Shutdown」しておきましょう。

SageMakerエンドポイントを使ってみる

さて、ここまででSageMakerエンドポイントを作成することができました。
サンプルコード内にも SageMakerエンドポイント を使用する箇所はあるのですが、今回は新たに Jupyter Notebook を新規で作成し、作成した エンドポイント にリクエストを投げて、レスポンスを確認してみたいと思います。

Jupyter Notebook 上で「New」をクリックして新規で Jupyter Notebook を作成します。表示されるポップアップでは「conda_python3」を選択します。
また、同階層に、画像分類させたい画像を「Upload」から画像をアップロードし、配置させておきましょう。
今回はアメリカ国旗の画像をアップロードしておきました。

サンプルコードで推論用のエンドポイントを使用している部分を参考にコードを記述していきます。

file_name = "flag.jpg" # アップロードした画像ファイル名

# test image
from IPython.display import Image

# 画像の確認
Image(file_name_4)
# ラインタイムを使用したsageMakerエンドポイント呼び出し

# 作成済みのエンドポイント指定
endpoint_name = 'sagemaker-imageclassification-notebook-ep--2023-02-09-06-29-58'

# ランタイムの開始
import boto3

runtime = boto3.Session().client(service_name="runtime.sagemaker")

import json
import numpy as np

with open(file_name_4, "rb") as f:
    payload = f.read()
    payload = bytearray(payload)
response = runtime.invoke_endpoint(
    EndpointName=endpoint_name, ContentType="application/x-image", Body=payload
)
result = response["Body"].read()
# result will be in json format and convert it to ndarray
result = json.loads(result)
# the result will output the probabilities for all classes
# find the class with maximum probability and print the class index
index = np.argmax(result)

object_categories = [
    "ak47",
    "american-flag",
    "backpack",
    "baseball-bat",
    "baseball-glove",
    "basketball-hoop",
    "bat",
    "bathtub",
    "bear",
    "beer-mug",
    "billiards",
    "binoculars",
    "birdbath",
    "blimp",
    "bonsai-101",
    "boom-box",
    "bowling-ball",
    "bowling-pin",
    "boxing-glove",
    "brain-101",
    "breadmaker",
    "buddha-101",
    "bulldozer",
    "butterfly",
    "cactus",
    "cake",
    "calculator",
    "camel",
    "cannon",
    "canoe",
    "car-tire",
    "cartman",
    "cd",
    "centipede",
    "cereal-box",
    "chandelier-101",
    "chess-board",
    "chimp",
    "chopsticks",
    "cockroach",
    "coffee-mug",
    "coffin",
    "coin",
    "comet",
    "computer-keyboard",
    "computer-monitor",
    "computer-mouse",
    "conch",
    "cormorant",
    "covered-wagon",
    "cowboy-hat",
    "crab-101",
    "desk-globe",
    "diamond-ring",
    "dice",
    "dog",
    "dolphin-101",
    "doorknob",
    "drinking-straw",
    "duck",
    "dumb-bell",
    "eiffel-tower",
    "electric-guitar-101",
    "elephant-101",
    "elk",
    "ewer-101",
    "eyeglasses",
    "fern",
    "fighter-jet",
    "fire-extinguisher",
    "fire-hydrant",
    "fire-truck",
    "fireworks",
    "flashlight",
    "floppy-disk",
    "football-helmet",
    "french-horn",
    "fried-egg",
    "frisbee",
    "frog",
    "frying-pan",
    "galaxy",
    "gas-pump",
    "giraffe",
    "goat",
    "golden-gate-bridge",
    "goldfish",
    "golf-ball",
    "goose",
    "gorilla",
    "grand-piano-101",
    "grapes",
    "grasshopper",
    "guitar-pick",
    "hamburger",
    "hammock",
    "harmonica",
    "harp",
    "harpsichord",
    "hawksbill-101",
    "head-phones",
    "helicopter-101",
    "hibiscus",
    "homer-simpson",
    "horse",
    "horseshoe-crab",
    "hot-air-balloon",
    "hot-dog",
    "hot-tub",
    "hourglass",
    "house-fly",
    "human-skeleton",
    "hummingbird",
    "ibis-101",
    "ice-cream-cone",
    "iguana",
    "ipod",
    "iris",
    "jesus-christ",
    "joy-stick",
    "kangaroo-101",
    "kayak",
    "ketch-101",
    "killer-whale",
    "knife",
    "ladder",
    "laptop-101",
    "lathe",
    "leopards-101",
    "license-plate",
    "lightbulb",
    "light-house",
    "lightning",
    "llama-101",
    "mailbox",
    "mandolin",
    "mars",
    "mattress",
    "megaphone",
    "menorah-101",
    "microscope",
    "microwave",
    "minaret",
    "minotaur",
    "motorbikes-101",
    "mountain-bike",
    "mushroom",
    "mussels",
    "necktie",
    "octopus",
    "ostrich",
    "owl",
    "palm-pilot",
    "palm-tree",
    "paperclip",
    "paper-shredder",
    "pci-card",
    "penguin",
    "people",
    "pez-dispenser",
    "photocopier",
    "picnic-table",
    "playing-card",
    "porcupine",
    "pram",
    "praying-mantis",
    "pyramid",
    "raccoon",
    "radio-telescope",
    "rainbow",
    "refrigerator",
    "revolver-101",
    "rifle",
    "rotary-phone",
    "roulette-wheel",
    "saddle",
    "saturn",
    "school-bus",
    "scorpion-101",
    "screwdriver",
    "segway",
    "self-propelled-lawn-mower",
    "sextant",
    "sheet-music",
    "skateboard",
    "skunk",
    "skyscraper",
    "smokestack",
    "snail",
    "snake",
    "sneaker",
    "snowmobile",
    "soccer-ball",
    "socks",
    "soda-can",
    "spaghetti",
    "speed-boat",
    "spider",
    "spoon",
    "stained-glass",
    "starfish-101",
    "steering-wheel",
    "stirrups",
    "sunflower-101",
    "superman",
    "sushi",
    "swan",
    "swiss-army-knife",
    "sword",
    "syringe",
    "tambourine",
    "teapot",
    "teddy-bear",
    "teepee",
    "telephone-box",
    "tennis-ball",
    "tennis-court",
    "tennis-racket",
    "theodolite",
    "toaster",
    "tomato",
    "tombstone",
    "top-hat",
    "touring-bike",
    "tower-pisa",
    "traffic-light",
    "treadmill",
    "triceratops",
    "tricycle",
    "trilobite-101",
    "tripod",
    "t-shirt",
    "tuning-fork",
    "tweezer",
    "umbrella-101",
    "unicorn",
    "vcr",
    "video-projector",
    "washing-machine",
    "watch-101",
    "waterfall",
    "watermelon",
    "welding-mask",
    "wheelbarrow",
    "windmill",
    "wine-bottle",
    "xylophone",
    "yarmulke",
    "yo-yo",
    "zebra",
    "airplanes-101",
    "car-side-101",
    "faces-easy-101",
    "greyhound",
    "tennis-shoes",
    "toad",
    "clutter",
]
print("Result: label - " + object_categories[index] + ", probability - " + str(result[index]))

「Run」をクリック して順番に上から実行しましょう。

実行した結果は、、、

Result: label - american-flag, probability - 0.8584699034690857

「american-flag」が約85.8%だと表示されました!しっかりアメリカ国旗だと分類されていますね!
SageMakerエンドポイントで推論した結果が返ってきました!
「object_categories」リストにある種類の画像なら高い精度で画像分類してくれます。
いろいろと試してみましょう!

おわりに

お疲れ様でした!SageMakerエンドポイントを作成して、リクエスト、レスポンスを確認できましたね!
SageMakerの使い方が少し分かってきたのではないでしょうか?
ノートブックインスタンスの停止とSageMakerエンドポイントの削除をお忘れなく!
次回は今回作成したエンドポイントを使用してAPIGatewayとLambdaを連携させてみたいと思います!

私の記事が少しでも皆様のご参考になれば幸いです!

この記事をシェアする
著者:nakao
IoT、サーバーレスな開発に興味深々。AWSエンジニア。