{
"cells": [
{
"cell_type": "markdown",
"id": "f0cdd62f",
"metadata": {},
"source": [
"# Introduction to JumpStart - 画像分類"
]
},
{
"cell_type": "markdown",
"id": "9c85c24b",
"metadata": {},
"source": [
"---\n",
"Amazon [SageMaker JumpStart](https://docs.aws.amazon.com/sagemaker/latest/dg/studio-jumpstart.html)へようこそ! JumpStartを使用すると、SageMaker Studioのワンクリック、または[SageMaker JumpStart API](https://sagemaker.readthedocs.io/en/stable/overview.html#use-prebuilt-models-with-sagemaker-jumpstart)を通じて、多くの機械学習タスクを解決することができます。\n",
"\n",
"このノートブックのデモでは、画像分類のためのJumpStart APIを使用する方法を紹介します。画像分類とは、画像をトレーニングデータセットのクラスラベルのいずれかに分類することです。 このデモでは、画像分類モデルの2つの使用例を紹介します。\n",
"\n",
"* ImageNetデータセットを使って事前学習されたモデルを使用して、画像を分類する方法。[ImageNetLabels](https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt)。\n",
"* 独自のデータセットを使って事前学習済みモデルをファインチューニングし、推論を実行する方法。\n",
"\n",
"注:このノートブックは、Amazon SageMaker Studio with Python 3 (Data Science) kernel の ml.t3.medium インスタンスと、Amazon SageMaker Notebook インスタンス with conda_python3 kernel でテストされています。\n",
"\n",
"---"
]
},
{
"cell_type": "markdown",
"id": "4a25d2ce",
"metadata": {},
"source": [
"1. [セットアップ](#1.-セットアップ)\n",
"2. [学習済みモデルを選択する](#2.-学習済みモデルを選択する)\n",
"3. [学習済みモデルで推論する](#3.-学習済みモデルで推論する)\n",
" * [JumpStartのモデルを取得してエンドポイントをデプロイする](#3.1.-JumpStartのモデルを取得してエンドポイントをデプロイする)\n",
" * [推論用のサンプル画像をダウンロードする](#3.2.-推論用のサンプル画像をダウンロードする)\n",
" * [エンドポイントにクエリし、レスポンスをパースする](#3.3.-エンドポイントにクエリし、レスポンスをパースする)\n",
" * [エンドポイントを削除する](#3.4.-エンドポイントを削除する)\n",
"4. [独自のデータセットを使って学習済みモデルをファインチューニングする](#4.-独自のデータセットを使って学習済みモデルをファインチューニングする)\n",
" * [JumpStartの学習用アーティファクトを取得する](#4.1.-JumpStartの学習用アーティファクトを取得する)\n",
" * [トレーニングのパラメータを設定する](#4.2.-トレーニングのパラメータを設定する)\n",
" * [自動モデルチューニングを使って学習する](#AMT)\n",
" * [学習を開始する](#4.4.-学習を開始する)\n",
" * [ファインチューニングしたモデルをデプロイして推論する](#4.5.-ファインチューニングしたモデルをデプロイして推論する)\n",
" * [ファインチューニング済みモデルを増分学習する](#4.6.-ファインチューニング済みモデルを増分学習する)"
]
},
{
"cell_type": "markdown",
"id": "b0d4f91e",
"metadata": {},
"source": [
"## 1. セットアップ\n",
"***\n",
"ノートブックを実行する前に、セットアップに必要ないくつかの初期化のステップがあります。このノートブックには、最新版のsagemakerとipywidgetsが必要です。\n",
"***"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2c2aed57",
"metadata": {},
"outputs": [],
"source": [
"!pip install sagemaker ipywidgets --upgrade --quiet"
]
},
{
"cell_type": "markdown",
"id": "257215b1",
"metadata": {},
"source": [
"---\n",
"\n",
"Amazon Sagemakerでトレーニングやホスティングを行うには、AWSのサービスを利用するための設定と認証が必要です。ここでは、SageMakerにアクセスできるAWSアカウントロールとして、現在のノートブックインスタンスに関連付けられた実行ロールを使用します。S3内のデータへのアクセスなど、権限を持つ必要があります。\n",
"\n",
"---"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c1b825ef",
"metadata": {},
"outputs": [],
"source": [
"import sagemaker, boto3, json\n",
"from sagemaker import get_execution_role\n",
"\n",
"aws_role = get_execution_role()\n",
"aws_region = boto3.Session().region_name\n",
"sess = sagemaker.Session()"
]
},
{
"cell_type": "markdown",
"id": "144d8152",
"metadata": {},
"source": [
"## 2. 学習済みモデルを選択する\n",
"***\n",
"デフォルトのモデルで進めることも、次のセルを実行したときに生成されるドロップダウンから別のモデルを選択することもできます。JumpStart の全モデルのリストは、[JumpStart Models](https://sagemaker.readthedocs.io/en/stable/doc_utils/pretrainedmodels.html) からも確認できます。\n",
"***"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "12e86150",
"metadata": {},
"outputs": [],
"source": [
"model_id, model_version, = (\n",
" \"pytorch-ic-mobilenet-v2\",\n",
" \"*\",\n",
")"
]
},
{
"cell_type": "markdown",
"id": "8040c5bc",
"metadata": {},
"source": [
"***\n",
"[オプション] 別の JumpStart モデルを選択します。ここでは、jumpstart model_manifest ファイルを jumpstart s3 バケットからダウンロードし、すべての 画像分類モデルから選択して、推論用のモデルを選択します。\n",
"***"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d2aa00cf",
"metadata": {},
"outputs": [],
"source": [
"import IPython\n",
"from ipywidgets import Dropdown\n",
"\n",
"# JumpStartの model_manifest ファイルをダウンロードします\n",
"boto3.client(\"s3\").download_file(\n",
" f\"jumpstart-cache-prod-{aws_region}\", \"models_manifest.json\", \"models_manifest.json\"\n",
")\n",
"with open(\"models_manifest.json\", \"rb\") as json_file:\n",
" model_list = json.load(json_file)\n",
"\n",
"# manifestファイルから全ての画像分類モデルを選択します\n",
"ic_models_all_versions, ic_models = [\n",
" model[\"model_id\"] for model in model_list if \"-ic-\" in model[\"model_id\"]\n",
"], []\n",
"[ic_models.append(model) for model in ic_models_all_versions if model not in ic_models]\n",
"\n",
"# ユーザ選択のため、model-idsのドロップダウンリストを表示します\n",
"dropdown = Dropdown(\n",
" options=ic_models,\n",
" value=model_id,\n",
" description=\"JumpStart Image Classification Models:\",\n",
" style={\"description_width\": \"initial\"},\n",
" layout={\"width\": \"max-content\"},\n",
")\n",
"display(IPython.display.Markdown(\"## Select a JumpStart pre-trained model from the dropdown below\"))\n",
"display(dropdown)"
]
},
{
"cell_type": "markdown",
"id": "84883a00",
"metadata": {},
"source": [
"## 3. 学習済みモデルで推論する\n",
"***\n",
"JumpStartを使えば、独自のデータセットで最初にファインチューニングを行わなくても、事前学習済みモデルで推論を実行することができます。この例では、入力画像に対して、ImageNetデータセットの1000クラスのうちの1つのクラスラベルを予測します。\n",
"[ImageNetLabels](https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt)。\n",
"***"
]
},
{
"cell_type": "markdown",
"id": "78268000",
"metadata": {},
"source": [
"### 3.1. JumpStartのモデルを取得してエンドポイントをデプロイする\n",
"***\n",
"事前学習済みモデルの deploy_image_uri, deploy_source_uri, base_model_uri を取得します。事前学習済みのベースモデルをホストするために、[`sagemaker.model.Model`](https://sagemaker.readthedocs.io/en/stable/api/inference/model.html) のインスタンスを作成し、デプロイします。\n",
"***"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cfd878a4",
"metadata": {},
"outputs": [],
"source": [
"from sagemaker import image_uris, model_uris, script_uris\n",
"from sagemaker.model import Model\n",
"from sagemaker.predictor import Predictor\n",
"from sagemaker.utils import name_from_base\n",
"\n",
"# model_version=\"*\" は最新のモデルバージョンを取得します\n",
"infer_model_id, infer_model_version = dropdown.value, \"*\"\n",
"\n",
"endpoint_name = name_from_base(f\"jumpstart-example-{infer_model_id}\")\n",
"\n",
"inference_instance_type = \"ml.m5.xlarge\"\n",
"\n",
"# 推論用Dockerコンテナを取得します\n",
"deploy_image_uri = image_uris.retrieve(\n",
" region=None,\n",
" framework=None,\n",
" image_scope=\"inference\",\n",
" model_id=infer_model_id,\n",
" model_version=infer_model_version,\n",
" instance_type=inference_instance_type,\n",
")\n",
"# 推論用スクリプトを取得します\n",
"deploy_source_uri = script_uris.retrieve(\n",
" model_id=infer_model_id, model_version=infer_model_version, script_scope=\"inference\"\n",
")\n",
"# ベースモデルのuriを取得します\n",
"base_model_uri = model_uris.retrieve(\n",
" model_id=infer_model_id, model_version=infer_model_version, model_scope=\"inference\"\n",
")\n",
"# SageMaker モデルのインスタンスを作成します。sagemaker APIを通して推論を実行するには、model をデプロイする際に、Predictorクラスを通す必要があります。\n",
"model = Model(\n",
" image_uri=deploy_image_uri,\n",
" source_dir=deploy_source_uri,\n",
" model_data=base_model_uri,\n",
" entry_point=\"inference.py\",\n",
" role=aws_role,\n",
" predictor_cls=Predictor,\n",
" name=endpoint_name,\n",
")\n",
"# モデルをデプロイします。\n",
"base_model_predictor = model.deploy(\n",
" initial_instance_count=1,\n",
" instance_type=inference_instance_type,\n",
" endpoint_name=endpoint_name,\n",
")"
]
},
{
"cell_type": "markdown",
"id": "742e0c63",
"metadata": {},
"source": [
"### 3.2. 推論用のサンプル画像をダウンロードする\n",
"***\n",
"JumpStart S3バケットからサンプル画像をダウンロードします。\n",
"***"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "68d7b7e0",
"metadata": {},
"outputs": [],
"source": [
"s3_bucket = f\"jumpstart-cache-prod-{aws_region}\"\n",
"key_prefix = \"inference-notebook-assets\"\n",
"\n",
"\n",
"def download_from_s3(images):\n",
" for filename, image_key in images.items():\n",
" boto3.client(\"s3\").download_file(s3_bucket, f\"{key_prefix}/{image_key}\", filename)\n",
"\n",
"\n",
"images = {\"img1.jpg\": \"cat.jpg\", \"img2.jpg\": \"dog.jpg\"}\n",
"download_from_s3(images)"
]
},
{
"cell_type": "markdown",
"id": "1d763c89",
"metadata": {},
"source": [
"### 3.3. エンドポイントにクエリし、レスポンスをパースする\n",
"***\n",
"エンドポイントへの入力は、2 値化された 1 枚の画像です。エンドポイントからのレスポンスは、上位 k 個の予測したクラスラベルと、各クラスの確率のリストを含む dictionary です。\n",
"***"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6ac75c02",
"metadata": {},
"outputs": [],
"source": [
"from IPython.core.display import HTML\n",
"\n",
"\n",
"def predict_top_k_labels(probabilities, labels, k):\n",
" topk_prediction_ids = sorted(\n",
" range(len(probabilities)), key=lambda index: probabilities[index], reverse=True\n",
" )[:k]\n",
" topk_class_labels = \", \".join([labels[id] for id in topk_prediction_ids])\n",
" return topk_class_labels\n",
"\n",
"\n",
"for image_filename in images.keys():\n",
" with open(image_filename, \"rb\") as file:\n",
" img = file.read()\n",
" query_response = base_model_predictor.predict(\n",
" img, {\"ContentType\": \"application/x-image\", \"Accept\": \"application/json;verbose\"}\n",
" )\n",
" model_predictions = json.loads(query_response)\n",
" labels, probabilities = model_predictions[\"labels\"], model_predictions[\"probabilities\"]\n",
" top5_class_labels = predict_top_k_labels(probabilities, labels, 5)\n",
" display(\n",
" HTML(\n",
" f'
'\n",
" f\"Top-5 predictions: {top5_class_labels} \"\n",
" )\n",
" )"
]
},
{
"cell_type": "markdown",
"id": "e9735ca6",
"metadata": {},
"source": [
"### 3.4. エンドポイントを削除する"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "60cc6cb8",
"metadata": {},
"outputs": [],
"source": [
"# SageMakerエンdポイントとアタッチされたリソースを削除します\n",
"base_model_predictor.delete_model()\n",
"base_model_predictor.delete_endpoint()"
]
},
{
"cell_type": "markdown",
"id": "2129bc4a",
"metadata": {},
"source": [
"## 4. 独自のデータセットを使って学習済みモデルをファインチューニングする\n",
"***\n",
"前回は、事前に学習したモデルに対して推論を実行する方法を確認しました。次に、任意の数のクラスを持つカスタムデータセットに対してモデルをファインチューニングする方法について説明します。\n",
"\n",
"ファインチューニングが可能なモデルは、利用可能な TensorFlow/PyTorch Hub の対応する特徴抽出モデルに、分類レイヤーを取り付けて、パラメータをランダムな値に初期化します。分類層の出力次元\n",
"は入力データ中のクラス数に基づいて決定されます。ファインチューニングステップでモデルのパラメータをファインチューニングします。その目的は、入力データに対する分類誤差を最小にすることです\n",
"。ファインチューニングによって得たモデルは、推論のためにデプロイすることができます。以下は、モデルへの入力のために教師データをどのようにフォーマットすべきかを示しています。\n",
"\n",
"- **入力:** クラスの数と同じ数の子ディレクトリを持つディレクトリ。 \n",
" - それぞれの子ディレクトリは .jpg フォオーマットで画像を含む必要があります。 \n",
"- **出力:** 推論用にデプロイできる学習したモデル。 \n",
" - ラベルのマッピングファイルは同じS3バケットに保存されます。 \n",
"\n",
"入力ディレクトリは以下のようになります。\n",
"学習画像が、バラ(roses)とタンポポ(dandelion)の2つのクラスをもつ場合、入力ディレクトリは以下のようになります。s3のパスは`s3://bucket_name/input_directory/`のようになります。\n",
"末尾の `/` は必須であることに注意してください。フォルダ名と 'roses', 'dandelion', .jpg ファイル名についてはは何でもかまいません。\n",
"学習済みモデルとともにs3バケットに保存されるラベルのマッピングファイルは、モデルが出力するクラス確率のリストのインデックスに、フォルダ名'roses'と'dandelion'をマッピングします。\n",
"このマッピングは、フォルダ名のアルファベット順に行われます。以下の例では、モデル出力リストのインデックス0は'dandelion'に対応し、インデックス1は'roses'に対応します。\n",
"\n",
" input_directory\n",
" |--roses\n",
" |--abc.jpg\n",
" |--def.jpg\n",
" |--dandelion\n",
" |--ghi.jpg\n",
" |--jkl.jpg\n",
"\n",
"モデルのファインチューニングのために、デフォルトのデータセットとして、tf_flowers データセットを提供します。\n",
"tf_flowers は5種類の花の画像を含みます。\n",
"データセットは [TensorFlow](https://www.tensorflow.org/datasets/catalog/tf_flowers) からダウンロードできます。. \n",
"[Apache 2.0 License](https://jumpstart-cache-prod-us-west-2.s3-us-west-2.amazonaws.com/licenses/Apache-License/LICENSE-2.0.txt).\n",
"Citation:\n",
"\n",
"@ONLINE {tfflowers,\n",
"author = \"The TensorFlow Team\",\n",
"title = \"Flowers\",\n",
"month = \"jan\",\n",
"year = \"2019\",\n",
"url = \"http://download.tensorflow.org/example_images/flower_photos.tgz\" }\n",
" source: [TensorFlow Hub](model_url). \n",
"***"
]
},
{
"cell_type": "markdown",
"id": "ce04a67a",
"metadata": {},
"source": [
"### 4.1. JumpStartの学習用アーティファクトを取得する\n",
"***\n",
"ここでは、選択されたモデルについて、学習用Dockerコンテナ、学習アルゴリズムソース、事前学習済みベースモデル、アルゴリズムがデフォルト値で使う学習用ハイパーパラメータのPython dictionaryを取得しています。model_version=\"*\"は、最新のモデルを取得することに注意してください。また、train_image_uriを取得するために、training_instance_typeを指定する必要があります。(訳注: ml.p3.2xlarge を使用するには、上限緩和申請が必要です。詳しくは[こちら](https://aws.amazon.com/jp/premiumsupport/knowledge-center/resourcelimitexceeded-sagemaker/)をご覧ください。)\n",
"***"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ae4cf8a1",
"metadata": {},
"outputs": [],
"source": [
"from sagemaker import image_uris, model_uris, script_uris, hyperparameters\n",
"\n",
"model_id, model_version = dropdown.value, \"*\"\n",
"training_instance_type = \"ml.p3.2xlarge\"\n",
"\n",
"# Docker imageを取得します\n",
"train_image_uri = image_uris.retrieve(\n",
" region=None,\n",
" framework=None,\n",
" model_id=model_id,\n",
" model_version=model_version,\n",
" image_scope=\"training\",\n",
" instance_type=training_instance_type,\n",
")\n",
"# 学習スクリプトを取得します\n",
"train_source_uri = script_uris.retrieve(\n",
" model_id=model_id, model_version=model_version, script_scope=\"training\"\n",
")\n",
"# ファインチューニングのため事前学習済みモデルのtarアーカイブを取得します\n",
"train_model_uri = model_uris.retrieve(\n",
" model_id=model_id, model_version=model_version, model_scope=\"training\"\n",
")"
]
},
{
"cell_type": "markdown",
"id": "4de2e48b",
"metadata": {},
"source": [
"### 4.2. トレーニングのパラメータを設定する\n",
"***\n",
"さて、必要な設定はすべて終わったので、次は画像分類のモデルのファインチューニングを行います。まず、[``sageMaker.estimator.Estimator``](https://sagemaker.readthedocs.io/en/stable/api/training/estimators.html)オブジェクトを作成します。このEstimatorにより,学習ジョブが起動されます.\n",
"\n",
"学習には 2 種類のパラメータを設定する必要があります。\n",
"\n",
"1つ目はトレーニングジョブのパラメータです.(i) 教師データのパス.これは、入力データが格納されているS3フォルダです、(ii) Output path: 学習の出力が格納されるS3フォルダ。(iii) 学習インスタンスタイプ: 学習を実行するマシンの種類を示します。通常、これらの学習にはGPUインスタンスを使用します。ここでは、正しいtrain_image_uriを取得するために、トレーニングインスタンスタイプの定義は前のステップで実施しました。\n",
"\n",
"2つ目のパラメータは、アルゴリズム固有の学習用ハイパーパラメータです。\n",
"***"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "363bd237",
"metadata": {},
"outputs": [],
"source": [
"# 有効なバケット内のサンプル教師画像\n",
"training_data_bucket = f\"jumpstart-cache-prod-{aws_region}\"\n",
"training_data_prefix = \"training-datasets/tf_flowers/\"\n",
"\n",
"training_dataset_s3_path = f\"s3://{training_data_bucket}/{training_data_prefix}\"\n",
"\n",
"output_bucket = sess.default_bucket()\n",
"output_prefix = \"jumpstart-example-ic-training\"\n",
"\n",
"s3_output_location = f\"s3://{output_bucket}/{output_prefix}/output\""
]
},
{
"cell_type": "markdown",
"id": "838e795c",
"metadata": {},
"source": [
"***\n",
"アルゴリズム固有のハイパーパラメータについては、まずアルゴリズムがデフォルト値で受け入れるトレーニングハイパーパラメータのPython dictionaryを取得します。これは独自の値に上書きすることができます。\n",
"***"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "44361de9",
"metadata": {},
"outputs": [],
"source": [
"from sagemaker import hyperparameters\n",
"\n",
"# モデルのファインチューニングのためのデフォルトのハイパーパラメータを取得します\n",
"hyperparameters = hyperparameters.retrieve_default(model_id=model_id, model_version=model_version)\n",
"\n",
"# [オプション] デフォルトのハイパーパラメータを独自の値で上書きします\n",
"hyperparameters[\"epochs\"] = \"5\"\n",
"print(hyperparameters)"
]
},
{
"cell_type": "markdown",
"id": "a7817d05",
"metadata": {},
"source": [
"### 4.3. 自動モデルチューニングを使って学習する ([HPO: hyper parameter optimization](https://docs.aws.amazon.com/sagemaker/latest/dg/automatic-model-tuning.html)) \n",
"***\n",
"Amazon SageMaker の自動モデルチューニングは、ハイパーパラメータチューニングとも呼ばれ、指定したアルゴリズムとハイパーパラメータの範囲で、データセット上で多くのトレーニングジョブを実行することにより、モデルのベストなバージョンを見つけます。そして、選択したメトリクスによって測定された、最高のパフォーマンスを発揮するモデルになるハイパーパラメータ値を選択します。Amazon SageMaker のハイパーパラメータチューニング API と連携するために [HyperparameterTuner](https://sagemaker.readthedocs.io/en/stable/api/training/tuner.html) オブジェクトを使用します。\n",
"***"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "71281ebf",
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
},
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"from sagemaker.tuner import ContinuousParameter\n",
"\n",
"# チューニングとモデルの選択にAMT (Automatic Model Tuning)を利用するかどうか \n",
"use_amt = True\n",
"\n",
"# ベストなモデルを選択するための目標となるメトリクスを、フレームワークごとに定義します\n",
"metric_definitions_per_model = {\n",
" \"tensorflow\": {\n",
" \"metrics\": [{\"Name\": \"val_accuracy\", \"Regex\": \"val_accuracy: ([0-9\\\\.]+)\"}],\n",
" \"type\": \"Maximize\",\n",
" },\n",
" \"pytorch\": {\n",
" \"metrics\": [{\"Name\": \"val_accuracy\", \"Regex\": \"val Acc: ([0-9\\\\.]+)\"}],\n",
" \"type\": \"Maximize\",\n",
" },\n",
"}\n",
"\n",
"# モデルがサポートするハイパーパラメータを選択し、最適なモデルを学習するために探索する値の範囲を設定できます (https://docs.aws.amazon.com/sagemaker/latest/dg/automatic-model-tuning-define-ranges.html)\n",
"hyperparameter_ranges = {\n",
" \"adam-learning-rate\": ContinuousParameter(0.0001, 0.1, scaling_type=\"Logarithmic\")\n",
"}\n",
"\n",
"# 精度を向上する(学習時間も増加します)ため、AMT (Automatic Model Tuning) の学習ジョブの数を増やす\n",
"max_jobs = 6\n",
"# 学習時間を短縮するために、AMT (Automatic Model Tuning) の並列学習ジョブ(アカウントごとにリミットで制限せれます)を変更します\n",
"# もし、最大ジョブ数と並列学習ジョブ数が同一の場合、探索方法が Bayesian から Random に変更されます。\n",
"max_parallel_jobs = 2"
]
},
{
"cell_type": "markdown",
"id": "aefe3561",
"metadata": {},
"source": [
"### 4.4. 学習を開始する\n",
"***\n",
"必要なアセットをすべて含む Estimator オブジェクトを作成し、トレーニングジョブを起動します。\n",
"***"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ee54c672",
"metadata": {},
"outputs": [],
"source": [
"from sagemaker.estimator import Estimator\n",
"from sagemaker.utils import name_from_base\n",
"from sagemaker.tuner import HyperparameterTuner\n",
"\n",
"training_job_name = name_from_base(f\"jumpstart-example-{model_id}-transfer-learning\")\n",
"\n",
"# SageMakerのEstimatorインスタンスを作成します\n",
"ic_estimator = Estimator(\n",
" role=aws_role,\n",
" image_uri=train_image_uri,\n",
" source_dir=train_source_uri,\n",
" model_uri=train_model_uri,\n",
" entry_point=\"transfer_learning.py\",\n",
" instance_count=1,\n",
" instance_type=training_instance_type,\n",
" max_run=360000,\n",
" hyperparameters=hyperparameters,\n",
" output_path=s3_output_location,\n",
" base_job_name=training_job_name,\n",
")\n",
"\n",
"if use_amt:\n",
" metric_definitions = next(\n",
" value for key, value in metric_definitions_per_model.items() if model_id.startswith(key)\n",
" )\n",
"\n",
" hp_tuner = HyperparameterTuner(\n",
" ic_estimator,\n",
" metric_definitions[\"metrics\"][0][\"Name\"],\n",
" hyperparameter_ranges,\n",
" metric_definitions[\"metrics\"],\n",
" max_jobs=max_jobs,\n",
" max_parallel_jobs=max_parallel_jobs,\n",
" objective_type=metric_definitions[\"type\"],\n",
" base_tuning_job_name=training_job_name,\n",
" )\n",
"\n",
" # ベストなハイパーパラメータのための探索するために、SageMakerのチューニングジョブを開始します\n",
" hp_tuner.fit({\"training\": training_dataset_s3_path})\n",
"else:\n",
" # トレーニングデータのS3パスを渡して、SageMaker 学習ジョブを開始します\n",
" ic_estimator.fit({\"training\": training_dataset_s3_path}, logs=True)"
]
},
{
"cell_type": "markdown",
"id": "e496dc14",
"metadata": {},
"source": [
"## 4.5. ファインチューニングしたモデルをデプロイして推論する\n",
"***\n",
"学習されたモデルはそれ自体では何もしてくれません。ここでは、そのモデルを使って推論を行いたいと思います。この例では、画像のクラスラベルを予測することを意味します。[3.学習済みモデルで推論する](#3.-学習済みモデルで推論する) と同じステップを踏んでいます。まず、エンドポイントをデプロイするための JumpStart のアーティファクトを取得することから始めます。base_predictorの代わりに、fine-tuningした`ic_estimator`をデプロイします。\n",
"***"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "40a21b25",
"metadata": {},
"outputs": [],
"source": [
"inference_instance_type = \"ml.m5.xlarge\"\n",
"\n",
"# 推論用 Docker コンテナの uri を取得します\n",
"deploy_image_uri = image_uris.retrieve(\n",
" region=None,\n",
" framework=None,\n",
" image_scope=\"inference\",\n",
" model_id=model_id,\n",
" model_version=model_version,\n",
" instance_type=inference_instance_type,\n",
")\n",
"# 推論用のスクリプト uri を取得します\n",
"deploy_source_uri = script_uris.retrieve(\n",
" model_id=model_id, model_version=model_version, script_scope=\"inference\"\n",
")\n",
"\n",
"endpoint_name = name_from_base(f\"jumpstart-example-FT-{model_id}-\")\n",
"\n",
"# SageMakerエンドポイントをデプロイするため前のステップのestimatorを使用します\n",
"finetuned_predictor = (hp_tuner if use_amt else ic_estimator).deploy(\n",
" initial_instance_count=1,\n",
" instance_type=inference_instance_type,\n",
" entry_point=\"inference.py\",\n",
" image_uri=deploy_image_uri,\n",
" source_dir=deploy_source_uri,\n",
" endpoint_name=endpoint_name,\n",
")"
]
},
{
"cell_type": "markdown",
"id": "db4ccdf1",
"metadata": {},
"source": [
"---\n",
"次に、S3バケットからバラとヒマワリのサンプル画像をダウンロードし、推論を行います。\n",
"\n",
"---"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9e39ff9a",
"metadata": {},
"outputs": [],
"source": [
"s3_bucket = f\"jumpstart-cache-prod-{aws_region}\"\n",
"key_prefix = \"training-datasets/tf_flowers\"\n",
"\n",
"\n",
"def download_from_s3(images):\n",
" for filename, image_key in images.items():\n",
" boto3.client(\"s3\").download_file(s3_bucket, f\"{key_prefix}/{image_key}\", filename)\n",
"\n",
"\n",
"flower_images = {\n",
" \"img1.jpg\": \"roses/10503217854_e66a804309.jpg\",\n",
" \"img2.jpg\": \"sunflowers/1008566138_6927679c8a.jpg\",\n",
"}\n",
"download_from_s3(flower_images)"
]
},
{
"cell_type": "markdown",
"id": "4fcc7601",
"metadata": {},
"source": [
"---\n",
"次に、ファインチューニングしたモデルに対してクエリを行い、そのレスポンスをパースして予測値を表示します。\n",
"\n",
"---"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2ea921ea",
"metadata": {},
"outputs": [],
"source": [
"from IPython.core.display import HTML\n",
"\n",
"for image_filename in flower_images.keys():\n",
" with open(image_filename, \"rb\") as file:\n",
" img = file.read()\n",
" query_response = finetuned_predictor.predict(\n",
" img, {\"ContentType\": \"application/x-image\", \"Accept\": \"application/json;verbose\"}\n",
" )\n",
" model_predictions = json.loads(query_response)\n",
" predicted_label = model_predictions[\"predicted_label\"]\n",
" display(\n",
" HTML(\n",
" f'
'\n",
" f\"Predicted Label: {predicted_label}\"\n",
" )\n",
" )"
]
},