背景
AWS SageMaker Canvasを用いる事で、機械学習モデルを自動作成して、そのままデプロイも行う事が出来るようですので、試してみました。
試した事(概要)
Nishikaのコンペの訓練(train)データとテスト(test)データを使って、SageMaker Canvasにて機械学習モデルを作成、デプロイして、デプロイしたモデルで推論を試してみました。
試した事(詳細)
1. 準備
1.1. データを用意
こちらのサイトから、train.zipとtest.csvをダウンロードします。
zipファイルを解凍すると、trainフォルダ内に多数のcsvファイルが入っていますので、それらcsvファイルを、pandasを使って1つのcsvファイルに纏めて、train.csvとします。
train_df_list = []
for csv_file in glob.glob("data/Nishika_ApartmentPrice/train/*"):
df = pd.read_csv(filepath_or_buffer=csv_file,
converters={"面積(㎡)": str},
encoding="utf-8")
train_df_list.append(df)
train_df = pd.concat(objs=train_df_list,
axis=0,
ignore_index=True)
print(train_df.columns)
train_df.to_csv(path_or_buf="data/Nishika_ApartmentPrice/train.csv",
header=True,
index=False,
encoding="utf-8")
Index(['ID', '種類', '地域', '市区町村コード', '都道府県名', '市区町村名', '地区名', '最寄駅:名称', '最寄駅:距離(分)', '間取り', '面積(㎡)', '土地の形状', '間口', '延床面積(㎡)', '建築年', '建物の構造', '用途', '今後の利用目的', '前面道路:方位', '前面道路:種類', '前面道路:幅員(m)', '都市計画', '建ぺい率(%)', '容積率(%)', '取引時点', '改装', '取引の事情等', '取引価格(総額)_log'], dtype='object')
1.2. データを前処理
先程作成したtrain.csvと、先程ダウンロードしたtest.csvをDataFrameの形で取得します。
train_df = pd.read_csv(filepath_or_buffer="data/Nishika_ApartmentPrice/train.csv",
converters={"面積(㎡)": str},
encoding="utf-8")
test_df = pd.read_csv(filepath_or_buffer="data/Nishika_ApartmentPrice/test.csv",
converters={"面積(㎡)": str},
encoding="utf-8")
見やすくするために、カラムを少し減らそうと思います。
今回はこちらの記事の1.4.と同様の前処理を、train_dfとtest_dfに行います。
simple_train_df = train_df[["市区町村コード", "最寄駅:距離(分)", "面積(㎡)", "建ぺい率(%)", "容積率(%)", "取引価格(総額)_log"]].dropna(how="any").copy()
simple_train_df["面積(㎡)"] = simple_train_df["面積(㎡)"].apply(lambda x: "2000" if x == "2000㎡以上" else x)
simple_train_df["面積(㎡)"] = simple_train_df["面積(㎡)"].astype("int")
simple_train_df["最寄駅:距離(分)"] = simple_train_df["最寄駅:距離(分)"].apply(lambda x: "45" if x == "30分?60分" else "75" if x == "1H?1H30" else "105" if x == "1H30?2H" else "120" if x == "2H?" else x)
simple_train_df["最寄駅:距離(分)"] = simple_train_df["最寄駅:距離(分)"].astype("int")
simple_train_df["建ぺい率(%)"] = simple_train_df["建ぺい率(%)"].astype("int")
simple_train_df["容積率(%)"] = simple_train_df["容積率(%)"].astype("int")
print(simple_train_df)
市区町村コード 最寄駅:距離(分) 面積(㎡) 建ぺい率(%) 容積率(%) 取引価格(総額)_log
0 30201 45 45 80 300 6.875061
1 30201 8 75 80 400 7.397940
2 30201 6 75 80 400 6.880814
3 30201 29 60 80 300 6.869232
4 30201 9 65 80 400 7.255273
... ... ... ... ... ... ...
637346 41201 24 70 60 200 6.944483
637347 41201 6 65 80 400 7.000000
637348 41201 26 35 80 400 6.643453
637349 41201 28 15 80 400 6.431364
637350 41201 8 75 60 200 7.146128
[600296 rows x 6 columns]
simple_test_df = test_df[["市区町村コード", "最寄駅:距離(分)", "面積(㎡)", "建ぺい率(%)", "容積率(%)"]].dropna(how="any").copy()
simple_test_df["面積(㎡)"] = simple_test_df["面積(㎡)"].apply(lambda x: "2000" if x == "2000㎡以上" else x)
simple_test_df["面積(㎡)"] = simple_test_df["面積(㎡)"].astype("int")
simple_test_df["最寄駅:距離(分)"] = simple_test_df["最寄駅:距離(分)"].apply(lambda x: "45" if x == "30分?60分" else "75" if x == "1H?1H30" else "105" if x == "1H30?2H" else "120" if x == "2H?" else x)
simple_test_df["最寄駅:距離(分)"] = simple_test_df["最寄駅:距離(分)"].astype("int")
simple_test_df["建ぺい率(%)"] = simple_test_df["建ぺい率(%)"].astype("int")
simple_test_df["容積率(%)"] = simple_test_df["容積率(%)"].astype("int")
print(simple_test_df)
市区町村コード 最寄駅:距離(分) 面積(㎡) 建ぺい率(%) 容積率(%)
0 1101 26 75 40 60
1 1101 1 55 80 600
2 1101 2 15 80 400
3 1101 2 45 80 400
4 1101 3 20 80 400
... ... ... ... ... ...
19453 47201 16 75 60 200
19454 47201 16 15 60 200
19456 47201 11 65 60 200
19457 47208 45 60 60 200
19458 47208 6 55 60 150
[19032 rows x 5 columns]
作成したsimple_train_dfとsimple_test_dfを、simple_train.csvとsimple_test.csvのCSVファイルで保存して、ダウンロードします。
simple_train_df.to_csv(path_or_buf="data/Nishika_ApartmentPrice/simple_train.csv",
header=True,
index=False,
encoding="utf-8")
simple_test_df.to_csv(path_or_buf="data/Nishika_ApartmentPrice/simple_test.csv",
header=True,
index=False,
encoding="utf-8")
1.3. S3にデータを保存
S3バケットにフォルダを作成して、そのフォルダに先程作成したsimple_train.csvとsimple_test.csvを保存します。
1.4. SageMakerのドメインのCanvas権限を変更
今回扱うSageMakerのドメインで、「アプリケーション設定」の「Canvas」部分の「Canvas モデルの直接デプロイを有効にする」が有効かどうかを確認します。
これが無効だった場合は、有効に変更します。
まずは編集ボタンをクリックします。
画面が変わった後、こちらのトグルを切り替えます。
画面下部の送信ボタンをクリックします。
有効に変わりました。
準備は以上になります。
2. 実装
SageMaker Canvasを開きます。
2.1. Datasetsを作成
まずは、S3に保存しているsimple_train.csvをインポートします。
Datasetsをクリックします。
画面右上のImport dataボタンをクリックして、Tabularをクリックします。
dataset名を入力します。今回はtrain_data_ForQiitaを入力して、Createボタンをクリックします。
Select a data sourceでAmazon S3を選択します。
対象バケットの対象フォルダからsimple_train.csvを選択して、Preview datasetボタンをクリックします。
simple_train.csvのプレビュー画面が表示されます。画面右上のCreate datasetボタンをクリックします。
Datasetsの画面に戻ります。train_data_ForQiitaが新規に作成されました。
同様の作業を、S3に保存しているsimple_test.csvに対しても行います。
(dataset名はtest_data_ForQiitaにしました。)
2.2. モデルを作成
訓練(train)データを使って、モデルを作成します。
Datasetsの画面で、train_data_ForQiitaを選択して、画面右上のCreate a modelボタンをクリックします。
モデル名はmodel_ForQiitaにします。今回はアパート価格の予測なので、回帰のPredictive analysisを選択した後、画面右下のCreateボタンをクリックします。
Target columnで取引価格_総額(log)を選択します。画面右のStandard buildの横の三角ボタンをクリックして、Quick buildを選択した後、Quick buildボタンをクリックします。
データ型の検証などが行われた後、モデルの作成が始まります。
少し待つと、モデルが作成されました。
画面右のModel leaderboardの横の矢印ボタンをクリックすると、モデルに関する情報を確認出来ます。
一通り内容を確認したら、画面右上のPredictボタンをクリックします。
Batch predictionを選択した後、Manualボタンをクリックします。
テスト(test)データのDatasetsであるtest_data_ForQiitaを選択して、画面右下のGenerate predictionsボタンをクリックします。
画面が戻ります。戻った画面の下で推論ジョブが行われた事を確認出来ます。
画面を右にスクロールして、status欄の縦三点ボタンをクリックすると、推論ジョブの結果の扱い方を選べますので、まずはPreviewを選んでみます。
予測されたアパート価格(取引価格_総額(log))を確認出来ました。
次はDownloadを選んでみます。
csvファイルの形で予測結果をダウンロード出来ました。
2.3. モデルをデプロイ
モデルを作成出来たので、このモデルをデプロイしてみます。
画面上のタブをAnalyzeに切り替えます。
画面右のDeployボタンをクリックします。
(もし、クリック出来ない場合は、1.4.の作業でキチンと権限が有効になっている事を確認します。)
デプロイの設定画面が出てきます。今回はデプロイ名をdeployForQiita、インスタンスタイプをml.t2.medium、インスタンス数を1に設定して、Deployボタンをクリックします。
モデルのデプロイが始まります。
数分待つと、デプロイが完了しました。
2.4. リアルタイム推論を実験
デプロイしたモデルのエンドポイント(URL)へ、説明変数のデータを投げると、目的変数のアパート価格の予測結果が返ってくる事を確認してみます。
画面上のDeployタブで、対象のデプロイの画面右の縦三点ボタンをクリックして、View detailsを選択します。
対象のデプロイの詳細情報が表示されます。View sample codeの三角ボタンをクリックします。
デプロイしたモデルのエンドポイントを叩くための参考プログラムコードが表示されます。
これを参考にして、Notebookインスタンスから叩いてみます。
今回はSageMaker StudioのJupyterLabで試してみます。
import boto3
import pandas as pd
data1 = ["11111", "50", "12", "220", "65"]
data2 = ["22222", "100", "5", "250", "75"]
data3 = ["33333", "75", "8", "200", "60"]
client = boto3.client("runtime.sagemaker")
body = pd.DataFrame([data1, data2, data3]).to_csv(header=False, index=False).encode("utf-8")
response = client.invoke_endpoint(
EndpointName="canvas-deployForQiita",
ContentType="text/csv",
Body=body,
Accept="application/json"
)
結果を確認してみます。
print(response)
{'ResponseMetadata': {'RequestId': '70941f63-16ff-4277-a1d5-*****', 'HTTPStatusCode': 200, 'HTTPHeaders': {'x-amzn-requestid': '70941f63-16ff-4277-a1d5-*****', 'x-amzn-invoked-production-variant': 'canvas-model-variant-2024-07-11-02-00-56-194512', 'date': 'Thu, 11 Jul 2024 02:40:51 GMT', 'content-type': 'application/json', 'content-length': '107', 'connection': 'keep-alive'}, 'RetryAttempts': 0}, 'ContentType': 'application/json', 'InvokedProductionVariant': 'canvas-model-variant-2024-07-11-02-00-56-194512', 'Body': <botocore.response.StreamingBody object at 0x7f71e09*****>}
予測結果の確認は、readメソッドを使うみたいです。
print(response['Body'].read().decode('utf-8'))
{"predictions": [{"score": 6.932327747344971}, {"score": 6.297735214233398}, {"score": 6.183495998382568}]}
アパート価格の予測結果を取得出来ました。
2.5. 後片付け
デプロイしたモデルのエンドポイントを残し続けると、インスタンスが稼働し続けている状態になってしまうので、課金対象になってしまいます。そのため、デプロイしたモデルのエンドポイントを削除します。
SageMaker CanvasのMy Modelsから対象のモデルをクリックします。
Version欄のV1をクリックします。
画面上のDeployタブに切り替えて、対象のモデルのデプロイの画面右の縦三点ボタンをクリックして、Delete deploymentをクリックします。
Deleteボタンをクリックします。
デプロイしたモデルのエンドポイントが削除されました。
試しにJupyterLabで先程実験したコードを叩いてみると、想定通りエラーになります。
ValidationError: An error occurred (ValidationError) when calling the InvokeEndpoint operation: Endpoint canvas-deployForQiita of account ***** not found.
以上になります。
まとめ
SageMaker CanvasのGUI操作でモデルの自動作成からデプロイまでを行う事が出来ました。デプロイしたモデルのエンドポイントを使った推論も簡単に出来ましたので、データを用意さえすれば、簡単にモデルの作成からデプロイまで出来そうと思いました。
参考