Chapter 14 of 18
Six complete, end-to-end projects across forecasting, NLP, and more
এই চ্যাপ্টারে আমরা এই কোর্সে শেখা প্রতিটি বিষয় — ডেটা প্রিপারেশন, মডেল বিল্ডিং, মূল্যায়ন এবং হাইপারপ্যারামিটার অপ্টিমাইজেশন — তিনটি সম্পূর্ণ প্রজেক্টের মাধ্যমে বাস্তব ক্ষেত্রে প্রয়োগ করব। প্রতিটি প্রজেক্টে আমরা একই নিয়মতান্ত্রিক ধাপগুলো অনুসরণ করব: ডেটাসেট সংগ্রহ, এক্সপ্লোরেটরি ডেটা অ্যানালাইসিস (EDA), ক্লিনিং, প্রি-প্রসেসিং, মডেল ট্রেনিং, মূল্যায়ন, এরর অ্যানালাইসিস এবং সবশেষে মডেল সংরক্ষণ ও লোড করা। এটি আপনাকে স্পষ্টভাবে বুঝতে সাহায্য করবে যে কীভাবে একই ডেটা-ওয়ার্কফ্লো তিনটি সম্পূর্ণ ভিন্ন কাজের উপযোগী করে মানিয়ে নেওয়া যায়।
ডেটাসেট সম্পর্কে একটি নোট: নিচের প্রজেক্টগুলোতে আমরা বাস্তব ডেটার কাঠামোর ওপর ভিত্তি করে সিন্থেটিক ডেটা (synthetic data) তৈরি করে ব্যবহার করেছি যাতে ইন্টারনেট সংযোগ ছাড়াই কোডগুলো সরাসরি রান করা যায়। প্রতিটি সেকশনে আমরা আসল প্রজেক্টে ব্যবহৃত ক্যানোনিকাল ডেটাসেটটির নামও উল্লেখ করে দিয়েছি; কোডের পরিবর্তন হবে খুবই সামান্য — কেবল ডেটা লোড করার ধাপটিতে।
বাস্তব ডেটাসেট: IMDB Movie Reviews (keras.datasets.imdb), যেখানে ৫০,০০০ লেবেলযুক্ত মুভি রিভিউ রয়েছে।
import numpy as np
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow import keras
from tensorflow.keras import layers
positive_words = ["great", "amazing", "wonderful", "loved", "excellent", "fantastic",
"brilliant", "enjoyable", "superb", "delightful", "recommend", "best"]
negative_words = ["terrible", "awful", "boring", "hated", "worst", "disappointing",
"poor", "dull", "waste", "bad", "mediocre", "avoid"]
neutral_words = ["movie", "film", "the", "acting", "story", "plot", "scene", "director",
"cast", "ending", "watched", "really", "very", "quite", "some", "was"]
rng = np.random.default_rng(42)
def generate_review(label, min_len=8, max_len=25):
pool = positive_words if label == 1 else negative_words
words = [rng.choice(pool if rng.random() < 0.35 else neutral_words)
for _ in range(rng.integers(min_len, max_len))]
return " ".join(words)
n_train, n_test = 3200, 800
train_labels = [rng.integers(0, 2) for _ in range(n_train)]
test_labels = [rng.integers(0, 2) for _ in range(n_test)]
train_texts = [generate_review(l) for l in train_labels]
test_texts = [generate_review(l) for l in test_labels]tokenizer = Tokenizer(num_words=2000, oov_token="<OOV>")
tokenizer.fit_on_texts(train_texts) # কেবল এবং কেবল ট্রেনিং ডেটার ওপর ফিট করুন
X_train = pad_sequences(tokenizer.texts_to_sequences(train_texts), maxlen=30, padding="post")
X_test = pad_sequences(tokenizer.texts_to_sequences(test_texts), maxlen=30, padding="post")
y_train = np.array(train_labels)
y_test = np.array(test_labels)model = keras.Sequential([
layers.Input(shape=(30,)),
layers.Embedding(2000, 16),
layers.LSTM(32, dropout=0.2, recurrent_dropout=0.1),
layers.Dense(1, activation="sigmoid"),
])
model.compile(optimizer="adam", loss="binary_crossentropy", metrics=["accuracy"])
history = model.fit(
X_train, y_train,
epochs=20, batch_size=64,
validation_split=0.15,
callbacks=[
keras.callbacks.EarlyStopping(patience=4, restore_best_weights=True),
keras.callbacks.ModelCheckpoint("best_sentiment.keras", save_best_only=True),
],
verbose=1,
)from sklearn.metrics import classification_report, confusion_matrix
y_prob = model.predict(X_test, verbose=0).ravel()
y_pred = (y_prob >= 0.5).astype(int)
print(classification_report(y_test, y_pred, target_names=["Negative", "Positive"]))
print("Confusion matrix:")
print(confusion_matrix(y_test, y_pred))বাস্তব ডেটাসেট: যেকোনো প্লেইন টেক্সট কর্পাস — শেক্সপিয়ারের নাটক, সংবাদের আর্টিকেল কিংবা উইকিপিডিয়া টেক্সট।
# একটি পুনরাবৃত্তিমূলক কাঠামোর সিন্থেটিক কর্পাস তৈরি করা (যাতে মডেলটি সহজে শিখতে পারে)
words = (["the", "king", "fought"] * 100 +
["the", "queen", "ruled"] * 100 +
["the", "knight", "served"] * 80)
rng.shuffle(words)
corpus = " ".join(words)
# শব্দ স্তরের ভোকাবুলারি তৈরি করা
word_to_idx = {w: i for i, w in enumerate(sorted(set(words)))}
idx_to_word = {i: w for w, i in word_to_idx.items()}
vocab_size = len(word_to_idx)
# (window, next_word) ট্রেইনিং জোড়া তৈরি করা
encoded = [word_to_idx[w] for w in words]
seq_len = 4
X = np.array([encoded[i:i+seq_len] for i in range(len(encoded)-seq_len)])
y = np.array([encoded[i+seq_len] for i in range(len(encoded)-seq_len)])
# মডেল তৈরি
gen_model = keras.Sequential([
layers.Input(shape=(seq_len,)),
layers.Embedding(vocab_size, 16),
layers.LSTM(64),
layers.Dense(vocab_size, activation="softmax"),
])
gen_model.compile(optimizer="adam", loss="sparse_categorical_crossentropy")
gen_model.fit(X, y, epochs=30, batch_size=32, verbose=0)
# টেম্পারেচার স্যাম্পলিং (temperature sampling) ব্যবহার করে টেক্সট জেনারেট করা
def generate_text(seed_words, n_words=20, temperature=1.0):
result = list(seed_words)
for _ in range(n_words):
x = np.array([[word_to_idx.get(w, 0) for w in result[-seq_len:]]])
probs = gen_model.predict(x, verbose=0)[0]
probs = np.log(probs + 1e-10) / temperature
probs = np.exp(probs) / np.exp(probs).sum()
result.append(idx_to_word[rng.choice(vocab_size, p=probs)])
return " ".join(result)
print(generate_text(["the", "king", "fought", "the"], temperature=0.7))টেম্পারেচার < ১.০: মডেল বেশি সুনির্দিষ্ট বা ডিটারমিনিস্টিক আচরণ করে এবং সর্বোচ্চ আত্মবিশ্বাসী শব্দগুলোই পছন্দ করে। টেম্পারেচার > ১.০: মডেল অনেক বেশি ক্রিয়েটিভ কিন্তু মাঝে মাঝে অসংলগ্ন শব্দ তৈরি করতে পারে। টেম্পারেচার = ১.০: সরাসরি মডেলের শেখা ডিস্ট্রিবিউশন থেকে স্যাম্পলিং করা হয়।
বাস্তব ডেটাসেট: UCI Household Electric Power Consumption, কিংবা যেকোনো শেয়ার/আবহাওয়ার CSV ফাইল।
# সিন্থেটিক টাইম সিরিজ: ট্রেন্ড + সিজনালিটি + নয়েজ
t = np.linspace(0, 4*np.pi, 1000)
series = 0.5*t + 3*np.sin(t) + rng.normal(0, 0.3, len(t))
# স্কেলিং → স্লাইডিং উইন্ডো → ট্রেন/টেস্ট স্প্লিট
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
scaled = scaler.fit_transform(series.reshape(-1, 1)).ravel()
window = 30
X_all = np.array([scaled[i:i+window] for i in range(len(scaled)-window)])
y_all = np.array([scaled[i+window] for i in range(len(scaled)-window)])
split = int(0.8 * len(X_all))
X_tr, X_te = X_all[:split, :, np.newaxis], X_all[split:, :, np.newaxis]
y_tr, y_te = y_all[:split], y_all[split:]
# মডেল
ts_model = keras.Sequential([
layers.Input(shape=(window, 1)),
layers.LSTM(64, return_sequences=True),
layers.LSTM(32),
layers.Dense(1),
])
ts_model.compile(optimizer="adam", loss="mse")
ts_model.fit(X_tr, y_tr, epochs=30, validation_split=0.15, verbose=0,
callbacks=[keras.callbacks.EarlyStopping(patience=5, restore_best_weights=True)])
# আসল ইউনিটে কনভার্ট করে মূল্যায়ন করুন
y_pred_scaled = ts_model.predict(X_te, verbose=0)
y_pred_orig = scaler.inverse_transform(y_pred_scaled).ravel()
y_true_orig = scaler.inverse_transform(y_te.reshape(-1,1)).ravel()
from sklearn.metrics import mean_absolute_error, mean_squared_error
print(f"MAE: {mean_absolute_error(y_true_orig, y_pred_orig):.4f}")
print(f"RMSE: {np.sqrt(mean_squared_error(y_true_orig, y_pred_orig)):.4f}")# ট্রেনিং শেষে মডেল সংরক্ষণ বা সেভ করা
model.save("my_lstm_model.keras")
# সংরক্ষণ করা ফাইল থেকে মডেল পুনরায় লোড করা — সব ওয়েট ও আর্কিটেকচার অক্ষতভাবে ফিরে আসবে
loaded = keras.models.load_model("my_lstm_model.keras")
assert np.allclose(model.predict(X_test[:5], verbose=0),
loaded.predict(X_test[:5], verbose=0))
print("Model save/load verified ✓")