AI & AutomationAI-generated

Hoe een plaatje uit ruis ontstaat

Vraag een beeldgenerator om "een huisje met een rood dak" en een paar seconden later staat er een plaatje. De meeste van die generatoren werken met diffusie. Ze beginnen met een vlak vol willekeurige ruis en halen daar in tientallen kleine stappen ruis uit, tot er een beeld overblijft.

Dit is deel 6 van Hoe AI echt werkt. In deel 1 werd tekst een rij getallen. Hier gebeurt hetzelfde met een plaatje. Het ruis toevoegen draait hieronder echt, met de formule en het schema uit het oorspronkelijke paper. Een getraind netwerk past niet in een blogpost; waar dat nodig is, zeg ik wat ervoor in de plaats staat.

DiffusieEen plaatje van 32×32
-1,0-1,01,01,01,0-1,01,01,01,01,01,01,01,01,01,0-1,0-1,00,40,40,4-1,0-1,00,40,40,4

1.024 getallen tussen -1 (zwart) en 1 (wit)

Een plaatje is een raster getallen

Dit huisje is 32 bij 32 pixels, voor een computer 1.024 getallen. Elk getal loopt van -1 (zwart) tot 1 (wit): de achtergrond is -1, het dak 1 en de muur 0,4. Rechts staan de getallen uit het oranje vierkantje.

Een kleurenfoto heeft drie getallen per pixel, voor rood, groen en blauw. Een foto van 512 bij 512 pixels is dan 786.432 getallen.

Ruis is ook een raster getallen

Dit is ruis: 1.024 getallen, elk getrokken uit een normaalverdeling. Ze liggen meestal dicht bij nul, zelden verder weg dan 2 of 3: de klokvorm in het histogram. Deze trekking komt uit op een gemiddelde van -0,08 en een spreiding van 0,99. Theoretisch is dat 0 en 1.

Die ruis heet ε (epsilon). Hij komt uit een vaste seed, dus je ziet bij elk bezoek dezelfde.

Stap voor stap ruis erbij

Het voorwaartse proces mengt het plaatje met ruis. Bij elke stap wordt het beeld iets zwakker en de ruis iets sterker, tot er na duizend stappen niets van het huisje over is. Voor elke stap t is er een directe formule:

x_t = √ᾱ_t · x₀ + √(1−ᾱ_t) · ε

Hier is x₀ het origineel en bepaalt ᾱ_t (alfa-streep) de verhouding. Onder elk plaatje staan de twee gewichten. Bij t=200 telt het huisje nog voor 0,81 mee en de ruis voor 0,58.

Het schema

Hoe snel de ruis toeneemt, ligt vast in een ruisschema. Het paper waarmee diffusie doorbrak, DDPM van Ho, Jain en Abbeel (2020), gebruikt T = 1000 stappen, met een ruis per stap (β) die lineair oploopt van 0,0001 naar 0,02. Dat schema staat hier.

De groene lijn is het gewicht van het beeld, de oranje lijn dat van de ruis. Eerst verandert er weinig, rond het midden gaat het hard. Bij t = 1000 is het gewicht van het beeld 0,006. Wat overblijft is vrijwel zuivere ruis. Daar begint de terugweg.

Wat het model leert

Wie weet welke ruis er is opgeteld, kan die weer aftrekken. Het netwerk krijgt daarom tijdens de training een plaatje met ruis, x_t, plus het getal t, en moet raden welke ruis ε erin zit.

Neem een plaatje uit de dataset, kies een willekeurige t, trek ruis en reken x_t uit. Laat het netwerk de ruis voorspellen (ε̂) en meet hoe ver het ernaast zit: het gemiddelde van (ε̂ − ε)² over alle pixels. Dat herhaal je met miljoenen plaatjes. Zo'n netwerk heet een denoiser.

Terug met het antwoordblad

Tijdens de training kennen we de echte ruis, want die hebben we zelf getrokken. Met dat antwoordblad is terugrekenen simpel. Trek √(1−ᾱ_t) · ε af en deel door √ᾱ_t. Wat overblijft is precies het originele huisje, zelfs bij t = 600, waar je het met het blote oog niet meer ziet.

Dit is een orakel, geen model. Bij een nieuw plaatje is er geen echte ruis om op te zoeken, want er was nooit een origineel. Een echt model moet de ruis schatten.

Terug vanaf pure ruis

Bij het genereren begin je met pure ruis bij t = 1000. Het model schat de ruis, en daarmee hoe het eindbeeld eruit zou zien (x̂₀, onderste rij). Je haalt een deel van de geschatte ruis weg, zet een stap terug en schat opnieuw. Hier in 50 stappen, met de DDIM-methode.

