فاز 19 · درس 75

یکپارچه‌سازی پایپ‌لاین ارزیابی مدل‌های زبانی: ساخت رانر کامل

نوع
ساختنی
زمان
حدود 90 دقیقه
زبان‌ها
Python
پیش‌نیاز
مبانی فاز 19 مسیر B، درس‌های 70 تا 74
یک کنسول مهندسی با چندین کابل رنگی منظم که پنج ماژول پردازشی مجزا را به یک نمایشگر مرکزی گزارش متصل کرده‌اند.
فهرست مطالب
  1. اهداف یادگیری
  2. پایپ‌لاین
  3. اینترفیس تطبیق‌دهنده
  4. اجرای موازی
  5. حلقه‌ی امتیازدهی تک‌پیمایشی
  6. تجمیع
  7. اجرای نمایشی خودپایان‌دهنده
  8. این درس چه کارهایی انجام نمی‌دهد؟
  9. راهنمای خواندن کد
  10. گام‌های بعدی

در مسیر توسعه‌ی سیستم‌های مبتنی بر هوش مصنوعی، ساخت متریک‌های مجزا و فرمول‌های کالیبراسیون به‌تنهایی کافی نیست؛ چالش اصلی زمانی آغاز می‌شود که بخواهید این قطعات پراکنده را به یک پایپ‌لاین یکپارچه و خودکار متصل کنید. بدون یک سامانه‌ی اجرای ارزیابی (Eval Runner) استاندارد، مقایسه‌ی مدل‌های مختلف نیازمند اجرای دستی اسکریپت‌ها و جمع‌آوری پراکنده‌ی نتایج خواهد بود که خطای انسانی را به شدت بالا می‌برد.

در این درس یاد می‌گیرید که چگونه تمام اجزای طراحی‌شده در درس‌های پیشین — از مشخصات تسک‌ها و لایه‌ی متریک‌ها گرفته تا تحلیل کالیبراسیون و تجمیع لیدربورد — را با یک رابط تطبیق‌دهنده (Adapter) تمیز به هم گره بزنید. این رانر وظایف را به‌صورت موازی پردازش کرده و در یک دور پیمایش، هم امتیازات و هم داده‌های قابلیت اطمینان مدل را استخراج می‌کند.

برای اجرای کدهای این درس به کارت گرافیک گران‌قیمت یا اتصال مداوم به API خارجی نیازی ندارید؛ اجرای آزمایشی روی CPU با استفاده از مدل‌های ساختگی (Mock) و ماژول استاندارد concurrent.futures در پایتون انجام می‌شود و معماری حاصل، آماده‌ی اتصال به مدل‌های محلی یا سرویس‌های ابری است.

پنج درس لوله‌کشی کردیم و حالا در این درس همه را به هم وصل می‌کنیم. رانر (runner) مشخصات وظیفه را از درس 70 می‌خواند، مدل را از طریق یک تطبیق‌دهنده (adapter) فراخوانی می‌کند، با منطق درس‌های 71 و 72 امتیاز می‌دهد، گزارش کالیبراسیون درس 73 را ضمیمه می‌کند و در نهایت جدول رده‌بندی درس 74 را تحویل می‌دهد. اجرای نمایشی در پایان به‌طور خودکار بسته می‌شود.

اهداف یادگیری

  • تعریف اینترفیس ModelAdapter به‌گونه‌ای که هر مدلی (ساختگی، محلی، API) با پیاده‌سازی چند متد محدود با آن سازگار شود.
  • اجرای ارزیابی روی یک فایل فیکسچر JSONL با اجرای موازی وظایف در استخری از ورکرها.
  • ترکیب لایه‌ی متریک‌ها (exact_match، F1، BLEU-4، ROUGE-L و code_exec) با لایه‌ی کالیبراسیون تنها در یک دور پیمایش (single pass).
  • تولید رکوردهای EvalRun به تفکیک هر مدل و ارسال مستقیم آن‌ها به تجمیع‌کننده‌ی جدول رده‌بندی.
  • ارائه‌ی خروجی در هر دو قالب گزارش JSON و جدول Markdown؛ خروج خودکار با کد صفر در صورت اجرای موفق، و کد غیرصفر در صورت بروز خطای اعتبارسنجی یا محیط اجرا.
