Best practice: inferenza AI su Cloud Run con GPU

Questa pagina fornisce le best practice per ottimizzare le prestazioni quando si utilizza un servizio Cloud Run con una GPU per l'inferenza AI, incentrata sui modelli linguistici di grandi dimensioni (LLM).

Devi creare ed eseguire il deployment di un servizio Cloud Run in grado di rispondere in tempo reale agli eventi di scalabilità. Ciò significa che devi:

  • Utilizza modelli che si caricano rapidamente e richiedono una trasformazione minima in strutture pronte per GPU e ottimizza il loro caricamento.
  • Utilizza configurazioni che consentano un'esecuzione massima, efficiente e simultanea per ridurre il numero di GPU necessarie per soddisfare una richiesta target al secondo, mantenendo bassi i costi.

Metodi consigliati per caricare modelli di ML di grandi dimensioni su Cloud Run

Google consiglia di archiviare i modelli di ML all'interno di immagini container o di ottimizzare il loro caricamento da Cloud Storage.

Compromessi relativi allo stoccaggio e al caricamento dei modelli di ML

Ecco un confronto delle opzioni:

Posizione modello Ora di deployment Esperienza di sviluppo Tempi di avvio del contenitore Costo di archiviazione
Immagine container Lento. L'importazione di un'immagine contenente un modello di grandi dimensioni in Cloud Run richiede più tempo. Le modifiche all'immagine del contenitore richiedono il nuovo deployment, che potrebbe essere lento per le immagini di grandi dimensioni. Dipende dalle dimensioni del modello. Per modelli di grandi dimensioni, utilizza Cloud Storage per prestazioni più prevedibili, ma più lente. Potenzialmente più copie in Artifact Registry.
Cloud Storage, caricato utilizzando il montaggio del volume Cloud Storage FUSE Veloce. Modello scaricato durante l'avvio del container. Non è difficile da configurare e non richiede modifiche all'immagine Docker. Veloce per le ottimizzazioni della rete. Non esegue il parallelismo del download. Una copia in Cloud Storage.
Cloud Storage, scaricato contemporaneamente utilizzando il comando gcloud storage cp di Google Cloud CLI o l'API Cloud Storage, come mostrato nell'esempio di codice di download simultaneo di Transfer Manager. Veloce. Modello scaricato durante l'avvio del container. È leggermente più difficile da configurare, perché dovrai installare Google Cloud CLI sull'immagine o aggiornare il codice per utilizzare l'API Cloud Storage. Veloce per le ottimizzazioni della rete. Google Cloud CLI scarica il file del modello in parallelo, rendendolo più veloce del montaggio FUSE. Una copia in Cloud Storage.
Internet Veloce. Modello scaricato durante l'avvio del container. In genere sono più semplici (molti framework scaricano i modelli da repository centrali). In genere scarsa e imprevedibile:
  • I framework possono applicare trasformazioni del modello durante l'inizializzazione. (devi farlo in fase di compilazione).
  • L'host del modello e le librerie per il download del modello potrebbero non essere efficienti.
  • Il download da internet comporta un rischio di affidabilità. Il servizio potrebbe non riuscire ad avviarsi se la destinazione di download non è disponibile e il modello sottostante scaricato potrebbe cambiare, con una conseguente riduzione della qualità. Ti consigliamo di eseguire l'hosting nel tuo bucket Cloud Storage.
Dipende dal provider host del modello.

Memorizzare i modelli nelle immagini container

La memorizzazione dei modelli ML nelle immagini container di cui è stato eseguito il deployment in Cloud Run trae vantaggio dalle ottimizzazioni dello streaming delle immagini container integrate di Cloud Run, che massimizzano il tempo di caricamento dei file senza ulteriori ottimizzazioni di rete.

La creazione di contenitori che includono modelli ML può richiedere un po' di tempo. Se utilizzi Cloud Build, puoi configurarlo in modo da utilizzare macchine più grandi per build più rapide. Per farlo, crea un'immagine utilizzando un file di configurazione della build con i seguenti passaggi:

steps:
- name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'IMAGE', '.']
- name: 'gcr.io/cloud-builders/docker'
  args: ['push', 'IMAGE']
images:
- IMAGE
options:
 machineType: 'E2_HIGHCPU_32'
 diskSizeGb: '500'
 

Può creare una copia del modello per immagine se il livello contenente il modello è distinto tra le immagini (hash diverso). Potrebbero esserci costi aggiuntivi per Artifact Registry perché potrebbe esserci una copia del modello per immagine se il livello del modello è univoco per ogni immagine.