Op de plek van het netwerk staat hier de best mogelijke schatter voor een wereld met precies negen voorbeeldplaatjes: drie huisjes, drie bomen en drie keer de letter A. Die is exact uit te rekenen. In het begin is x̂₀ een vage mix van alle negen, want bij zoveel ruis is alles nog mogelijk. Gaandeweg valt de keuze, hier op een boom. Een getraind netwerk doet hetzelfde, met kennis uit miljoenen plaatjes in plaats van negen.

Tekst stuurt

Om een huisje te krijgen en geen boom, krijgt het netwerk ook de tekst mee, als rij getallen. Dat heet conditionering. In de bovenste rij begint alles met dezelfde ruis; alleen het label verschilt.

Daarbovenop zit vaak classifier-free guidance (Ho en Salimans): het model schat de ruis twee keer, met en zonder tekst, en vergroot het verschil met een factor g. Bij g = 0 telt de tekst niet mee; met dezelfde ruis komt er dan weer een boom uit. Bij g = 1 krijg je de gewone schatting met tekst. Daarboven wordt het verschil overdreven. De onderste rij toont de eerste schatting van het eindbeeld bij oplopende g. Bij 7,5, de standaard voor Stable Diffusion in de diffusers-bibliotheek, schieten de waarden tot ruim 6, ver buiten -1 tot 1. Een hogere g volgt de tekst strakker; te hoog geeft overdreven, verzadigde plaatjes.

Kleiner rekenen: de latente ruimte

Diffusie op volle pixels is duur: elke stap rekent het hele netwerk over het hele beeld, tientallen keren per plaatje. Latent diffusion (Rombach en collega's, 2022) pakt dat anders aan. Een apart getrainde encoder comprimeert het plaatje eerst. Stable Diffusion 1 maakt van 512×512 pixels met drie kleuren een raster van 64×64 met vier kanalen.

Dat zijn 16.384 getallen in plaats van 786.432, 48 keer minder. Alle ruisstappen gebeuren in die kleine ruimte. Pas aan het eind maakt een decoder er weer een plaatje van.

Speel zelf

In de stand heen schuif je t van 0 tot 1000 en zie je de formule aan het werk. Met andere ruis trek je een nieuwe ε. Rond t = 400 wordt het huisje voor het oog vaag, terwijl het beeld dan nog voor 0,44 meetelt.

In de stand terug kies je een label en een guidance-waarde, en scrub je door de 50 stappen. Let op de rechter schatting in de eerste stappen. Ook hier rekent de ideale schatter voor negen plaatjes, geen getraind netwerk.

Wat niet in het plaatje past

Een echt model kopieert meestal niet. Onze ideale schatter komt altijd uit op een van zijn negen plaatjes; iets anders bestaat voor hem niet. Een getraind netwerk kan niet elk trainingsplaatje onthouden en leert daarom patronen, zoals hoe daken lopen en hoe licht valt. Zo maakt het ook iets dat nooit in de dataset stond. Helemaal waterdicht is dat niet. Carlini en collega's haalden in 2023 meer dan duizend trainingsbeelden vrijwel letterlijk terug uit modellen als Stable Diffusion en Imagen.

Het netwerk zelf. In DDPM en Stable Diffusion 1 is de denoiser een U-Net, een convolutienetwerk dat het beeld verkleint en weer vergroot. De tekst komt binnen via een aparte tekst-encoder (bij Stable Diffusion 1 die van CLIP) en cross-attention. Nieuwere modellen gebruiken vaak transformers en een verwante trainingsmethode, rectified flow, zoals Stable Diffusion 3.

Minder stappen. DDPM gebruikt bij het genereren alle duizend stappen. DDIM (Song e.a., 2020) haalt vergelijkbare kwaliteit 10 tot 50 keer sneller. De Stable Diffusion-pijplijn in diffusers staat standaard op 50. Er zijn inmiddels methoden die met een handvol stappen of zelfs één stap toekomen.

Zelf proberen

Het ruisschema reken je in een paar regels Python na, met de gewichten van beeld en ruis per t:

python3 -c "
import numpy as np
b = np.linspace(1e-4, 0.02, 1000); ab = np.cumprod(1 - b)
for t in (200, 500, 1000): print(t, round(ab[t-1]**.5, 3), round((1-ab[t-1])**.5, 3))"

Dat geeft 0.812 0.584, 0.28 0.96 en 0.006 1.0, afgerond dezelfde getallen als in de visual.

Tot slot

Ik had me diffusie altijd voorgesteld als iets dat een plaatje "uit het niets" tekent. Bij het narekenen viel me op hoe bescheiden de taak van het netwerk is. Het raadt welke ruis erin zit, vijftig keer achter elkaar, en dat is alles.

Het eerlijkste moment vond ik de stap met het orakel. Met het antwoordblad is terugrekenen één aftreksom; zonder antwoordblad is het het hele vak. Alle rekenkracht in een beeldgenerator gaat op aan het schatten van iets wat bij het genereren nergens bestaat: de ruis die er nooit in is gestopt.