التقييم والنشر
المشاكل الشائعة وإصلاحها
3 دقيقة للقراءة
الضبط الدقيق لا يسير دائماً بسلاسة. دعنا نشخص ونصلح المشاكل الأكثر شيوعاً.
مشاكل الخسارة
الخسارة تنفجر (NaN أو Inf)
الأعراض: الخسارة تصبح NaN أو لانهاية مبكراً في التدريب
الأسباب والإصلاحات:
# المشكلة: معدل التعلم عالي جداً
# الإصلاح: قلل معدل التعلم
learning_rate = 5e-6 # ابدأ منخفضاً، زد إذا لزم
# المشكلة: فيضان التدرجات
# الإصلاح: فعّل قص التدرجات
max_grad_norm = 1.0
# المشكلة: مشاكل الدقة المختلطة
# الإصلاح: استخدم bf16 بدل fp16
bf16 = True # أكثر استقراراً من fp16
fp16 = False
# المشكلة: بيانات سيئة (نصوص فارغة، أحرف خاصة)
# الإصلاح: تحقق من مجموعة البيانات
def validate_example(example):
if not example.get("text") or len(example["text"]) < 10:
return False
if "NaN" in example["text"] or "\x00" in example["text"]:
return False
return True
dataset = dataset.filter(validate_example)
الخسارة لا تتناقص
الأعراض: الخسارة تبقى ثابتة أو تتأرجح
الإصلاحات:
# المشكلة: معدل التعلم منخفض جداً
learning_rate = 2e-4 # جرب الزيادة
# المشكلة: رتبة LoRA منخفضة جداً
r = 32 # زد من 8 أو 16
# المشكلة: وحدات مستهدفة غير كافية
target_modules = [
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"
] # ضمّن جميع الطبقات الخطية
# المشكلة: مجموعة البيانات صغيرة جداً أو متجانسة
# الإصلاح: أضف أمثلة أكثر تنوعاً
الخسارة تتناقص ثم تزيد
الأعراض: نمط الإفراط في التدريب الكلاسيكي
الإصلاحات:
# الحل 1: التوقف المبكر
from transformers import EarlyStoppingCallback
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
callbacks=[EarlyStoppingCallback(early_stopping_patience=3)]
)
# الحل 2: تنظيم أكثر
lora_dropout = 0.1 # أضف dropout
weight_decay = 0.01 # أضف تناقص الأوزان
# الحل 3: قلل epochs
num_train_epochs = 1 # غالباً 1-2 يكفي
# الحل 4: بيانات تدريب أكثر
# زد حجم مجموعة البيانات أو استخدم تعزيز البيانات
مشاكل الذاكرة
نفاد الذاكرة (OOM)
الأعراض: خطأ CUDA out of memory
إصلاحات سريعة:
# قلل حجم الدفعة
per_device_train_batch_size = 1 # ابدأ بـ 1
# زد تراكم التدرجات للحفاظ على حجم الدفعة الفعال
gradient_accumulation_steps = 8 # الدفعة الفعالة = 1 * 8 = 8
# قلل طول التسلسل
max_seq_length = 512 # تسلسلات أقصر تستخدم ذاكرة أقل
# فعّل نقاط فحص التدرجات
use_gradient_checkpointing = "unsloth" # يستبدل الحساب بالذاكرة
# استخدم التكميم 4-bit
load_in_4bit = True
# امسح ذاكرة CUDA قبل التدريب
import torch
torch.cuda.empty_cache()
الذاكرة تنمو أثناء التدريب
الأعراض: استخدام الذاكرة يزيد كل خطوة
# الإصلاح: عطّل التخزين المؤقت أثناء التدريب
model.config.use_cache = False
# الإصلاح: امسح التدرجات بشكل صحيح (عادة يُدار بواسطة المدرّب)
optimizer.zero_grad(set_to_none=True)
# الإصلاح: تحقق من تسربات الذاكرة في callbacks
# تجنب تخزين tensors في قوائم
مشاكل جودة المخرجات
مخرجات متكررة
الأعراض: النموذج يكرر عبارات أو جمل
# أثناء الاستنتاج، اضبط معاملات التوليد
outputs = model.generate(
**inputs,
max_new_tokens=200,
repetition_penalty=1.2, # عاقب التكرار
no_repeat_ngram_size=3, # لا تكرر 3-grams
temperature=0.7, # أضف عشوائية
top_p=0.9, # أخذ العينات النووي
)
# أثناء التدريب، تحقق من بيانات التدريب المتكررة
from collections import Counter
def check_repetition(dataset):
texts = [ex["text"] for ex in dataset]
duplicates = [t for t, count in Counter(texts).items() if count > 1]
print(f"وُجد {len(duplicates)} أمثلة مكررة")
return duplicates
النسيان الكارثي
الأعراض: النموذج يفقد القدرات العامة
# الإصلاح 1: قلل معدل التعلم
learning_rate = 1e-6 # محافظ جداً
# الإصلاح 2: زد LoRA alpha نسبة للرتبة
r = 16
lora_alpha = 32 # 2x الرتبة
# الإصلاح 3: اخلط بيانات عامة
from datasets import concatenate_datasets
# أضف بعض بيانات التعليمات العامة
general_dataset = load_dataset("yahma/alpaca-cleaned", split="train[:1000]")
combined = concatenate_datasets([domain_dataset, general_dataset])
combined = combined.shuffle(seed=42)
# الإصلاح 4: استخدم beta أعلى في DPO (ابق أقرب للمرجع)
beta = 0.5 # أعلى = انحراف أقل
صيغة/أسلوب خاطئ
الأعراض: النموذج لا يتبع الصيغة المتوقعة
# الإصلاح: تأكد أن بيانات التدريب تطابق الصيغة المتوقعة بالضبط
def format_example(example):
# استخدم قالب المحادثة الذي يتوقعه نموذجك بالضبط
messages = [
{"role": "system", "content": "أنت مساعد مفيد."},
{"role": "user", "content": example["instruction"]},
{"role": "assistant", "content": example["output"]}
]
return {"text": tokenizer.apply_chat_template(messages, tokenize=False)}
# تحقق أن الصيغة صحيحة
sample = dataset[0]
print(format_example(sample)["text"])
عدم استقرار التدريب
مشاكل التدرجات
# راقب التدرجات
def log_gradients(model):
total_norm = 0
for p in model.parameters():
if p.grad is not None:
param_norm = p.grad.data.norm(2)
total_norm += param_norm.item() ** 2
total_norm = total_norm ** 0.5
print(f"معيار التدرج: {total_norm}")
# إذا كانت التدرجات كبيرة جداً
max_grad_norm = 0.5 # اقص بقوة أكبر
# إذا كانت التدرجات صغيرة جداً (تتلاشى)
learning_rate = 5e-5 # زد معدل التعلم
تدريب DPO غير مستقر
# مشاكل خاصة بـ DPO
dpo_config = DPOConfig(
# ابدأ بـ beta محافظ
beta=0.1,
# معدل تعلم أقل من SFT
learning_rate=5e-7,
# تأكد أن النموذج المرجعي مجمد
# (يُدار تلقائياً بواسطة DPOTrainer)
# راقب هوامش المكافأة
logging_steps=10,
)
# إذا أصبحت الهوامش سالبة، تحقق من جودة البيانات
# المختار يجب أن يكون أفضل بوضوح من المرفوض
قائمة فحص التصحيح
عندما يفشل التدريب:
-
تحقق من البيانات أولاً
- لا أمثلة فارغة
- صيغة صحيحة
- أطوال معقولة
- لا أحرف خاصة تسبب مشاكل
-
تحقق من التكوين
- معدل التعلم مناسب للمهمة
- حجم الدفعة يناسب الذاكرة
- وحدات مستهدفة صحيحة للنموذج
-
راقب المقاييس
- الخسارة تتجه للأسفل
- لا قيم NaN
- استخدام الذاكرة مستقر
-
اختبر تدريجياً
- درّب على 100 مثال أولاً
- تحقق من المخرجات قبل التدريب الكامل
- احفظ نقاط الفحص بشكل متكرر
نصيحة: عند التصحيح، قلل كل شيء للحد الأدنى (1 epoch، 100 مثال، حجم دفعة 1) وتحقق أن خط الأنابيب يعمل قبل التوسع.
بعد ذلك، لنتعلم كيفية نشر نموذجك المضبوط على Ollama. :::