ottimizza l’utilizzo di AWS Inferentia con modelli FastAPI e PyTorch sulle istanze Amazon EC2 Inf1 e Inf2

Utilizza AWS Inferentia su EC2 Inf1 e Inf2 con FastAPI e PyTorch

Quando si distribuiscono modelli di Deep Learning su larga scala, è fondamentale utilizzare in modo efficace l’hardware sottostante per massimizzare le prestazioni e i vantaggi in termini di costi. Per i carichi di lavoro di produzione che richiedono un’elevata velocità di trasferimento e una bassa latenza, è molto importante selezionare l’istanza di Amazon Elastic Compute Cloud (EC2), lo stack di servizio del modello e l’architettura di distribuzione. Un’architettura inefficiente può portare a un utilizzo subottimale dei dispositivi di accelerazione e a costi di produzione inutilmente elevati.

In questo post, ti illustreremo il processo di distribuzione di server di modelli FastAPI su dispositivi AWS Inferentia (presenti nelle istanze Amazon EC2 Inf1 e Amazon EC Inf2). Mostreremo anche come ospitare un modello di esempio distribuito in parallelo su tutti i NeuronCores per un utilizzo massimo dell’hardware.

Panoramica della soluzione

FastAPI è un framework web open-source per la distribuzione di applicazioni Python che è molto più veloce dei framework tradizionali come Flask e Django. Utilizza un’interfaccia Asynchronous Server Gateway Interface (ASGI) anziché l’interfaccia Web Server Gateway Interface (WSGI) ampiamente utilizzata. ASGI elabora le richieste in ingresso in modo asincrono, a differenza di WSGI che elabora le richieste in modo sequenziale. Questo rende FastAPI la scelta ideale per gestire le richieste sensibili alla latenza. Puoi utilizzare FastAPI per distribuire un server che ospita un endpoint su istanze Inferentia (Inf1/Inf2) che riceve le richieste dei client attraverso una porta designata.

Il nostro obiettivo è ottenere le migliori prestazioni al costo più basso attraverso l’utilizzo massimo dell’hardware. Questo ci consente di gestire un numero maggiore di richieste di inferenza con meno dispositivi di accelerazione. Ogni dispositivo AWS Inferentia1 contiene quattro NeuronCores-v1 e ogni dispositivo AWS Inferentia2 contiene due NeuronCores-v2. L’SDK AWS Neuron ci consente di utilizzare ciascuno dei NeuronCores in parallelo, il che ci offre maggior controllo nel caricare e inferire quattro o più modelli contemporaneamente senza sacrificare la velocità di trasferimento.

Con FastAPI, puoi scegliere il tuo server web Python (Gunicorn, Uvicorn, Hypercorn, Daphne). Questi server web forniscono uno strato di astrazione sopra il modello di Machine Learning (ML) sottostante. Il client richiedente può beneficiare del fatto di non dover conoscere il nome o la versione del modello ospitato. Un client non ha bisogno di conoscere il nome e la versione del modello che è stato distribuito sotto il server; il nome dell’endpoint è solo un proxy per una funzione che carica ed esegue il modello. Al contrario, in uno strumento di servizio specifico del framework, come TensorFlow Serving, il nome e la versione del modello fanno parte del nome dell’endpoint. Se il modello cambia sul lato del server, il client deve conoscere e modificare la sua chiamata API al nuovo endpoint di conseguenza. Pertanto, se stai evolvendo continuamente le versioni dei modelli, come nel caso dei test A/B, utilizzare un server web Python generico con FastAPI è un modo comodo per servire i modelli, perché il nome dell’endpoint è statico.

Il ruolo di un server ASGI è generare un numero specificato di worker che ascoltano le richieste dei client ed eseguono il codice di inferenza. Una capacità importante del server è assicurarsi che il numero richiesto di worker sia disponibile e attivo. Nel caso in cui un worker venga eliminato, il server deve avviare un nuovo worker. In questo contesto, il server e i worker possono essere identificati dal loro ID di processo Unix (PID). Per questo post, utilizziamo un server Hypercorn, che è una scelta popolare per i server web Python.

In questo post, condivideremo le migliori pratiche per distribuire modelli di apprendimento profondo con FastAPI su AWS Inferentia NeuronCores. Mostreremo che è possibile distribuire più modelli su NeuronCores separati che possono essere chiamati contemporaneamente. Questa configurazione aumenta la velocità di trasferimento perché è possibile inferire più modelli contemporaneamente e l’utilizzo di NeuronCore è completamente ottimizzato. Il codice può essere trovato nel repository GitHub. La figura seguente mostra l’architettura di come configurare la soluzione su un’istanza EC2 Inf2.

Lo stesso tipo di architettura si applica a un’istanza EC2 Inf1, tranne che ha quattro core. Quindi, l’architettura del diagramma cambia un po’.

AWS Inferentia NeuronCores

Approfondiamo un po’ gli strumenti forniti da AWS Neuron per interagire con i NeuronCores. Le tabelle seguenti mostrano il numero di NeuronCores in ciascun tipo di istanza Inf1 e Inf2. Le vCPUs dell’host e la memoria di sistema sono condivise tra tutti i NeuronCores disponibili.

Dimensione dell’istanza # Acceleratori Inferentia # NeuronCores-v1 vCPUs Memoria (GiB)
Inf1.xlarge 1 4 4 8
Inf1.2xlarge 1 4 8 16
Inf1.6xlarge 4 16 24 48
Inf1.24xlarge 16 64 96 192
Dimensione dell’istanza # Acceleratori Inferentia # NeuronCores-v2 vCPUs Memoria (GiB)
Inf2.xlarge 1 2 4 32
Inf2.8xlarge 1 2 32 32
Inf2.24xlarge 6 12 96 192
Inf2.48xlarge 12 24 192 384

Le istanze Inf2 contengono i nuovi NeuronCores-v2 rispetto ai NeuronCore-v1 delle istanze Inf1. Nonostante abbiano meno core, sono in grado di offrire un throughput 4 volte superiore e una latenza 10 volte inferiore rispetto alle istanze Inf1. Le istanze Inf2 sono ideali per carichi di lavoro di Deep Learning come Generative AI, Large Language Models (LLM) nella famiglia OPT/GPT e vision transformers come Stable Diffusion.

Neuron Runtime è responsabile dell’esecuzione dei modelli sui dispositivi Neuron. Neuron Runtime determina quale NeuronCore eseguirà quale modello e come eseguirlo. La configurazione di Neuron Runtime viene controllata attraverso l’utilizzo di variabili d’ambiente a livello di processo. Di default, le estensioni del framework Neuron si occuperanno della configurazione di Neuron Runtime per conto dell’utente; tuttavia, sono possibili anche configurazioni esplicite per ottenere un comportamento più ottimizzato.

Due variabili d’ambiente popolari sono NEURON_RT_NUM_CORES e NEURON_RT_VISIBLE_CORES. Con queste variabili d’ambiente, i processi Python possono essere associati a un NeuronCore. Con NEURON_RT_NUM_CORES, è possibile riservare un numero specificato di core per un processo, e con NEURON_RT_VISIBLE_CORES, è possibile riservare un intervallo di NeuronCores. Ad esempio, NEURON_RT_NUM_CORES=2 myapp.py riserverà due core e NEURON_RT_VISIBLE_CORES=’0-2’ myapp.py riserverà zero, uno e due core per myapp.py. È anche possibile riservare NeuronCores su dispositivi (chip AWS Inferentia). Quindi, NEURON_RT_VISIBLE_CORES=’0-5’ myapp.py riserverà i primi quattro core su device1 e un core su device2 in un’istanza Ec2 di tipo Inf1. Allo stesso modo, su un’istanza EC2 di tipo Inf2, questa configurazione riserverà due core su device1 e device2 e un core su device3. La tabella seguente riassume la configurazione di queste variabili.

