المحاذاة مع DPO
إعداد بيانات DPO
3 دقيقة للقراءة
DPO يتطلب بيانات تفضيل مع أزواج استجابة مختارة ومرفوضة. دعنا نتعلم كيفية هيكلة وإعداد هذه البيانات.
صيغة مجموعة بيانات DPO
الصيغة القياسية لـ DPO:
{
"prompt": "ما هي عاصمة فرنسا؟",
"chosen": "عاصمة فرنسا هي باريس. معروفة ببرج إيفل، متحف اللوفر، وتراثها الثقافي الغني.",
"rejected": "مش عارف يمكن باريس أو شي"
}
تحميل مجموعات البيانات الموجودة
العديد من مجموعات بيانات التفضيل متاحة:
from datasets import load_dataset
# UltraFeedback - بيانات تفضيل عالية الجودة
dataset = load_dataset("HuggingFaceH4/ultrafeedback_binarized")
# Anthropic HH-RLHF
dataset = load_dataset("Anthropic/hh-rlhf")
# Intel Orca DPO Pairs
dataset = load_dataset("Intel/orca_dpo_pairs")
التنسيق لـ DPOTrainer
DPOTrainer من TRL يتوقع أسماء أعمدة محددة:
from datasets import load_dataset
dataset = load_dataset("HuggingFaceH4/ultrafeedback_binarized", split="train_prefs")
# تحقق من الأعمدة
print(dataset.column_names)
# يجب أن يكون: prompt، chosen، rejected
# أو تعيين للصيغة الصحيحة
def format_dpo(example):
return {
"prompt": example["question"],
"chosen": example["response_a"],
"rejected": example["response_b"]
}
dataset = dataset.map(format_dpo)
استخدام قوالب المحادثة
لنماذج التعليمات، نسّق بقوالب المحادثة:
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.2-3B-Instruct")
def format_with_template(example):
# نسّق المحث
prompt_messages = [
{"role": "user", "content": example["prompt"]}
]
# نسّق الاستجابة المختارة
chosen_messages = [
{"role": "user", "content": example["prompt"]},
{"role": "assistant", "content": example["chosen"]}
]
# نسّق الاستجابة المرفوضة
rejected_messages = [
{"role": "user", "content": example["prompt"]},
{"role": "assistant", "content": example["rejected"]}
]
return {
"prompt": tokenizer.apply_chat_template(prompt_messages, tokenize=False),
"chosen": tokenizer.apply_chat_template(chosen_messages, tokenize=False),
"rejected": tokenizer.apply_chat_template(rejected_messages, tokenize=False)
}
dataset = dataset.map(format_with_template)
إنشاء بيانات تفضيل مخصصة
من مخرجات النموذج
ولّد استجابات متعددة ورتّبها:
from transformers import pipeline
import random
generator = pipeline("text-generation", model="meta-llama/Llama-3.2-3B-Instruct")
def create_preference_pair(prompt):
# ولّد استجابات متعددة
responses = []
for temp in [0.3, 0.7, 1.0, 1.2]:
response = generator(prompt, temperature=temp, max_new_tokens=200)
responses.append(response[0]["generated_text"])
# اطلب من البشر أو LLM ترتيبها
# ثم اختر الأفضل والأسوأ
chosen = responses[0] # الأفضل ترتيباً
rejected = responses[-1] # الأسوأ ترتيباً
return {
"prompt": prompt,
"chosen": chosen,
"rejected": rejected
}
من المحادثات الموجودة
حوّل بيانات الملاحظات لأزواج تفضيل:
def convert_feedback_to_dpo(feedback_data):
"""
المدخل: {"prompt": ..., "response": ..., "rating": 1-5}
المخرج: أزواج DPO
"""
# جمّع حسب المحث
prompt_groups = {}
for item in feedback_data:
prompt = item["prompt"]
if prompt not in prompt_groups:
prompt_groups[prompt] = []
prompt_groups[prompt].append(item)
# أنشئ أزواج من تقييمات مختلفة
dpo_data = []
for prompt, responses in prompt_groups.items():
sorted_responses = sorted(responses, key=lambda x: x["rating"], reverse=True)
if len(sorted_responses) >= 2:
dpo_data.append({
"prompt": prompt,
"chosen": sorted_responses[0]["response"],
"rejected": sorted_responses[-1]["response"]
})
return dpo_data
إرشادات جودة البيانات
أزواج تفضيل جيدة
# فرق جودة واضح
{
"prompt": "اشرح التمثيل الضوئي",
"chosen": "التمثيل الضوئي هو العملية التي تحول بها النباتات ضوء الشمس والماء وثاني أكسيد الكربون إلى جلوكوز وأكسجين. يحدث في البلاستيدات الخضراء وهو ضروري للحياة على الأرض.",
"rejected": "النباتات تصنع طعام من الشمس."
}
تجنّب
# متشابهة جداً (النموذج لا يستطيع التعلم)
{
"prompt": "ما هو 2+2؟",
"chosen": "2+2 يساوي 4.",
"rejected": "الجواب هو 4."
}
# نفس الجودة، أسلوب مختلف (ليس تفضيل)
{
"prompt": "أخبرني عن الكلاب",
"chosen": "الكلاب رفقاء مخلصون...",
"rejected": "الكلبيات تم تدجينها..."
}
التحقق
تحقق من مجموعة بياناتك قبل التدريب:
def validate_dpo_dataset(dataset):
issues = []
for i, example in enumerate(dataset):
# تحقق من الحقول المطلوبة
if not example.get("prompt"):
issues.append(f"مثال {i}: محث مفقود")
if not example.get("chosen"):
issues.append(f"مثال {i}: مختار مفقود")
if not example.get("rejected"):
issues.append(f"مثال {i}: مرفوض مفقود")
# تحقق أنهم مختلفون
if example.get("chosen") == example.get("rejected"):
issues.append(f"مثال {i}: المختار يساوي المرفوض")
# تحقق من الأطوال
if len(example.get("chosen", "")) < 10:
issues.append(f"مثال {i}: المختار قصير جداً")
print(f"وُجد {len(issues)} مشاكل")
return issues
issues = validate_dpo_dataset(dataset)
توصيات حجم مجموعة البيانات
| حجم مجموعة البيانات | النتائج المتوقعة |
|---|---|
| 100-500 | تأثير ضئيل |
| 500-2,000 | تحسن ملحوظ |
| 2,000-10,000 | محاذاة جيدة |
| 10,000+ | محاذاة قوية |
نصيحة: الجودة أهم من الكمية. 1,000 زوج منسّق بعناية يتفوق على 10,000 زوج مشوش.
بعد ذلك، لننفذ تدريب DPO مع DPOTrainer من TRL. :::