LoginSignup
0
0

【AWS SageMaker】Notebookインスタンスにて組み込みアルゴリズムのLDAを使ってモデル開発~学習~デプロイを行ってみた

Posted at

背景

AWS SageMakerを勉強していると、SageMakerで機械学習モデルを実装する場合、大きくは3通りの方法がありそうです。

  • SageMakerの組み込みアルゴリズムを使って実装する
  • TensorFlowやPyTorchなどで自作したコードを使って実装する
  • TensorFlowやPyTorchなど以外で自作したコードを使って実装する

1つ目の方法は、SageMakerには既に複数のアルゴリズムが組み込まれていて、Pythonのクラスからのインスタンス化のような感じで、それらのアルゴリズムを使えて、それを使って機械学習モデルを実装します。

2つ目の方法は、TensorFlowやPyTorchなどで自作した機械学習モデルのコードを使って、SageMakerに機械学習モデルを実装します。

3つ目の方法は、TensorFlowやPyTorchなど以外で自作した機械学習モデルのコードを使って、SageMakerに機械学習モデルを実装します。2つ目の方法との違いは、TensorFlowやPyTorchなどのフレームワークの場合、AWS側で用意済みのコンテナを利用してTensorFlowやPyTorchなどを走らせられますが、AWS側でコンテナを用意していないフレームワークの場合、そのコンテナもユーザ側で用意しなければならない点が、2つ目との違いっぽい気がしました。

今回は、3つの中で一番簡単そうな1つ目の方法で、機械学習モデルの実装(開発~学習~デプロイ)を試してみようと思います。

環境

sagemaker 2.219.0

このsagemakerのv1とv2で組み込みアルゴリズムを使うためのコードが微妙に違っていました。今回は、v2でのコードになります。

試した事(概要)

AWS SageMaker Notebookインスタンスにて、組み込みアルゴリズムのLDAを使って、機械学習モデルを開発~学習~デプロイして、デプロイ後の機械学習モデルで、文章をトピック分類してみました。
学習に使うデータは、こちらで取得した500個の文章データにしました。

試した事(詳細)

1. SageMaker Notebookインスタンス内に.ipynbファイルを作成

カーネルは「conda_python3」を選びました。

キャプチャ1.png

2. コードを記載

Notebookインスタンスにコードを書いていきます。

2.1. ライブラリーをインストール

Notebookインスタンスには標準でインストールされていないライブラリーをインストールします。

!pip install janome
!sudo yum install -y ipa-gothic-fonts
!pip install mxnet
!pip install japanize-matplotlib
2.2. ライブラリーをインポート

必要なライブラリーをインポートします。

hogehoge.ipynb
import os
import pickle
import random
import tarfile
import matplotlib.pyplot as plt
import japanize_matplotlib

import numpy as np
import pandas as pd

import boto3
import sagemaker

from janome import tokenizer
from janome import charfilter
from janome import tokenfilter
from janome import analyzer
from sklearn import feature_extraction

import mxnet as mx

np.random.seed(3407)
2.3. 初期変数を設定

初期変数を設定します。

hogehoge.ipynb
ROLE = sagemaker.get_execution_role()
SAGEMAKER_SESSION = sagemaker.Session()
S3_BUCKET = SAGEMAKER_SESSION.default_bucket()
S3_PREFIX = "folder_for_algorithm_LDA"
TRAIN_FILENAME = "train_text_500_lda.data"

変数ROLEは、このSageMaker Notebookインスタンスに割り当てられているロール名を保存します。これと、変数SAGEMAKER_SESSIONに保存したセッション情報を使って、AWSのSDKであるboto3ライブラリーやsagemakerライブラリーを触ります。
変数S3_BUCKETS3_PREFIXTRAIN_FILENAMEは、S3へデータをアップロードしたりする時に使います。

2.4. 500個の文章データを取得

こちらで取得した文章データ(pandasのDataFrameの形)を、事前に500文章だけpickleで保存していたので、それをロードします。

hogehoge.ipynb
with open("data/20240501_random22_500data/text.pkl", mode="rb") as f:
    text_500 = pickle.load(file=f)

DataFrameの中身はこのような形です。

キャプチャ2.png

カラム名の「summary」は3行要約、「text」は記事本文になります。今回は「text」部分を使います。

2.5. janomeで分かち書きを行う関数を作成

janomeを使って分かち書きを行います。また、今回は文章内の名詞だけを取得して、分かち書きの形にしようと思います。

