Amazon SageMakerのハンズオンを通してAmazon SageMaker AIでデータの準備からモデルのチューニングまでやってみた
お疲れさまです。とーちです。
AWS Machine Learning Associate (MLA) の取得を目指すにあたり、どういった勉強をすればいいか調べている際にSageMaker Immersion Dayというハンズオンが良いという記事を見かけました。
sagemakerはほとんど触ったことがなかったので興味もあり、せっかくなのでこちらのハンズオンをやってみることにしました。
SageMaker Immersion Dayはラボ1〜ラボ9まであり、ラボ1とラボ2でデータの準備から機械学習モデルのトレーニング、またデプロイまでが完了する形になっています。またラボ1、ラボ2はそれぞれ複数の手段のハンズオンが用意されています。
この記事では上記のうちの「ラボ1オプション3」と「ラボ2オプション1」にあたる、SageMakerProcessingを使ってデータを準備し、SageMaker Studioノートブックを使ってモデルのトレーニング、デプロイまでを行ってみます
ちなみにこのハンズオンでは、顧客が定期預金 (CD) に加入するかどうかを予測する機械学習モデルを開発 します。
ハンズオン実施、その前に
ハンズオンを始める前に気になるのが料金ですよね。実施前にSageMakerの料金を確認してみましょう。
今回の記事の範囲で使用するサービスとその料金は以下のとおりです(2025/2/2時点、東京リージョン):
Amazon SageMaker Studio JupyterLab
SageMaker StudioでJupyterLabアプリケーションを使用するとかかってくる料金です
- インスタンス料金(起動時間ベース)
- インスタンスタイプごとに料金は異なる
- 今回使用したml.t3.mediumだと:USD 0.065/時間
- ストレージ料金
- 使用した容量(GB)に対して課金
- USD 0.1344/GB-月
Amazon SageMaker Processing
- インスタンス料金(起動時間ベース)
- インスタンスタイプごとに料金は異なる
- ml.m5.largeの場合:USD 0.149/時間
- ストレージ料金
- 使用した容量(GB)に対して課金
- USD 0.12/GB-月
Amazon SageMaker トレーニング
モデルのトレーニングをする際にかかってくる料金です。自動パラメータチューニングは裏側でトレーニングジョブが複数起動されるので、自動パラメータチューニングもこちらの料金が適用されると思われます。
- インスタンス料金(起動時間ベース)
- インスタンスタイプごとに料金は異なる
- ml.m4.xlargeの場合:USD 0.31/時間
- ストレージ料金
- 使用した容量(GB)に対して課金
- USD 0.168/GB-月
Amazon SageMaker ホスティング: リアルタイム推論
モデルをデプロイするとエンドポイントとして使用できますが、そのエンドポイントが起動している間、課金される料金となります。
- インスタンス料金(起動時間ベース)
- インスタンスタイプごとに料金は異なる
- ml.m4.xlargeの場合:USD 0.31/時間
- ストレージ料金
- 使用した容量(GB)に対して課金
- USD 0.168/GB-月
- データ処理料金
- 処理されたデータ (IN):USD 0.016/GB
- 処理されたデータ (OUT):USD 0.016/GB
ハンズオン環境の準備
まずはAmazon SageMaker Studio JupyterLabの環境を準備します。この記事ではドメインの作成手順は割愛し、ドメインが作成済みの状態から説明させていただきます。なお今回は料金節約のためオレゴンリージョンで実施してみました。
- まずはマネージメントコンソールからSageMakerAIの画面にいき、SageMaker Studioを開きましょう
- こんな感じのかっこいい画面が出てくるのでJupyterLabをクリックして、
Create JupyterLab space
のボタンを押します - 適当な名前をつけてCreate spaceを押しましょう
- するとこんなかんじでインスタンスのスペックなどを選ぶ画面がでてきます。ハンズオンの画面上、Storageサイズが20GBになっていたのでそこだけ変えてみました。ml.t3.mediumになってることを確認してRun spaceを押せばJupyterノートブックにアクセスできるようになります
- JupyterLabに入ったら、ハンズオン用コンテンツがあるGitリポジトリからcloneすればハンズオンの準備は完了です。
ラボ1:特徴量エンジニアリング
ラボ1では機械学習のプロセスにおける以下の部分を行います
※画像はSageMaker Immersion Dayより
具体的にはSageMaker Processingを使って、トレーニングデータの作成を行っていきます。
そもそもSageMaker Processingとはというところについては以下のブログで詳しく解説されていますが、ざっくりいうと機械学習のための前処理や後処理を実行するためのマネージドサービスとなっています。今回はこれを使ってトレーニングデータの作成を行います。
このラボでは画像のようなイメージでs3においてあるファイルを読み込みSageMaker Processingで処理したあとS3に出力します
※画像はSageMaker Immersion Dayより
実体としてはコンテナ実行環境がSageMakerProcessingにより提供されるようですね。コンテナイメージとしてはSageMakerにより事前に用意されているものやカスタムイメージも使えるようです
ハンズオンを進めてみる
それではハンズオンを進めてみます。JupyterLabアプリで実行していきます。
「ハンズオン環境の準備」でcloneしてきたamazon-sagemaker-immersion-day/feature-engineering/processing_xgboost.ipynb
のファイルをJupyterLab上で開きます
cmd+Enterでどんどんコードを実行していきます。なお、本記事ではコードの詳細は割愛しています。完全なコードについては、実際のハンズオンでご確認ください。
S3バケットへのデータのアップロード
まずは整形元となるデータをS3バケットにアップロードしています。
JupyterLabのノートブックの最初のほうで以下のようにbucketとprefixを定義しています。SageMakerのデフォルトバケットにある sagemaker/DEMO-xgboost-dm
というパスに結果を格納するようですね。
import sagemaker
bucket = sagemaker.Session().default_bucket()
prefix = 'sagemaker/DEMO-xgboost-dm'
ちなみに default_bucket
メソッドでは指定がない場合、“sagemaker-{region}-{aws-account-id}"のフォーマットでs3バケットが決定されます。ご参考
整形元となるデータは「ハンズオン環境の準備」でcloneしてきた中に含まれています。そのデータを以下の行でs3にアップロードしてるわけですね。
input_source = sess.upload_data('./bank-additional/bank-additional-full.csv', bucket=bucket, key_prefix=f'{prefix}/input_data')
前処理スクリプトの作成
%%writefile preprocessing.py
でpythonファイルをJupyterLabアプリ内ローカルに書き込めます。preprocessing.pyがSageMaker Processingにより実行されるコードになります。
スクリプトの中身まではちゃんと読み込めてませんが、不要な列の削除やデータをランダムに並び変えたうえでトレーニングデータと検証データに分割といった処理等を行っているようです。
SageMaker Processing実行
肝心のSageMakerProcessingを起動する処理が上記の部分ですね。
SageMaker Processingの実行はsklearn_processorオブジェクトを通じて行います。インスタンス化時にインスタンスタイプと数を指定し、runメソッドで処理を実行します。runメソッドには、前処理用のpreprocessing.pyをcode引数で指定し、入力データのパス(/opt/ml/processing/input)と3種類の出力先を定義します
- トレーニングデータの出力(train_data):機械学習モデルのトレーニングに使用するデータで、コンテナ内の
/opt/ml/processing/output/train
に出力されたデータをS3バケット(パス末尾がtrain)に出力するように指定しています。 - 検証用データの出力(validation_data): 機械学習モデルのトレーニング中の検証に使用するデータで、コンテナ内、
/opt/ml/processing/output/validation
に出力されたデータをS3バケット(パス末尾がvalidation)に出力するように指定しています。 - テスト用データの出力(test_data):機械学習モデルデプロイ後にテストのために使用されるデータで、コンテナ内、
/opt/ml/processing/output/test
に出力されたデータをS3バケット(パス末尾がtest)に出力するように指定しています。
ラボ1の最後のステップではs3に処理済みデータが格納されたことを確認しています
ラボ2:学習、調整、デプロイ
ラボ2では機械学習のプロセスにおける以下の部分を行います
※画像はSageMaker Immersion Dayより
具体的にはSageMakerAIで機械学習モデルのトレーニングとデプロイをしていきます。
ラボ2のオプション 1では引き続きラボ1と同じファイル amazon-sagemaker-immersion-day/feature-engineering/processing_xgboost.ipynb
を使って続きのステップを実行していきます。
モデルのトレーニング
トレーニングには機械学習アルゴリズムの1つであるXGBoostを使用します。
まずはXGBoostを使用するためのコンテナイメージのURIを取得します。以下のコードで取得できます。
container = sagemaker.image_uris.retrieve(
region=boto3.Session().region_name,
framework='xgboost',
version='latest'
)
取得されるURIは以下のような形式になります。
433757028032.dkr.ecr.us-west-2.amazonaws.com/xgboost:latest
なお、URIに含まれる433757028032
はAWS管理のアカウントIDです。このURIはAWS公式ドキュメントでも確認できます。
次に、ラボ1で作成したデータのパスを指定します。具体的には以下の2つのパスを設定しています
s3_input_train
:モデルの学習に使用するデータセットのパスs3_input_validation
:モデルの性能評価に使用するデータセットのパス
これらのデータセットは、モデルのトレーニングをする際に合わせて指定する形になります。
モデルのデプロイ
続いて、モデルのトレーニングを行います。トレーニング自体は以下のような短いコードだけでできてしまうんですね。
おおまかに流れを説明すると以下のようなことをやっています。
sagemaker.estimator.Estimator
でトレーニングするためのインスタンスタイプや数、アウトプットパス(トレーニング結果を保存するs3)などを定義したEstimatorオブジェクトをインスタンス化(ご参考)xgb.set_hyperparameters
でXGBoostアルゴリズムのハイパーパラメータ(学習率、決定木の深さ等)を設定xgb.fit
でトレーニングデータと検証データを指定して、モデルの学習を実施
sageMakerコンソール画面からも機械学習モデルをトレーニングした履歴が確認できますね。
estimatorで指定したoutputにモデルアーティファクトを出力していることが確認できます。
続いてトレーニングしたモデルをデプロイしていきます。デプロイは以下の行だけでできます。
マネージメントコンソールの方でもエンドポイントが作成されたことが確認できますね。
モデルの評価
冒頭でも説明したようにこのハンズオンでは、顧客が定期預金 (CD) に加入するかどうかを予測する機械学習モデルを作っています。最終的に予測する値は定期預金に加入するかしないかの2択です。
今回はモデルの評価に混同行列を使います。混同行列は予測結果の正確性を評価するための表で、以下のような形式で表されます
実際\予測 | 加入 | 非加入 |
---|---|---|
加入 | TP | FN |
非加入 | FP | TN |
各要素の説明は以下の通りです。
- TP(True Positive):実際に加入した顧客を正しく「加入する」と予測
- TN(True Negative):実際に加入しなかった顧客を正しく「加入しない」と予測
- FP(False Positive):加入しなかった顧客を誤って「加入する」と予測
- FN(False Negative):加入した顧客を誤って「加入しない」と予測
モデルの性能を評価するため、作成したSageMakerエンドポイントを使って予測を行い、その結果から混同行列を作成していきます。以下が予測処理を行うコードです。
ここの部分がなかなか理解しづらかったので説明していきます。
シリアライザーの設定
まず注目すべきは、xgb_predictor
に対するシリアライザーの設定です。XGBoostアルゴリズムはCSV形式の入力を要求するため、この設定が必要になります。
このシリアライザーについて自分はSageMakerエンドポイント側の設定だと勘違いしていたのですが、正確にはPredictorオブジェクト(xgb_predictor)がエンドポイントと通信する際のデータ変換方法を定義するものなので、シリアライズ処理(CSV形式への変換)が実際に実行されるのは今回でいうとJupyterLabのノートブック内ということになります。
予測用関数の実装
次にpredict
関数を実装しています。この関数は以下の3つの引数を受け取ります:
data
:予測対象のデータ(numpy配列)predictor
:デプロイされたモデルrows
:1回の予測処理行数(デフォルト500)
この関数は受け取ったデータを500行ごとに分割し、SageMakerエンドポイントで予測を行った後、結果を結合して返します。予測時にはpredictor.predict(array).decode('utf-8')
でnumpy配列をCSVに変換したうえでSageMakerエンドポイントに予測させています。
predict関数を呼び出す前にtest_xという変数にローカルに持ってきたテスト用データ(CSV形式)を読み込んでいるのですが、このとき pd.read_csv
によりCSVファイルをPandas DataFrameという形式で読み込んでいます。
predict関数を呼び出す際にpredict(test_x.to_numpy(), xgb_predictor)
to_numpyでnumpy配列に変換してpredict関数に渡しているようです。
最終的にSageMakerエンドポイントに予測させたデータ(predictions
)とtest_yに入っている正解データをpd.crosstab
で突き合わせることで、混同行列を作成しています。
まとめるとこんな感じです。
データの流れ
- S3からテストデータ(CSV)をローカルに取得
- Pandas DataFrameとして読み込み
- numpy配列に変換してpredict関数に渡す
- 予測結果と正解データを
pd.crosstab
で突き合わせ
実際に作成された混同行列が以下になります。
predictionsが予想値、actualsが正解の値です。加入が1、非加入が0で表されており、例えば右上は非加入と予測して、実際に非加入(True Negative)だった人が3584人であることを示しています。左上は加入と予測したけど実際には非加入(False Positive)の人数が51人だったことを表していますね。
自動モデルチューニング
自動モデルチューニング(ハイパーパラメータチューニング)をやってみます。
自動モデルチューニングでは、指定したアルゴリズムとハイパーパラメータの範囲を使用して、データセットに対して多数の学習ジョブを実行することで、最適なハイパーパラメータの値を見つけるといったことをやっています。
また自動モデルチューニングする際には改善対象となるメトリクスを指定する必要があります。このラボでは、曲線下面積 (AUC)を最大化させることを目標としてハイパーパラメータチューニングを行っています。曲線下面積 (AUC)とはざっくりいうと予測モデルの正確さを0から1の数値で表す指標のことです。(1に近づくほど予測が正確)
これらの設定を行っているのがコードの以下の部分です。
hyperparameter_rangesにハイパーパラメータの範囲、objective_metric_nameに曲線下面積 (AUC)をメトリックとしてチューニングすることが指定されています。実際のチューニングは HyperparameterTuner
オブジェクトをインスタンス化した後に fit
メソッドで行うようですね。トレーニングは10分ほどかかりました。
自動モデルチューニングの結果はマネージメントコンソール上でも確認できます。
自動モデルチューニングしたモデルのエンドポイントを使用し、predict関数で再度テストを行い、混同行列を作成してみます。
結果は以下のようになりました。微妙に性能が上がりましたね。
- 事前
- 事後
注意点
- 不要なコストを避けるため、使用後は必ずエンドポイントを削除しましょう
- JupyterLab Spaceも使用しない時は停止することをお勧めします
- 再開時はノートブックの状態が初期化されるので、必要なインポート文から実行し直す必要があります
まとめ
SageMaker Immersion Dayを通じて、SageMaker Processingを使ったデータ処理から、モデルのトレーニング、デプロイまでの一連の流れを学ぶことができました。特に印象的だったのは、複雑な機械学習のワークフローが比較的シンプルなコードで実現できる点です。
以上、とーちでした。