Chapter 18 of 18
The constructs used throughout this course, in one place
এই অ্যাপেন্ডিক্সটি মূলত একটি সংক্ষিপ্ত রেফারেন্স গাইড — যেখানে আমরা পুরো কোর্সে ব্যবহার করা Python এবং NumPy-এর বিভিন্ন কনস্ট্রাক্ট এক জায়গায় গুছিয়ে দিয়েছি। বিশেষ করে যারা NumPy দিয়ে LSTM তৈরি, ডেটা প্রিপারেশন, ইভ্যালুয়েশন এবং হাইপারপ্যারামিটার অপ্টিমাইজেশন চ্যাপ্টারগুলো পড়ার সময় দ্রুত কোনো কিছু মনে করিয়ে নিতে চান — তাদের জন্য এটি বিশেষভাবে উপকারী।
কোর্সে আমরা যা-ই গণনা করেছি — স্কেলার (scalar), ভেক্টর (vector), ম্যাট্রিক্স (matrix) বা টেনসর (tensor) — সবকিছুকেই কোডে NumPy-এর ndarray হিসেবে প্রকাশ করা হয়েছে, শুধু .shape দিয়ে তাদের আলাদা করা যায়।
import numpy as np
a = np.array([1, 2, 3]) # একটি ভেক্টর, শেপ (3,)
b = np.zeros((2, 3)) # 2×3 ম্যাট্রিক্স, সব শূন্য
c = np.random.randn(2, 3) # 2×3 ম্যাট্রিক্স, স্ট্যান্ডার্ড নর্মাল র্যান্ডম মান
d = np.ones((4, 5, 3)) # 3-D টেনসর: 4টি স্যাম্পল, 5টি টাইম স্টেপ, 3টি ফিচার
print(f"a shape: {a.shape}") # (3,)
print(f"b shape: {b.shape}") # (2, 3)
print(f"d shape: {d.shape}") # (4, 5, 3)এক-মাত্রিক ভেক্টর (3,) মানেই কলাম ভেক্টর (3,1) বা রো ভেক্টর (1,3) নয়। NumPy দিয়ে তৈরি LSTM-এ বেশিরভাগ শেপ মিসম্যাচ বাগের কারণ ঠিক এই সূক্ষ্ম পার্থক্যটি। তাই কখনো শেপ অনুমান করবেন না — সরাসরি .shape চেক করুন।
v1 = np.array([1, 2, 3]) # শেপ (3,)
v2 = np.array([[1], [2], [3]]) # শেপ (3,1) — একটি কলাম ভেক্টর
v3 = v1.reshape(3, 1) # শেপ (3,1)
v4 = v1[:, np.newaxis] # শেপ (3,1)A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# উপাদান-ভিত্তিক অপারেশন (element-wise)
print(A + B) # উপাদান-ভিত্তিক যোগ
print(A * B) # উপাদান-ভিত্তিক গুণ (এটি ম্যাট্রিক্স গুণ নয়!)
# ম্যাট্রিক্স গুণন (LSTM-এ এটিই ব্যবহৃত হয়)
print(A @ B) # np.matmul(A, B)-এর সমতুল্য
print(A.dot(B)) # এটিও একই কাজ করে
# ট্রান্সপোজ (Transposition)
print(A.T) # শেপ (2,2) → শেপ (2,2); সাধারণভাবে (m,n) → (n,m)
# ভেক্টর স্ট্যাক করা (Stacking vectors)
x = np.array([[1], [2]]) # শেপ (2,1)
h = np.array([[0.5], [0.3]]) # শেপ (2,1)
concat = np.vstack([x, h]) # শেপ (4,1) — NumPy LSTM-এ ব্যবহৃতNumPy স্বয়ংক্রিয়ভাবে পরস্পর-সামঞ্জস্যপূর্ণ শেপের অ্যারেগুলোকে ডেটা কপি না করেই আকারে সমান করে ফেলে — এই কৌশলকে ব্রডকাস্টিং বলে। এর জন্যই একটি বায়াস ভেক্টর ম্যাট্রিক্সের প্রতিটি রোতে একটিমাত্র লাইনে যোগ করা সম্ভব হয়:
x = np.array([[1, 2, 3],
[4, 5, 6]]) # শেপ (2, 3)
y = np.array([10, 20, 30]) # শেপ (3,)
print(x + y)
# [[11 22 33]
# [14 25 36]]
# y-কে x-এর দুটি রোতেই আলাদাভাবে যোগ হিসেবে গণ্য করা হয়েছেব্রডকাস্টিং-এর নিয়ম: ডানদিকের ডাইমেনশন থেকে পেছনের দিকে কাজ করলে — দুটি ডাইমেনশন সামঞ্জস্যপূর্ণ তখনই হয় যদি তারা সমান হয় অথবা তাদের একটি ১ হয়। যখন একটি ১ হয়, সেটি অন্যটির সমান করে "স্ট্রেচ" করে নেওয়া হয়।
z = np.arange(12).reshape(3, 4) # [[0,1,2,3],[4,5,6,7],[8,9,10,11]]
print(z[:, 1]) # কলাম 1: [1, 5, 9]
print(z[0, :]) # রো 0: [0, 1, 2, 3]
print(z[1:, 2:]) # রো ১-২, কলাম ২-৩: [[6,7],[10,11]]
# রিশেপিং (ফ্ল্যাট অ্যারে ও টেনসরের মধ্যে রূপান্তর)
flat = np.arange(24) # শেপ (24,)
cube = flat.reshape(2, 3, 4) # শেপ (2, 3, 4)
back = cube.flatten() # আবার শেপ (24,)
# নতুন অক্ষ যোগ করা (Keras LSTM-এ 3-D ইনপুট তৈরি করতে ব্যবহৃত)
series = np.array([1., 2., 3., 4., 5.]) # শেপ (5,)
lstm_input = series[:, np.newaxis] # শেপ (5, 1)
batch_input = lstm_input[np.newaxis, :] # শেপ (1, 5, 1) — ব্যাচ সাইজ ১| ফাংশন | কাজ | উদাহরণ |
|---|---|---|
| np.zeros(shape) | শূন্য দিয়ে ভরা অ্যারে তৈরি করে | np.zeros((3, 4)) |
| np.ones(shape) | এক দিয়ে ভরা অ্যারে তৈরি করে | np.ones((2, 2)) |
| np.random.randn(*shape) | স্ট্যান্ডার্ড নর্মাল র্যান্ডম মান তৈরি করে | np.random.randn(3, 4) |
| np.random.seed(n) | রিপ্রোডিউসিবিলিটির জন্য র্যান্ডম সিড সেট করে | np.random.seed(42) |
| arr.reshape(shape) | ডেটা কপি না করে শেপ পরিবর্তন করে | arr.reshape(10, 1) |
| np.vstack([a, b]) | অক্ষ ০ বরাবর অ্যারে স্ট্যাক করে | x_t এবং h_{t-1} কনক্যাটেনেট করতে |
| np.concatenate([a,b], axis) | যেকোনো অক্ষ বরাবর কনক্যাটেনেট করে | np.concatenate([x, h]) |
| arr.T | ট্রান্সপোজ করে | গ্রেডিয়েন্ট সমীকরণে W.T |
| A @ B | ম্যাট্রিক্স গুণন | গেট সমীকরণে W @ x |
| arr1 * arr2 | উপাদান-ভিত্তিক গুণন (⊙) | সেল আপডেটে f_t * C_prev |
| np.tanh(arr) | Tanh উপাদান-ভিত্তিকভাবে প্রয়োগ করে | ক্যান্ডিডেট সেল ও আউটপুট স্কোয়াশিং |
| np.exp(arr) | এক্সপোনেনশিয়াল উপাদান-ভিত্তিকভাবে প্রয়োগ করে | সিগময়েডের ভেতরে: 1/(1+exp(-z)) |
| np.clip(arr, min, max) | মানকে নির্দিষ্ট সীমায় আটকে রাখে | গ্রেডিয়েন্ট ক্লিপিং |
| np.allclose(a, b) | দুটি অ্যারে সংখ্যাগতভাবে সমান কি না পরীক্ষা করে | ফরোয়ার্ড পাসের মান যাচাইয়ে |
# লিস্ট কম্প্রিহেনশন — ডেটা প্রিপারেশনে বহুল ব্যবহৃত
windows = [series[i:i+4] for i in range(len(series)-4)]
# অ্যারের ডিকশনারি — NumPy LSTM-এ প্যারামিটার সংরক্ষণে ব্যবহৃত
params = {
"W_f": np.random.randn(8, 9) * 0.1,
"b_f": np.zeros((8, 1)),
}
# enumerate এবং reversed — BPTT-তে ব্যবহৃত
for t, cache in enumerate(caches):
... # ফরোয়ার্ড ইন্ডেক্সিং
for t in reversed(range(len(caches))):
... # টাইমের উল্টো দিকে ব্যাকপ্রপাগেশন
# f-string — সর্বত্র পঠনযোগ্য আউটপুটের জন্য
hidden_size = 64
print(f"Hidden size: {hidden_size}, parameters: {4*hidden_size*(hidden_size+1+1)}")
# টাইপ হিন্টস (Python 3.5+)
def make_windows(series: np.ndarray, w: int) -> tuple[np.ndarray, np.ndarray]:
...pip install numpy tensorflow scikit-learn matplotlib optunaকোর্সের সব কোড Python 3.9+, NumPy 1.24+ এবং TensorFlow 2.12+-এ পরীক্ষিত। রিপ্রোডিউসিবিলিটির জন্য নির্দিষ্ট ভার্সন পিন করতে:
pip install "numpy==1.24.*" "tensorflow==2.13.*" "scikit-learn==1.3.*" \
"matplotlib==3.7.*" "optuna==3.3.*"