hogehoge.ipynb
def setting_janome():
    janome_tokenizer = tokenizer.Tokenizer()
    janome_char_filter = [charfilter.UnicodeNormalizeCharFilter()]
    syutoku_list = ["名詞"]
    zyogai_list = ["名詞,非自立", "名詞,代名詞", "名詞,副詞可能", "名詞,形容動詞語幹", "名詞,接尾"]
    janome_token_filter = [tokenfilter.CompoundNounFilter(),
                           tokenfilter.POSKeepFilter(syutoku_list),
                           tokenfilter.POSStopFilter(zyogai_list)]
    janome_analyzer = analyzer.Analyzer(char_filters=janome_char_filter,
                                        tokenizer=janome_tokenizer,
                                        token_filters=janome_token_filter)
    return janome_analyzer


def janome_wakati(doc, janome_analyzer):
    temp_wakati = []
    for token in janome_analyzer.analyze(doc):
        temp_wakati.append(token.surface)
    wakati = " ".join(temp_wakati)
    return wakati
2.6. janomeで500個の文章データを分かち書き

先程の関数を使って、文章データ(DataFrameの「text」カラムにある記事本文)を分かち書きの形にします。分かち書き後のデータは、DataFrameの「wakati」カラムに保存します。

hogehoge.ipynb
janome_ANALYZER = setting_janome()
text_500["wakati"] = text_500["text"].apply(janome_wakati, args=(janome_ANALYZER,))

DataFrameの中身はこのような形になりました。
キャプチャ3.png

2.7. 500文章の分かち書きの部分を取得

DataFrameから分かち書きの部分(「wakati」カラム)のみを取得します。取得後は、要素数が500のarray型(500は文章数)になります。

hogehoge.ipynb
text_500_wakati_array = text_500["wakati"].values
print(type(text_500_wakati_array))
print(text_500_wakati_array.shape)
<class 'numpy.ndarray'>
(500,)
2.8. 500文章の分かち書きから、500文章のBoW((文章数, トークン数)行列)を作成 ※この後のLDAモデルへの入力データになります

sklearnライブラリーのfeature_extractionを使って、500文章の分かち書きから、500文章のBoWを取得します。
BoWは他にgensimライブラリーを使っても取得出来ますが、SageMakerの組み込みアルゴリズムのLDAでは、入力データは(文章数, トークン数)行列である必要があるようなので、sklearnライブラリーを使いました。

hogehoge.ipynb
bag_of_words_instance = feature_extraction.text.CountVectorizer()
bag_of_words_instance.fit(text_500_wakati_array)
train_input_text_500_bow = bag_of_words_instance.transform(text_500_wakati_array).toarray()
print(type(train_input_text_500_bow))
print(train_input_text_500_bow.shape)
<class 'numpy.ndarray'>
(500, 18339)

(名詞だけの分かち書きでも、トークン数(単語数)は18,339個もあって少し驚きました。)

2.9. 500文章の分かち書きから、ID:トークンの辞書を作成

先程のsklearnでの処理で、トークン(単語)はID扱いになっているので、IDからトークンに変換しやすいように、辞書型で「ID: トークン」の形の辞書データを作ります。

hogehoge.ipynb
id2token_dictionary = {}
for k, v in bag_of_words_instance.vocabulary_.items():
    id2token_dictionary[v] = k
print(len(id2token_dictionary))
print(id2token_dictionary[7777])
18339
メーカー純正品

キチンと辞書には18,339個のデータがあります。IDの7,777は「メーカー純正品」というトークン(単語)と紐付いているみたいです。


データの前処理はここまでになります。
次からは、SageMakerの組み込みアルゴリズムを使うためのコードになっていきます。

2.10. 500文章のBoWの行列をRecordIO形式に変換

先程作成した(500, 18339)のarray行列を、SageMakerの組み込みアルゴリズムのLDAに入力できる形式のRecordIO形式に変換します。

hogehoge.ipynb
recordio_serializer = sagemaker.amazon.common.RecordSerializer()
train_input_text_500_bow_recordio = recordio_serializer.serialize(train_input_text_500_bow)
print(type(train_input_text_500_bow_recordio))
<class '_io.BytesIO'>
2.11. S3向けのパスを準備

SageMakerで機械学習モデルを実装する際、基本的にデータはS3に保存されている事が前提になるようですので、データの保存先となるS3のパスを準備します。

hogehoge.ipynb
s3_train_data_path = os.path.join(S3_PREFIX, TRAIN_FILENAME)
print(s3_train_data_path)
s3_train_input_path = "s3://" + os.path.join(S3_BUCKET, s3_train_data_path)
print(s3_train_input_path)
s3_train_output_path = "s3://" + os.path.join(S3_BUCKET, S3_PREFIX)
print(s3_train_output_path)

キャプチャ4.png

パスの頭の「s3://」が意外と重要だったりしました。

2.12. RecordIO形式にしたBoWデータをS3にアップロード

boto3ライブラリーを使って、S3にアップロードします。

hogehoge.ipynb
boto3.Session().resource("s3").Bucket(S3_BUCKET).Object(s3_train_data_path).upload_fileobj(train_input_text_500_bow_recordio)

キャプチャ5.png

S3にアップロードされました。

2.13. AWSが提供するLDAモデルのdocker imageのURIを取得

SageMakerの組み込みアルゴリズムのLDAモデルを走らせるためのDockerイメージのURIを取得します。このDockerイメージはAWS側で用意済みですので、そのDockerイメージのURIを取得します。

hogehoge.ipynb
lda_container = sagemaker.image_uris.retrieve(framework="lda" ,region="ap-northeast-1")
print(lda_container)
258307448986.dkr.ecr.ap-northeast-1.amazonaws.com/lda:1

ちなみに、LDA以外の組み込みアルゴリズムのDockerイメージもありまして、東京リージョンではこれらの組み込みアルゴリズムのDockerイメージを取得出来るようです。

2.14. EstimatorクラスにLDAモデルのDockerイメージを渡して、LDAモデルのオブジェクトを作成

SageMakerで機械学習モデルを実装する時は、sagemakerライブラリーのEstimatorクラスでモデルのオブジェクトを作成する事がお作法みたいです。

hogehoge.ipynb
lda_model = sagemaker.estimator.Estimator(image_uri=lda_container,
                                          role=ROLE,
                                          instance_count=1,
                                          instance_type="ml.m5.large",
                                          output_path=s3_train_output_path,
                                          sagemaker_session=SAGEMAKER_SESSION)

それぞれの引数の意味は下記になります。
image_uri
 組み込みアルゴリズムのDockerイメージのURI
role
 割り当てるロール
instance_count
 組み込みアルゴリズムのモデルを動かすインスタンスの数
instance_type
 組み込みアルゴリズムのモデルを動かすインスタンスのタイプ
 インスタンス毎の価格は

output_path
 学習完了後のモデルをファイル出力するS3のパス
sagemaker_session
 割り当てるセッション

2.15. 作成したLDAモデルのオブジェクトにハイパーパラメータを設定

作成したLDAモデルのオブジェクトにハイパーパラメータを設定します。

hogehoge.ipynb
n_text = train_input_text_500_bow.shape[0]
n_token = train_input_text_500_bow.shape[1]
lda_model.set_hyperparameters(num_topics=15,
                              feature_dim=n_token,
                              mini_batch_size=n_text)

それぞれの引数の意味は下記になります。
num_topics
 LDAで作成するトピック数(今回は試しに15で設定)
feature_dim
 トークン数(今回は18,339個)
mini_batch_size
 文章数(今回は500個)
他にも引数はoptionalでいくつかあるようです。

2.16. 学習ジョブの実行

500文章のBoWデータを使って、作成したLDAモデルを学習させます。
学習は、このNotebookインスタンス上で行われるのではなく、先程のEstimatorクラスでLDAモデルのオブジェクトを作成する際に指定したインスタンス上で行われます。

hogehoge.ipynb
now = datetime.now()
year = str(now.year)
month = str(now.month)
day = str(now.day)
hour = str(now.hour)
minute = str(now.minute)
second = str(now.second)
job_timestamp = year + month + day + hour + minute + second
training_job_name = "test-training-sagemaker-algorithm-LDA-{a}".format(a=job_timestamp)
lda_model.fit({"train": s3_train_input_path}, job_name=training_job_name)

(もっとスマートにタイムスタンプを作成する方法がある事を知りつつも、このようなタイムスタンプの作り方でゴメンなさい。)

fitメソッドを実行すると、このようなログが出てきました。学習ジョブが実行されているようです。
キャプチャ6.png

学習ジョブの状況は、SageMakerの「トレーニング > トレーニングジョブ」からも確認出来ます。
キャプチャ7.png
無事に学習ジョブは完了しました。

2.17. 学習後のLDAモデルの中身を確認

