English· Español· Deutsch· Nederlands· Français· 日本語· ქართული· 繁體中文· 简体中文· Português· Русский· العربية· हिन्दी· Italiano· 한국어· Polski· Svenska· Türkçe· Українська· Tiếng Việt· Bahasa Indonesia

un

gość
1 / ?
powrót do lekcji

Zapytanie, Klucz, Wartość

Trzy mapowania liniowe z tego samego wejścia

Po osadzeniu (aktywność 4) każda pozycja niesie wektor 768-wymiarowy x_t. Uwaga rozpoczyna się od wygenerowania trzech różnych projekcji x:


Q (zapytanie): czego ta pozycja chce się dowiedzieć?


K (klucz): co ta pozycja oferuje innym pozycjom?


V (wartość): jaką treść ta pozycja dostarcza, jeśli zostanie uwzględniona?


Każda projekcja pochodzi z wyuczonej macierzy wag:


Q = x · W_Q     # kształt W_Q: (d_model, d_k)
K = x · W_K     # kształt W_K: (d_model, d_k)
V = x · W_V     # kształt W_V: (d_model, d_k)

Trzy macierze, wszystkie trenowane za pomocą propagacji wstecznej. Model uczy się: na tej pozycji, które zapytanie najlepiej pobiera przydatny kontekst z przeszłości? Który klucz dobrze reklamuje zawartość tej pozycji? Jaka wartość jest dostarczana, jeśli pozycja zostanie wybrana?


Scaled dot-product attention


Analogia biblioteczna

Wyobraź sobie katalog kartkowy w bibliotece. Wchodzisz z tematem w głowie (twoje zapytanie). Każda karta zawiera słowa kluczowe (klucz). Gdy twój temat pasuje do słów kluczowych na karcie, pobierasz treść książki (wartość). Mechanizm uwagi wykonuje to dla każdego tokena równolegle: każda pozycja wysyła zapytanie do każdej innej pozycji, rankuje dopasowanie i pobiera ważoną kombinację wektorów wartości.


Wymiary ANDREA-120M


WielkośćWartośćUwagi
d_model768Rozmiar wektora w każdej pozycji
n_head12Równoległe głowice uwagi
d_k64Wymiar na głowicę (= d_model / n_head)
T1024Długość kontekstu

d_k = d_model / n_head = 768 / 12 = 64. Każda głowica widzi 64-wymiarowy wycinek pełnej przestrzeni 768-wymiarowej. Aktywność 6 (grow_a_language_model_multi_head) szczegółowo omawia podział na głowice.

Oblicz d_k

Oblicz d_k dla dwóch wariantów ANDREA. (a) ANDREA-12M: d_model = 384, n_head = 12. (b) ANDREA-480M: d_model = 1536, n_head = 24. Pokaż wzór d_k = d_model / n_head dla każdego przypadku.

Dlaczego dzielimy przez sqrt(d_k)

Macierz ocen

Gdy Q i K istnieją (każde o kształcie (T, d_k)), uwaga oblicza macierz ocen:


scores = Q · K^T     # kształt: (T, T)

scores[i, j] = jak silnie zapytanie (query) z pozycji i jest zgodne z kluczem (key) z pozycji j. Każda para (i, j) otrzymuje jeden wynik: 1024 × 1024 = 1 048 576 wyników na głowę uwagi (attention head) w jednym przebiegu do przodu (forward pass).


Dlaczego dzielimy

Iloczyny skalarne dwóch losowych wektorów jednostkowych w przestrzeni d-wymiarowej mają wielkość rzędu sqrt(d). Bez skalowania wyniki rosną wraz z d_k:


- d_k = 64: typowe iloczyny skalaryczne rzędu 8.

- d_k = 256: typowe iloczyny skalaryczne rzędu 16.

- d_k = 4096: typowe iloczyny skalaryczne rzędu 64.


Wysokie wartości punktacji prowadzą do ostrego rozkładu softmax (jedna pozycja dominuje, a gradienty zanikają w pozostałych miejscach). Trening staje w miejscu. Skalowanie koryguje rzęd wielkości:


scaled_scores = (Q · K^T) / sqrt(d_k)

Dla ANDREA-120M, sqrt(d_k) = sqrt(64) = 8. Każdy wynik jest dzielony przez 8. Wartości pozostają w przybliżeniu w skali jednostkowej, niezależnie od d_k. Funkcja softmax zachowuje się stabilnie. Gradienty przepływają.


Oryginalne uzasadnienie Vaswaniego

Z artykułu Attention Is All You Need (2017): „Dla dużych wartości d_k iloczyny skalarnie rosną w wartości bezwzględnej, co popycha funkcję softmax do obszarów, w których ma ona ekstremalnie małe gradienty.” Dzielnik sqrt(d_k) przeciwdziała temu wzrostowi.


Widok kodu

W pliku microgpt_cuda.cu to skalowanie pojawia się jako dosłowne dzielenie:


scores[i][j] = dot(Q[i], K[j]) * (1.0f / sqrtf(d_k));

Jedno mnożenie liczb zmiennoprzecinkowych na wynik. Tanie. Krytyczne.

Skalowanie przy d_model = 4096

Załóżmy, że zespół badawczy buduje ANDREA-2B z d_model = 4096 i n_head = 32. (a) Oblicz d_k. (b) Oblicz sqrt(d_k). (c) Wyjaśnij w jednym zdaniu, co by się stało, gdyby zespół zapomniał podzielić przez sqrt(d_k) przy tej skali.

Dlaczego pozycja i nie może widzieć pozycji j > i

Ograniczenie wynikające z generowania

ANDREA generuje jeden token naraz. Podczas inferencji pozycja 0 produkuje pierwszy token, następnie pozycja 1 widzi wynik pozycji 0 i produkuje drugi token, i tak dalej. Model nigdy nie ma dostępu do przyszłych tokenów podczas generowania.


