720 lines
42 KiB
Plaintext
720 lines
42 KiB
Plaintext
{
|
||
"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",
|
||
"\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",
|
||
"या आर्किटेक्चरमुळे, आमच्या नेटवर्कसाठी मिनीबॅचेस विशिष्ट पद्धतीने तयार करणे आवश्यक होईल. मागील युनिटमध्ये, बॅग-ऑफ-वर्ड्स वापरताना, मिनीबॅचमधील सर्व BoW टेन्सर्सचा आकार `vocab_size` इतकाच होता, आपल्या मजकूर अनुक्रमाच्या वास्तविक लांबीची पर्वा न करता. जेव्हा आपण वर्ड एम्बेडिंगकडे जातो, तेव्हा प्रत्येक मजकूर नमुन्यात वेगवेगळ्या संख्येने शब्द असतील, आणि ते नमुने मिनीबॅचमध्ये एकत्र करताना आपल्याला काही पॅडिंग लागू करावे लागेल.\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": [
|
||
"> **टीप**: वेळेच्या बचतीसाठी आम्ही येथे फक्त २५,००० नोंदींसाठी प्रशिक्षण देत आहोत (एक पूर्ण युगापेक्षा कमी), परंतु तुम्ही प्रशिक्षण सुरू ठेवू शकता, अनेक युगांसाठी प्रशिक्षण देण्यासाठी एक फंक्शन लिहू शकता आणि उच्च अचूकता मिळवण्यासाठी शिक्षण दर पॅरामीटरसह प्रयोग करू शकता. तुम्ही सुमारे ९०% अचूकतेपर्यंत पोहोचू शकता.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### EmbeddingBag लेयर आणि बदलत्या लांबीच्या अनुक्रमाचे प्रतिनिधित्व\n",
|
||
"\n",
|
||
"मागील आर्किटेक्चरमध्ये, सर्व अनुक्रम समान लांबीचे करण्यासाठी त्यांना पॅड करणे आवश्यक होते, जेणेकरून ते मिनीबॅचमध्ये बसतील. बदलत्या लांबीच्या अनुक्रमांचे प्रतिनिधित्व करण्याचा हा सर्वात कार्यक्षम मार्ग नाही - दुसरा दृष्टिकोन म्हणजे **ऑफसेट** व्हेक्टर वापरणे, जो एका मोठ्या व्हेक्टरमध्ये संग्रहित केलेल्या सर्व अनुक्रमांचे ऑफसेट ठेवेल.\n",
|
||
"\n",
|
||
"\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": [
|
||
"आता लक्षात घ्या, की सर्व पूर्वीच्या उदाहरणांपेक्षा वेगळे, आमचे नेटवर्क आता दोन पॅरामीटर्स स्वीकारते: डेटा व्हेक्टर आणि ऑफसेट व्हेक्टर, जे वेगवेगळ्या आकाराचे आहेत. त्याचप्रमाणे, आमचा डेटा लोडर देखील आम्हाला 2 ऐवजी 3 मूल्ये प्रदान करतो: मजकूर आणि ऑफसेट व्हेक्टर दोन्ही वैशिष्ट्ये म्हणून प्रदान केले जातात. त्यामुळे, आम्हाला आमच्या प्रशिक्षण फंक्शनमध्ये थोडासा बदल करणे आवश्यक आहे:\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": [
|
||
"## सिमॅंटिक एम्बेडिंग्स: वर्ड2व्हेक\n",
|
||
"\n",
|
||
"आपल्या मागील उदाहरणात, मॉडेलच्या एम्बेडिंग लेयरने शब्दांना व्हेक्टर स्वरूपात मॅप करणे शिकले, परंतु या स्वरूपात फारसा सिमॅंटिक अर्थ नव्हता. असे व्हेक्टर स्वरूप शिकणे चांगले ठरेल, ज्यामध्ये समान शब्द किंवा समानार्थी शब्द अशा व्हेक्टरना सादर करतील जे काही व्हेक्टर अंतर (उदा. युक्लिडियन अंतर) यांच्या दृष्टीने एकमेकांच्या जवळ असतील.\n",
|
||
"\n",
|
||
"हे साध्य करण्यासाठी, आपल्याला मोठ्या प्रमाणातील मजकुरावर विशिष्ट पद्धतीने आपले एम्बेडिंग मॉडेल प्री-ट्रेन करावे लागेल. सिमॅंटिक एम्बेडिंग्स ट्रेन करण्याच्या पहिल्या पद्धतींपैकी एक म्हणजे [Word2Vec](https://en.wikipedia.org/wiki/Word2vec). हे दोन मुख्य आर्किटेक्चर्सवर आधारित आहे, जे शब्दांचे वितरित प्रतिनिधित्व तयार करण्यासाठी वापरले जातात:\n",
|
||
"\n",
|
||
" - **कंटिन्युअस बॅग-ऑफ-वर्ड्स** (CBoW) — या आर्किटेक्चरमध्ये, आपण मॉडेलला आजूबाजूच्या संदर्भातून एखादा शब्द भाकीत करण्यासाठी ट्रेन करतो. दिलेल्या ngram $(W_{-2},W_{-1},W_0,W_1,W_2)$ मध्ये, मॉडेलचे उद्दिष्ट $(W_{-2},W_{-1},W_1,W_2)$ वरून $W_0$ भाकीत करणे आहे.\n",
|
||
" - **कंटिन्युअस स्किप-ग्राम** हे CBoW च्या उलट आहे. मॉडेल सध्याचा शब्द भाकीत करण्यासाठी संदर्भातील आजूबाजूच्या शब्दांचा वापर करते.\n",
|
||
"\n",
|
||
"CBoW जलद आहे, तर स्किप-ग्राम थोडा धीमा आहे, परंतु दुर्मिळ शब्दांचे प्रतिनिधित्व करण्याचे काम अधिक चांगल्या प्रकारे करतो.\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"Google News डेटासेटवर प्री-ट्रेन केलेल्या word2vec एम्बेडिंगसह प्रयोग करण्यासाठी, आपण **gensim** लायब्ररीचा वापर करू शकतो. खाली 'neural' या शब्दाशी सर्वाधिक समान शब्द शोधले आहेत:\n",
|
||
"\n",
|
||
"> **Note:** जेव्हा तुम्ही प्रथमच शब्दांचे व्हेक्टर तयार करता, तेव्हा त्यांना डाउनलोड करण्यात काही वेळ लागू शकतो!\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": []
|
||
},
|
||
{
|
||
"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-grams साठी व्हेक्टर प्रतिनिधित्व शिकवले जाते. या प्रतिनिधित्वांचे मूल्य प्रत्येक प्रशिक्षण टप्प्यावर एका व्हेक्टरमध्ये सरासरी काढले जाते. जरी यामुळे प्री-ट्रेनिंगसाठी अतिरिक्त गणना लागते, तरीही हे शब्द एम्बेडिंग्सना उप-शब्द माहिती एन्कोड करण्यास सक्षम करते.\n",
|
||
"\n",
|
||
"आणखी एक पद्धत, **GloVe**, सह-अस्तित्व मॅट्रिक्सच्या संकल्पनेचा उपयोग करते आणि सह-अस्तित्व मॅट्रिक्सला अधिक अभिव्यक्त आणि नॉन-लिनियर शब्द व्हेक्टरमध्ये विघटित करण्यासाठी न्यूरल पद्धतींचा वापर करते.\n",
|
||
"\n",
|
||
"तुम्ही एम्बेडिंग्स बदलून FastText आणि GloVe वापरून उदाहरण खेळू शकता, कारण gensim विविध शब्द एम्बेडिंग मॉडेल्सला समर्थन देते.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## PyTorch मध्ये पूर्व-प्रशिक्षित एम्बेडिंग्ज वापरणे\n",
|
||
"\n",
|
||
"वरील उदाहरण बदलून आपण आपल्या एम्बेडिंग लेयरमधील मॅट्रिक्सला Word2Vec सारख्या अर्थपूर्ण एम्बेडिंग्जने पूर्व-भरू शकतो. आपल्याला हे लक्षात घ्यावे लागेल की पूर्व-प्रशिक्षित एम्बेडिंग आणि आपल्या टेक्स्ट कॉर्पसचे शब्दसंग्रह (vocabularies) बहुधा जुळणार नाहीत, त्यामुळे गहाळ शब्दांसाठी वेट्स (weights) यादृच्छिक (random) मूल्यांनी प्रारंभ करू:\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": []
|
||
},
|
||
{
|
||
"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": []
|
||
},
|
||
{
|
||
"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 यांची एक महत्त्वाची मर्यादा म्हणजे शब्द अर्थ अस्पष्टता (word sense disambiguation) ची समस्या. प्रीट्रेन केलेल्या एम्बेडिंग्स काही प्रमाणात शब्दांचा संदर्भातील अर्थ पकडू शकतात, परंतु प्रत्येक संभाव्य अर्थ एका एम्बेडिंगमध्येच समाविष्ट केला जातो. यामुळे डाउनस्ट्रीम मॉडेल्समध्ये समस्या निर्माण होऊ शकतात, कारण अनेक शब्द, जसे की 'play', वेगवेगळ्या संदर्भांमध्ये वेगवेगळे अर्थ दर्शवतात.\n",
|
||
"\n",
|
||
"उदाहरणार्थ, 'play' या शब्दाचा खालील दोन वाक्यांमध्ये अर्थ पूर्णपणे वेगळा आहे:\n",
|
||
"- मी थिएटरमध्ये एक **play** पाहायला गेलो.\n",
|
||
"- जॉनला त्याच्या मित्रांसोबत **play** करायचे आहे.\n",
|
||
"\n",
|
||
"वरील प्रीट्रेन केलेल्या एम्बेडिंग्स 'play' या शब्दाचे दोन्ही अर्थ एकाच एम्बेडिंगमध्ये दर्शवतात. ही मर्यादा दूर करण्यासाठी, आपल्याला **भाषा मॉडेल** आधारित एम्बेडिंग्स तयार करणे आवश्यक आहे, जे मोठ्या प्रमाणातील मजकूरावर प्रशिक्षित केले जाते आणि *जाणते* की शब्द वेगवेगळ्या संदर्भांमध्ये कसे एकत्र ठेवले जाऊ शकतात. संदर्भात्मक एम्बेडिंग्सवर चर्चा करणे या ट्यूटोरियलच्या कक्षेबाहेर आहे, परंतु आपण पुढील युनिटमध्ये भाषा मॉडेल्सबद्दल बोलताना त्याकडे परत येऊ.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"\n---\n\n**अस्वीकरण**: \nहा दस्तऐवज AI भाषांतर सेवा [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-28T09:46:19+00:00",
|
||
"source_file": "lessons/5-NLP/14-Embeddings/EmbeddingsPyTorch.ipynb",
|
||
"language_code": "mr"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 2
|
||
} |