Un video con avatar risulta credibile solo se la persona rimane coerente nel tempo. Quando il volto si sposta, i denti cambiano, la sincronizzazione labiale si perde o il movimento si azzera tra una clip e l’altra, le persone se ne accorgono subito. Questo è ancora più importante per gli avatar rispetto a molti altri tipi di generazione video, perché lo spettatore sta guardando una persona specifica parlare, spesso da vicino e per un periodo prolungato.
In today's video generation world, duration is still one of the most visible limitations. Many models and products expose generation as a fixed-length clip — a few seconds, with few systems able to generate more than a few minutes. For avatar products, that limit shows up directly in customer workflows. Customers want longer consistent scenes/videos for training videos, sales demos, product walkthroughs, education, support, and agents that should keep talking until the task is done, and also they want fast preview to iterate on prompts, motion and script.
In HeyGen, questo si è tradotto in tre requisiti concreti:
- Coerenza nelle scene lungheL’avatar deve mantenere identità, sincronizzazione labiale, espressione e continuità del movimento non solo per una breve clip, ma anche attraverso molti segmenti di video generato.
- Nessun limite di durata fissoUna generazione può durare dieci secondi, dieci minuti o essere una sessione in tempo reale senza limiti.
- Anteprima rapida, generazione in tempo reale o più veloce del tempo reale. Il sistema dovrebbe iniziare a produrre fotogrammi rapidamente e persino consentire lo streaming dei fotogrammi generati mentre l’inferenza è ancora in corso.
Questo articolo illustra il framework di inferenza che abbiamo sviluppato per soddisfare tali requisiti.
L'architettura di base del modello
Il framework è basato sui modelli di generazione video di avatar di HeyGen, delle famiglie Avatar IV e Avatar V. A livello generale, il modello prende un’immagine/video di riferimento, l’audio di guida e, facoltativamente, testo o condizioni di scena, quindi genera un video di quell’avatar che parla con l’identità, l’espressione e il movimento corretti.
Il modello di generazione principale è un Diffusion Transformer, o DiT, addestrato con flow matching. Invece di comprimere la persona in un piccolo embedding di identità, il modello si basa su ricchi token di riferimento, così da preservare i dettagli che contano per gli avatar: forma del viso, denti, texture della pelle, movimento della bocca, stile dei gesti e ritmo del parlato.
The production inference path has three main stages:
- Generazione da audio a video. Un modello DiT di base genera latenze video a bassa risoluzione a partire dall’identità di riferimento, dalle caratteristiche audio e dai segnali di condizionamento. Questa fase si concentra su movimento, sincronizzazione labiale e coerenza temporale.
- Identity-aware super-resolution. A second model refines those latents into high-resolution output, with extra attention on regions where people are most sensitive to artifacts, especially the face and mouth.
- Decodifica VAE in streaming. Un decoder VAE converte i latenti ad alta risoluzione in fotogrammi RGB, blocco dopo blocco, così i fotogrammi possono essere emessi prima che l’intero video sia completo.
Per generare video lunghi, il sistema elabora i dati in blocchi. Mentre il primo blocco si basa interamente sul riferimento statico, i blocchi successivi utilizzano i dati di confine dei segmenti precedenti. Questo permette all’avatar di continuare a parlare in modo naturale senza dover azzerare da zero la postura o l’identità.
Il framework di streaming e il ciclo della pipeline
Per supportare l’esecuzione basata su chunk, il framework di inferenza utilizza un’architettura modulare a tre livelli che opera su finestre temporali localizzate, rilasciando le risorse immediatamente dopo l’elaborazione di ciascun chunk.
- Modulo: Un wrapper attorno a uno specifico modello e al suo checkpoint (ad es. A2V DiT, Super-Resolution DiT, componenti VAE, encoder di testo/audio).
- Fase: un'unità di esecuzione tipizzata che coordina uno o più moduli (ad es. generazione del contesto, super-risoluzione).
- Pipeline: il grafo di esecuzione che collega gli stage tra loro, gestisce lo stato condiviso e coordina le modalità di esecuzione in streaming o batch.
La fase di inizializzazione codifica l’identità di riferimento in latenti una volta per ogni richiesta. La pipeline esegue quindi un ciclo continuo attraverso le fasi rimanenti finché il flusso audio in ingresso non è esaurito:

