AI trainen om te schilderen met code

Wanneer je een afbeelding genereert met een AI-model, is de prompt de enige manier om invloed uit te oefenen. Je kunt de afbeelding niet direct bewerken; om iets te veranderen, moet je terug naar het model en opnieuw een prompt invoeren. Deze beperking vormde de aanleiding voor dit project. Samen met mijn vriend Cameron heb ik een taalmodel getraind om afbeeldingen te maken door code te schrijven, gebruikmakend van reinforcement learning (RL). In dit geval is de code het artefact, en code is bewerkbaar. Hierdoor kun je de output van het model op een fijnmaziger niveau aanpassen zonder terug te hoeven grijpen naar de prompt.

De diepere vraag die dit project stelt, is hoe reinforcement learning toegepast kan worden op creatieve en designgerichte taken. RL werkt optimaal wanneer de beloning (reward) verifieerbaar is. Een wiskundig probleem is correct of incorrect; een spel wordt gewonnen of verloren. Esthetische kwaliteit is geen van beide. Het designprobleem verschuift hierdoor naar de beloningsfunctie en de criteria die een beoordelaar moet toepassen. Als deze te rigide zijn, convergeert het model te snel; als ze te los zijn, gaat het model driften.

Hoe het werkt

Het systeem bestaat uit een loop van vier stappen die tijdens de training duizenden keren wordt uitgevoerd:

  1. Prompt: Het model ontvangt een prompt, zoals "teken een perzikkleurige hibiscus in aquarel", en schrijft een complete p5.brush JavaScript-sketch.
  2. Renderen: De sketch wordt uitgevoerd in een gesandboxte Puppeteer-omgeving, wat resulteert in een PNG-afbeelding.
  3. Beoordeling: De PNG wordt vergeleken met twee willekeurige referentiepaintings uit een handmatig beoordeelde pool. Een apart judge-model bepaalt welke aquarel superieur is.
  4. Update: De beoordeling wordt omgezet in een beloningssignaal. GRPO (Group Relative Policy Optimization) update het model, waarna de loop opnieuw begint.

De cruciale keuzes in dit proces liggen in wat er precies wordt beoordeeld, hoe die beoordeling plaatsvindt, de samenstelling van de referentiepool en de formulering van de systeemprompt.

Beloningsfuncties

De eerste rubric bestond uit negen aparte signalen:

  • Een compilatie-gate.
  • Een controle of de code daadwerkelijk p5.brush gebruikte in plaats van native p5.
  • Een code-lengte ramp gericht op ongeveer 3.000 tokens.
  • HPSv3 (een model voor menselijke voorkeuren).
  • Prompt-trouw, beoordeeld door een raad van GPT-5.4 en Gemini.
  • Vier kwaliteitsbeoordelaars: herkenbaarheid, esthetiek, techniek en diepte.

Het model stagneerde bij een beloning van ongeveer 0,65. Elke output leek op elkaar: een vlakke, clip-art-achtige bloem met vijf ronde bloemblaadjes. Hoewel de beloningsscore steeg, verbeterden de werkelijke capaciteiten niet.

De diagnose bleek dat de vier kwaliteitsbeoordelaars en de prompt-trouw sterk met elkaar gecorreleerd waren (0,85 tot 0,95); ze maten in feite vijf keer hetzelfde. De codelengte, die ongeveer een derde van de totale beloning vormde, was na stap dertig verzadigd en leverde daarna geen gradiënt meer op. HPSv3, het enige signaal dat echte variantie vertoonde, was slechts gewogen op 0,10. De rubric vertelde het model dus herhaaldelijk hetzelfde.