اجراکننده‌ی ارزیابی (EVAL RUNNER)توزیع وظایف، روشن‌شدن امتیازها
EVAL RUNNERThe runner reads the task spec, fans the tasks across a worker pool, and scores each with the metric layer plus the calibration report. Cells light pass (blue) or fail (orange) as the sweep crosses them. Per-model EvalRun records flow straight into the leaderboard aggregator; the demo self-terminates on a clean run.ورکراستخرw0w1w2w3tasks.jsonl →score = mean(pass) · per-model EvalRun → leaderboard
رانر مشخصات وظیفه را می‌خواند، وظایف را میان استخری از ورکرها توزیع می‌کند، و هر کدام را از طریق لایه‌ی متریک همراه با گزارش کالیبراسیون امتیازدهی می‌کند. با پیشروی پیمایش، خانه‌ها به رنگ قبولی (آبی) یا رد (نارنجی) روشن می‌شوند. رکوردهای EvalRun هر مدل مستقیماً به تجمیع‌کننده‌ی لیدربورد منتقل می‌شوند؛ دمو پس از یک اجرای موفق و بی‌نقص خودبه‌خود پایان می‌یابد.

پایپ‌لاین

exact_match/f1/bleu_4/rouge_l/accuracycode_exectasks.jsonl از درس 70اعتبارسنجیرندر پرامپت‌هاتولید با تطبیق‌دهنده مدلپس‌پردازشmetric_nameامتیازدهی از درس 71run_candidate از درس 72رکورد EvalRunاطمینان و nll به ازای هر توکنCalibrationReport از درس 73تجمیع از درس 74بخش کالیبراسیون به ازای هر مدلجدول امتیازات JSON + markdown

رانر نقطه‌ی یکپارچه‌سازی کل سیستم است. هر یک از درس‌های 70 تا 74 ماژولی ساخته‌اند که رانر آن‌ها را کنار هم می‌نشاند. رانر منطق هیچ‌کدام از این ماژول‌ها را دوباره تکرار نمی‌کند؛ صرفاً آن‌ها را ایمپورت می‌کند.

اینترفیس تطبیق‌دهنده

تطبیق‌دهنده مرز اتصال میان رانر و هر مدلی است. این اینترفیس را عمداً بسیار جمع‌وجور طراحی کرده‌ایم.

class ModelAdapter:
    model_id: str

    def generate(self, prompt: str, task: TaskSpec) -> Generation: ...

کلاس داده‌ی Generation شامل فیلدهای زیر است:

  • text: خروجی متنی آزاد مدل
  • confidence: عددی اعشاری در بازه‌ی [0, 1] که نشان‌دهنده‌ی احتمال خوداظهاریِ مدل برای پاسخ است
  • token_nll: مجموع درست‌نمایی لگاریتمی منفیِ توکن‌های تولیدشده (اختیاری)
  • token_count: تعداد توکن‌های تولیدشده (اختیاری)

تطبیق‌دهنده‌های ساختگی (mock) در رانر سه رفتار مختلف ارائه می‌دهند: RuleBasedAdapter (قطعیت‌گرا و تقریباً بی‌نقص)، NoisyAdapter (بیش‌ازحد مطمئن، اما اغلب اشتباه) و BiasedAdapter (عالی در یک دسته‌بندی و فاجعه در دسته‌بندی دیگر). دموی برنامه هر سه را روی فیکسچر درس 70 اجرا می‌کند.

اجرای موازی

رانر با استفاده از concurrent.futures.ThreadPoolExecutor وظایف مربوط به هر مدل را به‌شکل موازی اجرا می‌کند. تعداد ورکرها به‌طور پیش‌فرض برابر با مقدار کمتر میان عدد 8 و تعداد کل وظایف است. استفاده از نخ‌ها (threads) کاملاً کفایت می‌کند، چرا که گلوگاه اصلی در فراخوانی مدل‌های واقعی، I/O شبکه است. مسیر ارزیابی اجرای کد (code_exec)، زیرفرایند (subprocess) اختصاصی خود را داخل تسک می‌سازد و مجری (executor) فقط منتظر پایان آن می‌ماند.

رانر برای آزمون‌های قطعی، تابع run_eval(adapters, tasks, parallel=False) را ارائه می‌دهد تا تست‌ها بتوانند ترتیب اجرا را ثابت نگه دارند.

حلقه‌ی امتیازدهی تک‌پیمایشی

