Best practice: inferenza AI sui servizi Cloud Run con GPU

Questa pagina fornisce le best practice per l'ottimizzazione del rendimento quando si utilizza un servizio Cloud Run con GPU per l'inferenza AI, con particolare attenzione ai modelli linguistici di grandi dimensioni (LLM). Per creare ed eseguire il deployment di un servizio Cloud Run in grado di rispondere in tempo reale agli eventi di scalabilità, devi:
  • Utilizzare modelli che si caricano rapidamente e richiedono una trasformazione minima in strutture pronte per la GPU e ottimizzare la modalità di caricamento.
  • Utilizzare configurazioni che consentano l'esecuzione simultanea massima ed efficiente per ridurre il numero di GPU necessarie per gestire una richiesta di destinazione al secondo, mantenendo bassi i costi.

Modalità consigliate per caricare modelli ML di grandi dimensioni su Cloud Run

Google consiglia di scaricare i modelli ML da Cloud Storage e di accedervi tramite Google Cloud CLI. In alternativa, puoi archiviare i modelli all'interno delle immagini container, ma questo metodo è più adatto ai modelli più piccoli di dimensioni inferiori a 10 GB.

Compromessi per l'archiviazione e il caricamento dei modelli ML

Ecco un confronto tra le opzioni:

Posizione modello Tempo di deployment Esperienza di sviluppo Tempo di avvio del container Costo di archiviazione
Cloud Storage, scaricato contemporaneamente utilizzando il comando Google Cloud CLI gcloud storage cp o l'API Storage di Cloud Storage, come mostrato nell'esempio di codice per il download simultaneo del transfer manager. Il più veloce. Modello scaricato durante l'avvio del container. Assicurati che all'istanza Cloud Run sia allocata RAM sufficiente per archiviare i file del modello. Leggermente più difficile da configurare, perché dovrai installare Google Cloud CLI sull'immagine o aggiornare il codice per utilizzare l' API Cloud Storage. Per ulteriori informazioni su come recuperare le credenziali dal server di metadati, consulta Introduzione all'identità del servizio. Veloce quando utilizzi le ottimizzazioni di rete. Google Cloud CLI scarica il file del modello in parallelo, rendendolo più veloce del montaggio FUSE. Una copia in Cloud Storage.
Cloud Storage, caricato utilizzando il montaggio del volume Cloud Storage FUSE Più veloce. Modello scaricato durante l'avvio del container. Non è difficile da configurare, non richiede modifiche all'immagine Docker. Veloce quando utilizzi le ottimizzazioni di rete. Non parallelizza il download. Una copia in Cloud Storage.
Immagine container Veloce. L'importazione di un'immagine contenente un modello di grandi dimensioni in Cloud Run richiede più tempo. Dovrai creare una nuova immagine ogni volta che vuoi utilizzare un modello diverso. Le modifiche all'immagine container richiedono un nuovo deployment, che potrebbe essere lento per le immagini di grandi dimensioni. Dipende dalle dimensioni del modello. Per i modelli di dimensioni molto grandi, utilizza Cloud Storage per prestazioni più prevedibili, ma più lente. Potenzialmente più copie in Artifact Registry.
Internet Lento. Modello scaricato durante l'avvio del container. In genere più semplice (molti framework scaricano i modelli da repository centrali). In genere scadenti e imprevedibili:
  • I framework potrebbero applicare trasformazioni del modello durante l'inizializzazione. (Dovresti farlo al momento della creazione).
  • L'host del modello e le librerie per il download del modello potrebbero non essere efficienti.
  • Esiste un rischio di affidabilità associato al download da internet. Il servizio potrebbe non avviarsi se la destinazione di download non è disponibile e il modello sottostante scaricato potrebbe cambiare, il che riduce la qualità. Ti consigliamo di eseguire l'hosting nel tuo bucket Cloud Storage.
Dipende dal provider host dei modelli.

Archiviare i modelli in Cloud Storage

Per ottimizzare il caricamento dei modelli ML quando li carichi da Cloud Storage, utilizzando i montaggi dei volumi Cloud Storage o direttamente l'API Storage o la riga di comando di Cloud Storage, devi utilizzare Direct VPC con il valore dell'impostazione di uscita impostato su all-traffic, insieme all'accesso privato Google.

