Container Runtimeによる並列ハイパーパラメーター最適化(HPO) ML

Snowflake ML Hyperparameter Optimization(HPO) API は、効率的で並列化されたモデルのハイパーパラメーターチューニングを可能にする、モデルにとらわれないフレームワークです。オープンソースのフレームワークやアルゴリズムを使用することができます。Snowflake ML APIs も使えます。

今日、この API は、Snowpark Container Services (SPCS) のContainer Runtimeを使用するように構成された Snowflake Notebooks 内で使用できます。 このようなノートブック を作成したら、次のことができます。

  • 任意のオープンソースパッケージを使用してモデルをトレーニングし、この API を使用してハイパーパラメーターのチューニングプロセスを配布します。

  • Snowflake ML 分散トレーニング APIs を使用してモデルをトレーニングし、 HPO をスケーリングしながら、トレーニングの各実行もスケーリングします。

Notebookから開始された HPO ワークロードは、 CPU または GPU インスタンス上の Snowpark Container Services 内部で実行され、 SPCS コンピュートプールの単一ノードで利用可能なコア(CPUs または GPUs)までスケールアウトします。

並列化された HPO API には、以下のようなメリットがあります:

  • 単一の API は、複数のリソースにトレーニングを分配する複雑な作業をすべて自動的に処理します。

  • オープンソースの ML フレームワークまたはSnowflake ML モデリング APIs を使用して、仮想的にあらゆるフレームワークやアルゴリズムでトレーニングできます。

  • 様々な連続および非連続サンプリング関数とともに、ベイズおよびランダムサーチアルゴリズムを含む、チューニングおよびサンプリングオプションの選択

  • 残りのSnowflakeの緊密な統合です。例えば、Snowflake DatasetsまたはDataframesを介した効率的なデータインジェストや、 ML の自動リネージキャプチャなどです。

注釈

SPCS コンピューティングプールの複数のノードを使用するために、 HPO ランをスケールすることができます。詳細については、 マルチノードクラスタでのワークロードの実行 をご参照ください。

モデルのハイパーパラメーターの最適化

Snowflake ML HPO API を使ってモデルをチューニングします。以下のステップはそのプロセスを示しています。

  1. データを取り込みます。

  2. 検索アルゴリズムを使用して、ハイパーパラメーターを最適化するための戦略を定義します。

  3. ハイパーパラメーターのサンプリング方法を定義します。

  4. Tunerを構成します。

  5. 各トレーニングジョブからハイパーパラメーターとトレーニングメトリックを取得します。

  6. トレーニングジョブを開始します。

  7. トレーニングジョブの結果を取得します。

以下のセクションでは、その手順を説明します。例については、 Container Runtime HPO の例 を参照してください。

データの取り込み

dataset_map オブジェクトを使用して、 HPO API にデータを取り込みます。 dataset_map オブジェクトは、トレーニングデータセットまたはテストデータセットと、対応するSnowflake DataConnector オブジェクトをペアにした辞書です。 dataset_map オブジェクトがトレーニング関数に渡されます。以下は dataset_map オブジェクトの例です。

dataset_map = {
  "x_train": DataConnector.from_dataframe(session.create_dataframe(X_train)),
  "y_train": DataConnector.from_dataframe(
      session.create_dataframe(y_train.to_frame())
  ),
  "x_test": DataConnector.from_dataframe(session.create_dataframe(X_test)),
  "y_test": DataConnector.from_dataframe(
      session.create_dataframe(y_test.to_frame())
  ),
}
Copy

検索アルゴリズムの定義

ハイパーパラメーター空間の探索に使用する検索アルゴリズムを定義します。アルゴリズムは、ハイパーパラメーターの構成方法を決定するために、以前の試行の結果を使用します。以下の検索アルゴリズムを使用できます。

  • グリッド検索

    定義したハイパーパラメーター値のグリッドを探索します。HPO API は、ハイパーパラメーターの可能な限りの組み合わせを評価します。以下はハイパーパラメーターグリッドの例です。

    search_space = {
        "n_estimators": [50, 51],
        "max_depth": [4, 5]),
        "learning_rate": [0.01, 0.3],
    }
    
    Copy

    前述の例では、各パラメーターには2つの値があります。ハイパーパラメーターの組み合わせは8通り(2 * 2 * 2)あります。

  • Bayesian最適化

    確率モデルを使用して、次に評価するハイパーパラメーターのセットを決定します。アルゴリズムは、ハイパーパラメーターの構成方法を決定するために、以前の試行の結果を使用します。Bayesian最適化についての情報は、 Bayesian最適化 をご覧ください。

  • ランダム検索

    ハイパーパラメーター空間をランダムにサンプルします。これはシンプルで効果的なアプローチであり、大容量または混合(連続または離散)の検索空間で特に効果的です。