Nome Descrizione Tipo Valori attesi Valore predefinito Versione RT
NEURON_RT_VISIBLE_CORES Intervallo di NeuronCores specifici necessari per il processo Intervallo intero (come 1-3) Qualsiasi valore o intervallo compreso tra 0 e il massimo numero di NeuronCore nel sistema Nessuno 2.0+
NEURON_RT_NUM_CORES Numero di NeuronCores richiesti dal processo Intero Un valore compreso tra 1 e il massimo numero di NeuronCore nel sistema 0, che viene interpretato come “tutti” 2.0+

Per un elenco di tutte le variabili d’ambiente, fare riferimento alla configurazione dell’esecuzione di Neuron.

Per impostazione predefinita, durante il caricamento dei modelli, i modelli vengono caricati su NeuronCore 0 e poi su NeuronCore 1 a meno che non venga esplicitamente indicato dalle variabili d’ambiente precedenti. Come specificato in precedenza, i NeuronCores condividono le vCPUs host disponibili e la memoria di sistema. Pertanto, i modelli distribuiti su ciascun NeuronCore competono per le risorse disponibili. Questo non sarà un problema se il modello utilizza in larga misura i NeuronCores. Ma se un modello viene eseguito solo in parte sui NeuronCores e il resto sulle vCPUs host, diventa importante considerare la disponibilità della CPU per NeuronCore. Questo influisce anche sulla scelta dell’istanza.

La tabella seguente mostra il numero di vCPUs host e la memoria di sistema disponibile per ogni modello se un modello fosse distribuito su ciascun NeuronCore. A seconda dell’utilizzo dei NeuronCores dell’applicazione, dell’utilizzo delle vCPU e della memoria, si consiglia di eseguire test per scoprire quale configurazione è più performante per l’applicazione. Lo strumento Neuron Top può aiutare a visualizzare l’utilizzo delle core e l’utilizzo della memoria del dispositivo e dell’host. Sulla base di queste metriche è possibile prendere una decisione informata. Dimostriamo l’utilizzo di Neuron Top alla fine di questo blog.

Dimensione dell’istanza # Acceleratori Inferentia # Modelli vCPUs/Modello Memoria/Modello (GiB)
Inf1.xlarge 1 4 1 2
Inf1.2xlarge 1 4 2 4
Inf1.6xlarge 4 16 1.5 3
Inf1.24xlarge 16 64 1.5 3
Dimensione dell’istanza # Acceleratori Inferentia # Modelli vCPUs/Modello Memoria/Modello (GiB)
Inf2.xlarge 1 2 2 8
Inf2.8xlarge 1 2 16 64
Inf2.24xlarge 6 12 8 32
Inf2.48xlarge 12 24 8 32

Per testare le funzionalità del Neuron SDK da soli, controlla le ultime capacità di Neuron per PyTorch.

Configurazione del sistema

Di seguito è riportata la configurazione di sistema utilizzata per questa soluzione:

  • Dimensione dell’istanza – 6xlarge (se si utilizza Inf1), Inf2.xlarge (se si utilizza Inf2)
  • Immagine per l’istanza – Deep Learning AMI Neuron PyTorch 1.11.0 (Ubuntu 20.04) 20230125
  • Modello – https://huggingface.co/twmkn9/bert-base-uncased-squad2
  • Framework – PyTorch

Configurazione della soluzione

Ci sono un paio di cose che dobbiamo fare per configurare la soluzione. Inizia creando un ruolo IAM che la tua istanza EC2 assumerà per consentirle di spingere e tirare da Amazon Elastic Container Registry.

Passaggio 1: Configura il ruolo IAM

  1. Inizia effettuando l’accesso alla console e accedendo a IAM > Ruoli > Crea ruolo
  2. Seleziona il tipo di entità fidata AWS Service
  3. Seleziona EC2 come servizio per il caso d’uso
  4. Fai clic su Avanti e potrai vedere tutte le politiche disponibili
  5. Per questa soluzione, stiamo dando alla nostra istanza EC2 pieno accesso a ECR. Filtra per AmazonEC2ContainerRegistryFullAccess e selezionalo.
  6. Premi Avanti e dai un nome al ruolo inf-ecr-access

