AI-For-Beginners/translations/km/lessons/5-NLP/13-TextRep/TextRepresentationTF.ipynb

641 lines
39 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# ការប្រភេទអត្ថបទ\n",
"\n",
"ក្នុងមូឌុលនេះ យើង​នឹងចាប់​ផ្តើម​ជាមួយ​ការងារ​ប្រភេទ​អត្ថបទ​រឹងមួយ​ដែលមានមូលដ្ឋានលើ **[AG_NEWS](http://www.di.unipi.it/~gulli/AG_corpus_of_news_articles.html)**៖ យើង​នឹងចាត់ថ្នាក់​ចំណងជើង​ព័ត៌មាន​ទៅក្នុង​ប្រភេទ​មួយពីចំនួន ៤ គឺ​ពិភពលោក កីឡា អាជីវកម្ម និង វិទ្យាសាស្ត្រ/បច្ចេកវិទ្យា។\n",
"\n",
"## សំណុំទិន្នន័យ\n",
"\n",
"ដើម្បី​ផ្ទុក​សំណុំទិន្នន័យ យើង​នឹង​ប្រើ​អ្នកប្រើប្រាស់ API របស់ **[TensorFlow Datasets](https://www.tensorflow.org/datasets)**។\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import tensorflow as tf\n",
"from tensorflow import keras\n",
"import tensorflow_datasets as tfds\n",
"\n",
"# In this tutorial, we will be training a lot of models. In order to use GPU memory cautiously,\n",
"# we will set tensorflow option to grow GPU memory allocation when required.\n",
"physical_devices = tf.config.list_physical_devices('GPU') \n",
"if len(physical_devices)>0:\n",
" tf.config.experimental.set_memory_growth(physical_devices[0], True)\n",
"\n",
"dataset = tfds.load('ag_news_subset')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះយើងអាចចូលប្រើផ្នែកបណ្តុះបណ្តាល និងផ្នែកសាកល្បងនៃសំណុំទិន្នន័យដោយប្រើ `dataset['train']` និង `dataset['test']` តាមលំដាប់៖\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Length of train dataset = 120000\n",
"Length of test dataset = 7600\n"
]
}
],
"source": [
"ds_train = dataset['train']\n",
"ds_test = dataset['test']\n",
"\n",
"print(f\"Length of train dataset = {len(ds_train)}\")\n",
"print(f\"Length of test dataset = {len(ds_test)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"មកបោះពុម្ពចេញចំណងជើងព័ត៌មានថ្មី ១០ ប្រធានចុងពីកំណត់ត្រារបស់យើង៖\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3 (Sci/Tech) -> b'AMD Debuts Dual-Core Opteron Processor' b'AMD #39;s new dual-core Opteron chip is designed mainly for corporate computing applications, including databases, Web services, and financial transactions.'\n",
"1 (Sports) -> b\"Wood's Suspension Upheld (Reuters)\" b'Reuters - Major League Baseball\\\\Monday announced a decision on the appeal filed by Chicago Cubs\\\\pitcher Kerry Wood regarding a suspension stemming from an\\\\incident earlier this season.'\n",
"2 (Business) -> b'Bush reform may have blue states seeing red' b'President Bush #39;s quot;revenue-neutral quot; tax reform needs losers to balance its winners, and people claiming the federal deduction for state and local taxes may be in administration planners #39; sights, news reports say.'\n",
"3 (Sci/Tech) -> b\"'Halt science decline in schools'\" b'Britain will run out of leading scientists unless science education is improved, says Professor Colin Pillinger.'\n",
"1 (Sports) -> b'Gerrard leaves practice' b'London, England (Sports Network) - England midfielder Steven Gerrard injured his groin late in Thursday #39;s training session, but is hopeful he will be ready for Saturday #39;s World Cup qualifier against Austria.'\n"
]
}
],
"source": [
"classes = ['World', 'Sports', 'Business', 'Sci/Tech']\n",
"\n",
"for i,x in zip(range(5),ds_train):\n",
" print(f\"{x['label']} ({classes[x['label']]}) -> {x['title']} {x['description']}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការបម្លែងអត្ថបទទៅជាវិចទ័រ\n",
"\n",
"ឥឡូវនេះយើងត្រូវការបម្លែងអត្ថបទទៅជា **លេខ** ដែលអាចត្រូវបានតំណាងជាទង់សរ។ ប្រសិនបើយើងចង់បានការតំណាងនៅកម្រិតពាក្យ យើងត្រូវធ្វើរឿងពីរនេះ៖\n",
"\n",
"* ប្រើ **tokenizer** ដើម្បីបំបែកអត្ថបទទៅជាផ្នែកតូចៗ (**tokens**)។\n",
"* បង្កើត **វ៉ុកាប្យូលារី** សម្រាប់ those tokens នោះ។\n",
"\n",
"### ការកំណត់ទំហំវ៉ុកាប្យូលារី\n",
"\n",
"ក្នុងឧទាហរណ៍ឯកទេស AG News ទំហំវ៉ុកាប្យូលារីគឺធំបំផុត មានពាក្យលើស ១០០,០០០។ ជាទូទៅ យើងមិនត្រូវការពាក្យដែលមានកម្រិតតិចក្នុងអត្ថបទទេ — មានតែប៉ុន្មានវាក្សត្រ​ដែលមានពាក្យនោះ ហើយម៉ូដែលនឹងមិនបានរៀនពីពួកវា។ ដូច្នេះ វាមានន័យថាត្រូវកំណត់ទំហំវ៉ុកាប្យូលារីឲ្យតូចជាងនេះដោយផ្ញើអាគឺម៉ង់ទៅកាន់អ្នកបង្កើត vectorizer:\n",
"\n",
"ការ​ដំណើរការ​ទាំងពីរ​នេះ​អាច​ត្រូវបាន​គ្រប់គ្រង​ដោយ​ការ​ស្រទាប់ **TextVectorization** ។ យើងមកបង្កើតវត្ថុ vectorizer ហើយបន្ទាប់មកហៅវិធី `adapt` ដើម្បីឆែកអត្ថបទទាំងអស់និងបង្កើតវ៉ុកាប្យូលារី។\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"vocab_size = 50000\n",
"vectorizer = keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size)\n",
"vectorizer.adapt(ds_train.take(500).map(lambda x: x['title']+' '+x['description']))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **ចំណាំ** ថា​យើង​កំពុង​ប្រើ​តែ​ផ្នែក​មួយ​នៃ​សំណុំ​ទិន្នន័យ​ទាំងមូល ដើម្បី​បង្កើត​ពាក្យសម្បត្តិ បង្រៀនគ្នា​ដើម្បី​ចំណាយ​ពេល​តែ្វ​រហ័ស និង​មិន​បាច់​ឲ្យ​អ្នក​រង់ចាំ។ ទោះ​យ៉ាង​ណា​យើង​កំពុង​រក្សា​ឲ្យ​មាន​ហានិភ័យ​ថា​ពាក្យ​ខ្លះ​ពី​សំណុំ​ទិន្នន័យ​ទាំង​មូល​នោះ နឹង​មិនមាន​នៅ​ក្នុង​ពាក្យសម្បត្តិ​នោះ​ទេ ហើយ​នឹង​ត្រូវ​មិនគិត​ទៅ​វិញ​ពេល​បណ្ដុះបណ្ដាល។ ដូច្នេះ​ការ​ប្រើ​កំណត់​ទំហំ​ពាក្យសម្បត្តិ​ទាំងមូល និង​រត់​តាម​សំណុំ​ទិន្នន័យ​ទាំងមូល​នៅ​ពេល `adapt` គួរតែ​បង្កើន​ភាពត្រឹមត្រូវ​ចុងក្រោយ ប៉ុន្តែ​មិន​បាន​ធំ​ទេ។\n",
"\n",
"ឥឡូវ​នេះ​យើង​អាច​ចូលដំណើរការ​ពាក្យសម្បត្តិ​ពិតប្រាកដ:\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['', '[UNK]', 'the', 'to', 'a', 'in', 'of', 'and', 'on', 'for']\n",
"Length of vocabulary: 5335\n"
]
}
],
"source": [
"vocab = vectorizer.get_vocabulary()\n",
"vocab_size = len(vocab)\n",
"print(vocab[:10])\n",
"print(f\"Length of vocabulary: {vocab_size}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ដោយប្រើឧបករណ៍បំលែងវ៉ិចទ័រ យើងអាចបំលែងអត្ថបទណាមួយទៅជាសំណុំលេខបានយ៉ាងងាយស្រួល៖\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<tf.Tensor: shape=(7,), dtype=int64, numpy=array([ 112, 3695, 3, 304, 11, 1041, 1], dtype=int64)>"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"vectorizer('I love to play with my words')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការទ្រទ្រង់អត្ថបទដោយក្មេងពាក្យ\n",
"\n",
"ដោយសារពាក្យតំណាងឲ្យ​អត្ថន័យ កម្រិតខ្លះ យើងអាចរកឃើញ​អត្ថន័យ​របស់​អត្ថបទមួយ​តាមរយៈ​ការ​មើល​រូបមន្តពាក្យ​ផ្តាច់មុខដោយមិនគិតពីរបៀបរៀបចំ​របស់​ពួកវា​ក្នុង​ប្រយោគ។ ឧទាហរណ៍ ដោយពិចារណាក្រោមបែបបទផ្សាយព័ត៌មាន ពាក្យដូចជា *អាកាសធាតុ* និង *ព្រិល* មានន័យប្រាប់​ពី *ការព្យាករណ៍អាកាសធាតុ* ខណៈពេលដែលពាក្យដូចជា *ភាគហ៊ុន* និង *ដុល្លារ* នឹងរាប់បញ្ចូលទៅក្នុង *ព័ត៌មានហិរញ្ញវត្ថុ* ។\n",
"\n",
"**ការទ្រទ្រង់ជាម៉ូដែល Bag-of-words** (BoW) គឺជាការទ្រទ្រង់វ៉ិចទ័រដែលងាយស្រួលយល់បំផុតតាមលំនាំប្រពៃណី។ ពាក្យនីមួយៗត្រូវបានភ្ជាប់ទៅនឹងការរូបរាងវ៉ិចទ័រមួយ ហើយធាតុវ៉ិចទ័រមួយមានចំនួនករណីនៃពាក្យនីមួយៗដែលមាននៅក្នុងឯកសារដែលបានផ្តល់។\n",
"\n",
"![រូបភាពបង្ហាញរបៀប​ដែលការទ្រទ្រង់ជាវ៉ិចទ័រម៉ូដែល Bag-of-words ត្រូវបានបង្ហាញក្នុងអង្គចងចាំ។](../../../../../translated_images/km/bag-of-words-example.606fc1738f1d7ba9.webp) \n",
"\n",
"> **ចំណាំ**៖ អ្នកក៏អាចគិតថា BoW គឺជាការបូកគណនារូបរាងវ៉ិចទ័រ one-hot-encoded សម្រាប់ពាក្យនីមួយៗនៅក្នុងអត្ថបទ។\n",
"\n",
"ខាងក្រោមជាឧទាហរណ៍​នៃ​របៀប​បង្កើតការទ្រទ្រង់ bag-of-words ដោយប្រើ thư viện python Scikit Learn:\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1, 1, 0, 2, 0, 0, 0, 0, 0]], dtype=int64)"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.feature_extraction.text import CountVectorizer\n",
"sc_vectorizer = CountVectorizer()\n",
"corpus = [\n",
" 'I like hot dogs.',\n",
" 'The dog ran fast.',\n",
" 'Its hot outside.',\n",
" ]\n",
"sc_vectorizer.fit_transform(corpus)\n",
"sc_vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"យើងក៏អាចប្រើប្រាស់កម្មវិធី Keras vectorizer ដែលយើងបានកំណត់ខាងលើ ដើម្បីបម្លែងលេខពាក្យនីមួយៗទៅជាការអ៊ិនកូដមួយកំឡុង ហើយបូកវ៉ិចទ័រទាំងអស់នោះឡើង៖\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([0., 5., 0., ..., 0., 0., 0.], dtype=float32)"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def to_bow(text):\n",
" return tf.reduce_sum(tf.one_hot(vectorizer(text),vocab_size),axis=0)\n",
"\n",
"to_bow('My dog likes hot dogs on a hot day.').numpy()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **ចំណាំ**: អ្នកប្រហែលជាភ្ញាក់ផ្អើលថាលទ្ធផលខុសពីឧទាហរណ៍មុននេះ។ ការរឿងនោះស្ថិតនៅក្នុងឧទាហរណ៍ Keras ដែលប្រវែងនៃវ៉ិកទ័រត្រូវបានផ្គូរផ្គងនឹងទំហំវចនានុក្រម ដែលបានសាងសង់ពីទិន្នន័យ AG News ទាំងមូល ខណៈនៅក្នុងឧទាហរណ៍ Scikit Learn យើងបានសង់វចនានុក្រមពីអត្ថបទគំរូក្នុងពេលជាក់លាក់។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## បណ្តុះបណ្តាលអ្នកចាត់ថ្នាក់ BoW\n",
"\n",
"ឥឡូវនេះដែលយើងបានរៀនយ៉ាងដឹងថាតើធ្វើដូចម្តេចដើម្បីបង្កើតការបង្ហាញ bag-of-words សម្រាប់អត្ថបទរបស់យើងហើយ ចូរបណ្តុះបណ្តាលអ្នកចាត់ថ្នាក់មួយដែលប្រើវា។ ជាដំបូង យើងត្រូវបំលែង dataset របស់យើងទៅជាការបង្ហាញ bag-of-words។ វាអាចត្រូវបានសំរេចដោយប្រើមុខងារ `map` ដូចខាងក្រោម៖\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"batch_size = 128\n",
"\n",
"ds_train_bow = ds_train.map(lambda x: (to_bow(x['title']+x['description']),x['label'])).batch(batch_size)\n",
"ds_test_bow = ds_test.map(lambda x: (to_bow(x['title']+x['description']),x['label'])).batch(batch_size)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវយើងខ្លាំងកំណត់បណ្តាញសរសៃប្រស фотографииាទម្នាក់ជាកម្មវិធីចំណាត់ថ្នាក់សាមញ្ញមួយដែលមានថាសភ្ជាប់តែមួយ។ ទំហំបញ្ចូលគឺ `vocab_size` ហើយទំហំបញ្ចូលតំណាងឲ្យចំនួនថ្នាក់ (4)។ ព្រោះយើងកំពុងដោះស្រាយបញ្ហាការចំណាត់ថ្នាក់, មុខងារជំរុញចុងក្រោយគឺ **softmax**៖\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"938/938 [==============================] - 66s 70ms/step - loss: 0.6144 - acc: 0.8427 - val_loss: 0.4416 - val_acc: 0.8697\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c70a947f0>"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.Dense(4,activation='softmax',input_shape=(vocab_size,))\n",
"])\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train_bow,validation_data=ds_test_bow)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Since we have 4 classes, an accuracy of above 80% is a good result.\n",
"\n",
"## ការបណ្តុះបណ្តាលព្យាករណ៍ជាបណ្ដាញតែមួយ\n",
"\n",
"ដោយសារតែ vectorizer ក៏ជាស្រទាប់ Keras ផងដែរ យើងអាចកំណត់បណ្ដាញមួយដែលរួមមានវា ហើយបណ្តុះបណ្តាលវាជាចុងទៅចុង។ ដូច្នេះយើងមិនចាំបាច់ vectorize សំណុំទិន្នន័យដោយប្រើ `map` ទេ អ្នកអាចផ្តល់សំណុំទិន្នន័យដើមទៅការបញ្ចូលរបស់បណ្ដាញ។\n",
"\n",
"> **កំណត់ចំណាំ**: យើងនៅតែត្រូវតែប្រើម៉ាប់ទៅលើសំណុំទិន្នន័យរបស់យើងដើម្បីផ្លាស់ប្ដូរបន្ទះពីវចនានុក្រម (ដូចជា `title`, `description` និង `label`) ទៅជា tuples។ ទោះយ៉ាងណា នៅពេលផ្ទុកទិន្នន័យពីឌីស អាចកសាងសំណុំទិន្នន័យជាមួយរចនាសម្ព័ន្ធដែលត្រូវការជាលើកដំបូង។\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"model\"\n",
"_________________________________________________________________\n",
" Layer (type) Output Shape Param # \n",
"=================================================================\n",
" input_1 (InputLayer) [(None, 1)] 0 \n",
" \n",
" text_vectorization (TextVec (None, None) 0 \n",
" torization) \n",
" \n",
" tf.one_hot (TFOpLambda) (None, None, 5335) 0 \n",
" \n",
" tf.math.reduce_sum (TFOpLam (None, 5335) 0 \n",
" bda) \n",
" \n",
" dense_2 (Dense) (None, 4) 21344 \n",
" \n",
"=================================================================\n",
"Total params: 21,344\n",
"Trainable params: 21,344\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n",
"938/938 [==============================] - 73s 77ms/step - loss: 0.6057 - acc: 0.8414 - val_loss: 0.4202 - val_acc: 0.8736\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c721521f0>"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def extract_text(x):\n",
" return x['title']+' '+x['description']\n",
"\n",
"def tupelize(x):\n",
" return (extract_text(x),x['label'])\n",
"\n",
"inp = keras.Input(shape=(1,),dtype=tf.string)\n",
"x = vectorizer(inp)\n",
"x = tf.reduce_sum(tf.one_hot(x,vocab_size),axis=1)\n",
"out = keras.layers.Dense(4,activation='softmax')(x)\n",
"model = keras.models.Model(inp,out)\n",
"model.summary()\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Bigrams, trigrams និង n-grams\n",
"\n",
"កំណត់ហេតុមួយនៃវិធីសាស្រ្ត bag-of-words គឺពាក្យខ្លះជាផ្នែកនៃអត្ថបទពេញលេញមួយដែលមានពាក្យច្រើន, ឧទាហរណ៍, ពាក្យ 'hot dog' មានអត្ថន័យខុសគ្នាឥតខ្ចោះពីពាក្យ 'hot' និង 'dog' នៅក្នុងបរិបទផ្សេងទៀត។ ប្រសិនបើយើងបង្ហាញពាក្យ 'hot' និង 'dog' ជារូបមន្តដូចគ្នាទាំងអស់ វាអាចធ្វើឱ្យម៉ូដែលរបស់យើងបូកស្រួល។\n",
"\n",
"ដើម្បីដោះស្រាយបញ្ហានេះ, **ការតំណាងនៃ n-gram** ត្រូវបានប្រើយ៉ាងធម្មតា ក្នុងវិធីសាស្រ្តចំណាត់ថ្នាក់ឯកសារ ដែលដែលបរិមាណនៃពាក្យនីមួយៗ bi-word ឬ tri-word ជាសមាសធាតុមានប្រយោជន៍សម្រាប់បណ្តុះបណ្តាលអ្នកចំណាត់ថ្នាក់។ នៅក្នុងការតំណាង bigram, ឧទាហរណ៍, យើងនឹងបន្ថែមគូពាក្យទាំងអស់ទៅវចនានុក្រម បន្ថែមផងដល់ពាក្យដើម។\n",
"\n",
"ខាងក្រោមជាឧទាហរណ៍នៃវិធីបង្កើតការតំណាង bag of word bigram ដោយប្រើ Scikit Learnៈ\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"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": 14,
"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** របស់យើង យើងត្រូវបញ្ជូនចូលប៉ារ៉ាម៉ែត្រ `ngrams` ទៅក្នុងអ្នកបង្កើត `TextVectorization` របស់យើង។ ប្រវែងនៃវាក្យសម្ពន្ធ bigram គឺ **ធំជាងយ៉ាងសំខាន់** ក្នុងករណីរបស់យើងវាធ្វើបានលើស 1.3 លានសញ្ញានៅឡើយ! ដូចនេះវាអាចមានអត្ថប្រយោជន៍ក្នុងការរំលងត្រីកោណ bigram ដោយចំនួនដែលសមរម្យ។\n",
"\n",
"យើងអាចប្រើកូដដូចខាងលើដដែលដើម្បីបណ្តុះបណ្តាលអ្នកចាត់ថ្នាក់ ក៏ប៉ុន្តែ វាកើតមានការប្រើប្រាស់អង្គចងចាំមិនមានប្រសិទ្ធភាពទេ។ នៅឯកតាទៅមុខយើងនឹងបណ្តុះបណ្តាលអ្នកចាត់ថ្នាក់ bigram ប្រើ embeddings។ នៅពេលនេះ អ្នកអាចសាកល្បងបណ្តុះបណ្តាលអ្នកចាត់ថ្នាក់ bigram ក្នុងសៀវភៅកំណត់ត្រានេះ ហើយមើលថាតើអ្នកអាចទទួលបានភាពច្បាស់លាស់ខ្ពស់ជាងមុនទេ។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការគណនាផ្ទាល់ដោយស្វ័យប្រវត្តិរបស់វ៉ិចទ័រប៊លស័រ BoW\n",
"\n",
"នៅក្នុងឧទាហរណ៍ខាងលើ យើងបានគណនាវ៉ិចទ័រប៊លស័រ BoW ដោយដៃ ដោយបូកសំឡេងបញ្ចូលមួយ-កម្រាស់នៃពាក្យមួយៗ។ ទោះបីជាយ៉ាងណា កំណែចុងក្រោយនៃ TensorFlow អនុញ្ញាតឱ្យយើងគណនាវ៉ិចទ័រប៊លស័រ BoW ដោយស្វ័យប្រវត្តិ ដោយផ្តល់ប៉ារ៉ាម៉ែត្រ `output_mode='count` ទៅដល់អ្នកបង្កើតវ៉ិចទ័រ។ វានាំឲ្យការកំណត់និងបណ្តុះបណ្តាលម៉ូដែលរបស់យើងក្លាយជាស្រួលយ៉ាងច្រើន៖\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training vectorizer\n",
"938/938 [==============================] - 7s 7ms/step - loss: 0.5929 - acc: 0.8486 - val_loss: 0.4168 - val_acc: 0.8772\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c725217c0>"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size,output_mode='count'),\n",
" keras.layers.Dense(4,input_shape=(vocab_size,), activation='softmax')\n",
"])\n",
"print(\"Training vectorizer\")\n",
"model.layers[0].adapt(ds_train.take(500).map(extract_text))\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការពេញនិយមពាក្យ - អត្រាប្រាក់ឯកសារវិទ្យុបញ្ច្រាស (TF-IDF)\n",
"\n",
"ក្នុងការបង្ហាញ BoW,ការ កើតឡើងនៃពាក្យត្រូវបានវាស់គ្រប់យ៉ាង ដោយប្រើប្រាស់បច្ចេកវិទ្យាដូចគ្នាដោយមិនគិតពីពាក្យ។ ទោះយ៉ាងណា វCLEARថាពាក្យដែលកើតឡើងជាញឹកញាប់ដូចជា *a* និង *in* មានសារៈសំខាន់តិចជាងសម្រាប់ការធ្វើចំណាត់ថ្នាក់ជាងពាក្យឯកទេស។ ក្នុងភារកិច្ច NLP ភាគច្រើនពាក្យខ្លះមានសារៈសំខាន់ជាងអ្វីៗផ្សេងទៀត។\n",
"\n",
"**TF-IDF** មានន័យថា **ការពេញនិយមពាក្យ - អត្រាប្រាក់ឯកសារវិទ្យុបញ្ច្រាស**។ វាជារបៀបបំលែង bag-of-words មួយ ដែលជំនួសជំនួសតម្លៃ 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": 16,
"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": 16,
"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": [
"នៅក្នុង Keras ស្រទាប់ `TextVectorization` អាចគណនាប្រមាណភាព TF-IDF ដោយស្វ័យប្រវត្តិដោយផ្ទេរព៉ារ៉ាម៉ែត្រ `output_mode='tf-idf'`។ សូមធ្វើម្តងទៀតនូវកូដដែលយើងបានប្រើខាងលើ ដើម្បីមើលថា តើការប្រើ TF-IDF មានបង្កើនភាពត្រឹមត្រូវឬអត់៖\n"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training vectorizer\n",
"938/938 [==============================] - 12s 12ms/step - loss: 0.4197 - acc: 0.8662 - val_loss: 0.3432 - val_acc: 0.8849\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c729dfd30>"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size,output_mode='tf-idf'),\n",
" keras.layers.Dense(4,input_shape=(vocab_size,), activation='softmax')\n",
"])\n",
"print(\"Training vectorizer\")\n",
"model.layers[0].adapt(ds_train.take(500).map(extract_text))\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## សេចក្ដីសន្នឹម\n",
"\n",
"ទោះបីជារូបមន្ត TF-IDF ផ្ដល់ទម្ងន់ប្រេកង់ទៅពាក្យផ្សេងៗក៏ដោយ វាមិនអាចបង្ហាញអត្ថន័យ ឬលំដាប់បានឡើយ។ ដូចដែលអ្នកភាសាល្បី J. R. Firth បាននិយាយនៅឆ្នាំ 1935 ថា \"អត្ថន័យពេញលេញនៃពាក្យមួយតែងតែមានបរិបទ ហើយការសិក្សាអំពីអត្ថន័យដែលមិនពាក់ព័ន្ធនឹងបរិបទមិនអាចយកទៅពិចារណាឲ្យបានចាប់អារម្មណ៍ឡើយ។\" យើងនឹងរៀនពីរបៀបចាប់យកព័ត៌មានបរិបទពីអត្ថបទដោយប្រើម៉ូដែលភាសាបន្ថែមនៅពេលក្រោយក្នុងវគ្គសិក្សា។\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": "0cb620c6d4b9f7a635928804c26cf22403d89d98d79684e4529119355ee6d5a5"
},
"kernel_info": {
"name": "conda-env-py37_tensorflow-py"
},
"kernelspec": {
"display_name": "py37_tensorflow",
"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"
},
"nteract": {
"version": "nteract-front-end@1.0.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}