{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "NXTSugt6ieXh" }, "source": [ "## CBoW မော်ဒယ်ကိုလေ့ကျင့်ခြင်း\n", "\n", "ဒီ notebook က [AI for Beginners Curriculum](http://aka.ms/ai-beginners) ရဲ့ အစိတ်အပိုင်းတစ်ခုဖြစ်ပါတယ်။\n", "\n", "ဒီဥပမာမှာတော့ CBoW ဘာသာစကားမော်ဒယ်ကိုလေ့ကျင့်ပြီး Word2Vec embedding space ကို ကိုယ်တိုင်ရရှိအောင်လုပ်မယ်။ AG News dataset ကို စာသားရင်းမြစ်အဖြစ်အသုံးပြုမယ်။\n" ] }, { "cell_type": "code", "source": [ "import torch\n", "import torchtext\n", "import os\n", "import collections\n", "import builtins\n", "import random\n", "import numpy as np" ], "metadata": { "id": "q-UiiJUKaxHj" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")" ], "metadata": { "id": "TFbR8CZaTZ1q" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "အရင်ဆုံး ကျွန်တော်တို့ရဲ့ ဒေတာစနစ်ကို load လုပ်ပြီး tokenizer နဲ့ vocabulary ကို သတ်မှတ်ပါမယ်။ `vocab_size` ကို ၅၀၀၀ အထိ သတ်မှတ်ပြီး ရှုထောင့်များကို အနည်းငယ် ကန့်သတ်ပါမယ်။\n" ], "metadata": { "id": "HIwC7lI5T-ov" } }, { "cell_type": "code", "source": [ "def load_dataset(ngrams = 1, min_freq = 1, vocab_size = 5000 , lines_cnt = 500):\n", " tokenizer = torchtext.data.utils.get_tokenizer('basic_english')\n", " print(\"Loading dataset...\")\n", " test_dataset, train_dataset = torchtext.datasets.AG_NEWS(root='./data')\n", " train_dataset = list(train_dataset)\n", " test_dataset = list(test_dataset)\n", " classes = ['World', 'Sports', 'Business', 'Sci/Tech']\n", " print('Building vocab...')\n", " counter = collections.Counter()\n", " for i, (_, line) in enumerate(train_dataset):\n", " counter.update(torchtext.data.utils.ngrams_iterator(tokenizer(line),ngrams=ngrams))\n", " if i == lines_cnt:\n", " break\n", " vocab = torchtext.vocab.Vocab(collections.Counter(dict(counter.most_common(vocab_size))), min_freq=min_freq)\n", " return train_dataset, test_dataset, classes, vocab, tokenizer" ], "metadata": { "id": "wdZuygtgiuLG" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "train_dataset, test_dataset, _, vocab, tokenizer = load_dataset()" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "4d1nU1gsivGu", "outputId": "949fe272-ae0e-49f5-c373-6703458b3a74" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Loading dataset...\n", "Building vocab...\n" ] } ] }, { "cell_type": "code", "source": [ "def encode(x, vocabulary, tokenizer = tokenizer):\n", " return [vocabulary[s] for s in tokenizer(x)]" ], "metadata": { "id": "1XDYNhG8ToFV" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "LIlQk6_PaHVY" }, "source": [ "## CBoW မော်ဒယ်\n", "\n", "CBoW သည် $2N$ အနီးအနားရှိ စကားလုံးများကို အခြေခံပြီး စကားလုံးတစ်လုံးကို ခန့်မှန်းရန် သင်ယူသည်။ ဥပမာအားဖြင့် $N=1$ ဖြစ်သောအခါ *I like to train networks* ဆိုသော စာကြောင်းမှ အောက်ပါ စုံတွဲများကို ရရှိမည်ဖြစ်သည် - (like,I), (I, like), (to, like), (like,to), (train,to), (to, train), (networks, train), (train,networks)။ ဒီမှာ ပထမ စကားလုံးသည် input အဖြစ် အသုံးပြုသော အနီးအနားရှိ စကားလုံးဖြစ်ပြီး ဒုတိယ စကားလုံးသည် ခန့်မှန်းရန် ရည်ရွယ်ထားသော စကားလုံးဖြစ်သည်။\n", "\n", "နောက်ထပ် စကားလုံးကို ခန့်မှန်းရန် network တစ်ခုကို တည်ဆောက်ရန်အတွက် အနီးအနားရှိ စကားလုံးကို input အဖြစ် ပေးရမည်ဖြစ်ပြီး စကားလုံးနံပါတ်ကို output အဖြစ် ရယူရမည်။ CBoW network ၏ architecture သည် အောက်ပါအတိုင်းဖြစ်သည် -\n", "\n", "* Input စကားလုံးကို embedding layer မှတဆင့် ဖြတ်သွားမည်။ ဒီ embedding layer သည် Word2Vec embedding ဖြစ်မည်ဖြစ်ပြီး `embedder` variable အဖြစ် သီးသန့်သတ်မှတ်မည်။ ဤဥပမာတွင် embedding size = 30 ကို အသုံးပြုမည်ဖြစ်သော်လည်း အမြင့် dimension များ (အမှန်တကယ် Word2Vec တွင် 300 ရှိသည်) ကို စမ်းသပ်လိုပါက ပြောင်းလဲနိုင်သည်။\n", "* Embedding vector ကို linear layer သို့ ဖြတ်သွားပြီး output စကားလုံးကို ခန့်မှန်းမည်။ ထို့ကြောင့် `vocab_size` neurons ရှိသည်။\n", "\n", "Output အတွက် `CrossEntropyLoss` ကို loss function အဖြစ် အသုံးပြုပါက one-hot encoding မပါဘဲ စကားလုံးနံပါတ်များကိုသာ expected results အဖြစ် ပေးရမည်။\n" ] }, { "cell_type": "code", "source": [ "vocab_size = len(vocab)\n", "\n", "embedder = torch.nn.Embedding(num_embeddings = vocab_size, embedding_dim = 30)\n", "model = torch.nn.Sequential(\n", " embedder,\n", " torch.nn.Linear(in_features = 30, out_features = vocab_size),\n", ")\n", "\n", "print(model)" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "akKTcKQKkfl2", "outputId": "da687e3e-a8ec-4c1a-e456-ab8cd6ac7dad" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Sequential(\n", " (0): Embedding(5002, 30)\n", " (1): Linear(in_features=30, out_features=5002, bias=True)\n", ")\n" ] } ] }, { "cell_type": "markdown", "metadata": { "id": "Nud6jgGPaHVa" }, "source": [ "## လေ့ကျင့်မှု ဒေတာ ပြင်ဆင်ခြင်း\n", "\n", "အခုတော့ စာသားထဲမှ CBoW စကားလုံးစုံများကိုတွက်ချက်ပေးမည့် အဓိက function ကိုရေးကြမယ်။ ဒီ function က window size ကို သတ်မှတ်ပေးနိုင်မှာဖြစ်ပြီး၊ input နှင့် output စကားလုံးစုံများကို ပြန်ပေးမယ်။ ဒီ function ကို စကားလုံးများအပေါ်မှာသာမက၊ vectors/tensors အပေါ်မှာလည်း အသုံးပြုနိုင်တယ် - ဒါကြောင့် စာသားကို encode လုပ်ပြီးနောက်မှ `to_cbow` function ကို ပေးပို့နိုင်မယ်။\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "x-dsXygOieXn", "outputId": "c2218280-e540-40ba-9546-efe48d0d714f" }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "[['like', 'I'], ['to', 'I'], ['I', 'like'], ['to', 'like'], ['train', 'like'], ['I', 'to'], ['like', 'to'], ['train', 'to'], ['networks', 'to'], ['like', 'train'], ['to', 'train'], ['networks', 'train'], ['to', 'networks'], ['train', 'networks']]\n", "[[232, 172], [5, 172], [172, 232], [5, 232], [0, 232], [172, 5], [232, 5], [0, 5], [1202, 5], [232, 0], [5, 0], [1202, 0], [5, 1202], [0, 1202]]\n" ] } ], "source": [ "def to_cbow(sent,window_size=2):\n", " res = []\n", " for i,x in enumerate(sent):\n", " for j in range(max(0,i-window_size),min(i+window_size+1,len(sent))):\n", " if i!=j:\n", " res.append([sent[j],x])\n", " return res\n", "\n", "print(to_cbow(['I','like','to','train','networks']))\n", "print(to_cbow(encode('I like to train networks', vocab)))" ] }, { "cell_type": "markdown", "metadata": { "id": "XVaaDLjaaHVb" }, "source": [ "ကျောင်းသားသင်ကြားမှုဒေတာစုံကို ပြင်ဆင်ကြမယ်။ သတင်းအားလုံးကို ကျော်လွှားပြီး `to_cbow` ကို ခေါ်သုံးကာ စကားလုံးအတွဲများစာရင်းကို ရယူပြီး အဲ့ဒီအတွဲများကို `X` နဲ့ `Y` ထဲထည့်ပါမယ်။ အချိန်သက်သာစေရန်အတွက် ပထမ 10k သတင်းပစ္စည်းများကိုသာ စဉ်းစားပါမယ် - သင့်မှာ စောင့်ဆိုင်းဖို့ အချိန်ပိုရှိပြီး ပိုမိုကောင်းမွန်တဲ့ embedding များရယူလိုပါက အကန့်အသတ်ကို လွယ်ကူစွာ ဖယ်ရှားနိုင်ပါတယ် :)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "54b-Gd9TieXo" }, "outputs": [], "source": [ "X = []\n", "Y = []\n", "for i, x in zip(range(10000), train_dataset):\n", " for w1, w2 in to_cbow(encode(x[1], vocab), window_size = 5):\n", " X.append(w1)\n", " Y.append(w2)\n", "\n", "X = torch.tensor(X)\n", "Y = torch.tensor(Y)" ] }, { "cell_type": "markdown", "source": [ "ကျွန်ုပ်တို့သည် အဆိုပါဒေတာကို တစ်ခုတည်းသောဒေတာစုံအဖြစ် ပြောင်းလဲမည်ဖြစ်ပြီး၊ dataloader တစ်ခုကို ဖန်တီးမည်:\n" ], "metadata": { "id": "cwWy0PzXWhN5" } }, { "cell_type": "code", "source": [ "class SimpleIterableDataset(torch.utils.data.IterableDataset):\n", " def __init__(self, X, Y):\n", " super(SimpleIterableDataset).__init__()\n", " self.data = []\n", " for i in range(len(X)):\n", " self.data.append( (Y[i], X[i]) )\n", " random.shuffle(self.data)\n", "\n", " def __iter__(self):\n", " return iter(self.data)" ], "metadata": { "id": "mfoAcGPFZU8p" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "e4NQ_-5waHVc" }, "source": [ "ကျွန်ုပ်တို့သည် အဆိုပါဒေတာကို တစ်ခုတည်းသောဒေတာစုံအဖြစ် ပြောင်းလဲမည်ဖြစ်ပြီး၊ dataloader တစ်ခုကို ဖန်တီးမည်:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "AbLUcojlieXo" }, "outputs": [], "source": [ "ds = SimpleIterableDataset(X, Y)\n", "dl = torch.utils.data.DataLoader(ds, batch_size = 256)" ] }, { "cell_type": "markdown", "metadata": { "id": "pKQr7sXeaHVc" }, "source": [ "အခုတော့ အမှန်တကယ် သင်ကြားမှုကို စတင်ကြမယ်။ ကျွန်တော်တို့ `SGD` optimizer ကို အသုံးပြုပြီး အလွန်မြင့်မားတဲ့ learning rate နဲ့ သင်ကြားပါမယ်။ သင် `Adam` ကဲ့သို့သော အခြား optimizer များကိုလည်း စမ်းသပ်ကြည့်နိုင်ပါတယ်။ အစမှာ 10 epochs အထိ သင်ကြားပါမယ် - သင်ပိုနည်းတဲ့ loss ရချင်ရင် ဒီ cell ကို ပြန်လည် run လုပ်နိုင်ပါတယ်။\n" ] }, { "cell_type": "code", "source": [ "def train_epoch(net, dataloader, lr = 0.01, optimizer = None, loss_fn = torch.nn.CrossEntropyLoss(), epochs = None, report_freq = 1):\n", " optimizer = optimizer or torch.optim.Adam(net.parameters(), lr = lr)\n", " loss_fn = loss_fn.to(device)\n", " net.train()\n", "\n", " for i in range(epochs):\n", " total_loss, j = 0, 0, \n", " for labels, features in dataloader:\n", " optimizer.zero_grad()\n", " features, labels = features.to(device), labels.to(device)\n", " out = net(features)\n", " loss = loss_fn(out, labels)\n", " loss.backward()\n", " optimizer.step()\n", " total_loss += loss\n", " j += 1\n", " if i % report_freq == 0:\n", " print(f\"Epoch: {i+1}: loss={total_loss.item()/j}\")\n", "\n", " return total_loss.item()/j" ], "metadata": { "id": "HeeCYKr_KF1w" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "train_epoch(net = model, dataloader = dl, optimizer = torch.optim.SGD(model.parameters(), lr = 0.1), loss_fn = torch.nn.CrossEntropyLoss(), epochs = 10)" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "KVgwGtDHgDlT", "outputId": "2447833f-f0e3-4566-c33d-addbfe2f451d" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Epoch: 1: loss=5.664632366860172\n", "Epoch: 2: loss=5.632101973960962\n", "Epoch: 3: loss=5.610399051405015\n", "Epoch: 4: loss=5.594621561080262\n", "Epoch: 5: loss=5.582538017415446\n", "Epoch: 6: loss=5.572900234519603\n", "Epoch: 7: loss=5.564951676341915\n", "Epoch: 8: loss=5.558288112064614\n", "Epoch: 9: loss=5.552576955031129\n", "Epoch: 10: loss=5.547634165194347\n" ] }, { "output_type": "execute_result", "data": { "text/plain": [ "5.547634165194347" ] }, "metadata": {}, "execution_count": 16 } ] }, { "cell_type": "markdown", "metadata": { "id": "W8u2qXZmaHVd" }, "source": [ "## Word2Vec ကို စမ်းသပ်ခြင်း\n", "\n", "Word2Vec ကို အသုံးပြုရန်၊ ကျွန်ုပ်တို့၏ ဝေါဟာရစာရင်းထဲရှိ စကားလုံးအားလုံးနှင့် ကိုက်ညီသော ဗက်တာများကို ထုတ်ယူကြမယ်။\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "r8TatcXjkU_t" }, "outputs": [], "source": [ "vectors = torch.stack([embedder(torch.tensor(vocab[s])) for s in vocab.itos], 0)" ] }, { "cell_type": "markdown", "metadata": { "id": "3OcX21UOaHVd" }, "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "bz6tAeLzieXp", "outputId": "5b20850e-4342-45e9-f840-cfac2b4d61d8" }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "tensor([-0.0915, 2.1224, -0.0281, -0.6819, 1.1219, 0.6458, -1.3704, -1.3314,\n", " -1.1437, 0.4496, 0.2301, -0.3515, -0.8485, 1.0481, 0.4386, -0.8949,\n", " 0.5644, 1.0939, -2.5096, 3.2949, -0.2601, -0.8640, 0.1421, -0.0804,\n", " -0.5083, -1.0560, 0.9753, -0.5949, -1.6046, 0.5774],\n", " grad_fn=)\n" ] } ], "source": [ "paris_vec = embedder(torch.tensor(vocab['paris']))\n", "print(paris_vec)" ] }, { "cell_type": "markdown", "metadata": { "id": "pHTJlaeYaHVd" }, "source": [ "Word2Vec ကို သုံးပြီး အနီးစပ်ဆုံးသော စကားလုံးများကို ရှာဖွေခြင်းသည် စိတ်ဝင်စားဖွယ်ကောင်းသည်။ အောက်ပါ function သည် ပေးထားသော input အတွက် `n` အနီးစပ်ဆုံးသော စကားလုံးများကို ပြန်လည်ပေးပါမည်။ ၎င်းတို့ကို ရှာဖွေရန် $|w_i - v|$ ၏ norm ကို တွက်ချက်ပါမည်၊ ဤနေရာတွင် $v$ သည် input စကားလုံးနှင့် ဆက်စပ်သော vector ဖြစ်ပြီး $w_i$ သည် vocabulary အတွင်းရှိ $i$-th စကားလုံး၏ encoding ဖြစ်သည်။ ထို့နောက် array ကို sort လုပ်ပြီး `argsort` ကို အသုံးပြု၍ ဆက်စပ်သော indices များကို ပြန်လည်ပေးပြီး vocabulary အတွင်းရှိ အနီးစပ်ဆုံးသော စကားလုံးများ၏ တည်နေရာကို encode လုပ်ထားသော list ၏ ပထမဆုံး `n` elements ကို ယူပါမည်။\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "NlZyi-_olFar", "outputId": "b5dbb163-88c4-4d5a-eaf2-6751f700e98c" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "['microsoft', 'quoted', 'lp', 'rate', 'top']" ] }, "metadata": {}, "execution_count": 56 } ], "source": [ "def close_words(x, n = 5):\n", " vec = embedder(torch.tensor(vocab[x]))\n", " top5 = np.linalg.norm(vectors.detach().numpy() - vec.detach().numpy(), axis = 1).argsort()[:n]\n", " return [ vocab.itos[x] for x in top5 ]\n", "\n", "close_words('microsoft')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "-dQq7xeAln0U", "outputId": "66f768c3-c248-4bfd-ce4f-c8ffc6d0dd0d" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "['basketball', 'lot', 'sinai', 'states', 'healthdaynews']" ] }, "metadata": {}, "execution_count": 51 } ], "source": [ "close_words('basketball')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "fJXqK26b29sa", "outputId": "78f0baba-ffd0-485a-dd87-0a12bedfd7fa" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "['funds', 'travel', 'sydney', 'japan', 'business']" ] }, "metadata": {}, "execution_count": 77 } ], "source": [ "close_words('funds')" ] }, { "cell_type": "markdown", "metadata": { "id": "My0VeTDd3Ji8" }, "source": [ "## အဓိကအချက်\n", "\n", "CBoW ကဲ့သို့သော ထူးခြားသောနည်းလမ်းများကို အသုံးပြု၍ Word2Vec မော်ဒယ်ကို လေ့ကျင့်နိုင်ပါသည်။ သင်သည် အလယ်ရှိ စကားလုံးကို ပေးပြီး အနီးအနားရှိ စကားလုံးကို ခန့်မှန်းရန် လေ့ကျင့်ထားသော skip-gram မော်ဒယ်ကိုလည်း လေ့ကျင့်ကြည့်ပြီး၊ ၎င်း၏ လုပ်ဆောင်မှုကောင်းမွန်မှုကို ကြည့်ရှုနိုင်ပါသည်။\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n---\n\n**အကြောင်းကြားချက်**: \nဤစာရွက်စာတမ်းကို AI ဘာသာပြန်ဝန်ဆောင်မှု [Co-op Translator](https://github.com/Azure/co-op-translator) ကို အသုံးပြု၍ ဘာသာပြန်ထားပါသည်။ ကျွန်ုပ်တို့သည် တိကျမှုအတွက် ကြိုးစားနေသော်လည်း၊ အလိုအလျောက် ဘာသာပြန်ခြင်းတွင် အမှားများ သို့မဟုတ် မတိကျမှုများ ပါဝင်နိုင်သည်ကို သတိပြုပါ။ မူရင်းစာရွက်စာတမ်းကို ၎င်း၏ မူရင်းဘာသာစကားဖြင့် အာဏာတရားရှိသော အရင်းအမြစ်အဖြစ် သတ်မှတ်သင့်ပါသည်။ အရေးကြီးသော အချက်အလက်များအတွက် လူ့ဘာသာပြန်ပညာရှင်များမှ ပရော်ဖက်ရှင်နယ် ဘာသာပြန်ခြင်းကို အကြံပြုပါသည်။ ဤဘာသာပြန်ကို အသုံးပြုခြင်းမှ ဖြစ်ပေါ်လာသော အလွဲအလွတ်များ သို့မဟုတ် အနားယူမှုမှားများအတွက် ကျွန်ုပ်တို့သည် တာဝန်မယူပါ။\n" ] } ], "metadata": { "colab": { "collapsed_sections": [], "name": "CBoW-PyTorch.ipynb", "provenance": [] }, "interpreter": { "hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f" }, "kernelspec": { "display_name": "Python 3.8.12 ('py38')", "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" }, "orig_nbformat": 4, "gpuClass": "standard", "coopTranslator": { "original_hash": "36df28efe3fe40b6fb0a7fa48fe3ea82", "translation_date": "2025-08-30T10:15:52+00:00", "source_file": "lessons/5-NLP/15-LanguageModeling/CBoW-PyTorch.ipynb", "language_code": "my" } }, "nbformat": 4, "nbformat_minor": 0 }