AI-For-Beginners/translations/bn/lessons/5-NLP/16-RNN/RNNTF.ipynb

462 lines
40 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# পুনরাবৃত্তি নিউরাল নেটওয়ার্ক\n",
"\n",
"পূর্ববর্তী মডিউলে, আমরা টেক্সটের সমৃদ্ধ অর্থবহ উপস্থাপনাগুলি নিয়ে আলোচনা করেছি। আমরা যে আর্কিটেকচারটি ব্যবহার করেছি তা বাক্যের শব্দগুলির সম্মিলিত অর্থ ধারণ করে, তবে এটি শব্দগুলির **ক্রম** বিবেচনা করে না, কারণ এম্বেডিংয়ের পরে যে সংযোজন প্রক্রিয়া হয় তা মূল টেক্সট থেকে এই তথ্যটি সরিয়ে দেয়। যেহেতু এই মডেলগুলি শব্দের ক্রম উপস্থাপন করতে অক্ষম, তাই তারা টেক্সট জেনারেশন বা প্রশ্নোত্তরের মতো আরও জটিল বা দ্ব্যর্থক কাজ সমাধান করতে পারে না।\n",
"\n",
"একটি টেক্সট সিকোয়েন্সের অর্থ ধরতে, আমরা **পুনরাবৃত্তি নিউরাল নেটওয়ার্ক** বা RNN নামে একটি নিউরাল নেটওয়ার্ক আর্কিটেকচার ব্যবহার করব। RNN ব্যবহার করার সময়, আমরা আমাদের বাক্যটি নেটওয়ার্কের মধ্য দিয়ে একবারে একটি টোকেন পাঠাই, এবং নেটওয়ার্কটি কিছু **অবস্থা** তৈরি করে, যা আমরা পরবর্তী টোকেনের সাথে আবার নেটওয়ার্কে পাঠাই।\n",
"\n",
"![একটি উদাহরণ পুনরাবৃত্তি নিউরাল নেটওয়ার্ক জেনারেশন দেখানো চিত্র।](../../../../../translated_images/bn/rnn.27f5c29c53d727b5.webp)\n",
"\n",
"টোকেনগুলির ইনপুট সিকোয়েন্স $X_0,\\dots,X_n$ দেওয়া হলে, RNN একটি নিউরাল নেটওয়ার্ক ব্লকের সিকোয়েন্স তৈরি করে এবং ব্যাকপ্রোপাগেশনের মাধ্যমে এই সিকোয়েন্সটি এন্ড-টু-এন্ড প্রশিক্ষণ দেয়। প্রতিটি নেটওয়ার্ক ব্লক $(X_i,S_i)$ জোড়াকে ইনপুট হিসাবে নেয় এবং ফলাফল হিসাবে $S_{i+1}$ তৈরি করে। চূড়ান্ত অবস্থা $S_n$ বা আউটপুট $Y_n$ একটি লিনিয়ার ক্লাসিফায়ারে যায় ফলাফল তৈরি করতে। সমস্ত নেটওয়ার্ক ব্লক একই ওজন ভাগ করে এবং একটি ব্যাকপ্রোপাগেশন পাস ব্যবহার করে এন্ড-টু-এন্ড প্রশিক্ষণ দেওয়া হয়।\n",
"\n",
"> উপরের চিত্রটি পুনরাবৃত্তি নিউরাল নেটওয়ার্ককে আনরোলড ফর্মে (বামে) এবং আরও কমপ্যাক্ট পুনরাবৃত্তি উপস্থাপনায় (ডানে) দেখায়। এটি বোঝা গুরুত্বপূর্ণ যে সমস্ত RNN সেলগুলির একই **শেয়ারযোগ্য ওজন** রয়েছে।\n",
"\n",
"কারণ অবস্থা ভেক্টর $S_0,\\dots,S_n$ নেটওয়ার্কের মধ্য দিয়ে যায়, RNN শব্দগুলির মধ্যে ক্রমিক নির্ভরতা শিখতে সক্ষম। উদাহরণস্বরূপ, যখন *not* শব্দটি সিকোয়েন্সের কোথাও উপস্থিত হয়, এটি অবস্থা ভেক্টরের নির্দিষ্ট উপাদানগুলিকে অস্বীকার করতে শিখতে পারে।\n",
"\n",
"প্রত্যেকটি RNN সেলের ভিতরে দুটি ওজন ম্যাট্রিক্স থাকে: $W_H$ এবং $W_I$, এবং বায়াস $b$। প্রতিটি RNN ধাপে, ইনপুট $X_i$ এবং ইনপুট অবস্থা $S_i$ দেওয়া হলে, আউটপুট অবস্থা হিসাব করা হয় $S_{i+1} = f(W_H\\times S_i + W_I\\times X_i+b)$, যেখানে $f$ একটি অ্যাক্টিভেশন ফাংশন (সাধারণত $\\tanh$)।\n",
"\n",
"> টেক্সট জেনারেশন (যা আমরা পরবর্তী ইউনিটে আলোচনা করব) বা মেশিন ট্রান্সলেশনের মতো সমস্যার জন্য আমরা প্রতিটি RNN ধাপে কিছু আউটপুট মানও পেতে চাই। এই ক্ষেত্রে, আরেকটি ম্যাট্রিক্স $W_O$ থাকে, এবং আউটপুট হিসাব করা হয় $Y_i=f(W_O\\times S_i+b_O)$।\n",
"\n",
"চলুন দেখি কীভাবে পুনরাবৃত্তি নিউরাল নেটওয়ার্ক আমাদের নিউজ ডেটাসেট শ্রেণীবদ্ধ করতে সাহায্য করতে পারে।\n",
"\n",
"> স্যান্ডবক্স পরিবেশের জন্য, আমাদের নিশ্চিত করতে হবে যে প্রয়োজনীয় লাইব্রেরি ইনস্টল করা হয়েছে এবং ডেটা প্রিফেচ করা হয়েছে, এজন্য নিম্নলিখিত সেলটি চালাতে হবে। আপনি যদি লোকাল মেশিনে কাজ করেন, তবে এই সেলটি এড়িয়ে যেতে পারেন।\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"!{sys.executable} -m pip install --quiet tensorflow_datasets==4.4.0\n",
"!cd ~ && wget -q -O - https://mslearntensorflowlp.blob.core.windows.net/data/tfds-ag-news.tgz | tar xz"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import tensorflow as tf\n",
"from tensorflow import keras\n",
"import tensorflow_datasets as tfds\n",
"import numpy as np\n",
"\n",
"# We are going to be training pretty large models. In order not to face errors, we need\n",
"# to 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",
"ds_train, ds_test = tfds.load('ag_news_subset').values()"
]
},
{
"cell_type": "markdown",
"metadata": {
"nteract": {
"transient": {
"deleting": false
}
}
},
"source": [
"বড় মডেল প্রশিক্ষণ করার সময় GPU মেমোরি বরাদ্দ একটি সমস্যা হয়ে উঠতে পারে। এছাড়াও, আমাদের বিভিন্ন মিনিব্যাচ সাইজ নিয়ে পরীক্ষা করতে হতে পারে, যাতে ডেটা GPU মেমোরিতে ফিট করে, এবং প্রশিক্ষণ যথেষ্ট দ্রুত হয়। যদি আপনি আপনার নিজস্ব GPU মেশিনে এই কোড চালাচ্ছেন, তাহলে প্রশিক্ষণের গতি বাড়ানোর জন্য মিনিব্যাচ সাইজ সামঞ্জস্য করার চেষ্টা করতে পারেন।\n",
"\n",
"> **Note**: NVidia ড্রাইভারের কিছু নির্দিষ্ট সংস্করণ মডেল প্রশিক্ষণের পর মেমোরি মুক্ত করতে ব্যর্থ হতে পারে। আমরা এই নোটবুকে কয়েকটি উদাহরণ চালাচ্ছি, এবং এটি কিছু সেটআপে মেমোরি শেষ হয়ে যাওয়ার কারণ হতে পারে, বিশেষত যদি আপনি একই নোটবুকের অংশ হিসেবে নিজের পরীক্ষা চালাচ্ছেন। যদি আপনি মডেল প্রশিক্ষণ শুরু করার সময় কিছু অদ্ভুত ত্রুটি সম্মুখীন করেন, তাহলে নোটবুকের কার্নেল পুনরায় চালু করার কথা বিবেচনা করতে পারেন।\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": true,
"jupyter": {
"outputs_hidden": false,
"source_hidden": false
},
"nteract": {
"transient": {
"deleting": false
}
}
},
"outputs": [],
"source": [
"batch_size = 16\n",
"embed_size = 64"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## সহজ RNN শ্রেণীবিভাজক\n",
"\n",
"একটি সহজ RNN-এর ক্ষেত্রে, প্রতিটি পুনরাবৃত্তি ইউনিট একটি সাধারণ রৈখিক নেটওয়ার্ক, যা একটি ইনপুট ভেক্টর এবং স্টেট ভেক্টর গ্রহণ করে এবং একটি নতুন স্টেট ভেক্টর তৈরি করে। Keras-এ, এটি `SimpleRNN` স্তর দ্বারা উপস্থাপন করা যেতে পারে।\n",
"\n",
"যদিও আমরা সরাসরি RNN স্তরে এক-হট এনকোড করা টোকেন পাস করতে পারি, এটি একটি ভালো ধারণা নয় কারণ এগুলোর উচ্চ মাত্রা থাকে। তাই, আমরা শব্দ ভেক্টরের মাত্রা কমানোর জন্য একটি এমবেডিং স্তর ব্যবহার করব, এরপর একটি RNN স্তর এবং শেষে একটি `Dense` শ্রেণীবিভাজক।\n",
"\n",
"> **Note**: এমন ক্ষেত্রে যেখানে মাত্রা এত বেশি নয়, যেমন চরিত্র-স্তরের টোকেনাইজেশন ব্যবহার করার সময়, এক-হট এনকোড করা টোকেন সরাসরি RNN সেলে পাস করা যুক্তিযুক্ত হতে পারে।\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential\"\n",
"_________________________________________________________________\n",
"Layer (type) Output Shape Param # \n",
"=================================================================\n",
"text_vectorization (TextVect (None, None) 0 \n",
"_________________________________________________________________\n",
"embedding (Embedding) (None, None, 64) 1280000 \n",
"_________________________________________________________________\n",
"simple_rnn (SimpleRNN) (None, 16) 1296 \n",
"_________________________________________________________________\n",
"dense (Dense) (None, 4) 68 \n",
"=================================================================\n",
"Total params: 1,281,364\n",
"Trainable params: 1,281,364\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"vocab_size = 20000\n",
"\n",
"vectorizer = keras.layers.experimental.preprocessing.TextVectorization(\n",
" max_tokens=vocab_size,\n",
" input_shape=(1,))\n",
"\n",
"model = keras.models.Sequential([\n",
" vectorizer,\n",
" keras.layers.Embedding(vocab_size, embed_size),\n",
" keras.layers.SimpleRNN(16),\n",
" keras.layers.Dense(4,activation='softmax')\n",
"])\n",
"\n",
"model.summary()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **নোট:** এখানে আমরা সরলতার জন্য একটি অনট্রেইন্ড এমবেডিং লেয়ার ব্যবহার করছি, তবে আরও ভালো ফলাফলের জন্য আমরা Word2Vec ব্যবহার করে একটি প্রিট্রেইন্ড এমবেডিং লেয়ার ব্যবহার করতে পারি, যা আগের ইউনিটে বর্ণনা করা হয়েছে। এটি আপনার জন্য একটি ভালো অনুশীলন হবে যদি আপনি এই কোডটি প্রিট্রেইন্ড এমবেডিংয়ের সাথে কাজ করার জন্য মানিয়ে নিতে পারেন।\n",
"\n",
"এখন চলুন আমাদের RNN প্রশিক্ষণ করি। সাধারণভাবে RNN প্রশিক্ষণ করা বেশ কঠিন, কারণ RNN সেলগুলো সিকোয়েন্সের দৈর্ঘ্য বরাবর আনরোল করার পর, ব্যাকপ্রোপাগেশনে জড়িত লেয়ারগুলোর সংখ্যা অনেক বেড়ে যায়। তাই আমাদের একটি ছোট লার্নিং রেট নির্বাচন করতে হবে এবং ভালো ফলাফলের জন্য বড় ডেটাসেটে নেটওয়ার্কটি প্রশিক্ষণ দিতে হবে। এটি করতে বেশ সময় লাগতে পারে, তাই GPU ব্যবহার করাই উত্তম।\n",
"\n",
"গতি বাড়ানোর জন্য, আমরা শুধুমাত্র নিউজ শিরোনামে RNN মডেলটি প্রশিক্ষণ দেব, বর্ণনা অংশটি বাদ দিয়ে। আপনি চাইলে বর্ণনা সহ প্রশিক্ষণ দিয়ে দেখতে পারেন যে মডেলটি প্রশিক্ষণ পেতে পারে কিনা।\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training vectorizer\n"
]
}
],
"source": [
"def extract_title(x):\n",
" return x['title']\n",
"\n",
"def tupelize_title(x):\n",
" return (extract_title(x),x['label'])\n",
"\n",
"print('Training vectorizer')\n",
"vectorizer.adapt(ds_train.take(2000).map(extract_title))"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"7500/7500 [==============================] - 82s 11ms/step - loss: 0.6629 - acc: 0.7623 - val_loss: 0.5559 - val_acc: 0.7995\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f3e0030d350>"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n",
"model.fit(ds_train.map(tupelize_title).batch(batch_size),validation_data=ds_test.map(tupelize_title).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {
"nteract": {
"transient": {
"deleting": false
}
}
},
"source": [
"> **নোট** যে এখানে সঠিকতা সম্ভবত কম হবে, কারণ আমরা শুধুমাত্র সংবাদ শিরোনামের উপর প্রশিক্ষণ দিচ্ছি।\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ভেরিয়েবল সিকোয়েন্স পুনর্বিবেচনা\n",
"\n",
"মনে রাখবেন যে `TextVectorization` লেয়ার একটি মিনিব্যাচে ভেরিয়েবল দৈর্ঘ্যের সিকোয়েন্সগুলোকে স্বয়ংক্রিয়ভাবে প্যাড টোকেন দিয়ে পূরণ করবে। দেখা গেছে, এই টোকেনগুলোও প্রশিক্ষণে অংশ নেয় এবং মডেলের কনভার্জেন্স জটিল করে তুলতে পারে।\n",
"\n",
"প্যাডিংয়ের পরিমাণ কমানোর জন্য আমরা কয়েকটি পদ্ধতি অবলম্বন করতে পারি। এর মধ্যে একটি হলো ডেটাসেটকে সিকোয়েন্সের দৈর্ঘ্য অনুযায়ী পুনর্বিন্যাস করা এবং সব সিকোয়েন্সকে তাদের আকার অনুযায়ী গ্রুপ করা। এটি `tf.data.experimental.bucket_by_sequence_length` ফাংশন ব্যবহার করে করা যেতে পারে (দেখুন [ডকুমেন্টেশন](https://www.tensorflow.org/api_docs/python/tf/data/experimental/bucket_by_sequence_length))।\n",
"\n",
"আরেকটি পদ্ধতি হলো **মাস্কিং** ব্যবহার করা। কেরাসে, কিছু লেয়ার অতিরিক্ত ইনপুট সমর্থন করে যা দেখায় কোন টোকেনগুলো প্রশিক্ষণের সময় বিবেচনায় নেওয়া উচিত। আমাদের মডেলে মাস্কিং অন্তর্ভুক্ত করতে, আমরা হয় একটি আলাদা `Masking` লেয়ার ([ডকস](https://keras.io/api/layers/core_layers/masking/)) যোগ করতে পারি, অথবা আমাদের `Embedding` লেয়ারের `mask_zero=True` প্যারামিটার নির্দিষ্ট করতে পারি।\n",
"\n",
"> **Note**: পুরো ডেটাসেটে একটি এপোক সম্পন্ন করতে এই প্রশিক্ষণে প্রায় ৫ মিনিট সময় লাগবে। ধৈর্য হারালে যে কোনো সময় প্রশিক্ষণ বন্ধ করতে পারেন। এছাড়াও, প্রশিক্ষণের জন্য ব্যবহৃত ডেটার পরিমাণ সীমিত করতে পারেন, `ds_train` এবং `ds_test` ডেটাসেটের পরে `.take(...)` ক্লজ যোগ করে।\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"7500/7500 [==============================] - 371s 49ms/step - loss: 0.5401 - acc: 0.8079 - val_loss: 0.3780 - val_acc: 0.8822\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f3dec118850>"
]
},
"execution_count": 7,
"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",
"model = keras.models.Sequential([\n",
" vectorizer,\n",
" keras.layers.Embedding(vocab_size,embed_size,mask_zero=True),\n",
" keras.layers.SimpleRNN(16),\n",
" keras.layers.Dense(4,activation='softmax')\n",
"])\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\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",
"> **Note**: আপনি কি লক্ষ্য করেছেন যে আমরা নিউজ শিরোনামের উপর প্রশিক্ষিত ভেক্টরাইজার ব্যবহার করছি, পুরো নিবন্ধের মূল অংশের উপর নয়? এটি সম্ভবত কিছু টোকেন উপেক্ষা করতে পারে, তাই ভেক্টরাইজারটি পুনরায় প্রশিক্ষণ দেওয়া ভালো। তবে, এর প্রভাব খুবই সামান্য হতে পারে, তাই সরলতার জন্য আমরা পূর্বে প্রশিক্ষিত ভেক্টরাইজারটিই ব্যবহার করব।\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## LSTM: দীর্ঘমেয়াদী স্মৃতি\n",
"\n",
"RNN-এর প্রধান সমস্যাগুলোর একটি হলো **vanishing gradients**। RNN অনেক দীর্ঘ হতে পারে এবং ব্যাকপ্রোপাগেশনের সময় নেটওয়ার্কের প্রথম স্তর পর্যন্ত গ্রেডিয়েন্টগুলো সঠিকভাবে পৌঁছাতে সমস্যা হতে পারে। যখন এটি ঘটে, তখন নেটওয়ার্ক দূরবর্তী টোকেনগুলোর মধ্যে সম্পর্ক শিখতে পারে না। এই সমস্যাটি এড়ানোর একটি উপায় হলো **স্পষ্ট স্টেট ম্যানেজমেন্ট** প্রবর্তন করা, যা **গেট** ব্যবহার করে করা হয়। গেট প্রবর্তনকারী সবচেয়ে সাধারণ দুটি আর্কিটেকচার হলো **দীর্ঘমেয়াদী স্মৃতি** (LSTM) এবং **গেটেড রিলে ইউনিট** (GRU)। এখানে আমরা LSTM নিয়ে আলোচনা করব।\n",
"\n",
"![দীর্ঘমেয়াদী স্মৃতি সেলের একটি উদাহরণ দেখানো চিত্র](../../../../../lessons/5-NLP/16-RNN/images/long-short-term-memory-cell.svg)\n",
"\n",
"একটি LSTM নেটওয়ার্ক RNN-এর মতোই সংগঠিত, তবে এখানে দুটি স্টেট স্তর থেকে স্তরে প্রেরণ করা হয়: প্রকৃত স্টেট $c$, এবং হিডেন ভেক্টর $h$। প্রতিটি ইউনিটে, হিডেন ভেক্টর $h_{t-1}$ ইনপুট $x_t$ এর সাথে মিলিত হয় এবং একসাথে তারা **গেট** এর মাধ্যমে স্টেট $c_t$ এবং আউটপুট $h_{t}$ এর উপর কী ঘটবে তা নিয়ন্ত্রণ করে। প্রতিটি গেটের সিগময়েড অ্যাক্টিভেশন থাকে (আউটপুট $[0,1]$ পরিসরে), যা স্টেট ভেক্টরের সাথে গুণ করলে বিটওয়াইজ মাস্ক হিসেবে ভাবা যেতে পারে। LSTM-এ নিম্নলিখিত গেটগুলো থাকে (উপরের ছবিতে বাম থেকে ডানে):\n",
"* **forget gate**, যা নির্ধারণ করে ভেক্টর $c_{t-1}$ এর কোন উপাদানগুলো আমরা ভুলে যাব এবং কোনগুলো প্রেরণ করব।\n",
"* **input gate**, যা নির্ধারণ করে ইনপুট ভেক্টর এবং পূর্ববর্তী হিডেন ভেক্টর থেকে কতটুকু তথ্য স্টেট ভেক্টরে অন্তর্ভুক্ত করা হবে।\n",
"* **output gate**, যা নতুন স্টেট ভেক্টর নিয়ে সিদ্ধান্ত নেয় এর কোন উপাদানগুলো নতুন হিডেন ভেক্টর $h_t$ উৎপাদনের জন্য ব্যবহার করা হবে।\n",
"\n",
"স্টেট $c$ এর উপাদানগুলোকে এমন ফ্ল্যাগ হিসেবে ভাবা যেতে পারে যা চালু এবং বন্ধ করা যায়। উদাহরণস্বরূপ, যখন আমরা সিকোয়েন্সে *Alice* নামটি পাই, আমরা অনুমান করি এটি একজন নারীর নাম এবং স্টেটে একটি ফ্ল্যাগ উত্থাপন করি যা বলে যে বাক্যে একটি নারীবাচক বিশেষ্য রয়েছে। যখন আমরা আরও *and Tom* শব্দগুলো পাই, তখন আমরা একটি ফ্ল্যাগ উত্থাপন করি যা বলে যে আমাদের কাছে একটি বহুবচন বিশেষ্য রয়েছে। এভাবে স্টেট ম্যানিপুলেট করে আমরা বাক্যের ব্যাকরণগত বৈশিষ্ট্যগুলো ট্র্যাক করতে পারি।\n",
"\n",
"> **Note**: LSTM-এর অভ্যন্তরীণ বিষয়গুলো বোঝার জন্য এটি একটি চমৎকার রিসোর্স: [Understanding LSTM Networks](https://colah.github.io/posts/2015-08-Understanding-LSTMs/) ক্রিস্টোফার ওলাহ দ্বারা।\n",
"\n",
"যদিও একটি LSTM সেলের অভ্যন্তরীণ গঠন জটিল মনে হতে পারে, Keras এই বাস্তবায়নটি `LSTM` লেয়ারের ভিতরে লুকিয়ে রাখে, তাই উপরের উদাহরণে আমাদের যা করতে হবে তা হলো পুনরাবৃত্ত স্তরটি প্রতিস্থাপন করা:\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"15000/15000 [==============================] - 188s 13ms/step - loss: 0.5692 - acc: 0.7916 - val_loss: 0.3441 - val_acc: 0.8870\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f3d6af5c350>"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" vectorizer,\n",
" keras.layers.Embedding(vocab_size, embed_size),\n",
" keras.layers.LSTM(8),\n",
" keras.layers.Dense(4,activation='softmax')\n",
"])\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n",
"model.fit(ds_train.map(tupelize).batch(8),validation_data=ds_test.map(tupelize).batch(8))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**বিঃদ্রঃ** LSTM প্রশিক্ষণ দেওয়া বেশ ধীরগতির, এবং প্রশিক্ষণের শুরুতে আপনি হয়তো সঠিকতার ক্ষেত্রে খুব বেশি উন্নতি দেখতে পাবেন না। ভালো সঠিকতা অর্জনের জন্য আপনাকে কিছু সময় ধরে প্রশিক্ষণ চালিয়ে যেতে হতে পারে।\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## দ্বিমুখী এবং বহুস্তর RNN\n",
"\n",
"আমাদের আগের উদাহরণগুলোতে, পুনরাবৃত্ত নেটওয়ার্কগুলো একটি সিকোয়েন্সের শুরু থেকে শেষ পর্যন্ত কাজ করে। এটি আমাদের কাছে স্বাভাবিক মনে হয় কারণ এটি সেই দিক অনুসরণ করে যেভাবে আমরা পড়ি বা কথা শুনি। তবে এমন পরিস্থিতিতে যেখানে ইনপুট সিকোয়েন্সের র‍্যান্ডম অ্যাক্সেস প্রয়োজন, সেখানে পুনরাবৃত্ত গণনা উভয় দিকেই চালানো আরও যুক্তিসঙ্গত। এমন RNN-গুলো, যেগুলো উভয় দিকেই গণনা করতে পারে, তাদের **দ্বিমুখী** RNN বলা হয়, এবং এগুলো তৈরি করা যায় পুনরাবৃত্ত স্তরকে একটি বিশেষ `Bidirectional` স্তর দিয়ে মোড়ানোর মাধ্যমে।\n",
"\n",
"> **Note**: `Bidirectional` স্তরটি তার মধ্যে থাকা স্তরের দুটি কপি তৈরি করে এবং সেই কপিগুলোর একটির `go_backwards` প্রপার্টিকে `True` সেট করে, যা সিকোয়েন্সের বিপরীত দিকে কাজ করে।\n",
"\n",
"পুনরাবৃত্ত নেটওয়ার্ক, একমুখী বা দ্বিমুখী, সিকোয়েন্সের মধ্যে প্যাটার্নগুলো ধরে এবং সেগুলোকে স্টেট ভেক্টরে সংরক্ষণ করে বা আউটপুট হিসেবে ফেরত দেয়। কনভোলিউশনাল নেটওয়ার্কের মতো, আমরা প্রথম স্তরের মাধ্যমে নিম্ন স্তরের প্যাটার্নগুলো থেকে উচ্চ স্তরের প্যাটার্ন ধরার জন্য আরেকটি পুনরাবৃত্ত স্তর তৈরি করতে পারি। এটি আমাদের **বহুস্তর RNN** ধারণার দিকে নিয়ে যায়, যা দুটি বা তার বেশি পুনরাবৃত্ত নেটওয়ার্ক নিয়ে গঠিত, যেখানে আগের স্তরের আউটপুট পরবর্তী স্তরের ইনপুট হিসেবে ব্যবহৃত হয়।\n",
"\n",
"![একটি বহুস্তর দীর্ঘ-মেয়াদী-মেমরি RNN-এর ছবি](../../../../../translated_images/bn/multi-layer-lstm.dd975e29bb2a59fe.webp)\n",
"\n",
"*ছবি [এই চমৎকার পোস্ট](https://towardsdatascience.com/from-a-lstm-cell-to-a-multilayer-lstm-network-with-pytorch-2899eb5696f3) থেকে, লেখক Fernando López।*\n",
"\n",
"Keras এই নেটওয়ার্কগুলো তৈরি করাকে সহজ করে তোলে, কারণ আপনাকে শুধু মডেলে আরও পুনরাবৃত্ত স্তর যোগ করতে হবে। শেষ স্তর ছাড়া অন্য সব স্তরের জন্য, আমাদের `return_sequences=True` প্যারামিটার নির্দিষ্ট করতে হবে, কারণ আমাদের স্তর থেকে সমস্ত মধ্যবর্তী স্টেট ফেরত দরকার, শুধুমাত্র পুনরাবৃত্ত গণনার চূড়ান্ত স্টেট নয়।\n",
"\n",
"চলুন আমাদের শ্রেণীবিন্যাস সমস্যার জন্য একটি দুই-স্তর বিশিষ্ট দ্বিমুখী LSTM তৈরি করি।\n",
"\n",
"> **Note** এই কোডটি সম্পন্ন হতে আবারও বেশ সময় নেয়, তবে এটি আমাদের এখন পর্যন্ত দেখা সর্বোচ্চ সঠিকতা প্রদান করে। তাই হয়তো অপেক্ষা করা এবং ফলাফল দেখা মূল্যবান।\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"5044/7500 [===================>..........] - ETA: 2:33 - loss: 0.3709 - acc: 0.8706\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r5045/7500 [===================>..........] - ETA: 2:33 - loss: 0.3709 - acc: 0.8706"
]
}
],
"source": [
"model = keras.models.Sequential([\n",
" vectorizer,\n",
" keras.layers.Embedding(vocab_size, 128, mask_zero=True),\n",
" keras.layers.Bidirectional(keras.layers.LSTM(64,return_sequences=True)),\n",
" keras.layers.Bidirectional(keras.layers.LSTM(64)), \n",
" keras.layers.Dense(4,activation='softmax')\n",
"])\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),\n",
" validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## অন্যান্য কাজের জন্য RNNs\n",
"\n",
"এখন পর্যন্ত, আমরা RNNs ব্যবহার করে টেক্সট সিকোয়েন্স শ্রেণীবদ্ধ করার উপর জোর দিয়েছি। তবে এগুলো আরও অনেক কাজ পরিচালনা করতে পারে, যেমন টেক্সট জেনারেশন এবং মেশিন অনুবাদ — আমরা পরবর্তী ইউনিটে এই কাজগুলো নিয়ে আলোচনা করব।\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**অস্বীকৃতি**: \nএই নথিটি AI অনুবাদ পরিষেবা [Co-op Translator](https://github.com/Azure/co-op-translator) ব্যবহার করে অনুবাদ করা হয়েছে। আমরা যথাসম্ভব সঠিকতার জন্য চেষ্টা করি, তবে অনুগ্রহ করে মনে রাখবেন যে স্বয়ংক্রিয় অনুবাদে ত্রুটি বা অসঙ্গতি থাকতে পারে। মূল ভাষায় থাকা নথিটিকে প্রামাণিক উৎস হিসেবে বিবেচনা করা উচিত। গুরুত্বপূর্ণ তথ্যের জন্য, পেশাদার মানব অনুবাদ সুপারিশ করা হয়। এই অনুবাদ ব্যবহারের ফলে কোনো ভুল বোঝাবুঝি বা ভুল ব্যাখ্যা হলে আমরা দায়বদ্ধ থাকব না।\n"
]
}
],
"metadata": {
"kernel_info": {
"name": "conda-env-py37_tensorflow-py"
},
"kernelspec": {
"display_name": "py37_tensorflow",
"language": "python",
"name": "conda-env-py37_tensorflow-py"
},
"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.7.9"
},
"nteract": {
"version": "nteract-front-end@1.0.0"
},
"coopTranslator": {
"original_hash": "81351e61f619b432ff51010a4f993194",
"translation_date": "2025-08-28T12:17:33+00:00",
"source_file": "lessons/5-NLP/16-RNN/RNNTF.ipynb",
"language_code": "bn"
}
},
"nbformat": 4,
"nbformat_minor": 4
}