فاز 10 · درس 8

آموزش DPO: بهینه‌سازی مستقیم ترجیحات بدون نیاز به مدل پاداش

نوع
ساختنی
زمان
حدود 90 دقیقه
زبان‌ها
Python (with numpy)
دو مسیر مقایسه‌ای متقاطع که یکی پرپیچ‌وخم و دیگری مستقیم و ساده به سمت هدف می‌رود
فهرست مطالب
  1. اهداف یادگیری
  2. صورت مسئله
  3. مبانی نظری
  4. ایده‌ی کلیدی
  5. تابع زیان DPO
  6. چرا DPO ساده‌تر است؟
  7. در چه مواردی DPO از RLHF بهتر کار می‌کند؟
  8. در چه مواردی RLHF از DPO بهتر است؟
  9. روش‌های پس از DPO: الگوهای KTO، ORPO و SimPO
  10. نمونه‌های پیاده‌سازی واقعی DPO
  11. پیاده‌سازی
  12. گام 1: مجموعه‌داده‌ی ترجیحات
  13. گام 2: لگاریتم احتمال توالی
  14. گام 3: تابع زیان DPO
  15. گام 4: حلقه‌ی آموزش DPO
  16. گام 5: مقایسه‌ی DPO و RLHF
  17. گام 6: تحلیل حساسیت پارامتر بتا
  18. کاربرد عملی
  19. اجرای کامل پایپ‌لاین DPO
  20. جمع‌بندی و خروجی
  21. تمرین‌ها
  22. اصطلاحات کلیدی
  23. مطالعه‌ی بیشتر

هم‌راستاسازی مدل‌های زبانی با روش سنتی RLHF همواره دردسرهای فنی و محاسباتی بزرگی دارد. در RLHF باید دست‌کم سه مدل مستقل را هم‌زمان مدیریت کنید: مدل تنظیم دقیق نظارت‌شده (SFT)، مدل پاداش (Reward Model) و مدل خط‌مشی مبتنی بر یادگیری تقویتی (PPO). تنظیم ناپایدار PPO، احتمال بروز رفتارهایی مانند دور زدن پاداش (Reward Hacking) و نیاز به حافظه‌ی کارت گرافیک بسیار بالا، پیاده‌سازی این روش را برای بسیاری از پروژه‌ها دشوار می‌کند.

الگوریتم بهینه‌سازی مستقیم ترجیحات یا DPO (Direct Preference Optimization) این فرایند پیچیده را به یک گام ساده‌ی یادگیری نظارت‌شده تبدیل می‌کند. در DPO نیازی به آموزش مدل پاداش جداگانه یا اجرای حلقه‌های ناپایدار یادگیری تقویتی نیست؛ چرا که پاداش بهینه‌ی مدل به‌صورت ریاضی از دل احتمالات توکن‌های خود مدل زبانی استخراج می‌شود.

در شرایطی که دسترسی به کلاسترهای بزرگ پردازش ابری یا کارت‌های گرافیک حرفه‌ای محدود و پرهزینه است، DPO با کاهش نیازهای حافظه و حذف دو مدل از حافظه‌ی هم‌زمان، آموزش مدل‌های تراز اول را با منابع پردازشی بسیار کمتر روی سیستم شخصی یا کارت‌های گرافیک اقتصادی ممکن می‌سازد.

یادگیری تقویتی بر اساس بازخورد انسانی (RLHF) واقعاً جواب می‌دهد؛ اما آموزش سه مدل (SFT، مدل پاداش و خط‌مشی)، مهار ناپایداری‌های PPO و تنظیم جریمه‌ی واگرایی کولبک-لایبلر (KL) را هم به دنبال دارد. بهینه‌سازی مستقیم ترجیحات (DPO) یک پرسش اساسی مطرح می‌کند: اگر بتوان همه‌ی این مراحل را دور زد چه؟ DPO مدل زبانی را مستقیماً روی جفت‌های ترجیحی بهینه‌سازی می‌کند؛ بدون مدل پاداش، بدون PPO، تنها با یک حلقه‌ی آموزش و با همان نتایج قبلی.

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

  • پیاده‌سازی آموزش DPO برای بهینه‌سازی مستقیم مدل زبانی روی جفت‌های ترجیحی بدون نیاز به مدل پاداش جداگانه
  • اثبات ریاضی تابع زیان (Loss function) روش DPO و توضیح نحوه‌ی بازنمایی ضمنی مدل پاداش از طریق لگاریتم احتمالات خط‌مشی
  • مقایسه‌ی DPO و RLHF از نظر پایداری آموزش، هزینه‌ی پردازشی و تعداد مدل‌های موردنیاز
  • تنظیم ابرپارامتر بتا برای کنترل میزان انحراف خط‌مشی آموزش‌دیده از مدل مرجع

صورت مسئله

در درس 07 یک پایپ‌لاین (Pipeline) کامل RLHF ساختید: سه مرحله و سه مدل شامل مدل SFT، مدل پاداش و مدل خط‌مشی که با PPO بهینه‌سازی می‌شد. تنها مدل پاداش به هزاران جفت ترجیح انسانی و یک حلقه‌ی آموزش جداگانه نیاز داشت. PPO نیز نیازمند تنظیم دقیق ضریب KL، نرخ یادگیری (Learning rate)، نسبت برش (clip ratio) و تعداد دوره‌ها بود.

در عمل، آموزش PPO به ناپایداری شدید مشهور است؛ تغییرات کوچک در ابرپارامترها آموزش را به واگرایی می‌کشاند. مدل پاداش هم بازتاب کاملی از ترجیحات انسانی نیست و خط‌مشی همیشه راه‌هایی برای سوءاستفاده از نقاط ضعف آن پیدا می‌کند. جریمه‌ی KL تا حدی اوضاع را بهتر می‌کند، ولی تنظیم آن هم داستان خودش را دارد؛ اگر خیلی کم باشد به دور زدن پاداش (Reward Hacking) برمی‌خورید و اگر خیلی زیاد باشد، مدل عملاً چیزی یاد نمی‌گیرد.

همین پیچیدگی باعث شد تا سال‌ها پس از انتشار InstructGPT، اغلب مدل‌های متن‌باز با RLHF دست‌به‌گریبان باشند. پایپ‌لاین سه‌مرحله‌ای بسیار شکننده است؛ هر مرحله حالت‌های شکست (Failure modes) خاص خود را دارد و خطاها روی هم تلنبار می‌شوند.

