forked from filipg/aitech-eks-pub
15
This commit is contained in:
parent
78fb510cba
commit
97d92d38e8
250
wyk/15_transformer.ipynb
Normal file
250
wyk/15_transformer.ipynb
Normal 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
124
wyk/15_transformer.org
Normal 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
1
wyk/transformer.drawio
Normal 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>
|
Loading…
Reference in New Issue
Block a user