RLHF ও ভ্যালু অ্যালাইনমেন্ট — কার মূল্যবোধ?
এই পাঠে যা শিখবেন
- RLHF-এর মূল মেকানিজম — reward model + policy আপডেট — একটি ছোট সিমুলেশনের মাধ্যমে
- কেন reward model একটি প্রক্সি মাত্র, মানুষের প্রকৃত পছন্দের নিখুঁত প্রতিরূপ নয়
- একটি সত্যিকারের, গণনা-করা উদাহরণ — কীভাবে একটি ভুল প্রক্সি (length) অপ্টিমাইজেশনকে ভুল পথে নিয়ে যায়
- "কার মূল্যবোধ?" প্রশ্নটি কেন RLHF আলোচনায় কেন্দ্রীয়
১ · RLHF সংক্ষেপে
L27-এ আমরা দেখেছি একটি LLM প্রথমে বিশাল কর্পাসে next-token prediction দিয়ে প্রি-ট্রেইনড হয়, এরপর ফাইন-টিউনিং হয়। RLHFRLHF (Reinforcement Learning from Human Feedback)মানুষের পছন্দ-অপছন্দের ডেটা থেকে একটি reward model শিখিয়ে, সেই reward model-এর স্কোর সর্বোচ্চ করার দিকে মডেলের আউটপুট-জেনারেটিং নীতি (policy) ধাপে ধাপে সমন্বয় করার একটি কৌশল। হলো এর পরের একটি সাধারণ ধাপ, তিনটি মোটামুটি অংশে ভাঙা যায়:
- মানুষ রেটাররা একাধিক candidate আউটপুট দেখে কোনটি ভালো/বেশি পছন্দনীয় তা রেট করেন বা তুলনা করেন।
- এই তুলনাগুলো থেকে একটি reward model ট্রেইন করা হয় — একটি ফাংশন যা যেকোনো আউটপুট দেখে একটি স্কোর দিতে শেখে, মানুষের রেটিং প্যাটার্ন অনুকরণ করে।
- মূল মডেলের নীতি (policy) তখন এমনভাবে আপডেট করা হয় যাতে সে এমন আউটপুট তৈরি করে যা reward model-কে বেশি স্কোর দেয় — একটি অপ্টিমাইজেশন লুপ।
মূল ধারণাটি সহজ: reward model-কে একটি "মানুষের পছন্দের প্রক্সি" হিসেবে ব্যবহার করে policy-কে সেই প্রক্সি সর্বোচ্চ করার দিকে চালিত করা। এখানেই সমস্যাটির বীজ লুকিয়ে — একটি প্রক্সি কখনোই আসল লক্ষ্যের নিখুঁত প্রতিরূপ নয় (এই থিমটি L24-এর specification gaming ও L25-এর Goodhart's law পাঠে ইতিমধ্যে বিস্তারিত দেখা হয়েছে)।
২ · একটি সত্যিকারের সিমুলেশন — reward model + hill-climbing
নিচের কোডে আমরা একটি বাস্তব ভাষা-মডেল বানাচ্ছি না — বরং RLHF-এর মেকানিজমটা একটি ছোট,
সম্পূর্ণ genuine সার্চ লুপ দিয়ে দেখাচ্ছি। একটি "candidate আউটপুট" এখানে কয়েকটি টেক্সট-কম্পোনেন্টের
(বাক্যাংশ) তালিকা। আমাদের reward_model_length() ফাংশনটি একটি সরলীকৃত, এক্সপ্লিসিট স্কোরিং
নিয়ম — এটি একটি শেখা (learned) reward model-এর জায়গায় দাঁড়িয়েছে, এবং ইচ্ছাকৃতভাবে শুধু আউটপুটের
দৈর্ঘ্য-কে পুরস্কৃত করে (একটি বাস্তব, নথিভুক্ত RLHF ব্যর্থতা প্যাটার্ন — length bias)।
একটি ছোট population-ভিত্তিক hill-climbing/mutation লুপ প্রতি রাউন্ডে সেরা candidate-দের রেখে, নতুন
candidate mutate করে reward score বাড়ানোর চেষ্টা করে — policy আপডেটের একটি সরলীকৃত
স্ট্যান্ড-ইন।
import random
random.seed(7)
# তথ্যবহুল (content) কম্পোনেন্ট -- মানুষ আসলে যা মূল্যবান মনে করে
CONTENT_POOL = [
"নিয়মিত ব্যায়াম হৃদযন্ত্র সুস্থ রাখে",
"ব্যায়াম রক্তচাপ নিয়ন্ত্রণে সাহায্য করে",
"ব্যায়াম মানসিক চাপ কমায়",
"ব্যায়াম ঘুমের মান উন্নত করে",
"ব্যায়াম ওজন নিয়ন্ত্রণে সহায়ক",
]
# ফিলার/প্যাডিং কম্পোনেন্ট -- কোনো নতুন তথ্য যোগ করে না, শুধু দৈর্ঘ্য বাড়ায়
FILLER_POOL = [
"এটি সত্যিই সত্যিই গুরুত্বপূর্ণ একটি বিষয়",
"আসলে আসলেই এটি সম্পূর্ণ সত্য কথা",
"অবশ্যই অবশ্যই এটি মনে রাখা উচিত",
"তাছাড়া তাছাড়া এই বিষয়টি উল্লেখযোগ্য",
]
ALL_POOL = CONTENT_POOL + FILLER_POOL
def render(candidate):
return " ".join(candidate)
def reward_model_length(candidate):
# সরলীকৃত "reward model" -- আউটপুট যত লম্বা, স্কোর তত বেশি (length-বায়াসড প্রক্সি)
return len(render(candidate))
def true_quality(candidate):
# মানুষ আসলে যা চায়: কতগুলো *ভিন্ন* তথ্যবহুল পয়েন্ট আছে -- reward model এটা দেখেই না
return len(set(c for c in candidate if c in CONTENT_POOL))
def mutate(candidate):
new_candidate = list(candidate)
if random.random() < 0.5 and len(new_candidate) > 1:
idx = random.randrange(len(new_candidate))
new_candidate[idx] = random.choice(ALL_POOL) # একটি কম্পোনেন্ট বদলানো
else:
new_candidate.append(random.choice(ALL_POOL)) # নতুন কম্পোনেন্ট যোগ করা (দৈর্ঘ্য বাড়ে)
return new_candidate
POP_SIZE = 6
ROUNDS = 6
population = [random.choices(ALL_POOL, k=3) for _ in range(POP_SIZE)]
print("রাউন্ড | reward-model স্কোর (length) | true quality (distinct content points)")
for round_num in range(1, ROUNDS + 1):
# mutation দিয়ে নতুন offspring তৈরি -- policy আপডেটের একটি সরলীকৃত স্ট্যান্ড-ইন
offspring = [mutate(random.choice(population)) for _ in range(POP_SIZE)]
combined = population + offspring
# reward model অনুযায়ী সাজিয়ে সেরা POP_SIZE রাখা (higher reward-কে "উৎসাহিত" করা হচ্ছে)
combined.sort(key=reward_model_length, reverse=True)
population = combined[:POP_SIZE]
best = population[0]
print(f"{round_num:>2} | {reward_model_length(best):>3} | {true_quality(best)}")
print()
print("শেষ রাউন্ডের সেরা ক্যান্ডিডেট:")
print(render(population[0]))
print("true quality (distinct content points):", true_quality(population[0]))
print("reward-model score:", reward_model_length(population[0]))
৩ · কার মূল্যবোধ?
উপরের ডেমোতে আমরা ইচ্ছাকৃতভাবে একটি "খারাপ" reward model (শুধু length) বেছে নিয়েছি যাতে সমস্যাটি স্পষ্ট হয়। বাস্তবে, একটি প্রকৃত RLHF reward model শত শত বা হাজার হাজার মানুষ রেটারের তুলনা-সিদ্ধান্ত থেকে শেখে — যা length-এর মতো সরল না হলেও, এখনও একটি প্রক্সিই থেকে যায়। এবং এই প্রক্সিটি কার কাছ থেকে আসছে তা গুরুত্বপূর্ণ প্রশ্ন:
রেটারদের নির্দিষ্ট সাংস্কৃতিক প্রেক্ষাপট, ভাষা, শিক্ষাগত পটভূমি থাকে — তাদের রুচি একটি নির্দিষ্ট জনগোষ্ঠীর প্রতিনিধিত্ব করে, সার্বজনীন মানবতার নয়।
রেটারদের "কী ভালো উত্তর" তা নির্ধারণে দেওয়া গাইডলাইন একটি নির্দিষ্ট প্রতিষ্ঠান/টিম লেখে — এই গাইডলাইনও নিরপেক্ষ নয়, একটি নির্দিষ্ট দৃষ্টিভঙ্গি বহন করে।
রাজনৈতিক, নৈতিক, সাংস্কৃতিক ভাবে বিতর্কিত প্রশ্নে ভিন্ন ভিন্ন মানুষ ভিন্ন "সঠিক" উত্তর প্রত্যাশা করে — reward model কে সেখানে কোনো একটি অবস্থান বেছে নিতেই হয়।
এই কারণেই "মডেলটি human feedback দিয়ে অ্যালাইনড করা হয়েছে" এই বাক্যটি একা যথেষ্ট তথ্যপূর্ণ নয় — আসল প্রশ্ন হলো কোন মানুষ, কোন গাইডলাইনে, কোন প্রেক্ষাপটে সেই ফিডব্যাক দিয়েছেন। এটি একটি কারিগরি সীমাবদ্ধতা নয়, বরং একটি কাঠামোগত বাস্তবতা — কোনো একক reward model কখনোই "সবার মূল্যবোধ" ধারণ করতে পারে না, কারণ মানুষের মূল্যবোধ নিজেই বৈচিত্র্যময় এবং প্রায়ই পরস্পরবিরোধী।
RLHF মডেলের আচরণকে মানুষের ফিডব্যাকের সাথে সামঞ্জস্যপূর্ণ করে তোলে — কিন্তু এটি "নিরপেক্ষ সততা" যোগ করে না। reward model একটি শেখা প্রক্সি, এবং প্রক্সি maximize করা প্রায়ই প্রকৃত লক্ষ্য (মানুষ আসলে যা চায়) থেকে বিচ্যুত হতে পারে — উপরের ডেমোতে যেমন length maximize করা quality কমিয়ে দিয়েছে। আর সেই reward model যে human feedback থেকে শেখে, সেই feedback নিজেই একটি নির্দিষ্ট, সীমিত গোষ্ঠীর মূল্যবোধের প্রতিফলন — "কার মূল্যবোধ?" প্রশ্নটি তাই RLHF আলোচনায় কখনোই এড়িয়ে যাওয়া উচিত নয়।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১
উপরের ডেমোতে reward_model_length() কখনো কমে না, কিন্তু true_quality()
শেষে কমে যায় কেন? এই দুটো ঘটনার মধ্যে কি বৈপরীত্য আছে?
কোনো বৈপরীত্য নেই — বরং এটাই মূল পয়েন্ট। elitist সিলেকশনের কারণে reward score কখনো কমে না (আগের সেরা candidate সবসময় সংরক্ষিত থাকে)। কিন্তু reward model যেহেতু শুধু length মাপে, quality নয়, তাই সার্চ প্রক্রিয়া এমন candidate-দের প্রাধান্য দেয় যারা length-এ ভালো করে — এবং length বাড়ানোর সবচেয়ে সহজ উপায় হলো ফিলার পুনরাবৃত্তি করা, নতুন তথ্য যোগ করা নয়। তাই reward স্কোর একরৈখিকভাবে বাড়ে, আর প্রকৃত quality মোটেও তার সাথে তাল মিলিয়ে বাড়ে না।
প্র ০২
যদি reward_model_length()-এর বদলে একটি reward model ব্যবহার করা হতো যা
true_quality()-কেই সরাসরি স্কোর করে, তাহলে কী ঘটতো বলে আপনার ধারণা?
তাহলে সার্চ প্রক্রিয়া সরাসরি distinct content component-দের প্রাধান্য দিত, এবং ফিলার পুনরাবৃত্তি
কোনো সুবিধা দিত না (কারণ ফিলার CONTENT_POOL-এ নেই)। সেক্ষেত্রে reward score ও true
quality একসাথে বাড়ত — অর্থাৎ সমস্যাটা RLHF নিজে নয়, বরং reward model কতটা ভালোভাবে
প্রকৃত লক্ষ্যের প্রতিনিধিত্ব করে তার উপর নির্ভর করে। বাস্তবে একটি নিখুঁত true-quality
reward model বানানো কঠিন — সেটাই মূল চ্যালেঞ্জ।
প্র ০৩ "আমাদের মডেল RLHF দিয়ে human feedback-এর সাথে অ্যালাইনড" — এই দাবিটি শোনার পর আপনি আর কী প্রশ্ন করবেন?
যুক্তিসঙ্গত প্রশ্ন হতে পারে: রেটাররা কারা ছিলেন (তাদের সংখ্যা, ভাষা, সাংস্কৃতিক/ভৌগোলিক প্রেক্ষাপট)? তাদের কী গাইডলাইন দেওয়া হয়েছিল? বিতর্কিত/মূল্যবোধ-নির্ভর প্রশ্নে কীভাবে সিদ্ধান্ত নেওয়া হয়েছে? এবং reward model কতটা ভালোভাবে প্রকৃত মানব-পছন্দ প্রতিফলিত করে তা কীভাবে যাচাই করা হয়েছে (নাকি শুধু কিছু সহজ প্রক্সি অপ্টিমাইজ হচ্ছে, উপরের ডেমোর মতো)?
অনুশীলন
-
চিন্তা করুন: উপরের কোডে
ROUNDS-কে6থেকে15-এ বাড়ালে reward-model স্কোর ও true quality-র মধ্যে গ্যাপ কীভাবে বদলাবে বলে আপনার ধারণা?বেশি রাউন্ডে reward-model স্কোর (length) আরও বাড়তে থাকবে, কারণ সার্চ প্রক্রিয়ার প্রতি রাউন্ডে ফিলার যোগ করার সুযোগ থাকে। কিন্তু true quality-র একটি upper bound আছে —
CONTENT_POOL-এ মাত্র ৫টি distinct আইটেম আছে, তাই এটি সর্বোচ্চ ৫-এ পৌঁছাতে পারে, তারপর আর বাড়বে না। ফলে বেশি রাউন্ডে reward score ও true quality-র মধ্যে গ্যাপ সাধারণত আরও বড় হবে — misalignment আরও স্পষ্ট হয়ে উঠবে। -
পরীক্ষা করুন: উপরের কোডে
reward_model_length-এর বদলেkey=true_qualityব্যবহার করে (combined.sort(key=true_quality, reverse=True)) Run চেপে দেখুন সার্চ প্রক্রিয়ার আচরণ কীভাবে বদলায়।এখন সার্চ সরাসরি distinct content point-দের প্রাধান্য দেবে — শেষ candidate-এ ফিলার বাক্যাংশের বদলে বিভিন্ন
CONTENT_POOLআইটেম বেশি দেখা যাবে, এবংtrue_qualityদ্রুত তার সর্বোচ্চ মান (৫)-এর কাছাকাছি পৌঁছে যাবে। এটি প্রমাণ করে সমস্যাটি hill-climbing মেকানিজমে নয় — সমস্যাটি reward model কী মাপছে তাতে।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ নৈতিক ফ্রেমওয়ার্ক, বায়াস-ফেয়ারনেস, প্রাইভেসি, ট্রান্সপারেন্সি, AI অ্যালাইনমেন্ট, জেনারেটিভ AI/LLM এথিক্স, সামাজিক প্রভাব, গভর্নেন্স ও রেগুলেশন, সেক্টর-স্পেসিফিক এথিক্স ও এক্সিস্টেনশিয়াল রিস্ক বিতর্ক।
- স্পেসিফিকেশন গেমিং ও Goodhart's law M6 এই পাঠের length-বায়াসড reward model demo যে সাধারণ প্যাটার্নের একটি নির্দিষ্ট উদাহরণ, তার সম্পূর্ণ ভিত্তি M6 মডিউলে।
- Machine Learning কোর্স ফাউন্ডেশন রিইনফোর্সমেন্ট লার্নিং ও অপ্টিমাইজেশনের টেকনিক্যাল ভিত্তি।