সম্পূর্ণ ব্যাকপ্রপ — হাতে-কলমে ও NumPy-তে
এই পাঠে যা শিখবেন
- একটি সম্পূর্ণ ছোট নেটওয়ার্কের ফরওয়ার্ড পাস আবার ঝালিয়ে নেওয়া, এবার একটি পরিষ্কার টেবিল আকারে
- একই নেটওয়ার্কের সম্পূর্ণ ব্যাকওয়ার্ড পাস — সব পাঁচটি গ্রেডিয়েন্ট একসাথে, হাতে হিসাব করা
- হাতে-হিসাব ও NumPy কোডের আউটপুট পাশাপাশি রেখে লাইন-বাই-লাইন মিলিয়ে দেখা
- একটি গ্রেডিয়েন্ট ডিসেন্ট স্টেপের পর নতুন প্যারামিটার ও কম লস গণনা করা
১ · নেটওয়ার্ক ও সংখ্যা — পুনরায় স্মরণ
পাঠ ১৯-এ প্রবর্তিত এবং পাঠ ২০-তে ব্যবহৃত নেটওয়ার্কটিই এখানে আবার — এবারই শেষবার এই একই সংখ্যা দিয়ে, তবে এখন সবকিছু একসাথে, সম্পূর্ণ চিত্র হিসেবে।
$$ z_1 = w_1 x_1 + w_2 x_2 + b_1 \qquad h = \sigma(z_1) \qquad \hat{y} = w_3 h + b_2 \qquad L = (\hat{y}-y)^2 $$
$x_1=1.0,\ x_2=2.0,\ y=0.0$ · $w_1=0.5,\ w_2=-0.5,\ b_1=0.5$ · $w_3=2.0,\ b_2=0.0$
২ · ফরওয়ার্ড পাস — সম্পূর্ণ হাতে হিসাব
নিচের টেবিলের প্রতিটি সারি আগেরটির উপর নির্ভরশীল — ঠিক পাঠ ১৯-এর টপোলজিক্যাল অর্ডার অনুযায়ী:
| রাশি | সূত্র | মান |
|---|---|---|
| $z_1$ | $w_1x_1+w_2x_2+b_1$ | $0.5(1.0)+(-0.5)(2.0)+0.5 = 0.0$ |
| $h$ | $\sigma(z_1)$ | $\sigma(0) = 0.5$ |
| $\hat{y}$ | $w_3h+b_2$ | $2.0(0.5)+0.0 = 1.0$ |
| $L$ | $(\hat{y}-y)^2$ | $(1.0-0.0)^2 = 1.0$ |
তাই এই ইনপুটে আমাদের নেটওয়ার্কের লস $\boxed{L=1.0}$ — এই মানটি এই পাঠের পুরো যাচাইয়ের ভিত্তি।
৩ · ব্যাকওয়ার্ড পাস — সম্পূর্ণ হাতে হিসাব
পাঠ ২০-এর ধাপগুলো একত্র করে (আপস্ট্রিম গ্রেডিয়েন্ট × লোকাল গ্রেডিয়েন্ট, প্রতিটি নোডে), সম্পূর্ণ ব্যাকওয়ার্ড পাসটি একটি টেবিলে সাজানো যাক:
| গ্রেডিয়েন্ট | সূত্র | মান |
|---|---|---|
| $\partial L/\partial \hat{y}$ | $2(\hat{y}-y)$ | $2(1.0) = 2.0$ |
| $\partial L/\partial w_3$ | $\dfrac{\partial L}{\partial \hat{y}}\cdot h$ | $2.0\times 0.5 = 1.0$ |
| $\partial L/\partial b_2$ | $\dfrac{\partial L}{\partial \hat{y}}\cdot 1$ | $2.0$ |
| $\partial L/\partial h$ | $\dfrac{\partial L}{\partial \hat{y}}\cdot w_3$ | $2.0\times 2.0 = 4.0$ |
| $\partial L/\partial z_1$ | $\dfrac{\partial L}{\partial h}\cdot h(1-h)$ | $4.0\times 0.25 = 1.0$ |
| $\partial L/\partial w_1$ | $\dfrac{\partial L}{\partial z_1}\cdot x_1$ | $1.0\times 1.0 = 1.0$ |
| $\partial L/\partial w_2$ | $\dfrac{\partial L}{\partial z_1}\cdot x_2$ | $1.0\times 2.0 = 2.0$ |
| $\partial L/\partial b_1$ | $\dfrac{\partial L}{\partial z_1}\cdot 1$ | $1.0$ |
সংক্ষেপে — পাঁচটি প্যারামিটারের গ্রেডিয়েন্ট: $\partial L/\partial w_1 = 1.0$, $\partial L/\partial w_2 = 2.0$, $\partial L/\partial b_1 = 1.0$, $\partial L/\partial w_3 = 1.0$, $\partial L/\partial b_2 = 2.0$।
৪ · NumPy-তে যাচাই — কোড ও হাতে-হিসাব মেলানো
নিচের কোডে আমরা ফরওয়ার্ড পাস, তারপর ব্যাকওয়ার্ড পাস — দুটোই একসাথে বাস্তবায়ন করছি, এবং প্রতিটি প্রিন্ট স্টেটমেন্টের পাশে উপরের টেবিলের সেই সংখ্যাটি মন্তব্য হিসেবে লেখা আছে যাতে সরাসরি মিলিয়ে দেখা যায়।
import numpy as np
# ---- ইনপুট ও প্যারামিটার (পাঠ ১৯-এর মতোই অপরিবর্তিত) ----
x1, x2 = 1.0, 2.0
y = 0.0
w1, w2, b1 = 0.5, -0.5, 0.5
w3, b2 = 2.0, 0.0
def sigmoid(x):
return 1.0 / (1.0 + np.exp(-x))
# ---- ফরওয়ার্ড পাস ----
z1 = w1 * x1 + w2 * x2 + b1 # আশা করি: 0.0
h = sigmoid(z1) # আশা করি: 0.5
yhat = w3 * h + b2 # আশা করি: 1.0
L = (yhat - y) ** 2 # আশা করি: 1.0
print("ফরওয়ার্ড পাস:")
print(f" z1={z1}, h={h}, yhat={yhat}, L={L}")
# ---- ব্যাকওয়ার্ড পাস ----
dL_dyhat = 2 * (yhat - y) # আশা করি: 2.0
dL_dw3 = dL_dyhat * h # আশা করি: 1.0
dL_db2 = dL_dyhat * 1.0 # আশা করি: 2.0
dL_dh = dL_dyhat * w3 # আশা করি: 4.0
dL_dz1 = dL_dh * h * (1 - h) # আশা করি: 1.0
dL_dw1 = dL_dz1 * x1 # আশা করি: 1.0
dL_dw2 = dL_dz1 * x2 # আশা করি: 2.0
dL_db1 = dL_dz1 * 1.0 # আশা করি: 1.0
print("\nব্যাকওয়ার্ড পাস (গ্রেডিয়েন্ট):")
print(f" dL/dw1={dL_dw1}, dL/dw2={dL_dw2}, dL/db1={dL_db1}")
print(f" dL/dw3={dL_dw3}, dL/db2={dL_db2}")
# ---- sanity check: finite-difference দিয়ে স্বাধীনভাবে যাচাই ----
def loss(w1, w2, b1, w3, b2):
z1 = w1 * x1 + w2 * x2 + b1
h = sigmoid(z1)
yhat = w3 * h + b2
return (yhat - y) ** 2
eps = 1e-6
base = loss(w1, w2, b1, w3, b2)
fd_w1 = (loss(w1 + eps, w2, b1, w3, b2) - base) / eps
print("\nfinite-difference দিয়ে dL/dw1 ≈", fd_w1, "(হাতে-হিসাবের সাথে তুলনা করুন)")
z1=0.0, h=0.5, yhat=1.0, L=1.0 এবং dL/dw1=1.0, dL/dw2=2.0, dL/db1=1.0,
dL/dw3=1.0, dL/db2=2.0) উপরের দুটো টেবিলের সাথে প্রতিটি সংখ্যায় মিলে যায়। এটাই এই
মডিউলের সবচেয়ে গুরুত্বপূর্ণ যাচাই-বিন্দু — হাতে করা ডেরিভেশন ও কোড একই গণিত বাস্তবায়ন করছে তার প্রমাণ।
শেষ লাইনের finite-difference যাচাই একটি সম্পূর্ণ স্বতন্ত্র পদ্ধতি (লিমিট সংজ্ঞা, পাঠ ১৩) দিয়ে একই উত্তর
নিশ্চিত করে — তিনটি ভিন্ন পদ্ধতি (হাতে চেইন রুল, কোডে চেইন রুল, সংখ্যাগত আনুমানিক) একই জায়গায় মিলছে।
৫ · একটি গ্রেডিয়েন্ট ডিসেন্ট স্টেপ (পাঠ ১৭-এর প্রয়োগ)
পাঠ ১৭-এ দেখেছিলাম, আপডেট নিয়ম $\theta_{new} = \theta - \eta\,\partial L/\partial\theta$ প্রতিটি প্যারামিটারকে গ্রেডিয়েন্টের বিপরীত দিকে সরিয়ে লস কমায়। লার্নিং রেট $\eta=0.1$ ধরে আমাদের পাঁচটি প্যারামিটারে প্রয়োগ করি:
$w_1^{new} = 0.5 - 0.1(1.0) = 0.4$ · $w_2^{new} = -0.5 - 0.1(2.0) = -0.7$ · $b_1^{new} = 0.5 - 0.1(1.0) = 0.4$ · $w_3^{new} = 2.0 - 0.1(1.0) = 1.9$ · $b_2^{new} = 0.0 - 0.1(2.0) = -0.2$
এই নতুন প্যারামিটারে আবার ফরওয়ার্ড পাস চালালে:
$z_1^{new} = 0.4(1.0)+(-0.7)(2.0)+0.4 = -0.6$ → $h^{new}=\sigma(-0.6)\approx 0.3543$ → $\hat{y}^{new}=1.9(0.3543)+(-0.2)\approx 0.4732$ → $L^{new}=(0.4732-0)^2\approx 0.2240$
একটিমাত্র গ্রেডিয়েন্ট ডিসেন্ট স্টেপের পরই লস $1.0$ থেকে কমে $\approx 0.224$-এ নেমে এসেছে — অর্থাৎ প্রায় ৭৮% হ্রাস। এটাই ব্যাকপ্রপাগেশনের পুরো উদ্দেশ্য: প্রতিটি প্যারামিটারের সাপেক্ষে গ্রেডিয়েন্ট বের করে, সেই দিকে ছোট ছোট স্টেপ নিয়ে, লসকে ধারাবাহিকভাবে কমিয়ে আনা। একটি বাস্তব প্রশিক্ষণ লুপ এই একই ধাপ হাজার হাজার বার পুনরাবৃত্তি করে।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ যদি কোডের আউটপুট হাতে-হিসাবের সাথে না মিলত, ডিবাগ করার সবচেয়ে কার্যকর পদ্ধতি কী হতো?
সবার আগে ফরওয়ার্ড পাসের মান (z1, h, yhat, L) মিলছে কি না দেখতে হবে — যদি সেখানেই অমিল থাকে,
সমস্যা ব্যাকপ্রপে নয়, ফরওয়ার্ড গণনায়। ফরওয়ার্ড মিললে তারপর ব্যাকওয়ার্ড পাসের প্রতিটি ধাপ একে একে
(গ্রাফের শেষ থেকে শুরুর দিকে) মিলিয়ে দেখতে হবে — যেই ধাপে প্রথম অমিল দেখা যাবে, ভুলটি ঠিক সেই লোকাল
গ্রেডিয়েন্টের সূত্রে বা তার আগের আপস্ট্রিম গ্রেডিয়েন্টে। এই "ধাপে ধাপে মিলিয়ে দেখা" পদ্ধতিটিই বাস্তব
ডিপ লার্নিং কোডেও gradient-checking নামে ব্যবহৃত হয়।
প্র ০২ finite-difference পদ্ধতি (কোডের শেষ অংশ) থাকতে হাতে চেইন রুল ডেরাইভ করার দরকার কী?
finite difference প্রতিটি প্যারামিটারের জন্য একটি আলাদা ফরওয়ার্ড পাস চালানো লাগে (এখানে ৫টি প্যারামিটার মানে ৫টি অতিরিক্ত ফরওয়ার্ড পাস) — একটি বাস্তব নেটওয়ার্কে লক্ষ কোটি প্যারামিটারের জন্য এটি ভয়াবহ ধীর। ব্যাকপ্রপাগেশন মাত্র একটি ফরওয়ার্ড ও একটি ব্যাকওয়ার্ড পাসে সব গ্রেডিয়েন্ট একসাথে বের করে ফেলে — তাই এটিই বাস্তবে ব্যবহৃত হয়, আর finite difference শুধু debugging/sanity-check-এর জন্য ব্যবহৃত হয়, যেমন আমরা এখানে করেছি।
প্র ০৩ একাধিক গ্রেডিয়েন্ট ডিসেন্ট স্টেপ চালালে লস কি প্রতিবার একইভাবে (৭৮% হারে) কমতে থাকবে?
না। যত লস তার সর্বনিম্ন মানের কাছাকাছি যাবে, গ্রেডিয়েন্টের মান ছোট হতে থাকবে (পাঠ ২০-এর অনুশীলন ২ দেখুন, যেখানে $\hat{y}=y$ হলে গ্রেডিয়েন্ট শূন্য হয়ে যায়), ফলে প্রতিটি পরবর্তী স্টেপের প্রভাব ক্রমশ ছোট হবে। এই কারণেই ট্রেনিং কার্ভ সাধারণত শুরুতে দ্রুত নামে, তারপর ধীরে ধীরে সমতল হয়ে আসে — যা পাঠ ১৭-এর গ্রেডিয়েন্ট ডিসেন্ট কনভার্জেন্স আচরণের সাথে সামঞ্জস্যপূর্ণ।
অনুশীলন
-
কোড চালান ও মেলান: উপরের code cell Run করুন এবং নিশ্চিত করুন প্রতিটি প্রিন্ট হওয়া সংখ্যা
এই পাঠের দুটো টেবিলের সাথে হুবহু মেলে।
ফরওয়ার্ড: z1=0.0, h=0.5, yhat=1.0, L=1.0। ব্যাকওয়ার্ড: dL/dw1=1.0, dL/dw2=2.0, dL/db1=1.0, dL/dw3=1.0, dL/db2=2.0। finite-difference মান ≈ 1.0000... (হাতে-হিসাবের সাথে প্রায় হুবহু, সামান্য floating-point পার্থক্যসহ)।
-
নিজে গণনা করুন: $\eta=0.5$ (আরও বড় লার্নিং রেট) ব্যবহার করলে নতুন প্যারামিটারগুলো কী হতো,
এবং নতুন লস কি $\eta=0.1$-এর চেয়ে কম না বেশি হবে বলে আপনার ধারণা?
$w_1^{new}=0.5-0.5(1.0)=0.0$, $w_2^{new}=-0.5-0.5(2.0)=-1.5$, $b_1^{new}=0.5-0.5(1.0)=0.0$, $w_3^{new}=2.0-0.5(1.0)=1.5$, $b_2^{new}=0.0-0.5(2.0)=-1.0$। এই বড় স্টেপ নেওয়ার ফলে লস হয়তো আরও কমতে পারে, অথবা পাঠ ১৭-এর সতর্কতা অনুযায়ী খুব বড় $\eta$ ওভারশুট করে লস বাড়িয়েও দিতে পারে — সঠিক উত্তর পেতে কোডে বসিয়ে ফরওয়ার্ড পাস চালিয়ে দেখাই সবচেয়ে নির্ভরযোগ্য উপায়।
-
সম্প্রসারণ করুন: যদি একটি দ্বিতীয় ডেটা পয়েন্ট ($x_1', x_2', y'$) যোগ করা হতো, ব্যাকপ্রপাগেশনের
মৌলিক পদ্ধতিতে কী বদলাত?
পদ্ধতি অপরিবর্তিত থাকত — শুধু প্রতিটি ডেটা পয়েন্টের জন্য আলাদাভাবে ফরওয়ার্ড ও ব্যাকওয়ার্ড পাস চালিয়ে গ্রেডিয়েন্ট বের করে, সাধারণত সব ডেটা পয়েন্টের গ্রেডিয়েন্টের গড় (mean) নিয়ে একটি একক আপডেট করা হয় — এটাই ব্যাচ (batch) গ্রেডিয়েন্ট ডিসেন্টের ভিত্তি, যা ML কোর্সে বিস্তারিত আসবে।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পাঠ ২২ — অটোমেটিক ডিফারেনশিয়েশন, PyTorch autograd পরবর্তী পাঠ দেখুন কীভাবে PyTorch-এর মতো ফ্রেমওয়ার্ক এই একই ব্যাকওয়ার্ড পাস স্বয়ংক্রিয়ভাবে চালায়।
- সব AI Courses দেখুন ABCL TECH AI Foundations, Python for AI, Machine Learning, Deep Learning, Math for AI ও আরও অনেক কিছু — সব এক জায়গায়।
- Deep Learning কোর্স প্রয়োগ দেখুন এই হাতে-করা ব্যাকপ্রপাগেশন বাস্তবে বহু-লেয়ার নেটওয়ার্কে কীভাবে স্কেল করে তা দেখতে।