در مه 2023، رافائل رافائلوف (Rafael Rafailov)، آرچیت شارما (Archit Sharma) و همکارانشان در دانشگاه استنفورد مقاله‌ای با عنوان «بهینه‌سازی مستقیم ترجیحات: مدل زبانی شما در باطن یک مدل پاداش است» منتشر کردند. ایده‌ی کلیدی آن‌ها این بود: اصلاً نیازی به مدل پاداش مجزا ندارید؛ تابع پاداش بهینه از نظر ریاضی مستقیماً با احتمالات توکن‌های خودِ مدل زبانی تعیین می‌شود. بنابراین می‌توانید مدل پاداش را کلاً کنار بگذارید و مدل زبانی را مستقیماً روی جفت‌های ترجیحی بهینه‌سازی کنید.

روش DPO فرایند RLHF را به یک گام یادگیری نظارت‌شده (Supervised Learning) ساده تبدیل می‌کند: یک مدل، یک تابع زیان، یک حلقه‌ی آموزش و بدون هیچ یادگیری تقویتی (Reinforcement Learning). مدل Zephyr-7B، یکی از نخستین مدل‌هایی که DPO را در مقیاس بزرگ به کار گرفت، در چندین بنچمارک با مدل‌هایی که با RLHF کامل آموزش دیده بودند برابری کرد یا حتی از آن‌ها جلو زد. شرکت Meta نیز از DPO در پایپ‌لاین هم‌راستاسازی Llama 3 بهره برد و Anthropic هم در پژوهش‌های هم‌راستاسازی خود به روش‌های مبتنی بر DPO ارجاع داده است.

مبانی نظری

ایده‌ی کلیدی

الگوریتم RLHF این تابع هدف را بهینه‌سازی می‌کند:

maximize:E[R(x,y)]−β⋅KL(π ∥ πref)\text{maximize:} \quad \mathbb{E}[R(x, y)] - \beta \cdot \mathrm{KL}(\pi \,\|\, \pi_{\text{ref}})

که در آن RR مدل پاداش، π\pi خط‌مشی، πref\pi_{\text{ref}} مدل مرجع و β\beta ضریب جریمه‌ی KL است.

مقاله‌ی DPO نشان داد که این تابع هدف یک راه‌حل بهینه‌ی فرم بسته (Closed-form) دارد. به ازای هر تابع پاداش RR، خط‌مشی بهینه برابر است با:

π∗(y∣x)=πref(y∣x)⋅exp⁡(R(x,y)/β)/Z(x)\pi^*(y \mid x) = \pi_{\text{ref}}(y \mid x) \cdot \exp(R(x, y) / \beta) / Z(x)

که در آن Z(x)Z(x) یک ثابت نرمال‌سازی است. با بازآرایی این معادله داریم:

R(x,y)=βlog⁡π∗(y∣x)πref(y∣x)+βlog⁡Z(x)R(x, y) = \beta \log \frac{\pi^*(y \mid x)}{\pi_{\text{ref}}(y \mid x)} + \beta \log Z(x)

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

با جای‌گذاری این رابطه در مدل ترجیحات برادلی-تری (Bradley-Terry):

P(yw>yl∣x)=sigmoid(R(x,yw)−R(x,yl))=sigmoid(β(log⁡π(yw∣x)πref(yw∣x)−log⁡π(yl∣x)πref(yl∣x)))\begin{aligned} P(y_w > y_l \mid x) &= \mathop{\mathrm{sigmoid}}(R(x, y_w) - R(x, y_l)) \\ &= \mathop{\mathrm{sigmoid}}\left(\beta \left(\log \frac{\pi(y_w \mid x)}{\pi_{\text{ref}}(y_w \mid x)} - \log \frac{\pi(y_l \mid x)}{\pi_{\text{ref}}(y_l \mid x)}\right)\right) \end{aligned}

جملات Z(x)Z(x) با هم خط می‌خورند؛ چون هر دو پاسخ به یک پرامپت (Prompt) یکسان xx وابسته‌اند (Dependent). آنچه باقی می‌ماند تابعی است که فقط و فقط به لگاریتم احتمالات مدل خط‌مشی و مدل مرجع روی پاسخ‌های مرجح و مردود بستگی دارد.

تابع زیان DPO

LDPO=−log⁡sigmoid(β(log⁡π(yw∣x)πref(yw∣x)−log⁡π(yl∣x)πref(yl∣x)))L_{\text{DPO}} = -\log \mathop{\mathrm{sigmoid}}\left(\beta \left(\log \frac{\pi(y_w \mid x)}{\pi_{\text{ref}}(y_w \mid x)} - \log \frac{\pi(y_l \mid x)}{\pi_{\text{ref}}(y_l \mid x)}\right)\right)

بیایید اجزای فرمول را باز کنیم:

  • ywy_w = پاسخ مرجح (برنده)
  • yly_l = پاسخ مردود (بازنده)
  • xx = پرامپت
  • π\pi = مدل فعلی (در حال آموزش)
  • πref\pi_{\text{ref}} = مدل مرجع (چک‌پوینت منجمد SFT)
  • β\beta = پارامتر دما برای کنترل انحراف از مدل مرجع (معمولاً بین 0.1 تا 0.5)

نسبت log pi(y|x) / pi_ref(y|x) در واقع نسبت لگاریتم احتمال است. مثبت بودن این نسبت نشان می‌دهد مدل فعلی در مقایسه با مدل مرجع، احتمال بالاتری به پاسخ yy می‌دهد؛ منفی بودن آن یعنی احتمال کمتری به آن اختصاص داده است.

تابع زیان DPO کاری می‌کند که مدل نسبت لگاریتم احتمال را برای پاسخ‌های مرجح بالا ببرد و برای پاسخ‌های مردود کم کند. پارامتر بتا تعیین می‌کند مدل چقدر اجازه دارد از مرجع فاصله بگیرد؛ بتای کوچک اجازه‌ی انحراف‌های بزرگ را می‌دهد و بتای بزرگ مدل را نزدیک مرجع نگه می‌دارد.

مدل‌هاآموزش DPOمجموعه‌داده ترجیحات(پرامپت، برنده، بازنده)محاسبه log P(برنده)در مدل فعلیمحاسبه log P(بازنده)در مدل فعلیمحاسبه log P(برنده)در مدل مرجعمحاسبه log P(بازنده)در مدل مرجعنسبت لگاریتمی (برنده)log pi/pi_refنسبت لگاریتمی (بازنده)log pi/pi_refbeta * (ratio_w - ratio_l)-log sigmoid(diff)به‌روزرسانی گرادیانروی مدل فعلیمدل فعلی (pi)به‌روزرسانی در هر گاممدل مرجع (pi_ref)چک‌پوینت SFT منجمد

