Implementare un lavoro AutoML personalizzato utilizzando algoritmi preselezionati in Amazon SageMaker Automatic Model Tuning

Creare un lavoro personalizzato di AutoML utilizzando algoritmi preselezionati in Amazon SageMaker Automatic Model Tuning

AutoML ti consente di ottenere rapidamente informazioni generali dai tuoi dati all’inizio di un progetto di machine learning (ML). Capire in anticipo quali tecniche di pre-elaborazione e tipi di algoritmo offrono i migliori risultati riduce il tempo per sviluppare, addestrare e implementare il modello corretto. Gioca un ruolo cruciale in ogni processo di sviluppo del modello e consente ai data scientist di concentrarsi sulle tecniche di ML più promettenti. Inoltre, AutoML fornisce una prestazione di modello di base che può fungere da punto di riferimento per il team di data science.

Un tool di AutoML applica una combinazione di algoritmi diversi e diverse tecniche di pre-elaborazione ai tuoi dati. Ad esempio, può scalare i dati, eseguire una selezione delle feature univariate, condurre una PCA a diversi livelli di soglia di varianza e applicare il clustering. Tali tecniche di pre-elaborazione potrebbero essere applicate singolarmente o combinate in un flusso di lavoro. Successivamente, un tool di AutoML addestrerà diversi tipi di modello, come la regressione lineare, Elastic-Net o Random Forest, su diverse versioni del tuo dataset pre-elaborato e eseguirà l’ottimizzazione degli iperparametri (HPO). Amazon SageMaker Autopilot elimina il lavoro impegnativo per la creazione di modelli di ML. Dopo aver fornito il dataset, SageMaker Autopilot esplora automaticamente diverse soluzioni per trovare il miglior modello. Ma cosa succede se vuoi implementare la tua versione personalizzata di un flusso di lavoro AutoML?

Questo post mostra come creare un flusso di lavoro AutoML su misura su Amazon SageMaker utilizzando Amazon SageMaker Automatic Model Tuning con il codice di esempio disponibile in un repository GitHub.

Panoramica della soluzione

In questo caso d’uso, supponiamo che tu faccia parte di un team di data science che sviluppa modelli in un dominio specializzato. Hai sviluppato un insieme di tecniche personalizzate di pre-elaborazione e selezionato un numero di algoritmi che ti aspetti tipicamente funzionino bene con il tuo problema di ML. Quando lavori su nuovi casi d’uso di ML, vorresti prima eseguire una fase di AutoML utilizzando le tue tecniche di pre-elaborazione e algoritmi per restringere il campo delle possibili soluzioni.

In questo esempio, non utilizzi un dataset specializzato; al contrario, lavori con il dataset California Housing che importerai da Amazon Simple Storage Service (Amazon S3). L’obiettivo è dimostrare l’implementazione tecnica della soluzione utilizzando SageMaker HPO, che in seguito può essere applicato a qualsiasi dataset e dominio.

Il diagramma seguente presenta il flusso di lavoro della soluzione nel complesso.

Diagramma dell'architettura che mostra i passaggi spiegati nella sezione seguente.

Prerequisiti

I seguenti sono prerequisiti per completare la guida di questo post:

  • Un account AWS
  • Familiarità con i concetti di SageMaker, come Estimator, job di addestramento e job di HPO
  • Familiarità con l’Amazon SageMaker Python SDK
  • Conoscenza della programmazione Python

Implementare la soluzione

Il codice completo è disponibile nel repository GitHub.

I passaggi per implementare la soluzione (come indicato nel diagramma del flusso di lavoro) sono i seguenti:

  1. Creare una istanza del notebook e specificare quanto segue:
    1. Per il tipo di istanza del notebook, scegliere ml.t3.medium.
    2. Per Inferenza elastica, scegliere nessuna.
    3. Per Indentificatore della piattaforma, scegliere Amazon Linux 2, Jupyter Lab 3.
    4. Per Ruolo IAM, scegliere il AmazonSageMaker-ExecutionRole predefinito. Se non esiste, creare un nuovo Ruolo di accesso e gestione delle identità di AWS (IAM) e allegare la policy IAM AmazonSageMakerFullAccess.

È importante creare un ruolo di esecuzione e una policy minimamente limitati per l’ambiente di produzione.

  1. Aprire l’interfaccia JupyterLab per la tua istanza del notebook e clonare il repository GitHub.

