AI-For-Beginners/translations/cs/lessons/5-NLP/14-Embeddings/EmbeddingsPyTorch.ipynb

726 lines
28 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Vektorizace\n",
"\n",
"V našem předchozím příkladu jsme pracovali s vysoko-dimenzionálními vektory bag-of-words o délce `vocab_size` a explicitně jsme převáděli nízko-dimenzionální poziční reprezentace na řídké one-hot reprezentace. Tato one-hot reprezentace není paměťově efektivní, navíc je každý slovní prvek zpracováván nezávisle na ostatních, tj. one-hot kódované vektory nevyjadřují žádnou sémantickou podobnost mezi slovy.\n",
"\n",
"V této části budeme pokračovat v průzkumu datasetu **News AG**. Nejprve načtěme data a získáme některé definice z předchozího notebooku.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Loading dataset...\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"d:\\WORK\\ai-for-beginners\\5-NLP\\14-Embeddings\\data\\train.csv: 29.5MB [00:01, 18.8MB/s] \n",
"d:\\WORK\\ai-for-beginners\\5-NLP\\14-Embeddings\\data\\test.csv: 1.86MB [00:00, 11.2MB/s] \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Building vocab...\n",
"Vocab size = 95812\n"
]
}
],
"source": [
"import torch\n",
"import torchtext\n",
"import numpy as np\n",
"from torchnlp import *\n",
"train_dataset, test_dataset, classes, vocab = load_dataset()\n",
"vocab_size = len(vocab)\n",
"print(\"Vocab size = \",vocab_size)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Co je to embedding?\n",
"\n",
"Myšlenka **embeddingu** spočívá v reprezentaci slov pomocí nižší dimenze hustých vektorů, které nějakým způsobem odrážejí sémantický význam slova. Později si povíme, jak vytvořit smysluplné word embeddings, ale prozatím si představme embeddingy jako způsob, jak snížit dimenzionalitu vektoru slova.\n",
"\n",
"Embeddingová vrstva tedy přijme slovo jako vstup a vytvoří výstupní vektor o specifikované velikosti `embedding_size`. V jistém smyslu je velmi podobná vrstvě `Linear`, ale místo toho, aby přijímala vektor zakódovaný metodou one-hot, dokáže přijmout číslo slova jako vstup.\n",
"\n",
"Použitím embeddingové vrstvy jako první vrstvy v naší síti můžeme přejít od modelu bag-of-words k modelu **embedding bag**, kde nejprve převedeme každé slovo v našem textu na odpovídající embedding a poté vypočítáme nějakou agregační funkci přes všechny tyto embeddingy, například `sum`, `average` nebo `max`.\n",
"\n",
"![Obrázek ukazující klasifikátor embeddingu pro pět slov v sekvenci.](../../../../../translated_images/cs/embedding-classifier-example.b77f021a7ee67eee.webp)\n",
"\n",
"Naše klasifikační neuronová síť začne embeddingovou vrstvou, poté agregační vrstvou a na vrcholu bude lineární klasifikátor:\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"class EmbedClassifier(torch.nn.Module):\n",
" def __init__(self, vocab_size, embed_dim, num_class):\n",
" super().__init__()\n",
" self.embedding = torch.nn.Embedding(vocab_size, embed_dim)\n",
" self.fc = torch.nn.Linear(embed_dim, num_class)\n",
"\n",
" def forward(self, x):\n",
" x = self.embedding(x)\n",
" x = torch.mean(x,dim=1)\n",
" return self.fc(x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Práce s proměnnou délkou sekvence\n",
"\n",
"V důsledku této architektury je nutné vytvářet minibatch pro naši síť určitým způsobem. V předchozí části, při použití metody bag-of-words, měly všechny BoW tenzory v minibatch stejnou velikost `vocab_size`, bez ohledu na skutečnou délku textové sekvence. Jakmile přejdeme na slovní vektory (word embeddings), skončíme s proměnným počtem slov v každém textovém vzorku, a při kombinování těchto vzorků do minibatch bude nutné použít nějaké doplnění (padding).\n",
"\n",
"To lze provést pomocí stejné techniky, kdy se funkce `collate_fn` poskytne datovému zdroji:\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"def padify(b):\n",
" # b is the list of tuples of length batch_size\n",
" # - first element of a tuple = label, \n",
" # - second = feature (text sequence)\n",
" # build vectorized sequence\n",
" v = [encode(x[1]) for x in b]\n",
" # first, compute max length of a sequence in this minibatch\n",
" l = max(map(len,v))\n",
" return ( # tuple of two tensors - labels and features\n",
" torch.LongTensor([t[0]-1 for t in b]),\n",
" torch.stack([torch.nn.functional.pad(torch.tensor(t),(0,l-len(t)),mode='constant',value=0) for t in v])\n",
" )\n",
"\n",
"train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=padify, shuffle=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Trénování klasifikátoru embeddingů\n",
"\n",
"Nyní, když jsme definovali správný dataloader, můžeme model natrénovat pomocí trénovací funkce, kterou jsme definovali v předchozí části:\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.6415625\n",
"6400: acc=0.6865625\n",
"9600: acc=0.7103125\n",
"12800: acc=0.726953125\n",
"16000: acc=0.739375\n",
"19200: acc=0.75046875\n",
"22400: acc=0.7572321428571429\n"
]
},
{
"data": {
"text/plain": [
"(0.889799795315499, 0.7623160588611644)"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"net = EmbedClassifier(vocab_size,32,len(classes)).to(device)\n",
"train_epoch(net,train_loader, lr=1, epoch_size=25000)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Poznámka**: Zde trénujeme pouze na 25 tisíc záznamů (méně než jeden celý epoch) kvůli úspoře času, ale můžete pokračovat v tréninku, napsat funkci pro trénink na několik epoch a experimentovat s parametrem rychlosti učení, abyste dosáhli vyšší přesnosti. Měli byste být schopni dosáhnout přesnosti kolem 90 %.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Vrstva EmbeddingBag a reprezentace sekvencí s proměnnou délkou\n",
"\n",
"V předchozí architektuře jsme museli všechny sekvence doplnit na stejnou délku, aby se vešly do minibatch. To není nejefektivnější způsob, jak reprezentovat sekvence s proměnnou délkou jiný přístup by byl použití **offsetového** vektoru, který by obsahoval offsety všech sekvencí uložených v jednom velkém vektoru.\n",
"\n",
"![Obrázek znázorňující reprezentaci sekvencí pomocí offsetů](../../../../../translated_images/cs/offset-sequence-representation.eb73fcefb29b46ee.webp)\n",
"\n",
"> **Note**: Na obrázku výše je znázorněna sekvence znaků, ale v našem příkladu pracujeme se sekvencemi slov. Nicméně obecný princip reprezentace sekvencí pomocí offsetového vektoru zůstává stejný.\n",
"\n",
"Pro práci s offsetovou reprezentací používáme vrstvu [`EmbeddingBag`](https://pytorch.org/docs/stable/generated/torch.nn.EmbeddingBag.html). Je podobná vrstvě `Embedding`, ale jako vstup bere obsahový vektor a offsetový vektor, a navíc zahrnuje vrstvu pro průměrování, která může být `mean`, `sum` nebo `max`.\n",
"\n",
"Zde je upravená síť, která používá `EmbeddingBag`:\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"class EmbedClassifier(torch.nn.Module):\n",
" def __init__(self, vocab_size, embed_dim, num_class):\n",
" super().__init__()\n",
" self.embedding = torch.nn.EmbeddingBag(vocab_size, embed_dim)\n",
" self.fc = torch.nn.Linear(embed_dim, num_class)\n",
"\n",
" def forward(self, text, off):\n",
" x = self.embedding(text, off)\n",
" return self.fc(x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Pro přípravu datové sady pro trénink musíme poskytnout konverzní funkci, která připraví vektor offsetu:\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"def offsetify(b):\n",
" # first, compute data tensor from all sequences\n",
" x = [torch.tensor(encode(t[1])) for t in b]\n",
" # now, compute the offsets by accumulating the tensor of sequence lengths\n",
" o = [0] + [len(t) for t in x]\n",
" o = torch.tensor(o[:-1]).cumsum(dim=0)\n",
" return ( \n",
" torch.LongTensor([t[0]-1 for t in b]), # labels\n",
" torch.cat(x), # text \n",
" o\n",
" )\n",
"\n",
"train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=offsetify, shuffle=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Všimněte si, že na rozdíl od všech předchozích příkladů naše síť nyní přijímá dva parametry: datový vektor a vektor offsetu, které mají různé velikosti. Podobně nám náš datový nakladač poskytuje 3 hodnoty místo 2: jako vlastnosti jsou poskytovány jak textové, tak offsetové vektory. Proto musíme mírně upravit naši trénovací funkci, aby to zohlednila:\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.6153125\n",
"6400: acc=0.6615625\n",
"9600: acc=0.6932291666666667\n",
"12800: acc=0.715078125\n",
"16000: acc=0.7270625\n",
"19200: acc=0.7382291666666667\n",
"22400: acc=0.7486160714285715\n"
]
},
{
"data": {
"text/plain": [
"(22.771553103007037, 0.7551983365323096)"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"net = EmbedClassifier(vocab_size,32,len(classes)).to(device)\n",
"\n",
"def train_epoch_emb(net,dataloader,lr=0.01,optimizer=None,loss_fn = torch.nn.CrossEntropyLoss(),epoch_size=None, report_freq=200):\n",
" optimizer = optimizer or torch.optim.Adam(net.parameters(),lr=lr)\n",
" loss_fn = loss_fn.to(device)\n",
" net.train()\n",
" total_loss,acc,count,i = 0,0,0,0\n",
" for labels,text,off in dataloader:\n",
" optimizer.zero_grad()\n",
" labels,text,off = labels.to(device), text.to(device), off.to(device)\n",
" out = net(text, off)\n",
" loss = loss_fn(out,labels) #cross_entropy(out,labels)\n",
" loss.backward()\n",
" optimizer.step()\n",
" total_loss+=loss\n",
" _,predicted = torch.max(out,1)\n",
" acc+=(predicted==labels).sum()\n",
" count+=len(labels)\n",
" i+=1\n",
" if i%report_freq==0:\n",
" print(f\"{count}: acc={acc.item()/count}\")\n",
" if epoch_size and count>epoch_size:\n",
" break\n",
" return total_loss.item()/count, acc.item()/count\n",
"\n",
"\n",
"train_epoch_emb(net,train_loader, lr=4, epoch_size=25000)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Sémantické vektory: Word2Vec\n",
"\n",
"V našem předchozím příkladu se vrstva modelu pro vektorizaci naučila mapovat slova na jejich vektorovou reprezentaci, avšak tato reprezentace neměla příliš velký sémantický význam. Bylo by skvělé naučit se takovou vektorovou reprezentaci, kde by podobná slova nebo synonyma odpovídala vektorům, které jsou blízko sebe podle určité vektorové vzdálenosti (např. euklidovské vzdálenosti).\n",
"\n",
"Abychom toho dosáhli, musíme náš model pro vektorizaci předem natrénovat na velké kolekci textů specifickým způsobem. Jedním z prvních způsobů, jak trénovat sémantické vektory, je metoda nazvaná [Word2Vec](https://en.wikipedia.org/wiki/Word2vec). Ta je založena na dvou hlavních architekturách, které se používají k vytvoření distribuované reprezentace slov:\n",
"\n",
" - **Continuous bag-of-words** (CBoW) — v této architektuře trénujeme model, aby předpovídal slovo na základě okolního kontextu. Při daném ngramu $(W_{-2},W_{-1},W_0,W_1,W_2)$ je cílem modelu předpovědět $W_0$ na základě $(W_{-2},W_{-1},W_1,W_2)$.\n",
" - **Continuous skip-gram** je opakem CBoW. Model využívá okolní okno kontextových slov k předpovědi aktuálního slova.\n",
"\n",
"CBoW je rychlejší, zatímco skip-gram je pomalejší, ale lépe reprezentuje méně častá slova.\n",
"\n",
"![Obrázek ukazující algoritmy CBoW a Skip-Gram pro převod slov na vektory.](../../../../../translated_images/cs/example-algorithms-for-converting-words-to-vectors.fbe9207a726922f6.webp)\n",
"\n",
"Pro experimentování s Word2Vec vektory předem natrénovanými na datasetu Google News můžeme použít knihovnu **gensim**. Níže najdeme slova nejpodobnější slovu 'neural'.\n",
"\n",
"> **Note:** Když poprvé vytváříte vektorové reprezentace slov, jejich stahování může chvíli trvat!\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"import gensim.downloader as api\n",
"w2v = api.load('word2vec-google-news-300')"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"neuronal -> 0.7804799675941467\n",
"neurons -> 0.7326500415802002\n",
"neural_circuits -> 0.7252851724624634\n",
"neuron -> 0.7174385190010071\n",
"cortical -> 0.6941086649894714\n",
"brain_circuitry -> 0.6923246383666992\n",
"synaptic -> 0.6699118614196777\n",
"neural_circuitry -> 0.6638563275337219\n",
"neurochemical -> 0.6555314064025879\n",
"neuronal_activity -> 0.6531826257705688\n"
]
}
],
"source": [
"for w,p in w2v.most_similar('neural'):\n",
" print(f\"{w} -> {p}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Můžeme také vypočítat vektorové embeddingy ze slova, které budou použity při trénování klasifikačního modelu (pro přehlednost zobrazujeme pouze prvních 20 komponent vektoru):\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 0.01226807, 0.06225586, 0.10693359, 0.05810547, 0.23828125,\n",
" 0.03686523, 0.05151367, -0.20703125, 0.01989746, 0.10058594,\n",
" -0.03759766, -0.1015625 , -0.15820312, -0.08105469, -0.0390625 ,\n",
" -0.05053711, 0.16015625, 0.2578125 , 0.10058594, -0.25976562],\n",
" dtype=float32)"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"w2v.word_vec('play')[:20]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Skvělá věc na sémantických vnořeních je, že můžete manipulovat s vektorovým kódováním, abyste změnili sémantiku. Například můžeme požádat o nalezení slova, jehož vektorová reprezentace by byla co nejblíže slovům *král* a *žena* a co nejdále od slova *muž*:\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"('queen', 0.7118192911148071)"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"w2v.most_similar(positive=['king','woman'],negative=['man'])[0]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Oba modely, CBoW i Skip-Grams, jsou „prediktivní“ vektorizace, protože berou v úvahu pouze lokální kontexty. Word2Vec nevyužívá globální kontext.\n",
"\n",
"**FastText** staví na Word2Vec tím, že se učí vektorové reprezentace pro každé slovo a n-gramy znaků, které se v daném slově nacházejí. Hodnoty těchto reprezentací se pak při každém kroku trénování zprůměrují do jednoho vektoru. I když to přidává značné množství výpočetní náročnosti při předtrénování, umožňuje to vektorizacím slov zakódovat informace o podslovech.\n",
"\n",
"Další metoda, **GloVe**, využívá myšlenku matice společného výskytu a používá neuronové metody k dekompozici této matice do expresivnějších a nelineárních vektorů slov.\n",
"\n",
"Můžete si vyzkoušet příklad tím, že změníte vektorizace na FastText a GloVe, protože gensim podporuje několik různých modelů vektorizace slov.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Použití předtrénovaných vektorů v PyTorch\n",
"\n",
"Můžeme upravit výše uvedený příklad tak, aby byla matice v naší vrstvě embedding předem naplněna sémantickými vektory, jako je Word2Vec. Musíme vzít v úvahu, že slovníky předtrénovaných vektorů a našeho textového korpusu se pravděpodobně nebudou shodovat, takže inicializujeme váhy pro chybějící slova náhodnými hodnotami:\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Embedding size: 300\n",
"Populating matrix, this will take some time...Done, found 41080 words, 54732 words missing\n"
]
}
],
"source": [
"embed_size = len(w2v.get_vector('hello'))\n",
"print(f'Embedding size: {embed_size}')\n",
"\n",
"net = EmbedClassifier(vocab_size,embed_size,len(classes))\n",
"\n",
"print('Populating matrix, this will take some time...',end='')\n",
"found, not_found = 0,0\n",
"for i,w in enumerate(vocab.get_itos()):\n",
" try:\n",
" net.embedding.weight[i].data = torch.tensor(w2v.get_vector(w))\n",
" found+=1\n",
" except:\n",
" net.embedding.weight[i].data = torch.normal(0.0,1.0,(embed_size,))\n",
" not_found+=1\n",
"\n",
"print(f\"Done, found {found} words, {not_found} words missing\")\n",
"net = net.to(device)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Nyní pojďme natrénovat náš model. Všimněte si, že doba potřebná k natrénování modelu je výrazně delší než v předchozím příkladu, a to kvůli větší velikosti vrstvy vnoření, a tím pádem mnohem vyššímu počtu parametrů. Také z tohoto důvodu možná budeme muset natrénovat náš model na více příkladech, pokud se chceme vyhnout přeučení.\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.6359375\n",
"6400: acc=0.68109375\n",
"9600: acc=0.7067708333333333\n",
"12800: acc=0.723671875\n",
"16000: acc=0.73625\n",
"19200: acc=0.7463541666666667\n",
"22400: acc=0.7560714285714286\n"
]
},
{
"data": {
"text/plain": [
"(214.1013875559821, 0.7626759436980166)"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"train_epoch_emb(net,train_loader, lr=4, epoch_size=25000)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"V našem případě nevidíme výrazné zvýšení přesnosti, což je pravděpodobně způsobeno velmi odlišnými slovníky. \n",
"Abychom překonali problém odlišných slovníků, můžeme použít jedno z následujících řešení: \n",
"* Znovu natrénovat model word2vec na našem slovníku \n",
"* Načíst náš dataset se slovníkem z předtrénovaného modelu word2vec. Slovník použitý k načtení datasetu lze specifikovat během načítání. \n",
"\n",
"Druhý přístup se zdá být jednodušší, zejména proto, že framework `torchtext` v PyTorch obsahuje vestavěnou podporu pro embeddingy. Můžeme například vytvořit slovník založený na GloVe následujícím způsobem: \n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"100%|█████████▉| 399999/400000 [00:15<00:00, 25411.14it/s]\n"
]
}
],
"source": [
"vocab = torchtext.vocab.GloVe(name='6B', dim=50)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Načtená slovní zásoba má následující základní operace:\n",
"* Slovník `vocab.stoi` nám umožňuje převést slovo na jeho index ve slovníku\n",
"* `vocab.itos` dělá opak - převádí číslo na slovo\n",
"* `vocab.vectors` je pole vektorů pro vkládání, takže pro získání vektoru pro slovo `s` musíme použít `vocab.vectors[vocab.stoi[s]]`\n",
"\n",
"Zde je příklad manipulace s vektory pro demonstraci rovnice **kind-man+woman = queen** (musel jsem trochu upravit koeficient, aby to fungovalo):\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'queen'"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# get the vector corresponding to kind-man+woman\n",
"qvec = vocab.vectors[vocab.stoi['king']]-vocab.vectors[vocab.stoi['man']]+1.3*vocab.vectors[vocab.stoi['woman']]\n",
"# find the index of the closest embedding vector \n",
"d = torch.sum((vocab.vectors-qvec)**2,dim=1)\n",
"min_idx = torch.argmin(d)\n",
"# find the corresponding word\n",
"vocab.itos[min_idx]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"K trénování klasifikátoru pomocí těchto vektorových reprezentací musíme nejprve zakódovat náš dataset pomocí slovníku GloVe:\n"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"def offsetify(b):\n",
" # first, compute data tensor from all sequences\n",
" x = [torch.tensor(encode(t[1],voc=vocab)) for t in b] # pass the instance of vocab to encode function!\n",
" # now, compute the offsets by accumulating the tensor of sequence lengths\n",
" o = [0] + [len(t) for t in x]\n",
" o = torch.tensor(o[:-1]).cumsum(dim=0)\n",
" return ( \n",
" torch.LongTensor([t[0]-1 for t in b]), # labels\n",
" torch.cat(x), # text \n",
" o\n",
" )"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Jak jsme viděli výše, všechny vektorové embeddingy jsou uloženy v matici `vocab.vectors`. To umožňuje velmi snadné načtení těchto vah do vah vrstvy embeddingu pomocí jednoduchého kopírování:\n"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"net = EmbedClassifier(len(vocab),len(vocab.vectors[0]),len(classes))\n",
"net.embedding.weight.data = vocab.vectors\n",
"net = net.to(device)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Nyní pojďme natrénovat náš model a zjistit, zda dosáhneme lepších výsledků:\n"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.6271875\n",
"6400: acc=0.68078125\n",
"9600: acc=0.7030208333333333\n",
"12800: acc=0.71984375\n",
"16000: acc=0.7346875\n",
"19200: acc=0.7455729166666667\n",
"22400: acc=0.7529464285714286\n"
]
},
{
"data": {
"text/plain": [
"(35.53972978646833, 0.7575175943698017)"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=offsetify, shuffle=True)\n",
"train_epoch_emb(net,train_loader, lr=4, epoch_size=25000)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Jedním z důvodů, proč nevidíme významné zvýšení přesnosti, je skutečnost, že některá slova z našeho datového souboru chybí v předtrénovaném slovníku GloVe, a proto jsou v podstatě ignorována. Abychom tuto skutečnost překonali, můžeme na našem datovém souboru natrénovat vlastní vektory slov.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Kontextuální vektory slov\n",
"\n",
"Jedním z hlavních omezení tradičních předtrénovaných reprezentací vektorů slov, jako je Word2Vec, je problém s rozlišením významu slov. Zatímco předtrénované vektory dokážou zachytit část významu slov v kontextu, každý možný význam slova je zakódován do stejného vektoru. To může způsobovat problémy v následných modelech, protože mnoho slov, například slovo „play“, má různé významy v závislosti na kontextu, ve kterém jsou použity.\n",
"\n",
"Například slovo „play“ má v těchto dvou větách zcela odlišný význam:\n",
"- Šel jsem na **hru** do divadla.\n",
"- John si chce **hrát** se svými přáteli.\n",
"\n",
"Předtrénované vektory výše reprezentují oba tyto významy slova „play“ stejným vektorem. Abychom toto omezení překonali, musíme vytvářet vektory založené na **jazykovém modelu**, který je natrénován na rozsáhlém korpusu textu a *rozumí*, jak lze slova skládat v různých kontextech. Diskuze o kontextuálních vektorech slov přesahuje rámec tohoto tutoriálu, ale vrátíme se k nim při probírání jazykových modelů v další části.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Upozornění**: \nTento dokument byl přeložen pomocí služby pro automatický překlad [Co-op Translator](https://github.com/Azure/co-op-translator). I když se snažíme o přesnost, mějte prosím na paměti, že automatické překlady mohou obsahovat chyby nebo nepřesnosti. Původní dokument v jeho původním jazyce by měl být považován za závazný zdroj. Pro důležité informace se doporučuje profesionální lidský překlad. Neodpovídáme za jakékoli nedorozumění nebo nesprávné interpretace vyplývající z použití tohoto překladu.\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "0cb620c6d4b9f7a635928804c26cf22403d89d98d79684e4529119355ee6d5a5"
},
"kernelspec": {
"display_name": "py37_pytorch",
"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.8.12"
},
"coopTranslator": {
"original_hash": "f50b026abce5cf36783a560ea72cb9b1",
"translation_date": "2025-08-29T16:35:48+00:00",
"source_file": "lessons/5-NLP/14-Embeddings/EmbeddingsPyTorch.ipynb",
"language_code": "cs"
}
},
"nbformat": 4,
"nbformat_minor": 2
}