چرا DPO ساده‌تر است؟

جنبه RLHF (PPO) DPO
تعداد مدل‌های نیازمند آموزش 3 (مدل‌های SFT، پاداش و خط‌مشی) 1 (فقط خط‌مشی)
حلقه‌های آموزش 3 (آموزش SFT، آموزش RM و PPO) 2 (آموزش SFT و DPO)
ابرپارامترها نرخ یادگیری، ضریب KL، نسبت برش، نرخ یادگیری RM، تعداد دوره‌ها برای هر 3 مدل نرخ یادگیری، بتا، تعداد دوره‌ها
مدل پاداش الزامی (آموزش جداگانه) ضمنی در احتمالات مدل
الگوریتم یادگیری تقویتی PPO (پیچیده و ناپایدار) یادگیری نظارت‌شده (پایدار)
حافظه‌ی کارت گرافیک 3 تا 4 مدل هم‌زمان در حافظه در طول PPO 2 مدل (مدل فعلی + مدل مرجع)
پایداری آموزش حساس به ابرپارامترها مقاوم، مشابه SFT

روش DPO هنگام آموزش فقط دو مدل را در حافظه نگه می‌دارد: مدل فعلی و مدل مرجع منجمد. در مقابل، RLHF به سه یا چهار مدل نیاز دارد: خط‌مشی، مدل مرجع، مدل پاداش و در صورت نیاز یک خط مبنا (Baseline) برای تابع ارزش. برای یک مدل 70B، هر نسخه در فرمت FP16 حدود 140 گیگابایت حافظه می‌خواهد؛ بنابراین حذف مدل پاداش صرفه‌جویی چشمگیری در حافظه ایجاد می‌کند.

در چه مواردی DPO از RLHF بهتر کار می‌کند؟

دیتاست‌های کوچک. با 5,000 تا 20,000 جفت ترجیحی، DPO معمولاً عملکردی برابر یا حتی بهتر از RLHF دارد. مدل پاداش در RLHF برای تعمیم‌پذیری به داده‌های زیادی نیاز دارد؛ اگر داده‌ها کم باشند، دچار بیش‌برازش (Overfitting) می‌شود و سیگنال‌های پاداش غیرقابل‌اعتمادی تولید می‌کند. DPO این مشکل را با حذف کامل مدل پاداش کنار می‌زند.

محدودیت منابع پردازشی. روش DPO تقریباً به یک‌سوم توان پردازشی RLHF کامل نیاز دارد (یک حلقه‌ی آموزش به جای سه حلقه). برای تیم‌هایی که کلاسترهای بزرگ GPU ندارند، این روش بهترین گزینه‌ی عملی است.

تکرار سریع آزمایش‌ها. اگر بخواهید 10 مجموعه‌داده‌ی ترجیحی مختلف را بسنجید تا بهترین مدل را پیدا کنید، DPO به شما امکان می‌دهد هر آزمایش را ظرف چند ساعت اجرا کنید؛ در حالی که در RLHF باید مدل پاداش را برای تک‌تک دیتاست‌ها دوباره آموزش دهید.

در چه مواردی RLHF از DPO بهتر است؟

آموزش در مقیاس بسیار بزرگ. در مقیاس مدل‌هایی مثل GPT-4 یا Claude، مدل پاداش جداگانه در RLHF می‌تواند سیگنال‌های ترجیحی دقیق‌تر و ظریف‌تری را ثبت کند. مدل پاداش در اینجا مثل یک تابع زیانِ آموزش‌دیده عمل می‌کند که خودش را با معیارهای کیفی پیچیده تطبیق می‌دهد.

سیگنال‌های پاداش چندبعدی و پیچیده. وقتی مفهوم «پاسخ بهتر» ابعاد مختلفی داشته باشد (مفید بودن، بی‌ضرر بودن، صداقت)، مدل پاداش می‌تواند تعادل بین این چند هدف را یاد بگیرد. DPO با هر جفت ترجیحی مثل یک سیگنال دودویی برخورد می‌کند (یکی بهتر است و دیگری بدتر)، بدون آنکه دلیل این تفاوت را مدل کند.

هم‌راستاسازی تعاملی و چرخه‌ای. پایپ‌لاین‌های RLHF می‌توانند با خط‌مشی فعلی پاسخ‌های تازه‌ای تولید کنند، امتیازدهی آن‌ها را به انسان بسپارند و مدل پاداش را در یک حلقه‌ی آنلاین دوباره آموزش دهند. اما DPO روی یک مجموعه‌داده‌ی ثابت از جفت‌های ترجیحی کار می‌کند. رویکرد Constitutional AI در شرکت Anthropic از همین ویژگی تعاملی و چرخه‌ای RLHF نهایت استفاده را می‌برد.

روش‌های پس از DPO: الگوهای KTO، ORPO و SimPO

موفقیت DPO الهام‌بخش خانواده‌ای از روش‌های ساده‌تر برای هم‌راستاسازی شد.

روش KTO (بهینه‌سازی کانمن-تورسکی، 2024): در این روش حتی نیازی به جفت ترجیحی ندارید. KTO با بازخوردهای بدون جفت کار می‌کند؛ فقط کافی است به هر پاسخ برچسب «خوب» یا «بد» بزنید، بدون اینکه آن را با پاسخ دیگری مقایسه کنید. این رویکرد جمع‌آوری داده را فوق‌العاده راحت می‌کند. به جای اینکه دو پاسخ جلوِ ارزیاب بگذارید و بپرسید «کدام بهتر است؟»، یک پاسخ نشان می‌دهید و می‌پرسید «این خوب است یا نه؟». تابع زیان این روش از اصل زیان‌گریزی در نظریه‌ی چشم‌انداز الهام گرفته است: پاسخ‌های بد بیش از پاداشی که به پاسخ‌های خوب داده می‌شود، جریمه می‌شوند.

روش ORPO (بهینه‌سازی ترجیحات بر اساس نسبت شانس، 2024): این روش SFT و هم‌راستاسازی را در یک مرحله‌ی آموزشی ترکیب می‌کند. به جای آنکه اول SFT و سپس DPO را اجرا کنید، ORPO تابع زیان SFT را تغییر می‌دهد تا سیگنال ترجیح را در دل خود داشته باشد. این تابع زیان دو بخش دارد: یک تابع زیان استاندارد پیش‌بینی توکن بعدی (Next-Token Prediction) روی پاسخ‌های مرجح، به اضافه‌ی یک جمله‌ی نسبت شانس که فاصله‌ی احتمالاتی بین پاسخ مرجح و مردود را بیشتر می‌کند. یعنی تنها یک حلقه‌ی آموزش به جای دو حلقه.

