647 lines
39 KiB
Plaintext
647 lines
39 KiB
Plaintext
{
|
||
"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",
|
||
"ডেটাসেট লোড করার জন্য, আমরা **[TensorFlow Datasets](https://www.tensorflow.org/datasets)** API ব্যবহার করব।\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",
|
||
"* একটি **টোকেনাইজার** ব্যবহার করে টেক্সটকে **টোকেন**-এ ভাগ করতে হবে।\n",
|
||
"* সেই টোকেনগুলোর একটি **ভোকাবুলারি** তৈরি করতে হবে।\n",
|
||
"\n",
|
||
"### ভোকাবুলারির আকার সীমিত করা\n",
|
||
"\n",
|
||
"AG News ডেটাসেট উদাহরণে, ভোকাবুলারির আকার বেশ বড়, ১০০k এর বেশি শব্দ। সাধারণভাবে বলতে গেলে, আমাদের এমন শব্দের প্রয়োজন নেই যা টেক্সটে খুব কম উপস্থিত থাকে — শুধুমাত্র কয়েকটি বাক্যে সেগুলো থাকবে, এবং মডেল সেগুলো থেকে কিছু শিখতে পারবে না। তাই, ভোকাবুলারির আকার একটি ছোট সংখ্যায় সীমিত করা যুক্তিযুক্ত, যা ভেক্টরাইজার কনস্ট্রাক্টরে একটি আর্গুমেন্ট পাস করে করা যায়:\n",
|
||
"\n",
|
||
"এই দুটি ধাপই **TextVectorization** লেয়ার ব্যবহার করে সম্পন্ন করা যেতে পারে। চলুন ভেক্টরাইজার অবজেক্টটি ইনস্ট্যানশিয়েট করি, এবং তারপর `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",
|
||
"**ব্যাগ-অফ-ওয়ার্ডস** (BoW) ভেক্টর উপস্থাপন হল সবচেয়ে সহজে বোঝা যায় এমন ঐতিহ্যবাহী ভেক্টর উপস্থাপন। প্রতিটি শব্দ একটি ভেক্টর সূচকের সাথে যুক্ত থাকে, এবং একটি ভেক্টর উপাদান একটি নির্দিষ্ট ডকুমেন্টে প্রতিটি শব্দের উপস্থিতির সংখ্যা ধারণ করে।\n",
|
||
"\n",
|
||
" \n",
|
||
"\n",
|
||
"> **Note**: BoW কে আপনি টেক্সটের পৃথক শব্দগুলোর জন্য সমস্ত এক-হট-এনকোডেড ভেক্টরের যোগফল হিসেবেও ভাবতে পারেন।\n",
|
||
"\n",
|
||
"নিচে 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": [
|
||
"আমরা উপরে সংজ্ঞায়িত করা কেরাস ভেক্টরাইজারও ব্যবহার করতে পারি, প্রতিটি শব্দ সংখ্যাকে এক-হট এনকোডিংয়ে রূপান্তরিত করে এবং সেই সমস্ত ভেক্টর যোগ করে:\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",
|
||
"এখন আমরা শিখেছি কীভাবে আমাদের টেক্সটের ব্যাগ-অফ-ওয়ার্ডস উপস্থাপন তৈরি করতে হয়, চলুন একটি শ্রেণীবিভাজক প্রশিক্ষণ করি যা এটি ব্যবহার করে। প্রথমে, আমাদের ডেটাসেটকে ব্যাগ-অফ-ওয়ার্ডস উপস্থাপনে রূপান্তর করতে হবে। এটি নিম্নলিখিতভাবে `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`, এবং আউটপুট সাইজ শ্রেণীর সংখ্যা (৪) এর সাথে সম্পর্কিত। যেহেতু আমরা একটি শ্রেণীবিন্যাস কাজ সমাধান করছি, চূড়ান্ত সক্রিয়করণ ফাংশন হলো **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": [
|
||
"যেহেতু আমাদের ৪টি ক্লাস রয়েছে, ৮০% এর উপরে সঠিকতা একটি ভালো ফলাফল।\n",
|
||
"\n",
|
||
"## একটি নেটওয়ার্ক হিসেবে ক্লাসিফায়ার প্রশিক্ষণ\n",
|
||
"\n",
|
||
"কারণ ভেক্টরাইজারটি একটি Keras লেয়ারও, আমরা একটি নেটওয়ার্ক সংজ্ঞায়িত করতে পারি যা এটিকে অন্তর্ভুক্ত করে এবং এটিকে সম্পূর্ণভাবে প্রশিক্ষণ দিতে পারি। এইভাবে, আমাদের `map` ব্যবহার করে ডেটাসেট ভেক্টরাইজ করার প্রয়োজন নেই, আমরা শুধু মূল ডেটাসেটটি নেটওয়ার্কের ইনপুটে পাস করতে পারি।\n",
|
||
"\n",
|
||
"> **Note**: আমাদের এখনও আমাদের ডেটাসেটে `map` প্রয়োগ করতে হবে যাতে ডিকশনারি থেকে ক্ষেত্রগুলো (যেমন `title`, `description` এবং `label`) টুপলে রূপান্তরিত করা যায়। তবে, যখন ডিস্ক থেকে ডেটা লোড করা হয়, তখন আমরা প্রথম থেকেই প্রয়োজনীয় কাঠামো সহ একটি ডেটাসেট তৈরি করতে পারি।\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": [
|
||
"## বাইগ্রাম, ট্রাইগ্রাম এবং এন-গ্রাম\n",
|
||
"\n",
|
||
"ব্যাগ-অফ-ওয়ার্ড পদ্ধতির একটি সীমাবদ্ধতা হলো কিছু শব্দ বহু-শব্দের অভিব্যক্তির অংশ, যেমন 'হট ডগ' শব্দটি 'হট' এবং 'ডগ' শব্দের থেকে সম্পূর্ণ ভিন্ন অর্থ বহন করে। যদি আমরা 'হট' এবং 'ডগ' শব্দগুলো সবসময় একই ভেক্টর দিয়ে উপস্থাপন করি, তাহলে এটি আমাদের মডেলকে বিভ্রান্ত করতে পারে।\n",
|
||
"\n",
|
||
"এই সমস্যার সমাধানে, **এন-গ্রাম উপস্থাপনাগুলো** প্রায়ই ডকুমেন্ট শ্রেণীবিন্যাস পদ্ধতিতে ব্যবহৃত হয়, যেখানে প্রতিটি শব্দ, দ্বি-শব্দ বা ত্রি-শব্দের ফ্রিকোয়েন্সি শ্রেণীবিন্যাসকারী প্রশিক্ষণের জন্য একটি কার্যকর বৈশিষ্ট্য হিসেবে কাজ করে। উদাহরণস্বরূপ, বাইগ্রাম উপস্থাপনায় আমরা মূল শব্দগুলোর পাশাপাশি সমস্ত শব্দ জোড়াকে শব্দভাণ্ডারে যোগ করব।\n",
|
||
"\n",
|
||
"নিচে 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",
|
||
"আমাদের **AG News** ডেটাসেটে n-gram উপস্থাপন ব্যবহার করতে হলে, আমাদের `TextVectorization` কনস্ট্রাক্টরে `ngrams` প্যারামিটারটি পাস করতে হবে। একটি বিগ্রামের শব্দভাণ্ডারের দৈর্ঘ্য **অত্যন্ত বড়**, আমাদের ক্ষেত্রে এটি ১.৩ মিলিয়নেরও বেশি টোকেন! তাই এটি যৌক্তিক যে বিগ্রাম টোকেনগুলোকেও একটি যুক্তিসঙ্গত সংখ্যায় সীমাবদ্ধ করা উচিত।\n",
|
||
"\n",
|
||
"আমরা উপরের কোডটি ব্যবহার করে ক্লাসিফায়ার প্রশিক্ষণ দিতে পারি, তবে এটি খুবই মেমোরি-অকার্যকর হবে। পরবর্তী ইউনিটে, আমরা embeddings ব্যবহার করে বিগ্রাম ক্লাসিফায়ার প্রশিক্ষণ দেব। এর মধ্যে, আপনি এই নোটবুকে বিগ্রাম ক্লাসিফায়ার প্রশিক্ষণের সাথে পরীক্ষা-নিরীক্ষা করতে পারেন এবং দেখুন আপনি কি উচ্চতর সঠিকতা অর্জন করতে পারেন।\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## স্বয়ংক্রিয়ভাবে BoW ভেক্টর গণনা করা\n",
|
||
"\n",
|
||
"উপরের উদাহরণে আমরা একক শব্দের এক-হট এনকোডিং যোগ করে হাতে BoW ভেক্টর গণনা করেছি। তবে, TensorFlow-এর সর্বশেষ সংস্করণ আমাদেরকে `output_mode='count` প্যারামিটার ভেক্টরাইজার কনস্ট্রাক্টরে পাস করে স্বয়ংক্রিয়ভাবে BoW ভেক্টর গণনা করার সুযোগ দেয়। এটি আমাদের মডেল সংজ্ঞায়িত এবং প্রশিক্ষণ দেওয়া উল্লেখযোগ্যভাবে সহজ করে তোলে:\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 উপস্থাপনায়, শব্দের উপস্থিতি একই পদ্ধতি ব্যবহার করে ওজন দেওয়া হয়, শব্দটি যাই হোক না কেন। তবে, এটা স্পষ্ট যে *a* এবং *in* এর মতো সাধারণ শব্দগুলো শ্রেণীবিন্যাসের জন্য বিশেষায়িত শব্দগুলোর তুলনায় অনেক কম গুরুত্বপূর্ণ। বেশিরভাগ NLP কাজের ক্ষেত্রে কিছু শব্দ অন্যদের তুলনায় বেশি প্রাসঙ্গিক।\n",
|
||
"\n",
|
||
"**TF-IDF** এর পূর্ণরূপ হলো **টার্ম ফ্রিকোয়েন্সি - ইনভার্স ডকুমেন্ট ফ্রিকোয়েন্সি**। এটি ব্যাগ-অফ-ওয়ার্ডসের একটি পরিবর্তিত রূপ, যেখানে একটি শব্দের উপস্থিতি একটি ডকুমেন্টে 0/1 বাইনারি মান দিয়ে নির্দেশ করার পরিবর্তে একটি ফ্লোটিং-পয়েন্ট মান ব্যবহার করা হয়, যা কর্পাসে শব্দের উপস্থিতির ফ্রিকোয়েন্সির সাথে সম্পর্কিত।\n",
|
||
"\n",
|
||
"আরও আনুষ্ঠানিকভাবে, একটি শব্দ $i$ এর ওজন $w_{ij}$ একটি ডকুমেন্ট $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",
|
||
"আপনি সহজেই Scikit Learn ব্যবহার করে টেক্সটের TF-IDF ভেক্টরাইজেশন তৈরি করতে পারেন:\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` স্তরটি `output_mode='tf-idf'` প্যারামিটার পাস করে স্বয়ংক্রিয়ভাবে 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 উপস্থাপনাগুলি বিভিন্ন শব্দের জন্য ফ্রিকোয়েন্সি ওজন প্রদান করে, সেগুলি অর্থ বা ক্রম উপস্থাপন করতে অক্ষম। ১৯৩৫ সালে বিখ্যাত ভাষাবিদ জে. আর. ফার্থ বলেছিলেন, \"একটি শব্দের সম্পূর্ণ অর্থ সর্বদা প্রাসঙ্গিক, এবং প্রসঙ্গ ছাড়া অর্থের কোনো অধ্যয়নকে গুরুত্ব সহকারে নেওয়া যায় না।\" আমরা এই কোর্সের পরবর্তী অংশে ভাষা মডেলিং ব্যবহার করে পাঠ্য থেকে প্রাসঙ্গিক তথ্য কীভাবে ধারণ করা যায় তা শিখব।\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"
|
||
},
|
||
"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"
|
||
},
|
||
"coopTranslator": {
|
||
"original_hash": "19b43951d55b377a76209c24c1f017e4",
|
||
"translation_date": "2025-08-28T12:33:47+00:00",
|
||
"source_file": "lessons/5-NLP/13-TextRep/TextRepresentationTF.ipynb",
|
||
"language_code": "bn"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 4
|
||
} |