Trening musi to odzwierciedlać. Gdyby podczas treningu pozycja 5 mogła zwracać uwagę na pozycję 6, model nauczyłby się skrótu: „przewidz token 6, czytając token 6”. Podczas inferencji ten skrót znika (token 6 jeszcze nie istnieje). Zachowanie modelu podczas treningu i inferencji rozjechałoby się katastrofalnie.


Maska

Maska przyczynowa blokuje uwagę z dowolnej pozycji i do dowolnej pozycji j > i. Implementacja: ustaw scaled_scores[i][j] = -∞ wszędzie tam, gdzie j > i. Po softmax te wpisy stają się exp(-∞) = 0. Maska czysto zeruje uwagę do przyszłych pozycji.


for i in range(T):
for j in range(T):
if j > i:
scaled_scores[i][j] = -1e9   # effectively -inf

Po zastosowaniu softmax (wzdłuż wierszy), suma każdego wiersza wynosi 1, ale masę prawdopodobieństwa niosą wyłącznie elementy [0, i]. Pozycja i miesza informacje wyłącznie z pozycji poprzedzających.


Wizualizacja maski

Macierz ocen o kształcie (T, T) z zastosowaną maską wygląda jak struktura dolnego trójkąta:


scaled_scores po zastosowaniu maski, softmax wzdłuż wierszy:

wiersz 0:  [1.0, 0,   0,   0,   ...]   # widzi tylko siebie
wiersz 1:  [0.4, 0.6, 0,   0,   ...]   # widzi pozycje 0, 1
wiersz 2:  [0.2, 0.3, 0.5, 0,   ...]   # widzi 0, 1, 2
wiersz 3:  [0.1, 0.2, 0.3, 0.4, ...]   # widzi 0, 1, 2, 3
...

Ścisłe rozkład prawdopodobieństwa dolnego trójkąta w każdym wierszu. Przyszłość pozostaje niewidoczna.


Dlaczego Transformer tylko z dekodownikiem potrzebuje tego

Modele wyłącznie dekodera, takie jak ANDREA, GPT i LLaMA, mają wspólny cel: przewidywanie następnego tokena na podstawie przeszłości. Maska przyczynowa (causal mask) sprawia, że ten cel można trenować równolegle: każda pozycja oblicza swoje własne przewidywanie następnego tokena jednocześnie, a żadna pozycja nie „oszukuje”, podglądając przyszłość.

Maska i warianty

W Aktywności 2 (wstęp) omówiono trzy warianty transformera: wyłącznie enkoder, enkoder-dekoder oraz wyłącznie dekoder. (a) Który wariant używa maski przyczynowej? (b) W jednym zdaniu wyjaśnij, dlaczego inny wariant (wyłącznie enkoder, np. BERT) NIE używałby maski przyczynowej. (c) Na jakim celu trenowany jest enkoder bez maski?

Od wyników do wyjścia

Softmax: Punkty do prawdopodobieństw

Zamaskowane i znormalizowane punkty nadal przyjmują wartości z zakresu liczb rzeczywistych. Funkcja Softmax przekształca każdy wiersz w rozkład prawdopodobieństwa:


A[i][j] = exp(scaled_scores[i][j]) / sum_k exp(scaled_scores[i][k])

Wynikają z tego trzy właściwości:


- A[i][j] >= 0 dla wszystkich (i, j).

- sum_j A[i][j] = 1 dla każdego wiersza i.

- Wyższe surowe wyniki generują wyższe prawdopodobieństwa (monotoniczność).


Wektor prawdopodobieństwa w wierszu i mówi modelowi: na ile pozycja i powinna zwracać uwagę na każdą z poprzednich pozycji przy obliczaniu swojego wyjścia?


Zważona suma V

Ostateczny wynik uwagi dla pozycji i:


output[i] = sum_j A[i][j] · V[j]

Każdy wektor wartości V[j] jest ważony przez prawdopodobieństwo uwagi A[i][j], a następnie sumowany. Wynik dla pozycji i łączy wektory wartości ze wszystkich poprzednich pozycji, ważone według stopnia istotności.


W postaci macierzowej, wszystkie pozycje naraz:


Attention(Q, K, V) = softmax(mask(Q · K^T / sqrt(d_k))) · V

Jedna linia. Cały mechanizm uwagi. Vaswani i in. napisali ten wiersz w 2017 roku; transfomy nie zmieniły się fundamentalnie od tamtej pory.


Kształt wyjścia na głowę

Wyjście jednej głowy uwagi: kształt (T, d_k). W przypadku ANDREA-120M: (1024, 64). Wszystkie 12 głów oblicza równolegle; ich wyjścia są łączone w (1024, 768) i trafiają do końcowej projekcji liniowej (W_O), a następnie do MLP bloku transformera.


Aktywność 6 (grow_a_language_model_multi_head) obejmuje podział na wiele głów. Aktywność 7 (grow_a_language_model_transformer_block) obejmuje wszystko, co otacza uwagę: połączenia rezydualne, normalizację warstwy oraz MLP.

Zsyntetyzuj linię przetwarzania

Zsyntetyzuj cały proces uwagi własnymi słowami. Opisz, co dzieje się z pojedynczą pozycją i (np. pozycja 5 w sekwencji), od wektora wejściowego x_5 do wyjścia uwagi[5]. Wymień cztery operacje w kolejności: (1) projekcja do Q/K/V, (2) obliczenie przeskalowanych punktów względem wszystkich pozycji, (3) zastosowanie maski przyczynowej + softmax, (4) suma wektorów V ważona przez prawdopodobieństwa. Jeden krótki akapit.