Momentum, RMSProp ও Adam — আধুনিক অপ্টিমাইজারের গণিত
এই পাঠে যা শিখবেন
- ভ্যানিলা গ্রেডিয়েন্ট ডিসেন্টের ঠিক কোন সীমাবদ্ধতাগুলো Momentum, RMSProp ও Adam সমাধান করতে চায়
- Momentum, RMSProp ও Adam-এর সম্পূর্ণ আপডেট সূত্র, প্রতিটি পদের অর্থসহ
- বায়াস কারেকশন কেন দরকার এবং এটি সংখ্যাগতভাবে কী প্রভাব ফেলে
- NumPy-তে তিনটি অপ্টিমাইজারই বাস্তবায়ন করে একটি সাধারণ ফাংশনে তাদের আচরণ পর্যবেক্ষণ করা
১ · ভ্যানিলা গ্রেডিয়েন্ট ডিসেন্টের সীমাবদ্ধতা
পাঠ ১৭-তে আমরা দেখেছিলাম আপডেট নিয়ম $\mathbf{x}_{t+1} = \mathbf{x}_t - \eta\nabla f(\mathbf{x}_t)$ কেন কাজ করে। কিন্তু এই সরল নিয়মের দুটি বাস্তব সমস্যা আছে। প্রথমত, যদি লস-ফাংশনের পৃষ্ঠতল একটি সরু "রেভিন" (ravine) — কোনো দিকে খুব খাড়া, অন্য দিকে খুব সমতল — হয়, তাহলে একটিমাত্র $\eta$ দিয়ে খাড়া দিকে স্থিতিশীল থাকতে গেলে সমতল দিকে অগ্রগতি অসম্ভব রকম ধীর হয়ে যায়। দ্বিতীয়ত, একটি নেটওয়ার্কের ভিন্ন ভিন্ন প্যারামিটারের গ্রেডিয়েন্টের স্কেল ভিন্ন হতে পারে — একই $\eta$ সবার জন্য উপযুক্ত নাও হতে পারে। নিচের তিনটি পদ্ধতি এই দুই সমস্যা সমাধানের চেষ্টা করে।
২ · Momentum — গ্রেডিয়েন্টের এক্সপোনেনশিয়াল মুভিং এভারেজ
Momentum প্রতিটি স্টেপে সরাসরি গ্রেডিয়েন্ট ব্যবহার না করে, একটি "বেগ" (velocity) ভেক্টর $\mathbf{v}$ জমা রাখে — বর্তমান গ্রেডিয়েন্ট ও অতীতের বেগের একটি এক্সপোনেনশিয়াল মুভিং এভারেজ:
$$ \mathbf{v}_t = \beta\,\mathbf{v}_{t-1} + \nabla f(\mathbf{x}_t) \qquad \mathbf{x}_{t+1} = \mathbf{x}_t - \eta\,\mathbf{v}_t $$
$\beta$ (সাধারণত $0.9$) নিয়ন্ত্রণ করে কতটা "স্মৃতি" রাখা হবে। যদি ধারাবাহিক কয়েকটি স্টেপে গ্রেডিয়েন্ট একই দিকে থাকে (একটি সমতল, দীর্ঘ ঢালে যেমন হয়), $\mathbf{v}$ সেই দিকে ক্রমশ বড় হতে থাকে — গতি তৈরি হয়। আবার যদি গ্রেডিয়েন্ট বারবার দিক পাল্টায় (একটি সরু রেভিনের খাড়া দিকে যেমন হয়), বিপরীতমুখী গ্রেডিয়েন্টগুলো $\mathbf{v}$-তে আংশিকভাবে একে অপরকে কাটাকাটি করে ফেলে — দোলন কিছুটা কমে।
৩ · RMSProp — প্রতি-প্যারামিটার অ্যাডাপটিভ লার্নিং রেট
RMSProp ভিন্ন সমস্যার সমাধান করে — প্রতিটি প্যারামিটারের নিজস্ব, স্বয়ংক্রিয়ভাবে সমন্বিত লার্নিং রেট থাকা। এটি গ্রেডিয়েন্টের স্কোয়ারের একটি এক্সপোনেনশিয়াল মুভিং এভারেজ $\mathbf{s}$ জমা রাখে:
$$ \mathbf{s}_t = \beta\,\mathbf{s}_{t-1} + (1-\beta)\big(\nabla f(\mathbf{x}_t)\big)^2 \qquad \mathbf{x}_{t+1} = \mathbf{x}_t - \frac{\eta}{\sqrt{\mathbf{s}_t}+\epsilon}\,\nabla f(\mathbf{x}_t) $$
(এখানে বর্গ ও বর্গমূল উপাদান-ভিত্তিক, এবং $\epsilon$ একটি ছোট সংখ্যা, যেমন $10^{-8}$, শূন্য দিয়ে ভাগ এড়াতে।) যে প্যারামিটারের গ্রেডিয়েন্ট বরাবরই বড় (বা খুব ওঠানামা করে), তার $\mathbf{s}$ বড় হবে, ফলে ভাগফলের কারণে সেই প্যারামিটারের কার্যকর স্টেপ ছোট হয়ে যাবে — খাড়া দিকে স্বয়ংক্রিয়ভাবে ব্রেক কষা। যে প্যারামিটারের গ্রেডিয়েন্ট সবসময় ছোট, তার $\mathbf{s}$ ছোট থাকে, ফলে সেই দিকে অপেক্ষাকৃত বড় স্টেপ নেওয়া হয় — সমতল দিকে দ্রুত এগোনো।
৪ · Adam — Momentum ও RMSProp-এর সমন্বয়, বায়াস কারেকশনসহ
Adam (Adaptive Moment Estimation) দুটো ধারণাই একসাথে ব্যবহার করে — গ্রেডিয়েন্টের প্রথম-মোমেন্ট (গড়, Momentum-এর $\mathbf{v}$-এর মতো, এখানে $\mathbf{m}$ নামে) ও দ্বিতীয়-মোমেন্ট (স্কোয়ার্ড গড়, RMSProp-এর $\mathbf{s}$-এর মতো) দুটোই এক্সপোনেনশিয়াল মুভিং এভারেজ হিসেবে জমা রাখে:
$$ \mathbf{m}_t = \beta_1\mathbf{m}_{t-1} + (1-\beta_1)\nabla f(\mathbf{x}_t) \qquad \mathbf{v}_t = \beta_2\mathbf{v}_{t-1} + (1-\beta_2)\big(\nabla f(\mathbf{x}_t)\big)^2 $$
শুরুর কয়েকটি স্টেপে $\mathbf{m}_0=\mathbf{v}_0=0$ হওয়ায় $\mathbf{m}_t,\mathbf{v}_t$ শূন্যের দিকে পক্ষপাতদুষ্ট (biased) থাকে — বিশেষত যখন $\beta_1,\beta_2$ (সাধারণত $0.9$ ও $0.999$) $1$-এর কাছাকাছি হয়। এই পক্ষপাত সংশোধন করতে বায়াস কারেকশন প্রয়োগ করা হয়:
$$ \hat{\mathbf{m}}_t = \frac{\mathbf{m}_t}{1-\beta_1^{t}} \qquad \hat{\mathbf{v}}_t = \frac{\mathbf{v}_t}{1-\beta_2^{t}} $$
এবং চূড়ান্ত আপডেট:
$$ \mathbf{x}_{t+1} = \mathbf{x}_t - \eta\,\frac{\hat{\mathbf{m}}_t}{\sqrt{\hat{\mathbf{v}}_t}+\epsilon} $$
৫ · কেন Adam ডিফল্ট অপ্টিমাইজার
Adam একসাথে Momentum-এর সুবিধা (ধারাবাহিক দিকের গ্রেডিয়েন্টে গতি বাড়ানো, সরু রেভিনে দোলন কমানো) ও RMSProp-এর সুবিধা (প্রতিটি প্যারামিটারের নিজস্ব স্কেল-সমন্বিত স্টেপ) একসাথে দেয়, প্লাস বায়াস কারেকশনের কারণে প্রশিক্ষণের একদম শুরুতেও স্থিতিশীলভাবে কাজ করে। এটি সাধারণত ডিফল্ট হাইপারপ্যারামিটারেই ($\eta=0.001$, $\beta_1=0.9$, $\beta_2=0.999$) বিভিন্ন ধরনের সমস্যায় ভালো কাজ করে — তাই বাস্তবে খুব কম টিউনিং দিয়ে একটি নির্ভরযোগ্য প্রথম পছন্দ হিসেবে ব্যবহৃত হয়।
তিনটি পদ্ধতিই একই ভিত্তির উপর দাঁড়িয়ে — ব্যাকপ্রপাগেশন (পাঠ ২০-২২) থেকে পাওয়া কাঁচা গ্রেডিয়েন্ট। পার্থক্য শুধু সেই গ্রেডিয়েন্ট দিয়ে কীভাবে স্টেপ নেওয়া হয়: সরাসরি (ভ্যানিলা GD), অতীতের গড় দিয়ে মসৃণ করে (Momentum), প্রতি-প্যারামিটার স্কেল সমন্বয় করে (RMSProp), অথবা দুটোই একসাথে, পক্ষপাত সংশোধনসহ (Adam)।
নিচের কোডে তিনটি পদ্ধতিই $f(x)=x^2$ (গ্রেডিয়েন্ট $f'(x)=2x$) ফাংশনে $x_0=5.0$ থেকে শুরু করে বাস্তবায়ন করা হলো — প্রতিটি স্টেপের মান প্রিন্ট করে হাতে-হিসাব করা সংখ্যার সাথে মিলিয়ে দেখা যাবে।
import numpy as np
def grad(x):
return 2 * x
x0 = 5.0
steps = 5
# ---- ভ্যানিলা গ্রেডিয়েন্ট ডিসেন্ট ----
print("ভ্যানিলা GD (eta=0.05):")
x = x0
for t in range(1, steps + 1):
x = x - 0.05 * grad(x)
print(f" t={t}: x={x:.6f}")
# ---- Momentum ----
print("\nMomentum (eta=0.05, beta=0.9):")
x, v = x0, 0.0
for t in range(1, steps + 1):
g = grad(x)
v = 0.9 * v + g
x = x - 0.05 * v
print(f" t={t}: g={g:.4f}, v={v:.4f}, x={x:.6f}")
# ---- RMSProp ----
print("\nRMSProp (eta=0.1, beta=0.9, eps=1e-8):")
x, s = x0, 0.0
for t in range(1, steps + 1):
g = grad(x)
s = 0.9 * s + 0.1 * g ** 2
x = x - 0.1 * g / (np.sqrt(s) + 1e-8)
print(f" t={t}: g={g:.4f}, s={s:.4f}, x={x:.6f}")
# ---- Adam ----
print("\nAdam (eta=0.1, beta1=0.9, beta2=0.999, eps=1e-8):")
x, m, v = x0, 0.0, 0.0
for t in range(1, steps + 1):
g = grad(x)
m = 0.9 * m + 0.1 * g
v = 0.999 * v + 0.001 * g ** 2
m_hat = m / (1 - 0.9 ** t)
v_hat = v / (1 - 0.999 ** t)
x = x - 0.1 * m_hat / (np.sqrt(v_hat) + 1e-8)
print(f" t={t}: g={g:.4f}, m_hat={m_hat:.4f}, v_hat={v_hat:.4f}, x={x:.6f}")
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ Momentum-এ $\beta=0$ বসালে কী হবে? এটি কি পরিচিত কোনো পদ্ধতিতে পরিণত হয়?
$\beta=0$ হলে $\mathbf{v}_t = 0\cdot\mathbf{v}_{t-1} + \nabla f(\mathbf{x}_t) = \nabla f(\mathbf{x}_t)$ — অর্থাৎ কোনো "স্মৃতি" থাকে না, প্রতিটি স্টেপ শুধু বর্তমান গ্রেডিয়েন্টের উপর নির্ভর করে। এটি ঠিক পাঠ ১৭-এর ভ্যানিলা গ্রেডিয়েন্ট ডিসেন্টের সমতুল্য হয়ে যায় — Momentum আসলে ভ্যানিলা GD-এর একটি সাধারণীকরণ, $\beta$ বাড়ালে ধীরে ধীরে আগের গ্রেডিয়েন্টের প্রভাব যোগ হতে থাকে।
প্র ০২ RMSProp-এ $\epsilon$ (এপসিলন) না থাকলে কী সমস্যা হতে পারত?
যদি কোনো প্যারামিটারের গ্রেডিয়েন্ট বহুবার শূন্যের খুব কাছাকাছি থাকে, তাহলে $\mathbf{s}_t$ প্রায় শূন্য হয়ে যাবে, এবং আপডেট সূত্রে $\sqrt{\mathbf{s}_t}$ দিয়ে ভাগ করার সময় শূন্য দিয়ে ভাগের সমস্যা (বা সংখ্যাগতভাবে অস্থির, বিশাল স্টেপ) তৈরি হতো। $\epsilon$ (যেমন $10^{-8}$) হর-কে সবসময় শূন্যের চেয়ে সামান্য বড় রেখে এই সমস্যা প্রতিরোধ করে, অথচ এত ছোট যে বড় $\mathbf{s}_t$-এর ক্ষেত্রে হিসাবে কার্যত কোনো প্রভাব ফেলে না।
প্র ০৩ বায়াস কারেকশন ছাড়া Adam ব্যবহার করলে প্রশিক্ষণের প্রথম কয়েকটি স্টেপে কী সমস্যা হতো?
বায়াস কারেকশন ছাড়া, শুরুতে $\mathbf{m}_0=\mathbf{v}_0=0$ হওয়ায় $\mathbf{m}_1=(1-\beta_1)g_1$ ও $\mathbf{v}_1=(1-\beta_2)g_1^2$ — উভয়ই তাদের "প্রকৃত" মানের চেয়ে অনেক ছোট (বিশেষত $\mathbf{v}_1$, কারণ $1-\beta_2=0.001$ অত্যন্ত ছোট একটি ফ্যাক্টর)। এর ফলে প্রথম কয়েকটি আপডেট অস্বাভাবিকভাবে ছোট বা বিকৃত হতো, প্রশিক্ষণের একদম শুরুতে অপ্টিমাইজারকে কার্যত অকার্যকর করে দিত। বায়াস কারেকশন এই সমস্যা ঠিক করে দেয় ঠিক আমাদের কোড আউটপুটে ($t=1$-এ আপডেট সাইজ প্রায় $\eta$-এর সমান দেখা) যেমনটা দেখা গেছে।
অনুশীলন
-
কোড চালান ও মিলিয়ে দেখুন: উপরের code cell Run করুন এবং Momentum-এর $t=1$ থেকে $t=3$
পর্যন্ত মান এই পাঠের নোটে হাতে-হিসাব করা মানের ($x=4.5, 3.6, 2.43$) সাথে মেলে কি না দেখুন।
কোডের আউটপুটে t=1: x=4.500000, t=2: x=3.600000, t=3: x=2.430000 আসা উচিত — উপরের নোটের সাথে হুবহু মেলে।
-
নিজে গণনা করুন: RMSProp-এ $t=1$-এ $g=10$, তাহলে $s_1$ ও প্রথম আপডেট সাইজ (eta=0.1,
beta=0.9) হাতে হিসাব করুন।
$s_1 = 0.9(0)+0.1(10)^2 = 10$। আপডেট $= 0.1\times 10/(\sqrt{10}+\epsilon) \approx 1/3.1623 \approx 0.3162$। নতুন $x = 5.0 - 0.3162 \approx 4.6838$ — কোডের আউটপুটের সাথে মেলে।
-
পরীক্ষা করুন: কোডে
steps-এর মান বাড়িয়ে (যেমন ৩০) Run করুন — তিনটি পদ্ধতিই শেষ পর্যন্ত $x=0$-এর কাছাকাছি পৌঁছায় কি না লক্ষ করুন।তিনটি পদ্ধতিই $f(x)=x^2$-এর একমাত্র মিনিমা $x=0$-এর দিকেই এগোবে, যদিও পথ ও গতি ভিন্ন — Momentum দোলন করে দ্রুত কাছাকাছি পৌঁছাতে পারে, RMSProp/Adam ধারাবাহিকভাবে ছোট হতে থাকা স্টেপে অগ্রসর হয়। এই সাধারণ ১D উদাহরণে সব পদ্ধতিই একই মিনিমাম খুঁজে পায় — পার্থক্যটা মূলত গতিতে ও উচ্চ-মাত্রিক, অসম-বাঁকা (ill-conditioned) পৃষ্ঠতলে বেশি স্পষ্ট হয়।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পাঠ ২৪ — সম্ভাবনার স্বতঃসিদ্ধ ও শর্তাধীন সম্ভাবনা পরবর্তী পাঠ মডিউল ৬-এ প্রবেশ — এখন থেকে আমরা সম্ভাবনা তত্ত্বের ভিত্তি দিয়ে অনিশ্চয়তা ও লস ফাংশনের গাণিতিক শিকড় বুঝব।
- সব AI Courses দেখুন ABCL TECH AI Foundations, Python for AI, Machine Learning, Deep Learning, Math for AI ও আরও অনেক কিছু — সব এক জায়গায়।
-
Deep Learning কোর্স প্রয়োগ দেখুন
PyTorch-এ
torch.optim.Adam-এর মতো অপ্টিমাইজার বাস্তবে কীভাবে ব্যবহৃত হয় তা দেখতে।