Chapter 9 of 18
From raw API to high-level layers — and knowing the difference
আমরা এর আগের NumPy চ্যাপ্টারে মৌলিক ধারণা থেকে স্ক্র্যাচ থেকে একটি LSTM মডেল তৈরি করেছিলাম যাতে আপনি সেলের ভেতরের হিসাব-নিকাশ নিখুঁতভাবে বুঝতে পারেন। কিন্তু বাস্তবে প্রোডাকশন মডেল তৈরি বা ট্রেইন করার সময় কেউ NumPy দিয়ে হাত লিখে ব্যাকপ্রোপাগেশন করে না। এর বদলে আমরা TensorFlow/Keras-এর মতো আধুনিক ফ্রেমওয়ার্ক ব্যবহার করি, যা আমাদের একটি অত্যন্ত পরীক্ষিত এবং জিপিইউ-ত্বরিত (GPU-accelerated) LSTM লেয়ার প্রদান করে এবং নিজে নিজেই অটোমেটিক্যালি গ্রেডিয়েন্ট হিসাব করে। এই চ্যাপ্টারে আমরা দেখবো কীভাবে সেই লেয়ারটি সঠিকভাবে ব্যবহার করতে হয় — এবং কীভাবে পরীক্ষা করে নিশ্চিত হওয়া যায় যে Keras আসলে আমাদের খাতা-কলমে শেখা সমীকরণগুলোই ব্যাকগ্রাউন্ডে রান করছে।
Keras-এর সবচেয়ে সহজ মডেল তৈরির মাধ্যম হলো Sequential API: এটি মূলত একটার ওপর আরেকটা সাজানো লেয়ারের একটি সোজা স্ট্যাক, যেখানে এক লেয়ারের আউটপুট সরাসরি পরের লেয়ারের ইনপুট হিসেবে প্রবেশ করে।
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
tf.random.set_seed(0)
model = keras.Sequential([
layers.Input(shape=(10, 50)), # (timesteps, features); ব্যাচ ডাইমেনশনটি এখানে উহ্য থাকে
layers.LSTM(100),
])
model.summary()
# Mathematics চ্যাপ্টারের প্যারামিটার সংখ্যা হিসাবের সূত্রের সাথে মিলিয়ে দেখুন
n_x, n_h = 50, 100
formula = 4 * n_h * (n_x + n_h + 1)
print("Formula predicts:", formula) # predictions: 60400, যা model.summary()-এর সাথে মিলবেএখানে model.summary() রান করলে আউটপুটে দেখতে পাবেন ৬০,৪০০ টি প্যারামিটার — যা আমাদের সূত্রের হিসাব -এর একদম সমান। এটি কোনো কাকতালীয় বিষয় নয়; এটি সরাসরি প্রমাণ করে যে Keras-এর LSTM আমরা নিজে হাতে করা সমীকরণগুলোর ওপর ভিত্তি করেই তৈরি।
units (প্রথম পজিশনাল আর্গুমেন্ট) — হিডেন/সেল স্টেটের ডাইমেনশন ।return_sequences (ডিফল্ট মান False) — এটি True সেট করলে প্রতিটি টাইম স্টেপের আউটপুট পাওয়া যায়; আর False থাকলে কেবল শেষ টাইম স্টেপের আউটপুট পাওয়া যায়। একের পর এক LSTM লেয়ার স্ট্যাক করার সময় এটি অবশ্যই True রাখতে হবে।return_state (ডিফল্ট মান False) — এটি True সেট করলে শেষ স্টেপের হিডেন স্টেট এবং সেল স্টেট আলাদাভাবে রিটার্ন করে, যা এনকোডার-ডিকোডার (encoder-decoder) আর্কিটেকচারের জন্য প্রয়োজন হয়।dropout / recurrent_dropout — ইনপুট এবং রিক্যারেন্ট কানেকশনের ওভারফিটিং রোধ করার জন্য রেগুলারাইজেশন প্যারামিটার।ফাংশনাল এপিআই (Functional API) একটি মডেলকে বিভিন্ন লেয়ার কলের একটি স্পষ্ট গ্রাফ হিসেবে প্রকাশ করে — যা মাল্টি-ইনপুট/আউটপুট কিংবা জটিল ও অসাড়িবদ্ধ লেয়ার গ্রাফের জন্য অত্যন্ত প্রয়োজনীয়।
import numpy as np
vocab_size, embed_dim, max_len = 5000, 64, 20
inputs = keras.Input(shape=(max_len,))
x = layers.Embedding(input_dim=vocab_size, output_dim=embed_dim)(inputs)
x = layers.LSTM(32)(x)
outputs = layers.Dense(1, activation="sigmoid")(x)
model = keras.Model(inputs, outputs)
model.compile(optimizer="adam", loss="binary_crossentropy", metrics=["accuracy"])
model.summary()এখানে Embedding লেয়ারটি ইন্টিজার টোকেন আইডিগুলোকে গ্রহণ করে এবং সেগুলোকে ডেন্স লার্নড ভেক্টরে রূপান্তর করে LSTM-এ পাঠায়। সিকোয়েন্স লার্নিং চ্যাপ্টারের সেই সতর্কবার্তাটি মনে করুন: LSTM-এ কখনো সরাসরি raw ইন্টিজার আইডি পাঠাবেন না — তার আগে অবশ্যই একটি এমবেডিং লেয়ার ব্যবহার করবেন।
যখন একটি একক LSTM লেয়ার জটিল প্যাটার্ন শেখার জন্য যথেষ্ট হয় না, তখন আমরা একাধিক লেয়ার একের ওপর আরেকটা সাজাতে পারি (যাকে stacked LSTM বলে)। এর প্রধান শর্ত হলো: শেষ লেয়ারটি ছাড়া তার আগের প্রতিটি LSTM লেয়ারে অবশ্যই return_sequences=True সেট করতে হবে যাতে পরবর্তী লেয়ারটি ইনপুট হিসেবে পুরো হিডেন স্টেটের সিকোয়েন্সটি পায়।
model = keras.Sequential([
layers.Input(shape=(20, 64)),
layers.LSTM(64, return_sequences=True), # ← স্ট্যাকিংয়ের সময় এটি অবশ্যই True হতে হবে
layers.LSTM(32, return_sequences=True),
layers.LSTM(16),
layers.Dense(1),
])একটি বাইডাইরেকশনাল এলএসটিএম (Bidirectional LSTM) সিকোয়েন্সটিকে একই সাথে সামনের দিক থেকে এবং পেছনের দিক থেকে (উভয় মুখে) প্রসেস করে এবং প্রাপ্ত দুটি হিডেন স্টেটকে একত্রিত বা কনক্যাটেন করে। এটি মডেলটিকে প্রতিটি টাইম স্টেপের আগের ও পরের উভয় কনটেক্সট একসাথে ব্যবহার করতে সাহায্য করে — যা টেক্সট ক্লাসিফিকেশন বা সেন্টিমেন্ট বিশ্লেষণের মতো কাজের জন্য অত্যন্ত কার্যকর যেখানে পুরো সিকোয়েন্সটি শুরুতেই একসাথে পাওয়া যায়। তবে রিয়েল-টাইম অনলাইন প্রেডিকশনের ক্ষেত্রে এটি ব্যবহার করা যায় না।
model = keras.Sequential([
layers.Input(shape=(20, 64)),
layers.Bidirectional(layers.LSTM(32)),
layers.Dense(1, activation="sigmoid"),
])
# Bidirectional লেয়ারের আউটপুট শেপ হবে: (2*32,) = (64,)ডিফল্টভাবে, Keras প্রতিটি নতুন ব্যাচ ট্রেনিং শুরু করার আগে হিডেন স্টেট এবং সেল স্টেট -কে রিসেট করে শূন্য বানিয়ে দেয়। কিন্তু stateful=True মোডে, আগের ব্যাচের শেষ স্টেটটি পরবর্তী ব্যাচের শুরুর স্টেট হিসেবে কাজ করে — যা অনেক বড় সিকোয়েন্স হ্যান্ডেল করার জন্য অত্যন্ত দরকারি যেখানে পুরো ডেটাকে ছোট ছোট চঙ্কে (chunks) ভাগ করে প্রসেস করতে হয়।
model = keras.Sequential([
layers.LSTM(32, stateful=True, batch_input_shape=(4, 20, 1)),
])
# একটি ব্যাচ ট্রেইনিং শেষ হওয়ার পর model.reset_states() কল করে নতুন সিকোয়েন্সের জন্য স্টেট রিসেট করতে হবে।Keras ডিফল্টভাবে ফরগেট গেটের বায়াসগুলোকে ১.০ দিয়ে ইনিশিয়ালাইজ করে (unit_forget_bias=True)। এটি ট্রেনিংয়ের শুরুতে নেটওয়ার্কটিকে সবকিছু ভুলে যাওয়ার বদলে মনে রাখার দিকে বেশি পক্ষপাতী করে তোলে, যা ট্রেনিংয়ের গতি বাড়ায়। আমাদের স্ক্র্যাচ থেকে তৈরি NumPy ইমপ্লিমেন্টেশনে আমরা এগুলোকে ০ দিয়ে ইনিশিয়ালাইজ করেছিলাম — আপনি চাইলে self.bf = np.ones((hidden_size, 1)) লিখে Keras-এর মতো একই আচরণ তৈরি করতে পারেন।
# খুব ছোট ডেটা ব্যবহার করে সেন্টিমেন্ট অ্যানালাইসিস ট্রেনিং
import numpy as np
n_samples, seq_len, vocab_size = 1000, 20, 200
embed_dim, hidden_size = 16, 32
X = np.random.randint(1, vocab_size, size=(n_samples, seq_len))
y = np.random.randint(0, 2, size=(n_samples,)).astype(float)
model = keras.Sequential([
layers.Input(shape=(seq_len,)),
layers.Embedding(vocab_size, embed_dim),
layers.LSTM(hidden_size),
layers.Dense(1, activation="sigmoid"),
])
model.compile(optimizer="adam", loss="binary_crossentropy", metrics=["accuracy"])
history = model.fit(X, y, epochs=10, batch_size=32, validation_split=0.2, verbose=1)মডেল ট্রেনিং শেষে, history.history["loss"] এবং history.history["val_loss"] দেখলে আপনি বুঝতে পারবেন লস কত দ্রুত কমছে। র্যান্ডম বা এলোমেলো ডেটার ওপর হয়তো কোনো অর্থপূর্ণ অ্যাকুরেসি পাওয়া যাবে না — তবে শুরুর চেয়ে লস কমে আসা এটিই প্রমাণ করে যে গ্রেডিয়েন্টের প্রবাহ ঠিকঠাক কাজ করছে।
রিক্যারেন্ট আর্কিটেকচার ব্যবহার করে যেকোনো টেক্সট ক্লাসিফিকেশন, টাইম সিরিজ ফোরকাস্টিং কিংবা স্পিচ রিকগনিশন মডেল তৈরি করার সময় Keras-এর LSTM লেয়ারটি প্রতিনিয়ত ব্যবহৃত হয়। return_sequences, return_state এবং Bidirectional প্যারামিটারগুলোর সঠিক ব্যবহার জানা আপনাকে যেকোনো গবেষণাপত্রের (research papers) জটিল আর্কিটেকচারগুলো সহজে পড়তে ও বুঝতে সাহায্য করবে। পরবর্তী চ্যাপ্টারে আমরা শিখবো কীভাবে বাস্তব ডেটাকে এই লেয়ারগুলোর উপযোগী করে প্রস্তুত করতে হয়।