برای هر وظیفه مراحل زیر طی می‌شود:

  1. پرامپت آماده و رندر می‌شود (پیشوند چندمثاله به‌همراه متن اصلی پرامپت).
  2. تطبیق‌دهنده فراخوانی شده و مدت‌زمان فراخوانی اندازه گرفته می‌شود.
  3. خروجی مدل بر اساس قوانین همان وظیفه پس‌پردازش می‌شود.
  4. خروجی به لایه‌ی متریک فرستاده می‌شود.
  5. رکورد EvalRun شامل امتیاز و متادیتای متریک ساخته می‌شود.
  6. جفت (confidence, correct) به بافر کالیبراسیون اضافه می‌شود.

سیگنال درستی (correct) برای متریک‌های مشابه تطابق دقیق (exact_match، accuracy و code_exec) شرط score >= 1.0 و برای متریک‌های درجه‌بندی‌شده شرط score >= 0.5 است. این آستانه در _correct_from_score قرار دارد و رانر امکان بازنویسی (override) عمومی آن را نمی‌دهد.

تجمیع

پس از ثبت نتیجه‌ی تمام وظایف، رانر aggregate و pairwise_diffs از درس 74 و CalibrationReport.from_predictions از درس 73 را فراخوانی می‌کند. خروجی نهایی یک پوشش (envelope) واحدِ JSON است:

{
  "leaderboard": [...],
  "pairwise": [...],
  "calibration": {
    "model_id_a": {"ece": 0.04, "brier": 0.10, "populated_bins": 8, ...},
    ...
  },
  "summary": {
    "tasks": 10,
    "models": 3,
    "wall_seconds": 1.2
  }
}

رانر همچنین یک جدول Markdown در خروجی استاندارد چاپ می‌کند تا کاربر بتواند نتیجه را مستقیماً در بررسی Pull Request بچسباند.

اجرای نمایشی خودپایان‌دهنده

دموی برنامه سه تطبیق‌دهنده‌ی ساختگی را روی 10 وظیفه‌ی فیکسچر درس 70 اجرا می‌کند. زمان اجرای واقعی (wall time) باید زیر 10 ثانیه بماند. اگر اجرا تمیز و بی‌نقص باشد، کد خروجی صفر خواهد بود.

معیارهای یک اجرای تمیز عبارتند از:

  • اعتبارسنجی همه‌ی وظایف بر اساس درس 70.
  • امتیازدهی تمام وظایف بر اساس درس‌های 71 و 72.
  • تجمیع بدون خطای گزارش کالیبراسیون با منطق درس 73.
  • قرار گرفتن تطبیق‌دهنده‌ی مبتنی بر قاعده بالاتر از تطبیق‌دهنده‌ی تصادفی در رتبه‌بندی جدول.

اگر هرکدام از این موارد نقض شود، رانر با کد غیرصفر خارج می‌شود و یک خطای ساختاریافته در پوشش JSON برمی‌گرداند.

این درس چه کارهایی انجام نمی‌دهد؟

در این درس به یک مدل واقعی متصل نمی‌شویم. جریان کاری مدیریت کلید API یا محدودیت نرخ درخواست را پیاده‌سازی نمی‌کنیم. خبری از استریمینگ یا تولید جزئی پاسخ نیست؛ تطبیق‌دهنده در هر فراخوانی دقیقاً یک خروجی برمی‌گرداند. همچنین مکانیزم تلاش مجدد یا کش کردن را پیاده نمی‌کنیم. این دغدغه‌ها به لایه‌ی تطبیق‌دهنده مربوط می‌شوند؛ رانر به نوع متریک و ارائه‌دهنده‌ی مدل کاملاً بی‌اعتنا و مستقل است.

راهنمای خواندن کد

فایل main.py محل یکپارچه‌سازی نهایی است. این فایل با کمک یک تابع کمکی کوچک به نام _load_sibling ماژول‌های پنج درس قبلی را از مسیر نسبی ایمپورت می‌کند. کلاس‌های داده‌ی Generation، EvalReport و ModelAdapter داخل خود فایل تعریف شده‌اند. تطبیق‌دهنده‌های ساختگی نیز در انتهای فایل قرار دارند.