A un costo aggiuntivo, l'utilizzo di Rapid Cache può ridurre la latenza di caricamento dei modelli memorizzando in modo efficiente i dati sugli SSD per letture più veloci.

Per ridurre i tempi di lettura dei modelli, prova le seguenti opzioni di montaggio per attivare le funzionalità di Cloud Storage FUSE:

  • cache-dir: attiva la funzionalità di memorizzazione nella cache dei file con un montaggio del volume in memoria da utilizzare come directory sottostante per rendere persistenti i file. Imposta il valore dell'opzione di montaggio cache-dir sul nome del volume in memoria nel formato cr-volume:{volume name}. Ad esempio, se hai un volume in memoria denominato in-memory-1 che vuoi utilizzare come directory della cache, specifica cr-volume:in-memory-1. Quando questo valore è impostato, puoi anche impostare altri file-cache flag disponibili per la configurazione della cache.
  • enable-buffered-read: imposta il campo enable-buffered-read su true per il recupero asincrono delle parti di un oggetto Cloud Storage in un buffer in memoria. In questo modo, le letture successive vengono eseguite dal buffer anziché richiedere chiamate di rete. Quando configuri questo campo, puoi anche impostare il read-global-max-blocks campo per configurare il numero massimo di blocchi disponibili per le letture con buffer in tutti gli handle dei file.

Quando vengono utilizzati sia cache-dir sia enable-buffered-read, cache-dir ha la precedenza. Tieni presente che l'attivazione di una di queste funzionalità modificherà la contabilità delle risorse del processo Cloud Storage FUSE in modo che venga conteggiata nei limiti di memoria del container. Valuta la possibilità di aumentare il limite di memoria del container seguendo le istruzioni su come configurare i limiti di memoria.

Archiviare i modelli nelle immagini container

Se archivi il modello ML nell'immagine container, il caricamento del modello trarrà vantaggio dall'infrastruttura di streaming dei container ottimizzata di Cloud Run. Tuttavia, la creazione di immagini container che includono modelli ML è un processo che richiede molte risorse, soprattutto quando si lavora con modelli di grandi dimensioni. In particolare, il processo di compilazione può diventare un collo di bottiglia per il throughput di rete. Quando utilizzi Cloud Build, ti consigliamo di utilizzare una macchina di build più potente con prestazioni di calcolo e di rete maggiori. 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'
 

Puoi creare una copia del modello per immagine se il livello contenente il modello è distinto tra le immagini (hash diverso). Potrebbe esserci un costo aggiuntivo di Artifact Registry costo perché potrebbe esserci una copia del modello per immagine se il livello del modello è univoco in ogni immagine.

Caricare i modelli da internet

Per ottimizzare il caricamento dei modelli ML da internet, instrada tutto il traffico attraverso la rete VPC con il valore dell'impostazione di uscita impostato su all-traffic e configura Cloud NAT per raggiungere la rete internet pubblica con una larghezza di banda elevata.

Considerazioni su creazione, deployment, runtime e progettazione del sistema

Le sezioni seguenti descrivono le considerazioni relative alla creazione, al deployment, al runtime e alla progettazione del sistema.

Al tempo di compilazione

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

  • Scegli una buona immagine di base. Dovresti iniziare con un'immagine da Deep Learning Containers o dal registro container NVIDIA per il framework ML che stai utilizzando. Queste immagini hanno installato i pacchetti più recenti relativi al rendimento. Non è consigliabile 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 runtime. Idealmente, i modelli devono essere addestrati alla profondità di bit di destinazione anziché quantizzati.
  • Scegli un formato di modello con tempi di caricamento rapidi per ridurre al minimo il tempo di avvio del container, ad esempio GGUF. Questi formati riflettono in modo più accurato il tipo di quantizzazione di destinazione 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 al tempo di compilazione. Avvia l'LLM sulla macchina di build durante la creazione dell'immagine Docker. Attiva la memorizzazione nella cache dei prompt e fornisci prompt comuni o di esempio per riscaldare la cache per l'utilizzo nel mondo reale. Salva gli output generati per caricarli in fase di runtime.
  • Salva il modello di inferenza che generi durante il tempo di compilazione. 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 container.

