Creare un modello in Amazon SageMaker AI con ModelBuilder - Amazon SageMaker AI

Creare un modello in Amazon SageMaker AI con ModelBuilder

La preparazione del modello per l’implementazione su un endpoint SageMaker AI richiede diversi passaggi, tra cui la scelta di un’immagine del modello, l’impostazione della configurazione dell’endpoint, la codifica delle funzioni di serializzazione e deserializzazione per trasferire dati da e verso server e client, l’identificazione delle dipendenze del modello e il caricamento su Amazon S3. ModelBuilder può ridurre la complessità della configurazione e dell’implementazione iniziali per consentire di creare un modello implementabile in un’unica fase.

ModelBuilder esegue automaticamente le seguenti attività:

  • Converte i modelli di machine learning addestrati utilizzando vari framework, come XGBoost o PyTorch, in modelli implementabili in un’unica fase.

  • Esegue la selezione automatica del container in base al framework del modello, in modo da non doverlo specificare manualmente. È comunque possibile importare un container personale passando l’URI a ModelBuilder.

  • Gestisce la serializzazione dei dati sul lato client prima di inviarli al server per l’inferenza e la deserializzazione dei risultati restituiti dal server. I dati vengono formattati correttamente senza elaborazione manuale.

  • Consente l’acquisizione automatica delle dipendenze e crea un pacchetto del modello in base alle aspettative del server del modello. L’acquisizione automatica delle dipendenze da parte di ModelBuilder è l’approccio ottimale per caricare le dipendenze in modo dinamico. È consigliabile testare l’acquisizione automatica a livello locale e aggiornare le dipendenze in base alle esigenze.

  • Per i casi d’uso di modelli linguistici di grandi dimensioni (LLM), esegue facoltativamente l’ottimizzazione locale dei parametri delle proprietà di servizio che possono essere implementate per migliorare le prestazioni durante l’hosting su un endpoint SageMaker AI.

  • Supporta la maggior parte dei server e container di modelli più diffusi, come TorchServe, Triton, DJLServing e TGI.

Creare un modello con ModelBuilder

ModelBuilder è una classe Python che accetta un modello di framework, come XGBoost o PyTorch, o una specifica di inferenza specificata dall’utente e la converte in un modello implementabile. ModelBuilder fornisce una funzione che genera gli artefatti per l’implementazione. L’artefatto del modello generato è specifico del server del modello, che è anche possibile specificare come uno degli input. Per maggiori dettagli sulla classe ModelBuilder, consulta ModelBuilder.

Il diagramma seguente illustra il flusso di lavoro generale per la creazione del modello in caso di utilizzo di ModelBuilder. ModelBuilder accetta un modello o una specifica di inferenza insieme allo schema per creare un modello implementabile che è possibile testare localmente prima dell’implementazione.

Flusso di creazione e implementazione del modello mediante ModelBuilder.

ModelBuilder è in grado di gestire qualsiasi personalizzazione da applicare. Tuttavia, per implementare un modello di framework, il generatore di modelli prevede almeno un modello, un input e un output di esempio e il ruolo. Nel seguente esempio di codice, ModelBuilder viene chiamato con un modello di framework e un’istanza di SchemaBuilder con argomenti minimi (per dedurre le funzioni corrispondenti per la serializzazione e la deserializzazione dell’input e dell’output dell’endpoint). Non viene specificato alcun container e non vengono passati pacchetti di dipendenze: SageMaker AI deduce automaticamente queste risorse in fase di creazione del modello.

from sagemaker.serve.builder.model_builder import ModelBuilder from sagemaker.serve.builder.schema_builder import SchemaBuilder model_builder = ModelBuilder( model=model, schema_builder=SchemaBuilder(input, output), role_arn="execution-role", )

Il seguente esempio di codice invoca ModelBuilder con una specifica di inferenza (come un’istanza di InferenceSpec) anziché con un modello, con personalizzazione aggiuntiva. In questo caso, la chiamata al generatore di modelli include un percorso per archiviare gli artefatti del modello e attiva anche l’acquisizione automatica di tutte le dipendenze disponibili. Per ulteriori dettagli su InferenceSpec, consulta Personalizzare il caricamento del modello e la gestione delle richieste.

model_builder = ModelBuilder( mode=Mode.LOCAL_CONTAINER, model_path=model-artifact-directory, inference_spec=your-inference-spec, schema_builder=SchemaBuilder(input, output), role_arn=execution-role, dependencies={"auto": True} )

Definire i metodi di serializzazione e deserializzazione

