- Je berekent één ongemaskeerde beeldattentionhead en leest een CLS-classificatiescore uit.
- Je onderscheidt querybreedte, tokenaantal en exacte scorekosten inclusief CLS.
Vier losse beeldtegels vertellen nog niet hoe onderdelen bij elkaar horen. Een gele vlek kan een stukje zon, trui of verkeersbord zijn. Beeldattention laat een patch informatie uit andere patches gebruiken, zodat een volgende laag meer context heeft.
Denk aan kaarten op tafel met een extra verzamelkaart. Iedere kaart stelt een vraag, vergelijkt die met de andere kaarten en maakt een gewogen mengsel van hun informatie. De verzamelkaart is het class-token, CLS, dat in de vorige les vóór de patches kwam.
We onderzoeken één zelfgekozen attentionhead. Dit is een rekenvoorbeeld zonder training, residualverbindingen, normalisatielagen of MLP; het volledige ViT bevat die onderdelen wel. Gebruik de transformerlessen als je wilt reconstrueren hoe deze stap in een volledig blok past.
1. Laat het hele beeld meedoen
De tokenmatrix Z heeft T rijen en D invoerkenmerken. Vermenigvuldig Z met drie gewichtsmatrices om queries Q, keys K en values V te krijgen. Queries en keys delen hun breedte d; values mogen een andere breedte hebben.
Iedere rij van A verdeelt gewicht over de keys. Daarna is de uitvoer Y gelijk aan AV: dezelfde gewichten mengen ieder valuekenmerk. Deel door de wortel van de query-/keybreedte, niet door de invoerbreedte D of het aantal tokens T.
Neem twee tokens met waarden 1 en 2, query- en keygewicht 1 en valuegewicht 3. De eerste query krijgt scores 1 en 2; na softmax wordt dat ongeveer 0,269 en 0,731. De values zijn 3 en 6, dus het eerste mengsel is ongeveer 5,193.
tokens = np.array([[1.],[2.]])
step = visual_attention(
tokens,[[1]],[[1]],[[3]])
print(step['weights'].round(3).tolist())
# [[0.269, 0.731], [0.119, 0.881]]
print(step['context'].round(3).tolist())
# [[5.193], [5.642]]
Maak visual_attention met weights en context als uitvoervelden. Alle tokens mogen hier alle tokens gebruiken; een causaal driehoeksmasker uit een taalmodel zou informatie onnodig afsluiten. Een hoog attentiongewicht blijft een rekengewicht, geen bewijs dat deze patch de volledige voorspelling verklaart.
Twee tokens hebben waarden 1 en 2. Keys blijven 1 en 2, values 3 en 6. Verander alleen de queryprojectie.
- Gewogen uitvoer
- 5,193
- Som van gewichten
- 1
Beide keys blijven bereikbaar. Dit is ongemaskeerde beeldattention, geen woordvoorspelling.
- Tokens inclusief CLS
- 5
- Aandachtsscorecellen
- 25
Patchmaat 2 blijft gelijk. Dit telt scores in één laag; de telling is geen meting van tijd of FLOPs.
Handgekozen rekenvoorbeelden. De getallen komen uit de eigen NumPy-functies; er is geen getrainde beeld- of tekstencoder.
2. Lees de verzamelkaart uit
CLS is rij nul, zowel vóór als na deze mengstap. Een classificatiehead projecteert die uitvoerrij naar een score per klasse en telt een bias op. Het zijn ruwe scores, ook wel logits; ze hoeven niet positief te zijn of op te tellen tot één.
scores = classify_visual_tokens(
step['context'],[[1,-1]],[0,1])
print(scores.round(3).tolist())
# [5.193, -4.193]
Maak classify_visual_tokens voor deze lineaire head. Neem uitsluitend rij nul en geef een zelfstandige scorevector terug. De hoogste score is in dit voorbeeld index nul, maar zonder getrainde parameters en afgesproken klassennaam zegt die index niets over de inhoud van een foto.
Gemiddeld poolen is een mogelijke andere architectuurkeuze, maar het is een ander contract. Stilzwijgend alle tokenrijen middelen verandert hier de uitkomst. Controleer ook dat head en bias bij de featurebreedte en het aantal klassen passen.
023. Meer resolutie vraagt meer vergelijkingen
Elke head vergelijkt ieder token met ieder token. Voor h heads bevat de scorematrix daarom hT² getallen. We tellen hier scorecellen in één laag; dit is geen FLOP-telling, totale modelgrootte of gemeten laadtijd.
small = visual_attention_cost(4,4,2)
large = visual_attention_cost(8,8,2)
print(small)
print(large)
# {'tokens': 5, 'scores': 25}
# {'tokens': 17, 'scores': 289}
De patchmaat blijft 2. Verdubbel je hoogte én breedte, dan stijgt het aantal patches van vier naar zestien; met CLS zijn dat vijf en zeventien tokens. Hun scoreaantallen verschillen een factor 11,56, dus bij dit kleine voorbeeld niet exact zestien.
print(large['scores']/small['scores'])
# 11.56
Maak visual_attention_cost met tokens en scores, inclusief CLS en het opgegeven aantal heads. Bij grote aantallen patches nadert de resolutiefactor zestien; CLS veroorzaakt de afwijking in kleine voorbeelden. Zo kun je een ontwerptrade-off narekenen voordat je een model kiest.
03Wat neem je mee?
- Beeldattention is hier ongemaskeerd en normaliseert langs keys.
- De classificatiehead leest het bijgewerkte CLS-token uit.
- Kleinere patches leveren meer tokens en veel meer onderlinge scores op.