অধ্যায় 3 · ক্যালকুলাস: মডেল কীভাবে শেখে
গ্রেডিয়েন্ট ডিসেন্ট: মডেল কীভাবে শেখে
- পৃষ্ঠা 7 / 17
- 4 মিনিট পড়া
যে মডেলের কথাই শুনেছেন — স্প্যাম ফিল্টার থেকে GPT — সবাই একইভাবে শেখে। এলোমেলো ওয়েট দিয়ে শুরু করুন। মডেল কতটা ভুল তা একটা লস সংখ্যা দিয়ে মাপুন। কোন দিকে গেলে লস কমে তা বের করুন (আগের পাতার ডেরিভেটিভ)। সেদিকে ছোট্ট একটা পা ফেলুন। আবার করুন। এটাই গ্রেডিয়েন্ট ডিসেন্ট।
নতুন ওয়েট = পুরোনো ওয়েট − লার্নিং রেট × গ্রেডিয়েন্টবিয়োগ চিহ্নটাই মূল: গ্রেডিয়েন্ট ওপরের দিক দেখায়, তাই উল্টো দিকে পা ফেলুন। লার্নিং রেট ঠিক করে প্রতিটা পা কত বড়।
একটা ওয়েট, তিনটা লার্নিং রেট
এখানে লস হলো (w − 3)², যা w = 3-এ সবচেয়ে ছোট। প্রতিটা রান w = 0 থেকে শুরু করে ২০টা ধাপ নেয়:
def loss(w):
return (w - 3) ** 2 # w = 3-এ সবচেয়ে ছোট
def gradient(w):
return 2 * (w - 3) # এর ডেরিভেটিভ
for learning_rate in [0.1, 0.01, 1.1]:
w = 0.0
for step in range(20):
w = w - learning_rate * gradient(w)
print(f"learning rate {learning_rate:<4}: w = {w:10.4f}, loss = {loss(w):.4f}")learning rate 0.1 : w = 2.9654, loss = 0.0012
learning rate 0.01: w = 0.9972, loss = 4.0113
learning rate 1.1 : w = -112.0128, loss = 13227.9441- 0.1 — ঠিকঠাক: ২০ ধাপে w প্রায় ৩-এ।
- 0.01 — খুব ছোট: ঠিক দিকে যাচ্ছে, কিন্তু মাত্র ১.০-এ পৌঁছেছে। পৌঁছাবে, খুব ধীরে।
- 1.1 — খুব বড়: প্রতিটা পা তলা পেরিয়ে যায়, প্রতিবার আরও দূরে, আর লস বিস্ফোরিত হয়। ট্রেনিং লস হঠাৎ বিশাল বা
nanহয়ে গেলে প্রথম সন্দেহ খুব বড় লার্নিং রেট।
শূন্য থেকে একটা আসল মডেল ট্রেন
এবার দুটো ওয়েট। ছয়জন ছাত্রের ডেটায় একটা সরলরেখা ফিট করব, অনুমিত নম্বর = w × ঘণ্টা + b। লস হলো মিন স্কোয়ার্ড এরর (MSE); এর পার্শিয়াল ডেরিভেটিভ বলে w আর b কীভাবে বদলাতে হবে:
import numpy as np
# ৬ জন ছাত্রের পড়ার ঘণ্টা আর পরীক্ষার নম্বর
hours = np.array([1, 2, 3, 4, 5, 6], dtype=float)
marks = np.array([52, 55, 61, 64, 70, 74], dtype=float)
w, b = 0.0, 0.0 # রেখা: অনুমান = w * ঘণ্টা + b
learning_rate = 0.02
for step in range(5001):
predicted = w * hours + b
error = predicted - marks
loss = np.mean(error ** 2) # মিন স্কোয়ার্ড এরর
grad_w = 2 * np.mean(error * hours) # ∂loss/∂w
grad_b = 2 * np.mean(error) # ∂loss/∂b
w -= learning_rate * grad_w
b -= learning_rate * grad_b
if step in (0, 100, 1000, 5000):
print(f"step {step:4}: w = {w:5.2f}, b = {b:5.2f}, loss = {loss:8.2f}")
print("NumPy's exact answer:", np.polyfit(hours, marks, 1).round(2))
print("prediction for 7 hours:", round(w * 7 + b, 1))step 0: w = 9.30, b = 2.51, loss = 3987.00
step 100: w = 9.36, b = 26.14, loss = 84.36
step 1000: w = 4.52, b = 46.84, loss = 0.45
step 5000: w = 4.51, b = 46.87, loss = 0.45
NumPy's exact answer: [ 4.51 46.87]
prediction for 7 hours: 78.5লস ৩,৯৮৭ থেকে নেমে ০.৪৫ হয়, আর ওয়েটগুলো ঠিক সেই উত্তরে থিতু হয়, যা NumPy-র নির্ভুল সমাধানকারী দেয়: পড়ার প্রতিটা বাড়তি ঘণ্টার দাম প্রায় ৪.৫ নম্বর, শুরু প্রায় ৪৭ থেকে। আপনি এইমাত্র একটা লিনিয়ার রিগ্রেশন মডেল ট্রেন করলেন — এই একই লুপ, শতকোটি ওয়েটে বাড়িয়ে GPU-তে চালালে একটা ল্যাঙ্গুয়েজ মডেল ট্রেন হয়।
আসল ট্রেনিংয়ে কী বদলায়
- স্টোকাস্টিক গ্রেডিয়েন্ট ডিসেন্ট (SGD): প্রতি ধাপে সব ডেটায় গ্রেডিয়েন্ট না কষে ছোট একটা এলোমেলো মিনি-ব্যাচ ব্যবহার। প্রতিটা ধাপ একটু অগোছালো, কিন্তু অনেক সস্তা।
- এপক: পুরো ডেটাসেটের ওপর দিয়ে একবার যাওয়া। ট্রেনিং সাধারণত কয়েকটা এপক চলে।
- Adam-এর মতো অপ্টিমাইজার প্রতিটা ওয়েটের ধাপের মাপ নিজে থেকে মানিয়ে নেয়। শুরুর লার্নিং রেট তবু আপনাকেই বাছতে হয়।
- লোকাল মিনিমা: আসল লসের ভূদৃশ্যে অনেক উপত্যকা থাকে। বাস্তবে, বড় নেটওয়ার্কে গ্রেডিয়েন্ট ডিসেন্ট তবু ভালো কাজ করা ওয়েট খুঁজে পায়।
নিজে চেষ্টা করুন
- প্রথম উদাহরণে সবচেয়ে বড় কোন লার্নিং রেটে তবু মান মিলে যায়, খুঁজুন। (ইঙ্গিত: ০.৯ আর ১.০-এর মধ্যে চেষ্টা করুন।)
- রেখা ফিটে
learning_rate = 0.05, তারপর0.07দিয়ে চেষ্টা করুন। একটা কেন তবু কাজ করে আর অন্যটাnan-এ শেষ হয়? - সপ্তম একজন ছাত্র যোগ করুন, যে ৮ ঘণ্টা পড়ে ৯০ পেয়েছে। w আর b কীভাবে বদলায়?