In fase di invocazione di un endpoint SageMaker AI, i dati vengono inviati tramite payload HTTP con diversi tipi MIME. Ad esempio, un’immagine inviata all’endpoint per l’inferenza deve essere convertita in byte sul lato client e inviata tramite un payload HTTP all’endpoint. Quando l’endpoint riceve il payload, deve deserializzare la stringa di byte riportandola al tipo di dati previsto dal modello (processo noto anche come deserializzazione lato server). Dopo che il modello ha terminato la previsione, è inoltre necessario serializzare i risultati in byte che possono essere inviati nuovamente all’utente o al client tramite il payload HTTP. Una volta ricevuti i dati dei byte di risposta, il client deve eseguire la deserializzazione lato client per riconvertire i dati in byte nel formato di dati previsto, ad esempio JSON. Come condizione minima, è necessario convertire i dati per le seguenti attività:

  1. Serializzazione della richiesta di inferenza (gestita dal client)

  2. Deserializzazione della richiesta di inferenza (gestita dal server o dall’algoritmo)

  3. Invocazione del modello con il payload e invio del payload di risposta

  4. Serializzazione della risposta di inferenza (gestita dal server o dall’algoritmo)

  5. Deserializzazione della risposta di inferenza (gestita dal client)

Il diagramma seguente mostra i processi di serializzazione e deserializzazione che si verificano quando si invoca l’endpoint.

Diagramma della serializzazione e deserializzazione dei dati da client a server.

Quando vengono forniti input e output di esempio a SchemaBuilder, il generatore di schemi genera le funzioni di marshalling corrispondenti per la serializzazione e la deserializzazione dell’input e dell’output. È possibile personalizzare ulteriormente le funzioni di serializzazione con CustomPayloadTranslator. Nella maggior parte dei casi, tuttavia, è sufficiente un serializzatore semplice come il seguente:

input = "How is the demo going?" output = "Comment la démo va-t-elle?" schema = SchemaBuilder(input, output)

Per ulteriori dettagli su SchemaBuilder, consulta SchemaBuilder.

Il seguente frammento di codice illustra un esempio in cui si desidera personalizzare le funzioni di serializzazione e deserializzazione sui lati client e server. È possibile definire specifici convertitori di richieste e risposte con CustomPayloadTranslator e passare questi convertitori a SchemaBuilder.

Includendo gli input e gli output con i convertitori, il generatore di modelli può estrarre il formato di dati previsto dal modello. Ad esempio, si supponga che l’input di esempio sia un’immagine non elaborata e che i convertitori personalizzati ritaglino l’immagine e la inviino al server come tensore. ModelBuilder necessita sia dell’input non elaborato che di qualsiasi codice di pre-elaborazione o post-elaborazione personalizzato per ricavare un metodo per convertire i dati sui lati client e server.

from sagemaker.serve import CustomPayloadTranslator # request translator class MyRequestTranslator(CustomPayloadTranslator): # This function converts the payload to bytes - happens on client side def serialize_payload_to_bytes(self, payload: object) -> bytes: # converts the input payload to bytes ... ... return //return object as bytes # This function converts the bytes to payload - happens on server side def deserialize_payload_from_stream(self, stream) -> object: # convert bytes to in-memory object ... ... return //return in-memory object # response translator class MyResponseTranslator(CustomPayloadTranslator): # This function converts the payload to bytes - happens on server side def serialize_payload_to_bytes(self, payload: object) -> bytes: # converts the response payload to bytes ... ... return //return object as bytes # This function converts the bytes to payload - happens on client side def deserialize_payload_from_stream(self, stream) -> object: # convert bytes to in-memory object ... ... return //return in-memory object

L’input e l’output di esempio vengono passati insieme ai convertitori personalizzati definiti in precedenza durante la creazione dell’oggetto SchemaBuilder, come illustrato nell’esempio seguente:

my_schema = SchemaBuilder( sample_input=image, sample_output=output, input_translator=MyRequestTranslator(), output_translator=MyResponseTranslator() )

Quindi, l’input e l’output di esempio, insieme ai convertitori personalizzati definiti in precedenza, vengono passati all’oggetto SchemaBuilder.

my_schema = SchemaBuilder( sample_input=image, sample_output=output, input_translator=MyRequestTranslator(), output_translator=MyResponseTranslator() )

Le sezioni seguenti spiegano in dettaglio come generare un modello ModelBuilder e utilizzare le relative classi di supporto per personalizzare l’esperienza in base al caso d’uso.

Personalizzare il caricamento del modello e la gestione delle richieste

Fornire il proprio codice di inferenza tramite InferenceSpec offre un ulteriore livello di personalizzazione. Con InferenceSpec, è possibile personalizzare le modalità di caricamento del modello e gestione delle richieste di inferenza in entrata, aggirando i meccanismi predefiniti. Questo livello di flessibilità è particolarmente utile in caso di utilizzo di modelli non standard o pipeline di inferenza personalizzate. È possibile personalizzare il metodo invoke per controllare il modo in cui il modello pre-elabora e post-elabora le richieste in entrata. Il metodo invoke garantisce che il modello gestisca correttamente le richieste di inferenza. L’esempio seguente utilizza InferenceSpec per generare un modello con la pipeline HuggingFace. Per ulteriori dettagli su InferenceSpec, fai riferimento a InferenceSpec.

