Apprendimento automatico distribuito su Instacart

Mar 20 2023
In che modo Instacart utilizza l'apprendimento automatico distribuito per addestrare in modo efficiente migliaia di modelli in produzione
Autore: Han Li In Instacart, siamo orgogliosi di offrire una vasta gamma di prodotti di machine learning (ML) che potenziano ogni aspetto del nostro mercato, inclusi clienti, acquirenti, rivenditori e marchi. Insieme alla crescita delle applicazioni aziendali e ML, abbiamo riscontrato un numero crescente di casi d'uso che richiedono tecniche ML distribuite per scalare efficacemente i nostri prodotti ML.

Autore: HanLi

In Instacart, siamo orgogliosi di offrire una vasta gamma di prodotti di machine learning (ML) che potenziano ogni aspetto del nostro mercato, inclusi clienti, acquirenti, rivenditori e marchi. Insieme alla crescita delle applicazioni aziendali e ML, abbiamo riscontrato un numero crescente di casi d'uso che richiedono tecniche ML distribuite per scalare efficacemente i nostri prodotti ML.

Per supportare le richieste emergenti, abbiamo progettato il sistema ML distribuito con le seguenti considerazioni di progettazione chiave:

  • Scalabilità: dobbiamo essere in grado di scalare un gran numero di carichi di lavoro ML distribuiti su istanze CPU e GPU con un sistema robusto che mantenga prestazioni e affidabilità elevate.
  • Efficienza delle risorse : miriamo a utilizzare completamente le risorse di calcolo distribuite per massimizzare il throughput del sistema e ottenere l'esecuzione più rapida a un costo ottimale.
  • Diversità : il framework di calcolo selezionato dovrebbe essere il più estensibile possibile per supportare diversi paradigmi ML distribuiti. Inoltre, dovremmo essere in grado di gestire diversi ambienti specifici per diversi carichi di lavoro ML.
  • Parallelizzazione di migliaia di modelli di addestramento di piccole e medie dimensioni su host distribuiti con un utilizzo efficiente delle risorse e tempi di accodamento ragionevoli.
  • Utilizzo del parallelismo dei dati per consentire ai modelli di deep learning di lavorare con set di dati di grandi dimensioni in modo più efficace.
  • Sviluppo di capacità di inferenza batch scalabili con un gran numero di lavori paralleli che elaborano una grande quantità di dati.

Architettura di sistema

Riconosciamo che un sistema con un'esperienza utente semplice è essenziale per aumentare la produttività degli sviluppatori e massimizzare l'impatto delle nostre applicazioni ML distribuite. Pertanto, oltre ai principi di progettazione di scalabilità, efficienza delle risorse e diversità , diamo la priorità ai seguenti obiettivi per semplificare l'esperienza dell'utente:

  • Semplicità di sviluppo : miriamo a semplificare il processo di sviluppo per gli ingegneri ML fornendo loro strumenti per testare il loro codice distribuito senza problemi in un ambiente locale e ambienti distribuiti.
  • Semplicità di manutenzione : il nostro obiettivo è offrire un modello di sviluppo senza server che consenta ai nostri ingegneri di sviluppare ed eseguire carichi di lavoro senza l'onere di gestire alcun servizio. Crediamo che eliminando la necessità di gestire la gestione dei servizi, possiamo effettivamente migliorare la produttività di MLE.
  • Integrazione perfetta : il nostro obiettivo è integrare perfettamente i carichi di lavoro ML distribuiti con Instacart ML Platform Griffin , senza creare un set ridondante di strumenti o piattaforme MLOps. Piuttosto che reinventare la ruota, miriamo a migliorare la nostra infrastruttura esistente.
Fig 1: Applicazione ML distribuita in sviluppo e produzione su Ray Cluster

Ecco i dettagli di ogni componente che interagisce con l'ambiente distribuito Ray:

  • Durante la fase di sviluppo, gli utenti possono impacchettare frammenti di codice di prototipazione nel proprio ambiente di sviluppo e avviarli su host AWS EKS remoti tramite un'API di avvio interna che astrae l'accesso a Ray Cluster tramite l'API Ray Job (vedere la figura 1a ) .
  • Fig 1a: Connetti l'ambiente di sviluppo con Ray Cluster
  • Quando gli utenti sono pronti ad automatizzare il proprio codice nelle pipeline di produzione (ad es. Airflow), possono utilizzare lo stesso set di API per avviare la propria applicazione containerizzata nei Ray Clusters di produzione (vedere la figura 1b).
  • Fig 1b: applicazione containerizzata automatizzata in esecuzione su Ray Cluster
  • Ogni Ray Cluster è configurato in modo indipendente con installazioni Python e variabili d'ambiente. Ciò separa efficacemente gli ambienti dell'area di lavoro tra i cluster, evitando il sovraccarico di mantenere un ambiente Python monolitico, che verrà discusso in dettaglio nella sezione successiva (vedere la figura 1c).
  • Fig 1c: Ambienti Python isolati tra diversi Ray Clusters
  • A livello di applicazione, gli utenti devono creare applicazioni ML utilizzando le API Ray per ottenere un'ampia varietà di modelli di calcolo distribuiti, come le API Ray Core , Ray AIR e Ray Serve .
  • Sul lato controller, utilizziamo KubeRay come controller per il provisioning, il ridimensionamento e l'eliminazione delle risorse Ray Cluster su Kubernetes.

