08
This commit is contained in:
parent
f4b2dead07
commit
2d43e1e66e
159
cw/08_Model_neuronowy_typu_word2vec.ipynb
Normal file
159
cw/08_Model_neuronowy_typu_word2vec.ipynb
Normal file
@ -0,0 +1,159 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n",
|
||||
"<div class=\"alert alert-block alert-info\">\n",
|
||||
"<h1> Modelowanie Języka</h1>\n",
|
||||
"<h2> 8. <i>Model neuronowy typu word2vec</i> [ćwiczenia]</h2> \n",
|
||||
"<h3> Jakub Pokrywka (2022)</h3>\n",
|
||||
"</div>\n",
|
||||
"\n",
|
||||
"![Logo 2](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech2.jpg)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Zadania"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Proszę wykonać zadanie 1 lub zadanie 2 (nie oba naraz). Zadanie 3 można zrobić niezależnie."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Zadanie 1\n",
|
||||
"\n",
|
||||
"Wzorując się na materiałach z wykładu stworzyć 5-gramowy model neuronowy oparty na jednym ze schematów z wykładu, np.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"![img](bow1.drawio.png \"Model typu worek słów\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Warunkiem koniecznym jest, żeby przewidywać słowo środkowe, np. Mając tekst ['Ala', 'ma', '[MASK]'\n",
|
||||
" 'i', 'psa'] chcemy przewidzieć kontekst środkowego słowa (tutaj '[MASK]')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Warunki zaliczenia:\n",
|
||||
"- wynik widoczny na platformie zarówno dla dev i dla test\n",
|
||||
"- wynik dla dev i test lepszy (niższy) niż 6.50 (liczone przy pomocy geval)\n",
|
||||
"- deadline do końca dnia 08.05\n",
|
||||
"- commitując rozwiązanie proszę również umieścić rozwiązanie w pliku /run.py (czyli na szczycie katalogu). Można przekonwertować jupyter do pliku python przez File → Download as → Python. Rozwiązanie nie musi być w pythonie, może być w innym języku.\n",
|
||||
"- zadania wykonujemy samodzielnie\n",
|
||||
"- w nazwie commita podaj nr indeksu\n",
|
||||
"- w tagach podaj **neural-network** oraz **5gram**!\n",
|
||||
"- zadanie tym razem jest dla polskiego odpowiednika word-gap https://gonito.net/challenge-my-submissions/retro-gap\n",
|
||||
"- metryka to LogLossHashed (praktycznie to samo, co PerlpexityHased). Przelicznik, to LogLossHased = log(PerplexityHashed). Podając równe prawd. dla każdego słowa dostaniemy 6.93, bo log(1024) = 6.93\n",
|
||||
"\n",
|
||||
"Punktacja:\n",
|
||||
"- podstawa: 60 punktów\n",
|
||||
"- 40 punktów z najlepszy wynik z 2 grup\n",
|
||||
"- 20 punktów z 3 kolejno najlepszych wyników z 2 grup\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Jak stworzyć model?\n",
|
||||
"- warto bazować na kodzie ze wykładu 7 Zanurzenia słów\n",
|
||||
"- elementy, które na pewno trzeba będzie wykorzystać to: nn.Embedding, nn.Linear, nn.Softmax\n",
|
||||
"- w odróżnieniu do materiałów z wykładu lepiej nie korzystać z nn.Sequential, tylko wszystki operacje zapisywać w model.forward. Przy użyciu sequential może być problem np. z dodawaniem lub konkatenacją tensorów"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### W jaki sposób uzyskać lepszy wynik?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"- Po pierwsze proszę stosować sie do rad z poprzednich cwiczeń (trenowanie przez kilka epok i monitorowanie wyniku na zbiorze deweloperskim)\n",
|
||||
"- dobry start to zawsze zaczęcie od jak najprostszego modelu (czyli 1 warstwa liniowa, zwykłe dodawanie embeddingów słów) i dopiero później go rozbudowywać monitorując wynik. Jest to rada uniwersalna w uczeniu maszynowym.\n",
|
||||
"- Poza tym warto wypróbować przynajmniej kilka modeli z wykładu. Mając zaimplementowany cały kod dla jednego modelu, wystarczy jedynie delikatnie zmienić architekturę modelu i wytrenować go od nowa. Cała reszta kodu zostaje bez zmian.\n",
|
||||
"- warto spróbować dodanie np 2 warstw liniowych (lub nawet 3) zamiast jednej warstwy (koniecznie trzeba dodać między nimi funkcję aktywacji, np RELU).\n",
|
||||
"- poza tym można zmieniać różne parametry (np. wielkość słownika, wielkość warstwy ukrytej, różne funkcje aktywacji)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Zadanie 2\n",
|
||||
"\n",
|
||||
"Proszę zrobić parameter Hyperparameter Tuning dla zadania 1 i zaprezentować na forum grupy razem z wnioskami\n",
|
||||
"\n",
|
||||
"- wymóg wyniku najlepszego modelu, conajwyżej 6.10\n",
|
||||
"- wnioski nie muszą być specjalnie rozbudowane, prezentacja może trwać 3-5minut lub dłużej\n",
|
||||
"- należy wybrać dla siebie metodę hypermarameter tuningu\n",
|
||||
"- należy stworzyć conajmniej 10 modeli, należy pokazać wyniku dla conajmniej paru\n",
|
||||
"- oczywiście kod musi być automatyczny (a nie ręcznie zmieniamy paratery), natomiast nie ma wymogu korzystania ze specjalnych bibliotek\n",
|
||||
"- podstawa punktów 100\n",
|
||||
"- za wynik lepszy (niższy) niż 5.50 +20 punktów\n",
|
||||
"- użycie GPU na dowolnym cloud lub od WMI + 30 punktów\n",
|
||||
"- termin 16.05 na zajęciach\n",
|
||||
"- punkty przyznam na MS TEAMS, ale proszę zgłosić te rozwiązanie na gonito (nie trzeba w żadnym challenge ani z konkretymi tagami)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Zadanie 3\n",
|
||||
"\n",
|
||||
"Zaangażowanie się w pygonito.\n",
|
||||
"\n",
|
||||
"- https://github.com/filipggg/pygonito\n",
|
||||
"- dobra okazja, żeby nauczyć się tworzyć paczki pythonowe\n",
|
||||
"- wsparcie ode mnie lub prof. Gralińskiego przy tworzeniu\n",
|
||||
"- może się przydać przy pracy magisterskiej (jeżeli wyzwanie będzie na gonito)\n",
|
||||
"- ilość punktów zależy od zakresu pracy. Sczególnie warto samemu zaproponować co zrobić) Zakres prac i punktów do dogdania\n",
|
||||
"- w celu ustalenia szczegółów proszę sie zgłosić do mnie\n",
|
||||
"- termin dowolny"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"author": "Jakub Pokrywka",
|
||||
"email": "kubapok@wmi.amu.edu.pl",
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"lang": "pl",
|
||||
"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.7"
|
||||
},
|
||||
"subtitle": "0.Informacje na temat przedmiotu[ćwiczenia]",
|
||||
"title": "Ekstrakcja informacji",
|
||||
"year": "2021"
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
992
wyk/07_Zanurzenia_slow.ipynb
Normal file
992
wyk/07_Zanurzenia_slow.ipynb
Normal file
@ -0,0 +1,992 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n",
|
||||
"<div class=\"alert alert-block alert-info\">\n",
|
||||
"<h1> Modelowanie języka</h1>\n",
|
||||
"<h2> 7. <i>Zanurzenia słów</i> [wykład]</h2> \n",
|
||||
"<h3> Filip Graliński (2022)</h3>\n",
|
||||
"</div>\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": [
|
||||
"## Zanurzenia słów\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"W praktyce stosowalność słowosieci okazała się zaskakująco\n",
|
||||
"ograniczona. Większy przełom w przetwarzaniu języka naturalnego przyniosły\n",
|
||||
"wielowymiarowe reprezentacje słów, inaczej: zanurzenia słów.\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### „Wymiary” słów\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Moglibyśmy zanurzyć (ang. *embed*) w wielowymiarowej przestrzeni, tzn. zdefiniować odwzorowanie\n",
|
||||
"$E \\colon V \\rightarrow \\mathcal{R}^m$ dla pewnego $m$ i określić taki sposób estymowania\n",
|
||||
"prawdopodobieństw $P(u|v)$, by dla par $E(v)$ i $E(v')$ oraz $E(u)$ i $E(u')$ znajdujących się w pobliżu\n",
|
||||
"(według jakiejś metryki odległości, na przykład zwykłej odległości euklidesowej):\n",
|
||||
"\n",
|
||||
"$$P(u|v) \\approx P(u'|v').$$\n",
|
||||
"\n",
|
||||
"$E(u)$ nazywamy zanurzeniem (embeddingiem) słowa.\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Wymiary określone z góry?\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Można by sobie wyobrazić, że $m$ wymiarów mogłoby być z góry\n",
|
||||
"określonych przez lingwistę. Wymiary te byłyby związane z typowymi\n",
|
||||
"„osiami” rozpatrywanymi w językoznawstwie, na przykład:\n",
|
||||
"\n",
|
||||
"- czy słowo jest wulgarne, pospolite, potoczne, neutralne czy książkowe?\n",
|
||||
"- czy słowo jest archaiczne, wychodzące z użycia czy jest neologizmem?\n",
|
||||
"- czy słowo dotyczy kobiet, czy mężczyzn (w sensie rodzaju gramatycznego i/lub\n",
|
||||
" socjolingwistycznym)?\n",
|
||||
"- czy słowo jest w liczbie pojedynczej czy mnogiej?\n",
|
||||
"- czy słowo jest rzeczownikiem czy czasownikiem?\n",
|
||||
"- czy słowo jest rdzennym słowem czy zapożyczeniem?\n",
|
||||
"- czy słowo jest nazwą czy słowem pospolitym?\n",
|
||||
"- czy słowo opisuje konkretną rzecz czy pojęcie abstrakcyjne?\n",
|
||||
"- …\n",
|
||||
"\n",
|
||||
"W praktyce okazało się jednak, że lepiej, żeby komputer uczył się sam\n",
|
||||
"możliwych wymiarów — z góry określamy tylko $m$ (liczbę wymiarów).\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Bigramowy model języka oparty na zanurzeniach\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Zbudujemy teraz najprostszy model język oparty na zanurzeniach. Będzie to właściwie najprostszy\n",
|
||||
"**neuronowy model języka**, jako że zbudowany model można traktować jako prostą sieć neuronową.\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Słownik\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"W typowym neuronowym modelu języka rozmiar słownika musi być z góry\n",
|
||||
"ograniczony. Zazwyczaj jest to liczba rzędu kilkudziesięciu wyrazów —\n",
|
||||
"po prostu będziemy rozpatrywać $|V|$ najczęstszych wyrazów, pozostałe zamienimy\n",
|
||||
"na specjalny token `<unk>` reprezentujący nieznany (*unknown*) wyraz.\n",
|
||||
"\n",
|
||||
"Aby utworzyć taki słownik użyjemy gotowej klasy `Vocab` z pakietu torchtext:\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"/media/kuba/ssdsam/anaconda3/envs/lmzajecia/lib/python3.10/site-packages/torch/_masked/__init__.py:223: UserWarning: Failed to initialize NumPy: No module named 'numpy' (Triggered internally at /opt/conda/conda-bld/pytorch_1646755897462/work/torch/csrc/utils/tensor_numpy.cpp:68.)\n",
|
||||
" example_input = torch.tensor([[-3, -2, -1], [0, 1, 2]])\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"16"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from itertools import islice\n",
|
||||
"import regex as re\n",
|
||||
"import sys\n",
|
||||
"from torchtext.vocab import build_vocab_from_iterator\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def get_words_from_line(line):\n",
|
||||
" line = line.rstrip()\n",
|
||||
" yield '<s>'\n",
|
||||
" for m in re.finditer(r'[\\p{L}0-9\\*]+|\\p{P}+', line):\n",
|
||||
" yield m.group(0).lower()\n",
|
||||
" yield '</s>'\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def get_word_lines_from_file(file_name):\n",
|
||||
" with open(file_name, 'r') as fh:\n",
|
||||
" for line in fh:\n",
|
||||
" yield get_words_from_line(line)\n",
|
||||
"\n",
|
||||
"vocab_size = 20000\n",
|
||||
"\n",
|
||||
"vocab = build_vocab_from_iterator(\n",
|
||||
" get_word_lines_from_file('opensubtitlesA.pl.txt'),\n",
|
||||
" max_tokens = vocab_size,\n",
|
||||
" specials = ['<unk>'])\n",
|
||||
"\n",
|
||||
"vocab['jest']"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"['<unk>', '</s>', '<s>', 'w', 'policyjny']"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"vocab.lookup_tokens([0, 1, 2, 10, 12345])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Definicja sieci\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Naszą prostą sieć neuronową zaimplementujemy używając frameworku PyTorch.\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "NameError",
|
||||
"evalue": "name 'out' is not defined",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
|
||||
"Input \u001b[0;32mIn [4]\u001b[0m, in \u001b[0;36m<cell line: 22>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 20\u001b[0m vocab\u001b[38;5;241m.\u001b[39mset_default_index(vocab[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m<unk>\u001b[39m\u001b[38;5;124m'\u001b[39m])\n\u001b[1;32m 21\u001b[0m ixs \u001b[38;5;241m=\u001b[39m torch\u001b[38;5;241m.\u001b[39mtensor(vocab\u001b[38;5;241m.\u001b[39mforward([\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mpies\u001b[39m\u001b[38;5;124m'\u001b[39m]))\n\u001b[0;32m---> 22\u001b[0m \u001b[43mout\u001b[49m[\u001b[38;5;241m0\u001b[39m][vocab[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mjest\u001b[39m\u001b[38;5;124m'\u001b[39m]]\n",
|
||||
"\u001b[0;31mNameError\u001b[0m: name 'out' is not defined"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from torch import nn\n",
|
||||
"import torch\n",
|
||||
"\n",
|
||||
"embed_size = 100\n",
|
||||
"\n",
|
||||
"class SimpleBigramNeuralLanguageModel(nn.Module):\n",
|
||||
" def __init__(self, vocabulary_size, embedding_size):\n",
|
||||
" super(SimpleBigramNeuralLanguageModel, self).__init__()\n",
|
||||
" self.model = nn.Sequential(\n",
|
||||
" nn.Embedding(vocabulary_size, embedding_size),\n",
|
||||
" nn.Linear(embedding_size, vocabulary_size),\n",
|
||||
" nn.Softmax()\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" def forward(self, x):\n",
|
||||
" return self.model(x)\n",
|
||||
"\n",
|
||||
"model = SimpleBigramNeuralLanguageModel(vocab_size, embed_size)\n",
|
||||
"\n",
|
||||
"vocab.set_default_index(vocab['<unk>'])\n",
|
||||
"ixs = torch.tensor(vocab.forward(['pies']))\n",
|
||||
"out[0][vocab['jest']]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Teraz wyuczmy model. Wpierw tylko potasujmy nasz plik:\n",
|
||||
"\n",
|
||||
" shuf < opensubtitlesA.pl.txt > opensubtitlesA.pl.shuf.txt\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!shuf < opensubtitlesA.pl.txt > opensubtitlesA.pl.shuf.txt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from torch.utils.data import IterableDataset\n",
|
||||
"import itertools\n",
|
||||
"\n",
|
||||
"def look_ahead_iterator(gen):\n",
|
||||
" prev = None\n",
|
||||
" for item in gen:\n",
|
||||
" if prev is not None:\n",
|
||||
" yield (prev, item)\n",
|
||||
" prev = item\n",
|
||||
"\n",
|
||||
"class Bigrams(IterableDataset):\n",
|
||||
" def __init__(self, text_file, vocabulary_size):\n",
|
||||
" self.vocab = build_vocab_from_iterator(\n",
|
||||
" get_word_lines_from_file(text_file),\n",
|
||||
" max_tokens = vocabulary_size,\n",
|
||||
" specials = ['<unk>'])\n",
|
||||
" self.vocab.set_default_index(self.vocab['<unk>'])\n",
|
||||
" self.vocabulary_size = vocabulary_size\n",
|
||||
" self.text_file = text_file\n",
|
||||
"\n",
|
||||
" def __iter__(self):\n",
|
||||
" return look_ahead_iterator(\n",
|
||||
" (self.vocab[t] for t in itertools.chain.from_iterable(get_word_lines_from_file(self.text_file))))\n",
|
||||
"\n",
|
||||
"train_dataset = Bigrams('opensubtitlesA.pl.shuf.txt', vocab_size)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"(2, 72)"
|
||||
]
|
||||
},
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from torch.utils.data import DataLoader\n",
|
||||
"\n",
|
||||
"next(iter(train_dataset))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[tensor([ 2, 72, 615, 11, 92]), tensor([ 72, 615, 11, 92, 4])]"
|
||||
]
|
||||
},
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from torch.utils.data import DataLoader\n",
|
||||
"\n",
|
||||
"next(iter(DataLoader(train_dataset, batch_size=5)))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"/media/kuba/ssdsam/anaconda3/envs/lmzajecia/lib/python3.10/site-packages/torch/nn/modules/container.py:141: UserWarning: Implicit dimension choice for softmax has been deprecated. Change the call to include dim=X as an argument.\n",
|
||||
" input = module(input)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"0 tensor(10.2158, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"100 tensor(6.9743, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"200 tensor(6.2186, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"300 tensor(5.6430, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"400 tensor(5.3539, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"500 tensor(5.0689, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"600 tensor(4.9418, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"700 tensor(4.8142, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"800 tensor(4.6436, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"900 tensor(4.6770, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"1000 tensor(4.6069, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"1100 tensor(4.5514, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"1200 tensor(4.5288, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"1300 tensor(4.4578, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"1400 tensor(4.5290, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"1500 tensor(4.5229, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"1600 tensor(4.4973, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"1700 tensor(4.3793, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"1800 tensor(4.5056, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"1900 tensor(4.3709, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"2000 tensor(4.3841, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"2100 tensor(4.4515, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"2200 tensor(4.3367, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"2300 tensor(4.4187, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"2400 tensor(4.3672, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"2500 tensor(4.3117, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"2600 tensor(4.2908, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"2700 tensor(4.3188, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"2800 tensor(4.2870, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"2900 tensor(4.2855, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"3000 tensor(4.2927, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"3100 tensor(4.3358, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"3200 tensor(4.2719, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"3300 tensor(4.2606, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"3400 tensor(4.2953, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"3500 tensor(4.3175, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"3600 tensor(4.2448, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"3700 tensor(4.2430, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"3800 tensor(4.2586, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"3900 tensor(4.2905, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"4000 tensor(4.2455, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"4100 tensor(4.2214, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"4200 tensor(4.2325, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"4300 tensor(4.3036, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"4400 tensor(4.2335, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"4500 tensor(4.2377, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"4600 tensor(4.2109, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"4700 tensor(4.2942, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"4800 tensor(4.2234, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"4900 tensor(4.1918, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"5000 tensor(4.3084, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"5100 tensor(4.1666, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"5200 tensor(4.2307, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"5300 tensor(4.2050, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"5400 tensor(4.1853, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"5500 tensor(4.1917, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"5600 tensor(4.1453, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"5700 tensor(4.2423, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"5800 tensor(4.1972, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"5900 tensor(4.2143, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"6000 tensor(4.2172, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"6100 tensor(4.2463, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"6200 tensor(4.1756, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"6300 tensor(4.1223, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"6400 tensor(4.1852, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"6500 tensor(4.1559, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"6600 tensor(4.1833, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"6700 tensor(4.2090, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"6800 tensor(4.1896, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"6900 tensor(4.2057, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"7000 tensor(4.1523, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"7100 tensor(4.2645, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"7200 tensor(4.1974, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"7300 tensor(4.2031, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"7400 tensor(4.1613, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"7500 tensor(4.2018, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"7600 tensor(4.2197, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"7700 tensor(4.1976, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"7800 tensor(4.1650, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"7900 tensor(4.1380, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"8000 tensor(4.1014, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"8100 tensor(4.2058, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"8200 tensor(4.1514, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"8300 tensor(4.1187, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"8400 tensor(4.2438, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"8500 tensor(4.2094, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"8600 tensor(4.2077, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"8700 tensor(4.0819, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"8800 tensor(4.1766, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"8900 tensor(4.1805, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"9000 tensor(4.1847, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"9100 tensor(4.1929, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"9200 tensor(4.1434, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"9300 tensor(4.1678, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"9400 tensor(4.1699, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"9500 tensor(4.0885, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"9600 tensor(4.1544, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"9700 tensor(4.1828, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"9800 tensor(4.1314, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"9900 tensor(4.1473, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"10000 tensor(4.0948, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"10100 tensor(4.1396, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"10200 tensor(4.1999, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"10300 tensor(4.1027, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"10400 tensor(4.2049, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"10500 tensor(4.1470, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"10600 tensor(4.0974, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"10700 tensor(4.1239, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"10800 tensor(4.1381, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"10900 tensor(4.0569, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"11000 tensor(4.1138, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"11100 tensor(4.2053, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"11200 tensor(4.1404, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"11300 tensor(4.0741, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"11400 tensor(4.0090, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"11500 tensor(4.1568, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"11600 tensor(4.1498, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"11700 tensor(4.1052, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"11800 tensor(4.0600, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"11900 tensor(4.1274, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"12000 tensor(4.1346, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"12100 tensor(4.1024, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"12200 tensor(4.0966, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"12300 tensor(4.1036, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"12400 tensor(4.0127, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"12500 tensor(4.0575, device='cuda:0', grad_fn=<NllLossBackward0>)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"12600 tensor(4.1542, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"12700 tensor(4.1810, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"12800 tensor(4.1948, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"12900 tensor(4.1085, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"13000 tensor(4.1283, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"13100 tensor(4.1548, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"13200 tensor(4.1015, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"13300 tensor(4.1342, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"13400 tensor(4.0724, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"13500 tensor(4.1006, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"13600 tensor(4.0998, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"13700 tensor(4.1021, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"13800 tensor(4.1175, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"13900 tensor(4.1017, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"14000 tensor(4.1877, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"14100 tensor(4.1664, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"14200 tensor(4.1582, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"14300 tensor(4.1526, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"14400 tensor(4.1208, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"14500 tensor(4.0752, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"14600 tensor(4.1907, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"14700 tensor(4.0496, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"14800 tensor(4.1371, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"14900 tensor(4.1215, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"15000 tensor(4.1059, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"15100 tensor(4.0888, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"15200 tensor(4.1359, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"15300 tensor(4.1328, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"15400 tensor(4.1044, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"15500 tensor(4.1167, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"15600 tensor(4.0449, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"15700 tensor(4.1159, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"15800 tensor(4.1082, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"15900 tensor(4.1653, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"16000 tensor(4.1111, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"16100 tensor(4.0870, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"16200 tensor(4.1085, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"16300 tensor(4.1216, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"16400 tensor(4.1307, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"16500 tensor(4.0872, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"16600 tensor(4.0754, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"16700 tensor(4.0067, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"16800 tensor(4.0413, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"16900 tensor(4.1242, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"17000 tensor(4.1169, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"17100 tensor(4.0942, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"17200 tensor(4.1518, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"17300 tensor(4.0968, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"17400 tensor(4.0476, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"17500 tensor(4.0230, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"17600 tensor(4.1268, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"17700 tensor(4.0388, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"17800 tensor(4.1741, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"17900 tensor(4.1147, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"18000 tensor(4.2020, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"18100 tensor(4.0304, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"18200 tensor(4.1171, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"18300 tensor(4.0945, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"18400 tensor(4.1019, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"18500 tensor(4.1301, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"18600 tensor(4.0979, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"18700 tensor(4.0755, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"18800 tensor(4.0760, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"18900 tensor(4.0553, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"19000 tensor(4.1530, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"19100 tensor(4.1403, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"19200 tensor(4.1449, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"19300 tensor(4.0105, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"19400 tensor(4.0742, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"19500 tensor(4.0666, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"19600 tensor(4.1549, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"19700 tensor(4.0930, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"19800 tensor(4.1271, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"19900 tensor(4.1169, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"20000 tensor(4.1053, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"20100 tensor(4.1070, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"20200 tensor(4.0848, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"20300 tensor(4.1330, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"20400 tensor(3.9828, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"20500 tensor(4.1411, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"20600 tensor(4.0537, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"20700 tensor(4.1171, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"20800 tensor(4.0510, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"20900 tensor(4.1230, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"21000 tensor(4.1241, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"21100 tensor(4.1600, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"21200 tensor(4.0699, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"21300 tensor(4.0870, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"21400 tensor(4.0774, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"21500 tensor(4.1492, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"21600 tensor(4.0883, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"21700 tensor(4.0358, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"21800 tensor(4.0569, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"21900 tensor(4.0832, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"22000 tensor(4.0827, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"22100 tensor(4.0534, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"22200 tensor(4.0173, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"22300 tensor(4.0549, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"22400 tensor(4.0613, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"22500 tensor(4.1058, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"22600 tensor(4.1230, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"22700 tensor(4.1114, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"22800 tensor(4.0541, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"22900 tensor(4.0732, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"23000 tensor(4.0983, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"23100 tensor(4.0547, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"23200 tensor(4.1198, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"23300 tensor(4.0687, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"23400 tensor(4.0676, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"23500 tensor(4.0834, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"23600 tensor(4.0996, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"23700 tensor(4.0791, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"23800 tensor(4.0700, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"23900 tensor(4.0388, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"24000 tensor(4.0625, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"24100 tensor(4.1095, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"24200 tensor(4.1589, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"24300 tensor(4.1565, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"24400 tensor(4.1396, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"24500 tensor(4.1642, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"24600 tensor(4.0868, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"24700 tensor(4.0770, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"24800 tensor(4.0577, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"24900 tensor(4.0662, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"25000 tensor(4.0877, device='cuda:0', grad_fn=<NllLossBackward0>)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"25100 tensor(4.0505, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"25200 tensor(4.1542, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"25300 tensor(4.0740, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"25400 tensor(4.0893, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"25500 tensor(4.0370, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"25600 tensor(4.1480, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"25700 tensor(4.1070, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"25800 tensor(4.0381, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"25900 tensor(4.0800, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"26000 tensor(4.0842, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"26100 tensor(4.1127, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"26200 tensor(4.1184, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"26300 tensor(4.0885, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"26400 tensor(4.1423, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"26500 tensor(4.1359, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"26600 tensor(4.0986, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"26700 tensor(4.0580, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"26800 tensor(4.0806, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"26900 tensor(4.0169, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"27000 tensor(4.1111, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"27100 tensor(4.1417, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"27200 tensor(4.1497, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"27300 tensor(4.1093, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"27400 tensor(4.0306, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"27500 tensor(4.1214, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"27600 tensor(4.0745, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"27700 tensor(4.0559, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"27800 tensor(4.0286, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"27900 tensor(4.1266, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"28000 tensor(3.9690, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"28100 tensor(4.1141, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"28200 tensor(4.0565, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"28300 tensor(4.0682, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"28400 tensor(4.0646, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"28500 tensor(4.0386, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"28600 tensor(4.0903, device='cuda:0', grad_fn=<NllLossBackward0>)\n",
|
||||
"28700 tensor(4.1060, device='cuda:0', grad_fn=<NllLossBackward0>)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
" device = 'cuda'\n",
|
||||
" model = SimpleBigramNeuralLanguageModel(vocab_size, embed_size).to(device)\n",
|
||||
" data = DataLoader(train_dataset, batch_size=5000)\n",
|
||||
" optimizer = torch.optim.Adam(model.parameters())\n",
|
||||
" criterion = torch.nn.NLLLoss()\n",
|
||||
" \n",
|
||||
" model.train()\n",
|
||||
" step = 0\n",
|
||||
" for x, y in data:\n",
|
||||
" x = x.to(device)\n",
|
||||
" y = y.to(device)\n",
|
||||
" optimizer.zero_grad()\n",
|
||||
" ypredicted = model(x)\n",
|
||||
" loss = criterion(torch.log(ypredicted), y)\n",
|
||||
" if step % 100 == 0:\n",
|
||||
" print(step, loss)\n",
|
||||
" step += 1\n",
|
||||
" loss.backward()\n",
|
||||
" optimizer.step()\n",
|
||||
" \n",
|
||||
" torch.save(model.state_dict(), 'model1.bin')\n",
|
||||
"\n",
|
||||
"#Policzmy najbardziej prawdopodobne kontynuację dla zadanego słowa:\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"SimpleBigramNeuralLanguageModel(\n",
|
||||
" (model): Sequential(\n",
|
||||
" (0): Embedding(20000, 100)\n",
|
||||
" (1): Linear(in_features=100, out_features=20000, bias=True)\n",
|
||||
" (2): Softmax(dim=None)\n",
|
||||
" )\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"model"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[('mnie', 26, 0.16004179418087006),\n",
|
||||
" ('ciebie', 73, 0.13592898845672607),\n",
|
||||
" ('<unk>', 0, 0.12769868969917297),\n",
|
||||
" ('nas', 83, 0.04033529385924339),\n",
|
||||
" ('niego', 172, 0.033195145428180695),\n",
|
||||
" ('niej', 247, 0.021507620811462402),\n",
|
||||
" ('was', 162, 0.017743170261383057),\n",
|
||||
" ('siebie', 181, 0.01618184894323349),\n",
|
||||
" ('nich', 222, 0.01589815877377987),\n",
|
||||
" ('pana', 156, 0.014923062175512314)]"
|
||||
]
|
||||
},
|
||||
"execution_count": 15,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"device = 'cuda'\n",
|
||||
"model = SimpleBigramNeuralLanguageModel(vocab_size, embed_size).to(device)\n",
|
||||
"model.load_state_dict(torch.load('model1.bin'))\n",
|
||||
"model.eval()\n",
|
||||
"\n",
|
||||
"ixs = torch.tensor(vocab.forward(['dla'])).to(device)\n",
|
||||
"\n",
|
||||
"out = model(ixs)\n",
|
||||
"top = torch.topk(out[0], 10)\n",
|
||||
"top_indices = top.indices.tolist()\n",
|
||||
"top_probs = top.values.tolist()\n",
|
||||
"top_words = vocab.lookup_tokens(top_indices)\n",
|
||||
"list(zip(top_words, top_indices, top_probs))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Teraz zbadajmy najbardziej podobne zanurzenia dla zadanego słowa:\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[('.', 3, 0.3327740728855133),\n",
|
||||
" ('z', 14, 0.191472589969635),\n",
|
||||
" (',', 4, 0.18250100314617157),\n",
|
||||
" ('w', 10, 0.06395534425973892),\n",
|
||||
" ('?', 6, 0.059775471687316895),\n",
|
||||
" ('i', 11, 0.019332991912961006),\n",
|
||||
" ('ze', 60, 0.016418060287833214),\n",
|
||||
" ('<unk>', 0, 0.014098692685365677),\n",
|
||||
" ('na', 12, 0.01183203887194395),\n",
|
||||
" ('...', 15, 0.010537521913647652)]"
|
||||
]
|
||||
},
|
||||
"execution_count": 16,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"vocab = train_dataset.vocab\n",
|
||||
"ixs = torch.tensor(vocab.forward(['kłopot'])).to(device)\n",
|
||||
"\n",
|
||||
"out = model(ixs)\n",
|
||||
"top = torch.topk(out[0], 10)\n",
|
||||
"top_indices = top.indices.tolist()\n",
|
||||
"top_probs = top.values.tolist()\n",
|
||||
"top_words = vocab.lookup_tokens(top_indices)\n",
|
||||
"list(zip(top_words, top_indices, top_probs))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[('poszedł', 1088, 1.0),\n",
|
||||
" ('wsiąść', 9766, 0.46510031819343567),\n",
|
||||
" ('pojedzie', 6485, 0.4598822593688965),\n",
|
||||
" ('wyjeżdża', 6459, 0.4378735423088074),\n",
|
||||
" ('szedłem', 8969, 0.4232063889503479),\n",
|
||||
" ('zadzwoniłem', 4889, 0.41752171516418457),\n",
|
||||
" ('dotrzemy', 6098, 0.40929487347602844),\n",
|
||||
" ('spóźnić', 9923, 0.4015277922153473),\n",
|
||||
" ('pójdę', 635, 0.3992091119289398),\n",
|
||||
" ('wrócimy', 2070, 0.39785560965538025)]"
|
||||
]
|
||||
},
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"cos = nn.CosineSimilarity(dim=1, eps=1e-6)\n",
|
||||
"\n",
|
||||
"embeddings = model.model[0].weight\n",
|
||||
"\n",
|
||||
"vec = embeddings[vocab['poszedł']]\n",
|
||||
"\n",
|
||||
"similarities = cos(vec, embeddings)\n",
|
||||
"\n",
|
||||
"top = torch.topk(similarities, 10)\n",
|
||||
"\n",
|
||||
"top_indices = top.indices.tolist()\n",
|
||||
"top_probs = top.values.tolist()\n",
|
||||
"top_words = vocab.lookup_tokens(top_indices)\n",
|
||||
"list(zip(top_words, top_indices, top_probs))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Zapis przy użyciu wzoru matematycznego\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Powyżej zaprogramowaną sieć neuronową można opisać następującym wzorem:\n",
|
||||
"\n",
|
||||
"$$\\vec{y} = \\operatorname{softmax}(CE(w_{i-1}),$$\n",
|
||||
"\n",
|
||||
"gdzie:\n",
|
||||
"\n",
|
||||
"- $w_{i-1}$ to pierwszy wyraz w bigramie (poprzedzający wyraz),\n",
|
||||
"- $E(w)$ to zanurzenie (embedding) wyrazy $w$ — wektor o rozmiarze $m$,\n",
|
||||
"- $C$ to macierz o rozmiarze $|V| \\times m$, która rzutuje wektor zanurzenia w wektor o rozmiarze słownika,\n",
|
||||
"- $\\vec{y}$ to wyjściowy wektor prawdopodobieństw o rozmiarze $|V|$.\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"##### Hiperparametry\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Zauważmy, że nasz model ma dwa hiperparametry:\n",
|
||||
"\n",
|
||||
"- $m$ — rozmiar zanurzenia,\n",
|
||||
"- $|V|$ — rozmiar słownika, jeśli zakładamy, że możemy sterować\n",
|
||||
" rozmiarem słownika (np. przez obcinanie słownika do zadanej liczby\n",
|
||||
" najczęstszych wyrazów i zamiany pozostałych na specjalny token, powiedzmy, `<UNK>`.\n",
|
||||
"\n",
|
||||
"Oczywiście możemy próbować manipulować wartościami $m$ i $|V|$ w celu\n",
|
||||
"polepszenia wyników naszego modelu.\n",
|
||||
"\n",
|
||||
"**Pytanie**: dlaczego nie ma sensu wartość $m \\approx |V|$ ? dlaczego nie ma sensu wartość $m = 1$?\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Diagram sieci\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Jako że mnożenie przez macierz ($C$) oznacza po prostu zastosowanie\n",
|
||||
"warstwy liniowej, naszą sieć możemy interpretować jako jednowarstwową\n",
|
||||
"sieć neuronową, co można zilustrować za pomocą następującego diagramu:\n",
|
||||
"\n",
|
||||
"![img](./07_Zanurzenia_slow/bigram1.drawio.png \"Diagram prostego bigramowego neuronowego modelu języka\")\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Zanurzenie jako mnożenie przez macierz\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Uzyskanie zanurzenia ($E(w)$) zazwyczaj realizowane jest na zasadzie\n",
|
||||
"odpytania (<sub>look</sub>-up\\_). Co ciekawe, zanurzenie można intepretować jako\n",
|
||||
"mnożenie przez macierz zanurzeń (embeddingów) $E$ o rozmiarze $m \\times |V|$ — jeśli słowo będziemy na wejściu kodowali przy użyciu\n",
|
||||
"wektora z gorącą jedynką (<sub>one</sub>-hot encoding\\_), tzn. słowo $w$ zostanie\n",
|
||||
"podane na wejściu jako wektor $\\vec{1_V}(w) = [0,\\ldots,0,1,0\\ldots,0]$ o rozmiarze $|V|$\n",
|
||||
"złożony z samych zer z wyjątkiem jedynki na pozycji odpowiadającej indeksowi wyrazu $w$ w słowniku $V$.\n",
|
||||
"\n",
|
||||
"Wówczas wzór przyjmie postać:\n",
|
||||
"\n",
|
||||
"$$\\vec{y} = \\operatorname{softmax}(CE\\vec{1_V}(w_{i-1})),$$\n",
|
||||
"\n",
|
||||
"gdzie $E$ będzie tym razem macierzą $m \\times |V|$.\n",
|
||||
"\n",
|
||||
"**Pytanie**: czy $\\vec{1_V}(w)$ intepretujemy jako wektor wierszowy czy kolumnowy?\n",
|
||||
"\n",
|
||||
"W postaci diagramu można tę interpretację zilustrować w następujący sposób:\n",
|
||||
"\n",
|
||||
"![img](./07_Zanurzenia_slow/bigram2.drawio.png \"Diagram prostego bigramowego neuronowego modelu języka z wejściem w postaci one-hot\")\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"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
|
||||
}
|
338
wyk/07_Zanurzenia_slow.org
Normal file
338
wyk/07_Zanurzenia_slow.org
Normal file
@ -0,0 +1,338 @@
|
||||
* Zanurzenia słów
|
||||
|
||||
W praktyce stosowalność słowosieci okazała się zaskakująco
|
||||
ograniczona. Większy przełom w przetwarzaniu języka naturalnego przyniosły
|
||||
wielowymiarowe reprezentacje słów, inaczej: zanurzenia słów.
|
||||
|
||||
** „Wymiary” słów
|
||||
|
||||
Moglibyśmy zanurzyć (ang. /embed/) w wielowymiarowej przestrzeni, tzn. zdefiniować odwzorowanie
|
||||
$E \colon V \rightarrow \mathcal{R}^m$ dla pewnego $m$ i określić taki sposób estymowania
|
||||
prawdopodobieństw $P(u|v)$, by dla par $E(v)$ i $E(v')$ oraz $E(u)$ i $E(u')$ znajdujących się w pobliżu
|
||||
(według jakiejś metryki odległości, na przykład zwykłej odległości euklidesowej):
|
||||
|
||||
$$P(u|v) \approx P(u'|v').$$
|
||||
|
||||
$E(u)$ nazywamy zanurzeniem (embeddingiem) słowa.
|
||||
|
||||
*** Wymiary określone z góry?
|
||||
|
||||
Można by sobie wyobrazić, że $m$ wymiarów mogłoby być z góry
|
||||
określonych przez lingwistę. Wymiary te byłyby związane z typowymi
|
||||
„osiami” rozpatrywanymi w językoznawstwie, na przykład:
|
||||
|
||||
- czy słowo jest wulgarne, pospolite, potoczne, neutralne czy książkowe?
|
||||
- czy słowo jest archaiczne, wychodzące z użycia czy jest neologizmem?
|
||||
- czy słowo dotyczy kobiet, czy mężczyzn (w sensie rodzaju gramatycznego i/lub
|
||||
socjolingwistycznym)?
|
||||
- czy słowo jest w liczbie pojedynczej czy mnogiej?
|
||||
- czy słowo jest rzeczownikiem czy czasownikiem?
|
||||
- czy słowo jest rdzennym słowem czy zapożyczeniem?
|
||||
- czy słowo jest nazwą czy słowem pospolitym?
|
||||
- czy słowo opisuje konkretną rzecz czy pojęcie abstrakcyjne?
|
||||
- …
|
||||
|
||||
W praktyce okazało się jednak, że lepiej, żeby komputer uczył się sam
|
||||
możliwych wymiarów — z góry określamy tylko $m$ (liczbę wymiarów).
|
||||
|
||||
** Bigramowy model języka oparty na zanurzeniach
|
||||
|
||||
Zbudujemy teraz najprostszy model język oparty na zanurzeniach. Będzie to właściwie najprostszy
|
||||
*neuronowy model języka*, jako że zbudowany model można traktować jako prostą sieć neuronową.
|
||||
|
||||
*** Słownik
|
||||
|
||||
W typowym neuronowym modelu języka rozmiar słownika musi być z góry
|
||||
ograniczony. Zazwyczaj jest to liczba rzędu kilkudziesięciu wyrazów —
|
||||
po prostu będziemy rozpatrywać $|V|$ najczęstszych wyrazów, pozostałe zamienimy
|
||||
na specjalny token ~<unk>~ reprezentujący nieznany (/unknown/) wyraz.
|
||||
|
||||
Aby utworzyć taki słownik użyjemy gotowej klasy ~Vocab~ z pakietu torchtext:
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
from itertools import islice
|
||||
import regex as re
|
||||
import sys
|
||||
from torchtext.vocab import build_vocab_from_iterator
|
||||
|
||||
|
||||
def get_words_from_line(line):
|
||||
line = line.rstrip()
|
||||
yield '<s>'
|
||||
for m in re.finditer(r'[\p{L}0-9\*]+|\p{P}+', line):
|
||||
yield m.group(0).lower()
|
||||
yield '</s>'
|
||||
|
||||
|
||||
def get_word_lines_from_file(file_name):
|
||||
with open(file_name, 'r') as fh:
|
||||
for line in fh:
|
||||
yield get_words_from_line(line)
|
||||
|
||||
vocab_size = 20000
|
||||
|
||||
vocab = build_vocab_from_iterator(
|
||||
get_word_lines_from_file('opensubtitlesA.pl.txt'),
|
||||
max_tokens = vocab_size,
|
||||
specials = ['<unk>'])
|
||||
|
||||
vocab['jest']
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
16
|
||||
:end:
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
vocab.lookup_tokens([0, 1, 2, 10, 12345])
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
['<unk>', '</s>', '<s>', 'w', 'wierzyli']
|
||||
:end:
|
||||
|
||||
*** Definicja sieci
|
||||
|
||||
Naszą prostą sieć neuronową zaimplementujemy używając frameworku PyTorch.
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
from torch import nn
|
||||
import torch
|
||||
|
||||
embed_size = 100
|
||||
|
||||
class SimpleBigramNeuralLanguageModel(nn.Module):
|
||||
def __init__(self, vocabulary_size, embedding_size):
|
||||
super(SimpleBigramNeuralLanguageModel, self).__init__()
|
||||
self.model = nn.Sequential(
|
||||
nn.Embedding(vocabulary_size, embedding_size),
|
||||
nn.Linear(embedding_size, vocabulary_size),
|
||||
nn.Softmax()
|
||||
)
|
||||
|
||||
def forward(self, x):
|
||||
return self.model(x)
|
||||
|
||||
model = SimpleBigramNeuralLanguageModel(vocab_size, embed_size)
|
||||
|
||||
vocab.set_default_index(vocab['<unk>'])
|
||||
ixs = torch.tensor(vocab.forward(['pies']))
|
||||
out[0][vocab['jest']]
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
:end:
|
||||
|
||||
Teraz wyuczmy model. Wpierw tylko potasujmy nasz plik:
|
||||
|
||||
#+BEGIN_SRC
|
||||
shuf < opensubtitlesA.pl.txt > opensubtitlesA.pl.shuf.txt
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
from torch.utils.data import IterableDataset
|
||||
import itertools
|
||||
|
||||
def look_ahead_iterator(gen):
|
||||
prev = None
|
||||
for item in gen:
|
||||
if prev is not None:
|
||||
yield (prev, item)
|
||||
prev = item
|
||||
|
||||
class Bigrams(IterableDataset):
|
||||
def __init__(self, text_file, vocabulary_size):
|
||||
self.vocab = build_vocab_from_iterator(
|
||||
get_word_lines_from_file(text_file),
|
||||
max_tokens = vocabulary_size,
|
||||
specials = ['<unk>'])
|
||||
self.vocab.set_default_index(self.vocab['<unk>'])
|
||||
self.vocabulary_size = vocabulary_size
|
||||
self.text_file = text_file
|
||||
|
||||
def __iter__(self):
|
||||
return look_ahead_iterator(
|
||||
(self.vocab[t] for t in itertools.chain.from_iterable(get_word_lines_from_file(self.text_file))))
|
||||
|
||||
train_dataset = Bigrams('opensubtitlesA.pl.shuf.txt', vocab_size)
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
:end:
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
from torch.utils.data import DataLoader
|
||||
|
||||
next(iter(train_dataset))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
(2, 5)
|
||||
:end:
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
from torch.utils.data import DataLoader
|
||||
|
||||
next(iter(DataLoader(train_dataset, batch_size=5)))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
[tensor([ 2, 5, 51, 3481, 231]), tensor([ 5, 51, 3481, 231, 4])]
|
||||
:end:
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
device = 'cuda'
|
||||
model = SimpleBigramNeuralLanguageModel(vocab_size, embed_size).to(device)
|
||||
data = DataLoader(train_dataset, batch_size=5000)
|
||||
optimizer = torch.optim.Adam(model.parameters())
|
||||
criterion = torch.nn.NLLLoss()
|
||||
|
||||
model.train()
|
||||
step = 0
|
||||
for x, y in data:
|
||||
x = x.to(device)
|
||||
y = y.to(device)
|
||||
optimizer.zero_grad()
|
||||
ypredicted = model(x)
|
||||
loss = criterion(torch.log(ypredicted), y)
|
||||
if step % 100 == 0:
|
||||
print(step, loss)
|
||||
step += 1
|
||||
loss.backward()
|
||||
optimizer.step()
|
||||
|
||||
torch.save(model.state_dict(), 'model1.bin')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
None
|
||||
:end:
|
||||
|
||||
Policzmy najbardziej prawdopodobne kontynuację dla zadanego słowa:
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
device = 'cuda'
|
||||
model = SimpleBigramNeuralLanguageModel(vocab_size, embed_size).to(device)
|
||||
model.load_state_dict(torch.load('model1.bin'))
|
||||
model.eval()
|
||||
|
||||
ixs = torch.tensor(vocab.forward(['dla'])).to(device)
|
||||
|
||||
out = model(ixs)
|
||||
top = torch.topk(out[0], 10)
|
||||
top_indices = top.indices.tolist()
|
||||
top_probs = top.values.tolist()
|
||||
top_words = vocab.lookup_tokens(top_indices)
|
||||
list(zip(top_words, top_indices, top_probs))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
[('ciebie', 73, 0.1580502986907959), ('mnie', 26, 0.15395283699035645), ('<unk>', 0, 0.12862136960029602), ('nas', 83, 0.0410110242664814), ('niego', 172, 0.03281523287296295), ('niej', 245, 0.02104802615940571), ('siebie', 181, 0.020788608118891716), ('którego', 365, 0.019379809498786926), ('was', 162, 0.013852755539119244), ('wszystkich', 235, 0.01381855271756649)]
|
||||
:end:
|
||||
|
||||
Teraz zbadajmy najbardziej podobne zanurzenia dla zadanego słowa:
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
vocab = train_dataset.vocab
|
||||
ixs = torch.tensor(vocab.forward(['kłopot'])).to(device)
|
||||
|
||||
out = model(ixs)
|
||||
top = torch.topk(out[0], 10)
|
||||
top_indices = top.indices.tolist()
|
||||
top_probs = top.values.tolist()
|
||||
top_words = vocab.lookup_tokens(top_indices)
|
||||
list(zip(top_words, top_indices, top_probs))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
[('.', 3, 0.404473215341568), (',', 4, 0.14222915470600128), ('z', 14, 0.10945753753185272), ('?', 6, 0.09583134204149246), ('w', 10, 0.050338443368673325), ('na', 12, 0.020703863352537155), ('i', 11, 0.016762692481279373), ('<unk>', 0, 0.014571071602404118), ('...', 15, 0.01453721895813942), ('</s>', 1, 0.011769450269639492)]
|
||||
:end:
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
cos = nn.CosineSimilarity(dim=1, eps=1e-6)
|
||||
|
||||
embeddings = model.model[0].weight
|
||||
|
||||
vec = embeddings[vocab['poszedł']]
|
||||
|
||||
similarities = cos(vec, embeddings)
|
||||
|
||||
top = torch.topk(similarities, 10)
|
||||
|
||||
top_indices = top.indices.tolist()
|
||||
top_probs = top.values.tolist()
|
||||
top_words = vocab.lookup_tokens(top_indices)
|
||||
list(zip(top_words, top_indices, top_probs))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
[('poszedł', 1087, 1.0), ('idziesz', 1050, 0.4907470941543579), ('przyjeżdża', 4920, 0.45242372155189514), ('pojechałam', 12784, 0.4342481195926666), ('wrócił', 1023, 0.431664377450943), ('dobrać', 10351, 0.4312002956867218), ('stałeś', 5738, 0.4258835017681122), ('poszła', 1563, 0.41979148983955383), ('trafiłam', 18857, 0.4109022617340088), ('jedzie', 1674, 0.4091658890247345)]
|
||||
:end:
|
||||
|
||||
*** Zapis przy użyciu wzoru matematycznego
|
||||
|
||||
Powyżej zaprogramowaną sieć neuronową można opisać następującym wzorem:
|
||||
|
||||
$$\vec{y} = \operatorname{softmax}(CE(w_{i-1}),$$
|
||||
|
||||
gdzie:
|
||||
|
||||
- $w_{i-1}$ to pierwszy wyraz w bigramie (poprzedzający wyraz),
|
||||
- $E(w)$ to zanurzenie (embedding) wyrazy $w$ — wektor o rozmiarze $m$,
|
||||
- $C$ to macierz o rozmiarze $|V| \times m$, która rzutuje wektor zanurzenia w wektor o rozmiarze słownika,
|
||||
- $\vec{y}$ to wyjściowy wektor prawdopodobieństw o rozmiarze $|V|$.
|
||||
|
||||
**** Hiperparametry
|
||||
|
||||
Zauważmy, że nasz model ma dwa hiperparametry:
|
||||
|
||||
- $m$ — rozmiar zanurzenia,
|
||||
- $|V|$ — rozmiar słownika, jeśli zakładamy, że możemy sterować
|
||||
rozmiarem słownika (np. przez obcinanie słownika do zadanej liczby
|
||||
najczęstszych wyrazów i zamiany pozostałych na specjalny token, powiedzmy, ~<UNK>~.
|
||||
|
||||
Oczywiście możemy próbować manipulować wartościami $m$ i $|V|$ w celu
|
||||
polepszenia wyników naszego modelu.
|
||||
|
||||
*Pytanie*: dlaczego nie ma sensu wartość $m \approx |V|$ ? dlaczego nie ma sensu wartość $m = 1$?
|
||||
|
||||
*** Diagram sieci
|
||||
|
||||
Jako że mnożenie przez macierz ($C$) oznacza po prostu zastosowanie
|
||||
warstwy liniowej, naszą sieć możemy interpretować jako jednowarstwową
|
||||
sieć neuronową, co można zilustrować za pomocą następującego diagramu:
|
||||
|
||||
#+CAPTION: Diagram prostego bigramowego neuronowego modelu języka
|
||||
[[./07_Zanurzenia_slow/bigram1.drawio.png]]
|
||||
|
||||
*** Zanurzenie jako mnożenie przez macierz
|
||||
|
||||
Uzyskanie zanurzenia ($E(w)$) zazwyczaj realizowane jest na zasadzie
|
||||
odpytania (_look-up_). Co ciekawe, zanurzenie można intepretować jako
|
||||
mnożenie przez macierz zanurzeń (embeddingów) $E$ o rozmiarze $m \times |V|$ — jeśli słowo będziemy na wejściu kodowali przy użyciu
|
||||
wektora z gorącą jedynką (_one-hot encoding_), tzn. słowo $w$ zostanie
|
||||
podane na wejściu jako wektor $\vec{1_V}(w) = [0,\ldots,0,1,0\ldots,0]$ o rozmiarze $|V|$
|
||||
złożony z samych zer z wyjątkiem jedynki na pozycji odpowiadającej indeksowi wyrazu $w$ w słowniku $V$.
|
||||
|
||||
Wówczas wzór przyjmie postać:
|
||||
|
||||
$$\vec{y} = \operatorname{softmax}(CE\vec{1_V}(w_{i-1})),$$
|
||||
|
||||
gdzie $E$ będzie tym razem macierzą $m \times |V|$.
|
||||
|
||||
*Pytanie*: czy $\vec{1_V}(w)$ intepretujemy jako wektor wierszowy czy kolumnowy?
|
||||
|
||||
W postaci diagramu można tę interpretację zilustrować w następujący sposób:
|
||||
|
||||
#+CAPTION: Diagram prostego bigramowego neuronowego modelu języka z wejściem w postaci one-hot
|
||||
[[./07_Zanurzenia_slow/bigram2.drawio.png]]
|
781
wyk/08_Neuronowy_ngramowy_model.ipynb
Normal file
781
wyk/08_Neuronowy_ngramowy_model.ipynb
Normal file
File diff suppressed because one or more lines are too long
406
wyk/08_Neuronowy_ngramowy_model.org
Normal file
406
wyk/08_Neuronowy_ngramowy_model.org
Normal file
@ -0,0 +1,406 @@
|
||||
* Neuronowy n-gramowy model języka
|
||||
|
||||
Omówiony w poprzedniej części neuronowy bigramowy model języka
|
||||
warunkuje kolejny wyraz jedynie względem bezpośrednio poprzedzającego
|
||||
— jak w każdym bigramowym modelu przyjmujemy założenie, że $w_i$
|
||||
zależy tylko od $w_{i-1}$. Rzecz jasna jest to bardzo duże
|
||||
ograniczenie, w rzeczywistości bardzo często prawdopodobieństwo
|
||||
kolejnego wyrazu zależy od wyrazu dwie, trzy, cztery itd. pozycje
|
||||
wstecz czy w ogólności od wszystkich wyrazów poprzedzających (bez
|
||||
względu na ich pozycje).
|
||||
|
||||
*Pytanie*: Wskaż zależności o zasięgu większym niż 1 wyraz w zdaniu
|
||||
/Zatopieni w kłębach dymu cygar i pochyleni nad butelkami z ciemnego
|
||||
szkła obywatele tej dzielnicy, jedni zakładali się o wygranę lub
|
||||
przegranę Anglii, drudzy o bankructwo Wokulskiego; jedni nazywali
|
||||
geniuszem Bismarcka, drudzy — awanturnikiem Wokulskiego; jedni
|
||||
krytykowali postępowanie prezydenta MacMahona, inni twierdzili, że
|
||||
Wokulski jest zdecydowanym wariatem, jeżeli nie czymś gorszym…/
|
||||
|
||||
** Trigramowy neuronowy model języka
|
||||
|
||||
Spróbujmy najpierw rozszerzyć nasz model na trigramy, to znaczy
|
||||
będziemy przewidywać słowo $w_i$ na podstawie słów $w_{i-2}$ i
|
||||
$w_{i-1}$.
|
||||
|
||||
Najprostsze rozwiązanie polegałoby na zanurzeniu pary $(w_{i-2},
|
||||
w_{i-1})$ w całości i postępowaniu jak w przypadku modelu bigramowego.
|
||||
Byłoby to jednak zupełnie niepraktyczne, jako że:
|
||||
|
||||
- liczba zanurzeń do wyuczenia byłaby olbrzymia ($|V|^2$ — byłoby to
|
||||
ewentualnie akceptowalne dla modeli operujących na krótszych
|
||||
jednostkach niż słowa, np. na znakach),
|
||||
- w szczególności zanurzenia dla par $(v, u)$, $(u, v)$, $(u, u)$ i
|
||||
$(v, v)$ nie miałyby ze sobą nic wspólnego.
|
||||
|
||||
*** Konketanacja zanurzeń
|
||||
|
||||
Właściwsze rozwiązanie polega na zanurzeniu dalej pojedynczych słów i
|
||||
następnie ich *konkatenowaniu*.
|
||||
|
||||
Przypomnijmy, że konkatenacja wektorów $\vec{x_1}$ i $\vec{x_2}$ to wektor o rozmiarze
|
||||
$|\vec{x_1}| + |\vec{x_2}|$ powstały ze „sklejania” wektorów $\vec{x_1}$ i $\vec{x_2}$.
|
||||
Konkatenację wektorów $\vec{x_1}$ i $\vec{x_2}$ będziemy oznaczać za pomocą $[\vec{x_1}, \vec{x_2}]$.
|
||||
|
||||
Przykład: jeśli $\vec{x_1} = [-1, 2, 0]$ i $\vec{x_2} = [3, -3]$,
|
||||
wówczas $[\vec{x_1}, \vec{x_2}] = [-1, 2, 0, 3, -3]$
|
||||
|
||||
Oznacza to, że nasza macierz „kontekstowa” $C$ powinna mieć w modelu trigramowym rozmiar nie
|
||||
$|V| \times m$, lecz $|V| \times (m+m)$ = $|V| \times 2m$ i wyjście będzie zdefiniowane za pomocą wzoru:
|
||||
|
||||
$$\vec{y} = \operatorname{softmax}(C[E(w_{i-2}),E(w_{i-1})]),$$
|
||||
|
||||
co można przedstawić za pomocą następującego schematu:
|
||||
|
||||
#+CAPTION: Diagram prostego bigramowego neuronowego modelu języka
|
||||
[[./08_Neuronowy_ngramowy_model/trigram1.drawio.png]]
|
||||
|
||||
**** Rozbicie macierzy $C$
|
||||
|
||||
Zamiast mnożyć macierz $C$ przez konkatenację dwóch wektorów, można
|
||||
rozbić macierz $C$ na dwie, powiedzmy $C_{-2}$ i $C_{-1}$, przemnażać
|
||||
je osobno przez odpowiadające im wektory i następnie *dodać* macierze,
|
||||
tak aby:
|
||||
|
||||
$$C[E(w_{i-2}),E(w_{i-1})] = C_{-2}E(w_{i-2}) + C_{-1}E(w_{i-1}).$$
|
||||
|
||||
Macierze $C_{-2}$ i $C_{-1}$ będą miały rozmiar $|V| \times m$.
|
||||
|
||||
Przy tym podejściu możemy powiedzieć, że ostatni i przedostatni wyraz
|
||||
mają swoje osobne macierze o potencjalnie różnych wagach — co ma sens,
|
||||
jako że na inne aspekty zwracamy uwagę przewidując kolejne słowo na
|
||||
podstawie wyrazu bezpośrednio poprzedzającego, a na inne — na
|
||||
podstawie słowa występującego dwie pozycje wcześniej.
|
||||
|
||||
** Uogólnienie na $n$-gramowy model języka dla dowolnego $n$
|
||||
|
||||
Łatwo uogólnić opisany wyżej trigramowy model języka dla dowolnego $n$.
|
||||
Uogólniony model można przedstawić za pomocą wzoru:
|
||||
|
||||
$$\vec{y} = \operatorname{softmax}(C[E(w_{i-n+1}),\dots,E(w_{i-1})]),$$
|
||||
|
||||
gdzie macierz $C$ ma rozmiar $|V| \times nm$ lub za pomocą wzoru:
|
||||
|
||||
$$\vec{y} = \operatorname{softmax}(C_{-(n-1)}E(w_{i-n+1}) + \dots + C_{-1}E(w_{i-1}),$$
|
||||
|
||||
gdzie macierze $C_{-(n-1)}$, \dots, $C_{-1}$ mają rozmiary $|V| \times m$.
|
||||
|
||||
Por. diagram:
|
||||
|
||||
#+CAPTION: Diagram prostego n-gramowego neuronowego modelu języka
|
||||
[[./08_Neuronowy_ngramowy_model/ngram.drawio.png]]
|
||||
|
||||
** Dodanie kolejnej warstwy
|
||||
|
||||
W wypadku trigramowego czy — ogólniej — n-gramowego modelu języka dla
|
||||
$n \geq 3$ warto dodać kolejną (*ukrytą*) warstwę, na którą będziemy rzutować
|
||||
skonkatenowane embeddingi, zanim zrzutujemy je do długiego wektora
|
||||
prawdopodobieństw.
|
||||
|
||||
Zakładamy, że warstwa ukryta zawiera $h$ neuronów. Wartość $h$ powinna być mniejsza
|
||||
niż $nm$ (a może nawet od $m$).
|
||||
|
||||
*Pytanie*: Dlaczego wartość $h > nm$ nie jest racjonalnym wyborem?
|
||||
|
||||
*Pytanie*: Dlaczego dodanie kolejnej warstwy nie ma sensu dla modelu bigramowego?
|
||||
|
||||
*** Funkcja aktywacji
|
||||
|
||||
Aby warstwa ukryta wnosiła coś nowego, na wyjściu z tej funkcji musimy (dlaczego?)
|
||||
zastosować nieliniową *funkcji aktywacji*. Zazwyczaj jako funkcji
|
||||
aktywacji w sieciach neuronowych używa się funkcji ReLU albo funkcji
|
||||
sigmoidalnej. W prostych neuronowych modelach języka sprawdza się też
|
||||
*tangens hiperboliczny* (tgh, w literaturze anglojęzycznej tanh):
|
||||
|
||||
$$\operatorname{tgh}(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}}.$$
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
import matplotlib.pyplot as plt
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
|
||||
x = torch.linspace(-5,5,100)
|
||||
plt.xlabel("x")
|
||||
plt.ylabel("y")
|
||||
a = torch.Tensor(x.size()[0]).fill_(2.)
|
||||
m = torch.stack([x, a])
|
||||
plt.plot(x, nn.functional.tanh(m)[0])
|
||||
fname = '08_Neuronowy_ngramowy_model/tanh.png'
|
||||
plt.savefig(fname)
|
||||
fname
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
[[file:08_Neuronowy_ngramowy_model/tanh.png]]
|
||||
|
||||
**** Tangens hiperboliczny zastosowany dla wektora
|
||||
|
||||
Tangens hiperboliczny wektora będzie po prostu wektorem tangensów
|
||||
hiperbolicznych poszczególnych wartości.
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
|
||||
v = torch.Tensor([-100, -2.0, 0.0, 0.5, 1000.0])
|
||||
nn.functional.tanh(v)
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
[[file:tensor([-1.0000, -0.9640, 0.0000, 0.4621, 1.0000])]]
|
||||
|
||||
*** Wzór i schemat dwuwarstwowego n-gramowego neuronowego modelu języka
|
||||
|
||||
Dwuwarstwowy model języka będzie określony następującym wzorem:
|
||||
|
||||
$$\vec{y} = \operatorname{softmax}(C\operatorname{tgh}(W[E(w_{i-n+1}),\dots,E(w_{i-1})])),$$
|
||||
|
||||
gdzie:
|
||||
|
||||
- $W$ jest wyuczalną macierzą wag o rozmiarze $h \times nm$,
|
||||
- $C$ będzie macierzą o rozmiarze $|V| \times h$.
|
||||
|
||||
Zmodyfikowaną sieć można przedstawić za pomocą następującego schematu:
|
||||
|
||||
#+CAPTION: Dwuwarstwowy n-gramowy neuronowy model języka
|
||||
[[./08_Neuronowy_ngramowy_model/ngram-tgh.drawio.png]]
|
||||
|
||||
*** Liczba wag w modelu dwuwarstwowym
|
||||
|
||||
Na wagi w modelu dwuwarstwowym składają się:
|
||||
|
||||
- zanurzenia: $m|V|$,
|
||||
- wagi warstwy ukrytej: $hnm$,
|
||||
- wagi warstwy wyjściowej: $|V|h$,
|
||||
|
||||
a zatem łącznie:
|
||||
|
||||
$$m|V| + hnm + |V|h$$
|
||||
|
||||
Jeśli $h \approx m$ (co jest realistyczną opcją), wówczas otrzymamy oszacowanie:
|
||||
|
||||
$$O(m|V| + nm^2).$$
|
||||
|
||||
Zauważmy, że względem $n$ oznacza to bardzo korzystną złożoność
|
||||
$O(n)$! Oznacza to, że nasz model może działać dla dużo większych
|
||||
wartości $n$ niż tradycyjny, statystyczny n-gramowy model języka (dla którego
|
||||
wartości $n > 5$ zazwyczaj nie mają sensu).
|
||||
|
||||
** Model worka słów
|
||||
|
||||
Jak stwierdziliśmy przed chwilą, dwuwarstwowy n-gramowy model języka
|
||||
może działać dla stosunkowo dużego $n$. Zauważmy jednak, że istnieje
|
||||
pewna słabość tego modelu. Otóż o ile intuicyjnie ma sens odróżniać
|
||||
słowo poprzedzające, słowo występujące dwie pozycje wstecz i zapewne
|
||||
trzy pozycje wstecz, a zatem uczyć się osobnych macierzy $C_{-1}$,
|
||||
$C_{-2}$, $C_{-3}$ to różnica między wpływem słowa
|
||||
występującego cztery pozycje wstecz i pięć pozycji wstecz jest już
|
||||
raczej nieistotna; innymi słowy różnica między macierzami $C_{-4}$ i
|
||||
$C_{-5}$ będzie raczej niewielka i sieć niepotrzebnie będzie uczyła
|
||||
się dwukrotnie podobnych wag. Im dalej wstecz, tym różnica wpływu
|
||||
będzie jeszcze mniej istotna, można np. przypuszczać, że różnica
|
||||
między $C_{-10}$ i $C_{-13}$ nie powinna być duża.
|
||||
|
||||
Spróbujmy najpierw zaproponować radykalne podejście, w którym nie
|
||||
będziemy w ogóle uwzględniać pozycji słów (lub będziemy je uwzględniać
|
||||
w niewielkim stopniu), później połączymy to z omówionym wcześniej
|
||||
modelem $n$-gramowym.
|
||||
|
||||
*** Agregacja wektorów
|
||||
|
||||
Zamiast patrzeć na kilka poprzedzających słów, można przewidywać na
|
||||
podstawie *całego* ciągu słów poprzedzających odgadywane słowo. Zauważmy jednak, że
|
||||
sieć neuronowa musi mieć ustaloną strukturę, nie możemy zmieniać jej
|
||||
rozmiaru. Musimy zatem najpierw zagregować cały ciąg do wektora o
|
||||
*stałej* długości. Potrzebujemy zatem pewnej funkcji agregującej $A$, takiej by
|
||||
$A(w_1,\dots,w_{i-1})$ było wektorem o stałej długości, niezależnie od $i$.
|
||||
|
||||
*** Worek słów
|
||||
|
||||
Najprostszą funkcją agregującą jest po prostu… suma. Dodajemy po
|
||||
prostu zanurzenia słów:
|
||||
|
||||
$$A(w_1,\dots,w_{i-1}) = E(w_1) + \dots + E(w_{i-1}) = \sum_{j=1}^{i-1} E(w_j).$$
|
||||
|
||||
*Uwaga*: zanurzenia słów nie zależą od pozycji słowa (podobnie było w wypadku n-gramowego modelu!).
|
||||
|
||||
Jeśli rozmiar zanurzenia (embeddingu) wynosi $m$, wówczas rozmiar
|
||||
wektora uzyskanego dla całego poprzedzającego tekstu wynosi również $m$.
|
||||
|
||||
Proste dodawanie wydaje się bardzo „prostacką” metodą, a jednak
|
||||
suma wektorów słów jest *zaskakująco skuteczną metodą zanurzenia
|
||||
(embedowania) całych tekstów (doc2vec)*. Prostym wariantem dodawania jest obliczanie *średniej wektorów*:
|
||||
|
||||
$$A(w_1,\dots,w_{i-1}) = \frac{E(w_1) + \dots + E(w_{i-1})}{i-1} = \frac{\sum_{j=1}^{i-1} E(w_j)}{i-1}.$$
|
||||
|
||||
Tak czy siak uzyskany wektor *nie zależy od kolejności słów*
|
||||
(dodawanie jest przemienne i łączne!). Mówimy więc o *worku słów*
|
||||
(/bag of words/, /BoW/) — co ma symbolizować fakt, że słowa są
|
||||
przemieszane, niczym produkty w torbie na zakupy.
|
||||
|
||||
**** Schemat graficzny modelu typu worek słów
|
||||
|
||||
Po zanurzeniu całego poprzedzającego tekstu postępujemy podobnie jak w
|
||||
modelu bigramowym — rzutujemy embedding na długi wektor wartości, na
|
||||
którym stosujemy funkcję softmax:
|
||||
|
||||
#+CAPTION: Model typu worek słów
|
||||
[[./08_Neuronowy_ngramowy_model/bow1.drawio.png]]
|
||||
|
||||
Odpowiada to wzorowi:
|
||||
|
||||
$$y = \operatorname{softmax}(C\sum_{j=1}^{i-1} E(w_j)).$$
|
||||
|
||||
*** Jak traktować powtarzające się słowa?
|
||||
|
||||
Według wzoru podanego wyżej, jeśli słowo w poprzedzającym tekście
|
||||
pojawia się więcej niż raz, jego embedding zostanie zsumowany odpowiednią liczbę razy.
|
||||
Na przykład embedding tekstu /to be or not to be/ będzie wynosił:
|
||||
|
||||
$$E(\mathrm{to}) + E(\mathrm{be}) + E(\mathrm{or}) + E(\mathrm{not}) + E(\mathrm{to}) + E(\mathrm{be}) = 2E(\mathrm{to}) + 2E(\mathrm{be}) + E(\mathrm{or}) + E(\mathrm{not}).$$
|
||||
|
||||
Innymi słowy, choć w worku słów nie uwzględniamy kolejności słów, to
|
||||
*liczba wystąpień* ma dla nas ciągle znaczenie. Można powiedzieć, że
|
||||
traktujemy poprzedzający tekst jako *multizbiór* (struktura
|
||||
matematyczna, w której nie uwzględnia się kolejności, choć zachowana
|
||||
jest informacja o liczbie wystąpień).
|
||||
|
||||
**** Zbiór słów
|
||||
|
||||
Oczywiście moglibyśmy przy agregowaniu zanurzeń pomijać powtarzające
|
||||
się słowa, a zatem zamiast multizbioru słów rozpatrywać po prostu ich zbiór:
|
||||
|
||||
$$A(w_1,\dots,w_{i-1}) = \sum_{w \in \{w_1,\dots,w_{i-1}\}} E(w).$$
|
||||
|
||||
Jest kwestią dyskusyjną, czy to lepsze czy gorsze podejście — w końcu
|
||||
liczba wystąpień np. słów /Ukraina/ czy /Polska/ może wpływać w jakimś
|
||||
stopniu na prawdopodobieństwo kolejnego słowa (/Kijów/ czy
|
||||
/Warszawa/?).
|
||||
|
||||
*** Worek słów a wektoryzacja tf
|
||||
|
||||
Wzór na sumę zanurzeń słów można przekształcić w taki sposób, by
|
||||
sumować po wszystkich słowach ze słownika, zamiast po słowach rzeczywiście występujących w tekście:
|
||||
|
||||
$$A(w_1,\dots,w_{i-1}) = \sum_{j=1}^{i-1} E(w_j) = \sum_{w \in V} \#wE(w)$$
|
||||
|
||||
gdzie $\#w$ to liczba wystąpień słowa $w$ w ciagu $w_1,\dots,w_{i-1}$ (w wielu przypadkach równa zero!).
|
||||
|
||||
Jeśli teraz zanurzenia będziemy reprezentować jako macierz $E$ (por. poprzedni wykład),
|
||||
wówczas sumę można przedstawić jako iloczyn macierzy $E$ i pewnego wektora:
|
||||
|
||||
$$A(w_1,\dots,w_{i-1}) = E(w) [\#w^1,\dots,\#w^{|V|}]^T.$$
|
||||
|
||||
(Odróżniamy $w^i$ jako $i$-ty wyraz w słowniku $V$ od $w_i$ jako $i$-tego wyraz w rozpatrywanym ciągu).
|
||||
|
||||
Zwróćmy uwagę, że wektor $[\#w_1,\dots,\#w_{|V|}]$ to po prostu
|
||||
reprezentacja wektora poprzedzającego tekstu (tj. ciągu
|
||||
$(w_1,\dots,w_{i-1})$) przy użyciu schematu wektoryzacji tf (/term
|
||||
frequency/). Przypomnijmy, że tf to reprezentacja tekstu przy użyciu
|
||||
wektorów o rozmiarze $|V|$ — na każdej pozycji odnotowujemy liczbę wystąpień.
|
||||
Wektory tf są *rzadkie*, tj. na wielu pozycjach zawierają zera.
|
||||
|
||||
Innymi słowy, nasz model języka /bag of words/ można przedstawić za pomocą wzoru:
|
||||
|
||||
$$y = \operatorname{softmax}(C\operatorname{tf}(w_1,\dots,w_{i-1})),$$
|
||||
|
||||
co można zilustrować w następujący sposób:
|
||||
|
||||
#+CAPTION: Model typu worek słów — alternatywna reprezentacja
|
||||
[[./08_Neuronowy_ngramowy_model/bow2.drawio.png]]
|
||||
|
||||
Można stwierdzić, że zanurzenie tekstu przekształca rzadki, długi wektor
|
||||
tf w gęsty, krótki wektor.
|
||||
|
||||
** Ważenie słów
|
||||
|
||||
Czy wszystkie słowa są tak samo istotne? Rzecz jasna, nie:
|
||||
|
||||
- jak już wiemy z naszych rozważań dotyczących n-gramowych modeli języka, słowa bezpośrednio
|
||||
poprzedzające odgadywany wyraz mają większy wpływ niż słowa wcześniejsze;
|
||||
intuicyjnie, wpływ słów stopniowo spada — tym bardziej, im bardziej słowo jest oddalone od słowa odgadywanego;
|
||||
- jak wiemy z wyszukiwania informacji, słowa, które występują w wielu tekstach czy dokumentach, powinny mieć
|
||||
mniejsze znaczenie, w skrajnym przypadku słowa występujące w prawie każdym tekście (/że/, /w/, /i/ itd.) powinny
|
||||
być praktycznie pomijane jako /stop words/ (jeśli rozpatrywać je w „masie” worka słów — oczywiście
|
||||
to, czy słowo poprzedzające odgadywane słowo to /że/, /w/ czy /i/ ma olbrzymie znaczenie!).
|
||||
|
||||
Zamiast po prostu dodawać zanurzenia, można operować na sumie (bądź średniej) ważonej:
|
||||
|
||||
$$\sum_{j=1}^{i-1} \omega(j, w_j)E(w_j),$$
|
||||
|
||||
gdzie $\omega(j, w_j)$ jest pewną wagą, która może zależeć od pozycji $j$ lub samego słowa $w_j$.
|
||||
|
||||
*** Uwzględnienie pozycji
|
||||
|
||||
Można w pewnym stopniu złamać „workowatość” naszej sieci przez proste
|
||||
uwzględnienie pozycji słowa, np. w taki sposób:
|
||||
|
||||
$$\omega(j, w_j) = \beta^{i-j-1},$$
|
||||
|
||||
dla pewnego hiperparametru $\beta$. Na przykład jeśli $\beta=0,9$,
|
||||
wówczas słowo bezpośrednio poprzedzające dane słowo ma $1 / 0,9^9 \approx 2,58$
|
||||
większy wpływ niż słowo występujące 10 pozycji wstecz.
|
||||
|
||||
*** Odwrócona częstość dokumentowa
|
||||
|
||||
Aby większą wagę przykładać do słów występujących w mniejszej liczbie
|
||||
dokumentów, możemy użyć, znanej z wyszukiwania informacji,
|
||||
odwrotnej częstości dokumentowej (/inverted document frequency/, /idf/):
|
||||
|
||||
$$\omega(j, w_j) = \operatorname{idf}_S(w_j) = \operatorname{log}\frac{|S|}{\operatorname{df}_S(w_j)},$$
|
||||
|
||||
gdzie:
|
||||
|
||||
- $S$ jest pewną kolekcją dokumentów czy tekstów, z którego pochodzi przedmiotowy ciąg słów,
|
||||
- $\operatorname{df}_S(w)$ to częstość dokumentowa słowa $w$ w kolekcji $S$, tzn. odpowiedź na pytanie,
|
||||
w ilu dokumentach występuje $w$.
|
||||
|
||||
Rzecz jasna, ten sposób ważenia oznacza tak naprawdę zastosowanie wektoryzacji tf-idf zamiast tf,
|
||||
nasza sieć będzie dana zatem wzorem:
|
||||
|
||||
$$y = \operatorname{softmax}(C\operatorname{tfidf}(w_1,\dots,w_{i-1})).$$
|
||||
|
||||
*** Bardziej skomplikowane sposoby ważenia słów
|
||||
|
||||
Można oczywiście połączyć odwrotną częstość dokumentową z uwzględnieniem pozycji słowa:
|
||||
|
||||
$$\omega(j, w_j) = \beta^{i-j-1}\operatorname{idf}_S(w_j).$$
|
||||
|
||||
*Uwaga*: „wagi” $\omega(j, w_j)$ nie są tak naprawdę wyuczalnymi
|
||||
wagami (parametrami) naszej sieci neuronowej, terminologia może być
|
||||
tutaj myląca. Z punktu widzenia sieci neuronowej $\omega(j, w_j)$ są
|
||||
stałe i *nie* są optymalizowane w procesie propagacji wstecznej. Innymi
|
||||
słowy, tak zdefiniowane $\omega(j, w_j)$ zależą tylko od:
|
||||
|
||||
- hiperparametru $\beta$, który może być optymalizowany już poza siecią (w procesie *hiperoptymalizacji*),
|
||||
- wartości $\operatorname{idf}_S(w_j)$ wyliczanych wcześniej na podstawie kolekcji $S$.
|
||||
|
||||
*Pytanie*: czy wagi $\omega(j, w_j)$ mogłyby sensownie uwzględniać
|
||||
jakieś parametry wyuczalne z całą siecią?
|
||||
|
||||
** Modelowanie języka przy użyciu bardziej złożonych neuronowych sieci /feed-forward/
|
||||
|
||||
Można połączyć zalety obu ogólnych podejść (n-gramowego modelu i worka
|
||||
słów) — można *równocześnie* traktować w specjalny sposób (na
|
||||
przykład) dwa poprzedzające wyrazy, wszystkie zaś inne wyrazy
|
||||
reprezentować jako „tło” modelowane za pomocą worka słów lub podobnej
|
||||
reprezentacji. Osiągamy to poprzez konkatenację wektora
|
||||
poprzedzającego słowa, słowa występującego dwie pozycje wstecz oraz
|
||||
zagregowanego zanurzenia całego wcześniejszego tekstu:
|
||||
|
||||
$$y = \operatorname{softmax}(C[E(w_{i-1}),E(w_{i-2}),A(w_1,\dots,w_{i-3})]),$$
|
||||
|
||||
czy lepiej z dodatkową warstwą ukrytą:
|
||||
|
||||
$$y = \operatorname{softmax}(C\operatorname{tgh}(W[E(w_{i-1}),E(w_{i-2}),A(w_1,\dots,w_{i-3})])),$$
|
||||
|
||||
W tak uzyskanym dwuwarstwowym neuronowym modelu języka, łączącym model
|
||||
trigramowy z workiem słów, macierz $W$ ma rozmiar $h \times 3m$.
|
||||
|
||||
*Pytanie*: jakie mamy możliwości, jeśli zamiast przewidywać kolejne słowo, mamy za zadanie
|
||||
odgadywać słowo w luce (jak w wyzwaniach typu /word gap/)?
|
||||
|
||||
** Literatura
|
||||
|
||||
Skuteczny n-gramowy neuronowy model języka opisano po raz pierwszy
|
||||
w pracy [[https://www.jmlr.org/papers/volume3/bengio03a/bengio03a.pdf][A Neural Probabilistic Language Model]] autorstwa Yoshua Bengio i in.
|
1
wyk/08_Neuronowy_ngramowy_model/bow1.drawio
Normal file
1
wyk/08_Neuronowy_ngramowy_model/bow1.drawio
Normal file
@ -0,0 +1 @@
|
||||
<mxfile host="app.diagrams.net" modified="2022-04-23T08:10:01.287Z" agent="5.0 (X11)" etag="DuwX-avzVRfuxOlr24Vt" version="17.4.6" type="device"><diagram id="UNyY5TJjaPirS19H5Hif" name="Page-1">7VpZd9o4GP01PJLjDWM/BgKZmaaTtjmnU+alR8XCVjCWI4sY8utHQjLexNKwk3kB6Wr/tvvJdsPsTmb3BMTBZ+zBsGFo3qxh3jUMw7V09suBuQB027UE4hPkSSwHntAblKAm0SnyYFLqSDEOKYrL4BBHERzSEgYIwWm52wiH5VVj4MMa8DQEYR39B3k0EKhjtHP8D4j8IFuZHVC0TEDWWU6RBMDDqYAWhzN7DbNLMKaiNJl1YciFl8lFSKC/onW5MQIjutWAbu/xCwqcTz//fvZerAc4TN6aUhkJnWcHhh47v6xiQgPs4wiEvRztEDyNPMhn1Vgt7/OAccxAnYHPkNK5VCaYUsyggE5C2QpniP7gw29asjaQk/Hy3axYmWeViJL5j2JlkM/Aq/mwRS0bN8IRlRvhIu+I8/JDrhRjpi88JUPZ6+vj5/Txfjy+f/gz+vbS96nuPDQNaY6A+JCukbG+VDbzEognkO2PjSMwBBS9lvcBpLn6y365RllBKlWt4HWbfAXhVK5U03iuT66cNEAUPsVgcfSUOXVZdyvF9QoJhbMCVD+xbDU06dsyJpiurKe5g+mmxIKCc2XY3oVkKoRkh2zVjodeWdGni5MzZ7HSn412BzGxtu8EkPVkC5c6V4TMZEPLkkwowWPYxSEmDIlwxH1rhMKwAoEQ+RGrDpnEIcM7XNKIRahb2TBBnrdwTJXqys66B+1ZFe1ZTl179jGV515KCHt/pLHrkUbZz1FGt1OFHvv8Qo/ulo1Xb9WNd2nQR7Fe/QIZOCfdQTbfGgZ+v9k7W5q9bp6V3Tvnb/enN3ttJeWijENDjMfNaVwgWHT99GrrFXq1Tkyvej2DTPCITsDsepVgVZSga4oMVTuqFrZKUQl+Gze6rYZjAI/LgIDUwzH+heACtRKaAn4ZD/nvGHCw0/Wgjxv87ijSW8TLrS6K2P/39SmuIkUW0C9SRT5Kdmw4BmPHou0sQ13Bdgy3dRjbUd4/zYvLMJYpxTHv+EPsPPe/uoM++itwv7eM3sTrZLI7mzv+uk2eU8LR0k94x1cK6ePm2ftLi+XQLxixJXJdt91yytKu6FB4mRxVfEK5aSKjMpFww9pEt4SAeaFbzDskv7FhS/u9fZX7s4LYQW6cS+G+315Vt+f1z6T0D/tMqmW1K6x7zKdSSkKoh+ArCzf7Id30SXvRSWwPevff/gWfsNW3ps3sPc+5kO66TZ4T6Zp22QmOSrpKIV1e6nkppGsZbjXkvZd2FVMdiHgVK22g3o0jdiZfpd3Wyffm5uZ6+dPcIls/FHsq5d9WBFeR6ehZhnOtujDM02UySl04/8fwA8XwpR53jeC1iQ4Uv2vrbIjeG/rvHLuVWWHrUux1Pxn0QTLjFWRsVmhC287M9qVZVcotLrpclCWd2y9TnDU0k4WQb1kHZuKzvDG/GBefU4u5VlyZ2S5RnKwig4JBgCQWn6ON0IwbVmcFDyj0u/VrCdOsU4OloAbrUJfc9qW42mkvuUrZbftNh72jK++k4MN8wrGTE1QvuUb7iJdcpZDq7/tTQOSrthBFCPPSGaeru8UkqxyTDMXrrn29KmXV/HNZQSr5R8dm7z8=</diagram></mxfile>
|
BIN
wyk/08_Neuronowy_ngramowy_model/bow1.drawio.png
Normal file
BIN
wyk/08_Neuronowy_ngramowy_model/bow1.drawio.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
1
wyk/08_Neuronowy_ngramowy_model/bow2.drawio
Normal file
1
wyk/08_Neuronowy_ngramowy_model/bow2.drawio
Normal file
@ -0,0 +1 @@
|
||||
<mxfile host="app.diagrams.net" modified="2022-04-23T09:02:43.180Z" agent="5.0 (X11)" etag="6a48B_aLc62Epg4yxUQr" version="17.4.6" type="device"><diagram id="UNyY5TJjaPirS19H5Hif" name="Page-1">5Vpdc+I2FP01nmkfkkGyAftxcYC2m22ym5lt05cdrS1sgbGIEDHw6ythGX/IEDYECOQBkI6vJOueo6srDYbpjud9hibhF+rjyIANf26YNwaEjgXEtwQWKQBajpUiASO+wnLggSyxAhsKnREfT0uGnNKIk0kZ9GgcY4+XMMQYTcpmAxqVR52gAGvAg4ciHf2H+DxMURu2c/wPTIIwG1lMMH0yRpmx6mIaIp8mKbSanNk1TJdRytPSeO7iSDov80vqgd6Gp+sXYzjmuzT4evclueuPRv3bP+NvT72AA/v2ykx7eUbRTE3YgK1I9NfxybMoBrJoQMGZlfww2h1yBY32TQpklmLIkvFqsnyReZDjucRDPo4EAERxyhkdYZdGlAkkprGw7AxIFFUgFJEgFlVPzBALvPOMGSeCm0/qwZj4vhymk4SE44cJ8uSYiVCiwBidxT6Wk2+sX6voLeVA2SeeFyDlvT6mY8zZQpiop1ZLaVJp2bJVPcmFkZmEBU2YCkNKisG655wtUVCE/QJ5juZr7AvxqiplPKQBjVHUzdGKV3KbW0onip4h5nyhViKacVomD88J/1c2v26q2qPqTJZv5sXK4iXnT+mMeXjLFFtqySMWYL7Fzk7t5Py3UslwhDh5Li/uNyemVbOqKkzlPIAN+i34/A3EC5yyeEFTF+9a0EdRL7DORb7C62xRaCSrj1l/spI3W9X2l729o+yB+a50b79/3Z9e9lBz0pQO+BjNL3jnBJXg09BZWGPHYWGnxIfR5chwm4YNkS99wFDi0wn9SfAKtaY8QTK5jeT3CEmw4/o4oIbMxdKkichy0yWx+P2+PXGqSbxS6CerIh8l5xKZtoi5Re1cAV070GkeRjsetYe9r85jj/wVOt+bsDv2O7W7+/acGXzYnLlptSv8HTNrTh4aT4BNWo/d/rf/0Gdq9axZduQ5q7TDcpxfSTxWtXvMiPCYFMF2NivJQzntAG737p6E9ucffw/9J+sWe9NlevDYI8lQTe8pEa+S7xLQqWqlXRFBmjipdsWz7stdwUpX6SS1rj4xhhYFs4k0mGqiW8/69TrUw8j19fXlRgKzkgOYzonjQLsmjKcxG2Sx+lK5gObpYnJtQGmeS0we0JirDqWDOxsi6AtnvmMGVbOy7Bq7xcGXO6qKYUNsfkW4rHVP+1wk8trbggNKa9dbtNaeEtwrBhzm0kwLijUe3LxntcpxErZrzq3mMQOlfsOSIKaOoRGJCV2VfnN/f9eb116kWFY5EMGaAyGAxyTF0UgRI7nFD6jU5QdusKmzPdQnG2uVebqNky+46m2dWZOYHOy6rpbbTFxnlKbvF/Iq2/zJU0MANAISPOKULZbIG8poxweXS4el35+YOiEHuzutZ0S/wV6ieMaWOCZY4EM0khegtRtT9wNtTGYNU/C4TOm33GyJ/JG8k04X0eWyUT2u1MSxIy8bSyMjMFzLcBzh/o9HSG0u/UaEiGr+v5r0AJr/O8ns/g8=</diagram></mxfile>
|
BIN
wyk/08_Neuronowy_ngramowy_model/bow2.drawio.png
Normal file
BIN
wyk/08_Neuronowy_ngramowy_model/bow2.drawio.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
1
wyk/08_Neuronowy_ngramowy_model/ngram-tgh.drawio
Normal file
1
wyk/08_Neuronowy_ngramowy_model/ngram-tgh.drawio
Normal file
@ -0,0 +1 @@
|
||||
<mxfile host="app.diagrams.net" modified="2022-04-23T07:25:35.437Z" agent="5.0 (X11)" etag="wQ0k74k1QtIDXs4Ob3ey" version="17.4.6" type="device"><diagram id="UNyY5TJjaPirS19H5Hif" name="Page-1">7Vpbc5s4FP41PCZjxMXwWBzb6W4y3TQz3c2+dFSjgGoZUVkOdn99pSDMTb6kviVxZzKxdDi68J2PcxEYVm8yHzKYxrc0RMQAnXBuWFcGAKYNOuJHShZK4ttWLokYDpWsFNzjn0gJ1cBohkM0rSlySgnHaV04okmCRrwmg4zRrK72SEl91RRGqCW4H0HSlv6LQx7nUg90S/k1wlFcrGy6fn5lAgtlNcU0hiHNctHzzVl9w+oxSnnemsx7iEj0ClxyBAYrri43xlDCtxlw9+k2+zQcj4c3H5PPPwYRN72bC5DP8gTJTN2w2ixfFAgwOktCJCcxDSvIYszRfQpH8momjC5kMZ8Qdbm9KbXPJ8Q4mldEapNDRCeIs4VQUVeBpUyvKANs1c9K/M1CJ65gX8igMnm0nLpERTQUMC8AydKA5BKxahDiJ9GM+POd2+Iv+2p0Ayxg7V7lgkJTLFxTboAssOF1JKec0THqUUKZkCQ0EZrBIyakIYIER4nojgTiSMgDiTQWBP6gLkxwGMpltKYrjdvZj/WWT7yynmW1rece03h+C2sUiidcdSnjMY1oAkm/lDZQKXVuKE2Veb4jzhfKXcEZp3XjoTnm/8nhl47qPajJZPtqXu0sNoE/pTM2Qmtu0VV+EbII8TV6Xq4n73+tKRkikOOnugfcu2HcV+h6OnXyXjht8treMdlr2m+FvgJ1tqgMkt2HYj7ZKYc993anvbcl7U3rVfHeewO8N09P/M7KoIuLKEooHV/M0kqIxe8/wLp2Iz3yTxxgTbNlqQyyKc+gEBKcYCpb79UcdjNb7Wiy1c5R7dHO6af0kU/g/B1bATQd2OnNsFXVwOjPsdFzDA/AUILAYBbSlH7D6Flqq8coJPL/GEph0AtRRA15x3nFgWXb6eFE/H5ZX3VoqpZc9I01JedSsAAfiISlRp7l4UOFPMB3DkOeEfW+D+78hwH+K/a/OKA/CQNtxXniHMEx6ygdtSzXgnS+qfH+Mlk19B+KxRKlrb1GEQ8aNsxzczWqeua0YSLQbUyUJ++tiT4wBhcVtVQqTLffcJEUbb2vur5o5DsoybkE9/f5qit41x8jmWd7jOQ4DQYe8RiJumlggX7wlc5ur3vh3dXH61FxUHoqZwOO5W0armVjZZ7dd36YLHUf+sPP/8O/qT2wZxfFQX2lMteCeqw6fN0mX1OMtbwTxlgtSNafGHugGGvbfiPv/O0o257qUHFWs9KGSLtxxM6xVsvbdqy9vLx8v+HSah4KaRzHocKlFv/ui3MdUb0G55vvALfhC46Y72gN6P1x/Ady/MsD213dfnOiQzn91jobXP4G/Z0dvjaV7J4HX1+anq9Ou7dIz50d+b9TwXWY9LzlkTUIro6yTt1Jm5pzQrN7zKrUfSus3yN7nTZ7V39fcCr2Oi328ihuG4sQnE5XJRkVyOE0zT9ue8Rzabp9sLn5zkT3ylfDZftQXG6/F5+N2YLLFx9v633iblaxukW9VPUqzn68iuiWHxzmobf8btPq/wI=</diagram></mxfile>
|
BIN
wyk/08_Neuronowy_ngramowy_model/ngram-tgh.drawio.png
Normal file
BIN
wyk/08_Neuronowy_ngramowy_model/ngram-tgh.drawio.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
1
wyk/08_Neuronowy_ngramowy_model/ngram.drawio
Normal file
1
wyk/08_Neuronowy_ngramowy_model/ngram.drawio
Normal file
@ -0,0 +1 @@
|
||||
<mxfile host="app.diagrams.net" modified="2022-04-23T06:52:34.125Z" agent="5.0 (X11)" etag="F7oHlS30BOIVpfAPOky4" version="17.1.3" type="device"><diagram id="UNyY5TJjaPirS19H5Hif" name="Page-1">7VpZc9owEP41fkwGn9iPhQA90mmTzKRNXzoqVmwV4XWFiKG/vhKW4zMYypUmfQHp0+r6dtlDg2b2p4sRQ3H4EXxMNaPjLzTzQjMMz9LFpwSWKaA7npUiASO+wnLghvzGCuwodE58PCsJcgDKSVwGxxBFeMxLGGIMkrLYPdDyrjEKcA24GSNaR78Qn4cp6hrdHH+LSRBmO4sLpiNTlAmrJWYh8iFJodXlzIFm9hkAT1vTRR9TSV7GS8rA8InRx4MxHPFNJlx9+ph8Gk0mo8t30fWvYcB19/LMSFd5QHSuLqwOy5cZAwzmkY/lIrpm9pKQcHwTo7EcTYTOBRbyKVXD9UOpcz5gxvGiAKlDjjBMMWdLIaJGDVOpXpmMYal+kvOvZzJhgfsMQ0rlwePSOSuioYjZgiSzgSSHil17PnkQzYCvbi4M20q+a90eEbR2L1IgkxQbl4QrJAtueJnJGWcwwX2gwAQSQSQke/eE0gqEKAki0R0LxrHAe5JpIgz4jRqYEt+X2zSqLlduZz/as4yy9kyzrj3nmMrzalxjX/zCVRcYDyGACNFBjlZYyWUuAWKlnp+Y86VyV2jOoaw8vCD8q5x+bqvenVpMti8Wxc6yjfwZzNkYr7mio/wiYgHma+TcVE7ef60qGaaIk4eyB9y7Ypzn53p0r2y8ul03Xss9pvXq1r9ivoJ1tixMkt27bD3Zyaeterubvbuh2evms7J79/nb/enNvvNkyCVZDKUAk7N5XAiw5OWHV8eqJEfeicOrrtc0lSA24wkSICURAdl6qeqwqrlqpyFX7RxVH/WMfgb3fIoWL1gLeiVsn14LG5UMDH5PtL6tuQbyJQcMJT7E8IPgFWqpX5FP5ecESbDX93EAmkyy03KDyLbdJ5H4vl1fcjSULCn0g1WR11KtiEJeZCtF23kMPQXbMTz7MLYzBvfn8Mq7G5L3oXdrG4Op32usNk+cH9h6maSjluSNJL3etHh/Waya+hmI2CLXtVsp4I2KDtO8XM0qvje1LGR0KwuliXttoTeMoWVBLJYCs80PnKVEG5+rLC8a6Qly43wk9+/ttanYXf+EpL/aJyTbrljgEZ+QkpvOL53Fzt1gdP0NfQBraM3P7NM6G2PbN6SKi2itrhsvnT22t1XXzo5eaCfN1IuPfcTKmqk2MPik9ZruCWNlI0nm64iV7Va/91hpWV4lffzraFlf6lDxsmGnlojZOmPnmNlot/WYeX5+/qzD3m6Oo/q00+A4jhr2ulvnLKII7f3TectOCjScii84dd7i/nf8B3L8hrenIqm60KGcfm2fFpffIr+twxfd/I8OqXj+dxFz8Ac=</diagram></mxfile>
|
BIN
wyk/08_Neuronowy_ngramowy_model/ngram.drawio.png
Normal file
BIN
wyk/08_Neuronowy_ngramowy_model/ngram.drawio.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
BIN
wyk/08_Neuronowy_ngramowy_model/tanh.png
Normal file
BIN
wyk/08_Neuronowy_ngramowy_model/tanh.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.3 KiB |
1
wyk/08_Neuronowy_ngramowy_model/trigram1.drawio
Normal file
1
wyk/08_Neuronowy_ngramowy_model/trigram1.drawio
Normal file
@ -0,0 +1 @@
|
||||
<mxfile host="app.diagrams.net" modified="2022-04-22T20:26:07.083Z" agent="5.0 (X11)" etag="6MNvURN8OzIm5K8R91Ac" version="17.1.3" type="device"><diagram id="UNyY5TJjaPirS19H5Hif" name="Page-1">5VldU+IwFP01fdTpJ5RHQXB3R8d1ndldn3YiiW0k7WVDsOCv34SmtKWBRVERfYHk5Puec3OT1PJ6yeyMo3F8AZgwy7XxzPJOLdft+I78VcA8B5xWx8+RiFOssRK4po9Eg7ZGpxSTSa2iAGCCjuvgENKUDEUNQ5xDVq92B6w+6hhFpAFcDxFror8oFnGOhm67xL8QGsXFyHKBeUmCisq6i0mMMGQ5tFic17e8HgcQeSqZ9QhTxivskltgsKZ0OTFOUrFNgyGE94Orzs2Afos7PwO3n+DukV7GRMyLBRMs16+zwEUMEaSI9Uu0y2GaYqJ6tWWurHMOMJagI8F7IsRck4mmAiQUi4TpUjKj4nclfaO7UunTWTUzLzKp4HPVxD4OiuxN0YPKlM0WuaJdvjq1pLVGK9iBKR/qWleXF9nl2Wh0dv41/fF3EAknPD9ytfgQj4jYUK+1pFb6BIGEyPnIdpwwJOhDfR5IizNa1iv5kwlNoZnOTZN8QGyqR2rwW7KnjJfFVJDrMVosPZMuXGdqrbkeCBdkVoGaK9alnq09We8Arq/zWelOjqexuOJKBbaLkYyab9rkDTWvBXwoqve2VL27o+oXTU84R/NKhTHQVEwqPX9XQEVaraAmLa++A8pE3mMpleXUnu9insHFWkzapovpg0xGYsGAjHJ+9sdqd6m0Tfs0B4qacuBa5RU5Ss8SdfVMBIcR6QEDLpEUUqXJO8rYCoQYjVKZHUqiicS7yk+pjGYnuiChGC8EbXL8ushfwvd920hQ1fdbr+T6RvI6h+L6z/fY1pYeGxp3iX0Frtb7C1zFeaoQrxM0xeu7b6lexz8U+e4WuZ4j+3BL2Tveu9J9+P51v3/Z22tDLi1iKAMYHU3HlQBLP354DZyVo3W45/DqOA2mMsQnIkMSZDSloFIflQ7fW6HDNtx07Dflo3kfnMCdSNDsA7Ow4hTO/lnY6srA4XFk9QIrdBFWNuAowzCGW0oWqK+9CDP1O0IK7PYwicBSm3F+3aAqHfRoKv9/br5yGK4sOXTLV5HPcltxQ/e4fqFchp6KdtxO8DraMb5VmKSz+/mgYROD5bbf5vb+oPNJjsX/f9DZ9QGm8cLih/6x+Y1l2Ul+MtftSiK36Mptr3SVH94bXT31WcgwUsd+6tzqLXZ+SjLq1nTp3fyU5BzyU9Juu06wRocvf9aV2fKrTM51+W3L6/8D</diagram></mxfile>
|
BIN
wyk/08_Neuronowy_ngramowy_model/trigram1.drawio.png
Normal file
BIN
wyk/08_Neuronowy_ngramowy_model/trigram1.drawio.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
Loading…
Reference in New Issue
Block a user