کد main.py را از بالا به پایین بخوانید: ابتدا نگاهی گذرا به ایمپورت‌ها بیندازید، بعد سراغ run_eval و سپس _score_one بروید و در آخر تطبیق‌دهنده‌ها را ببینید. دموی انتهای فایل نقطه‌ی ورود برنامه است.

تست‌های موجود در code/tests/test_runner.py اینترفیس تطبیق‌دهنده، حلقه‌ی تک‌پیمایشی، یکسانی اجرای موازی و ترتیبی، بافر کالیبراسیون و ساختار پوشش JSON را تثبیت و بررسی می‌کنند.

گام‌های بعدی

این رانر تازه کفِ کار است. یک سامانه‌ی ارزیابی در محیط عملیاتی (پروداکشن) این موارد را اضافه می‌کند: کش نتایج با کلید ترکیبی (task_id, model_id, model_version)، دفتر ثبت هزینه‌ها برای رهگیری دلاری و توکنیِ هر اجرا، لایه‌ی تلاش مجدد با پس‌نشینی هنگام برخورد به محدودیت نرخ درخواست، سیاست نمونه‌برداری برای وظایف pass-at-k، و فرمت خروجی استریمینگ برای مجموعه‌آزمون‌های طولانی. هر یک از این موارد یک دغدغه‌ی مستقل است که بدون تغییر لایه‌های متریک یا تجمیع، دور رانر را می‌پوشاند. هدف از این قرارداد دقیقاً رسیدن به همین تفکیک وظایف است.

وقتی تطبیق‌دهنده‌های ساختگی به‌درستی کار کردند، یک تطبیق‌دهنده برای ارائه‌دهنده‌ای واقعی بنویسید. سرویسی با پلن رایگان انتخاب کنید، 30 خط کد اتصال بنویسید و روشن شدن جدول رده‌بندی را تماشا کنید. سپس ارائه‌دهنده‌ی دوم را اضافه کنید و کار را به این بستر آزمایشی بسپارید.

خودآزمایی

به سؤال‌ها جواب بدهید تا ببینید چقدر از درس در ذهنتان مانده است.

  1. پیش از درسکوچک‌ترین سطح ممکن برای رابط ModelAdapter چیست؟
  2. پیش از درسچرا رانر به‌جای اجرای همیشگی به‌صورت موازی، یک فلگ parallel دریافت می‌کند؟
  3. حین درسرانر چگونه فلگ صحیح بافر کالیبراسیون را تعیین می‌کند؟
  4. حین درسچرا رانر رکوردهای EvalRun را ایجاد کرده و تحویل تجمیع‌کننده می‌دهد، به‌جای اینکه لیدربورد را درون خودش محاسبه کند؟
  5. حین درسنقش بخش پرپلکسیتی در انولوپ نهایی JSON چیست؟
  6. پس از درسمعیار خروج با اجرای موفق (clean run) در دموی خودپایان‌پذیر چیست؟

سؤالات متداول

چرا در رانر ارزیابی از ThreadPoolExecutor استفاده می‌شود و نه فرایندهای جداگانه؟

چون در سناریوهای واقعی ارزیابی مدل، گلوگاه اصلی I/O شبکه ناشی از فراخوانی API مدل‌هاست و نخ‌ها برای این کار سبک و کافی هستند؛ البته در ارزیابی کدها (code_exec)، خود تسک یک ساب‌پراسس اختصاصی می‌سازد.

معیار تعیین پاسخ درست (correct) برای کالیبراسیون در این رانر چیست؟

برای متریک‌های تطابق قطعی مانند exact_match، accuracy و code_exec امتیاز مساوی یا بزرگ‌تر از 1.0، و برای متریک‌های درجه‌بندی‌شده امتیاز مساوی یا بزرگ‌تر از 0.5 به عنوان پاسخ درست ثبت می‌شود.

نقش اینترفیس ModelAdapter در این سیستم ارزیابی چیست؟

اینترفیس تطبیق‌دهنده مرز انتزاعی میان رانر و مدل است تا رانر بدون وابستگی به ارائه‌دهنده (API، محلی یا ساختگی)، تنها یک شیء استاندارد حاوی متن، درجه اطمینان و متادیتا دریافت کند.

ما رو توی گوگل بیشتر ببین

با افزودن نکست ادمین به «منابع ترجیحی» گوگل، درس‌ها و مطالب ما را در بخش اخبار برتر جستجو بیشتر می‌بینید.