from sagemaker.serve.spec.inference_spec import InferenceSpec from transformers import pipeline class MyInferenceSpec(InferenceSpec): def load(self, model_dir: str): return pipeline("translation_en_to_fr", model="t5-small") def invoke(self, input, model): return model(input) inf_spec = MyInferenceSpec() model_builder = ModelBuilder( inference_spec=your-inference-spec, schema_builder=SchemaBuilder(X_test, y_pred) )

Il seguente esempio illustra una variante più personalizzata di un esempio precedente. Un modello viene definito con una specifica di inferenza che presenta dipendenze. In questo caso, il codice nella specifica di inferenza dipende dal pacchetto lang-segment. L’argomento per dependencies contiene un’istruzione che indica al generatore di installare lang-segment mediante Git. Poiché il generatore di modelli è istruito dall’utente a eseguire un’installazione personalizzata di una dipendenza, la chiave auto è impostata su False per disattivare l’acquisizione automatica delle dipendenze.

model_builder = ModelBuilder( mode=Mode.LOCAL_CONTAINER, model_path=model-artifact-directory, inference_spec=your-inference-spec, schema_builder=SchemaBuilder(input, output), role_arn=execution-role, dependencies={"auto": False, "custom": ["-e git+https://github.com/luca-medeiros/lang-segment-anything.git#egg=lang-sam"],} )

Creare e implementare un modello personalizzato

Chiama la funzione build per creare un modello implementabile. Questa fase crea un codice di inferenza (come inference.py) nella directory di lavoro con il codice necessario per creare lo schema, eseguire la serializzazione e la deserializzazione di input e output ed eseguire altra logica personalizzata specificata dall’utente.

Come controllo di integrità, SageMaker AI comprime e serializza i file necessari per l’implementazione nell’ambito della funzione di generazione di ModelBuilder. Durante questo processo, SageMaker AI crea anche la firma HMAC per il file pickle e aggiunge la chiave segreta nell’API CreateModel come variabile di ambiente durante il metodo deploy (o create). L’avvio dell’endpoint utilizza la variabile di ambiente per convalidare l’integrità del file pickle.

# Build the model according to the model server specification and save it as files in the working directory model = model_builder.build()

Implementa il modello con il metodo deploy esistente. In questa fase, SageMaker AI configura un endpoint per ospitare il modello non appena inizia a generare previsioni sulle richieste in entrata. Sebbene ModelBuilder deduca le risorse dell’endpoint necessarie per implementare il modello, è possibile sovrascrivere tali stime con valori di parametro personalizzati. L’esempio seguente istruisce SageMaker AI a implementare il modello in una singola istanza di ml.c6i.xlarge. Un modello costruito da ModelBuilder consente la registrazione di log in tempo reale durante l’implementazione come funzionalità aggiuntiva.

predictor = model.deploy( initial_instance_count=1, instance_type="ml.c6i.xlarge" )

Per un controllo più granulare sulle risorse dell’endpoint assegnate al modello, è possibile utilizzare un oggetto ResourceRequirements. Con l’oggetto ResourceRequirements, è possibile richiedere un numero minimo di CPU, acceleratori e copie dei modelli da implementare. È anche possibile richiedere un limite minimo e un limite massimo di memoria (in MB). Per utilizzare questa funzionalità, è necessario specificare il tipo di endpoint comeEndpointType.INFERENCE_COMPONENT_BASED. L’esempio seguente richiede quattro acceleratori, una dimensione minima di memoria di 1.024 MB e una copia del modello da implementare in un endpoint di tipo EndpointType.INFERENCE_COMPONENT_BASED.

resource_requirements = ResourceRequirements( requests={ "num_accelerators": 4, "memory": 1024, "copies": 1, }, limits={}, ) predictor = model.deploy( mode=Mode.SAGEMAKER_ENDPOINT, endpoint_type=EndpointType.INFERENCE_COMPONENT_BASED, resources=resource_requirements, role="role" )

Importare un container personalizzato (Bring Your Own Container, BYOC)

Per importare un container personalizzato (esteso da un container SageMaker AI), è anche possibile specificare l’URI dell’immagine, come mostrato nell’esempio seguente. È inoltre necessario identificare il server del modello che corrisponde all’immagine per consentire a ModelBuilder di generare artefatti specifici per il server.

model_builder = ModelBuilder( model=model, model_server=ModelServer.TORCHSERVE, schema_builder=SchemaBuilder(X_test, y_pred), image_uri="123123123123.dkr.ecr.ap-southeast-2.amazonaws.com/byoc-image:xgb-1.7-1") )