学習が完了すると、EstimatorクラスでLDAモデルのオブジェクトを作成する際に、引数output_pathで指定したS3のパスに、学習後のLDAモデルがmodel.tar.gzというファイルで保存されています。

キャプチャ8.png

この学習後のLDAモデルについて、中身を少し見てみます。
まずは、このmodel.tar.gzファイルを、Notebookインスタンスのローカルにダウンロードしたいので、Notebookインスタンスでboto3ライブラリーを使ってダウンロードします。
(コードは先程の学習ジョブの実行のfitメソッドの続きで書いています。)

hogehoge.ipynb
model_file_path = os.path.join(S3_PREFIX, training_job_name, "output", "model.tar.gz")
boto3.Session().resource("s3").Bucket(S3_BUCKET).Object(model_file_path).download_file("trained_LDA_model.tar.gz")

続いて、ローカルにダウンロードしたmodel.tar.gzファイルを解凍して、モデルファイルのファイル名を取得します。
(今回は解凍すると、ローカルにmodel_algo-1というファイルが展開されました。そのファイル名を変数model_filenameに保存しています。)

hogehoge.ipynb
with tarfile.open("./trained_LDA_model.tar.gz") as tar:
    tar.extractall()
model_filename_list = [fname for fname in os.listdir(".") if fname.startswith("model_")]
model_filename = model_filename_list[0]
print(model_filename)
model_algo-1

このmodel_algo-1ファイルに対して、mxライブラリーを使って、モデルの情報であると思われるαβをarray型の形で取得します。

hogehoge.ipynb
alpha, beta = mx.ndarray.load(model_filename)
learned_alpha_permuted = alpha.asnumpy()
learned_beta_permuted = beta.asnumpy()
print(type(learned_alpha_permuted))
print("Learned alpha.shape = {}".format(learned_alpha_permuted.shape))
print(type(learned_beta_permuted))
print("Learned beta.shape = {}".format(learned_beta_permuted.shape))
print(learned_beta_permuted[0])
<class 'numpy.ndarray'>
Learned alpha.shape = (15,)
<class 'numpy.ndarray'>
Learned beta.shape = (15, 18339)
[0. 0. 0. ... 0. 0. 0.]

αは15次元ベクトルであり、今回のLDAモデルのトピック数と同じになります。
βは15行18,339列の行列であり、今回のLDAモデルのトピック数を行に、トークン数を列に持ちます。
試しにβの1行目(トピック0)にある18,339次元ベクトルを見てみると、おそらく18,339個のトークン毎に、トピック0に属している割合を値として持っていそうです。
(値が0のものは、トピック0に属していないトークンになると思います。)

となると、トピック毎に、numpyのwhereメソッドを使って、値が0ではない要素を取得すれば、トピック毎に属しているトークンの数が分かるのでは、と思い、試してみました。

hogehoge.ipynb
all_topic = {}
for i in range(15):
    topic = {}
    ids_in_topic = np.where(learned_beta_permuted[i]!=0)[0]
    print("トピック{a}を構成しているトークン数は{b}".format(a=i, b=len(ids_in_topic)))
トピック0を構成しているトークン数は1327
トピック1を構成しているトークン数は4029
トピック2を構成しているトークン数は136
トピック3を構成しているトークン数は75
トピック4を構成しているトークン数は33
トピック5を構成しているトークン数は31
トピック6を構成しているトークン数は9
トピック7を構成しているトークン数は10
トピック8を構成しているトークン数は9
トピック9を構成しているトークン数は10
トピック10を構成しているトークン数は6
トピック11を構成しているトークン数は8
トピック12を構成しているトークン数は5
トピック13を構成しているトークン数は1
トピック14を構成しているトークン数は1

トピック0とトピック1は多くのトークンで構成されているにも関わらず、トピック13とトピック14は1つだけのトークンで構成されているようです。もしかしたら、トピック数を15に指定した事は適切でなかったのかもしれません。


続いて、トピック毎に構成割合の高いトップ10のトークンをグラフ化してみます。

hogehoge.ipynb
# トピック毎にidを纏める
all_topic = {}
for i in range(15):
    topic = {}
    ids_in_topic = np.where(learned_beta_permuted[i]!=0)[0]
    for j in ids_in_topic:
        topic[j] = learned_beta_permuted[i][j]
    sorted_topic = dict(sorted(topic.items(), key=lambda x: x[1], reverse=True))
    all_topic[i] = sorted_topic