Memorizza i modelli in Cloud Storage

Per ottimizzare il caricamento dei modelli ML quando li carichi da Cloud Storage, utilizzando i mount dei volumi Cloud Storage o direttamente l'API Cloud Storage o la riga di comando, devi utilizzare VPC diretto con il valore dell'impostazione di uscita impostato su all-traffic, insieme a Private Service Connect.

Caricare i modelli da internet

Per ottimizzare il caricamento del modello di ML da internet, indirizza tutto il traffico tramite la rete VPC con il valore dell'impostazione di uscita impostato su all-traffic e configura Cloud NAT per raggiungere la rete internet pubblica a larghezza di banda elevata.

Considerazioni su compilazione, deployment, runtime e progettazione del sistema

Le sezioni seguenti descrivono le considerazioni per la compilazione, il deployment, il runtime e la progettazione del sistema.

Al momento della compilazione

Il seguente elenco mostra le considerazioni da tenere presenti quando pianifichi la compilazione:

  • Scegli un'immagine di base di buona qualità. Ti consigliamo di iniziare con un'immagine di Deep Learning Containers o del registro di container NVIDIA per il framework ML in uso. Su queste immagini sono installati i pacchetti correlati al rendimento più recenti. Ti sconsigliamo di creare un'immagine personalizzata.
  • Scegli modelli quantizzati a 4 bit per massimizzare la concorrenza, a meno che tu non possa dimostrare che influiscono sulla qualità dei risultati. La quantizzazione produce modelli più piccoli e veloci, riducendo la quantità di memoria GPU necessaria per pubblicare il modello e può aumentare il parallelismo in fase di esecuzione. Idealmente, i modelli dovrebbero essere addestrati alla profondità di bit target anziché essere quantizzati in base a questa.
  • Scegli un formato del modello con tempi di caricamento rapidi per ridurre al minimo il tempo di avvio del contenitore, come GGUF. Questi formati riflettono in modo più accurato il tipo di quantizzazione target e richiedono meno trasformazioni quando vengono caricati sulla GPU. Per motivi di sicurezza, non utilizzare i checkpoint in formato pickle.
  • Crea e riscalda le cache LLM in fase di compilazione. Avvia LLM sulla macchina di compilazione durante la creazione dell'immagine Docker. Attiva la memorizzazione nella cache dei prompt e inserisci prompt comuni o di esempio per contribuire ad attivare la cache per l'utilizzo reale. Salva gli output generati per il caricamento in fase di esecuzione.
  • Salva il tuo modello di inferenza generato durante la compilazione. In questo modo si risparmia un tempo significativo rispetto al caricamento di modelli archiviati in modo meno efficiente e all'applicazione di trasformazioni come la quantizzazione all'avvio del contenitore.

Al momento del deployment

  1. Assicurati di impostare con precisione la concorrenza del servizio in Cloud Run.
  2. Modifica i probe di avvio in base alla tua configurazione.

I probe di avvio determinano se il container è stato avviato ed è pronto ad accettare il traffico. Tieni presenti questi punti chiave durante la configurazione delle prove di avvio:

  • Tempo di avvio adeguato: attendi il tempo necessario per l'inizializzazione e il caricamento completo del contenitore, inclusi i modelli.
  • Verifica dell'idoneità del modello: configura il probe in modo che passi solo quando l'applicazione è pronta a gestire le richieste. La maggior parte degli engine di pubblicazione lo ottiene automaticamente quando il modello viene caricato nella memoria GPU, impedendo le richieste premature.

Tieni presente che Ollama può aprire una porta TCP prima del caricamento di un modello. Per risolvere il problema:

  • Precarica i modelli: consulta la documentazione di Ollama per indicazioni sul precaricamento del modello durante l'avvio.

In fase di esecuzione

  • Gestisci attivamente la lunghezza del contesto supportata. Più piccola è la finestra di contesto supportata, più query puoi eseguire in parallelo. I dettagli su come eseguire questa operazione dipendono dal framework.
  • Utilizza le cache LLM generate in fase di compilazione. Fornisci gli stessi flag utilizzati durante il tempo di compilazione quando hai generato la cache del prompt e del prefisso.
  • Carica dal modello salvato che hai appena scritto. Consulta la sezione Compromisi di archiviazione e caricamento dei modelli per un confronto su come caricare il modello.
  • Valuta la possibilità di utilizzare una cache quantizzata delle coppie chiave-valore, se il tuo framework la supporta. In questo modo è possibile ridurre i requisiti di memoria per query e configurare un maggiore parallelismo. Tuttavia, può influire anche sulla qualità.
  • Ottimizza la quantità di memoria GPU da riservare per i pesi, le attivazioni e le cache chiave-valore del modello. Imposta il valore più alto possibile senza ricevere un errore di esaurimento della memoria.
  • Configura la concorrenza correttamente all'interno del codice di servizio. Assicurati che il codice del servizio sia configurato per funzionare con le impostazioni di concorrenza del servizio Cloud Run.
  • Verifica se il tuo framework offre opzioni per migliorare le prestazioni di avvio del contenitore (ad esempio, utilizzando la parallellizzazione del caricamento del modello).

A livello di progettazione del sistema

  • Aggiungi cache semantiche ove opportuno. In alcuni casi, memorizzare nella cache intere query e risposte può essere un ottimo modo per limitare il costo delle query comuni.
  • Controlla la varianza nei preamboli. Le cache dei prompt sono utili solo se contengono i prompt in sequenza. Le cache sono effettivamente con memorizzazione nella cache del prefisso. Le inserzioni o le modifiche nella sequenza indicano che non sono memorizzate nella cache o sono presenti solo parzialmente.

Scalabilità automatica e GPU

Cloud Run scala automaticamente il numero di istanze di ogni revisione in base a fattori quali l'utilizzo della CPU e la concorrenza delle richieste. Tuttavia, Cloud Run non scala automaticamente il numero di istanze in base all'utilizzo della GPU.

Per una revisione con una GPU, se la revisione non ha un utilizzo significativo della CPU, Cloud Run esegue il ridimensionamento per la concorrenza delle richieste. Per ottenere un scaling ottimale per la concorrenza delle richieste, devi impostare un numero ottimale di richieste in parallelo massime per istanza, come descritto nella sezione successiva.

Numero massimo di richieste in parallelo per istanza

L'impostazione Numero massimo di richieste in parallelo per istanza controlla il numero massimo di richieste inviate da Cloud Run a una singola istanza contemporaneamente. Devi ottimizzare la concorrenza in modo che corrisponda alla concorrenza massima che il codice all'interno di ogni istanza può gestire con buon rendimento.

Concorrenza massima e carichi di lavoro di AI

Quando esegui un workload di inferenza AI su una GPU in ogni istanza, la concorrenza massima che il codice può gestire con buone prestazioni dipende da dettagli specifici del framework e dell'implementazione. I seguenti fattori influiscono sulla modalità di impostazione dell'impostazione ottimale per il numero massimo di richieste in parallelo:

  • Numero di istanze del modello caricate sulla GPU
  • Numero di query parallele per modello
  • Utilizzo del raggruppamento
  • Parametri di configurazione batch specifici
  • Quantità di lavoro non GPU

Se il numero massimo di richieste in parallelo è impostato su un valore troppo elevato, le richieste potrebbero finire per attendere all'interno dell'istanza per l'accesso alla GPU, con un conseguente aumento della latenza. Se il numero massimo di richieste in parallelo è impostato su un valore troppo basso, la GPU potrebbe essere sottoutilizzata, provocando un aumento delle istanze di Cloud Run più del necessario.

Una regola empirica per la configurazione del numero massimo di richieste in parallelo per i workload di AI è:

(Number of model instances * parallel queries per model) + (number of model instances * ideal batch size)

Ad esempio, supponiamo che un'istanza carichi 3 istanze modello sulla GPU e che ogni istanza modello possa gestire 4 query parallele. La dimensione del batch ideale è anche 4 perché è il numero di query parallele che ogni istanza del modello può gestire. Secondo la regola empirica, dovresti impostare il numero massimo di richieste simultanee24: (3 * 4) + (3 * 4).

Tieni presente che questa formula è solo una regola empirica. L'impostazione ideale per il numero massimo di richieste contemporaneamente dipende dai dettagli specifici dell'implementazione. Per ottenere il rendimento ottimale effettivo, ti consigliamo di eseguire test di carico del servizio con impostazioni diverse per il numero massimo di richieste simultanee per valutare quale opzione ha il rendimento migliore.

Compromessi tra velocità effettiva, latenza e costi

Consulta la sezione Compromisi tra velocità effettiva, latenza e costi per informazioni sull'impatto delle richieste simultanee massime su velocità effettiva, latenza e costi. Tieni presente che a tutti i servizi Cloud Run che utilizzano GPU è sempre allocata la CPU.