Caso di studio: lavori di machine learning ad adempimento parallelo

In Instacart, il machine learning viene applicato per tutto il ciclo di vita dell'evasione di ogni ordine effettuato sull'app Instacart (Fig. 2). Ciò include il raggruppamento di più ordini insieme per migliorare l'efficienza, l'instradamento per determinare i percorsi di consegna ottimali, la previsione dell'orario di arrivo previsto dell'ordine e la previsione della domanda/offertaper evitare consegne perse quando non ci sono abbastanza acquirenti disponibili e molti altri. Un numero significativo di tali modelli viene addestrato con i dati raccolti in un quartiere specifico e alcuni di questi modelli sono anche sensibili ai dati raccolti in un determinato periodo di tempo, pertanto è prassi comune suddividere l'intero set di dati nazionale in base a uno o più spazi /time e quindi avviare un processo di addestramento per partizione di dati, preferibilmente in parallelo.

Fig 2: Alcuni scenari comuni di Fulfillment ML in Instacart

L'"attributo" più comune è la posizione geografica degli ordini, chiamata "zone". In Instacart gestiamo migliaia di zone univoche per partizionare il nostro set di dati nazionale. Per ogni applicazione Fulfillment ML, è normale lanciare fino a migliaia di lavori di formazione paralleli per coprire tutte le zone in un singolo esperimento del modello.

Soluzioni e limitazioni precedenti

Fig 3: Il nostro precedente sistema di addestramento del modello a livello di zona parallela

La nostra soluzione legacy ha implementato un servizio di coda delle attività distribuito utilizzando Celery ; La figura 3 illustra lo schema architettonico. Per ogni applicazione modello univoca (rappresentata come Modello nel diagramma) che richiede l'addestramento parallelo nella zona 1~n, i processi di addestramento per tutte le zone vengono pubblicati come attività nella stessa coda di attività su Message Broker . Successivamente, un gruppo di lavoratori di Celery si iscrive a ciascuna coda di attività ed esegue le attività al suo interno. Le attività vengono eseguite in modo asincrono e ogni volta che un lavoratore Celery è libero, l'attività in cima alla coda viene rimossa e assegnata al lavoratore libero. Una volta terminato, il lavoratore aggiorna lo stato dell'attività nel back-end dei messaggi e recupera l'attività successiva nella coda da eseguire.

Con l'aumentare nel tempo del numero di applicazioni ML che richiedono l'addestramento parallelo a livello di zona, questo tipo di servizio monolitico ha iniziato a diventare difficile da scalare ulteriormente a causa dei seguenti motivi:

  • Utilizzo inefficiente delle risorse: molte applicazioni ML condividevano la stessa coda di attività e i servizi di lavoro distribuiti Celery. Si è scoperto che i lavoratori distribuiti non potevano essere utilizzati completamente in modo molto efficiente:
    - Il nodo di lavoro doveva essere sovradimensionato con risorse sufficienti per adattarsi a tutti i tipi di modelli. Tuttavia, in Fulfillment ML, la maggior parte dei modelli è piuttosto leggera, come regressione, classificazione e così via. Pertanto, quando era in esecuzione un modello di piccole dimensioni, il lavoratore era scarsamente utilizzato. Ad esempio, nel grafico a sinistra della figura 4, un modello leggero era in esecuzione su un'istanza da 16 CPU, con un utilizzo della CPU solo dal 10% al 15% circa.
    - Il servizio di lunga durata potrebbe lasciare il sistema inattivo se il carico è stato sbilanciato durante il giorno. Ad esempio, nella parte destra della figura 4, la coda non eseguiva alcuna attività per oltre il 60% della giornata, determinando un utilizzo inefficiente delle risorse.
  • Fig 4: Esempi di contenitori di servizi poco utilizzati (a sinistra) e code di attività inattive (a destra)
  • Tempo di accodamento lungo : è molto difficile ottenere tempi di esecuzione più rapidi senza eseguire l'upscaling dei servizi della coda delle attività:
    - La concorrenza dei lavoratori Low Celery è configurata per host della coda delle attività, perché non è possibile aumentare semplicemente la concorrenza per adattare tutti i modelli a un servizio monolitico.
    - Quando una coda di attività viene assegnata con troppe attività, come la Fig. 5 in cui da 300 a 1k+ attività sono in coda tutto il giorno, il tempo di accodamento di ciascuna attività da eseguire aumenterà in modo significativo, rallentando l'end-to-end tempo di esecuzione di ciascuna applicazione ML.
    - Pertanto, l'unico modo per accelerare una coda occupata è eseguire l'upscaling per aggiungere più host fisici, che continuano ad aggiungere risorse scarsamente utilizzate al sistema.
  • Fig 5: esempi di una coda di attività molto occupata che ospita troppe attività
  • Difficile gestione delle dipendenze : è difficile gestire le dipendenze Python per tutte le applicazioni modello in esecuzione sulla stessa coda. L'aggiornamento di una versione specifica del pacchetto Python è impegnativo.
  • Carico di manutenzione : questo sistema è complesso da automatizzare e non fornisce un approccio semplice per replicare il sistema in un ambiente locale a scopo di test.