Nota: la politica che abbiamo allegato fornisce all’istanza EC2 pieno accesso ad Amazon ECR. Consigliamo vivamente di seguire il principio del privilegio minimo per i carichi di lavoro di produzione.

Passaggio 2: Configura AWS CLI

Se stai utilizzando l’AMI di Deep Learning prescritta elencata sopra, viene fornita con AWS CLI installato. Se stai utilizzando un’AMI diversa (Amazon Linux 2023, Base Ubuntu, ecc.), installa gli strumenti CLI seguendo questa guida.

Una volta installati gli strumenti CLI, configura CLI utilizzando il comando aws configure. Se hai le chiavi di accesso, puoi aggiungerle qui, ma non ne hai necessariamente bisogno per interagire con i servizi AWS. Ci affidiamo ai ruoli IAM per farlo.

Nota: è necessario inserire almeno un valore (regione predefinita o formato predefinito) per creare il profilo predefinito. Per questo esempio, stiamo scegliendo us-east-2 come regione e json come output predefinito.

Clonare il repository GitHub

Il repository GitHub fornisce tutti gli script necessari per distribuire modelli utilizzando FastAPI su NeuronCores su istanze AWS Inferentia. Questo esempio utilizza contenitori Docker per garantire la creazione di soluzioni riutilizzabili. In questo esempio è incluso il seguente file config.properties per consentire agli utenti di fornire input.

# Nome dell'immagine e del contenitore Docker
docker_image_name_prefix=<Nome dell'immagine Docker>
docker_container_name_prefix=<Nome del contenitore Docker>

# Configurazione del deployment
path_to_traced_models=<Percorso del modello tracciato>
compiled_model=<Nome del file del modello compilato>
num_cores=<Numero di NeuronCores per distribuire un server di modelli>
num_models_per_server=<Numero di modelli da caricare per server>

Il file di configurazione richiede prefissi di nome definiti dall’utente per l’immagine Docker e i contenitori Docker. Lo script build.sh nelle cartelle fastapi e trace-model utilizza questi prefissi per creare immagini Docker.

Compila un modello su AWS Inferentia

Inizieremo tracciando il modello e producendo un file .pt di PyTorch Torchscript. Inizia accedendo alla directory trace-model e modificando il file .env. A seconda del tipo di istanza scelto, modifica CHIP_TYPE all’interno del file .env. Come esempio, sceglieremo Inf2 come guida. Gli stessi passaggi si applicano al processo di distribuzione per Inf1.

Successivamente, imposta la regione predefinita nello stesso file. Questa regione verrà utilizzata per creare un repository ECR e le immagini Docker verranno caricate in questo repository. In questa cartella, forniamo tutti gli script necessari per tracciare un modello bert-base-uncased su AWS Inferentia. Questo script può essere utilizzato per la maggior parte dei modelli disponibili su Hugging Face. Il Dockerfile contiene tutte le dipendenze per eseguire modelli con Neuron e esegue il codice trace-model.py come punto di ingresso.

Spiegazione della compilazione di Neuron

L’API del Neuron SDK assomiglia molto all’API Python di PyTorch. La funzione torch.jit.trace() di PyTorch prende il modello e il tensore di input di esempio come argomenti. Gli input di esempio vengono alimentati al modello e le operazioni che vengono invocate mentre l’input si fa strada attraverso i layer del modello vengono registrate come TorchScript. Per saperne di più su JIT Tracing in PyTorch, consulta la seguente documentazione.

Come torch.jit.trace(), puoi verificare se il tuo modello può essere compilato su AWS Inferentia con il seguente codice per le istanze inf1.

import torch_neuron
model_traced = torch.neuron.trace(model, 
                                  example_inputs,
                                  compiler_args = 
                                  [‘--fast-math’, ‘fp32-cast-matmul’,
                                   ‘--neuron-core-pipeline-cores’,’1’],
                         optimizations=[torch_neuron.Optimization.FLOAT32_TO_FLOAT16])

Per inf2, la libreria si chiama torch_neuronx. Ecco come puoi testare la compilazione del tuo modello su istanze inf2.

