4. Aandag Meganismes
Reading time: 15 minutes
tip
Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
Aandag Meganismes en Self-Aandag in Neurale Netwerke
Aandag meganismes laat neurale netwerke toe om op spesifieke dele van die invoer te fokus wanneer hulle elke deel van die uitvoer genereer. Hulle ken verskillende gewigte aan verskillende invoere toe, wat die model help om te besluit watter invoere die relevantste is vir die taak wat voorlê. Dit is van kardinale belang in take soos masjienvertaling, waar begrip van die konteks van die hele sin noodsaaklik is vir akkurate vertaling.
tip
Die doel van hierdie vierde fase is baie eenvoudig: Pas 'n paar aandag meganismes toe. Hierdie gaan baie herhaalde lae wees wat die verhouding van 'n woord in die woordeskat met sy bure in die huidige sin wat gebruik word om die LLM te train, gaan vasvang.
'n Groot aantal lae word hiervoor gebruik, so 'n groot aantal leerbare parameters gaan hierdie inligting vasvang.
Verstaan Aandag Meganismes
In tradisionele volgorde-tot-volgorde modelle wat vir taalvertaling gebruik word, kodeer die model 'n invoer volgorde in 'n vaste-grootte konteksvektor. Hierdie benadering sukkel egter met lang sinne omdat die vaste-grootte konteksvektor dalk nie al die nodige inligting vasvang nie. Aandag meganismes spreek hierdie beperking aan deur die model toe te laat om al die invoer tokens te oorweeg wanneer dit elke uitvoer token genereer.
Voorbeeld: Masjienvertaling
Oorweeg om die Duitse sin "Kannst du mir helfen diesen Satz zu übersetzen" in Engels te vertaal. 'n Woord-vir-woord vertaling sou nie 'n grammatikaal korrekte Engelse sin lewer nie weens verskille in grammaticale strukture tussen tale. 'n Aandag meganisme stel die model in staat om op relevante dele van die invoer sin te fokus wanneer dit elke woord van die uitvoer sin genereer, wat lei tot 'n meer akkurate en samehangende vertaling.
Inleiding tot Self-Aandag
Self-aandag, of intra-aandag, is 'n meganisme waar aandag binne 'n enkele volgorde toegepas word om 'n voorstelling van daardie volgorde te bereken. Dit laat elke token in die volgorde toe om op al die ander tokens te let, wat die model help om afhanklikhede tussen tokens vas te vang ongeag hul afstand in die volgorde.
Sleutelkonsepte
- Tokens: Individuele elemente van die invoer volgorde (bv. woorde in 'n sin).
- Embeddings: Vektor voorstellings van tokens, wat semantiese inligting vasvang.
- Aandag Gewigte: Waardes wat die belangrikheid van elke token relatief tot ander bepaal.
Berekening van Aandag Gewigte: 'n Stap-vir-Stap Voorbeeld
Kom ons oorweeg die sin "Hello shiny sun!" en verteenwoordig elke woord met 'n 3-dimensionele embedding:
- Hello:
[0.34, 0.22, 0.54]
- shiny:
[0.53, 0.34, 0.98]
- sun:
[0.29, 0.54, 0.93]
Ons doel is om die konteksvektor vir die woord "shiny" te bereken met behulp van self-aandag.
Stap 1: Bereken Aandag Punte
tip
Vermy om verlore te raak in die wiskundige terme, die doel van hierdie funksie is eenvoudig, normaliseer al die gewigte sodat hulle in totaal 1 optel.
Boonop, softmax funksie word gebruik omdat dit verskille beklemtoon weens die eksponensiële deel, wat dit makliker maak om nuttige waardes te identifiseer.
Vir elke woord in die sin, bereken die aandag punt ten opsigte van "shiny" deur die dot produk van hul embeddings te bereken.
Aandag Punt tussen "Hello" en "shiny"
 (1) (1).png)
