4. Attention Mechanisms
Mechanizmy Uwagowe i Samo-Uwaga w Sieciach Neuronowych
Mechanizmy uwagowe pozwalają sieciom neuronowym skupić się na konkretnych częściach wejścia podczas generowania każdej części wyjścia. Przypisują różne wagi różnym wejściom, pomagając modelowi zdecydować, które wejścia są najbardziej istotne dla danego zadania. Jest to kluczowe w zadaniach takich jak tłumaczenie maszynowe, gdzie zrozumienie kontekstu całego zdania jest niezbędne do dokładnego tłumaczenia.
Celem tej czwartej fazy jest bardzo prosty: Zastosować kilka mechanizmów uwagowych. Będą to powtarzające się warstwy, które uchwycą relację słowa w słowniku z jego sąsiadami w aktualnym zdaniu używanym do trenowania LLM. Do tego celu używa się wielu warstw, więc wiele parametrów do uczenia będzie uchwytywać te informacje.
Zrozumienie Mechanizmów Uwagowych
W tradycyjnych modelach sekwencja-do-sekwencji używanych do tłumaczenia języków, model koduje sekwencję wejściową w wektor kontekstowy o stałym rozmiarze. Jednak podejście to ma trudności z długimi zdaniami, ponieważ wektor kontekstowy o stałym rozmiarze może nie uchwycić wszystkich niezbędnych informacji. Mechanizmy uwagowe rozwiązują to ograniczenie, pozwalając modelowi rozważać wszystkie tokeny wejściowe podczas generowania każdego tokenu wyjściowego.
Przykład: Tłumaczenie Maszynowe
Rozważmy tłumaczenie niemieckiego zdania "Kannst du mir helfen diesen Satz zu übersetzen" na angielski. Tłumaczenie słowo po słowie nie dałoby gramatycznie poprawnego zdania w języku angielskim z powodu różnic w strukturach gramatycznych między językami. Mechanizm uwagi umożliwia modelowi skupienie się na istotnych częściach zdania wejściowego podczas generowania każdego słowa zdania wyjściowego, co prowadzi do dokładniejszego i spójnego tłumaczenia.
Wprowadzenie do Samo-Uwagi
Samo-uwaga, lub intra-uwaga, to mechanizm, w którym uwaga jest stosowana w obrębie jednej sekwencji w celu obliczenia reprezentacji tej sekwencji. Pozwala to każdemu tokenowi w sekwencji zwracać uwagę na wszystkie inne tokeny, pomagając modelowi uchwycić zależności między tokenami, niezależnie od ich odległości w sekwencji.
Kluczowe Pojęcia
Tokeny: Indywidualne elementy sekwencji wejściowej (np. słowa w zdaniu).
Osadzenia: Wektorowe reprezentacje tokenów, uchwycające informacje semantyczne.
Wagi Uwagowe: Wartości, które określają znaczenie każdego tokenu w stosunku do innych.
Obliczanie Wag Uwagowych: Przykład Krok po Kroku
Rozważmy zdanie "Hello shiny sun!" i przedstawmy każde słowo za pomocą 3-wymiarowego osadzenia:
Hello:
[0.34, 0.22, 0.54]
shiny:
[0.53, 0.34, 0.98]
sun:
[0.29, 0.54, 0.93]
Naszym celem jest obliczenie wektora kontekstowego dla słowa "shiny" przy użyciu samo-uwagi.
Krok 1: Obliczanie Wyników Uwagowych
Po prostu pomnóż każdą wartość wymiaru zapytania przez odpowiednią wartość każdego tokenu i dodaj wyniki. Otrzymasz 1 wartość dla każdej pary tokenów.
Dla każdego słowa w zdaniu oblicz wynik uwagi w odniesieniu do "shiny", obliczając iloczyn skalarny ich osadzeń.
Wynik Uwagowy między "Hello" a "shiny"
Wynik Uwagowy między "shiny" a "shiny"
Wynik Uwagowy między "sun" a "shiny"
Krok 2: Normalizacja Wyników Uwagowych w Celu Uzyskania Wag Uwagowych
Nie gub się w terminach matematycznych, cel tej funkcji jest prosty, znormalizować wszystkie wagi, aby suma wyniosła 1.
Ponadto, funkcja softmax jest używana, ponieważ akcentuje różnice dzięki części wykładniczej, co ułatwia wykrywanie użytecznych wartości.
Zastosuj funkcję softmax do wyników uwagi, aby przekształcić je w wagi uwagowe, które sumują się do 1.
Obliczanie wykładników:
Obliczanie sumy:
Obliczanie wag uwagowych:
Krok 3: Obliczanie Wektora Kontekstowego
Po prostu weź każdą wagę uwagową i pomnóż ją przez odpowiednie wymiary tokenów, a następnie zsumuj wszystkie wymiary, aby uzyskać tylko 1 wektor (wektor kontekstowy)
Wektor kontekstowy jest obliczany jako ważona suma osadzeń wszystkich słów, przy użyciu wag uwagowych.
Obliczanie każdego składnika:
Ważone Osadzenie "Hello":
* **Ważone Osadzenie "shiny"**:
* **Ważone Osadzenie "sun"**:
Sumując ważone osadzenia:
wektor kontekstowy=[0.0779+0.2156+0.1057, 0.0504+0.1382+0.1972, 0.1237+0.3983+0.3390]=[0.3992,0.3858,0.8610]
Ten wektor kontekstowy reprezentuje wzbogaconą osadzenie dla słowa "shiny", uwzględniając informacje ze wszystkich słów w zdaniu.
Podsumowanie Procesu
Oblicz Wyniki Uwagowe: Użyj iloczynu skalarnego między osadzeniem docelowego słowa a osadzeniami wszystkich słów w sekwencji.
Normalizuj Wyniki, aby Uzyskać Wagi Uwagowe: Zastosuj funkcję softmax do wyników uwagi, aby uzyskać wagi, które sumują się do 1.
Oblicz Wektor Kontekstowy: Pomnóż osadzenie każdego słowa przez jego wagę uwagową i zsumuj wyniki.
Samo-Uwaga z Uczonymi Wagami
W praktyce mechanizmy samo-uwagi używają uczących się wag, aby nauczyć się najlepszych reprezentacji dla zapytań, kluczy i wartości. Obejmuje to wprowadzenie trzech macierzy wag:
Zapytanie to dane do użycia jak wcześniej, podczas gdy macierze kluczy i wartości to po prostu losowe macierze do uczenia.
Krok 1: Obliczanie Zapytania, Kluczy i Wartości
Każdy token będzie miał swoją własną macierz zapytania, klucza i wartości, mnożąc swoje wartości wymiarowe przez zdefiniowane macierze:
Te macierze przekształcają oryginalne osadzenia w nową przestrzeń odpowiednią do obliczania uwagi.
Przykład
Zakładając:
Wymiar wejściowy
din=3
(rozmiar osadzenia)Wymiar wyjściowy
dout=2
(pożądany wymiar dla zapytań, kluczy i wartości)
Zainicjuj macierze wag:
Oblicz zapytania, klucze i wartości:
Krok 2: Obliczanie uwagi z wykorzystaniem skalowanego iloczynu skalarnego
Obliczanie wyników uwagi
Podobnie jak w poprzednim przykładzie, ale tym razem, zamiast używać wartości wymiarów tokenów, używamy macierzy kluczy tokena (już obliczonej przy użyciu wymiarów):. Tak więc, dla każdego zapytania qi
i klucza kj
:
Skalowanie wyników
Aby zapobiec zbyt dużym iloczynom skalarnym, skaluj je przez pierwiastek kwadratowy z wymiaru klucza dk
:
Wynik jest dzielony przez pierwiastek kwadratowy z wymiarów, ponieważ iloczyny skalarne mogą stać się bardzo duże, a to pomaga je regulować.
Zastosuj Softmax, aby uzyskać wagi uwagi: Jak w początkowym przykładzie, znormalizuj wszystkie wartości, aby ich suma wynosiła 1.
Krok 3: Obliczanie wektorów kontekstu
Jak w początkowym przykładzie, po prostu zsumuj wszystkie macierze wartości, mnożąc każdą z nich przez jej wagę uwagi:
Przykład kodu
Zabierając przykład z https://github.com/rasbt/LLMs-from-scratch/blob/main/ch03/01_main-chapter-code/ch03.ipynb, możesz sprawdzić tę klasę, która implementuje funkcjonalność samodzielnej uwagi, o której rozmawialiśmy:
Zauważ, że zamiast inicjować macierze losowymi wartościami, używa się nn.Linear
, aby oznaczyć wszystkie wagi jako parametry do trenowania.
Causal Attention: Ukrywanie Przyszłych Słów
Dla LLM-ów chcemy, aby model brał pod uwagę tylko tokeny, które pojawiają się przed bieżącą pozycją, aby przewidzieć następny token. Causal attention, znane również jako masked attention, osiąga to poprzez modyfikację mechanizmu uwagi, aby zapobiec dostępowi do przyszłych tokenów.
Stosowanie Maski Causal Attention
Aby zaimplementować causal attention, stosujemy maskę do wyników uwagi przed operacją softmax, aby pozostałe sumowały się do 1. Ta maska ustawia wyniki uwagi przyszłych tokenów na minus nieskończoność, zapewniając, że po softmax ich wagi uwagi wynoszą zero.
Kroki
Oblicz Wyniki Uwagi: Tak jak wcześniej.
Zastosuj Maskę: Użyj macierzy górnej trójkątnej wypełnionej minus nieskończonością powyżej przekątnej.
Zastosuj Softmax: Oblicz wagi uwagi, używając zamaskowanych wyników.
Maskowanie Dodatkowych Wag Uwagi za Pomocą Dropoutu
Aby zapobiec przeuczeniu, możemy zastosować dropout do wag uwagi po operacji softmax. Dropout losowo zeruje niektóre z wag uwagi podczas treningu.
Zwykła utrata danych wynosi około 10-20%.
Code Example
Code example from https://github.com/rasbt/LLMs-from-scratch/blob/main/ch03/01_main-chapter-code/ch03.ipynb:
Rozszerzenie uwagi z pojedynczej głowy na uwagę z wieloma głowami
Uwaga z wieloma głowami w praktyce polega na wykonywaniu wielu instancji funkcji uwagi własnej, z których każda ma swoje własne wagi, dzięki czemu obliczane są różne wektory końcowe.
Przykład kodu
Możliwe byłoby ponowne wykorzystanie poprzedniego kodu i po prostu dodanie opakowania, które uruchamia go kilka razy, ale to jest bardziej zoptymalizowana wersja z https://github.com/rasbt/LLMs-from-scratch/blob/main/ch03/01_main-chapter-code/ch03.ipynb, która przetwarza wszystkie głowy jednocześnie (zmniejszając liczbę kosztownych pętli for). Jak widać w kodzie, wymiary każdego tokena są dzielone na różne wymiary w zależności od liczby głów. W ten sposób, jeśli token ma 8 wymiarów, a chcemy użyć 3 głów, wymiary będą podzielone na 2 tablice po 4 wymiary, a każda głowa użyje jednej z nich:
Dla innej kompaktowej i wydajnej implementacji możesz użyć klasy torch.nn.MultiheadAttention
w PyTorch.
Krótka odpowiedź ChatGPT na pytanie, dlaczego lepiej jest podzielić wymiary tokenów między głowami, zamiast pozwalać każdej głowie sprawdzać wszystkie wymiary wszystkich tokenów:
Chociaż pozwolenie każdej głowie na przetwarzanie wszystkich wymiarów osadzenia może wydawać się korzystne, ponieważ każda głowa miałaby dostęp do pełnych informacji, standardową praktyką jest podział wymiarów osadzenia między głowami. Takie podejście równoważy wydajność obliczeniową z wydajnością modelu i zachęca każdą głowę do uczenia się różnorodnych reprezentacji. Dlatego podział wymiarów osadzenia jest ogólnie preferowany w porównaniu do pozwolenia każdej głowie na sprawdzanie wszystkich wymiarów.
References
Last updated