Al momento del deployment

Il seguente elenco mostra le considerazioni da tenere presenti quando pianifichi il deployment:

  1. Assicurati di impostare correttamente la concorrenza del servizio 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 ad accettare il traffico. Tieni presenti questi punti chiave quando configuri i probe di avvio:

  • Tempo di avvio adeguato: lascia un tempo sufficiente per l'inizializzazione e il caricamento completi del container, inclusi i modelli.
  • Verifica della preparazione del modello: configura il probe in modo che venga superato solo quando l'applicazione è pronta a gestire le richieste. Molti motori di pubblicazione lo fanno automaticamente quando il modello viene caricato nella memoria GPU, impedendo richieste premature.

Tieni presente che Ollama può aprire una porta TCP prima che venga caricato 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 runtime

  • Gestisci attivamente la finestra contestuale supportata. Più piccola è la finestra contestuale supportata, più query puoi supportare in esecuzione in parallelo. I dettagli su come farlo dipendono dal framework.
  • Utilizza le cache LLM generate al momento della creazione. Fornisci gli stessi flag utilizzati durante il tempo di compilazione quando hai generato la cache dei prompt e dei prefissi.
  • Carica dal modello salvato che hai appena scritto. Per un confronto su come caricare il modello, consulta Compromessi per l'archiviazione e il caricamento dei modelli.
  • Valuta la possibilità di utilizzare una cache coppia chiave-valore quantizzata 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 per i pesi dei modelli, le attivazioni e le cache coppia chiave-valore. Impostala il più alta possibile senza ricevere un errore di memoria insufficiente.
  • Verifica se il tuo framework offre opzioni per migliorare il rendimento di avvio del container (ad esempio, utilizzando la parallelizzazione del caricamento dei modelli).
  • Configura correttamente la concorrenza nel codice del servizio. Assicurati che il codice del servizio sia configurato per funzionare con le impostazioni di concorrenza del servizio Cloud Run.

A livello di progettazione del sistema

  • Aggiungi cache semantiche, se necessario. In alcuni casi, la memorizzazione nella cache di 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 memorizzate nella cache dei prefissi. Gli inserimenti o le modifiche nella sequenza indicano che non sono memorizzati nella cache o sono presenti solo parzialmente.

Scalabilità automatica e GPU

Se utilizzi la scalabilità automatica predefinita di Cloud Run, 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 lo scale out per la concorrenza delle richieste. Per ottenere una scalabilità ottimale per la concorrenza delle richieste, devi impostare un numero massimo ottimale di richieste simultanee per istanza, come descritto nella sezione successiva.

Numero massimo di richieste simultanee per istanza

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

Concorrenza massima e carichi di lavoro AI

Quando esegui un carico di lavoro di inferenza AI su una GPU in ogni istanza, la concorrenza massima che il codice può gestire con un buon rendimento dipende da dettagli specifici del framework e dell'implementazione. I seguenti fattori influiscono sulla configurazione dell'impostazione del numero massimo di richieste simultanee ottimale:

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

Se il numero massimo di richieste simultanee è impostato su un valore troppo elevato, le richieste potrebbero finire per attendere all'interno dell'istanza l'accesso alla GPU, il che comporta un aumento della latenza. Se il numero massimo di richieste simultanee è impostato su un valore troppo basso, la GPU potrebbe essere sottoutilizzata, causando a Cloud Run di fare lo scale out di più istanze del necessario.

Una regola pratica per la configurazione del numero massimo di richieste simultanee per i carichi di lavoro AI è:

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

Supponiamo, ad esempio, che un'istanza carichi 3 istanze del modello sulla GPU e che ogni istanza del 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. Utilizzando la regola pratica, imposteresti il numero massimo di richieste simultanee su 24: (3 * 4) + (3 * 4).

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

Compromessi tra velocità effettiva, latenza e costi

Per l'impatto del numero massimo di richieste simultanee su velocità effettiva, latenza e costi, consulta Compromessi tra velocità effettiva, latenza e costi. Tieni presente che tutti i servizi Cloud Run che utilizzano le GPU devono avere la fatturazione basata sulle istanze configurata.