Amazon SageMakerの自動モデルチューニングを使用して、事前に選択されたアルゴリズムを使用してカスタムのAutoMLジョブを実装します

「Amazon SageMakerの自動モデルチューニングを駆使し、カスタムのAutoMLジョブを実現するための事前選択アルゴリズムの活用方法」

AutoML(自動機械学習)は、機械学習(ML)プロジェクトのライフサイクルの初めからデータから迅速で一般的な洞察を導き出すことができます。前もって最も良い結果を提供する前処理技術やアルゴリズムの種類を理解することで、適切なモデルの開発、トレーニング、展開にかかる時間を削減することができます。それはすべてのモデルの開発プロセスで重要な役割を果たし、データサイエンティストたちは最も有望なML技術に注力することができます。さらに、AutoMLはデータサイエンスチームの参考点となるベースラインのモデルのパフォーマンスを提供します。

AutoMLツールは、さまざまなアルゴリズムとさまざまな前処理技術の組み合わせをデータに適用します。たとえば、データのスケーリングや単変量特徴選択、異なる分散閾値レベルでのPCAの実行、クラスタリングの適用などがあります。このような前処理技術は個別に適用されることもあり、またはパイプラインで組み合わせられることもあります。その後、AutoMLツールは事前処理されたデータセットのさまざまなバージョン上で、線形回帰、Elastic-Net、またはランダムフォレストなどのさまざまなモデルタイプをトレーニングし、ハイパーパラメータの最適化(HPO)を実行します。Amazon SageMaker Autopilotは、MLモデルの構築の手間を軽減します。データセットを提供した後、SageMaker Autopilotは最適なモデルを見つけるために異なる解決策を自動的に試行します。しかし、AutoMLワークフローのカスタムバージョンを展開したい場合はどうなるでしょうか?

この投稿では、Amazon SageMakerでカスタムなAutoMLワークフローを作成する方法を紹介します。それには、Amazon SageMaker Automatic Model Tuningを使用し、GitHubリポジトリで利用可能なサンプルコードを使用します。

ソリューションの概要

このユースケースでは、専門的な領域でモデルを開発するデータサイエンスチームの一員であることを想定します。カスタムな前処理技術を開発し、MLの問題に適切に機能すると考えられるいくつかのアルゴリズムを選択しました。新しいMLユースケースに取り組む際には、まず、前処理技術とアルゴリズムを使用したAutoMLの実行を行い、潜在的な解決策の範囲を絞り込むことを望んでいます。

この例では、専門的なデータセットを使用せず、代わりにAmazon Simple Storage Service(Amazon S3)からインポートするCalifornia Housingデータセットを使用します。重点は、SageMaker HPOを使用したソリューションの技術的な実装をデモンストレーションすることであり、後で任意のデータセットとドメインに適用できます。

次の図は、全体的なソリューションのワークフローを示しています。

ワークスルーのセクションで説明されるステップを示すアーキテクチャダイアグラム。

前提条件

この記事のワークスルーを完了するための前提条件は次のとおりです:

ソリューションの実装

完全なコードはGitHubリポジトリで利用できます。

(ワークフローダイアグラムで注記されているように)ソリューションを実装するための手順は次のとおりです:

  1. ノートブックインスタンス を作成し、以下を指定します:
    1. ノートブックインスタンスタイプとして、ml.t3.mediumを選択します。
    2. Elastic Inferenceとして、noneを選択します。
    3. プラットフォーム識別子として、Amazon Linux 2、Jupyter Lab 3を選択します。
    4. IAMロールとして、デフォルトの AmazonSageMaker-ExecutionRole を選択します。存在しない場合は、新しい AWS Identity and Access Management (IAM) ロールを作成し、AmazonSageMakerFullAccess IAMポリシーをアタッチします。

製品では、最小限のスコープの実行ロールとポリシーを作成する必要があることに注意してください。

  1. ノートブックインスタンスの JupyterLab インターフェースを開き、GitHub リポジトリをクローンします。

新しいターミナルセッションを開始して git clone <REPO> コマンドを実行するか、以下のスクリーンショットに示すように UI 機能を使用して行うことができます。

JupyterLab git integration button

  1. automl.ipynb ノートブックファイルを開き、conda_python3 カーネルを選択し、一連の HPO ジョブ をトリガーするための手順に従います。

