Chapter 12
শূন্য থেকে ANN বানানো
Building ANN from Scratch
🎬 কেন শূন্য থেকে?
PyTorch বা TensorFlow ব্যবহার করার আগে অন্তত একবার নিজের হাতে পুরো নেটওয়ার্ক বানালে — যে জাদু হয় ভেতরে — সেটা চিরদিন মনে থাকবে। এই অধ্যায়ে আমরা শুধু NumPy দিয়ে digit classifier বানাব।
পরিকল্পনা
Input (784) → Hidden (128, ReLU) → Output (10, Softmax)
Loss: Categorical Cross-Entropy
Optimizer: Mini-batch SGDসম্পূর্ণ কোড
import numpy as np
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
# ---- ডেটা ----
data = load_digits()
X = data.data / 16.0 # normalize
y = data.target
# one-hot encode
Y = np.zeros((y.size, 10))
Y[np.arange(y.size), y] = 1
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.2, random_state=0)
# ---- Helpers ----
def relu(z): return np.maximum(0, z)
def relu_deriv(z): return (z > 0).astype(float)
def softmax(z):
z = z - z.max(axis=1, keepdims=True)
e = np.exp(z)
return e / e.sum(axis=1, keepdims=True)
def cross_entropy(y_true, y_pred, eps=1e-12):
return -np.mean(np.sum(y_true * np.log(y_pred + eps), axis=1))
# ---- Initialize ----
np.random.seed(42)
W1 = np.random.randn(64, 128) * np.sqrt(2/64) # He init
b1 = np.zeros((1, 128))
W2 = np.random.randn(128, 10) * np.sqrt(2/128)
b2 = np.zeros((1, 10))
lr = 0.1
batch_size = 32
epochs = 50
# ---- Train ----
for epoch in range(epochs):
# shuffle
idx = np.random.permutation(len(X_train))
X_train, Y_train = X_train[idx], Y_train[idx]
losses = []
for i in range(0, len(X_train), batch_size):
xb = X_train[i:i+batch_size]
yb = Y_train[i:i+batch_size]
# Forward
z1 = xb @ W1 + b1
a1 = relu(z1)
z2 = a1 @ W2 + b2
a2 = softmax(z2)
loss = cross_entropy(yb, a2)
losses.append(loss)
# Backward
dz2 = (a2 - yb) / len(xb) # softmax+CE shortcut
dW2 = a1.T @ dz2
db2 = dz2.sum(axis=0, keepdims=True)
dz1 = (dz2 @ W2.T) * relu_deriv(z1)
dW1 = xb.T @ dz1
db1 = dz1.sum(axis=0, keepdims=True)
# Update
W2 -= lr * dW2; b2 -= lr * db2
W1 -= lr * dW1; b1 -= lr * db1
# Eval
a1_t = relu(X_test @ W1 + b1)
pred = softmax(a1_t @ W2 + b2).argmax(axis=1)
acc = (pred == Y_test.argmax(axis=1)).mean()
print(f"Epoch {epoch+1:2d} | loss {np.mean(losses):.4f} | acc {acc:.3f}")🔑 He Initialization
ReLU-এর জন্য সবচেয়ে ভালো initialization —
std = √(2/fan_in)। এটা vanishing/exploding gradient কমায়।Softmax + Cross-Entropy এর Magic Shortcut
Softmax আর Cross-Entropy আলাদাভাবে derivative করা জটিল। কিন্তু একসাথে — অসাধারণ সরল হয়ে যায়:
dz_output = a_output - y_true # এটাই পুরো derivative!কী শিখলেন?
- কোনো framework ছাড়াই end-to-end একটা নিউরাল নেট তৈরি করা যায়।
- Forward, backward, update — সব হাতে।
- Sklearn digits-এ ~95%+ accuracy পাওয়া যায়।
সাধারণ ভুল ধারণা
⚠️ এড়িয়ে চলবেন
- Initialization 0 দেওয়া — সব নিউরন একই শিখবে।
- Softmax-এ exp overflow — তাই max বাদ দিয়ে exp করুন।
- Cross-entropy-তে log(0) — epsilon দিয়ে clip।
অনুশীলন
১. Hidden layer-এর size 128 → 256 বা 64 — accuracy কেমন বদলায়?
২. আরো একটি hidden layer যোগ করুন (64-128-64-10)।
৩. ReLU-এর বদলে Sigmoid দিয়ে train করুন — অনেক ধীর কেন?
মিনি প্রজেক্ট
🚀 আজকের চ্যালেঞ্জ
উপরের কোডে momentum যোগ করুন (
v = β·v + grad; w -= lr·v)। convergence speed তুলনা করুন।ইন্টারভিউ প্রশ্ন
- He vs Xavier initialization — পার্থক্য।
- Softmax+CE-এর derivative কেন এত সরল?
- Mini-batch ব্যবহার কেন?
সারসংক্ষেপ
✨ এই অধ্যায়ে যা শিখলাম
- শূন্য থেকে NumPy দিয়ে একটি digit classifier।
- Forward, backward, init, training loop — সব হাতে।
- পরের অধ্যায়ে — TensorFlow-এ একই কাজ ১০ লাইনে।