
{
"cell_type": "markdown",
"id": "d289868a",
"metadata": {},
"source": [
"---\n",
"次に、デプロイしたエンドポイントを削除します。\n",
"\n",
"---"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d3c77910",
"metadata": {},
"outputs": [],
"source": [
"# SageMakerエンドポイントとアタッチされたリソースを削除します\n",
"finetuned_predictor.delete_model()\n",
"finetuned_predictor.delete_endpoint()"
]
},
{
"cell_type": "markdown",
"id": "c55085e2",
"metadata": {},
"source": [
"## 4.6. ファインチューニング済みモデルを増分学習する\n",
"\n",
"***\n",
"増分学習は、前回の学習で考慮されなかったためにモデルのパフォーマンスの低下をもたらしたパターンを含む、拡張されたデータセットを使用して、新しいモデルを学習させることができます。既存のモデルのアーティファクトと拡張されたデータセットを使用して新しいモデルを学習することができます。増分学習は、ゼロからモデルを再トレーニングする必要がないため、時間とリソースの両方を節約することができます。\n",
"\n",
"データセットの形式(クラスのセット)が同じであれば、どんなデータセット(新旧問わず)を使ってもかまいません。増分学習ステップは、前述のファインチューニングと似ていますが、次の違いがあります。ファインチューニングでは事前学習済みモデルから開始するのに対し、増分学習では既存のファインチューニング済みモデルから始めます。\n",
"***"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "74237150",
"metadata": {},
"outputs": [],
"source": [
"# 学習ジョブ名とアーティファクトのアウトプット場所をもとに、前のステップで学習したモデルを特定します\n",
"if use_amt: # amtを利用している場合、ベストな学習ジョブを選択します\n",
" sage_client = boto3.Session().client(\"sagemaker\")\n",
" tuning_job_result = sage_client.describe_hyper_parameter_tuning_job(\n",
" HyperParameterTuningJobName=hp_tuner._current_job_name\n",
" )\n",
" last_training_job_name = tuning_job_result[\"BestTrainingJob\"][\"TrainingJobName\"]\n",
"else:\n",
" last_training_job_name = ic_estimator._current_job_name\n",
"\n",
"last_trained_model_path = f\"{s3_output_location}/{last_training_job_name}/output/model.tar.gz\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "474f8531",
"metadata": {},
"outputs": [],
"source": [
"incremental_train_output_prefix = \"jumpstart-example-ic-incremental-training\"\n",
"\n",
"incremental_s3_output_location = f\"s3://{output_bucket}/{incremental_train_output_prefix}/output\"\n",
"\n",
"incremental_training_job_name = name_from_base(f\"jumpstart-example-{model_id}-incremental-training\")\n",
"\n",
"incremental_train_estimator = Estimator(\n",
" role=aws_role,\n",
" image_uri=train_image_uri,\n",
" source_dir=train_source_uri,\n",
" model_uri=last_trained_model_path,\n",
" entry_point=\"transfer_learning.py\",\n",
" instance_count=1,\n",
" instance_type=training_instance_type,\n",
" max_run=360000,\n",
" hyperparameters=hyperparameters,\n",
" output_path=incremental_s3_output_location,\n",
" base_job_name=incremental_training_job_name,\n",
")\n",
"\n",
"incremental_train_estimator.fit({\"training\": training_dataset_s3_path}, logs=True)"
]
},
{
"cell_type": "markdown",
"id": "f82dc42c",
"metadata": {},
"source": [
"学習が完了したら、4.5 [ファインチューニングしたモデルをデプロイして推論する](#4.5.-ファインチューニングしたモデルをデプロイして推論する) と同じ手順でモデルをデプロイすることができます。"
]
}
],
"metadata": {
"instance_type": "ml.t3.medium",
"kernelspec": {
"display_name": "Python 3 (Data Science)",
"language": "python",
"name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:ap-northeast-1:102112518831:image/datascience-1.0"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.10"
},
"pycharm": {
"stem_cell": {
"cell_type": "raw",
"metadata": {
"collapsed": false
},
"source": []
}
}
},
"nbformat": 4,
"nbformat_minor": 5
}