Utilizzo di ModelBuilder in modalità locale

È possibile implementare il modello in locale utilizzando l’argomento mode per passare dal test locale all’implementazione in un endpoint e viceversa. È necessario archiviare gli artefatti del modello nella directory di lavoro, come mostrato nel frammento di codice seguente:

model = XGBClassifier() model.fit(X_train, y_train) model.save_model(model_dir + "/my_model.xgb")

Passa l’oggetto del modello, un’istanza di SchemaBuilder e imposta la modalità su Mode.LOCAL_CONTAINER. Durante la chiamata della funzione build, ModelBuilder identifica automaticamente il container framework supportato e cerca dipendenze. L’esempio seguente mostra la creazione di un modello con un modello XGBoost in modalità locale.

model_builder_local = ModelBuilder( model=model, schema_builder=SchemaBuilder(X_test, y_pred), role_arn=execution-role, mode=Mode.LOCAL_CONTAINER ) xgb_local_builder = model_builder_local.build()

Chiama la funzione deploy per l’implementazione locale, come mostrato nel frammento di codice seguente. In caso di specifica di parametri, ad esempio type o count, questi argomenti vengono ignorati.

predictor_local = xgb_local_builder.deploy()

Risoluzione dei problemi della modalità locale

A seconda della singola configurazione locale, potrebbero verificarsi problemi con l’esecuzione di ModelBuilder nell’ambiente in uso. Consulta l’elenco seguente per alcuni problemi che potresti riscontrare e come risolverli.

  • Already already in use: è possibile che si verifichi un errore Address already in use. In questo caso, un container Docker potrebbe essere in esecuzione sulla porta in questione oppure potrebbe essere utilizzato da un altro processo. È possibile seguire l’approccio descritto nella documentazione di Linux per identificare il processo e reindirizzare correttamente il processo locale dalla porta 8080 a un’altra porta o pulire l’istanza di Docker.

  • Problema di autorizzazione IAM: potresti riscontrare un problema di autorizzazione nel tentativo di estrarre un’immagine Amazon ECR o di accedere ad Amazon S3. In questo caso, accedi al ruolo di esecuzione del notebook o dell’istanza di Studio Classic per verificare la policy per SageMakerFullAccess o le rispettive autorizzazioni API.

  • Problema relativo alla capacità del volume EBS: se implementi un LLM, potresti esaurire lo spazio durante l’esecuzione di Docker in modalità locale o riscontrare limitazioni di spazio per la cache Docker. In questo caso, puoi provare a spostare il volume Docker su un file system con spazio sufficiente. Per spostare il volume Docker, completa i seguenti passaggi:

    1. Apri un terminale ed esegui df per visualizzare l’utilizzo del disco, come mostrato nel seguente output:

      (python3) sh-4.2$ df Filesystem 1K-blocks Used Available Use% Mounted on devtmpfs 195928700 0 195928700 0% /dev tmpfs 195939296 0 195939296 0% /dev/shm tmpfs 195939296 1048 195938248 1% /run tmpfs 195939296 0 195939296 0% /sys/fs/cgroup /dev/nvme0n1p1 141545452 135242112 6303340 96% / tmpfs 39187860 0 39187860 0% /run/user/0 /dev/nvme2n1 264055236 76594068 176644712 31% /home/ec2-user/SageMaker tmpfs 39187860 0 39187860 0% /run/user/1002 tmpfs 39187860 0 39187860 0% /run/user/1001 tmpfs 39187860 0 39187860 0% /run/user/1000
    2. Sposta la directory Docker predefinita da /dev/nvme0n1p1 a /dev/nvme2n1 per poter utilizzare appieno il volume SageMaker AI da 256 GB. Per ulteriori dettagli, consulta la documentazione su come spostare la directory Docker.

    3. Arresta Docker con il seguente comando:

      sudo service docker stop
    4. Aggiungi un file daemon.json a /etc/docker oppure aggiungi il seguente blob JSON a quello esistente.

      { "data-root": "/home/ec2-user/SageMaker/{created_docker_folder}" }
    5. Sposta la directory Docker presente nel percorso /var/lib/docker in /home/ec2-user/SageMaker AI con il seguente comando:

      sudo rsync -aP /var/lib/docker/ /home/ec2-user/SageMaker/{created_docker_folder}
    6. Avvia Docker con il seguente comando:

      sudo service docker start
    7. Svuota il cestino con il seguente comando:

      cd /home/ec2-user/SageMaker/.Trash-1000/files/* sudo rm -r *
    8. Se utilizzi un’istanza di notebook SageMaker, è possibile seguire i passaggi del file di preparazione di Docker per preparare Docker per la modalità locale.

Esempi di ModelBuilder

Per altri esempi di utilizzo di ModelBuilder per creare modelli personalizzati, consulta i notebook di esempio di ModelBuilder.