BLOG

ブログ

Amazon SageMaker Jumpstart でファインチューニングをやってみた!!

投稿日:2021年4月26日

Amazon SageMaker Jumpstartとは?

機械学習をスピーディーかつ、簡単に始められるサービスです。

本来、機械学習を始めるには、データセットの準備、アルゴリズムの選択、モデルのトレーニング、精度の最適化、本番稼働環境へのデプロイ、パフォーマンスの経時的モニタリングといった、数々の障壁をクリアする必要があります。しかしAmazon SageMaker Jumpstart(以下、SageMaker Jumpstart)を用いると、数回クリックしただけで、すでに学習済みのモデルを備えたインスタンスをデプロイすることができます。

今回は機械学習初心者の私が、実際に推論インスタンスを立ち上げて、画像を推論し、さらにファインチューニングを用いて、新しい機械学習モデルを作成した経験を記していきます。

SageMaker Jumpstart でファインチューニングをしてみる

本記事では、一度、用意されているオープンソースモデルの一つであるResnet 18をデプロイして、画像の推論を行います。
ResNet 18は1000種類のクラス分類がされているモデルですが、詳細な花の分類ができるモデルではありません。
そこでResnet 18を元にファインチューニングを行い、Resnet 18ではラベリングされていなかった花の画像の推論が、正しく行えるようになったか見ていきたいと思います。

Amazon SageMaker Studioを起動

SageMaker JumpStart は機械学習のための統合開発環境である Amazon SageMaker Studio(以下、SageMaker Studio)の中に、統合されているため、まず始めにSageMaker Studioを起動します。

※ SageMaker JumpStartを利用するためには、SageMaker Studioの設定で、SageMaker JumpStartを有効化しなければならないので、[設定を編集]から有効化にチェックをします。

SageMaker Jumpstartの画面に移動

SageMaker Studioを起動すると、下記の画像のような画面に遷移しますので、赤枠の部分をクリックして SageMaker Jumpstartの画面を開きます。

学習モデルを選択

150以上の事前トレーニング済みのオープンソースモデルが用意されています。

これまではAmazon Sagemakerでオープンソースのモデルを利用するためには、推論エンドポイントを作成するためにソースコードを書く必要がありました。
SageMaker JumpStartでは、この書き換えの手間が必要なく、ワンクリックでオープンソースモデルのデプロイができます。

今回は[ResNet 18]というモデルを選択します。

オープンソースモデル(ResNet 18)をデプロイする

一度、事前にトレーニングされたモデルをデプロイしてみます。
Deployment Configuretionのプルダウンをクリックすると、インスタンスタイプやエンドポイント名を指定できます。
今回はデフォルトのままデプロイします。

ステータスがIn Serviceになれば、デプロイ完了です。

サンプルノートブックを開く

デプロイが完了すると、自動的にこのようなノートブックが開きます。
(もし自動的にノートブックが開かなければ、デプロイした画面の[Open Notebook]をクリックすると、ノートブックが開きます)

コードの解説

import boto3
from IPython.core.display import HTML

region = boto3.Session().region_name
s3_bucket = f"jumpstart-cache-prod-{region}"
key_prefix = "inference-notebook-assets"
s3 = boto3.client("s3")

def download_from_s3(key_filenames):
    for key_filename in key_filenames:
        s3.download_file(s3_bucket, f"{key_prefix}/{key_filename}", key_filename)

cat_jpg, dog_jpg, ImageNetLabels = "cat.jpg", "dog.jpg", "ImageNetLabels.txt"
download_from_s3(key_filenames=[cat_jpg, dog_jpg, ImageNetLabels])

1つ目のセルで、公開されているS3から、犬と猫のサンプル画像をSageMaker Studio内にダウンロードします。

images = {}
with open(cat_jpg, 'rb') as file: images[cat_jpg] = file.read()
with open(dog_jpg, 'rb') as file: images[dog_jpg] = file.read()
with open(ImageNetLabels, 'r') as file: class_id_to_label = file.read().splitlines()[1::] 
#The label file has 1001 class labels starting with 'background' class 
#but the model predicts 1000 classes sans the background class. 

2つ目のセルで、先ほどS3からSageMaker Studio内にダウンロードしたサンプル画像を読み込みます。

import json

def query_endpoint(img):
    endpoint_name = 'jumpstart-dft-pt-ic-resnet18'
    client = boto3.client('runtime.sagemaker')
    response = client.invoke_endpoint(EndpointName=endpoint_name, ContentType='application/x-image', Body=img)
    model_predictions = json.loads(response['Body'].read())
    return model_predictions

for filename, img in images.items():
    model_predictions = query_endpoint(img)
    # 1000件のラベルの重みの合計が1になるように、各値の推論結果が格納されている
    # model_predictions = [1.9669976758507346e-09, 5.9363845394955206e-08, ........, 1.6102101653814316e-05]
    top5_prediction_ids = sorted(range(len(model_predictions)), key=lambda index: model_predictions[index],         reverse=True)[:5]
    top5_class_labels = ", ".join([class_id_to_label[id] for id in top5_prediction_ids])
    display(HTML(f'<img src={filename} alt={filename} align="left" style="width: 250px;"/>' 
                 f'<figcaption>Top-5 model predictions are: {top5_class_labels}</figcaption>'))

3つ目のセルで推論を行います。
client.invoke_endpoint の引数の中に、先ほど立てたResNet 18の推論インスタンスのエンドポイントと、画像を渡してやるだけで、推論することができます。

試しに上から順に実行をしていきます。

サンプルのコードだとこのような形で推論できます。
あまりに簡単に推論ができたので、唖然としてしまいました。

推論結果ですが犬も猫も、正しく推論されていますね。
ではこちらのモデルでラベリングされていない花の画像を読み込んで、推論をさせるとどうなるのか見てみたい思います。

ラベリングされていない画像を推論してみる

推論インスタンスに、ResNet 18にラベリングされていない花の画像を渡して、推論してみます。

ひまわりの方はデイジーと推論されていて、惜しくもないのですが、バラの方は豚の貯金箱と認識されていたりと面白いですね。
ResNet 18では、これらの花はラベリングされておらず、正しく推論できないのは当たり前なので、これからファインチューニングをして、これらの花を分類できるモデルを新しく作成します。

ファインチューニングしてみる

補足:ファインチューニングと転移学習の違い

今回、SageMaker Jumpstartでは転移学習ができると思って利用したのですが、実際はファインチューニングという手法でした。
どちらも既存の学習モデルから、新しいモデルを作成するのですが、両者には違いがあるので補足します。

転移学習

転移学習は、学習済みのモデルのネットワークの重みを固定して、最終出力層に分類したいクラスを追加することで、新しいモデルを作成します。

ファインチューニング

ファインチューニングは、学習済みモデルの重みを初期値として、再度全体で学習することで、ネットワークの重みの微調整を行い、新しいモデルを作成します。

今回はファインチューニングを用いて、ResNet 18では行えなかった、花の分類をできるように新しいモデルを作成します。

S3にデータセットを保存する

ファインチューニングする方法はオープンソースモデル(今回だとResNet 18)をデプロイする画面の下部に書かれています。

ラベリングしたい項目ごとにフォルダを作成し、その中に画像をひたすら入れていきます。
(rosesというフォルダの中に、バラの画像を入れていく)
今回は赤線部分のリンクから、サンプルデータセットをダウンロードして、それを使用してファインチューニングを行います。
※ この際に何枚かの画像を推論用に省いておくことをお勧めします。


ダウンロードしてきたサンプルデータセットをS3にアップロードしました。
今回は5種類の花の識別ができるモデルを作成していきます。

トレーニングする

先ほどアップロードしたS3バケットのアドレスを指定して [Train] をクリックします。
本当にこれだけでファインチューニングができます。

下記のようにトレーニングするインスタンスのタイプや、ハイパーパラメーターの設定も行うことができます。
今回はデフォルトの設定のままで行いました。

ステータスがCompleteになればトレーニング完了です。
今回は7分ほどで終わりました。

トレーニングしたモデルをデプロイして、推論する

新たにトレーニングさせたモデルをデプロイして、推論します。

推論を行う前に、先ほど推論用に省いた画像を、SageMaker Studio内に取り込みます。
画像はドラッグ&ドロップで移すことができます。

ラベルの修正も必要なので、imageNetLabels2.txtという名前のテキストファイルを新規作成し、学習させた画像のラベルを書きます。
※ラベルはアルファベット順で保存してください。

コードの修正も必要なので行います。

import boto3
from IPython.core.display import HTML
import json

def query_endpoint(img):
    endpoint_name = 'jumpstart-ftc-pt-ic-resnet18'
    client = boto3.client('runtime.sagemaker')
    response = client.invoke_endpoint(EndpointName=endpoint_name, ContentType='application/x-image', Body=img)
    model_predictions = json.loads(response['Body'].read())
    return model_predictions

image1 = "daisy.jpg"
image2 = "dandelion.jpg"
image3 = "roses.jpg"
image4 = "sunflower.jpg"
image5 = "tulips.jpg"
ImageNetLabels = "ImageNetLabels2.txt"

images = {}
with open(image1, 'rb') as file: images[image1] = file.read()
with open(image2, 'rb') as file: images[image2] = file.read()
with open(image3, 'rb') as file: images[image3] = file.read()
with open(image4, 'rb') as file: images[image4] = file.read()
with open(image5, 'rb') as file: images[image5] = file.read()
with open(ImageNetLabels, 'r') as file: class_id_to_label = file.read().splitlines()

for filename, img in images.items():
    model_predictions = query_endpoint(img)  
    prediction_ids = sorted(range(len(model_predictions)), key=lambda index: model_predictions[index], reverse=True)[:2]
    class_labels = ", ".join([class_id_to_label[id] for id in prediction_ids])
    display(HTML(f'<img src={filename} alt={filename} align="left" style="width: 250px;"/>' 
                 f'<figcaption>Top-2 model predictions are: {class_labels}</figcaption>'))
推論結果

先ほど推論できていなかったバラやひまわりが、推論できるようになっていますね。
また他の画像も正しく推論できているようです。

まとめ

このように、SageMaker Jumpstart では機械学習初心者でも、簡単にファインチューニングを行うことができ、独自モデルを作ることができました。
オープンソースモデルを使用するための事前準備のコードを書く必要がなく、エンドポイントと画像を指定するだけで推論を行うことができます。これによって、迅速にかつ簡単に機械学習を始めることができます。

お掃除

今回使用したインスタンスは、選択できるものの中から一番安いインスタンスを選択しましたが、それでも一時間で0.149USDかかり、1ヶ月に換算すると1万円を超える金額となるため、使用しないのであれば削除しましょう。

下記のDeleteをクリックすると削除されます。
今回は2つの推論インスタンスを立てたので、2つとも忘れずに削除しましょう。

サイドバーのプルダウンを開いて、[Model Endpoints] が(0)になっていれば、全ての推論用インスタンスが削除されています。

注意点

推論用インスタンスを削除しても、ノートブックは使うことができます。
ノートブック用のインスタンスが起動しているので、そちらも削除する必要があります。
赤枠の部分をクリックすると削除することができます。
※ このインスタンスで複数のノートブックを実行しているので、このインスタンスを削除すれば、今回使用したノートブックの2つとも、使えなくなります。

こちらの削除が完了すれば、全てのインスタンスが削除されます。