コードを変更せずに実行するには、トレーニングジョブの使用に対する ml.m5.large のサービスクォータすべてのトレーニングジョブのインスタンス数のクォータを増やす必要があります。AWSでは、デフォルトでSageMakerの並行トレーニングジョブは20個までしか許可されません。両方のクォータを30に増やすためにクォータの増加をリクエストする必要があります。通常、両方のクォータの変更は数分以内に承認されます。詳細については、クォータの増加をリクエストする を参照してください。

AWS Service Quotas page allowing to request an increase in particular instance type parallel training jobs

クォータを変更したくない場合は、スクリプト内の MAX_PARALLEL_JOBS 変数の値を変更するだけで済みます(たとえば、5に変更)。

  1. 各 HPO ジョブは一連のトレーニングジョブトライアルを完了し、最適なハイパーパラメータを持つモデルを示します。
  2. 結果を分析し、最も良いパフォーミングモデルをデプロイします。

このソリューションには、AWS アカウントでの費用がかかります。このソリューションの費用は、HPO トレーニングジョブの数と期間によって異なります。これらが増えると、費用も増加します。トレーニング時間を制限し、後述する手順に従って TuningJobCompletionCriteriaConfig を設定することで、コストを削減することができます。価格情報については、Amazon SageMaker の価格 を参照してください。

以下では、コードの例や結果の分析手法、最適なモデルの選択手法について、ノートブックを詳しく解説します。

初期設定

始めに、custom-automl.ipynbノートブックでImports & Setupセクションを実行しましょう。このセクションでは、必要な依存関係をインストールし、インポートし、SageMakerセッションとクライアントをインスタンス化し、デフォルトのリージョンとS3バケットを設定します。

データの準備

California Housingデータセットをダウンロードし、ノートブックのDownload Dataセクションを実行して準備します。このデータセットは、トレーニングデータフレームとテストデータフレームに分割され、SageMakerセッションのデフォルトS3バケットにアップロードされます。

データセット全体には、20,640レコードと総計9つの列があります。予測する対象は、家の中央値(medianHouseValue列)です。以下のスクリーンショットは、データセットの上位の行を表示しています。

Top five rows of the California housing data frame showing the structure of the table

トレーニングスクリプトのテンプレート

この投稿でのAutoMLワークフローは、scikit-learnの前処理パイプラインとアルゴリズムに基づいています。目的は、さまざまな前処理パイプラインとアルゴリズムの組み合わせを生成し、最も良いパフォーマンスの設定を見つけることです。一般的なトレーニングスクリプトを作成して始めましょう。このスクリプトには、2つの空のコメントブロックがあります。1つはハイパーパラメータを注入するためのブロックであり、もう1つは前処理モデルパイプラインオブジェクトを注入するためのブロックです。これらは、各前処理モデル候補のために動的に注入されます。1つの汎用スクリプトがあることで、実装がDRY(重複を避ける)になります。

#create base script_script = """import argparseimport joblibimport osimport numpy as npimport pandas as pdfrom sklearn.metrics import mean_squared_errorfrom sklearn.pipeline import Pipeline, FeatureUnionfrom sklearn.preprocessing import StandardScalerfrom sklearn.decomposition import PCAfrom sklearn.impute import SimpleImputerfrom sklearn.cluster import KMeansfrom sklearn.linear_model import ElasticNetfrom sklearn.ensemble import RandomForestRegressorfrom sklearn.ensemble import GradientBoostingRegressor############################## 推論関数 ##############################def model_fn(model_dir):clf = joblib.load(os.path.join(model_dir, "model.joblib"))return clfif __name__ == "__main__":print("引数の抽出")parser = argparse.ArgumentParser()# ハイパーパラメータ##### 動的に挿入されます #####{}############################# データ、モデル、および出力ディレクトリparser.add_argument("--model-dir", type=str, default=os.environ.get("SM_MODEL_DIR"))parser.add_argument("--train", type=str, default=os.environ.get("SM_CHANNEL_TRAIN"))parser.add_argument("--test", type=str, default=os.environ.get("SM_CHANNEL_TEST"))parser.add_argument("--train-file", type=str, default="train.parquet")parser.add_argument("--test-file", type=str, default="test.parquet")parser.add_argument("--features", type=str)parser.add_argument("--target", type=str)args, _ = parser.parse_known_args()# データの読み込みと準備train_df = pd.read_parquet(os.path.join(args.train, args.train_file))test_df = pd.read_parquet(os.path.join(args.test, args.test_file))X_train = train_df[args.features.split()]X_test = test_df[args.features.split()]y_train = train_df[args.target]y_test = test_df[args.target]# モデルの学習##### 動的に挿入されます #####{}{}############################pipeline = Pipeline([('preprocessor', preprocessor), ('model', model)])pipeline.fit(X_train, y_train)# モデルの検証とメトリクスの表示rmse = mean_squared_error(y_test, pipeline.predict(X_test), squared=False)print("RMSE: " + str(rmse))# モデルの永続化path = os.path.join(args.model_dir, "model.joblib")joblib.dump(pipeline, path)"""# 手元にスクリプトを書き出すために.pyファイルに書き込むwith open("script_draft.py", "w") as f:print(_script, file=f)

前処理とモデルの組み合わせを作成する

preprocessorsディクショナリには、モデルのすべての入力特徴量に適用される前処理技術の仕様が含まれています。各レシピは、scikit-learnのPipelineまたはFeatureUnionオブジェクトを使用して定義され、個々のデータ変換を連鎖させて結合します。たとえば、mean-imp-scaleは、欠損値を各列の平均値で補完し、すべての特徴量をStandardScalerを使用してスケーリングするというシンプルなレシピです。その対照として、mean-imp-scale-pcaレシピは、さらにいくつかの操作を連鎖させています。

  1. 欠損値を平均値で補完します。
  2. 平均値と標準偏差を使用して特徴量のスケーリングを適用します。
  3. 指定された分散閾値値で入力データにPCAを計算し、欠損値補完とスケーリングされた入力特徴量と結合します。

この記事では、すべての入力特徴量は数値です。入力データセットにより多様なデータ型がある場合、異なる前処理ブランチを異なる特徴量タイプセットに適用するより複雑なパイプラインを指定する必要があります。

preprocessors = {    "mean-imp-scale": "preprocessor = Pipeline([('imputer', SimpleImputer(strategy='mean')), ('scaler', StandardScaler())])\n",    "mean-imp-scale-knn": "preprocessor = FeatureUnion([('base-features', Pipeline([('imputer', SimpleImputer(strategy='mean')), ('scaler', StandardScaler())])), ('knn', Pipeline([('imputer', SimpleImputer(strategy='mean')), ('scaler', StandardScaler()), ('knn', KMeans(n_clusters=10))]))])\n",    "mean-imp-scale-pca": "preprocessor = FeatureUnion([('base-features', Pipeline([('imputer', SimpleImputer(strategy='mean')), ('scaler', StandardScaler())])), ('pca', Pipeline([('imputer', SimpleImputer(strategy='mean')), ('scaler', StandardScaler()), ('pca', PCA(n_components=0.9))]))])\n"   }

modelsの辞書には、データセットを適合させるさまざまなアルゴリズムの仕様が含まれています。すべてのモデルタイプには、次の仕様が辞書に含まれています:

  • script_output – 推定子によって使用されるトレーニングスクリプトの場所を指します。このフィールドは、models辞書がpreprocessors辞書と組み合わされるときに動的に埋められます。
  • insertionsscript_draft.pyに挿入され、次にscript_outputの下に保存されるコードを定義します。キー“preprocessor”は意図的に空白にしてあります。なぜなら、この場所には前処理器のいずれかが挿入されるため、複数のモデル-前処理器の組み合わせを作成するためです。
  • hyperparameters – HPOジョブによって最適化される一連のハイパーパラメータです。
  • include_cls_metadata – SageMaker Tunerクラスで必要なより詳細な設定の詳細です。

models辞書の完全な例は、GitHubリポジトリにあります。

