This commit is contained in:
Filip Gralinski 2021-06-22 21:15:58 +02:00
parent 78fb510cba
commit 97d92d38e8
3 changed files with 375 additions and 0 deletions

250
wyk/15_transformer.ipynb Normal file
View File

@ -0,0 +1,250 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Modele Transformer\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Atencja\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Atencję w modelach Transformer można interpretować jako rodzaj\n",
"„miękkiego” odpytywania swego rodzaju bazy danych, w której\n",
"przechowywane są pary klucz-wartość. Mamy trzy rodzaje wektorów (a\n",
"właściwie macierzy, bo wektory są od razu upakowane w macierze):\n",
"\n",
"- $Q$ - macierz zapytań,\n",
"- $K$ - macierz kluczy,\n",
"- $V$ - macierz wartości odpowiadających kluczom $K$.\n",
"\n",
"W atencji modeli Transformer patrzymy jak bardzo zapytania $Q$ pasują\n",
"do kluczy $K$ i na tej podstawie zwracamy wartości $V$ (im bardziej\n",
"**klucz** pasuje do **zapytania**, tym większy wkład wnosi odpowiednia **wartość**).\n",
"Ten rodzaj odpytywania można zrealizować z pomocą mnożenia macierzy i funkcji softmax:\n",
"\n",
"$$\\operatorname{Atention}(Q,K,V) = \\operatorname{softmax}(QK^T)V$$\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Uproszczony przykład\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Załóżmy, że rozmiar embeddingu wynosi 4, w macierzach rozpatrywać\n",
"będziemy po 3 wektory naraz (możemy sobie wyobrazić, że zdanie zawiera 3 wyrazy).\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[20.5700, 36.2400, 31.1000],\n",
" [15.1100, 13.9100, 7.9500],\n",
" [ 2.2100, 7.1800, 7.4000]])"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import torch\n",
"\n",
"Q = torch.tensor([\n",
" [0.3, -2.0, 0.4, 6.0],\n",
" [-1.0, 1.5, 0.2, 3.0],\n",
" [0.3, -1.0, 0.2, 1.0]])\n",
"\n",
"K = torch.tensor([\n",
" [-0.5, 1.7, 0.3, 4.0],\n",
" [0.4, -1.5, 0.3, 5.5],\n",
" [-1.0, -3.5, 1.0, 4.0]])\n",
"\n",
"M = Q @ torch.transpose(K, 0, 1)\n",
"M"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Jak widać, najbardziej pierwszy wektor $Q$ pasuje do drugiego wektora $K$.\n",
"Znormalizujmy te wartości używać funkcji softmax.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[1.5562e-07, 9.9418e-01, 5.8236e-03],\n",
" [7.6807e-01, 2.3134e-01, 5.9683e-04],\n",
" [3.0817e-03, 4.4385e-01, 5.5307e-01]])"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import torch\n",
"\n",
"Mn = torch.softmax(M, 1)\n",
"Mn"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Drugi wektor zapytania najbardziej pasuje do pierwszego klucza, trochę\n",
"mniej do drugiego klucza, o wiele mniej do trzeciego klucza. Te\n",
"wektory to oczywiście wektory atencji (drugie słowo najbardziej\n",
"„patrzy” na pierwsze słowo).\n",
"\n",
"Teraz będziemy przemnażać przez wektory wartości:\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"tensor([[ 3.9750e+00, 9.9419e-02, 1.0116e-01, 1.5765e-01, 5.8255e-04],\n",
" [ 9.2517e-01, 6.9357e+00, 2.3313e-02, -3.8112e+00, 9.2174e-01],\n",
" [ 1.6095e+00, 7.2120e-02, 2.1031e-01, 5.5597e+00, 5.9005e-02]])"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import torch\n",
"\n",
"V = torch.tensor([\n",
" [0.0, 9.0, 0.0, -5.0, 1.2],\n",
" [4.0, 0.1, 0.1, 0.1, 0.0],\n",
" [-0.3, 0.0, 0.3, 10.0, 0.1]])\n",
"\n",
"Mn @ V"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Dodatkowa normalizacja\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"W praktyce dobrze jest znormalizować pierwszy iloczyn przez\n",
"$\\sqrt{d_k}$, gdzie $d_k$ to rozmiar wektora klucza.\n",
"\n",
"$$\\operatorname{Atention}(Q,K,V) = \\operatorname{softmax}(\\frac{QK^T}{\\sqrt{d^k}})V$$\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Skąd się biorą Q, K i V?\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Wektory (macierze) $Q$, $K$ i $V$ w pierwszej warstwie pochodzą z\n",
"embeddingów tokenów $E$ (właściwie jednostek BPE).\n",
"\n",
"- $Q$ = $EW^Q$\n",
"- $K$ = $EW^K$\n",
"- $V$ = $EW^V$\n",
"\n",
"W kolejnych warstwach zamiast $E$ wykorzystywane jest wyjście z poprzedniej warstwy.\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Literatura\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"[https://arxiv.org/pdf/1706.03762.pdf](https://arxiv.org/pdf/1706.03762.pdf)\n",
"\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2"
},
"org": null
},
"nbformat": 4,
"nbformat_minor": 1
}

