Maak kennis met Avatar V, de meest levensechte avatar ooit gemaakt. Maak de jouwe gratis

By Jiajun Zhao & Pedram Haqiqi

Avatarvideo voelt alleen geloofwaardig aan als de persoon in de loop van de tijd consistent blijft. Zodra het gezicht verschuift, de tanden veranderen, de lipsynchronisatie niet meer klopt of de beweging tussen clips wordt gereset, merken mensen dat meteen. Dit is belangrijker voor avatars dan voor veel andere vormen van videogeneratie, omdat de kijker een specifiek persoon ziet spreken, vaak van dichtbij en gedurende langere tijd.

In de huidige wereld van videogeneratie is de duur nog steeds een van de meest zichtbare beperkingen. Veel modellen en producten bieden generatie aan als een clip met vaste lengte — een paar seconden, waarbij maar weinig systemen meer dan enkele minuten kunnen genereren. Bij avatarproducten komt die beperking direct terug in de workflows van klanten. Klanten willen langere, consistente scènes/video’s voor trainingsvideo’s, salesdemo’s, productwalkthroughs, educatie, support en agents die moeten blijven praten totdat de taak is voltooid, en daarnaast willen ze ook een snelle preview om te kunnen itereren op prompts, beweging en script.

Bij HeyGen heeft dat geleid tot drie concrete vereisten:

  1. Consistentie over lange scènes. De avatar moet niet alleen in één kort fragment, maar in meerdere aaneengesloten stukken gegenereerde video de identiteit, lipsynchronisatie, gezichtsuitdrukking en bewegingscontinuïteit behouden.
  2. Geen vaste tijdslimietEen generatie kan tien seconden, tien minuten of een open‑einde realtime sessie duren.
  3. Snelle preview, realtime of sneller-dan-realtime generatieHet systeem moet snel frames beginnen te produceren en zelfs toestaan dat de gegenereerde frames worden gestreamd terwijl de inferentie nog bezig is.

Dit artikel bespreekt stap voor stap het inferentieraamwerk dat we hebben gebouwd om aan die vereisten te voldoen.

De onderliggende modelarchitectuur

Het framework is opgebouwd rond HeyGen's avatar-videogeneratiemodellen — de Avatar IV- en Avatar V-families. Op hoofdlijnen neemt het model een referentieafbeelding/-video, sturende audio en optionele tekst- of scènecondities, en genereert vervolgens een video van die avatar die spreekt met de juiste identiteit, expressie en beweging.

Het kernmodel voor generatie is een Diffusion Transformer, of DiT, getraind met flow matching. In plaats van de persoon samen te persen in een kleine identiteitsembedding, stuurt het model op rijke referentietokens aan, zodat het details kan behouden die belangrijk zijn voor avatars: gezichtsvorm, gebit, huidtextuur, mondbeweging, gebarenstijl en spreekritme.

Het productie-inferentiepad bestaat uit drie hoofdfasen:

  1. Audio-naar-videogeneratie. Een basis-DiT genereert video-latents met lage resolutie op basis van de referentie-identiteit, audiofeatures en conditioneringssignalen. Deze fase richt zich op beweging, lipsynchronisatie en temporele samenhang.
  2. Identiteitsbewuste superresolutie. Een tweede model verfijnt deze latente representaties tot een uitvoer met hoge resolutie, met extra aandacht voor gebieden waar mensen het meest gevoelig zijn voor artefacten, vooral het gezicht en de mond.
  3. Streaming VAE-decodering. Een VAE-decoder zet latents met hoge resolutie stukje bij beetje om in RGB-frames, zodat frames al kunnen worden uitgezonden voordat de volledige video klaar is.

Om lange video’s te genereren, verwerkt het systeem de data in segmenten. Terwijl het eerste segment volledig op de statische referentie steunt, gebruiken de volgende segmenten grensgegevens uit de voorgaande delen. Hierdoor kan de avatar natuurlijk blijven doorpraten zonder zijn houding of identiteit telkens vanaf nul te hoeven resetten.

Het streamingframework en de pijplijnlus

Om uitvoering op basis van chunks mogelijk te maken, maakt het inferentieraamwerk gebruik van een modulaire architectuur met drie lagen, die werkt op gelokaliseerde tijdvensters en middelen direct vrijgeeft zodra een chunk is verwerkt.

  • Module: Een omhulsel rond een specifiek model en het bijbehorende checkpoint (bijv. A2V DiT, Super-Resolution DiT, VAE-componenten, tekst-/audio-encoders).
  • Fase: Een getypeerde uitvoereenheid die één of meer modules coördineert (bijv. contextgeneratie, superresolutie).
  • Pipeline: de uitvoeringsgrafiek die stages met elkaar verbindt, gedeelde status beheert en streaming- of batch-uitvoeringsmodi coördineert.

