Transformer
This commit is contained in:
parent
c8b9a7823e
commit
33a7a1f83e
@ -61,4 +61,221 @@ $(j-1) \times d_v$), powyższy wzór będziemy mogli zapisać jako iloczyn wekto
|
||||
$$A(w_1,\dots,j-1) = \vec{\alpha}_{*,j}^T V = \operatorname{softmax}(\vec{q_j}^T K)^T V.$$
|
||||
|
||||
Sposób patrzenia na atencję przez pryzmat trójki
|
||||
zapytania-klucze-wartości okaże się niezwykle ważny w wypadku modelu Transformer (zob. kolejny wykład).
|
||||
zapytania-klucze-wartości okaże się niezwykle ważny w wypadku modelu Transformer.
|
||||
|
||||
** Model Transformer — historia
|
||||
|
||||
Architekturę Transformer opracowano, pierwotnie, na potrzeby
|
||||
tłumaczenia automatycznego (rok 2017, artykuł [Attention Is All You
|
||||
Need](https://arxiv.org/abs/1706.03762)). Szybko okazało się, że
|
||||
podobnie jak w wypadku modelu ELMo dla sieci LSTM, można *pretrenować*
|
||||
duże modele Transformer (po prostu na dużych korpusach tekstowych, w
|
||||
sposób nienadzorowany), a potem dostrajać pod konkretne zadanie
|
||||
przetwarzania języka naturalnego. Jednym z pierwszych przykładów
|
||||
takiego podejścia był model BERT (rok 2018, artykuł [BERT:
|
||||
Pre-training of Deep Bidirectional Transformers for Language
|
||||
Understanding](https://arxiv.org/abs/1810.04805)). To podejście było
|
||||
później rozwinięte w postaci różnych modeli Transformer, również dla innych
|
||||
języków niż angielski (RoBERTa, XLM, Polish RoBERTa itd.).
|
||||
|
||||
Na tym wykładzie my skupimy się na innej odnodze modeli Transformer —
|
||||
modelach generatywnych, takich jak na przykład GPT-2 czy GPT-3. To
|
||||
podejście jest bliższe duchowi czystego modelowania języka — model
|
||||
języka jest używany wprost jako generator.
|
||||
|
||||
** GPT-2 — przykład działania
|
||||
|
||||
Dokonajmy najpierw tokenizacji:
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
from transformers import AutoTokenizer
|
||||
tokenizer = AutoTokenizer.from_pretrained("gpt2")
|
||||
text = "The World War III will begin in"
|
||||
encoded_input = tokenizer(text, return_tensors='pt')
|
||||
encoded_input
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
{'input_ids': tensor([[ 464, 2159, 1810, 6711, 481, 2221, 287]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1]])}
|
||||
:end:
|
||||
|
||||
Możemy podejrzeć uzyskane tokeny:
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
[tokenizer.decode(i) for i in encoded_input.input_ids[0]]
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
['The', ' World', ' War', ' III', ' will', ' begin', ' in']
|
||||
:end:
|
||||
|
||||
Zwróćmy uwagę, że w GPT-2 tokeny obejmują spacje!
|
||||
|
||||
Teraz uruchommy zasadniczy model:
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
from transformers import AutoModelForCausalLM
|
||||
model = AutoModelForCausalLM.from_pretrained("gpt2")
|
||||
outputs = model(**encoded_input)
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
:end:
|
||||
|
||||
Z modelu GPT-2 otrzymamy rozkład prawdopodobieństwa kolejnego wyrazu, najpierw w postaci
|
||||
nieznormalizowanych *logitów*:
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
logits = outputs[0][0][-1]
|
||||
logits
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
tensor([-130.2947, -129.5677, -136.4030, ..., -138.3791, -138.8967,
|
||||
-131.6319], grad_fn=<SelectBackward0>)
|
||||
:end:
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
from torch import softmax, topk
|
||||
|
||||
k = 20
|
||||
|
||||
t = topk(softmax(logits, -1), k)
|
||||
|
||||
tb = [[tokenizer.decode(t.indices[ix]), t.values[ix].item()] for ix in range(k)]
|
||||
tb
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
[[' earnest', 0.07378227263689041], [' the', 0.06698606163263321], [' 1945', 0.043497972190380096], [' September', 0.024068640545010567], [' March', 0.0228887926787138], [' October', 0.02232857048511505], [' Europe', 0.02032744698226452], [' 2020', 0.018564637750387192], [' Japan', 0.018423961475491524], [' December', 0.016560807824134827], [' January', 0.015074416995048523], [' July', 0.014139187522232533], [' April', 0.013183596543967724], [' November', 0.012901309877634048], [' 20', 0.012770282104611397], [' Afghanistan', 0.012765118852257729], [' 1944', 0.01266297698020935], [' June', 0.012072316370904446], [' 1914', 0.011765970848500729], [' May', 0.011659453622996807]]
|
||||
:end:
|
||||
|
||||
*** Generowanie tekstu za pomocą GPT-2
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
from transformers import pipeline
|
||||
generator = pipeline('text-generation', model='gpt2')
|
||||
generator('Hello, I\'m a language model,', max_length=30, num_return_sequences=1)
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
:end:
|
||||
|
||||
** Model Transformer — podstawowa idea
|
||||
|
||||
Model Transformer sprowadza się właściwie do atencji; nie posiada
|
||||
żadnego komponentu rekurencyjnego, ani nawet nie stosujemy czegoś w
|
||||
rodzaju połączenia modelu worka słów i modelu n-gramowego.
|
||||
|
||||
W pierwszym przybliżeniu przy obliczaniu rozkładu prawdopodobieństwa
|
||||
dla kolejnego wyrazu, to jest:
|
||||
|
||||
$$P(w_j|w_1\dots w_{j-1})$$
|
||||
|
||||
na $j$-tym miejscu (w miejscu przewidywanego wyrazu) doklejamy
|
||||
specjalny token, powiedzmy ~<mask>~. Token ten będzie „atendował” do
|
||||
innych wszystkich wcześniejszych tokenów w zdaniu:
|
||||
|
||||
$$\vec{\alpha}_{*,j}^T V = \operatorname{softmax}(\vec{q_j}^T K)^T V.$$
|
||||
|
||||
Samo to byłoby oczywiście zbyt proste:
|
||||
|
||||
1. Otrzymalibyśmy model (ważonego) worka słów, w dodatku każde słowo
|
||||
miałoby zawsze taką samą wagę! — Token $w_j$, który atenduje jest
|
||||
zawsze ten sam (~<mask>~). Musimy wzbogacić reprezentację wektorową
|
||||
słów i specjalnego tokenu (~<mask>~).
|
||||
|
||||
2. Model Transformer w swojej podstawowej postaci w ogóle nie jest
|
||||
wyposażony w pojęcie sekwencji — w przeciwieństwie do sieci
|
||||
rekurencyjnych, które w sposób inherentny operują krok po kroku, w
|
||||
sekwencji (w czasie). Musimy pozycję tokenów wprowadzić do sieci
|
||||
Transformer nie przez modyfikację jej architektury, lecz przez dołączenie
|
||||
informacji pozycyjnej do początkowych zanurzeń.
|
||||
|
||||
3. Model Transformer nie powinien mieć żadnych tokenów OOV/UNK. Musimy
|
||||
wrócić do kwestii tokenizacji tekstu i wprowadzić podział rzadszych
|
||||
tokenów na mniejsze, *podwyrazowe* jednostki.
|
||||
|
||||
** Atencja wsobna
|
||||
|
||||
Jeśli chodzi problem (1), rozwiążemy go przez wprowadzenie
|
||||
**skontekstualizowanych reprezentacji** tokenów.
|
||||
|
||||
Na przykład słowo /mysz/ ma jedno wejściowe (/statyczne/) zanurzenie
|
||||
(embedding) — bez względu na to, czy chodzi o zwierzę czy urządzenie
|
||||
peryferyjne, tymczasem dość łatwo ustalić na podstawie kontekstu, o
|
||||
które znaczenie chodzi.
|
||||
|
||||
Rozwiązanie polega na tym, że tokenom będziemy przypisywać kolejne
|
||||
zanurzenia skontekstualizowane — zależne od innych wyrazów w zdaniu. W
|
||||
tym celu zastosujemy atencję wsobną (samo-atencję, /self-attention/).
|
||||
Każdy token będzie atendował potencjalnie do każdego innego tokenu,
|
||||
również do samego siebie (!).
|
||||
|
||||
*** Wzory
|
||||
|
||||
Rozpatrywać zatem będziemy nie tylko pojedynczy wektor znormalizowanych atencji
|
||||
|
||||
$$\vec{\alpha}_{*,j}^T V = \operatorname{softmax}(\vec{q_j}^T K)^T V$$,
|
||||
|
||||
lecz całą serię wektorów:
|
||||
|
||||
$$\vec{\alpha}_{*,1},\dots,\vec{\alpha}_{*,i},\dots,\vec{\alpha}_{*,j}$$
|
||||
|
||||
gdzie:
|
||||
|
||||
$$\vec{\alpha}_{*,i} = \operatorname{softmax}(\vec{q_i}^T K)$$
|
||||
|
||||
i $K$ jest macierzą kluczy o rozmiarze $d_k \times j$ (tym razem obejmuje również sam $i$-ty token).
|
||||
|
||||
Nowa, skontekstualizowana reprezentacja $i$-tego tokenu będzie po prostu średnią wszystkich
|
||||
wektorów ważoną atencją:
|
||||
|
||||
$$E_1(w_i) = \operatorname{softmax}(\vec{q_i}^T K)^T V,$$
|
||||
|
||||
gdzie:
|
||||
|
||||
- $E_1(w_i)$ — skontekstualizowane zanurzenie $i$-tego tokenu; używając indeksu $_1$
|
||||
zaznaczamy, że to jest pierwszy skonstekstualizowany embedding, rekurencyjnie będziemy budowali
|
||||
kolejne $E_2(w_i)$, $E_3(w_i)$ itd. (zaś wejściowy statyczny embedding możemy oznaczyć przez $E_0(w_i)$);
|
||||
- $V$ to macierz wartości o rozmiarze $j \times d_v$.
|
||||
|
||||
**** Zwarta postać macierzowa atencji wsobnej
|
||||
|
||||
Z praktycznych powodów (szybkość obliczeń na kartach graficznych) dużą
|
||||
zaletą atencji wsobnej jest to, że wyliczenie skonstekstualizowanych zanurzeń dla wszystkich tokenów
|
||||
w tekście da się zapisać w postaci zwartego wzoru macierzowego:
|
||||
|
||||
$$E_1 = \operatorname{Attention}(Q, K, V) = \operatorname{softmax}(QK)^T V,$$
|
||||
|
||||
gdzie $Q$ to macierz wszystkich zapytań o rozmiarze $j \times d_k$ (wektory ułożone poziomo).
|
||||
|
||||
**** Skalowanie atencji
|
||||
|
||||
Twórcy modelu Transformer odkryli, że lepsze wyniki daje skalowanie atencji
|
||||
przez stałą zależną od rozmiaru wektora klucza/zapytania $d_k$:
|
||||
|
||||
$\operatorname{Attention}(Q, K, V) = \operatorname{softmax}(\frac{QK}{d_k})^T V,$$
|
||||
|
||||
** Wielogłowicowa atencja
|
||||
|
||||
Od samego początku w Transformerze zamiast jednej atencji zaproponowano wiele **głowic atencji**
|
||||
$(\operatorname{head}_1,\dots,\operatorname{head}_h$, każda głowica atencji działa w następujący sposób:
|
||||
|
||||
$$\operatorname{head_i} = \operatorname{Attention}(QW_i^Q, KW_i^K,VW_i^V),$$
|
||||
|
||||
to znaczy każda głowica atencji działa tak samo, tylko przed jej zastosowaniem mnożymy
|
||||
wektory zapytań, kluczy i wartości przez różne wyuczalne macierze, odpowiednio,
|
||||
W_i^Q, W_i^K,W_i^V. Otrzymamy w ten sposób $h$ wektorów, konkatenujemy po prostu i mnożymy
|
||||
przez dodatkową wyuczalną macierz $W^O$:
|
||||
|
||||
$$\operatorname{MultiHead}(Q, K, V) = [\operatorname{head}_1,...,\operatorname{head}_n]W^O.$$
|
||||
|
||||
Przyjmujemy, że $d_k = d_v = m/h$, wtedy rozmiary macierzy $W_i^Q$ i $W_i^K$ będą wynosiły
|
||||
$m \times d_k$, macierzy $W_i^V$ — $m \times d_v$, $W^O$ — $hd_v \times m$.
|
||||
|
Loading…
Reference in New Issue
Block a user