De oplossing bestond uit twee delen:

  1. Vervanging van absolute scoring door paarsgewijze beoordeling (pairwise judgment): In plaats van de judge te vragen een score van 0 tot 10 te geven (wat leidde tot scores die dicht bij nul geclusterd waren), werd de vraag veranderd naar: "Welke van deze is de betere hibiscus-aquarel?" De beloning is nu de fractie van de vergelijkingen die het model wint. Dit vergroot het dynamische bereik aanzienlijk, omdat ein judge-model relatieve vragen betrouwbaarder beantwoordt dan abstracte schalen.
  2. Het bouwen van een referentiepool met handmatig beoordeelde voorbeelden: Er werden 1.664 afbeeldingen beoordeeld in de categorieën love, okay, en nope. De 117 'love-tier' voorbeelden vormden de basis van de vergelijkingspool. Elke output werd voortaan getoetst aan wat ik als "goed" had gedefinieerd. Een volgende stap (die niet is bereikt) zou het trainen van een klein beloningsmodel op deze ratings zijn (proper RLHF), zodat het gevoel voor kwaliteit toegepast kan worden zonder telkens de pool te raadplegen.

De nieuwe rubric werd vereenvoudigd tot vier componenten:

  • Binaire compile-and-uses-brush gate (0,05)
  • Binaire lengtecontrole (0,05)
  • HPSv3 (0,30)
  • Paarsgewijze judge tegenover de referentiepool (0,60)

Met hetzelfde basismodel en dezelfde trainingsdata bereikte de volgende run het vorige plateau drie keer sneller en steeg daarna verder. Bovendien werd de code gecomprimeerd van 13.500 tokens naar minder dan 2.000; het model leerde dat winnende composities geen verbose code nodig hadden.

De referentiepool

De pool bevat 581 referentiepaintings. Deze zijn gefilterd uit 1.664 generaties: 117 'love-tier', 266 'okay', en 198 supplementen uit een aparte generatieronde om gaten in het kleurenpalet op te vullen.

Alle afbeeldingen in de pool zijn model-outputs, omdat er onvoldoende menselijke voorbeelden beschikbaar waren (p5.brush is een niche-tool). Het generatieproces verliep via twee pipelines:

  • AutoResearch: Met Opus 4.6, GPT-5.4 en Gemini 3.1 Pro, die iteraties uitvoerden tegen referentiefoto's onder begeleiding van een VLM-judge.
  • Batch run: Een grotere run op Gemini 3.1 Pro.

Beide pipelines gebruikten een systeemprompt die was geëvolueerd via GEPA.

Evolutie van de systeemprompt

Ook de systeemprompt vereiste optimalisatie. Vroege versies bevatten een API-referentie voor p5.brush van 400 regels. Het model produceerde weliswaar zelfverzekerde en goed geformatteerde code, maar verzon daarbij API-functies die niet bestonden.

Dit werd opgelost met GEPA, een bibliotheek voor prompt-optimalisatie die een prompt evolueert tegen een scorefunctie. Na 200 iteraties tegen een 'taste-anchored' 7-shot judge, convergeerde de optimalisatie naar een prompt met een strikte allowlist van acht brush-methoden, zonder API-documentatie of voorbeelden. Pas nadat de referentie van 400 regels volledig was verwijderd, produceerden drie op de drie generaties zichtbare hibiscus-vormen.

De bevinding was dat uitgebreide referentiedocumentatie in een systeemprompt modellen aanzet tot het hallucineren van API's. Een korte, opiniërende allowlist beperkt de output effectiever dan de originele specificatie.

Conclusie

Reinforcement learning heeft een verifieerbare beloning nodig. Esthetische voorkeur is echter niet binair. Om RL toe te passen op subjectief werk, moet je de beloning handmatig authoreren en deze zorgvuldig genoeg ontwerpen zodat deze generaliseert. Te specifiek, en het model leert enkel de voorbeelden te kopiëren; te los, en het model leert niets specifieks. RL voor creatieve taken is in essentie een designprobleem: het creëren van een structuur waardoor smaak kan generaliseren naar gebruikersvoorkeuren.

Ik geloof niet dat dit een betere manier is om afbeeldingen te maken; het is zelfs veel langzamer. Maar ik was gefrustreerd door het feit dat de enige manier om deel te nemen aan AI-beeldcreatie via de prompt was. Dit project stelde me in staat om aandacht en inspanning te steken in de prompt, het model én het artefact. Het project is nog gaande, met een laatste trainingsrun om ontdekte problemen op te lossen. Een volledig technisch rapport wordt in juni 2026 gepubliceerd.