De initialisatiefase codeert de referentie-identiteit één keer per verzoek in latents. De pipeline voert vervolgens een continue lus uit over de resterende fasen totdat de inkomende audiostream is uitgeput:

Stroomschema van een avatar-streaming-inferentie­pipeline die beeld-/video-, audio- en tekstinvoer verwerkt via stappen zoals encodering, contextgeneratie en superresolutie, met een op chunks gebaseerde lus, om een gegenereerd uitvoerbestand te produceren.
  • Contextgeneratie: Zet binnenkomende audiosegmenten om in kenmerken, combineert deze met tekst- of scènecondities en bereidt de doelruis-tensors voor.
  • Audio-naar-video: Voert een meerstaps-diffusieproces uit om latents met lage resolutie te produceren. In deze fase wordt het huidige segment afgestemd op de randframes van het vorige segment om de bewegingscontinuïteit te behouden.
  • Superresolutie: Schaal de bewegingslatenten in één stap op naar volledige resolutie, met prioriteit voor ruimtelijke details in het gezicht.
  • VAE Decode-and-Publish: Decodeert de latents met hoge resolutie naar RGB-frames en schrijft deze direct weg naar de uitvoerencoder (H.264 / AAC) voor onmiddellijke opslag of live weergave.

Grenscontinuïteit en chunkconsistentie

Het genereren van video in afzonderlijke segmenten kan leiden tot mogelijke onderbrekingen op de grenzen. Het framework beperkt dit door gebruik te maken van twee verschillende typen chunks:

  • N-segmenten: Segmenten die de primaire tijdlijn van de avatar genereren.
  • I Chunks (Interpolatie): Segmenten die zijn ontworpen om overgangen tussen opeenvolgende N-chunks te versoepelen.

De uitvoeringsvolgorde is als volgt opgebouwd:

N0 -> N1 -> I0 -> N2 -> I1 -> N3 -> I2 -> ...

Een I-chunk wordt pas gegenereerd nadat de voorafgaande en daaropvolgende N-chunks zijn voltooid. Hij gebruikt het laatste frame van de vorige N-chunk en een vroeg frame van de huidige N-chunk als ankerrames om de overgangsbeweging te berekenen. Na de generatie worden de overbodige anker-voorspellingen weggegooid, zodat alleen de vloeiend geïnterpoleerde overgang overblijft. Dit mechanisme begrenst het vereiste contextvenster terwijl de temporele consistentie behouden blijft.

Constante geheugencapaciteit gedurende de hele duur

Een conventionele videopijplijn stapelt tijdens de uitvoering latents, gedecodeerde frames en aandachtcontext op, waardoor het GPU-geheugengebruik lineair toeneemt met de videoduur.

Om open‑ended generatie mogelijk te maken, hanteert dit framework een strikt rollend geheugen. Het systeem bewaart alleen de statische referentie‑conditionering en een minimale set anker‑tensors die nodig zijn voor overgang tussen chunks. Alle tussentijdse assets—waaronder audiofeatures, ruis‑tensors, interne activaties en ruwe RGB‑frames—worden direct uit het geheugen verwijderd zodra een chunk is gedecodeerd en weggeschreven.

Daardoor blijft het piekgeheugenprofiel van de GPU gelijk, of er nu een korte clip of een langere reeks wordt gegenereerd; het resourcegebruik schaalt met de gedefinieerde chunkgrootte in plaats van met de totale duur van de sessie.

Laad- en ontlaadfasen binnen de pijplijn

Elke aanvraag wordt uitgevoerd op een node met 8 GPU’s. We gebruiken FSDP om de parameters van grote modellen over de GPU’s te verdelen. Elke rank bezit slechts een fractie van de gewichten, verzamelt de parameters die nodig zijn voor een berekening en geeft ze daarna weer vrij. Dit maakt het mogelijk om meerdere grote modellen — de basis-DiT, de superresolutie-DiT, de tekstencoder, de audio-encoder en de VAE — op één node te laten passen.

Er is een afweging. FSDP zorgt tijdens inferentie voor extra communicatie-overhead, omdat parameters tijdens de forward passes moeten worden verzameld. We gebruiken een combinatie van technieken om die overhead te verbergen en om samen geplaatste modellen van de GPU te houden wanneer ze niet in gebruik zijn:

  • Voorwaarts prefetchen. De AllGather van de parameters van het volgende blok wordt vroegtijdig gestart en overlapt met de berekening van het huidige blok, waardoor de wachttijd voor het ophalen op het kritieke pad wordt verborgen.
  • Lui per-blok unsharding vanaf de CPU. Wanneer een model wordt teruggehaald uit gepinde CPU-geheugen, laden we niet vooraf de volledige set gewichten. Elk transformerblok wordt pas vlak voor zijn forward pass unsharded (host-naar-device kopie + AllGather), zodat de H2D-overdracht van blok n+1 overlapt met de berekening van blok n.
  • Gepinde CPU-offload tussen fasen. De parameters van een model dat op dat moment niet actief is, worden in gepinde CPU-geheugenruimte bewaard, zodat samen geplaatste modellen (base DiT, super-resolution DiT, tekstencoder, audio-encoder, VAE) niet allemaal tegelijk hun gewichten in het GPU-geheugen hoeven te houden. Gepind geheugen zorgt ervoor dat de H2D-kopieën snel genoeg zijn om met de berekeningen te overlappen.
  • NUMA-bewuste procesplaatsing. Elk proces wordt vastgezet op hetzelfde NUMA-knooppunt als de toegewezen GPU, zodat CPU↔GPU-overdrachten op volledige PCIe/NVLink-bandbreedte kunnen plaatsvinden zonder de inter-socket-interconnect te kruisen.

Modelwissel tussen fasen in minder dan 10 ms

Het praktische voordeel van de bovenstaande technieken is dat het doorgeven van de GPU van het model van de ene fase naar de volgende — bijvoorbeeld A2V DiT → Super-Resolution DiT, of SR DiT → VAE-decoder — in de praktijk geen extra kosten met zich meebrengt. Doordat het uitgaande model asynchroon wordt uitgeladen en het eerste blok van het inkomende model precies op tijd wordt “unsharded”, worden zowel de H2D-kopie als de AllGather volledig verborgen achter berekeningen die toch al draaien. Over de hele keten gemeten blijft de waarneembare overhead per wissel onder de 10 ms — ruim onder het budget van één frame bij onze beoogde framerates. Concreet is dit wat het mogelijk maakt dat de streamingpijplijnlus (Context Gen → A2V → SR → VAE Decode-and-Publish) per chunk meerdere grote modellen kan doorlopen, zonder dat de modelwissel zelf ooit de bottleneck wordt.

Realtime streaming publicatie

Om het model snel genoeg te maken voor realtime streaming, hebben we veel inferentie-optimalisaties doorgevoerd, raadpleeg https://www.heygen.com/research/avatar-v-inference voor meer details over dit onderdeel.

Zodra de pipeline de video in realtime stuk voor stuk uitstuurt, wordt streaminglevering een natuurlijke uitbreiding van de inferentie in plaats van een aparte nabewerkingsstap.

Voor het realtime pad in broadcast-stijl publiceren we de gegenereerde frames naar Amazon Kinesis Video Streams (KVS). KVS wordt meestal besproken in de context van camera’s, IoT-apparaten en geüploade media. In ons geval is de "camera" de inference-pijplijn zelf: frames worden door het model gecreëerd, direct gecodeerd en als livestream naar KVS gestuurd.

De output-writer ontvangt gedecodeerde RGB-frames van de streaming VAE en stuurt deze naar een GStreamer-pijplijn. De video wordt gecodeerd als H.264 en het geluid als AAC, waarna beide sporen naar kvssink, de KVS-producer-sink, worden gestuurd. Vanaf daar kunnen kijkers de sessie als een livestream afspelen terwijl deze nog wordt gegenereerd.

Resultaten en inzichten

Het framework heeft de generatie van Avatar IV en Avatar V veranderd van rendering in vaste scènes naar open‑ended streaminggeneratie. Het belangrijkste resultaat is eenvoudig: we hebben de beperkingen op de sceneduur voor Avatar IV en Avatar V verwijderd. Voor realtime generatie van Avatar IV hebben we een time‑to‑first‑frame van minder dan 5 seconden bereikt en een generatie­snelheid van meer dan 27 frames per seconde voor 720p Avatar IV‑video’s — sneller dan realtime weergave.