forked from filipg/aitech-eks-pub
125 lines
3.2 KiB
Org Mode
125 lines
3.2 KiB
Org Mode
|
* Modele Transformer
|
||
|
|
||
|
** Atencja
|
||
|
|
||
|
Atencję w modelach Transformer można interpretować jako rodzaj
|
||
|
„miękkiego” odpytywania swego rodzaju bazy danych, w której
|
||
|
przechowywane są pary klucz-wartość. Mamy trzy rodzaje wektorów (a
|
||
|
właściwie macierzy, bo wektory są od razu upakowane w macierze):
|
||
|
|
||
|
- $Q$ - macierz zapytań,
|
||
|
- $K$ - macierz kluczy,
|
||
|
- $V$ - macierz wartości odpowiadających kluczom $K$.
|
||
|
|
||
|
W atencji modeli Transformer patrzymy jak bardzo zapytania $Q$ pasują
|
||
|
do kluczy $K$ i na tej podstawie zwracamy wartości $V$ (im bardziej
|
||
|
*klucz* pasuje do *zapytania*, tym większy wkład wnosi odpowiednia *wartość*).
|
||
|
Ten rodzaj odpytywania można zrealizować z pomocą mnożenia macierzy i funkcji softmax:
|
||
|
|
||
|
$$\operatorname{Atention}(Q,K,V) = \operatorname{softmax}(QK^T)V$$
|
||
|
|
||
|
*** Uproszczony przykład
|
||
|
|
||
|
Załóżmy, że rozmiar embeddingu wynosi 4, w macierzach rozpatrywać
|
||
|
będziemy po 3 wektory naraz (możemy sobie wyobrazić, że zdanie zawiera 3 wyrazy).
|
||
|
|
||
|
|
||
|
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
|
||
|
import torch
|
||
|
|
||
|
Q = torch.tensor([
|
||
|
[0.3, -2.0, 0.4, 6.0],
|
||
|
[-1.0, 1.5, 0.2, 3.0],
|
||
|
[0.3, -1.0, 0.2, 1.0]])
|
||
|
|
||
|
K = torch.tensor([
|
||
|
[-0.5, 1.7, 0.3, 4.0],
|
||
|
[0.4, -1.5, 0.3, 5.5],
|
||
|
[-1.0, -3.5, 1.0, 4.0]])
|
||
|
|
||
|
M = Q @ torch.transpose(K, 0, 1)
|
||
|
M
|
||
|
|
||
|
#+END_SRC
|
||
|
|
||
|
#+RESULTS:
|
||
|
:results:
|
||
|
# Out[11]:
|
||
|
#+BEGIN_EXAMPLE
|
||
|
tensor([[20.5700, 36.2400, 31.1000],
|
||
|
[15.1100, 13.9100, 7.9500],
|
||
|
[ 2.2100, 7.1800, 7.4000]])
|
||
|
#+END_EXAMPLE
|
||
|
:end:
|
||
|
|
||
|
Jak widać, najbardziej pierwszy wektor $Q$ pasuje do drugiego wektora $K$.
|
||
|
Znormalizujmy te wartości używać funkcji softmax.
|
||
|
|
||
|
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
|
||
|
import torch
|
||
|
|
||
|
Mn = torch.softmax(M, 1)
|
||
|
Mn
|
||
|
|
||
|
#+END_SRC
|
||
|
|
||
|
#+RESULTS:
|
||
|
:results:
|
||
|
# Out[12]:
|
||
|
#+BEGIN_EXAMPLE
|
||
|
tensor([[1.5562e-07, 9.9418e-01, 5.8236e-03],
|
||
|
[7.6807e-01, 2.3134e-01, 5.9683e-04],
|
||
|
[3.0817e-03, 4.4385e-01, 5.5307e-01]])
|
||
|
#+END_EXAMPLE
|
||
|
:end:
|
||
|
|
||
|
Drugi wektor zapytania najbardziej pasuje do pierwszego klucza, trochę
|
||
|
mniej do drugiego klucza, o wiele mniej do trzeciego klucza. Te
|
||
|
wektory to oczywiście wektory atencji (drugie słowo najbardziej
|
||
|
„patrzy” na pierwsze słowo).
|
||
|
|
||
|
Teraz będziemy przemnażać przez wektory wartości:
|
||
|
|
||
|
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
|
||
|
import torch
|
||
|
|
||
|
V = torch.tensor([
|
||
|
[0.0, 9.0, 0.0, -5.0],
|
||
|
[4.0, 0.1, 0.1, 0.1],
|
||
|
[-0.3, 0.0, 0.3, 10.0]])
|
||
|
|
||
|
Mn @ V
|
||
|
#+END_SRC
|
||
|
|
||
|
#+RESULTS:
|
||
|
:results:
|
||
|
# Out[13]:
|
||
|
#+BEGIN_EXAMPLE
|
||
|
tensor([[ 3.9750, 0.0994, 0.1012, 0.1577],
|
||
|
[ 0.9252, 6.9357, 0.0233, -3.8112],
|
||
|
[ 1.6095, 0.0721, 0.2103, 5.5597]])
|
||
|
#+END_EXAMPLE
|
||
|
:end:
|
||
|
|
||
|
*** Dodatkowa normalizacja
|
||
|
|
||
|
W praktyce dobrze jest znormalizować pierwszy iloczyn przez
|
||
|
$\sqrt{d_k}$, gdzie $d_k$ to rozmiar wektora klucza.
|
||
|
|
||
|
$$\operatorname{Atention}(Q,K,V) = \operatorname{softmax}(\frac{QK^T}{d^k})V$$
|
||
|
|
||
|
*** Skąd się biorą Q, K i V?
|
||
|
|
||
|
Wektory (macierze) $Q$, $K$ i $V$ w pierwszej warstwie pochodzą z
|
||
|
embeddingów tokenów $E$ (właściwie jednostek BPE).
|
||
|
|
||
|
- $Q$ = $EW^Q$
|
||
|
- $K$ = $EW^K$
|
||
|
- $V$ = $EW^V$
|
||
|
|
||
|
W kolejnych warstwach zamiast $E$ wykorzystywane jest wyjście z poprzedniej warstwy.
|
||
|
|
||
|
** Literatura
|
||
|
|
||
|
https://arxiv.org/pdf/1706.03762.pdf
|