Merge branch 'master' of git.wmi.amu.edu.pl:filipg/aitech-eks

This commit is contained in:
Jakub Pokrywka 2021-06-16 15:14:53 +02:00
commit 9d96c9ec4f
19 changed files with 2114 additions and 22 deletions

View File

@ -375,13 +375,13 @@ Definicja w PyTorchu:
z_plus = torch.exp(z)
return z_plus / torch.sum(z_plus)
softmax(torch.tensor([3., -1., 0., 5.]))
softmax(torch.tensor([3., 1., -1., 1.]))
#+END_SRC
#+RESULTS:
:results:
# Out[75]:
: tensor([0.1182, 0.0022, 0.0059, 0.8737])
# Out[3]:
: tensor([7.8678e-01, 1.0648e-01, 2.6393e-04, 1.0648e-01])
:end:
#+CAPTION: Softmax

File diff suppressed because one or more lines are too long

View File

@ -87,7 +87,7 @@ $$s^k = \sigma(W\langle\vec{v}(t^k), \vec{s^{k-1}}\rangle + \vec{b}),$$
gdzie:
- $\langle\vec{x},\vec{y}\rangle$ to konkatenacja dwóch wektorów,
- $W \in \mathcal{R}^m \times \mathcal{R}^{n+m} $ — macierz wag,
- $W \in \mathcal{R}^m \times \mathcal{R}^{n+m}$ — macierz wag,
- $b \in \mathcal{R}^m$ — wektor obciążeń (/biases/).
Taką sieć RNN można przedstawić schematycznie w następujący sposób:
@ -181,7 +181,7 @@ selektywnie wygaszać pozycje wektora, np. tutaj wyzerowaliśmy 2. i 5. pozycję
Co więcej, za pomocą bramki możemy selektywnie kontrolować, co
zapamiętujemy, a co zapominamy. Rozpatrzmy mianowicie wektor zer i
jedynek $\vec{g} \in \{0,1}^m$, dla stanu (pamięci) $\vec{s}$ i nowej informacji
jedynek $\vec{g} \in \{0,1\}^m$, dla stanu (pamięci) $\vec{s}$ i nowej informacji
$\vec{x}$ możemy dokonywać aktualizacji w następujący sposób:
$$\vec{s} \leftarrow \vec{g} \odot \vec{x} + (1 - \vec{g}) \odot \vec{s}$$
@ -259,7 +259,7 @@ $$\vec{i} = \sigma(W_i\langle\vec{v}(t^k),\vec{h^{k-1}}\rangle)$$
$$\vec{f} = \sigma(W_f\langle\vec{v}(t^k),\vec{h^{k-1}}\rangle)$$
$$\vec{o} = \sigma(W_f\langle\vec{v}(t^k),\vec{h^{k-1}}\rangle)$$
$$\vec{o} = \sigma(W_o\langle\vec{v}(t^k),\vec{h^{k-1}}\rangle)$$
Jak widać, wzory różnią się tylko macierzami wag $W_*$.
@ -279,10 +279,10 @@ Ostateczne wyjście może być wyliczane na podstawie wektora $\vec{h^k}$:
$$O(\vec{s}) = O(\langle\vec{c},\vec{h}\rangle) = \vec{h}$$
*Pytanie*: Ile wag/parametrów ma sieć RNN o rozmiarze wejścia $n$ i
*Pytanie*: Ile wag/parametrów ma sieć RNN o rozmiarze wejścia $n$ i rozmiarze warstwy ukrytej $m$?
** Literatura
Yoav Goldberg, /Neural Network Methods for Natural Language
Processing/, Morgan & Claypool Publishers, 2017
Yoav Goldberg, /Neural Network Methods for Natural Language Processing/,
Morgan & Claypool Publishers, 2017

839
wyk/12_bpe.ipynb Normal file

File diff suppressed because one or more lines are too long

View File

@ -36,7 +36,7 @@ Ile jest różnych form fleksyjnych w języku polskim? Zobaczmy w słowniku Poli
Tak naprawdę form jest jeszcze więcej, oczywiście PoliMorf nie wyczerpuje zbioru…
*Pytanie* Podaj przykłady „oczywistych” wyrazów, których w PoliMorfie. Jak w sposób systematyczny szukać takich wyrazów?
*Pytanie* Podaj przykłady „oczywistych” wyrazów, których nie ma w PoliMorfie. Jak w sposób systematyczny szukać takich wyrazów?
Z drugiej strony, w PoliMorfie jest dużo dziwnych, „sztucznych” wyrazów.
@ -88,7 +88,7 @@ nie pokryje on sporej części tekstów przetwarzanych w czasie inferencji.
Zobaczmy, ilu wyrazów ze zbioru deweloperskiego nie będzie w słowniku.
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
! cat petite-difference-challenge2/dev-0/in.tsv.xz | perl -C -ne 'print "$&\n" while/\p{L}+/g;' | sort -u | comm vocab.txt - -13 | wc -l
! cat petite-difference-challenge2/dev-0/in.tsv | perl -C -ne 'print "$&\n" while/\p{L}+/g;' | sort -u | comm vocab.txt - -13 | wc -l
#+END_SRC
Takie wyrazy nazywamy wyrazami *OOV* (/out-of-vocabulary/).
@ -112,7 +112,7 @@ Daje to lepszy efekt niż można się spodziewać. Odrzucamy w ten sposób
tylko bardzo rzadkie słowa (albo takie, które wystąpiły tylko raz w
korpusie — tzw. /hapax legomena/), choć tych słów jest bardzo dużo.
*Zagadka*: 50000 najczęstszych słów (1,9\% *typów*) pokrywa jaki odsetek *wystąpień*?
*Zagadka*: 50000 najczęstszych słów (1,9% *typów*) pokrywa jaki odsetek *wystąpień*?
Rozkład normalny w języku nie jest… normalny — nie spotkamy się z nim
badając języki. W tekstach dominują „skrzywione” rozkłady z długimi,
@ -244,7 +244,7 @@ momentu traktujemy go jako całostkę (wkładamy go do „pudełka”).
#+RESULTS:
:results:
# Out[4]:
# Out[1]:
: ['e$', 'to', 'to$', 'be$', 't$', 'th', 'or', 'or$', 'no', 'not$']
:end:
@ -256,13 +256,17 @@ na którym słownik był wyuczony:
d = list(d.replace(' ', '$') + '$')
vocab_set = set(vocab)
ix = 0
while ix < len(d) - 1:
bigram = d[ix] + d[ix+1]
if bigram in vocab_set:
d[ix:ix+2] = [bigram]
else:
ix += 1
modified = True
while modified:
ix = 0
modified = False
while ix < len(d) - 1:
bigram = d[ix] + d[ix+1]
if bigram in vocab_set:
d[ix:ix+2] = [bigram]
modified = True
else:
ix += 1
return d
@ -272,7 +276,7 @@ na którym słownik był wyuczony:
#+RESULTS:
:results:
# Out[5]:
: 'to$ b e$ or$ no t$ to$ b e$ th a t$ i s $ th e$ q u e s t i o n $'
: 'to$ be$ or$ not$ to$ be$ th a t$ i s $ th e$ q u e s t i o n $'
:end:
Zauważmy, że oprócz jednostek podwyrazowych zostały izolowane litery,
@ -289,6 +293,12 @@ Słownik jednostek podwyrazowych można stosować dla dowolnego tekstu:
' '.join(apply_bpe_vocab(vocab1, 'tom will be the best'))
#+END_SRC
#+RESULTS:
:results:
# Out[6]:
: 'to m $ w i l l $ be$ th e$ b e s t$'
:end:
Jak można zauważyć algorytm BPE daje dwa rodzaje jednostek podwyrazowych:
- jednostki, które mogą doklejane na początku wyrazu;

