{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## எம்பெடிங்ஸ்\n", "\n", "முந்தைய எடுத்துக்காட்டில், `vocab_size` நீளமுள்ள உயர்-பரிமாண bag-of-words வெக்டர்களில் செயல்பட்டோம், மேலும் குறைந்த பரிமாண positional representation வெக்டர்களிலிருந்து sparse one-hot representation-க்கு வெளிப்படையாக மாற்றினோம். இந்த one-hot representation நினைவகத்தை திறமையாக பயன்படுத்தாது, மேலும் ஒவ்வொரு வார்த்தையும் மற்றவற்றிலிருந்து தனித்துவமாக நடத்தப்படுகிறது, அதாவது one-hot encoded வெக்டர்கள் வார்த்தைகளுக்கு இடையேயான semantical ஒற்றுமையை வெளிப்படுத்துவதில்லை.\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", "எங்கள் நெட்வொர்க்கில் முதல் லேயராக எம்பெடிங் லேயரை பயன்படுத்துவதன் மூலம், நாம் bag-of-words மாடலிலிருந்து **embedding bag** மாடலுக்கு மாற முடியும், இதில் முதலில் எங்கள் உரையில் உள்ள ஒவ்வொரு சொல்லையும் தொடர்புடைய எம்பெடிங்காக மாற்றி, பின்னர் அந்த எம்பெடிங்களிலிருந்து `sum`, `average` அல்லது `max` போன்ற ஒரு தொகுப்புக் செயல்பாட்டை கணக்கிடலாம்.\n", "\n", "![ஐந்து வரிசை சொற்களுக்கான எம்பெடிங் வகைப்பாட்டாளரை காட்டும் படம்.](../../../../../translated_images/ta/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", "இதை datasource க்கு `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": [ "> **குறிப்பு**: நேரத்தை மிச்சப்படுத்துவதற்காக, இங்கு நாங்கள் 25k பதிவுகளுக்கு மட்டுமே பயிற்சி அளிக்கிறோம் (ஒரு முழு யுக்திக்கு குறைவாக), ஆனால் நீங்கள் தொடர்ந்து பயிற்சி அளிக்கலாம், பல யுக்திகளுக்கு பயிற்சி அளிக்க ஒரு செயல்பாட்டை எழுதலாம், மேலும் அதிக துல்லியத்தை அடைய கற்றல் விகித அளவுருவில் பரிசோதிக்கலாம். நீங்கள் சுமார் 90% துல்லியத்தை அடைய முடியும்.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### EmbeddingBag லேயர் மற்றும் மாறுபட்ட நீள வரிசை பிரதிநிதித்துவம்\n", "\n", "முந்தைய கட்டமைப்பில், மினிபேட்சில் பொருந்துவதற்காக அனைத்து வரிசைகளையும் ஒரே நீளத்திற்கு பதம் செய்ய வேண்டியிருந்தது. மாறுபட்ட நீள வரிசைகளை பிரதிநிதித்துவப்படுத்த இது மிகவும் திறமையான வழி அல்ல - மற்றொரு அணுகுமுறை **offset** வெக்டரைப் பயன்படுத்துவது, இது ஒரு பெரிய வெக்டரில் சேமிக்கப்பட்ட அனைத்து வரிசைகளின் இடைவெளிகளை வைத்திருக்கும்.\n", "\n", "![Offset வரிசை பிரதிநிதித்துவத்தை காட்டும் படம்](../../../../../translated_images/ta/offset-sequence-representation.eb73fcefb29b46ee.webp)\n", "\n", "> **Note**: மேலே உள்ள படத்தில், நாம் எழுத்துக்களின் வரிசையை காட்டுகிறோம், ஆனால் எங்கள் எடுத்துக்காட்டில் நாம் சொற்களின் வரிசைகளுடன் வேலை செய்கிறோம். இருப்பினும், offset வெக்டருடன் வரிசைகளை பிரதிநிதித்துவப்படுத்தும் பொது கொள்கை மாறாமல் இருக்கும்.\n", "\n", "Offset பிரதிநிதித்துவத்துடன் வேலை செய்ய, நாம் [`EmbeddingBag`](https://pytorch.org/docs/stable/generated/torch.nn.EmbeddingBag.html) லேயரைப் பயன்படுத்துகிறோம். இது `Embedding` போன்றதே, ஆனால் இது உள்ளடக்க வெக்டர் மற்றும் offset வெக்டரை உள்ளீடாக எடுக்கிறது, மேலும் இது சராசரி லேயரையும் கொண்டுள்ளது, இது `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": [ "## செமாண்டிக் எம்பெடிங்ஸ்: 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)$ என்ற ngram கொடுக்கப்பட்டால், மாடலின் நோக்கம் $(W_{-2},W_{-1},W_1,W_2)$-இல் இருந்து $W_0$-ஐ கணிக்க வேண்டும்.\n", " - **தொடர்ச்சியான ஸ்கிப்-கிராம்** என்பது CBoW-க்கு எதிர்மறையாகும். மாடல் தற்போதைய வார்த்தையை கணிக்க சுற்றியுள்ள சூழல் வார்த்தைகளின் சாளரத்தைப் பயன்படுத்துகிறது.\n", "\n", "CBoW வேகமாக செயல்படுகிறது, ஆனால் ஸ்கிப்-கிராம் மெதுவாக செயல்படுகிறது, ஆனால் அரிதான வார்த்தைகளை பிரதிநிதித்துவப்படுத்த சிறப்பாக செயல்படுகிறது.\n", "\n", "![வார்த்தைகளை வெக்டார்களாக மாற்ற CBoW மற்றும் ஸ்கிப்-கிராம் அல்காரிதங்களை காட்டும் படம்.](../../../../../translated_images/ta/example-algorithms-for-converting-words-to-vectors.fbe9207a726922f6.webp)\n", "\n", "Google News தரவுத்தொகுப்பில் முன்கூட்டியே பயிற்சி செய்யப்பட்ட word2vec எம்பெடிங்குடன் பரிசோதிக்க, **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": [ "செமாண்டிக்கல் எம்பெடிங்க்ஸ் பற்றிய சிறந்த விஷயம் என்னவென்றால், அர்த்தங்களை மாற்றுவதற்கு வெக்டர் குறியீட்டை மாற்றலாம். உதாரணமாக, *king* மற்றும் *woman* என்ற வார்த்தைகளுக்கு όσοமட்டும் அருகில் இருக்கும், மற்றும் *man* என்ற வார்த்தைக்கு όσοமட்டும் தூரமாக இருக்கும் ஒரு வார்த்தையை கண்டுபிடிக்கக் கேட்கலாம்:\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 இரண்டும் \"predictive\" embedding-கள், ஏனெனில் அவை உள்ளூர் சூழல்களை மட்டுமே கணக்கில் எடுத்துக்கொள்கின்றன. Word2Vec உலகளாவிய சூழலின் நன்மைகளை பயன்படுத்துவதில்லை.\n", "\n", "**FastText** என்பது Word2Vec-ஐ அடிப்படையாகக் கொண்டு ஒவ்வொரு வார்த்தைக்கும் மற்றும் ஒவ்வொரு வார்த்தையிலும் உள்ள character n-grams-க்கு vector representations-ஐ கற்றுக்கொள்கிறது. இந்த representations-இன் மதிப்புகள் ஒவ்வொரு பயிற்சி படியில் ஒரு vector-ஆக சராசரி எடுக்கப்படும். இது pre-training-க்கு கூடுதல் கணக்கீடுகளை சேர்த்தாலும், sub-word தகவல்களை word embeddings-ல் குறிக்க உதவுகிறது.\n", "\n", "மற்றொரு முறை, **GloVe**, co-occurrence matrix-இன் யோசனையை பயன்படுத்தி, co-occurrence matrix-ஐ neural முறைகளை கொண்டு decomposing செய்து, மேலும் வெளிப்படையான மற்றும் non-linear word vectors-ஐ உருவாக்குகிறது.\n", "\n", "நீங்கள் embeddings-ஐ FastText மற்றும் GloVe-ஆக மாற்றி உதாரணத்தை முயற்சிக்கலாம், ஏனெனில் gensim பல்வேறு word embedding மாதிரிகளை ஆதரிக்கிறது.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## PyTorch-ல் முன்பே பயிற்சியளிக்கப்பட்ட எம்பெடிங்குகளை பயன்படுத்துதல்\n", "\n", "மேலே உள்ள உதாரணத்தை மாற்றி, எம்பெடிங் லேயரில் உள்ள மேட்ரிக்ஸை Word2Vec போன்ற அர்த்தபூர்வமான எம்பெடிங்குகளால் முன்பே நிரப்பலாம். முன்பே பயிற்சியளிக்கப்பட்ட எம்பெடிங் மற்றும் நமது உரை தொகுப்பின் சொற்கள்தொகை பொருந்தாமல் இருக்க வாய்ப்பு உள்ளது என்பதைக் கருத்தில் கொள்ள வேண்டும், எனவே காணாமல் போன சொற்களுக்கான எடை மதிப்புகளை சீரற்ற (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": [ "இப்போது நமது மாதிரியை பயிற்சி செய்யலாம். மாதிரியை பயிற்சி செய்யும் நேரம் முந்தைய உதாரணத்தை விட குறிப்பிடத்தக்க அளவில் அதிகமாக இருக்கும் என்பதை கவனிக்கவும், ஏனெனில் பெரிய எம்பெடிங் லேயர் அளவு மற்றும் அதனால் மிக அதிகமான பராமேட்டர்கள் உள்ளன. மேலும், இதனால், ஓவர்ஃபிட்டிங்கை தவிர்க்க விரும்பினால், நமது மாதிரியை மேலும் பல உதாரணங்களில் பயிற்சி செய்ய வேண்டியிருக்கும்.\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) என்ற AI மொழிபெயர்ப்பு சேவையைப் பயன்படுத்தி மொழிபெயர்க்கப்பட்டுள்ளது. நாங்கள் துல்லியத்திற்காக முயற்சிக்கின்றோம், ஆனால் தானியங்கி மொழிபெயர்ப்புகளில் பிழைகள் அல்லது தவறான தகவல்கள் இருக்கக்கூடும் என்பதை தயவுசெய்து கவனத்தில் கொள்ளுங்கள். அதன் தாய்மொழியில் உள்ள மூல ஆவணம் அதிகாரப்பூர்வ ஆதாரமாக கருதப்பட வேண்டும். முக்கியமான தகவல்களுக்கு, தொழில்முறை மனித மொழிபெயர்ப்பு பரிந்துரைக்கப்படுகிறது. இந்த மொழிபெயர்ப்பைப் பயன்படுத்துவதால் ஏற்படும் எந்த தவறான புரிதல்கள் அல்லது தவறான விளக்கங்களுக்கு நாங்கள் பொறுப்பல்ல.\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-10-11T12:40:40+00:00", "source_file": "lessons/5-NLP/14-Embeddings/EmbeddingsPyTorch.ipynb", "language_code": "ta" } }, "nbformat": 4, "nbformat_minor": 2 }