Parallele Hyperparameter Optimization (HPO) auf Container Runtime für ML¶
Die Snowflake ML Hyperparameter-Optimierung (HPO) API ist ein modellunabhängiges Framework, das eine effiziente, parallelisierte Hyperparameter-Abstimmung von Modellen ermöglicht. Sie können jedes Open-Source-Framework oder jeden Algorithmus verwenden. Sie können auch Snowflake ML-APIs verwenden.
Heute ist diese API für die Verwendung innerhalb eines Snowflake Notebooks verfügbar, das so konfiguriert ist, dass es Container Runtime auf Snowpark Container Services (SPCS) verwendet. Nachdem Sie ein solches Notebook erstellt haben, können Sie folgende Aufgaben ausführen:
Trainieren eines Modells mit einem beliebigen Open-Source-Paket und Verwenden dieser API, um den Hyperparameter-Tuning-Prozess zu verteilen
Trainieren eines Modells mit APIs für verteiltes Training von Snowflake ML und Skalieren von HPO bei gleichzeitiger Skalierung jedes Trainingslaufs
Der vom Notebook initiierte HPO-Workload wird innerhalb von Snowpark Container Services auf den CPU- oder GPU-Instanzen ausgeführt und skaliert bis zu den Kernen (CPUs oder GPUs), die auf einem einzelnen Knoten im SPCS-Computepool verfügbar sind.
Die parallelisierte HPO-API bietet die folgenden Vorteile:
Eine einzige API, die automatisch alle komplexen Aufgaben der Verteilung des Trainings auf mehrere Ressourcen übernimmt
Die Möglichkeit, mit praktisch jedem Framework oder Algorithmus zu trainieren, unter Verwendung von Open-Source-ML-Frameworks oder der Modellierungs-APIs von Snowflake ML
Eine Auswahl an Tuning- und Sampling-Optionen, einschließlich Bayes’scher und zufälliger Suchalgorithmen sowie verschiedener kontinuierlicher und nicht-kontinuierlicher Sampling-Funktionen
Enge Datenintegration mit dem Rest von Snowflake, z. B. effiziente Datenaufnahme (Ingestion) über Snowflake-Datensets oder -Datenframes und automatische Erfassung der ML-Datenherkunft
Bemerkung
Sie können den HPO-Lauf skalieren, um mehrere Knoten im SPCS-Computepool zu verwenden. Weitere Informationen dazu finden Sie unter Workload auf einem Multi-Node-Cluster ausführen.
Optimieren Sie die Hyperparameter eines Modells¶
Verwenden Sie die Snowflake ML HPO-API, um ein Modell zu tunen. Die folgenden Schritte veranschaulichen den Vorgang:
Nehmen Sie die Daten auf.
Verwenden Sie den Suchalgorithmus, um die Strategie für die Optimierung der Hyperparameter zu definieren.
Definieren Sie, wie die Hyperparameter abgetastet werden.
Konfigurieren Sie den Tuner.
Holen Sie sich die Hyperparameter und Trainingsmetriken von jedem Trainingsauftrag.
Starten Sie den Trainingsauftrag.
Holen Sie sich die Ergebnisse des Trainings.
In den folgenden Abschnitten werden die vorangegangenen Schritte erläutert. Ein Beispiel finden Sie unter Container Runtime HPO-Beispiel.
Nehmen Sie die Daten auf.¶
Verwenden Sie das Objekt dataset_map
, um die Daten in die HPO-API zu übernehmen. Das dataset_map
-Objekt ist ein Wörterbuch, das den Trainings- oder Testdatensatz mit dem entsprechenden Snowflake DataConnector-Objekt verbindet. Das Objekt dataset_map
wird an die Trainingsfunktion übergeben. Im Folgenden finden Sie ein Beispiel für ein dataset_map
-Objekt:
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())
),
}
Definieren Sie den Suchalgorithmus¶
Definieren Sie den Suchalgorithmus, der zur Erkundung des Hyperparameterraums verwendet wird. Der Algorithmus verwendet die Ergebnisse früherer Versuche, um zu bestimmen, wie die Hyperparameter konfiguriert werden sollen. Sie können die folgenden Suchalgorithmen verwenden:
Rastersuche
Durchsucht ein Raster nach Hyperparamter-Werten, die Sie definieren. Die HPO-API wertet jede mögliche Kombination von Hyperparametern aus. Im Folgenden sehen Sie ein Beispiel für ein Hyperparameter-Raster:
search_space = { "n_estimators": [50, 51], "max_depth": [4, 5]), "learning_rate": [0.01, 0.3], }
Im vorangegangenen Beispiel hat jeder Parameter zwei mögliche Werte. Es gibt 8 (2 * 2 * 2) mögliche Kombinationen von Hyperparametern.
Bayessche Optimierung
Verwendet ein probabilistisches Modell, um den nächsten Satz von zu bewertenden Hyperparametern zu bestimmen. Der Algorithmus verwendet die Ergebnisse früherer Versuche, um zu bestimmen, wie die Hyperparameter konfiguriert werden sollen. Weitere Informationen zur Bayes’schen Optimierung finden Sie unter Bayes’sche Optimierung.
Zufällige Suche
Nimmt zufällige Stichproben aus dem Hyperparameterraum. Dies ist ein einfacher und effektiver Ansatz, der besonders gut bei großen oder gemischten (kontinuierlichen oder diskreten) Suchräumen funktioniert.
Sie können den folgenden Code verwenden, um den Suchalgorithmus zu definieren:
from entities import search_algorithm
search_alg = search_algorithm.BayesOpt()
search_alg = search_algorithm.RandomSearch()
search_alg = search_algorithm.GridSearch()
Definieren Sie Hyperparameter-Sampling¶
Verwenden Sie die Suchraumfunktionen, um die Hyperparameter-Sampling-Methode bei jedem Versuch zu definieren. Verwenden Sie sie, um den Bereich und die Art der Werte zu beschreiben, die die Hyperparameter annehmen können.
Im Folgenden finden Sie die verfügbaren Stichprobenfunktionen:
uniform(
lower
,upper
): Nimmt einen kontinuierlichen Wert gleichmäßig zwischen dem unteren und oberen Wert auf. Nützlich für Parameter wie Dropout-Raten oder Regularisierungsstärken.loguniform(
lower
,upper
): Nimmt einen Wert im logarithmischen Raum auf, ideal für Parameter, die mehrere Größenordnungen umfassen (z. B. Lernraten).randint(
lower
,upper
): Nimmt eine ganze Zahl gleichmäßig zwischen dem unteren (inklusive) und oberen (exklusive) Wert auf. Geeignet für diskrete Parameter wie die Anzahl der Ebenen.choice(options): Wählt zufällig einen Wert aus einer vorgegebenen Liste aus. Wird oft für kategorische Parameter verwendet.
Im Folgenden finden Sie ein Beispiel dafür, wie Sie den Suchraum mit der Uniform-Funktion definieren können:
search_space = {
"n_estimators": tune.uniform(50, 200),
"max_depth": tune.uniform(3, 10),
"learning_rate": tune.uniform(0.01, 0.3),
}
Konfigurieren Sie den Tuner¶
Verwenden Sie das Objekt TunerConfig
, um den Tuner zu konfigurieren. Innerhalb des Objekts geben Sie die zu optimierende Metrik, den Optimierungsmodus und die anderen Ausführungsparameter an. Im Folgenden finden Sie die verfügbaren Konfigurationsoptionen:
Metrik Die Leistungsmetrik, wie z. B. Genauigkeit oder Verlust, die Sie optimieren möchten.
Modus bestimmt, ob das Ziel darin besteht, die Metrik zu maximieren oder zu minimieren (
"max"
oder"min"
).Suchalgorithmus legt die Strategie zur Erkundung des Hyperparameterraums fest.
Anzahl der Versuche legt die Gesamtzahl der zu bewertenden Hyperparameter-Konfigurationen fest.
Parallelität legt fest, wie viele Versuche gleichzeitig laufen können.
Der folgende Beispielcode verwendet die Bayes’sche Optimierungsbibliothek, um die Genauigkeit eines Modells über fünf Versuche zu maximieren.
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,
)
Holen Sie sich die Hyperparameter und Trainingsmetriken¶
Die Snowflake ML HPO-API benötigt die Trainingsmetriken und Hyperparameter aus jedem Trainingslauf, um die Hyperparameter effektiv zu optimieren. Verwenden Sie das Objekt TunerContext
, um die Hyperparameter und Trainingsmetriken zu erhalten. Das folgende Beispiel erstellt eine Trainingsfunktion, um die Hyperparameter und Trainingsmetriken zu ermitteln:
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)
Initiieren Sie den Trainings-Job¶
Verwenden Sie das Objekt Tuner
, um den Trainings-Job zu starten. Das Objekt Tuner
nimmt die Trainingsfunktion, den Suchraum und die Tuner-Konfiguration als Argumente an. Im Folgenden finden Sie ein Beispiel dafür, wie Sie den Trainings-Job initiieren:
from snowflake.ml.modeling import tune
tuner = tune.Tuner(train_func, search_space, tuner_config)
tuner_results = tuner.run(dataset_map=dataset_map)
Der vorangehende Code verteilt die Trainingsfunktion auf die verfügbaren Ressourcen. Es sammelt und fasst die Versuchsergebnisse zusammen und identifiziert die beste Konfiguration.
Holen Sie sich die Ergebnisse des Trainings-Jobs¶
Nachdem alle Versuche abgeschlossen sind, konsolidiert das Objekt
TunerResults
die Ergebnisse der einzelnen Versuche. Es bietet einen strukturierten Zugang zu den Leistungsmetriken, der besten Konfiguration und dem besten Modell.Im Folgenden finden Sie die verfügbaren Attribute:
results: Ein pandas-DataFrame mit Metriken und Konfigurationen für jeden Versuch.
best_result:: Eine DataFrame-Zeile, die den Versuch mit der besten Leistung zusammenfasst.
best_model: Die mit der besten Studie verbundene Modellinstanz, falls zutreffend.
Der folgende Code liefert die Ergebnisse, das beste Modell und das beste Ergebnis:
print(tuner_results.results)
print(tuner_results.best_model)
print(tuner_results.best_result)
API-Referenz¶
Tuner¶
Im Folgenden finden Sie die Import-Anweisung für das Tuner-Modul:
from snowflake.ml.modeling.tune import Tuner
Die Tuner-Klasse ist die Hauptschnittstelle für die Interaktion mit der Container Runtime HPO-API. Um einen HPO-Job auszuführen, verwenden Sie den folgenden Code, um ein Tuner-Objekt zu initialisieren und die Run-Methode mit den Snowflake-Datensätzen aufzurufen.
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
SearchSpace¶
Im Folgenden finden Sie die Importanweisung für den Suchraum:
from entities.search_space import uniform, choice, loguniform, randint
Der folgende Code definiert die Suchraumfunktionen:
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']
"""
TunerConfig¶
Im Folgenden finden Sie die Importanweisung für das TunerConfig-Modul:
from snowflake.ml.modeling.tune import TunerConfig
Verwenden Sie den folgenden Code, um die Konfigurationsklasse für den Tuner zu definieren:
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
... )
"""
SearchAlgorithm¶
Im Folgenden finden Sie die Importanweisung für den Suchalgorithmus:
from entities.search_algorithm import BayesOpt, RandomSearch, GridSearch
Der folgende Code erstellt ein Objekt für einen Suchalgorithmus der Bayes’schen Optimierung:
@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
Der folgende Code erstellt ein Objekt für einen zufälligen Suchalgorithmus:
@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
TunerResults¶
Im Folgenden finden Sie die Importanweisung für das TunerResults-Modul:
from entities.tuner_results import TunerResults
Der folgende Code erstellt ein TunerResults-Objekt:
@dataclass
class TunerResults:
results: pd.DataFrame
best_result: pd.DataFrame
best_model: Optional[Any]
get_tuner_context¶
Im Folgenden finden Sie die Importanweisung für das get_tuner_context
-Modul:
from snowflake.ml.modeling.tune import get_tuner_context
Diese Hilfsmethode ist dafür gedacht, innerhalb der Trainingsfunktion aufgerufen zu werden. Sie gibt ein TunerContext-Objekt zurück, das mehrere nützliche Felder für die Durchführung der Studie enthält, darunter:
Vom HPO-Framework für die aktuelle Studie ausgewählte Hyperparameter.
Der für das Training benötigte Datensatz.
Eine Hilfsfunktion zum Berichten von Metriken, die das HPO-Framework beim Vorschlagen des nächsten Satzes von Hyperparametern unterstützt
Der folgende Code erstellt ein Tuner-Kontextobjekt:
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
Einschränkungen¶
Die Bayes’sche Optimierung erfordert kontinuierliche Suchräume und funktioniert nur mit der einheitlichen Stichprobenfunktion. Sie ist nicht kompatibel mit diskreten Parametern, die mit den tune.randint
- oder tune.choice
-Methoden ausgewählt werden. Um diese Beschränkung zu umgehen, verwenden Sie entweder tune.uniform
und wandeln den Parameter innerhalb der Trainingsfunktion um, oder Sie wechseln zu einem Sampling-Algorithmus, der sowohl diskrete als auch kontinuierliche Räume verarbeitet, wie z. B. tune.RandomSearch
.
Problembehandlung¶
Fehlermeldung |
Mögliche Ursachen |
Mögliche Lösungen |
---|---|---|
Ungültige Suchraumkonfiguration: BayesOpt verlangt, dass alle Sampling-Funktionen vom Typ „Uniform“ sind. |
Die Bayes’sche Optimierung funktioniert nur mit einheitlichem Sampling, nicht mit diskreten Stichproben. (Siehe Einschränkungen oben.) |
|
Unzureichende CPU-Ressourcen. Benötigt: 16, Verfügbar: 8. Die Anzahl der erforderlichen und verfügbaren Ressourcen kann unterschiedlich sein. |
|
Folgen Sie den Anweisungen in der Fehlermeldung. |
Unzureichende GPU-Ressourcen. Benötigt: 4, verfügbar: 2. Kann sich auf CPU oder GPU beziehen. Die Anzahl der erforderlichen und verfügbaren Ressourcen kann unterschiedlich sein. |
|
Folgen Sie den Anweisungen in der Fehlermeldung. |