diff --git a/wyk/11_Transformer.ipynb b/wyk/11_Transformer.ipynb
new file mode 100644
index 0000000..b5e0f8a
--- /dev/null
+++ b/wyk/11_Transformer.ipynb
@@ -0,0 +1,495 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n",
+ "
\n",
+ "
Modelowanie języka
\n",
+ " 11. Transformer [wykład]
\n",
+ " Filip Graliński (2022)
\n",
+ "\n",
+ "\n",
+ "![Logo 2](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech2.jpg)\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Transformer\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Atencja jako „miękka” baza danych\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "O atencji można myśleć metaforycznie jako o odpytywaniu „miękkiej”, wektorowej\n",
+ "bazy danych. Możemy sobie wyobrazić, że słowa $w_1,\\dots,w_{j-1}$ są\n",
+ "naszą bazą danych, a słowo $w_j$ (z którego kierujemy „snop” uwagi)\n",
+ "jest **zapytaniem** (*query*). To zapytanie dopasowujemy do **kluczy**\n",
+ "(*keys*), w najprostszym ujęciu po prostu słów $w_1,\\dots,w_{j-1}$ (a\n",
+ "właściwie ich zanurzeń). Jeśli klucz pasuje do zapytania, odpowiednia\n",
+ "wartość (*value*) jest wydobywana z bazy. Nasza baza jest jednak\n",
+ "„miękka”, nie — zerojedynkowa, zapytanie pasuje do klucza w pewnym\n",
+ "stopniu, mniej lub bardziej.\n",
+ "\n",
+ "W najprostszym ujęciu wartości są tym samym co klucze, czyli z naszej\n",
+ "bazy wydobywamy te same zanurzenia słów, których używamy jako kluczy.\n",
+ "Można jednak skomplikować schemat, rozróżniając klucze i wartości —\n",
+ "mogą one powstawać przez rzutowanie podstawowych zanurzeń różnymi\n",
+ "macierzami:\n",
+ "\n",
+ "$$\\vec{k_i} = W_k E(w_i),$$\n",
+ "\n",
+ "$$\\vec{v_i} = W_v E(w_i).$$\n",
+ "\n",
+ "Również samo zapytanie może powstać przez rzutowanie:\n",
+ "\n",
+ "$$\\vec{q_i} = W_q E(w_i).$$\n",
+ "\n",
+ "Jeśli zanurzenie $E(w_i)$ o rozmiarze $m$ przedstawimy w postaci\n",
+ "kolumnowej, wówczas macierze będą $W_k$ i $W_q$ będą miały rozmiar\n",
+ "$d_k \\times m$, gdzie $d_k$ jest rozmiarem kluczy i zapytań (dlaczego\n",
+ "wektory kluczy i zapytań powinny mieć raczej ten sam rozmiar?), zaś macierz\n",
+ "$W_v$ — $d_v \\times m$, gdzie $d_v$ to rozmiar zanurzenia wektora wartości.\n",
+ "Zazwyczaj $d_k = d_v = m$, ale nie jest to obligatoryjne.\n",
+ "\n",
+ "Teraz nieznormalizowane wagi atencji przyjmą postać:\n",
+ "\n",
+ "$$\\hat{\\alpha}_{i,j} = \\vec{q_i}^T\\vec{k_j} = (W_q E(w_i))(W_k E(k_j)).$$\n",
+ "\n",
+ "Zauważmy, że ciąg $\\hat{\\alpha}_{1,j},\\dots,\\hat{\\alpha}_{j-1,j}$ można potraktować jako wektor\n",
+ "$\\hat{\\vec{\\alpha}_{*,j}}$ i wyliczać w postaci zwartej:\n",
+ "\n",
+ "$$\\hat{\\vec{\\alpha}_{*,j}} = \\vec{q_j}^T K$$\n",
+ "\n",
+ "gdzie $K$ to macierz kluczy złożona z wektorów\n",
+ "$\\vec{k_1},\\dots,\\vec{k_{j-1}}$, tj. macierz o rozmiarze $d_k \\times (j-1)$.\n",
+ "\n",
+ "Wektor znormalizowanych wag atencji będzie miał wówczas postać:\n",
+ "\n",
+ "$$\\vec{\\alpha}_{*,j} = \\operatorname{softmax}(\\vec{q_j}^T K).$$\n",
+ "\n",
+ "Dokonajmy teraz agregacji wartości — obliczamy średnią wektorów\n",
+ "wartości ($\\vec{v_i}$) ważoną atencją:\n",
+ "\n",
+ "$$A(w_1,\\dots,j-1) = \\alpha_{1,j} \\vec{v_1} + \\dots + \\alpha_{j-1,j} \\vec{v_{j-1}} = \\sum_{i=1}^{j-1} \\alpha_{i,j} v_i.$$\n",
+ "\n",
+ "Jeśli $j-1$ wektorów wartości ułożymy w macierz $V$ (o rozmiarze\n",
+ "$(j-1) \\times d_v$), powyższy wzór będziemy mogli zapisać jako iloczyn wektora wag atencji i macierzy $V$:\n",
+ "\n",
+ "$$A(w_1,\\dots,j-1) = \\vec{\\alpha}_{*,j}^T V = \\operatorname{softmax}(\\vec{q_j}^T K)^T V.$$\n",
+ "\n",
+ "Sposób patrzenia na atencję przez pryzmat trójki\n",
+ "zapytania-klucze-wartości okaże się niezwykle ważny w wypadku modelu Transformer.\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Model Transformer — historia\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Architekturę Transformer opracowano, pierwotnie, na potrzeby\n",
+ "tłumaczenia automatycznego (rok 2017, artykuł [Attention Is All You\n",
+ "Need]([https://arxiv.org/abs/1706.03762](https://arxiv.org/abs/1706.03762))). Szybko okazało się, że\n",
+ "podobnie jak w wypadku modelu ELMo dla sieci LSTM, można **pretrenować**\n",
+ "duże modele Transformer (po prostu na dużych korpusach tekstowych, w\n",
+ "sposób nienadzorowany), a potem dostrajać pod konkretne zadanie\n",
+ "przetwarzania języka naturalnego. Jednym z pierwszych przykładów\n",
+ "takiego podejścia był model BERT (rok 2018, artykuł [BERT:\n",
+ "Pre-training of Deep Bidirectional Transformers for Language\n",
+ "Understanding]([https://arxiv.org/abs/1810.04805](https://arxiv.org/abs/1810.04805))). To podejście było\n",
+ "później rozwinięte w postaci różnych modeli Transformer, również dla innych\n",
+ "języków niż angielski (RoBERTa, XLM, Polish RoBERTa itd.).\n",
+ "\n",
+ "Na tym wykładzie my skupimy się na innej odnodze modeli Transformer —\n",
+ "modelach generatywnych, takich jak na przykład GPT-2 czy GPT-3. To\n",
+ "podejście jest bliższe duchowi czystego modelowania języka — model\n",
+ "języka jest używany wprost jako generator.\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### GPT-2 — przykład działania\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Dokonajmy najpierw tokenizacji:\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{'input_ids': tensor([[ 464, 2159, 1810, 6711, 481, 2221, 287, 1160, 2078, 287]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])}"
+ ]
+ }
+ ],
+ "source": [
+ "from transformers import AutoTokenizer\n",
+ "tokenizer = AutoTokenizer.from_pretrained(\"gpt2\")\n",
+ "text = \"The World War III will begin in 2028 in\"\n",
+ "encoded_input = tokenizer(text, return_tensors='pt')\n",
+ "encoded_input"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "['The', ' World', ' War', ' III', ' will', ' begin', ' in', ' 20', '28', ' in']"
+ ]
+ }
+ ],
+ "source": [
+ "[tokenizer.decode(i) for i in encoded_input.input_ids[0]]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Zwróćmy uwagę, że w GPT-2 tokeny obejmują spacje!\n",
+ "\n",
+ "Teraz uruchommy zasadniczy model:\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from transformers import AutoModelForCausalLM\n",
+ "model = AutoModelForCausalLM.from_pretrained(\"gpt2\")\n",
+ "outputs = model(**encoded_input)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "softmax(outputs[0][0][-1])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Z modelu GPT-2 otrzymamy rozkład prawdopodobieństwa kolejnego wyrazu, najpierw w postaci\n",
+ "nieznormalizowanych **logitów**:\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "tensor([-130.2947, -129.5677, -136.4030, ..., -138.3791, -138.8967,\n",
+ " -131.6319], grad_fn=)"
+ ]
+ }
+ ],
+ "source": [
+ "logits = outputs[0][0][-1]\n",
+ "logits"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[[' 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]]"
+ ]
+ }
+ ],
+ "source": [
+ "from torch import softmax, topk\n",
+ "\n",
+ "k = 20\n",
+ "\n",
+ "t = topk(softmax(logits, -1), k)\n",
+ "\n",
+ "tb = [[tokenizer.decode(t.indices[ix]), t.values[ix].item()] for ix in range(k)]\n",
+ "tb"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Generowanie tekstu za pomocą GPT-2\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from transformers import pipeline\n",
+ "generator = pipeline('text-generation', model='gpt2')\n",
+ "generator('Hello, I\\'m a language model,', max_length=30, num_return_sequences=1)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Model Transformer — podstawowa idea\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Model Transformer sprowadza się właściwie do atencji; nie posiada\n",
+ "żadnego komponentu rekurencyjnego, ani nawet nie stosujemy czegoś w\n",
+ "rodzaju połączenia modelu worka słów i modelu n-gramowego.\n",
+ "\n",
+ "W pierwszym przybliżeniu przy obliczaniu rozkładu prawdopodobieństwa\n",
+ "dla kolejnego wyrazu, to jest:\n",
+ "\n",
+ "$$P(w_j|w_1\\dots w_{j-1})$$\n",
+ "\n",
+ "na $j$-tym miejscu (w miejscu przewidywanego wyrazu) doklejamy\n",
+ "specjalny token, powiedzmy ``. Token ten będzie „atendował” do\n",
+ "innych wszystkich wcześniejszych tokenów w zdaniu:\n",
+ "\n",
+ "$$\\vec{\\alpha}_{*,j}^T V = \\operatorname{softmax}(\\vec{q_j}^T K)^T V.$$\n",
+ "\n",
+ "Samo to byłoby oczywiście zbyt proste:\n",
+ "\n",
+ "1. Otrzymalibyśmy model (ważonego) worka słów, w dodatku każde słowo\n",
+ " miałoby zawsze taką samą wagę! — token $w_j$, który atenduje jest\n",
+ " zawsze ten sam (``). Musimy wzbogacić reprezentację wektorową\n",
+ " słów i specjalnego tokenu (``).\n",
+ "\n",
+ "2. Model Transformer w swojej podstawowej postaci w ogóle nie jest\n",
+ " wyposażony w pojęcie sekwencji — w przeciwieństwie do sieci\n",
+ " rekurencyjnych, które w sposób inherentny operują krok po kroku, w\n",
+ " sekwencji (w czasie). Musimy pozycję tokenów wprowadzić do sieci\n",
+ " Transformer nie przez modyfikację jej architektury, lecz przez dołączenie\n",
+ " informacji pozycyjnej do początkowych zanurzeń.\n",
+ "\n",
+ "3. Model Transformer nie powinien mieć żadnych tokenów OOV/UNK. Musimy\n",
+ " wrócić do kwestii tokenizacji tekstu i wprowadzić podział rzadszych\n",
+ " tokenów na mniejsze, **podwyrazowe** jednostki.\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Atencja wsobna\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Jeśli chodzi problem (1), rozwiążemy go przez wprowadzenie\n",
+ "****skontekstualizowanych reprezentacji**** tokenów.\n",
+ "\n",
+ "Na przykład słowo *mysz* ma jedno wejściowe (*statyczne*) zanurzenie\n",
+ "(embedding) — bez względu na to, czy chodzi o zwierzę czy urządzenie\n",
+ "peryferyjne, tymczasem dość łatwo ustalić na podstawie kontekstu, o\n",
+ "które znaczenie chodzi.\n",
+ "\n",
+ "Rozwiązanie polega na tym, że wszystkim tokenom będziemy przypisywać kolejne\n",
+ "zanurzenia skontekstualizowane — zależne od innych tokenów w zdaniu. W\n",
+ "tym celu zastosujemy atencję wsobną (samo-atencję, *self-attention*).\n",
+ "Każdy token będzie atendował potencjalnie do każdego innego tokenu,\n",
+ "również do samego siebie (!).\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Wzory\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Rozpatrywać zatem będziemy nie tylko pojedynczy wektor znormalizowanych atencji\n",
+ "\n",
+ "$$\\vec{\\alpha}_{*,j}^T V = \\operatorname{softmax}(\\vec{q_j}^T K)^T V,$$\n",
+ "\n",
+ "lecz całą serię wektorów:\n",
+ "\n",
+ "$$\\vec{\\alpha}_{*,1},\\dots,\\vec{\\alpha}_{*,i},\\dots,\\vec{\\alpha}_{*,j},$$\n",
+ "\n",
+ "gdzie:\n",
+ "\n",
+ "$$\\vec{\\alpha}_{*,i} = \\operatorname{softmax}(\\vec{q_i}^T K)$$\n",
+ "\n",
+ "i $K$ jest macierzą kluczy o rozmiarze $d_k \\times j$ (tym razem obejmuje również sam $i$-ty token).\n",
+ "\n",
+ "Nowa, skontekstualizowana reprezentacja $i$-tego tokenu będzie po prostu średnią wszystkich\n",
+ "wektorów ważoną atencją:\n",
+ "\n",
+ "$$E_1(w_i) = \\operatorname{softmax}(\\vec{q_i}^T K)^T V,$$\n",
+ "\n",
+ "gdzie:\n",
+ "\n",
+ "- $E_1(w_i)$ — skontekstualizowane zanurzenie $i$-tego tokenu; używając indeksu $_1$\n",
+ " zaznaczamy, że to jest pierwszy skonstekstualizowany embedding, rekurencyjnie będziemy budowali\n",
+ " kolejne $E_2(w_i)$, $E_3(w_i)$ itd. (zaś wejściowy statyczny embedding możemy oznaczyć przez $E_0(w_i)$);\n",
+ "- $V$ — macierz wartości o rozmiarze $j \\times d_v$.\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "##### Zwarta postać macierzowa atencji wsobnej\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Z praktycznych powodów (szybkość obliczeń na kartach graficznych) dużą\n",
+ "zaletą atencji wsobnej jest to, że wyliczenie skonstekstualizowanych zanurzeń dla wszystkich tokenów\n",
+ "w tekście da się zapisać w postaci zwartego wzoru macierzowego:\n",
+ "\n",
+ "$$E_1 = \\operatorname{Attention}(Q, K, V) = \\operatorname{softmax}(QK)^T V,$$\n",
+ "\n",
+ "gdzie $Q$ to macierz wszystkich zapytań o rozmiarze $j \\times d_k$ (wektory ułożone poziomo).\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "##### Skalowanie atencji\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Twórcy modelu Transformer odkryli, że lepsze wyniki daje skalowanie atencji\n",
+ "przez stałą zależną od rozmiaru wektora klucza/zapytania $d_k$:\n",
+ "\n",
+ "$$\\operatorname{Attention}(Q, K, V) = \\operatorname{softmax}(\\frac{QK}{d_k})^T V,$$\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Wielogłowicowa atencja\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Od samego początku w Transformerze zamiast jednej atencji zaproponowano wiele ****głowic atencji****\n",
+ "$(\\operatorname{head}_1,\\dots,\\operatorname{head}_h)$, każda głowica atencji działa w następujący sposób:\n",
+ "\n",
+ "$$\\operatorname{head_i} = \\operatorname{Attention}(QW_i^Q, KW_i^K,VW_i^V),$$\n",
+ "\n",
+ "to znaczy każda głowica atencji działa tak samo, tylko przed jej zastosowaniem mnożymy\n",
+ "wektory zapytań, kluczy i wartości przez różne wyuczalne macierze, odpowiednio,\n",
+ "$W_i^Q$, $W_i^K$, $W_i^V$. Otrzymamy w ten sposób $h$ wektorów, konkatenujemy je po prostu i mnożymy\n",
+ "przez dodatkową wyuczalną macierz $W^O$:\n",
+ "\n",
+ "$$\\operatorname{MultiHead}(Q, K, V) = [\\operatorname{head}_1,...,\\operatorname{head}_n]W^O.$$\n",
+ "\n",
+ "Przyjmujemy, że $d_k = d_v = m/h$, wtedy rozmiary macierzy $W_i^Q$ i $W_i^K$ będą wynosiły\n",
+ "$m \\times d_k$, macierzy $W_i^V$ — $m \\times d_v$, $W^O$ — $hd_v \\times m$.\n",
+ "\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "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.10.4"
+ },
+ "org": null
+ },
+ "nbformat": 4,
+ "nbformat_minor": 1
+}
diff --git a/wyk/11_Transformer.org b/wyk/11_Transformer.org
index bef5f66..bd9be02 100644
--- a/wyk/11_Transformer.org
+++ b/wyk/11_Transformer.org
@@ -15,7 +15,7 @@ stopniu, mniej lub bardziej.
W najprostszym ujęciu wartości są tym samym co klucze, czyli z naszej
bazy wydobywamy te same zanurzenia słów, których używamy jako kluczy.
-Można jednak skomplikować schemat rozróżniając klucze i wartości —
+Można jednak skomplikować schemat, rozróżniając klucze i wartości —
mogą one powstawać przez rzutowanie podstawowych zanurzeń różnymi
macierzami:
@@ -55,7 +55,7 @@ wartości ($\vec{v_i}$) ważoną atencją:
$$A(w_1,\dots,j-1) = \alpha_{1,j} \vec{v_1} + \dots + \alpha_{j-1,j} \vec{v_{j-1}} = \sum_{i=1}^{j-1} \alpha_{i,j} v_i.$$
-Jeśli $j-1$ wektorów wartości ułożyłem w macierz $V$ (o rozmiarze
+Jeśli $j-1$ wektorów wartości ułożymy w macierz $V$ (o rozmiarze
$(j-1) \times d_v$), powyższy wzór będziemy mogli zapisać jako iloczyn wektora wag atencji i macierzy $V$:
$$A(w_1,\dots,j-1) = \vec{\alpha}_{*,j}^T V = \operatorname{softmax}(\vec{q_j}^T K)^T V.$$
@@ -87,7 +87,7 @@ języka jest używany wprost jako generator.
Dokonajmy najpierw tokenizacji:
-#+BEGIN_SRC python :session mysession :exports both :results raw drawer
+#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("gpt2")
text = "The World War III will begin in 2028 in"
@@ -100,7 +100,7 @@ Dokonajmy najpierw tokenizacji:
{'input_ids': tensor([[ 464, 2159, 1810, 6711, 481, 2221, 287, 1160, 2078, 287]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])}
:end:
-#+BEGIN_SRC python :session mysession :exports both :results raw drawer
+#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
[tokenizer.decode(i) for i in encoded_input.input_ids[0]]
#+END_SRC
@@ -113,7 +113,7 @@ Zwróćmy uwagę, że w GPT-2 tokeny obejmują spacje!
Teraz uruchommy zasadniczy model:
-#+BEGIN_SRC python :session mysession :exports both :results raw drawer
+#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("gpt2")
outputs = model(**encoded_input)
@@ -123,7 +123,7 @@ Teraz uruchommy zasadniczy model:
:results:
:end:
-#+BEGIN_SRC python :session mysession :exports both :results raw drawer
+#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
softmax(outputs[0][0][-1])
#+END_SRC
@@ -135,7 +135,7 @@ Teraz uruchommy zasadniczy model:
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
+#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
logits = outputs[0][0][-1]
logits
#+END_SRC
@@ -146,7 +146,7 @@ tensor([-130.2947, -129.5677, -136.4030, ..., -138.3791, -138.8967,
-131.6319], grad_fn=)
:end:
-#+BEGIN_SRC python :session mysession :exports both :results raw drawer
+#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
from torch import softmax, topk
k = 20
@@ -164,7 +164,7 @@ tensor([-130.2947, -129.5677, -136.4030, ..., -138.3791, -138.8967,
*** Generowanie tekstu za pomocą GPT-2
-#+BEGIN_SRC python :session mysession :exports both :results raw drawer
+#+BEGIN_SRC ipython :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)
@@ -194,7 +194,7 @@ $$\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
+ miałoby zawsze taką samą wagę! — token $w_j$, który atenduje jest
zawsze ten sam (~~). Musimy wzbogacić reprezentację wektorową
słów i specjalnego tokenu (~~).
@@ -219,8 +219,8 @@ Na przykład słowo /mysz/ ma jedno wejściowe (/statyczne/) zanurzenie
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
+Rozwiązanie polega na tym, że wszystkim tokenom będziemy przypisywać kolejne
+zanurzenia skontekstualizowane — zależne od innych tokenó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 (!).
@@ -229,11 +229,11 @@ również do samego siebie (!).
Rozpatrywać zatem będziemy nie tylko pojedynczy wektor znormalizowanych atencji
-$$\vec{\alpha}_{*,j}^T V = \operatorname{softmax}(\vec{q_j}^T K)^T V$$,
+$$\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}$$
+$$\vec{\alpha}_{*,1},\dots,\vec{\alpha}_{*,i},\dots,\vec{\alpha}_{*,j},$$
gdzie:
@@ -251,7 +251,7 @@ 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$.
+- $V$ — macierz wartości o rozmiarze $j \times d_v$.
**** Zwarta postać macierzowa atencji wsobnej
@@ -268,18 +268,18 @@ gdzie $Q$ to macierz wszystkich zapytań o rozmiarze $j \times d_k$ (wektory uł
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,$$
+$$\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}_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
+$W_i^Q$, $W_i^K$, $W_i^V$. Otrzymamy w ten sposób $h$ wektorów, konkatenujemy je po prostu i mnożymy
przez dodatkową wyuczalną macierz $W^O$:
$$\operatorname{MultiHead}(Q, K, V) = [\operatorname{head}_1,...,\operatorname{head}_n]W^O.$$
diff --git a/wyk/helpers/intro b/wyk/helpers/intro
index 6da9943..7d82176 100644
--- a/wyk/helpers/intro
+++ b/wyk/helpers/intro
@@ -8,7 +8,7 @@
"![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n",
"\n",
"
Modelowanie języka
\n",
- " 10. Atencja [wykład]
\n",
+ " 11. Transformer [wykład]
\n",
" Filip Graliński (2022)
\n",
"\n",
"\n",