إعداد مجموعة البيانات
بيانات التفضيل لـ DPO
3 دقيقة للقراءة
التحسين المباشر للتفضيلات (DPO) يتطلب صيغة مجموعة بيانات خاصة: أزواج من الاستجابات حيث واحدة مفضلة على الأخرى. دعنا نتعلم كيفية إنشاء هذه البيانات.
صيغة مجموعة بيانات DPO
الصيغة القياسية
{
"prompt": "اشرح الحوسبة الكمية بمصطلحات بسيطة",
"chosen": "الحوسبة الكمية تستخدم بتات كمية (كيوبت) يمكنها التواجد في حالات متعددة في وقت واحد. بخلاف البتات العادية التي هي إما 0 أو 1، الكيوبت يمكن أن تكون كلاهما في وقت واحد من خلال 'التراكب'. هذا يسمح للحواسيب الكمية بمعالجة إمكانيات كثيرة في نفس الوقت، مما يجعلها قوية بشكل لا يصدق لمشاكل محددة مثل التشفير واكتشاف الأدوية.",
"rejected": "الحوسبة الكمية معقدة جداً وصعبة الشرح. تستخدم أشياء فيزيائية. ربما لن تفهمها بدون دكتوراه."
}
مع محث النظام
{
"system": "أنت معلم مفيد صبور يشرح المواضيع المعقدة بوضوح.",
"prompt": "ما هو التعلم الآلي؟",
"chosen": "التعلم الآلي هو نوع من الذكاء الاصطناعي حيث تتعلم الحواسيب الأنماط من البيانات بدلاً من برمجتها صراحة...",
"rejected": "التعلم الآلي هو عندما تتعلم الحواسيب أشياء. ابحث في جوجل للمزيد."
}
إنشاء أزواج التفضيل
الطريقة 1: توليد النموذج + ترتيب بشري
ولّد استجابات متعددة واطلب من البشر ترتيبها:
from openai import OpenAI
client = OpenAI()
def generate_candidates(prompt, n=4):
"""ولّد استجابات مرشحة متعددة."""
responses = []
for _ in range(n):
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
temperature=0.9 # درجة حرارة عالية للتنوع
)
responses.append(response.choices[0].message.content)
return responses
# ولّد المرشحين
prompt = "اشرح التكرار"
candidates = generate_candidates(prompt)
# البشر يرتبون هذه كـ: [2, 0, 3, 1] (من الأفضل للأسوأ)
# أنشئ أزواج من الترتيبات
الطريقة 2: مقارنة النماذج
استخدم نموذجاً أقوى لمقارنة الاستجابات:
def compare_responses(prompt, response_a, response_b):
"""استخدم LLM للحكم أي استجابة أفضل."""
judge_prompt = f"""قارن هاتين الاستجابتين للمحث: "{prompt}"
الاستجابة أ:
{response_a}
الاستجابة ب:
{response_b}
أي استجابة أفضل ولماذا؟ أجب فقط بـ "أ" أو "ب"."""
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": judge_prompt}]
)
winner = response.choices[0].message.content.strip()
return winner
def create_preference_pair(prompt, response_a, response_b):
winner = compare_responses(prompt, response_a, response_b)
if winner == "أ":
return {"prompt": prompt, "chosen": response_a, "rejected": response_b}
else:
return {"prompt": prompt, "chosen": response_b, "rejected": response_a}
الطريقة 3: الاختيار المبني على القواعد
أنشئ أزواج بناءً على معايير محددة:
def create_quality_pairs(prompt, responses):
"""أنشئ أزواج بناءً على معايير جودة قابلة للقياس."""
scored_responses = []
for response in responses:
score = 0
# درجة الطول (فضّل الاستجابات المفصلة)
if 100 < len(response) < 1000:
score += 2
# درجة الهيكل (فضّل الاستجابات المنظمة)
if any(marker in response for marker in ["1.", "أولاً،", "•"]):
score += 1
# درجة الاكتمال
if response.endswith((".", "!", "؟", "\"")):
score += 1
# لا تردد
if not response.startswith(("أعتقد", "ربما", "لست متأكداً")):
score += 1
scored_responses.append((response, score))
# رتّب حسب الدرجة
scored_responses.sort(key=lambda x: x[1], reverse=True)
# أنشئ أزواج من الأفضل مقابل الأسوأ
pairs = []
for i in range(len(scored_responses) // 2):
pairs.append({
"prompt": prompt,
"chosen": scored_responses[i][0],
"rejected": scored_responses[-(i+1)][0]
})
return pairs
معايير التفضيل
ما الذي يجعل استجابة "أفضل"؟ حدد معايير واضحة:
| المعيار | مثال مختار | مثال مرفوض |
|---|---|---|
| المساعدة | يوفر إجابة كاملة | يقول "ابحث في جوجل" |
| السلامة | يرفض الطلبات الضارة بشكل مناسب | يمتثل للطلبات الضارة |
| الدقة | صحيح واقعياً | يحتوي على أخطاء |
| الوضوح | منظم جيداً، سهل المتابعة | مربك، متشعب |
| النبرة | مناسبة للسياق | وقحة أو رافضة |
توسيع بيانات التفضيل
خط أنابيب التمهيد
def bootstrap_preference_dataset(seed_prompts, target_size=1000):
"""وسّع بيانات التفضيل من المحثات البذرية."""
dataset = []
for prompt in seed_prompts:
# ولّد استجابات متعددة
responses = generate_candidates(prompt, n=4)
# أنشئ كل الأزواج الممكنة
for i in range(len(responses)):
for j in range(i+1, len(responses)):
pair = create_preference_pair(prompt, responses[i], responses[j])
dataset.append(pair)
if len(dataset) >= target_size:
break
return dataset
استخدام مجموعات البيانات الموجودة
العديد من مجموعات بيانات التفضيل متاحة على Hugging Face:
from datasets import load_dataset
# حمّل مجموعات بيانات التفضيل الشائعة
datasets = {
"ultrafeedback": load_dataset("HuggingFaceH4/ultrafeedback_binarized"),
"orca_dpo": load_dataset("Intel/orca_dpo_pairs"),
"helpful_base": load_dataset("Anthropic/hh-rlhf", data_dir="helpful-base")
}
# ادمج وعيّن
combined = concatenate_datasets([d["train"] for d in datasets.values()])
sampled = combined.shuffle().select(range(10000))
ضمان الجودة
تحقق من أزواج التفضيل
def validate_preference_pair(example):
"""تأكد أن زوج التفضيل صالح."""
checks = [
len(example["prompt"]) > 10,
len(example["chosen"]) > 20,
len(example["rejected"]) > 20,
example["chosen"] != example["rejected"], # ليست متطابقة
len(example["chosen"]) != len(example["rejected"]), # أطوال مختلفة
]
return all(checks)
# صفّي الأزواج غير الصالحة
dataset = dataset.filter(validate_preference_pair)
تحقق من ضوضاء التسميات
عيّن عشوائياً وتحقق يدوياً:
import random
def audit_preferences(dataset, sample_size=50):
"""راجع يدوياً عينة من أزواج التفضيل."""
sample = random.sample(list(dataset), sample_size)
correct = 0
for example in sample:
print(f"المحث: {example['prompt'][:100]}...")
print(f"المختار: {example['chosen'][:200]}...")
print(f"المرفوض: {example['rejected'][:200]}...")
# التحقق البشري
verdict = input("تفضيل صحيح؟ (y/n): ")
if verdict.lower() == 'y':
correct += 1
accuracy = correct / sample_size
print(f"دقة التسميات: {accuracy:.1%}")
if accuracy < 0.8:
print("تحذير: ضوضاء تسميات عالية مكتشفة!")
هيكل مجموعة البيانات النهائي
# احفظ بالصيغة القياسية
preference_dataset = {
"prompt": [...],
"chosen": [...],
"rejected": [...]
}
# حوّل إلى Hugging Face Dataset
from datasets import Dataset
dataset = Dataset.from_dict(preference_dataset)
# قسّم للتدريب
dataset = dataset.train_test_split(test_size=0.1)
# احفظ على القرص
dataset.save_to_disk("./preference_data")
نصيحة: استهدف على الأقل 1,000 زوج تفضيل عالي الجودة لتدريب DPO. الجودة أهم من الكمية - التسميات المشوشة ستضر بالمحاذاة.
في الوحدة التالية، سنجمع كل هذا معاً ونبدأ الضبط الدقيق مع LoRA و QLoRA. :::