View File

@ -0,0 +1,113 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Ekstrakcja informacji a podejście generatywne\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Podejście generatywne\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Do tej pory zadanie ekstrakcji informacji traktowaliśmy jako zadanie etykietowania sekwencji, tzn. uczyliśmy system zaznaczać tokeny składające się na ekstrahowane informacje.\n",
"\n",
"![img](./ie-seqlab.png)\n",
"\n",
"Możliwe jest inne podeście, **generatywne**, w którym podchodzimy do problemu ekstrakcji informacji jak do swego rodzaju **tłumaczenia maszynowego** — „tłumaczymy” tekst (wraz z pytaniem lub etykietą) na informację.\n",
"\n",
"![img](./ie-gener.png)\n",
"\n",
"To podejście może się wydawać trudniejsze niż etykietowanie sekwencji, ale wystarczająco zaawansowanej architekturze sieci, jest wykonalne.\n",
"\n",
"Zalety:\n",
"\n",
"- informacja nie musi być dosłownie zapisana w tekście, ekstraktor może nauczyć się również normalizacji czy parafrazowania,\n",
"- nie wprowadzamy wielu kroków przetwarzania (gdzie błędy mogą się\n",
" namnażać), system działa na zasadzie *end-to-end*.\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Atencja\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Pierwsze systemu neuronowego tłumaczenia maszynowego używały siecie LSTM. Dopiero jednak dodanie tzw. atencji (*attention*) umożliwiło duży przeskok jakościowy. Najpierw atencję dodano do sieci rekurencyjnych, później powstały sieci oparte *wyłącznie* na atencji — modele Transformer.\n",
"\n",
"Idea atencji polega na tym, że sieć może kierować selektywnie „snop” uwagi na wyrazy na wejściu lub do tej pory wygenerowane wyrazy.\n",
"\n",
"Mechanizm atencji korzysta z:\n",
"\n",
"- z poprzedniego stanu sieci $\\vec{s^{k-1}}$ (to jest „miejsce”, z którego „kierujemy” atencję),\n",
"- z wektora reprezentującego słowo $\\vec{v}(t_i)$ (to jest „miejsce”, na które kierujemy atencję), gdzie\n",
" $\\vec{v}(t_i)$ to reprezentacja wektorowa wyrazu $t_i$ (statyczny embedding lub reprezentacja wektorowa\n",
" z poprzedniej warstwy dla sieci wielowarstwowej),\n",
"\n",
"aby wytworzyć wektor kontekstu $\\vec{\\xi^k}$ (który z kolei będzie w jakiś sposób wnosił wkład do wyliczenia nowej wartości stanu $\\vec{s^k}$ lub wyjścia $y^k$.\n",
"\n",
"Najpierw wyliczymy skalarne wartości atencji, tzn. liczby, które będą sygnalizowały, jak bardzo wektor $\\vec{v}(t_i)$ „pasuje” do $\\vec{s^{k-1}}$, w najprostszej wersji można po prostu skorzystać z iloczynu skalarnego (o ile $n=m$),\n",
"\n",
"$$a(\\vec{s^{k-1}}, \\vec{v}(t_i)) = \\vec{s^{k-1}}\\vec{v}(t_i).$$\n",
"\n",
"**Pytanie**: co jeśli $n$ nie jest równe $m$, tzn. rozmiar embeddingu nie jest równy rozmiarowi wektora stanu?\n",
"\n",
"W przypadku sieci LSTM korzysta się częściej z bardziej skomplikowanego wzoru zawierającego dodatkowe wyuczalne wagi:\n",
"\n",
"$$a(\\vec{s^{k-1}}, \\vec{v}(t_i)) = \\vec{w_a}\\operatorname{tanh}(W_a\\vec{s^{k-1}} + U_a\\vec{v}(t_i))$$\n",
"\n",
"**Pytanie**: jakie rozmiary mają macierze $W_a$, $U_a$ i wektor $w_a$?\n",
"\n",
"Powtórzmy, że wartości $a$ są wartościami skalarnymi, natomiast nie są one znormalizowane (nie sumują się do jedynki), normalizujemy je używając schematu podobnego do softmaxa:\n",
"\n",
"$$\\alpha_{i} = \\frac{e^{a(\\vec{s^{k-1}}, \\vec{v}(t_i))}}{\\sum_j e^{a(\\vec{s^{k-1}}, \\vec{v}(t_j))}}$$\n",
"\n",
"Wektor kontekstu $\\vec{\\xi^k}$ będzie po prostu średnią ważoną wektorowych reprezentacji słów:\n",
"\n",
"$$\\vec{\\xi^k} = \\sum_i \\alpha_i\\vec{v}(t_i)$$\n",
"\n",
"**Pytanie**: zasadniczo atencja jest środkiem do celu (żeby sieć się sprawniej uczyła), czy można atencja sama w sobie może być do czegoś przydatna?\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
}

