Chapter 20 of 25
Putting every piece together into one training loop
আগের প্রতিটি চ্যাপ্টার আপনার হাতে একটি মেশিনের এক একটি অংশ তুলে দিয়েছে: একটি আর্কিটেকচার, একটি ফরওয়ার্ড পাস, ব্যাকপ্রোপাগেশন, একটি অ্যাক্টিভেশন ফাংশন, একটি লস ফাংশন, একটি অপ্টিমাইজার, একটি ইনিশিয়ালাইজেশন স্কিম, এবং রেগুলারাইজ করার নানা উপায়। প্রতিটি অংশই কাজ করে। কিন্তু ওয়ার্কবেঞ্চের ওপর ফেলে রাখা একগাদা নিখুঁত ইঞ্জিন পার্টস দিয়ে তো আর গাড়ি চলে না। কাউকে না কাউকে সেগুলোকে জোড়া লাগাতে হবে, ঠিক অর্ডারে বা ক্রমানুসারে, এবং তারপর তাকে চালাতে হবে।
এই চ্যাপ্টারটি হলো ঠিক সেই জোড়া লাগানোর বা অ্যাসেম্বলি করার (assembly) ধাপ। এটি এতক্ষণ পর্যন্ত শেখা প্রতিটি আইডিয়াকে এক করে একটি পূর্ণাঙ্গ ও বাস্তব ট্রেনিং লুপ (training loop) তৈরি করে — বাস্তবে কোনো প্রজেক্টে যখন আপনি .fit() কল করেন, তখন ঠিক যে কাজগুলো পরপর ঘটে, এটি তারই রূপ — এবং এরপর এটি এমন কিছু ব্যবহারিক বা প্র্যাক্টিক্যাল বিষয় নিয়ে আলোচনা করে যেগুলো আগের কোনো নির্দিষ্ট চ্যাপ্টারের মধ্যে পড়ে না: যেমন হাইপারপ্যারামিটারগুলোর আকার কীভাবে ঠিক করতে হয়, একটি নেটওয়ার্ক বাস্তবে ঠিক কতটা কম্পিউট বা মেমরি খরচ করে, সময়ের সাথে লার্নিং রেট কীভাবে বদলাতে হয়, এবং ট্রেন হওয়ার পর ফলাফলটা আসলেই ভালো হলো কি না তা কীভাবে বুঝতে হয়।
ভাবুন তো, একটি প্রফেশনাল বা পেশাদার রান্নাঘরে প্রথমবারের মতো খুব জটিল কোনো একটি পদ বা ডিশ (dish) রান্না করা হচ্ছে। সবচেয়ে ভালো ছুরি, সবচেয়ে তাজা উপকরণ এবং একদম নিখুঁতভাবে মাপা একটি ওভেন থাকলেই যে ভালো রান্নার গ্যারান্টি দেওয়া যায়, তা কিন্তু নয় — যদি সেগুলোকে ভুল ক্রমানুসারে বা ভুল সময়ে ব্যবহার করা হয়। যেমন মশলা মাখানোর আগেই যদি মাংস ভেজে ফেলা হয়, অথবা রান্না শেষ করেই বিশ্রাম নেওয়ার সময় না দিয়ে সরাসরি পরিবেশন করা হয়। একজন শেফের (chef) একটি রেসিপি (recipe) দরকার হয়: একটি নির্দিষ্ট ধারা বা সিকোয়েন্স যা ওই অসাধারণ উপকরণগুলোর প্রতিটিকে সঠিক সময়ে এবং সঠিক নিয়মে একসাথে মেলায়।
একটি MLP ট্রেন করার বিষয়টুকি ঠিক এমনই। আপনার কাছে আলাদা আলাদাভাবে সেরা ইনিশিয়ালাইজেশন স্কিম, সেরা অপ্টিমাইজার এবং সেরা রেগুলারাইজেশন স্ট্র্যাটেজি থাকতে পারে, কিন্তু সেগুলোকে ভুলভাবে জোড়া লাগালে আপনি একটি ভাঙাচোরা ফলাফলই পাবেন — যেমন ডেটা শাফল বা ওলটপালট করার আগেই যদি গ্রেডিয়েন্ট ক্যালকুলেট করে ফেলা হয়, অথবা এমন কোনো ভ্যালিডেশন সেটের ওপর মডেল ইভ্যালুয়েট করা হয় যা প্রিপ্রসেসিংয়ের সময় ট্রেনিং ডেটার সাথে মিশে দূষিত হয়ে গিয়েছিল। ট্রেনিং পাইপলাইন (training pipeline) হলো সেই রেসিপি যা নিশ্চিত করে যে প্রতিটি উপকরণ সঠিক জায়গায়, সঠিক সময়ে ব্যবহার করা হচ্ছে।
পুরো অ্যালগরিদমটি দেখার আগে, এর চেহারাটা কেমন তা একবার দেখে নেওয়া যাক:
ইনিশিয়ালাইজ ও প্রিপ্রসেস (Initialize & preprocess)
He বা Xavier ইনিশিয়ালাইজেশন দিয়ে ওয়েট সেট করুন; শুধুমাত্র ট্রেনিং সেটের স্ট্যাটিস্টিকস ব্যবহার করে ইনপুট ফিচারগুলোকে স্ট্যান্ডার্ডাইজ করুন।
শাফল ও ব্যাচ (Shuffle & batch)
প্রতিটি ইপকের শুরুতে, ট্রেনিং ডেটাকে শাফল করুন এবং B আকারের ছোট ছোট মিনি-ব্যাচে ভাগ করুন।
ফরওয়ার্ড পাস (Forward pass)
প্রেডিকশন তৈরি করার জন্য প্রতিটি মিনি-ব্যাচকে নেটওয়ার্কের ভেতর দিয়ে সামনে প্রবাহিত করুন।
লস ক্যালকুলেট করা (Compute loss)
টাস্কের লস ফাংশন ব্যবহার করে আসল লেবেলের সাথে প্রেডিকশনের তুলনা করুন।
ব্যাকওয়ার্ড পাস (Backward pass)
প্রতিটি ওয়েট এবং বায়াসের গ্রেডিয়েন্ট ক্যালকুলেট করার জন্য লসকে পেছনের দিকে প্রোপাগেট বা প্রবাহিত করুন।
প্যারামিটার আপডেট (Update parameters)
নতুন ক্যালকুলেট করা গ্রেডিয়েন্টগুলো ব্যবহার করে আপনার বেছে নেওয়া অপ্টিমাইজারের আপডেট রুলটি প্রয়োগ করুন।
ভ্যালিডেট ও চেক (Validate & check)
প্রতিটি ইপকের পর আলাদা করে রাখা ভ্যালিডেশন সেটের ওপর ইভ্যালুয়েট করুন; পারফরম্যান্স থমকে গেলে আর্লি স্টপিং (early stopping) প্রয়োগ করুন।
ইনপুট: ট্রেনিং ডেটা , ভ্যালিডেশন ডেটা , লার্নিং রেট , ব্যাচ সাইজ , ইপক সংখ্যা ।
পেছনের যুক্তি বা Intuition: আগের প্রতিটি চ্যাপ্টার এই লুপের ঠিক একটিমাত্র লাইনের সাথে যুক্ত। ইনিশিয়ালাইজেশন শুরুর পয়েন্ট ঠিক করে দেয়; স্ট্যান্ডার্ডাইজেশন ইনপুটের স্কেলগুলোকে সামঞ্জস্যপূর্ণ রাখে; ভেতরের লুপটি হলো ফরওয়ার্ড পাস, লস, ব্যাকপ্রপ, এবং অপ্টিমাইজার আপডেটের একটি ক্রমানুসার; আর বাইরের লুপের ভ্যালিডেশন চেক হলো সেই জায়গা যেখানে আর্লি স্টপিংয়ের মতো রেগুলারাইজেশনের সিদ্ধান্তগুলো আসলে প্রয়োগ করা হয়।
ওপরের সিউডোকোডটিকে (pseudocode) এবার একটি বাস্তব, রান-করার-যোগ্য PyTorch-স্টাইলের ট্রেনিং লুপে রূপান্তর করা যাক, যেখানে প্রতিটি ধাপে ঠিক কোন চ্যাপ্টারের ধারণাটি কাজ করছে তা মন্তব্য বা কমেন্ট আকারে দেখানো হয়েছে:
import torch
import torch.nn as nn
# --- ১. আর্কিটেকচার এবং ইনিশিয়ালাইজেশন (চ্যাপ্টার: আর্কিটেকচার, ইনিশিয়ালাইজেশন) ---
model = nn.Sequential(
nn.Linear(20, 64), nn.ReLU(),
nn.Linear(64, 32), nn.ReLU(),
nn.Linear(32, 1),
)
for layer in model:
if isinstance(layer, nn.Linear):
nn.init.kaiming_normal_(layer.weight, nonlinearity="relu") # He ইনিশিয়ালাইজেশন
nn.init.zeros_(layer.bias)
# --- ২. লস এবং অপ্টিমাইজার (চ্যাপ্টার: লস ফাংশন, অপ্টিমাইজার, রেগুলারাইজেশন) ---
criterion = nn.BCEWithLogitsLoss()
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3, weight_decay=1e-4)
scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, patience=3)
best_val_loss = float("inf")
patience_counter = 0
PATIENCE = 10
# --- ৩. বাইরের লুপ: ইপক (চ্যাপ্টার: ট্রেনিং পাইপলাইন) ---
for epoch in range(max_epochs):
model.train() # ড্রপআউট/BatchNorm-কে ট্রেনিং মোডে সুইচ করা (চ্যাপ্টার: রেগুলারাইজেশন)
for X_batch, y_batch in train_loader: # প্রতিটি ইপকে শাফল করা হয় DataLoader দিয়ে
optimizer.zero_grad()
y_pred = model(X_batch) # ফরওয়ার্ড পাস
loss = criterion(y_pred.squeeze(), y_batch) # লস ক্যালকুলেশন
loss.backward() # ব্যাকওয়ার্ড পাস (ব্যাকপ্রোপাগেশন)
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=5.0) # গ্রেডিয়েন্ট ক্লিপিং (চ্যাপ্টার: অপ্টিমাইজার)
optimizer.step() # প্যারামিটার আপডেট
# --- ৪. ভ্যালিডেশন (চ্যাপ্টার: রেগুলারাইজেশন — আর্লি স্টপিং) ---
model.eval()
with torch.no_grad():
val_loss = evaluate(model, val_loader, criterion)
scheduler.step(val_loss) # লার্নিং রেট শিডিউলিং
if val_loss < best_val_loss:
best_val_loss = val_loss
patience_counter = 0
best_state = {k: v.clone() for k, v in model.state_dict().items()} # সবচেয়ে ভালো চেকপয়েন্ট রাখা
else:
patience_counter += 1
if patience_counter >= PATIENCE:
print(f"আর্লি স্টপিং: {epoch} ইপকে থেমে গেছে")
break
model.load_state_dict(best_state) # সবচেয়ে ভালো চেকপয়েন্ট ফিরিয়ে আনা, শেষেরটি নয়এই কোডের প্রতিটি অংশ এই কোর্সের একটি ভিন্ন চ্যাপ্টারের সাথে সরাসরি যুক্ত — He ইনিশিয়ালাইজেশন, AdamW অপ্টিমাইজার, ওয়েট ডিকে, গ্রেডিয়েন্ট ক্লিপিং, লার্নিং রেট শিডিউলিং, এবং আর্লি স্টপিং একসাথে কাজ করছে একটিমাত্র সুসংগঠিত লুপে। model.train() এবং model.eval()-এর মধ্যে সুইচ করাটা বিশেষভাবে খেয়াল করার মতো — এটি ঠিক সেই জায়গা যেখানে ড্রপআউট এবং BatchNorm-এর ট্রেনিং/ইনফারেন্স আচরণের পার্থক্যটি বাস্তবে প্রয়োগ হয়।
Keras-এ এই পুরো লুপটি model.fit(X_train, y_train, validation_data=(X_val, y_val), epochs=100, callbacks=[EarlyStopping(patience=10, restore_best_weights=True), ReduceLROnPlateau(patience=3)]) লিখে পাওয়া যায় — ফ্রেমওয়ার্কটি ভেতরে ভেতরে ঠিক এই একই ধাপগুলোই চালায়, শুধু সেগুলোকে আপনার থেকে আড়াল করে রাখে।
ট্রেনিংয়ের আগে, সবসময়: (১) মিসিং বা হারিয়ে যাওয়া ভ্যালুগুলোকে ইম্পিউট (impute) করে বা বাদ দিয়ে সামলান; (২) ক্যাটাগরিকাল বা শ্রেণীভিত্তিক ফিচারগুলোকে এনকোড করুন, যেমন ওয়ান-হট এনকোডিং (one-hot encoding); (৩) নিউমেরিক বা সংখ্যাভিত্তিক ফিচারগুলোকে স্ট্যান্ডার্ডাইজ বা নরমালাইজ করুন যাতে সব ফিচার একটি সামঞ্জস্যপূর্ণ স্কেলে থাকে — বিশেষ করে MLP-র জন্য এটি খুবই গুরুত্বপূর্ণ, কারণ খুব আলাদা স্কেলের ফিচারগুলো কিছু কিছু ওয়েটকে শুরুর দিকের গ্রেডিয়েন্টে দাপট দেখাতে পারে এবং কনভার্জেন্সকে ধীর করে দিতে পারে; এবং (৪) যেকোনো প্রিপ্রসেসিং স্ট্যাটিস্টিকস ক্যালকুলেট করার আগেই ডেটাকে ট্রেন/ভ্যালিডেশন/টেস্ট সেটে ভাগ করে নিন, ডেটা লিকেজ বা ফাঁস হওয়া এড়ানোর জন্য শুধুমাত্র ট্রেনিং সেটের ওপরই স্কেলারটিকে (scaler) ফিট করুন।
পুরো ডেটাসেট থেকে ফিচারের মিন (mean) এবং স্ট্যান্ডার্ড ডেভিয়েশন (standard deviations) ক্যালকুলেট করে, তারপর ট্রেন/টেস্ট-এ ভাগ করলে টেস্ট সেটের তথ্য খুব নীরবে ট্রেনিং ফিচারগুলোর স্কেলিংকে প্রভাবিত করে ফেলে। এটি ডেটা লিকেজের বা ডেটা ফাঁস হওয়ার একটি খুব সূক্ষ্ম কিন্তু খুব বাস্তব রূপ — সবসময় শুধুমাত্র ট্রেনিং স্প্লিট বা অংশের ওপরই স্কেলার ফিট করুন, তারপর ওই একই ফিট করা ট্রান্সফর্ম বা পরিবর্তনটি ভ্যালিডেশন এবং টেস্ট ডেটায় প্রয়োগ করুন।
| হাইপারপ্যারামিটার (Hyperparameter) | সাধারণ রেঞ্জ / গাইডেন্স (Typical Range / Guidance) |
|---|---|
| হিডেন লেয়ারের সংখ্যা | টেবুলার (tabular) ডেটার জন্য ১-৫টি; খুব জটিল সমস্যার জন্য আরও গভীর, যদিও MLP খুব কম সময়ই CNN বা ট্রান্সফর্মারের মতো অতটা গভীর হয় |
| প্রতি লেয়ারে নিউরনের সংখ্যা | সাধারণত কমতে থাকে (যেমন, 128 → 64 → 32) বা একই থাকে; সাধারণত ২-এর পাওয়ার বা গুণিতক হয় |
| অ্যাক্টিভেশন ফাংশন | ReLU (ডিফল্ট), অথবা এর ভ্যারিয়েন্টগুলো; সিগময়েড/সফটম্যাক্স শুধুমাত্র আউটপুট লেয়ারের জন্য বরাদ্দ থাকে |
| লস ফাংশন | টাস্ক বা কাজ অনুযায়ী ঠিক করা হয় |
| অপ্টিমাইজার | Adam / AdamW (ডিফল্ট প্রথম পছন্দ) |
| লার্নিং রেট | সাধারণত থেকে ; লগ স্কেলে (log scale) সার্চ করুন |
| ব্যাচ সাইজ | 32, 64, 128, 256 হলো খুব সাধারণ ডিফল্ট মান |
| ইপকের সংখ্যা | আর্লি স্টপিংয়ের সাথে মিলিয়ে ঠিক করা হয়, আগে থেকে ফিক্স বা নির্দিষ্ট করে দেওয়া হয় না |
| ড্রপআউট রেট (Dropout rate) | মাঝারি আকারের নেটওয়ার্কের জন্য ০.২-০.৫ |
| এল২ রেগুলারাইজেশনের শক্তি | সাধারণত থেকে |
ট্রেনিংয়ের শুরুর দিকে, একটি তুলনামূলক বড় লার্নিং রেট লস ল্যান্ডস্কেপের ওপর দ্রুত এগোতে সাহায্য করে। ট্রেনিংয়ের শেষের দিকে, যখন প্যারামিটারগুলো একটি ভালো মিনিমামের কাছাকাছি চলে আসে, তখন একটি ছোট লার্নিং রেট লক্ষ্য টপকে না গিয়ে সূক্ষ্মভাবে মানিয়ে নিতে বা ফাইন-টিউন (fine-tune) করতে সাহায্য করে। পুরো ট্রেনিং জুড়ে একটিমাত্র ফিক্সড বা নির্দিষ্ট লার্নিং রেট হলো একটি আপস (compromise), যা খুব কম সময়ই দুটি ধাপে সমানভাবে সেরা হতে পারে।
| শিডিউল (Schedule) | বিবরণ (Description) |
|---|---|
| স্টেপ ডিকে (Step decay) | একটি নির্দিষ্ট সংখ্যক ইপক পরপর -কে একটি নির্দিষ্ট ফ্যাক্টর (যেমন, ০.১) দিয়ে গুণ করে কমানো হয় |
| এক্সপোনেনশিয়াল ডিকে (Exponential decay) | , প্রতিটি ধাপে মসৃণভাবে কমতে থাকে |
| কোসাইন অ্যানিলিং (Cosine annealing) | ট্রেনিংয়ের পুরো সময় জুড়ে একটি কোসাইন কার্ভ অনুসরণ করে থেকে প্রায় শূন্যের কাছাকাছি নেমে আসে, প্রায়শই এর মাঝে মাঝে পিরিয়ডিক রিস্টার্ট বা নতুন করে শুরু করার সুযোগ থাকে |
| রিডিউস-অন-প্ল্যাট্যু (Reduce-on-plateau) | যখন ভ্যালিডেশন লস একটি নির্দিষ্ট সংখ্যক ইপক ধরে আর কমে না, তখন স্বয়ংক্রিয়ভাবে -কে কমিয়ে দেওয়া হয় |
| ওয়ার্মআপ (Warmup) | ট্রেনিংয়ের ঠিক শুরুতে -কে একটি খুব ছোট মান থেকে লিনিয়ারলি বা সমানুপাতিক হারে বাড়ানো হয়, তারপর অন্য কোনো শিডিউলে সুইচ করা হয় — এটি বিশেষ করে অ্যাডাপ্টিভ অপ্টিমাইজার বা বড় ব্যাচ সাইজের ক্ষেত্রে প্রথম কয়েকটি ধাপকে স্থিতিশীল করতে সাহায্য করে |
ট্রেনিং এবং ভ্যালিডেশন লসের কার্ভ দুটো একসাথে প্লট করাটাই সম্ভবত একটি ট্রেনিং রান ডায়াগনোজ করার সবচেয়ে দ্রুত এবং সবচেয়ে তথ্যবহুল উপায়।
| প্যাটার্ন (Pattern) | সম্ভাব্য রোগনির্ণয় (Likely Diagnosis) | কী করবেন (What to Do) |
|---|---|---|
| ট্রেনিং এবং ভ্যালিডেশন — দুটো লসই বেশি এবং সমতল | আন্ডারফিটিং (underfitting): মডেলের ক্যাপাসিটি অথবা ট্রেনিং সময় যথেষ্ট নয় | মডেল বড় করুন, লার্নিং রেট বাড়ান, রেগুলারাইজেশন কমান |
| ট্রেনিং লস কমছে কিন্তু ভ্যালিডেশন লস আবার বাড়তে শুরু করেছে | ওভারফিটিং (overfitting): মডেল ট্রেনিং ডেটার নয়েজ মুখস্থ করছে | রেগুলারাইজেশন বাড়ান (dropout/L2), আর্লি স্টপিং প্রয়োগ করুন, বা আরও ডেটা জোগাড় করুন |
| দুটো লসই কমছে কিন্তু ভ্যালিডেশন লস ট্রেনিং লসের চেয়ে অনেক বেশি | একটি হালকা জেনারেলাইজেশন গ্যাপ — স্বাভাবিক, তবে নজরে রাখার মতো | রেগুলারাইজেশন সামান্য বাড়ানো বিবেচনা করুন |
| ট্রেনিং লস দোদুল্যমান বা খুব ওঠানামা করছে, কমছেই না | লার্নিং রেট অনেক বেশি বড়, অথবা ব্যাচ সাইজ খুব ছোট | লার্নিং রেট কমান বা ব্যাচ সাইজ বাড়ান |
ট্রেনিং লস এবং ভ্যালিডেশন লসের মধ্যেকার ফারাককে বলা হয় জেনারেলাইজেশন গ্যাপ। এই গ্যাপ ছোট থাকা মানেই যে মডেলটি ভালো, তা কিন্তু নয় — যদি দুটো লসই বেশি হয়ে থাকে (আন্ডারফিটিং), তবে গ্যাপ ছোট হলেও মডেলটি খারাপ। লক্ষ্য হলো ভ্যালিডেশন লসকে যতটা সম্ভব কম রাখা, শুধু গ্যাপ কমানো নয়।
সাইজের সংখ্যক লেয়ারের একটি নেটওয়ার্কের জন্য প্যারামিটারের সংখ্যা হলো:
একটিমাত্র এক্সাম্পলের জন্য একটি ফরওয়ার্ড পাসের টাইম কমপ্লেক্সিটি (Time complexity) হলো , যা মূলত ম্যাট্রিক্স মাল্টিপ্লিকেশনের ওপর নির্ভরশীল; ব্যাকপ্রোপাগেশনের খরচও প্রায় একই। সাইজের একটি মিনি-ব্যাচের জন্য, এটি দাঁড়ায় ।
মেমরি কমপ্লেক্সিটিতে (Memory complexity) সব ওয়েট এবং বায়াস স্টোর করে রাখতে হয় বা জমিয়ে রাখতে হয় (), সাথে ব্যাকপ্রোপাগেশনের জন্য দরকারি ব্যাচের প্রতিটি এক্সাম্পলের ফরওয়ার্ড পাসের প্রতিটি অ্যাক্টিভেশন: ।
(বায়াস-সহ ফুললি কানেক্টেড বা fully connected) আর্কিটেকচারের একটি নেটওয়ার্কের জন্য:
একটি আসল ট্রেনিং রান শুরু করার আগে Keras-এ model.summary() অথবা PyTorch-এ sum(p.numel() for p in model.parameters()) ব্যবহার করুন। এটি সাথে সাথেই জানিয়ে দেয় যে মডেলটি হাতের কাছে থাকা ডেটার তুলনায় অবাস্তবভাবে বড় কি না — যা ওভারফিটিংয়ের ঝুঁকি বাড়ায় — অথবা এটি পিসির মেমরি ক্ষমতার বাইরে কি না।
| টাস্ক (Task) | সাধারণ মেট্রিক্স (Common Metrics) |
|---|---|
| রিগ্রেশন (Regression) | Mean Squared Error, Mean Absolute Error, |
| বাইনারি ক্লাসিফিকেশন | Accuracy, Precision, Recall, F1-score, ROC-AUC |
| মাল্টি-ক্লাস ক্লাসিফিকেশন | Accuracy, macro/micro-averaged F1-score, Confusion Matrix |
একটি ইমব্যালান্সড বা ভারসাম্যহীন ডেটাসেটের ওপর — ধরা যাক, ৯৫% নেগেটিভ এবং ৫% পজিটিভ — এমন একটি খুব সাধারণ মডেল যে সবসময় "নেগেটিভ" প্রেডিক্ট করে, সেও পুরোপুরি ইউজলেস বা অকেজো হওয়ার পরও ৯৫% অ্যাকিউরেসি (accuracy) অর্জন করে। ঠিক এই কারণেই বিশেষত জালিয়াতি (fraud) বা রোগ নির্ণয়ের (disease detection) মতো ইমব্যালান্সড ক্লাসিফিকেশন সমস্যাগুলোর ক্ষেত্রে প্রিসিশন (precision), রিকল (recall), F1, এবং কনফিউশন ম্যাট্রিক্স (confusion matrix) নিজেই অ্যাকিউরেসির অত্যাবশ্যকীয় পরিপূরক হিসেবে কাজ করে।
মডেলের আসল ভুলগুলোর একটি নমুনা বা স্যাম্পল নিজে হাতে পরীক্ষা করা মেশিন লার্নিংয়ের সবচেয়ে কম ব্যবহৃত কিন্তু সবচেয়ে কাজের ব্যবহারিক দক্ষতাগুলোর একটি। প্যাটার্ন খুঁজুন: ভুলগুলো কি কোনো নির্দিষ্ট ক্লাসে, বা ইনপুট ভ্যালুগুলোর কোনো নির্দিষ্ট রেঞ্জে আটকে আছে? এটি প্রায়শই ডেটা কোয়ালিটির সমস্যা, মিসিং ফিচার, অথবা এমন কোনো পদ্ধতিগত দুর্বলতা প্রকাশ করে দেয় যা শুধুমাত্র অ্যাগ্রিগেট (aggregate) বা সাধারণ গাণিতিক মেট্রিক্সগুলো পুরোপুরি লুকিয়ে রাখতে পারে।
পুরো ডেটাসেটের ওপর প্রিপ্রসেসিং স্ট্যাটিস্টিকস ক্যালকুলেট করার পর ডেটাকে ট্রেন/ভ্যালিডেশন/টেস্ট-এ ভাগ করলে টেস্ট-সেটের তথ্য নীরবে ট্রেনিংয়ের মধ্যে লিক বা ফাঁস হয়ে যায়। সবসময় আগে ভাগ করুন (split first), তারপর ফিট (fit) করুন।
আগে থেকে একটি নির্দিষ্ট সংখ্যক ইপক বেছে নিলে এই বাস্তব সত্যটি এড়িয়ে যাওয়া হয় যে ট্রেনিং থামানোর সঠিক জায়গাটি আসলে ভ্যালিডেশনের পারফরম্যান্সের ওপর নির্ভর করে, যা আগে থেকে জানা সম্ভব নয়। ইপক সংখ্যাকে আগে থেকে ফিক্স করে না দিয়ে বরং একে আর্লি স্টপিংয়ের (early stopping) সাথে মিলিয়ে দিন।
একটি ইমব্যালান্সড ডেটাসেটে খুব বেশি অ্যাকিউরেসি নম্বর বা পারসেন্টেজ এমন একটি মডেলকে লুকিয়ে রাখতে পারে যা কখনোই মাইনরিটি বা সংখ্যালঘু ক্লাসটিকে সঠিকভাবে চিহ্নিত করতে পারে না — যে ক্লাসটি সাধারণত জালিয়াতি বা রোগ নির্ণয়ের মতো সমস্যাগুলোতে সবচেয়ে বেশি গুরুত্বপূর্ণ হয়।
PyTorch-এর মতো ফ্রেমওয়ার্কে ম্যানুয়ালি ট্রেনিং লুপ লেখার সময়, প্রতিটি ইপকের ট্রেনিং অংশের শুরুতে model.train() এবং ভ্যালিডেশন অংশের আগে model.eval() কল করতে ভুলে গেলে ড্রপআউট এবং BatchNorm ভুল মোডে থেকে যায় — এটি নীরবে ভুল ভ্যালিডেশন মেট্রিক্স তৈরি করে, যা ডিবাগ করা খুব কঠিন, কারণ কোডে কোনো এরর দেখায় না।
আর্লি স্টপিং প্রয়োগ করলেও, যদি ট্রেনিং লুপ প্রতিটি ইপকে সবচেয়ে ভালো ভ্যালিডেশন পারফরম্যান্সের মডেল স্টেট আলাদা করে সংরক্ষণ না করে, তবে ট্রেনিং থামার মুহূর্তের মডেলটি আসলে সবচেয়ে ভালো মডেল নাও হতে পারে — বিশেষ করে যদি patience কয়েক ইপক বেশি বাড়িয়ে ধরা হয়ে থাকে।
ঠিক এই লুপটিই — ইনিশিয়ালাইজ, প্রিপ্রসেস, ফরওয়ার্ড/ব্যাকওয়ার্ড/আপডেট-এর সাথে মিনি-ব্যাচের ওপর ইটারেট (iterate) করা, ভ্যালিডেট করা, থামানো — প্রত্যেকটি হাই-লেভেল বা উচ্চ-স্তরের ট্রেনিং API আড়ালে কাজ করার সময় ঠিক এটাই করে, তা সেটি Keras বা scikit-learn-এর model.fit() হোক, অথবা PyTorch-এর নিজে হাতে লেখা কোনো লুপই হোক। পরের চ্যাপ্টারটি এই পাইপলাইনটিকে এই তিনটি ফ্রেমওয়ার্কেরই কাজের ওপর প্রয়োগ করে দেখাবে, যাতে আপনি নিখুঁতভাবে দেখতে পান যে প্রতিটি ফ্রেমওয়ার্ক কীভাবে এই ধাপগুলোর প্রতিটিকে প্রকাশ করে (অথবা লুকিয়ে রাখে)।