571 lines
31 KiB
Plaintext
571 lines
31 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# មុខងារបែងចែកអត្ថបទ\n",
|
||
"\n",
|
||
"ដូចដែលយើងបានរំលឹក អេភាសីយើងនឹងផ្តោតលើមុខងារបែងចែកអត្ថបទសាមញ្ញមួយ dựa trên **AG_NEWS** ភាពទិន្នន័យ ដែលជាការបែងចែកសេចក្តីដំបូន្មានព័ត៌មានទៅក្នុងមួយចំណាត់ថ្នាក់ពីរាបបួន៖ ពិភពលោក កីឡា ពាណិជ្ជកម្ម និង វិទ្យាសាស្រ្ត/បច្ចេកវិទ្យា។\n",
|
||
"\n",
|
||
"## ព្រំប្រៃទិន្នន័យ\n",
|
||
"\n",
|
||
"ព្រំប្រៃទិន្នន័យនេះត្រូវបានសាងសង់គ្នាចូលក្នុងម៉ូឌុល [`torchtext`](https://github.com/pytorch/text) ដូច្នេះ យើងអាចចូលដំណើរការយ៉ាងងាយស្រួល។\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 1,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"import torch\n",
|
||
"import torchtext\n",
|
||
"import os\n",
|
||
"import collections\n",
|
||
"os.makedirs('./data',exist_ok=True)\n",
|
||
"train_dataset, test_dataset = torchtext.datasets.AG_NEWS(root='./data')\n",
|
||
"classes = ['World', 'Sports', 'Business', 'Sci/Tech']"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"នៅទីនេះ `train_dataset` និង `test_dataset` មានប្រមាញ់ដែលត្រឡប់វ៉ាល្យូមនៃស្លាក (ចំនួនថ្នាក់) និងអត្ថបទដោយលំដាប់ ជាឧទាហរណ៍ៈ\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 2,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"(3,\n",
|
||
" \"Wall St. Bears Claw Back Into the Black (Reuters) Reuters - Short-sellers, Wall Street's dwindling\\\\band of ultra-cynics, are seeing green again.\")"
|
||
]
|
||
},
|
||
"execution_count": 2,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"list(train_dataset)[0]"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"ដូច្នេះ យើងចេញសារព័ត៌មានថ្មី ១០ ចំណងជើងដំបូងពីឃ្លាំងទិន្នន័យរបស់យើង៖\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 5,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"**Sci/Tech** -> Wall St. Bears Claw Back Into the Black (Reuters) Reuters - Short-sellers, Wall Street's dwindling\\band of ultra-cynics, are seeing green again.\n",
|
||
"**Sci/Tech** -> Carlyle Looks Toward Commercial Aerospace (Reuters) Reuters - Private investment firm Carlyle Group,\\which has a reputation for making well-timed and occasionally\\controversial plays in the defense industry, has quietly placed\\its bets on another part of the market.\n",
|
||
"**Sci/Tech** -> Oil and Economy Cloud Stocks' Outlook (Reuters) Reuters - Soaring crude prices plus worries\\about the economy and the outlook for earnings are expected to\\hang over the stock market next week during the depth of the\\summer doldrums.\n",
|
||
"**Sci/Tech** -> Iraq Halts Oil Exports from Main Southern Pipeline (Reuters) Reuters - Authorities have halted oil export\\flows from the main pipeline in southern Iraq after\\intelligence showed a rebel militia could strike\\infrastructure, an oil official said on Saturday.\n",
|
||
"**Sci/Tech** -> Oil prices soar to all-time record, posing new menace to US economy (AFP) AFP - Tearaway world oil prices, toppling records and straining wallets, present a new economic menace barely three months before the US presidential elections.\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"for i,x in zip(range(5),train_dataset):\n",
|
||
" print(f\"**{classes[x[0]]}** -> {x[1]}\")\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"ដោយសារតែទិន្នន័យជា iterator បើយើងចង់ប្រើទិន្នន័យជាច្រើនដងយើងត្រូវបម្លែងវាទៅជាបរមាណៈ list:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"train_dataset, test_dataset = torchtext.datasets.AG_NEWS(root='./data')\n",
|
||
"train_dataset = list(train_dataset)\n",
|
||
"test_dataset = list(test_dataset)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## ការបំបែកពាក្យ\n",
|
||
"\n",
|
||
"ឥឡូវនេះយើងត្រូវបំលែងអត្ថបទទៅជាខ្ទង់ **លេខ** ដែលអាចត្រូវបានតំណាងជាទិន្ស័រ។ ប្រសិនបើយើងចង់តំណាងជារាយនាមអក្សរពាក្យ ត្រូវធ្វើពីរជំហាន៖\n",
|
||
"* ប្រើ **tokenizer** ដើម្បីបំបែកអត្ថបទទៅជាប្រភេទពាក្យ **tokens**\n",
|
||
"* បង្កើត **vocabulary** សម្រាប់ពាក្យទាំងនោះ។\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 4,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"['he', 'said', 'hello']"
|
||
]
|
||
},
|
||
"execution_count": 4,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"tokenizer = torchtext.data.utils.get_tokenizer('basic_english')\n",
|
||
"tokenizer('He said: hello')"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 5,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"counter = collections.Counter()\n",
|
||
"for (label, line) in train_dataset:\n",
|
||
" counter.update(tokenizer(line))\n",
|
||
"vocab = torchtext.vocab.vocab(counter, min_freq=1)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"ប្រើវាក្យសព្ទ យើងអាចបំលែងខ្សែអក្សរដែលបានបំបែករបស់យើងទៅជាសំណុំលេខបានយ៉ាងងាយស្រួលៈ\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 19,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Vocab size if 95810\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"[599, 3279, 97, 1220, 329, 225, 7368]"
|
||
]
|
||
},
|
||
"execution_count": 19,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"vocab_size = len(vocab)\n",
|
||
"print(f\"Vocab size if {vocab_size}\")\n",
|
||
"\n",
|
||
"stoi = vocab.get_stoi() # dict to convert tokens to indices\n",
|
||
"\n",
|
||
"def encode(x):\n",
|
||
" return [stoi[s] for s in tokenizer(x)]\n",
|
||
"\n",
|
||
"encode('I love to play with my words')"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## ការបង្ហាញអត្ថបទជាថង់ពាក្យ\n",
|
||
"\n",
|
||
"ដោយសារពាក្យសម្គាល់អត្ថន័យ ម្តងម្កាលយើងអាចរកឃើញអត្ថន័យនៃអត្ថបទតាមរយៈការមើលតែពាក្យនីមួយៗ ដោយមិនគិតពីលំដាប់របស់ពួកវានៅក្នុងប្រយោគ។ ឧទាហរណ៍ សម្រាប់ការតែងចំណាត់ថ្នាក់ព័ត៌មាន ពាក្យដូចជា *អាកាសធាតុ*, *ហេីយគ្រាប់ទឹកកក* មានសក្តានុពលបង្ហាញពី *ការព្យាករណ៍អាកាសធាតុ* ខណៈពាក្យដូចជា *ភាគហ៊ុន*, *ដុល្លារ* នឹងចាត់ទុកថាជា *ព័ត៌មានហិរញ្ញវត្ថុ*។\n",
|
||
"\n",
|
||
"**ថង់ពាក្យ** (BoW) គឺជាការបង្ហាញវ៉ិចទ័រដែលប្រើប្រាស់ធម្មតាពិសេសច្រើនបំផុត។ ពាក្យនីមួយៗ ត្រូវបានភ្ជាប់ទៅនឹងឧSobatាយវ៉ិចទ័រ ដោយធាតុវ៉ិចទ័រមានចំនួនករណីកើតឡើងនៃពាក្យនៅក្នុងឯកសារដែលបានផ្ដល់។\n",
|
||
"\n",
|
||
" \n",
|
||
"\n",
|
||
"> **សំគាល់**: អ្នកគួរតែគិតថា BoW ជា៉ការសរុបវ៉ិចទ័រ one-hot-encoded សម្រាប់ពាក្យនីមួយៗនៅក្នុងអត្ថបទ។\n",
|
||
"\n",
|
||
"ខាងក្រោមជាឧទាហរណ៍នៃរបៀបបង្កើតការបង្ហាញថង់ពាក្យប្រើប្រាស់បណ្ណាល័យ Scikit Learn ក្នុងភាសា python ៖\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 7,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"array([[1, 1, 0, 2, 0, 0, 0, 0, 0]], dtype=int64)"
|
||
]
|
||
},
|
||
"execution_count": 7,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"from sklearn.feature_extraction.text import CountVectorizer\n",
|
||
"vectorizer = CountVectorizer()\n",
|
||
"corpus = [\n",
|
||
" 'I like hot dogs.',\n",
|
||
" 'The dog ran fast.',\n",
|
||
" 'Its hot outside.',\n",
|
||
" ]\n",
|
||
"vectorizer.fit_transform(corpus)\n",
|
||
"vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"ដើម្បីគណនាពុម្ពទំនុកចិត្ត bag-of-words ពីតំណាងវ៉ិកទ័រនៃឃ្លាសន្និដ្ឋាន AG_NEWS របស់យើង យើងអាចប្រើមុខងារដូចខាងក្រោម៖\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 20,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"tensor([2., 1., 2., ..., 0., 0., 0.])\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"vocab_size = len(vocab)\n",
|
||
"\n",
|
||
"def to_bow(text,bow_vocab_size=vocab_size):\n",
|
||
" res = torch.zeros(bow_vocab_size,dtype=torch.float32)\n",
|
||
" for i in encode(text):\n",
|
||
" if i<bow_vocab_size:\n",
|
||
" res[i] += 1\n",
|
||
" return res\n",
|
||
"\n",
|
||
"print(to_bow(train_dataset[0][1]))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"> **កំណត់សម្គាល់:** នៅទីនេះយើងកំពុងប្រើអថេរ `vocab_size` កម្រិតសកល ដើម្បីបញ្ជាក់ទំហំលំនាំដើមនៃវាក្យសព្ទ។ ពីព្រោះទំហំពាក្យសព្ទជាញែកខ្លាំងជារឿយៗ យើងអាចកំណត់ទំហំវាក្យសព្ទទៅតែពាក្យដែលមានភាពញឹកញាប់ខ្ពស់បំផុត។ សូមព្យាយាមកាត់បន្ថយតម្លៃ `vocab_size` ហើយរត់កូដខាងក្រោម ហើយមើលថាវាមានឥទ្ធិពលយ៉ាងណាលើភាពត្រឹមត្រូវ។ អ្នកគួរត្រូវរំពឹងថា ភាពត្រឹមត្រូវនឹងធ្លាក់ចុះបន្តិច ប៉ុន្តែមិនខ្លាំងទេ ដើម្បីសំរាប់ការសមត្ថភាពខ្ពស់ជាងមុន។\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## ការបណ្តុះបណ្តាលអ្នកចាត់ថ្នាក់ BoW\n",
|
||
"\n",
|
||
"ឥឡូវនេះដែលយើងបានរៀនថាតើធ្វើដូចម្តេចដើម្បីបង្កើតតំណាងបង្គោលពាក្យ Bag-of-Words នៃអត្ថបទរបស់យើងហើយ យើងចង់បណ្តុះបណ្តាលអ្នកចាត់ថ្នាក់សម្រាប់វា។ ជាមួយនេះ ដំបូង យើងត្រូវបម្លែងទិន្នន័យសម្រាប់ការបណ្តុះបណ្តាលដោយរបៀបគឺ ដំណាក់កាលតំណាងពាក្យតាមទីតាំងទាំងអស់ត្រូវបានបម្លែងទៅជាតំណាង Bag-of-Words។ នេះអាចសម្រេចបានដោយផ្ទេរអនុគមន៍ `bowify` ជាព៉ារ៉ាម៉ែត្រ `collate_fn` ទៅឲ្យ `DataLoader` នៃ torch ដែលមានស្តង់ដារ៖\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 21,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"from torch.utils.data import DataLoader\n",
|
||
"import numpy as np \n",
|
||
"\n",
|
||
"# this collate function gets list of batch_size tuples, and needs to \n",
|
||
"# return a pair of label-feature tensors for the whole minibatch\n",
|
||
"def bowify(b):\n",
|
||
" return (\n",
|
||
" torch.LongTensor([t[0]-1 for t in b]),\n",
|
||
" torch.stack([to_bow(t[1]) for t in b])\n",
|
||
" )\n",
|
||
"\n",
|
||
"train_loader = DataLoader(train_dataset, batch_size=16, collate_fn=bowify, shuffle=True)\n",
|
||
"test_loader = DataLoader(test_dataset, batch_size=16, collate_fn=bowify, shuffle=True)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"ឥឡូវនេះចូរអនុស្សាណារៀបចំបណ្តាញសរសេរមួយសម្រាប់ចំណាត់ថ្នាក់សាមញ្ញ ដែលមានស្រទាប់ខាងស្រទាប់តែមួយ។ ទំហំវ៉ិចទ័រចូលមានទំហំស្មើនឹង `vocab_size` ហើយទំហំចេញឆបគ្នានឹងចំនួនថ្នាក់ (4)។ ពីព្រោះយើងកំពុងដោះស្រាយបញ្ហាចំណាត់ថ្នាក់ ការជំរុញចុងក្រោយគឺជា `LogSoftmax()`។\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 22,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"net = torch.nn.Sequential(torch.nn.Linear(vocab_size,4),torch.nn.LogSoftmax(dim=1))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"ឥឡូវនេះយើងនឹងកំណត់រង្វិលបណ្តុះបណ្តាល PyTorch ស្តង់ដារ។ ព្រោះតែកំណត់ទិន្នន័យរបស់យើងមានទំហំធំជាងមធ្យម សម្រាប់គោលបំណងបង្រៀនយើងនឹងបណ្តុះបណ្តាលគ្រាន់តែកំណត់មួយទេ ហើយខ្លះពេលម្យ៉ាងទៀតក៏អាចបណ្តុះបណ្តាលតិចជាងមួយកំណត់ផង (ការបញ្ជាក់ពាក្យបញ្ជា `epoch_size` អនុញ្ញាតឲ្យយើងកំណត់ដែនកំណត់ការបណ្តុះបណ្តាល)។ យើងក៏នឹងរាយការណ៍ភាពត្រឹមត្រូវបណ្តុះបណ្តាលដែលបានសង្ស័យក្នុងអំឡុងពេលបណ្តុះបណ្តាលផងដែរ; ភាគរយនៃការរាយការណ៍ត្រូវបានកំណត់ដោយការបញ្ជាក់ពាក្យបញ្ជា `report_freq`។\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 24,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"def train_epoch(net,dataloader,lr=0.01,optimizer=None,loss_fn = torch.nn.NLLLoss(),epoch_size=None, report_freq=200):\n",
|
||
" optimizer = optimizer or torch.optim.Adam(net.parameters(),lr=lr)\n",
|
||
" net.train()\n",
|
||
" total_loss,acc,count,i = 0,0,0,0\n",
|
||
" for labels,features in dataloader:\n",
|
||
" optimizer.zero_grad()\n",
|
||
" out = net(features)\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"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 25,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"3200: acc=0.8028125\n",
|
||
"6400: acc=0.8371875\n",
|
||
"9600: acc=0.8534375\n",
|
||
"12800: acc=0.85765625\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"(0.026090790722161722, 0.8620069296375267)"
|
||
]
|
||
},
|
||
"execution_count": 25,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"train_epoch(net,train_loader,epoch_size=15000)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## BiGrams, TriGrams និង N-Grams\n",
|
||
"\n",
|
||
"ការកំណត់មួយនៃវិធីសាស្រ្តថតពាក្យ (bag of words) គឺពាក្យខ្លះជាផ្នែកមួយនៃការបង្កើតអត្ថាធិប្បាយពាក្យច្រើនពាក្យ ដូចជាឧទាហរណ៍ ពាក្យ 'hot dog' មានន័យខុសពីពាក្យ 'hot' និង 'dog' ក្នុងបរិបទផ្សេងៗ។ ប្រសិនបើយើងបង្ហាញពាក្យ 'hot' និង 'dog' ជានិរន្តរភាពដោយវ៉ិចទ័រដូចគ្នា វាអាចបង្កការជ្រុះច្រឡំចំពោះម៉ូដែលរបស់យើង។\n",
|
||
"\n",
|
||
"ដើម្បីដោះស្រាយបញ្ហានេះ, **ការតំណាង N-gram** ត្រូវបានប្រើជាញឹកញាប់ក្នុងវិធីសាស្រ្តចាត់ថ្នាក់ឯកសារ, ដែលប្រេកង់នៃពាក្យរាល់ខ្ទង់ពាក្យពីរឬបីពាក្យគឺជាលក្ខណៈសំខាន់សំរាប់ការបណ្តុះបណ្តាលម៉ាស៊ីនចាត់ថ្នាក់។ ក្នុងការតំណាង bigram, ឧទាហរណ៍យើងនឹងបន្ថែមដំណាក់កាលពាក្យទាំងអស់ទៅក្នុងវ៉ុកាប្យូលារី ខៀវបន្ថែមពីពាក្យដើម។\n",
|
||
"\n",
|
||
"ខាងក្រោមជាឧទាហរណ៍ពីរបៀបបង្កើតការតំណាង bigram bag of word ដោយប្រើ Scikit Learn៖\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 26,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Vocabulary:\n",
|
||
" {'i': 7, 'like': 11, 'hot': 4, 'dogs': 2, 'i like': 8, 'like hot': 12, 'hot dogs': 5, 'the': 16, 'dog': 0, 'ran': 14, 'fast': 3, 'the dog': 17, 'dog ran': 1, 'ran fast': 15, 'its': 9, 'outside': 13, 'its hot': 10, 'hot outside': 6}\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"array([[1, 0, 1, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],\n",
|
||
" dtype=int64)"
|
||
]
|
||
},
|
||
"execution_count": 26,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"bigram_vectorizer = CountVectorizer(ngram_range=(1, 2), token_pattern=r'\\b\\w+\\b', min_df=1)\n",
|
||
"corpus = [\n",
|
||
" 'I like hot dogs.',\n",
|
||
" 'The dog ran fast.',\n",
|
||
" 'Its hot outside.',\n",
|
||
" ]\n",
|
||
"bigram_vectorizer.fit_transform(corpus)\n",
|
||
"print(\"Vocabulary:\\n\",bigram_vectorizer.vocabulary_)\n",
|
||
"bigram_vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"ចំណុចខ្វះខាតសំខាន់នៃវិធីសាស្រ្ត N-gram គឺទំហំវេយ្យាករណ៍ចាប់ផ្តើមរីកចម្រើនយ៉ាងឆាប់រហ័ស ។ ក្នុងការអនុវត្តន៍ ពួកយើងត្រូវការចងក្រងការតំណាង N-gram ជាមួយបច្ចេកទេសការកាត់បន្ថយរាងវេកទិសខ្លះៗ ដូចជា *embeddings* ដែលយើងនឹងពិភាក្សានៅឯកតាចុងក្រោយ។\n",
|
||
"\n",
|
||
"ដើម្បីប្រើប្រាស់ការតំណាង N-gram នៅក្នុងទិន្នន័យ **AG News** របស់យើង យើងត្រូវតែបង្កើតវេយ្យាករណ៍ ngram ពិសេស ៖\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 27,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Bigram vocabulary length = 1308842\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"counter = collections.Counter()\n",
|
||
"for (label, line) in train_dataset:\n",
|
||
" l = tokenizer(line)\n",
|
||
" counter.update(torchtext.data.utils.ngrams_iterator(l,ngrams=2))\n",
|
||
" \n",
|
||
"bi_vocab = torchtext.vocab.vocab(counter, min_freq=1)\n",
|
||
"\n",
|
||
"print(\"Bigram vocabulary length = \",len(bi_vocab))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"យើងអាចប្រើកូដដូចខាងលើដើម្បីបណ្តុះម៉ាស៊ីនចាត់ថ្នាក់ ប៉ុន្តែវានឹងប្រើអង្គចងចាំខ្លាំងណាស់។ នៅឯកត្តាបន្ទាប់ យើងនឹងបណ្តុះម៉ាស៊ីនចាត់ថ្នាក់ bigram ដោយប្រើ embeddings។\n",
|
||
"\n",
|
||
"> **សម្គាល់:** អ្នកអាចទុកតែ ngrams ដែលបញ្ចេញឡើងក្នុងអត្ថបទច្រើនជាងចំនួនដែលបានបញ្ជាក់។ វានឹងធានាថា bigrams ដែលមានកំណត់នឹងត្រូវដកចេញ ហើយនឹងបន្ថយវិមាត្រជាប្រសើរណាស់។ ដើម្បីធ្វើដូចនេះ សូមកំណត់ប៉ារ៉ាម៉ែត្រ `min_freq` ទៅតម្លៃខ្ពស់ជាងនេះ ហើយមើលការផ្លាស់ប្តូរវែងនៃវចនានុក្រម។\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Term Frequency Inverse Document Frequency TF-IDF\n",
|
||
"\n",
|
||
"ក្នុងការតំណាង BoW, ការបង្ហាញពាក្យត្រូវបានគិតសោយាក់កម្រ, មិនគិតថាពាក្យនោះជាពាក្យអ្វីនោះទេ។ ទោះជាយ៉ាងណា, គឺច្បាស់ថាពាក្យដែលមានប្រេកង់ច្រើន ដូចជា *a*, *in* ល។ មានសារៈសំខាន់តិចជាងបច្ចេកទេសពិសេស។ ជាការពិត, ក្នុងភារកិច្ច NLP ភាគច្រើនពាក្យខ្លះមានទំនាក់ទំនងសំខាន់ជាងពាក្យផ្សេងទៀត។\n",
|
||
"\n",
|
||
"**TF-IDF** មានន័យថា **term frequency–inverse document frequency**។ វាជាបម្លែងពីបាវពាក្យដែលជំនួសដោយតម្លៃពីរបៀប 0/1 ដែលបង្ហាញពីការបង្ហាញរបស់ពាក្យមួយក្នុងឯកសារ ដែលមានតម្លៃជាចំនួនទសភាគ ដែលទាក់ទងនឹងប្រេកង់នៃការបង្ហាញពាក្យនៅក្នុងក្រុមឯកសារ។\n",
|
||
"\n",
|
||
"យ៉ាងជាក់លាក់, ទម្ងន់ $w_{ij}$ នៃពាក្យ $i$ នៅក្នុងឯកសារ $j$ ត្រូវបានកំណត់ដូចជា៖\n",
|
||
"$$\n",
|
||
"w_{ij} = tf_{ij}\\times\\log({N\\over df_i})\n",
|
||
"$$\n",
|
||
"ដែល\n",
|
||
"* $tf_{ij}$ គឺជាចំនួនការបង្ហាញនៃ $i$ នៅក្នុង $j$, គឺតម្លៃ BoW ដែលយើងបានឃើញមុន\n",
|
||
"* $N$ គឺជាចំនួនឯកសារនៅក្នុងប្រមូលផ្តុំ\n",
|
||
"* $df_i$ គឺជាចំនួនឯកសារដែលមានពាក្យ $i$ នៅក្នុងប្រមូលផ្តុំទាំងមូល\n",
|
||
"\n",
|
||
"តម្លៃ TF-IDF $w_{ij}$ បន្ថែមឡើងជាផ្តាច់មុខទៅនឹងចំនួនដងដែលពាក្យមួយប្រែប្រួលក្នុងឯកសារ ហើយត្រូវបានពន្លាក់ដោយចំនួនឯកសារនៅក្នុងក្រុមឯកសារដែលមានពាក្យនោះ ដែលជួយកែសម្រួលសម្រាប់ការពិតថាពាក្យខ្លះបង្ហាញញឹកញាប់ជាងពាក្យផ្សេងៗ។ ឧទាហរណ៍ ប្រសិនបើពាក្យបង្ហាញនៅក្នុង *គ្រប់* ឯកសារនៅក្នុងប្រមូលផ្តុំ, $df_i=N$, ហើយ $w_{ij}=0$, ហើយពាក្យទាំងនោះនឹងត្រូវបានមិនគិតទេ។\n",
|
||
"\n",
|
||
"អ្នកអាចបង្កើតបច្ចេកទេសវ៉េកទ័រ TF-IDF របស់អត្ថបទដោយងាយស្រួលជាមួយ Scikit Learn:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 28,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"array([[0.43381609, 0. , 0.43381609, 0. , 0.65985664,\n",
|
||
" 0.43381609, 0. , 0. , 0. , 0. ,\n",
|
||
" 0. , 0. , 0. , 0. , 0. ,\n",
|
||
" 0. ]])"
|
||
]
|
||
},
|
||
"execution_count": 28,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"from sklearn.feature_extraction.text import TfidfVectorizer\n",
|
||
"vectorizer = TfidfVectorizer(ngram_range=(1,2))\n",
|
||
"vectorizer.fit_transform(corpus)\n",
|
||
"vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## និទស្សន៏\n",
|
||
"\n",
|
||
"ទោះបីជាការបង្ហាញ TF-IDF ផ្តល់ទំងន់ប្រេកង់ចំពោះពាក្យផ្សេងៗក៏ដោយ វាមិនអាចបង្ហាញអត្ថន័យឬលំដាប់បានទេ។ ដូចដែលវចនករល្បី J. R. Firth បាននិយាយនៅឆ្នាំ ១៩៣៥ ថា “អត្ថន័យពេញលេញនៃពាក្យមួយគឺជានិរិច្ឆេទតែប៉ុណ្ណោះ ហើយការសិក្សាអត្ថន័យដោយមិនពាក់ព័ន្ធនឹងបរិបទមិនអាចយកត្រឹមត្រូវបានទេ។”។ យើងនឹងរៀនបន្ថែមនៅពេលក្រោយក្នុងវគ្គថ្នាក់របៀបចាប់យកព័ត៌មានបរិបទពីអត្ថបទដោយប្រើគំរូភាសា។\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**ការពិបាក**៖\nឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលដែលយើងខិតខំសម្រាប់ភាពត្រឹមត្រូវ សូមយកចិត្តទុកដាក់ថាបកប្រែដោយស្វ័យប្រវត្តិក្នុងខ្លះអាចមានកំហុសឬភាពមិនត្រឹមត្រូវ។ ឯកសារដែលមានភាសាមូលដ្ឋានគួរត្រូវបានគេចាត់ទុកជាផ្លូវការមួយ។ សម្រាប់ព័ត៌មានសំខាន់ៗ ការបកប្រែដោយអ្នកជំនាញមនុស្សគឺមានការផ្តល់អនុសាសន៍។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំឬការបកស្រាយខុសឆ្គងដែលកើតឡើងពីការប្រើប្រាស់បកប្រែនេះឡើយ។\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"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"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 2
|
||
} |