726 lines
35 KiB
Plaintext
726 lines
35 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": [
|
||
"> **نوٹ**: ہم یہاں صرف 25,000 ریکارڈز کے لیے تربیت کر رہے ہیں (ایک مکمل ایپوک سے کم) وقت کی بچت کے لیے، لیکن آپ تربیت جاری رکھ سکتے ہیں، کئی ایپوکز کے لیے تربیت دینے کے لیے ایک فنکشن لکھ سکتے ہیں، اور زیادہ درستگی حاصل کرنے کے لیے لرننگ ریٹ پیرامیٹر کے ساتھ تجربہ کر سکتے ہیں۔ آپ تقریباً 90% درستگی تک پہنچنے کے قابل ہونا چاہیے۔\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### ایمبیڈنگ بیگ لیئر اور مختلف لمبائی کی ترتیب کی نمائندگی\n",
|
||
"\n",
|
||
"پچھلی آرکیٹیکچر میں، ہمیں تمام ترتیبوں کو ایک ہی لمبائی تک بڑھانا پڑتا تھا تاکہ انہیں ایک منی بیچ میں فٹ کیا جا سکے۔ یہ مختلف لمبائی کی ترتیبوں کو ظاہر کرنے کا سب سے مؤثر طریقہ نہیں ہے - ایک اور طریقہ یہ ہو سکتا ہے کہ **آفسیٹ** ویکٹر استعمال کیا جائے، جو ایک بڑے ویکٹر میں محفوظ تمام ترتیبوں کے آفسیٹس کو رکھے۔\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"> **نوٹ**: اوپر دی گئی تصویر میں، ہم حروف کی ترتیب دکھا رہے ہیں، لیکن ہمارے مثال میں ہم الفاظ کی ترتیب کے ساتھ کام کر رہے ہیں۔ تاہم، آفسیٹ ویکٹر کے ساتھ ترتیبوں کی نمائندگی کا عمومی اصول وہی رہتا ہے۔\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",
|
||
"ایسا کرنے کے لیے، ہمیں اپنے ایمبیڈنگ ماڈل کو ایک خاص طریقے سے بڑے ٹیکسٹ ڈیٹا پر پہلے سے ٹرین کرنا ہوگا۔ سیمینٹک ایمبیڈنگز کو ٹرین کرنے کے ابتدائی طریقوں میں سے ایک کو [ورڈ2ویک](https://en.wikipedia.org/wiki/Word2vec) کہا جاتا ہے۔ یہ دو بنیادی آرکیٹیکچرز پر مبنی ہے جو الفاظ کی ڈسٹریبیوٹڈ ریپریزنٹیشن پیدا کرنے کے لیے استعمال ہوتے ہیں:\n",
|
||
"\n",
|
||
"- **کنٹینیوس بیگ آف ورڈز** (CBoW) — اس آرکیٹیکچر میں، ماڈل کو ارد گرد کے کانٹیکسٹ سے ایک لفظ کی پیش گوئی کرنے کے لیے ٹرین کیا جاتا ہے۔ دیے گئے این گرام $(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",
|
||
"گوگل نیوز ڈیٹاسیٹ پر پہلے سے ٹرین کیے گئے ورڈ2ویک ایمبیڈنگ کے ساتھ تجربہ کرنے کے لیے، ہم **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-grams کی بھی۔ ان نمائندگیوں کی قدریں ہر تربیتی مرحلے میں ایک ویکٹر میں اوسط کی جاتی ہیں۔ اگرچہ یہ پیشگی تربیت میں اضافی حساب کتاب شامل کرتا ہے، لیکن یہ لفظی ایمبیڈنگز کو ذیلی لفظی معلومات کو انکوڈ کرنے کے قابل بناتا ہے۔\n",
|
||
"\n",
|
||
"ایک اور طریقہ، **GloVe**، ہم وقوع میٹرکس کے تصور کا فائدہ اٹھاتا ہے اور ہم وقوع میٹرکس کو زیادہ مؤثر اور غیر خطی لفظی ویکٹرز میں تقسیم کرنے کے لیے نیورل طریقے استعمال کرتا ہے۔\n",
|
||
"\n",
|
||
"آپ مثال کے ساتھ کھیل سکتے ہیں اور ایمبیڈنگز کو FastText اور GloVe میں تبدیل کر سکتے ہیں، کیونکہ gensim کئی مختلف لفظی ایمبیڈنگ ماڈلز کو سپورٹ کرتا ہے۔\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## پائی ٹارچ میں پہلے سے تربیت یافتہ ایمبیڈنگز کا استعمال\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",
|
||
"- میں تھیٹر میں ایک **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-28T04:33:43+00:00",
|
||
"source_file": "lessons/5-NLP/14-Embeddings/EmbeddingsPyTorch.ipynb",
|
||
"language_code": "ur"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 2
|
||
} |