124
wyk/15_transformer.org Normal file
View File

@ -0,0 +1,124 @@
* 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

1
wyk/transformer.drawio Normal file
View File

@ -0,0 +1 @@
<mxfile host="app.diagrams.net" modified="2021-06-21T18:26:41.003Z" agent="5.0 (X11)" etag="PRyyghb9x3NmC1nfczsT" version="14.7.6" type="device"><diagram id="RKMbFXdSo0HOZQEC31J_" name="Page-1">7Ztbb5swFMc/DdL2sCpgLs0jkHbXvjSTqj5NKLgJKuCMOLd9+tnBkGK7TTqtsmVXiiJzMBf/fz7mHGMckFa7z022XNygHJaON8p3Dpg4njf2XfJPDfvWEADQGuZNkbcm92iYFn8gM46YdV3kcDWoiBEqcbEcGmeoruEMD2xZ06DtsNoDKodXXWZzKBims6wUrXdFjhet9dKLjvYvsJgvuiu74bjdU2VdZXaK1SLL0bY1HRoHrhyQNgjhtlTtUlhS7TpdWgWun9nb31gDa3zOAd8m9+PsKs7r9f5r7F9H6Y/q9lPATrPJyjVrMbtbvO8kaNC6ziE9y8gByXZRYDhdZjO6d0uYE9sCVyXZckmRnQ42GO6evVG3bz7pNhBVEDd7UqXrMwz9vusJbHt71D9kbR0tnmgPQmbMGPN5f+qjLKTAlHmFSqJIcZkJOpEW46EYK9ygR5iiEjXEUqOa1EweirLkTFlZzGuyOSMKQWJPqH4F6YQx21EVeU4vI1V/yOc/AHAvhwRAIBLwJQC8t9LfF/SvDJbfA5rJHwjyPyJsMgDd+n8kGaRTc/UHujnApah/kNzE0+9OMDEYg25uMBYwJNmqMHgg8n3NCHRRuSVP4mCkm/6ScN2CkSgIdePgCRwuzJW/z7a0kR9IAiKf/oJ0A2dOlGycaPKBbFEGBSYGmrBFk4+smrGohNTNVY1KzN1OoaqsICVkecpJiWneKVKHNNAGVtp5VfhqVjRjtAAV4J9VylHJkvcTqI4hnQ3EtHMuSbr/TuylcFw5MXFm4D3IkCawqkl5kgT2BKl2jscCWH6gGywxy+Vg/SZcTMficpNwvd7KsJxMqR5twBJxWJR7y1n5k/FYxrp5iyz+TgwGwIXT/XIKZQBk4bTBAPiJHfUAZNGxyQB084CuQ9gCgJ+DUQ9AlnWYDEA7D5BlEgYD4FM59QBkb8wMBsBPfKgHIEvaTAYQ6gZAlp6FJVU7LzakOMeHlg8ytiWdjHL7mae2Orn84AhTEQqZRKQYoS8bxM5C6FmKUMhFlCOUDYNnIQS2ItTOC/95IB1bijB0dUMoWz5gEwDVwYj/+kUBFza8Agt1WxTlS5f+eyPajpR4UXoo0KVT6YiWaJifeuTf5OW4HudOvuQLvR7J4Au9N8N0cgHA7Jdrw9sXLlhwgWL/6eZBXgIztgAM/wRSD0ackbuLb6c/72JzIbg8hLd7upDN45fdh31PPo8HV38B</diagram></mxfile>