Quando abbiamo iniziato ad adottare i carichi di lavoro Fulfillment ML per i nostri nuovi sistemi ML distribuiti, il cambiamento più significativo è stata la migrazione dai servizi monolitici di lunga durata alle applicazioni serverless basate su Ray. Invece di tutti i modelli in esecuzione sullo stesso ambiente, ogni applicazione Fulfillment ML viene lanciata come lavoro Ray indipendente associato a un Ray Cluster dedicato per gestire tutti i suoi lavori di addestramento a livello di zona, come illustrato nella figura 6. Questo nuovo design offre diversi vantaggi rispetto a la nostra soluzione legacy:

Fig 6: Panoramica dell'architettura dei flussi di lavoro Distributed Fulfillment ML ospitati su Ray Cluster
  • Con il nostro nuovo sistema, ogni modello ha ora il proprio ambiente di lavoro isolato , consentendo la gestione indipendente delle dipendenze Python e l'utilizzo delle risorse in base al modello (Fig. 7).
  • Fig 7: Un diagramma per illustrare l'idea dell'isolamento dello spazio di lavoro tra diversi modelli
  • I servizi di coda delle attività a esecuzione prolungata sono ora obsoleti . Ciò riduce i costi delle risorse di calcolo e, cosa più importante, rende l'infrastruttura molto più facile da scalare per ospitare le nuove applicazioni imminenti.
  • Le applicazioni serverless offrono agli utenti la possibilità di eseguire il provisioning delle risorse per lavoratore Ray in modo più accurato, risultando in un utilizzo delle risorse molto più efficiente . La figura 8 fornisce un esempio reale di questo miglioramento confrontando l'utilizzo della CPU prima/dopo di un modello di produzione Fulfillment che esegue 1,5k attività di addestramento univoche sullo stesso gruppo di host: -
    Nel sistema legacy descritto in precedenza, solo pochi lavoratori Celery sono stati configurati per essere eseguiti su ciascun host, con un utilizzo della CPU di circa il 10-15% .
    - Con la nostra nuova architettura basata su Ray, possiamo personalizzare in modo più accurato i requisiti delle risorse. Attraverso il benchmarking, abbiamo scoperto che l'allocazione di sole 2 CPU per lavoro di addestramento zonale è sufficiente. Di conseguenza, siamo in grado di creare più lavoratori Ray simultanei sulla stessa istanza, aumentando significativamente l'utilizzo della CPU per host fino all'80% .
  • Fig 8: Prima (a sinistra) e dopo (a destra) l'utilizzo della CPU dello stesso modello che addestra le stesse zone.
  • Il migliore utilizzo delle risorse ha contribuito a una più rapida esecuzione end-to-end . Con lo stesso modello di produzione sopra menzionato in esecuzione su 10 istanze da 16 CPU, c'erano solo 10 worker simultanei Celery in totale sul servizio legacy, mentre un'applicazione basata su Ray può avviare fino a 70+ worker Ray. Di conseguenza, ora siamo in grado di velocizzare notevolmente il tempo di completamento end-to-end (in precedenza ~4 ore) a 20 minuti !
Fig 9: Esempio di codice per convertire un oggetto di classe Forecast esistente in un oggetto Ray Actor

Apprendimenti e lavoro futuro

Abbiamo acquisito preziose informazioni dalla nostra esperienza nella creazione di soluzioni ML distribuite e nella migrazione dei primi casi d'uso dai sistemi legacy. Abbiamo scoperto che l'hosting di un servizio monolitico come back-end di calcolo per tutte le applicazioni ML distribuite presenta limitazioni in termini di scalabilità, efficienza e diversità, data la natura in rapida evoluzione e altamente diversificata delle applicazioni ML. Ad esempio, passando da servizi monolitici ad applicazioni serverless autonome per la formazione a livello di zona di evasione ordini, siamo stati in grado di aumentare notevolmente i tempi di esecuzione, l'utilizzo delle risorse e la semplicità di sviluppo.

Sebbene la topologia di ogni applicazione possa essere altamente personalizzata dal proprietario dell'applicazione nel machine learning distribuito, è essenziale disporre di strumenti unificati per la creazione e l'avvio a livello della piattaforma machine learning. Questo approccio ci consente di supportare più tipi di carichi di lavoro ML distribuiti in futuro, garantendo al contempo che la nostra piattaforma rimanga estensibile.

Guardando al futuro, miriamo a promuovere un'adozione più ampia delle applicazioni ML distribuite su Instacart su più linee di prodotti ML. Il nostro obiettivo per il 2023 è far maturare ulteriormente la nostra soluzione ML distribuita basata su Ray come soluzione unificata in esecuzione come parte di Griffin. Mentre intraprendiamo questo viaggio, siamo entusiasti di vedere cosa il ML distribuito può aiutarci a raggiungere il prossimo obiettivo su Instacart.