import torch
import torch_neuronx
model_traced = torch.neuronx.trace(model, 
                                   example_inputs,
                                   compiler_args = 
                                   [‘--fast-math’, ‘fp32-cast-matmul’,
                                    ‘--neuron-core-pipeline-cores’,’1’],
          optimizations=[torch_neuronx.Optimization.FLOAT32_TO_FLOAT16])

Dopo aver creato l’istanza tracciata, è possibile passare l’input del tensore di esempio in questo modo:

answer_logits = model_traced(*example_inputs)

E infine salvare l’output TorchScript risultante sul disco locale

model_traced.save('./compiled-model-bs-{batch_size}.pt')

Come mostrato nel codice precedente, è possibile utilizzare compiler_args e optimizations per ottimizzare il deployment. Per un elenco dettagliato degli argomenti per l’API torch.neuron.trace, consulta l’API Python PyTorch-Neuron trace.

Tieni presente i seguenti punti importanti:

  • Il Neuron SDK non supporta forme di tensore dinamiche alla data di scrittura di questo documento. Pertanto, un modello dovrà essere compilato separatamente per diverse forme di input. Per ulteriori informazioni sull’esecuzione dell’inferenza su forme di input variabili con il bucketing, consulta l’esecuzione dell’inferenza su forme di input variabili con il bucketing.
  • Se si verificano problemi di memoria insufficiente durante la compilazione di un modello, prova a compilare il modello su un’istanza AWS Inferentia con più vCPUs o memoria, o addirittura su un’istanza c6i o r6i di grandi dimensioni, poiché la compilazione utilizza solo le CPU. Una volta compilato, il modello tracciato potrebbe essere eseguito probabilmente su dimensioni di istanze AWS Inferentia più piccole.

Spiegazione del processo di compilazione

Ora costruiremo questo container eseguendo build.sh. Il file dello script di compilazione crea semplicemente l’immagine Docker scaricando un’immagine di base del contenitore di apprendimento profondo e installando il pacchetto HuggingFace transformers. In base al CHIP_TYPE specificato nel file .env, il file docker.properties decide la BASE_IMAGE appropriata. Questa BASE_IMAGE punta a un’immagine del contenitore di apprendimento profondo per Neuron Runtime fornita da AWS.

È disponibile tramite un repository privato ECR. Prima di poter scaricare l’immagine, è necessario effettuare l’accesso e ottenere le credenziali temporanee di AWS.

aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin 763104351884.dkr.ecr.<region>.amazonaws.com

Nota: è necessario sostituire la regione elencata nel comando specificato dalla flag region e all’interno dell’URI del repository con la regione che mettiamo nel file .env.

A scopo di semplificazione di questo processo, possiamo utilizzare il file fetch-credentials.sh. La regione verrà presa automaticamente dal file .env.

Successivamente, spingeremo l’immagine utilizzando lo script push.sh. Lo script di push crea un repository in Amazon ECR per te e spinge l’immagine del contenitore.

Infine, una volta che l’immagine è stata costruita e spinta, possiamo eseguirla come un contenitore eseguendo run.sh e seguire i log di esecuzione con logs.sh. Nei log del compilatore (vedi la seguente schermata), vedrai la percentuale di operatori aritmetici compilati su Neuron e la percentuale di sottografi del modello compilati con successo su Neuron. La schermata mostra i log del compilatore per il modello bert-base-uncased-squad2. I log mostrano che il 95,64% degli operatori aritmetici è stato compilato e forniscono anche un elenco degli operatori che sono stati compilati su Neuron e quelli che non sono supportati.

Ecco un elenco di tutti gli operatori supportati nell’ultima versione del pacchetto PyTorch Neuron. Allo stesso modo, ecco l’elenco di tutti gli operatori supportati nell’ultima versione del pacchetto PyTorch Neuronx.

Deploy dei modelli con FastAPI

