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

726 lines
36 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": [
"## Угњеждења\n",
"\n",
"У нашем претходном примеру, радили смо са векторима високе димензионалности заснованим на моделу \"вреће речи\" са дужином `vocab_size`, и експлицитно смо конвертовали векторе ниске димензионалности позиционе репрезентације у ретке једноелементне репрезентације. Ова једноелементна репрезентација није меморијски ефикасна, а поред тога, свака реч се третира независно од других, тј. вектори кодирани једноелементно не изражавају никакву семантичку сличност између речи.\n",
"\n",
"У овој јединици наставићемо истраживање **News AG** скупа података. За почетак, хајде да учитамо податке и преузмемо неке дефиниције из претходног нотебука.\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": [
"## Шта је угњеждавање?\n",
"\n",
"Идеја **угњеждавања** је да се речи представе као густе векторе нижих димензија, који на неки начин одражавају семантичко значење речи. Касније ћемо разговарати о томе како изградити смислене угњеждене представе речи, али за сада замислимо угњеждавање као начин смањења димензионалности вектора речи.\n",
"\n",
"Дакле, слој за угњеждавање узима реч као улаз и производи излазни вектор одређене величине `embedding_size`. У суштини, веома је сличан слоју `Linear`, али уместо да узима једновекторски кодирани улаз, он може узети број речи као улаз.\n",
"\n",
"Користећи слој за угњеждавање као први слој у нашој мрежи, можемо прећи са модела торбе речи на модел **торбе угњеждавања**, где прво конвертујемо сваку реч у нашем тексту у одговарајуће угњеждавање, а затим израчунавамо неку агрегатну функцију над свим тим угњеждавањима, као што су `sum`, `average` или `max`.\n",
"\n",
"![Слика која приказује класификатор угњеждавања за пет речи у низу.](../../../../../translated_images/sr/embedding-classifier-example.b77f021a7ee67eee.webp)\n",
"\n",
"Наша неуронска мрежа класификатора ће почети са слојем за угњеждавање, затим слојем за агрегирање, и линеарним класификатором на врху:\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": [
"### Рад са променљивом дужином секвенце\n",
"\n",
"Као резултат ове архитектуре, минибатчеви за нашу мрежу морају бити креирани на одређени начин. У претходној јединици, када смо користили bag-of-words, сви BoW тензори у једном минибатчу имали су исту величину `vocab_size`, без обзира на стварну дужину наше текстуалне секвенце. Када пређемо на уграђивање речи (word embeddings), завршићемо са променљивим бројем речи у сваком узорку текста, и приликом комбиновања тих узорака у минибатчеве мораћемо да применимо неко попуњавање (padding).\n",
"\n",
"Ово се може урадити коришћењем исте технике пружања функције `collate_fn` извору података:\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": [
"### Тренинг класификатора за уграђивање\n",
"\n",
"Сада када смо дефинисали одговарајући учитавач података, можемо тренирати модел користећи функцију за тренинг коју смо дефинисали у претходној јединици:\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": [
"> **Напомена**: Овде тренирамо само за 25 хиљада записа (мање од једне целе епохе) ради уштеде времена, али можете наставити са тренингом, написати функцију за тренинг током неколико епоха и експериментисати са параметром стопе учења како бисте постигли већу тачност. Требало би да будете у могућности да постигнете тачност од око 90%.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Слој EmbeddingBag и репрезентација секвенци променљиве дужине\n",
"\n",
"У претходној архитектури, морали смо да попунимо све секвенце до исте дужине како би се уклопиле у мини серију. Ово није најефикаснији начин за представљање секвенци променљиве дужине - други приступ би био коришћење **вектора офсета**, који би садржао офсете свих секвенци смештених у један велики вектор.\n",
"\n",
"![Слика која приказује репрезентацију секвенци са офсетом](../../../../../translated_images/sr/offset-sequence-representation.eb73fcefb29b46ee.webp)\n",
"\n",
"> **Note**: На слици изнад приказујемо секвенцу карактера, али у нашем примеру радимо са секвенцама речи. Међутим, општи принцип представљања секвенци помоћу вектора офсета остаје исти.\n",
"\n",
"За рад са репрезентацијом офсета користимо слој [`EmbeddingBag`](https://pytorch.org/docs/stable/generated/torch.nn.EmbeddingBag.html). Сличан је слоју `Embedding`, али узима вектор садржаја и вектор офсета као улаз, а такође укључује слој за просечавање, који може бити `mean`, `sum` или `max`.\n",
"\n",
"Ево модификоване мреже која користи `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": [
"Да бисмо припремили скуп података за тренирање, потребно је да обезбедимо функцију за конверзију која ће припремити вектор померања:\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": [
"Напомена, да за разлику од свих претходних примера, наша мрежа сада прихвата два параметра: вектор података и вектор помераја, који су различитих величина. Слично томе, наш учитач података нам такође пружа 3 вредности уместо 2: и текстуални и вектори помераја су обезбеђени као карактеристике. Због тога, потребно је да мало прилагодимо нашу функцију за обуку како бисмо то узели у обзир:\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": [
"## Семантичка угнежђења: Word2Vec\n",
"\n",
"У нашем претходном примеру, слој за угнежђење модела је научио да мапира речи у векторске репрезентације, али та репрезентација није имала много семантичког значења. Било би корисно научити такву векторску репрезентацију где би сличне речи или синоними одговарали векторима који су блиски једни другима у смислу неке векторске удаљености (нпр. еуклидске удаљености).\n",
"\n",
"Да бисмо то постигли, потребно је да претходно обучимо наш модел за угнежђење на великој збирци текста на специфичан начин. Један од првих начина за обуку семантичких угнежђења назива се [Word2Vec](https://en.wikipedia.org/wiki/Word2vec). Овај метод се заснива на две главне архитектуре које се користе за добијање дистрибуиране репрезентације речи:\n",
"\n",
" - **Континуирана торба речи** (CBoW) — у овој архитектури, обучавамо модел да предвиди реч из околног контекста. Дат је нграм $(W_{-2},W_{-1},W_0,W_1,W_2)$, циљ модела је да предвиди $W_0$ из $(W_{-2},W_{-1},W_1,W_2)$.\n",
" - **Континуирани skip-gram** је супротан од CBoW. Модел користи околни прозор контекстуалних речи да би предвидео тренутну реч.\n",
"\n",
"CBoW је бржи, док је skip-gram спорији, али боље представља речи које се ређе јављају.\n",
"\n",
"![Слика која приказује и CBoW и Skip-Gram алгоритме за претварање речи у векторе.](../../../../../translated_images/sr/example-algorithms-for-converting-words-to-vectors.fbe9207a726922f6.webp)\n",
"\n",
"Да бисмо експериментисали са Word2Vec угнежђењем претходно обученим на Google News скупу података, можемо користити библиотеку **gensim**. Испод налазимо речи које су најсличније речи 'neural'.\n",
"\n",
"> **Напомена:** Када први пут креирате векторе речи, њихово преузимање може потрајати!\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": [
"Можемо такође израчунати векторске уграђене вредности из речи, које ће се користити у обуци модела класификације (приказујемо само првих 20 компоненти вектора ради јасноће):\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": [
"Сјајна ствар код семантичких уграђивања је то што можете манипулисати векторским кодирањем како бисте променили семантику. На пример, можемо тражити реч чија би векторска репрезентација била што је могуће ближа речима *краљ* и *жена*, а што даља од речи *мушкарац*:\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": [
"И CBoW и Skip-Grams су „предиктивни“ уграђивања, јер узимају у обзир само локалне контексте. Word2Vec не користи предности глобалног контекста.\n",
"\n",
"**FastText** се надовезује на Word2Vec тако што учи векторске репрезентације за сваку реч и карактер n-граме који се налазе унутар сваке речи. Вредности репрезентација се затим просечавају у један вектор на сваком кораку тренинга. Иако ово додаје доста додатних рачунања током пред-тренинга, омогућава уграђивањима речи да кодирају информације о под-речима.\n",
"\n",
"Друга метода, **GloVe**, користи идеју матрице ко-јављања и примењује неуронске методе за декомпозицију матрице ко-јављања у изражајније и нелинеарне векторе речи.\n",
"\n",
"Можете се играти са примером тако што ћете променити уграђивања на FastText и GloVe, пошто gensim подржава неколико различитих модела за уграђивање речи.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Коришћење претходно обучених уграђивања у PyTorch-у\n",
"\n",
"Можемо изменити горњи пример како бисмо унапред попунили матрицу у нашем слоју за уграђивање семантичким уграђивањима, као што је Word2Vec. Морамо узети у обзир да се речници претходно обученог уграђивања и нашег корпуса текста вероватно неће поклапати, па ћемо иницијализовати тежине за недостајуће речи насумичним вредностима:\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": [
"Сада хајде да обучимо наш модел. Имајте на уму да је време потребно за обуку модела значајно дуже него у претходном примеру, због веће величине слоја за уграђивање, а самим тим и много већег броја параметара. Такође, због овога, можда ћемо морати да обучимо наш модел на више примера ако желимо да избегнемо пренапрегнутост.\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": [
"У нашем случају не видимо велики пораст тачности, што је вероватно због прилично различитих речника. \n",
"Да бисмо превазишли проблем различитих речника, можемо користити једно од следећих решења: \n",
"* Поново обучити word2vec модел на нашем речнику \n",
"* Учитати наш скуп података са речником из унапред обученог word2vec модела. Речник који се користи за учитавање скупа података може се одредити током учитавања. \n",
"\n",
"Други приступ изгледа лакши, посебно зато што PyTorch `torchtext` оквир садржи уграђену подршку за уграђивања. На пример, можемо инстанцирати речник заснован на GloVe на следећи начин: \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": [
"Учитани речник има следеће основне операције:\n",
"* Речник `vocab.stoi` нам омогућава да реч претворимо у њен индекс у речнику\n",
"* `vocab.itos` ради супротно - претвара број у реч\n",
"* `vocab.vectors` је низ векторских уграђивања, тако да, да бисмо добили уграђивање за реч `s`, потребно је да користимо `vocab.vectors[vocab.stoi[s]]`\n",
"\n",
"Ево примера манипулације уграђивањима како бисмо демонстрирали једначину **kind-man+woman = queen** (морао сам мало да прилагодим коефицијент да би функционисало):\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": [
"Да бисмо обучили класификатор користећи те уградње, прво морамо да кодирујемо наш скуп података користећи 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": [
"Као што смо видели изнад, сви векторски уграђивања су смештени у матрицу `vocab.vectors`. То чини веома једноставним учитавање тих тежина у тежине слоја за уграђивање користећи једноставно копирање:\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": [
"Сада хајде да обучимо наш модел и видимо да ли ћемо добити боље резултате:\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": [
"Један од разлога зашто не видимо значајно повећање тачности је чињеница да неке речи из нашег скупа података недостају у претходно обученом GloVe речнику, и стога се у суштини игноришу. Да бисмо превазишли ову чињеницу, можемо обучити сопствене уградње на нашем скупу података.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Контекстуални Ембедингси\n",
"\n",
"Једно од главних ограничења традиционалних претходно обучених ембединг репрезентација као што је Word2Vec је проблем разликовања значења речи. Иако претходно обучени ембедингси могу да ухвате део значења речи у контексту, сва могућа значења једне речи су кодирана у исти ембединг. Ово може изазвати проблеме у моделима који се користе касније, јер многе речи, као што је реч 'play', имају различита значења у зависности од контекста у коме се користе.\n",
"\n",
"На пример, реч 'play' у ове две различите реченице има прилично различита значења:\n",
"- Ишао сам на **представу** у позоришту.\n",
"- Џон жели да се **игра** са својим пријатељима.\n",
"\n",
"Претходно обучени ембедингси горе представљају оба ова значења речи 'play' у истом ембедингу. Да бисмо превазишли ово ограничење, потребно је да изградимо ембедингсе засноване на **језичком моделу**, који је обучен на великом корпусу текста и *зна* како се речи могу комбиновати у различитим контекстима. Разматрање контекстуалних ембедингса је ван домета овог туторијала, али ћемо се вратити на њих када будемо говорили о језичким моделима у наредној јединици.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Одрицање од одговорности**: \nОвај документ је преведен коришћењем услуге за превођење помоћу вештачке интелигенције [Co-op Translator](https://github.com/Azure/co-op-translator). Иако настојимо да обезбедимо тачност, молимо вас да имате у виду да аутоматски преводи могу садржати грешке или нетачности. Оригинални документ на изворном језику треба сматрати ауторитативним извором. За критичне информације препоручује се професионални превод од стране људи. Не сносимо одговорност за било каква неспоразумевања или погрешна тумачења која могу произаћи из коришћења овог превода.\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-30T01:10:18+00:00",
"source_file": "lessons/5-NLP/14-Embeddings/EmbeddingsPyTorch.ipynb",
"language_code": "sr"
}
},
"nbformat": 4,
"nbformat_minor": 2
}