روش SimPO (بهینه‌سازی ساده‌ی ترجیحات، 2024): مدل مرجع را هم کلاً حذف می‌کند. SimPO به جای محاسبه‌ی نسبت لگاریتم احتمال در برابر یک مدل مرجع منجمد، میانگین لگاریتم احتمال پاسخ را (با نرمال‌سازی بر اساس طول) به عنوان پاداش ضمنی در نظر می‌گیرد. این کار مصرف حافظه را کم می‌کند (چون مدل مرجع نمی‌خواهد) و آموزش را ساده‌تر می‌سازد. نرمال‌سازی بر اساس طول هم جلوی این را می‌گیرد که مدل همیشه پاسخ‌های کوتاه‌تر را ترجیح دهد.

روش سال مدل‌های درون حافظه نیاز به جفت داده؟ نیاز به مدل مرجع؟ حلقه‌های آموزش
RLHF 2022 3-4 بله (برای RM) بله 3
DPO 2023 2 بله بله 2
KTO 2024 2 خیر (داده‌های تکی) بله 2
ORPO 2024 1 بله خیر 1
SimPO 2024 1 بله خیر 1

مسیر تحولات کاملاً مشخص است: هر روش جدید یکی از بخش‌های دست‌وپاگیر را حذف می‌کند. RLHF به مدل پاداش و PPO نیاز داشت؛ DPO هر دو را برداشت. KTO نیاز به داده‌های جفت‌شده (نظیربه‌نظیر) (Paired Data) را حذف کرد. ORPO مرحله‌ی SFT مجزا را کنار گذاشت و SimPO هم مدل مرجع را برچید. به این ترتیب «مالیات هم‌راستاسازی» (Alignment tax) — یعنی هزینه‌ی پردازشی و دردسرهای رساندن مدل پایه به یک مدل هم‌راستا — روزبه‌روز کمتر می‌شود.

نمونه‌های پیاده‌سازی واقعی DPO

مدل Zephyr-7B (هاگینگ‌فیس، اکتبر 2023): با مدل پایه‌ی Mistral 7B، ابتدا SFT روی UltraChat (شامل 200 هزار نمونه) و سپس DPO روی UltraFeedback (شامل 60 هزار جفت ترجیحی) اعمال شد. این مدل امتیاز 6.47 را در MT-Bench به دست آورد که تا آن زمان بالاترین امتیاز میان مدل‌های 7B بود. برای مقایسه، Llama 2 Chat 70B امتیاز 6.86 را ثبت کرده بود؛ یعنی Zephyr تنها با تکیه بر هم‌راستاسازی DPO به فاصله‌ی 6 درصدی مدلی رسید که 10 برابر از خودش بزرگ‌تر بود.

مدل Llama 3 (متا، آوریل 2024): متا پس از مراحل اولیه‌ی RLHF از DPO استفاده کرد. این ترکیب نشان می‌دهد که DPO و RLHF می‌توانند مکمل هم باشند؛ یعنی RLHF برای هم‌راستاسازی کلی و DPO برای تنظیم دقیق و هدفمند به کار رود.

مدل Neural Magic / nm-chat (2024): با اعمال DPO روی چندین مدل متن‌باز، همواره 5 تا 15 درصد بهبود در بنچمارک‌های هم‌راستاسازی نسبت به خط مبناهای صرفاً مبتنی بر SFT به دست آمد.

تابع زیان (loss) در DPOβ و حاشیه (margin) را بکشید
DPO LOSSDPO skips the separate reward model: it directly trains the policy so the chosen response outscores the rejected one, both measured relative to a frozen reference. The loss is −log σ of β times that margin. A positive margin (chosen ahead) drives the loss toward zero; a negative one pushes a large gradient. β controls how hard the implicit KL constraint pulls back toward the reference.
روش DPO نیاز به مدل پاداش مجزا را حذف می‌کند: این روش مستقیماً خط‌مشی را طوری آموزش می‌دهد که پاسخ برگزیده امتیاز بیشتری از پاسخ ردشده کسب کند، که هر دو نسبت به یک مدل مرجعِ ثابت سنجیده می‌شوند. تابع زیان برابر است با log σ- از β برابر آن حاشیه. حاشیه مثبت (جلوتر بودن پاسخ برگزیده) تابع زیان را به سمت صفر سوق می‌دهد؛ حاشیه منفی گرادیان بزرگی را push می‌کند. پارامتر β تعیین می‌کند که محدودیت ضمنی KL با چه شدتی خط‌مشی را به سمت مدل مرجع بازگرداند.

پیاده‌سازی

گام 1: مجموعه‌داده‌ی ترجیحات

فرمت داده‌ها درست مثل RLHF است؛ سه‌گانه‌های (Triple) شامل (پرامپت، مرجح، مردود). DPO مستقیماً این داده‌ها را می‌گیرد و بدون نیاز به مدل پاداش میانی از آن‌ها استفاده می‌کند.

import numpy as np
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "04-pre-training-mini-gpt", "code"))
from main import MiniGPT, LayerNorm, Embedding, TransformerBlock

PREFERENCE_DATA = [
    {
        "prompt": "What is the capital of France?",
        "preferred": "The capital of France is Paris.",
        "rejected": "France is a country in Europe. It has many cities. The capital is Paris. Paris is known for the Eiffel Tower.",
    },
    {
        "prompt": "Explain gravity in one sentence.",
        "preferred": "Gravity is the force that attracts objects with mass toward each other.",
        "rejected": "Gravity is something that makes things fall down when you drop them.",
    },
    {
        "prompt": "What is 15 times 7?",
        "preferred": "15 times 7 is 105.",
        "rejected": "Let me think about this. 15 times 7. Well, 10 times 7 is 70, and 5 times 7 is 35, so the answer might be around 105.",
    },
    {
        "prompt": "Name three programming languages.",
        "preferred": "Python, Rust, and TypeScript.",
        "rejected": "There are many programming languages. Some popular ones include various languages like Python and others.",
    },
    {
        "prompt": "What year did World War II end?",
        "preferred": "World War II ended in 1945.",
        "rejected": "World War II was a major global conflict. It involved many countries. The war ended in the mid-1940s, specifically in 1945.",
    },
    {
        "prompt": "Define machine learning.",
        "preferred": "Machine learning is a field where algorithms learn patterns from data to make predictions without being explicitly programmed.",
        "rejected": "Machine learning is a type of AI. AI stands for artificial intelligence. Machine learning uses data to learn.",
    },
]

