পাঠ ২৩ · ৩৫-এর মধ্যে · মডিউল ৫
Home / AI Courses / Math for AI & ML / Momentum, RMSProp, Adam

Momentum, RMSProp ও Adam — আধুনিক অপ্টিমাইজারের গণিত

Momentum, RMSProp & Adam — the math of modern optimizers
১৪ মিনিট পড়া উন্নত · Advanced NumPy কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • ভ্যানিলা গ্রেডিয়েন্ট ডিসেন্টের ঠিক কোন সীমাবদ্ধতাগুলো 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}$-তে আংশিকভাবে একে অপরকে কাটাকাটি করে ফেলে — দোলন কিছুটা কমে।

একটি বলকে পাহাড়ের গায়ে গড়িয়ে দেওয়ার কথা ভাবুন। বলটির নিজস্ব ভর ও গতিবেগ আছে — শুধু বর্তমান ঢালের দিকে নয়, তার আগের গতির দিকেও এটি এগোতে থাকে। এই কারণেই একটি সমতল অংশেও বলটি গতি হারায় না সহজে, আবার হঠাৎ দিক পরিবর্তনেও (রেভিনের দেয়ালে ধাক্কা খেয়ে) সম্পূর্ণ থেমে যায় না, বরং একটু কেঁপে এগিয়ে চলে। $\beta$ হলো সেই বলের "ভরের" মতো — বেশি $\beta$ মানে বেশি জড়তা (inertia)।

৩ · 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} $$

$t=1$-এ $1-\beta_1^1 = 1-0.9 = 0.1$ ও $1-\beta_2^1=1-0.999=0.001$ — খুব ছোট হর, তাই $\hat{\mathbf{m}}_1, \hat{\mathbf{v}}_1$ কাঁচা $\mathbf{m}_1,\mathbf{v}_1$-এর তুলনায় অনেক বড় হয়ে যায় (পক্ষপাত সংশোধন)। $t$ বড় হতে থাকলে $\beta_1^t,\beta_2^t \to 0$, তাই $\hat{\mathbf{m}}_t\to\mathbf{m}_t$ ও $\hat{\mathbf{v}}_t\to\mathbf{v}_t$ — সংশোধনের প্রভাব ধীরে ধীরে মিলিয়ে যায়।

৫ · কেন Adam ডিফল্ট অপ্টিমাইজার

Adam একসাথে Momentum-এর সুবিধা (ধারাবাহিক দিকের গ্রেডিয়েন্টে গতি বাড়ানো, সরু রেভিনে দোলন কমানো) ও RMSProp-এর সুবিধা (প্রতিটি প্যারামিটারের নিজস্ব স্কেল-সমন্বিত স্টেপ) একসাথে দেয়, প্লাস বায়াস কারেকশনের কারণে প্রশিক্ষণের একদম শুরুতেও স্থিতিশীলভাবে কাজ করে। এটি সাধারণত ডিফল্ট হাইপারপ্যারামিটারেই ($\eta=0.001$, $\beta_1=0.9$, $\beta_2=0.999$) বিভিন্ন ধরনের সমস্যায় ভালো কাজ করে — তাই বাস্তবে খুব কম টিউনিং দিয়ে একটি নির্ভরযোগ্য প্রথম পছন্দ হিসেবে ব্যবহৃত হয়।

মূল কথা · Key takeaway

তিনটি পদ্ধতিই একই ভিত্তির উপর দাঁড়িয়ে — ব্যাকপ্রপাগেশন (পাঠ ২০-২২) থেকে পাওয়া কাঁচা গ্রেডিয়েন্ট। পার্থক্য শুধু সেই গ্রেডিয়েন্ট দিয়ে কীভাবে স্টেপ নেওয়া হয়: সরাসরি (ভ্যানিলা GD), অতীতের গড় দিয়ে মসৃণ করে (Momentum), প্রতি-প্যারামিটার স্কেল সমন্বয় করে (RMSProp), অথবা দুটোই একসাথে, পক্ষপাত সংশোধনসহ (Adam)।

নিচের কোডে তিনটি পদ্ধতিই $f(x)=x^2$ (গ্রেডিয়েন্ট $f'(x)=2x$) ফাংশনে $x_0=5.0$ থেকে শুরু করে বাস্তবায়ন করা হলো — প্রতিটি স্টেপের মান প্রিন্ট করে হাতে-হিসাব করা সংখ্যার সাথে মিলিয়ে দেখা যাবে।

Python · NumPy
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-এর ট্রেস হাতে মিলিয়ে দেখুন — $t=1$: $g=10, v=10, x=5-0.05(10)=4.5$; $t=2$: $g=2(4.5)=9, v=0.9(10)+9=18, x=4.5-0.05(18)=3.6$; এভাবে $t=5$-এ $x\approx -0.146$-এ পৌঁছায় — শূন্য অতিক্রম করে গেছে, কারণ জমে থাকা গতি (velocity) থামার আগেই ওভারশুট করে ফেলেছে। তুলনায় একই $\eta$-তে ভ্যানিলা GD $t=5$-এ মাত্র $x\approx 2.95$-এ পৌঁছায় — অর্থাৎ Momentum এখানে অনেক দ্রুত শূন্যের কাছাকাছি পৌঁছেছে, যদিও একটু ওভারশুট করে।
Adam-এর প্রথম কয়েকটি স্টেপে লক্ষ করুন — বায়াস-কারেক্টেড আপডেট সাইজ প্রায় ঠিক $\eta=0.1$-এর সমান থাকে (কারণ প্রাথমিক অবস্থায় $\hat{\mathbf{v}}_t \approx g_t^2$, ফলে $\hat{\mathbf{m}}_t/\sqrt{\hat{\mathbf{v}}_t} \approx \text{sign}(g_t)$)। এটি ইচ্ছাকৃত নকশা — Adam শুরুতে গ্রেডিয়েন্টের বিশাল ম্যাগনিটিউডের তোয়াক্কা না করে একটি অনুমানযোগ্য, স্থিতিশীল স্টেপ সাইজ দিয়ে শুরু করে। এটিকে ভুল করে "গ্রেডিয়েন্ট উপেক্ষা করা হচ্ছে" মনে করবেন না — এটি বায়াস কারেকশনের প্রত্যাশিত ও সঠিক আচরণ।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ 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$-এর সমান দেখা) যেমনটা দেখা গেছে।

অনুশীলন

  1. কোড চালান ও মিলিয়ে দেখুন: উপরের 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 আসা উচিত — উপরের নোটের সাথে হুবহু মেলে।

  2. নিজে গণনা করুন: 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$ — কোডের আউটপুটের সাথে মেলে।

  3. পরীক্ষা করুন: কোডে steps-এর মান বাড়িয়ে (যেমন ৩০) Run করুন — তিনটি পদ্ধতিই শেষ পর্যন্ত $x=0$-এর কাছাকাছি পৌঁছায় কি না লক্ষ করুন।

    তিনটি পদ্ধতিই $f(x)=x^2$-এর একমাত্র মিনিমা $x=0$-এর দিকেই এগোবে, যদিও পথ ও গতি ভিন্ন — Momentum দোলন করে দ্রুত কাছাকাছি পৌঁছাতে পারে, RMSProp/Adam ধারাবাহিকভাবে ছোট হতে থাকা স্টেপে অগ্রসর হয়। এই সাধারণ ১D উদাহরণে সব পদ্ধতিই একই মিনিমাম খুঁজে পায় — পার্থক্যটা মূলত গতিতে ও উচ্চ-মাত্রিক, অসম-বাঁকা (ill-conditioned) পৃষ্ঠতলে বেশি স্পষ্ট হয়।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

পূর্ববর্তী পাঠ
অটোমেটিক ডিফারেনশিয়েশন — PyTorch autograd