- Generazione del contesto: Converte i segmenti audio in ingresso in caratteristiche, li combina con il testo o con il conditioning della scena e prepara i tensori di rumore di destinazione.
- Da audio a video: Esegue un processo di diffusione in più fasi per generare latenze a bassa risoluzione. Questa fase condiziona il blocco corrente sui frame di confine del blocco precedente per mantenere la continuità del movimento.
- Super-Risoluzione: aumenta la risoluzione dei latenti di movimento fino alla piena risoluzione in un unico passaggio, dando priorità ai dettagli spaziali del volto.
- VAE Decode-and-Publish: decodifica i latenti ad alta risoluzione in frame RGB e li invia direttamente al codificatore di output (H.264 / AAC) per l’archiviazione immediata o la riproduzione in tempo reale.
Continuità dei confini e coerenza dei segmenti
La generazione di video in segmenti distinti introduce potenziali discontinuità ai confini. Il framework riduce questo problema utilizzando due diverse classificazioni di chunk:
- Chunk N: segmenti che generano la timeline principale dell’avatar.
- Chunk I (Interpolazione): segmenti progettati per rendere più fluide le transizioni tra chunk N sequenziali.
La sequenza di esecuzione è strutturata come segue:
N0 -> N1 -> I0 -> N2 -> I1 -> N3 -> I2 -> ...
Un chunk I viene generato solo dopo che i chunk N precedente e successivo sono stati completati. Utilizza il frame finale del chunk N precedente e un frame iniziale del chunk N corrente come frame di ancoraggio per calcolare il movimento di transizione. Dopo la generazione, le previsioni di ancoraggio ridondanti vengono scartate, lasciando solo la transizione interpolata in modo fluido. Questo meccanismo limita la finestra di contesto richiesta preservando al contempo la coerenza temporale.
Memoria costante nel tempo
Una pipeline video tradizionale accumula latenti, frame decodificati e contesto di attenzione durante l’esecuzione, facendo sì che il consumo di memoria GPU aumenti linearmente con la durata del video.
Per abilitare una generazione aperta e continua, questo framework mantiene uno stato a scorrimento rigoroso. Il sistema conserva solo il conditioning di riferimento statico e un set minimo di tensori di ancoraggio necessari per le transizioni tra i chunk. Tutte le risorse intermedie — incluse le caratteristiche audio, i tensori di rumore, le attivazioni interne e i frame RGB grezzi — vengono eliminate dalla memoria immediatamente dopo che un chunk è stato decodificato e scritto.
Di conseguenza, il profilo di picco della memoria GPU rimane costante sia che si generi una clip breve sia una sequenza estesa; l’utilizzo delle risorse scala in base alla dimensione del chunk definita, invece che alla durata complessiva della sessione.
Fasi di caricamento/scaricamento all'interno della pipeline
Ogni richiesta viene eseguita su un nodo con 8 GPU. Usiamo FSDP per suddividere i parametri dei modelli di grandi dimensioni tra le GPU. Ogni rank possiede solo una frazione dei pesi, raccoglie i parametri di cui ha bisogno per un calcolo e poi li rilascia nuovamente. È questo che permette a più modelli di grandi dimensioni — il DiT di base, il DiT di super-risoluzione, il text encoder, l’audio encoder e il VAE — di entrare in un unico nodo.
C’è un compromesso. FSDP introduce un overhead di comunicazione durante l’inferenza perché i parametri devono essere raccolti durante i passaggi in forward. Usiamo una combinazione di tecniche per nascondere questo overhead e per mantenere i modelli co-localizzati fuori dalla GPU quando non sono in uso:
- Prefetching in avanti. L’operazione di AllGather dei parametri del blocco successivo viene avviata in anticipo e sovrapposta al calcolo del blocco corrente, nascondendo la latenza di raccolta sul percorso critico.
- Unsharding pigro per blocco dalla CPU. Quando un modello viene riportato dalla memoria CPU bloccata (pinned), non carichiamo subito l’intero set di pesi. Ogni blocco del trasformatore viene “unshardato” (copia host-to-device + AllGather) appena prima della sua passata forward, così il trasferimento H2D del blocco n+1 si sovrappone al calcolo del blocco n.
- Offload su CPU con memoria bloccata tra le fasi. I parametri di un modello che non è attualmente in esecuzione vengono mantenuti nella memoria CPU bloccata (pinned), così i modelli co-localizzati (DiT base, DiT per super‑risoluzione, text encoder, audio encoder, VAE) non devono tutti mantenere i propri pesi sulla GPU nello stesso momento. È la memoria bloccata che rende le copie H2D abbastanza veloci da sovrapporsi al calcolo.
- Assegnazione dei processi ottimizzata per NUMA. Ogni processo è fissato allo stesso nodo NUMA della GPU a cui è assegnato, così i trasferimenti CPU↔GPU avvengono alla massima banda PCIe/NVLink senza attraversare l’interconnessione tra socket.
Cambio di modello tra le fasi in meno di 10 ms
Il vantaggio pratico delle tecniche descritte sopra è che passare la GPU dal modello di una fase a quello della fase successiva — ad esempio, da A2V DiT a Super-Resolution DiT, oppure da SR DiT al decoder VAE — è praticamente gratuito. Poiché il modello in uscita viene scaricato in modo asincrono e il primo blocco del modello in ingresso viene de-shardato just-in-time, sia la copia H2D sia l’operazione di AllGather risultano nascoste dietro il calcolo già in esecuzione. Da un’estremità all’altra, l’overhead osservabile per ogni switch è inferiore a 10 ms — ben al di sotto del budget di un singolo frame ai nostri frame rate target. In concreto, è questo che permette al loop della pipeline di streaming (Context Gen → A2V → SR → VAE Decode-and-Publish) di passare attraverso diversi modelli di grandi dimensioni per ogni chunk senza che il cambio di modello diventi mai il collo di bottiglia.
Pubblicazione in streaming in tempo reale
Per rendere il modello sufficientemente veloce da trasmettere in tempo reale, abbiamo effettuato numerose ottimizzazioni di inferenza; fai riferimento a https://www.heygen.com/research/avatar-v-inference per maggiori dettagli su questo aspetto.
Una volta che la pipeline emette il video, frammento dopo frammento, in tempo reale, la distribuzione in streaming diventa una naturale estensione dell’inferenza invece di un passaggio di post‑elaborazione separato.
Per il percorso in tempo reale in stile broadcast, pubblichiamo i frame generati su Amazon Kinesis Video Streams (KVS). KVS viene solitamente menzionato nel contesto di videocamere, dispositivi IoT e contenuti multimediali caricati. Nel nostro caso, la "videocamera" è la pipeline di inferenza stessa: i frame vengono creati dal modello, codificati immediatamente e inviati a KVS come flusso live.
Il writer di output riceve i frame RGB decodificati dallo streaming VAE e li invia a una pipeline GStreamer. Il video viene codificato in H.264 e l’audio in AAC, quindi entrambe le tracce vengono inviate a kvssink, il sink di produzione KVS. Da lì, gli spettatori possono riprodurre la sessione come live stream mentre è ancora in fase di generazione.
Risultati e insegnamenti
Il framework ha trasformato la generazione di Avatar IV e Avatar V da un rendering a scena fissa a una generazione in streaming aperta. Il risultato più importante è semplice: abbiamo eliminato i limiti di durata della scena per Avatar IV e Avatar V. Per la generazione in tempo reale di Avatar IV, abbiamo ottenuto un time to first frame inferiore a 5 secondi e una generazione a oltre 27 fotogrammi al secondo per video Avatar IV in 720p — più veloce della riproduzione in tempo reale.