Character-embeddings: een technische primer

Hoe character-lock-systemen daadwerkelijk werken in moderne AI-videopipelines: architectuur, ontwerpkeuzes, failure modes en open problemen.

·9 min read·technical

Dit artikel is voor engineers onderzoekers, ML-praktijkmensen en developers die AI-videotooling bouwen of evalueren. Wil je een niet-technisch overzicht van waarom character-consistentie ertoe doet, begin dan met de volledige gids.

Hier lopen we door hoe character-embedding-systemen daadwerkelijk werken in moderne AI-videostacks: de architectuur, de ontwerpkeuzes, de failure modes en de open problemen die we nog niet hebben opgelost.

De probleemstelling

Gegeven een generatief videomodel M en een character C, willen we een procedure zodat voor elke prompt p_i in een reeks p_1, p_2, , p_n die naar C verwijst, de gegenereerde outputs allemaal de identiteit van C behouden.

De naïeve aanpak de character-beschrijving in elke prompt zetten faalt omdat diffusion-sampling stochastisch is en prompts categorieën beschrijven, geen identiteiten. Elke generatie is een trekking uit de verdeling van geldige characters die bij de beschrijving passen; de identiteit drift tussen trekkingen.

We hebben een manier nodig om de output van het model te conditioneren op een specifieke geleerde identiteit, niet alleen op een beschrijving.

De architectuur

Een modern character-consistentiesysteem heeft zes componenten:

1. Feature-extractie         — produceert identity-embedding uit de referentie
2. Storage                   — bewaart embedding gekoppeld aan character_id
3. Negative-prompt-synthese  — bouwt automatisch negative_prompts uit drift-catalogus
4. Conditioning-injectie     — injecteert embedding in de modelconditioning
5. Generatie                 — diffusion-sampling met geconditioneerd model
6. Consistentie-verificatie  — post-hoc similariteitscheck, opnieuw genereren indien nodig

We lopen ze stuk voor stuk langs.

1. Feature-extractie

Bij upload van een character draaien meerdere gespecialiseerde modellen op de referentie:

Deze worden geconcateneerd (of via attention samengevoegd) tot een hoogdimensionale character-embedding e_C. Totale dimensionaliteit ligt typisch tussen 1500 en 3000.

Waarom meerdere modellen in plaats van één? Omdat identiteit meerdere assen heeft die geen enkele encoder volledig vangt. Face-encoders zijn goed in is dit hetzelfde gezicht? maar blind voor lichaamsproporties. Body-parsers zien geen gezichtsdetails. CLIP is sterk in semantisch uiterlijk maar verliest fijne identiteit. Concateneren geeft orthogonale dekking.

Trade-off: een complexere extractie-pipeline betekent meer compute bij upload (~30-90 seconden in sommige systemen). Voor consumenten-tools is dat prima. Voor pipelines met hoge throughput kun je embeddings één keer pre-computen bij upload en bij generatie refereren.

2. Storage

Elke character wordt opgeslagen als (character_id, embedding_vector, metadata). Metadata bevat:

Storage is doorgaans een vectordatabase (Pinecone, Qdrant, Weaviate) of een eigen geïndexeerde structuur. Lookups moeten snel zijn sub-100ms omdat ze bij elke generatie gebeuren.

Voor privacy-gevoelige deployments kunnen embeddings versleuteld worden opgeslagen met per-tenant sleutels. De extractie is een one-way functie (je kunt het referentiebeeld niet reconstrueren uit de embedding), maar embeddings als PII behandelen is de juiste default voor systemen die met echte mensen werken.

3. Negative-prompt-synthese

Dit is het niet-vanzelfsprekende deel van het systeem en waar het meeste engineeringwerk zit.

In de praktijk houdt men een catalogus bij van veelvoorkomende drift modes categorische failure-types waargenomen over duizenden generaties. Voor elke mode is er een corresponderend negative_prompt-fragment dat die failure onderdrukt.

Voorbeelden uit de catalogus:

Drift modeNegative-prompt-fragment
Oogkleurverschuiving (bruin groen)green eyes, hazel eyes (wanneer referentie bruin is)
Versmalling van de kaaklijnnarrow jaw, weak chin, soft jawline
Wijkende haargrenshigh hairline, thinning hair, receding hairline
Warmer wordende huidstoonwarm skin tone, golden complexion (wanneer referentie koel is)
Asymmetrie-driftasymmetric face, uneven features
Verschuivende oogafstandwide-set eyes, close-set eyes