Puoi farlo avviando una nuova sessione terminale e eseguendo il comando git clone <REPO> o utilizzando la funzionalità dell’interfaccia utente, come mostrato nell’immagine seguente.

Pulsante di integrazione di git in JupyterLab

  1. Aprire il file notebook automl.ipynb, selezionare il kernel conda_python3 e seguire le istruzioni per avviare un insieme di job HPO.

Per eseguire il codice senza alcuna modifica, è necessario aumentare la quota di servizio per ml.m5.large per l’utilizzo dei job di training e Numero di istanze per tutti i job di training. AWS consente solo 20 job di training paralleli in contemporanea per entrambe le quote. È necessario richiedere un aumento della quota a 30 per entrambe. Di solito, entrambi i cambiamenti di quota vengono approvati entro pochi minuti. Consultare la guida Richiesta di aumento della quota per ulteriori informazioni.

Pagina delle quote di servizio AWS che consente di richiedere un aumento delle istanze di training parallele

Se non si desidera modificare la quota, è sufficiente modificare il valore della variabile MAX_PARALLEL_JOBS nello script (ad esempio, a 5).

  1. Ogni job HPO completerà un set di job di training prove e indicherà il modello con gli iperparametri ottimali.
  2. Analizzare i risultati e deployare il modello con le prestazioni migliori.

Questa soluzione comporterà costi sul tuo account AWS. Il costo della soluzione dipenderà dal numero e dalla durata dei job di training HPO. Aumentando questi, aumenteranno anche i costi. È possibile ridurre i costi limitando il tempo di training e configurando TuningJobCompletionCriteriaConfig secondo le istruzioni discusse in seguito in questo post. Per informazioni sui prezzi, consultare la pagina Prezzi di Amazon SageMaker.

Nelle sezioni seguenti, discutiamo in dettaglio il quaderno con esempi di codice e i passaggi per analizzare i risultati e selezionare il miglior modello.

Impostazione iniziale

Iniziamo eseguendo la sezione Importazioni e configurazioni nel quaderno custom-automl.ipynb. Vengono installate e importate tutte le dipendenze necessarie, viene istanziata una sessione e un client SageMaker, e viene impostata la regione e l’utilizzo predefinito del bucket S3 per archiviare i dati.

Preparazione dei dati

Scarica il set di dati California Housing e preparalo eseguendo la sezione Scarica dati del quaderno. Il dataset viene diviso in frame di dati di addestramento e di test e caricato nel bucket S3 predefinito della sessione SageMaker.

L’intero set di dati contiene 20.640 record e un totale di 9 colonne, compresa la variabile target. Lo scopo è quello di prevedere il valore mediano di una casa (colonna medianHouseValue). La seguente schermata mostra le prime righe del set di dati.

Prime cinque righe del frame di dati delle abitazioni in California che mostra la struttura della tabella

Modello di script di addestramento

Il flusso di lavoro AutoML in questo post si basa su scikit-learn pipeline di preprocessing e algoritmi. L’obiettivo è generare una vasta combinazione di diverse pipeline di preprocessing e algoritmi per trovare la migliore configurazione in termini di prestazioni. Iniziamo creando uno script di addestramento generico, che viene salvato localmente nell’istanza del quaderno. In questo script, ci sono due blocchi di commenti vuoti: uno per l’iniezione di iperparametri e l’altro per l’oggetto di pipeline preprocessing-modello. Verranno iniettati dinamicamente per ogni modello di preprocessing candidato. Lo scopo di avere uno script generico è quello di mantenere l’implementazione DRY (don’t repeat yourself).

#crea script base_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############################## Funzioni di inferenza ##############################def model_fn(model_dir):clf = joblib.load(os.path.join(model_dir, "model.joblib"))return clfif __name__ == "__main__":print("Estrazione degli argomenti")parser = argparse.ArgumentParser()# Iperparametri##### VERRANNO INSERITI DINAMICAMENTE #####{}############################# Directory di dati, modello e outputparser.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()# Carica e prepara i datatrain_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]# Modello di addestramento##### VERRANNO INSERITI DINAMICAMENTE #####{}{}############################pipeline = Pipeline([('preprocessor', preprocessor), ('model', model)])pipeline.fit(X_train, y_train)# Valida il modello e stampa le metrichermse = mean_squared_error(y_test, pipeline.predict(X_test), squared=False)print("RMSE: " + str(rmse))# Salva il modellopercorso = os.path.join(args.model_dir, "model.joblib")joblib.dump(pipeline, percorso)"""# scrivere _script in un file solo per averlo a portata di manowith open("script_draft.py", "w") as f:print(_script, file=f)

Crea combinazioni di preprocessing e modelli

Il dizionario preprocessors contiene una specifica delle tecniche di preprocessing applicate a tutte le caratteristiche di input del modello. Ogni ricetta è definita utilizzando un oggetto Pipeline o FeatureUnion di scikit-learn, che concatenano singole trasformazioni dei dati e le combinano insieme. Ad esempio, mean-imp-scale è una semplice ricetta che garantisce che i valori mancanti vengano imputati utilizzando i valori medi delle rispettive colonne e che tutte le caratteristiche vengano scalate utilizzando il StandardScaler. Al contrario, la ricetta mean-imp-scale-pca concatena alcune operazioni aggiuntive:

  1. Assegna i valori mancanti nelle colonne con la loro media.
  2. Applica la ridimensionamento delle caratteristiche utilizzando la media e la deviazione standard.
  3. Calcola la PCA in cima ai dati di input a un valore di soglia di varianza specificato e uniscilo insieme alle caratteristiche di input imputate e scalate.

In questo post, tutte le caratteristiche di input sono numeriche. Se hai più tipi di dati nel tuo dataset di input, dovresti specificare una pipeline più complicata in cui vengono applicati rami di preprocessing diversi a diversi set di tipi di caratteristiche.

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"   }

Il dizionario models contiene le specifiche di diversi algoritmi su cui addestri il dataset. Ogni tipo di modello ha la seguente specifica nel dizionario:

  • script_output – Punti alla posizione dello script di addestramento utilizzato dall’estimatore. Questo campo viene compilato dinamicamente quando il dizionario models viene combinato con il dizionario preprocessors.
  • insertions – Definisce il codice che verrà inserito nel file script_draft.py e successivamente salvato in script_output.La chiave “preprocessor” è intenzionalmente lasciata vuota perché questa posizione viene riempita con uno dei preprocessors al fine di creare più combinazioni modello-preprocessor.
  • hyperparameters – Un set di iperparametri che vengono ottimizzati dal lavoro HPO.
  • include_cls_metadata – Ulteriori dettagli di configurazione richiesti dalla classe Tuner di SageMaker.

Un esempio completo del dizionario models è disponibile nel repository 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,    }}

Successivamente, iteriamo attraverso i dizionari preprocessors e models e creiamo tutte le possibili combinazioni. Ad esempio, se il dizionario preprocessors contiene 10 ricette e hai 5 definizioni di modello nel dizionario models, il dizionario pipelines contiene 50 pipeline di pre-elaboratore-modello che vengono valutate durante l’HPO. Notare che gli script delle pipeline individuali non vengono creati ancora in questo momento. Il blocco di codice successivo (cella 9) del notebook di Jupyter itera su tutti gli oggetti di preelaboratore-modello nella pipeline, inserisce tutti i pezzi di codice pertinenti e salva localmente una versione specifica della pipeline dello script. Questi script sono utilizzati nei passaggi successivi quando si creano stimatori individuali che vengono collegati al lavoro HPO.

“`html

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"

Definisci gli estimatori

Ora puoi lavorare sulla definizione degli estimatori SageMaker che vengono utilizzati dopo che gli script sono pronti per il lavoro HPO. Iniziamo creando una classe wrapper che definisce alcune proprietà comuni per tutti gli estimatori. Eredita dalla classe SKLearn e specifica il ruolo, il conteggio delle istanze e il tipo, nonché le colonne utilizzate dallo script come feature e target.

class SKLearnBase(SKLearn):    def __init__(        self,         entry_point=".", # intenzionalmente vuoto, verrà sovrascritto nella prossima funzione        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        )

Costruiamo ora il dizionario estimators iterando attraverso tutti gli script generati in precedenza e situati nella directory scripts. Istanziamo un nuovo estimator utilizzando la classe SKLearnBase, con un nome di estimator unico e uno degli script. Nota che il dizionario estimators ha due livelli: il livello superiore definisce una pipeline_family. Questa è una raggruppamento logico basato sul tipo di modelli da valutare ed è uguale alla lunghezza del dizionario models. Il secondo livello contiene i singoli tipi di preprocessor combinati con la pipeline_family data. Questo raggruppamento logico è necessario durante la creazione del lavoro 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,            )

Definisci gli argomenti HPO tuner

Per ottimizzare il passaggio di argomenti nella classe HPO Tuner, la classe dati HyperparameterTunerArgs viene inizializzata con gli argomenti richiesti dalla classe HPO. Viene fornito un insieme di funzioni che garantiscono che gli argomenti HPO siano restituiti in un formato previsto durante la distribuzione di più definizioni di modello contemporaneamente.

@dataclassclass 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)}

“`

Il blocco di codice successivo utilizza la classe dati HyperparameterTunerArgs precedentemente introdotta. Si crea un altro dizionario chiamato hp_args e si genera un insieme di parametri di input specifici per ogni estimator_family dal dizionario estimators. Questi argomenti vengono utilizzati nel passaggio successivo durante l’inizializzazione dei lavori HPO per ogni famiglia di modelli.

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()],    )

Creazione di oggetti HPO tuner

In questo passaggio, si creano sintonizzatori individuali per ogni estimator_family. Perché si creano tre lavori HPO separati anziché lanciarne solo uno su tutti gli estimatori? La classe HyperparameterTuner è limitata a 10 definizioni di modelli ad essa collegati. Pertanto, ogni HPO è responsabile della ricerca del preelaboratore che produce i migliori risultati per una determinata famiglia di modelli e del tuning degli iperparametri di quella famiglia di modelli.

Ecco alcuni altri punti riguardanti la configurazione:

  • La strategia di ottimizzazione è bayesiana, il che significa che l’HPO monitora attivamente le prestazioni di tutte le prove e orienta l’ottimizzazione verso combinazioni di iperparametri più promettenti. L’arresto anticipato dovrebbe essere impostato su Off o Auto quando si lavora con una strategia bayesiana, che gestisce autonomamente questa logica.
  • Ogni lavoro HPO viene eseguito per un massimo di 100 lavori e ne vengono eseguiti 10 in parallelo. Se si stanno gestendo set di dati più grandi, potrebbe essere necessario aumentare il numero totale di lavori.
  • Inoltre, potrebbe essere opportuno utilizzare impostazioni che controllano la durata di esecuzione di un lavoro e il numero di lavori che il vostro HPO sta avviando. Un modo per farlo è impostare il tempo di esecuzione massimo in secondi (per questo post, lo abbiamo impostato su 1 ora). Un altro modo consiste nell’utilizzare la recentemente pubblicata TuningJobCompletionCriteriaConfig. Essa offre un insieme di impostazioni che monitorano il progresso dei vostri lavori e decidono se è probabile che ulteriori lavori migliorino il risultato. In questo post, abbiamo impostato il numero massimo di lavori di addestramento che non migliorano a 20. In questo modo, se il punteggio non sta migliorando (ad esempio, dalla quarantesima prova in poi), non sarà necessario pagare per le prove rimanenti fino a raggiungere max_jobs.
STRATEGY = "Bayesian"OBJECTIVE_TYPE = "Minimize"MAX_JOBS = 100MAX_PARALLEL_JOBS = 10MAX_RUNTIME_IN_SECONDS = 3600EARLY_STOPPING_TYPE = "Off"# RANDOM_SEED = 42 # rimuovere il commento se si desidera la riproducibilità tra le esecuzioniTUNING_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, # l'arresto anticipato dei lavori di addestramento non è attualmente supportato quando vengono utilizzate più definizioni di lavoro di addestramento        # random_seed=RANDOM_SEED,    )

Ora iteriamo attraverso i dizionari tuners e hp_args e avviamo tutti i lavori HPO in SageMaker. Notare l’uso dell’argomento di attesa impostato su False, ciò significa che il kernel non aspetterà finché i risultati non saranno completi e potrete avviare tutti i lavori contemporaneamente.

È probabile che non tutti i lavori di formazione siano completati e alcuni di essi potrebbero essere interrotti dal lavoro HPO. Il motivo è il TuningJobCompletionCriteriaConfig: l’ottimizzazione termina se viene soddisfatto uno qualsiasi dei criteri specificati. In questo caso, quando i criteri di ottimizzazione non migliorano per 20 lavori consecutivi.

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,        )

Analizza i risultati

La cella 15 del notebook controlla se tutti i lavori HPO sono completi e combina tutti i risultati in forma di un dataframe pandas per ulteriori analisi. Prima di analizzare i risultati in dettaglio, diamo un’occhiata generale alla console di SageMaker.

In cima alla pagina Lavori di ottimizzazione iperparametrica, puoi vedere i tre lavori HPO lanciati. Tutti hanno terminato in anticipo e non hanno effettuato tutti i 100 lavori di formazione. Nella schermata seguente, puoi vedere che la famiglia di modelli Elastic-Net ha completato il numero più elevato di prove, mentre gli altri non hanno avuto bisogno di così tanti lavori di formazione per trovare il miglior risultato.

Console dei lavori di ottimizzazione iperparametrica di SageMaker che mostra lo stato dei tre lavori HPO avviati

Puoi aprire il lavoro HPO per accedere a ulteriori dettagli, come singoli lavori di formazione, configurazione del lavoro e informazioni sul miglior lavoro di formazione e sulle sue prestazioni.

Vista dettagliata di uno dei lavori HPO selezionati

Produciamo una visualizzazione basata sui risultati per ottenere ulteriori informazioni sulle prestazioni del flusso di lavoro di AutoML attraverso tutte le famiglie di modelli.

Dal grafico seguente, puoi concludere che le prestazioni del modello Elastic-Net oscillavano tra 70.000 e 80.000 RMSE e alla fine si sono fermate, poiché l’algoritmo non è stato in grado di migliorare le sue prestazioni nonostante abbia provato varie tecniche di preelaborazione e valori degli iperparametri. Sembra anche che le prestazioni di RandomForest siano variate molto a seconda dell’insieme di iperparametri esplorati da HPO, ma nonostante molti tentativi non è stato possibile scendere al di sotto dell’errore RMSE di 50.000. GradientBoosting ha ottenuto le migliori prestazioni fin dall’inizio scendendo al di sotto di 50.000 RMSE. HPO ha cercato di migliorare ulteriormente quel risultato, ma non è stato in grado di ottenere prestazioni migliori con altre combinazioni di iperparametri. Una conclusione generale per tutti i lavori HPO è che non sono stati necessari molti lavori per trovare l’insieme di iperparametri migliori per ogni algoritmo. Per migliorare ulteriormente il risultato, sarebbe necessario sperimentare la creazione di più funzionalità e ulteriori tecniche di ingegneria delle caratteristiche.

Variazione del valore obiettivo HPO nel tempo per ogni famiglia di modelli

Puoi anche esaminare una vista più dettagliata della combinazione modello-preprocessore per trarre conclusioni sulle combinazioni più promettenti.

Variazione del valore obiettivo HPO nel tempo per ogni combinazione modello-preprocessore

Seleziona il miglior modello e deployalo

Il seguente frammento di codice seleziona il miglior modello in base al valore obiettivo più basso raggiunto. Puoi quindi deployare il modello come endpoint di 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}",)

Pulizia

Per evitare addebiti indesiderati sul tuo account AWS, ti consigliamo di eliminare le risorse AWS utilizzate in questo post:

  1. Nella console Amazon S3, svuota i dati dal bucket S3 in cui erano archiviati i dati di addestramento.

Console Amazon S3 che mostra come svuotare o eliminare completamente un bucket

  1. Nella console SageMaker, interrompi l’istanza del notebook.

Console istanze del notebook di SageMaker che mostra come interrompere un'istanza

  1. Elimina il punto di fine del modello se lo hai distribuito. I punti finali dovrebbero essere eliminati quando non sono più in uso, poiché vengono addebitati per il tempo di distribuzione.
sm_client.delete_endpoint(EndpointName=predictor.endpoint)

Conclusione

In questo post, abbiamo mostrato come creare un lavoro HPO personalizzato in SageMaker utilizzando una selezione personalizzata di algoritmi e tecniche di preprocessing. In particolare, questo esempio illustra come automatizzare il processo di generazione di molti script di addestramento e come utilizzare strutture di programmazione Python per un efficiente deployment di numerosi lavori di ottimizzazione parallela. Speriamo che questa soluzione costituisca la struttura di qualsiasi lavoro di messa a punto di modelli personalizzati che si voglia effettuare utilizzando SageMaker per ottenere prestazioni migliori e velocizzare i flussi di lavoro di machine learning.

Consulta le risorse seguenti per approfondire ulteriormente la tua conoscenza su come utilizzare SageMaker HPO: