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 IA, incentrata sui modelli LLM (Large Language Model).

Devi creare ed eseguire il deployment di un servizio Cloud Run in grado di rispondere in tempo reale per scalare gli eventi. 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.

Modalità di caricamento di modelli ML di grandi dimensioni su Cloud Run

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

Vantaggi dell'archiviazione e del caricamento dei modelli ML

Ecco un confronto delle opzioni:

Posizione modello Tempi di deployment Esperienza di sviluppo Tempi di avvio del container Costo di archiviazione
Immagine container Lento. L'importazione in Cloud Run di un'immagine contenente un modello di grandi dimensioni richiederà 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 i modelli molto grandi, 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 contenitore. 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 mediante il comando Google Cloud CLI gcloud storage cp 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 durante 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. (dovresti eseguire questa operazione al momento della creazione).
  • 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.

Archivia i modelli nelle immagini container

Archiviazione dei modelli ML in immagini container di cui è stato eseguito il deployment in Cloud Run dalle ottimizzazioni integrate per i flussi di immagini container di Cloud Run, che massimizza il tempo di caricamento dei file senza ulteriori ottimizzazioni di rete.

La creazione di container che includono modelli di ML può richiedere un po' di tempo. Se utilizzi Cloud Build, puoi configurare Cloud Build in modo che utilizzi per velocizzare le build. Per farlo, crea un'immagine utilizzando un file di configurazione della build che prevede 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.

Archivia i modelli in Cloud Storage

Per ottimizzare il caricamento del modello ML durante il caricamento dei modelli ML da Cloud Storage, utilizzando i montaggi dei volumi di Cloud Storage oppure direttamente tramite l'API o la riga di comando Cloud Storage, devi utilizzare il VPC diretto con il valore dell'impostazione in uscita impostato su all-traffic, insieme a Private Service Connect.

Considerazioni su compilazione, deployment, runtime e progettazione del sistema

Le seguenti sezioni descrivono considerazioni relative a build, deployment, runtime e progettazione del sistema.

In fase di creazione

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

  • Scegli un'immagine di base valida. Devi iniziare con un'immagine dal Container di deep learning o NVIDIA Container Registry per il framework ML che stai utilizzando. Queste immagini hanno le più recenti di pacchetti installati. 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 più veloci, riducendo la quantità di memoria GPU necessaria per gestire il modello e può aumentare il parallelismo in fase di esecuzione. Idealmente, i modelli devono essere addestrati alla profondità in bit target anziché quantificati fino a raggiungere la profondità.
  • Scegli un formato di modello con tempi di caricamento rapidi per ridurre al minimo i tempi di avvio del container, ad esempio 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 utilizzano checkpoint in formato pickle.
  • Crea e riscalda le cache LLM in fase di compilazione. avvia l'LLM sulla macchina di build 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. Salvare gli output che genera da caricare in fase di runtime.
  • Salva il tuo modello di inferenza che generi durante la creazione. In questo modo si risparmia molto tempo 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 la contemporaneità dei servizi in modo accurato in Cloud Run.
  2. Modifica i probe di avvio in base alla configurazione.

I probe di avvio determinano se il container è stato avviato ed è pronto per l'accettazione per via del traffico. Quando configuri i probe di avvio, considera questi punti chiave:

  • Tempo di avvio adeguato: concedi tempo sufficiente per l'inizializzazione e il caricamento completo del container, inclusi i modelli.
  • Verifica dell'idoneità del modello: configura il probe in modo che venga superato solo quando l'applicazione è pronta a gestire le richieste. La maggior parte dei motori di gestione raggiunge automaticamente questo obiettivo quando il modello viene caricato nella memoria GPU, evitando richieste prematura.

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 Oliver per informazioni su come precaricare il modello durante l'avvio.

In fase di esecuzione

  • Gestisci attivamente la lunghezza del contesto supportata. Più piccola è la finestra contestuale supportate, maggiore sarà il numero di query supportate eseguite in parallelo. I dettagli di come farlo 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 Svantaggi 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ò anche influire sulla qualità.
  • Ottimizza la quantità di memoria GPU da riservare a pesi del modello, attivazioni e le cache di coppie chiave-valore. 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 di servizio sia configurato in modo da funzionare con le impostazioni di contemporaneità 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 quando contengono i prompt in sequenza. Le cache sono effettivamente con memorizzazione nella cache del prefisso. Gli inserimenti o le modifiche nella sequenza indicano che non vengono memorizzati nella cache o parzialmente presente.

Scalabilità automatica e GPU

Cloud Run scala automaticamente il numero di istanze di ogni revisione in base a fattori come l'utilizzo della CPU e la contemporaneità delle richieste. Tuttavia, Cloud Run non scala automaticamente il numero di di archiviazione in base all'utilizzo delle 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 raggiungere della scalabilità per la contemporaneità delle richieste, devi impostare un numero massimo di richieste in parallelo per istanza, descritti nella prossima sezione.

Numero massimo di richieste in parallelo per istanza

Il numero massimo di richieste in parallelo per istanza controlla il numero massimo di richieste che Cloud Run invia a un a un'unica 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.

Massima contemporaneità e carichi di lavoro di AI

Quando esegui un carico di lavoro di inferenza AI su una GPU in ogni istanza, la contemporaneità che il codice è in grado di gestire con buone prestazioni dipende da specifiche framework e dettagli sull'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 della gestione in batch
  • 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 accedere alla GPU, il che comporta un 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 configurare il numero massimo di richieste in parallelo per AI carichi di lavoro sono:

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

Ad esempio, supponiamo che un'istanza carichi 3 istanze del modello nella GPU e ciascuna istanza del modello può gestire 4 query parallele. La dimensione ideale del batch è anche 4 perché questo è il numero di query parallele per ciascuna istanza del modello è in grado di gestire. Utilizzando la regola empirica, devi impostare il numero massimo di richieste in parallelo 24: (3 * 4) + (3 * 4).

Tieni presente che questa formula è solo una regola empirica. Il massimo l'impostazione delle richieste dipende dai dettagli specifici del tuo implementazione. Per ottenere il rendimento ottimale effettivo, ti consigliamo testare il carico del tuo servizio con valori massimi le impostazioni delle richieste in parallelo per valutare quale opzione ha il rendimento migliore.

Confronto tra velocità effettiva, latenza e compromessi in termini di costo

Consulta Scontri tra velocità effettiva, latenza e costi per l'impatto del numero massimo di richieste in parallelo su velocità effettiva, latenza e costi. Tieni presente che a tutti i servizi Cloud Run che utilizzano GPU è sempre allocata la CPU.