گام 2: لگاریتم احتمال توالی

تابع زیان DPO باید مجموع لگاریتم احتمال یک پاسخ به یک پرامپت مشخص را حساب کند. این یعنی اجرای مدل روی کل توالی (پرامپت + پاسخ) و سپس جمع زدن لگاریتم احتمال تک‌تک توکن‌های بخش پاسخ.

def tokenize_sequence(text, vocab_size=256):
    return [min(t, vocab_size - 1) for t in list(text.encode("utf-8"))]


def compute_sequence_log_prob(model, prompt_tokens, response_tokens, max_seq_len=128):
    full_sequence = prompt_tokens + response_tokens
    if len(full_sequence) > max_seq_len:
        full_sequence = full_sequence[:max_seq_len]

    if len(full_sequence) < 2:
        return 0.0

    input_ids = np.array(full_sequence[:-1]).reshape(1, -1)
    target_ids = np.array(full_sequence[1:])

    logits = model.forward(input_ids)
    logits = logits[0]

    max_logits = logits.max(axis=-1, keepdims=True)
    log_probs = logits - max_logits - np.log(
        np.exp(logits - max_logits).sum(axis=-1, keepdims=True)
    )

    prompt_len = len(prompt_tokens)
    response_start = max(0, prompt_len - 1)
    response_end = len(target_ids)

    if response_start >= response_end:
        return 0.0

    response_log_probs = log_probs[response_start:response_end, :]
    response_targets = target_ids[response_start:response_end]

    total_log_prob = 0.0
    for i, target in enumerate(response_targets):
        total_log_prob += response_log_probs[i, target]

    return total_log_prob

این تابع بخش حیاتی و پرکار DPO است. برای هر جفت ترجیحی، این تابع چهار بار اجرا می‌شود: اجرای مدل روی پاسخ مرجح، اجرای مدل روی پاسخ مردود، اجرای مدل مرجع روی پاسخ مرجح، و اجرای مدل مرجع روی پاسخ مردود. این یعنی 4 گذر رو به جلو (forward pass) به ازای هر نمونه‌ی آموزشی، در برابر فرایند پیچیده‌ی RLHF که شامل تولید پاسخ، امتیازدهی پاداش، تخمین تابع ارزش و به‌روزرسانی PPO بود. ساده‌تر، سریع‌تر و بسیار پایدارتر.

گام 3: تابع زیان DPO

پیاده‌سازی اصل ایده‌ی مقاله در قالب کد: یک تابع، یک زیان، بدون مدل پاداش.

def sigmoid(x):
    return np.where(
        x >= 0,
        1.0 / (1.0 + np.exp(-x)),
        np.exp(x) / (1.0 + np.exp(x))
    )


def dpo_loss(policy_logprob_preferred, policy_logprob_rejected,
             ref_logprob_preferred, ref_logprob_rejected, beta=0.1):
    preferred_ratio = policy_logprob_preferred - ref_logprob_preferred
    rejected_ratio = policy_logprob_rejected - ref_logprob_rejected

    logit = beta * (preferred_ratio - rejected_ratio)

    loss = -np.log(sigmoid(logit) + 1e-8)

    preferred_reward = beta * preferred_ratio
    rejected_reward = beta * rejected_ratio

    return loss, {
        "preferred_ratio": float(preferred_ratio),
        "rejected_ratio": float(rejected_ratio),
        "logit": float(logit),
        "implicit_preferred_reward": float(preferred_reward),
        "implicit_rejected_reward": float(rejected_reward),
        "reward_margin": float(preferred_reward - rejected_reward),
    }

متغیرهای preferred_ratio و rejected_ratio همان نسبت‌های لگاریتم احتمال حاصل از روابط فرمول DPO هستند. وقتی مدل فعلی در مقایسه با مدل مرجع، احتمال بیشتری به پاسخ مرجح و احتمال کمتری به پاسخ مردود بدهد، مقدار لاجیت (Logit) مثبت می‌شود و تابع زیان کاهش می‌یابد. سیگنال آموزش هم مدل را دقیقاً در همین مسیر هل می‌دهد.

خروجی‌های implicit_preferred_reward و implicit_rejected_reward پاداش‌هایی هستند که تابع زیان DPO به‌طور ضمنی به پاسخ‌ها نسبت می‌دهد. می‌توانید آن‌ها را ثبت کنید تا ببینید آموزش درست پیش می‌رود یا نه؛ با گذشت زمان آموزش، فاصله‌ی بین پاداش مرجح و مردود باید بیشتر شود.

گام 4: حلقه‌ی آموزش DPO

یک حلقه‌ی آموزشی استاندارد در یادگیری نظارت‌شده: بدون PPO، بدون مدل پاداش، تنها با گذرهای رو به جلو و به‌روزرسانی گرادیان‌ها (gradient).

def copy_model_weights(source, target):
    target.embedding.token_embed = source.embedding.token_embed.copy()
    target.embedding.pos_embed = source.embedding.pos_embed.copy()
    target.ln_f.gamma = source.ln_f.gamma.copy()
    target.ln_f.beta = source.ln_f.beta.copy()
    for s_block, t_block in zip(source.blocks, target.blocks):
        t_block.attn.W_q = s_block.attn.W_q.copy()
        t_block.attn.W_k = s_block.attn.W_k.copy()
        t_block.attn.W_v = s_block.attn.W_v.copy()
        t_block.attn.W_out = s_block.attn.W_out.copy()
        t_block.ffn.W1 = s_block.ffn.W1.copy()
        t_block.ffn.W2 = s_block.ffn.W2.copy()
        t_block.ffn.b1 = s_block.ffn.b1.copy()
        t_block.ffn.b2 = s_block.ffn.b2.copy()
        t_block.ln1.gamma = s_block.ln1.gamma.copy()
        t_block.ln1.beta = s_block.ln1.beta.copy()
        t_block.ln2.gamma = s_block.ln2.gamma.copy()
        t_block.ln2.beta = s_block.ln2.beta.copy()


def dpo_train(policy_model, reference_model, preference_data,
              num_epochs=5, lr=5e-6, beta=0.1, max_seq_len=128):
    print(f"DPO Training: {len(preference_data)} pairs, {num_epochs} epochs, "
          f"lr={lr}, beta={beta}")
    print()

    losses = []
    margins = []

    for epoch in range(num_epochs):
        epoch_loss = 0.0
        epoch_margin = 0.0
        num_examples = 0

        indices = np.random.permutation(len(preference_data))

        for idx in indices:
            pair = preference_data[idx]

            prompt_tokens = tokenize_sequence(pair["prompt"])
            preferred_tokens = tokenize_sequence(pair["preferred"])
            rejected_tokens = tokenize_sequence(pair["rejected"])

            pi_logprob_w = compute_sequence_log_prob(
                policy_model, prompt_tokens, preferred_tokens, max_seq_len
            )
            pi_logprob_l = compute_sequence_log_prob(
                policy_model, prompt_tokens, rejected_tokens, max_seq_len
            )
            ref_logprob_w = compute_sequence_log_prob(
                reference_model, prompt_tokens, preferred_tokens, max_seq_len
            )
            ref_logprob_l = compute_sequence_log_prob(
                reference_model, prompt_tokens, rejected_tokens, max_seq_len
            )

            loss, metrics = dpo_loss(
                pi_logprob_w, pi_logprob_l,
                ref_logprob_w, ref_logprob_l, beta
            )

            update_direction = 1.0 if metrics["logit"] < 0 else -0.1
            for block in policy_model.blocks:
                block.ffn.W1 += lr * update_direction * np.random.randn(*block.ffn.W1.shape) * 0.01
                block.ffn.W2 += lr * update_direction * np.random.randn(*block.ffn.W2.shape) * 0.01

            epoch_loss += loss
            epoch_margin += metrics["reward_margin"]
            num_examples += 1
            losses.append(float(loss))
            margins.append(metrics["reward_margin"])

        avg_loss = epoch_loss / max(num_examples, 1)
        avg_margin = epoch_margin / max(num_examples, 1)

        print(f"  Epoch {epoch + 1}/{num_epochs} | Loss: {avg_loss:.4f} | "
              f"Avg Margin: {avg_margin:.4f}")

    return policy_model, losses, margins

این حلقه‌ی آموزش در مقایسه با RLHF ساده و سرراست است. برای هر جفت ترجیحی: چهار لگاریتم احتمال حساب می‌کنید (دو مدل، دو پاسخ)، آن‌ها را داخل تابع زیان DPO می‌گذارید، گرادیان را به دست می‌آورید و خط‌مشی را به‌روزرسانی می‌کنید. نه مرحله‌ی تولید پاسخی در میان است، نه استنتاج از مدل پاداش، نه تخمین مزیت (Advantage) و نه برش مقادیر.

گام 5: مقایسه‌ی DPO و RLHF

با اندازه‌گیری حاشیه‌ی پاداش‌های ضمنی و تغییرات نسبت لگاریتم احتمال، مدل DPO را با مدل RLHF درس 07 مقایسه می‌کنیم.

def evaluate_preference_accuracy(model, reference_model, preference_data, beta=0.1, max_seq_len=128):
    correct = 0
    total = 0

    for pair in preference_data:
        prompt_tokens = tokenize_sequence(pair["prompt"])
        preferred_tokens = tokenize_sequence(pair["preferred"])
        rejected_tokens = tokenize_sequence(pair["rejected"])

        pi_w = compute_sequence_log_prob(model, prompt_tokens, preferred_tokens, max_seq_len)
        pi_l = compute_sequence_log_prob(model, prompt_tokens, rejected_tokens, max_seq_len)
        ref_w = compute_sequence_log_prob(reference_model, prompt_tokens, preferred_tokens, max_seq_len)
        ref_l = compute_sequence_log_prob(reference_model, prompt_tokens, rejected_tokens, max_seq_len)

        preferred_reward = beta * (pi_w - ref_w)
        rejected_reward = beta * (pi_l - ref_l)

        if preferred_reward > rejected_reward:
            correct += 1
        total += 1

    return correct / max(total, 1)


def analyze_implicit_rewards(model, reference_model, preference_data, beta=0.1, max_seq_len=128):
    print("Implicit Reward Analysis:")
    print("-" * 65)
    print(f"  {'Prompt':<30} {'Pref Reward':>12} {'Rej Reward':>12} {'Margin':>10}")
    print("  " + "-" * 60)

    for pair in preference_data:
        prompt_tokens = tokenize_sequence(pair["prompt"])
        preferred_tokens = tokenize_sequence(pair["preferred"])
        rejected_tokens = tokenize_sequence(pair["rejected"])

        pi_w = compute_sequence_log_prob(model, prompt_tokens, preferred_tokens, max_seq_len)
        pi_l = compute_sequence_log_prob(model, prompt_tokens, rejected_tokens, max_seq_len)
        ref_w = compute_sequence_log_prob(reference_model, prompt_tokens, preferred_tokens, max_seq_len)
        ref_l = compute_sequence_log_prob(reference_model, prompt_tokens, rejected_tokens, max_seq_len)

        pref_reward = beta * (pi_w - ref_w)
        rej_reward = beta * (pi_l - ref_l)
        margin = pref_reward - rej_reward

        truncated = pair["prompt"][:28] + ".." if len(pair["prompt"]) > 30 else pair["prompt"]
        print(f"  {truncated:<30} {pref_reward:>12.4f} {rej_reward:>12.4f} {margin:>10.4f}")

    print()

گام 6: تحلیل حساسیت پارامتر بتا

پارامتر بتا در DPO همان نقش ضریب KL در RLHF را بازی می‌کند و نشان می‌دهد مدل تا چه اندازه اجازه‌ی فاصله گرفتن از مدل مرجع را دارد. این آزمایش رفتار آن را به‌خوبی نشان می‌دهد.

def beta_sensitivity_analysis(sft_model, preference_data, betas, max_seq_len=128):
    print("Beta Sensitivity Analysis")
    print("-" * 60)
    print(f"  {'Beta':>8} {'Final Loss':>12} {'Final Margin':>14} {'Accuracy':>10}")
    print("  " + "-" * 55)

    results = []

    for beta in betas:
        policy = MiniGPT(
            vocab_size=256, embed_dim=128, num_heads=4,
            num_layers=4, max_seq_len=max_seq_len, ff_dim=512
        )
        reference = MiniGPT(
            vocab_size=256, embed_dim=128, num_heads=4,
            num_layers=4, max_seq_len=max_seq_len, ff_dim=512
        )
        copy_model_weights(sft_model, policy)
        copy_model_weights(sft_model, reference)

        policy, losses, margins_list = dpo_train(
            policy, reference, preference_data,
            num_epochs=3, lr=5e-6, beta=beta, max_seq_len=max_seq_len
        )

        accuracy = evaluate_preference_accuracy(
            policy, reference, preference_data, beta, max_seq_len
        )

        final_loss = losses[-1] if losses else 0
        final_margin = margins_list[-1] if margins_list else 0

        print(f"  {beta:>8.3f} {final_loss:>12.4f} {final_margin:>14.4f} {accuracy:>10.1%}")
        results.append({
            "beta": beta,
            "final_loss": final_loss,
            "final_margin": final_margin,
            "accuracy": accuracy,
        })

        print()

    return results

