Chapter 12 of 28
Choosing how a network descends its loss landscape
ব্যাকপ্রোপাগেশন (চ্যাপ্টার ৮) একটি নেটওয়ার্ককে সুনির্দিষ্টভাবে বলে দেয় যে লস কমানোর জন্য প্রতিটি ওজনকে (weight) ঠিক কোন দিকে সরানো উচিত। কিন্তু এটি ওজনকে কতটুকু সরাতে হবে সে সম্পর্কে কিছুই বলে না। আবার একটি বাস্তব CNN-এর লস ল্যান্ডস্কেপ (loss landscape) কিন্তু সমতল নয়, এটি অত্যন্ত খাড়া, বহুমাত্রিক এবং খানাখন্দ, মালভূমি ও অসংখ্য নয়েজে ভরা একটি অসম তল। এই লস ল্যান্ডস্কেপ পাড়ি দেওয়ার কাজই হলো অপ্টিমাইজারের (optimizer) — যা প্রতিটি ধাপে গ্রেডিয়েন্টকে একটি বাস্তব ওয়েট আপডেটে রূপান্তর করে, যতক্ষণ না লস কমা বন্ধ হয়।
সরাসরি বা সাধারণ নিয়ম "লার্নিং রেট দিয়ে গুণ করে গ্রেডিয়েন্ট বিয়োগ করা" কাজ করে ঠিকই, কিন্তু এটি বেশ নাজুক: পদক্ষেপ সামান্য বড় হলে ট্রেনিং বিস্ফোরিত বা অস্থিতিশীল হয়ে যায়, আর পদক্ষেপ বেশি ছোট হলে ট্রেনিংয়ের গতি শামুকের মতো ধীর হয়ে যায়। এই চ্যাপ্টারের প্রতিটি অপ্টিমাইজারই মূলত এই লার্নিং রেট নামক বোতামটিকে আরও নমনীয় ও সহজ করার এক একটি চেষ্টা — যা পূর্ববর্তী গ্রেডিয়েন্ট মনে রেখে, প্রতিটি প্যারামিটারের পদক্ষেপের আকার আলাদাভাবে নিয়ন্ত্রণ করে অথবা উভয় পদ্ধতি একসাথে ব্যবহার করে কাজ করে।
কুয়াশাচ্ছন্ন পাহাড়ি পথ বেয়ে একটি উপত্যকার সবচেয়ে নিচু পয়েন্টে পৌঁছানোর চেষ্টা করছেন এমন একজন হাইকারের কথা কল্পনা করুন, যিনি শুধু নিজের পায়ের নিচের ঢালটুকু অনুভব করতে পারছেন। সাধারণ গ্রেডিয়েন্ট ডিসেন্ট হলো প্রতি মুহূর্তে ঠিক যে দিকে খাড়া ঢাল, সে দিকে একটি নির্দিষ্ট দৈর্ঘ্যের কদম ফেলা — এটি যৌক্তিক, তবে এটি সংকীর্ণ গিরিখাতগুলোতে খুব এলোমেলোভাবে আঁকাবাঁকা হয়ে চলে এবং সমতল জায়গায় এসে থমকে যায়। কিন্তু মোমেন্টাম বা গতিবেগ সম্পন্ন একজন হাইকার মনে রাখেন যে তিনি সামগ্রিকভাবে কোন দিকে হাঁটছিলেন, এবং সমতল বা সামান্য আঁকাবাঁকা জায়গায় এসেও সেই গতিবেগের কিছু অংশ কাজে লাগান, যা আঁকাবাঁকা পথকে মসৃণ করে। আবার Adam-এর মতো অ্যাডাপ্টিভ পদ্ধতি ব্যবহারকারী হাইকার আরও বুদ্ধিমান কাজ করেন: তিনি লক্ষ্য করেন কোন দিকগুলো অনবরত খাড়া ছিল এবং সেগুলোতে একটু ছোট ও সতর্ক পদক্ষেপ নেন, আর যে দিকগুলো মৃদু ও হালকা ছিল সেগুলোতে একটু বড় পদক্ষেপ নেন। এই চ্যাপ্টারের প্রতিটি অপ্টিমাইজারই মূলত কুয়াশাচ্ছন্ন পাহাড়ের নিচে নামার এক একটি ভিন্ন কৌশল।
সহজ কথা: প্রতিবার ওজনের সংশোধনের জন্য প্রথমে সম্পূর্ণ ট্রেনিং সেটের ওপর গ্রেডিয়েন্ট হিসাব করতে হয়। এর ফলে প্রাপ্ত দিকটি অত্যন্ত নিখুঁত হয় ঠিকই, কিন্তু খেলনা প্রজেক্টের চেয়ে বড় যেকোনো বাস্তব ডেটাসেটের জন্য এটি অবাস্তব রকমের ধীরগতির এবং প্রচুর মেমরি ব্যবহারকারী — আপনাকে লক্ষ লক্ষ ছবির ওপর দিয়ে একবার পুরো পাস করে মাত্র একটি পদক্ষেপ নিতে হবে।
সহজ কথা: ওপরের ব্যাচ গ্রডিয়েন্ট ডিসেন্টের ঠিক বিপরীত রূপ — যেখানে মাত্র একটি ট্রেনিং উদাহরণ দেখে সাথে সাথে ওজনকে আপডেট করা হয়। প্রতিটি পদক্ষেপের হিসাব করা খুবই সহজ ও দ্রুত, কিন্তু মাত্র একটি ছবি দেখে পাওয়া গ্রেডিয়েন্ট অনুমানটি নয়েজে ভরা থাকে, ফলে সর্বনিম্ন বিন্দুর দিকে যাওয়ার পথটি মসৃণ না হয়ে আঁকাবাঁকা ও এলোমেলো হয়।
সহজ কথা: একটি বাস্তবসম্মত মাঝামাঝি পথ — যেখানে একটি ছবি বা সম্পূর্ণ ডেটাসেটের বদলে একটি ছোট ব্যাচ (সাধারণত ৩২, ৬৪ বা ১২৮টি উদাহরণ) নিয়ে তার গ্রেডিয়েন্ট হিসাব করা হয়। আধুনিক প্রায় প্রতিটি ডিপ লার্নিং ফ্রেমওয়ার্ক বাস্তবে এটিই রান করে; যখন কোনো PyTorch টিউটোরিয়ালে "SGD" লেখা থাকে, তখন তার অর্থ প্রায় সবসময়ই মিনি-ব্যাচ SGD।
যেখানে: হলো জমে থাকা "গতিবেগ (velocity)," এবং নিয়ন্ত্রণ করে পূর্ববর্তী গতিবেগের কতটুকু অংশ বজায় থাকবে।
সহজ কথা: শুধুমাত্র বর্তমান গ্রেডিয়েন্টের ওপর ভিত্তি করে সিদ্ধান্ত নেওয়ার বদলে, Momentum পূর্ববর্তী গ্রেডিয়েন্টগুলোর একটি রানিং গড় বা গতিবেগ জমিয়ে রাখে — যেমন পাহাড় থেকে গড়িয়ে পড়া একটি বলের মতো যা ঢালের সামান্য পরিবর্তনেও তার গতিবেগের কারণে দিক বজায় রাখে। এটি সংকীর্ণ খাদের আঁকাবাঁকা কম্পন দূর করে এবং যেদিকে গ্রেডিয়েন্ট অনবরত একই ইঙ্গিত করছে সেদিকে গতি বাড়ায়।
সহজ কথা: RMSProp প্রতিটি প্যারামিটারের সাম্পতিক গ্রেডিয়েন্টের বর্গের (squared) একটি রানিং গড় বজায় রাখে, তারপর লার্নিং রেটকে সেই গড়ের বর্গমূল দিয়ে ভাগ করে। যে প্যারামিটারগুলোর গ্রেডিয়েন্ট খুব বড় ও অস্থির ছিল তাদের পদক্ষেপের আকার ছোট হয়ে যায়; আর যেগুলোর গ্রেডিয়েন্ট ছোট ও মৃদু ছিল তাদের পদক্ষেপের আকার বড় হয়ে যায়। এর ফলে প্রতিটি প্যারামিটার কার্যকরভাবে নিজস্ব অ্যাডাপ্টিভ লার্নিং রেট লাভ করে।
যেখানে: হলো প্রথম মোমেন্ট (gradient-এর Momentum-স্টাইল রানিং গড়), হলো দ্বিতীয় মোমেন্ট (RMSProp-স্টাইল স্কয়ার্ড গ্রেডিয়েন্টের রানিং গড়), এবং হলো উভয়ের বায়াস-কারেকশন বা সংশোধন রূপ — যা প্রয়োজন কারণ দুটিই শুরুতে শূন্য থেকে শুরু হয় এবং অন্যথায় প্রথম কয়েকটি পদ শূন্যের দিকে ঝুঁকে থাকবে। সাধারণ ডিফল্ট মান: , , ।
সহজ কথা: Adam হলো মূলত Momentum এবং RMSProp-এর সমন্বয় — এটি দিয়ে আপডেটের দিককে মসৃণ করে এবং দিয়ে প্রতি প্যারামিটারের পদক্ষেপের আকারকে মানানসই করে, তারপর শূন্য-ইনিশিয়ালাইজেশনের ত্রুটি সংশোধন করে। এর ফলে পাওয়া অপ্টিমাইজারটি অত্যন্ত দ্রুত, হাইপারপ্যারামিটারের ভুল নির্বাচনের ক্ষেত্রেও নমনীয় এবং আধুনিক প্রায় প্রতিটি CNN ট্রেনিংয়ের ডিফল্ট পছন্দ।
| অপ্টিমাইজার (Optimizer) | মূল আইডিয়া (Key Idea) | সুবিধাসমূহ (Pros) | অসুবিধাসমূহ (Cons) |
|---|---|---|---|
| Batch GD | সম্পূর্ণ ডেটাসেটের গ্রেডিয়েন্ট | স্থিতিশীল ও নিখুঁত দিক প্রদান করে | অত্যন্ত ধীরগতির, বিশাল মেমরি প্রয়োজন |
| SGD | একক উদাহরণের গ্রেডিয়েন্ট | খুব দ্রুত আপডেট হয়, অগভীর লোকাল মিনিমা এড়াতে পারে | অত্যন্ত এলোমেলো ও অস্থির পথ তৈরি করে |
| Mini-batch GD | ছোট ব্যাচের গ্রেডিয়েন্ট | গতি ও স্থিতিশীলতার চমৎকার ব্যালেন্স | ব্যাচ সাইজ একটি অতিরিক্ত হাইপারপ্যারামিটার |
| Momentum | গতিবেগ বা velocity টার্ম যোগ করে | দ্রুট কনভার্জ করে এবং আঁকাবাঁকা কম্পন কমায় | β-র মতো আরেকটি হাইপারপ্যারামিটার লাগে |
| RMSProp | প্যারামিটার প্রতি অ্যাডাপ্টিভ লার্নিং রেট | নয়েজি বা অস্থিতিশীল সমস্যার জন্য চমৎকার কাজ করে | লার্নিং রেট টিউনিংয়ের প্রয়োজন হতে পারে |
| Adam | Momentum + RMSProp + bias correction | অত্যন্ত দ্রুত, বিশ্বস্ত, বেশিরভাগ CNN-এর ডিফল্ট পছন্দ | কখনো কখনো নিখুঁত টিউন করা SGD+Momentum-এর চেয়ে সামান্য কম জেনারেলাইজ করতে পারে |

