「Amazon SageMakerを使用して、効率的にカスタムアンサンブルをトレーニング、チューニング、デプロイする」
Efficiently train, tune, and deploy custom ensembles using Amazon SageMaker.
人工知能(AI)は、技術コミュニティにおいて重要で人気のあるトピックとなっています。AIの進化とともに、さまざまなタイプの機械学習(ML)モデルが登場しています。アンサンブルモデリングというアプローチは、データサイエンティストや実践者の間で急速に注目を集めています。この記事では、アンサンブルモデルとは何か、なぜ使用すると有益なのかについて説明します。そして、Amazon SageMakerを使用してカスタムのアンサンブルをトレーニング、最適化、展開する方法の例を提供します。
アンサンブル学習は、複数の学習モデルやアルゴリズムを使用して、単一の学習アルゴリズムよりも正確な予測を行うことを指します。これらは、サイバーセキュリティ[1]や詐欺検出、リモートセンシング、金融の意思決定における最適な次のステップの予測、医学診断、さらにはコンピュータビジョンや自然言語処理(NLP)のタスクなど、さまざまなアプリケーションや学習環境で効率的であることが証明されています。アンサンブルは、それらをトレーニングするために使用される技術、構成、異なる予測を単一の推論に統合する方法に基づいて分類されます。これらのカテゴリには以下が含まれます:
- ブースティング – 弱い学習者を順次トレーニングし、前の学習者の誤った予測に対してより高い重みを与え、次の学習者への入力とします。これにより、より強力な学習者が作成されます。AdaBoost、Gradient Boosting、XGBoostなどがあります。
- バギング – 単一のモデルの分散を減らすために、複数のモデルを使用します。Random ForestやExtra Treesなどがあります。
- スタッキング(ブレンディング) – 通常、異種のモデルを使用し、各個別の推定器の予測を積み重ね、予測を処理する最終推定器の入力として使用します。この最終推定器のトレーニングプロセスでは、しばしば交差検証が使用されます。
モデルが最終的に生成する単一の予測に予測を組み合わせるための複数の方法があります。たとえば、分類タスクでは、線形学習者のようなメタ推定器、多数決に基づいて複数のモデルを使用して予測を行う投票方法、または回帰のためのアンサンブル平均化などを使用することができます。
XGBoost、CatBoost、またはscikit-learnのランダムフォレストなど、アンサンブルモデルの実装を提供するいくつかのライブラリやフレームワークがありますが、この記事では、専用のリソース(モデルごとの専用トレーニングや調整のジョブ、モデルごとのホスティングエンドポイント)を使用せずに、カスタムアンサンブル(複数のモデル)を単一のSageMakerトレーニングジョブと単一のチューニングジョブでトレーニング、最適化、展開する方法に焦点を当てます。これにより、コストと運用のオーバーヘッドを削減することができます。
BYOE: 独自のアンサンブルを持ち込む
SageMakerを使用して異種のアンサンブルモデルをトレーニングおよび展開する方法はいくつかあります:それぞれのモデルを個別のトレーニングジョブでトレーニングし、Amazon SageMakerの自動モデルチューニングを使用して各モデルを個別に最適化することができます。これらのモデルをホスティングする際には、SageMakerは同じテナントインフラストラクチャ上に複数のモデルをホストするためのさまざまなコスト効果の高い方法を提供します。このような設定の詳細な展開パターンについては、「Amazon SageMakerでのMLアプリケーションの一般的な設計パターン」のモデルホスティングパターンに関する記事で説明されています。これらのパターンには、複数のエンドポイント(各トレーニング済みモデル用)または単一のマルチモデルエンドポイント、または単一のマルチコンテナエンドポイントを使用する方法が含まれます。これらのソリューションは、各モデルを呼び出し、ブレンディングまたは投票機能を実装するメタ推定器(たとえばAWS Lambda関数内)を含みます。
ただし、複数のトレーニングジョブを実行すると、オペレーションとコストのオーバーヘッドが発生する場合があります。同様に、異なるモデルを別々のエンドポイントやコンテナにホストし、予測結果を組み合わせてより正確な結果を得るために複数の呼び出しが必要な場合、管理、コスト、モニタリングの労力が増えます。たとえば、SageMakerはTriton Inference Serverを使用したアンサンブルMLモデルをサポートしていますが、このソリューションでは、モデルやモデルアンサンブルがTritonバックエンドでサポートされている必要があります。さらに、お客様はTritonサーバーを設定し、さまざまなTritonバックエンドの動作を理解するために追加の努力が必要です。そのため、お客様は、エンドポイントに対して一度の呼び出しを送信し、結果を集約して最終出力を生成する方法をより簡単に実装できるようなソリューションを好むことが多いです。
ソリューションの概要
これらの懸念に対処するために、単一のトレーニングジョブを使用してアンサンブルのトレーニングを行い、モデルのハイパーパラメータを最適化し、単一のコンテナを使用してサーバーレスのエンドポイントに展開する例を紹介します。私たちは、アンサンブルスタック用に2つのモデル、CatBoostとXGBoost(いずれもブースティングアンサンブル)を使用します。データには、scikit-learnライブラリの糖尿病データセット[2]を使用します。このデータセットには10の特徴量(年齢、性別、体重指数、血圧、6つの血清測定値)が含まれており、モデルはベースライン特徴量が収集された後の1年後の病気の進行を予測します(回帰モデル)。
完全なコードリポジトリはGitHubで見つけることができます。
SageMakerの単一のジョブで複数のモデルをトレーニングする
モデルのトレーニングには、ScriptモードでSageMakerのトレーニングジョブを使用しています。 Scriptモードでは、SageMakerフレームワークコンテナを使用しながら、カスタムのトレーニング(および後の推論コード)を書くことができます。フレームワークコンテナを使用すると、AWSによって管理される必要な構成やモジュールが含まれた準備済みの環境を使用できます。フレームワークコンテナをカスタマイズする方法をデモンストレーションするために、XGBoostとCatBoostパッケージが含まれていない事前にビルドされたSKLearnコンテナを使用しています。これらのパッケージを追加するには、ビルトインコンテナを拡張してCatBoostとXGBoostをインストールする(その後、カスタムコンテナとしてデプロイする)か、SageMakerのトレーニングジョブスクリプトモード機能を使用して、トレーニングエスティメータを作成する際にrequirements.txt
ファイルを指定する方法があります。 SageMakerトレーニングジョブは、requirements.txt
ファイルにリストされたライブラリを実行時にインストールします。これにより、独自のDockerイメージリポジトリを管理する必要がなくなり、追加のPythonパッケージが必要なトレーニングスクリプトを実行する際に柔軟性が向上します。
次のコードブロックは、トレーニングを開始するために使用するコードを示しています。 entry_point
パラメータは、トレーニングスクリプトを指すものです。また、SageMaker SDK APIの2つの魅力的な機能も使用しています:
- まず、
source_dir
パラメータとdependencies
パラメータにソースディレクトリと依存関係のローカルパスを指定します。SDKはこれらのディレクトリを圧縮してAmazon Simple Storage Service(Amazon S3)にアップロードし、SageMakerはトレーニングインスタンスの作業ディレクトリ/opt/ml/code
でそれらを利用できるようにします。 - 次に、SDKの
SKLearn
エスティメータオブジェクトを使用して、好ましいPythonおよびフレームワークバージョンでSageMakerが対応するコンテナを取得します。また、トレーニングログに出力され、SageMakerによってキャプチャされるカスタムトレーニングメトリック「validation:rmse
」を定義しています。後で、このメトリックをチューニングジョブの目標メトリックとして使用します。
hyperparameters = {"num_round": 6, "max_depth": 5}
estimator_parameters = {
"entry_point": "multi_model_hpo.py",
"source_dir": "code",
"dependencies": ["my_custom_library"],
"instance_type": training_instance_type,
"instance_count": 1,
"hyperparameters": hyperparameters,
"role": role,
"base_job_name": "xgboost-model",
"framework_version": "1.0-1",
"keep_alive_period_in_seconds": 60,
"metric_definitions":[
{'Name': 'validation:rmse', 'Regex': 'validation-rmse:(.*?);'}
]
}
estimator = SKLearn(**estimator_parameters)
次に、トレーニングスクリプト(multi_model_hpo.py)を作成します。スクリプトは次の単純なフローに従います:ジョブが構成されたハイパーパラメータをキャプチャし、CatBoostモデルとXGBoostモデルをトレーニングします。また、k-foldクロスバリデーション関数も実装しています。次のコードを参照してください:
if __name__ == "__main__":
parser = argparse.ArgumentParser()
# Sagemaker specific arguments. Defaults are set in the environment variables.
parser.add_argument("--output-data-dir", type=str, default=os.environ["SM_OUTPUT_DATA_DIR"])
parser.add_argument("--model-dir", type=str, default=os.environ["SM_MODEL_DIR"])
parser.add_argument("--train", type=str, default=os.environ["SM_CHANNEL_TRAIN"])
parser.add_argument("--validation", type=str, default=os.environ["SM_CHANNEL_VALIDATION"])
.
.
.
"""
Train catboost
"""
K = args.k_fold
catboost_hyperparameters = {
"max_depth": args.max_depth,
"eta": args.eta,
}
rmse_list, model_catboost = cross_validation_catboost(train_df, K, catboost_hyperparameters)
.
.
.
"""
Train the XGBoost model
"""
hyperparameters = {
"max_depth": args.max_depth,
"eta": args.eta,
"objective": args.objective,
"num_round": args.num_round,
}
rmse_list, model_xgb = cross_validation(train_df, K, hyperparameters)
モデルのトレーニングが完了した後、CatBoostとXGBoostの予測の平均値を計算します。結果はpred_mean
となり、アンサンブルの最終予測となります。その後、検証セットに対するmean_squared_error
を計算します。val_rmse
はトレーニング中のアンサンブル全体の評価に使用されます。注意してくださいが、metric_definitions
で使用した正規表現に適合する形式でRMSEの値も表示されます。後に、SageMaker Automatic Model Tuningがその目的のメトリックを取得するために使用します。以下のコードを参照してください:
pred_mean = np.mean(np.array([pred_catboost, pred_xgb]), axis=0)
val_rmse = mean_squared_error(y_validation, pred_mean, squared=False)
print(f"最終評価結果:validation-rmse:{val_rmse}")
最後に、スクリプトはモデルのアーティファクトを/opt/ml/model
に保存します。
トレーニングジョブが完了すると、SageMakerはジョブの設定で指定したS3の場所に、/opt/ml/model
ディレクトリの内容を圧縮されたTAR形式の単一オブジェクトとしてパッケージ化してコピーします。この場合、SageMakerは2つのモデルをTARファイルにまとめてトレーニングジョブの最後にそれをAmazon S3にアップロードします。以下のコードを参照してください:
model_file_name = 'catboost-regressor-model.dump'
# CatBoostモデルを保存
path = os.path.join(args.model_dir, model_file_name)
print('モデルファイルを保存先に保存中: {}'.format(path))
model.save_model(path)
.
.
.
# XGBoostモデルを保存
model_location = args.model_dir + "/xgboost-model"
pickle.dump(model, open(model_location, "wb"))
logging.info("トレーニングされたモデルを保存先に格納しました: {}".format(model_location))
要約すると、この手順ではデータを1回ダウンロードし、1つのトレーニングジョブで2つのモデルをトレーニングしています。
自動アンサンブルモデルのチューニング
MLモデルのコレクションを構築するため、すべての可能なハイパーパラメータの組み合わせを探索することは現実的ではありません。 SageMakerでは、指定した範囲内の最も有望な値の組み合わせに焦点を当てて、最適なモデルハイパーパラメータを探索するAutomatic Model Tuning(AMT)が提供されています(探索するための適切な範囲を定義するのはあなた次第です)。 SageMakerでは、選択できる複数の最適化方法がサポートされています。
最初に、最適化プロセスの2つの部分(目的のメトリックとチューニングしたいハイパーパラメータ)を定義します。この例では、検証RMSEをターゲットメトリックとして使用し、eta
とmax_depth
をチューニングします(他のハイパーパラメータについては、XGBoost HyperparametersおよびCatBoost hyperparametersを参照してください):
from sagemaker.tuner import (
IntegerParameter,
ContinuousParameter,
HyperparameterTuner,
)
hyperparameter_ranges = {
"eta": ContinuousParameter(0.2, 0.3),
"max_depth": IntegerParameter(3, 4)
}
metric_definitions = [{"Name": "validation:rmse", "Regex": "validation-rmse:([0-9\\.]+)"}]
objective_metric_name = "validation:rmse"
また、トレーニングスクリプトでハイパーパラメータがハードコードされていないことを確認する必要もあります。これらはSageMakerランタイム引数から取得されます:
catboost_hyperparameters = {
"max_depth": args.max_depth,
"eta": args.eta,
}
SageMakerはまた、ハイパーパラメータをJSONファイルに書き込み、トレーニングインスタンスの/opt/ml/input/config/hyperparameters.json
から読み取ることもできます。
CatBoostの場合と同様に、XGBoostモデルのハイパーパラメータもキャプチャします(objective
とnum_round
はチューニングされません):
catboost_hyperparameters = {
"max_depth": args.max_depth,
"eta": args.eta,
}
最後に、これらの設定を使用してハイパーパラメータチューニングジョブを開始します:
tuner = HyperparameterTuner(
estimator,
objective_metric_name,
hyperparameter_ranges,
max_jobs=4,
max_parallel_jobs=2,
objective_type='Minimize'
)
tuner.fit({"train": train_location, "validation": validation_location}, include_cls_metadata=False)
ジョブが完了したら、最良のトレーニングジョブ(最小RMSE)の値を取得できます:
job_name=tuner.latest_tuning_job.name
attached_tuner = HyperparameterTuner.attach(job_name)
attached_tuner.describe()["BestTrainingJob"]
AMTの詳細については、「SageMakerを使用した自動モデルチューニングの実行」を参照してください。
デプロイ
カスタムアンサンブルをデプロイするには、推論リクエストを処理するスクリプトとSageMakerホスティングを構成する必要があります。この例では、トレーニングと推論のコードを含む単一のファイル(multi_model_hpo.py)を使用しました。SageMakerは、_ main _ == "_ main _"
の下にあるコードをトレーニングに使用し、model_fn
、input_fn
、およびpredict_fn
の関数をモデルのデプロイとサービングに使用します。
推論スクリプト
トレーニングと同様に、独自の推論スクリプトを使用してSageMaker SKLearnフレームワークコンテナを使用します。スクリプトは、SageMakerで必要な3つのメソッドを実装します。
まず、model_fn
メソッドは保存されたモデルアーティファクトファイルを読み込んでメモリにロードします。この例では、メソッドはall_model
というPythonリストとしてアンサンブルを返しますが、モデル名をキーとする辞書を使用することもできます。
def model_fn(model_dir):
catboost_model = CatBoostRegressor()
catboost_model.load_model(os.path.join(model_dir, model_file_name))
model_file = "xgboost-model"
model = pickle.load(open(os.path.join(model_dir, model_file), "rb"))
all_model = [catboost_model, model]
return all_model
次に、input_fn
メソッドはリクエストの入力データを逆シリアル化して推論ハンドラに渡します。入力ハンドラについての詳細は、「独自の推論コンテナの適応」を参照してください。
def input_fn(input_data, content_type):
dtype=None
payload = StringIO(input_data)
return np.genfromtxt(payload, dtype=dtype, delimiter=",")
最後に、predict_fn
メソッドはモデルから予測を取得する責任を持ちます。このメソッドは、input_fn
から返されたモデルとデータをパラメータとして受け取り、最終的な予測を返します。この例では、モデルリストの最初のメンバー(model[0]
)からCatBoostの結果を取得し、2番目のメンバー(model[1]
)からXGBoostの結果を取得し、両方の予測の平均値を返すブレンディング関数を使用しています。
def predict_fn(input_data, model):
predictions_catb = model[0].predict(input_data)
dtest = xgb.DMatrix(input_data)
predictions_xgb = model[1].predict(dtest,
ntree_limit=getattr(model, "best_ntree_limit", 0),
validate_features=False)
return np.mean(np.array([predictions_catb, predictions_xgb]), axis=0)
トレーニング済みのモデルと推論スクリプトが用意できたので、アンサンブルをデプロイするための環境を構成できます。
SageMakerサーバーレス推論
SageMakerには多くのホスティングオプションがありますが、この例ではサーバーレスエンドポイントを使用します。サーバーレスエンドポイントは、トラフィックに応じて自動的にコンピューティングリソースを起動し、スケールインおよびスケールアウトします。これにより、サーバーの管理にかかる負荷を軽減できます。このオプションは、トラフィックが急増する間にアイドル期間があるワークロードや、コールドスタートを許容できるワークロードに最適です。
サーバーレスエンドポイントの構成は簡単です。インスタンスタイプを選択したり、スケーリングポリシーを管理したりする必要はありません。2つのパラメーターを提供するだけです:メモリサイズと最大同時実行数です。サーバーレスエンドポイントは、選択したメモリに比例してコンピューティングリソースを割り当てます。メモリサイズを大きく選択すると、コンテナにより多くのvCPUが割り当てられます。常にモデルのサイズに応じてエンドポイントのメモリサイズを選択する必要があります。提供する必要がある2番目のパラメーターは、最大同時実行数です。単一のエンドポイントでは、このパラメーターを最大200まで設定できます(現在のところ、リージョンごとのサーバーレスエンドポイントの合計数の制限は50です)。個々のエンドポイントの最大同時実行数は、アカウントで許可されている呼び出しのすべてを占有しないようにします。なぜなら、最大同時実行数を超えるエンドポイントの呼び出しは制限されるからです(リージョンごとのすべてのサーバーレスエンドポイントの合計同時実行数についての詳細は、Amazon SageMakerエンドポイントとクオータを参照してください)。
from sagemaker.serverless.serverless_inference_config import ServerlessInferenceConfig
serverless_config = ServerlessInferenceConfig(
memory_size_in_mb=6144,
max_concurrency=1,
)
エンドポイントを設定したので、ハイパーパラメータ最適化ジョブで選択されたモデルを最終的にデプロイできます:
estimator=attached_tuner.best_estimator()
predictor = estimator.deploy(serverless_inference_config=serverless_config)
クリーンアップ
サーバーレスエンドポイントは使用されていない場合にはコストがかからないものの、この例の実行が終了したらエンドポイントを削除する必要があります:
predictor.delete_endpoint(predictor.endpoint)
結論
この記事では、カスタムアンサンブルのトレーニング、最適化、デプロイのアプローチについて説明しました。複数のモデルをトレーニングするための単一のトレーニングジョブのプロセス、アンサンブルハイパーパラメータを最適化する自動モデルチューニングの使用方法、および複数のモデルからの推論をブレンドする単一のサーバーレスエンドポイントをデプロイする方法について詳細に説明しました。
この方法を使用することで、コストと運用上の問題を解決できます。トレーニングジョブのコストは使用するリソースの使用時間に基づいています。2つのモデルのトレーニングにはデータを1回だけダウンロードするため、ジョブのデータダウンロードフェーズとデータを保存するボリュームの使用量を半分に減らすことができ、トレーニングジョブの総コストを削減できます。さらに、AMTジョブでは前述の時間とストレージの削減が4回行われたため、コストの節約は4倍になります!サーバーレスエンドポイントへのモデルデプロイに関しては、処理するデータ量に対しても支払いが発生するため、2つのモデルに対してエンドポイントを1回だけ呼び出すことで、I/Oデータの料金の半分しか支払う必要はありません。
この記事では2つのモデルの利点のみを示しましたが、この方法を使用して多数のアンサンブルモデルをトレーニング、チューニング、およびデプロイすることで、さらなる効果を得ることができます。
参考文献
[1] Raj Kumar, P. Arun; Selvakumar, S. (2011). “Distributed denial of service attack detection using an ensemble of neural classifier”. Computer Communications. 34 (11): 1328–1341. doi:10.1016/j.comcom.2011.01.012.
[2] Bradley Efron, Trevor Hastie, Iain Johnstone and Robert Tibshirani (2004) “Least Angle Regression,” Annals of Statistics (with discussion), 407-499. (https://web.stanford.edu/~hastie/Papers/LARS/LeastAngle_2002.pdf)
We will continue to update VoAGI; if you have any questions or suggestions, please contact us!
Was this article helpful?
93 out of 132 found this helpful
Related articles