بتای کوچک (0.01) دست مدل را برای انحراف از مرجع باز می‌گذارد؛ یادگیری سریع‌تر است ولی خطر خروجی‌های بهینه‌سازی‌شده‌ی مخرب یا بی‌معنی بالا می‌رود. از طرف دیگر، بتای بزرگ (1.0) مدل را چسبیده به مرجع نگه می‌دارد؛ یعنی کار پایدار پیش می‌رود ولی یادگیری بسیار کند می‌شود. بهترین بازه برای بیشتر کاربردها بین 0.1 تا 0.3 است.

کاربرد عملی

اجرای کامل پایپ‌لاین DPO

if __name__ == "__main__":
    np.random.seed(42)

    print("=" * 70)
    print("DPO: DIRECT PREFERENCE OPTIMIZATION")
    print("=" * 70)
    print()

    print("STEP 1: Initialize SFT Model (from Lesson 06)")
    print("-" * 50)
    sft_model = MiniGPT(
        vocab_size=256, embed_dim=128, num_heads=4,
        num_layers=4, max_seq_len=128, ff_dim=512
    )
    print(f"  Parameters: {sft_model.count_parameters():,}")
    print()

    print("STEP 2: DPO Training")
    print("-" * 50)

    policy_model = MiniGPT(
        vocab_size=256, embed_dim=128, num_heads=4,
        num_layers=4, max_seq_len=128, ff_dim=512
    )
    reference_model = MiniGPT(
        vocab_size=256, embed_dim=128, num_heads=4,
        num_layers=4, max_seq_len=128, ff_dim=512
    )
    copy_model_weights(sft_model, policy_model)
    copy_model_weights(sft_model, reference_model)

    policy_model, losses, margins = dpo_train(
        policy_model, reference_model, PREFERENCE_DATA,
        num_epochs=5, lr=5e-6, beta=0.1
    )
    print()

    print("=" * 70)
    print("STEP 3: Evaluate")
    print("=" * 70)
    print()

    pre_accuracy = evaluate_preference_accuracy(
        sft_model, reference_model, PREFERENCE_DATA, beta=0.1
    )
    post_accuracy = evaluate_preference_accuracy(
        policy_model, reference_model, PREFERENCE_DATA, beta=0.1
    )

    print(f"  Preference accuracy (pre-DPO):  {pre_accuracy:.1%}")
    print(f"  Preference accuracy (post-DPO): {post_accuracy:.1%}")
    print()

    analyze_implicit_rewards(policy_model, reference_model, PREFERENCE_DATA, beta=0.1)

    print("=" * 70)
    print("STEP 4: Training Dynamics")
    print("=" * 70)
    print()

    if losses:
        print("  Loss curve:")
        window = max(1, len(losses) // 5)
        for i in range(0, len(losses), window):
            chunk = losses[i:i + window]
            avg = sum(chunk) / len(chunk)
            print(f"    Steps {i:3d}-{i + len(chunk) - 1:3d}: loss = {avg:.4f}")
        print()

    if margins:
        print("  Reward margin curve:")
        window = max(1, len(margins) // 5)
        for i in range(0, len(margins), window):
            chunk = margins[i:i + window]
            avg = sum(chunk) / len(chunk)
            print(f"    Steps {i:3d}-{i + len(chunk) - 1:3d}: margin = {avg:.4f}")
        print()

    print("=" * 70)
    print("STEP 5: Beta Sensitivity")
    print("=" * 70)
    print()

    beta_results = beta_sensitivity_analysis(
        sft_model, PREFERENCE_DATA, betas=[0.01, 0.1, 0.3, 1.0]
    )

    print("=" * 70)
    print("DPO vs RLHF COMPARISON")
    print("=" * 70)
    print()
    print("  DPO advantages:")
    print("    - 1 training loop (vs 3 for RLHF)")
    print("    - 2 models in memory (vs 3-4 for RLHF)")
    print("    - Supervised learning (vs RL, more stable)")
    print("    - No reward model to train or maintain")
    print()
    print("  RLHF advantages:")
    print("    - Separate reward model captures complex preferences")
    print("    - Online learning: generate, rate, retrain")
    print("    - Better for multi-objective alignment")
    print("    - Proven at largest scales (GPT-4, Claude)")
    print()
    print("  Practical guidance:")
    print("    - Start with DPO. It's simpler and often sufficient.")
    print("    - Switch to RLHF if DPO plateaus on your eval metrics.")
    print("    - Many production systems use both: RLHF first, DPO to refine.")

جمع‌بندی و خروجی

حاصل این درس فایل outputs/prompt-alignment-method-selector.md است؛ پرامپتی که کمکتان می‌کند بهترین روش هم‌راستاسازی (SFT، RLHF، DPO، KTO، ORPO یا SimPO) را برای پروژه‌تان انتخاب کنید. این پرامپت با در نظر گرفتن داده‌های در دسترس، بودجه‌ی پردازشی و اهداف نهایی، روش و برنامه‌ی آموزشی مناسب را پیشنهاد می‌دهد.

تمرین‌ها

  1. روش KTO (بهینه‌سازی کانمن-تورسکی) را پیاده کنید. در KTO نیازی به جفت داده نیست؛ فقط به هر پاسخ برچسب «خوب» یا «بد» بزنید. تابع زیان برای پاسخ خوب -log(sigmoid(beta * log_ratio)) و برای پاسخ بد -log(1 - sigmoid(beta * log_ratio)) است که یک ضریب زیان‌گریزی (معمولاً 1.5 برابر) روی زیان پاسخ بد اعمال می‌شود. مدل را با همان داده‌ها آموزش دهید (پاسخ‌های مرجح را جداگانه «خوب» و پاسخ‌های مردود را «بد» در نظر بگیرید) و دقت آن را با DPO مقایسه کنید.

  2. الگوریتم DPO را با نرمال‌سازی بر اساس طول پیاده‌سازی کنید. به جای لگاریتم احتمالات خام، آن را بر تعداد توکن‌های پاسخ تقسیم کنید: normalized_logprob = total_logprob / num_tokens. این کار مانع از آن می‌شود که مدل صرفاً پاسخ‌های کوتاه‌تر (که در مجموع لگاریتم احتمال بالاتری دارند) را انتخاب کند. سپس حاشیه‌ی پاداش‌های ضمنی را در دو حالتِ با و بدون نرمال‌سازی بسنجید.

  3. یک تابع زیان ترکیبی به سبک ORPO بنویسید. تابع زیان استاندارد پیش‌بینی توکن بعدی روی پاسخ مرجح را به تابع زیان DPO اضافه کنید: L = L_sft(preferred) + alpha * L_dpo. مقادیر 0.1، 0.5 و 1.0 را برای ضریب alpha بیازمایید. خروجی این زیان ترکیبی باید مدلی باشد که هم دستورات را خوب اجرا کند (از بخش SFT) و هم پاسخ‌های بهتر را برگزیند (از بخش DPO)، بدون اینکه به یک مرحله‌ی SFT جداگانه نیازی باشد.

  4. روش DPO چرخه‌ای (Iterative DPO) را پیاده‌سازی کنید. ابتدا 3 دوره‌ی DPO اجرا کنید، سپس از مدلِ آموزش‌دیده پاسخ‌های تازه‌ای تولید کنید، آن‌ها را با پاسخ‌های مرجح اولیه جفت کنید تا داده‌های ترجیحی جدید بسازید، و دوباره DPO را اجرا کنید. این فرایند «خودبازی» (Self-play) را در دو دور پیش ببرید. دقت تشخیص ترجیحات را پس از دورهای 1 و 2 مقایسه کنید تا ببینید بازآموزی چرخه‌ای چقدر کمک می‌کند.

  5. عملکرد DPO را با مدل‌های مرجع مختلف مقایسه کنید. به جای استفاده از چک‌پوینت SFT به عنوان مرجع، این حالت‌ها را بیازمایید: (الف) مدل پایه (پیش از SFT)، (ب) چک‌پوینت به دست آمده از دوره‌ی 1 آموزش DPO، (ج) میانگین متحرک نمایی (EMA) مدل خط‌مشی. در نهایت گزارش دهید کدام مدل مرجع بیشترین دقت ترجیح و پایدارترین منحنی آموزش را ارائه می‌دهد.

اصطلاحات کلیدی

اصطلاح در گفتار روزمره معنای دقیق فنی
DPO «RLHF بدون RL» بهینه‌سازی مستقیم ترجیحات (Direct Preference Optimization): یک الگوریتم یادگیری نظارت‌شده که مدل زبانی را مستقیماً بر اساس جفت‌های ترجیحی بهینه می‌کند و نیازی به مدل پاداش و PPO ندارد
پاداش ضمنی (Implicit reward) «پاداش درون خودِ مدل است» تابع پاداشی که با نسبت لگاریتم احتمال بین مدل‌های خط‌مشی و مرجع مشخص می‌شود و نیاز به مدل پاداش جداگانه را از بین می‌برد
بتای DPO «همان دما» تعیین می‌کند خط‌مشی چقدر اجازه‌ی انحراف از مدل مرجع را دارد؛ بتای کم اجازه‌ی انحراف زیاد می‌دهد و بتای زیاد مدل را نزدیک به مرجع نگه می‌دارد
نسبت لگاریتم احتمال (Log-probability ratio) «میزان تغییر رفتار مدل» log⁡π(y∣x)−log⁡πref(y∣x)\log \pi(y \mid x) - \log \pi_{\text{ref}}(y \mid x)؛ مقدار مثبت نشان می‌دهد مدل فعلی در مقایسه با مرجع، احتمال بیشتری برای آن در نظر گرفته است
مدل مرجع (Reference model) «چک‌پوینت دست‌نخورده» نسخه‌ای از مدل SFT که وزن‌هایش ثابت است و به عنوان پایه‌ای برای سنجش نسبت احتمالات استفاده می‌شود
KTO «DPO بدون جفت داده» بهینه‌سازی کانمن-تورسکی: با برچسب‌های مستقل «خوب» یا «بد» کار می‌کند و نیازی به جفت‌های ترجیحی ندارد
ORPO «هم‌راستاسازی یک‌مرحله‌ای» بهینه‌سازی ترجیحات بر اساس نسبت شانس: مراحل SFT و هم‌راستاسازی را با افزودن جمله‌ی ترجیح به زیان SFT، در یک حلقه‌ی آموزشی ادغام می‌کند
SimPO «بی‌نیاز از مدل مرجع» بهینه‌سازی ساده‌ی ترجیحات: با در نظر گرفتن میانگین لگاریتم احتمالِ نرمال‌شده بر اساس طول به عنوان پاداش ضمنی، مدل مرجع را حذف می‌کند
مالیات هم‌راستاسازی (Alignment tax) «هزینه‌ی امن کردن مدل» منابع پردازشی، داده‌ها و پیچیدگی‌های اضافه برای تبدیل یک مدل پایه به مدلی هم‌راستا؛ روش DPO این هزینه را چشمگیر کاهش می‌دهد

مطالعه‌ی بیشتر

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

الگوریتم DPO چیست و چه فرقی با RLHF دارد؟

روش DPO مستقیماً مدل زبانی را روی جفت‌های ترجیحی آموزش می‌دهد و برخلاف RLHF به مدل پاداش مجزا و الگوریتم‌های ناپایدار یادگیری تقویتی مثل PPO نیازی ندارد.

پارامتر بتا در DPO چه نقشی دارد؟

پارامتر بتا میزان انحراف مجاز مدل از مدل مرجع را تعیین می‌کند؛ بتای کوچک‌تر به مدل اجازه‌ی تغییرات بیشتر و سریع‌تر می‌دهد و بتای بزرگ‌تر مدل را به رفتار مدل مرجع نزدیک نگه می‌دارد.

مزیت DPO از نظر مصرف حافظه‌ی کارت گرافیک (VRAM) چیست؟

روش DPO حین آموزش فقط به دو مدل در حافظه (مدل جاری و مدل مرجع منجمد) نیاز دارد، در حالی که در PPO هم‌زمان به 3 تا 4 مدل در VRAM نیاز است.

روش‌های پس از DPO مثل KTO و SimPO چه تفاوتی دارند؟

روش KTO نیاز به جفت‌های ترجیحی را حذف کرده و با برچسب تکی خوب/بد کار می‌کند؛ SimPO نیز با نرمال‌سازی طول، نیاز به نگه‌داشتن مدل مرجع در حافظه را از بین می‌برد.

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

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