# トピック毎にトークンを纏める
all_topic_token = {}
for i in range(15):
    token_in_topic = {}
    for k, v in all_topic[i].items():
        token_in_topic[id2token_dictionary[k]] = v
    all_topic_token[i] = token_in_topic
# トピック毎にトークンのトップ10をグラフ化
for i in range(15):
    fig, (axes1) = plt.subplots(nrows=1, ncols=1, figsize=(16, 5))
    if len(all_topic_token[i]) > 10:
        ranking = 10
    else:
        ranking = len(all_topic_token[i])
    graph_y_axis = np.arange(1, ranking+1, 1)
    token_ranking_list = []
    importance_ranking_list = []
    count = 0
    for k, v in all_topic_token[i].items():
        token_ranking_list.append(k)
        importance_ranking_list.append(v)
        count += 1
        if count == ranking:
            break
    axes1.barh(graph_y_axis, importance_ranking_list, tick_label=token_ranking_list)
    axes1.set_title("token ranking {a} in topic {b}".format(a=ranking, b=i))
    axes1.set_xlabel("importance")
    axes1.set_ylabel("token")
    axes1.set_yticks(ticks=graph_y_axis)
    plt.show()

コードがキレイでなくてゴメンなさい。
結果はこのような形です。

キャプチャ9.png

キャプチャ10.png

キャプチャ11.png

何となくトークンがトピック毎に纏まっているような気がします。纏まっていると思いたいです(笑)

2.18. 学習後のLDAモデルをデプロイ

SageMakerは、機械学習モデルの開発、学習、デプロイを一気通貫で出来るサービスになります。
今回、組み込みアルゴリズムを使ってLDAモデルを開発して、そして、500個の分かち書き文章のBoWでLDAモデルの学習を行ったので、次はこの学習後LDAモデルをデプロイしてみようと思います。

Notebookインスタンスに今までのコードの続きで下記を記載します。

hogehoge.ipynb
lda_model_inference = lda_model.deploy(initial_instance_count=1, instance_type="ml.m5.large")
print("LDA model Endpoint name: {}".format(lda_model_inference.endpoint_name))
LDA model Endpoint name: lda-2024-05-18-07-27-41-652

無事にデプロイ出来たようです。
デプロイ結果は、SageMakerの「推論 > エンドポイント」からも確認出来ます。

キャプチャ12.png

また、SageMakerの「推論 > エンドポイント設定」や「推論 > モデル」にも情報があります。

キャプチャ13.png

キャプチャ14.png

2.19. デプロイした学習後LDAモデルで推論

デプロイした学習後LDAモデルに文章データ(文章のBoWデータ)を投げて、その文章データのトピック割合を表示してみようと思います。

今回、500文章を全て学習に使ってしまったので(笑)、完全なデータリークですが、学習に使った500文章の内の最初の5文章を、デプロイした学習後LDAモデルのエンドポイント(オブジェクト)に投げてみます。

まずは、デプロイ時に引数で設定しそびれたシリアライズとデシリアライズを、デプロイした学習後LDAモデルのオブジェクトに設定します。

hogehoge.ipynb
lda_model_inference.serializer = sagemaker.serializers.CSVSerializer()
lda_model_inference.deserializer = sagemaker.deserializers.JSONDeserializer()

では、学習に使った500文章の内の最初の5文章のBoW(変数train_input_text_500_bow[0]~train_input_text_500_bow[4])を、デプロイした学習後LDAモデルのオブジェクトに投げます。

hogehoge.ipynb
for i in range(5):
    results = lda_model_inference.predict(train_input_text_500_bow[i])
    print(results)
{'predictions': [{'topic_mixture': [0.4112326204776764, 0.0, 0.0, 0.588767409324646, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]}]}
{'predictions': [{'topic_mixture': [0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]}]}
{'predictions': [{'topic_mixture': [0.0, 0.5673089623451233, 0.0, 0.0, 0.0, 0.4326910078525543, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]}]}
{'predictions': [{'topic_mixture': [0.5596829652786255, 0.4403170645236969, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]}]}
{'predictions': [{'topic_mixture': [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]}]}

ちょっと辞書型の結果が見にくいので、キー部分は省いて、バリュー部分のみを取得するようにします。

hogehoge.ipynb
for i in range(5):
    results = lda_model_inference.predict(train_input_text_500_bow[i])
    print("{a}文章目のトピック割合:".format(a=i), results["predictions"][0]["topic_mixture"])
