অধ্যায় 5 · সম্ভাবনা
ল্যাঙ্গুয়েজ মডেলের ভেতরে সম্ভাবনা
- পৃষ্ঠা 15 / 17
- 3 মিনিট পড়া
আগের কয়েক পাতার সবকিছু একটা ল্যাঙ্গুয়েজ মডেলের ভেতরে এসে মেলে। প্রতিটা ধাপে মডেল এ পর্যন্ত লেখা পড়ে আর তার শব্দভান্ডারের প্রতিটা টোকেনের একটা স্কোর দেয় — হাজার হাজার টোকেন। সফটম্যাক্স (পাতা ৮) স্কোরগুলোকে সম্ভাবনায় বদলায়। তারপর একটা টোকেন স্যাম্পল করে, লেখায় যোগ করে, আবার করে। API-তে যে সেটিং দেন — টেম্পারেচার, top-p — সেগুলো শুধু এই শেষ ধাপটা বদলায়।
টেম্পারেচার
ধরুন এ পর্যন্ত লেখা "The capital of Bangladesh is"। এগুলো পাঁচটা সম্ভাব্য শব্দের বানানো স্কোর (লজিট)। টেম্পারেচার সফটম্যাক্সের আগে লজিটগুলোকে ভাগ করে:
import numpy as np
words = ["Dhaka", "Chittagong", "Sylhet", "Paris", "banana"]
logits = np.array([6.0, 4.5, 4.0, 2.0, -1.0]) # পরের শব্দের জন্য মডেলের কাঁচা স্কোর
def softmax(z):
e = np.exp(z - z.max())
return e / e.sum()
for temperature in [0.5, 1.0, 2.0]:
probs = softmax(logits / temperature)
print(f"T={temperature}: " + " ".join(f"{w} {p:.2f}" for w, p in zip(words, probs)))T=0.5: Dhaka 0.94 Chittagong 0.05 Sylhet 0.02 Paris 0.00 banana 0.00
T=1.0: Dhaka 0.73 Chittagong 0.16 Sylhet 0.10 Paris 0.01 banana 0.00
T=2.0: Dhaka 0.50 Chittagong 0.24 Sylhet 0.18 Paris 0.07 banana 0.02- কম টেম্পারেচার (০.৫) ডিস্ট্রিবিউশনকে তীক্ষ্ণ করে: "Dhaka" পায় ৯৪%। আউটপুট কেন্দ্রীভূত আর পুনরাবৃত্তিযোগ্য হয় — তথ্য বের করা, শ্রেণিবিভাগ আর কোডের জন্য ভালো।
- টেম্পারেচার ১ মডেলের নিজের সম্ভাবনাই ব্যবহার করে।
- বেশি টেম্পারেচার (২.০) এটাকে চ্যাপ্টা করে: "Paris" আর "banana"-ও সত্যিকারের সুযোগ পায়। আউটপুট বেশি বৈচিত্র্যময় আর সৃজনশীল হয় — আর ভুল হওয়ার সম্ভাবনাও বাড়ে।
- টেম্পারেচার ০ মানে সবসময় সেরা টোকেনটা বাছা (একে বলে গ্রিডি ডিকোডিং)। তবুও সার্ভারের ভেতরের কারিগরি কারণে উত্তর সবসময় হুবহু একই হয় না।
স্যাম্পলিং, top-k আর top-p
স্যাম্পলিং মানে ওই সম্ভাবনা অনুযায়ী এলোমেলোভাবে একটা টোকেন তোলা। টেম্পারেচার ১-এ ১,০০০ বার তুললে গণনা সম্ভাবনার খুব কাছাকাছি থাকে:
import numpy as np
from collections import Counter
words = ["Dhaka", "Chittagong", "Sylhet", "Paris", "banana"]
logits = np.array([6.0, 4.5, 4.0, 2.0, -1.0])
probs = np.exp(logits - logits.max())
probs /= probs.sum()
rng = np.random.default_rng(9)
picks = rng.choice(words, size=1000, p=probs) # স্যাম্পলিং: মডেল ১,০০০ বার কী "বলে"
print(Counter(picks.tolist()).most_common())
top_k = 2 # top-k: শুধু সবচেয়ে সম্ভাব্য k-টা শব্দ রাখা
keep = np.argsort(probs)[::-1][:top_k]
print("top-2 candidates:", [words[i] for i in keep])[('Dhaka', 721), ('Chittagong', 177), ('Sylhet', 90), ('Paris', 11), ('banana', 1)]
top-2 candidates: ['Dhaka', 'Chittagong']হাজারে একবার এসেছে "banana"। লম্বা উত্তরে এই বিরল খারাপ বাছাইগুলো জমতে থাকে, তাই দুটো সেটিং স্যাম্পলিংয়ের আগে অসম্ভাব্য লেজটা কেটে দেয়:
- Top-k শুধু সবচেয়ে সম্ভাব্য k-টা টোকেন রাখে।
- Top-p (নিউক্লিয়াস স্যাম্পলিং) ওপরের দিকের টোকেনগুলোর সবচেয়ে ছোট সেটটা রাখে, যাদের সম্ভাবনার যোগফল p — যেমন ০.৯। মডেল নিশ্চিত হলে সেটা এক-দুটো টোকেন; অনিশ্চিত হলে বেশি।
এটা কী ব্যাখ্যা করে
- একই প্রম্পটে কেন আলাদা উত্তর আসে: এটা স্যাম্পলিং, ইচ্ছাকৃতভাবেই।
- ভুল হলেও মডেল কেন আত্মবিশ্বাসী শোনায়: সম্ভাবনাগুলো কোন লেখা সম্ভাব্য তা নিয়ে, কোন তথ্য সত্য তা নিয়ে নয় (Level 0, বিষয় ১)।
- লগ-সম্ভাবনা: কিছু API প্রতিটা টোকেনের সম্ভাবনার লগ ফেরত দেয়। খুব কম মান এমন শব্দ চিহ্নিত করে, যা নিয়ে মডেল অনিশ্চিত ছিল — সম্ভাব্য ভুল খোঁজার কাজের সংকেত।
- ট্রেনিং হলো আসল পরের টোকেনের ওপর ক্রস-এনট্রপি (পাতা ৮), লক্ষ-কোটি টোকেন জুড়ে গড় করা।
নিজে চেষ্টা করুন
- T = ০.১ আর T = ৫ দিয়ে টেম্পারেচারের উদাহরণ চালান। "Dhaka"-র কী হয়, বর্ণনা করুন।
- top-p বানান: সম্ভাবনাগুলো সাজান,
np.cumsumব্যবহার করুন, আর যোগফল ০.৯ পেরোনো পর্যন্ত টোকেন রাখুন। কোন শব্দগুলো থাকে? - T = ২-এ ১,০০০ বার স্যাম্পল করুন। "banana" এখন কতবার আসে?