以下のコードを使って検索アルゴリズムを定義することができます。

from entities import search_algorithm
search_alg = search_algorithm.BayesOpt()
search_alg = search_algorithm.RandomSearch()
search_alg = search_algorithm.GridSearch()
Copy

ハイパーパラメーターサンプリングの定義

検索空間関数を使用して、各試行中のハイパーパラメーターのサンプリング方法を定義します。ハイパーパラメーターが取り得る値の範囲とタイプを記述するために使用します。

利用可能なサンプリング関数を以下に示します。

  • uniform(lower, upper): 連続値を下限値と上限値の間で一様にサンプルします。ドロップアウト率や正則化の強さなどのパラメーターに便利です。

  • loguniform(lower, upper): 対数空間で値をサンプルし、数桁に渡るパラメーター(例えば学習率)に最適です。

  • randint(lower, upper): 整数を下限値(包含)と上限値(排他)の間で一様にサンプルします。レイヤー数のような離散的なパラメーターに適しています。

  • choice(options): 提供されたリストからランダムに値を選択します。カテゴリパラメーターによく使われます。

以下は、一様関数による検索空間の定義の例です。

search_space = {
    "n_estimators": tune.uniform(50, 200),
    "max_depth": tune.uniform(3, 10),
    "learning_rate": tune.uniform(0.01, 0.3),
}
Copy

Tunerの構成

TunerConfig オブジェクトを使ってTunerを構成します。オブジェクトの中で、最適化されるメトリック、最適化モード、その他の実行パラメーターを指定します。以下は利用可能な構成オプションです。

  • メトリック 最適化する精度や損失などのパフォーマンスメトリック。

  • モード 目的がメトリックの最大化か最小化か("max" または "min")を決定します。

  • 検索アルゴリズム ハイパーパラメーター空間を探索する戦略を指定します。

  • 試行回数 評価するハイパーパラメーター構成の総数をセットします。

  • 同時実行 同時に実行できる試行数を定義します。

次のコード例では、Bayesian最適化ライブラリを使用して、5回の試行でモデルの精度を最大化します。

from snowflake.ml.modeling import tune
tuner_config = tune.TunerConfig(
  metric="accuracy",
  mode="max",
  search_alg=search_algorithm.BayesOpt(
      utility_kwargs={"kind": "ucb", "kappa": 2.5, "xi": 0.0}
  ),
  num_trials=5,
  max_concurrent_trials=1,
)
Copy

ハイパーパラメーターとトレーニングメトリックの取得

Snowflake ML HPO API は、ハイパーパラメーターを効果的に最適化するために、各トレーニング実行からのトレーニングメトリックとハイパーパラメーターを必要とします。 TunerContext オブジェクトを使用して、ハイパーパラメーターとトレーニングメトリックを取得します。次の例では、ハイパーパラメーターとトレーニングメトリックを取得するトレーニング関数を作成します。

def train_func():
  tuner_context = get_tuner_context()
  config = tuner_context.get_hyper_params()
  dm = tuner_context.get_dataset_map()
  ...
  tuner_context.report(metrics={"accuracy": accuracy}, model=model)
Copy

トレーニングジョブの開始

Tuner オブジェクトを使用してトレーニングジョブを開始します。 Tuner オブジェクトは引数としてトレーニング関数、検索空間、Tuner構成をとります。以下は、トレーニングジョブの開始方法の例です。

from snowflake.ml.modeling import tune
tuner = tune.Tuner(train_func, search_space, tuner_config)
tuner_results = tuner.run(dataset_map=dataset_map)
Copy

前のコードは、利用可能なリソースにトレーニング関数を分散させます。試行の結果を収集・要約し、最もパフォーマンスの高い構成を識別します。

トレーニングジョブの結果の取得

すべての試行が終了すると、 TunerResults オブジェクトが各試行の結果を集約します。パフォーマンスメトリック、最適な構成、最適なモデルへの構造的なアクセスを提供します。