0文章目のトピック割合: [0.4112326204776764, 0.0, 0.0, 0.588767409324646, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
1文章目のトピック割合: [0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
2文章目のトピック割合: [0.0, 0.5673089623451233, 0.0, 0.0, 0.0, 0.4326910078525543, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
3文章目のトピック割合: [0.5596829652786255, 0.4403170645236969, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
4文章目のトピック割合: [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

結果が出ました。
イイ感じに文章をトピック分け出来ていそうです。
ただし、個人的にはちょっと「?」と思っている仕様があります。
例えば、上記の0文章目のトピック割合については、
 トピック0の割合:41.1%
 トピック1の割合:0%
 トピック2の割合:0%
 トピック3の割合:58.8%
 トピック4の割合:0%
 ・・・
と思ってしまいそうですが、こちらを確認すると、

If you decide to compare these results to the known topic mixtures generated in the Obtain Example Data Section keep in mind that SageMaker LDA discovers topics in no particular order. That is, the approximate topic mixtures computed above may be permutations of the known topic mixtures corresponding to the same documents.

と書かれています。
「SageMaker LDA discovers topics in no particular order.」となると、この0文章目の41.1%はトピック0の割合ではなく、トピック1の割合かもしれないし、トピック2の割合かもしれない、という事になってしまいます。

この点の仕様について、私の理解が誤っているのか、それとも本当にこのような仕様なのか、「?」になっています。

もし、本当にこのような仕様だった場合、このLDAモデルはどのような用途で使うのか分からなくなってしまいました。

2.20. 後片付け

デプロイした学習後LDAモデルのオブジェクトの実体はエンドポイントであり、このエンドポイントを削除しない限り、課金が続いてしまうので、今回作成したエンドポイントを削除します。
(deployメソッド時に指定したインスタンス上でエンドポイントは動いているので、作成したエンドポイントを削除しないと、インスタンスの稼働料金が課金され続けてしまう。)

hogehoge.ipynb
sagemaker.Session().delete_endpoint(lda_model_inference.endpoint_name)

SageMakerの「推論 > エンドポイント」を確認すると、先程まであったエンドポイントが消えている事が確認出来ました。

キャプチャ15.png

これで課金は発生しない形になりますが、エンドポイント設定やモデルは残ったままなので、念のためこれらもマネジメントコンソールにて削除します。

「推論 > エンドポイント設定」
キャプチャ16.png
キャプチャ17.png

「推論 > モデル」
キャプチャ18.png
キャプチャ19.png

以上になります。

補足:model.tar.gzファイルから学習後モデルのオブジェクトをロードする場合

例えばですが、fitメソッドで学習を行って、S3にmodel.tar.gzファイルを作成した後、そのままdeployメソッドを行わずに、Notebookインスタンスを落として、別日にdeployメソッドを行うとします。
もちろんNotebookインスタンスを再び立ち上げた際に、モデルのオブジェクト(今回ならば変数lda_model)は空っぽなので、このままではdeployメソッドを行えません。
この場合、model.tar.gzファイルを使って、学習後LDAモデルのオブジェクトを変数lda_modelに改めてロード出来ます。

hogehoge.ipynb
training_job_name = "test-training-sagemaker-algorithm-LDA-202451351210"
lda_model = sagemaker.model.Model(image_uri=lda_container,
                                  model_data="{a}/{b}/output/model.tar.gz".format(a=s3_train_output_path, b=training_job_name),
                                  role=ROLE,
                                  predictor_cls=sagemaker.predictor.RealTimePredictor)

Modelクラスの引数は下記の意味になります。
image_uri
 モデルを走らせるためのコンテナのURI
 今回の場合は、

hogehoge.ipynb
lda_container = sagemaker.image_uris.retrieve(framework="lda" ,region="ap-northeast-1")

 で取得したコンテナのURIになります。
model_data
 model.tar.gzファイルが保存されているS3のパス
role
 割り当てるロール
 今回の場合は、

hogehoge.ipynb
ROLE = sagemaker.get_execution_role()

 で取得したロールになります。
predictor_cls
 詳細は分からずですが、sagemaker.predictor.RealTimePredictorを設定する必要のある引数のようです。

まとめ

SageMakerの組み込みアルゴリズムのLDAを題材にして、SageMakerの開発~学習~デプロイの流れを最低限ではありますが、行う事が出来て、「SageMakerとは」の具体的な理解が一歩深まりました。
一方で、組み込みアルゴリズムのLDAの推論結果で、出力された割合の順番は、トピックの順番と一致しているとは限らない、というのは「本当に?」と思ってしまいました。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0