Deze catalogus opbouwen vergt gelabelde data. In de praktijk labelt men ~10.000 generaties van publieke AI-videotools (Runway, Pika, Sora etc.) met de specifieke drift modes die verschenen. Clustering levert typisch ~30 distincte modes die ~85% van waargenomen drift dekken.

Voor elke generatie:

  1. Haalt het systeem de referentie-attributen van de character op
  2. Berekent het tegenovergestelde van elk attribuut (bv. als de referentie donkere ogen heeft, is het tegengestelde lichte ogen)
  3. Stelt een character-specifieke negative prompt samen door de relevante drift-suppressors te bundelen

Het resultaat is een veel sterker conditioning-signaal dan vanille prompt-only generatie.

4. Conditioning-injectie

Verschillende videomodellen accepteren conditioning op verschillende manieren:

In de praktijk is API-level injectie veel effectiever dan reference-image-gebaseerd, maar de meeste publieke APIs bieden deze diepte niet. Werkend op de beschikbare API-oppervlakte: een sterke negative prompt combineren met een als referentiebeeld gecodeerde embedding levert ongeveer 80-90% van het effect van API-level injectie.

Mede daarom is een character-consistentie-laag bouwen zinvol, ook als je het onderliggende model niet beheert er is significante speelruimte op de conditioning-oppervlakte die publieke APIs al bieden.

5. Generatie

Standaard diffusion-sampling, met als nuance dat de conditioning nu een combinatie is van:

Generatiekosten zijn typisch 1.0-1.2× die van een vanille generatie. De marginale kosten zijn klein.

6. Consistentie-verificatie

Na generatie laten we een apart identity-model (gewoonlijk dezelfde face-encoder als in stap 1) los op de output. We berekenen de cosine similarity tussen de identity-embedding van de output en de oorspronkelijke referentie-embedding.

Drempel: typisch 0,85 cosine similarity. Boven de drempel wordt de output geaccepteerd. Eronder wordt regeneratie getriggerd met strakker conditioning (hoger negative-prompt-gewicht, sterkere embedding-injectie).

Dit voegt gemiddeld ~5-10% generatiekosten toe (de meeste shots passeren in één keer) en houdt de ergste drift-gevallen weg van de gebruiker.

Wat goed werkt, wat niet

Wat werkt:

Wat moeilijker is:

Open onderzoeksproblemen

Wie in dit veld werkt, hier zijn problemen die we graag opgelost zouden zien:

  1. Form-variant-invarianten. Wat is de juiste geleerde representatie die identiteits-invariante gezichtsstructuur vangt en tegelijk willekeurige toestandstransformaties toelaat?
  2. Actieve drift-detectie tijdens sampling. Huidige consistentiechecks zijn post-hoc. Kunnen we drift detecteren tijdens het diffusion-proces en mid-sampling corrigeren?
  3. Trade-off impliciete vs. expliciete identiteit. Wanneer overtreft een kleine per-character LoRA embedding-gebaseerde conditioning? Waar ligt de grens?
  4. Modellering van multi-character-interactie. Hoe vangen we niet alleen twee gelockte identiteiten maar ook hun relationele dynamiek zo dat het over shots stand houdt?
  5. Identity-uncertainty kwantificeren. Wanneer het model onzeker is over identiteit, kan het die onzekerheid expliciet maken in plaats van een zelfverzekerde drift te produceren?

Werk je aan een van deze en wil je sparren? Het team achter Juying heeft echt belangstelling. Neem contact op.

Praktisch advies voor builders

Overweeg je een character-consistentielaag voor je eigen product te bouwen, drie adviezen:

1. Begin met de negative-prompt-catalogus. Dit is de hoogste-impact-laagste-kosten-winst. Je hebt geen API-level modeltoegang nodig; de negative prompt wordt door elke publieke API ondersteund. Besteed een week aan het labelen van 1000 generaties en je hebt een catalogus die het meeste drift dekt.

2. Onderschat post-hoc verificatie niet. Een simpele opnieuw genereren als similarity < 0,85-loop toevoegen vangt de slechtste 10% van failures en verhoogt de waargenomen kwaliteit drastisch. Het is de goedkoopste 90/100 95/100 quality-bump die er is.

3. Investeer vroeg in storage. Character-embeddings als persistente assets is het architectuurinzicht dat compoundt. Bouw de juiste primitives één keer en elke toekomstige feature (style-locks, scènebibliotheken, asset-hergebruik) breidt zich natuurlijk uit.

Verwante leesstof

Bouw je in dit gebied en wil je praten info@juying.art