Dopo che i modelli sono stati compilati, il modello tracciato sarà presente nella cartella trace-model. In questo esempio, abbiamo posizionato il modello tracciato per una dimensione del batch di 1. Consideriamo una dimensione del batch di 1 qui per tener conto dei casi d’uso in cui una dimensione del batch più grande non è fattibile o necessaria. Per i casi d’uso in cui sono necessarie dimensioni del batch più grandi, può essere utile anche l’API torch.neuron.DataParallel (per Inf1) o torch.neuronx.DataParallel (per Inf2).

La cartella fast-api fornisce tutti gli script necessari per distribuire i modelli con FastAPI. Per distribuire i modelli senza alcuna modifica, esegui semplicemente lo script deploy.sh e verrà creata un’immagine del contenitore FastAPI, verranno eseguiti i contenitori sul numero specificato di core e verranno distribuiti il numero specificato di modelli per server in ogni server del modello FastAPI. Questa cartella contiene anche un file .env, modificare per riflettere il corretto CHIP_TYPE e AWS_DEFAULT_REGION.

Nota: gli script di FastAPI si basano sulle stesse variabili di ambiente utilizzate per costruire, spingere ed eseguire le immagini come contenitori. Gli script di distribuzione di FastAPI utilizzeranno gli ultimi valori noti di queste variabili. Quindi, se hai tracciato il modello per il tipo di istanza Inf1 l’ultima volta, quel modello verrà distribuito tramite questi script.

Il file fastapi-server.py che è responsabile per l’hosting del server e l’invio delle richieste al modello fa quanto segue:

  • Legge il numero di modelli per server e la posizione del modello compilato dal file delle proprietà
  • Imposta le NeuronCores visibili come variabili di ambiente per il contenitore Docker e legge le variabili di ambiente per specificare quali NeuronCores utilizzare
  • Fornisce un’API di inferenza per il modello bert-base-uncased-squad2
  • Con jit.load(), carica il numero di modelli per server come specificato nella configurazione e memorizza i modelli e i tokenizer richiesti in dizionari globali

Con questa configurazione, sarebbe relativamente facile impostare API che elencano quali modelli e quanti modelli sono memorizzati in ogni NeuronCore. Allo stesso modo, potrebbero essere scritte API per eliminare modelli da specifici NeuronCores.

Il Dockerfile per la creazione dei contenitori FastAPI è basato sull’immagine Docker che abbiamo creato per tracciare i modelli. Questo è il motivo per cui il file docker.properties specifica il percorso ECR dell’immagine Docker per tracciare i modelli. Nella nostra configurazione, i contenitori Docker su tutti i NeuronCores sono simili, quindi possiamo creare un’immagine e eseguire più contenitori da un’immagine. Per evitare eventuali errori del punto di ingresso, specificare ENTRYPOINT ["/usr/bin/env"] nel Dockerfile prima di eseguire lo script startup.sh, che assomiglia a hypercorn fastapi-server:app -b 0.0.0.0:8080. Questo script di avvio è lo stesso per tutti i contenitori. Se stai utilizzando la stessa immagine di base per tracciare i modelli, puoi creare questo contenitore semplicemente eseguendo lo script build.sh. Lo script push.sh rimane lo stesso di prima per tracciare i modelli. L’immagine Docker modificata e il nome del contenitore sono forniti dal file docker.properties.

Il file run.sh fa quanto segue:

  • Legge l’immagine Docker e il nome del contenitore dal file delle proprietà, che a sua volta legge il file config.properties, che ha una impostazione utente num_cores
  • Avvia un ciclo da 0 a num_cores e per ogni core:
    • Imposta il numero di porta e il numero del dispositivo
    • Imposta la variabile di ambiente NEURON_RT_VISIBLE_CORES
    • Specifica il mount del volume
    • Esegue un contenitore Docker

Per chiarezza, il comando di esecuzione di Docker per il dispiegamento in NeuronCore 0 per Inf1 sarebbe simile al seguente codice:

docker run -t -d \
        --name $ bert-inf-fastapi-nc-0 \
        --env NEURON_RT_VISIBLE_CORES="0-0" \
        --env CHIP_TYPE="inf1" \
        -p ${port_num}:8080 --device=/dev/neuron0 ${registry}/ bert-inf-fastapi