以下はその利用可能な属性です。

  • results: すべての試行のメトリックと構成を含むPandas DataFrame。

  • best_result: 最もパフォーマンスが良かった試行をまとめた DataFrame 行。

  • best_model: 該当する場合、最良の試行に関連するモデルインスタンス。

次のコードは、結果、最良のモデル、最良の結果を取得します。

print(tuner_results.results)
print(tuner_results.best_model)
print(tuner_results.best_result)
Copy

API リファレンス

Tuner

Tunerモジュールのimportステートメントを以下に示します。

from snowflake.ml.modeling.tune import Tuner
Copy

Tunerクラスは、コンテナーランタイム HPO API とやり取りするためのメインインターフェイスです。HPO ジョブを実行するには、以下のコードを使用してTunerオブジェクトを初期化し、Snowflakeデータセットを指定してrunメソッドを呼び出します。

class Tuner:
  def __init__(
      self,
      train_func: Callable,
      search_space: SearchSpace,
      tuner_config: TunerConfig,
  )

  def run(
      self, dataset_map: Optional[Dict[str, DataConnector]] = None
  ) -> TunerResults
Copy

SearchSpace

以下は検索空間のimportステートメントです。

from entities.search_space import uniform, choice, loguniform, randint
Copy

以下のコードでは、検索空間の関数を定義しています。

def uniform(lower: float, upper: float)
    """
    Sample a float value uniformly between lower and upper.

    Use for parameters where all values in range are equally likely to be optimal.
    Examples: dropout rates (0.1 to 0.5), batch normalization momentum (0.1 to 0.9).
    """


def loguniform(lower: float, upper: float) -> float:
    """
    Sample a float value uniformly in log space between lower and upper.

    Use for parameters spanning several orders of magnitude.
    Examples: learning rates (1e-5 to 1e-1), regularization strengths (1e-4 to 1e-1).
    """


def randint(lower: int, upper: int) -> int:
    """
    Sample an integer value uniformly between lower(inclusive) and upper(exclusive).

    Use for discrete parameters with a range of values.
    Examples: number of layers, number of epochs, number of estimators.
    """



def choice(options: List[Union[float, int, str]]) -> Union[float, int, str]:
    """
    Sample a value uniformly from the given options.

    Use for categorical parameters or discrete options.
    Examples: activation functions ['relu', 'tanh', 'sigmoid']
    """
Copy

TunerConfig

以下は TunerConfig モジュールのimportステートメントです。

from snowflake.ml.modeling.tune import TunerConfig
Copy

以下のコードを使用して、Tunerの構成クラスを定義します。

class TunerConfig:
  """
  Configuration class for the tuning process.

  Attributes:
    metric (str): The name of the metric to optimize. This should correspond
        to a key in the metrics dictionary reported by the training function.

    mode (str): The optimization mode for the metric. Must be either "min"
        for minimization or "max" for maximization.

    search_alg (SearchAlgorithm): The search algorithm to use for
        exploring the hyperparameter space. Defaults to random search.

    num_trials (int): The maximum number of parameter configurations to
        try. Defaults to 5

    max_concurrent_trials (Optional[int]): The maximum number of concurrently running trials per node. If   not specified, it defaults to the total number of nodes in the cluster. This value must be a positive
    integer if provided.


  Example:
      >>> from entities import search_algorithm        >>> from snowflake.ml.modeling.tune import  TunerConfig
      >>> config = TunerConfig(
      ...     metric="accuracy",
      ...     mode="max",
      ...     num_trials=5,
      ...     max_concurrent_trials=1
      ... )
  """
Copy

SearchAlgorithm

以下は検索アルゴリズムのimportステートメントです。

from entities.search_algorithm import BayesOpt, RandomSearch, GridSearch
Copy

次のコードは、Bayesian最適化検索アルゴリズムオブジェクトを作成します。

@dataclass
class BayesOpt():
    """
    Bayesian Optimization class that encapsulates parameters for the acquisition function.

    This class is designed to facilitate Bayesian optimization by configuring
    the acquisition function through a dictionary of keyword arguments.

    Attributes:
        utility_kwargs (Optional[Dict[str, Any]]):
            A dictionary specifying parameters for the utility (acquisition) function.
            If not provided, it defaults to:
                {
                    'kind': 'ucb',   # Upper Confidence Bound acquisition strategy
                    'kappa': 2.576,  # Exploration parameter for UCB
                    'xi': 0.0      # Exploitation parameter
                }
    """
    utility_kwargs: Optional[Dict[str, Any]] = None
Copy

以下のコードは、ランダムサーチアルゴリズムオブジェクトを作成します。

@dataclass
class RandomSearch():
    The default and most basic way to do hyperparameter search is via random search.

    Attributes:
Seed or NumPy random generator for reproducible results. If set to None (default), the global generator (np.random) is used.
    random_state: Optional[int] = None
Copy

TunerResults

以下は TunerResults モジュールのimportステートメントです。

from entities.tuner_results import TunerResults
Copy

次のコードは、 TunerResults オブジェクトを作成します。

@dataclass
class TunerResults:
    results: pd.DataFrame
    best_result: pd.DataFrame
    best_model: Optional[Any]
Copy

get_tuner_context

以下は get_tuner_context モジュールのimportステートメントです。

from snowflake.ml.modeling.tune import get_tuner_context
Copy

このhelperメソッドはトレーニング関数内で呼び出されるように設計されています。これは TunerContext オブジェクトを返します。このオブジェクトには、次を含む試行を実行するために有用なフィールドがいくつかカプセル化されています。

  • 現在の試行に対して HPO フレームワークによって選択されたハイパーパラメーター。

  • トレーニングに必要なデータセット。

  • HPO フレームワークが次のハイパーパラメーターのセットを提案する際の指針となる、メトリックをレポートするhelper関数

次のコードはTunerコンテキストオブジェクトを作成します。

class TunerContext:
    """
    A centralized context class for managing trial configuration, reporting, and dataset information.
    """

    def get_hyper_params(self) -> Dict[str, Any]:
        """
        Retrieve the configuration dictionary.

        Returns:
            Dict[str, Any]: The configuration dictionary for the trial.
        """
        return self._hyper_params

    def report(self, metrics: Dict[str, Any], model: Optional[Any] = None) -> None:
    """
    Report metrics and optionally the model if provided.

    This method is used to report the performance metrics of a model and, if provided, the model itself.
    The reported metrics will be used to guide the next set of hyperparameters selection in the
    optimization process.

    Args:
        metrics (Dict[str, Any]): A dictionary containing the performance metrics of the model.
            The keys are metric names, and the values are the corresponding metric values.
        model (Optional[Any], optional): The trained model to be reported. Defaults to None.

    Returns:
        None: This method doesn't return anything.
    """

    def get_dataset_map(self) -> Optional[Dict[str, Type[DataConnector]]]:
        """
        Retrieve the dataset mapping.

        Returns:
            Optional[Dict[str, Type[DataConnector]]]: A mapping of dataset names to DataConnector types, if available.
        """
        return self._dataset_map
Copy

制限事項

Bayesian最適化は連続的な検索空間を必要とし、一様サンプリング関数でのみ機能します。離散パラメーターとは互換性がありません。 tune.randint または tune.choice メソッドでサンプルされたものです。この制限を回避するには、 tune.uniform を使い、パラメーターを学習関数内にキャストするか、 tune.RandomSearch のような、離散空間と連続空間の両方を扱うサンプリングアルゴリズムに切り替えます。

トラブルシューティング

エラーメッセージ

考えられる原因

考えられる解決策

無効な探索空間の構成: BayesOpt は、すべてのサンプリング関数が 'Uniform' タイプであることを要求しています。

ベイズ最適化は一様サンプリングでのみ機能し、離散サンプルでは機能しません。(上記の 制限事項 をご参照ください)

  • tune.uniform を使用して、結果をトレーニング関数にキャストします。

  • 離散サンプルと非離散サンプルの両方を受け付ける RandomSearch アルゴリズムに切り替えます。

CPU リソースが不十分です。必須16、可用性: 8.必要なリソースの数と可用性は異なる場合があります。

max_concurrent_trials は可用性より高い値にセットされます。

エラーメッセージの指示に従ってください。

GPU リソースが不十分です。必須: 4、利用可能: 2。CPU または GPU をご参照ください。必要なリソースの数と可用性は異なる場合があります。

max_concurrent_trials は可用性より高い値にセットされます。

エラーメッセージの指示に従ってください。