Aandag Punt tussen "shiny" en "shiny"
 (1) (1) (1) (1) (1) (1) (1).png)
Aandag Punt tussen "sun" en "shiny"
 (1) (1) (1) (1).png)
Stap 2: Normaliseer Aandag Punte om Aandag Gewigte te Verkry
tip
Moet nie verlore gaan in die wiskundige terme nie, die doel van hierdie funksie is eenvoudig, normaliseer al die gewigte sodat hulle in totaal 1 optel.
Boonop, softmax funksie word gebruik omdat dit verskille beklemtoon weens die eksponensiële deel, wat dit makliker maak om nuttige waardes te identifiseer.
Pas die softmax funksie toe op die aandag punte om hulle in aandag gewigte te omskep wat tot 1 optel.
 (1) (1) (1) (1).png)
Berekening van die eksponensiale:
 (1) (1).png)
Berekening van die som:
 (1) (1).png)
Berekening van aandag gewigte:
 (1) (1).png)
Stap 3: Bereken die Konteksvektor
tip
Kry net elke aandag gewig en vermenigvuldig dit met die verwante token dimensies en som dan al die dimensies op om net 1 vektor (die konteksvektor) te kry.
Die konteksvektor word bereken as die gewogen som van die embeddings van al die woorde, met behulp van die aandag gewigte.
.png)
Berekening van elke komponent:
- Gewogen Embedding van "Hello":
 (1) (1).png)
- Gewogen Embedding van "shiny":
 (1) (1).png)
- Gewogen Embedding van "sun":
 (1) (1).png)
Som die gewogen embeddings op:
konteksvektor=[0.0779+0.2156+0.1057, 0.0504+0.1382+0.1972, 0.1237+0.3983+0.3390]=[0.3992,0.3858,0.8610]
Hierdie konteksvektor verteenwoordig die verrykte embedding vir die woord "shiny," wat inligting van al die woorde in die sin inkorporeer.
Samevatting van die Proses
- Bereken Aandag Punte: Gebruik die dot produk tussen die embedding van die teikenwoord en die embeddings van al die woorde in die volgorde.
- Normaliseer Punte om Aandag Gewigte te Verkry: Pas die softmax funksie toe op die aandag punte om gewigte te verkry wat tot 1 optel.
- Bereken Konteksvektor: Vermenigvuldig elke woord se embedding met sy aandag gewig en som die resultate op.
Self-Aandag met Leerbare Gewigte
In praktyk gebruik self-aandag meganismes leerbare gewigte om die beste voorstellings vir vrae, sleutels, en waardes te leer. Dit behels die bekendstelling van drie gewig matrikse:
 (1) (1).png)
Die vraag is die data om soos voorheen te gebruik, terwyl die sleutels en waardes matrikse bloot ewekansige-leerbare matrikse is.
Stap 1: Bereken Vrae, Sleutels, en Waardes
Elke token sal sy eie vraag, sleutel en waarde matriks hê deur sy dimensiewaarde met die gedefinieerde matrikse te vermenigvuldig:
.png)
Hierdie matrikse transformeer die oorspronklike embeddings in 'n nuwe ruimte wat geskik is vir die berekening van aandag.
Voorbeeld
Aanvaar:
- Invoer dimensie
din=3
(embedding grootte) - Uitvoer dimensie
dout=2
(gewens dimensie vir vrae, sleutels, en waardes)
Inisialiseer die gewig matrikse:
import torch.nn as nn
d_in = 3
d_out = 2
W_query = nn.Parameter(torch.rand(d_in, d_out))
W_key = nn.Parameter(torch.rand(d_in, d_out))
W_value = nn.Parameter(torch.rand(d_in, d_out))
Bereken vrae, sleutels en waardes:
queries = torch.matmul(inputs, W_query)
keys = torch.matmul(inputs, W_key)
values = torch.matmul(inputs, W_value)
Stap 2: Bereken Geskaalde Dot-Produk Aandag
Bereken Aandag Punte
Soos in die voorbeeld van tevore, maar hierdie keer, in plaas daarvan om die waardes van die dimensies van die tokens te gebruik, gebruik ons die sleutel matriks van die token (wat reeds bereken is met behulp van die dimensies):. So, vir elke navraag qi
en sleutel kj
:
.png)
Skaal die Punte
Om te voorkom dat die dot produkte te groot word, skaal hulle met die vierkantswortel van die sleutel dimensie dk
:
.png)
tip
Die punt word gedeel deur die vierkantswortel van die dimensies omdat dot produkte baie groot kan word en dit help om hulle te reguleer.
Pas Softmax toe om Aandag Gewigte te Verkry: Soos in die aanvanklike voorbeeld, normaliseer al die waardes sodat hulle 1 som.
.png)
Stap 3: Bereken Konteks Vektore
Soos in die aanvanklike voorbeeld, som net al die waardes matriks op deur elkeen met sy aandag gewig te vermenigvuldig:
.png)
Kode Voorbeeld
Grijp 'n voorbeeld van https://github.com/rasbt/LLMs-from-scratch/blob/main/ch03/01_main-chapter-code/ch03.ipynb jy kan hierdie klas kyk wat die self-aandag funksionaliteit implementeer waaroor ons gepraat het:
import torch
inputs = torch.tensor(
[[0.43, 0.15, 0.89], # Your (x^1)
[0.55, 0.87, 0.66], # journey (x^2)
[0.57, 0.85, 0.64], # starts (x^3)
[0.22, 0.58, 0.33], # with (x^4)
[0.77, 0.25, 0.10], # one (x^5)
[0.05, 0.80, 0.55]] # step (x^6)
)
import torch.nn as nn
class SelfAttention_v2(nn.Module):
def __init__(self, d_in, d_out, qkv_bias=False):
super().__init__()
self.W_query = nn.Linear(d_in, d_out, bias=qkv_bias)
self.W_key = nn.Linear(d_in, d_out, bias=qkv_bias)
self.W_value = nn.Linear(d_in, d_out, bias=qkv_bias)
def forward(self, x):
keys = self.W_key(x)
queries = self.W_query(x)
values = self.W_value(x)
attn_scores = queries @ keys.T
attn_weights = torch.softmax(attn_scores / keys.shape[-1]**0.5, dim=-1)
context_vec = attn_weights @ values
return context_vec
d_in=3
d_out=2
torch.manual_seed(789)
sa_v2 = SelfAttention_v2(d_in, d_out)
print(sa_v2(inputs))
tip
Let daarop dat in plaas van om die matriks met ewekansige waardes te initialiseer, nn.Linear
gebruik word om al die gewigte as parameters te merk om te train.
Oorsaaklike Aandag: Toekomstige Woorde Versteek
Vir LLM's wil ons hê dat die model slegs die tokens wat voor die huidige posisie verskyn, moet oorweeg om die volgende token te voorspel. Oorsaaklike aandag, ook bekend as gemaskerde aandag, bereik dit deur die aandagmeganisme te wysig om toegang tot toekomstige tokens te verhoed.
Toepassing van 'n Oorsaaklike Aandagmasker
Om oorsaaklike aandag te implementeer, pas ons 'n masker toe op die aandagspunte voor die softmax-operasie sodat die oorblywende eenhede steeds 1 sal optel. Hierdie masker stel die aandagspunte van toekomstige tokens op negatiewe oneindigheid, wat verseker dat na die softmax, hul aandaggewigte nul is.
Stappe
- Bereken Aandagspunte: Dieselfde as voorheen.
- Pas Masker Toe: Gebruik 'n boonste driehoekige matriks wat met negatiewe oneindigheid bo die diagonaal gevul is.
mask = torch.triu(torch.ones(seq_len, seq_len), diagonal=1) * float('-inf')
masked_scores = attention_scores + mask
- Pas Softmax Toe: Bereken aandaggewigte met behulp van die gemaskerde punte.
attention_weights = torch.softmax(masked_scores, dim=-1)
Maskering van Addisionele Aandaggewigte met Dropout
Om oorpassing te voorkom, kan ons dropout toepas op die aandaggewigte na die softmax-operasie. Dropout maak sommige van die aandaggewigte ewekansig nul tydens opleiding.
dropout = nn.Dropout(p=0.5)
attention_weights = dropout(attention_weights)
'n Gereelde dropout is ongeveer 10-20%.
Code Voorbeeld
Code voorbeeld van https://github.com/rasbt/LLMs-from-scratch/blob/main/ch03/01_main-chapter-code/ch03.ipynb:
import torch
import torch.nn as nn
inputs = torch.tensor(
[[0.43, 0.15, 0.89], # Your (x^1)
[0.55, 0.87, 0.66], # journey (x^2)
[0.57, 0.85, 0.64], # starts (x^3)
[0.22, 0.58, 0.33], # with (x^4)
[0.77, 0.25, 0.10], # one (x^5)
[0.05, 0.80, 0.55]] # step (x^6)
)
batch = torch.stack((inputs, inputs), dim=0)
print(batch.shape)
class CausalAttention(nn.Module):
def __init__(self, d_in, d_out, context_length,
dropout, qkv_bias=False):
super().__init__()
self.d_out = d_out
self.W_query = nn.Linear(d_in, d_out, bias=qkv_bias)
self.W_key = nn.Linear(d_in, d_out, bias=qkv_bias)
self.W_value = nn.Linear(d_in, d_out, bias=qkv_bias)
self.dropout = nn.Dropout(dropout)
self.register_buffer('mask', torch.triu(torch.ones(context_length, context_length), diagonal=1)) # New
def forward(self, x):
b, num_tokens, d_in = x.shape
# b is the num of batches
# num_tokens is the number of tokens per batch
# d_in is the dimensions er token
keys = self.W_key(x) # This generates the keys of the tokens
queries = self.W_query(x)
values = self.W_value(x)
attn_scores = queries @ keys.transpose(1, 2) # Moves the third dimension to the second one and the second one to the third one to be able to multiply
attn_scores.masked_fill_( # New, _ ops are in-place
self.mask.bool()[:num_tokens, :num_tokens], -torch.inf) # `:num_tokens` to account for cases where the number of tokens in the batch is smaller than the supported context_size
attn_weights = torch.softmax(
attn_scores / keys.shape[-1]**0.5, dim=-1
)
attn_weights = self.dropout(attn_weights)
context_vec = attn_weights @ values
return context_vec
torch.manual_seed(123)
context_length = batch.shape[1]
d_in = 3
d_out = 2
ca = CausalAttention(d_in, d_out, context_length, 0.0)
context_vecs = ca(batch)
print(context_vecs)
print("context_vecs.shape:", context_vecs.shape)
Om Enkelkop Aandag uit te brei na Meerkop Aandag
Meerkop aandag bestaan in praktiese terme uit die uitvoering van meerdere instansies van die self-aandag funksie, elk met hulle eie gewigte, sodat verskillende finale vektore bereken kan word.
Kode Voorbeeld
Dit kan moontlik wees om die vorige kode te hergebruik en net 'n omhulsel toe te voeg wat dit verskeie kere ontplooi, maar dit is 'n meer geoptimaliseerde weergawe van https://github.com/rasbt/LLMs-from-scratch/blob/main/ch03/01_main-chapter-code/ch03.ipynb wat al die koppe terselfdertyd verwerk (wat die aantal duur vir-lusse verminder). Soos jy in die kode kan sien, word die dimensies van elke token in verskillende dimensies verdeel volgens die aantal koppe. Op hierdie manier, as 'n token 8 dimensies het en ons 3 koppe wil gebruik, sal die dimensies in 2 arrays van 4 dimensies verdeel word en elke kop sal een daarvan gebruik:
class MultiHeadAttention(nn.Module):
def __init__(self, d_in, d_out, context_length, dropout, num_heads, qkv_bias=False):
super().__init__()
assert (d_out % num_heads == 0), \
"d_out must be divisible by num_heads"
self.d_out = d_out
self.num_heads = num_heads
self.head_dim = d_out // num_heads # Reduce the projection dim to match desired output dim
self.W_query = nn.Linear(d_in, d_out, bias=qkv_bias)
self.W_key = nn.Linear(d_in, d_out, bias=qkv_bias)
self.W_value = nn.Linear(d_in, d_out, bias=qkv_bias)
self.out_proj = nn.Linear(d_out, d_out) # Linear layer to combine head outputs
self.dropout = nn.Dropout(dropout)
self.register_buffer(
"mask",
torch.triu(torch.ones(context_length, context_length),
diagonal=1)
)
def forward(self, x):
b, num_tokens, d_in = x.shape
# b is the num of batches
# num_tokens is the number of tokens per batch
# d_in is the dimensions er token
keys = self.W_key(x) # Shape: (b, num_tokens, d_out)
queries = self.W_query(x)
values = self.W_value(x)
# We implicitly split the matrix by adding a `num_heads` dimension
# Unroll last dim: (b, num_tokens, d_out) -> (b, num_tokens, num_heads, head_dim)
keys = keys.view(b, num_tokens, self.num_heads, self.head_dim)
values = values.view(b, num_tokens, self.num_heads, self.head_dim)
queries = queries.view(b, num_tokens, self.num_heads, self.head_dim)
# Transpose: (b, num_tokens, num_heads, head_dim) -> (b, num_heads, num_tokens, head_dim)
keys = keys.transpose(1, 2)
queries = queries.transpose(1, 2)
values = values.transpose(1, 2)
# Compute scaled dot-product attention (aka self-attention) with a causal mask
attn_scores = queries @ keys.transpose(2, 3) # Dot product for each head
# Original mask truncated to the number of tokens and converted to boolean
mask_bool = self.mask.bool()[:num_tokens, :num_tokens]
# Use the mask to fill attention scores
attn_scores.masked_fill_(mask_bool, -torch.inf)
attn_weights = torch.softmax(attn_scores / keys.shape[-1]**0.5, dim=-1)
attn_weights = self.dropout(attn_weights)
# Shape: (b, num_tokens, num_heads, head_dim)
context_vec = (attn_weights @ values).transpose(1, 2)
# Combine heads, where self.d_out = self.num_heads * self.head_dim
context_vec = context_vec.contiguous().view(b, num_tokens, self.d_out)
context_vec = self.out_proj(context_vec) # optional projection
return context_vec
torch.manual_seed(123)
batch_size, context_length, d_in = batch.shape
d_out = 2
mha = MultiHeadAttention(d_in, d_out, context_length, 0.0, num_heads=2)
context_vecs = mha(batch)
print(context_vecs)
print("context_vecs.shape:", context_vecs.shape)
Vir 'n ander kompakte en doeltreffende implementering kan jy die torch.nn.MultiheadAttention
klas in PyTorch gebruik.
tip
Kort antwoord van ChatGPT oor hoekom dit beter is om dimensies van tokens onder die koppe te verdeel in plaas daarvan om elke kop al die dimensies van al die tokens te laat nagaan:
Terwyl dit mag lyk asof dit voordelig is om elke kop al die inbedingsdimensies te laat verwerk omdat elke kop toegang tot die volle inligting sou hê, is die standaard praktyk om die inbedingsdimensies onder die koppe te verdeel. Hierdie benadering balanseer rekenkundige doeltreffendheid met modelprestasie en moedig elke kop aan om diverse voorstellings te leer. Daarom is dit oor die algemeen verkieslik om die inbedingsdimensies te verdeel eerder as om elke kop al die dimensies te laat nagaan.
References
tip
Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.