AI-For-Beginners/translations/bn/lessons/5-NLP/17-GenerativeNetworks/GenerativeTF.ipynb

497 lines
42 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. 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",
"Recurrent Neural Networks (RNNs) এবং তাদের গেটেড সেল ভ্যারিয়েন্ট যেমন Long Short Term Memory Cells (LSTMs) এবং Gated Recurrent Units (GRUs) ভাষা মডেলিংয়ের জন্য একটি পদ্ধতি প্রদান করে, অর্থাৎ তারা শব্দের ক্রম শিখতে পারে এবং একটি ক্রমে পরবর্তী শব্দের পূর্বাভাস দিতে পারে। এটি আমাদের RNNs ব্যবহার করে **জেনারেটিভ কাজ** সম্পাদন করতে দেয়, যেমন সাধারণ টেক্সট জেনারেশন, মেশিন ট্রান্সলেশন, এবং এমনকি ইমেজ ক্যাপশনিং।\n",
"\n",
"পূর্ববর্তী ইউনিটে আমরা যে RNN আর্কিটেকচার আলোচনা করেছি, সেখানে প্রতিটি RNN ইউনিট পরবর্তী হিডেন স্টেটকে আউটপুট হিসেবে তৈরি করত। তবে, আমরা প্রতিটি রিকারেন্ট ইউনিটে আরেকটি আউটপুট যোগ করতে পারি, যা আমাদের একটি **সিকোয়েন্স** আউটপুট করতে সাহায্য করবে (যা মূল সিকোয়েন্সের দৈর্ঘ্যের সমান)। এছাড়াও, আমরা এমন RNN ইউনিট ব্যবহার করতে পারি যা প্রতিটি ধাপে ইনপুট গ্রহণ করে না, বরং শুধুমাত্র একটি প্রাথমিক স্টেট ভেক্টর গ্রহণ করে এবং তারপর আউটপুটের একটি সিকোয়েন্স তৈরি করে।\n",
"\n",
"এই নোটবুকে, আমরা সহজ জেনারেটিভ মডেলের উপর ফোকাস করব যা আমাদের টেক্সট জেনারেট করতে সাহায্য করে। সরলতার জন্য, আসুন **ক্যারেক্টার-লেভেল নেটওয়ার্ক** তৈরি করি, যা অক্ষর ধরে ধরে টেক্সট জেনারেট করে। প্রশিক্ষণের সময়, আমাদের কিছু টেক্সট কর্পাস নিতে হবে এবং এটিকে অক্ষরের সিকোয়েন্সে ভাগ করতে হবে।\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",
"import numpy as np\n",
"\n",
"ds_train, ds_test = tfds.load('ag_news_subset').values()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## চরিত্র ভোকাবুলারি তৈরি করা\n",
"\n",
"চরিত্র-স্তরের জেনারেটিভ নেটওয়ার্ক তৈরি করতে, আমাদের টেক্সটকে শব্দের পরিবর্তে পৃথক চরিত্রে বিভক্ত করতে হবে। `TextVectorization` লেয়ার, যা আমরা আগে ব্যবহার করেছি, এটি করতে পারে না, তাই আমাদের দুটি বিকল্প রয়েছে:\n",
"\n",
"* ম্যানুয়ালি টেক্সট লোড করে এবং 'হাতে' টোকেনাইজেশন করা, যেমন [এই অফিসিয়াল কেরাস উদাহরণে](https://keras.io/examples/generative/lstm_character_level_text_generation/) দেখানো হয়েছে\n",
"* চরিত্র-স্তরের টোকেনাইজেশনের জন্য `Tokenizer` ক্লাস ব্যবহার করা।\n",
"\n",
"আমরা দ্বিতীয় বিকল্পটি বেছে নেব। `Tokenizer` শব্দে টোকেনাইজ করার জন্যও ব্যবহার করা যেতে পারে, তাই চরিত্র-স্তর থেকে শব্দ-স্তরের টোকেনাইজেশনে সহজেই স্যুইচ করা সম্ভব।\n",
"\n",
"চরিত্র-স্তরের টোকেনাইজেশন করতে, আমাদের `char_level=True` প্যারামিটার পাস করতে হবে:\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"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",
"tokenizer = keras.preprocessing.text.Tokenizer(char_level=True,lower=False)\n",
"tokenizer.fit_on_texts([x['title'].numpy().decode('utf-8') for x in ds_train])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"আমরা একটি বিশেষ টোকেন ব্যবহার করতে চাই যা **সিকোয়েন্সের শেষ** নির্দেশ করবে, যাকে আমরা `<eos>` বলব। চলুন এটি ম্যানুয়ালি ভোকাবুলারিতে যোগ করি:\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"eos_token = len(tokenizer.word_index)+1\n",
"tokenizer.word_index['<eos>'] = eos_token\n",
"\n",
"vocab_size = eos_token + 1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"এখন, পাঠ্যকে সংখ্যার ক্রমে এনকোড করতে, আমরা ব্যবহার করতে পারি:\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[[48, 2, 10, 10, 5, 44, 1, 25, 5, 8, 10, 13, 78]]"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tokenizer.texts_to_sequences(['Hello, world!'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## শিরোনাম তৈরি করার জন্য একটি জেনারেটিভ RNN প্রশিক্ষণ\n",
"\n",
"আমরা যেভাবে RNN প্রশিক্ষণ করব যাতে এটি সংবাদ শিরোনাম তৈরি করতে পারে তা হলো নিম্নরূপ। প্রতিটি ধাপে, আমরা একটি শিরোনাম নেব, যা RNN-এ প্রবেশ করানো হবে, এবং প্রতিটি ইনপুট অক্ষরের জন্য আমরা নেটওয়ার্ককে পরবর্তী আউটপুট অক্ষর তৈরি করতে বলব:\n",
"\n",
"![চিত্রটি 'HELLO' শব্দটি তৈরি করার একটি উদাহরণ RNN দেখাচ্ছে।](../../../../../translated_images/bn/rnn-generate.56c54afb52f9781d.webp)\n",
"\n",
"আমাদের ক্রমের শেষ অক্ষরের জন্য, আমরা নেটওয়ার্ককে `<eos>` টোকেন তৈরি করতে বলব।\n",
"\n",
"আমরা এখানে যে জেনারেটিভ RNN ব্যবহার করছি তার প্রধান পার্থক্য হলো আমরা RNN-এর প্রতিটি ধাপ থেকে আউটপুট নেব, শুধুমাত্র চূড়ান্ত সেল থেকে নয়। এটি `return_sequences` প্যারামিটার RNN সেলে নির্দিষ্ট করে অর্জন করা যেতে পারে।\n",
"\n",
"তাই, প্রশিক্ষণের সময়, নেটওয়ার্কে ইনপুট হবে নির্দিষ্ট দৈর্ঘ্যের এনকোড করা অক্ষরের একটি ক্রম, এবং আউটপুট হবে একই দৈর্ঘ্যের একটি ক্রম, তবে এক উপাদান দ্বারা স্থানান্তরিত এবং `<eos>` দিয়ে শেষ। মিনিব্যাচে এমন কয়েকটি ক্রম থাকবে, এবং আমাদের **প্যাডিং** ব্যবহার করতে হবে যাতে সব ক্রম একসঙ্গে সামঞ্জস্যপূর্ণ হয়।\n",
"\n",
"চলুন এমন ফাংশন তৈরি করি যা আমাদের জন্য ডেটাসেট রূপান্তর করবে। কারণ আমরা মিনিব্যাচ স্তরে ক্রম প্যাড করতে চাই, আমরা প্রথমে `.batch()` কল করে ডেটাসেট ব্যাচ করব, এবং তারপর `map` ব্যবহার করে এটি রূপান্তর করব। সুতরাং, রূপান্তর ফাংশন একটি সম্পূর্ণ মিনিব্যাচকে প্যারামিটার হিসেবে নেবে:\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"def title_batch(x):\n",
" x = [t.numpy().decode('utf-8') for t in x]\n",
" z = tokenizer.texts_to_sequences(x)\n",
" z = tf.keras.preprocessing.sequence.pad_sequences(z)\n",
" return tf.one_hot(z,vocab_size), tf.one_hot(tf.concat([z[:,1:],tf.constant(eos_token,shape=(len(z),1))],axis=1),vocab_size)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"কিছু গুরুত্বপূর্ণ বিষয় যা আমরা এখানে করি:\n",
"* প্রথমে আমরা স্ট্রিং টেনসর থেকে প্রকৃত টেক্সট বের করি\n",
"* `text_to_sequences` স্ট্রিংগুলোর তালিকাকে পূর্ণসংখ্যার টেনসরের তালিকায় রূপান্তর করে\n",
"* `pad_sequences` সেই টেনসরগুলোকে তাদের সর্বোচ্চ দৈর্ঘ্যে প্যাড করে\n",
"* শেষে আমরা সমস্ত অক্ষরকে ওয়ান-হট এনকোড করি, এবং শিফটিং ও `<eos>` যোগ করার কাজও করি। কেন আমাদের ওয়ান-হট-এনকোডেড অক্ষর প্রয়োজন, তা আমরা শীঘ্রই দেখব\n",
"\n",
"তবে, এই ফাংশনটি **Pythonic**, অর্থাৎ এটি স্বয়ংক্রিয়ভাবে Tensorflow এর গণনামূলক গ্রাফে রূপান্তরিত হতে পারে না। যদি আমরা সরাসরি এই ফাংশনটি `Dataset.map` ফাংশনে ব্যবহার করার চেষ্টা করি, তাহলে ত্রুটি পাব। আমাদের এই Pythonic কলটিকে `py_function` র‍্যাপার ব্যবহার করে আবদ্ধ করতে হবে:\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"def title_batch_fn(x):\n",
" x = x['title']\n",
" a,b = tf.py_function(title_batch,inp=[x],Tout=(tf.float32,tf.float32))\n",
" return a,b"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Note**: পাইথনিক এবং টেনসরফ্লো ট্রান্সফরমেশন ফাংশনের মধ্যে পার্থক্য করা কিছুটা জটিল মনে হতে পারে, এবং আপনি হয়তো ভাবছেন কেন আমরা ডেটাসেটকে `fit`-এ পাঠানোর আগে স্ট্যান্ডার্ড পাইথন ফাংশন ব্যবহার করে ট্রান্সফর্ম করি না। যদিও এটি অবশ্যই করা সম্ভব, `Dataset.map` ব্যবহার করার একটি বড় সুবিধা রয়েছে, কারণ ডেটা ট্রান্সফরমেশন পাইপলাইন টেনসরফ্লো কম্পিউটেশনাল গ্রাফ ব্যবহার করে সম্পাদিত হয়, যা GPU কম্পিউটেশনের সুবিধা নেয় এবং CPU/GPU এর মধ্যে ডেটা পাস করার প্রয়োজনীয়তা কমিয়ে আনে।\n",
"\n",
"এখন আমরা আমাদের জেনারেটর নেটওয়ার্ক তৈরি করতে পারি এবং প্রশিক্ষণ শুরু করতে পারি। এটি পূর্ববর্তী ইউনিটে আলোচনা করা যেকোনো রিকারেন্ট সেল (সিম্পল, LSTM বা GRU) এর উপর ভিত্তি করে হতে পারে। আমাদের উদাহরণে আমরা LSTM ব্যবহার করব।\n",
"\n",
"যেহেতু নেটওয়ার্কটি ইনপুট হিসেবে অক্ষর গ্রহণ করে এবং ভোকাবুলারি সাইজ বেশ ছোট, তাই আমাদের এম্বেডিং লেয়ারের প্রয়োজন নেই; ওয়ান-হট-এনকোডেড ইনপুট সরাসরি LSTM সেলে যেতে পারে। আউটপুট লেয়ারটি একটি `Dense` ক্লাসিফায়ার হবে যা LSTM আউটপুটকে ওয়ান-হট-এনকোডেড টোকেন নম্বরে রূপান্তর করবে।\n",
"\n",
"এর পাশাপাশি, যেহেতু আমরা ভ্যারিয়েবল-লেংথ সিকোয়েন্স নিয়ে কাজ করছি, আমরা `Masking` লেয়ার ব্যবহার করতে পারি একটি মাস্ক তৈরি করার জন্য যা স্ট্রিংয়ের প্যাডেড অংশকে উপেক্ষা করবে। এটি কঠোরভাবে প্রয়োজনীয় নয়, কারণ `<eos>` টোকেনের বাইরে যা কিছু আছে তাতে আমরা খুব বেশি আগ্রহী নই, তবে আমরা এই লেয়ার টাইপের সাথে কিছু অভিজ্ঞতা অর্জনের জন্য এটি ব্যবহার করব। `input_shape` হবে `(None, vocab_size)`, যেখানে `None` ভ্যারিয়েবল লেংথ সিকোয়েন্স নির্দেশ করে, এবং আউটপুট শেপও `(None, vocab_size)` হবে, যেমনটি আপনি `summary` থেকে দেখতে পারেন।\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential\"\n",
"_________________________________________________________________\n",
"Layer (type) Output Shape Param # \n",
"=================================================================\n",
"masking (Masking) (None, None, 84) 0 \n",
"_________________________________________________________________\n",
"lstm (LSTM) (None, None, 128) 109056 \n",
"_________________________________________________________________\n",
"dense (Dense) (None, None, 84) 10836 \n",
"=================================================================\n",
"Total params: 119,892\n",
"Trainable params: 119,892\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n",
"15000/15000 [==============================] - 229s 15ms/step - loss: 1.5385\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7fa40c1245e0>"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.Masking(input_shape=(None,vocab_size)),\n",
" keras.layers.LSTM(128,return_sequences=True),\n",
" keras.layers.Dense(vocab_size,activation='softmax')\n",
"])\n",
"\n",
"model.summary()\n",
"model.compile(loss='categorical_crossentropy')\n",
"\n",
"model.fit(ds_train.batch(8).map(title_batch_fn))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## আউটপুট তৈরি করা\n",
"\n",
"এখন আমরা মডেলটি প্রশিক্ষণ দিয়েছি, আমরা এটি ব্যবহার করে কিছু আউটপুট তৈরি করতে চাই। প্রথমেই, আমাদের একটি পদ্ধতি দরকার যা টোকেন নম্বরের সিকোয়েন্স দ্বারা উপস্থাপিত টেক্সট ডিকোড করতে পারে। এটি করার জন্য, আমরা `tokenizer.sequences_to_texts` ফাংশন ব্যবহার করতে পারি; তবে, এটি চরিত্র-স্তরের টোকেনাইজেশনের ক্ষেত্রে ভালো কাজ করে না। তাই আমরা টোকেনাইজারের একটি টোকেনের ডিকশনারি (যাকে `word_index` বলা হয়) নেব, একটি রিভার্স ম্যাপ তৈরি করব এবং আমাদের নিজস্ব ডিকোডিং ফাংশন লিখব:\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"reverse_map = {val:key for key, val in tokenizer.word_index.items()}\n",
"\n",
"def decode(x):\n",
" return ''.join([reverse_map[t] for t in x])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"এখন, চলুন জেনারেশন শুরু করি। আমরা প্রথমে কিছু স্ট্রিং `start` দিয়ে শুরু করব, এটিকে একটি সিকোয়েন্স `inp`-এ এনকোড করব, এবং তারপর প্রতিটি ধাপে আমাদের নেটওয়ার্ককে কল করব পরবর্তী অক্ষর নির্ধারণের জন্য।\n",
"\n",
"নেটওয়ার্কের আউটপুট `out` একটি ভেক্টর, যেখানে `vocab_size` সংখ্যক উপাদান থাকে, যা প্রতিটি টোকেনের সম্ভাব্যতা উপস্থাপন করে। আমরা `argmax` ব্যবহার করে সবচেয়ে সম্ভাব্য টোকেন নম্বর খুঁজে বের করতে পারি। এরপর আমরা এই অক্ষরটি জেনারেট করা টোকেনগুলোর তালিকায় যোগ করি এবং জেনারেশনের প্রক্রিয়া চালিয়ে যাই। এই প্রক্রিয়াটি একবারে একটি অক্ষর জেনারেট করার জন্য `size` বার পুনরাবৃত্তি করা হয়, যতক্ষণ না প্রয়োজনীয় সংখ্যক অক্ষর তৈরি হয়। আমরা প্রক্রিয়াটি আগেই বন্ধ করি যদি `eos_token` পাওয়া যায়।\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Today #39;s lead to strike for the strike for the strike for the strike (AFP)'"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def generate(model,size=100,start='Today '):\n",
" inp = tokenizer.texts_to_sequences([start])[0]\n",
" chars = inp\n",
" for i in range(size):\n",
" out = model(tf.expand_dims(tf.one_hot(inp,vocab_size),0))[0][-1]\n",
" nc = tf.argmax(out)\n",
" if nc==eos_token:\n",
" break\n",
" chars.append(nc.numpy())\n",
" inp = inp+[nc]\n",
" return decode(chars)\n",
" \n",
"generate(model)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## প্রশিক্ষণের সময় আউটপুট নমুনা করা\n",
"\n",
"যেহেতু আমাদের কাছে *সঠিকতা* (accuracy) এর মতো কোনো কার্যকর মেট্রিক নেই, তাই আমাদের মডেল উন্নতি করছে কিনা তা দেখার একমাত্র উপায় হল প্রশিক্ষণের সময় তৈরি করা স্ট্রিং-এর **নমুনা** নেওয়া। এটি করার জন্য, আমরা **কলব্যাকস** ব্যবহার করব, অর্থাৎ এমন ফাংশন যা আমরা `fit` ফাংশনে পাস করতে পারি এবং যা প্রশিক্ষণের সময় নির্দিষ্ট বিরতিতে ডাকা হবে।\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1/3\n",
"15000/15000 [==============================] - 226s 15ms/step - loss: 1.2703\n",
"Today #39;s a lead in the company for the strike\n",
"Epoch 2/3\n",
"15000/15000 [==============================] - 227s 15ms/step - loss: 1.2057\n",
"Today #39;s the Market Service on Security Start (AP)\n",
"Epoch 3/3\n",
"15000/15000 [==============================] - 226s 15ms/step - loss: 1.1752\n",
"Today #39;s a line on the strike to start for the start\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7fa40c74e3d0>"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sampling_callback = keras.callbacks.LambdaCallback(\n",
" on_epoch_end = lambda batch, logs: print(generate(model))\n",
")\n",
"\n",
"model.fit(ds_train.batch(8).map(title_batch_fn),callbacks=[sampling_callback],epochs=3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"এই উদাহরণটি ইতিমধ্যেই বেশ ভালো টেক্সট তৈরি করে, তবে এটি আরও কিছু উপায়ে উন্নত করা যেতে পারে:\n",
"\n",
"* **আরও টেক্সট**। আমরা আমাদের কাজের জন্য শুধুমাত্র শিরোনাম ব্যবহার করেছি, তবে আপনি পুরো টেক্সট নিয়ে পরীক্ষা করতে পারেন। মনে রাখবেন, RNN দীর্ঘ সিকোয়েন্স পরিচালনায় খুব ভালো নয়, তাই সেগুলোকে ছোট বাক্যে ভাগ করা বা একটি নির্ধারিত মান `num_chars` (যেমন, ২৫৬) অনুযায়ী নির্দিষ্ট সিকোয়েন্স দৈর্ঘ্যে প্রশিক্ষণ দেওয়া বুদ্ধিমানের কাজ। উপরের উদাহরণটি এমন আর্কিটেকচারে পরিবর্তন করার চেষ্টা করতে পারেন, যেখানে [অফিশিয়াল Keras টিউটোরিয়াল](https://keras.io/examples/generative/lstm_character_level_text_generation/) থেকে অনুপ্রেরণা নেওয়া যেতে পারে।\n",
"\n",
"* **মাল্টিলেয়ার LSTM**। ২ বা ৩ স্তরের LSTM সেল ব্যবহার করার চেষ্টা করা যৌক্তিক। আমরা আগের ইউনিটে উল্লেখ করেছি, LSTM-এর প্রতিটি স্তর টেক্সট থেকে নির্দিষ্ট প্যাটার্ন বের করে, এবং চরিত্র-স্তরের জেনারেটরের ক্ষেত্রে আমরা আশা করতে পারি যে নিম্ন স্তরের LSTM সিলেবল বের করতে দায়ী হবে, এবং উচ্চ স্তরগুলো শব্দ এবং শব্দের সংমিশ্রণ বের করবে। এটি সহজেই LSTM কনস্ট্রাক্টরে লেয়ারের সংখ্যা প্যারামিটার পাস করে বাস্তবায়ন করা যেতে পারে।\n",
"\n",
"* আপনি **GRU ইউনিট** নিয়ে পরীক্ষা করতে পারেন এবং দেখতে পারেন কোনটি ভালো কাজ করে, এবং **বিভিন্ন হিডেন লেয়ারের আকার** নিয়ে পরীক্ষা করতে পারেন। খুব বড় হিডেন লেয়ার ওভারফিটিং ঘটাতে পারে (যেমন, নেটওয়ার্ক সঠিক টেক্সট শিখে নেবে), এবং ছোট আকার ভালো ফলাফল নাও দিতে পারে।\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## নরম টেক্সট জেনারেশন এবং টেম্পারেচার\n",
"\n",
"`generate` এর পূর্ববর্তী সংজ্ঞায়, আমরা সর্বদা সর্বোচ্চ সম্ভাবনাযুক্ত চরিত্রটিকে পরবর্তী চরিত্র হিসেবে গ্রহণ করতাম। এর ফলে প্রায়ই টেক্সট একই চরিত্রের ক্রম বারবার পুনরাবৃত্তি করত, যেমন এই উদাহরণে:\n",
"```\n",
"today of the second the company and a second the company ...\n",
"```\n",
"\n",
"তবে, যদি আমরা পরবর্তী চরিত্রের জন্য সম্ভাবনা বণ্টন দেখি, তাহলে দেখা যায় যে কয়েকটি সর্বোচ্চ সম্ভাবনার মধ্যে পার্থক্য খুব বেশি নয়, যেমন একটি চরিত্রের সম্ভাবনা হতে পারে .২, আরেকটির .১৯, ইত্যাদি। উদাহরণস্বরূপ, যদি আমরা '*play*' ক্রমের পরবর্তী চরিত্র খুঁজছি, তাহলে পরবর্তী চরিত্রটি সমানভাবে স্পেস বা **e** (যেমন শব্দ *player* এ) হতে পারে।\n",
"\n",
"এটি আমাদের এই সিদ্ধান্তে পৌঁছায় যে সর্বোচ্চ সম্ভাবনাযুক্ত চরিত্র নির্বাচন করাই সবসময় \"ন্যায্য\" নয়, কারণ দ্বিতীয় সর্বোচ্চটি নির্বাচন করলেও অর্থবহ টেক্সট পাওয়া যেতে পারে। এটি আরও বুদ্ধিমানের কাজ হবে যদি আমরা নেটওয়ার্ক আউটপুট দ্বারা প্রদত্ত সম্ভাবনা বণ্টন থেকে চরিত্রগুলি **নমুনা** করি।\n",
"\n",
"এই নমুনা প্রক্রিয়া `np.multinomial` ফাংশন ব্যবহার করে করা যেতে পারে, যা তথাকথিত **মাল্টিনোমিয়াল বণ্টন** বাস্তবায়ন করে। একটি ফাংশন যা এই **নরম** টেক্সট জেনারেশন বাস্তবায়ন করে তা নিচে সংজ্ঞায়িত করা হয়েছে:\n"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"--- Temperature = 0.3\n",
"Today #39;s strike #39; to start at the store return\n",
"On Sunday PO to Be Data Profit Up (Reuters)\n",
"Moscow, SP wins straight to the Microsoft #39;s control of the space start\n",
"President olding of the blast start for the strike to pay &lt;b&gt;...&lt;/b&gt;\n",
"Little red riding hood ficed to the spam countered in European &lt;b&gt;...&lt;/b&gt;\n",
"\n",
"--- Temperature = 0.8\n",
"Today countie strikes ryder missile faces food market blut\n",
"On Sunday collores lose-toppy of sale of Bullment in &lt;b&gt;...&lt;/b&gt;\n",
"Moscow, IBM Diffeiting in Afghan Software Hotels (Reuters)\n",
"President Ol Luster for Profit Peaced Raised (AP)\n",
"Little red riding hood dace on depart talks #39; bank up\n",
"\n",
"--- Temperature = 1.0\n",
"Today wits House buiting debate fixes #39; supervice stake again\n",
"On Sunday arling digital poaching In for level\n",
"Moscow, DS Up 7, Top Proble Protest Caprey Mamarian Strike\n",
"President teps help of roubler stepted lessabul-Dhalitics (AFP)\n",
"Little red riding hood signs on cash in Carter-youb\n",
"\n",
"--- Temperature = 1.3\n",
"Today wits flawer ro, pSIA figat's co DroftwavesIs Talo up\n",
"On Sunday hround elitwing wint EU Powerburlinetien\n",
"Moscow, Bazz #39;s sentries olymen winnelds' next for Olympite Huc?\n",
"President lost securitys from power Elections in Smiltrials\n",
"Little red riding hood vides profit, exponituity, profitmainalist-at said listers\n",
"\n",
"--- Temperature = 1.8\n",
"Today #39;It: He deat: N.KA Asside\n",
"On Sunday i arry Par aldeup patient Wo stele1\n"
]
},
{
"ename": "KeyError",
"evalue": "0",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-33-db32367a0feb>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"\\n--- Temperature = {i}\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mj\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgenerate_soft\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmodel\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0msize\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m300\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mstart\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mwords\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mtemperature\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-33-db32367a0feb>\u001b[0m in \u001b[0;36mgenerate_soft\u001b[0;34m(model, size, start, temperature)\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0mchars\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0minp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minp\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mnc\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 13\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mchars\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 14\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0mwords\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m'Today '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'On Sunday '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'Moscow, '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'President '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'Little red riding hood '\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m<ipython-input-10-3f5fa6130b1d>\u001b[0m in \u001b[0;36mdecode\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mreverse_map\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-10-3f5fa6130b1d>\u001b[0m in \u001b[0;36m<listcomp>\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mreverse_map\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mKeyError\u001b[0m: 0"
]
}
],
"source": [
"def generate_soft(model,size=100,start='Today ',temperature=1.0):\n",
" inp = tokenizer.texts_to_sequences([start])[0]\n",
" chars = inp\n",
" for i in range(size):\n",
" out = model(tf.expand_dims(tf.one_hot(inp,vocab_size),0))[0][-1]\n",
" probs = tf.exp(tf.math.log(out)/temperature).numpy().astype(np.float64)\n",
" probs = probs/np.sum(probs)\n",
" nc = np.argmax(np.random.multinomial(1,probs,1))\n",
" if nc==eos_token:\n",
" break\n",
" chars.append(nc)\n",
" inp = inp+[nc]\n",
" return decode(chars)\n",
"\n",
"words = ['Today ','On Sunday ','Moscow, ','President ','Little red riding hood ']\n",
" \n",
"for i in [0.3,0.8,1.0,1.3,1.8]:\n",
" print(f\"\\n--- Temperature = {i}\")\n",
" for j in range(5):\n",
" print(generate_soft(model,size=300,start=words[j],temperature=i))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"আমরা **temperature** নামে একটি অতিরিক্ত প্যারামিটার পরিচয় করিয়েছি, যা নির্দেশ করে যে সর্বোচ্চ সম্ভাবনার প্রতি আমরা কতটা কঠোরভাবে অনুসরণ করব। যদি temperature 1.0 হয়, আমরা ন্যায্য মাল্টিনোমিয়াল স্যাম্পলিং করি, এবং যখন temperature অসীমে পৌঁছায় - সমস্ত সম্ভাবনা সমান হয়ে যায়, এবং আমরা পরবর্তী অক্ষরটি এলোমেলোভাবে নির্বাচন করি। নিচের উদাহরণে আমরা দেখতে পারি যে temperature খুব বেশি বাড়ালে টেক্সট অর্থহীন হয়ে যায়, এবং এটি \"cycled\" কঠোরভাবে তৈরি টেক্সটের মতো হয়ে যায় যখন এটি 0-এর কাছাকাছি পৌঁছায়।\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": "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"
},
"coopTranslator": {
"original_hash": "9fbb7d5fda708537649f71f5f646fcde",
"translation_date": "2025-08-28T11:59:08+00:00",
"source_file": "lessons/5-NLP/17-GenerativeNetworks/GenerativeTF.ipynb",
"language_code": "bn"
}
},
"nbformat": 4,
"nbformat_minor": 4
}