Query, Key, Value
Tre Linjära Kartor från Samma Input
Efter inbäddning (aktivitet 4) bär varje position en 768-dimensionell vektor x_t. Attention börjar med att producera tre distinkta projektioner av x:
Q (query): vad vill denna position veta?
K (nyckel): vad erbjuder denna position till andra positioner?
V (värde): vilket innehåll levererar denna position om den uppmärksammas?
Varje projektion kommer från en inlärd viktmatris:
Q = x · W_Q # W_Q form: (d_model, d_k)
K = x · W_K # W_K form: (d_model, d_k)
V = x · W_V # W_V form: (d_model, d_k)
Tre matriser, alla tränade via bakåtpropagering. En modell lär sig: på denna position, vilken query hämtar bäst användbart tidigare sammanhang? Vilken key annonserar denna positions innehåll väl? Vilket value levereras om det väljs?
Ett biblioteksanalogiexempel
Tänk dig ett bibliotekskortregister. Du går in med ett ämne i åtanke (din query). Varje kort listar nyckelord (en key). När ditt ämne matchar ett korts nyckelord, tar du bokens innehåll (ett value). Attention gör detta för varje token parallellt: varje position frågar varje annan position, rankar överensstämmelse, & hämtar en viktad kombination av value-vektorer.
ANDREA-120M Dimensioner
| Mängd | Värde | Noter |
|---|---|---|
| d_model | 768 | Vektorstorlek på varje position |
| n_head | 12 | Parallella uppmärksamhetsheadar |
| d_k | 64 | Dimension per head (= d_model / n_head) |
| T | 1024 | Kontextlängd |
d_k = d_model / n_head = 768 / 12 = 64. Varje head ser en 64-dimensionell skiva av ett fullt 768-dimensionellt utrymme. Activity 6 (grow_a_language_model_multi_head) täcker en uppdelning per head i detalj.
Beräkna d_k
Varför dividera med sqrt(d_k)
En poängmatris
När Q & K finns (varje form (T, d_k)), beräknar attention en poängmatris:
scores = Q · K^T # shape: (T, T)
scores[i, j] = hur starkt position i:s query stämmer överens med position j:s key. Varje (i, j)-par får en score: 1024 × 1024 = 1 048 576 scores per attention head per forward pass.
Varför dividera
Priorsprodukter av två slumpmässiga d-dimensionella enhetsvektorer har en magnitud av ordningen sqrt(d). Utan skalning växer scores med d_k:
- d_k = 64: typiska skalära produkter i storleksordningen 8.
- d_k = 256: typiska skalära produkter i storleksordningen 16.
- d_k = 4096: typiska skalära produkter i storleksordningen 64.
Stora värden ger en spetsig softmax (en position dominerar, gradienter försvinner på annat håll). Träningen stannar av. Skalning fixar magnituden:
scaled_scores = (Q · K^T) / sqrt(d_k)
För ANDREA-120M är sqrt(d_k) = sqrt(64) = 8. Varje poäng delas med 8. Magnituderna förblir ungefär i enhetsskala oavsett d_k. Softmax förblir välbeteende. Gradienterna flyter.
Vaswanis ursprungliga motivering
Från Attention Is All You Need (2017): 'För stora värden av d_k växer punktprodukterna i magnitud, vilket trycker softmax-funktionen in i regioner där den har extremt små gradienter.' En sqrt(d_k)-divisor motverkar den tillväxten.
En Kodvy
Inne i microgpt_cuda.cu visas denna skalning som en literal division:
scores[i][j] = dot(Q[i], K[j]) * (1.0f / sqrtf(d_k));
En float-multiplikation per score. Billigt. Kritiskt.
Skalning vid d_model = 4096
Varför Position i Inte Kan Se Position j > i
En Begränsning Född ur Generering
ANDREA genererar en token i taget. Vid inferens producerar position 0 en första token, sedan ser position 1 position 0:s utdata & producerar en andra token, & så vidare. En modell har aldrig tillgång till framtida tokens under generering.
Träningen måste spegla detta. Om under träning position 5 kunde uppmärksamma position 6, skulle en modell lära sig en genväg: 'förutsäg token 6 genom att läsa token 6'. Vid inferens försvinner den genvägen (token 6 existerar inte ännu). En models tränings- kontra inferensbeteende skulle divergara katastrofalt.
En Mask
En kausal mask blockerar uppmärksamhet från valfri position i till valfri position j > i. Implementering: sätt scaled_scores[i][j] = -infinity överallt där j > i. Efter softmax blir de posterna exp(-inf) = 0. Masken nollställer uppmärksamhet till framtida positioner rent.
för i i range(T):
för j i range(T):
om j > i:
scaled_scores[i][j] = -1e9 # effektivt -inf
Efter softmax (radvis), summerar varje rad till 1, men endast positioner [0, i] bär sannolikhetsmassa. Position i blandar information endast från tidigare positioner.
Visualisera en mask
En poängmatris med form (T, T) med mask applicerad ser ut som en nedre-triangulär struktur:
scaled_scores efter mask, radvis softmax:
rad 0: [1.0, 0, 0, 0, ...] # ser bara sig själv
rad 1: [0.4, 0.6, 0, 0, ...] # ser positioner 0, 1
rad 2: [0.2, 0.3, 0.5, 0, ...] # ser 0, 1, 2
rad 3: [0.1, 0.2, 0.3, 0.4, ...] # ser 0, 1, 2, 3
...
Strikt nedre-triangulär sannolikhetsfördelning per rad. Framtiden förblir osynlig.
Varför en Decoder-Only Transformer Behöver Detta
Decoder-only-modeller som ANDREA, GPT & LLaMA har alla ett gemensamt mål: förutsäg nästa token från det förflutna. En causal mask gör det målet tränbart parallellt: varje position beräknar sin egen nästa-token-förutsägelse på en gång, & ingen position fuskar genom att kika framåt.
Mask & Smak
Från Poäng till Utmatning
Softmax: Sannolikheter från poäng
Maskerade, skalade poäng varierar fortfarande över reella tal. Softmax omvandlar varje rad till en sannolikhetsfördelning:
A[i][j] = exp(scaled_scores[i][j]) / sum_k exp(scaled_scores[i][k])
Tre egenskaper uppstår:
- A[i][j] >= 0 för alla (i, j).
- sum_j A[i][j] = 1 för varje rad i.
- Större råpoäng ger större sannolikheter (monoton).
Rad i:s sannolikhetsvektor berättar för en modell: hur mycket ska position i uppmärksamma varje tidigare position när dess utdata beräknas?
Viktad V-summa
En slutlig uppmärksamhetsutdata för position i:
output[i] = sum_j A[i][j] · V[j]
Varje värdevektor V[j] vägs med uppmärksamhetsprobabiliteten A[i][j], sedan summeras de. Position i:s utdata kombinerar värdevektorer från varje tidigare position, vägd efter relevans.
I matrisform, alla positioner på en gång:
Attention(Q, K, V) = softmax(mask(Q · K^T / sqrt(d_k))) · V
En rad. En hel uppmärksamhetsmekanism. Vaswani et al. skrev den raden 2017; transformatorer har inte förändrats fundamentalt sedan dess.
Form på utdata per huvud
Utdata från ett uppmärksamhets huvud: form (T, d_k). För ANDREA-120M: (1024, 64). Alla 12 huvuden beräknas parallellt; deras utdata konkateras till (1024, 768) & matas in i en slutlig linjär projektion (W_O), sedan vidare till en transformerblocks MLP.
Aktivitet 6 (grow_a_language_model_multi_head) täcker en multi-head-uppdelning. Aktivitet 7 (grow_a_language_model_transformer_block) täcker allt som omger uppmärksamhet: residualkopplingar, lager-normalisering, MLP.