Il comando di esecuzione per il dispiegamento in NeuronCore 5 sarebbe simile al seguente codice:

docker run -t -d \
        --name $ bert-inf-fastapi-nc-5 \
        --env NEURON_RT_VISIBLE_CORES="5-5" \
        --env CHIP_TYPE="inf1" \
        -p ${port_num}:8080 --device=/dev/neuron0 ${registry}/ bert-inf-fastapi

Dopo che i contenitori sono stati dispiegati, utilizziamo lo script run_apis.py, che chiama le API in thread paralleli. Il codice è impostato per chiamare sei modelli dispiegati, uno su ogni NeuronCore, ma può essere facilmente modificato in base a una diversa configurazione. Chiamiamo le API dal lato client come segue:

import requests

url_template = http://localhost:%i/predictions_neuron_core_%i/model_%i

# NeuronCore 0
response = requests.get(url_template % (8081,0,0))

# NeuronCore 5
response = requests.get(url_template % (8086,5,0))

Monitoraggio di NeuronCore

Dopo che i server dei modelli sono stati dispiegati, per monitorare l’utilizzo di NeuronCore, possiamo utilizzare neuron-top per osservare in tempo reale la percentuale di utilizzo di ogni NeuronCore. neuron-top è un’utility CLI nell’SDK Neuron per fornire informazioni come NeuronCore, vCPU e utilizzo della memoria. In un terminale separato, immettere il seguente comando:

neuron-top

Il tuo output dovrebbe essere simile alla seguente figura. In questo scenario, abbiamo specificato di utilizzare due NeuronCores e due modelli per server su un’istanza Inf2.xlarge. La seguente schermata mostra che due modelli di dimensioni 287,8 MB ciascuno sono caricati su due NeuronCores. Con un totale di 4 modelli caricati, puoi vedere che la memoria del dispositivo utilizzata è di 1,3 GB. Utilizza i tasti freccia per spostarti tra i NeuronCores su diversi dispositivi

Allo stesso modo, su un’istanza di tipo Inf1.16xlarge, vediamo un totale di 12 modelli (2 modelli per core su 6 core) caricati. Vengono utilizzati complessivamente 2,1 GB di memoria e ogni modello ha una dimensione di 177,2 MB.

Dopo aver eseguito lo script run_apis.py, è possibile vedere la percentuale di utilizzo di ciascuno dei sei NeuronCores (vedere la seguente schermata). È anche possibile vedere l’utilizzo vCPU di sistema e l’utilizzo vCPU di runtime.

La seguente schermata mostra la percentuale di utilizzo del core dell’istanza Inf2.

Allo stesso modo, questa schermata mostra l’utilizzo del core in un’istanza di tipo inf1.6xlarge.

Pulizia

Per eliminare tutti i contenitori Docker creati, forniamo uno script cleanup.sh che rimuove tutti i contenitori in esecuzione e fermati. Questo script rimuoverà tutti i contenitori, quindi non utilizzarlo se si desidera mantenere alcuni contenitori in esecuzione.

Conclusioni

I carichi di lavoro di produzione spesso richiedono alto throughput, bassa latenza e costi ridotti. Architetture inefficienti che utilizzano in modo sub-ottimale gli acceleratori potrebbero comportare costi di produzione non necessariamente elevati. In questo post, abbiamo mostrato come utilizzare in modo ottimale i NeuronCores con FastAPI per massimizzare il throughput con una latenza minima. Abbiamo pubblicato le istruzioni nel nostro repository GitHub. Con questa architettura di soluzione, è possibile distribuire più modelli in ciascun NeuronCore e operare contemporaneamente più modelli su diversi NeuronCores senza perdere prestazioni. Per ulteriori informazioni su come distribuire modelli su larga scala con servizi come Amazon Elastic Kubernetes Service (Amazon EKS), fare riferimento a Serve 3.000 modelli di deep learning su Amazon EKS con AWS Inferentia per meno di $50 all’ora.