models = {    "rf": {        "script_output": None,        "insertions": {            # Arguments            "arguments" :             "parser.add_argument('--n_estimators', type=int, default=100)\n"+            "    parser.add_argument('--max_depth', type=int, default=None)\n"+                        "    parser.add_argument('--min_samples_leaf', type=int, default=1)\n"+            "    parser.add_argument('--min_samples_split', type=int, default=2)\n"+                        "    parser.add_argument('--max_features', type=str, default='auto')\n",            # Model call            "preprocessor": None,            "model_call" : "model = RandomForestRegressor(n_estimators=args.n_estimators,max_depth=args.max_depth,min_samples_leaf=args.min_samples_leaf,min_samples_split=args.min_samples_split,max_features=args.max_features)\n"        },        "hyperparameters": {            "n_estimators": IntegerParameter(100, 2000, "Linear"),            "max_depth": IntegerParameter(1, 100, "Logarithmic"),            "min_samples_leaf": IntegerParameter(1, 6, "Linear"),            "min_samples_split": IntegerParameter(2, 20, "Linear"),            "max_features": CategoricalParameter(["auto", "sqrt", "log2"]),        },        "include_cls_metadata": False,    }}

次に、preprocessorsmodelsの辞書を繰り返し処理し、すべての可能な組み合わせを作成します。たとえば、preprocessorsの辞書には10のレシピが含まれており、modelsの辞書には5つのモデル定義がある場合、新たに作成されたパイプライン辞書には、HPO中に評価される50の前処理器-モデルパイプラインが含まれます。この時点では、個々のパイプラインスクリプトはまだ作成されていません。Jupyterノートブックの次のコードブロック(セル9)では、pipelines辞書内のすべての前処理器-モデルオブジェクトを繰り返し処理し、関連するすべてのコード断片を挿入し、ノートブックにパイプライン固有のスクリプトバージョンをローカルに保存します。これらのスクリプトは、個々の推定器を作成する際に次のステップで使用され、HPOジョブに組み込まれます。

pipelines = {}
for model_name, model_spec in models.items():
    pipelines[model_name] = {}
    for preprocessor_name, preprocessor_spec in preprocessors.items():
        pipeline_name = f"{model_name}-{preprocessor_name}"
        pipelines[model_name][pipeline_name] = {}
        pipelines[model_name][pipeline_name]["insertions"] = {}
        pipelines[model_name][pipeline_name]["insertions"]["preprocessor"] = preprocessor_spec
        pipelines[model_name][pipeline_name]["hyperparameters"] = model_spec["hyperparameters"]
        pipelines[model_name][pipeline_name]["include_cls_metadata"] = model_spec["include_cls_metadata"]
        
        pipelines[model_name][pipeline_name]["insertions"]["arguments"] = model_spec["insertions"]["arguments"]
        pipelines[model_name][pipeline_name]["insertions"]["model_call"] = model_spec["insertions"]["model_call"]
        pipelines[model_name][pipeline_name]["script_output"] = f"scripts/{model_name}/script-{pipeline_name}.py"

推定器を定義する

スクリプトが準備できた後にHPOジョブで使用されるSageMaker Estimatorsを定義することができます。まず、すべての推定器に共通のプロパティを定義するラッパークラスを作成しましょう。このクラスはSKLearnクラスを継承し、役割、インスタンス数、タイプ、およびスクリプトが使用するフィーチャーおよびターゲットの列を指定します。

class SKLearnBase(SKLearn):
    def __init__(
        self,
        entry_point=".", # 意図的に空白にしてあり、次の関数で上書きされます
        framework_version="1.2-1",
        role=sm_role,
        instance_count=1,
        instance_type="ml.c5.xlarge",
        hyperparameters={
           "features": "medianIncome housingMedianAge totalRooms totalBedrooms population households latitude longitude",
            "target": "medianHouseValue",
        },
        **kwargs,
    ):
        super(SKLearnBase, self).__init__(
            entry_point=entry_point,
            framework_version=framework_version,
            role=role,
            instance_count=instance_count,
            instance_type=instance_type,
            hyperparameters=hyperparameters,
            **kwargs
        )

次に、前もって生成されたすべてのスクリプトを反復処理し、scriptsディレクトリにある推定器の辞書estimatorsを構築します。一意の推定器名とスクリプトの1つを使用して、SKLearnBaseクラスをインスタンス化します。なお、estimators辞書は2つのレベルを持っており、最上位レベルはpipeline_familyを定義しています。これは、評価するモデルのタイプに基づく論理的なグループであり、models辞書の長さと等しいです。2番目のレベルには、個々の前処理タイプが与えられたpipeline_familyとともに含まれています。この論理的なグループ化は、HPOジョブを作成する際に必要です。

estimators = {}
for pipeline_family in pipelines.keys():
    estimators[pipeline_family] = {}
    scripts = os.listdir(f"scripts/{pipeline_family}")
    for script in scripts:
        if script.endswith(".py"):
            estimator_name = script.split(".")[0].replace("_", "-").replace("script", "estimator")
            estimators[pipeline_family][estimator_name] = SKLearnBase(
                entry_point=f"scripts/{pipeline_family}/{script}",
                base_job_name=estimator_name,
            )

HPOチューナーの引数を定義する

HPO Tunerクラスへの引数を最適化するために、HyperparameterTunerArgsデータクラスを初期化します。このクラスには、HPOクラスで必要な引数が含まれており、複数のモデル定義を一度に展開する際に必要なフォーマットでHPO引数を返す一連の関数も付属しています。

@dataclass
class HyperparameterTunerArgs:
    base_job_names: list[str]
    estimators: list[object]
    inputs: dict[str]
    objective_metric_name: str
    hyperparameter_ranges: list[dict]
    metric_definition: dict[str]
    include_cls_metadata: list[bool]
    
    def get_estimator_dict(self) -> dict:
        return {k:v for (k, v) in zip(self.base_job_names, self.estimators)}
    
    def get_inputs_dict(self) -> dict:
        return {k:v for (k, v) in zip(self.base_job_names, [self.inputs]*len(self.base_job_names))}
    
    def get_objective_metric_name_dict(self) -> dict:
        return {k:v for (k, v) in zip(self.base_job_names, [self.objective_metric_name]*len(self.base_job_names))}
    
    def get_hyperparameter_ranges_dict(self) -> dict:
        return {k:v for (k, v) in zip(self.base_job_names, self.hyperparameter_ranges)}
    
    def get_metric_definition_dict(self) -> dict:
        return {k:[v] for (k, v) in zip(self.base_job_names, [self.metric_definition]*len(self.base_job_names))}
    
    def get_include_cls_metadata_dict(self) -> dict:
        return {k:v for (k, v) in zip(self.base_job_names, self.include_cls_metadata)}

次のコードブロックでは、先ほど紹介した HyperparameterTunerArgs のデータクラスを使用します。 estimators の辞書から、各 estimator_family に特定の入力パラメータのセットを生成するために、hp_args という別の辞書を作成します。これらの引数は、次のステップでモデルファミリごとに HPO ジョブを初期化する際に使用されます。

hp_args = {}for estimator_family, estimators in estimators.items():    hp_args[estimator_family] = HyperparameterTunerArgs(        base_job_names=list(estimators.keys()),        estimators=list(estimators.values()),        inputs={"train": s3_data_train.uri, "test": s3_data_test.uri},        objective_metric_name="RMSE",        hyperparameter_ranges=[pipeline.get("hyperparameters") for pipeline in pipelines[estimator_family].values()],        metric_definition={"Name": "RMSE", "Regex": "RMSE: ([0-9.]+).*$"},        include_cls_metadata=[pipeline.get("include_cls_metadata") for pipeline in pipelines[estimator_family].values()],    )

HPO チューナーオブジェクトの作成

このステップでは、個々のestimator_familyごとにチューナーを作成します。すべての estimators で1つだけを起動するかわりに、なぜ3つの別々のHPOジョブを作成するのでしょうか?HyperparameterTuner クラスは、それにアタッチされた10つのモデル定義に制限されています。そのため、各HPOは、与えられたモデルファミリに対して最もパフォーマンスの良いプリプロセッサを見つけ、そのモデルファミリのハイパーパラメータをチューニングする役割を担っています。

設定に関する追加のポイントは次のとおりです:

  • 最適化戦略はベイズです。これは、HPOがすべての試行のパフォーマンスを積極的に監視し、より有望なハイパーパラメータの組み合わせに向かう方向を決定します。ベイズ戦略を使用する場合、早期停止は オフ または オート に設定する必要があります。
  • 各HPOジョブは最大100件のジョブであり、10件のジョブを並行して実行します。より大きなデータセットに対処する場合は、総ジョブ数を増やす必要があります。
  • また、ジョブの実行時間とトリガーされるジョブの数を制御するための設定を使用することもできます。一つは秒単位で最大ランタイムを設定することです(これはこの記事では1時間に設定しています)。もう一つは、最近リリースされた TuningJobCompletionCriteriaConfig を使用する方法です。これは、ジョブの進捗状況を監視し、より多くのジョブが結果を改善する可能性があるかどうかを判断するための設定のセットを提供します。この記事では、スコアが改善されない最大のトレーニングジョブ数を20に設定しています。これにより、スコアが改善されない場合(たとえば、40番目の試行から)、最大ジョブ数までの残りの試行に対して支払いをする必要はありません。
STRATEGY = "Bayesian"OBJECTIVE_TYPE = "Minimize"MAX_JOBS = 100MAX_PARALLEL_JOBS = 10MAX_RUNTIME_IN_SECONDS = 3600EARLY_STOPPING_TYPE = "Off"# RANDOM_SEED = 42 # uncomment if you require reproducibility across runsTUNING_JOB_COMPLETION_CRITERIA_CONFIG = TuningJobCompletionCriteriaConfig(    max_number_of_training_jobs_not_improving=20,    )tuners = {}for estimator_family, hp in hp_args.items():    tuners[estimator_family] = HyperparameterTuner.create(        estimator_dict=hp.get_estimator_dict(),        objective_metric_name_dict=hp.get_objective_metric_name_dict(),        hyperparameter_ranges_dict=hp.get_hyperparameter_ranges_dict(),        metric_definitions_dict=hp.get_metric_definition_dict(),        strategy=STRATEGY,        completion_criteria_config=TUNING_JOB_COMPLETION_CRITERIA_CONFIG,        objective_type=OBJECTIVE_TYPE,        max_jobs=MAX_JOBS,        max_parallel_jobs=MAX_PARALLEL_JOBS,        max_runtime_in_seconds=MAX_RUNTIME_IN_SECONDS,        base_tuning_job_name=f"custom-automl-{estimator_family}",        early_stopping_type=EARLY_STOPPING_TYPE, # early stopping of training jobs is not currently supported when multiple training job definitions are used        # random_seed=RANDOM_SEED,    )

次に、tunershp_args の辞書を繰り返し処理し、SageMaker ですべての HPO ジョブをトリガーします。結果が完了するまでカーネルが待機しないように、wait 引数を False に設定して、すべてのジョブを一度にトリガーできるようにします。

すべてのトレーニングジョブが完了せず、一部のジョブはHPOジョブによって停止される可能性があります。これは、TuningJobCompletionCriteriaConfigが指定された基準のいずれかが満たされた場合に最適化が終了するためです。この場合は、最適化基準が20回連続して改善されない場合です。

for tuner, hpo in zip(tuners.values(), hp_args.values()):    tuner.fit(        inputs=hpo.get_inputs_dict(),        include_cls_metadata=hpo.get_include_cls_metadata_dict(),        wait=False,        )

結果の分析

ノートブックのセル15では、すべてのHPOジョブが完了しているかどうかをチェックし、さらなる分析のためにパンダデータフレームの形式で結果を結合します。詳細な結果を分析する前に、SageMakerコンソールを大まかに見てみましょう。

ハイパーパラメータチューニングジョブページの上部には、起動された3つのHPOジョブが表示されます。すべてのジョブは早期に終了し、すべての100個のトレーニングジョブを実行しませんでした。以下のスクリーンショットでは、Elastic-Netモデルファミリーが最も多くの試行を完了しましたが、他のモデルファミリーは最適な結果を見つけるためにそんなに多くのトレーニングジョブが必要ではありませんでした。

SageMaker Hyperparameter tuning jobs console showing all three triggered HPO jobs status

HPOジョブを開くと、個々のトレーニングジョブ、ジョブの構成、および最良のトレーニングジョブの情報とパフォーマンスなど、詳細な情報にアクセスできます。

Detailed view of one of the selected HPO jobs

結果に基づいて視覚化を行い、すべてのモデルファミリーにおけるAutoMLワークフローのパフォーマンスについてさらなる洞察を得ましょう。

次のグラフから、Elastic-Netモデルのパフォーマンスが70,000から80,000のRMSEの間で振動し、アルゴリズムがさまざまな前処理技術やハイパーパラメータ値を試してもパフォーマンスを改善することができなかったことがわかります。また、RandomForestのパフォーマンスはHPOによって探索されたハイパーパラメータセットによって大きく変動しましたが、多くの試行にもかかわらず、50,000のRMSE誤差を下回ることができませんでした。GradientBoostingは、最初から50,000のRMSEを下回る最良のパフォーマンスを達成しました。HPOはその結果をさらに改善しようとしましたが、他のハイパーパラメータの組み合わせでより優れたパフォーマンスを達成することはできませんでした。すべてのHPOジョブにおいて一般的な結論は、各アルゴリズムの最適なハイパーパラメータセットを見つけるために多くのジョブが必要ではなかったということです。結果をさらに改善するには、より多くのフィーチャーを作成し追加のフィーチャーエンジニアリングを行う必要があります。

Changes in HPO objective value over time by each model family

また、最も有望な組み合わせについての結論を得るために、モデルとプリプロセッサの組み合わせのより詳細なビューも調べることができます。

Changes in HPO objective value over time by each model-preprocessor combination

ベストモデルを選択して展開する

次のコードスニペットは、最も低い目標値を達成したベストモデルを選択し、そのモデルをSageMakerエンドポイントとして展開します。

df_best_job = df_tuner_results.loc[df_tuner_results["FinalObjectiveValue"] == df_tuner_results["FinalObjectiveValue"].min()]df_best_jobBEST_MODEL_FAMILY = df_best_job["TrainingJobFamily"].values[0]tuners.get(BEST_MODEL_FAMILY).best_training_job()tuners.get(BEST_MODEL_FAMILY).best_estimator()predictor = tuners.get(BEST_MODEL_FAMILY).deploy(    initial_instance_count=1,    instance_type="ml.c4.large",    endpoint_name=f"custom-automl-endpoint-{BEST_MODEL_FAMILY}",)

片付け

不要な料金がAWSアカウントに発生しないように、この投稿で使用したAWSリソースを削除することをおすすめします:

  1. Amazon S3コンソールで、トレーニングデータが保存されていたS3バケットからデータを削除してください。

Amazon S3コンソールでバケットを空にする方法を示す画像

  1. SageMakerコンソールでノートブックインスタンスを停止してください。

SageMaker Notebookインスタンスコンソールでインスタンスを停止する方法を示す画像

  1. デプロイしたモデルのエンドポイントを削除してください。エンドポイントは使用していない場合には削除する必要があります。時間の経過によって請求されるためです。
sm_client.delete_endpoint(EndpointName=predictor.endpoint)

結論

この投稿では、SageMakerを使用してカスタムのHPOジョブを作成し、カスタムのアルゴリズムと前処理技術を使用する方法を紹介しました。特に、この例では多くのトレーニングスクリプトを自動生成するプロセスと、複数の並列最適化ジョブを効率的に展開するためのPythonプログラミング構造の使用方法を示しています。このソリューションがSageMakerを使用して展開するカスタムモデルチューニングジョブの骨組みとなり、MLワークフローのパフォーマンス向上と高速化に貢献することを願っています。

SageMaker HPOの使用方法をさらに詳しく理解するために、以下のリソースをご覧ください:

We will continue to update VoAGI; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

AI研究

複雑なAIモデルの解読:パデュー大学の研究者が、ディープラーニングの予測を位相マップに変換

複雑な予測モデルの高度なパラメータ化の性質により、予測戦略の説明と解釈が困難です。研究者たちは、この問題を解決するた...

AI研究

取りましょう NVIDIA NeMo SteerLMは、推論中にモデルの応答をカスタマイズすることができるようにします

開発者は、強力な大規模な言語モデル(LLMs)を自分たちの目的地に到達する際に、AIパワードステアリングホイールを利用して...

データサイエンス

メタAIのもう一つの革命的な大規模モデル — 画像特徴抽出のためのDINOv2

Mete AIは、画像から自動的に視覚的な特徴を抽出する新しい画像特徴抽出モデルDINOv2の新バージョンを紹介しましたこれはAIの...

人工知能

「先延ばしハック:ChatGPTを使ってプロジェクトをビデオゲームに変える」

「あなたのやるべきことリストを、ドーパミンが絶えず放出されるワクワクするビデオゲームに変えましょう」

機械学習

2024年に探索するべきトップ12の生成 AI モデル

はじめに 近年、人工知能(AI)は非凡な変革を遂げ、創造性の風景を再構築するだけでなく、多様な産業における自動化の新たな...

人工知能

偉大さの開放:アレクサンダー大王の創造的AIとの旅 (Idai-sa no kaihō Arekusandā Taio no sōzō-teki AI to no tabi)

「生成型AI(GAI)はコーチングの効果を高めるためにどのように使用できるのか、また生成型AI(GAI)をコーチングツールとし...