ধরুন, ধাপে কোনো একটি ওজনের গ্রেডিয়েন্ট , যেখানে শুরুতে , এবং সাধারণ ডিফল্ট মানগুলো হলো , , , ।
প্রথম মোমেন্ট: । দ্বিতীয় মোমেন্ট: ।
বায়াস কারেকশন: , এবং ।
লক্ষ্য করুন কীভাবে বায়াস কারেকশন ও -র শূন্য থেকে শুরু হওয়ার ত্রুটি দূর করে দিল — সংশোধনের পর সরাসরি raw গ্রেডিয়েন্টের সমান হয়ে গেল, যা একদম প্রথম পদক্ষেপের জন্য চমৎকার ও কাঙ্ক্ষিত।
আপডেট: । গ্রেডিয়েন্টের বিপরীত দিকে একটি চমৎকার সুশৃঙ্খল পদক্ষেপ।
import numpy as np
class AdamOptimizer:
def __init__(self, params_shape, lr=0.001, beta1=0.9, beta2=0.999, eps=1e-8):
self.lr, self.beta1, self.beta2, self.eps = lr, beta1, beta2, eps
self.m = np.zeros(params_shape)
self.v = np.zeros(params_shape)
self.t = 0
def step(self, w, grad):
self.t += 1
self.m = self.beta1 * self.m + (1 - self.beta1) * grad
self.v = self.beta2 * self.v + (1 - self.beta2) * (grad ** 2)
m_hat = self.m / (1 - self.beta1 ** self.t)
v_hat = self.v / (1 - self.beta2 ** self.t)
w -= self.lr * m_hat / (np.sqrt(v_hat) + self.eps)
return w
# Convergence যাচাই করার জন্য L(w) = (w - 3)^2 কোয়াড্রাটিক লস মিনিমাইজ করা
w = np.array([0.0])
optimizer = AdamOptimizer(params_shape=w.shape, lr=0.1)
for step in range(50):
grad = 2 * (w - 3.0) # dL/dw for L = (w - 3)^2
w = optimizer.step(w, grad)
print(f"চূড়ান্ত w (যা ৩.০ এর কাছাকাছি হওয়া উচিত): {w}")কোডটির কয়েকটি বিশেষ দিক লক্ষ্য করুন:
self.t এর মান ১ বাড়ানো হয়েছে — যাতে প্রথম পদক্ষেপ থেকেই হিসেবে শূন্য দিয়ে ভাগ হওয়া এড়ানো যায়।m এবং v এর মান প্রতিটি step কলের পরেও বজায় থাকে, যা PyTorch বা TensorFlow অপ্টিমাইজারের মতোই রানিং গড়গুলো ধরে রাখার জন্য চমৎকার কাজ করে।w ৩.০ এর দিকে ধাবিত না হয়, তবে বুঝতে হবে কোডে গন্ডগোল আছে।প্রোটোটাইপ বা শুরুর দিকে সবসময় Adam দিয়ে পরীক্ষা করুন — এটি খুব দ্রুত ও হাইপারপ্যারামিটারের ভুলগুলোর প্রতি সহনশীল। কিন্তু একদম চূড়ান্ত মডেলের সেরা অ্যাকুরেসি পাওয়ার জন্য SGD with Momentum এবং একটি লার্নিং রেট শিডিউলার দিয়ে ট্রাই করে দেখুন; এটি প্রায়শই Adam-এর চেয়ে সামান্য ভালো জেনারেলাইজ করতে সাহায্য করে।
ব্যাচ সাইজ ও ওজন বা parameters ম্যানেজমেন্টের বিষয় নয় — এটি সরাসরি গ্রেডিয়েন্ট নয়েজকে প্রভাবিত করে, যার ফলে মডেলের কনভার্জেন্স ও জেনারেলাইজেশন উভয়ের ওপরই বড় প্রভাব পড়ে। লার্নিং রেট না বদলিয়ে শুধু ব্যাচ সাইজ দ্বিগুণ করলে ট্রেনিংয়ের রূপ সম্পূর্ণ বদলে যেতে পারে।
Adam প্রোটোটাইপিংয়ের জন্য চমৎকার ও দ্রুত কাজ করে ঠিকই, তবে নিখুঁতভাবে টিউন করা SGD with Momentum এবং লার্নিং রেট শিডিউল অনেক ক্ষেত্রে চূড়ান্ত অ্যাকুরেসি ও জেনারেলাইজেশনের দিক থেকে Adam-কে ছাড়িয়ে যেতে পারে।
যেকোনো ডিপ লার্নিং লাইব্রেরি এই ছয়টি অপ্টিমাইজারই ডিফল্টভাবে অফার করে, এবং প্রজেক্ট কনফিগার করার সময় এটিই একদম প্রথম হাইপারপ্যারামিটারগুলোর একটি। প্রজেক্টের শুরুতে খুব দ্রুত একটি কাজ সম্পন্ন করার জন্য Adam বেছে নেওয়া হয়, এবং পরবর্তীতে চূড়ান্ত ফলাফলের কোয়ালিটি বাড়াতে SGD + Momentum এবং লার্নিং রেট শিডিউলিং দিয়ে ট্রাই করা হয়, যা উপরেও উল্লেখ করা হয়েছে।