در پروژههای ارزیابی مدلهای زبانی، بهدستآوردن نمرات خام روی تسکهای گوناگون فقط نیمی از مسیر است. وقتی خروجیها از جنس سنجههای مختلفی مثل دقت، BLEU یا نرخ قبولی باشند، مقایسهی سرراست مدلها شما را به اشتباه میاندازد؛ چون معیارهایی با دامنهی بزرگتر بهسادگی اثر سایر تسکها را محو میکنند.
مشکل جدیتر زمانی رخ میدهد که تفاوتهای کوچک میان نمرات دو مدل را برتری قطعی تلقی کنیم. بدون اعتبارسنجی آماری و در نظر گرفتن بازههای اطمینان، تشخیص اینکه کدام تفاوتها تصادفی و کدام معنادار هستند ناممکن خواهد بود.
در این درس یاد میگیرید که چطور خروجی ارزیابیهای ناهمگن را نرمالسازی کنید، رتبهبندی را با دو رویکرد میانگین و نرخ برد (Win-rate) بسازید و با روش نمونهبرداری مجدد بوتاسترپ (Bootstrap) در پایتون، بازههای اطمینان دقیق و مقایسههای جفتی قابل دفاع تولید کنید.
محاسبهی امتیازها به ازای هر وظیفه ساده است. رتبهبندی مدلها در میان وظایف ناهمگن دشوارتر میشود. با این حال، محاسبهی معناداری آماری روی لیدربوردی با هزار پیشبینی، بخشی است که همه از کنارش میگذرند. این درس از آن عبور نمیکند.
اهداف یادگیری
- تجمیع امتیازهای هر وظیفه (task) برای چندین مدل و چندین وظیفه در قالب سطرهای تمیز و تفکیکشده به ازای هر مدل.
- نرمالسازی امتیازهای ناهمگن تا مواردی مثل نرخ قبولی (pass rate) و مقادیر BLEU، وزن نامتناسبی به تجمیع ندهند.
- رتبهبندی (rank) مدلها بر اساس میانگین و نرخ برد (win-rate)، به همراه توضیح اینکه هر کدام در چه شرایطی خلاصهی آماری مناسبتری هستند.
- محاسبهی بازههای اطمینان (confidence intervals) با روش تخمین اولیه (بوتاسترپ) (bootstrap) برای میانگین امتیاز هر مدل و تفاضلهای جفتی.
- ارائهی خروجی لیدربورد در قالب گزارش JSON و جدول Markdown تا رانر در درس 75 بتواند آن را در کامنت CI قرار دهد.
ساختار دادههای ورودی
بخش تجمیعکننده فهرستی از رکوردهای EvalRun را دریافت میکند:
@dataclass
class EvalRun:
model_id: str
task_id: str
metric_name: str
score: float # in [0, 1]
category: str
رانرِ درس 75 به ازای هر جفت (model, task) یک رکورد صادر میکند. تجمیعکننده کاری به نحوهی تولید امتیاز ندارد؛ بلکه انتظار دارد نرمالسازی قبلاً انجام شده باشد و تمام امتیازها در بازهی [0, 1] قرار بگیرند.
ساختار خروجی
سه جدول خروجی تولید میشود:
هر سطر لیدربورد شامل این موارد است: model_id، mean_score، mean_ci_lo، mean_ci_hi، win_rate، tasks_completed و یک نگاشت (map) اختیاری به نام categories برای میانگین امتیاز در هر دستهبندی.
نرمالسازی
اگر امتیاز یک وظیفه در بازهی [0, 1] و دیگری در [0, 100] باشد، وظیفهی دوم بیسروصدا میانگین را تحتالشعاع قرار میدهد. تجمیعکننده بررسی میکند که همهی امتیازهای ورودی حتماً در بازهی [0, 1] باشند و در غیر این صورت، اجرا را رد میکند. اصلاح این مشکل بر عهدهی بخشهای بالادستی است: متریک باید از همان ابتدا مقداری کسری برگرداند؛ قاعدهای که درسهای 71 تا 73 رعایت آن را تضمین میکنند.
میانگین و نرخ برد
این دو روش رتبهبندی اهداف متفاوتی را دنبال میکنند.
میانگین امتیاز، معدل نمرات هر مدل در تمامی وظایف است؛ همان عدد شاخصی که لیدربوردها گزارش میکنند. این شاخص در برابر دادههای پرت و نامتعادل بودن وظایف حساس است.
نرخ برد نشان میدهد یک مدل چند بار توانسته سایر مدلها را در یک وظیفهی مشابه شکست دهد. در هر وظیفه، مدلی که بالاترین امتیاز را بیاورد برنده است (در صورت تساوی، امتیاز یک برد کامل به تمام مدلهای همامتیاز داده میشود). نرخ برد برابر است با تعداد بردها تقسیم بر تعداد وظایفی که مدل در آنها امتیاز دارد. این معیار حساسیت کمتری به دادههای پرت و تفاوت مقیاسها دارد، اما بخشی از اطلاعات را نادیده میگیرد.
def win_rate(model_id, runs_by_task, all_models):
wins, total = 0, 0
for task_id, runs in runs_by_task.items():
scores = {r.model_id: r.score for r in runs if r.model_id in all_models}
if model_id not in scores:
continue
total += 1
best = max(scores.values())
if scores[model_id] >= best:
wins += 1
return wins / total if total else 0.0
بستر آزمایشی (harness) هر دو معیار را گزارش میدهد. رانرِ درس 75 بهصورت پیشفرض مدلها را بر اساس میانگین رتبهبندی میکند، اما ستون نرخ برد هم در جدول Markdown قرار دارد تا اگر ترجیح دادید، از آن استفاده کنید.
بازههای اطمینان با تخمین اولیه (بوتاسترپ)
میانگین امتیاز هر مدل همراه با یک بازهی اطمینان ارائه میشود که با روش نمونهبرداری مجدد با تخمین اولیه (بوتاسترپ) روی وظایف برآورد شده است. شناسههای وظایف را با جایگذاری مجدداً نمونهبرداری میکنیم، میانگین را روی مجموعهی نمونهبرداریشده بهدست میآوریم، این کار را B بار تکرار میکنیم و در نهایت بازهی صدکی را در سطح alpha در نظر میگیریم.
برای مقایسههای جفتی (pairwise comparisons)، تفاضل امتیاز هر وظیفه یعنی score_A - score_B را با تخمین اولیه (بوتاسترپ) نمونهبرداری کرده، بازهی صدکی آن را بهدست میآوریم و گزارش میدهیم. در این حالت بهراحتی میتوان دید که آیا این بازه عدد صفر را در بر نمیگیرد یا نه؛ اگر صفر را در بر نگیرد، تفاضل در سطح alpha معنادار است. اگر شامل صفر باشد، لیدربورد عملکرد دو مدل را برابر در نظر میگیرد.
توابع کمکی سطح پایین (bootstrap_mean_ci و bootstrap_pairwise_diff) بهصورت پیشفرض با B=1000 اجرا میشوند؛ اما توابع تجمیعکنندهی عمومی (aggregate و pairwise_diffs) مقدار پیشفرض b=500 دارند تا اجرای دمو و تستها سریع بماند. سطح alpha پیشفرض نیز 0.05 است. محاسبات تخمین اولیه (بوتاسترپ) در این درس کاملاً با numpy پیادهسازی شده و نیازی به scipy نیست.
دستهبندیها
اگر فیلد EvalRun.category مقداردهی شده باشد، تجمیعکننده میانگین امتیاز را به تفکیک هر دسته نیز گزارش میکند؛ همان ستونهایی مثل math، reasoning، code و safety که در همهی لیدربوردها میبینید. این تفکیک به رانر کمک میکند متوجه شود آیا مدلی در مجموع خوب عمل کرده اما در کدنویسی ضعیف است یا نه؛ اطلاعاتی که میانگین کل معمولاً آن را پنهان میکند.
رندر جدول Markdown
لیدربورد در قالب یک جدول Markdown رندر میشود:
| Rank | Model | Mean | 95% CI | Win rate | Tasks |
|------|-------|------|--------|----------|-------|
| 1 | gpt | 0.78 | 0.74-0.82 | 0.62 | 50 |
| 2 | claude| 0.75 | 0.71-0.79 | 0.34 | 50 |
| 3 | random| 0.10 | 0.07-0.13 | 0.04 | 50 |
جدول بر اساس میانگین امتیاز مرتب میشود، بازهی اطمینان تا دو رقم اعشار نمایش مییابد و شناسههای طولانی مدلها به بیست کاراکتر خلاصه میشوند.
مواردی که در این درس بررسی نمیشوند
این درس مدلها را اجرا نمیکند، لایهی متریک را فراخوانی نمیکند و کالیبراسیون (calibration) متغیر مثل ECE تطبیقی را پیادهسازی نمیکند؛ این موارد به درس 73 مربوط میشوند. همچنین وزندهی به وظایف در اینجا پیادهسازی نمیشود و همهی وظایف وزن یکسانی دارند. لیدربوردهای محیط عملیاتی (پروداکشن) (production) به وظایف مختلف وزن میدهند؛ ما فیلد weight را برای این منظور باز گذاشتهایم اما فعلاً در تجمیعکننده از آن صرفنظر میکنیم. در صورت نیاز میتوانید در درسهای بعدی وزندهی را اضافه کنید.
راهنمای خواندن کد
فایل main.py شامل تعاریف EvalRun، LeaderboardRow، aggregate، bootstrap_mean_ci، bootstrap_pairwise_diff و render_markdown است. بخش دمو یک مجموعهی ساختگی از سه مدل و 12 وظیفه میسازد، آنها را تجمیع میکند و در نهایت لیدربورد و جدول تفاضلهای جفتی را چاپ میکند. تستهای موجود در code/tests/test_leaderboard.py نیز رفتار تخمین اولیه (بوتاسترپ)، رندر Markdown، حالتهای خاص نرخ برد و ورودیهای خالی را اعتبارسنجی میکنند.
فایل main.py را از بالا به پایین بخوانید: ابتدا ساختار دادهها (EvalRun و LeaderboardRow)، سپس تجمیعکننده، بعد از آن تخمین اولیه (بوتاسترپ) و در آخر بخش رندر قرار دارد. هر تابع وظیفهی مشخص و مستقلی را انجام میدهد.
برای مطالعهی بیشتر
بازههای اطمینان به ازای هر مدل بهصورت مستقل (ناجفت) محاسبه میشوند، اما مقایسهی میان مدلها باید بهشکل جفتی باشد. اگر هر دو مدل A و B روی صد وظیفهی یکسان اجرا شدهاند، آزمون آماری مناسب، تخمین اولیه (بوتاسترپ) جفتی روی تکتک تفاوتهای هر وظیفه است؛ کاری که bootstrap_pairwise_diff قبلاً پیادهسازی کرده است. فراتر از این، به یک تخمین اولیه (بوتاسترپ) سلسلهمراتبی (hierarchical) نیاز دارید که ساختار خانوادهی وظایف را در نظر بگیرد (مسائل ریاضی از یکدیگر ناوابسته نیستند و وابسته (dependent) به هماند؛ بهطوریکه یک الگوی خطای محاسباتی میتواند روی 10 تای آنها اثر بگذارد). این موضوع را در درسهای بعدی بررسی میکنیم. هدف این درس، پایهریزی درست فرآیند ارزیابی است تا گزارشی با اعداد و ارقام قابل دفاع در دست داشته باشید.