View File

@ -0,0 +1,55 @@
* Ekstrakcja informacji a podejście generatywne
** Podejście generatywne
Do tej pory zadanie ekstrakcji informacji traktowaliśmy jako zadanie etykietowania sekwencji, tzn. uczyliśmy system zaznaczać tokeny składające się na ekstrahowane informacje.
[[./ie-seqlab.png]]
Możliwe jest inne podeście, *generatywne*, w którym podchodzimy do problemu ekstrakcji informacji jak do swego rodzaju *tłumaczenia maszynowego* — „tłumaczymy” tekst (wraz z pytaniem lub etykietą) na informację.
[[./ie-gener.png]]
To podejście może się wydawać trudniejsze niż etykietowanie sekwencji, ale wystarczająco zaawansowanej architekturze sieci, jest wykonalne.
Zalety:
- informacja nie musi być dosłownie zapisana w tekście, ekstraktor może nauczyć się również normalizacji czy parafrazowania,
- nie wprowadzamy wielu kroków przetwarzania (gdzie błędy mogą się
namnażać), system działa na zasadzie /end-to-end/.
** Atencja
Pierwsze systemu neuronowego tłumaczenia maszynowego używały siecie LSTM. Dopiero jednak dodanie tzw. atencji (/attention/) umożliwiło duży przeskok jakościowy. Najpierw atencję dodano do sieci rekurencyjnych, później powstały sieci oparte /wyłącznie/ na atencji — modele Transformer.
Idea atencji polega na tym, że sieć może kierować selektywnie „snop” uwagi na wyrazy na wejściu lub do tej pory wygenerowane wyrazy.
Mechanizm atencji korzysta z:
- z poprzedniego stanu sieci $\vec{s^{k-1}}$ (to jest „miejsce”, z którego „kierujemy” atencję),
- z wektora reprezentującego słowo $\vec{v}(t_i)$ (to jest „miejsce”, na które kierujemy atencję), gdzie
$\vec{v}(t_i)$ to reprezentacja wektorowa wyrazu $t_i$ (statyczny embedding lub reprezentacja wektorowa
z poprzedniej warstwy dla sieci wielowarstwowej),
aby wytworzyć wektor kontekstu $\vec{\xi^k}$ (który z kolei będzie w jakiś sposób wnosił wkład do wyliczenia nowej wartości stanu $\vec{s^k}$ lub wyjścia $y^k$.
Najpierw wyliczymy skalarne wartości atencji, tzn. liczby, które będą sygnalizowały, jak bardzo wektor $\vec{v}(t_i)$ „pasuje” do $\vec{s^{k-1}}$, w najprostszej wersji można po prostu skorzystać z iloczynu skalarnego (o ile $n=m$),
$$a(\vec{s^{k-1}}, \vec{v}(t_i)) = \vec{s^{k-1}}\vec{v}(t_i).$$
*Pytanie*: co jeśli $n$ nie jest równe $m$, tzn. rozmiar embeddingu nie jest równy rozmiarowi wektora stanu?
W przypadku sieci LSTM korzysta się częściej z bardziej skomplikowanego wzoru zawierającego dodatkowe wyuczalne wagi:
$$a(\vec{s^{k-1}}, \vec{v}(t_i)) = \vec{w_a}\operatorname{tanh}(W_a\vec{s^{k-1}} + U_a\vec{v}(t_i))$$
*Pytanie*: jakie rozmiary mają macierze $W_a$, $U_a$ i wektor $w_a$?
Powtórzmy, że wartości $a$ są wartościami skalarnymi, natomiast nie są one znormalizowane (nie sumują się do jedynki), normalizujemy je używając schematu podobnego do softmaxa:
$$\alpha_{i} = \frac{e^{a(\vec{s^{k-1}}, \vec{v}(t_i))}}{\sum_j e^{a(\vec{s^{k-1}}, \vec{v}(t_j))}}$$
Wektor kontekstu $\vec{\xi^k}$ będzie po prostu średnią ważoną wektorowych reprezentacji słów:
$$\vec{\xi^k} = \sum_i \alpha_i\vec{v}(t_i)$$
*Pytanie*: zasadniczo atencja jest środkiem do celu (żeby sieć się sprawniej uczyła), czy można atencja sama w sobie może być do czegoś przydatna?

338
wyk/14_pretrenowanie.ipynb Normal file
View File

@ -0,0 +1,338 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Pretrenowanie modeli\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"System AlphaZero uczy się grając sam ze sobą — wystarczy 24 godziny,\n",
"by system nauczył się grać w szachy lub go na nadludzkim poziomie.\n",
"\n",
"**Pytanie**: Dlaczego granie samemu ze sobą nie jest dobrym sposobem\n",
" nauczenia się grania w szachy dla człowieka, a dla maszyny jest?\n",
"\n",
"Co jest odpowiednikiem grania samemu ze sobą w świecie przetwarzania tekstu?\n",
"Tzn. **pretrenowanie** (*pretraining*) na dużym korpusie tekstu. (Tekst jest tani!)\n",
"\n",
"Jest kilka sposobów na pretrenowanie modelu, w każdym razie sprowadza\n",
"się do odgadywania następnego bądź zamaskowanego słowa.\n",
"W każdym razie zawsze stosujemy softmax (być może ze „sztuczkami” takimi jak\n",
"negatywne próbkowanie albo hierarchiczny softamx) na pewnej **representecji kontekstowej**:\n",
"\n",
"$$\\vec{p} = \\operatorname{softmax}(f(\\vec{c})).$$\n",
"\n",
"Model jest karany używając funkcji log loss:\n",
"\n",
"$$-\\log(p_j),$$\n",
"\n",
"gdzie $w_j$ jest wyrazem, który pojawił się rzeczywiście w korpusie.\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Przewidywanie słowa (GPT-2)\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Jeden ze sposobów pretrenowania modelu to po prostu przewidywanie\n",
"następnego słowa.\n",
"\n",
"Zainstalujmy najpierw bibliotekę transformers.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"! pip install transformers"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"50257\n"
]
},
{
"data": {
"text/plain": [
"[('Ġon', 0.6786560416221619),\n",
" ('Ġupon', 0.04339785501360893),\n",
" ('Ġheavily', 0.02208443358540535),\n",
" ('Ġin', 0.021049050614237785),\n",
" (',', 0.020188499242067337),\n",
" ('Ġa', 0.01833895780146122),\n",
" ('Ġvery', 0.017935041338205338),\n",
" ('Ġentirely', 0.017528969794511795),\n",
" ('Ġlargely', 0.016769640147686005),\n",
" ('Ġto', 0.01009418722242117),\n",
" ('Ġgreatly', 0.010009866207838058),\n",
" ('Ġnot', 0.009016563184559345),\n",
" ('Ġmore', 0.005853226874023676),\n",
" ('Ġprimarily', 0.005203146021813154),\n",
" ('Ġstrongly', 0.0034501152113080025),\n",
" ('Ġpartly', 0.0033184229396283627),\n",
" ('Ġmuch', 0.0033095215912908316),\n",
" ('Ġmostly', 0.0032150144688785076),\n",
" ('Ġmainly', 0.0030899408739060163),\n",
" ('Ġfor', 0.003034428460523486),\n",
" ('.', 0.0028878094162791967),\n",
" ('Ġboth', 0.0028405177872627974),\n",
" ('Ġsomewhat', 0.0028194624464958906),\n",
" ('Ġcru', 0.002263976726680994),\n",
" ('Ġas', 0.00221616611815989),\n",
" ('Ġof', 0.0022000609897077084),\n",
" ('Ġalmost', 0.001968063646927476),\n",
" ('Ġat', 0.0018015997484326363),\n",
" ('Ġhighly', 0.0017461496172472835),\n",
" ('Ġcompletely', 0.001692073536105454)]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import torch\n",
"from transformers import GPT2Tokenizer, GPT2LMHeadModel\n",
"tokenizer = GPT2Tokenizer.from_pretrained('gpt2-large')\n",
"model = GPT2LMHeadModel.from_pretrained('gpt2-large')\n",
"text = \"This issue depends\"\n",
"encoded_input = tokenizer(text, return_tensors='pt')\n",
"output = model(**encoded_input)\n",
"next_token_probs = torch.softmax(output[0][:, -1, :][0], dim=0)\n",
"\n",
"next_token_probs\n",
"nb_of_tokens = next_token_probs.size()[0]\n",
"print(nb_of_tokens)\n",
"\n",
"_, top_k_indices = torch.topk(next_token_probs, 30, sorted=True)\n",
"\n",
"words = tokenizer.convert_ids_to_tokens(top_k_indices)\n",
"\n",
"top_probs = []\n",
"\n",
"for ix in range(len(top_k_indices)):\n",
" top_probs.append((words[ix], next_token_probs[top_k_indices[ix]].item()))\n",
"\n",
"top_probs"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Zalety tego podejścia:\n",
"\n",
"- prostota,\n",
"- dobra podstawa do strojenia systemów generowania tekstu zwłaszcza\n",
" „otwartego” (systemy dialogowe, generowanie (fake) newsów, streszczanie tekstu),\n",
" ale niekoniecznie tłumaczenia maszynowego,\n",
"- zaskakująca skuteczność przy uczeniu *few-shot* i *zero-shot*.\n",
"\n",
"Wady:\n",
"\n",
"- asymetryczność, przetwarzanie tylko z lewej do prawej, preferencja\n",
" dla lewego kontekstu,\n",
"- mniejsza skuteczność przy dostrajaniu do zadań klasyfikacji i innych zadań\n",
" niepolegających na prostym generowaniu.\n",
"\n",
"Przykłady modeli: GPT, GPT-2, GPT-3, DialoGPT.\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Maskowanie słów (BERT)\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Inną metodą jest maskowanie słów (*Masked Language Modeling*, *MLM*).\n",
"\n",
"W tym podejściu losowe wybrane zastępujemy losowe słowa specjalnym\n",
"tokenem (`[MASK]`) i każemy modelowi odgadywać w ten sposób\n",
"zamaskowane słowa (z uwzględnieniem również prawego kontekstu!).\n",
"\n",
"Móciąc ściśle, w jednym z pierwszych modeli tego typu (BERT)\n",
"zastosowano schemat, w którym również niezamaskowane słowa są odgadywane (!):\n",
"\n",
"- wybieramy losowe 15% wyrazów do odgadnięcia\n",
"- 80% z nich zastępujemy tokenem `[MASK]`,\n",
"- 10% zastępujemy innym losowym wyrazem,\n",
"- 10% pozostawiamy bez zmian.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"# Out[3]:"
]
}
],
"source": [
"from transformers import AutoModelWithLMHead, AutoTokenizer\n",
"import torch\n",
"\n",
"tokenizer = AutoTokenizer.from_pretrained(\"xlm-roberta-large\")\n",
"model = AutoModelWithLMHead.from_pretrained(\"xlm-roberta-large\")\n",
"\n",
"sequence = f'II wojna światowa zakończyła się w {tokenizer.mask_token} roku.'\n",
"\n",
"input_ids = tokenizer.encode(sequence, return_tensors=\"pt\")\n",
"mask_token_index = torch.where(input_ids == tokenizer.mask_token_id)[1]\n",
"\n",
"token_logits = model(input_ids)[0]\n",
"mask_token_logits = token_logits[0, mask_token_index, :]\n",
"mask_token_logits = torch.softmax(mask_token_logits, dim=1)\n",
"\n",
"top_10 = torch.topk(mask_token_logits, 10, dim=1)\n",
"top_10_tokens = zip(top_10.indices[0].tolist(), top_10.values[0].tolist())\n",
"\n",
"for token, score in top_10_tokens:\n",
" print(sequence.replace(tokenizer.mask_token, tokenizer.decode([token])), f\"(score: {score})\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Przykłady: BERT, RoBERTa (również Polish RoBERTa).\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Podejście generatywne (koder-dekoder).\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"System ma wygenerować odpowiedź na różne pytania (również\n",
"odpowiadające zadaniu MLM), np.:\n",
"\n",
"- \"translate English to German: That is good.\" => \"Das ist gut.\"\n",
"- \"cola sentence: The course is jumping well.\" => \"not acceptable\"\n",
"- \"summarize: state authorities dispatched emergency crews tuesday to survey the damage after an onslaught of severe weather in mississippi&#x2026;\"\n",
" => \"six people hospitalized after a storm in attala county\"\n",
"- \"Thank you for <X> me to your party <Y> week.\" => <X> for inviting <Y> last <Z>\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from transformers import T5Tokenizer, T5Config, T5ForConditionalGeneration\n",
"\n",
"T5_PATH = 't5-base'\n",
"\n",
"t5_tokenizer = T5Tokenizer.from_pretrained(T5_PATH)\n",
"t5_config = T5Config.from_pretrained(T5_PATH)\n",
"t5_mlm = T5ForConditionalGeneration.from_pretrained(T5_PATH, config=t5_config)\n",
"\n",
"slot = '<extra_id_0>'\n",
"\n",
"text = f'Warsaw is the {slot} of Poland.'\n",
"\n",
"encoded = t5_tokenizer.encode_plus(text, add_special_tokens=True, return_tensors='pt')\n",
"input_ids = encoded['input_ids']\n",
"\n",
"outputs = t5_mlm.generate(input_ids=input_ids,\n",
" num_beams=200, num_return_sequences=5,\n",
" max_length=5)\n",
"\n",
"_0_index = text.index(slot)\n",
"_result_prefix = text[:_0_index]\n",
"_result_suffix = text[_0_index+len(slot):]\n",
"\n",
"def _filter(output, end_token='<extra_id_1>'):\n",
" _txt = t5_tokenizer.decode(output[2:], skip_special_tokens=False, clean_up_tokenization_spaces=False)\n",
" if end_token in _txt:\n",
" _end_token_index = _txt.index(end_token)\n",
" return _result_prefix + _txt[:_end_token_index] + _result_suffix\n",
" else:\n",
" return _result_prefix + _txt + _result_suffix\n",
"\n",
"\n",
"results = [_filter(out) for out in outputs]\n",
"results"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"(Zob. [https://arxiv.org/pdf/1910.10683.pdf](https://arxiv.org/pdf/1910.10683.pdf))\n",
"\n",
"Przykład: T5, mT5\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
}

212
wyk/14_pretrenowanie.org Normal file
View File

@ -0,0 +1,212 @@
* Pretrenowanie modeli
System AlphaZero uczy się grając sam ze sobą — wystarczy 24 godziny,
by system nauczył się grać w szachy lub go na nadludzkim poziomie.
*Pytanie*: Dlaczego granie samemu ze sobą nie jest dobrym sposobem
nauczenia się grania w szachy dla człowieka, a dla maszyny jest?
Co jest odpowiednikiem grania samemu ze sobą w świecie przetwarzania tekstu?
Tzn. *pretrenowanie* (/pretraining/) na dużym korpusie tekstu. (Tekst jest tani!)
Jest kilka sposobów na pretrenowanie modelu, w każdym razie sprowadza
się do odgadywania następnego bądź zamaskowanego słowa.
W każdym razie zawsze stosujemy softmax (być może ze „sztuczkami” takimi jak
negatywne próbkowanie albo hierarchiczny softamx) na pewnej *representecji kontekstowej*:
$$\vec{p} = \operatorname{softmax}(f(\vec{c})).$$
Model jest karany używając funkcji log loss:
$$-\log(p_j),$$
gdzie $w_j$ jest wyrazem, który pojawił się rzeczywiście w korpusie.
** Przewidywanie słowa (GPT-2)
Jeden ze sposobów pretrenowania modelu to po prostu przewidywanie
następnego słowa.
Zainstalujmy najpierw bibliotekę transformers.
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
! pip install transformers
#+END_SRC
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
import torch
from transformers import GPT2Tokenizer, GPT2LMHeadModel
tokenizer = GPT2Tokenizer.from_pretrained('gpt2-large')
model = GPT2LMHeadModel.from_pretrained('gpt2-large')
text = "Warsaw is the capital city of"
encoded_input = tokenizer(text, return_tensors='pt')
output = model(**encoded_input)
next_token_probs = torch.softmax(output[0][:, -1, :][0], dim=0)
nb_of_tokens = next_token_probs.size()[0]
_, top_k_indices = torch.topk(next_token_probs, 30, sorted=True)
top_k_indices
# words = tokenizer.convert_ids_to_tokens(top)
# top_probs = []
# for ix in range(len(top)):
# top_probs.append((words[ix], next_token_probs[top[ix]].item()))
# top_probs
#+END_SRC
#+RESULTS:
:results:
# Out[8]:
#+BEGIN_EXAMPLE
[('Ġthe', 0.4415026307106018),
('ĠPoland', 0.236798495054245),
('ĠBelarus', 0.10114768147468567),
('ĠUkraine', 0.058283545076847076),
('Ġeastern', 0.020564062520861626),
('ĠEastern', 0.011137397028505802),
('ĠPolish', 0.010205904021859169),
('ĠWestern', 0.00833223108202219),
('Ġwestern', 0.006872199941426516),
('Ġa', 0.004939113277941942),
('ĠSlovakia', 0.003553805174306035),
('ĠLithuania', 0.003335304092615843),
('ĠRussia', 0.002872465644031763),
('Ġcentral', 0.002493523992598057),
('Ġmodern', 0.0022767107002437115),
('ĠCzech', 0.0022264323197305202),
('ĠPr', 0.002146221464499831),
('Ġformer', 0.0021054286044090986),
('Ġwhat', 0.0017435317859053612),
('ĠSlov', 0.0014634730760008097),
('ĠUkrainian', 0.0014347084797918797),
('ĠCentral', 0.0013676199596375227),
('ĠSouth', 0.0013484350638464093),
('Ġone', 0.001204205909743905),
('ĠNorthern', 0.0011802552035078406),
('ĠWest', 0.001175572513602674),
('ĠEast', 0.0011596156982704997),
('Ġsouthern', 0.0011580033460631967),
('Ġnorthern', 0.001110077602788806),
('Ġ"', 0.0010494199814274907)]
#+END_EXAMPLE
:end:
Zalety tego podejścia:
- prostota,
- dobra podstawa do strojenia systemów generowania tekstu zwłaszcza
„otwartego” (systemy dialogowe, generowanie (fake) newsów, streszczanie tekstu),
ale niekoniecznie tłumaczenia maszynowego,
- zaskakująca skuteczność przy uczeniu /few-shot/ i /zero-shot/.
Wady:
- asymetryczność, przetwarzanie tylko z lewej do prawej, preferencja
dla lewego kontekstu,
- mniejsza skuteczność przy dostrajaniu do zadań klasyfikacji i innych zadań
niepolegających na prostym generowaniu.
Przykłady modeli: GPT, GPT-2, GPT-3, DialoGPT.
** Maskowanie słów (BERT)
Inną metodą jest maskowanie słów (/Masked Language Modeling/, /MLM/).
W tym podejściu losowe wybrane zastępujemy losowe słowa specjalnym
tokenem (~[MASK]~) i każemy modelowi odgadywać w ten sposób
zamaskowane słowa (z uwzględnieniem również prawego kontekstu!).
Móciąc ściśle, w jednym z pierwszych modeli tego typu (BERT)
zastosowano schemat, w którym również niezamaskowane słowa są odgadywane (!):
- wybieramy losowe 15% wyrazów do odgadnięcia
- 80% z nich zastępujemy tokenem ~[MASK]~,
- 10% zastępujemy innym losowym wyrazem,
- 10% pozostawiamy bez zmian.
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
from transformers import AutoModelWithLMHead, AutoTokenizer
import torch
tokenizer = AutoTokenizer.from_pretrained("xlm-roberta-large")
model = AutoModelWithLMHead.from_pretrained("xlm-roberta-large")
sequence = f'II wojna światowa zakończyła się w {tokenizer.mask_token} roku.'
input_ids = tokenizer.encode(sequence, return_tensors="pt")
mask_token_index = torch.where(input_ids == tokenizer.mask_token_id)[1]
token_logits = model(input_ids)[0]
mask_token_logits = token_logits[0, mask_token_index, :]
mask_token_logits = torch.softmax(mask_token_logits, dim=1)
top_10 = torch.topk(mask_token_logits, 10, dim=1)
top_10_tokens = zip(top_10.indices[0].tolist(), top_10.values[0].tolist())
for token, score in top_10_tokens:
print(sequence.replace(tokenizer.mask_token, tokenizer.decode([token])), f"(score: {score})")
#+END_SRC
#+RESULTS:
:results:
# Out[3]:
:end:
Przykłady: BERT, RoBERTa (również Polish RoBERTa).
** Podejście generatywne (koder-dekoder).
System ma wygenerować odpowiedź na różne pytania (również
odpowiadające zadaniu MLM), np.:
- "translate English to German: That is good." => "Das ist gut."
- "cola sentence: The course is jumping well." => "not acceptable"
- "summarize: state authorities dispatched emergency crews tuesday to survey the damage after an onslaught of severe weather in mississippi..."
=> "six people hospitalized after a storm in attala county"
- "Thank you for <X> me to your party <Y> week." => <X> for inviting <Y> last <Z>
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
from transformers import T5Tokenizer, T5Config, T5ForConditionalGeneration
T5_PATH = 't5-base'
t5_tokenizer = T5Tokenizer.from_pretrained(T5_PATH)
t5_config = T5Config.from_pretrained(T5_PATH)
t5_mlm = T5ForConditionalGeneration.from_pretrained(T5_PATH, config=t5_config)
slot = '<extra_id_0>'
text = f'Warsaw is the {slot} of Poland.'
encoded = t5_tokenizer.encode_plus(text, add_special_tokens=True, return_tensors='pt')
input_ids = encoded['input_ids']
outputs = t5_mlm.generate(input_ids=input_ids,
num_beams=200, num_return_sequences=5,
max_length=5)
_0_index = text.index(slot)
_result_prefix = text[:_0_index]
_result_suffix = text[_0_index+len(slot):]
def _filter(output, end_token='<extra_id_1>'):
_txt = t5_tokenizer.decode(output[2:], skip_special_tokens=False, clean_up_tokenization_spaces=False)
if end_token in _txt:
_end_token_index = _txt.index(end_token)
return _result_prefix + _txt[:_end_token_index] + _result_suffix
else:
return _result_prefix + _txt + _result_suffix
results = [_filter(out) for out in outputs]
results
#+END_SRC
(Zob. https://arxiv.org/pdf/1910.10683.pdf)
Przykład: T5, mT5

BIN
wyk/bpe.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

1
wyk/ie-gener.drawio Normal file
View File

@ -0,0 +1 @@
<mxfile host="app.diagrams.net" modified="2021-06-09T07:54:35.721Z" agent="5.0 (X11)" etag="NciLNBJF1axAiSJ0r0sv" version="14.7.3" type="device"><diagram id="HvCQlNLg7fWOxGx64C6g" name="Page-1">3Vjbbts4EP0aAe2DF9bNiR9jO9lisVekQLF9Y8SxRJsSVYqKrHz9Di+SJctF0m6TtvGDRB2RM+QcnhnKXrjOD79KUmZ/CArcC+b04IUbLwiWkY9XDbQWiMPQAqlk1EL+EbhlD+DAuUNrRqEadVRCcMXKMZiIooBEjTAipWjG3baCj72WJIUJcJsQPkU/MKoyi14GF0f8HbA06zz7i6V9k5Ous1tJlREqmgEUXnvhWgqhbCs/rIHr2HVxseNuPvO2n5iEQj1lgPgrjt7/+du/G76THw8f5Wyxv545K/eE127BXrDgaG+V4atFqlsdUpWk0OtQrQvO4lOtJ7+6I8k+laIu6CwRXEgvvMJ+Mr17E8Sxp6e1xutJ++1xfOfoHRDKirTzh0uxLsfTQHg6t/LFJ/u7kJDr8JZVre/UGEOPTOmtl4Oyo3FjVrgxQdX6LS6wZBVLzDLnwJnrVQE1NjTI6ioX+lFBXhqbrEgYZbQutOlaXzi5Q/+6t+p8g9l0aUG0G84+1eSXxyM5iFswCleg4GC2gco5Aj42t4zztQ3ZphAF2CibpYSb+Pj0XpQIzDB84arJmIJbxLXVBjMEYuIe5JYbKWSMUigQM4SA3ql6VKWk2EPnywvCufn100QDOL3P6sDv1YVZCQRSIVvs0g24dIJ0GclfuufmqO8gclg20rYDicspaW/7KDtsOOV9gQqDiQoV7CvNbAM7bx17y1XCRNM+gaRx6BxNZ5jDHZJi4DcJRg0QX+mYMsx7V+5FjtRoN2cpHNP1LUjxHyflHCfBc1ESnkmMJ8HHhF7q5pbD4UqXGgwFFNQ1NwknFSp9TI81AnRSdB4N1CAQ8ZlAdJgEThS7H5s/Fx3n4W/BTFZxPERRPOIBpTc2UYlaJuBGDavNiaHYf8SQIjIFNTFkyOqX/fX8RRP+tKIk2Sc7nSBNlnwgFaEPDEymtymRdfkQiZwpMcPbIFuyL8iWP6kQo8WJEC++sxCXEyK7SquLXV19XeH6llF/1moVh2M++kAP+Fi+JB9doh4Q0rR9kYJOLXey08qbprXSy0RDCjDHma2QOUl28Pb1Cik+PWYspsT1Ve9lmDtX0yxblN13dP1Tm7MnVP3B0gtvpqwOsuJg8P8TI4et+oGlODk4Rk88OD4fo9MqV7aKFFqGN6DaPQNFXq/E/PkJIeF3rlXdmWeUGwfJrzUfdfZkb0ia53XF9A0f1pF3eWE84PLb5KHAoz9GQ1QKv6rsV+KO7PXqrJVByn2tBMfLk+J3+Xw5FB+P/8XYU+jxD63w+j8=</diagram></mxfile>

BIN
wyk/ie-gener.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

1
wyk/ie-seqlab.drawio Normal file
View File

@ -0,0 +1 @@
<mxfile host="app.diagrams.net" modified="2021-06-09T07:51:04.277Z" agent="5.0 (X11)" etag="tdTX7mJTGI1dKBKJk9w0" version="14.7.3" type="device"><diagram id="HvCQlNLg7fWOxGx64C6g" name="Page-1">7Vhtk5MwEP41zOiHOhQKd/14bc+3Uet4zjj6LSVbyDUQDOEo/no3EEp5uempd+qc9kMbHpLd7PNkl6WWu4z3LyRJo7eCArccm+4td2U5znw2xW8NlDXguW4NhJLRGpq2wBX7Bga0DZozCllnohKCK5Z2wUAkCQSqgxEpRdGdthW86zUlIQyAq4DwIfqJURXV6Llz1uIvgYVR43nqz+s7MWkmm0iyiFBRHEHupeUupRCqHsX7JXDNXcNLve75LXcPG5OQqLssEGtv9vHd688rfi2/7L/Iib+7nBgrN4TnJmDL8TnaW0R4yw/1qEGylCQ6DlUacvyvud78YkOCXShFntBJILiQlnuB82S4eeJ4nqW3tcTv3vhpu75x9BIIZUnY+MNQapfdbSA83Fv62zf7RkiINb1plutfWhlDj0zpoxeDqlfjwczwYILK9V0MMGUZC6owbeDMzMqAVjY0yPIsFvpSQZxWNlkSMMponmjTuf7iZIP+9WzV+Ibq0IUJ0W44+5qTZ6eZPOLN6dDlKNhXx0DFHIEpDreM82VN2SoRCdQsV6G4K6+9+ihSBCZIn7soIqbgCnFttcAKgZi4AbnlVSpEjFJIEKsEAX1S9apMSbGDxpfluHb1OWwTDeD2bs2D6SG7sCqBQClkiVOaBecmIU1Fmvrmumjz25kZLOrktgGJqSnhwXabdjgwmfcDWegMslDBLtPKFnBtLT1rvgiYKMo7iNSlzsg0ohyekBCJXwXIGiC+0JwyrHsX5kaM0mg3oxJ25boPUaY9Uc6Gooxp4jyUJO5IYeyRjwU91cMth/2FftQgFZBQM1wFnGSY6V15aiNABw+dk0QdEeGNENFgEjhR7KZrfowd4+G9YFVVMTrMvK4OA4IzkcsAzKrjp03PkOecMKSIDEENDFViHcL+ef1mA/1AlTsGShQkYfB4M2nm/2WZ5P1vMR5Bi/EAQXvTkZj7rcwtOvU7nI3sq7MVVSjbOttaR0ssYAx0yO+gGPrHXxLrxEw2WTp6ba9Pz7nLmtswezFZrd+sP+Do1WG0PmKijqwb7TD+/z3fUVH0vDv0fP5Yzzd7qLLo/5sNxrl7Tw3G3P6zDcbZQL9Uikzp0lWUVGzKQHcZdtXI54+33Tif/WXtxnygS/+R8jNF7z5Zf9BKN+/nl+0N9Jj/Tj2aF7sjQYry8FILwwfYk6LUOSNJpFt1qHqTrZAxCa7h6eNNpPnZ6UfU4S35F5XDy/Z/x7ogtn/eupffAQ==</diagram></mxfile>

BIN
wyk/ie-seqlab.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

1
wyk/rnn-seq.drawio Normal file
View File

@ -0,0 +1 @@
<mxfile host="app.diagrams.net" modified="2021-06-01T16:04:31.943Z" agent="5.0 (X11)" etag="_GtJ7cj7F7SQ6oQHAF32" version="14.6.13" type="device"><diagram id="Q_5Aon-lI3fA6Ftl2Xdk" name="Page-1">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</diagram></mxfile>

BIN
wyk/rnn-seq.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

1
wyk/rnn.drawio Normal file
View File

@ -0,0 +1 @@
<mxfile host="app.diagrams.net" modified="2021-06-01T15:52:54.501Z" agent="5.0 (X11)" etag="o_4DnBy9wLtBbjAQzQYJ" version="14.6.13" type="device"><diagram id="Q_5Aon-lI3fA6Ftl2Xdk" name="Page-1">5Vltj5s4EP41SO2HXcUYwuZjQ3J3H1pdpb3TtffNBRfcAI6M88L++hsH8w45qk2W7FbarDyPX7Bn5pkZjIHd+Pi7INvwE/dpZJgz/2jglWGaCwvBfwVkOYDmjpkjgWC+xirgkT1RDc40umM+TRsDJeeRZNsm6PEkoZ5sYEQIfmgO+86j5lO3JKAd4NEjURf9h/kyzNEH06nwPygLwuLJaL7Ie2JSDNZLpCHx+SGHTofDawO7gnOZt+KjSyOlvEIvuQZ+G+gtNyZoIsdM+Fu6u39ttrGyB2edrZxPf338cadX2ZNopw+sNyuzQgOC7xKfqkVmBl4eQibp45Z4qvcANgcslHEEEoKmXo4KSY+D+0Tl6cFtKI+pFBkM0ROwpU1fuAzW8qHSP9JnnYV13TsaJNrmQbl2pRZoaM38hJbmHaVQH7xEi1zIkAc8IdG6QpdNtVVjPnK+1cr6QaXMtMuTneRNVdIjk1/U9HtbS1/1Yqq9OtaFrBASOG5tkhK/FuspoZp2kop5+fnUoc4bDXTAd8KjZ3SlHUgSEVB5ZhzudwJBIyLZvrmPixvU7HF7C/6kYa83ebNjcvBo2bRQKgXfUJdHXACS8ETZ/TuLohZEIhYkIHqgTAr4UvGDQYz5oDti5vsnp+ljV9ORLkGwhybB8KJLMKuHX/ha9LJfC70uSBM8kiZoPiVPcIcnNP5GfZ8lAcCG7b6D3556hrPcG87q3Yk/7wF7fyaNoJdJIwjdm3bT0a2eTOI49/YL+nqRuKZxdlR39dLx/y+X1DNJLbFcP5c4r4IkzkAySYEMQIwNFFnO6q0nlaL6LLhmWvaopGJei2jIPmOWN5/jbXxj5ig5f/NJ/gZqaDQfG/icKQNfsc0axQ5EpPJADHMeKSJ9E9AKVCtiCeOqY+qywG7WBGZPTbB4yeIXLV4fMSYrCNDoisCekhgmfn02nS7YjbVpfjc1WbAbKvPgbSdlQUwGSorJA9xsXIC7Xubv6uRGyXBBp362r+qpnzmDR5fGtWatu9FZy2o5ifSsluHKbTzDlkMXZ3/eqPejken9et4/9BqS/QqvIe2rRmfcTePVrIFHfO/wdmJfeixN/A/qK5JSaUTSlHnPDzM+ScPyAUr4TCQYKzkh5gxdOL0OVEI1E9g9JiiwZwYsu/Uxp2PafP+dgNVZyGwvZI2LfGA9ktWGbdWA9MyGF/0bHtqX3YrId/b58e1z3KHGeGjkO75o2MbdsJ1uxZPhWsZiYbi2sXRpwiiMeIJfQlKZd22TLAZgA7GHUdXynkjKDwp8sxEL99uncWd8oZgFYvX5N7d19REdr/8D</diagram></mxfile>

BIN
wyk/rnn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
wyk/word-distribution.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB